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