1 /* $NetBSD: ipnat_y.y,v 1.4 2014/06/29 08:58:01 darrenr Exp $ */
2
3 /*
4 * Copyright (C) 2012 by Darren Reed.
5 *
6 * See the IPFILTER.LICENCE file for details on licencing.
7 */
8 %{
9 #ifdef __FreeBSD__
10 # ifndef __FreeBSD_cc_version
11 # include <osreldate.h>
12 # else
13 # if __FreeBSD_cc_version < 430000
14 # include <osreldate.h>
15 # endif
16 # endif
17 #endif
18 #include <stdio.h>
19 #include <unistd.h>
20 #include <string.h>
21 #include <fcntl.h>
22 #include <errno.h>
23 #if !defined(__SVR4) && !defined(__GNUC__)
24 #include <strings.h>
25 #endif
26 #include <sys/types.h>
27 #include <sys/param.h>
28 #include <sys/file.h>
29 #include <stdlib.h>
30 #include <stddef.h>
31 #include <sys/socket.h>
32 #include <sys/ioctl.h>
33 #include <netinet/in.h>
34 #include <netinet/in_systm.h>
35 #include <sys/time.h>
36 #include <syslog.h>
37 #include <net/if.h>
38 #if __FreeBSD_version >= 300000
39 # include <net/if_var.h>
40 #endif
41 #include <netdb.h>
42 #include <arpa/nameser.h>
43 #include <resolv.h>
44 #include "ipf.h"
45 #include "netinet/ipl.h"
46 #include "ipnat_l.h"
47
48 #define YYDEBUG 1
49
50 extern void yyerror __P((char *));
51 extern int yyparse __P((void));
52 extern int yylex __P((void));
53 extern int yydebug;
54 extern FILE *yyin;
55 extern int yylineNum;
56
57 static ipnat_t *nattop = NULL;
58 static ipnat_t *nat = NULL;
59 static int natfd = -1;
60 static ioctlfunc_t natioctlfunc = NULL;
61 static addfunc_t nataddfunc = NULL;
62 static int suggest_port = 0;
63 static proxyrule_t *prules = NULL;
64 static int parser_error = 0;
65
66 static void newnatrule __P((void));
67 static void setnatproto __P((int));
68 static void setmapifnames __P((void));
69 static void setrdrifnames __P((void));
70 static void proxy_setconfig __P((int));
71 static void proxy_unsetconfig __P((void));
72 static namelist_t *proxy_dns_add_pass __P((char *, char *));
73 static namelist_t *proxy_dns_add_block __P((char *, char *));
74 static void proxy_addconfig __P((char *, int, char *, namelist_t *));
75 static void proxy_loadconfig __P((int, ioctlfunc_t, char *, int,
76 char *, namelist_t *));
77 static void proxy_loadrules __P((int, ioctlfunc_t, proxyrule_t *));
78 static void setmapifnames __P((void));
79 static void setrdrifnames __P((void));
80 static void setifname __P((ipnat_t **, int, char *));
81 static int addname __P((ipnat_t **, char *));
82 %}
83 %union {
84 char *str;
85 u_32_t num;
86 struct {
87 i6addr_t a;
88 int f;
89 } ipa;
90 frentry_t fr;
91 frtuc_t *frt;
92 u_short port;
93 struct {
94 int p1;
95 int p2;
96 int pc;
97 } pc;
98 struct {
99 i6addr_t a;
100 i6addr_t m;
101 int t; /* Address type */
102 int u;
103 int f; /* Family */
104 int v; /* IP version */
105 int s; /* 0 = number, 1 = text */
106 int n; /* number */
107 } ipp;
108 union i6addr ip6;
109 namelist_t *names;
110 };
111
112 %token <num> YY_NUMBER YY_HEX
113 %token <str> YY_STR
114 %token YY_COMMENT
115 %token YY_CMP_EQ YY_CMP_NE YY_CMP_LE YY_CMP_GE YY_CMP_LT YY_CMP_GT
116 %token YY_RANGE_OUT YY_RANGE_IN
117 %token <ip6> YY_IPV6
118
119 %token IPNY_MAPBLOCK IPNY_RDR IPNY_PORT IPNY_PORTS IPNY_AUTO IPNY_RANGE
120 %token IPNY_MAP IPNY_BIMAP IPNY_FROM IPNY_TO IPNY_MASK IPNY_PORTMAP IPNY_ANY
121 %token IPNY_ROUNDROBIN IPNY_FRAG IPNY_AGE IPNY_ICMPIDMAP IPNY_PROXY
122 %token IPNY_TCP IPNY_UDP IPNY_TCPUDP IPNY_STICKY IPNY_MSSCLAMP IPNY_TAG
123 %token IPNY_TLATE IPNY_POOL IPNY_HASH IPNY_NO IPNY_REWRITE IPNY_PROTO
124 %token IPNY_ON IPNY_SRC IPNY_DST IPNY_IN IPNY_OUT IPNY_DIVERT
125 %token IPNY_CONFIG IPNY_ALLOW IPNY_DENY IPNY_DNS IPNY_INET IPNY_INET6
126 %token IPNY_SEQUENTIAL IPNY_DSTLIST IPNY_PURGE
127 %type <port> portspec
128 %type <num> hexnumber compare range proto
129 %type <num> saddr daddr sobject dobject mapfrom rdrfrom dip
130 %type <ipa> hostname ipv4 ipaddr
131 %type <ipp> addr rhsaddr rhdaddr erhdaddr
132 %type <pc> portstuff portpair comaports srcports dstports
133 %type <names> dnslines dnsline
134 %%
135 file: line
136 | assign
137 | file line
138 | file assign
139 | file pconf ';'
140 ;
141
142 line: xx rule { int err;
143 while ((nat = nattop) != NULL) {
144 if (nat->in_v[0] == 0)
145 nat->in_v[0] = 4;
146 if (nat->in_v[1] == 0)
147 nat->in_v[1] = nat->in_v[0];
148 nattop = nat->in_next;
149 err = (*nataddfunc)(natfd, natioctlfunc, nat);
150 free(nat);
151 if (err != 0) {
152 parser_error = err;
153 break;
154 }
155 }
156 if (parser_error == 0 && prules != NULL) {
157 proxy_loadrules(natfd, natioctlfunc, prules);
158 prules = NULL;
159 }
160 resetlexer();
161 }
162 | YY_COMMENT
163 ;
164
165 assign: YY_STR assigning YY_STR ';' { set_variable($1, $3);
166 resetlexer();
167 free($1);
168 free($3);
169 yyvarnext = 0;
170 }
171 ;
172
173 assigning:
174 '=' { yyvarnext = 1; }
175 ;
176
177 xx: { newnatrule(); }
178 ;
179
180 rule: map eol
181 | mapblock eol
182 | redir eol
183 | rewrite ';'
184 | divert ';'
185 ;
186
187 no: IPNY_NO { nat->in_flags |= IPN_NO; }
188 ;
189
190 eol: | ';'
191 ;
192
193 map: mapit ifnames addr tlate rhsaddr proxy mapoptions
194 { if ($3.f != 0 && $3.f != $5.f && $5.f != 0)
195 yyerror("3.address family mismatch");
196 if (nat->in_v[0] == 0 && $5.v != 0)
197 nat->in_v[0] = $5.v;
198 else if (nat->in_v[0] == 0 && $3.v != 0)
199 nat->in_v[0] = $3.v;
200 if (nat->in_v[1] == 0 && $5.v != 0)
201 nat->in_v[1] = $5.v;
202 else if (nat->in_v[1] == 0 && $3.v != 0)
203 nat->in_v[1] = $3.v;
204 nat->in_osrcatype = $3.t;
205 bcopy(&$3.a, &nat->in_osrc.na_addr[0],
206 sizeof($3.a));
207 bcopy(&$3.m, &nat->in_osrc.na_addr[1],
208 sizeof($3.a));
209 nat->in_nsrcatype = $5.t;
210 nat->in_nsrcafunc = $5.u;
211 bcopy(&$5.a, &nat->in_nsrc.na_addr[0],
212 sizeof($5.a));
213 bcopy(&$5.m, &nat->in_nsrc.na_addr[1],
214 sizeof($5.a));
215
216 setmapifnames();
217 }
218 | mapit ifnames addr tlate rhsaddr mapport mapoptions
219 { if ($3.f != $5.f && $3.f != 0 && $5.f != 0)
220 yyerror("4.address family mismatch");
221 if (nat->in_v[1] == 0 && $5.v != 0)
222 nat->in_v[1] = $5.v;
223 else if (nat->in_v[0] == 0 && $3.v != 0)
224 nat->in_v[0] = $3.v;
225 if (nat->in_v[0] == 0 && $5.v != 0)
226 nat->in_v[0] = $5.v;
227 else if (nat->in_v[1] == 0 && $3.v != 0)
228 nat->in_v[1] = $3.v;
229 nat->in_osrcatype = $3.t;
230 bcopy(&$3.a, &nat->in_osrc.na_addr[0],
231 sizeof($3.a));
232 bcopy(&$3.m, &nat->in_osrc.na_addr[1],
233 sizeof($3.a));
234 nat->in_nsrcatype = $5.t;
235 nat->in_nsrcafunc = $5.u;
236 bcopy(&$5.a, &nat->in_nsrc.na_addr[0],
237 sizeof($5.a));
238 bcopy(&$5.m, &nat->in_nsrc.na_addr[1],
239 sizeof($5.a));
240
241 setmapifnames();
242 }
243 | no mapit ifnames addr setproto ';'
244 { if (nat->in_v[0] == 0)
245 nat->in_v[0] = $4.v;
246 nat->in_osrcatype = $4.t;
247 bcopy(&$4.a, &nat->in_osrc.na_addr[0],
248 sizeof($4.a));
249 bcopy(&$4.m, &nat->in_osrc.na_addr[1],
250 sizeof($4.a));
251
252 setmapifnames();
253 }
254 | mapit ifnames mapfrom tlate rhsaddr proxy mapoptions
255 { if ($3 != 0 && $5.f != 0 && $3 != $5.f)
256 yyerror("5.address family mismatch");
257 if (nat->in_v[0] == 0 && $5.v != 0)
258 nat->in_v[0] = $5.v;
259 else if (nat->in_v[0] == 0 && $3 != 0)
260 nat->in_v[0] = ftov($3);
261 if (nat->in_v[1] == 0 && $5.v != 0)
262 nat->in_v[1] = $5.v;
263 else if (nat->in_v[1] == 0 && $3 != 0)
264 nat->in_v[1] = ftov($3);
265 nat->in_nsrcatype = $5.t;
266 nat->in_nsrcafunc = $5.u;
267 bcopy(&$5.a, &nat->in_nsrc.na_addr[0],
268 sizeof($5.a));
269 bcopy(&$5.m, &nat->in_nsrc.na_addr[1],
270 sizeof($5.a));
271
272 setmapifnames();
273 }
274 | no mapit ifnames mapfrom setproto ';'
275 { nat->in_v[0] = ftov($4);
276 setmapifnames();
277 }
278 | mapit ifnames mapfrom tlate rhsaddr mapport mapoptions
279 { if ($3 != 0 && $5.f != 0 && $3 != $5.f)
280 yyerror("6.address family mismatch");
281 if (nat->in_v[0] == 0 && $5.v != 0)
282 nat->in_v[0] = $5.v;
283 else if (nat->in_v[0] == 0 && $3 != 0)
284 nat->in_v[0] = ftov($3);
285 if (nat->in_v[1] == 0 && $5.v != 0)
286 nat->in_v[1] = $5.v;
287 else if (nat->in_v[1] == 0 && $3 != 0)
288 nat->in_v[1] = ftov($3);
289 nat->in_nsrcatype = $5.t;
290 nat->in_nsrcafunc = $5.u;
291 bcopy(&$5.a, &nat->in_nsrc.na_addr[0],
292 sizeof($5.a));
293 bcopy(&$5.m, &nat->in_nsrc.na_addr[1],
294 sizeof($5.a));
295
296 setmapifnames();
297 }
298 ;
299
300 mapblock:
301 mapblockit ifnames addr tlate addr ports mapoptions
302 { if ($3.f != 0 && $5.f != 0 && $3.f != $5.f)
303 yyerror("7.address family mismatch");
304 if (nat->in_v[0] == 0 && $5.v != 0)
305 nat->in_v[0] = $5.v;
306 else if (nat->in_v[0] == 0 && $3.v != 0)
307 nat->in_v[0] = $3.v;
308 if (nat->in_v[1] == 0 && $5.v != 0)
309 nat->in_v[1] = $5.v;
310 else if (nat->in_v[1] == 0 && $3.v != 0)
311 nat->in_v[1] = $3.v;
312 nat->in_osrcatype = $3.t;
313 bcopy(&$3.a, &nat->in_osrc.na_addr[0],
314 sizeof($3.a));
315 bcopy(&$3.m, &nat->in_osrc.na_addr[1],
316 sizeof($3.a));
317 nat->in_nsrcatype = $5.t;
318 nat->in_nsrcafunc = $5.u;
319 bcopy(&$5.a, &nat->in_nsrc.na_addr[0],
320 sizeof($5.a));
321 bcopy(&$5.m, &nat->in_nsrc.na_addr[1],
322 sizeof($5.a));
323
324 setmapifnames();
325 }
326 | no mapblockit ifnames { yyexpectaddr = 1; } addr setproto ';'
327 { if (nat->in_v[0] == 0)
328 nat->in_v[0] = $5.v;
329 if (nat->in_v[1] == 0)
330 nat->in_v[1] = $5.v;
331 nat->in_osrcatype = $5.t;
332 bcopy(&$5.a, &nat->in_osrc.na_addr[0],
333 sizeof($5.a));
334 bcopy(&$5.m, &nat->in_osrc.na_addr[1],
335 sizeof($5.a));
336
337 setmapifnames();
338 }
339 ;
340
341 redir: rdrit ifnames addr dport tlate dip nport setproto rdroptions
342 { if ($6 != 0 && $3.f != 0 && $6 != $3.f)
343 yyerror("21.address family mismatch");
344 if (nat->in_v[0] == 0) {
345 if ($3.v != AF_UNSPEC)
346 nat->in_v[0] = ftov($3.f);
347 else
348 nat->in_v[0] = ftov($6);
349 }
350 nat->in_odstatype = $3.t;
351 bcopy(&$3.a, &nat->in_odst.na_addr[0],
352 sizeof($3.a));
353 bcopy(&$3.m, &nat->in_odst.na_addr[1],
354 sizeof($3.a));
355
356 setrdrifnames();
357 }
358 | no rdrit ifnames addr dport setproto ';'
359 { if (nat->in_v[0] == 0)
360 nat->in_v[0] = ftov($4.f);
361 nat->in_odstatype = $4.t;
362 bcopy(&$4.a, &nat->in_odst.na_addr[0],
363 sizeof($4.a));
364 bcopy(&$4.m, &nat->in_odst.na_addr[1],
365 sizeof($4.a));
366
367 setrdrifnames();
368 }
369 | rdrit ifnames rdrfrom tlate dip nport setproto rdroptions
370 { if ($5 != 0 && $3 != 0 && $5 != $3)
371 yyerror("20.address family mismatch");
372 if (nat->in_v[0] == 0) {
373 if ($3 != AF_UNSPEC)
374 nat->in_v[0] = ftov($3);
375 else
376 nat->in_v[0] = ftov($5);
377 }
378 setrdrifnames();
379 }
380 | no rdrit ifnames rdrfrom setproto ';'
381 { nat->in_v[0] = ftov($4);
382
383 setrdrifnames();
384 }
385 ;
386
387 rewrite:
388 IPNY_REWRITE oninout rwrproto mapfrom tlate newdst newopts
389 { if (nat->in_v[0] == 0)
390 nat->in_v[0] = ftov($4);
391 if (nat->in_redir & NAT_MAP)
392 setmapifnames();
393 else
394 setrdrifnames();
395 nat->in_redir |= NAT_REWRITE;
396 }
397 ;
398
399 divert: IPNY_DIVERT oninout rwrproto mapfrom tlate divdst newopts
400 { if (nat->in_v[0] == 0)
401 nat->in_v[0] = ftov($4);
402 if (nat->in_redir & NAT_MAP) {
403 setmapifnames();
404 nat->in_pr[0] = IPPROTO_UDP;
405 } else {
406 setrdrifnames();
407 nat->in_pr[1] = IPPROTO_UDP;
408 }
409 nat->in_flags &= ~IPN_TCP;
410 }
411 ;
412
413 tlate: IPNY_TLATE { yyexpectaddr = 1; }
414 ;
415
416 pconf: IPNY_PROXY { yysetdict(proxies); }
417 IPNY_DNS '/' proto IPNY_CONFIG YY_STR '{'
418 { proxy_setconfig(IPNY_DNS); }
419 dnslines ';' '}'
420 { proxy_addconfig("dns", $5, $7, $10);
421 proxy_unsetconfig();
422 }
423 ;
424
425 dnslines:
426 dnsline { $$ = $1; }
427 | dnslines ';' dnsline { $$ = $1; $1->na_next = $3; }
428 ;
429
430 dnsline:
431 IPNY_ALLOW YY_STR { $$ = proxy_dns_add_pass(NULL, $2); }
432 | IPNY_DENY YY_STR { $$ = proxy_dns_add_block(NULL, $2); }
433 | IPNY_ALLOW '.' YY_STR { $$ = proxy_dns_add_pass(".", $3); }
434 | IPNY_DENY '.' YY_STR { $$ = proxy_dns_add_block(".", $3); }
435 ;
436
437 oninout:
438 inout IPNY_ON ifnames { ; }
439 ;
440
441 inout: IPNY_IN { nat->in_redir = NAT_REDIRECT; }
442 | IPNY_OUT { nat->in_redir = NAT_MAP; }
443 ;
444
445 rwrproto:
446 | IPNY_PROTO setproto
447 ;
448
449 newdst: src rhsaddr srcports dst erhdaddr dstports
450 { nat->in_nsrc.na_addr[0] = $2.a;
451 nat->in_nsrc.na_addr[1] = $2.m;
452 nat->in_nsrc.na_atype = $2.t;
453 if ($2.t == FRI_LOOKUP) {
454 nat->in_nsrc.na_type = $2.u;
455 nat->in_nsrc.na_subtype = $2.s;
456 nat->in_nsrc.na_num = $2.n;
457 }
458 nat->in_nsports[0] = $3.p1;
459 nat->in_nsports[1] = $3.p2;
460 nat->in_ndst.na_addr[0] = $5.a;
461 nat->in_ndst.na_addr[1] = $5.m;
462 nat->in_ndst.na_atype = $5.t;
463 if ($5.t == FRI_LOOKUP) {
464 nat->in_ndst.na_type = $5.u;
465 nat->in_ndst.na_subtype = $5.s;
466 nat->in_ndst.na_num = $5.n;
467 }
468 nat->in_ndports[0] = $6.p1;
469 nat->in_ndports[1] = $6.p2;
470 }
471 ;
472
473 divdst: src addr ',' portspec dst addr ',' portspec IPNY_UDP
474 { nat->in_nsrc.na_addr[0] = $2.a;
475 if ($2.m.in4.s_addr != 0xffffffff)
476 yyerror("divert must have /32 dest");
477 nat->in_nsrc.na_addr[1] = $2.m;
478 nat->in_nsports[0] = $4;
479 nat->in_nsports[1] = $4;
480
481 nat->in_ndst.na_addr[0] = $6.a;
482 nat->in_ndst.na_addr[1] = $6.m;
483 if ($6.m.in4.s_addr != 0xffffffff)
484 yyerror("divert must have /32 dest");
485 nat->in_ndports[0] = $8;
486 nat->in_ndports[1] = $8;
487
488 nat->in_redir |= NAT_DIVERTUDP;
489 }
490 ;
491
492 src: IPNY_SRC { yyexpectaddr = 1; }
493 ;
494
495 dst: IPNY_DST { yyexpectaddr = 1; }
496 ;
497
498 srcports:
499 comaports { $$.p1 = $1.p1;
500 $$.p2 = $1.p2;
501 }
502 | IPNY_PORT '=' portspec
503 { $$.p1 = $3;
504 $$.p2 = $3;
505 nat->in_flags |= IPN_FIXEDSPORT;
506 }
507 ;
508
509 dstports:
510 comaports { $$.p1 = $1.p1;
511 $$.p2 = $1.p2;
512 }
513 | IPNY_PORT '=' portspec
514 { $$.p1 = $3;
515 $$.p2 = $3;
516 nat->in_flags |= IPN_FIXEDDPORT;
517 }
518 ;
519
520 comaports:
521 { $$.p1 = 0;
522 $$.p2 = 0;
523 }
524 | ',' { if (!(nat->in_flags & IPN_TCPUDP))
525 yyerror("must be TCP/UDP for ports");
526 }
527 portpair { $$.p1 = $3.p1;
528 $$.p2 = $3.p2;
529 }
530 ;
531
532 proxy: | IPNY_PROXY port portspec YY_STR '/' proto
533 { int pos;
534 pos = addname(&nat, $4);
535 nat->in_plabel = pos;
536 if (nat->in_dcmp == 0) {
537 nat->in_odport = $3;
538 } else if ($3 != nat->in_odport) {
539 yyerror("proxy port numbers not consistant");
540 }
541 nat->in_ndport = $3;
542 setnatproto($6);
543 free($4);
544 }
545 | IPNY_PROXY port YY_STR YY_STR '/' proto
546 { int pnum, pos;
547 pos = addname(&nat, $4);
548 nat->in_plabel = pos;
549 pnum = getportproto($3, $6);
550 if (pnum == -1)
551 yyerror("invalid port number");
552 nat->in_odport = ntohs(pnum);
553 nat->in_ndport = ntohs(pnum);
554 setnatproto($6);
555 free($3);
556 free($4);
557 }
558 | IPNY_PROXY port portspec YY_STR '/' proto IPNY_CONFIG YY_STR
559 { int pos;
560 pos = addname(&nat, $4);
561 nat->in_plabel = pos;
562 if (nat->in_dcmp == 0) {
563 nat->in_odport = $3;
564 } else if ($3 != nat->in_odport) {
565 yyerror("proxy port numbers not consistant");
566 }
567 nat->in_ndport = $3;
568 setnatproto($6);
569 nat->in_pconfig = addname(&nat, $8);
570 free($4);
571 free($8);
572 }
573 | IPNY_PROXY port YY_STR YY_STR '/' proto IPNY_CONFIG YY_STR
574 { int pnum, pos;
575 pos = addname(&nat, $4);
576 nat->in_plabel = pos;
577 pnum = getportproto($3, $6);
578 if (pnum == -1)
579 yyerror("invalid port number");
580 nat->in_odport = ntohs(pnum);
581 nat->in_ndport = ntohs(pnum);
582 setnatproto($6);
583 pos = addname(&nat, $8);
584 nat->in_pconfig = pos;
585 free($3);
586 free($4);
587 free($8);
588 }
589 ;
590 setproto:
591 | proto { if (nat->in_pr[0] != 0 ||
592 nat->in_pr[1] != 0 ||
593 nat->in_flags & IPN_TCPUDP)
594 yyerror("protocol set twice");
595 setnatproto($1);
596 }
597 | IPNY_TCPUDP { if (nat->in_pr[0] != 0 ||
598 nat->in_pr[1] != 0 ||
599 nat->in_flags & IPN_TCPUDP)
600 yyerror("protocol set twice");
601 nat->in_flags |= IPN_TCPUDP;
602 nat->in_pr[0] = 0;
603 nat->in_pr[1] = 0;
604 }
605 | IPNY_TCP '/' IPNY_UDP { if (nat->in_pr[0] != 0 ||
606 nat->in_pr[1] != 0 ||
607 nat->in_flags & IPN_TCPUDP)
608 yyerror("protocol set twice");
609 nat->in_flags |= IPN_TCPUDP;
610 nat->in_pr[0] = 0;
611 nat->in_pr[1] = 0;
612 }
613 ;
614
615 rhsaddr:
616 addr { $$ = $1;
617 yyexpectaddr = 0;
618 }
619 | hostname '-' { yyexpectaddr = 1; } hostname
620 { $$.t = FRI_RANGE;
621 if ($1.f != $4.f)
622 yyerror("8.address family "
623 "mismatch");
624 $$.f = $1.f;
625 $$.v = ftov($1.f);
626 $$.a = $1.a;
627 $$.m = $4.a;
628 nat->in_flags |= IPN_SIPRANGE;
629 yyexpectaddr = 0;
630 }
631 | IPNY_RANGE hostname '-' { yyexpectaddr = 1; } hostname
632 { $$.t = FRI_RANGE;
633 if ($2.f != $5.f)
634 yyerror("9.address family "
635 "mismatch");
636 $$.f = $2.f;
637 $$.v = ftov($2.f);
638 $$.a = $2.a;
639 $$.m = $5.a;
640 nat->in_flags |= IPN_SIPRANGE;
641 yyexpectaddr = 0;
642 }
643 ;
644
645 dip:
646 hostname ',' { yyexpectaddr = 1; } hostname
647 { nat->in_flags |= IPN_SPLIT;
648 if ($1.f != $4.f)
649 yyerror("10.address family "
650 "mismatch");
651 $$ = $1.f;
652 nat->in_ndstip6 = $1.a;
653 nat->in_ndstmsk6 = $4.a;
654 nat->in_ndstatype = FRI_SPLIT;
655 yyexpectaddr = 0;
656 }
657 | rhdaddr { int bits;
658 nat->in_ndstip6 = $1.a;
659 nat->in_ndstmsk6 = $1.m;
660 nat->in_ndst.na_atype = $1.t;
661 yyexpectaddr = 0;
662 if ($1.f == AF_INET)
663 bits = count4bits($1.m.in4.s_addr);
664 else
665 bits = count6bits($1.m.i6);
666 if (($1.f == AF_INET) && (bits != 0) &&
667 (bits != 32)) {
668 yyerror("dest ip bitmask not /32");
669 } else if (($1.f == AF_INET6) &&
670 (bits != 0) && (bits != 128)) {
671 yyerror("dest ip bitmask not /128");
672 }
673 $$ = $1.f;
674 }
675 ;
676
677 rhdaddr:
678 addr { $$ = $1;
679 yyexpectaddr = 0;
680 }
681 | hostname '-' hostname { bzero(&$$, sizeof($$));
682 $$.t = FRI_RANGE;
683 if ($1.f != 0 && $3.f != 0 &&
684 $1.f != $3.f)
685 yyerror("11.address family "
686 "mismatch");
687 $$.a = $1.a;
688 $$.m = $3.a;
689 nat->in_flags |= IPN_DIPRANGE;
690 yyexpectaddr = 0;
691 }
692 | IPNY_RANGE hostname '-' hostname
693 { bzero(&$$, sizeof($$));
694 $$.t = FRI_RANGE;
695 if ($2.f != 0 && $4.f != 0 &&
696 $2.f != $4.f)
697 yyerror("12.address family "
698 "mismatch");
699 $$.a = $2.a;
700 $$.m = $4.a;
701 nat->in_flags |= IPN_DIPRANGE;
702 yyexpectaddr = 0;
703 }
704 ;
705
706 erhdaddr:
707 rhdaddr { $$ = $1; }
708 | IPNY_DSTLIST '/' YY_NUMBER { $$.t = FRI_LOOKUP;
709 $$.u = IPLT_DSTLIST;
710 $$.s = 0;
711 $$.n = $3;
712 }
713 | IPNY_DSTLIST '/' YY_STR { $$.t = FRI_LOOKUP;
714 $$.u = IPLT_DSTLIST;
715 $$.s = 1;
716 $$.n = addname(&nat, $3);
717 }
718 ;
719
720 port: IPNY_PORT { suggest_port = 1; }
721 ;
722
723 portspec:
724 YY_NUMBER { if ($1 > 65535) /* Unsigned */
725 yyerror("invalid port number");
726 else
727 $$ = $1;
728 }
729 | YY_STR { if (getport(NULL, $1,
730 &($$), NULL) == -1)
731 yyerror("invalid port number");
732 $$ = ntohs($$);
733 }
734 ;
735
736 portpair:
737 portspec { $$.p1 = $1; $$.p2 = $1; }
738 | portspec '-' portspec { $$.p1 = $1; $$.p2 = $3; }
739 | portspec ':' portspec { $$.p1 = $1; $$.p2 = $3; }
740 ;
741
742 dport: | port portpair { nat->in_odport = $2.p1;
743 if ($2.p2 == 0)
744 nat->in_dtop = $2.p1;
745 else
746 nat->in_dtop = $2.p2;
747 }
748 ;
749
750 nport: | port portpair { nat->in_dpmin = $2.p1;
751 nat->in_dpnext = $2.p1;
752 nat->in_dpmax = $2.p2;
753 nat->in_ndport = $2.p1;
754 if (nat->in_dtop == 0)
755 nat->in_dtop = $2.p2;
756 }
757 | port '=' portspec { nat->in_dpmin = $3;
758 nat->in_dpnext = $3;
759 nat->in_ndport = $3;
760 if (nat->in_dtop == 0)
761 nat->in_dtop = nat->in_odport;
762 nat->in_flags |= IPN_FIXEDDPORT;
763 }
764 ;
765
766 ports: | IPNY_PORTS YY_NUMBER { nat->in_spmin = $2; }
767 | IPNY_PORTS IPNY_AUTO { nat->in_flags |= IPN_AUTOPORTMAP; }
768 ;
769
770 mapit: IPNY_MAP { nat->in_redir = NAT_MAP; }
771 | IPNY_BIMAP { nat->in_redir = NAT_BIMAP; }
772 ;
773
774 rdrit: IPNY_RDR { nat->in_redir = NAT_REDIRECT; }
775 ;
776
777 mapblockit:
778 IPNY_MAPBLOCK { nat->in_redir = NAT_MAPBLK; }
779 ;
780
781 mapfrom:
782 from sobject to dobject { if ($2 != 0 && $4 != 0 && $2 != $4)
783 yyerror("13.address family "
784 "mismatch");
785 $$ = $2;
786 }
787 | from sobject '!' to dobject
788 { if ($2 != 0 && $5 != 0 && $2 != $5)
789 yyerror("14.address family "
790 "mismatch");
791 nat->in_flags |= IPN_NOTDST;
792 $$ = $2;
793 }
794 | from sobject to '!' dobject
795 { if ($2 != 0 && $5 != 0 && $2 != $5)
796 yyerror("15.address family "
797 "mismatch");
798 nat->in_flags |= IPN_NOTDST;
799 $$ = $2;
800 }
801 ;
802
803 rdrfrom:
804 from sobject to dobject { if ($2 != 0 && $4 != 0 && $2 != $4)
805 yyerror("16.address family "
806 "mismatch");
807 $$ = $2;
808 }
809 | '!' from sobject to dobject
810 { if ($3 != 0 && $5 != 0 && $3 != $5)
811 yyerror("17.address family "
812 "mismatch");
813 nat->in_flags |= IPN_NOTSRC;
814 $$ = $3;
815 }
816 | from '!' sobject to dobject
817 { if ($3 != 0 && $5 != 0 && $3 != $5)
818 yyerror("18.address family "
819 "mismatch");
820 nat->in_flags |= IPN_NOTSRC;
821 $$ = $3;
822 }
823 ;
824
825 from: IPNY_FROM { nat->in_flags |= IPN_FILTER;
826 yyexpectaddr = 1;
827 }
828 ;
829
830 to: IPNY_TO { yyexpectaddr = 1; }
831 ;
832
833 ifnames:
834 ifname family { yyexpectaddr = 1; }
835 | ifname ',' otherifname family { yyexpectaddr = 1; }
836 ;
837
838 ifname: YY_STR { setifname(&nat, 0, $1);
839 free($1);
840 }
841 ;
842
843 family: | IPNY_INET { nat->in_v[0] = 4; nat->in_v[1] = 4; }
844 | IPNY_INET6 { nat->in_v[0] = 6; nat->in_v[1] = 6; }
845 ;
846
847 otherifname:
848 YY_STR { setifname(&nat, 1, $1);
849 free($1);
850 }
851 ;
852
853 mapport:
854 IPNY_PORTMAP tcpudp portpair sequential
855 { nat->in_spmin = $3.p1;
856 nat->in_spmax = $3.p2;
857 }
858 | IPNY_PORTMAP portpair tcpudp sequential
859 { nat->in_spmin = $2.p1;
860 nat->in_spmax = $2.p2;
861 }
862 | IPNY_PORTMAP tcpudp IPNY_AUTO sequential
863 { nat->in_flags |= IPN_AUTOPORTMAP;
864 nat->in_spmin = 1024;
865 nat->in_spmax = 65535;
866 }
867 | IPNY_ICMPIDMAP YY_STR portpair sequential
868 { if (strcmp($2, "icmp") != 0 &&
869 strcmp($2, "ipv6-icmp") != 0) {
870 yyerror("icmpidmap not followed by icmp");
871 }
872 free($2);
873 if ($3.p1 < 0 || $3.p1 > 65535)
874 yyerror("invalid 1st ICMP Id number");
875 if ($3.p2 < 0 || $3.p2 > 65535)
876 yyerror("invalid 2nd ICMP Id number");
877 if (strcmp($2, "ipv6-icmp") == 0) {
878 nat->in_pr[0] = IPPROTO_ICMPV6;
879 nat->in_pr[1] = IPPROTO_ICMPV6;
880 } else {
881 nat->in_pr[0] = IPPROTO_ICMP;
882 nat->in_pr[1] = IPPROTO_ICMP;
883 }
884 nat->in_flags = IPN_ICMPQUERY;
885 nat->in_spmin = $3.p1;
886 nat->in_spmax = $3.p2;
887 }
888 ;
889
890 sobject:
891 saddr { $$ = $1; }
892 | saddr port portstuff { nat->in_osport = $3.p1;
893 nat->in_stop = $3.p2;
894 nat->in_scmp = $3.pc;
895 $$ = $1;
896 }
897 ;
898
899 saddr: addr { nat->in_osrcatype = $1.t;
900 bcopy(&$1.a,
901 &nat->in_osrc.na_addr[0],
902 sizeof($1.a));
903 bcopy(&$1.m,
904 &nat->in_osrc.na_addr[1],
905 sizeof($1.m));
906 $$ = $1.f;
907 }
908 ;
909
910 dobject:
911 daddr { $$ = $1; }
912 | daddr port portstuff { nat->in_odport = $3.p1;
913 nat->in_dtop = $3.p2;
914 nat->in_dcmp = $3.pc;
915 $$ = $1;
916 }
917 ;
918
919 daddr: addr { nat->in_odstatype = $1.t;
920 bcopy(&$1.a,
921 &nat->in_odst.na_addr[0],
922 sizeof($1.a));
923 bcopy(&$1.m,
924 &nat->in_odst.na_addr[1],
925 sizeof($1.m));
926 $$ = $1.f;
927 }
928 ;
929
930 addr: IPNY_ANY { yyexpectaddr = 0;
931 bzero(&$$, sizeof($$));
932 $$.t = FRI_NORMAL;
933 }
934 | hostname { bzero(&$$, sizeof($$));
935 $$.a = $1.a;
936 $$.t = FRI_NORMAL;
937 $$.v = ftov($1.f);
938 $$.f = $1.f;
939 if ($$.f == AF_INET) {
940 $$.m.in4.s_addr = 0xffffffff;
941 } else if ($$.f == AF_INET6) {
942 $$.m.i6[0] = 0xffffffff;
943 $$.m.i6[1] = 0xffffffff;
944 $$.m.i6[2] = 0xffffffff;
945 $$.m.i6[3] = 0xffffffff;
946 }
947 yyexpectaddr = 0;
948 }
949 | hostname slash YY_NUMBER
950 { bzero(&$$, sizeof($$));
951 $$.a = $1.a;
952 $$.f = $1.f;
953 $$.v = ftov($1.f);
954 $$.t = FRI_NORMAL;
955 ntomask($$.f, $3, (u_32_t *)&$$.m);
956 $$.a.i6[0] &= $$.m.i6[0];
957 $$.a.i6[1] &= $$.m.i6[1];
958 $$.a.i6[2] &= $$.m.i6[2];
959 $$.a.i6[3] &= $$.m.i6[3];
960 yyexpectaddr = 0;
961 }
962 | hostname slash ipaddr { bzero(&$$, sizeof($$));
963 if ($1.f != $3.f) {
964 yyerror("1.address family "
965 "mismatch");
966 }
967 $$.a = $1.a;
968 $$.m = $3.a;
969 $$.t = FRI_NORMAL;
970 $$.a.i6[0] &= $$.m.i6[0];
971 $$.a.i6[1] &= $$.m.i6[1];
972 $$.a.i6[2] &= $$.m.i6[2];
973 $$.a.i6[3] &= $$.m.i6[3];
974 $$.f = $1.f;
975 $$.v = ftov($1.f);
976 yyexpectaddr = 0;
977 }
978 | hostname slash hexnumber { bzero(&$$, sizeof($$));
979 $$.a = $1.a;
980 $$.m.in4.s_addr = htonl($3);
981 $$.t = FRI_NORMAL;
982 $$.a.in4.s_addr &= $$.m.in4.s_addr;
983 $$.f = $1.f;
984 $$.v = ftov($1.f);
985 if ($$.f == AF_INET6)
986 yyerror("incorrect inet6 mask");
987 }
988 | hostname mask ipaddr { bzero(&$$, sizeof($$));
989 if ($1.f != $3.f) {
990 yyerror("2.address family "
991 "mismatch");
992 }
993 $$.a = $1.a;
994 $$.m = $3.a;
995 $$.t = FRI_NORMAL;
996 $$.a.i6[0] &= $$.m.i6[0];
997 $$.a.i6[1] &= $$.m.i6[1];
998 $$.a.i6[2] &= $$.m.i6[2];
999 $$.a.i6[3] &= $$.m.i6[3];
1000 $$.f = $1.f;
1001 $$.v = ftov($1.f);
1002 yyexpectaddr = 0;
1003 }
1004 | hostname mask hexnumber { bzero(&$$, sizeof($$));
1005 $$.a = $1.a;
1006 $$.m.in4.s_addr = htonl($3);
1007 $$.t = FRI_NORMAL;
1008 $$.a.in4.s_addr &= $$.m.in4.s_addr;
1009 $$.f = AF_INET;
1010 $$.v = 4;
1011 }
1012 | pool slash YY_NUMBER { bzero(&$$, sizeof($$));
1013 $$.a.iplookupnum = $3;
1014 $$.a.iplookuptype = IPLT_POOL;
1015 $$.a.iplookupsubtype = 0;
1016 $$.t = FRI_LOOKUP;
1017 }
1018 | pool slash YY_STR { bzero(&$$, sizeof($$));
1019 $$.a.iplookupname = addname(&nat,$3);
1020 $$.a.iplookuptype = IPLT_POOL;
1021 $$.a.iplookupsubtype = 1;
1022 $$.t = FRI_LOOKUP;
1023 }
1024 | hash slash YY_NUMBER { bzero(&$$, sizeof($$));
1025 $$.a.iplookupnum = $3;
1026 $$.a.iplookuptype = IPLT_HASH;
1027 $$.a.iplookupsubtype = 0;
1028 $$.t = FRI_LOOKUP;
1029 }
1030 | hash slash YY_STR { bzero(&$$, sizeof($$));
1031 $$.a.iplookupname = addname(&nat,$3);
1032 $$.a.iplookuptype = IPLT_HASH;
1033 $$.a.iplookupsubtype = 1;
1034 $$.t = FRI_LOOKUP;
1035 }
1036 ;
1037
1038 slash: '/' { yyexpectaddr = 0; }
1039 ;
1040
1041 mask: IPNY_MASK { yyexpectaddr = 0; }
1042 ;
1043
1044 pool: IPNY_POOL { if (!(nat->in_flags & IPN_FILTER)) {
1045 yyerror("Can only use pool with from/to rules\n");
1046 }
1047 yyexpectaddr = 0;
1048 yyresetdict();
1049 }
1050 ;
1051
1052 hash: IPNY_HASH { if (!(nat->in_flags & IPN_FILTER)) {
1053 yyerror("Can only use hash with from/to rules\n");
1054 }
1055 yyexpectaddr = 0;
1056 yyresetdict();
1057 }
1058 ;
1059
1060 portstuff:
1061 compare portspec { $$.pc = $1; $$.p1 = $2; $$.p2 = 0; }
1062 | portspec range portspec { $$.pc = $2; $$.p1 = $1; $$.p2 = $3; }
1063 ;
1064
1065 mapoptions:
1066 rr frag age mssclamp nattag setproto purge
1067 ;
1068
1069 rdroptions:
1070 rr frag age sticky mssclamp rdrproxy nattag purge
1071 ;
1072
1073 nattag: | IPNY_TAG YY_STR { strncpy(nat->in_tag.ipt_tag, $2,
1074 sizeof(nat->in_tag.ipt_tag));
1075 }
1076 rr: | IPNY_ROUNDROBIN { nat->in_flags |= IPN_ROUNDR; }
1077 ;
1078
1079 frag: | IPNY_FRAG { nat->in_flags |= IPN_FRAG; }
1080 ;
1081
1082 age: | IPNY_AGE YY_NUMBER { nat->in_age[0] = $2;
1083 nat->in_age[1] = $2; }
1084 | IPNY_AGE YY_NUMBER '/' YY_NUMBER { nat->in_age[0] = $2;
1085 nat->in_age[1] = $4; }
1086 ;
1087
1088 sticky: | IPNY_STICKY { if (!(nat->in_flags & IPN_ROUNDR) &&
1089 !(nat->in_flags & IPN_SPLIT)) {
1090 FPRINTF(stderr,
1091 "'sticky' for use with round-robin/IP splitting only\n");
1092 } else
1093 nat->in_flags |= IPN_STICKY;
1094 }
1095 ;
1096
1097 mssclamp:
1098 | IPNY_MSSCLAMP YY_NUMBER { nat->in_mssclamp = $2; }
1099 ;
1100
1101 tcpudp: IPNY_TCP { setnatproto(IPPROTO_TCP); }
1102 | IPNY_UDP { setnatproto(IPPROTO_UDP); }
1103 | IPNY_TCPUDP { nat->in_flags |= IPN_TCPUDP;
1104 nat->in_pr[0] = 0;
1105 nat->in_pr[1] = 0;
1106 }
1107 | IPNY_TCP '/' IPNY_UDP { nat->in_flags |= IPN_TCPUDP;
1108 nat->in_pr[0] = 0;
1109 nat->in_pr[1] = 0;
1110 }
1111 ;
1112
1113 sequential:
1114 | IPNY_SEQUENTIAL { nat->in_flags |= IPN_SEQUENTIAL; }
1115 ;
1116
1117 purge:
1118 | IPNY_PURGE { nat->in_flags |= IPN_PURGE; }
1119 ;
1120
1121 rdrproxy:
1122 IPNY_PROXY YY_STR
1123 { int pos;
1124 pos = addname(&nat, $2);
1125 nat->in_plabel = pos;
1126 nat->in_odport = nat->in_dpnext;
1127 nat->in_dtop = nat->in_odport;
1128 free($2);
1129 }
1130 | proxy { if (nat->in_plabel != -1) {
1131 nat->in_ndport = nat->in_odport;
1132 nat->in_dpmin = nat->in_odport;
1133 nat->in_dpmax = nat->in_dpmin;
1134 nat->in_dtop = nat->in_dpmin;
1135 nat->in_dpnext = nat->in_dpmin;
1136 }
1137 }
1138 ;
1139
1140 newopts:
1141 | IPNY_PURGE { nat->in_flags |= IPN_PURGE; }
1142 ;
1143
1144 proto: YY_NUMBER { $$ = $1;
1145 if ($$ != IPPROTO_TCP &&
1146 $$ != IPPROTO_UDP)
1147 suggest_port = 0;
1148 }
1149 | IPNY_TCP { $$ = IPPROTO_TCP; }
1150 | IPNY_UDP { $$ = IPPROTO_UDP; }
1151 | YY_STR { $$ = getproto($1);
1152 free($1);
1153 if ($$ == -1)
1154 yyerror("unknown protocol");
1155 if ($$ != IPPROTO_TCP &&
1156 $$ != IPPROTO_UDP)
1157 suggest_port = 0;
1158 }
1159 ;
1160
1161 hexnumber:
1162 YY_HEX { $$ = $1; }
1163 ;
1164
1165 hostname:
1166 YY_STR { i6addr_t addr;
1167 int family;
1168
1169 #ifdef USE_INET6
1170 if (nat->in_v[0] == 6)
1171 family = AF_INET6;
1172 else
1173 #endif
1174 family = AF_INET;
1175 memset(&($$), 0, sizeof($$));
1176 memset(&addr, 0, sizeof(addr));
1177 $$.f = family;
1178 if (gethost(family, $1,
1179 &addr) == 0) {
1180 $$.a = addr;
1181 } else {
1182 FPRINTF(stderr,
1183 "Unknown host '%s'\n",
1184 $1);
1185 }
1186 free($1);
1187 }
1188 | YY_NUMBER { memset(&($$), 0, sizeof($$));
1189 $$.a.in4.s_addr = htonl($1);
1190 if ($$.a.in4.s_addr != 0)
1191 $$.f = AF_INET;
1192 }
1193 | ipv4 { $$ = $1; }
1194 | YY_IPV6 { memset(&($$), 0, sizeof($$));
1195 $$.a = $1;
1196 $$.f = AF_INET6;
1197 }
1198 | YY_NUMBER YY_IPV6 { memset(&($$), 0, sizeof($$));
1199 $$.a = $2;
1200 $$.f = AF_INET6;
1201 }
1202 ;
1203
1204 compare:
1205 '=' { $$ = FR_EQUAL; }
1206 | YY_CMP_EQ { $$ = FR_EQUAL; }
1207 | YY_CMP_NE { $$ = FR_NEQUAL; }
1208 | YY_CMP_LT { $$ = FR_LESST; }
1209 | YY_CMP_LE { $$ = FR_LESSTE; }
1210 | YY_CMP_GT { $$ = FR_GREATERT; }
1211 | YY_CMP_GE { $$ = FR_GREATERTE; }
1212
1213 range:
1214 YY_RANGE_OUT { $$ = FR_OUTRANGE; }
1215 | YY_RANGE_IN { $$ = FR_INRANGE; }
1216 | ':' { $$ = FR_INCRANGE; }
1217 ;
1218
1219 ipaddr: ipv4 { $$ = $1; }
1220 | YY_IPV6 { $$.a = $1;
1221 $$.f = AF_INET6;
1222 }
1223 ;
1224
1225 ipv4: YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER
1226 { if ($1 > 255 || $3 > 255 || $5 > 255 || $7 > 255) {
1227 yyerror("Invalid octet string for IP address");
1228 return 0;
1229 }
1230 bzero((char *)&$$, sizeof($$));
1231 $$.a.in4.s_addr = ($1 << 24) | ($3 << 16) | ($5 << 8) | $7;
1232 $$.a.in4.s_addr = htonl($$.a.in4.s_addr);
1233 $$.f = AF_INET;
1234 }
1235 ;
1236
1237 %%
1238
1239
1240 static wordtab_t proxies[] = {
1241 { "dns", IPNY_DNS }
1242 };
1243
1244 static wordtab_t dnswords[] = {
1245 { "allow", IPNY_ALLOW },
1246 { "block", IPNY_DENY },
1247 { "deny", IPNY_DENY },
1248 { "drop", IPNY_DENY },
1249 { "pass", IPNY_ALLOW },
1250
1251 };
1252
1253 static wordtab_t yywords[] = {
1254 { "age", IPNY_AGE },
1255 { "any", IPNY_ANY },
1256 { "auto", IPNY_AUTO },
1257 { "bimap", IPNY_BIMAP },
1258 { "config", IPNY_CONFIG },
1259 { "divert", IPNY_DIVERT },
1260 { "dst", IPNY_DST },
1261 { "dstlist", IPNY_DSTLIST },
1262 { "frag", IPNY_FRAG },
1263 { "from", IPNY_FROM },
1264 { "hash", IPNY_HASH },
1265 { "icmpidmap", IPNY_ICMPIDMAP },
1266 { "in", IPNY_IN },
1267 { "inet", IPNY_INET },
1268 { "inet6", IPNY_INET6 },
1269 { "mask", IPNY_MASK },
1270 { "map", IPNY_MAP },
1271 { "map-block", IPNY_MAPBLOCK },
1272 { "mssclamp", IPNY_MSSCLAMP },
1273 { "netmask", IPNY_MASK },
1274 { "no", IPNY_NO },
1275 { "on", IPNY_ON },
1276 { "out", IPNY_OUT },
1277 { "pool", IPNY_POOL },
1278 { "port", IPNY_PORT },
1279 { "portmap", IPNY_PORTMAP },
1280 { "ports", IPNY_PORTS },
1281 { "proto", IPNY_PROTO },
1282 { "proxy", IPNY_PROXY },
1283 { "purge", IPNY_PURGE },
1284 { "range", IPNY_RANGE },
1285 { "rewrite", IPNY_REWRITE },
1286 { "rdr", IPNY_RDR },
1287 { "round-robin",IPNY_ROUNDROBIN },
1288 { "sequential", IPNY_SEQUENTIAL },
1289 { "src", IPNY_SRC },
1290 { "sticky", IPNY_STICKY },
1291 { "tag", IPNY_TAG },
1292 { "tcp", IPNY_TCP },
1293 { "tcpudp", IPNY_TCPUDP },
1294 { "to", IPNY_TO },
1295 { "udp", IPNY_UDP },
1296 { "-", '-' },
1297 { "->", IPNY_TLATE },
1298 { "eq", YY_CMP_EQ },
1299 { "ne", YY_CMP_NE },
1300 { "lt", YY_CMP_LT },
1301 { "gt", YY_CMP_GT },
1302 { "le", YY_CMP_LE },
1303 { "ge", YY_CMP_GE },
1304 { NULL, 0 }
1305 };
1306
1307
1308 int
ipnat_parsefile(fd,addfunc,ioctlfunc,filename)1309 ipnat_parsefile(fd, addfunc, ioctlfunc, filename)
1310 int fd;
1311 addfunc_t addfunc;
1312 ioctlfunc_t ioctlfunc;
1313 char *filename;
1314 {
1315 FILE *fp = NULL;
1316 int rval;
1317 char *s;
1318
1319 yylineNum = 1;
1320
1321 (void) yysettab(yywords);
1322
1323 s = getenv("YYDEBUG");
1324 if (s)
1325 yydebug = atoi(s);
1326 else
1327 yydebug = 0;
1328
1329 if (strcmp(filename, "-")) {
1330 fp = fopen(filename, "r");
1331 if (!fp) {
1332 FPRINTF(stderr, "fopen(%s) failed: %s\n", filename,
1333 STRERROR(errno));
1334 return -1;
1335 }
1336 } else
1337 fp = stdin;
1338
1339 while ((rval = ipnat_parsesome(fd, addfunc, ioctlfunc, fp)) == 0)
1340 ;
1341 if (fp != NULL)
1342 fclose(fp);
1343 if (rval == -1)
1344 rval = 0;
1345 else if (rval != 0)
1346 rval = 1;
1347 return rval;
1348 }
1349
1350
1351 int
ipnat_parsesome(fd,addfunc,ioctlfunc,fp)1352 ipnat_parsesome(fd, addfunc, ioctlfunc, fp)
1353 int fd;
1354 addfunc_t addfunc;
1355 ioctlfunc_t ioctlfunc;
1356 FILE *fp;
1357 {
1358 char *s;
1359 int i;
1360
1361 natfd = fd;
1362 parser_error = 0;
1363 nataddfunc = addfunc;
1364 natioctlfunc = ioctlfunc;
1365
1366 if (feof(fp))
1367 return -1;
1368 i = fgetc(fp);
1369 if (i == EOF)
1370 return -1;
1371 if (ungetc(i, fp) == EOF)
1372 return -1;
1373 if (feof(fp))
1374 return -1;
1375 s = getenv("YYDEBUG");
1376 if (s)
1377 yydebug = atoi(s);
1378 else
1379 yydebug = 0;
1380
1381 yyin = fp;
1382 yyparse();
1383 return parser_error;
1384 }
1385
1386
1387 static void
newnatrule()1388 newnatrule()
1389 {
1390 ipnat_t *n;
1391
1392 n = calloc(1, sizeof(*n));
1393 if (n == NULL)
1394 return;
1395
1396 if (nat == NULL) {
1397 nattop = nat = n;
1398 n->in_pnext = &nattop;
1399 } else {
1400 nat->in_next = n;
1401 n->in_pnext = &nat->in_next;
1402 nat = n;
1403 }
1404
1405 n->in_flineno = yylineNum;
1406 n->in_ifnames[0] = -1;
1407 n->in_ifnames[1] = -1;
1408 n->in_plabel = -1;
1409 n->in_pconfig = -1;
1410 n->in_size = sizeof(*n);
1411
1412 suggest_port = 0;
1413 }
1414
1415
1416 static void
setnatproto(p)1417 setnatproto(p)
1418 int p;
1419 {
1420 nat->in_pr[0] = p;
1421 nat->in_pr[1] = p;
1422
1423 switch (p)
1424 {
1425 case IPPROTO_TCP :
1426 nat->in_flags |= IPN_TCP;
1427 nat->in_flags &= ~IPN_UDP;
1428 break;
1429 case IPPROTO_UDP :
1430 nat->in_flags |= IPN_UDP;
1431 nat->in_flags &= ~IPN_TCP;
1432 break;
1433 #ifdef USE_INET6
1434 case IPPROTO_ICMPV6 :
1435 #endif
1436 case IPPROTO_ICMP :
1437 nat->in_flags &= ~IPN_TCPUDP;
1438 if (!(nat->in_flags & IPN_ICMPQUERY) &&
1439 !(nat->in_redir & NAT_DIVERTUDP)) {
1440 nat->in_dcmp = 0;
1441 nat->in_scmp = 0;
1442 nat->in_dpmin = 0;
1443 nat->in_dpmax = 0;
1444 nat->in_dpnext = 0;
1445 nat->in_spmin = 0;
1446 nat->in_spmax = 0;
1447 nat->in_spnext = 0;
1448 }
1449 break;
1450 default :
1451 if ((nat->in_redir & NAT_MAPBLK) == 0) {
1452 nat->in_flags &= ~IPN_TCPUDP;
1453 nat->in_dcmp = 0;
1454 nat->in_scmp = 0;
1455 nat->in_dpmin = 0;
1456 nat->in_dpmax = 0;
1457 nat->in_dpnext = 0;
1458 nat->in_spmin = 0;
1459 nat->in_spmax = 0;
1460 nat->in_spnext = 0;
1461 }
1462 break;
1463 }
1464
1465 if ((nat->in_flags & (IPN_TCP|IPN_UDP)) == 0) {
1466 nat->in_stop = 0;
1467 nat->in_dtop = 0;
1468 nat->in_osport = 0;
1469 nat->in_odport = 0;
1470 nat->in_stop = 0;
1471 nat->in_osport = 0;
1472 nat->in_dtop = 0;
1473 nat->in_odport = 0;
1474 }
1475 if ((nat->in_flags & (IPN_TCPUDP|IPN_FIXEDDPORT)) == IPN_FIXEDDPORT)
1476 nat->in_flags &= ~IPN_FIXEDDPORT;
1477 }
1478
1479
1480 int
ipnat_addrule(fd,ioctlfunc,ptr)1481 ipnat_addrule(fd, ioctlfunc, ptr)
1482 int fd;
1483 ioctlfunc_t ioctlfunc;
1484 void *ptr;
1485 {
1486 ioctlcmd_t add, del;
1487 ipfobj_t obj;
1488 ipnat_t *ipn;
1489
1490 ipn = ptr;
1491 bzero((char *)&obj, sizeof(obj));
1492 obj.ipfo_rev = IPFILTER_VERSION;
1493 obj.ipfo_size = ipn->in_size;
1494 obj.ipfo_type = IPFOBJ_IPNAT;
1495 obj.ipfo_ptr = ptr;
1496
1497 if ((opts & OPT_DONOTHING) != 0)
1498 fd = -1;
1499
1500 if (opts & OPT_ZERORULEST) {
1501 add = SIOCZRLST;
1502 del = 0;
1503 } else if (opts & OPT_PURGE) {
1504 add = 0;
1505 del = SIOCPURGENAT;
1506 } else {
1507 add = SIOCADNAT;
1508 del = SIOCRMNAT;
1509 }
1510
1511 if ((opts & OPT_VERBOSE) != 0)
1512 printnat(ipn, opts);
1513
1514 if (opts & OPT_DEBUG)
1515 binprint(ipn, ipn->in_size);
1516
1517 if ((opts & OPT_ZERORULEST) != 0) {
1518 if ((*ioctlfunc)(fd, add, (void *)&obj) == -1) {
1519 if ((opts & OPT_DONOTHING) == 0) {
1520 char msg[80];
1521
1522 sprintf(msg, "%d:ioctl(zero nat rule)",
1523 ipn->in_flineno);
1524 return ipf_perror_fd(fd, ioctlfunc, msg);
1525 }
1526 } else {
1527 PRINTF("hits %lu ", ipn->in_hits);
1528 #ifdef USE_QUAD_T
1529 PRINTF("bytes %"PRIu64" ",
1530 ipn->in_bytes[0] + ipn->in_bytes[1]);
1531 #else
1532 PRINTF("bytes %lu ",
1533 ipn->in_bytes[0] + ipn->in_bytes[1]);
1534 #endif
1535 printnat(ipn, opts);
1536 }
1537 } else if ((opts & OPT_REMOVE) != 0) {
1538 if ((*ioctlfunc)(fd, del, (void *)&obj) == -1) {
1539 if ((opts & OPT_DONOTHING) == 0) {
1540 char msg[80];
1541
1542 sprintf(msg, "%d:ioctl(delete nat rule)",
1543 ipn->in_flineno);
1544 return ipf_perror_fd(fd, ioctlfunc, msg);
1545 }
1546 }
1547 } else {
1548 if ((*ioctlfunc)(fd, add, (void *)&obj) == -1) {
1549 if ((opts & OPT_DONOTHING) == 0) {
1550 char msg[80];
1551
1552 sprintf(msg, "%d:ioctl(add/insert nat rule)",
1553 ipn->in_flineno);
1554 if (errno == EEXIST) {
1555 sprintf(msg + strlen(msg), "(line %d)",
1556 ipn->in_flineno);
1557 }
1558 return ipf_perror_fd(fd, ioctlfunc, msg);
1559 }
1560 }
1561 }
1562 return 0;
1563 }
1564
1565
1566 static void
setmapifnames()1567 setmapifnames()
1568 {
1569 if (nat->in_ifnames[1] == -1)
1570 nat->in_ifnames[1] = nat->in_ifnames[0];
1571
1572 if ((suggest_port == 1) && (nat->in_flags & IPN_TCPUDP) == 0)
1573 nat->in_flags |= IPN_TCPUDP;
1574
1575 if ((nat->in_flags & IPN_TCPUDP) == 0)
1576 setnatproto(nat->in_pr[1]);
1577
1578 if (((nat->in_redir & NAT_MAPBLK) != 0) ||
1579 ((nat->in_flags & IPN_AUTOPORTMAP) != 0))
1580 nat_setgroupmap(nat);
1581 }
1582
1583
1584 static void
setrdrifnames()1585 setrdrifnames()
1586 {
1587 if ((suggest_port == 1) && (nat->in_flags & IPN_TCPUDP) == 0)
1588 nat->in_flags |= IPN_TCPUDP;
1589
1590 if ((nat->in_pr[0] == 0) && ((nat->in_flags & IPN_TCPUDP) == 0) &&
1591 (nat->in_dpmin != 0 || nat->in_dpmax != 0 || nat->in_dpnext != 0))
1592 setnatproto(IPPROTO_TCP);
1593
1594 if (nat->in_ifnames[1] == -1)
1595 nat->in_ifnames[1] = nat->in_ifnames[0];
1596 }
1597
1598
1599 static void
proxy_setconfig(proxy)1600 proxy_setconfig(proxy)
1601 int proxy;
1602 {
1603 if (proxy == IPNY_DNS) {
1604 yysetfixeddict(dnswords);
1605 }
1606 }
1607
1608
1609 static void
proxy_unsetconfig()1610 proxy_unsetconfig()
1611 {
1612 yyresetdict();
1613 }
1614
1615
1616 static namelist_t *
proxy_dns_add_pass(prefix,name)1617 proxy_dns_add_pass(prefix, name)
1618 char *prefix, *name;
1619 {
1620 namelist_t *n;
1621
1622 n = calloc(1, sizeof(*n));
1623 if (n != NULL) {
1624 if (prefix == NULL || *prefix == '\0') {
1625 n->na_name = strdup(name);
1626 } else {
1627 n->na_name = malloc(strlen(name) + strlen(prefix) + 1);
1628 strcpy(n->na_name, prefix);
1629 strcat(n->na_name, name);
1630 }
1631 }
1632 return n;
1633 }
1634
1635
1636 static namelist_t *
proxy_dns_add_block(prefix,name)1637 proxy_dns_add_block(prefix, name)
1638 char *prefix, *name;
1639 {
1640 namelist_t *n;
1641
1642 n = calloc(1, sizeof(*n));
1643 if (n != NULL) {
1644 if (prefix == NULL || *prefix == '\0') {
1645 n->na_name = strdup(name);
1646 } else {
1647 n->na_name = malloc(strlen(name) + strlen(prefix) + 1);
1648 strcpy(n->na_name, prefix);
1649 strcat(n->na_name, name);
1650 }
1651 n->na_value = 1;
1652 }
1653 return n;
1654 }
1655
1656
1657 static void
proxy_addconfig(proxy,proto,conf,list)1658 proxy_addconfig(proxy, proto, conf, list)
1659 char *proxy, *conf;
1660 int proto;
1661 namelist_t *list;
1662 {
1663 proxyrule_t *pr;
1664
1665 pr = calloc(1, sizeof(*pr));
1666 if (pr != NULL) {
1667 pr->pr_proto = proto;
1668 pr->pr_proxy = proxy;
1669 pr->pr_conf = conf;
1670 pr->pr_names = list;
1671 pr->pr_next = prules;
1672 prules = pr;
1673 }
1674 }
1675
1676
1677 static void
proxy_loadrules(fd,ioctlfunc,rules)1678 proxy_loadrules(fd, ioctlfunc, rules)
1679 int fd;
1680 ioctlfunc_t ioctlfunc;
1681 proxyrule_t *rules;
1682 {
1683 proxyrule_t *pr;
1684
1685 while ((pr = rules) != NULL) {
1686 proxy_loadconfig(fd, ioctlfunc, pr->pr_proxy, pr->pr_proto,
1687 pr->pr_conf, pr->pr_names);
1688 rules = pr->pr_next;
1689 free(pr->pr_conf);
1690 free(pr);
1691 }
1692 }
1693
1694
1695 static void
proxy_loadconfig(fd,ioctlfunc,proxy,proto,conf,list)1696 proxy_loadconfig(fd, ioctlfunc, proxy, proto, conf, list)
1697 int fd;
1698 ioctlfunc_t ioctlfunc;
1699 char *proxy, *conf;
1700 int proto;
1701 namelist_t *list;
1702 {
1703 namelist_t *na;
1704 ipfobj_t obj;
1705 ap_ctl_t pcmd;
1706
1707 obj.ipfo_rev = IPFILTER_VERSION;
1708 obj.ipfo_type = IPFOBJ_PROXYCTL;
1709 obj.ipfo_size = sizeof(pcmd);
1710 obj.ipfo_ptr = &pcmd;
1711
1712 while ((na = list) != NULL) {
1713 if ((opts & OPT_REMOVE) != 0)
1714 pcmd.apc_cmd = APC_CMD_DEL;
1715 else
1716 pcmd.apc_cmd = APC_CMD_ADD;
1717 pcmd.apc_dsize = strlen(na->na_name) + 1;
1718 pcmd.apc_data = na->na_name;
1719 pcmd.apc_arg = na->na_value;
1720 pcmd.apc_p = proto;
1721
1722 strncpy(pcmd.apc_label, proxy, APR_LABELLEN);
1723 pcmd.apc_label[APR_LABELLEN - 1] = '\0';
1724
1725 strncpy(pcmd.apc_config, conf, APR_LABELLEN);
1726 pcmd.apc_config[APR_LABELLEN - 1] = '\0';
1727
1728 if ((*ioctlfunc)(fd, SIOCPROXY, (void *)&obj) == -1) {
1729 if ((opts & OPT_DONOTHING) == 0) {
1730 char msg[80];
1731
1732 sprintf(msg, "%d:ioctl(add/remove proxy rule)",
1733 yylineNum);
1734 ipf_perror_fd(fd, ioctlfunc, msg);
1735 return;
1736 }
1737 }
1738
1739 list = na->na_next;
1740 free(na->na_name);
1741 free(na);
1742 }
1743 }
1744
1745
1746 static void
setifname(np,idx,name)1747 setifname(np, idx, name)
1748 ipnat_t **np;
1749 int idx;
1750 char *name;
1751 {
1752 int pos;
1753
1754 pos = addname(np, name);
1755 if (pos == -1)
1756 return;
1757 (*np)->in_ifnames[idx] = pos;
1758 }
1759
1760
1761 static int
addname(np,name)1762 addname(np, name)
1763 ipnat_t **np;
1764 char *name;
1765 {
1766 ipnat_t *n;
1767 int nlen;
1768 int pos;
1769
1770 nlen = strlen(name) + 1;
1771 n = calloc(1, (*np)->in_size + nlen);
1772 memcpy(n, *np, (*np)->in_size);
1773 free(*np);
1774 if (*np == nattop)
1775 nattop = n;
1776 *np = n;
1777 if (n == NULL)
1778 return -1;
1779 if (n->in_pnext != NULL)
1780 *n->in_pnext = n;
1781 n->in_size += nlen;
1782 pos = n->in_namelen;
1783 n->in_namelen += nlen;
1784 strcpy(n->in_names + pos, name);
1785 n->in_names[n->in_namelen] = '\0';
1786 return pos;
1787 }
1788