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