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