xref: /netbsd-src/external/bsd/ipf/dist/tools/ipnat_y.y (revision e61202360d5611414dd6f6115934a96aa1f50b1a)
1 /*	$NetBSD: ipnat_y.y,v 1.1.1.2 2012/07/22 13:44:57 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 ICMP Id number");
875 			  if ($3.p2 < 0 || $3.p2 > 65535)
876 				yyerror("invalid 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; }
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("unknwon 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 
1168 					  bzero(&$$, sizeof($$));
1169 					  if (gethost(AF_INET, $1,
1170 						      &addr) == 0) {
1171 						$$.a = addr;
1172 						$$.f = AF_INET;
1173 					  } else
1174 					  if (gethost(AF_INET6, $1,
1175 						      &addr) == 0) {
1176 						$$.a = addr;
1177 						$$.f = AF_INET6;
1178 					  } else {
1179 						FPRINTF(stderr,
1180 							"Unknown host '%s'\n",
1181 							$1);
1182 					  }
1183 					  free($1);
1184 					}
1185 	| YY_NUMBER			{ bzero(&$$, sizeof($$));
1186 					  $$.a.in4.s_addr = htonl($1);
1187 					  if ($$.a.in4.s_addr != 0)
1188 						$$.f = AF_INET;
1189 					}
1190 	| ipv4				{ $$ = $1; }
1191 	| YY_IPV6			{ bzero(&$$, sizeof($$));
1192 					  $$.a = $1;
1193 					  $$.f = AF_INET6;
1194 					}
1195 	| YY_NUMBER YY_IPV6		{ bzero(&$$, sizeof($$));
1196 					  $$.a = $2;
1197 					  $$.f = AF_INET6;
1198 					}
1199 	;
1200 
1201 compare:
1202 	'='				{ $$ = FR_EQUAL; }
1203 	| YY_CMP_EQ			{ $$ = FR_EQUAL; }
1204 	| YY_CMP_NE			{ $$ = FR_NEQUAL; }
1205 	| YY_CMP_LT			{ $$ = FR_LESST; }
1206 	| YY_CMP_LE			{ $$ = FR_LESSTE; }
1207 	| YY_CMP_GT			{ $$ = FR_GREATERT; }
1208 	| YY_CMP_GE			{ $$ = FR_GREATERTE; }
1209 
1210 range:
1211 	YY_RANGE_OUT			{ $$ = FR_OUTRANGE; }
1212 	| YY_RANGE_IN			{ $$ = FR_INRANGE; }
1213 	| ':'				{ $$ = FR_INCRANGE; }
1214 	;
1215 
1216 ipaddr:	ipv4				{ $$ = $1; }
1217 	| YY_IPV6			{ $$.a = $1;
1218 					  $$.f = AF_INET6;
1219 					}
1220 	;
1221 
1222 ipv4:	YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER
1223 		{ if ($1 > 255 || $3 > 255 || $5 > 255 || $7 > 255) {
1224 			yyerror("Invalid octet string for IP address");
1225 			return 0;
1226 		  }
1227 		  bzero((char *)&$$, sizeof($$));
1228 		  $$.a.in4.s_addr = ($1 << 24) | ($3 << 16) | ($5 << 8) | $7;
1229 		  $$.a.in4.s_addr = htonl($$.a.in4.s_addr);
1230 		  $$.f = AF_INET;
1231 		}
1232 	;
1233 
1234 %%
1235 
1236 
1237 static	wordtab_t	proxies[] = {
1238 	{ "dns",	IPNY_DNS }
1239 };
1240 
1241 static	wordtab_t	dnswords[] = {
1242 	{ "allow",	IPNY_ALLOW },
1243 	{ "block",	IPNY_DENY },
1244 	{ "deny",	IPNY_DENY },
1245 	{ "drop",	IPNY_DENY },
1246 	{ "pass",	IPNY_ALLOW },
1247 
1248 };
1249 
1250 static	wordtab_t	yywords[] = {
1251 	{ "age",	IPNY_AGE },
1252 	{ "any",	IPNY_ANY },
1253 	{ "auto",	IPNY_AUTO },
1254 	{ "bimap",	IPNY_BIMAP },
1255 	{ "config",	IPNY_CONFIG },
1256 	{ "divert",	IPNY_DIVERT },
1257 	{ "dst",	IPNY_DST },
1258 	{ "dstlist",	IPNY_DSTLIST },
1259 	{ "frag",	IPNY_FRAG },
1260 	{ "from",	IPNY_FROM },
1261 	{ "hash",	IPNY_HASH },
1262 	{ "icmpidmap",	IPNY_ICMPIDMAP },
1263 	{ "in",		IPNY_IN },
1264 	{ "inet",	IPNY_INET },
1265 	{ "inet6",	IPNY_INET6 },
1266 	{ "mask",	IPNY_MASK },
1267 	{ "map",	IPNY_MAP },
1268 	{ "map-block",	IPNY_MAPBLOCK },
1269 	{ "mssclamp",	IPNY_MSSCLAMP },
1270 	{ "netmask",	IPNY_MASK },
1271 	{ "no",		IPNY_NO },
1272 	{ "on",		IPNY_ON },
1273 	{ "out",	IPNY_OUT },
1274 	{ "pool",	IPNY_POOL },
1275 	{ "port",	IPNY_PORT },
1276 	{ "portmap",	IPNY_PORTMAP },
1277 	{ "ports",	IPNY_PORTS },
1278 	{ "proto",	IPNY_PROTO },
1279 	{ "proxy",	IPNY_PROXY },
1280 	{ "purge",	IPNY_PURGE },
1281 	{ "range",	IPNY_RANGE },
1282 	{ "rewrite",	IPNY_REWRITE },
1283 	{ "rdr",	IPNY_RDR },
1284 	{ "round-robin",IPNY_ROUNDROBIN },
1285 	{ "sequential",	IPNY_SEQUENTIAL },
1286 	{ "src",	IPNY_SRC },
1287 	{ "sticky",	IPNY_STICKY },
1288 	{ "tag",	IPNY_TAG },
1289 	{ "tcp",	IPNY_TCP },
1290 	{ "tcpudp",	IPNY_TCPUDP },
1291 	{ "to",		IPNY_TO },
1292 	{ "udp",	IPNY_UDP },
1293 	{ "-",		'-' },
1294 	{ "->",		IPNY_TLATE },
1295 	{ "eq",		YY_CMP_EQ },
1296 	{ "ne",		YY_CMP_NE },
1297 	{ "lt",		YY_CMP_LT },
1298 	{ "gt",		YY_CMP_GT },
1299 	{ "le",		YY_CMP_LE },
1300 	{ "ge",		YY_CMP_GE },
1301 	{ NULL,		0 }
1302 };
1303 
1304 
1305 int
1306 ipnat_parsefile(fd, addfunc, ioctlfunc, filename)
1307 	int fd;
1308 	addfunc_t addfunc;
1309 	ioctlfunc_t ioctlfunc;
1310 	char *filename;
1311 {
1312 	FILE *fp = NULL;
1313 	int rval;
1314 	char *s;
1315 
1316 	yylineNum = 1;
1317 
1318 	(void) yysettab(yywords);
1319 
1320 	s = getenv("YYDEBUG");
1321 	if (s)
1322 		yydebug = atoi(s);
1323 	else
1324 		yydebug = 0;
1325 
1326 	if (strcmp(filename, "-")) {
1327 		fp = fopen(filename, "r");
1328 		if (!fp) {
1329 			FPRINTF(stderr, "fopen(%s) failed: %s\n", filename,
1330 				STRERROR(errno));
1331 			return -1;
1332 		}
1333 	} else
1334 		fp = stdin;
1335 
1336 	while ((rval = ipnat_parsesome(fd, addfunc, ioctlfunc, fp)) == 0)
1337 		;
1338 	if (fp != NULL)
1339 		fclose(fp);
1340 	if (rval == -1)
1341 		rval = 0;
1342 	else if (rval != 0)
1343 		rval = 1;
1344 	return rval;
1345 }
1346 
1347 
1348 int
1349 ipnat_parsesome(fd, addfunc, ioctlfunc, fp)
1350 	int fd;
1351 	addfunc_t addfunc;
1352 	ioctlfunc_t ioctlfunc;
1353 	FILE *fp;
1354 {
1355 	char *s;
1356 	int i;
1357 
1358 	natfd = fd;
1359 	parser_error = 0;
1360 	nataddfunc = addfunc;
1361 	natioctlfunc = ioctlfunc;
1362 
1363 	if (feof(fp))
1364 		return -1;
1365 	i = fgetc(fp);
1366 	if (i == EOF)
1367 		return -1;
1368 	if (ungetc(i, fp) == EOF)
1369 		return -1;
1370 	if (feof(fp))
1371 		return -1;
1372 	s = getenv("YYDEBUG");
1373 	if (s)
1374 		yydebug = atoi(s);
1375 	else
1376 		yydebug = 0;
1377 
1378 	yyin = fp;
1379 	yyparse();
1380 	return parser_error;
1381 }
1382 
1383 
1384 static void
1385 newnatrule()
1386 {
1387 	ipnat_t *n;
1388 
1389 	n = calloc(1, sizeof(*n));
1390 	if (n == NULL)
1391 		return;
1392 
1393 	if (nat == NULL) {
1394 		nattop = nat = n;
1395 		n->in_pnext = &nattop;
1396 	} else {
1397 		nat->in_next = n;
1398 		n->in_pnext = &nat->in_next;
1399 		nat = n;
1400 	}
1401 
1402 	n->in_flineno = yylineNum;
1403 	n->in_ifnames[0] = -1;
1404 	n->in_ifnames[1] = -1;
1405 	n->in_plabel = -1;
1406 	n->in_pconfig = -1;
1407 	n->in_size = sizeof(*n);
1408 
1409 	suggest_port = 0;
1410 }
1411 
1412 
1413 static void
1414 setnatproto(p)
1415 	int p;
1416 {
1417 	nat->in_pr[0] = p;
1418 	nat->in_pr[1] = p;
1419 
1420 	switch (p)
1421 	{
1422 	case IPPROTO_TCP :
1423 		nat->in_flags |= IPN_TCP;
1424 		nat->in_flags &= ~IPN_UDP;
1425 		break;
1426 	case IPPROTO_UDP :
1427 		nat->in_flags |= IPN_UDP;
1428 		nat->in_flags &= ~IPN_TCP;
1429 		break;
1430 	case IPPROTO_ICMP :
1431 		nat->in_flags &= ~IPN_TCPUDP;
1432 		if (!(nat->in_flags & IPN_ICMPQUERY) &&
1433 		    !(nat->in_redir & NAT_DIVERTUDP)) {
1434 			nat->in_dcmp = 0;
1435 			nat->in_scmp = 0;
1436 			nat->in_dpmin = 0;
1437 			nat->in_dpmax = 0;
1438 			nat->in_dpnext = 0;
1439 			nat->in_spmin = 0;
1440 			nat->in_spmax = 0;
1441 			nat->in_spnext = 0;
1442 		}
1443 		break;
1444 	default :
1445 		if ((nat->in_redir & NAT_MAPBLK) == 0) {
1446 			nat->in_flags &= ~IPN_TCPUDP;
1447 			nat->in_dcmp = 0;
1448 			nat->in_scmp = 0;
1449 			nat->in_dpmin = 0;
1450 			nat->in_dpmax = 0;
1451 			nat->in_dpnext = 0;
1452 			nat->in_spmin = 0;
1453 			nat->in_spmax = 0;
1454 			nat->in_spnext = 0;
1455 		}
1456 		break;
1457 	}
1458 
1459 	if ((nat->in_flags & (IPN_TCP|IPN_UDP)) == 0) {
1460 		nat->in_stop = 0;
1461 		nat->in_dtop = 0;
1462 		nat->in_osport = 0;
1463 		nat->in_odport = 0;
1464 		nat->in_stop = 0;
1465 		nat->in_osport = 0;
1466 		nat->in_dtop = 0;
1467 		nat->in_odport = 0;
1468 	}
1469 	if ((nat->in_flags & (IPN_TCPUDP|IPN_FIXEDDPORT)) == IPN_FIXEDDPORT)
1470 		nat->in_flags &= ~IPN_FIXEDDPORT;
1471 }
1472 
1473 
1474 int
1475 ipnat_addrule(fd, ioctlfunc, ptr)
1476 	int fd;
1477 	ioctlfunc_t ioctlfunc;
1478 	void *ptr;
1479 {
1480 	ioctlcmd_t add, del;
1481 	ipfobj_t obj;
1482 	ipnat_t *ipn;
1483 
1484 	ipn = ptr;
1485 	bzero((char *)&obj, sizeof(obj));
1486 	obj.ipfo_rev = IPFILTER_VERSION;
1487 	obj.ipfo_size = ipn->in_size;
1488 	obj.ipfo_type = IPFOBJ_IPNAT;
1489 	obj.ipfo_ptr = ptr;
1490 
1491 	if ((opts & OPT_DONOTHING) != 0)
1492 		fd = -1;
1493 
1494 	if (opts & OPT_ZERORULEST) {
1495 		add = SIOCZRLST;
1496 		del = 0;
1497 	} else if (opts & OPT_PURGE) {
1498 		add = 0;
1499 		del = SIOCPURGENAT;
1500 	} else {
1501 		add = SIOCADNAT;
1502 		del = SIOCRMNAT;
1503 	}
1504 
1505 	if ((opts & OPT_VERBOSE) != 0)
1506 		printnat(ipn, opts);
1507 
1508 	if (opts & OPT_DEBUG)
1509 		binprint(ipn, sizeof(*ipn));
1510 
1511 	if ((opts & OPT_ZERORULEST) != 0) {
1512 		if ((*ioctlfunc)(fd, add, (void *)&obj) == -1) {
1513 			if ((opts & OPT_DONOTHING) == 0) {
1514 				char msg[80];
1515 
1516 				sprintf(msg, "%d:ioctl(zero nat rule)",
1517 					ipn->in_flineno);
1518 				return ipf_perror_fd(fd, ioctlfunc, msg);
1519 			}
1520 		} else {
1521 			PRINTF("hits %lu ", ipn->in_hits);
1522 #ifdef USE_QUAD_T
1523 			PRINTF("bytes %"PRIu64" ",
1524 			       ipn->in_bytes[0] + ipn->in_bytes[1]);
1525 #else
1526 			PRINTF("bytes %lu ",
1527 			       ipn->in_bytes[0] + ipn->in_bytes[1]);
1528 #endif
1529 			printnat(ipn, opts);
1530 		}
1531 	} else if ((opts & OPT_REMOVE) != 0) {
1532 		if ((*ioctlfunc)(fd, del, (void *)&obj) == -1) {
1533 			if ((opts & OPT_DONOTHING) == 0) {
1534 				char msg[80];
1535 
1536 				sprintf(msg, "%d:ioctl(delete nat rule)",
1537 					ipn->in_flineno);
1538 				return ipf_perror_fd(fd, ioctlfunc, msg);
1539 			}
1540 		}
1541 	} else {
1542 		if ((*ioctlfunc)(fd, add, (void *)&obj) == -1) {
1543 			if ((opts & OPT_DONOTHING) == 0) {
1544 				char msg[80];
1545 
1546 				sprintf(msg, "%d:ioctl(add/insert nat rule)",
1547 					ipn->in_flineno);
1548 				if (errno == EEXIST) {
1549 					sprintf(msg + strlen(msg), "(line %d)",
1550 						ipn->in_flineno);
1551 				}
1552 				return ipf_perror_fd(fd, ioctlfunc, msg);
1553 			}
1554 		}
1555 	}
1556 	return 0;
1557 }
1558 
1559 
1560 static void
1561 setmapifnames()
1562 {
1563 	if (nat->in_ifnames[1] == -1)
1564 		nat->in_ifnames[1] = nat->in_ifnames[0];
1565 
1566 	if ((suggest_port == 1) && (nat->in_flags & IPN_TCPUDP) == 0)
1567 		nat->in_flags |= IPN_TCPUDP;
1568 
1569 	if ((nat->in_flags & IPN_TCPUDP) == 0)
1570 		setnatproto(nat->in_pr[1]);
1571 
1572 	if (((nat->in_redir & NAT_MAPBLK) != 0) ||
1573 	      ((nat->in_flags & IPN_AUTOPORTMAP) != 0))
1574 		nat_setgroupmap(nat);
1575 }
1576 
1577 
1578 static void
1579 setrdrifnames()
1580 {
1581 	if ((suggest_port == 1) && (nat->in_flags & IPN_TCPUDP) == 0)
1582 		nat->in_flags |= IPN_TCPUDP;
1583 
1584 	if ((nat->in_pr[0] == 0) && ((nat->in_flags & IPN_TCPUDP) == 0) &&
1585 	    (nat->in_dpmin != 0 || nat->in_dpmax != 0 || nat->in_dpnext != 0))
1586 		setnatproto(IPPROTO_TCP);
1587 
1588 	if (nat->in_ifnames[1] == -1)
1589 		nat->in_ifnames[1] = nat->in_ifnames[0];
1590 }
1591 
1592 
1593 static void
1594 proxy_setconfig(proxy)
1595 	int proxy;
1596 {
1597 	if (proxy == IPNY_DNS) {
1598 		yysetfixeddict(dnswords);
1599 	}
1600 }
1601 
1602 
1603 static void
1604 proxy_unsetconfig()
1605 {
1606 	yyresetdict();
1607 }
1608 
1609 
1610 static namelist_t *
1611 proxy_dns_add_pass(prefix, name)
1612 	char *prefix, *name;
1613 {
1614 	namelist_t *n;
1615 
1616 	n = calloc(1, sizeof(*n));
1617 	if (n != NULL) {
1618 		if (prefix == NULL || *prefix == '\0') {
1619 			n->na_name = strdup(name);
1620 		} else {
1621 			n->na_name = malloc(strlen(name) + strlen(prefix) + 1);
1622 			strcpy(n->na_name, prefix);
1623 			strcat(n->na_name, name);
1624 		}
1625 	}
1626 	return n;
1627 }
1628 
1629 
1630 static namelist_t *
1631 proxy_dns_add_block(prefix, name)
1632 	char *prefix, *name;
1633 {
1634 	namelist_t *n;
1635 
1636 	n = calloc(1, sizeof(*n));
1637 	if (n != NULL) {
1638 		if (prefix == NULL || *prefix == '\0') {
1639 			n->na_name = strdup(name);
1640 		} else {
1641 			n->na_name = malloc(strlen(name) + strlen(prefix) + 1);
1642 			strcpy(n->na_name, prefix);
1643 			strcat(n->na_name, name);
1644 		}
1645 		n->na_value = 1;
1646 	}
1647 	return n;
1648 }
1649 
1650 
1651 static void
1652 proxy_addconfig(proxy, proto, conf, list)
1653 	char *proxy, *conf;
1654 	int proto;
1655 	namelist_t *list;
1656 {
1657 	proxyrule_t *pr;
1658 
1659 	pr = calloc(1, sizeof(*pr));
1660 	if (pr != NULL) {
1661 		pr->pr_proto = proto;
1662 		pr->pr_proxy = proxy;
1663 		pr->pr_conf = conf;
1664 		pr->pr_names = list;
1665 		pr->pr_next = prules;
1666 		prules = pr;
1667 	}
1668 }
1669 
1670 
1671 static void
1672 proxy_loadrules(fd, ioctlfunc, rules)
1673 	int fd;
1674 	ioctlfunc_t ioctlfunc;
1675 	proxyrule_t *rules;
1676 {
1677 	proxyrule_t *pr;
1678 
1679 	while ((pr = rules) != NULL) {
1680 		proxy_loadconfig(fd, ioctlfunc, pr->pr_proxy, pr->pr_proto,
1681 				 pr->pr_conf, pr->pr_names);
1682 		rules = pr->pr_next;
1683 		free(pr->pr_conf);
1684 		free(pr);
1685 	}
1686 }
1687 
1688 
1689 static void
1690 proxy_loadconfig(fd, ioctlfunc, proxy, proto, conf, list)
1691 	int fd;
1692 	ioctlfunc_t ioctlfunc;
1693 	char *proxy, *conf;
1694 	int proto;
1695 	namelist_t *list;
1696 {
1697 	namelist_t *na;
1698 	ipfobj_t obj;
1699 	ap_ctl_t pcmd;
1700 
1701 	obj.ipfo_rev = IPFILTER_VERSION;
1702 	obj.ipfo_type = IPFOBJ_PROXYCTL;
1703 	obj.ipfo_size = sizeof(pcmd);
1704 	obj.ipfo_ptr = &pcmd;
1705 
1706 	while ((na = list) != NULL) {
1707 		if ((opts & OPT_REMOVE) != 0)
1708 			pcmd.apc_cmd = APC_CMD_DEL;
1709 		else
1710 			pcmd.apc_cmd = APC_CMD_ADD;
1711 		pcmd.apc_dsize = strlen(na->na_name) + 1;
1712 		pcmd.apc_data = na->na_name;
1713 		pcmd.apc_arg = na->na_value;
1714 		pcmd.apc_p = proto;
1715 
1716 		strncpy(pcmd.apc_label, proxy, APR_LABELLEN);
1717 		pcmd.apc_label[APR_LABELLEN - 1] = '\0';
1718 
1719 		strncpy(pcmd.apc_config, conf, APR_LABELLEN);
1720 		pcmd.apc_config[APR_LABELLEN - 1] = '\0';
1721 
1722 		if ((*ioctlfunc)(fd, SIOCPROXY, (void *)&obj) == -1) {
1723                         if ((opts & OPT_DONOTHING) == 0) {
1724                                 char msg[80];
1725 
1726                                 sprintf(msg, "%d:ioctl(add/remove proxy rule)",
1727 					yylineNum);
1728                                 ipf_perror_fd(fd, ioctlfunc, msg);
1729 				return;
1730                         }
1731 		}
1732 
1733 		list = na->na_next;
1734 		free(na->na_name);
1735 		free(na);
1736 	}
1737 }
1738 
1739 
1740 static void
1741 setifname(np, idx, name)
1742 	ipnat_t **np;
1743 	int idx;
1744 	char *name;
1745 {
1746 	int pos;
1747 
1748 	pos = addname(np, name);
1749 	if (pos == -1)
1750 		return;
1751 	(*np)->in_ifnames[idx] = pos;
1752 }
1753 
1754 
1755 static int
1756 addname(np, name)
1757 	ipnat_t **np;
1758 	char *name;
1759 {
1760 	ipnat_t *n;
1761 	int nlen;
1762 	int pos;
1763 
1764 	nlen = strlen(name) + 1;
1765 	n = realloc(*np, (*np)->in_size + nlen);
1766 	if (*np == nattop)
1767 		nattop = n;
1768 	*np = n;
1769 	if (n == NULL)
1770 		return -1;
1771 	if (n->in_pnext != NULL)
1772 		*n->in_pnext = n;
1773 	n->in_size += nlen;
1774 	pos = n->in_namelen;
1775 	n->in_namelen += nlen;
1776 	strcpy(n->in_names + pos, name);
1777 	n->in_names[n->in_namelen] = '\0';
1778 	return pos;
1779 }
1780