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