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