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