diff --git a/lib/libpfctl/libpfctl.h b/lib/libpfctl/libpfctl.h --- a/lib/libpfctl/libpfctl.h +++ b/lib/libpfctl/libpfctl.h @@ -174,7 +174,12 @@ char overload_tblname[PF_TABLE_NAME_SIZE]; TAILQ_ENTRY(pfctl_rule) entries; - struct pfctl_pool rpool; + struct pfctl_pool nat; + union { + /* Alias old and new names. */ + struct pfctl_pool rpool; + struct pfctl_pool rdr; + }; uint64_t evaluations; uint64_t packets[2]; @@ -521,7 +526,7 @@ int pfctl_set_limit(struct pfctl_handle *h, const int index, const uint limit); int pfctl_get_limit(struct pfctl_handle *h, const int index, uint *limit); int pfctl_begin_addrs(struct pfctl_handle *h, uint32_t *ticket); -int pfctl_add_addr(struct pfctl_handle *h, const struct pfioc_pooladdr *pa); +int pfctl_add_addr(struct pfctl_handle *h, const struct pfioc_pooladdr *pa, int which); int pfctl_get_addrs(struct pfctl_handle *h, uint32_t ticket, uint32_t r_num, uint8_t r_action, const char *anchor, uint32_t *nr); int pfctl_get_addr(struct pfctl_handle *h, uint32_t ticket, uint32_t r_num, diff --git a/lib/libpfctl/libpfctl.c b/lib/libpfctl/libpfctl.c --- a/lib/libpfctl/libpfctl.c +++ b/lib/libpfctl/libpfctl.c @@ -731,7 +731,7 @@ strlcpy(rule->overload_tblname, nvlist_get_string(nvl, "overload_tblname"), PF_TABLE_NAME_SIZE); - pf_nvpool_to_pool(nvlist_get_nvlist(nvl, "rpool"), &rule->rpool); + pf_nvpool_to_pool(nvlist_get_nvlist(nvl, "rpool"), &rule->rdr); rule->evaluations = nvlist_get_number(nvl, "evaluations"); pf_nvuint_64_array(nvl, "packets", 2, rule->packets, NULL); @@ -1226,7 +1226,8 @@ snl_add_msg_attr_string(nw, PF_RT_TAGNAME, r->tagname); snl_add_msg_attr_string(nw, PF_RT_MATCH_TAGNAME, r->match_tagname); snl_add_msg_attr_string(nw, PF_RT_OVERLOAD_TBLNAME, r->overload_tblname); - snl_add_msg_attr_rpool(nw, PF_RT_RPOOL, &r->rpool); + snl_add_msg_attr_rpool(nw, PF_RT_RPOOL_RDR, &r->rdr); + snl_add_msg_attr_rpool(nw, PF_RT_RPOOL_NAT, &r->nat); snl_add_msg_attr_u32(nw, PF_RT_OS_FINGERPRINT, r->os_fingerprint); snl_add_msg_attr_u32(nw, PF_RT_RTABLEID, r->rtableid); snl_add_msg_attr_timeouts(nw, PF_RT_TIMEOUT, r->timeout); @@ -1596,7 +1597,7 @@ { .type = PF_RT_TAGNAME, .off = _OUT(r.tagname), .arg = (void *)PF_TAG_NAME_SIZE, .cb = snl_attr_copy_string }, { .type = PF_RT_MATCH_TAGNAME, .off = _OUT(r.match_tagname), .arg = (void *)PF_TAG_NAME_SIZE, .cb = snl_attr_copy_string }, { .type = PF_RT_OVERLOAD_TBLNAME, .off = _OUT(r.overload_tblname), .arg = (void *)PF_TABLE_NAME_SIZE, .cb = snl_attr_copy_string }, - { .type = PF_RT_RPOOL, .off = _OUT(r.rpool), .arg = &pool_parser, .cb = snl_attr_get_nested }, + { .type = PF_RT_RPOOL_RDR, .off = _OUT(r.rdr), .arg = &pool_parser, .cb = snl_attr_get_nested }, { .type = PF_RT_OS_FINGERPRINT, .off = _OUT(r.os_fingerprint), .cb = snl_attr_get_uint32 }, { .type = PF_RT_RTABLEID, .off = _OUT(r.rtableid), .cb = snl_attr_get_uint32 }, { .type = PF_RT_TIMEOUT, .off = _OUT(r.timeout), .arg = &timeout_parser, .cb = snl_attr_get_nested_timeouts }, @@ -1660,6 +1661,7 @@ { .type = PF_RT_ANCHOR_CALL, .off = _OUT(anchor_call), .arg = (void*)MAXPATHLEN, .cb = snl_attr_copy_string }, { .type = PF_RT_RCV_IFNAME, .off = _OUT(r.rcv_ifname), .arg = (void*)IFNAMSIZ, .cb = snl_attr_copy_string }, { .type = PF_RT_MAX_SRC_CONN, .off = _OUT(r.max_src_conn), .cb = snl_attr_get_uint32 }, + { .type = PF_RT_RPOOL_NAT, .off = _OUT(r.nat), .arg = &pool_parser, .cb = snl_attr_get_nested }, }; static struct snl_field_parser fp_getrule[] = {}; #undef _OUT @@ -2771,7 +2773,7 @@ } int -pfctl_add_addr(struct pfctl_handle *h, const struct pfioc_pooladdr *pa) +pfctl_add_addr(struct pfctl_handle *h, const struct pfioc_pooladdr *pa, int which __unused) { struct snl_writer nw; struct snl_errmsg_data e = {}; diff --git a/sbin/pfctl/pfctl.c b/sbin/pfctl/pfctl.c --- a/sbin/pfctl/pfctl.c +++ b/sbin/pfctl/pfctl.c @@ -1687,7 +1687,7 @@ /* callbacks for rule/nat/rdr/addr */ int -pfctl_add_pool(struct pfctl *pf, struct pfctl_pool *p, sa_family_t af) +pfctl_add_pool(struct pfctl *pf, struct pfctl_pool *p, sa_family_t af, int which) { struct pf_pooladdr *pa; int ret; @@ -1701,7 +1701,7 @@ TAILQ_FOREACH(pa, &p->list, entries) { memcpy(&pf->paddr.addr, pa, sizeof(struct pf_pooladdr)); if ((pf->opts & PF_OPT_NOACTION) == 0) { - if ((ret = pfctl_add_addr(pf->h, &pf->paddr)) != 0) + if ((ret = pfctl_add_addr(pf->h, &pf->paddr, which)) != 0) errc(1, ret, "DIOCADDADDR"); } } @@ -2045,7 +2045,7 @@ was_present = false; if ((pf->opts & PF_OPT_NOACTION) == 0) { - if (pfctl_add_pool(pf, &r->rpool, r->af)) + if (pfctl_add_pool(pf, &r->rpool, r->af, PF_RDR)) return (1); error = pfctl_add_rule_h(pf->h, r, anchor, name, ticket, pf->paddr.ticket); diff --git a/sbin/pfctl/pfctl_parser.h b/sbin/pfctl/pfctl_parser.h --- a/sbin/pfctl/pfctl_parser.h +++ b/sbin/pfctl/pfctl_parser.h @@ -281,7 +281,7 @@ int pfctl_append_eth_rule(struct pfctl *, struct pfctl_eth_rule *, const char *); int pfctl_add_altq(struct pfctl *, struct pf_altq *); -int pfctl_add_pool(struct pfctl *, struct pfctl_pool *, sa_family_t); +int pfctl_add_pool(struct pfctl *, struct pfctl_pool *, sa_family_t, int); void pfctl_move_pool(struct pfctl_pool *, struct pfctl_pool *); void pfctl_clear_pool(struct pfctl_pool *); diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h --- a/sys/net/pfvar.h +++ b/sys/net/pfvar.h @@ -785,7 +785,8 @@ char overload_tblname[PF_TABLE_NAME_SIZE]; TAILQ_ENTRY(pf_krule) entries; - struct pf_kpool rpool; + struct pf_kpool nat; + struct pf_kpool rdr; struct pf_counter_u64 evaluations; struct pf_counter_u64 packets[2]; @@ -1604,8 +1605,10 @@ struct pf_addr *src; /* src address */ struct pf_addr *dst; /* dst address */ - u_int16_t *sport; - u_int16_t *dport; + u_int16_t *sport; + u_int16_t *dport; + u_int16_t osport; + u_int16_t odport; struct pf_mtag *pf_mtag; struct pf_rule_actions act; @@ -2192,7 +2195,7 @@ TAILQ_HEAD(pf_altqqueue, pf_altq); VNET_DECLARE(struct pf_altqqueue, pf_altqs[4]); #define V_pf_altqs VNET(pf_altqs) -VNET_DECLARE(struct pf_kpalist, pf_pabuf); +VNET_DECLARE(struct pf_kpalist, pf_pabuf[2]); #define V_pf_pabuf VNET(pf_pabuf) VNET_DECLARE(u_int32_t, ticket_altqs_active); @@ -2527,6 +2530,20 @@ #endif /* _KERNEL */ #ifdef _KERNEL +struct pf_nl_pooladdr { + u_int32_t action; + u_int32_t ticket; + u_int32_t nr; + u_int32_t r_num; + u_int8_t r_action; + u_int8_t r_last; + u_int8_t af; + char anchor[MAXPATHLEN]; + struct pf_pooladdr addr; + /* Above this is identical to pfioc_pooladdr */ + int which; +}; + VNET_DECLARE(struct pf_kanchor_global, pf_anchors); #define V_pf_anchors VNET(pf_anchors) VNET_DECLARE(struct pf_kanchor, pf_main_anchor); @@ -2579,9 +2596,9 @@ int pf_ioctl_get_limit(int, unsigned int *); int pf_ioctl_set_limit(int, unsigned int, unsigned int *); int pf_ioctl_begin_addrs(uint32_t *); -int pf_ioctl_add_addr(struct pfioc_pooladdr *); -int pf_ioctl_get_addrs(struct pfioc_pooladdr *); -int pf_ioctl_get_addr(struct pfioc_pooladdr *); +int pf_ioctl_add_addr(struct pf_nl_pooladdr *); +int pf_ioctl_get_addrs(struct pf_nl_pooladdr *); +int pf_ioctl_get_addr(struct pf_nl_pooladdr *); int pf_ioctl_get_rulesets(struct pfioc_ruleset *); int pf_ioctl_get_ruleset(struct pfioc_ruleset *); diff --git a/sys/netpfil/pf/if_pfsync.c b/sys/netpfil/pf/if_pfsync.c --- a/sys/netpfil/pf/if_pfsync.c +++ b/sys/netpfil/pf/if_pfsync.c @@ -582,7 +582,7 @@ * give up, as we can't be sure that we will pick the * same one as the pfsync peer did. */ - rpool_first = TAILQ_FIRST(&(r->rpool.list)); + rpool_first = TAILQ_FIRST(&(r->rdr.list)); if ((rpool_first == NULL) || (TAILQ_NEXT(rpool_first, entries) != NULL)) { DPFPRINTF(PF_DEBUG_MISC, diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c --- a/sys/netpfil/pf/pf.c +++ b/sys/netpfil/pf/pf.c @@ -157,7 +157,7 @@ /* state tables */ VNET_DEFINE(struct pf_altqqueue, pf_altqs[4]); -VNET_DEFINE(struct pf_kpalist, pf_pabuf); +VNET_DEFINE(struct pf_kpalist, pf_pabuf[2]); VNET_DEFINE(struct pf_altqqueue *, pf_altqs_active); VNET_DEFINE(struct pf_altqqueue *, pf_altq_ifs_active); VNET_DEFINE(struct pf_altqqueue *, pf_altqs_inactive); @@ -332,8 +332,7 @@ struct pf_kruleset **, struct inpcb *); static int pf_create_state(struct pf_krule *, struct pf_krule *, struct pf_krule *, struct pf_pdesc *, - struct pf_state_key *, struct pf_state_key *, - u_int16_t, u_int16_t, int *, + struct pf_state_key *, struct pf_state_key *, int *, struct pf_kstate **, int, u_int16_t, u_int16_t, struct pf_krule_slist *, struct pf_udp_mapping *); static int pf_state_key_addr_setup(struct pf_pdesc *, @@ -1027,7 +1026,7 @@ u_short reason = 0; KASSERT((rule->rule_flag & PFRULE_SRCTRACK || - rule->rpool.opts & PF_POOL_STICKYADDR), + rule->rdr.opts & PF_POOL_STICKYADDR), ("%s for non-tracking rule %p", __func__, rule)); /* @@ -1242,7 +1241,8 @@ TAILQ_INIT(&V_pf_altqs[1]); TAILQ_INIT(&V_pf_altqs[2]); TAILQ_INIT(&V_pf_altqs[3]); - TAILQ_INIT(&V_pf_pabuf); + TAILQ_INIT(&V_pf_pabuf[0]); + TAILQ_INIT(&V_pf_pabuf[1]); V_pf_altqs_active = &V_pf_altqs[0]; V_pf_altq_ifs_active = &V_pf_altqs[1]; V_pf_altqs_inactive = &V_pf_altqs[2]; @@ -4979,6 +4979,8 @@ sport = dport = 0; break; } + pd->osport = sport; + pd->odport = dport; r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr); @@ -5327,7 +5329,7 @@ (pd->flags & PFDESC_TCP_NORM)))) { int action; action = pf_create_state(r, nr, a, pd, nk, sk, - sport, dport, &rewrite, sm, tag, bproto_sum, bip_sum, + &rewrite, sm, tag, bproto_sum, bip_sum, &match_rules, udp_mapping); if (action != PF_PASS) { pf_udp_mapping_release(udp_mapping); @@ -5382,9 +5384,9 @@ static int pf_create_state(struct pf_krule *r, struct pf_krule *nr, struct pf_krule *a, struct pf_pdesc *pd, struct pf_state_key *nk, struct pf_state_key *sk, - u_int16_t sport, u_int16_t dport, int *rewrite, struct pf_kstate **sm, - int tag, u_int16_t bproto_sum, u_int16_t bip_sum, - struct pf_krule_slist *match_rules, struct pf_udp_mapping *udp_mapping) + int *rewrite, struct pf_kstate **sm, int tag, u_int16_t bproto_sum, + u_int16_t bip_sum, struct pf_krule_slist *match_rules, + struct pf_udp_mapping *udp_mapping) { struct pf_kstate *s = NULL; struct pf_ksrc_node *sn = NULL; @@ -5405,14 +5407,14 @@ } /* src node for filter rule */ if ((r->rule_flag & PFRULE_SRCTRACK || - r->rpool.opts & PF_POOL_STICKYADDR) && + r->rdr.opts & PF_POOL_STICKYADDR) && (sn_reason = pf_insert_src_node(&sn, &snh, r, pd->src, pd->af, &pd->act.rt_addr, pd->act.rt_kif)) != 0) { REASON_SET(&reason, sn_reason); goto csfailed; } /* src node for translation rule */ - if (nr != NULL && (nr->rpool.opts & PF_POOL_STICKYADDR) && + if (nr != NULL && (nr->rdr.opts & PF_POOL_STICKYADDR) && (sn_reason = pf_insert_src_node(&nsn, &nsnh, nr, &sk->addr[pd->sidx], pd->af, &nk->addr[1], NULL)) != 0 ) { REASON_SET(&reason, sn_reason); @@ -5535,7 +5537,9 @@ if (nr == NULL) { KASSERT((sk == NULL && nk == NULL), ("%s: nr %p sk %p, nk %p", __func__, nr, sk, nk)); - sk = pf_state_key_setup(pd, pd->src, pd->dst, sport, dport); + MPASS(pd->sport == NULL || (pd->osport == *pd->sport)); + MPASS(pd->dport == NULL || (pd->odport == *pd->dport)); + sk = pf_state_key_setup(pd, pd->src, pd->dst, pd->osport, pd->odport); if (sk == NULL) goto csfailed; nk = sk; diff --git a/sys/netpfil/pf/pf_ioctl.c b/sys/netpfil/pf/pf_ioctl.c --- a/sys/netpfil/pf/pf_ioctl.c +++ b/sys/netpfil/pf/pf_ioctl.c @@ -100,7 +100,7 @@ SDT_PROBE_DEFINE2(pf, ioctl, nvchk, error, "int", "int"); static struct pf_kpool *pf_get_kpool(const char *, u_int32_t, u_int8_t, - u_int32_t, u_int8_t, u_int8_t, u_int8_t); + u_int32_t, u_int8_t, u_int8_t, u_int8_t, int); static void pf_mv_kpool(struct pf_kpalist *, struct pf_kpalist *); static void pf_empty_kpool(struct pf_kpalist *); @@ -430,12 +430,14 @@ static struct pf_kpool * pf_get_kpool(const char *anchor, u_int32_t ticket, u_int8_t rule_action, u_int32_t rule_number, u_int8_t r_last, u_int8_t active, - u_int8_t check_ticket) + u_int8_t check_ticket, int which) { struct pf_kruleset *ruleset; struct pf_krule *rule; int rs_num; + MPASS(which == PF_RDR || which == PF_NAT); + ruleset = pf_find_kruleset(anchor); if (ruleset == NULL) return (NULL); @@ -468,7 +470,10 @@ if (rule == NULL) return (NULL); - return (&rule->rpool); + if (which == PF_NAT) + return (&rule->nat); + else + return (&rule->rdr); } static void @@ -605,7 +610,7 @@ if (rule->rcv_kif) pfi_kkif_unref(rule->rcv_kif); pf_kanchor_remove(rule); - pf_empty_kpool(&rule->rpool.list); + pf_empty_kpool(&rule->rdr.list); pf_krule_free(rule); } @@ -1824,7 +1829,8 @@ struct pf_krule *rule; rule = malloc(sizeof(struct pf_krule), M_PFRULE, M_WAITOK | M_ZERO); - mtx_init(&rule->rpool.mtx, "pf_krule_pool", NULL, MTX_DEF); + mtx_init(&rule->nat.mtx, "pf_krule_nat_pool", NULL, MTX_DEF); + mtx_init(&rule->rdr.mtx, "pf_krule_rdr_pool", NULL, MTX_DEF); rule->timestamp = uma_zalloc_pcpu(pf_timestamp_pcpu_zone, M_WAITOK | M_ZERO); return (rule); @@ -1862,7 +1868,8 @@ counter_u64_free(rule->src_nodes); uma_zfree_pcpu(pf_timestamp_pcpu_zone, rule->timestamp); - mtx_destroy(&rule->rpool.mtx); + mtx_destroy(&rule->nat.mtx); + mtx_destroy(&rule->rdr.mtx); free(rule, M_PFRULE); } @@ -1966,7 +1973,7 @@ if (ret != 0) return (ret); - pf_pool_to_kpool(&rule->rpool, &krule->rpool); + pf_pool_to_kpool(&rule->rpool, &krule->rdr); /* Don't allow userspace to set evaluations, packets or bytes. */ /* kif, anchor, overload_tbl are not copied over. */ @@ -2096,7 +2103,8 @@ rule->src_nodes = counter_u64_alloc(M_WAITOK); rule->cuid = uid; rule->cpid = pid; - TAILQ_INIT(&rule->rpool.list); + TAILQ_INIT(&rule->rdr.list); + TAILQ_INIT(&rule->nat.list); PF_CONFIG_LOCK(); PF_RULES_WLOCK(); @@ -2194,13 +2202,15 @@ (rule->set_prio[0] > PF_PRIO_MAX || rule->set_prio[1] > PF_PRIO_MAX)) error = EINVAL; - TAILQ_FOREACH(pa, &V_pf_pabuf, entries) - if (pa->addr.type == PF_ADDR_TABLE) { - pa->addr.p.tbl = pfr_attach_table(ruleset, - pa->addr.v.tblname); - if (pa->addr.p.tbl == NULL) - error = ENOMEM; - } + for (int i = 0; i < 2; i++) { + TAILQ_FOREACH(pa, &V_pf_pabuf[i], entries) + if (pa->addr.type == PF_ADDR_TABLE) { + pa->addr.p.tbl = pfr_attach_table(ruleset, + pa->addr.v.tblname); + if (pa->addr.p.tbl == NULL) + error = ENOMEM; + } + } rule->overload_tbl = NULL; if (rule->overload_tblname[0]) { @@ -2212,14 +2222,15 @@ PFR_TFLAG_ACTIVE; } - pf_mv_kpool(&V_pf_pabuf, &rule->rpool.list); + pf_mv_kpool(&V_pf_pabuf[0], &rule->nat.list); + pf_mv_kpool(&V_pf_pabuf[1], &rule->rdr.list); if (((((rule->action == PF_NAT) || (rule->action == PF_RDR) || (rule->action == PF_BINAT)) && rule->anchor == NULL) || (rule->rt > PF_NOPFROUTE)) && - (TAILQ_FIRST(&rule->rpool.list) == NULL)) + (TAILQ_FIRST(&rule->rdr.list) == NULL)) error = EINVAL; - if (rule->action == PF_PASS && rule->rpool.opts & PF_POOL_STICKYADDR && + if (rule->action == PF_PASS && rule->rdr.opts & PF_POOL_STICKYADDR && !rule->keep_state) { error = EINVAL; } @@ -2230,7 +2241,8 @@ ERROUT(error); } - rule->rpool.cur = TAILQ_FIRST(&rule->rpool.list); + rule->nat.cur = TAILQ_FIRST(&rule->nat.list); + rule->rdr.cur = TAILQ_FIRST(&rule->rdr.list); TAILQ_INSERT_TAIL(ruleset->rules[rs_num].inactive.ptr, rule, entries); ruleset->rules[rs_num].inactive.rcount++; @@ -2538,7 +2550,8 @@ pf_ioctl_begin_addrs(uint32_t *ticket) { PF_RULES_WLOCK(); - pf_empty_kpool(&V_pf_pabuf); + pf_empty_kpool(&V_pf_pabuf[0]); + pf_empty_kpool(&V_pf_pabuf[1]); *ticket = ++V_ticket_pabuf; PF_RULES_WUNLOCK(); @@ -2546,12 +2559,14 @@ } int -pf_ioctl_add_addr(struct pfioc_pooladdr *pp) +pf_ioctl_add_addr(struct pf_nl_pooladdr *pp) { struct pf_kpooladdr *pa = NULL; struct pfi_kkif *kif = NULL; int error; + MPASS(pp->which == PF_RDR || pp->which == PF_NAT); + #ifndef INET if (pp->af == AF_INET) return (EAFNOSUPPORT); @@ -2596,7 +2611,8 @@ PF_RULES_WUNLOCK(); goto out; } - TAILQ_INSERT_TAIL(&V_pf_pabuf, pa, entries); + TAILQ_INSERT_TAIL(&V_pf_pabuf[pp->which == PF_RDR ? 1 : 0], + pa, entries); PF_RULES_WUNLOCK(); return (0); @@ -2607,19 +2623,21 @@ } int -pf_ioctl_get_addrs(struct pfioc_pooladdr *pp) +pf_ioctl_get_addrs(struct pf_nl_pooladdr *pp) { struct pf_kpool *pool; struct pf_kpooladdr *pa; PF_RULES_RLOCK_TRACKER; + MPASS(pp->which == PF_RDR || pp->which == PF_NAT); + pp->anchor[sizeof(pp->anchor) - 1] = 0; pp->nr = 0; PF_RULES_RLOCK(); pool = pf_get_kpool(pp->anchor, pp->ticket, pp->r_action, - pp->r_num, 0, 1, 0); + pp->r_num, 0, 1, 0, pp->which); if (pool == NULL) { PF_RULES_RUNLOCK(); return (EBUSY); @@ -2632,19 +2650,21 @@ } int -pf_ioctl_get_addr(struct pfioc_pooladdr *pp) +pf_ioctl_get_addr(struct pf_nl_pooladdr *pp) { struct pf_kpool *pool; struct pf_kpooladdr *pa; u_int32_t nr = 0; + MPASS(pp->which == PF_RDR || pp->which == PF_NAT); + PF_RULES_RLOCK_TRACKER; pp->anchor[sizeof(pp->anchor) - 1] = 0; PF_RULES_RLOCK(); pool = pf_get_kpool(pp->anchor, pp->ticket, pp->r_action, - pp->r_num, 0, 1, 1); + pp->r_num, 0, 1, 1, pp->which); if (pool == NULL) { PF_RULES_RUNLOCK(); return (EBUSY); @@ -3626,7 +3646,8 @@ newrule->src_nodes = counter_u64_alloc(M_WAITOK); newrule->cuid = td->td_ucred->cr_ruid; newrule->cpid = td->td_proc ? td->td_proc->p_pid : 0; - TAILQ_INIT(&newrule->rpool.list); + TAILQ_INIT(&newrule->nat.list); + TAILQ_INIT(&newrule->rdr.list); } #define ERROUT(x) ERROUT_IOCTL(DIOCCHANGERULE_error, x) @@ -3723,14 +3744,16 @@ error = ENOMEM; if (pf_kanchor_setup(newrule, ruleset, pcr->anchor_call)) error = EINVAL; - TAILQ_FOREACH(pa, &V_pf_pabuf, entries) - if (pa->addr.type == PF_ADDR_TABLE) { - pa->addr.p.tbl = - pfr_attach_table(ruleset, - pa->addr.v.tblname); - if (pa->addr.p.tbl == NULL) - error = ENOMEM; - } + for (int i = 0; i < 2; i++) { + TAILQ_FOREACH(pa, &V_pf_pabuf[i], entries) + if (pa->addr.type == PF_ADDR_TABLE) { + pa->addr.p.tbl = + pfr_attach_table(ruleset, + pa->addr.v.tblname); + if (pa->addr.p.tbl == NULL) + error = ENOMEM; + } + } newrule->overload_tbl = NULL; if (newrule->overload_tblname[0]) { @@ -3743,13 +3766,14 @@ PFR_TFLAG_ACTIVE; } - pf_mv_kpool(&V_pf_pabuf, &newrule->rpool.list); + pf_mv_kpool(&V_pf_pabuf[0], &newrule->nat.list); + pf_mv_kpool(&V_pf_pabuf[1], &newrule->rdr.list); if (((((newrule->action == PF_NAT) || (newrule->action == PF_RDR) || (newrule->action == PF_BINAT) || (newrule->rt > PF_NOPFROUTE)) && !newrule->anchor)) && - (TAILQ_FIRST(&newrule->rpool.list) == NULL)) + (TAILQ_FIRST(&newrule->rdr.list) == NULL)) error = EINVAL; if (error) { @@ -3759,9 +3783,11 @@ break; } - newrule->rpool.cur = TAILQ_FIRST(&newrule->rpool.list); + newrule->nat.cur = TAILQ_FIRST(&newrule->nat.list); + newrule->rdr.cur = TAILQ_FIRST(&newrule->rdr.list); } - pf_empty_kpool(&V_pf_pabuf); + pf_empty_kpool(&V_pf_pabuf[0]); + pf_empty_kpool(&V_pf_pabuf[1]); if (pcr->action == PF_CHANGE_ADD_HEAD) oldrule = TAILQ_FIRST( @@ -4390,22 +4416,35 @@ case DIOCADDADDR: { struct pfioc_pooladdr *pp = (struct pfioc_pooladdr *)addr; + struct pf_nl_pooladdr npp = {}; - error = pf_ioctl_add_addr(pp); + npp.which = PF_RDR; + memcpy(&npp, pp, sizeof(*pp)); + error = pf_ioctl_add_addr(&npp); break; } case DIOCGETADDRS: { struct pfioc_pooladdr *pp = (struct pfioc_pooladdr *)addr; + struct pf_nl_pooladdr npp = {}; + + npp.which = PF_RDR; + memcpy(&npp, pp, sizeof(*pp)); + error = pf_ioctl_get_addrs(&npp); + memcpy(pp, &npp, sizeof(*pp)); - error = pf_ioctl_get_addrs(pp); break; } case DIOCGETADDR: { struct pfioc_pooladdr *pp = (struct pfioc_pooladdr *)addr; + struct pf_nl_pooladdr npp = {}; + + npp.which = PF_RDR; + memcpy(&npp, pp, sizeof(*pp)); + error = pf_ioctl_get_addr(&npp); + memcpy(pp, &npp, sizeof(*pp)); - error = pf_ioctl_get_addr(pp); break; } @@ -4460,7 +4499,7 @@ ERROUT(EBUSY); pool = pf_get_kpool(pca->anchor, pca->ticket, pca->r_action, - pca->r_num, pca->r_last, 1, 1); + pca->r_num, pca->r_last, 1, 1, PF_RDR); if (pool == NULL) ERROUT(EBUSY); diff --git a/sys/netpfil/pf/pf_lb.c b/sys/netpfil/pf/pf_lb.c --- a/sys/netpfil/pf/pf_lb.c +++ b/sys/netpfil/pf/pf_lb.c @@ -149,8 +149,8 @@ if (r->action == PF_BINAT && pd->dir == PF_IN) { src = &r->dst; - if (r->rpool.cur != NULL) - xdst = &r->rpool.cur->addr; + if (r->rdr.cur != NULL) + xdst = &r->rdr.cur->addr; } else { src = &r->src; dst = &r->dst; @@ -240,7 +240,7 @@ * from the mapping. In this case we have to look up the src_node as * pf_map_addr would. */ - if (proto == IPPROTO_UDP && (r->rpool.opts & PF_POOL_ENDPI)) { + if (proto == IPPROTO_UDP && (r->rdr.opts & PF_POOL_ENDPI)) { struct pf_udp_endpoint_cmp udp_source; bzero(&udp_source, sizeof(udp_source)); @@ -252,8 +252,8 @@ PF_ACPY(naddr, &(*udp_mapping)->endpoints[1].addr, af); *nport = (*udp_mapping)->endpoints[1].port; /* Try to find a src_node as per pf_map_addr(). */ - if (*sn == NULL && r->rpool.opts & PF_POOL_STICKYADDR && - (r->rpool.opts & PF_POOL_TYPEMASK) != PF_POOL_NONE) + if (*sn == NULL && r->rdr.opts & PF_POOL_STICKYADDR && + (r->rdr.opts & PF_POOL_TYPEMASK) != PF_POOL_NONE) *sn = pf_find_src_node(saddr, r, af, sh, false); if (*sn != NULL) PF_SRC_NODE_UNLOCK(*sn); @@ -363,7 +363,7 @@ tmp = cut; for (tmp -= 1; tmp >= low && tmp <= 0xffff; --tmp) { if (proto == IPPROTO_UDP && - (r->rpool.opts & PF_POOL_ENDPI)) { + (r->rdr.opts & PF_POOL_ENDPI)) { (*udp_mapping)->endpoints[1].port = htons(tmp); if (pf_udp_mapping_insert(*udp_mapping) == 0) { *nport = htons(tmp); @@ -379,7 +379,7 @@ } } - switch (r->rpool.opts & PF_POOL_TYPEMASK) { + switch (r->rdr.opts & PF_POOL_TYPEMASK) { case PF_POOL_RANDOM: case PF_POOL_ROUNDROBIN: /* @@ -423,13 +423,13 @@ uint16_t i, ahigh, cut; int ashift, psidshift; - ashift = 16 - r->rpool.mape.offset; - psidshift = ashift - r->rpool.mape.psidlen; - psmask = r->rpool.mape.psid & ((1U << r->rpool.mape.psidlen) - 1); + ashift = 16 - r->rdr.mape.offset; + psidshift = ashift - r->rdr.mape.psidlen; + psmask = r->rdr.mape.psid & ((1U << r->rdr.mape.psidlen) - 1); psmask = psmask << psidshift; highmask = (1U << psidshift) - 1; - ahigh = (1U << r->rpool.mape.offset) - 1; + ahigh = (1U << r->rdr.mape.offset) - 1; cut = arc4random() & ahigh; if (cut == 0) cut = 1; @@ -454,7 +454,7 @@ struct pf_addr *naddr, struct pfi_kkif **nkif, struct pf_addr *init_addr) { u_short reason = PFRES_MATCH; - struct pf_kpool *rpool = &r->rpool; + struct pf_kpool *rpool = &r->rdr; struct pf_addr *raddr = NULL, *rmask = NULL; mtx_lock(&rpool->mtx); @@ -629,7 +629,7 @@ struct pf_ksrc_node **sn, struct pf_srchash **sh) { u_short reason = 0; - struct pf_kpool *rpool = &r->rpool; + struct pf_kpool *rpool = &r->rdr; KASSERT(*sn == NULL, ("*sn not NULL")); @@ -638,8 +638,8 @@ * Request the sh to be unlocked if sn was not found, as we never * insert a new sn when parsing the ruleset. */ - if (r->rpool.opts & PF_POOL_STICKYADDR && - (r->rpool.opts & PF_POOL_TYPEMASK) != PF_POOL_NONE) + if (r->rdr.opts & PF_POOL_STICKYADDR && + (r->rdr.opts & PF_POOL_TYPEMASK) != PF_POOL_NONE) *sn = pf_find_src_node(saddr, r, af, sh, false); if (*sn != NULL) { @@ -763,19 +763,19 @@ low = 1; high = 65535; } else { - low = r->rpool.proxy_port[0]; - high = r->rpool.proxy_port[1]; + low = r->rdr.proxy_port[0]; + high = r->rdr.proxy_port[1]; } - if (r->rpool.mape.offset > 0) { + if (r->rdr.mape.offset > 0) { if (pf_get_mape_sport(pd->af, pd->proto, r, saddr, sport, daddr, dport, naddr, nportp, &sn, &sh, udp_mapping)) { DPFPRINTF(PF_DEBUG_MISC, ("pf: MAP-E port allocation (%u/%u/%u)" " failed\n", - r->rpool.mape.offset, - r->rpool.mape.psidlen, - r->rpool.mape.psid)); + r->rdr.mape.offset, + r->rdr.mape.psidlen, + r->rdr.mape.psid)); reason = PFRES_MAPFAILED; goto notrans; } @@ -784,7 +784,7 @@ udp_mapping)) { DPFPRINTF(PF_DEBUG_MISC, ("pf: NAT proxy port allocation (%u-%u) failed\n", - r->rpool.proxy_port[0], r->rpool.proxy_port[1])); + r->rdr.proxy_port[0], r->rdr.proxy_port[1])); reason = PFRES_MAPFAILED; goto notrans; } @@ -792,41 +792,41 @@ case PF_BINAT: switch (pd->dir) { case PF_OUT: - if (r->rpool.cur->addr.type == PF_ADDR_DYNIFTL){ + if (r->rdr.cur->addr.type == PF_ADDR_DYNIFTL){ switch (pd->af) { #ifdef INET case AF_INET: - if (r->rpool.cur->addr.p.dyn-> + if (r->rdr.cur->addr.p.dyn-> pfid_acnt4 < 1) { reason = PFRES_MAPFAILED; goto notrans; } PF_POOLMASK(naddr, - &r->rpool.cur->addr.p.dyn-> + &r->rdr.cur->addr.p.dyn-> pfid_addr4, - &r->rpool.cur->addr.p.dyn-> + &r->rdr.cur->addr.p.dyn-> pfid_mask4, saddr, AF_INET); break; #endif /* INET */ #ifdef INET6 case AF_INET6: - if (r->rpool.cur->addr.p.dyn-> + if (r->rdr.cur->addr.p.dyn-> pfid_acnt6 < 1) { reason = PFRES_MAPFAILED; goto notrans; } PF_POOLMASK(naddr, - &r->rpool.cur->addr.p.dyn-> + &r->rdr.cur->addr.p.dyn-> pfid_addr6, - &r->rpool.cur->addr.p.dyn-> + &r->rdr.cur->addr.p.dyn-> pfid_mask6, saddr, AF_INET6); break; #endif /* INET6 */ } } else PF_POOLMASK(naddr, - &r->rpool.cur->addr.v.a.addr, - &r->rpool.cur->addr.v.a.mask, saddr, + &r->rdr.cur->addr.v.a.addr, + &r->rdr.cur->addr.v.a.mask, saddr, pd->af); break; case PF_IN: @@ -871,27 +871,27 @@ reason = pf_map_addr_sn(pd->af, r, saddr, naddr, NULL, NULL, &sn, &sh); if (reason != 0) goto notrans; - if ((r->rpool.opts & PF_POOL_TYPEMASK) == PF_POOL_BITMASK) - PF_POOLMASK(naddr, naddr, &r->rpool.cur->addr.v.a.mask, + if ((r->rdr.opts & PF_POOL_TYPEMASK) == PF_POOL_BITMASK) + PF_POOLMASK(naddr, naddr, &r->rdr.cur->addr.v.a.mask, daddr, pd->af); /* Do not change SCTP ports. */ if (pd->proto == IPPROTO_SCTP) break; - if (r->rpool.proxy_port[1]) { + if (r->rdr.proxy_port[1]) { uint32_t tmp_nport; tmp_nport = ((ntohs(dport) - ntohs(r->dst.port[0])) % - (r->rpool.proxy_port[1] - r->rpool.proxy_port[0] + - 1)) + r->rpool.proxy_port[0]; + (r->rdr.proxy_port[1] - r->rdr.proxy_port[0] + + 1)) + r->rdr.proxy_port[0]; /* Wrap around if necessary. */ if (tmp_nport > 65535) tmp_nport -= 65535; nport = htons((uint16_t)tmp_nport); - } else if (r->rpool.proxy_port[0]) - nport = htons(r->rpool.proxy_port[0]); + } else if (r->rdr.proxy_port[0]) + nport = htons(r->rdr.proxy_port[0]); else nport = dport; diff --git a/sys/netpfil/pf/pf_nl.h b/sys/netpfil/pf/pf_nl.h --- a/sys/netpfil/pf/pf_nl.h +++ b/sys/netpfil/pf/pf_nl.h @@ -198,7 +198,7 @@ PF_RT_TAGNAME = 8, /* string */ PF_RT_MATCH_TAGNAME = 9, /* string */ PF_RT_OVERLOAD_TBLNAME = 10, /* string */ - PF_RT_RPOOL = 11, /* nested, pf_rpool_type_t */ + PF_RT_RPOOL_RDR = 11, /* nested, pf_rpool_type_t */ PF_RT_OS_FINGERPRINT = 12, /* u32 */ PF_RT_RTABLEID = 13, /* u32 */ PF_RT_TIMEOUT = 14, /* nested, pf_timeout_type_t */ @@ -262,6 +262,7 @@ PF_RT_ANCHOR_CALL = 72, /* string */ PF_RT_RCV_IFNAME = 73, /* string */ PF_RT_MAX_SRC_CONN = 74, /* u32 */ + PF_RT_RPOOL_NAT = 75, /* nested, pf_rpool_type_t */ }; enum pf_addrule_type_t { @@ -381,6 +382,7 @@ PF_AA_AF = 7, /* u8 */ PF_AA_ANCHOR = 8, /* string */ PF_AA_ADDR = 9, /* nested, pf_pooladdr */ + PF_AA_WHICH = 10, /* u32 */ }; enum pf_get_rulesets_types_t { diff --git a/sys/netpfil/pf/pf_nl.c b/sys/netpfil/pf/pf_nl.c --- a/sys/netpfil/pf/pf_nl.c +++ b/sys/netpfil/pf/pf_nl.c @@ -678,7 +678,7 @@ { .type = PF_RT_TAGNAME, .off = _OUT(tagname), .arg = (void *)PF_TAG_NAME_SIZE, .cb = nlattr_get_chara }, { .type = PF_RT_MATCH_TAGNAME, .off = _OUT(match_tagname), .arg = (void *)PF_TAG_NAME_SIZE, .cb = nlattr_get_chara }, { .type = PF_RT_OVERLOAD_TBLNAME, .off = _OUT(overload_tblname), .arg = (void *)PF_TABLE_NAME_SIZE, .cb = nlattr_get_chara }, - { .type = PF_RT_RPOOL, .off = _OUT(rpool), .arg = &pool_parser, .cb = nlattr_get_nested }, + { .type = PF_RT_RPOOL_RDR, .off = _OUT(rdr), .arg = &pool_parser, .cb = nlattr_get_nested }, { .type = PF_RT_OS_FINGERPRINT, .off = _OUT(os_fingerprint), .cb = nlattr_get_uint32 }, { .type = PF_RT_RTABLEID, .off = _OUT(rtableid), .cb = nlattr_get_uint32 }, { .type = PF_RT_TIMEOUT, .off = _OUT(timeout), .arg = &timeout_parser, .cb = nlattr_get_nested_timeouts }, @@ -732,6 +732,7 @@ { .type = PF_RT_DIVERT_PORT, .off = _OUT(divert.port), .cb = nlattr_get_uint16 }, { .type = PF_RT_RCV_IFNAME, .off = _OUT(rcv_ifname), .arg = (void *)IFNAMSIZ, .cb = nlattr_get_chara }, { .type = PF_RT_MAX_SRC_CONN, .off = _OUT(max_src_conn), .cb = nlattr_get_uint32 }, + { .type = PF_RT_RPOOL_NAT, .off = _OUT(nat), .arg = &pool_parser, .cb = nlattr_get_nested }, }; NL_DECLARE_ATTR_PARSER(rule_parser, nla_p_rule); #undef _OUT @@ -915,7 +916,8 @@ nlattr_add_string(nw, PF_RT_TAGNAME, rule->tagname); nlattr_add_string(nw, PF_RT_MATCH_TAGNAME, rule->match_tagname); nlattr_add_string(nw, PF_RT_OVERLOAD_TBLNAME, rule->overload_tblname); - nlattr_add_pool(nw, PF_RT_RPOOL, &rule->rpool); + nlattr_add_pool(nw, PF_RT_RPOOL_RDR, &rule->rdr); + nlattr_add_pool(nw, PF_RT_RPOOL_NAT, &rule->nat); nlattr_add_u32(nw, PF_RT_OS_FINGERPRINT, rule->os_fingerprint); nlattr_add_u32(nw, PF_RT_RTABLEID, rule->rtableid); nlattr_add_timeout(nw, PF_RT_TIMEOUT, rule->timeout); @@ -1528,7 +1530,7 @@ NL_DECLARE_ATTR_PARSER(pool_addr_parser, nla_p_pool_addr); #undef _OUT -#define _OUT(_field) offsetof(struct pfioc_pooladdr, _field) +#define _OUT(_field) offsetof(struct pf_nl_pooladdr, _field) static const struct nlattr_parser nla_p_add_addr[] = { { .type = PF_AA_ACTION, .off = _OUT(action), .cb = nlattr_get_uint32 }, { .type = PF_AA_TICKET, .off = _OUT(ticket), .cb = nlattr_get_uint32 }, @@ -1539,6 +1541,7 @@ { .type = PF_AA_AF, .off = _OUT(af), .cb = nlattr_get_uint8 }, { .type = PF_AA_ANCHOR, .off = _OUT(anchor), .arg = (void *)MAXPATHLEN, .cb = nlattr_get_chara }, { .type = PF_AA_ADDR, .off = _OUT(addr), .arg = &pool_addr_parser, .cb = nlattr_get_nested }, + { .type = PF_AA_WHICH, .off = _OUT(which), .cb = nlattr_get_uint32 }, }; static const struct nlfield_parser nlf_p_add_addr[] = {}; #undef _OUT @@ -1547,13 +1550,16 @@ static int pf_handle_add_addr(struct nlmsghdr *hdr, struct nl_pstate *npt) { - struct pfioc_pooladdr attrs = { 0 }; + struct pf_nl_pooladdr attrs = { 0 }; int error; error = nl_parse_nlmsg(hdr, &add_addr_parser, npt, &attrs); if (error != 0) return (error); + if (attrs.which == 0) + attrs.which = PF_RDR; + error = pf_ioctl_add_addr(&attrs); return (error); @@ -1562,7 +1568,7 @@ static int pf_handle_get_addrs(struct nlmsghdr *hdr, struct nl_pstate *npt) { - struct pfioc_pooladdr attrs = { 0 }; + struct pf_nl_pooladdr attrs = { 0 }; struct nl_writer *nw = npt->nw; struct genlmsghdr *ghdr_new; int error; @@ -1571,6 +1577,9 @@ if (error != 0) return (error); + if (attrs.which == 0) + attrs.which = PF_RDR; + error = pf_ioctl_get_addrs(&attrs); if (error != 0) return (error); @@ -1596,7 +1605,7 @@ static int pf_handle_get_addr(struct nlmsghdr *hdr, struct nl_pstate *npt) { - struct pfioc_pooladdr attrs = { 0 }; + struct pf_nl_pooladdr attrs = { 0 }; struct nl_writer *nw = npt->nw; struct genlmsghdr *ghdr_new; int error; @@ -1605,6 +1614,9 @@ if (error != 0) return (error); + if (attrs.which == 0) + attrs.which = PF_RDR; + error = pf_ioctl_get_addr(&attrs); if (error != 0) return (error); diff --git a/sys/netpfil/pf/pf_nv.c b/sys/netpfil/pf/pf_nv.c --- a/sys/netpfil/pf/pf_nv.c +++ b/sys/netpfil/pf/pf_nv.c @@ -563,7 +563,7 @@ if (! nvlist_exists_nvlist(nvl, "rpool")) ERROUT(EINVAL); PFNV_CHK(pf_nvpool_to_pool(nvlist_get_nvlist(nvl, "rpool"), - &rule->rpool)); + &rule->rdr)); PFNV_CHK(pf_nvuint32(nvl, "os_fingerprint", &rule->os_fingerprint)); @@ -721,7 +721,7 @@ nvlist_add_string(nvl, "match_tagname", rule->match_tagname); nvlist_add_string(nvl, "overload_tblname", rule->overload_tblname); - tmp = pf_pool_to_nvpool(&rule->rpool); + tmp = pf_pool_to_nvpool(&rule->rdr); if (tmp == NULL) goto error; nvlist_add_nvlist(nvl, "rpool", tmp);