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