Index: if_pfsync.c =================================================================== RCS file: /cvs/src/sys/net/if_pfsync.c,v retrieving revision 1.305 diff -u -p -r1.305 if_pfsync.c --- if_pfsync.c 21 Apr 2022 15:22:49 -0000 1.305 +++ if_pfsync.c 5 Nov 2022 17:31:57 -0000 @@ -523,213 +523,6 @@ pfsync_state_export(struct pfsync_state } int -pfsync_state_import(struct pfsync_state *sp, int flags) -{ - struct pf_state *st = NULL; - struct pf_state_key *skw = NULL, *sks = NULL; - struct pf_rule *r = NULL; - struct pfi_kif *kif; - int pool_flags; - int error = ENOMEM; - int n = 0; - - if (sp->creatorid == 0) { - DPFPRINTF(LOG_NOTICE, "pfsync_state_import: " - "invalid creator id: %08x", ntohl(sp->creatorid)); - return (EINVAL); - } - - if ((kif = pfi_kif_get(sp->ifname, NULL)) == NULL) { - DPFPRINTF(LOG_NOTICE, "pfsync_state_import: " - "unknown interface: %s", sp->ifname); - if (flags & PFSYNC_SI_IOCTL) - return (EINVAL); - return (0); /* skip this state */ - } - - if (sp->af == 0) - return (0); /* skip this state */ - - /* - * If the ruleset checksums match or the state is coming from the ioctl, - * it's safe to associate the state with the rule of that number. - */ - if (sp->rule != htonl(-1) && sp->anchor == htonl(-1) && - (flags & (PFSYNC_SI_IOCTL | PFSYNC_SI_CKSUM)) && ntohl(sp->rule) < - pf_main_ruleset.rules.active.rcount) { - TAILQ_FOREACH(r, pf_main_ruleset.rules.active.ptr, entries) - if (ntohl(sp->rule) == n++) - break; - } else - r = &pf_default_rule; - - if ((r->max_states && r->states_cur >= r->max_states)) - goto cleanup; - - if (flags & PFSYNC_SI_IOCTL) - pool_flags = PR_WAITOK | PR_LIMITFAIL | PR_ZERO; - else - pool_flags = PR_NOWAIT | PR_LIMITFAIL | PR_ZERO; - - if ((st = pool_get(&pf_state_pl, pool_flags)) == NULL) - goto cleanup; - - if ((skw = pf_alloc_state_key(pool_flags)) == NULL) - goto cleanup; - - if ((sp->key[PF_SK_WIRE].af && - (sp->key[PF_SK_WIRE].af != sp->key[PF_SK_STACK].af)) || - PF_ANEQ(&sp->key[PF_SK_WIRE].addr[0], - &sp->key[PF_SK_STACK].addr[0], sp->af) || - PF_ANEQ(&sp->key[PF_SK_WIRE].addr[1], - &sp->key[PF_SK_STACK].addr[1], sp->af) || - sp->key[PF_SK_WIRE].port[0] != sp->key[PF_SK_STACK].port[0] || - sp->key[PF_SK_WIRE].port[1] != sp->key[PF_SK_STACK].port[1] || - sp->key[PF_SK_WIRE].rdomain != sp->key[PF_SK_STACK].rdomain) { - if ((sks = pf_alloc_state_key(pool_flags)) == NULL) - goto cleanup; - } else - sks = skw; - - /* allocate memory for scrub info */ - if (pfsync_alloc_scrub_memory(&sp->src, &st->src) || - pfsync_alloc_scrub_memory(&sp->dst, &st->dst)) - goto cleanup; - - /* copy to state key(s) */ - skw->addr[0] = sp->key[PF_SK_WIRE].addr[0]; - skw->addr[1] = sp->key[PF_SK_WIRE].addr[1]; - skw->port[0] = sp->key[PF_SK_WIRE].port[0]; - skw->port[1] = sp->key[PF_SK_WIRE].port[1]; - skw->rdomain = ntohs(sp->key[PF_SK_WIRE].rdomain); - PF_REF_INIT(skw->refcnt); - skw->proto = sp->proto; - if (!(skw->af = sp->key[PF_SK_WIRE].af)) - skw->af = sp->af; - if (sks != skw) { - sks->addr[0] = sp->key[PF_SK_STACK].addr[0]; - sks->addr[1] = sp->key[PF_SK_STACK].addr[1]; - sks->port[0] = sp->key[PF_SK_STACK].port[0]; - sks->port[1] = sp->key[PF_SK_STACK].port[1]; - sks->rdomain = ntohs(sp->key[PF_SK_STACK].rdomain); - PF_REF_INIT(sks->refcnt); - if (!(sks->af = sp->key[PF_SK_STACK].af)) - sks->af = sp->af; - if (sks->af != skw->af) { - switch (sp->proto) { - case IPPROTO_ICMP: - sks->proto = IPPROTO_ICMPV6; - break; - case IPPROTO_ICMPV6: - sks->proto = IPPROTO_ICMP; - break; - default: - sks->proto = sp->proto; - } - } else - sks->proto = sp->proto; - - if (((sks->af != AF_INET) && (sks->af != AF_INET6)) || - ((skw->af != AF_INET) && (skw->af != AF_INET6))) { - error = EINVAL; - goto cleanup; - } - - } else if ((sks->af != AF_INET) && (sks->af != AF_INET6)) { - error = EINVAL; - goto cleanup; - } - st->rtableid[PF_SK_WIRE] = ntohl(sp->rtableid[PF_SK_WIRE]); - st->rtableid[PF_SK_STACK] = ntohl(sp->rtableid[PF_SK_STACK]); - - /* copy to state */ - st->rt_addr = sp->rt_addr; - st->rt = sp->rt; - st->creation = getuptime() - ntohl(sp->creation); - st->expire = getuptime(); - if (ntohl(sp->expire)) { - u_int32_t timeout; - - timeout = r->timeout[sp->timeout]; - if (!timeout) - timeout = pf_default_rule.timeout[sp->timeout]; - - /* sp->expire may have been adaptively scaled by export. */ - st->expire -= timeout - ntohl(sp->expire); - } - - st->direction = sp->direction; - st->log = sp->log; - st->timeout = sp->timeout; - st->state_flags = ntohs(sp->state_flags); - st->max_mss = ntohs(sp->max_mss); - st->min_ttl = sp->min_ttl; - st->set_tos = sp->set_tos; - st->set_prio[0] = sp->set_prio[0]; - st->set_prio[1] = sp->set_prio[1]; - - st->id = sp->id; - st->creatorid = sp->creatorid; - pf_state_peer_ntoh(&sp->src, &st->src); - pf_state_peer_ntoh(&sp->dst, &st->dst); - - st->rule.ptr = r; - st->anchor.ptr = NULL; - - st->pfsync_time = getuptime(); - st->sync_state = PFSYNC_S_NONE; - - refcnt_init(&st->refcnt); - - /* XXX when we have anchors, use STATE_INC_COUNTERS */ - r->states_cur++; - r->states_tot++; - - if (!ISSET(flags, PFSYNC_SI_IOCTL)) - SET(st->state_flags, PFSTATE_NOSYNC); - - /* - * We just set PFSTATE_NOSYNC bit, which prevents - * pfsync_insert_state() to insert state to pfsync. - */ - if (pf_state_insert(kif, &skw, &sks, st) != 0) { - /* XXX when we have anchors, use STATE_DEC_COUNTERS */ - r->states_cur--; - error = EEXIST; - goto cleanup_state; - } - - if (!ISSET(flags, PFSYNC_SI_IOCTL)) { - CLR(st->state_flags, PFSTATE_NOSYNC); - if (ISSET(st->state_flags, PFSTATE_ACK)) { - pfsync_q_ins(st, PFSYNC_S_IACK); - schednetisr(NETISR_PFSYNC); - } - } - CLR(st->state_flags, PFSTATE_ACK); - - return (0); - - cleanup: - if (skw == sks) - sks = NULL; - if (skw != NULL) - pool_put(&pf_state_key_pl, skw); - if (sks != NULL) - pool_put(&pf_state_key_pl, sks); - - cleanup_state: /* pf_state_insert frees the state keys */ - if (st) { - if (st->dst.scrub) - pool_put(&pf_state_scrub_pl, st->dst.scrub); - if (st->src.scrub) - pool_put(&pf_state_scrub_pl, st->src.scrub); - pool_put(&pf_state_pl, st); - } - return (error); -} - -int pfsync_input(struct mbuf **mp, int *offp, int proto, int af) { struct mbuf *n, *m = *mp; @@ -892,7 +685,7 @@ pfsync_in_ins(caddr_t buf, int len, int continue; } - if (pfsync_state_import(sp, flags) == ENOMEM) { + if (pf_state_import(sp, flags) == ENOMEM) { /* drop out, but process the rest of the actions */ break; } @@ -996,7 +789,7 @@ pfsync_in_upd(caddr_t buf, int len, int if (st == NULL) { /* insert the update */ PF_LOCK(); - error = pfsync_state_import(sp, flags); + error = pf_state_import(sp, flags); if (error) pfsyncstat_inc(pfsyncs_badstate); PF_UNLOCK(); @@ -2413,6 +2206,13 @@ pfsync_clear_states(u_int32_t creatorid, r.clr.creatorid = creatorid; pfsync_send_plus(&r, sizeof(r)); +} + +void +pfsync_iack(struct pf_state *st) +{ + pfsync_q_ins(st, PFSYNC_S_IACK); + schednetisr(NETISR_PFSYNC); } void Index: if_pfsync.h =================================================================== RCS file: /cvs/src/sys/net/if_pfsync.h,v retrieving revision 1.57 diff -u -p -r1.57 if_pfsync.h --- if_pfsync.h 7 Jul 2021 18:38:25 -0000 1.57 +++ if_pfsync.h 5 Nov 2022 17:31:57 -0000 @@ -343,6 +343,8 @@ void pfsync_undefer(struct pfsync_defe int pfsync_up(void); int pfsync_state_in_use(struct pf_state *); + +void pfsync_iack(struct pf_state *); #endif /* _KERNEL */ #endif /* _NET_IF_PFSYNC_H_ */ Index: pf.c =================================================================== RCS file: /cvs/src/sys/net/pf.c,v retrieving revision 1.1141 diff -u -p -r1.1141 pf.c --- pf.c 10 Oct 2022 16:43:12 -0000 1.1141 +++ pf.c 5 Nov 2022 17:31:57 -0000 @@ -1261,6 +1261,226 @@ pf_state_export(struct pfsync_state *sp, sp->set_prio[1] = st->set_prio[1]; } +int +pf_state_alloc_scrub_memory(const struct pfsync_state_peer *s, + struct pf_state_peer *d) +{ + if (s->scrub.scrub_flag && d->scrub == NULL) + return (pf_normalize_tcp_alloc(d)); + + return (0); +} + +int +pf_state_import(const struct pfsync_state *sp, int flags) +{ + struct pf_state *st = NULL; + struct pf_state_key *skw = NULL, *sks = NULL; + struct pf_rule *r = NULL; + struct pfi_kif *kif; + int pool_flags; + int error = ENOMEM; + int n = 0; + + if (sp->creatorid == 0) { + DPFPRINTF(LOG_NOTICE, "%s: invalid creator id: %08x", __func__, + ntohl(sp->creatorid)); + return (EINVAL); + } + + if ((kif = pfi_kif_get(sp->ifname, NULL)) == NULL) { + DPFPRINTF(LOG_NOTICE, "%s: unknown interface: %s", __func__, + sp->ifname); + if (flags & PFSYNC_SI_IOCTL) + return (EINVAL); + return (0); /* skip this state */ + } + + if (sp->af == 0) + return (0); /* skip this state */ + + /* + * If the ruleset checksums match or the state is coming from the ioctl, + * it's safe to associate the state with the rule of that number. + */ + if (sp->rule != htonl(-1) && sp->anchor == htonl(-1) && + (flags & (PFSYNC_SI_IOCTL | PFSYNC_SI_CKSUM)) && + ntohl(sp->rule) < pf_main_ruleset.rules.active.rcount) { + TAILQ_FOREACH(r, pf_main_ruleset.rules.active.ptr, entries) + if (ntohl(sp->rule) == n++) + break; + } else + r = &pf_default_rule; + + if ((r->max_states && r->states_cur >= r->max_states)) + goto cleanup; + + if (flags & PFSYNC_SI_IOCTL) + pool_flags = PR_WAITOK | PR_LIMITFAIL | PR_ZERO; + else + pool_flags = PR_NOWAIT | PR_LIMITFAIL | PR_ZERO; + + if ((st = pool_get(&pf_state_pl, pool_flags)) == NULL) + goto cleanup; + + if ((skw = pf_alloc_state_key(pool_flags)) == NULL) + goto cleanup; + + if ((sp->key[PF_SK_WIRE].af && + (sp->key[PF_SK_WIRE].af != sp->key[PF_SK_STACK].af)) || + PF_ANEQ(&sp->key[PF_SK_WIRE].addr[0], + &sp->key[PF_SK_STACK].addr[0], sp->af) || + PF_ANEQ(&sp->key[PF_SK_WIRE].addr[1], + &sp->key[PF_SK_STACK].addr[1], sp->af) || + sp->key[PF_SK_WIRE].port[0] != sp->key[PF_SK_STACK].port[0] || + sp->key[PF_SK_WIRE].port[1] != sp->key[PF_SK_STACK].port[1] || + sp->key[PF_SK_WIRE].rdomain != sp->key[PF_SK_STACK].rdomain) { + if ((sks = pf_alloc_state_key(pool_flags)) == NULL) + goto cleanup; + } else + sks = skw; + + /* allocate memory for scrub info */ + if (pf_state_alloc_scrub_memory(&sp->src, &st->src) || + pf_state_alloc_scrub_memory(&sp->dst, &st->dst)) + goto cleanup; + + /* copy to state key(s) */ + skw->addr[0] = sp->key[PF_SK_WIRE].addr[0]; + skw->addr[1] = sp->key[PF_SK_WIRE].addr[1]; + skw->port[0] = sp->key[PF_SK_WIRE].port[0]; + skw->port[1] = sp->key[PF_SK_WIRE].port[1]; + skw->rdomain = ntohs(sp->key[PF_SK_WIRE].rdomain); + PF_REF_INIT(skw->refcnt); + skw->proto = sp->proto; + if (!(skw->af = sp->key[PF_SK_WIRE].af)) + skw->af = sp->af; + if (sks != skw) { + sks->addr[0] = sp->key[PF_SK_STACK].addr[0]; + sks->addr[1] = sp->key[PF_SK_STACK].addr[1]; + sks->port[0] = sp->key[PF_SK_STACK].port[0]; + sks->port[1] = sp->key[PF_SK_STACK].port[1]; + sks->rdomain = ntohs(sp->key[PF_SK_STACK].rdomain); + PF_REF_INIT(sks->refcnt); + if (!(sks->af = sp->key[PF_SK_STACK].af)) + sks->af = sp->af; + if (sks->af != skw->af) { + switch (sp->proto) { + case IPPROTO_ICMP: + sks->proto = IPPROTO_ICMPV6; + break; + case IPPROTO_ICMPV6: + sks->proto = IPPROTO_ICMP; + break; + default: + sks->proto = sp->proto; + break; + } + } else + sks->proto = sp->proto; + + if (((sks->af != AF_INET) && (sks->af != AF_INET6)) || + ((skw->af != AF_INET) && (skw->af != AF_INET6))) { + error = EINVAL; + goto cleanup; + } + + } else if ((sks->af != AF_INET) && (sks->af != AF_INET6)) { + error = EINVAL; + goto cleanup; + } + st->rtableid[PF_SK_WIRE] = ntohl(sp->rtableid[PF_SK_WIRE]); + st->rtableid[PF_SK_STACK] = ntohl(sp->rtableid[PF_SK_STACK]); + + /* copy to state */ + st->rt_addr = sp->rt_addr; + st->rt = sp->rt; + st->creation = getuptime() - ntohl(sp->creation); + st->expire = getuptime(); + if (ntohl(sp->expire)) { + u_int32_t timeout; + + timeout = r->timeout[sp->timeout]; + if (!timeout) + timeout = pf_default_rule.timeout[sp->timeout]; + + /* sp->expire may have been adaptively scaled by export. */ + st->expire -= timeout - ntohl(sp->expire); + } + + st->direction = sp->direction; + st->log = sp->log; + st->timeout = sp->timeout; + st->state_flags = ntohs(sp->state_flags); + st->max_mss = ntohs(sp->max_mss); + st->min_ttl = sp->min_ttl; + st->set_tos = sp->set_tos; + st->set_prio[0] = sp->set_prio[0]; + st->set_prio[1] = sp->set_prio[1]; + + st->id = sp->id; + st->creatorid = sp->creatorid; + pf_state_peer_ntoh(&sp->src, &st->src); + pf_state_peer_ntoh(&sp->dst, &st->dst); + + st->rule.ptr = r; + st->anchor.ptr = NULL; + + st->pfsync_time = getuptime(); + st->sync_state = PFSYNC_S_NONE; + + refcnt_init(&st->refcnt); + + /* XXX when we have anchors, use STATE_INC_COUNTERS */ + r->states_cur++; + r->states_tot++; + +#if NPFSYNC > 0 + if (!ISSET(flags, PFSYNC_SI_IOCTL)) + SET(st->state_flags, PFSTATE_NOSYNC); +#endif + + /* + * We just set PFSTATE_NOSYNC bit, which prevents + * pfsync_insert_state() to insert state to pfsync. + */ + if (pf_state_insert(kif, &skw, &sks, st) != 0) { + /* XXX when we have anchors, use STATE_DEC_COUNTERS */ + r->states_cur--; + error = EEXIST; + goto cleanup_state; + } + +#if NPFSYNC > 0 + if (!ISSET(flags, PFSYNC_SI_IOCTL)) { + CLR(st->state_flags, PFSTATE_NOSYNC); + if (ISSET(st->state_flags, PFSTATE_ACK)) + pfsync_iack(st); + } + CLR(st->state_flags, PFSTATE_ACK); +#endif + + return (0); + + cleanup: + if (skw == sks) + sks = NULL; + if (skw != NULL) + pool_put(&pf_state_key_pl, skw); + if (sks != NULL) + pool_put(&pf_state_key_pl, sks); + + cleanup_state: /* pf_state_insert frees the state keys */ + if (st) { + if (st->dst.scrub) + pool_put(&pf_state_scrub_pl, st->dst.scrub); + if (st->src.scrub) + pool_put(&pf_state_scrub_pl, st->src.scrub); + pool_put(&pf_state_pl, st); + } + return (error); +} + /* END state table stuff */ void Index: pf_ioctl.c =================================================================== RCS file: /cvs/src/sys/net/pf_ioctl.c,v retrieving revision 1.385 diff -u -p -r1.385 pf_ioctl.c --- pf_ioctl.c 6 Aug 2022 15:57:58 -0000 1.385 +++ pf_ioctl.c 5 Nov 2022 17:31:57 -0000 @@ -1880,7 +1880,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t a } NET_LOCK(); PF_LOCK(); - error = pfsync_state_import(sp, PFSYNC_SI_IOCTL); + error = pf_state_import(sp, PFSYNC_SI_IOCTL); PF_UNLOCK(); NET_UNLOCK(); break; Index: pf_norm.c =================================================================== RCS file: /cvs/src/sys/net/pf_norm.c,v retrieving revision 1.225 diff -u -p -r1.225 pf_norm.c --- pf_norm.c 10 Oct 2022 16:43:12 -0000 1.225 +++ pf_norm.c 5 Nov 2022 17:31:57 -0000 @@ -1099,6 +1099,16 @@ no_fragment: #endif /* INET6 */ int +pf_normalize_tcp_alloc(struct pf_state_peer *src) +{ + src->scrub = pool_get(&pf_state_scrub_pl, PR_NOWAIT | PR_ZERO); + if (src->scrub == NULL) + return (ENOMEM); + + return (0); +} + +int pf_normalize_tcp(struct pf_pdesc *pd) { struct tcphdr *th = &pd->hdr.tcp; @@ -1165,10 +1175,8 @@ pf_normalize_tcp_init(struct pf_pdesc *p KASSERT(src->scrub == NULL); - src->scrub = pool_get(&pf_state_scrub_pl, PR_NOWAIT); - if (src->scrub == NULL) + if (pf_normalize_tcp_alloc(src) != 0) return (1); - memset(src->scrub, 0, sizeof(*src->scrub)); switch (pd->af) { case AF_INET: { Index: pfvar.h =================================================================== RCS file: /cvs/src/sys/net/pfvar.h,v retrieving revision 1.511 diff -u -p -r1.511 pfvar.h --- pfvar.h 10 Oct 2022 16:43:12 -0000 1.511 +++ pfvar.h 5 Nov 2022 17:31:57 -0000 @@ -1741,6 +1741,11 @@ extern struct pf_state *pf_find_state_a u_int, int *); extern void pf_state_export(struct pfsync_state *, struct pf_state *); +int pf_state_import(const struct pfsync_state *, + int); +int pf_state_alloc_scrub_memory( + const struct pfsync_state_peer *, + struct pf_state_peer *); extern void pf_print_state(struct pf_state *); extern void pf_print_flags(u_int8_t); extern void pf_addrcpy(struct pf_addr *, struct pf_addr *, @@ -1791,6 +1796,7 @@ int pf_normalize_ip6(struct pf_pdesc *, int pf_normalize_tcp(struct pf_pdesc *); void pf_normalize_tcp_cleanup(struct pf_state *); int pf_normalize_tcp_init(struct pf_pdesc *, struct pf_state_peer *); +int pf_normalize_tcp_alloc(struct pf_state_peer *); int pf_normalize_tcp_stateful(struct pf_pdesc *, u_short *, struct pf_state *, struct pf_state_peer *, struct pf_state_peer *, int *);