xref: /titanic_51/usr/src/cmd/ipf/tools/ipnat_y.y (revision 9512fe850e98fdd448c638ca63fdd92a8a510255)
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 ',' hostname		{ nat->in_flags |= IPN_SPLIT;
320 					  nat->in_inip = $1.s_addr;
321 					  nat->in_inmsk = $3.s_addr; }
322 	;
323 
324 portspec:
325 	YY_NUMBER			{ if ($1 > 65535)	/* Unsigned */
326 						yyerror("invalid port number");
327 					  else
328 						$$ = $1;
329 					}
330 	| YY_STR			{ if (getport(NULL, $1, &($$)) == -1)
331 						yyerror("invalid port number");
332 					  $$ = ntohs($$);
333 					}
334 	;
335 
336 dport:	| IPNY_PORT portspec			{ nat->in_pmin = htons($2);
337 						  nat->in_pmax = htons($2); }
338 	| IPNY_PORT portspec '-' portspec	{ nat->in_pmin = htons($2);
339 						  nat->in_pmax = htons($4); }
340 	| IPNY_PORT portspec ':' portspec	{ nat->in_pmin = htons($2);
341 						  nat->in_pmax = htons($4); }
342 	;
343 
344 nport:	IPNY_PORT portspec		{ nat->in_pnext = htons($2); }
345 	| IPNY_PORT '=' portspec	{ nat->in_pnext = htons($3);
346 					  nat->in_flags |= IPN_FIXEDDPORT;
347 					}
348 	;
349 
350 ports:	| IPNY_PORTS YY_NUMBER		{ nat->in_pmin = $2; }
351 	| IPNY_PORTS IPNY_AUTO		{ nat->in_flags |= IPN_AUTOPORTMAP; }
352 	;
353 
354 mapit:	IPNY_MAP			{ nat->in_redir = NAT_MAP; }
355 	| IPNY_BIMAP			{ nat->in_redir = NAT_BIMAP; }
356 	;
357 
358 rdrit:	IPNY_RDR			{ nat->in_redir = NAT_REDIRECT; }
359 	;
360 
361 mapblockit:
362 	IPNY_MAPBLOCK			{ nat->in_redir = NAT_MAPBLK; }
363 	;
364 
365 mapfrom:
366 	from sobject IPNY_TO dobject
367 	| from sobject '!' IPNY_TO dobject
368 					{ nat->in_flags |= IPN_NOTDST; }
369 	;
370 
371 rdrfrom:
372 	from sobject IPNY_TO dobject
373 	| '!' from sobject IPNY_TO dobject
374 					{ nat->in_flags |= IPN_NOTSRC; }
375 	;
376 
377 from:	IPNY_FROM			{ nat->in_flags |= IPN_FILTER; }
378 	;
379 
380 ifnames:
381 	ifname
382 	| ifname ',' otherifname
383 	;
384 
385 ifname:	YY_STR			{ strncpy(nat->in_ifnames[0], $1,
386 					  sizeof(nat->in_ifnames[0]));
387 				  nat->in_ifnames[0][LIFNAMSIZ - 1] = '\0';
388 				  free($1);
389 				}
390 	;
391 
392 otherifname:
393 	YY_STR			{ strncpy(nat->in_ifnames[1], $1,
394 					  sizeof(nat->in_ifnames[1]));
395 				  nat->in_ifnames[1][LIFNAMSIZ - 1] = '\0';
396 				  free($1);
397 				}
398 	;
399 
400 mapport:
401 	IPNY_PORTMAP tcpudp portspec ':' portspec
402 			{ nat->in_pmin = htons($3);
403 			  nat->in_pmax = htons($5);
404 			}
405 	| IPNY_PORTMAP tcpudp IPNY_AUTO
406 			{ nat->in_flags |= IPN_AUTOPORTMAP;
407 			  nat->in_pmin = htons(1024);
408 			  nat->in_pmax = htons(65535);
409 			}
410 	| IPNY_ICMPIDMAP YY_STR YY_NUMBER ':' YY_NUMBER
411 			{ if (strcmp($2, "icmp") != 0) {
412 				yyerror("icmpidmap not followed by icmp");
413 			  }
414 			  free($2);
415 			  if ($3 < 0 || $3 > 65535)
416 				yyerror("invalid ICMP Id number");
417 			  if ($5 < 0 || $5 > 65535)
418 				yyerror("invalid ICMP Id number");
419 			  nat->in_flags = IPN_ICMPQUERY;
420 			  nat->in_pmin = htons($3);
421 			  nat->in_pmax = htons($5);
422 			}
423 	;
424 
425 sobject:
426 	saddr
427 	| saddr IPNY_PORT portstuff	{ nat->in_sport = $3.p1;
428 					  nat->in_stop = $3.p2;
429 					  nat->in_scmp = $3.pc; }
430 	;
431 
432 saddr:	addr				{ if (nat->in_redir == NAT_REDIRECT) {
433 						nat->in_srcip = $1.a.s_addr;
434 						nat->in_srcmsk = $1.m.s_addr;
435 					  } else {
436 						nat->in_inip = $1.a.s_addr;
437 						nat->in_inmsk = $1.m.s_addr;
438 					  }
439 					}
440 	;
441 
442 dobject:
443 	daddr
444 	| daddr IPNY_PORT portstuff	{ nat->in_dport = $3.p1;
445 					  nat->in_dtop = $3.p2;
446 					  nat->in_dcmp = $3.pc;
447 					  if (nat->in_redir == NAT_REDIRECT)
448 						nat->in_pmin = htons($3.p1);
449 					}
450 	;
451 
452 daddr:	addr				{ if (nat->in_redir == NAT_REDIRECT) {
453 						nat->in_outip = $1.a.s_addr;
454 						nat->in_outmsk = $1.m.s_addr;
455 					  } else {
456 						nat->in_srcip = $1.a.s_addr;
457 						nat->in_srcmsk = $1.m.s_addr;
458 					  }
459 					}
460 	;
461 
462 addr:	IPNY_ANY			{ $$.a.s_addr = 0; $$.m.s_addr = 0; }
463 	| nummask			{ $$.a = $1.a; $$.m = $1.m;
464 					  $$.a.s_addr &= $$.m.s_addr; }
465 	| hostname '/' ipv4		{ $$.a = $1; $$.m = $3;
466 					  $$.a.s_addr &= $$.m.s_addr; }
467 	| hostname '/' hexnumber	{ $$.a = $1; $$.m.s_addr = $3;
468 					  $$.a.s_addr &= $$.m.s_addr; }
469 	| hostname IPNY_MASK ipv4	{ $$.a = $1; $$.m = $3;
470 					  $$.a.s_addr &= $$.m.s_addr; }
471 	| hostname IPNY_MASK hexnumber	{ $$.a = $1; $$.m.s_addr = $3;
472 					  $$.a.s_addr &= $$.m.s_addr; }
473 	;
474 
475 nummask:
476 	hostname			{ $$.a = $1;
477 					  $$.m.s_addr = 0xffffffff; }
478 	| hostname '/' YY_NUMBER	{ $$.a = $1;
479 					  ntomask(4, $3, &$$.m.s_addr); }
480 	;
481 
482 portstuff:
483 	compare portspec		{ $$.pc = $1; $$.p1 = $2; }
484 	| portspec range portspec	{ $$.pc = $2; $$.p1 = $1; $$.p1 = $3; }
485 	;
486 
487 mapoptions:
488 	rr frag age mssclamp nattag setproto
489 	;
490 
491 rdroptions:
492 	rr frag age sticky mssclamp rdrproxy nattag
493 	;
494 
495 nattag:	| IPNY_TAG YY_STR		{ strncpy(nat->in_tag.ipt_tag, $2,
496 						  sizeof(nat->in_tag.ipt_tag));
497 					}
498 rr:	| IPNY_ROUNDROBIN		{ nat->in_flags |= IPN_ROUNDR; }
499 	;
500 
501 frag:	| IPNY_FRAG			{ nat->in_flags |= IPN_FRAG; }
502 	;
503 
504 age:	| IPNY_AGE YY_NUMBER			{ nat->in_age[0] = $2;
505 						  nat->in_age[1] = $2; }
506 	| IPNY_AGE YY_NUMBER '/' YY_NUMBER	{ nat->in_age[0] = $2;
507 						  nat->in_age[1] = $4; }
508 	;
509 
510 sticky:	| IPNY_STICKY			{ if (!(nat->in_flags & IPN_ROUNDR) &&
511 					      !(nat->in_flags & IPN_SPLIT)) {
512 						fprintf(stderr,
513 		"'sticky' for use with round-robin/IP splitting only\n");
514 					  } else
515 						nat->in_flags |= IPN_STICKY;
516 					}
517 	;
518 
519 mssclamp:
520 	| IPNY_MSSCLAMP YY_NUMBER		{ nat->in_mssclamp = $2; }
521 	;
522 
523 tcpudp:	| IPNY_TCP			{ setnatproto(IPPROTO_TCP); }
524 	| IPNY_UDP			{ setnatproto(IPPROTO_UDP); }
525 	| IPNY_TCPUDP			{ nat->in_flags |= IPN_TCPUDP;
526 					  nat->in_p = 0;
527 					}
528 	| IPNY_TCP '/' IPNY_UDP		{ nat->in_flags |= IPN_TCPUDP;
529 					  nat->in_p = 0;
530 					}
531 	;
532 
533 rdrproxy:
534 	IPNY_PROXY YY_STR
535 					{ strncpy(nat->in_plabel, $2,
536 						  sizeof(nat->in_plabel));
537 					  nat->in_dport = nat->in_pnext;
538 					  nat->in_dport = htons(nat->in_dport);
539 					  free($2);
540 					}
541 	| proxy				{ if (nat->in_plabel[0] != '\0') {
542 						  nat->in_pmin = nat->in_dport;
543 						  nat->in_pmax = nat->in_pmin;
544 						  nat->in_pnext = nat->in_pmin;
545 					  }
546 					}
547 	;
548 
549 proto:	YY_NUMBER			{ $$ = $1; }
550 	| IPNY_TCP			{ $$ = IPPROTO_TCP; }
551 	| IPNY_UDP			{ $$ = IPPROTO_UDP; }
552 	| YY_STR			{ $$ = getproto($1); free($1); }
553 	;
554 
555 hexnumber:
556 	YY_HEX				{ $$ = $1; }
557 	;
558 
559 hostname:
560 	YY_STR				{ $$.s_addr = lookuphost($1);
561 					  free($1);
562 					  if ($$.s_addr == 0)
563 						yyerror("Unknown hostname");
564 					}
565 	| YY_NUMBER			{ $$.s_addr = htonl($1); }
566 	| ipv4				{ $$.s_addr = $1.s_addr; }
567 	;
568 
569 compare:
570 	'='				{ $$ = FR_EQUAL; }
571 	| YY_CMP_EQ			{ $$ = FR_EQUAL; }
572 	| YY_CMP_NE			{ $$ = FR_NEQUAL; }
573 	| YY_CMP_LT			{ $$ = FR_LESST; }
574 	| YY_CMP_LE			{ $$ = FR_LESSTE; }
575 	| YY_CMP_GT			{ $$ = FR_GREATERT; }
576 	| YY_CMP_GE			{ $$ = FR_GREATERTE; }
577 
578 range:
579 	YY_RANGE_OUT			{ $$ = FR_OUTRANGE; }
580 	| YY_RANGE_IN			{ $$ = FR_INRANGE; }
581 	;
582 
583 ipv4:	YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER
584 		{ if ($1 > 255 || $3 > 255 || $5 > 255 || $7 > 255) {
585 			yyerror("Invalid octet string for IP address");
586 			return 0;
587 		  }
588 		  $$.s_addr = ($1 << 24) | ($3 << 16) | ($5 << 8) | $7;
589 		  $$.s_addr = htonl($$.s_addr);
590 		}
591 	;
592 
593 %%
594 
595 
596 static	wordtab_t	yywords[] = {
597 	{ "age",	IPNY_AGE },
598 	{ "any",	IPNY_ANY },
599 	{ "auto",	IPNY_AUTO },
600 	{ "bimap",	IPNY_BIMAP },
601 	{ "frag",	IPNY_FRAG },
602 	{ "from",	IPNY_FROM },
603 	{ "icmpidmap",	IPNY_ICMPIDMAP },
604 	{ "mask",	IPNY_MASK },
605 	{ "map",	IPNY_MAP },
606 	{ "map-block",	IPNY_MAPBLOCK },
607 	{ "mssclamp",	IPNY_MSSCLAMP },
608 	{ "netmask",	IPNY_MASK },
609 	{ "port",	IPNY_PORT },
610 	{ "portmap",	IPNY_PORTMAP },
611 	{ "ports",	IPNY_PORTS },
612 	{ "proxy",	IPNY_PROXY },
613 	{ "range",	IPNY_RANGE },
614 	{ "rdr",	IPNY_RDR },
615 	{ "round-robin",IPNY_ROUNDROBIN },
616 	{ "sticky",	IPNY_STICKY },
617 	{ "tag",	IPNY_TAG },
618 	{ "tcp",	IPNY_TCP },
619 	{ "tcpudp",	IPNY_TCPUDP },
620 	{ "to",		IPNY_TO },
621 	{ "udp",	IPNY_UDP },
622 	{ "-",		'-' },
623 	{ "->",		IPNY_TLATE },
624 	{ "eq",		YY_CMP_EQ },
625 	{ "ne",		YY_CMP_NE },
626 	{ "lt",		YY_CMP_LT },
627 	{ "gt",		YY_CMP_GT },
628 	{ "le",		YY_CMP_LE },
629 	{ "ge",		YY_CMP_GE },
630 	{ NULL,		0 }
631 };
632 
633 
634 int ipnat_parsefile(fd, addfunc, ioctlfunc, filename)
635 int fd;
636 addfunc_t addfunc;
637 ioctlfunc_t ioctlfunc;
638 char *filename;
639 {
640 	FILE *fp = NULL;
641 	char *s;
642 
643 	(void) yysettab(yywords);
644 
645 	s = getenv("YYDEBUG");
646 	if (s)
647 		yydebug = atoi(s);
648 	else
649 		yydebug = 0;
650 
651 	if (strcmp(filename, "-")) {
652 		fp = fopen(filename, "r");
653 		if (!fp) {
654 			fprintf(stderr, "fopen(%s) failed: %s\n", filename,
655 				STRERROR(errno));
656 			return -1;
657 		}
658 	} else
659 		fp = stdin;
660 
661 	while (ipnat_parsesome(fd, addfunc, ioctlfunc, fp) == 1)
662 		;
663 	if (fp != NULL)
664 		fclose(fp);
665 	return 0;
666 }
667 
668 
669 int ipnat_parsesome(fd, addfunc, ioctlfunc, fp)
670 int fd;
671 addfunc_t addfunc;
672 ioctlfunc_t ioctlfunc;
673 FILE *fp;
674 {
675 	char *s;
676 	int i;
677 
678 	yylineNum = 1;
679 
680 	natfd = fd;
681 	nataddfunc = addfunc;
682 	natioctlfunc = ioctlfunc;
683 
684 	if (feof(fp))
685 		return 0;
686 	i = fgetc(fp);
687 	if (i == EOF)
688 		return 0;
689 	if (ungetc(i, fp) == EOF)
690 		return 0;
691 	if (feof(fp))
692 		return 0;
693 	s = getenv("YYDEBUG");
694 	if (s)
695 		yydebug = atoi(s);
696 	else
697 		yydebug = 0;
698 
699 	yyin = fp;
700 	yyparse();
701 	return 1;
702 }
703 
704 
705 static void newnatrule()
706 {
707 	ipnat_t *n;
708 
709 	n = calloc(1, sizeof(*n));
710 	if (n == NULL)
711 		return;
712 
713 	if (nat == NULL)
714 		nattop = nat = n;
715 	else {
716 		nat->in_next = n;
717 		nat = n;
718 	}
719 }
720 
721 
722 static void setnatproto(p)
723 int p;
724 {
725 	nat->in_p = p;
726 
727 	switch (p)
728 	{
729 	case IPPROTO_TCP :
730 		nat->in_flags |= IPN_TCP;
731 		nat->in_flags &= ~IPN_UDP;
732 		break;
733 	case IPPROTO_UDP :
734 		nat->in_flags |= IPN_UDP;
735 		nat->in_flags &= ~IPN_TCP;
736 		break;
737 	case IPPROTO_ICMP :
738 		nat->in_flags &= ~IPN_TCPUDP;
739 		if (!(nat->in_flags & IPN_ICMPQUERY)) {
740 			nat->in_dcmp = 0;
741 			nat->in_scmp = 0;
742 			nat->in_pmin = 0;
743 			nat->in_pmax = 0;
744 			nat->in_pnext = 0;
745 		}
746 		break;
747 	default :
748 		if ((nat->in_redir & NAT_MAPBLK) == 0) {
749 			/* Only reset dcmp/scmp in case dport/sport not set */
750 			if (0 == nat->in_tuc.ftu_dport)
751 				nat->in_dcmp = 0;
752 			if (0 == nat->in_tuc.ftu_sport)
753 				nat->in_scmp = 0;
754 			nat->in_pmin = 0;
755 			nat->in_pmax = 0;
756 			nat->in_pnext = 0;
757 			nat->in_flags &= ~IPN_TCPUDP;
758 		}
759 		break;
760 	}
761 
762 	if ((nat->in_flags & (IPN_TCPUDP|IPN_FIXEDDPORT)) == IPN_FIXEDDPORT)
763 		nat->in_flags &= ~IPN_FIXEDDPORT;
764 }
765 
766 
767 void ipnat_addrule(fd, ioctlfunc, ptr)
768 int fd;
769 ioctlfunc_t ioctlfunc;
770 void *ptr;
771 {
772 	ioctlcmd_t add, del;
773 	ipfobj_t obj;
774 	ipnat_t *ipn;
775 
776 	ipn = ptr;
777 	bzero((char *)&obj, sizeof(obj));
778 	obj.ipfo_rev = IPFILTER_VERSION;
779 	obj.ipfo_size = sizeof(ipnat_t);
780 	obj.ipfo_type = IPFOBJ_IPNAT;
781 	obj.ipfo_ptr = ptr;
782 	add = 0;
783 	del = 0;
784 
785 	if ((opts & OPT_DONOTHING) != 0)
786 		fd = -1;
787 
788 	if (opts & OPT_ZERORULEST) {
789 		add = SIOCZRLST;
790 	} else if (opts & OPT_INACTIVE) {
791 		add = SIOCADNAT;
792 		del = SIOCRMNAT;
793 	} else {
794 		add = SIOCADNAT;
795 		del = SIOCRMNAT;
796 	}
797 
798 	if (ipn && (opts & OPT_VERBOSE))
799 		printnat(ipn, opts);
800 
801 	if (opts & OPT_DEBUG)
802 		binprint(ipn, sizeof(*ipn));
803 
804 	if ((opts & OPT_ZERORULEST) != 0) {
805 		if ((*ioctlfunc)(fd, add, (void *)&obj) == -1) {
806 			if ((opts & OPT_DONOTHING) == 0) {
807 				fprintf(stderr, "%d:", yylineNum);
808 				perror("ioctl(SIOCZRLST)");
809 			}
810 		} else {
811 #ifdef	USE_QUAD_T
812 /*
813 			printf("hits %qd bytes %qd ",
814 				(long long)fr->fr_hits,
815 				(long long)fr->fr_bytes);
816 */
817 #else
818 /*
819 			printf("hits %ld bytes %ld ",
820 				fr->fr_hits, fr->fr_bytes);
821 */
822 #endif
823 			printnat(ipn, opts);
824 		}
825 	} else if ((opts & OPT_REMOVE) != 0) {
826 		if ((*ioctlfunc)(fd, del, (void *)&obj) == -1) {
827 			if ((opts & OPT_DONOTHING) == 0) {
828 				fprintf(stderr, "%d:", yylineNum);
829 				perror("ioctl(delete nat rule)");
830 			}
831 		}
832 	} else {
833 		if ((*ioctlfunc)(fd, add, (void *)&obj) == -1) {
834 			if ((opts & OPT_DONOTHING) == 0) {
835 				fprintf(stderr, "%d:", yylineNum);
836 				perror("ioctl(add/insert nat rule)");
837 			}
838 		}
839 	}
840 }
841 
842 static u_32_t lookuphost(name)
843 char *name;
844 {
845 	i6addr_t addr;
846 
847 	if (gethost(name, &addr, 0) == -1) {
848 		return 0;
849 	}
850 	return addr.in4_addr;
851 }
852