xref: /illumos-gate/usr/src/cmd/ipf/tools/ipnat_y.y (revision ef292b7f)
1 %{
2 /*
3  * Copyright (C) 2003 by Darren Reed.
4  *
5  * See the IPFILTER.LICENCE file for details on licencing.
6  *
7  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
8  * Use is subject to license terms.
9  */
10 
11 #pragma ident	"%Z%%M%	%I%	%E% SMI"
12 
13 #ifdef  __FreeBSD__
14 # ifndef __FreeBSD_cc_version
15 #  include <osreldate.h>
16 # else
17 #  if __FreeBSD_cc_version < 430000
18 #   include <osreldate.h>
19 #  endif
20 # endif
21 #endif
22 #include <stdio.h>
23 #include <unistd.h>
24 #include <string.h>
25 #include <fcntl.h>
26 #include <errno.h>
27 #if !defined(__SVR4) && !defined(__GNUC__)
28 #include <strings.h>
29 #endif
30 #include <sys/types.h>
31 #include <sys/param.h>
32 #include <sys/file.h>
33 #include <stdlib.h>
34 #include <stddef.h>
35 #include <sys/socket.h>
36 #include <sys/ioctl.h>
37 #include <netinet/in.h>
38 #include <netinet/in_systm.h>
39 #include <sys/time.h>
40 #include <syslog.h>
41 #include <net/if.h>
42 #if __FreeBSD_version >= 300000
43 # include <net/if_var.h>
44 #endif
45 #include <netdb.h>
46 #include <arpa/nameser.h>
47 #include <resolv.h>
48 #include "ipf.h"
49 #include "netinet/ipl.h"
50 #include "ipnat_l.h"
51 
52 #define	YYDEBUG	1
53 
54 extern	void	yyerror __P((char *));
55 extern	int	yyparse __P((void));
56 extern	int	yylex __P((void));
57 extern	int	yydebug;
58 extern	FILE	*yyin;
59 extern	int	yylineNum;
60 
61 static	ipnat_t		*nattop = NULL;
62 static	ipnat_t		*nat = NULL;
63 static	int		natfd = -1;
64 static	ioctlfunc_t	natioctlfunc = NULL;
65 static	addfunc_t	nataddfunc = NULL;
66 
67 static	void	newnatrule __P((void));
68 static	void	setnatproto __P((int));
69 static  u_32_t  lookuphost __P((char *));
70 
71 %}
72 %union	{
73 	char	*str;
74 	u_32_t	num;
75 	struct	in_addr	ipa;
76 	frentry_t	fr;
77 	frtuc_t	*frt;
78 	u_short	port;
79 	struct	{
80 		u_short	p1;
81 		u_short	p2;
82 		int	pc;
83 	} pc;
84 	struct	{
85 		struct	in_addr	a;
86 		struct	in_addr	m;
87 	} ipp;
88 	union	i6addr	ip6;
89 };
90 
91 %token  <num>   YY_NUMBER YY_HEX
92 %token  <str>   YY_STR
93 %token	  YY_COMMENT
94 %token	  YY_CMP_EQ YY_CMP_NE YY_CMP_LE YY_CMP_GE YY_CMP_LT YY_CMP_GT
95 %token	  YY_RANGE_OUT YY_RANGE_IN
96 %token  <ip6>   YY_IPV6
97 
98 %token	IPNY_MAPBLOCK IPNY_RDR IPNY_PORT IPNY_PORTS IPNY_AUTO IPNY_RANGE
99 %token	IPNY_MAP IPNY_BIMAP IPNY_FROM IPNY_TO IPNY_MASK IPNY_PORTMAP IPNY_ANY
100 %token	IPNY_ROUNDROBIN IPNY_FRAG IPNY_AGE IPNY_ICMPIDMAP IPNY_PROXY
101 %token	IPNY_TCP IPNY_UDP IPNY_TCPUDP IPNY_STICKY IPNY_MSSCLAMP IPNY_TAG
102 %token	IPNY_TLATE
103 %type	<port> portspec
104 %type	<num> hexnumber compare range proto
105 %type	<ipa> hostname ipv4
106 %type	<ipp> addr nummask rhaddr
107 %type	<pc> portstuff
108 %%
109 file:	line
110 	| assign
111 	| file line
112 	| file assign
113 	;
114 
115 line:	xx rule		{ while ((nat = nattop) != NULL) {
116 				nattop = nat->in_next;
117 				(*nataddfunc)(natfd, natioctlfunc, nat);
118 				free(nat);
119 			  }
120 			  resetlexer();
121 			}
122 	| YY_COMMENT
123 	;
124 
125 assign:	YY_STR assigning YY_STR ';'	{ set_variable($1, $3);
126 					  resetlexer();
127 					  free($1);
128 					  free($3);
129 					}
130 	;
131 
132 assigning:
133 	'='				{ yyvarnext = 1; }
134 	;
135 
136 xx:					{ newnatrule(); }
137 	;
138 
139 rule:	map eol
140 	| mapblock eol
141 	| redir eol
142 	;
143 
144 eol:	| ';'
145 	;
146 
147 map:	mapit ifnames addr IPNY_TLATE rhaddr proxy mapoptions
148 				{ nat->in_v = 4;
149 				  nat->in_inip = $3.a.s_addr;
150 				  nat->in_inmsk = $3.m.s_addr;
151 				  nat->in_outip = $5.a.s_addr;
152 				  nat->in_outmsk = $5.m.s_addr;
153 				  if (nat->in_ifnames[1][0] == '\0')
154 					strncpy(nat->in_ifnames[1],
155 						nat->in_ifnames[0],
156 						sizeof(nat->in_ifnames[0]));
157 				  if ((nat->in_flags & IPN_TCPUDP) == 0)
158 					setnatproto(nat->in_p);
159 				  if (((nat->in_redir & NAT_MAPBLK) != 0) ||
160 				      ((nat->in_flags & IPN_AUTOPORTMAP) != 0))
161 					nat_setgroupmap(nat);
162 				}
163 	| mapit ifnames addr IPNY_TLATE rhaddr mapport mapoptions
164 				{ nat->in_v = 4;
165 				  nat->in_inip = $3.a.s_addr;
166 				  nat->in_inmsk = $3.m.s_addr;
167 				  nat->in_outip = $5.a.s_addr;
168 				  nat->in_outmsk = $5.m.s_addr;
169 				  if (nat->in_ifnames[1][0] == '\0')
170 					strncpy(nat->in_ifnames[1],
171 						nat->in_ifnames[0],
172 						sizeof(nat->in_ifnames[0]));
173 				  if ((nat->in_flags & IPN_TCPUDPICMPQ) == 0)
174 					setnatproto(nat->in_p);
175 				  if (((nat->in_redir & NAT_MAPBLK) != 0) ||
176 				      ((nat->in_flags & IPN_AUTOPORTMAP) != 0))
177 					nat_setgroupmap(nat);
178 				}
179 	| mapit ifnames mapfrom IPNY_TLATE rhaddr proxy mapoptions
180 				{ nat->in_v = 4;
181 				  nat->in_outip = $5.a.s_addr;
182 				  nat->in_outmsk = $5.m.s_addr;
183 				  if (nat->in_ifnames[1][0] == '\0')
184 					strncpy(nat->in_ifnames[1],
185 						nat->in_ifnames[0],
186 						sizeof(nat->in_ifnames[0]));
187 				  if ((nat->in_flags & IPN_TCPUDP) == 0)
188 					setnatproto(nat->in_p);
189 				  if (((nat->in_redir & NAT_MAPBLK) != 0) ||
190 				      ((nat->in_flags & IPN_AUTOPORTMAP) != 0))
191 					nat_setgroupmap(nat);
192 				}
193 	| mapit ifnames mapfrom IPNY_TLATE rhaddr mapport mapoptions
194 				{ nat->in_v = 4;
195 				  nat->in_outip = $5.a.s_addr;
196 				  nat->in_outmsk = $5.m.s_addr;
197 				  if (nat->in_ifnames[1][0] == '\0')
198 					strncpy(nat->in_ifnames[1],
199 						nat->in_ifnames[0],
200 						sizeof(nat->in_ifnames[0]));
201 				  if ((nat->in_flags & IPN_TCPUDPICMPQ) == 0)
202 					setnatproto(nat->in_p);
203 				  if (((nat->in_redir & NAT_MAPBLK) != 0) ||
204 				      ((nat->in_flags & IPN_AUTOPORTMAP) != 0))
205 					nat_setgroupmap(nat);
206 				}
207 	;
208 
209 mapblock:
210 	mapblockit ifnames addr IPNY_TLATE addr ports mapoptions
211 				{ nat->in_v = 4;
212 				  nat->in_inip = $3.a.s_addr;
213 				  nat->in_inmsk = $3.m.s_addr;
214 				  nat->in_outip = $5.a.s_addr;
215 				  nat->in_outmsk = $5.m.s_addr;
216 				  if (nat->in_ifnames[1][0] == '\0')
217 					strncpy(nat->in_ifnames[1],
218 						nat->in_ifnames[0],
219 						sizeof(nat->in_ifnames[0]));
220 				  if ((nat->in_flags & IPN_TCPUDP) == 0)
221 					setnatproto(nat->in_p);
222 				  if (((nat->in_redir & NAT_MAPBLK) != 0) ||
223 				      ((nat->in_flags & IPN_AUTOPORTMAP) != 0))
224 					nat_setgroupmap(nat);
225 				}
226 	;
227 
228 redir:	rdrit ifnames addr dport IPNY_TLATE dip nport setproto rdroptions
229 				{ nat->in_v = 4;
230 				  nat->in_outip = $3.a.s_addr;
231 				  nat->in_outmsk = $3.m.s_addr;
232 				  if (nat->in_ifnames[1][0] == '\0')
233 					strncpy(nat->in_ifnames[1],
234 						nat->in_ifnames[0],
235 						sizeof(nat->in_ifnames[0]));
236 				  if ((nat->in_p == 0) &&
237 				      ((nat->in_flags & IPN_TCPUDP) == 0) &&
238 				      (nat->in_pmin != 0 ||
239 				       nat->in_pmax != 0 ||
240 				       nat->in_pnext != 0))
241 						setnatproto(IPPROTO_TCP);
242 				}
243 	| rdrit ifnames rdrfrom IPNY_TLATE dip nport setproto rdroptions
244 				{ nat->in_v = 4;
245 				  if ((nat->in_p == 0) &&
246 				      ((nat->in_flags & IPN_TCPUDP) == 0) &&
247 				      (nat->in_pmin != 0 ||
248 				       nat->in_pmax != 0 ||
249 				       nat->in_pnext != 0))
250 					setnatproto(IPPROTO_TCP);
251 				  if (nat->in_ifnames[1][0] == '\0')
252 					strncpy(nat->in_ifnames[1],
253 						nat->in_ifnames[0],
254 						sizeof(nat->in_ifnames[0]));
255 				}
256 	| rdrit ifnames addr IPNY_TLATE dip setproto rdroptions
257 				{ nat->in_v = 4;
258 				  nat->in_outip = $3.a.s_addr;
259 				  nat->in_outmsk = $3.m.s_addr;
260 				  if (nat->in_ifnames[1][0] == '\0')
261 					strncpy(nat->in_ifnames[1],
262 						nat->in_ifnames[0],
263 						sizeof(nat->in_ifnames[0]));
264 				}
265 	;
266 
267 proxy:	| IPNY_PROXY IPNY_PORT portspec YY_STR '/' proto
268 			{ strncpy(nat->in_plabel, $4, sizeof(nat->in_plabel));
269 			  if (nat->in_dcmp == 0) {
270 				nat->in_dport = htons($3);
271 			  } else if ($3 != nat->in_dport) {
272 				yyerror("proxy port numbers not consistant");
273 			  }
274 			  setnatproto($6);
275 			  free($4);
276 			}
277 	| IPNY_PROXY IPNY_PORT YY_STR YY_STR '/' proto
278 			{ int pnum;
279 			  strncpy(nat->in_plabel, $4, sizeof(nat->in_plabel));
280 			  pnum = getportproto($3, $6);
281 			  if (pnum == -1)
282 				yyerror("invalid port number");
283 			  nat->in_dport = pnum;
284 			  setnatproto($6);
285 			  free($3);
286 			  free($4);
287 			}
288 	;
289 
290 setproto:
291 	| proto				{ if (nat->in_p != 0 ||
292 					      nat->in_flags & IPN_TCPUDP)
293 						yyerror("protocol set twice");
294 					  setnatproto($1);
295 					}
296 	| IPNY_TCPUDP			{ if (nat->in_p != 0 ||
297 					      nat->in_flags & IPN_TCPUDP)
298 						yyerror("protocol set twice");
299 					  nat->in_flags |= IPN_TCPUDP;
300 					  nat->in_p = 0;
301 					}
302 	| IPNY_TCP '/' IPNY_UDP		{ if (nat->in_p != 0 ||
303 					      nat->in_flags & IPN_TCPUDP)
304 						yyerror("protocol set twice");
305 					  nat->in_flags |= IPN_TCPUDP;
306 					  nat->in_p = 0;
307 					}
308 	;
309 
310 rhaddr:	addr				{ $$.a = $1.a; $$.m = $1.m; }
311 	| IPNY_RANGE ipv4 '-' ipv4
312 					{ $$.a = $2; $$.m = $4;
313 					  nat->in_flags |= IPN_IPRANGE; }
314 	;
315 
316 dip:
317 	hostname			{ nat->in_inip = $1.s_addr;
318 					  nat->in_inmsk = 0xffffffff; }
319 	| hostname '/' YY_NUMBER        { nat->in_inip = $1.s_addr;
320 					  if (nat->in_inip != 0 ||
321 					      ($3 != 0 && $3 != 32))
322 						yyerror("Invalid mask for dip");
323 					  ntomask(4, $3, &nat->in_inmsk); }
324 	| hostname ',' hostname		{ nat->in_flags |= IPN_SPLIT;
325 					  nat->in_inip = $1.s_addr;
326 					  nat->in_inmsk = $3.s_addr; }
327 	;
328 
329 portspec:
330 	YY_NUMBER			{ if ($1 > 65535)	/* Unsigned */
331 						yyerror("invalid port number");
332 					  else
333 						$$ = $1;
334 					}
335 	| YY_STR			{ if (getport(NULL, $1, &($$)) == -1)
336 						yyerror("invalid port number");
337 					  $$ = ntohs($$);
338 					}
339 	;
340 
341 dport:	| IPNY_PORT portspec			{ nat->in_pmin = htons($2);
342 						  nat->in_pmax = htons($2); }
343 	| IPNY_PORT portspec '-' portspec	{ nat->in_pmin = htons($2);
344 						  nat->in_pmax = htons($4); }
345 	| IPNY_PORT portspec ':' portspec	{ nat->in_pmin = htons($2);
346 						  nat->in_pmax = htons($4); }
347 	;
348 
349 nport:	IPNY_PORT portspec		{ nat->in_pnext = htons($2); }
350 	| IPNY_PORT '=' portspec	{ nat->in_pnext = htons($3);
351 					  nat->in_flags |= IPN_FIXEDDPORT;
352 					}
353 	;
354 
355 ports:	| IPNY_PORTS YY_NUMBER		{ nat->in_pmin = $2; }
356 	| IPNY_PORTS IPNY_AUTO		{ nat->in_flags |= IPN_AUTOPORTMAP; }
357 	;
358 
359 mapit:	IPNY_MAP			{ nat->in_redir = NAT_MAP; }
360 	| IPNY_BIMAP			{ nat->in_redir = NAT_BIMAP; }
361 	;
362 
363 rdrit:	IPNY_RDR			{ nat->in_redir = NAT_REDIRECT; }
364 	;
365 
366 mapblockit:
367 	IPNY_MAPBLOCK			{ nat->in_redir = NAT_MAPBLK; }
368 	;
369 
370 mapfrom:
371 	from sobject IPNY_TO dobject
372 	| from sobject '!' IPNY_TO dobject
373 					{ nat->in_flags |= IPN_NOTDST; }
374 	;
375 
376 rdrfrom:
377 	from sobject IPNY_TO dobject
378 	| '!' from sobject IPNY_TO dobject
379 					{ nat->in_flags |= IPN_NOTSRC; }
380 	;
381 
382 from:	IPNY_FROM			{ nat->in_flags |= IPN_FILTER; }
383 	;
384 
385 ifnames:
386 	ifname
387 	| ifname ',' otherifname
388 	;
389 
390 ifname:	YY_STR			{ strncpy(nat->in_ifnames[0], $1,
391 					  sizeof(nat->in_ifnames[0]));
392 				  nat->in_ifnames[0][LIFNAMSIZ - 1] = '\0';
393 				  free($1);
394 				}
395 	;
396 
397 otherifname:
398 	YY_STR			{ strncpy(nat->in_ifnames[1], $1,
399 					  sizeof(nat->in_ifnames[1]));
400 				  nat->in_ifnames[1][LIFNAMSIZ - 1] = '\0';
401 				  free($1);
402 				}
403 	;
404 
405 mapport:
406 	IPNY_PORTMAP tcpudp portspec ':' portspec
407 			{ nat->in_pmin = htons($3);
408 			  nat->in_pmax = htons($5);
409 			}
410 	| IPNY_PORTMAP tcpudp IPNY_AUTO
411 			{ nat->in_flags |= IPN_AUTOPORTMAP;
412 			  nat->in_pmin = htons(1024);
413 			  nat->in_pmax = htons(65535);
414 			}
415 	| IPNY_ICMPIDMAP YY_STR YY_NUMBER ':' YY_NUMBER
416 			{ if (strcmp($2, "icmp") != 0) {
417 				yyerror("icmpidmap not followed by icmp");
418 			  }
419 			  free($2);
420 			  if ($3 < 0 || $3 > 65535)
421 				yyerror("invalid ICMP Id number");
422 			  if ($5 < 0 || $5 > 65535)
423 				yyerror("invalid ICMP Id number");
424 			  nat->in_flags = IPN_ICMPQUERY;
425 			  nat->in_pmin = htons($3);
426 			  nat->in_pmax = htons($5);
427 			}
428 	;
429 
430 sobject:
431 	saddr
432 	| saddr IPNY_PORT portstuff	{ nat->in_sport = $3.p1;
433 					  nat->in_stop = $3.p2;
434 					  nat->in_scmp = $3.pc; }
435 	;
436 
437 saddr:	addr				{ if (nat->in_redir == NAT_REDIRECT) {
438 						nat->in_srcip = $1.a.s_addr;
439 						nat->in_srcmsk = $1.m.s_addr;
440 					  } else {
441 						nat->in_inip = $1.a.s_addr;
442 						nat->in_inmsk = $1.m.s_addr;
443 					  }
444 					}
445 	;
446 
447 dobject:
448 	daddr
449 	| daddr IPNY_PORT portstuff	{ nat->in_dport = $3.p1;
450 					  nat->in_dtop = $3.p2;
451 					  nat->in_dcmp = $3.pc;
452 					  if (nat->in_redir == NAT_REDIRECT)
453 						nat->in_pmin = htons($3.p1);
454 					}
455 	;
456 
457 daddr:	addr				{ if (nat->in_redir == NAT_REDIRECT) {
458 						nat->in_outip = $1.a.s_addr;
459 						nat->in_outmsk = $1.m.s_addr;
460 					  } else {
461 						nat->in_srcip = $1.a.s_addr;
462 						nat->in_srcmsk = $1.m.s_addr;
463 					  }
464 					}
465 	;
466 
467 addr:	IPNY_ANY			{ $$.a.s_addr = 0; $$.m.s_addr = 0; }
468 	| nummask			{ $$.a = $1.a; $$.m = $1.m;
469 					  $$.a.s_addr &= $$.m.s_addr; }
470 	| hostname '/' ipv4		{ $$.a = $1; $$.m = $3;
471 					  $$.a.s_addr &= $$.m.s_addr; }
472 	| hostname '/' hexnumber	{ $$.a = $1; $$.m.s_addr = $3;
473 					  $$.a.s_addr &= $$.m.s_addr; }
474 	| hostname IPNY_MASK ipv4	{ $$.a = $1; $$.m = $3;
475 					  $$.a.s_addr &= $$.m.s_addr; }
476 	| hostname IPNY_MASK hexnumber	{ $$.a = $1; $$.m.s_addr = $3;
477 					  $$.a.s_addr &= $$.m.s_addr; }
478 	;
479 
480 nummask:
481 	hostname			{ $$.a = $1;
482 					  $$.m.s_addr = 0xffffffff; }
483 	| hostname '/' YY_NUMBER	{ $$.a = $1;
484 					  ntomask(4, $3, &$$.m.s_addr); }
485 	;
486 
487 portstuff:
488 	compare portspec		{ $$.pc = $1; $$.p1 = $2; }
489 	| portspec range portspec	{ $$.pc = $2; $$.p1 = $1; $$.p2 = $3; }
490 	;
491 
492 mapoptions:
493 	rr frag age mssclamp nattag setproto
494 	;
495 
496 rdroptions:
497 	rr frag age sticky mssclamp rdrproxy nattag
498 	;
499 
500 nattag:	| IPNY_TAG YY_STR		{ strncpy(nat->in_tag.ipt_tag, $2,
501 						  sizeof(nat->in_tag.ipt_tag));
502 					}
503 rr:	| IPNY_ROUNDROBIN		{ nat->in_flags |= IPN_ROUNDR; }
504 	;
505 
506 frag:	| IPNY_FRAG			{ nat->in_flags |= IPN_FRAG; }
507 	;
508 
509 age:	| IPNY_AGE YY_NUMBER			{ nat->in_age[0] = $2;
510 						  nat->in_age[1] = $2; }
511 	| IPNY_AGE YY_NUMBER '/' YY_NUMBER	{ nat->in_age[0] = $2;
512 						  nat->in_age[1] = $4; }
513 	;
514 
515 sticky:	| IPNY_STICKY			{ if (!(nat->in_flags & IPN_ROUNDR) &&
516 					      !(nat->in_flags & IPN_SPLIT)) {
517 						fprintf(stderr,
518 		"'sticky' for use with round-robin/IP splitting only\n");
519 					  } else
520 						nat->in_flags |= IPN_STICKY;
521 					}
522 	;
523 
524 mssclamp:
525 	| IPNY_MSSCLAMP YY_NUMBER		{ nat->in_mssclamp = $2; }
526 	;
527 
528 tcpudp:	| IPNY_TCP			{ setnatproto(IPPROTO_TCP); }
529 	| IPNY_UDP			{ setnatproto(IPPROTO_UDP); }
530 	| IPNY_TCPUDP			{ nat->in_flags |= IPN_TCPUDP;
531 					  nat->in_p = 0;
532 					}
533 	| IPNY_TCP '/' IPNY_UDP		{ nat->in_flags |= IPN_TCPUDP;
534 					  nat->in_p = 0;
535 					}
536 	;
537 
538 rdrproxy:
539 	IPNY_PROXY YY_STR
540 					{ strncpy(nat->in_plabel, $2,
541 						  sizeof(nat->in_plabel));
542 					  nat->in_dport = nat->in_pnext;
543 					  nat->in_dport = htons(nat->in_dport);
544 					  free($2);
545 					}
546 	| proxy				{ if (nat->in_plabel[0] != '\0') {
547 						  nat->in_pmin = nat->in_dport;
548 						  nat->in_pmax = nat->in_pmin;
549 						  nat->in_pnext = nat->in_pmin;
550 					  }
551 					}
552 	;
553 
554 proto:	YY_NUMBER			{ $$ = $1; }
555 	| IPNY_TCP			{ $$ = IPPROTO_TCP; }
556 	| IPNY_UDP			{ $$ = IPPROTO_UDP; }
557 	| YY_STR			{ $$ = getproto($1); free($1); }
558 	;
559 
560 hexnumber:
561 	YY_HEX				{ $$ = $1; }
562 	;
563 
564 hostname:
565 	YY_STR				{ $$.s_addr = lookuphost($1);
566 					  free($1);
567 					  if ($$.s_addr == 0)
568 						yyerror("Unknown hostname");
569 					}
570 	| YY_NUMBER			{ $$.s_addr = htonl($1); }
571 	| ipv4				{ $$.s_addr = $1.s_addr; }
572 	;
573 
574 compare:
575 	'='				{ $$ = FR_EQUAL; }
576 	| YY_CMP_EQ			{ $$ = FR_EQUAL; }
577 	| YY_CMP_NE			{ $$ = FR_NEQUAL; }
578 	| YY_CMP_LT			{ $$ = FR_LESST; }
579 	| YY_CMP_LE			{ $$ = FR_LESSTE; }
580 	| YY_CMP_GT			{ $$ = FR_GREATERT; }
581 	| YY_CMP_GE			{ $$ = FR_GREATERTE; }
582 
583 range:
584 	YY_RANGE_OUT			{ $$ = FR_OUTRANGE; }
585 	| YY_RANGE_IN			{ $$ = FR_INRANGE; }
586 	;
587 
588 ipv4:	YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER
589 		{ if ($1 > 255 || $3 > 255 || $5 > 255 || $7 > 255) {
590 			yyerror("Invalid octet string for IP address");
591 			return 0;
592 		  }
593 		  $$.s_addr = ($1 << 24) | ($3 << 16) | ($5 << 8) | $7;
594 		  $$.s_addr = htonl($$.s_addr);
595 		}
596 	;
597 
598 %%
599 
600 
601 static	wordtab_t	yywords[] = {
602 	{ "age",	IPNY_AGE },
603 	{ "any",	IPNY_ANY },
604 	{ "auto",	IPNY_AUTO },
605 	{ "bimap",	IPNY_BIMAP },
606 	{ "frag",	IPNY_FRAG },
607 	{ "from",	IPNY_FROM },
608 	{ "icmpidmap",	IPNY_ICMPIDMAP },
609 	{ "mask",	IPNY_MASK },
610 	{ "map",	IPNY_MAP },
611 	{ "map-block",	IPNY_MAPBLOCK },
612 	{ "mssclamp",	IPNY_MSSCLAMP },
613 	{ "netmask",	IPNY_MASK },
614 	{ "port",	IPNY_PORT },
615 	{ "portmap",	IPNY_PORTMAP },
616 	{ "ports",	IPNY_PORTS },
617 	{ "proxy",	IPNY_PROXY },
618 	{ "range",	IPNY_RANGE },
619 	{ "rdr",	IPNY_RDR },
620 	{ "round-robin",IPNY_ROUNDROBIN },
621 	{ "sticky",	IPNY_STICKY },
622 	{ "tag",	IPNY_TAG },
623 	{ "tcp",	IPNY_TCP },
624 	{ "tcpudp",	IPNY_TCPUDP },
625 	{ "to",		IPNY_TO },
626 	{ "udp",	IPNY_UDP },
627 	{ "-",		'-' },
628 	{ "->",		IPNY_TLATE },
629 	{ "eq",		YY_CMP_EQ },
630 	{ "ne",		YY_CMP_NE },
631 	{ "lt",		YY_CMP_LT },
632 	{ "gt",		YY_CMP_GT },
633 	{ "le",		YY_CMP_LE },
634 	{ "ge",		YY_CMP_GE },
635 	{ NULL,		0 }
636 };
637 
638 
639 int ipnat_parsefile(fd, addfunc, ioctlfunc, filename)
640 int fd;
641 addfunc_t addfunc;
642 ioctlfunc_t ioctlfunc;
643 char *filename;
644 {
645 	FILE *fp = NULL;
646 	char *s;
647 
648 	(void) yysettab(yywords);
649 
650 	s = getenv("YYDEBUG");
651 	if (s)
652 		yydebug = atoi(s);
653 	else
654 		yydebug = 0;
655 
656 	if (strcmp(filename, "-")) {
657 		fp = fopen(filename, "r");
658 		if (!fp) {
659 			fprintf(stderr, "fopen(%s) failed: %s\n", filename,
660 				STRERROR(errno));
661 			return -1;
662 		}
663 	} else
664 		fp = stdin;
665 
666 	while (ipnat_parsesome(fd, addfunc, ioctlfunc, fp) == 1)
667 		;
668 	if (fp != NULL)
669 		fclose(fp);
670 	return 0;
671 }
672 
673 
674 int ipnat_parsesome(fd, addfunc, ioctlfunc, fp)
675 int fd;
676 addfunc_t addfunc;
677 ioctlfunc_t ioctlfunc;
678 FILE *fp;
679 {
680 	char *s;
681 	int i;
682 
683 	yylineNum = 1;
684 
685 	natfd = fd;
686 	nataddfunc = addfunc;
687 	natioctlfunc = ioctlfunc;
688 
689 	if (feof(fp))
690 		return 0;
691 	i = fgetc(fp);
692 	if (i == EOF)
693 		return 0;
694 	if (ungetc(i, fp) == EOF)
695 		return 0;
696 	if (feof(fp))
697 		return 0;
698 	s = getenv("YYDEBUG");
699 	if (s)
700 		yydebug = atoi(s);
701 	else
702 		yydebug = 0;
703 
704 	yyin = fp;
705 	yyparse();
706 	return 1;
707 }
708 
709 
710 static void newnatrule()
711 {
712 	ipnat_t *n;
713 
714 	n = calloc(1, sizeof(*n));
715 	if (n == NULL)
716 		return;
717 
718 	if (nat == NULL)
719 		nattop = nat = n;
720 	else {
721 		nat->in_next = n;
722 		nat = n;
723 	}
724 }
725 
726 
727 static void setnatproto(p)
728 int p;
729 {
730 	nat->in_p = p;
731 
732 	switch (p)
733 	{
734 	case IPPROTO_TCP :
735 		nat->in_flags |= IPN_TCP;
736 		nat->in_flags &= ~IPN_UDP;
737 		break;
738 	case IPPROTO_UDP :
739 		nat->in_flags |= IPN_UDP;
740 		nat->in_flags &= ~IPN_TCP;
741 		break;
742 	case IPPROTO_ICMP :
743 		nat->in_flags &= ~IPN_TCPUDP;
744 		if (!(nat->in_flags & IPN_ICMPQUERY)) {
745 			nat->in_dcmp = 0;
746 			nat->in_scmp = 0;
747 			nat->in_pmin = 0;
748 			nat->in_pmax = 0;
749 			nat->in_pnext = 0;
750 		}
751 		break;
752 	default :
753 		if ((nat->in_redir & NAT_MAPBLK) == 0) {
754 			/* Only reset dcmp/scmp in case dport/sport not set */
755 			if (0 == nat->in_tuc.ftu_dport)
756 				nat->in_dcmp = 0;
757 			if (0 == nat->in_tuc.ftu_sport)
758 				nat->in_scmp = 0;
759 			nat->in_pmin = 0;
760 			nat->in_pmax = 0;
761 			nat->in_pnext = 0;
762 			nat->in_flags &= ~IPN_TCPUDP;
763 		}
764 		break;
765 	}
766 
767 	if ((nat->in_flags & (IPN_TCPUDP|IPN_FIXEDDPORT)) == IPN_FIXEDDPORT)
768 		nat->in_flags &= ~IPN_FIXEDDPORT;
769 }
770 
771 
772 void ipnat_addrule(fd, ioctlfunc, ptr)
773 int fd;
774 ioctlfunc_t ioctlfunc;
775 void *ptr;
776 {
777 	ioctlcmd_t add, del;
778 	ipfobj_t obj;
779 	ipnat_t *ipn;
780 
781 	ipn = ptr;
782 	bzero((char *)&obj, sizeof(obj));
783 	obj.ipfo_rev = IPFILTER_VERSION;
784 	obj.ipfo_size = sizeof(ipnat_t);
785 	obj.ipfo_type = IPFOBJ_IPNAT;
786 	obj.ipfo_ptr = ptr;
787 	add = 0;
788 	del = 0;
789 
790 	if ((opts & OPT_DONOTHING) != 0)
791 		fd = -1;
792 
793 	if (opts & OPT_ZERORULEST) {
794 		add = SIOCZRLST;
795 	} else if (opts & OPT_INACTIVE) {
796 		add = SIOCADNAT;
797 		del = SIOCRMNAT;
798 	} else {
799 		add = SIOCADNAT;
800 		del = SIOCRMNAT;
801 	}
802 
803 	if (ipn && (opts & OPT_VERBOSE))
804 		printnat(ipn, opts);
805 
806 	if (opts & OPT_DEBUG)
807 		binprint(ipn, sizeof(*ipn));
808 
809 	if ((opts & OPT_ZERORULEST) != 0) {
810 		if ((*ioctlfunc)(fd, add, (void *)&obj) == -1) {
811 			if ((opts & OPT_DONOTHING) == 0) {
812 				fprintf(stderr, "%d:", yylineNum);
813 				perror("ioctl(SIOCZRLST)");
814 			}
815 		} else {
816 #ifdef	USE_QUAD_T
817 /*
818 			printf("hits %qd bytes %qd ",
819 				(long long)fr->fr_hits,
820 				(long long)fr->fr_bytes);
821 */
822 #else
823 /*
824 			printf("hits %ld bytes %ld ",
825 				fr->fr_hits, fr->fr_bytes);
826 */
827 #endif
828 			printnat(ipn, opts);
829 		}
830 	} else if ((opts & OPT_REMOVE) != 0) {
831 		if ((*ioctlfunc)(fd, del, (void *)&obj) == -1) {
832 			if ((opts & OPT_DONOTHING) == 0) {
833 				fprintf(stderr, "%d:", yylineNum);
834 				perror("ioctl(delete nat rule)");
835 			}
836 		}
837 	} else {
838 		if ((*ioctlfunc)(fd, add, (void *)&obj) == -1) {
839 			if ((opts & OPT_DONOTHING) == 0) {
840 				fprintf(stderr, "%d:", yylineNum);
841 				perror("ioctl(add/insert nat rule)");
842 			}
843 		}
844 	}
845 }
846 
847 static u_32_t lookuphost(name)
848 char *name;
849 {
850 	i6addr_t addr;
851 
852 	if (gethost(name, &addr, 0) == -1) {
853 		return 0;
854 	}
855 	return addr.in4_addr;
856 }
857