1 /*        $NetBSD: ipf_y.y,v 1.3 2014/06/29 08:53:08 darrenr Exp $    */
2 
3 /*
4  * Copyright (C) 2012 by Darren Reed.
5  *
6  * See the IPFILTER.LICENCE file for details on licencing.
7  */
8 %{
9 #include "ipf.h"
10 #include <sys/ioctl.h>
11 #include <syslog.h>
12 #ifdef IPFILTER_BPF
13 # include "pcap-bpf.h"
14 # define _NET_BPF_H_
15 # include <pcap.h>
16 #endif
17 #include "netinet/ip_pool.h"
18 #include "netinet/ip_htable.h"
19 #include "netinet/ipl.h"
20 #include "ipf_l.h"
21 
22 #define   YYDEBUG   1
23 #define   DOALL(x)  for (fr = frc; fr != NULL; fr = fr->fr_next) { x }
24 #define   DOREM(x)  for (; fr != NULL; fr = fr->fr_next) { x }
25 
26 extern    void      yyerror __P((char *));
27 extern    int       yyparse __P((void));
28 extern    int       yylex __P((void));
29 extern    int       yydebug;
30 extern    FILE      *yyin;
31 extern    int       yylineNum;
32 
33 static    int       addname __P((frentry_t **, char *));
34 static    frentry_t *addrule __P((void));
35 static frentry_t *allocfr __P((void));
36 static    void      build_dstaddr_af __P((frentry_t *, void *));
37 static    void      build_srcaddr_af __P((frentry_t *, void *));
38 static    void      dobpf __P((int, char *));
39 static    void      doipfexpr __P((char *));
40 static    void      do_tuneint __P((char *, int));
41 static    void      do_tunestr __P((char *, char *));
42 static    void      fillgroup __P((frentry_t *));
43 static    int       lookuphost __P((char *, i6addr_t *));
44 static    u_int     makehash __P((struct alist_s *));
45 static    int       makepool __P((struct alist_s *));
46 static    struct    alist_s   *newalist __P((struct alist_s *));
47 static    void      newrule __P((void));
48 static    void      resetaddr __P((void));
49 static    void      setgroup __P((frentry_t **, char *));
50 static    void      setgrhead __P((frentry_t **, char *));
51 static    void      seticmphead __P((frentry_t **, char *));
52 static    void      setifname __P((frentry_t **, int, char *));
53 static    void      setipftype __P((void));
54 static    void      setsyslog __P((void));
55 static    void      unsetsyslog __P((void));
56 
57 frentry_t *fr = NULL, *frc = NULL, *frtop = NULL, *frold = NULL;
58 
59 static    int                 ifpflag = 0;
60 static    int                 nowith = 0;
61 static    int                 dynamic = -1;
62 static    int                 pooled = 0;
63 static    int                 hashed = 0;
64 static    int                 nrules = 0;
65 static    int                 newlist = 0;
66 static    int                 added = 0;
67 static    int                 ipffd = -1;
68 static    int                 *yycont = NULL;
69 static    ioctlfunc_t         ipfioctls[IPL_LOGSIZE];
70 static    addfunc_t ipfaddfunc = NULL;
71 
72 %}
73 %union    {
74           char      *str;
75           u_32_t    num;
76           frentry_t fr;
77           frtuc_t   *frt;
78           struct    alist_s   *alist;
79           u_short   port;
80           struct    in_addr   ip4;
81           struct    {
82                     u_short   p1;
83                     u_short   p2;
84                     int       pc;
85           } pc;
86           struct ipp_s {
87                     int                 type;
88                     int                 ifpos;
89                     int                 f;
90                     int                 v;
91                     int                 lif;
92                     union     i6addr    a;
93                     union     i6addr    m;
94                     char                *name;
95           } ipp;
96           struct    {
97                     i6addr_t  adr;
98                     int                 f;
99           } adr;
100           i6addr_t  ip6;
101           struct    {
102                     char      *if1;
103                     char      *if2;
104           } ifs;
105           char      gname[FR_GROUPLEN];
106 };
107 
108 %type     <port>    portnum
109 %type     <num>     facility priority icmpcode seclevel secname icmptype
110 %type     <num>     opt compare range opttype flagset optlist ipv6hdrlist ipv6hdr
111 %type     <num>     portc porteq ipmask maskopts
112 %type     <ip4>     ipv4 ipv4_16 ipv4_24
113 %type     <adr>     hostname
114 %type     <ipp>     addr ipaddr
115 %type     <str>     servicename name interfacename groupname
116 %type     <pc>      portrange portcomp
117 %type     <alist>   addrlist poollist
118 %type     <ifs>     onname
119 
120 %token    <num>     YY_NUMBER YY_HEX
121 %token    <str>     YY_STR
122 %token              YY_COMMENT
123 %token              YY_CMP_EQ YY_CMP_NE YY_CMP_LE YY_CMP_GE YY_CMP_LT YY_CMP_GT
124 %token              YY_RANGE_OUT YY_RANGE_IN
125 %token    <ip6>     YY_IPV6
126 
127 %token    IPFY_SET
128 %token    IPFY_PASS IPFY_BLOCK IPFY_COUNT IPFY_CALL IPFY_NOMATCH
129 %token    IPFY_RETICMP IPFY_RETRST IPFY_RETICMPASDST
130 %token    IPFY_IN IPFY_OUT
131 %token    IPFY_QUICK IPFY_ON IPFY_OUTVIA IPFY_INVIA
132 %token    IPFY_DUPTO IPFY_TO IPFY_FROUTE IPFY_REPLY_TO IPFY_ROUTETO
133 %token    IPFY_TOS IPFY_TTL IPFY_PROTO IPFY_INET IPFY_INET6
134 %token    IPFY_HEAD IPFY_GROUP
135 %token    IPFY_AUTH IPFY_PREAUTH
136 %token    IPFY_LOG IPFY_BODY IPFY_FIRST IPFY_LEVEL IPFY_ORBLOCK IPFY_L5AS
137 %token    IPFY_LOGTAG IPFY_MATCHTAG IPFY_SETTAG IPFY_SKIP IPFY_DECAPS
138 %token    IPFY_FROM IPFY_ALL IPFY_ANY IPFY_BPFV4 IPFY_BPFV6 IPFY_POOL IPFY_HASH
139 %token    IPFY_IPFEXPR IPFY_PPS IPFY_FAMILY IPFY_DSTLIST
140 %token    IPFY_ESP IPFY_AH
141 %token    IPFY_WITH IPFY_AND IPFY_NOT IPFY_NO IPFY_OPT
142 %token    IPFY_TCPUDP IPFY_TCP IPFY_UDP
143 %token    IPFY_FLAGS IPFY_MULTICAST
144 %token    IPFY_MASK IPFY_BROADCAST IPFY_NETWORK IPFY_NETMASKED IPFY_PEER
145 %token    IPFY_RPC IPFY_PORT
146 %token    IPFY_NOW IPFY_COMMENT IPFY_RULETTL
147 %token    IPFY_ICMP IPFY_ICMPTYPE IPFY_ICMPCODE
148 %token    IPFY_IPOPTS IPFY_SHORT IPFY_NAT IPFY_BADSRC IPFY_LOWTTL IPFY_FRAG
149 %token    IPFY_MBCAST IPFY_BAD IPFY_BADNAT IPFY_OOW IPFY_NEWISN IPFY_NOICMPERR
150 %token    IPFY_KEEP IPFY_STATE IPFY_FRAGS IPFY_LIMIT IPFY_STRICT IPFY_AGE
151 %token    IPFY_SYNC IPFY_FRAGBODY IPFY_ICMPHEAD IPFY_NOLOG IPFY_LOOSE
152 %token    IPFY_MAX_SRCS IPFY_MAX_PER_SRC
153 %token    IPFY_IPOPT_NOP IPFY_IPOPT_RR IPFY_IPOPT_ZSU IPFY_IPOPT_MTUP
154 %token    IPFY_IPOPT_MTUR IPFY_IPOPT_ENCODE IPFY_IPOPT_TS IPFY_IPOPT_TR
155 %token    IPFY_IPOPT_SEC IPFY_IPOPT_LSRR IPFY_IPOPT_ESEC IPFY_IPOPT_CIPSO
156 %token    IPFY_IPOPT_SATID IPFY_IPOPT_SSRR IPFY_IPOPT_ADDEXT IPFY_IPOPT_VISA
157 %token    IPFY_IPOPT_IMITD IPFY_IPOPT_EIP IPFY_IPOPT_FINN IPFY_IPOPT_DPS
158 %token    IPFY_IPOPT_SDB IPFY_IPOPT_NSAPA IPFY_IPOPT_RTRALRT IPFY_IPOPT_UMP
159 %token    IPFY_SECCLASS IPFY_SEC_UNC IPFY_SEC_CONF IPFY_SEC_RSV1 IPFY_SEC_RSV2
160 %token    IPFY_SEC_RSV4 IPFY_SEC_SEC IPFY_SEC_TS IPFY_SEC_RSV3 IPFY_DOI
161 
162 %token    IPFY_V6HDRS IPFY_IPV6OPT IPFY_IPV6OPT_DSTOPTS IPFY_IPV6OPT_HOPOPTS
163 %token    IPFY_IPV6OPT_IPV6 IPFY_IPV6OPT_NONE IPFY_IPV6OPT_ROUTING IPFY_V6HDR
164 %token    IPFY_IPV6OPT_MOBILITY IPFY_IPV6OPT_ESP IPFY_IPV6OPT_FRAG
165 
166 %token    IPFY_ICMPT_UNR IPFY_ICMPT_ECHO IPFY_ICMPT_ECHOR IPFY_ICMPT_SQUENCH
167 %token    IPFY_ICMPT_REDIR IPFY_ICMPT_TIMEX IPFY_ICMPT_PARAMP IPFY_ICMPT_TIMEST
168 %token    IPFY_ICMPT_TIMESTREP IPFY_ICMPT_INFOREQ IPFY_ICMPT_INFOREP
169 %token    IPFY_ICMPT_MASKREQ IPFY_ICMPT_MASKREP IPFY_ICMPT_ROUTERAD
170 %token    IPFY_ICMPT_ROUTERSOL
171 
172 %token    IPFY_ICMPC_NETUNR IPFY_ICMPC_HSTUNR IPFY_ICMPC_PROUNR IPFY_ICMPC_PORUNR
173 %token    IPFY_ICMPC_NEEDF IPFY_ICMPC_SRCFAIL IPFY_ICMPC_NETUNK IPFY_ICMPC_HSTUNK
174 %token    IPFY_ICMPC_ISOLATE IPFY_ICMPC_NETPRO IPFY_ICMPC_HSTPRO
175 %token    IPFY_ICMPC_NETTOS IPFY_ICMPC_HSTTOS IPFY_ICMPC_FLTPRO IPFY_ICMPC_HSTPRE
176 %token    IPFY_ICMPC_CUTPRE
177 
178 %token    IPFY_FAC_KERN IPFY_FAC_USER IPFY_FAC_MAIL IPFY_FAC_DAEMON IPFY_FAC_AUTH
179 %token    IPFY_FAC_SYSLOG IPFY_FAC_LPR IPFY_FAC_NEWS IPFY_FAC_UUCP IPFY_FAC_CRON
180 %token    IPFY_FAC_LOCAL0 IPFY_FAC_LOCAL1 IPFY_FAC_LOCAL2 IPFY_FAC_LOCAL3
181 %token    IPFY_FAC_LOCAL4 IPFY_FAC_LOCAL5 IPFY_FAC_LOCAL6 IPFY_FAC_LOCAL7
182 %token    IPFY_FAC_SECURITY IPFY_FAC_FTP IPFY_FAC_AUTHPRIV IPFY_FAC_AUDIT
183 %token    IPFY_FAC_LFMT IPFY_FAC_CONSOLE
184 
185 %token    IPFY_PRI_EMERG IPFY_PRI_ALERT IPFY_PRI_CRIT IPFY_PRI_ERR IPFY_PRI_WARN
186 %token    IPFY_PRI_NOTICE IPFY_PRI_INFO IPFY_PRI_DEBUG
187 %%
188 file:     settings rules
189           | rules
190           ;
191 
192 settings:
193           YY_COMMENT
194           | setting
195           | settings setting
196           ;
197 
198 rules:    line
199           | assign
200           | rules line
201           | rules assign
202           ;
203 
204 setting:
205           IPFY_SET YY_STR YY_NUMBER ';' { do_tuneint($2, $3); }
206           | IPFY_SET YY_STR YY_HEX ';'  { do_tuneint($2, $3); }
207           | IPFY_SET YY_STR YY_STR ';'  { do_tunestr($2, $3); }
208           ;
209 
210 line:     rule                { while ((fr = frtop) != NULL) {
211                                         frtop = fr->fr_next;
212                                         fr->fr_next = NULL;
213                                         if ((fr->fr_type == FR_T_IPF) &&
214                                             (fr->fr_ip.fi_v == 0))
215                                                   fr->fr_mip.fi_v = 0;
216                                         /* XXX validate ? */
217                                         (*ipfaddfunc)(ipffd, ipfioctls[IPL_LOGIPF], fr);
218                                         fr->fr_next = frold;
219                                         frold = fr;
220                                 }
221                                 resetlexer();
222                               }
223           | YY_COMMENT
224           ;
225 
226 xx:                                               { newrule(); }
227           ;
228 
229 assign:   YY_STR assigning YY_STR ';'   { set_variable($1, $3);
230                                                     resetlexer();
231                                                     free($1);
232                                                     free($3);
233                                                     yyvarnext = 0;
234                                                   }
235           ;
236 
237 assigning:
238           '='                                     { yyvarnext = 1; }
239           ;
240 
241 rule:     inrule eol
242           | outrule eol
243           ;
244 
245 eol:      | ';'
246           ;
247 
248 inrule:
249           rulehead markin inopts rulemain ruletail intag ruletail2
250           ;
251 
252 outrule:
253           rulehead markout outopts rulemain ruletail outtag ruletail2
254           ;
255 
256 rulehead:
257           xx collection action
258           | xx insert collection action
259           ;
260 
261 markin:   IPFY_IN                                 { fr->fr_flags |= FR_INQUE; }
262           ;
263 
264 markout:
265           IPFY_OUT                      { fr->fr_flags |= FR_OUTQUE; }
266           ;
267 
268 rulemain:
269           ipfrule
270           | bpfrule
271           | exprrule
272           ;
273 
274 ipfrule:
275           family tos ttl proto ip
276           ;
277 
278 family:   | IPFY_FAMILY IPFY_INET                 { if (use_inet6 == 1) {
279                                                             YYERROR;
280                                                     } else {
281                                                             frc->fr_family = AF_INET;
282                                                     }
283                                                   }
284           | IPFY_INET                             { if (use_inet6 == 1) {
285                                                             YYERROR;
286                                                     } else {
287                                                             frc->fr_family = AF_INET;
288                                                     }
289                                                   }
290           | IPFY_FAMILY IPFY_INET6      { if (use_inet6 == -1) {
291                                                             YYERROR;
292                                                     } else {
293                                                             frc->fr_family = AF_INET6;
294                                                     }
295                                                   }
296           | IPFY_INET6                            { if (use_inet6 == -1) {
297                                                             YYERROR;
298                                                     } else {
299                                                             frc->fr_family = AF_INET6;
300                                                     }
301                                                   }
302           ;
303 
304 bpfrule:
305           IPFY_BPFV4 '{' YY_STR '}'     { dobpf(4, $3); free($3); }
306           | IPFY_BPFV6 '{' YY_STR '}'   { dobpf(6, $3); free($3); }
307           ;
308 
309 exprrule:
310           IPFY_IPFEXPR '{' YY_STR '}'   { doipfexpr($3); }
311           ;
312 
313 ruletail:
314           with keep head group
315           ;
316 
317 ruletail2:
318           pps age new rulettl comment
319           ;
320 
321 intag:    settagin matchtagin
322           ;
323 
324 outtag:   settagout matchtagout
325           ;
326 
327 insert:
328           '@' YY_NUMBER                           { fr->fr_hits = (U_QUAD_T)$2 + 1; }
329           ;
330 
331 collection:
332           | YY_NUMBER                             { fr->fr_collect = $1; }
333           ;
334 
335 action:   block
336           | IPFY_PASS                             { fr->fr_flags |= FR_PASS; }
337           | IPFY_NOMATCH                          { fr->fr_flags |= FR_NOMATCH; }
338           | log
339           | IPFY_COUNT                            { fr->fr_flags |= FR_ACCOUNT; }
340           | decaps                      { fr->fr_flags |= FR_DECAPSULATE; }
341           | auth
342           | IPFY_SKIP YY_NUMBER                   { fr->fr_flags |= FR_SKIP;
343                                                     fr->fr_arg = $2; }
344           | IPFY_CALL func
345           | IPFY_CALL IPFY_NOW func     { fr->fr_flags |= FR_CALLNOW; }
346           ;
347 
348 block:    blocked
349           | blocked blockreturn
350           ;
351 
352 blocked:
353           IPFY_BLOCK                              { fr->fr_flags = FR_BLOCK; }
354           ;
355 blockreturn:
356           IPFY_RETICMP                            { fr->fr_flags |= FR_RETICMP; }
357           | IPFY_RETICMP returncode     { fr->fr_flags |= FR_RETICMP; }
358           | IPFY_RETICMPASDST           { fr->fr_flags |= FR_FAKEICMP; }
359           | IPFY_RETICMPASDST returncode          { fr->fr_flags |= FR_FAKEICMP; }
360           | IPFY_RETRST                           { fr->fr_flags |= FR_RETRST; }
361           ;
362 
363 decaps:   IPFY_DECAPS
364           | IPFY_DECAPS IPFY_L5AS '(' YY_STR ')'
365                                                   { fr->fr_icode = atoi($4); }
366           ;
367 
368 log:      IPFY_LOG                      { fr->fr_flags |= FR_LOG; }
369           | IPFY_LOG logoptions                   { fr->fr_flags |= FR_LOG; }
370           ;
371 
372 auth:     IPFY_AUTH                     { fr->fr_flags |= FR_AUTH; }
373           | IPFY_AUTH blockreturn                 { fr->fr_flags |= FR_AUTH;}
374           | IPFY_PREAUTH                          { fr->fr_flags |= FR_PREAUTH; }
375           ;
376 
377 func:     YY_STR '/' YY_NUMBER
378                               { fr->fr_func = nametokva($1, ipfioctls[IPL_LOGIPF]);
379                                 fr->fr_arg = $3;
380                                 free($1);
381                               }
382           ;
383 
384 inopts:
385           | inopts inopt
386           ;
387 
388 inopt:
389           logopt
390           | quick
391           | on
392           | dup
393           | froute
394           | proute
395           | replyto
396           ;
397 
398 outopts:
399           | outopts outopt
400           ;
401 
402 outopt:
403           logopt
404           | quick
405           | on
406           | dup
407           | proute
408           | froute
409           | replyto
410           ;
411 
412 tos:      | settos YY_NUMBER  { DOALL(fr->fr_tos = $2; fr->fr_mtos = 0xff;) }
413           | settos YY_HEX     { DOALL(fr->fr_tos = $2; fr->fr_mtos = 0xff;) }
414           | settos lstart toslist lend
415           ;
416 
417 settos:   IPFY_TOS                      { setipftype(); }
418           ;
419 
420 toslist:
421           YY_NUMBER { DOALL(fr->fr_tos = $1; fr->fr_mtos = 0xff;) }
422           | YY_HEX  { DOREM(fr->fr_tos = $1; fr->fr_mtos = 0xff;) }
423           | toslist lmore YY_NUMBER
424                               { DOREM(fr->fr_tos = $3; fr->fr_mtos = 0xff;) }
425           | toslist lmore YY_HEX
426                               { DOREM(fr->fr_tos = $3; fr->fr_mtos = 0xff;) }
427           ;
428 
429 ttl:      | setttl YY_NUMBER
430                               { DOALL(fr->fr_ttl = $2; fr->fr_mttl = 0xff;) }
431           | setttl lstart ttllist lend
432           ;
433 
434 lstart:   '{'                                     { newlist = 1; fr = frc; added = 0; }
435           ;
436 
437 lend:     '}'                                     { nrules += added; }
438           ;
439 
440 lmore:    lanother                      { if (newlist == 1) {
441                                                             newlist = 0;
442                                                     }
443                                                     fr = addrule();
444                                                     if (yycont != NULL)
445                                                             *yycont = 1;
446                                                   }
447           ;
448 
449 lanother:
450           | ','
451           ;
452 
453 setttl:   IPFY_TTL                      { setipftype(); }
454           ;
455 
456 ttllist:
457           YY_NUMBER { DOREM(fr->fr_ttl = $1; fr->fr_mttl = 0xff;) }
458           | ttllist lmore YY_NUMBER
459                               { DOREM(fr->fr_ttl = $3; fr->fr_mttl = 0xff;) }
460           ;
461 
462 proto:    | protox protocol             { yyresetdict(); }
463           ;
464 
465 protox:   IPFY_PROTO                              { setipftype();
466                                                     fr = frc;
467                                                     yysetdict(NULL); }
468           ;
469 
470 ip:       srcdst flags icmp
471           ;
472 
473 group:    | IPFY_GROUP groupname                  { DOALL(setgroup(&fr, $2); \
474                                                             fillgroup(fr););
475                                                     free($2);
476                                                   }
477           ;
478 
479 head:     | IPFY_HEAD groupname                   { DOALL(setgrhead(&fr, $2););
480                                                     free($2);
481                                                   }
482           ;
483 
484 groupname:
485           YY_STR                                  { $$ = $1;
486                                                     if (strlen($$) >= FR_GROUPLEN)
487                                                             $$[FR_GROUPLEN - 1] = '\0';
488                                                   }
489           | YY_NUMBER                             { $$ = malloc(16);
490                                                     sprintf($$, "%d", $1);
491                                                   }
492           ;
493 
494 settagin:
495           | IPFY_SETTAG '(' taginlist ')'
496           ;
497 
498 taginlist:
499           taginspec
500           | taginlist ',' taginspec
501           ;
502 
503 taginspec:
504           logtag
505           ;
506 
507 nattag:   IPFY_NAT '=' YY_STR           { DOALL(strncpy(fr->fr_nattag.ipt_tag,\
508                                                             $3, IPFTAG_LEN););
509                                                     free($3); }
510           | IPFY_NAT '=' YY_NUMBER      { DOALL(sprintf(fr->fr_nattag.ipt_tag,\
511                                                             "%d", $3 & 0xffffffff);) }
512           ;
513 
514 logtag:   IPFY_LOG '=' YY_NUMBER                  { DOALL(fr->fr_logtag = $3;) }
515           ;
516 
517 settagout:
518           | IPFY_SETTAG '(' tagoutlist ')'
519           ;
520 
521 tagoutlist:
522           tagoutspec
523           | tagoutlist ',' tagoutspec
524           ;
525 
526 tagoutspec:
527           logtag
528           | nattag
529           ;
530 
531 matchtagin:
532           | IPFY_MATCHTAG '(' tagoutlist ')'
533           ;
534 
535 matchtagout:
536           | IPFY_MATCHTAG '(' taginlist ')'
537           ;
538 
539 pps:      | IPFY_PPS YY_NUMBER                    { DOALL(fr->fr_pps = $2;) }
540           ;
541 
542 new:      | savegroup file restoregroup
543           ;
544 
545 rulettl:
546           | IPFY_RULETTL YY_NUMBER      { DOALL(fr->fr_die = $2;) }
547           ;
548 
549 comment:
550           | IPFY_COMMENT YY_STR                   { DOALL(fr->fr_comment = addname(&fr, \
551                                                             $2);) }
552           ;
553 
554 savegroup:
555           '{'
556           ;
557 
558 restoregroup:
559           '}'
560           ;
561 
562 logopt:   log
563           ;
564 
565 quick:    IPFY_QUICK                                        { fr->fr_flags |= FR_QUICK; }
566           ;
567 
568 on:       IPFY_ON onname                                    { setifname(&fr, 0, $2.if1);
569                                                               free($2.if1);
570                                                               if ($2.if2 != NULL) {
571                                                                       setifname(&fr, 1,
572                                                                                   $2.if2);
573                                                                       free($2.if2);
574                                                               }
575                                                             }
576           | IPFY_ON lstart onlist lend
577           | IPFY_ON onname IPFY_INVIA vianame     { setifname(&fr, 0, $2.if1);
578                                                               free($2.if1);
579                                                               if ($2.if2 != NULL) {
580                                                                       setifname(&fr, 1,
581                                                                                   $2.if2);
582                                                                       free($2.if2);
583                                                               }
584                                                             }
585           | IPFY_ON onname IPFY_OUTVIA vianame    { setifname(&fr, 0, $2.if1);
586                                                               free($2.if1);
587                                                               if ($2.if2 != NULL) {
588                                                                       setifname(&fr, 1,
589                                                                                   $2.if2);
590                                                                       free($2.if2);
591                                                               }
592                                                             }
593           ;
594 
595 onlist:   onname                        { DOREM(setifname(&fr, 0, $1.if1);         \
596                                                   if ($1.if2 != NULL)              \
597                                                             setifname(&fr, 1, $1.if2); \
598                                                   )
599                                           free($1.if1);
600                                           if ($1.if2 != NULL)
601                                                   free($1.if2);
602                                         }
603           | onlist lmore onname         { DOREM(setifname(&fr, 0, $3.if1);         \
604                                                   if ($3.if2 != NULL)              \
605                                                             setifname(&fr, 1, $3.if2); \
606                                                   )
607                                           free($3.if1);
608                                           if ($3.if2 != NULL)
609                                                   free($3.if2);
610                                         }
611           ;
612 
613 onname:   interfacename                 { $$.if1 = $1;
614                                           $$.if2 = NULL;
615                                         }
616           | interfacename ',' interfacename
617                                         { $$.if1 = $1;
618                                           $$.if2 = $3;
619                                         }
620           ;
621 
622 vianame:
623           name                          { setifname(&fr, 2, $1);
624                                           free($1);
625                                         }
626           | name ',' name               { setifname(&fr, 2, $1);
627                                           free($1);
628                                           setifname(&fr, 3, $3);
629                                           free($3);
630                                         }
631           ;
632 
633 dup:      IPFY_DUPTO name
634           { int idx = addname(&fr, $2);
635             fr->fr_dif.fd_name = idx;
636             free($2);
637           }
638           | IPFY_DUPTO IPFY_DSTLIST '/' name
639           { int idx = addname(&fr, $4);
640             fr->fr_dif.fd_name = idx;
641             fr->fr_dif.fd_type = FRD_DSTLIST;
642             free($4);
643           }
644           | IPFY_DUPTO name duptoseparator hostname
645           { int idx = addname(&fr, $2);
646             fr->fr_dif.fd_name = idx;
647             fr->fr_dif.fd_ptr = (void *)-1;
648             fr->fr_dif.fd_ip6 = $4.adr;
649             if (fr->fr_family == AF_UNSPEC && $4.f != AF_UNSPEC)
650                     fr->fr_family = $4.f;
651             yyexpectaddr = 0;
652             free($2);
653           }
654           ;
655 
656 duptoseparator:
657           ':'       { yyexpectaddr = 1; yycont = &yyexpectaddr; resetaddr(); }
658           ;
659 
660 froute:   IPFY_FROUTE                             { fr->fr_flags |= FR_FASTROUTE; }
661           ;
662 
663 proute:   routeto name
664           { int idx = addname(&fr, $2);
665             fr->fr_tif.fd_name = idx;
666             free($2);
667           }
668           | routeto IPFY_DSTLIST '/' name
669           { int idx = addname(&fr, $4);
670             fr->fr_tif.fd_name = idx;
671             fr->fr_tif.fd_type = FRD_DSTLIST;
672             free($4);
673           }
674           | routeto name duptoseparator hostname
675           { int idx = addname(&fr, $2);
676             fr->fr_tif.fd_name = idx;
677             fr->fr_tif.fd_ptr = (void *)-1;
678             fr->fr_tif.fd_ip6 = $4.adr;
679             if (fr->fr_family == AF_UNSPEC && $4.f != AF_UNSPEC)
680                     fr->fr_family = $4.f;
681             yyexpectaddr = 0;
682             free($2);
683           }
684           ;
685 
686 routeto:
687           IPFY_TO
688           | IPFY_ROUTETO
689           ;
690 
691 replyto:
692           IPFY_REPLY_TO name
693           { int idx = addname(&fr, $2);
694             fr->fr_rif.fd_name = idx;
695             free($2);
696           }
697           | IPFY_REPLY_TO IPFY_DSTLIST '/' name
698           { fr->fr_rif.fd_name = addname(&fr, $4);
699             fr->fr_rif.fd_type = FRD_DSTLIST;
700             free($4);
701           }
702           | IPFY_REPLY_TO name duptoseparator hostname
703           { int idx = addname(&fr, $2);
704             fr->fr_rif.fd_name = idx;
705             fr->fr_rif.fd_ptr = (void *)-1;
706             fr->fr_rif.fd_ip6 = $4.adr;
707             if (fr->fr_family == AF_UNSPEC && $4.f != AF_UNSPEC)
708                     fr->fr_family = $4.f;
709             free($2);
710           }
711           ;
712 
713 logoptions:
714           logoption
715           | logoptions logoption
716           ;
717 
718 logoption:
719           IPFY_BODY                     { fr->fr_flags |= FR_LOGBODY; }
720           | IPFY_FIRST                            { fr->fr_flags |= FR_LOGFIRST; }
721           | IPFY_ORBLOCK                          { fr->fr_flags |= FR_LOGORBLOCK; }
722           | level loglevel              { unsetsyslog(); }
723           ;
724 
725 returncode:
726           starticmpcode icmpcode ')'    { fr->fr_icode = $2; yyresetdict(); }
727           ;
728 
729 starticmpcode:
730           '('                                     { yysetdict(icmpcodewords); }
731           ;
732 
733 srcdst:   | IPFY_ALL
734           | fromto
735           ;
736 
737 protocol:
738           YY_NUMBER           { DOALL(fr->fr_proto = $1; \
739                                                   fr->fr_mproto = 0xff;)
740                                         }
741           | YY_STR            { if (!strcmp($1, "tcp-udp")) {
742                                                   DOALL(fr->fr_flx |= FI_TCPUDP; \
743                                                         fr->fr_mflx |= FI_TCPUDP;)
744                                           } else {
745                                                   int p = getproto($1);
746                                                   if (p == -1)
747                                                             yyerror("protocol unknown");
748                                                   DOALL(fr->fr_proto = p; \
749                                                             fr->fr_mproto = 0xff;)
750                                           }
751                                           free($1);
752                                         }
753           | YY_STR nextstring YY_STR
754                                         { if (!strcmp($1, "tcp") &&
755                                               !strcmp($3, "udp")) {
756                                                   DOREM(fr->fr_flx |= FI_TCPUDP; \
757                                                         fr->fr_mflx |= FI_TCPUDP;)
758                                           } else {
759                                                   YYERROR;
760                                           }
761                                           free($1);
762                                           free($3);
763                                         }
764           ;
765 
766 nextstring:
767           '/'                           { yysetdict(NULL); }
768           ;
769 
770 fromto:   from srcobject to dstobject   { yyexpectaddr = 0; yycont = NULL; }
771           | to dstobject                          { yyexpectaddr = 0; yycont = NULL; }
772           | from srcobject              { yyexpectaddr = 0; yycont = NULL; }
773           ;
774 
775 from:     IPFY_FROM                     { setipftype();
776                                                     if (fr == NULL)
777                                                             fr = frc;
778                                                     yyexpectaddr = 1;
779                                                     if (yydebug)
780                                                             printf("set yyexpectaddr\n");
781                                                     yycont = &yyexpectaddr;
782                                                     yysetdict(addrwords);
783                                                     resetaddr(); }
784           ;
785 
786 to:       IPFY_TO                                 { if (fr == NULL)
787                                                             fr = frc;
788                                                     yyexpectaddr = 1;
789                                                     if (yydebug)
790                                                             printf("set yyexpectaddr\n");
791                                                     yycont = &yyexpectaddr;
792                                                     yysetdict(addrwords);
793                                                     resetaddr();
794                                                   }
795           ;
796 
797 with:     | andwith withlist
798           ;
799 
800 andwith:
801           IPFY_WITH                     { nowith = 0; setipftype(); }
802           | IPFY_AND                              { nowith = 0; setipftype(); }
803           ;
804 
805 flags:    | startflags flagset
806                     { DOALL(fr->fr_tcpf = $2; fr->fr_tcpfm = FR_TCPFMAX;) }
807           | startflags flagset '/' flagset
808                     { DOALL(fr->fr_tcpf = $2; fr->fr_tcpfm = $4;) }
809           | startflags '/' flagset
810                     { DOALL(fr->fr_tcpf = 0; fr->fr_tcpfm = $3;) }
811           | startflags YY_NUMBER
812                     { DOALL(fr->fr_tcpf = $2; fr->fr_tcpfm = FR_TCPFMAX;) }
813           | startflags '/' YY_NUMBER
814                     { DOALL(fr->fr_tcpf = 0; fr->fr_tcpfm = $3;) }
815           | startflags YY_NUMBER '/' YY_NUMBER
816                     { DOALL(fr->fr_tcpf = $2; fr->fr_tcpfm = $4;) }
817           | startflags flagset '/' YY_NUMBER
818                     { DOALL(fr->fr_tcpf = $2; fr->fr_tcpfm = $4;) }
819           | startflags YY_NUMBER '/' flagset
820                     { DOALL(fr->fr_tcpf = $2; fr->fr_tcpfm = $4;) }
821           ;
822 
823 startflags:
824           IPFY_FLAGS          { if (frc->fr_type != FR_T_IPF)
825                                         yyerror("flags with non-ipf type rule");
826                                 if (frc->fr_proto != IPPROTO_TCP)
827                                         yyerror("flags with non-TCP rule");
828                               }
829           ;
830 
831 flagset:
832           YY_STR                                  { $$ = tcpflags($1); free($1); }
833           | YY_HEX                      { $$ = $1; }
834           ;
835 
836 srcobject:
837           { yyresetdict(); } fromport
838           | srcaddr srcport
839           | '!' srcaddr srcport
840                     { DOALL(fr->fr_flags |= FR_NOTSRCIP;) }
841           ;
842 
843 srcaddr:
844           addr      { build_srcaddr_af(fr, &$1); }
845           | lstart srcaddrlist lend
846           ;
847 
848 srcaddrlist:
849           addr      { build_srcaddr_af(fr, &$1); }
850           | srcaddrlist lmore addr
851                     { build_srcaddr_af(fr, &$3); }
852           ;
853 
854 srcport:
855           | portcomp
856                     { DOALL(fr->fr_scmp = $1.pc; fr->fr_sport = $1.p1;) }
857           | portrange
858                     { DOALL(fr->fr_scmp = $1.pc; fr->fr_sport = $1.p1; \
859                               fr->fr_stop = $1.p2;) }
860           | porteq lstart srcportlist lend
861                     { yyresetdict(); }
862           ;
863 
864 fromport:
865           portcomp
866                     { DOALL(fr->fr_scmp = $1.pc; fr->fr_sport = $1.p1;) }
867           | portrange
868                     { DOALL(fr->fr_scmp = $1.pc; fr->fr_sport = $1.p1; \
869                               fr->fr_stop = $1.p2;) }
870           | porteq lstart srcportlist lend
871                     { yyresetdict(); }
872           ;
873 
874 srcportlist:
875           portnum             { DOREM(fr->fr_scmp = FR_EQUAL; fr->fr_sport = $1;) }
876           | portnum ':' portnum
877                               { DOREM(fr->fr_scmp = FR_INCRANGE; fr->fr_sport = $1; \
878                                         fr->fr_stop = $3;) }
879           | portnum YY_RANGE_IN portnum
880                               { DOREM(fr->fr_scmp = FR_INRANGE; fr->fr_sport = $1; \
881                                         fr->fr_stop = $3;) }
882           | srcportlist lmore portnum
883                               { DOREM(fr->fr_scmp = FR_EQUAL; fr->fr_sport = $3;) }
884           | srcportlist lmore portnum ':' portnum
885                               { DOREM(fr->fr_scmp = FR_INCRANGE; fr->fr_sport = $3; \
886                                         fr->fr_stop = $5;) }
887           | srcportlist lmore portnum YY_RANGE_IN portnum
888                               { DOREM(fr->fr_scmp = FR_INRANGE; fr->fr_sport = $3; \
889                                         fr->fr_stop = $5;) }
890           ;
891 
892 dstobject:
893           { yyresetdict(); } toport
894           | dstaddr dstport
895           | '!' dstaddr dstport
896                               { DOALL(fr->fr_flags |= FR_NOTDSTIP;) }
897           ;
898 
899 dstaddr:
900           addr      { if (($1.f != AF_UNSPEC) && (frc->fr_family != AF_UNSPEC) &&
901                           ($1.f != frc->fr_family))
902                               yyerror("1.src/dst address family mismatch");
903                       build_dstaddr_af(fr, &$1);
904                     }
905           | lstart dstaddrlist lend
906           ;
907 
908 dstaddrlist:
909           addr      { if (($1.f != AF_UNSPEC) && (frc->fr_family != AF_UNSPEC) &&
910                           ($1.f != frc->fr_family))
911                               yyerror("2.src/dst address family mismatch");
912                       build_dstaddr_af(fr, &$1);
913                     }
914           | dstaddrlist lmore addr
915                     { if (($3.f != AF_UNSPEC) && (frc->fr_family != AF_UNSPEC) &&
916                           ($3.f != frc->fr_family))
917                               yyerror("3.src/dst address family mismatch");
918                       build_dstaddr_af(fr, &$3);
919                     }
920           ;
921 
922 
923 dstport:
924           | portcomp
925                     { DOALL(fr->fr_dcmp = $1.pc; fr->fr_dport = $1.p1;) }
926           | portrange
927                     { DOALL(fr->fr_dcmp = $1.pc; fr->fr_dport = $1.p1; \
928                               fr->fr_dtop = $1.p2;) }
929           | porteq lstart dstportlist lend
930                     { yyresetdict(); }
931           ;
932 
933 toport:
934           portcomp
935                     { DOALL(fr->fr_dcmp = $1.pc; fr->fr_dport = $1.p1;) }
936           | portrange
937                     { DOALL(fr->fr_dcmp = $1.pc; fr->fr_dport = $1.p1; \
938                               fr->fr_dtop = $1.p2;) }
939           | porteq lstart dstportlist lend
940                     { yyresetdict(); }
941           ;
942 
943 dstportlist:
944           portnum             { DOREM(fr->fr_dcmp = FR_EQUAL; fr->fr_dport = $1;) }
945           | portnum ':' portnum
946                               { DOREM(fr->fr_dcmp = FR_INCRANGE; fr->fr_dport = $1; \
947                                         fr->fr_dtop = $3;) }
948           | portnum YY_RANGE_IN portnum
949                               { DOREM(fr->fr_dcmp = FR_INRANGE; fr->fr_dport = $1; \
950                                         fr->fr_dtop = $3;) }
951           | dstportlist lmore portnum
952                               { DOREM(fr->fr_dcmp = FR_EQUAL; fr->fr_dport = $3;) }
953           | dstportlist lmore portnum ':' portnum
954                               { DOREM(fr->fr_dcmp = FR_INCRANGE; fr->fr_dport = $3; \
955                                         fr->fr_dtop = $5;) }
956           | dstportlist lmore portnum YY_RANGE_IN portnum
957                               { DOREM(fr->fr_dcmp = FR_INRANGE; fr->fr_dport = $3; \
958                                         fr->fr_dtop = $5;) }
959           ;
960 
961 addr:     pool '/' YY_NUMBER            { pooled = 1;
962                                                     yyexpectaddr = 0;
963                                                     $$.type = FRI_LOOKUP;
964                                                     $$.v = 0;
965                                                     $$.ifpos = -1;
966                                                     $$.f = AF_UNSPEC;
967                                                     $$.a.iplookuptype = IPLT_POOL;
968                                                     $$.a.iplookupsubtype = 0;
969                                                     $$.a.iplookupnum = $3; }
970           | pool '/' YY_STR             { pooled = 1;
971                                                     $$.ifpos = -1;
972                                                     $$.f = AF_UNSPEC;
973                                                     $$.type = FRI_LOOKUP;
974                                                     $$.a.iplookuptype = IPLT_POOL;
975                                                     $$.a.iplookupsubtype = 1;
976                                                     $$.a.iplookupname = addname(&fr, $3);
977                                                   }
978           | pool '=' '('                          { yyexpectaddr = 1;
979                                                     pooled = 1;
980                                                   }
981                               poollist ')'        { yyexpectaddr = 0;
982                                                     $$.v = 0;
983                                                     $$.ifpos = -1;
984                                                     $$.f = AF_UNSPEC;
985                                                     $$.type = FRI_LOOKUP;
986                                                     $$.a.iplookuptype = IPLT_POOL;
987                                                     $$.a.iplookupsubtype = 0;
988                                                     $$.a.iplookupnum = makepool($5);
989                                                   }
990           | hash '/' YY_NUMBER                    { hashed = 1;
991                                                     yyexpectaddr = 0;
992                                                     $$.v = 0;
993                                                     $$.ifpos = -1;
994                                                     $$.f = AF_UNSPEC;
995                                                     $$.type = FRI_LOOKUP;
996                                                     $$.a.iplookuptype = IPLT_HASH;
997                                                     $$.a.iplookupsubtype = 0;
998                                                     $$.a.iplookupnum = $3;
999                                                   }
1000           | hash '/' YY_STR             { hashed = 1;
1001                                                     $$.type = FRI_LOOKUP;
1002                                                     $$.v = 0;
1003                                                     $$.ifpos = -1;
1004                                                     $$.f = AF_UNSPEC;
1005                                                     $$.a.iplookuptype = IPLT_HASH;
1006                                                     $$.a.iplookupsubtype = 1;
1007                                                     $$.a.iplookupname = addname(&fr, $3);
1008                                                   }
1009           | hash '=' '('                          { hashed = 1;
1010                                                     yyexpectaddr = 1;
1011                                                   }
1012                               addrlist ')'        { yyexpectaddr = 0;
1013                                                     $$.v = 0;
1014                                                     $$.ifpos = -1;
1015                                                     $$.f = AF_UNSPEC;
1016                                                     $$.type = FRI_LOOKUP;
1017                                                     $$.a.iplookuptype = IPLT_HASH;
1018                                                     $$.a.iplookupsubtype = 0;
1019                                                     $$.a.iplookupnum = makehash($5);
1020                                                   }
1021           | ipaddr                      { $$ = $1;
1022                                                     yyexpectaddr = 0; }
1023           ;
1024 
1025 ipaddr:   IPFY_ANY                      { memset(&($$), 0, sizeof($$));
1026                                                     $$.type = FRI_NORMAL;
1027                                                     $$.ifpos = -1;
1028                                                     yyexpectaddr = 0;
1029                                                   }
1030           | hostname                              { memset(&($$), 0, sizeof($$));
1031                                                     $$.a = $1.adr;
1032                                                     $$.f = $1.f;
1033                                                     if ($1.f == AF_INET6)
1034                                                               fill6bits(128, $$.m.i6);
1035                                                     else if ($1.f == AF_INET)
1036                                                               fill6bits(32, $$.m.i6);
1037                                                     $$.v = ftov($1.f);
1038                                                     $$.ifpos = dynamic;
1039                                                     $$.type = FRI_NORMAL;
1040                                                   }
1041           | hostname                              { yyresetdict(); }
1042                     maskspace           { yysetdict(maskwords);
1043                                                     yyexpectaddr = 2; }
1044                     ipmask                        { memset(&($$), 0, sizeof($$));
1045                                                     ntomask($1.f, $5, $$.m.i6);
1046                                                     $$.a = $1.adr;
1047                                                     $$.a.i6[0] &= $$.m.i6[0];
1048                                                     $$.a.i6[1] &= $$.m.i6[1];
1049                                                     $$.a.i6[2] &= $$.m.i6[2];
1050                                                     $$.a.i6[3] &= $$.m.i6[3];
1051                                                     $$.f = $1.f;
1052                                                     $$.v = ftov($1.f);
1053                                                     $$.type = ifpflag;
1054                                                     $$.ifpos = dynamic;
1055                                                     if (ifpflag != 0 && $$.v == 0) {
1056                                                             if (frc->fr_family == AF_INET6){
1057                                                                       $$.v = 6;
1058                                                                       $$.f = AF_INET6;
1059                                                             } else {
1060                                                                       $$.v = 4;
1061                                                                       $$.f = AF_INET;
1062                                                             }
1063                                                     }
1064                                                     yyresetdict();
1065                                                     yyexpectaddr = 0;
1066                                                   }
1067           | '(' YY_STR ')'              { memset(&($$), 0, sizeof($$));
1068                                                     $$.type = FRI_DYNAMIC;
1069                                                     ifpflag = FRI_DYNAMIC;
1070                                                     $$.ifpos = addname(&fr, $2);
1071                                                     $$.lif = 0;
1072                                                   }
1073           | '(' YY_STR ')' '/'
1074             { ifpflag = FRI_DYNAMIC; yysetdict(maskwords); }
1075             maskopts
1076                                                   { memset(&($$), 0, sizeof($$));
1077                                                     $$.type = ifpflag;
1078                                                     $$.ifpos = addname(&fr, $2);
1079                                                     $$.lif = 0;
1080                                                     if (frc->fr_family == AF_UNSPEC)
1081                                                             frc->fr_family = AF_INET;
1082                                                     if (ifpflag == FRI_DYNAMIC) {
1083                                                             ntomask(frc->fr_family,
1084                                                                       $6, $$.m.i6);
1085                                                     }
1086                                                     yyresetdict();
1087                                                     yyexpectaddr = 0;
1088                                                   }
1089           | '(' YY_STR ':' YY_NUMBER ')' '/'
1090             { ifpflag = FRI_DYNAMIC; yysetdict(maskwords); }
1091             maskopts
1092                                                   { memset(&($$), 0, sizeof($$));
1093                                                     $$.type = ifpflag;
1094                                                     $$.ifpos = addname(&fr, $2);
1095                                                     $$.lif = $4;
1096                                                     if (frc->fr_family == AF_UNSPEC)
1097                                                             frc->fr_family = AF_INET;
1098                                                     if (ifpflag == FRI_DYNAMIC) {
1099                                                             ntomask(frc->fr_family,
1100                                                                       $8, $$.m.i6);
1101                                                     }
1102                                                     yyresetdict();
1103                                                     yyexpectaddr = 0;
1104                                                   }
1105           ;
1106 
1107 maskspace:
1108           '/'
1109           | IPFY_MASK
1110           ;
1111 
1112 ipmask:   ipv4                                    { $$ = count4bits($1.s_addr); }
1113           | YY_HEX                      { $$ = count4bits(htonl($1)); }
1114           | YY_NUMBER                             { $$ = $1; }
1115           | YY_IPV6                     { $$ = count6bits($1.i6); }
1116           | maskopts                              { $$ = $1; }
1117           ;
1118 
1119 maskopts:
1120           IPFY_BROADCAST                          { if (ifpflag == FRI_DYNAMIC) {
1121                                                             ifpflag = FRI_BROADCAST;
1122                                                     } else {
1123                                                             YYERROR;
1124                                                     }
1125                                                     $$ = 0;
1126                                                   }
1127           | IPFY_NETWORK                          { if (ifpflag == FRI_DYNAMIC) {
1128                                                             ifpflag = FRI_NETWORK;
1129                                                     } else {
1130                                                             YYERROR;
1131                                                     }
1132                                                     $$ = 0;
1133                                                   }
1134           | IPFY_NETMASKED              { if (ifpflag == FRI_DYNAMIC) {
1135                                                             ifpflag = FRI_NETMASKED;
1136                                                     } else {
1137                                                             YYERROR;
1138                                                     }
1139                                                     $$ = 0;
1140                                                   }
1141           | IPFY_PEER                             { if (ifpflag == FRI_DYNAMIC) {
1142                                                             ifpflag = FRI_PEERADDR;
1143                                                     } else {
1144                                                             YYERROR;
1145                                                     }
1146                                                     $$ = 0;
1147                                                   }
1148           | YY_NUMBER                             { $$ = $1; }
1149           ;
1150 
1151 hostname:
1152           ipv4                                    { memset(&($$), 0, sizeof($$));
1153                                                     $$.adr.in4 = $1;
1154                                                     if (frc->fr_family == AF_INET6)
1155                                                             YYERROR;
1156                                                     $$.f = AF_INET;
1157                                                     yyexpectaddr = 2;
1158                                                   }
1159           | YY_NUMBER                             { memset(&($$), 0, sizeof($$));
1160                                                     if (frc->fr_family == AF_INET6)
1161                                                             YYERROR;
1162                                                     $$.adr.in4_addr = $1;
1163                                                     $$.f = AF_INET;
1164                                                     yyexpectaddr = 2;
1165                                                   }
1166           | YY_HEX                      { memset(&($$), 0, sizeof($$));
1167                                                     if (frc->fr_family == AF_INET6)
1168                                                             YYERROR;
1169                                                     $$.adr.in4_addr = $1;
1170                                                     $$.f = AF_INET;
1171                                                     yyexpectaddr = 2;
1172                                                   }
1173           | YY_STR                      { memset(&($$), 0, sizeof($$));
1174                                                     if (lookuphost($1, &$$.adr) == 0)
1175                                                               $$.f = AF_INET;
1176                                                     free($1);
1177                                                     yyexpectaddr = 2;
1178                                                   }
1179           | YY_IPV6                     { memset(&($$), 0, sizeof($$));
1180                                                     if (frc->fr_family == AF_INET)
1181                                                             YYERROR;
1182                                                     $$.adr = $1;
1183                                                     $$.f = AF_INET6;
1184                                                     yyexpectaddr = 2;
1185                                                   }
1186           ;
1187 
1188 addrlist:
1189           ipaddr              { $$ = newalist(NULL);
1190                                 $$->al_family = $1.f;
1191                                 $$->al_i6addr = $1.a;
1192                                 $$->al_i6mask = $1.m;
1193                               }
1194           | ipaddr ',' { yyexpectaddr = 1; } addrlist
1195                               { $$ = newalist($4);
1196                                 $$->al_family = $1.f;
1197                                 $$->al_i6addr = $1.a;
1198                                 $$->al_i6mask = $1.m;
1199                               }
1200           ;
1201 
1202 pool:     IPFY_POOL { yyexpectaddr = 0; yycont = NULL; yyresetdict(); }
1203           ;
1204 
1205 hash:     IPFY_HASH { yyexpectaddr = 0; yycont = NULL; yyresetdict(); }
1206           ;
1207 
1208 poollist:
1209           ipaddr              { $$ = newalist(NULL);
1210                                 $$->al_family = $1.f;
1211                                 $$->al_i6addr = $1.a;
1212                                 $$->al_i6mask = $1.m;
1213                               }
1214           | '!' ipaddr        { $$ = newalist(NULL);
1215                                 $$->al_not = 1;
1216                                 $$->al_family = $2.f;
1217                                 $$->al_i6addr = $2.a;
1218                                 $$->al_i6mask = $2.m;
1219                               }
1220           | poollist ',' ipaddr
1221                               { $$ = newalist($1);
1222                                 $$->al_family = $3.f;
1223                                 $$->al_i6addr = $3.a;
1224                                 $$->al_i6mask = $3.m;
1225                               }
1226           | poollist ',' '!' ipaddr
1227                               { $$ = newalist($1);
1228                                 $$->al_not = 1;
1229                                 $$->al_family = $4.f;
1230                                 $$->al_i6addr = $4.a;
1231                                 $$->al_i6mask = $4.m;
1232                               }
1233           ;
1234 
1235 port:     IPFY_PORT                     { yyexpectaddr = 0;
1236                                                     yycont = NULL;
1237                                                     if (frc->fr_proto != 0 &&
1238                                                         frc->fr_proto != IPPROTO_UDP &&
1239                                                         frc->fr_proto != IPPROTO_TCP)
1240                                                             yyerror("port use incorrect");
1241                                                   }
1242           ;
1243 
1244 portc:    port compare                            { $$ = $2;
1245                                                     yysetdict(NULL);
1246                                                   }
1247           | porteq                      { $$ = $1; }
1248           ;
1249 
1250 porteq:   port '='                      { $$ = FR_EQUAL;
1251                                                     yysetdict(NULL);
1252                                                   }
1253           ;
1254 
1255 portr:    IPFY_PORT                     { yyexpectaddr = 0;
1256                                                     yycont = NULL;
1257                                                     yysetdict(NULL);
1258                                                   }
1259           ;
1260 
1261 portcomp:
1262           portc portnum                           { $$.pc = $1;
1263                                                     $$.p1 = $2;
1264                                                     yyresetdict();
1265                                                   }
1266           ;
1267 
1268 portrange:
1269           portr portnum range portnum   { $$.p1 = $2;
1270                                                     $$.pc = $3;
1271                                                     $$.p2 = $4;
1272                                                     yyresetdict();
1273                                                   }
1274           ;
1275 
1276 icmp:     | itype icode
1277           ;
1278 
1279 itype:    seticmptype icmptype
1280           { DOALL(fr->fr_icmp = htons($2 << 8); fr->fr_icmpm = htons(0xff00););
1281             yyresetdict();
1282           }
1283           | seticmptype lstart typelist lend      { yyresetdict(); }
1284           ;
1285 
1286 seticmptype:
1287           IPFY_ICMPTYPE                 { if (frc->fr_family == AF_UNSPEC)
1288                                                   frc->fr_family = AF_INET;
1289                                           if (frc->fr_family == AF_INET &&
1290                                               frc->fr_type == FR_T_IPF &&
1291                                               frc->fr_proto != IPPROTO_ICMP) {
1292                                                   yyerror("proto not icmp");
1293                                           }
1294                                           if (frc->fr_family == AF_INET6 &&
1295                                               frc->fr_type == FR_T_IPF &&
1296                                               frc->fr_proto != IPPROTO_ICMPV6) {
1297                                                   yyerror("proto not ipv6-icmp");
1298                                           }
1299                                           setipftype();
1300                                           DOALL(if (fr->fr_family == AF_INET) { \
1301                                                             fr->fr_ip.fi_v = 4; \
1302                                                             fr->fr_mip.fi_v = 0xf; \
1303                                                   }
1304                                                   if (fr->fr_family == AF_INET6) { \
1305                                                             fr->fr_ip.fi_v = 6; \
1306                                                             fr->fr_mip.fi_v = 0xf; \
1307                                                   }
1308                                           )
1309                                           yysetdict(NULL);
1310                                         }
1311           ;
1312 
1313 icode:    | seticmpcode icmpcode
1314           { DOALL(fr->fr_icmp |= htons($2); fr->fr_icmpm |= htons(0xff););
1315             yyresetdict();
1316           }
1317           | seticmpcode lstart codelist lend      { yyresetdict(); }
1318           ;
1319 
1320 seticmpcode:
1321           IPFY_ICMPCODE                                     { yysetdict(icmpcodewords); }
1322           ;
1323 
1324 typelist:
1325           icmptype
1326           { DOREM(fr->fr_icmp = htons($1 << 8); fr->fr_icmpm = htons(0xff00);) }
1327           | typelist lmore icmptype
1328           { DOREM(fr->fr_icmp = htons($3 << 8); fr->fr_icmpm = htons(0xff00);) }
1329           ;
1330 
1331 codelist:
1332           icmpcode
1333           { DOREM(fr->fr_icmp |= htons($1); fr->fr_icmpm |= htons(0xff);) }
1334           | codelist lmore icmpcode
1335           { DOREM(fr->fr_icmp &= htons(0xff00); fr->fr_icmp |= htons($3); \
1336                     fr->fr_icmpm |= htons(0xff);) }
1337           ;
1338 
1339 age:      | IPFY_AGE YY_NUMBER                    { DOALL(fr->fr_age[0] = $2; \
1340                                                             fr->fr_age[1] = $2;) }
1341           | IPFY_AGE YY_NUMBER '/' YY_NUMBER
1342                                                   { DOALL(fr->fr_age[0] = $2; \
1343                                                             fr->fr_age[1] = $4;) }
1344           ;
1345 
1346 keep:     | IPFY_KEEP keepstate keep
1347           | IPFY_KEEP keepfrag keep
1348           ;
1349 
1350 keepstate:
1351           IPFY_STATE stateoptlist                 { DOALL(fr->fr_flags |= FR_KEEPSTATE;)}
1352           ;
1353 
1354 keepfrag:
1355           IPFY_FRAGS fragoptlist                  { DOALL(fr->fr_flags |= FR_KEEPFRAG;) }
1356           | IPFY_FRAG fragoptlist                 { DOALL(fr->fr_flags |= FR_KEEPFRAG;) }
1357           ;
1358 
1359 fragoptlist:
1360           | '(' fragopts ')'
1361           ;
1362 
1363 fragopts:
1364           fragopt lanother fragopts
1365           | fragopt
1366           ;
1367 
1368 fragopt:
1369           IPFY_STRICT                             { DOALL(fr->fr_flags |= FR_FRSTRICT;) }
1370           ;
1371 
1372 stateoptlist:
1373           | '(' stateopts ')'
1374           ;
1375 
1376 stateopts:
1377           stateopt lanother stateopts
1378           | stateopt
1379           ;
1380 
1381 stateopt:
1382           IPFY_LIMIT YY_NUMBER          { DOALL(fr->fr_statemax = $2;) }
1383           | IPFY_STRICT                 { DOALL(if (fr->fr_proto != IPPROTO_TCP) { \
1384                                                             YYERROR; \
1385                                                   } else if (fr->fr_flags & FR_STLOOSE) {\
1386                                                             YYERROR; \
1387                                                   } else \
1388                                                             fr->fr_flags |= FR_STSTRICT;)
1389                                         }
1390           | IPFY_LOOSE                  { DOALL(if (fr->fr_proto != IPPROTO_TCP) { \
1391                                                             YYERROR; \
1392                                                   } else if (fr->fr_flags & FR_STSTRICT){\
1393                                                             YYERROR; \
1394                                                   } else \
1395                                                             fr->fr_flags |= FR_STLOOSE;)
1396                                         }
1397           | IPFY_NEWISN                 { DOALL(if (fr->fr_proto != IPPROTO_TCP) { \
1398                                                             YYERROR; \
1399                                                     } else \
1400                                                             fr->fr_flags |= FR_NEWISN;)
1401                                         }
1402           | IPFY_NOICMPERR    { DOALL(fr->fr_flags |= FR_NOICMPERR;) }
1403 
1404           | IPFY_SYNC                   { DOALL(fr->fr_flags |= FR_STATESYNC;) }
1405           | IPFY_AGE YY_NUMBER                    { DOALL(fr->fr_age[0] = $2; \
1406                                                             fr->fr_age[1] = $2;) }
1407           | IPFY_AGE YY_NUMBER '/' YY_NUMBER
1408                                                   { DOALL(fr->fr_age[0] = $2; \
1409                                                             fr->fr_age[1] = $4;) }
1410           | IPFY_ICMPHEAD groupname
1411                                         { DOALL(seticmphead(&fr, $2);)
1412                                           free($2);
1413                                         }
1414           | IPFY_NOLOG
1415                                         { DOALL(fr->fr_nostatelog = 1;) }
1416           | IPFY_RPC
1417                                         { DOALL(fr->fr_rpc = 1;) }
1418           | IPFY_RPC IPFY_IN YY_STR
1419                                         { DOALL(fr->fr_rpc = 1;) }
1420           | IPFY_MAX_SRCS YY_NUMBER
1421                                         { DOALL(fr->fr_srctrack.ht_max_nodes = $2;) }
1422           | IPFY_MAX_PER_SRC YY_NUMBER
1423                                         { DOALL(fr->fr_srctrack.ht_max_per_node = $2; \
1424                                                   fr->fr_srctrack.ht_netmask = \
1425                                                   fr->fr_family == AF_INET ? 32: 128;)
1426                                         }
1427           | IPFY_MAX_PER_SRC YY_NUMBER '/' YY_NUMBER
1428                                         { DOALL(fr->fr_srctrack.ht_max_per_node = $2; \
1429                                                   fr->fr_srctrack.ht_netmask = $4;)
1430                                         }
1431           ;
1432 
1433 portnum:
1434           servicename                             { if (getport(frc, $1,
1435                                                                   &($$), NULL) == -1)
1436                                                             yyerror("service unknown");
1437                                                     $$ = ntohs($$);
1438                                                     free($1);
1439                                                   }
1440           | YY_NUMBER                             { if ($1 > 65535)   /* Unsigned */
1441                                                             yyerror("invalid port number");
1442                                                     else
1443                                                             $$ = $1;
1444                                                   }
1445           ;
1446 
1447 withlist:
1448           withopt                                 { nowith = 0; }
1449           | withlist withopt            { nowith = 0; }
1450           | withlist ',' withopt                  { nowith = 0; }
1451           ;
1452 
1453 withopt:
1454           opttype             { DOALL(fr->fr_flx |= $1; fr->fr_mflx |= $1;) }
1455           | notwith opttype             { DOALL(fr->fr_mflx |= $2;) }
1456           | ipopt ipopts                          { yyresetdict(); }
1457           | notwith ipopt ipopts                  { yyresetdict(); }
1458           | startv6hdr ipv6hdrs                   { yyresetdict(); }
1459           ;
1460 
1461 ipopt:    IPFY_OPT                      { yysetdict(ipv4optwords); }
1462           ;
1463 
1464 startv6hdr:
1465           IPFY_V6HDR          { if (frc->fr_family != AF_INET6)
1466                                         yyerror("only available with IPv6");
1467                                 yysetdict(ipv6optwords);
1468                               }
1469           ;
1470 
1471 notwith:
1472           IPFY_NOT                      { nowith = 1; }
1473           | IPFY_NO                     { nowith = 1; }
1474           ;
1475 
1476 opttype:
1477           IPFY_IPOPTS                             { $$ = FI_OPTIONS; }
1478           | IPFY_SHORT                            { $$ = FI_SHORT; }
1479           | IPFY_NAT                              { $$ = FI_NATED; }
1480           | IPFY_BAD                              { $$ = FI_BAD; }
1481           | IPFY_BADNAT                           { $$ = FI_BADNAT; }
1482           | IPFY_BADSRC                           { $$ = FI_BADSRC; }
1483           | IPFY_LOWTTL                           { $$ = FI_LOWTTL; }
1484           | IPFY_FRAG                             { $$ = FI_FRAG; }
1485           | IPFY_FRAGBODY                         { $$ = FI_FRAGBODY; }
1486           | IPFY_FRAGS                            { $$ = FI_FRAG; }
1487           | IPFY_MBCAST                           { $$ = FI_MBCAST; }
1488           | IPFY_MULTICAST              { $$ = FI_MULTICAST; }
1489           | IPFY_BROADCAST              { $$ = FI_BROADCAST; }
1490           | IPFY_STATE                            { $$ = FI_STATE; }
1491           | IPFY_OOW                              { $$ = FI_OOW; }
1492           | IPFY_AH                     { $$ = FI_AH; }
1493           | IPFY_V6HDRS                           { $$ = FI_V6EXTHDR; }
1494           ;
1495 
1496 ipopts:   optlist             { DOALL(fr->fr_mip.fi_optmsk |= $1;
1497                                         if (fr->fr_family == AF_UNSPEC) {
1498                                                   fr->fr_family = AF_INET;
1499                                                   fr->fr_ip.fi_v = 4;
1500                                                   fr->fr_mip.fi_v = 0xf;
1501                                         } else if (fr->fr_family != AF_INET) {
1502                                                   YYERROR;
1503                                         }
1504                                         if (!nowith)
1505                                                   fr->fr_ip.fi_optmsk |= $1;)
1506                               }
1507           ;
1508 
1509 optlist:
1510           opt                                     { $$ |= $1; }
1511           | optlist ',' opt             { $$ |= $1 | $3; }
1512           ;
1513 
1514 ipv6hdrs:
1515           ipv6hdrlist         { DOALL(fr->fr_mip.fi_optmsk |= $1;
1516                                         if (!nowith)
1517                                                   fr->fr_ip.fi_optmsk |= $1;)
1518                               }
1519           ;
1520 
1521 ipv6hdrlist:
1522           ipv6hdr                                 { $$ |= $1; }
1523           | ipv6hdrlist ',' ipv6hdr     { $$ |= $1 | $3; }
1524           ;
1525 
1526 secname:
1527           seclevel                      { $$ |= $1; }
1528           | secname ',' seclevel                  { $$ |= $1 | $3; }
1529           ;
1530 
1531 seclevel:
1532           IPFY_SEC_UNC                            { $$ = secbit(IPSO_CLASS_UNCL); }
1533           | IPFY_SEC_CONF                         { $$ = secbit(IPSO_CLASS_CONF); }
1534           | IPFY_SEC_RSV1                         { $$ = secbit(IPSO_CLASS_RES1); }
1535           | IPFY_SEC_RSV2                         { $$ = secbit(IPSO_CLASS_RES2); }
1536           | IPFY_SEC_RSV3                         { $$ = secbit(IPSO_CLASS_RES3); }
1537           | IPFY_SEC_RSV4                         { $$ = secbit(IPSO_CLASS_RES4); }
1538           | IPFY_SEC_SEC                          { $$ = secbit(IPSO_CLASS_SECR); }
1539           | IPFY_SEC_TS                           { $$ = secbit(IPSO_CLASS_TOPS); }
1540           ;
1541 
1542 icmptype:
1543           YY_NUMBER           { $$ = $1; }
1544           | YY_STR            { $$ = geticmptype(frc->fr_family, $1);
1545                                           if ($$ == -1)
1546                                                   yyerror("unrecognised icmp type");
1547                                         }
1548           ;
1549 
1550 icmpcode:
1551           YY_NUMBER                     { $$ = $1; }
1552           | IPFY_ICMPC_NETUNR           { $$ = ICMP_UNREACH_NET; }
1553           | IPFY_ICMPC_HSTUNR           { $$ = ICMP_UNREACH_HOST; }
1554           | IPFY_ICMPC_PROUNR           { $$ = ICMP_UNREACH_PROTOCOL; }
1555           | IPFY_ICMPC_PORUNR           { $$ = ICMP_UNREACH_PORT; }
1556           | IPFY_ICMPC_NEEDF            { $$ = ICMP_UNREACH_NEEDFRAG; }
1557           | IPFY_ICMPC_SRCFAIL                    { $$ = ICMP_UNREACH_SRCFAIL; }
1558           | IPFY_ICMPC_NETUNK           { $$ = ICMP_UNREACH_NET_UNKNOWN; }
1559           | IPFY_ICMPC_HSTUNK           { $$ = ICMP_UNREACH_HOST_UNKNOWN; }
1560           | IPFY_ICMPC_ISOLATE                    { $$ = ICMP_UNREACH_ISOLATED; }
1561           | IPFY_ICMPC_NETPRO           { $$ = ICMP_UNREACH_NET_PROHIB; }
1562           | IPFY_ICMPC_HSTPRO           { $$ = ICMP_UNREACH_HOST_PROHIB; }
1563           | IPFY_ICMPC_NETTOS           { $$ = ICMP_UNREACH_TOSNET; }
1564           | IPFY_ICMPC_HSTTOS           { $$ = ICMP_UNREACH_TOSHOST; }
1565           | IPFY_ICMPC_FLTPRO           { $$ = ICMP_UNREACH_ADMIN_PROHIBIT; }
1566           | IPFY_ICMPC_HSTPRE           { $$ = 14; }
1567           | IPFY_ICMPC_CUTPRE           { $$ = 15; }
1568           ;
1569 
1570 opt:
1571           IPFY_IPOPT_NOP                          { $$ = getoptbyvalue(IPOPT_NOP); }
1572           | IPFY_IPOPT_RR                         { $$ = getoptbyvalue(IPOPT_RR); }
1573           | IPFY_IPOPT_ZSU              { $$ = getoptbyvalue(IPOPT_ZSU); }
1574           | IPFY_IPOPT_MTUP             { $$ = getoptbyvalue(IPOPT_MTUP); }
1575           | IPFY_IPOPT_MTUR             { $$ = getoptbyvalue(IPOPT_MTUR); }
1576           | IPFY_IPOPT_ENCODE           { $$ = getoptbyvalue(IPOPT_ENCODE); }
1577           | IPFY_IPOPT_TS                         { $$ = getoptbyvalue(IPOPT_TS); }
1578           | IPFY_IPOPT_TR                         { $$ = getoptbyvalue(IPOPT_TR); }
1579           | IPFY_IPOPT_SEC              { $$ = getoptbyvalue(IPOPT_SECURITY); }
1580           | IPFY_IPOPT_LSRR             { $$ = getoptbyvalue(IPOPT_LSRR); }
1581           | IPFY_IPOPT_ESEC             { $$ = getoptbyvalue(IPOPT_E_SEC); }
1582           | IPFY_IPOPT_CIPSO            { $$ = getoptbyvalue(IPOPT_CIPSO); }
1583           | IPFY_IPOPT_CIPSO doi                  { $$ = getoptbyvalue(IPOPT_CIPSO); }
1584           | IPFY_IPOPT_SATID            { $$ = getoptbyvalue(IPOPT_SATID); }
1585           | IPFY_IPOPT_SSRR             { $$ = getoptbyvalue(IPOPT_SSRR); }
1586           | IPFY_IPOPT_ADDEXT           { $$ = getoptbyvalue(IPOPT_ADDEXT); }
1587           | IPFY_IPOPT_VISA             { $$ = getoptbyvalue(IPOPT_VISA); }
1588           | IPFY_IPOPT_IMITD            { $$ = getoptbyvalue(IPOPT_IMITD); }
1589           | IPFY_IPOPT_EIP              { $$ = getoptbyvalue(IPOPT_EIP); }
1590           | IPFY_IPOPT_FINN             { $$ = getoptbyvalue(IPOPT_FINN); }
1591           | IPFY_IPOPT_DPS              { $$ = getoptbyvalue(IPOPT_DPS); }
1592           | IPFY_IPOPT_SDB              { $$ = getoptbyvalue(IPOPT_SDB); }
1593           | IPFY_IPOPT_NSAPA            { $$ = getoptbyvalue(IPOPT_NSAPA); }
1594           | IPFY_IPOPT_RTRALRT                    { $$ = getoptbyvalue(IPOPT_RTRALRT); }
1595           | IPFY_IPOPT_UMP              { $$ = getoptbyvalue(IPOPT_UMP); }
1596           | setsecclass secname
1597                               { DOALL(fr->fr_mip.fi_secmsk |= $2;
1598                                         if (fr->fr_family == AF_UNSPEC) {
1599                                                   fr->fr_family = AF_INET;
1600                                                   fr->fr_ip.fi_v = 4;
1601                                                   fr->fr_mip.fi_v = 0xf;
1602                                         } else if (fr->fr_family != AF_INET) {
1603                                                   YYERROR;
1604                                         }
1605                                         if (!nowith)
1606                                                   fr->fr_ip.fi_secmsk |= $2;)
1607                                 $$ = 0;
1608                                 yyresetdict();
1609                               }
1610           ;
1611 
1612 setsecclass:
1613           IPFY_SECCLASS                           { yysetdict(ipv4secwords); }
1614           ;
1615 
1616 doi:      IPFY_DOI YY_NUMBER            { DOALL(fr->fr_doimask = 0xffffffff; \
1617                                                             if (!nowith) \
1618                                                                       fr->fr_doi = $2;) }
1619           | IPFY_DOI YY_HEX             { DOALL(fr->fr_doimask = 0xffffffff; \
1620                                                             if (!nowith) \
1621                                                                       fr->fr_doi = $2;) }
1622           ;
1623 
1624 ipv6hdr:
1625           IPFY_AH                       { $$ = getv6optbyvalue(IPPROTO_AH); }
1626           | IPFY_IPV6OPT_DSTOPTS        { $$ = getv6optbyvalue(IPPROTO_DSTOPTS); }
1627           | IPFY_IPV6OPT_ESP  { $$ = getv6optbyvalue(IPPROTO_ESP); }
1628           | IPFY_IPV6OPT_HOPOPTS        { $$ = getv6optbyvalue(IPPROTO_HOPOPTS); }
1629           | IPFY_IPV6OPT_IPV6 { $$ = getv6optbyvalue(IPPROTO_IPV6); }
1630           | IPFY_IPV6OPT_NONE { $$ = getv6optbyvalue(IPPROTO_NONE); }
1631           | IPFY_IPV6OPT_ROUTING        { $$ = getv6optbyvalue(IPPROTO_ROUTING); }
1632           | IPFY_IPV6OPT_FRAG { $$ = getv6optbyvalue(IPPROTO_FRAGMENT); }
1633           | IPFY_IPV6OPT_MOBILITY       { $$ = getv6optbyvalue(IPPROTO_MOBILITY); }
1634           ;
1635 
1636 level:    IPFY_LEVEL                              { setsyslog(); }
1637           ;
1638 
1639 loglevel:
1640           priority                      { fr->fr_loglevel = LOG_LOCAL0|$1; }
1641           | facility '.' priority                 { fr->fr_loglevel = $1 | $3; }
1642           ;
1643 
1644 facility:
1645           IPFY_FAC_KERN                           { $$ = LOG_KERN; }
1646           | IPFY_FAC_USER                         { $$ = LOG_USER; }
1647           | IPFY_FAC_MAIL                         { $$ = LOG_MAIL; }
1648           | IPFY_FAC_DAEMON             { $$ = LOG_DAEMON; }
1649           | IPFY_FAC_AUTH                         { $$ = LOG_AUTH; }
1650           | IPFY_FAC_SYSLOG             { $$ = LOG_SYSLOG; }
1651           | IPFY_FAC_LPR                          { $$ = LOG_LPR; }
1652           | IPFY_FAC_NEWS                         { $$ = LOG_NEWS; }
1653           | IPFY_FAC_UUCP                         { $$ = LOG_UUCP; }
1654           | IPFY_FAC_CRON                         { $$ = LOG_CRON; }
1655           | IPFY_FAC_FTP                          { $$ = LOG_FTP; }
1656           | IPFY_FAC_AUTHPRIV           { $$ = LOG_AUTHPRIV; }
1657           | IPFY_FAC_AUDIT              { $$ = LOG_AUDIT; }
1658           | IPFY_FAC_LFMT                         { $$ = LOG_LFMT; }
1659           | IPFY_FAC_LOCAL0             { $$ = LOG_LOCAL0; }
1660           | IPFY_FAC_LOCAL1             { $$ = LOG_LOCAL1; }
1661           | IPFY_FAC_LOCAL2             { $$ = LOG_LOCAL2; }
1662           | IPFY_FAC_LOCAL3             { $$ = LOG_LOCAL3; }
1663           | IPFY_FAC_LOCAL4             { $$ = LOG_LOCAL4; }
1664           | IPFY_FAC_LOCAL5             { $$ = LOG_LOCAL5; }
1665           | IPFY_FAC_LOCAL6             { $$ = LOG_LOCAL6; }
1666           | IPFY_FAC_LOCAL7             { $$ = LOG_LOCAL7; }
1667           | IPFY_FAC_SECURITY           { $$ = LOG_SECURITY; }
1668           ;
1669 
1670 priority:
1671           IPFY_PRI_EMERG                          { $$ = LOG_EMERG; }
1672           | IPFY_PRI_ALERT              { $$ = LOG_ALERT; }
1673           | IPFY_PRI_CRIT                         { $$ = LOG_CRIT; }
1674           | IPFY_PRI_ERR                          { $$ = LOG_ERR; }
1675           | IPFY_PRI_WARN                         { $$ = LOG_WARNING; }
1676           | IPFY_PRI_NOTICE             { $$ = LOG_NOTICE; }
1677           | IPFY_PRI_INFO                         { $$ = LOG_INFO; }
1678           | IPFY_PRI_DEBUG              { $$ = LOG_DEBUG; }
1679           ;
1680 
1681 compare:
1682           YY_CMP_EQ                     { $$ = FR_EQUAL; }
1683           | YY_CMP_NE                             { $$ = FR_NEQUAL; }
1684           | YY_CMP_LT                             { $$ = FR_LESST; }
1685           | YY_CMP_LE                             { $$ = FR_LESSTE; }
1686           | YY_CMP_GT                             { $$ = FR_GREATERT; }
1687           | YY_CMP_GE                             { $$ = FR_GREATERTE; }
1688           ;
1689 
1690 range:    YY_RANGE_IN                             { $$ = FR_INRANGE; }
1691           | YY_RANGE_OUT                          { $$ = FR_OUTRANGE; }
1692           | ':'                                   { $$ = FR_INCRANGE; }
1693           ;
1694 
1695 servicename:
1696           YY_STR                                  { $$ = $1; }
1697           ;
1698 
1699 interfacename:      name                                    { $$ = $1; }
1700           | name ':' YY_NUMBER
1701                     { $$ = $1;
1702                       fprintf(stderr, "%d: Logical interface %s:%d unsupported, "
1703                                 "use the physical interface %s instead.\n",
1704                                 yylineNum, $1, $3, $1);
1705                     }
1706           ;
1707 
1708 name:     YY_STR                                  { $$ = $1; }
1709           | '-'                                   { $$ = strdup("-"); }
1710           ;
1711 
1712 ipv4_16:
1713           YY_NUMBER '.' YY_NUMBER
1714                     { if ($1 > 255 || $3 > 255) {
1715                               yyerror("Invalid octet string for IP address");
1716                               return 0;
1717                       }
1718                       $$.s_addr = ($1 << 24) | ($3 << 16);
1719                       $$.s_addr = htonl($$.s_addr);
1720                     }
1721           ;
1722 
1723 ipv4_24:
1724           ipv4_16 '.' YY_NUMBER
1725                     { if ($3 > 255) {
1726                               yyerror("Invalid octet string for IP address");
1727                               return 0;
1728                       }
1729                       $$.s_addr |= htonl($3 << 8);
1730                     }
1731           ;
1732 
1733 ipv4:     ipv4_24 '.' YY_NUMBER
1734                     { if ($3 > 255) {
1735                               yyerror("Invalid octet string for IP address");
1736                               return 0;
1737                       }
1738                       $$.s_addr |= htonl($3);
1739                     }
1740           | ipv4_24
1741           | ipv4_16
1742           ;
1743 
1744 %%
1745 
1746 
1747 static    struct    wordtab ipfwords[] = {
1748           { "age",                      IPFY_AGE },
1749           { "ah",                                 IPFY_AH },
1750           { "all",                      IPFY_ALL },
1751           { "and",                      IPFY_AND },
1752           { "auth",                     IPFY_AUTH },
1753           { "bad",                      IPFY_BAD },
1754           { "bad-nat",                            IPFY_BADNAT },
1755           { "bad-src",                            IPFY_BADSRC },
1756           { "bcast",                              IPFY_BROADCAST },
1757           { "block",                              IPFY_BLOCK },
1758           { "body",                     IPFY_BODY },
1759           { "bpf-v4",                             IPFY_BPFV4 },
1760 #ifdef USE_INET6
1761           { "bpf-v6",                             IPFY_BPFV6 },
1762 #endif
1763           { "call",                     IPFY_CALL },
1764           { "code",                     IPFY_ICMPCODE },
1765           { "comment",                            IPFY_COMMENT },
1766           { "count",                              IPFY_COUNT },
1767           { "decapsulate",              IPFY_DECAPS },
1768           { "dstlist",                            IPFY_DSTLIST },
1769           { "doi",                      IPFY_DOI },
1770           { "dup-to",                             IPFY_DUPTO },
1771           { "eq",                                 YY_CMP_EQ },
1772           { "esp",                      IPFY_ESP },
1773           { "exp",                      IPFY_IPFEXPR },
1774           { "family",                             IPFY_FAMILY },
1775           { "fastroute",                          IPFY_FROUTE },
1776           { "first",                              IPFY_FIRST },
1777           { "flags",                              IPFY_FLAGS },
1778           { "frag",                     IPFY_FRAG },
1779           { "frag-body",                          IPFY_FRAGBODY },
1780           { "frags",                              IPFY_FRAGS },
1781           { "from",                     IPFY_FROM },
1782           { "ge",                                 YY_CMP_GE },
1783           { "group",                              IPFY_GROUP },
1784           { "gt",                                 YY_CMP_GT },
1785           { "head",                     IPFY_HEAD },
1786           { "icmp",                     IPFY_ICMP },
1787           { "icmp-head",                          IPFY_ICMPHEAD },
1788           { "icmp-type",                          IPFY_ICMPTYPE },
1789           { "in",                                 IPFY_IN },
1790           { "in-via",                             IPFY_INVIA },
1791           { "inet",                     IPFY_INET },
1792           { "inet6",                              IPFY_INET6 },
1793           { "ipopt",                              IPFY_IPOPTS },
1794           { "ipopts",                             IPFY_IPOPTS },
1795           { "keep",                     IPFY_KEEP },
1796           { "l5-as",                              IPFY_L5AS },
1797           { "le",                                 YY_CMP_LE },
1798           { "level",                              IPFY_LEVEL },
1799           { "limit",                              IPFY_LIMIT },
1800           { "log",                      IPFY_LOG },
1801           { "loose",                              IPFY_LOOSE },
1802           { "lowttl",                             IPFY_LOWTTL },
1803           { "lt",                                 YY_CMP_LT },
1804           { "mask",                     IPFY_MASK },
1805           { "match-tag",                          IPFY_MATCHTAG },
1806           { "max-per-src",              IPFY_MAX_PER_SRC },
1807           { "max-srcs",                           IPFY_MAX_SRCS },
1808           { "mbcast",                             IPFY_MBCAST },
1809           { "mcast",                              IPFY_MULTICAST },
1810           { "multicast",                          IPFY_MULTICAST },
1811           { "nat",                      IPFY_NAT },
1812           { "ne",                                 YY_CMP_NE },
1813           { "net",                      IPFY_NETWORK },
1814           { "newisn",                             IPFY_NEWISN },
1815           { "no",                                 IPFY_NO },
1816           { "no-icmp-err",              IPFY_NOICMPERR },
1817           { "nolog",                              IPFY_NOLOG },
1818           { "nomatch",                            IPFY_NOMATCH },
1819           { "now",                      IPFY_NOW },
1820           { "not",                      IPFY_NOT },
1821           { "oow",                      IPFY_OOW },
1822           { "on",                                 IPFY_ON },
1823           { "opt",                      IPFY_OPT },
1824           { "or-block",                           IPFY_ORBLOCK },
1825           { "out",                      IPFY_OUT },
1826           { "out-via",                            IPFY_OUTVIA },
1827           { "pass",                     IPFY_PASS },
1828           { "port",                     IPFY_PORT },
1829           { "pps",                      IPFY_PPS },
1830           { "preauth",                            IPFY_PREAUTH },
1831           { "proto",                              IPFY_PROTO },
1832           { "quick",                              IPFY_QUICK },
1833           { "reply-to",                           IPFY_REPLY_TO },
1834           { "return-icmp",              IPFY_RETICMP },
1835           { "return-icmp-as-dest",      IPFY_RETICMPASDST },
1836           { "return-rst",                         IPFY_RETRST },
1837           { "route-to",                           IPFY_ROUTETO },
1838           { "rule-ttl",                           IPFY_RULETTL },
1839           { "rpc",                      IPFY_RPC },
1840           { "sec-class",                          IPFY_SECCLASS },
1841           { "set",                      IPFY_SET },
1842           { "set-tag",                            IPFY_SETTAG },
1843           { "skip",                     IPFY_SKIP },
1844           { "short",                              IPFY_SHORT },
1845           { "state",                              IPFY_STATE },
1846           { "state-age",                          IPFY_AGE },
1847           { "strict",                             IPFY_STRICT },
1848           { "sync",                     IPFY_SYNC },
1849           { "tcp",                      IPFY_TCP },
1850           { "tcp-udp",                            IPFY_TCPUDP },
1851           { "tos",                      IPFY_TOS },
1852           { "to",                                 IPFY_TO },
1853           { "ttl",                      IPFY_TTL },
1854           { "udp",                      IPFY_UDP },
1855           { "v6hdr",                              IPFY_V6HDR },
1856           { "v6hdrs",                             IPFY_V6HDRS },
1857           { "with",                     IPFY_WITH },
1858           { NULL,                                 0 }
1859 };
1860 
1861 static    struct    wordtab   addrwords[] = {
1862           { "any",                      IPFY_ANY },
1863           { "hash",                     IPFY_HASH },
1864           { "pool",                     IPFY_POOL },
1865           { NULL,                                 0 }
1866 };
1867 
1868 static    struct    wordtab   maskwords[] = {
1869           { "broadcast",                          IPFY_BROADCAST },
1870           { "netmasked",                          IPFY_NETMASKED },
1871           { "network",                            IPFY_NETWORK },
1872           { "peer",                     IPFY_PEER },
1873           { NULL,                                 0 }
1874 };
1875 
1876 static    struct    wordtab icmpcodewords[] = {
1877           { "cutoff-preced",            IPFY_ICMPC_CUTPRE },
1878           { "filter-prohib",            IPFY_ICMPC_FLTPRO },
1879           { "isolate",                            IPFY_ICMPC_ISOLATE },
1880           { "needfrag",                           IPFY_ICMPC_NEEDF },
1881           { "net-prohib",                         IPFY_ICMPC_NETPRO },
1882           { "net-tos",                            IPFY_ICMPC_NETTOS },
1883           { "host-preced",              IPFY_ICMPC_HSTPRE },
1884           { "host-prohib",              IPFY_ICMPC_HSTPRO },
1885           { "host-tos",                           IPFY_ICMPC_HSTTOS },
1886           { "host-unk",                           IPFY_ICMPC_HSTUNK },
1887           { "host-unr",                           IPFY_ICMPC_HSTUNR },
1888           { "net-unk",                            IPFY_ICMPC_NETUNK },
1889           { "net-unr",                            IPFY_ICMPC_NETUNR },
1890           { "port-unr",                           IPFY_ICMPC_PORUNR },
1891           { "proto-unr",                          IPFY_ICMPC_PROUNR },
1892           { "srcfail",                            IPFY_ICMPC_SRCFAIL },
1893           { NULL,                                 0 },
1894 };
1895 
1896 static    struct    wordtab ipv4optwords[] = {
1897           { "addext",                             IPFY_IPOPT_ADDEXT },
1898           { "cipso",                              IPFY_IPOPT_CIPSO },
1899           { "dps",                      IPFY_IPOPT_DPS },
1900           { "e-sec",                              IPFY_IPOPT_ESEC },
1901           { "eip",                      IPFY_IPOPT_EIP },
1902           { "encode",                             IPFY_IPOPT_ENCODE },
1903           { "finn",                     IPFY_IPOPT_FINN },
1904           { "imitd",                              IPFY_IPOPT_IMITD },
1905           { "lsrr",                     IPFY_IPOPT_LSRR },
1906           { "mtup",                     IPFY_IPOPT_MTUP },
1907           { "mtur",                     IPFY_IPOPT_MTUR },
1908           { "nop",                      IPFY_IPOPT_NOP },
1909           { "nsapa",                              IPFY_IPOPT_NSAPA },
1910           { "rr",                                 IPFY_IPOPT_RR },
1911           { "rtralrt",                            IPFY_IPOPT_RTRALRT },
1912           { "satid",                              IPFY_IPOPT_SATID },
1913           { "sdb",                      IPFY_IPOPT_SDB },
1914           { "sec",                      IPFY_IPOPT_SEC },
1915           { "ssrr",                     IPFY_IPOPT_SSRR },
1916           { "tr",                                 IPFY_IPOPT_TR },
1917           { "ts",                                 IPFY_IPOPT_TS },
1918           { "ump",                      IPFY_IPOPT_UMP },
1919           { "visa",                     IPFY_IPOPT_VISA },
1920           { "zsu",                      IPFY_IPOPT_ZSU },
1921           { NULL,                                 0 },
1922 };
1923 
1924 static    struct    wordtab ipv4secwords[] = {
1925           { "confid",                             IPFY_SEC_CONF },
1926           { "reserv-1",                           IPFY_SEC_RSV1 },
1927           { "reserv-2",                           IPFY_SEC_RSV2 },
1928           { "reserv-3",                           IPFY_SEC_RSV3 },
1929           { "reserv-4",                           IPFY_SEC_RSV4 },
1930           { "secret",                             IPFY_SEC_SEC },
1931           { "topsecret",                          IPFY_SEC_TS },
1932           { "unclass",                            IPFY_SEC_UNC },
1933           { NULL,                                 0 },
1934 };
1935 
1936 static    struct    wordtab ipv6optwords[] = {
1937           { "dstopts",                            IPFY_IPV6OPT_DSTOPTS },
1938           { "esp",                      IPFY_IPV6OPT_ESP },
1939           { "frag",                     IPFY_IPV6OPT_FRAG },
1940           { "hopopts",                            IPFY_IPV6OPT_HOPOPTS },
1941           { "ipv6",                     IPFY_IPV6OPT_IPV6 },
1942           { "mobility",                           IPFY_IPV6OPT_MOBILITY },
1943           { "none",                     IPFY_IPV6OPT_NONE },
1944           { "routing",                            IPFY_IPV6OPT_ROUTING },
1945           { NULL,                                 0 },
1946 };
1947 
1948 static    struct    wordtab logwords[] = {
1949           { "kern",                     IPFY_FAC_KERN },
1950           { "user",                     IPFY_FAC_USER },
1951           { "mail",                     IPFY_FAC_MAIL },
1952           { "daemon",                             IPFY_FAC_DAEMON },
1953           { "auth",                     IPFY_FAC_AUTH },
1954           { "syslog",                             IPFY_FAC_SYSLOG },
1955           { "lpr",                      IPFY_FAC_LPR },
1956           { "news",                     IPFY_FAC_NEWS },
1957           { "uucp",                     IPFY_FAC_UUCP },
1958           { "cron",                     IPFY_FAC_CRON },
1959           { "ftp",                      IPFY_FAC_FTP },
1960           { "authpriv",                           IPFY_FAC_AUTHPRIV },
1961           { "audit",                              IPFY_FAC_AUDIT },
1962           { "logalert",                           IPFY_FAC_LFMT },
1963           { "console",                            IPFY_FAC_CONSOLE },
1964           { "security",                           IPFY_FAC_SECURITY },
1965           { "local0",                             IPFY_FAC_LOCAL0 },
1966           { "local1",                             IPFY_FAC_LOCAL1 },
1967           { "local2",                             IPFY_FAC_LOCAL2 },
1968           { "local3",                             IPFY_FAC_LOCAL3 },
1969           { "local4",                             IPFY_FAC_LOCAL4 },
1970           { "local5",                             IPFY_FAC_LOCAL5 },
1971           { "local6",                             IPFY_FAC_LOCAL6 },
1972           { "local7",                             IPFY_FAC_LOCAL7 },
1973           { "emerg",                              IPFY_PRI_EMERG },
1974           { "alert",                              IPFY_PRI_ALERT },
1975           { "crit",                     IPFY_PRI_CRIT },
1976           { "err",                      IPFY_PRI_ERR },
1977           { "warn",                     IPFY_PRI_WARN },
1978           { "notice",                             IPFY_PRI_NOTICE },
1979           { "info",                     IPFY_PRI_INFO },
1980           { "debug",                              IPFY_PRI_DEBUG },
1981           { NULL,                                 0 },
1982 };
1983 
1984 
1985 
1986 
ipf_parsefile(fd,addfunc,iocfuncs,filename)1987 int ipf_parsefile(fd, addfunc, iocfuncs, filename)
1988 int fd;
1989 addfunc_t addfunc;
1990 ioctlfunc_t *iocfuncs;
1991 char *filename;
1992 {
1993           FILE *fp = NULL;
1994           char *s;
1995 
1996           yylineNum = 1;
1997           yysettab(ipfwords);
1998 
1999           s = getenv("YYDEBUG");
2000           if (s != NULL)
2001                     yydebug = atoi(s);
2002           else
2003                     yydebug = 0;
2004 
2005           if (strcmp(filename, "-")) {
2006                     fp = fopen(filename, "r");
2007                     if (fp == NULL) {
2008                               fprintf(stderr, "fopen(%s) failed: %s\n", filename,
2009                                         STRERROR(errno));
2010                               return -1;
2011                     }
2012           } else
2013                     fp = stdin;
2014 
2015           while (ipf_parsesome(fd, addfunc, iocfuncs, fp) == 1)
2016                     ;
2017           if (fp != NULL)
2018                     fclose(fp);
2019           return 0;
2020 }
2021 
2022 
ipf_parsesome(fd,addfunc,iocfuncs,fp)2023 int ipf_parsesome(fd, addfunc, iocfuncs, fp)
2024 int fd;
2025 addfunc_t addfunc;
2026 ioctlfunc_t *iocfuncs;
2027 FILE *fp;
2028 {
2029           char *s;
2030           int i;
2031 
2032           ipffd = fd;
2033           for (i = 0; i <= IPL_LOGMAX; i++)
2034                     ipfioctls[i] = iocfuncs[i];
2035           ipfaddfunc = addfunc;
2036 
2037           if (feof(fp))
2038                     return 0;
2039           i = fgetc(fp);
2040           if (i == EOF)
2041                     return 0;
2042           if (ungetc(i, fp) == 0)
2043                     return 0;
2044           if (feof(fp))
2045                     return 0;
2046           s = getenv("YYDEBUG");
2047           if (s != NULL)
2048                     yydebug = atoi(s);
2049           else
2050                     yydebug = 0;
2051 
2052           yyin = fp;
2053           yyparse();
2054           return 1;
2055 }
2056 
2057 
newrule()2058 static void newrule()
2059 {
2060           frentry_t *frn;
2061 
2062           frn = allocfr();
2063           for (fr = frtop; fr != NULL && fr->fr_next != NULL; fr = fr->fr_next)
2064                     ;
2065           if (fr != NULL) {
2066                     fr->fr_next = frn;
2067                     frn->fr_pnext = &fr->fr_next;
2068           }
2069           if (frtop == NULL) {
2070                     frtop = frn;
2071                     frn->fr_pnext = &frtop;
2072           }
2073           fr = frn;
2074           frc = frn;
2075           fr->fr_loglevel = 0xffff;
2076           fr->fr_isc = (void *)-1;
2077           fr->fr_logtag = FR_NOLOGTAG;
2078           fr->fr_type = FR_T_NONE;
2079           fr->fr_flineno = yylineNum;
2080 
2081           if (use_inet6 == 1)
2082                     fr->fr_family = AF_INET6;
2083           else if (use_inet6 == -1)
2084                     fr->fr_family = AF_INET;
2085 
2086           nrules = 1;
2087 }
2088 
2089 
setipftype()2090 static void setipftype()
2091 {
2092           for (fr = frc; fr != NULL; fr = fr->fr_next) {
2093                     if (fr->fr_type == FR_T_NONE) {
2094                               fr->fr_type = FR_T_IPF;
2095                               fr->fr_data = (void *)calloc(sizeof(fripf_t), 1);
2096                               fr->fr_dsize = sizeof(fripf_t);
2097                               fr->fr_family = frc->fr_family;
2098                               if (fr->fr_family == AF_INET) {
2099                                         fr->fr_ip.fi_v = 4;
2100                               }
2101                               else if (fr->fr_family == AF_INET6) {
2102                                         fr->fr_ip.fi_v = 6;
2103                               }
2104                               fr->fr_mip.fi_v = 0xf;
2105                               fr->fr_ipf->fri_sifpidx = -1;
2106                               fr->fr_ipf->fri_difpidx = -1;
2107                     }
2108                     if (fr->fr_type != FR_T_IPF) {
2109                               fprintf(stderr, "IPF Type not set\n");
2110                     }
2111           }
2112 }
2113 
2114 
addrule()2115 static frentry_t *addrule()
2116 {
2117           frentry_t *f, *f1, *f2;
2118           int count;
2119 
2120           for (f2 = frc; f2->fr_next != NULL; f2 = f2->fr_next)
2121                     ;
2122 
2123           count = nrules;
2124           f = f2;
2125           for (f1 = frc; count > 0; count--, f1 = f1->fr_next) {
2126                     f->fr_next = allocfr();
2127                     if (f->fr_next == NULL)
2128                               return NULL;
2129                     f->fr_next->fr_pnext = &f->fr_next;
2130                     added++;
2131                     f = f->fr_next;
2132                     *f = *f1;
2133                     f->fr_next = NULL;
2134                     if (f->fr_caddr != NULL) {
2135                               f->fr_caddr = malloc(f->fr_dsize);
2136                               bcopy(f1->fr_caddr, f->fr_caddr, f->fr_dsize);
2137                     }
2138           }
2139 
2140           return f2->fr_next;
2141 }
2142 
2143 
2144 static int
lookuphost(name,addrp)2145 lookuphost(name, addrp)
2146           char *name;
2147           i6addr_t *addrp;
2148 {
2149           int i;
2150 
2151           hashed = 0;
2152           pooled = 0;
2153           dynamic = -1;
2154 
2155           for (i = 0; i < 4; i++) {
2156                     if (fr->fr_ifnames[i] == -1)
2157                               continue;
2158                     if (strcmp(name, fr->fr_names + fr->fr_ifnames[i]) == 0) {
2159                               ifpflag = FRI_DYNAMIC;
2160                               dynamic = addname(&fr, name);
2161                               return 1;
2162                     }
2163           }
2164 
2165           if (gethost(AF_INET, name, addrp) == -1) {
2166                     fprintf(stderr, "unknown name \"%s\"\n", name);
2167                     return -1;
2168           }
2169           return 0;
2170 }
2171 
2172 
dobpf(v,phrase)2173 static void dobpf(v, phrase)
2174 int v;
2175 char *phrase;
2176 {
2177 #ifdef IPFILTER_BPF
2178           struct bpf_program bpf;
2179           struct pcap *p;
2180 #endif
2181           fakebpf_t *fb;
2182           u_32_t l;
2183           char *s;
2184           int i;
2185 
2186           for (fr = frc; fr != NULL; fr = fr->fr_next) {
2187                     if (fr->fr_type != FR_T_NONE) {
2188                               fprintf(stderr, "cannot mix IPF and BPF matching\n");
2189                               return;
2190                     }
2191                     fr->fr_family = vtof(v);
2192                     fr->fr_type = FR_T_BPFOPC;
2193 
2194                     if (!strncmp(phrase, "0x", 2)) {
2195                               fb = malloc(sizeof(fakebpf_t));
2196 
2197                               for (i = 0, s = strtok(phrase, " \r\n\t"); s != NULL;
2198                                    s = strtok(NULL, " \r\n\t"), i++) {
2199                                         fb = realloc(fb, (i / 4 + 1) * sizeof(*fb));
2200                                         l = (u_32_t)strtol(s, NULL, 0);
2201                                         switch (i & 3)
2202                                         {
2203                                         case 0 :
2204                                                   fb[i / 4].fb_c = l & 0xffff;
2205                                                   break;
2206                                         case 1 :
2207                                                   fb[i / 4].fb_t = l & 0xff;
2208                                                   break;
2209                                         case 2 :
2210                                                   fb[i / 4].fb_f = l & 0xff;
2211                                                   break;
2212                                         case 3 :
2213                                                   fb[i / 4].fb_k = l;
2214                                                   break;
2215                                         }
2216                               }
2217                               if ((i & 3) != 0) {
2218                                         fprintf(stderr,
2219                                                   "Odd number of bytes in BPF code\n");
2220                                         exit(1);
2221                               }
2222                               i--;
2223                               fr->fr_dsize = (i / 4 + 1) * sizeof(*fb);
2224                               fr->fr_data = fb;
2225                               return;
2226                     }
2227 
2228 #ifdef IPFILTER_BPF
2229                     bzero((char *)&bpf, sizeof(bpf));
2230                     p = pcap_open_dead(DLT_RAW, 1);
2231                     if (!p) {
2232                               fprintf(stderr, "pcap_open_dead failed\n");
2233                               return;
2234                     }
2235 
2236                     if (pcap_compile(p, &bpf, phrase, 1, 0xffffffff)) {
2237                               pcap_perror(p, "ipf");
2238                               pcap_close(p);
2239                               fprintf(stderr, "pcap parsing failed (%s)\n", phrase);
2240                               return;
2241                     }
2242                     pcap_close(p);
2243 
2244                     fr->fr_dsize = bpf.bf_len * sizeof(struct bpf_insn);
2245                     fr->fr_data = malloc(fr->fr_dsize);
2246                     bcopy((char *)bpf.bf_insns, fr->fr_data, fr->fr_dsize);
2247                     if (!bpf_validate(fr->fr_data, bpf.bf_len)) {
2248                               fprintf(stderr, "BPF validation failed\n");
2249                               return;
2250                     }
2251 #endif
2252           }
2253 
2254 #ifdef IPFILTER_BPF
2255           if (opts & OPT_DEBUG)
2256                     bpf_dump(&bpf, 0);
2257 #else
2258           fprintf(stderr, "BPF filter expressions not supported\n");
2259           exit(1);
2260 #endif
2261 }
2262 
2263 
resetaddr()2264 static void resetaddr()
2265 {
2266           hashed = 0;
2267           pooled = 0;
2268           dynamic = -1;
2269 }
2270 
2271 
newalist(ptr)2272 static alist_t *newalist(ptr)
2273 alist_t *ptr;
2274 {
2275           alist_t *al;
2276 
2277           al = malloc(sizeof(*al));
2278           if (al == NULL)
2279                     return NULL;
2280           al->al_not = 0;
2281           al->al_next = ptr;
2282           return al;
2283 }
2284 
2285 
2286 static int
makepool(list)2287 makepool(list)
2288           alist_t *list;
2289 {
2290           ip_pool_node_t *n, *top;
2291           ip_pool_t pool;
2292           alist_t *a;
2293           int num;
2294 
2295           if (list == NULL)
2296                     return 0;
2297           top = calloc(1, sizeof(*top));
2298           if (top == NULL)
2299                     return 0;
2300 
2301           for (n = top, a = list; (n != NULL) && (a != NULL); a = a->al_next) {
2302                     if (use_inet6 == 1) {
2303 #ifdef AF_INET6
2304                               n->ipn_addr.adf_family = AF_INET6;
2305                               n->ipn_addr.adf_addr = a->al_i6addr;
2306                               n->ipn_addr.adf_len = offsetof(addrfamily_t,
2307                                                                    adf_addr) + 16;
2308                               n->ipn_mask.adf_family = AF_INET6;
2309                               n->ipn_mask.adf_addr = a->al_i6mask;
2310                               n->ipn_mask.adf_len = offsetof(addrfamily_t,
2311                                                                    adf_addr) + 16;
2312 
2313 #endif
2314                     } else {
2315                               n->ipn_addr.adf_family = AF_INET;
2316                               n->ipn_addr.adf_addr.in4.s_addr = a->al_1;
2317                               n->ipn_addr.adf_len = offsetof(addrfamily_t,
2318                                                                    adf_addr) + 4;
2319                               n->ipn_mask.adf_family = AF_INET;
2320                               n->ipn_mask.adf_addr.in4.s_addr = a->al_2;
2321                               n->ipn_mask.adf_len = offsetof(addrfamily_t,
2322                                                                    adf_addr) + 4;
2323                     }
2324                     n->ipn_info = a->al_not;
2325                     if (a->al_next != NULL) {
2326                               n->ipn_next = calloc(1, sizeof(*n));
2327                               n = n->ipn_next;
2328                     }
2329           }
2330 
2331           bzero((char *)&pool, sizeof(pool));
2332           pool.ipo_unit = IPL_LOGIPF;
2333           pool.ipo_list = top;
2334           num = load_pool(&pool, ipfioctls[IPL_LOGLOOKUP]);
2335 
2336           while ((n = top) != NULL) {
2337                     top = n->ipn_next;
2338                     free(n);
2339           }
2340           return num;
2341 }
2342 
2343 
makehash(list)2344 static u_int makehash(list)
2345 alist_t *list;
2346 {
2347           iphtent_t *n, *top;
2348           iphtable_t iph;
2349           alist_t *a;
2350           int num;
2351 
2352           if (list == NULL)
2353                     return 0;
2354           top = calloc(1, sizeof(*top));
2355           if (top == NULL)
2356                     return 0;
2357 
2358           for (n = top, a = list; (n != NULL) && (a != NULL); a = a->al_next) {
2359                     if (a->al_family == AF_INET6) {
2360                               n->ipe_family = AF_INET6;
2361                               n->ipe_addr = a->al_i6addr;
2362                               n->ipe_mask = a->al_i6mask;
2363                     } else {
2364                               n->ipe_family = AF_INET;
2365                               n->ipe_addr.in4_addr = a->al_1;
2366                               n->ipe_mask.in4_addr = a->al_2;
2367                     }
2368                     n->ipe_value = 0;
2369                     if (a->al_next != NULL) {
2370                               n->ipe_next = calloc(1, sizeof(*n));
2371                               n = n->ipe_next;
2372                     }
2373           }
2374 
2375           bzero((char *)&iph, sizeof(iph));
2376           iph.iph_unit = IPL_LOGIPF;
2377           iph.iph_type = IPHASH_LOOKUP;
2378           *iph.iph_name = '\0';
2379 
2380           if (load_hash(&iph, top, ipfioctls[IPL_LOGLOOKUP]) == 0)
2381                     sscanf(iph.iph_name, "%u", &num);
2382           else
2383                     num = 0;
2384 
2385           while ((n = top) != NULL) {
2386                     top = n->ipe_next;
2387                     free(n);
2388           }
2389           return num;
2390 }
2391 
2392 
ipf_addrule(fd,ioctlfunc,ptr)2393 int ipf_addrule(fd, ioctlfunc, ptr)
2394 int fd;
2395 ioctlfunc_t ioctlfunc;
2396 void *ptr;
2397 {
2398           ioctlcmd_t add, del;
2399           frentry_t *fr;
2400           ipfobj_t obj;
2401 
2402           if (ptr == NULL)
2403                     return 0;
2404 
2405           fr = ptr;
2406           add = 0;
2407           del = 0;
2408 
2409           bzero((char *)&obj, sizeof(obj));
2410           obj.ipfo_rev = IPFILTER_VERSION;
2411           obj.ipfo_size = fr->fr_size;
2412           obj.ipfo_type = IPFOBJ_FRENTRY;
2413           obj.ipfo_ptr = ptr;
2414 
2415           if ((opts & OPT_DONOTHING) != 0)
2416                     fd = -1;
2417 
2418           if (opts & OPT_ZERORULEST) {
2419                     add = SIOCZRLST;
2420           } else if (opts & OPT_INACTIVE) {
2421                     add = (u_int)fr->fr_hits ? SIOCINIFR :
2422                                                      SIOCADIFR;
2423                     del = SIOCRMIFR;
2424           } else {
2425                     add = (u_int)fr->fr_hits ? SIOCINAFR :
2426                                                      SIOCADAFR;
2427                     del = SIOCRMAFR;
2428           }
2429 
2430           if ((opts & OPT_OUTQUE) != 0)
2431                     fr->fr_flags |= FR_OUTQUE;
2432           if (fr->fr_hits)
2433                     fr->fr_hits--;
2434           if ((opts & OPT_VERBOSE) != 0)
2435                     printfr(fr, ioctlfunc);
2436 
2437           if ((opts & OPT_DEBUG) != 0) {
2438                     binprint(fr, sizeof(*fr));
2439                     if (fr->fr_data != NULL)
2440                               binprint(fr->fr_data, fr->fr_dsize);
2441           }
2442 
2443           if ((opts & OPT_ZERORULEST) != 0) {
2444                     if ((*ioctlfunc)(fd, add, (void *)&obj) == -1) {
2445                               if ((opts & OPT_DONOTHING) == 0) {
2446                                         char msg[80];
2447 
2448                                         sprintf(msg, "%d:ioctl(zero rule)",
2449                                                   fr->fr_flineno);
2450                                         return ipf_perror_fd(fd, ioctlfunc, msg);
2451                               }
2452                     } else {
2453 #ifdef    USE_QUAD_T
2454                               printf("hits %qd bytes %qd ",
2455                                         (long long)fr->fr_hits,
2456                                         (long long)fr->fr_bytes);
2457 #else
2458                               printf("hits %ld bytes %ld ",
2459                                         fr->fr_hits, fr->fr_bytes);
2460 #endif
2461                               printfr(fr, ioctlfunc);
2462                     }
2463           } else if ((opts & OPT_REMOVE) != 0) {
2464                     if ((*ioctlfunc)(fd, del, (void *)&obj) == -1) {
2465                               if ((opts & OPT_DONOTHING) == 0) {
2466                                         char msg[80];
2467 
2468                                         sprintf(msg, "%d:ioctl(delete rule)",
2469                                                   fr->fr_flineno);
2470                                         return ipf_perror_fd(fd, ioctlfunc, msg);
2471                               }
2472                     }
2473           } else {
2474                     if ((*ioctlfunc)(fd, add, (void *)&obj) == -1) {
2475                               if ((opts & OPT_DONOTHING) == 0) {
2476                                         char msg[80];
2477 
2478                                         sprintf(msg, "%d:ioctl(add/insert rule)",
2479                                                   fr->fr_flineno);
2480                                         return ipf_perror_fd(fd, ioctlfunc, msg);
2481                               }
2482                     }
2483           }
2484           return 0;
2485 }
2486 
setsyslog()2487 static void setsyslog()
2488 {
2489           yysetdict(logwords);
2490           yybreakondot = 1;
2491 }
2492 
2493 
unsetsyslog()2494 static void unsetsyslog()
2495 {
2496           yyresetdict();
2497           yybreakondot = 0;
2498 }
2499 
2500 
fillgroup(fr)2501 static void fillgroup(fr)
2502 frentry_t *fr;
2503 {
2504           frentry_t *f;
2505 
2506           for (f = frold; f != NULL; f = f->fr_next) {
2507                     if (f->fr_grhead == -1 && fr->fr_group == -1)
2508                               break;
2509                     if (f->fr_grhead == -1 || fr->fr_group == -1)
2510                               continue;
2511                     if (strcmp(f->fr_names + f->fr_grhead,
2512                                  fr->fr_names + fr->fr_group) == 0)
2513                               break;
2514           }
2515 
2516           if (f == NULL)
2517                     return;
2518 
2519           /*
2520            * Only copy down matching fields if the rules are of the same type
2521            * and are of ipf type.   The only fields that are copied are those
2522            * that impact the rule parsing itself, eg. need for knowing what the
2523            * protocol should be for rules with port comparisons in them.
2524            */
2525           if (f->fr_type != fr->fr_type || f->fr_type != FR_T_IPF)
2526                     return;
2527 
2528           if (fr->fr_family == 0 && f->fr_family != 0)
2529                     fr->fr_family = f->fr_family;
2530 
2531           if (fr->fr_mproto == 0 && f->fr_mproto != 0)
2532                     fr->fr_mproto = f->fr_mproto;
2533           if (fr->fr_proto == 0 && f->fr_proto != 0)
2534                     fr->fr_proto = f->fr_proto;
2535 
2536           if ((fr->fr_mproto == 0) && ((fr->fr_flx & FI_TCPUDP) == 0) &&
2537               ((f->fr_flx & FI_TCPUDP) != 0)) {
2538                     fr->fr_flx |= FI_TCPUDP;
2539                     fr->fr_mflx |= FI_TCPUDP;
2540           }
2541 }
2542 
2543 
doipfexpr(line)2544 static void doipfexpr(line)
2545 char *line;
2546 {
2547           int *array;
2548           char *error;
2549 
2550           array = parseipfexpr(line, &error);
2551           if (array == NULL) {
2552                     fprintf(stderr, "%s:", error);
2553                     yyerror("error parsing ipf matching expression");
2554                     return;
2555           }
2556 
2557           fr->fr_type = FR_T_IPFEXPR;
2558           fr->fr_data = array;
2559           fr->fr_dsize = array[0] * sizeof(*array);
2560 }
2561 
2562 
do_tuneint(varname,value)2563 static void do_tuneint(varname, value)
2564 char *varname;
2565 int value;
2566 {
2567           char buffer[80];
2568 
2569           strncpy(buffer, varname, 60);
2570           buffer[59] = '\0';
2571           strcat(buffer, "=");
2572           sprintf(buffer, "%u", value);
2573           ipf_dotuning(ipffd, buffer, ioctl);
2574 }
2575 
2576 
do_tunestr(varname,value)2577 static void do_tunestr(varname, value)
2578 char *varname, *value;
2579 {
2580 
2581           if (!strcasecmp(value, "true")) {
2582                     do_tuneint(varname, 1);
2583           } else if (!strcasecmp(value, "false")) {
2584                     do_tuneint(varname, 0);
2585           } else {
2586                     yyerror("did not find true/false where expected");
2587           }
2588 }
2589 
2590 
setifname(frp,idx,name)2591 static void setifname(frp, idx, name)
2592 frentry_t **frp;
2593 int idx;
2594 char *name;
2595 {
2596           int pos;
2597 
2598           pos = addname(frp, name);
2599           if (pos == -1)
2600                     return;
2601           (*frp)->fr_ifnames[idx] = pos;
2602 }
2603 
2604 
addname(frp,name)2605 static int addname(frp, name)
2606 frentry_t **frp;
2607 char *name;
2608 {
2609           frentry_t *f;
2610           int nlen;
2611           int pos;
2612 
2613           nlen = strlen(name) + 1;
2614           /*
2615            * realloc is harder to use here because the end of the structure
2616            * needs to be zero'd, else it gets junk bytes.
2617            */
2618           f = calloc(1, (*frp)->fr_size + nlen);
2619           memcpy(f, *frp, (*frp)->fr_size);
2620           free(*frp);
2621           if (*frp == frc)
2622                     frc = f;
2623           *frp = f;
2624           if (f == NULL)
2625                     return -1;
2626           if (f->fr_pnext != NULL)
2627                     *f->fr_pnext = f;
2628           f->fr_size += nlen;
2629           pos = f->fr_namelen;
2630           f->fr_namelen += nlen;
2631           strcpy(f->fr_names + pos, name);
2632           f->fr_names[f->fr_namelen] = '\0';
2633           return pos;
2634 }
2635 
2636 
allocfr()2637 static frentry_t *allocfr()
2638 {
2639           frentry_t *fr;
2640 
2641           fr = calloc(1, sizeof(*fr));
2642           if (fr != NULL) {
2643                     fr->fr_size = sizeof(*fr);
2644                     fr->fr_comment = -1;
2645                     fr->fr_group = -1;
2646                     fr->fr_grhead = -1;
2647                     fr->fr_icmphead = -1;
2648                     fr->fr_ifnames[0] = -1;
2649                     fr->fr_ifnames[1] = -1;
2650                     fr->fr_ifnames[2] = -1;
2651                     fr->fr_ifnames[3] = -1;
2652                     fr->fr_tif.fd_name = -1;
2653                     fr->fr_rif.fd_name = -1;
2654                     fr->fr_dif.fd_name = -1;
2655           }
2656           return fr;
2657 }
2658 
2659 
setgroup(frp,name)2660 static void setgroup(frp, name)
2661 frentry_t **frp;
2662 char *name;
2663 {
2664           int pos;
2665 
2666           pos = addname(frp, name);
2667           if (pos == -1)
2668                     return;
2669           (*frp)->fr_group = pos;
2670 }
2671 
2672 
setgrhead(frp,name)2673 static void setgrhead(frp, name)
2674 frentry_t **frp;
2675 char *name;
2676 {
2677           int pos;
2678 
2679           pos = addname(frp, name);
2680           if (pos == -1)
2681                     return;
2682           (*frp)->fr_grhead = pos;
2683 }
2684 
2685 
seticmphead(frp,name)2686 static void seticmphead(frp, name)
2687 frentry_t **frp;
2688 char *name;
2689 {
2690           int pos;
2691 
2692           pos = addname(frp, name);
2693           if (pos == -1)
2694                     return;
2695           (*frp)->fr_icmphead = pos;
2696 }
2697 
2698 
2699 static void
build_dstaddr_af(fp,ptr)2700 build_dstaddr_af(fp, ptr)
2701           frentry_t *fp;
2702           void *ptr;
2703 {
2704           struct ipp_s *ipp = ptr;
2705           frentry_t *f = fp;
2706 
2707           if (f->fr_family != AF_UNSPEC && ipp->f == AF_UNSPEC) {
2708                     ipp->f = f->fr_family;
2709                     ipp->v = f->fr_ip.fi_v;
2710           }
2711           if (ipp->f == AF_INET)
2712                     ipp->v = 4;
2713           else if (ipp->f == AF_INET6)
2714                     ipp->v = 6;
2715 
2716           for (; f != NULL; f = f->fr_next) {
2717                     f->fr_ip.fi_dst = ipp->a;
2718                     f->fr_mip.fi_dst = ipp->m;
2719                     f->fr_family = ipp->f;
2720                     f->fr_ip.fi_v = ipp->v;
2721                     f->fr_mip.fi_v = 0xf;
2722                     f->fr_datype = ipp->type;
2723                     if (ipp->ifpos != -1)
2724                               f->fr_ipf->fri_difpidx = ipp->ifpos;
2725           }
2726           fr = NULL;
2727 }
2728 
2729 
2730 static void
build_srcaddr_af(fp,ptr)2731 build_srcaddr_af(fp, ptr)
2732           frentry_t *fp;
2733           void *ptr;
2734 {
2735           struct ipp_s *ipp = ptr;
2736           frentry_t *f = fp;
2737 
2738           if (f->fr_family != AF_UNSPEC && ipp->f == AF_UNSPEC) {
2739                     ipp->f = f->fr_family;
2740                     ipp->v = f->fr_ip.fi_v;
2741           }
2742           if (ipp->f == AF_INET)
2743                     ipp->v = 4;
2744           else if (ipp->f == AF_INET6)
2745                     ipp->v = 6;
2746 
2747           for (; f != NULL; f = f->fr_next) {
2748                     f->fr_ip.fi_src = ipp->a;
2749                     f->fr_mip.fi_src = ipp->m;
2750                     f->fr_family = ipp->f;
2751                     f->fr_ip.fi_v = ipp->v;
2752                     f->fr_mip.fi_v = 0xf;
2753                     f->fr_satype = ipp->type;
2754                     f->fr_ipf->fri_sifpidx = ipp->ifpos;
2755           }
2756           fr = NULL;
2757 }
2758