On Mon, May 15, 2017 at 03:19:19PM +0200, Alexandr Nedvedicky wrote:
>     I'm attaching updated final patch, which accepts your suggestion.

I think this broke sys/net/pf_forward.
http://bluhm.genua.de/regress/results/regress.html
When backing out pf.c rev 1.1024 it works again.

I guess it is a problem with tagged route-to rules in an anchor.
I cannot investigate right now, but will do later.

bluhm

> 
> thanks and
> regards
> sasha
> 
> --------8<---------------8<---------------8<------------------8<--------
> diff -r d1adecdc78cc src/sys/net/pf.c
> --- a/src/sys/net/pf.c        Fri May 12 00:09:06 2017 +0200
> +++ b/src/sys/net/pf.c        Mon May 15 13:36:45 2017 +0200
> @@ -119,12 +119,54 @@ u_char                   pf_tcp_secret[16];
>  int                   pf_tcp_secret_init;
>  int                   pf_tcp_iss_off;
>  
> -struct pf_anchor_stackframe {
> -     struct pf_ruleset                       *rs;
> -     struct pf_rule                          *r;
> -     struct pf_anchor_node                   *parent;
> -     struct pf_anchor                        *child;
> -} pf_anchor_stack[64];
> +enum pf_test_status {
> +     PF_TEST_FAIL = -1,
> +     PF_TEST_OK,
> +     PF_TEST_QUICK
> +};
> +
> +struct pf_test_ctx {
> +     enum pf_test_status       test_status;
> +     struct pf_pdesc          *pd;
> +     struct pf_rule_actions    act;
> +     u_int8_t                  icmpcode;
> +     u_int8_t                  icmptype;
> +     int                       icmp_dir;
> +     int                       state_icmp;
> +     int                       tag;
> +     u_short                   reason;
> +     struct pf_rule_item      *ri;
> +     struct pf_src_node       *sns[PF_SN_MAX];
> +     struct pf_rule_slist      rules;
> +     struct pf_rule           *nr;
> +     struct pf_rule          **rm;
> +     struct pf_rule           *a;
> +     struct pf_rule          **am;
> +     struct pf_ruleset       **rsm;
> +     struct pf_ruleset        *arsm;
> +     struct pf_ruleset        *aruleset;
> +     struct tcphdr            *th;
> +     int                       depth;
> +};
> +
> +#define      PF_ANCHOR_STACK_MAX     64
> +
> +/*
> + * Cannot fold into pf_pdesc directly, unknown storage size outside pf.c.
> + * Keep in sync with union pf_headers in pflog_bpfcopy() in if_pflog.c.
> + */
> +union pf_headers {
> +     struct tcphdr           tcp;
> +     struct udphdr           udp;
> +     struct icmp             icmp;
> +#ifdef INET6
> +     struct icmp6_hdr        icmp6;
> +     struct mld_hdr          mld;
> +     struct nd_neighbor_solicit nd_ns;
> +#endif /* INET6 */
> +};
> +
> +
>  
>  struct pool           pf_src_tree_pl, pf_rule_pl, pf_queue_pl;
>  struct pool           pf_state_pl, pf_state_key_pl, pf_state_item_pl;
> @@ -211,11 +253,8 @@ struct pf_state          *pf_find_state(struct p
>                           struct pf_state_key_cmp *, u_int, struct mbuf *);
>  int                   pf_src_connlimit(struct pf_state **);
>  int                   pf_match_rcvif(struct mbuf *, struct pf_rule *);
> -void                  pf_step_into_anchor(int *, struct pf_ruleset **,
> -                         struct pf_rule **, struct pf_rule **);
> -int                   pf_step_out_of_anchor(int *, struct pf_ruleset **,
> -                          struct pf_rule **, struct pf_rule **,
> -                          int *);
> +int                   pf_step_into_anchor(struct pf_test_ctx *, struct 
> pf_rule *);
> +int                   pf_match_rule(struct pf_test_ctx *, struct pf_ruleset 
> *);
>  void                  pf_counters_inc(int, struct pf_pdesc *,
>                           struct pf_state *, struct pf_rule *,
>                           struct pf_rule *);
> @@ -3020,74 +3059,39 @@ pf_tag_packet(struct mbuf *m, int tag, i
>               m->m_pkthdr.ph_rtableid = (u_int)rtableid;
>  }
>  
> -void
> -pf_step_into_anchor(int *depth, struct pf_ruleset **rs,
> -    struct pf_rule **r, struct pf_rule **a)
> +enum pf_test_status
> +pf_step_into_anchor(struct pf_test_ctx *ctx, struct pf_rule *r)
>  {
> -     struct pf_anchor_stackframe     *f;
> -
> -     if (*depth >= sizeof(pf_anchor_stack) /
> -         sizeof(pf_anchor_stack[0])) {
> -             log(LOG_ERR, "pf: anchor stack overflow\n");
> -             *r = TAILQ_NEXT(*r, entries);
> -             return;
> -     } else if (a != NULL)
> -             *a = *r;
> -     f = pf_anchor_stack + (*depth)++;
> -     f->rs = *rs;
> -     f->r = *r;
> -     if ((*r)->anchor_wildcard) {
> -             f->parent = &(*r)->anchor->children;
> -             if ((f->child = RB_MIN(pf_anchor_node, f->parent)) == NULL) {
> -                     *r = NULL;
> -                     return;
> -             }
> -             *rs = &f->child->ruleset;
> -     } else {
> -             f->parent = NULL;
> -             f->child = NULL;
> -             *rs = &(*r)->anchor->ruleset;
> -     }
> -     *r = TAILQ_FIRST((*rs)->rules.active.ptr);
> -}
> -
> -int
> -pf_step_out_of_anchor(int *depth, struct pf_ruleset **rs,
> -    struct pf_rule **r, struct pf_rule **a, int *match)
> -{
> -     struct pf_anchor_stackframe     *f;
> -     int quick = 0;
> -
> -     do {
> -             if (*depth <= 0)
> -                     break;
> -             f = pf_anchor_stack + *depth - 1;
> -             if (f->parent != NULL && f->child != NULL) {
> -                     f->child = RB_NEXT(pf_anchor_node, f->parent, f->child);
> -                     if (f->child != NULL) {
> -                             *rs = &f->child->ruleset;
> -                             *r = TAILQ_FIRST((*rs)->rules.active.ptr);
> -                             if (*r == NULL)
> -                                     continue;
> -                             else
> -                                     break;
> +     int     rv;
> +
> +     if (ctx->depth >= PF_ANCHOR_STACK_MAX) {
> +             log(LOG_ERR, "pf_step_into_anchor: stack overflow\n");
> +             return (PF_TEST_FAIL);
> +     }
> +
> +     ctx->depth++;
> +
> +     if (r->anchor_wildcard) {
> +             struct pf_anchor        *child;
> +             rv = PF_TEST_OK;
> +             RB_FOREACH(child, pf_anchor_node, &r->anchor->children) {
> +                     rv = pf_match_rule(ctx, &child->ruleset);
> +                     if ((rv == PF_TEST_QUICK) || (rv == PF_TEST_FAIL)) {
> +                             /*
> +                              * we either hit a rule qith quick action
> +                              * (more likely), or hit some runtime
> +                              * error (e.g. pool_get() faillure).
> +                              */
> +                             break;
>                       }
>               }
> -             (*depth)--;
> -             if (*depth == 0 && a != NULL)
> -                     *a = NULL;
> -             else if (a != NULL)
> -                     *a = f->r;
> -             *rs = f->rs;
> -             if (*match > *depth) {
> -                     *match = *depth;
> -                     if (f->r->quick)
> -                             quick = 1;
> -             }
> -             *r = TAILQ_NEXT(f->r, entries);
> -     } while (*r == NULL);
> -
> -     return (quick);
> +     } else {
> +             rv = pf_match_rule(ctx, &r->anchor->ruleset);
> +     }
> +
> +     ctx->depth--;
> +
> +     return (rv);
>  }
>  
>  void
> @@ -3451,54 +3455,241 @@ pf_rule_to_actions(struct pf_rule *r, st
>  }
>  
>  #define PF_TEST_ATTRIB(t, a)                 \
> -     do {                                    \
> -             if (t) {                        \
> -                     r = a;                  \
> -                     goto nextrule;          \
> -             }                               \
> +     if (t) {                                \
> +             r = a;                          \
> +             continue;                       \
> +     } else do {                             \
>       } while (0)
>  
> +enum pf_test_status
> +pf_match_rule(struct pf_test_ctx *ctx, struct pf_ruleset *ruleset)
> +{
> +     struct pf_rule  *r;
> +
> +     r = TAILQ_FIRST(ruleset->rules.active.ptr);
> +     while (r != NULL) {
> +             r->evaluations++;
> +             PF_TEST_ATTRIB(
> +                 (pfi_kif_match(r->kif, ctx->pd->kif) == r->ifnot),
> +                     r->skip[PF_SKIP_IFP].ptr);
> +             PF_TEST_ATTRIB((r->direction && r->direction != ctx->pd->dir),
> +                     r->skip[PF_SKIP_DIR].ptr);
> +             PF_TEST_ATTRIB((r->onrdomain >= 0  &&
> +                 (r->onrdomain == ctx->pd->rdomain) == r->ifnot),
> +                     r->skip[PF_SKIP_RDOM].ptr);
> +             PF_TEST_ATTRIB((r->af && r->af != ctx->pd->af),
> +                     r->skip[PF_SKIP_AF].ptr);
> +             PF_TEST_ATTRIB((r->proto && r->proto != ctx->pd->proto),
> +                     r->skip[PF_SKIP_PROTO].ptr);
> +             PF_TEST_ATTRIB((PF_MISMATCHAW(&r->src.addr, &ctx->pd->nsaddr,
> +                 ctx->pd->naf, r->src.neg, ctx->pd->kif,
> +                 ctx->act.rtableid)),
> +                     r->skip[PF_SKIP_SRC_ADDR].ptr);
> +             PF_TEST_ATTRIB((PF_MISMATCHAW(&r->dst.addr, &ctx->pd->ndaddr,
> +                 ctx->pd->af, r->dst.neg, NULL, ctx->act.rtableid)),
> +                     r->skip[PF_SKIP_DST_ADDR].ptr);
> +
> +             switch (ctx->pd->virtual_proto) {
> +             case PF_VPROTO_FRAGMENT:
> +                     /* tcp/udp only. port_op always 0 in other cases */
> +                     PF_TEST_ATTRIB((r->src.port_op || r->dst.port_op),
> +                             TAILQ_NEXT(r, entries));
> +                     PF_TEST_ATTRIB((ctx->pd->proto == IPPROTO_TCP &&
> +                         r->flagset),
> +                             TAILQ_NEXT(r, entries));
> +                     /* icmp only. type/code always 0 in other cases */
> +                     PF_TEST_ATTRIB((r->type || r->code),
> +                             TAILQ_NEXT(r, entries));
> +                     /* tcp/udp only. {uid|gid}.op always 0 in other cases */
> +                     PF_TEST_ATTRIB((r->gid.op || r->uid.op),
> +                             TAILQ_NEXT(r, entries));
> +                     break;
> +
> +             case IPPROTO_TCP:
> +                     PF_TEST_ATTRIB(((r->flagset & ctx->th->th_flags) !=
> +                         r->flags),
> +                             TAILQ_NEXT(r, entries));
> +                     PF_TEST_ATTRIB((r->os_fingerprint != PF_OSFP_ANY &&
> +                         !pf_osfp_match(pf_osfp_fingerprint(ctx->pd),
> +                         r->os_fingerprint)),
> +                             TAILQ_NEXT(r, entries));
> +                     /* FALLTHROUGH */
> +
> +             case IPPROTO_UDP:
> +                     /* tcp/udp only. port_op always 0 in other cases */
> +                     PF_TEST_ATTRIB((r->src.port_op &&
> +                         !pf_match_port(r->src.port_op, r->src.port[0],
> +                         r->src.port[1], ctx->pd->nsport)),
> +                             r->skip[PF_SKIP_SRC_PORT].ptr);
> +                     PF_TEST_ATTRIB((r->dst.port_op &&
> +                         !pf_match_port(r->dst.port_op, r->dst.port[0],
> +                         r->dst.port[1], ctx->pd->ndport)),
> +                             r->skip[PF_SKIP_DST_PORT].ptr);
> +                     /* tcp/udp only. uid.op always 0 in other cases */
> +                     PF_TEST_ATTRIB((r->uid.op && (ctx->pd->lookup.done ||
> +                         (ctx->pd->lookup.done =
> +                         pf_socket_lookup(ctx->pd), 1)) &&
> +                         !pf_match_uid(r->uid.op, r->uid.uid[0],
> +                         r->uid.uid[1], ctx->pd->lookup.uid)),
> +                             TAILQ_NEXT(r, entries));
> +                     /* tcp/udp only. gid.op always 0 in other cases */
> +                     PF_TEST_ATTRIB((r->gid.op && (ctx->pd->lookup.done ||
> +                         (ctx->pd->lookup.done =
> +                         pf_socket_lookup(ctx->pd), 1)) &&
> +                         !pf_match_gid(r->gid.op, r->gid.gid[0],
> +                         r->gid.gid[1], ctx->pd->lookup.gid)),
> +                             TAILQ_NEXT(r, entries));
> +                     break;
> +
> +             case IPPROTO_ICMP:
> +             case IPPROTO_ICMPV6:
> +                     /* icmp only. type always 0 in other cases */
> +                     PF_TEST_ATTRIB((r->type &&
> +                         r->type != ctx->icmptype + 1),
> +                             TAILQ_NEXT(r, entries));
> +                     /* icmp only. type always 0 in other cases */
> +                     PF_TEST_ATTRIB((r->code &&
> +                         r->code != ctx->icmpcode + 1),
> +                             TAILQ_NEXT(r, entries));
> +                     /* icmp only. don't create states on replies */
> +                     PF_TEST_ATTRIB((r->keep_state && !ctx->state_icmp &&
> +                         (r->rule_flag & PFRULE_STATESLOPPY) == 0 &&
> +                         ctx->icmp_dir != PF_IN),
> +                             TAILQ_NEXT(r, entries));
> +                     break;
> +
> +             default:
> +                     break;
> +             }
> +
> +             PF_TEST_ATTRIB((r->rule_flag & PFRULE_FRAGMENT &&
> +                 ctx->pd->virtual_proto != PF_VPROTO_FRAGMENT),
> +                     TAILQ_NEXT(r, entries));
> +             PF_TEST_ATTRIB((r->tos && !(r->tos == ctx->pd->tos)),
> +                     TAILQ_NEXT(r, entries));
> +             PF_TEST_ATTRIB((r->prob &&
> +                 r->prob <= arc4random_uniform(UINT_MAX - 1) + 1),
> +                     TAILQ_NEXT(r, entries));
> +             PF_TEST_ATTRIB((r->match_tag &&
> +                 !pf_match_tag(ctx->pd->m, r, &ctx->tag)),
> +                     TAILQ_NEXT(r, entries));
> +             PF_TEST_ATTRIB((r->rcv_kif && pf_match_rcvif(ctx->pd->m, r) ==
> +                 r->rcvifnot),
> +                     TAILQ_NEXT(r, entries));
> +             PF_TEST_ATTRIB((r->prio &&
> +                 (r->prio == PF_PRIO_ZERO ? 0 : r->prio) !=
> +                 ctx->pd->m->m_pkthdr.pf.prio),
> +                     TAILQ_NEXT(r, entries));
> +
> +             /* FALLTHROUGH */
> +             if (r->tag)
> +                     ctx->tag = r->tag;
> +             if (r->anchor == NULL) {
> +                     if (r->action == PF_MATCH) {
> +                             if ((ctx->ri = pool_get(&pf_rule_item_pl,
> +                                 PR_NOWAIT)) == NULL) {
> +                                     REASON_SET(&ctx->reason, PFRES_MEMORY);
> +                                     ctx->test_status = PF_TEST_FAIL;
> +                                     break;
> +                             }
> +                             ctx->ri->r = r;
> +                             /* order is irrelevant */
> +                             SLIST_INSERT_HEAD(&ctx->rules, ctx->ri, entry);
> +                             ctx->ri = NULL;
> +                             pf_rule_to_actions(r, &ctx->act);
> +                             if (r->rule_flag & PFRULE_AFTO)
> +                                     ctx->pd->naf = r->naf;
> +                             if (pf_get_transaddr(r, ctx->pd, ctx->sns,
> +                                 &ctx->nr) == -1) {
> +                                     REASON_SET(&ctx->reason,
> +                                         PFRES_TRANSLATE);
> +                                     ctx->test_status = PF_TEST_FAIL;
> +                                     break;
> +                             }
> +#if NPFLOG > 0 
> +                             if (r->log) {
> +                                     REASON_SET(&ctx->reason, PFRES_MATCH);
> +                                     PFLOG_PACKET(ctx->pd, ctx->reason, r,
> +                                         ctx->a, ruleset, NULL);
> +                             }
> +#endif       /* NPFLOG > 0 */
> +                     } else {
> +                             /*
> +                              * found matching r
> +                              */
> +                             *ctx->rm = r;
> +                             /*
> +                              * anchor, with ruleset, where r belongs to
> +                              */
> +                             *ctx->am = ctx->a;
> +                             /*
> +                              * ruleset where r belongs to
> +                              */
> +                             *ctx->rsm = ruleset;
> +                             /*
> +                              * ruleset, where anchor belongs to.
> +                              */
> +                             ctx->arsm = ctx->aruleset;
> +                     }
> +
> +#if NPFLOG > 0
> +                     if (ctx->act.log & PF_LOG_MATCHES)
> +                             pf_log_matches(ctx->pd, r, ctx->a, ruleset,
> +                                 &ctx->rules);
> +#endif       /* NPFLOG > 0 */
> +
> +                     if (r->quick) {
> +                             ctx->test_status = PF_TEST_QUICK;
> +                             break;
> +                     }
> +             } else {
> +                     ctx->a = r;             /* remember anchor */
> +                     ctx->aruleset = ruleset;        /* and its ruleset */
> +                     if (pf_step_into_anchor(ctx, r) != PF_TEST_OK) {
> +                             break;
> +                     }
> +             }
> +             r = TAILQ_NEXT(r, entries);
> +     }
> +
> +     return (ctx->test_status);
> +}
> +
>  int
>  pf_test_rule(struct pf_pdesc *pd, struct pf_rule **rm, struct pf_state **sm,
>      struct pf_rule **am, struct pf_ruleset **rsm, u_short *reason)
>  {
> -     struct pf_rule          *r;
> -     struct pf_rule          *nr = NULL;
> +     struct pf_rule          *r = NULL;
>       struct pf_rule          *a = NULL;
> -     struct pf_ruleset       *arsm = NULL;
> -     struct pf_ruleset       *aruleset = NULL;
>       struct pf_ruleset       *ruleset = NULL;
> -     struct pf_rule_slist     rules;
> -     struct pf_rule_item     *ri;
> -     struct pf_src_node      *sns[PF_SN_MAX];
>       struct pf_state_key     *skw = NULL, *sks = NULL;
> -     struct pf_rule_actions   act;
>       int                      rewrite = 0;
> -     int                      tag = -1;
> -     int                      asd = 0;
> -     int                      match = 0;
> -     int                      state_icmp = 0, icmp_dir = 0;
>       u_int16_t                virtual_type, virtual_id;
> -     u_int8_t                 icmptype = 0, icmpcode = 0;
>       int                      action = PF_DROP;
> -
> -     bzero(&act, sizeof(act));
> -     bzero(sns, sizeof(sns));
> -     act.rtableid = pd->rdomain;
> -     SLIST_INIT(&rules);
> +     struct pf_test_ctx       ctx;
> +     int                      rv;
> +
> +     bzero(&ctx, sizeof(ctx));
> +     ctx.pd = pd;
> +     ctx.rm = rm;
> +     ctx.am = am;
> +     ctx.rsm = rsm;
> +     ctx.th = &pd->hdr.tcp;
> +     ctx.act.rtableid = pd->rdomain;
> +     SLIST_INIT(&ctx.rules);
>  
>       if (pd->dir == PF_IN && if_congested()) {
> -             REASON_SET(reason, PFRES_CONGEST);
> +             REASON_SET(&ctx.reason, PFRES_CONGEST);
>               return (PF_DROP);
>       }
>  
>       switch (pd->virtual_proto) {
>       case IPPROTO_ICMP:
> -             icmptype = pd->hdr.icmp.icmp_type;
> -             icmpcode = pd->hdr.icmp.icmp_code;
> -             state_icmp = pf_icmp_mapping(pd, icmptype,
> -                 &icmp_dir, &virtual_id, &virtual_type);
> -             if (icmp_dir == PF_IN) {
> +             ctx.icmptype = pd->hdr.icmp.icmp_type;
> +             ctx.icmpcode = pd->hdr.icmp.icmp_code;
> +             ctx.state_icmp = pf_icmp_mapping(pd, ctx.icmptype,
> +                 &ctx.icmp_dir, &virtual_id, &virtual_type);
> +             if (ctx.icmp_dir == PF_IN) {
>                       pd->osport = pd->nsport = virtual_id;
>                       pd->odport = pd->ndport = virtual_type;
>               } else {
> @@ -3508,11 +3699,11 @@ pf_test_rule(struct pf_pdesc *pd, struct
>               break;
>  #ifdef INET6
>       case IPPROTO_ICMPV6:
> -             icmptype = pd->hdr.icmp6.icmp6_type;
> -             icmpcode = pd->hdr.icmp6.icmp6_code;
> -             state_icmp = pf_icmp_mapping(pd, icmptype,
> -                 &icmp_dir, &virtual_id, &virtual_type);
> -             if (icmp_dir == PF_IN) {
> +             ctx.icmptype = pd->hdr.icmp6.icmp6_type;
> +             ctx.icmpcode = pd->hdr.icmp6.icmp6_code;
> +             ctx.state_icmp = pf_icmp_mapping(pd, ctx.icmptype,
> +                 &ctx.icmp_dir, &virtual_id, &virtual_type);
> +             if (ctx.icmp_dir == PF_IN) {
>                       pd->osport = pd->nsport = virtual_id;
>                       pd->odport = pd->ndport = virtual_type;
>               } else {
> @@ -3524,191 +3715,36 @@ pf_test_rule(struct pf_pdesc *pd, struct
>       }
>  
>       ruleset = &pf_main_ruleset;
> -     r = TAILQ_FIRST(pf_main_ruleset.rules.active.ptr);
> -     while (r != NULL) {
> -             if (r->rule_flag & PFRULE_EXPIRED) {
> -                     r = TAILQ_NEXT(r, entries);
> -                     goto nextrule;
> -             }
> -             r->evaluations++;
> -             PF_TEST_ATTRIB((pfi_kif_match(r->kif, pd->kif) == r->ifnot),
> -                     r->skip[PF_SKIP_IFP].ptr);
> -             PF_TEST_ATTRIB((r->direction && r->direction != pd->dir),
> -                     r->skip[PF_SKIP_DIR].ptr);
> -             PF_TEST_ATTRIB((r->onrdomain >= 0  &&
> -                 (r->onrdomain == pd->rdomain) == r->ifnot),
> -                     r->skip[PF_SKIP_RDOM].ptr);
> -             PF_TEST_ATTRIB((r->af && r->af != pd->af),
> -                     r->skip[PF_SKIP_AF].ptr);
> -             PF_TEST_ATTRIB((r->proto && r->proto != pd->proto),
> -                     r->skip[PF_SKIP_PROTO].ptr);
> -             PF_TEST_ATTRIB((PF_MISMATCHAW(&r->src.addr, &pd->nsaddr,
> -                 pd->naf, r->src.neg, pd->kif, act.rtableid)),
> -                     r->skip[PF_SKIP_SRC_ADDR].ptr);
> -             PF_TEST_ATTRIB((PF_MISMATCHAW(&r->dst.addr, &pd->ndaddr, pd->af,
> -                 r->dst.neg, NULL, act.rtableid)),
> -                     r->skip[PF_SKIP_DST_ADDR].ptr);
> -
> -             switch (pd->virtual_proto) {
> -             case PF_VPROTO_FRAGMENT:
> -                     /* tcp/udp only. port_op always 0 in other cases */
> -                     PF_TEST_ATTRIB((r->src.port_op || r->dst.port_op),
> -                             TAILQ_NEXT(r, entries));
> -                     PF_TEST_ATTRIB((pd->proto == IPPROTO_TCP && r->flagset),
> -                             TAILQ_NEXT(r, entries));
> -                     /* icmp only. type/code always 0 in other cases */
> -                     PF_TEST_ATTRIB((r->type || r->code),
> -                             TAILQ_NEXT(r, entries));
> -                     /* tcp/udp only. {uid|gid}.op always 0 in other cases */
> -                     PF_TEST_ATTRIB((r->gid.op || r->uid.op),
> -                             TAILQ_NEXT(r, entries));
> -                     break;
> -
> -             case IPPROTO_TCP:
> -                     PF_TEST_ATTRIB(((r->flagset & pd->hdr.tcp.th_flags) !=
> -                         r->flags),
> -                             TAILQ_NEXT(r, entries));
> -                     PF_TEST_ATTRIB((r->os_fingerprint != PF_OSFP_ANY &&
> -                         !pf_osfp_match(pf_osfp_fingerprint(pd),
> -                         r->os_fingerprint)),
> -                             TAILQ_NEXT(r, entries));
> -                     /* FALLTHROUGH */
> -
> -             case IPPROTO_UDP:
> -                     /* tcp/udp only. port_op always 0 in other cases */
> -                     PF_TEST_ATTRIB((r->src.port_op &&
> -                         !pf_match_port(r->src.port_op, r->src.port[0],
> -                         r->src.port[1], pd->nsport)),
> -                             r->skip[PF_SKIP_SRC_PORT].ptr);
> -                     PF_TEST_ATTRIB((r->dst.port_op &&
> -                         !pf_match_port(r->dst.port_op, r->dst.port[0],
> -                         r->dst.port[1], pd->ndport)),
> -                             r->skip[PF_SKIP_DST_PORT].ptr);
> -                     /* tcp/udp only. uid.op always 0 in other cases */
> -                     PF_TEST_ATTRIB((r->uid.op && (pd->lookup.done ||
> -                         (pd->lookup.done =
> -                         pf_socket_lookup(pd), 1)) &&
> -                         !pf_match_uid(r->uid.op, r->uid.uid[0],
> -                         r->uid.uid[1], pd->lookup.uid)),
> -                             TAILQ_NEXT(r, entries));
> -                     /* tcp/udp only. gid.op always 0 in other cases */
> -                     PF_TEST_ATTRIB((r->gid.op && (pd->lookup.done ||
> -                         (pd->lookup.done =
> -                         pf_socket_lookup(pd), 1)) &&
> -                         !pf_match_gid(r->gid.op, r->gid.gid[0],
> -                         r->gid.gid[1], pd->lookup.gid)),
> -                             TAILQ_NEXT(r, entries));
> -                     break;
> -
> -             case IPPROTO_ICMP:
> -             case IPPROTO_ICMPV6:
> -                     /* icmp only. type always 0 in other cases */
> -                     PF_TEST_ATTRIB((r->type && r->type != icmptype + 1),
> -                             TAILQ_NEXT(r, entries));
> -                     /* icmp only. type always 0 in other cases */
> -                     PF_TEST_ATTRIB((r->code && r->code != icmpcode + 1),
> -                             TAILQ_NEXT(r, entries));
> -                     /* icmp only. don't create states on replies */
> -                     PF_TEST_ATTRIB((r->keep_state && !state_icmp &&
> -                         (r->rule_flag & PFRULE_STATESLOPPY) == 0 &&
> -                         icmp_dir != PF_IN),
> -                             TAILQ_NEXT(r, entries));
> -                     break;
> -
> -             default:
> -                     break;
> -             }
> -
> -             PF_TEST_ATTRIB((r->rule_flag & PFRULE_FRAGMENT &&
> -                 pd->virtual_proto != PF_VPROTO_FRAGMENT),
> -                     TAILQ_NEXT(r, entries));
> -             PF_TEST_ATTRIB((r->tos && !(r->tos == pd->tos)),
> -                     TAILQ_NEXT(r, entries));
> -             PF_TEST_ATTRIB((r->prob &&
> -                 r->prob <= arc4random_uniform(UINT_MAX - 1) + 1),
> -                     TAILQ_NEXT(r, entries));
> -             PF_TEST_ATTRIB((r->match_tag && !pf_match_tag(pd->m, r, &tag)),
> -                     TAILQ_NEXT(r, entries));
> -             PF_TEST_ATTRIB((r->rcv_kif && pf_match_rcvif(pd->m, r) ==
> -                 r->rcvifnot),
> -                     TAILQ_NEXT(r, entries));
> -             PF_TEST_ATTRIB((r->prio && (r->prio == PF_PRIO_ZERO ?
> -                 0 : r->prio) != pd->m->m_pkthdr.pf.prio),
> -                     TAILQ_NEXT(r, entries));
> -
> -             /* FALLTHROUGH */
> -             if (r->tag)
> -                     tag = r->tag;
> -             if (r->anchor == NULL) {
> -                     if (r->action == PF_MATCH) {
> -                             if ((ri = pool_get(&pf_rule_item_pl,
> -                                 PR_NOWAIT)) == NULL) {
> -                                     REASON_SET(reason, PFRES_MEMORY);
> -                                     goto cleanup;
> -                             }
> -                             ri->r = r;
> -                             /* order is irrelevant */
> -                             SLIST_INSERT_HEAD(&rules, ri, entry);
> -                             pf_rule_to_actions(r, &act);
> -                             if (r->rule_flag & PFRULE_AFTO)
> -                                     pd->naf = r->naf;
> -                             if (pf_get_transaddr(r, pd, sns, &nr) == -1) {
> -                                     REASON_SET(reason, PFRES_TRANSLATE);
> -                                     goto cleanup;
> -                             }
> -#if NPFLOG > 0
> -                             if (r->log) {
> -                                     REASON_SET(reason, PFRES_MATCH);
> -                                     PFLOG_PACKET(pd, *reason, r, a, ruleset,
> -                                         NULL);
> -                             }
> -#endif       /* NPFLOG > 0 */
> -                     } else {
> -                             match = asd;
> -                             *rm = r;
> -                             *am = a;
> -                             *rsm = ruleset;
> -                             arsm = aruleset;
> -                     }
> -
> -#if NPFLOG > 0
> -                     if (act.log & PF_LOG_MATCHES)
> -                             pf_log_matches(pd, r, a, ruleset, &rules);
> -#endif       /* NPFLOG > 0 */
> -
> -                     if (r->quick)
> -                             break;
> -                     r = TAILQ_NEXT(r, entries);
> -             } else {
> -                     aruleset = ruleset;
> -                     pf_step_into_anchor(&asd, &ruleset, &r, &a);
> -             }
> -
> - nextrule:
> -             if (r == NULL && pf_step_out_of_anchor(&asd, &ruleset,
> -                 &r, &a, &match))
> -                     break;
> -     }
> -     r = *rm;        /* matching rule */
> -     a = *am;        /* rule that defines an anchor containing 'r' */
> -     ruleset = *rsm; /* ruleset of the anchor defined by the rule 'a' */
> -     aruleset = arsm;/* ruleset of the 'a' rule itself */
> +     rv = pf_match_rule(&ctx, ruleset);
> +     if (rv == PF_TEST_FAIL) {
> +             /*
> +              * Reason has been set in pf_match_rule() already.
> +              */
> +             goto cleanup;
> +     }
> +
> +     r = *ctx.rm;    /* matching rule */
> +     a = *ctx.am;    /* rule that defines an anchor containing 'r' */
> +     ruleset = *ctx.rsm;/* ruleset of the anchor defined by the rule 'a' */
> +     ctx.aruleset = ctx.arsm;/* ruleset of the 'a' rule itself */
> +
> +
>  
>       /* apply actions for last matching pass/block rule */
> -     pf_rule_to_actions(r, &act);
> +     pf_rule_to_actions(r, &ctx.act);
>       if (r->rule_flag & PFRULE_AFTO)
>               pd->naf = r->naf;
> -     if (pf_get_transaddr(r, pd, sns, &nr) == -1) {
> -             REASON_SET(reason, PFRES_TRANSLATE);
> +     if (pf_get_transaddr(r, pd, ctx.sns, &ctx.nr) == -1) {
> +             REASON_SET(&ctx.reason, PFRES_TRANSLATE);
>               goto cleanup;
>       }
> -     REASON_SET(reason, PFRES_MATCH);
> +     REASON_SET(&ctx.reason, PFRES_MATCH);
>  
>  #if NPFLOG > 0
>       if (r->log)
> -             PFLOG_PACKET(pd, *reason, r, a, ruleset, NULL);
> -     if (act.log & PF_LOG_MATCHES)
> -             pf_log_matches(pd, r, a, ruleset, &rules);
> +             PFLOG_PACKET(pd, ctx.reason, r, ctx.a, ruleset, NULL);
> +     if (ctx.act.log & PF_LOG_MATCHES)
> +             pf_log_matches(pd, r, ctx.a, ruleset, &ctx.rules);
>  #endif       /* NPFLOG > 0 */
>  
>       if (pd->virtual_proto != PF_VPROTO_FRAGMENT &&
> @@ -3719,31 +3755,32 @@ pf_test_rule(struct pf_pdesc *pd, struct
>               if (pd->proto == IPPROTO_TCP &&
>                   ((r->rule_flag & PFRULE_RETURNRST) ||
>                   (r->rule_flag & PFRULE_RETURN)) &&
> -                 !(pd->hdr.tcp.th_flags & TH_RST)) {
> -                     struct tcphdr   *th = &pd->hdr.tcp;
> -                     u_int32_t ack = ntohl(th->th_seq) + pd->p_len;
> +                 !(ctx.th->th_flags & TH_RST)) {
> +                     u_int32_t        ack =
> +                         ntohl(ctx.th->th_seq) + pd->p_len;
>  
>                       if (pf_check_tcp_cksum(pd->m, pd->off,
>                           pd->tot_len - pd->off, pd->af))
> -                             REASON_SET(reason, PFRES_PROTCKSUM);
> +                             REASON_SET(&ctx.reason, PFRES_PROTCKSUM);
>                       else {
> -                             if (th->th_flags & TH_SYN)
> +                             if (ctx.th->th_flags & TH_SYN)
>                                       ack++;
> -                             if (th->th_flags & TH_FIN)
> +                             if (ctx.th->th_flags & TH_FIN)
>                                       ack++;
>                               pf_send_tcp(r, pd->af, pd->dst,
> -                                 pd->src, th->th_dport, th->th_sport,
> -                                 ntohl(th->th_ack), ack, TH_RST|TH_ACK, 0, 0,
> -                                 r->return_ttl, 1, 0, pd->rdomain);
> +                                 pd->src, ctx.th->th_dport,
> +                                 ctx.th->th_sport, ntohl(ctx.th->th_ack),
> +                                 ack, TH_RST|TH_ACK, 0, 0, r->return_ttl,
> +                                 1, 0, pd->rdomain);
>                       }
>               } else if ((pd->proto != IPPROTO_ICMP ||
> -                 ICMP_INFOTYPE(icmptype)) && pd->af == AF_INET &&
> +                 ICMP_INFOTYPE(ctx.icmptype)) && pd->af == AF_INET &&
>                   r->return_icmp)
>                       pf_send_icmp(pd->m, r->return_icmp >> 8,
>                           r->return_icmp & 255, pd->af, r, pd->rdomain);
>               else if ((pd->proto != IPPROTO_ICMPV6 ||
> -                 (icmptype >= ICMP6_ECHO_REQUEST &&
> -                 icmptype != ND_REDIRECT)) && pd->af == AF_INET6 &&
> +                 (ctx.icmptype >= ICMP6_ECHO_REQUEST &&
> +                 ctx.icmptype != ND_REDIRECT)) && pd->af == AF_INET6 &&
>                   r->return_icmp6)
>                       pf_send_icmp(pd->m, r->return_icmp6 >> 8,
>                           r->return_icmp6 & 255, pd->af, r, pd->rdomain);
> @@ -3752,13 +3789,13 @@ pf_test_rule(struct pf_pdesc *pd, struct
>       if (r->action == PF_DROP)
>               goto cleanup;
>  
> -     pf_tag_packet(pd->m, tag, act.rtableid);
> -     if (act.rtableid >= 0 &&
> -         rtable_l2(act.rtableid) != pd->rdomain)
> +     pf_tag_packet(pd->m, ctx.tag, ctx.act.rtableid);
> +     if (ctx.act.rtableid >= 0 &&
> +         rtable_l2(ctx.act.rtableid) != pd->rdomain)
>               pd->destchg = 1;
>  
>       if (r->action == PF_PASS && pd->badopts && ! r->allow_opts) {
> -             REASON_SET(reason, PFRES_IPOPTIONS);
> +             REASON_SET(&ctx.reason, PFRES_IPOPTIONS);
>  #if NPFLOG > 0
>               pd->pflog |= PF_LOG_FORCE;
>  #endif       /* NPFLOG > 0 */
> @@ -3770,23 +3807,23 @@ pf_test_rule(struct pf_pdesc *pd, struct
>       action = PF_PASS;
>  
>       if (pd->virtual_proto != PF_VPROTO_FRAGMENT
> -         && !state_icmp && r->keep_state) {
> +         && !ctx.state_icmp && r->keep_state) {
>  
>               if (r->rule_flag & PFRULE_SRCTRACK &&
> -                 pf_insert_src_node(&sns[PF_SN_NONE], r, PF_SN_NONE, pd->af,
> -                 pd->src, NULL) != 0) {
> -                     REASON_SET(reason, PFRES_SRCLIMIT);
> +                 pf_insert_src_node(&ctx.sns[PF_SN_NONE], r, PF_SN_NONE,
> +                 pd->af, pd->src, NULL) != 0) {
> +                     REASON_SET(&ctx.reason, PFRES_SRCLIMIT);
>                       goto cleanup;
>               }
>  
>               if (r->max_states && (r->states_cur >= r->max_states)) {
>                       pf_status.lcounters[LCNT_STATES]++;
> -                     REASON_SET(reason, PFRES_MAXSTATES);
> +                     REASON_SET(&ctx.reason, PFRES_MAXSTATES);
>                       goto cleanup;
>               }
>  
> -             action = pf_create_state(pd, r, a, nr, &skw, &sks, &rewrite,
> -                 sm, tag, &rules, &act, sns);
> +             action = pf_create_state(pd, r, a, ctx.nr, &skw, &sks,
> +                 &rewrite, sm, ctx.tag, &ctx.rules, &ctx.act, ctx.sns);
>  
>               if (action != PF_PASS)
>                       goto cleanup;
> @@ -3802,7 +3839,7 @@ pf_test_rule(struct pf_pdesc *pd, struct
>                           sk->port[pd->af == pd->naf ? pd->sidx : pd->didx],
>                           &sk->addr[pd->af == pd->naf ? pd->didx : pd->sidx],
>                           sk->port[pd->af == pd->naf ? pd->didx : pd->sidx],
> -                         virtual_type, icmp_dir);
> +                         virtual_type, ctx.icmp_dir);
>               }
>  
>  #ifdef INET6
> @@ -3811,9 +3848,9 @@ pf_test_rule(struct pf_pdesc *pd, struct
>  #endif /* INET6 */
>  
>       } else {
> -             while ((ri = SLIST_FIRST(&rules))) {
> -                     SLIST_REMOVE_HEAD(&rules, entry);
> -                     pool_put(&pf_rule_item_pl, ri);
> +             while ((ctx.ri = SLIST_FIRST(&ctx.rules))) {
> +                     SLIST_REMOVE_HEAD(&ctx.rules, entry);
> +                     pool_put(&pf_rule_item_pl, ctx.ri);
>               }
>       }
>  
> @@ -3845,9 +3882,9 @@ pf_test_rule(struct pf_pdesc *pd, struct
>       return (action);
>  
>  cleanup:
> -     while ((ri = SLIST_FIRST(&rules))) {
> -             SLIST_REMOVE_HEAD(&rules, entry);
> -             pool_put(&pf_rule_item_pl, ri);
> +     while ((ctx.ri = SLIST_FIRST(&ctx.rules))) {
> +             SLIST_REMOVE_HEAD(&ctx.rules, entry);
> +             pool_put(&pf_rule_item_pl, ctx.ri);
>       }
>  
>       return (action);

Reply via email to