1 %{
2 /*
3 * Copyright (C) 2001-2008 by Darren Reed.
4 *
5 * See the IPFILTER.LICENCE file for details on licencing.
6 *
7 * Copyright 2008 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
70 %}
71 %union {
72 char *str;
73 u_32_t num;
74 struct {
75 i6addr_t a;
76 int v;
77 } ipa;
78 frentry_t fr;
79 frtuc_t *frt;
80 u_short port;
81 struct {
82 u_short p1;
83 u_short p2;
84 int pc;
85 } pc;
86 struct {
87 i6addr_t a;
88 i6addr_t m;
89 int v;
90 } ipp;
91 union i6addr ip6;
92 };
93
94 %token <num> YY_NUMBER YY_HEX
95 %token <str> YY_STR
96 %token YY_COMMENT
97 %token YY_CMP_EQ YY_CMP_NE YY_CMP_LE YY_CMP_GE YY_CMP_LT YY_CMP_GT
98 %token YY_RANGE_OUT YY_RANGE_IN
99 %token <ip6> YY_IPV6
100
101 %token IPNY_MAPBLOCK IPNY_RDR IPNY_PORT IPNY_PORTS IPNY_AUTO IPNY_RANGE
102 %token IPNY_MAP IPNY_BIMAP IPNY_FROM IPNY_TO IPNY_MASK IPNY_PORTMAP IPNY_ANY
103 %token IPNY_ROUNDROBIN IPNY_FRAG IPNY_AGE IPNY_ICMPIDMAP IPNY_PROXY
104 %token IPNY_TCP IPNY_UDP IPNY_TCPUDP IPNY_STICKY IPNY_MSSCLAMP IPNY_TAG
105 %token IPNY_TLATE IPNY_SEQUENTIAL
106 %type <port> portspec
107 %type <num> hexnumber compare range proto
108 %type <num> saddr daddr sobject dobject mapfrom rdrfrom dip
109 %type <ipa> hostname ipv4 ipaddr
110 %type <ipp> addr rhaddr
111 %type <pc> portstuff
112 %%
113 file: line
114 | assign
115 | file line
116 | file assign
117 ;
118
119 line: xx rule { while ((nat = nattop) != NULL) {
120 if (nat->in_v == 0)
121 nat->in_v = 4;
122 nattop = nat->in_next;
123 (*nataddfunc)(natfd, natioctlfunc, nat);
124 free(nat);
125 }
126 resetlexer();
127 }
128 | YY_COMMENT
129 ;
130
131 assign: YY_STR assigning YY_STR ';' { set_variable($1, $3);
132 resetlexer();
133 free($1);
134 free($3);
135 }
136 ;
137
138 assigning:
139 '=' { yyvarnext = 1; }
140 ;
141
142 xx: { newnatrule(); }
143 ;
144
145 rule: map eol
146 | mapblock eol
147 | redir eol
148 ;
149
150 eol: | ';'
151 ;
152
153 map: mapit ifnames addr IPNY_TLATE rhaddr proxy mapoptions
154 { if ($3.v != 0 && $3.v != $5.v && $5.v != 0)
155 yyerror("1.address family mismatch");
156 bcopy(&$3.a, &nat->in_in[0], sizeof($3.a));
157 bcopy(&$3.m, &nat->in_in[1], sizeof($3.a));
158 bcopy(&$5.a, &nat->in_out[0], sizeof($5.a));
159 bcopy(&$5.m, &nat->in_out[1], sizeof($5.a));
160 if (nat->in_ifnames[1][0] == '\0')
161 strncpy(nat->in_ifnames[1],
162 nat->in_ifnames[0],
163 sizeof(nat->in_ifnames[0]));
164 if ((nat->in_flags & IPN_TCPUDP) == 0)
165 setnatproto(nat->in_p);
166 if (((nat->in_redir & NAT_MAPBLK) != 0) ||
167 ((nat->in_flags & IPN_AUTOPORTMAP) != 0))
168 nat_setgroupmap(nat);
169 }
170 | mapit ifnames addr IPNY_TLATE rhaddr mapport mapoptions
171 { if ($3.v != 0 && $3.v != $5.v && $5.v != 0)
172 yyerror("2.address family mismatch");
173 bcopy(&$3.a, &nat->in_in[0], sizeof($3.a));
174 bcopy(&$3.m, &nat->in_in[1], sizeof($3.a));
175 bcopy(&$5.a, &nat->in_out[0], sizeof($5.a));
176 bcopy(&$5.m, &nat->in_out[1], sizeof($5.a));
177 if (nat->in_ifnames[1][0] == '\0')
178 strncpy(nat->in_ifnames[1],
179 nat->in_ifnames[0],
180 sizeof(nat->in_ifnames[0]));
181 if ((nat->in_flags & IPN_TCPUDPICMPQ) == 0)
182 setnatproto(nat->in_p);
183 if (((nat->in_redir & NAT_MAPBLK) != 0) ||
184 ((nat->in_flags & IPN_AUTOPORTMAP) != 0))
185 nat_setgroupmap(nat);
186 }
187 | mapit ifnames mapfrom IPNY_TLATE rhaddr proxy mapoptions
188 { if ($3 != 0 && $3 != $5.v && $5.v != 0)
189 yyerror("3.address family mismatch");
190 bcopy(&$5.a, &nat->in_out[0], sizeof($5.a));
191 bcopy(&$5.m, &nat->in_out[1], sizeof($5.a));
192 if (nat->in_ifnames[1][0] == '\0')
193 strncpy(nat->in_ifnames[1],
194 nat->in_ifnames[0],
195 sizeof(nat->in_ifnames[0]));
196 if ((nat->in_flags & IPN_TCPUDP) == 0)
197 setnatproto(nat->in_p);
198 if (((nat->in_redir & NAT_MAPBLK) != 0) ||
199 ((nat->in_flags & IPN_AUTOPORTMAP) != 0))
200 nat_setgroupmap(nat);
201 }
202 | mapit ifnames mapfrom IPNY_TLATE rhaddr mapport mapoptions
203 { if ($3 != 0 && $3 != $5.v && $5.v != 0)
204 yyerror("4.address family mismatch");
205 bcopy(&$5.a, &nat->in_out[0], sizeof($5.a));
206 bcopy(&$5.m, &nat->in_out[1], sizeof($5.a));
207 if (nat->in_ifnames[1][0] == '\0')
208 strncpy(nat->in_ifnames[1],
209 nat->in_ifnames[0],
210 sizeof(nat->in_ifnames[0]));
211 if ((nat->in_flags & IPN_TCPUDPICMPQ) == 0)
212 setnatproto(nat->in_p);
213 if (((nat->in_redir & NAT_MAPBLK) != 0) ||
214 ((nat->in_flags & IPN_AUTOPORTMAP) != 0))
215 nat_setgroupmap(nat);
216 }
217 ;
218
219 mapblock:
220 mapblockit ifnames addr IPNY_TLATE addr ports mapoptions
221 { if ($3.v != 0 && $3.v != $5.v && $5.v != 0)
222 yyerror("5.address family mismatch");
223 bcopy(&$3.a, &nat->in_in[0], sizeof($3.a));
224 bcopy(&$3.m, &nat->in_in[1], sizeof($3.a));
225 bcopy(&$5.a, &nat->in_out[0], sizeof($5.a));
226 bcopy(&$5.m, &nat->in_out[1], sizeof($5.a));
227 if (nat->in_ifnames[1][0] == '\0')
228 strncpy(nat->in_ifnames[1],
229 nat->in_ifnames[0],
230 sizeof(nat->in_ifnames[0]));
231 if ((nat->in_flags & IPN_TCPUDP) == 0)
232 setnatproto(nat->in_p);
233 if (((nat->in_redir & NAT_MAPBLK) != 0) ||
234 ((nat->in_flags & IPN_AUTOPORTMAP) != 0))
235 nat_setgroupmap(nat);
236 }
237 ;
238
239 redir: rdrit ifnames addr dport IPNY_TLATE dip nport setproto rdroptions
240 { if ($6 != 0 && $3.v != 0 && $6 != $3.v)
241 yyerror("6.address family mismatch");
242 bcopy(&$3.a, &nat->in_out[0], sizeof($3.a));
243 bcopy(&$3.m, &nat->in_out[1], sizeof($3.a));
244 if (nat->in_ifnames[1][0] == '\0')
245 strncpy(nat->in_ifnames[1],
246 nat->in_ifnames[0],
247 sizeof(nat->in_ifnames[0]));
248 if ((nat->in_p == 0) &&
249 ((nat->in_flags & IPN_TCPUDP) == 0) &&
250 (nat->in_pmin != 0 ||
251 nat->in_pmax != 0 ||
252 nat->in_pnext != 0))
253 setnatproto(IPPROTO_TCP);
254 }
255 | rdrit ifnames rdrfrom IPNY_TLATE dip nport setproto rdroptions
256 { if ($5 != 0 && $3 != 0 && $5 != $3)
257 yyerror("7.address family mismatch");
258 if ((nat->in_p == 0) &&
259 ((nat->in_flags & IPN_TCPUDP) == 0) &&
260 (nat->in_pmin != 0 ||
261 nat->in_pmax != 0 ||
262 nat->in_pnext != 0))
263 setnatproto(IPPROTO_TCP);
264 if (nat->in_ifnames[1][0] == '\0')
265 strncpy(nat->in_ifnames[1],
266 nat->in_ifnames[0],
267 sizeof(nat->in_ifnames[0]));
268 }
269 | rdrit ifnames addr IPNY_TLATE dip setproto rdroptions
270 { if ($5 != 0 && $3.v != 0 && $5 != $3.v)
271 yyerror("8.address family mismatch");
272 bcopy(&$3.a, &nat->in_out[0], sizeof($3.a));
273 bcopy(&$3.m, &nat->in_out[1], sizeof($3.a));
274 if (nat->in_ifnames[1][0] == '\0')
275 strncpy(nat->in_ifnames[1],
276 nat->in_ifnames[0],
277 sizeof(nat->in_ifnames[0]));
278 }
279 ;
280
281 proxy: | IPNY_PROXY IPNY_PORT portspec YY_STR '/' proto
282 { strncpy(nat->in_plabel, $4, sizeof(nat->in_plabel));
283 if (nat->in_dcmp == 0) {
284 nat->in_dport = htons($3);
285 } else if ($3 != nat->in_dport) {
286 yyerror("proxy port numbers not consistant");
287 }
288 setnatproto($6);
289 free($4);
290 }
291 | IPNY_PROXY IPNY_PORT YY_STR YY_STR '/' proto
292 { int pnum;
293 strncpy(nat->in_plabel, $4, sizeof(nat->in_plabel));
294 pnum = getportproto($3, $6);
295 if (pnum == -1)
296 yyerror("invalid port number");
297 nat->in_dport = pnum;
298 setnatproto($6);
299 free($3);
300 free($4);
301 }
302 ;
303
304 setproto:
305 | proto { if (nat->in_p != 0 ||
306 nat->in_flags & IPN_TCPUDP)
307 yyerror("protocol set twice");
308 setnatproto($1);
309 }
310 | IPNY_TCPUDP { if (nat->in_p != 0 ||
311 nat->in_flags & IPN_TCPUDP)
312 yyerror("protocol set twice");
313 nat->in_flags |= IPN_TCPUDP;
314 nat->in_p = 0;
315 }
316 | IPNY_TCP '/' IPNY_UDP { if (nat->in_p != 0 ||
317 nat->in_flags & IPN_TCPUDP)
318 yyerror("protocol set twice");
319 nat->in_flags |= IPN_TCPUDP;
320 nat->in_p = 0;
321 }
322 ;
323
324 rhaddr: addr { $$.a = $1.a;
325 $$.m = $1.m;
326 $$.v = $1.v;
327 if ($$.v == 0)
328 $$.v = nat->in_v;
329 yyexpectaddr = 0; }
330 | IPNY_RANGE hostname '-' hostname
331 { if ($2.v != 0 && $4.v != 0 && $4.v != $2.v)
332 yyerror("9.address family "
333 "mismatch");
334 $$.v = $2.v;
335 $$.a = $2.a;
336 $$.m = $4.a;
337 nat->in_flags |= IPN_IPRANGE;
338 yyexpectaddr = 0; }
339 ;
340
341 dip:
342 hostname { bcopy(&$1.a, &nat->in_in[0],
343 sizeof($1.a));
344 if ($1.v == 0)
345 $1.v = nat->in_v;
346 if ($1.v == 4) {
347 nat->in_inmsk = 0xffffffff;
348 } else {
349 nat->in_in[1].i6[0] = 0xffffffff;
350 nat->in_in[1].i6[1] = 0xffffffff;
351 nat->in_in[1].i6[2] = 0xffffffff;
352 nat->in_in[1].i6[3] = 0xffffffff;
353 }
354 $$ = $1.v;
355 }
356 | hostname '/' YY_NUMBER { if ($1.v == 0)
357 $1.v = nat->in_v;
358 if ($1.v == 4 &&
359 ($1.a.in4.s_addr != 0 ||
360 ($3 != 0 && $3 != 32)))
361 yyerror("Invalid mask for dip");
362 else if ($1.v == 6 &&
363 ($1.a.in4.s_addr != 0 ||
364 ($3 != 0 && $3 != 128)))
365 yyerror("Invalid mask for dip");
366 else if ($1.v == 0 ) {
367 if ($1.a.in4.s_addr == 0 &&
368 ($3 == 32 || $3 == 0))
369 $1.v = 4;
370 else if ($3 == 128)
371 $1.v = 6;
372 }
373 bcopy(&$1.a, &nat->in_in[0],
374 sizeof($1.a));
375 ntomask($1.v, $3,
376 (u_32_t *)&nat->in_in[1]);
377 nat->in_in[0].i6[0] &= nat->in_in[1].i6[0];
378 nat->in_in[0].i6[0] &= nat->in_in[1].i6[1];
379 nat->in_in[0].i6[0] &= nat->in_in[1].i6[2];
380 nat->in_in[0].i6[0] &= nat->in_in[1].i6[3];
381 nat->in_v = $1.v;
382 $$ = $1.v;
383 }
384 | hostname ',' { yyexpectaddr = 1; } hostname
385 { if ($1.v != $4.v)
386 yyerror("10.address family "
387 "mismatch");
388 $$ = $1.v;
389 nat->in_flags |= IPN_SPLIT;
390 bcopy(&$1.a, &nat->in_in[0],
391 sizeof($1.a));
392 bcopy(&$4.a, &nat->in_in[1],
393 sizeof($4.a));
394 yyexpectaddr = 0; }
395 ;
396
397 portspec:
398 YY_NUMBER { if ($1 > 65535) /* Unsigned */
399 yyerror("invalid port number");
400 else
401 $$ = $1;
402 }
403 | YY_STR { if (getport(NULL, $1, &($$)) == -1)
404 yyerror("invalid port number");
405 $$ = ntohs($$);
406 }
407 ;
408
409 dport: | IPNY_PORT portspec { nat->in_pmin = htons($2);
410 nat->in_pmax = htons($2); }
411 | IPNY_PORT portspec '-' portspec { nat->in_pmin = htons($2);
412 nat->in_pmax = htons($4); }
413 | IPNY_PORT portspec ':' portspec { nat->in_pmin = htons($2);
414 nat->in_pmax = htons($4); }
415 ;
416
417 nport: IPNY_PORT portspec { nat->in_pnext = htons($2); }
418 | IPNY_PORT '=' portspec { nat->in_pnext = htons($3);
419 nat->in_flags |= IPN_FIXEDDPORT;
420 }
421 ;
422
423 ports: | IPNY_PORTS YY_NUMBER { nat->in_pmin = $2; }
424 | IPNY_PORTS IPNY_AUTO { nat->in_flags |= IPN_AUTOPORTMAP; }
425 ;
426
427 mapit: IPNY_MAP { nat->in_redir = NAT_MAP; }
428 | IPNY_BIMAP { nat->in_redir = NAT_BIMAP; }
429 ;
430
431 rdrit: IPNY_RDR { nat->in_redir = NAT_REDIRECT; }
432 ;
433
434 mapblockit:
435 IPNY_MAPBLOCK { nat->in_redir = NAT_MAPBLK; }
436 ;
437
438 mapfrom:
439 from sobject IPNY_TO dobject { if ($2 != 0 && $4 != 0 && $2 != $4)
440 yyerror("11.address family "
441 "mismatch");
442 $$ = $2;
443 }
444 | from sobject '!' IPNY_TO dobject
445 { if ($2 != 0 && $5 != 0 && $2 != $5)
446 yyerror("12.address family "
447 "mismatch");
448 nat->in_flags |= IPN_NOTDST;
449 $$ = $2;
450 }
451 ;
452
453 rdrfrom:
454 from sobject IPNY_TO dobject { if ($2 != 0 && $4 != 0 && $2 != $4)
455 yyerror("13.address family "
456 "mismatch");
457 $$ = $2;
458 }
459 | '!' from sobject IPNY_TO dobject
460 { if ($3 != 0 && $5 != 0 && $3 != $5)
461 yyerror("14.address family "
462 "mismatch");
463 nat->in_flags |= IPN_NOTSRC;
464 $$ = $3;
465 }
466 ;
467
468 from: IPNY_FROM { nat->in_flags |= IPN_FILTER;
469 yyexpectaddr = 1; }
470 ;
471
472 ifnames:
473 ifname { yyexpectaddr = 1; }
474 | ifname ',' otherifname { yyexpectaddr = 1; }
475 ;
476
477 ifname: YY_STR { strncpy(nat->in_ifnames[0], $1,
478 sizeof(nat->in_ifnames[0]));
479 nat->in_ifnames[0][LIFNAMSIZ - 1] = '\0';
480 free($1);
481 }
482 ;
483
484 otherifname:
485 YY_STR { strncpy(nat->in_ifnames[1], $1,
486 sizeof(nat->in_ifnames[1]));
487 nat->in_ifnames[1][LIFNAMSIZ - 1] = '\0';
488 free($1);
489 }
490 ;
491
492 mapport:
493 IPNY_PORTMAP tcpudp portspec ':' portspec randport
494 { nat->in_pmin = htons($3);
495 nat->in_pmax = htons($5);
496 }
497 | IPNY_PORTMAP tcpudp IPNY_AUTO randport
498 { nat->in_flags |= IPN_AUTOPORTMAP;
499 nat->in_pmin = htons(1024);
500 nat->in_pmax = htons(65535);
501 }
502 | IPNY_ICMPIDMAP YY_STR YY_NUMBER ':' YY_NUMBER
503 { if (strcmp($2, "icmp") != 0) {
504 yyerror("icmpidmap not followed by icmp");
505 }
506 free($2);
507 if ($3 < 0 || $3 > 65535)
508 yyerror("invalid ICMP Id number");
509 if ($5 < 0 || $5 > 65535)
510 yyerror("invalid ICMP Id number");
511 nat->in_flags = IPN_ICMPQUERY;
512 nat->in_pmin = htons($3);
513 nat->in_pmax = htons($5);
514 }
515 ;
516
517 randport:
518 | IPNY_SEQUENTIAL { nat->in_flags |= IPN_SEQUENTIAL; }
519 ;
520
521 sobject:
522 saddr { $$ = $1; }
523 | saddr IPNY_PORT portstuff { nat->in_sport = $3.p1;
524 nat->in_stop = $3.p2;
525 nat->in_scmp = $3.pc;
526 $$ = $1;
527 }
528 ;
529
530 saddr: addr { if (nat->in_redir == NAT_REDIRECT) {
531 bcopy(&$1.a, &nat->in_src[0],
532 sizeof($1.a));
533 bcopy(&$1.m, &nat->in_src[1],
534 sizeof($1.a));
535 } else {
536 bcopy(&$1.a, &nat->in_in[0],
537 sizeof($1.a));
538 bcopy(&$1.m, &nat->in_in[1],
539 sizeof($1.a));
540 }
541 $$ = $1.v;
542 }
543 ;
544
545 dobject:
546 daddr { $$ = $1; }
547 | daddr IPNY_PORT portstuff { nat->in_dport = $3.p1;
548 nat->in_dtop = $3.p2;
549 nat->in_dcmp = $3.pc;
550 if (nat->in_redir == NAT_REDIRECT)
551 nat->in_pmin = htons($3.p1);
552 }
553 ;
554
555 daddr: addr { if (nat->in_redir == NAT_REDIRECT) {
556 bcopy(&$1.a, &nat->in_out[0],
557 sizeof($1.a));
558 bcopy(&$1.m, &nat->in_out[1],
559 sizeof($1.a));
560 } else {
561 bcopy(&$1.a, &nat->in_src[0],
562 sizeof($1.a));
563 bcopy(&$1.m, &nat->in_src[1],
564 sizeof($1.a));
565 }
566 $$ = $1.v;
567 }
568 ;
569
570 addr: IPNY_ANY { yyexpectaddr = 0;
571 bzero(&$$.a, sizeof($$.a));
572 bzero(&$$.m, sizeof($$.a));
573 $$.v = nat->in_v;
574 }
575 | hostname { $$.a = $1.a;
576 $$.v = $1.v;
577 if ($$.v == 4) {
578 $$.m.in4.s_addr = 0xffffffff;
579 } else {
580 $$.m.i6[0] = 0xffffffff;
581 $$.m.i6[1] = 0xffffffff;
582 $$.m.i6[2] = 0xffffffff;
583 $$.m.i6[3] = 0xffffffff;
584 }
585 yyexpectaddr = 0;
586 }
587 | hostname '/' YY_NUMBER { $$.a = $1.a;
588 if ($1.v == 0) {
589 if ($1.a.in4.s_addr != 0)
590 yyerror("invalid addr");
591 if ($3 == 0 || $3 == 32)
592 $1.v = 4;
593 else if ($3 == 128)
594 $1.v = 6;
595 else
596 yyerror("invalid mask");
597 nat->in_v = $1.v;
598 }
599 ntomask($1.v, $3, (u_32_t *)&$$.m);
600 $$.a.i6[0] &= $$.m.i6[0];
601 $$.a.i6[1] &= $$.m.i6[1];
602 $$.a.i6[2] &= $$.m.i6[2];
603 $$.a.i6[3] &= $$.m.i6[3];
604 $$.v = $1.v;
605 yyexpectaddr = 0;
606 }
607 | hostname '/' ipaddr { if ($1.v != $3.v) {
608 yyerror("1.address family "
609 "mismatch");
610 }
611 $$.a = $1.a;
612 $$.m = $3.a;
613 $$.a.i6[0] &= $$.m.i6[0];
614 $$.a.i6[1] &= $$.m.i6[1];
615 $$.a.i6[2] &= $$.m.i6[2];
616 $$.a.i6[3] &= $$.m.i6[3];
617 $$.v = $1.v;
618 yyexpectaddr = 0;
619 }
620 | hostname '/' hexnumber { $$.a = $1.a;
621 $$.m.in4.s_addr = htonl($3);
622 $$.a.in4.s_addr &= $$.m.in4.s_addr;
623 $$.v = 4;
624 }
625 | hostname IPNY_MASK ipaddr { if ($1.v != $3.v) {
626 yyerror("2.address family "
627 "mismatch");
628 }
629 $$.a = $1.a;
630 $$.m = $3.a;
631 $$.a.i6[0] &= $$.m.i6[0];
632 $$.a.i6[1] &= $$.m.i6[1];
633 $$.a.i6[2] &= $$.m.i6[2];
634 $$.a.i6[3] &= $$.m.i6[3];
635 $$.v = $1.v;
636 yyexpectaddr = 0;
637 }
638 | hostname IPNY_MASK hexnumber { $$.a = $1.a;
639 $$.m.in4.s_addr = htonl($3);
640 $$.a.in4.s_addr &= $$.m.in4.s_addr;
641 $$.v = 4;
642 }
643 ;
644
645 portstuff:
646 compare portspec { $$.pc = $1; $$.p1 = $2; }
647 | portspec range portspec { $$.pc = $2; $$.p1 = $1; $$.p2 = $3; }
648 ;
649
650 mapoptions:
651 rr frag age mssclamp nattag setproto
652 ;
653
654 rdroptions:
655 rr frag age sticky mssclamp rdrproxy nattag
656 ;
657
658 nattag: | IPNY_TAG YY_STR { strncpy(nat->in_tag.ipt_tag, $2,
659 sizeof(nat->in_tag.ipt_tag));
660 }
661
662 rr: | IPNY_ROUNDROBIN { nat->in_flags |= IPN_ROUNDR; }
663 ;
664
665 frag: | IPNY_FRAG { nat->in_flags |= IPN_FRAG; }
666 ;
667
668 age: | IPNY_AGE YY_NUMBER { nat->in_age[0] = $2;
669 nat->in_age[1] = $2; }
670 | IPNY_AGE YY_NUMBER '/' YY_NUMBER { nat->in_age[0] = $2;
671 nat->in_age[1] = $4; }
672 ;
673
674 sticky: | IPNY_STICKY { if (!(nat->in_flags & IPN_ROUNDR) &&
675 !(nat->in_flags & IPN_SPLIT)) {
676 fprintf(stderr,
677 "'sticky' for use with round-robin/IP splitting only\n");
678 } else
679 nat->in_flags |= IPN_STICKY;
680 }
681 ;
682
683 mssclamp:
684 | IPNY_MSSCLAMP YY_NUMBER { nat->in_mssclamp = $2; }
685 ;
686
687 tcpudp: | IPNY_TCP { setnatproto(IPPROTO_TCP); }
688 | IPNY_UDP { setnatproto(IPPROTO_UDP); }
689 | IPNY_TCPUDP { nat->in_flags |= IPN_TCPUDP;
690 nat->in_p = 0;
691 }
692 | IPNY_TCP '/' IPNY_UDP { nat->in_flags |= IPN_TCPUDP;
693 nat->in_p = 0;
694 }
695 ;
696
697 rdrproxy:
698 IPNY_PROXY YY_STR
699 { strncpy(nat->in_plabel, $2,
700 sizeof(nat->in_plabel));
701 nat->in_dport = nat->in_pnext;
702 nat->in_dport = htons(nat->in_dport);
703 free($2);
704 }
705 | proxy { if (nat->in_plabel[0] != '\0') {
706 nat->in_pmin = nat->in_dport;
707 nat->in_pmax = nat->in_pmin;
708 nat->in_pnext = nat->in_pmin;
709 }
710 }
711 ;
712
713 proto: YY_NUMBER { $$ = $1; }
714 | IPNY_TCP { $$ = IPPROTO_TCP; }
715 | IPNY_UDP { $$ = IPPROTO_UDP; }
716 | YY_STR { $$ = getproto($1); free($1); }
717 ;
718
719 hexnumber:
720 YY_HEX { $$ = $1; }
721 ;
722
723 hostname:
724 YY_STR { i6addr_t addr;
725 if (gethost($1, &addr, 0) == 0) {
726 $$.a = addr;
727 $$.v = 4;
728 } else
729 if (gethost($1, &addr, 1) == 0) {
730 $$.a = addr;
731 $$.v = 6;
732 } else {
733 yyerror("Unknown hostname");
734 }
735 if ($$.v != 0)
736 nat->in_v = $$.v;
737 free($1);
738 }
739 | YY_NUMBER { bzero(&$$.a, sizeof($$.a));
740 $$.a.in4.s_addr = htonl($1);
741 if ($$.a.in4.s_addr != 0)
742 $$.v = 4;
743 else
744 $$.v = nat->in_v;
745 if ($$.v != 0)
746 nat->in_v = $$.v;
747 }
748 | ipv4 { $$ = $1;
749 nat->in_v = 4;
750 }
751 | YY_IPV6 { $$.a = $1;
752 $$.v = 6;
753 nat->in_v = 6;
754 }
755 | YY_NUMBER YY_IPV6 { $$.a = $2;
756 $$.v = 6;
757 }
758 ;
759
760 compare:
761 '=' { $$ = FR_EQUAL; }
762 | YY_CMP_EQ { $$ = FR_EQUAL; }
763 | YY_CMP_NE { $$ = FR_NEQUAL; }
764 | YY_CMP_LT { $$ = FR_LESST; }
765 | YY_CMP_LE { $$ = FR_LESSTE; }
766 | YY_CMP_GT { $$ = FR_GREATERT; }
767 | YY_CMP_GE { $$ = FR_GREATERTE; }
768
769 range:
770 YY_RANGE_OUT { $$ = FR_OUTRANGE; }
771 | YY_RANGE_IN { $$ = FR_INRANGE; }
772 ;
773
774 ipaddr: ipv4 { $$ = $1; }
775 | YY_IPV6 { $$.a = $1;
776 $$.v = 6;
777 }
778 ;
779
780 ipv4: YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER
781 { if ($1 > 255 || $3 > 255 || $5 > 255 || $7 > 255) {
782 yyerror("Invalid octet string for IP address");
783 return 0;
784 }
785 $$.a.in4.s_addr = ($1 << 24) | ($3 << 16) | ($5 << 8) | $7;
786 $$.a.in4.s_addr = htonl($$.a.in4.s_addr);
787 $$.v = 4;
788 }
789 ;
790
791 %%
792
793
794 static wordtab_t yywords[] = {
795 { "age", IPNY_AGE },
796 { "any", IPNY_ANY },
797 { "auto", IPNY_AUTO },
798 { "bimap", IPNY_BIMAP },
799 { "frag", IPNY_FRAG },
800 { "from", IPNY_FROM },
801 { "icmpidmap", IPNY_ICMPIDMAP },
802 { "mask", IPNY_MASK },
803 { "map", IPNY_MAP },
804 { "map-block", IPNY_MAPBLOCK },
805 { "mssclamp", IPNY_MSSCLAMP },
806 { "netmask", IPNY_MASK },
807 { "port", IPNY_PORT },
808 { "portmap", IPNY_PORTMAP },
809 { "ports", IPNY_PORTS },
810 { "proxy", IPNY_PROXY },
811 { "range", IPNY_RANGE },
812 { "rdr", IPNY_RDR },
813 { "round-robin",IPNY_ROUNDROBIN },
814 { "sequential", IPNY_SEQUENTIAL },
815 { "sticky", IPNY_STICKY },
816 { "tag", IPNY_TAG },
817 { "tcp", IPNY_TCP },
818 { "tcpudp", IPNY_TCPUDP },
819 { "to", IPNY_TO },
820 { "udp", IPNY_UDP },
821 { "-", '-' },
822 { "->", IPNY_TLATE },
823 { "eq", YY_CMP_EQ },
824 { "ne", YY_CMP_NE },
825 { "lt", YY_CMP_LT },
826 { "gt", YY_CMP_GT },
827 { "le", YY_CMP_LE },
828 { "ge", YY_CMP_GE },
829 { NULL, 0 }
830 };
831
832
ipnat_parsefile(fd,addfunc,ioctlfunc,filename)833 int ipnat_parsefile(fd, addfunc, ioctlfunc, filename)
834 int fd;
835 addfunc_t addfunc;
836 ioctlfunc_t ioctlfunc;
837 char *filename;
838 {
839 FILE *fp = NULL;
840 char *s;
841
842 (void) yysettab(yywords);
843
844 s = getenv("YYDEBUG");
845 if (s)
846 yydebug = atoi(s);
847 else
848 yydebug = 0;
849
850 if (strcmp(filename, "-")) {
851 fp = fopen(filename, "r");
852 if (!fp) {
853 fprintf(stderr, "fopen(%s) failed: %s\n", filename,
854 STRERROR(errno));
855 return -1;
856 }
857 } else
858 fp = stdin;
859
860 while (ipnat_parsesome(fd, addfunc, ioctlfunc, fp) == 1)
861 ;
862 if (fp != NULL)
863 fclose(fp);
864 return 0;
865 }
866
867
ipnat_parsesome(fd,addfunc,ioctlfunc,fp)868 int ipnat_parsesome(fd, addfunc, ioctlfunc, fp)
869 int fd;
870 addfunc_t addfunc;
871 ioctlfunc_t ioctlfunc;
872 FILE *fp;
873 {
874 char *s;
875 int i;
876
877 yylineNum = 1;
878
879 natfd = fd;
880 nataddfunc = addfunc;
881 natioctlfunc = ioctlfunc;
882
883 if (feof(fp))
884 return 0;
885 i = fgetc(fp);
886 if (i == EOF)
887 return 0;
888 if (ungetc(i, fp) == EOF)
889 return 0;
890 if (feof(fp))
891 return 0;
892 s = getenv("YYDEBUG");
893 if (s)
894 yydebug = atoi(s);
895 else
896 yydebug = 0;
897
898 yyin = fp;
899 yyparse();
900 return 1;
901 }
902
903
newnatrule()904 static void newnatrule()
905 {
906 ipnat_t *n;
907
908 n = calloc(1, sizeof(*n));
909 if (n == NULL)
910 return;
911
912 if (nat == NULL)
913 nattop = nat = n;
914 else {
915 nat->in_next = n;
916 nat = n;
917 }
918 }
919
920
setnatproto(p)921 static void setnatproto(p)
922 int p;
923 {
924 nat->in_p = p;
925
926 switch (p)
927 {
928 case IPPROTO_TCP :
929 nat->in_flags |= IPN_TCP;
930 nat->in_flags &= ~IPN_UDP;
931 break;
932 case IPPROTO_UDP :
933 nat->in_flags |= IPN_UDP;
934 nat->in_flags &= ~IPN_TCP;
935 break;
936 case IPPROTO_ICMP :
937 nat->in_flags &= ~IPN_TCPUDP;
938 if (!(nat->in_flags & IPN_ICMPQUERY)) {
939 nat->in_dcmp = 0;
940 nat->in_scmp = 0;
941 nat->in_pmin = 0;
942 nat->in_pmax = 0;
943 nat->in_pnext = 0;
944 }
945 break;
946 default :
947 if ((nat->in_redir & NAT_MAPBLK) == 0) {
948 /* Only reset dcmp/scmp in case dport/sport not set */
949 if (0 == nat->in_tuc.ftu_dport)
950 nat->in_dcmp = 0;
951 if (0 == nat->in_tuc.ftu_sport)
952 nat->in_scmp = 0;
953 nat->in_pmin = 0;
954 nat->in_pmax = 0;
955 nat->in_pnext = 0;
956 nat->in_flags &= ~IPN_TCPUDP;
957 }
958 break;
959 }
960
961 if ((nat->in_flags & (IPN_TCPUDP|IPN_FIXEDDPORT)) == IPN_FIXEDDPORT)
962 nat->in_flags &= ~IPN_FIXEDDPORT;
963 }
964
965
ipnat_addrule(fd,ioctlfunc,ptr)966 void ipnat_addrule(fd, ioctlfunc, ptr)
967 int fd;
968 ioctlfunc_t ioctlfunc;
969 void *ptr;
970 {
971 ioctlcmd_t add, del;
972 ipfobj_t obj;
973 ipnat_t *ipn;
974
975 ipn = ptr;
976 bzero((char *)&obj, sizeof(obj));
977 obj.ipfo_rev = IPFILTER_VERSION;
978 obj.ipfo_size = sizeof(ipnat_t);
979 obj.ipfo_type = IPFOBJ_IPNAT;
980 obj.ipfo_ptr = ptr;
981 add = 0;
982 del = 0;
983
984 if ((opts & OPT_DONOTHING) != 0)
985 fd = -1;
986
987 if (opts & OPT_ZERORULEST) {
988 add = SIOCZRLST;
989 } else if (opts & OPT_INACTIVE) {
990 add = SIOCADNAT;
991 del = SIOCRMNAT;
992 } else {
993 add = SIOCADNAT;
994 del = SIOCRMNAT;
995 }
996
997 if (ipn && (opts & OPT_VERBOSE))
998 printnat(ipn, opts);
999
1000 if (opts & OPT_DEBUG)
1001 binprint(ipn, sizeof(*ipn));
1002
1003 if ((opts & OPT_ZERORULEST) != 0) {
1004 if ((*ioctlfunc)(fd, add, (void *)&obj) == -1) {
1005 if ((opts & OPT_DONOTHING) == 0) {
1006 fprintf(stderr, "%d:", yylineNum);
1007 perror("ioctl(SIOCZRLST)");
1008 }
1009 } else {
1010 #ifdef USE_QUAD_T
1011 /*
1012 printf("hits %qd bytes %qd ",
1013 (long long)fr->fr_hits,
1014 (long long)fr->fr_bytes);
1015 */
1016 #else
1017 /*
1018 printf("hits %ld bytes %ld ",
1019 fr->fr_hits, fr->fr_bytes);
1020 */
1021 #endif
1022 printnat(ipn, opts);
1023 }
1024 } else if ((opts & OPT_REMOVE) != 0) {
1025 if ((*ioctlfunc)(fd, del, (void *)&obj) == -1) {
1026 if ((opts & OPT_DONOTHING) == 0) {
1027 fprintf(stderr, "%d:", yylineNum);
1028 perror("ioctl(delete nat rule)");
1029 }
1030 }
1031 } else {
1032 if ((*ioctlfunc)(fd, add, (void *)&obj) == -1) {
1033 if ((opts & OPT_DONOTHING) == 0) {
1034 fprintf(stderr, "%d:", yylineNum);
1035 perror("ioctl(add/insert nat rule)");
1036 }
1037 }
1038 }
1039 }
1040
1041