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