]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - contrib/ipfilter/tools/ipnat_y.y
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / contrib / ipfilter / tools / ipnat_y.y
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 #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
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
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
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
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
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
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
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
1600 proxy_setconfig(proxy)
1601         int proxy;
1602 {
1603         if (proxy == IPNY_DNS) {
1604                 yysetfixeddict(dnswords);
1605         }
1606 }
1607
1608
1609 static void
1610 proxy_unsetconfig()
1611 {
1612         yyresetdict();
1613 }
1614
1615
1616 static namelist_t *
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 *
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
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
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
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
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
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 = realloc(*np, (*np)->in_size + nlen);
1772         if (*np == nattop)
1773                 nattop = n;
1774         *np = n;
1775         if (n == NULL)
1776                 return -1;
1777         if (n->in_pnext != NULL)
1778                 *n->in_pnext = n;
1779         n->in_size += nlen;
1780         pos = n->in_namelen;
1781         n->in_namelen += nlen;
1782         strcpy(n->in_names + pos, name);
1783         n->in_names[n->in_namelen] = '\0';
1784         return pos;
1785 }