diff options
Diffstat (limited to 'sys/netpfil/pf')
| -rw-r--r-- | sys/netpfil/pf/if_pfsync.c | 3 | ||||
| -rw-r--r-- | sys/netpfil/pf/pf.c | 3 | ||||
| -rw-r--r-- | sys/netpfil/pf/pf_if.c | 2 | ||||
| -rw-r--r-- | sys/netpfil/pf/pf_ioctl.c | 13 | ||||
| -rw-r--r-- | sys/netpfil/pf/pf_lb.c | 118 | ||||
| -rw-r--r-- | sys/netpfil/pf/pf_nl.c | 44 | ||||
| -rw-r--r-- | sys/netpfil/pf/pf_nl.h | 2 | ||||
| -rw-r--r-- | sys/netpfil/pf/pf_table.c | 12 |
8 files changed, 186 insertions, 11 deletions
diff --git a/sys/netpfil/pf/if_pfsync.c b/sys/netpfil/pf/if_pfsync.c index 66bc99df2afa..de69ecbb0985 100644 --- a/sys/netpfil/pf/if_pfsync.c +++ b/sys/netpfil/pf/if_pfsync.c @@ -546,6 +546,9 @@ pfsync_state_import(union pfsync_state_union *sp, int flags, int msg_version) PF_RULES_RASSERT(); + if (strnlen(sp->pfs_1301.ifname, IFNAMSIZ) == IFNAMSIZ) + return (EINVAL); + if (sp->pfs_1301.creatorid == 0) { if (V_pf_status.debug >= PF_DEBUG_MISC) printf("%s: invalid creator id: %08x\n", __func__, diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c index d6fc24a23fe9..a39f5fe58cd6 100644 --- a/sys/netpfil/pf/pf.c +++ b/sys/netpfil/pf/pf.c @@ -1007,7 +1007,7 @@ pf_src_node_exists(struct pf_ksrc_node **sn, struct pf_srchash *sh) return (false); } -static void +void pf_free_src_node(struct pf_ksrc_node *sn) { @@ -5965,6 +5965,7 @@ pf_test_rule(struct pf_krule **rm, struct pf_kstate **sm, ctx.nat_pool = &(ctx.nr->rdr); } + *ctx.rm = &V_pf_default_rule; if (ctx.nr && ctx.nr->natpass) { r = ctx.nr; ruleset = *ctx.rsm; diff --git a/sys/netpfil/pf/pf_if.c b/sys/netpfil/pf/pf_if.c index f3be036ef745..6f41d453a7d1 100644 --- a/sys/netpfil/pf/pf_if.c +++ b/sys/netpfil/pf/pf_if.c @@ -702,7 +702,7 @@ pfi_table_update(struct pfr_ktable *kt, struct pfi_kkif *kif, uint8_t net, } if ((e = pfr_set_addrs(&kt->pfrkt_t, V_pfi_buffer, V_pfi_buffer_cnt, &size2, - NULL, NULL, NULL, 0, PFR_TFLAG_ALLMASK))) + NULL, NULL, NULL, PFR_FLAG_START | PFR_FLAG_DONE, PFR_TFLAG_ALLMASK))) printf("%s: cannot set %d new addresses into table %s: %d\n", __func__, V_pfi_buffer_cnt, kt->pfrkt_name, e); } diff --git a/sys/netpfil/pf/pf_ioctl.c b/sys/netpfil/pf/pf_ioctl.c index a4557f139ae5..5ec67021068b 100644 --- a/sys/netpfil/pf/pf_ioctl.c +++ b/sys/netpfil/pf/pf_ioctl.c @@ -4792,6 +4792,17 @@ DIOCCHANGEADDR_error: error = ENODEV; goto fail; } + if (strnlen(io->pfrio_table.pfrt_anchor, MAXPATHLEN) + == MAXPATHLEN) { + error = EINVAL; + goto fail; + } + if (strnlen(io->pfrio_table.pfrt_name, PF_TABLE_NAME_SIZE) + == PF_TABLE_NAME_SIZE) { + error = EINVAL; + goto fail; + } + PF_RULES_WLOCK(); error = pfr_clr_tables(&io->pfrio_table, &io->pfrio_ndel, io->pfrio_flags | PFR_FLAG_USERIOCTL); @@ -5131,7 +5142,7 @@ DIOCCHANGEADDR_error: error = pfr_set_addrs(&io->pfrio_table, pfras, io->pfrio_size, &io->pfrio_size2, &io->pfrio_nadd, &io->pfrio_ndel, &io->pfrio_nchange, io->pfrio_flags | - PFR_FLAG_USERIOCTL, 0); + PFR_FLAG_START | PFR_FLAG_DONE | PFR_FLAG_USERIOCTL, 0); PF_RULES_WUNLOCK(); if (error == 0 && io->pfrio_flags & PFR_FLAG_FEEDBACK) error = copyout(pfras, io->pfrio_buffer, totlen); diff --git a/sys/netpfil/pf/pf_lb.c b/sys/netpfil/pf/pf_lb.c index fb1b121d0bc0..7aeb8266ca8c 100644 --- a/sys/netpfil/pf/pf_lb.c +++ b/sys/netpfil/pf/pf_lb.c @@ -216,6 +216,7 @@ pf_match_translation_rule(int rs_num, struct pf_test_ctx *ctx, struct pf_krulese */ ctx->arsm = ctx->aruleset; } + break; } else { ctx->a = r; /* remember anchor */ ctx->aruleset = ruleset; /* and its ruleset */ @@ -534,6 +535,63 @@ pf_get_mape_sport(struct pf_pdesc *pd, struct pf_krule *r, return (1); } +static __inline u_short +pf_check_src_node_valid(struct pf_ksrc_node *sn, struct pf_kpool *rpool) +{ + struct pf_addr *raddr, *rmask; + struct pf_addr *caddr; /* cached redirection address */ + struct pf_kpooladdr *pa; + sa_family_t raf; + sa_family_t caf; /* cached redirection AF */ + u_short valid = 0; + + KASSERT(sn != NULL, ("sn is NULL")); + KASSERT(rpool != NULL, ("rpool is NULL")); + + /* check if the cached entry is still valid */ + + if (sn->type == PF_SN_LIMIT) { + /* Always valid as it does not store redirection address */ + return (1); + } + + mtx_lock(&rpool->mtx); + caddr = &(sn->raddr); + caf = sn->raf; + + TAILQ_FOREACH(pa, &rpool->list, entries) { + if (PF_AZERO(caddr, caf)) { + valid = 1; + goto done; + } else if (pa->addr.type == PF_ADDR_DYNIFTL) { + if (pfr_kentry_byaddr(pa->addr.p.dyn->pfid_kt, caddr, caf, 0)) { + valid = 1; + goto done; + } + } else if (pa->addr.type == PF_ADDR_TABLE) { + if (pfr_kentry_byaddr(pa->addr.p.tbl, caddr, caf, 0)) { + valid = 1; + goto done; + } + } else if (pa->addr.type != PF_ADDR_NOROUTE) { + /* PF_ADDR_URPFFAILED, PF_ADDR_RANGE, PF_ADDR_ADDRMASK */ + raddr = &(pa->addr.v.a.addr); + rmask = &(pa->addr.v.a.mask); + raf = pa->af; + if (raf == caf && pf_match_addr(0, raddr, rmask, caddr, caf)) { + valid = 1; + goto done; + } + } + /* else PF_ADDR_NOROUTE */ + } + +done: + mtx_unlock(&rpool->mtx); + + return (valid); +} + u_short pf_map_addr(sa_family_t saf, struct pf_krule *r, struct pf_addr *saddr, struct pf_addr *naddr, struct pfi_kkif **nkif, sa_family_t *naf, @@ -873,6 +931,45 @@ pf_map_addr_sn(sa_family_t saf, struct pf_krule *r, struct pf_addr *saddr, if (sn != NULL) { PF_SRC_NODE_LOCK_ASSERT(sn); + /* + * Check if source node's redirection address still exists + * in pool from which the SN was created. If not, delete it. + * Similar to pf_kill_srcnodes(). Unlink the source node + * from tree, unlink it from states, then free it. Do not + * overlap source node and state locks to avoid LOR. + */ + if (!pf_check_src_node_valid(sn, rpool)) { + pf_unlink_src_node(sn); + PF_SRC_NODE_UNLOCK(sn); + if (V_pf_status.debug >= PF_DEBUG_NOISY) { + printf("%s: stale src tracking (%d) ", + __func__, sn_type); + pf_print_host(saddr, 0, saf); + printf(" to "); + pf_print_host(&(sn->raddr), 0, sn->raf); + if (nkif) + printf("@%s", sn->rkif->pfik_name); + printf("\n"); + } + + for (int i = 0; i <= V_pf_hashmask; i++) { + struct pf_idhash *ih = &V_pf_idhash[i]; + struct pf_kstate *st; + + PF_HASHROW_LOCK(ih); + LIST_FOREACH(st, &ih->states, entry) { + if (st->sns[sn->type] == sn) { + st->sns[sn->type] = NULL; + } + } + PF_HASHROW_UNLOCK(ih); + } + pf_free_src_node(sn); + counter_u64_add(V_pf_status.scounters[SCNT_SRC_NODE_REMOVALS], 1); + sn = NULL; + goto map_addr; + } + (*naf) = sn->raf; /* If the supplied address is the same as the current one we've @@ -901,9 +998,10 @@ pf_map_addr_sn(sa_family_t saf, struct pf_krule *r, struct pf_addr *saddr, goto done; } +map_addr: /* - * Source node has not been found. Find a new address and store it - * in variables given by the caller. + * Source node has not been found or is invalid. Find a new address + * and store it in variables given by the caller. */ if ((reason = pf_map_addr(saf, r, saddr, naddr, nkif, naf, init_addr, rpool)) != 0) { @@ -973,6 +1071,7 @@ pf_get_transaddr(struct pf_test_ctx *ctx, struct pf_krule *r, { struct pf_pdesc *pd = ctx->pd; struct pf_addr *naddr; + int idx; uint16_t *nportp; uint16_t low, high; u_short reason; @@ -987,8 +1086,19 @@ pf_get_transaddr(struct pf_test_ctx *ctx, struct pf_krule *r, return (PFRES_MEMORY); } - naddr = &ctx->nk->addr[1]; - nportp = &ctx->nk->port[1]; + switch (nat_action) { + case PF_NAT: + idx = pd->sidx; + break; + case PF_BINAT: + idx = 1; + break; + case PF_RDR: + idx = pd->didx; + break; + } + naddr = &ctx->nk->addr[idx]; + nportp = &ctx->nk->port[idx]; switch (nat_action) { case PF_NAT: diff --git a/sys/netpfil/pf/pf_nl.c b/sys/netpfil/pf/pf_nl.c index 082b9b565153..21d4db1b8478 100644 --- a/sys/netpfil/pf/pf_nl.c +++ b/sys/netpfil/pf/pf_nl.c @@ -2100,6 +2100,7 @@ struct nl_parsed_table_addrs { size_t addr_count; int nadd; int ndel; + int nchange; }; #define _OUT(_field) offsetof(struct pfr_addr, _field) static const struct nlattr_parser nla_p_pfr_addr[] = { @@ -2209,6 +2210,42 @@ pf_handle_table_del_addrs(struct nlmsghdr *hdr, struct nl_pstate *npt) return (error); } +static int +pf_handle_table_set_addrs(struct nlmsghdr *hdr, struct nl_pstate *npt) +{ + struct nl_parsed_table_addrs attrs = { 0 }; + struct nl_writer *nw = npt->nw; + struct genlmsghdr *ghdr_new; + int error; + + error = nl_parse_nlmsg(hdr, &table_addr_parser, npt, &attrs); + if (error != 0) + return (error); + + PF_RULES_WLOCK(); + error = pfr_set_addrs(&attrs.table, &attrs.addrs[0], + attrs.addr_count, NULL, &attrs.nadd, &attrs.ndel, &attrs.nchange, + attrs.flags | PFR_FLAG_USERIOCTL, 0); + PF_RULES_WUNLOCK(); + + if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr))) + return (ENOMEM); + + ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr); + ghdr_new->cmd = PFNL_CMD_TABLE_DEL_ADDR; + ghdr_new->version = 0; + ghdr_new->reserved = 0; + + nlattr_add_u32(nw, PF_TA_NBR_ADDED, attrs.nadd); + nlattr_add_u32(nw, PF_TA_NBR_DELETED, attrs.ndel); + nlattr_add_u32(nw, PF_TA_NBR_CHANGED, attrs.nchange); + + if (!nlmsg_end(nw)) + return (ENOMEM); + + return (error); +} + static const struct nlhdr_parser *all_parsers[] = { &state_parser, &addrule_parser, @@ -2460,6 +2497,13 @@ static const struct genl_cmd pf_cmds[] = { .cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL, .cmd_priv = PRIV_NETINET_PF, }, + { + .cmd_num = PFNL_CMD_TABLE_SET_ADDR, + .cmd_name = "TABLE_SET_ADDRS", + .cmd_cb = pf_handle_table_set_addrs, + .cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL, + .cmd_priv = PRIV_NETINET_PF, + }, }; void diff --git a/sys/netpfil/pf/pf_nl.h b/sys/netpfil/pf/pf_nl.h index c46c8f2b2592..d1538ab4ff5b 100644 --- a/sys/netpfil/pf/pf_nl.h +++ b/sys/netpfil/pf/pf_nl.h @@ -69,6 +69,7 @@ enum { PFNL_CMD_CLR_ADDRS = 31, PFNL_CMD_TABLE_ADD_ADDR = 32, PFNL_CMD_TABLE_DEL_ADDR = 33, + PFNL_CMD_TABLE_SET_ADDR = 34, __PFNL_CMD_MAX, }; #define PFNL_CMD_MAX (__PFNL_CMD_MAX -1) @@ -483,6 +484,7 @@ enum pf_table_addrs_t { PF_TA_FLAGS = 3, /* u32 */ PF_TA_NBR_ADDED = 4, /* u32 */ PF_TA_NBR_DELETED = 5, /* u32 */ + PF_TA_NBR_CHANGED = 6, /* u32 */ }; #ifdef _KERNEL diff --git a/sys/netpfil/pf/pf_table.c b/sys/netpfil/pf/pf_table.c index 73ec18fa7646..0e2b9fe1cac8 100644 --- a/sys/netpfil/pf/pf_table.c +++ b/sys/netpfil/pf/pf_table.c @@ -399,7 +399,8 @@ pfr_set_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, PF_RULES_WASSERT(); - ACCEPT_FLAGS(flags, PFR_FLAG_DUMMY | PFR_FLAG_FEEDBACK); + ACCEPT_FLAGS(flags, PFR_FLAG_START | PFR_FLAG_DONE | + PFR_FLAG_DUMMY | PFR_FLAG_FEEDBACK); if (pfr_validate_table(tbl, ignore_pfrt_flags, flags & PFR_FLAG_USERIOCTL)) return (EINVAL); @@ -411,7 +412,8 @@ pfr_set_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, tmpkt = pfr_create_ktable(&V_pfr_nulltable, 0, 0); if (tmpkt == NULL) return (ENOMEM); - pfr_mark_addrs(kt); + if (flags & PFR_FLAG_START) + pfr_mark_addrs(kt); SLIST_INIT(&addq); SLIST_INIT(&delq); SLIST_INIT(&changeq); @@ -444,6 +446,7 @@ pfr_set_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, } p = pfr_create_kentry(&ad, (kt->pfrkt_flags & PFR_TFLAG_COUNTERS) != 0); + p->pfrke_mark = PFR_FB_ADDED; if (p == NULL) senderr(ENOMEM); if (pfr_route_kentry(tmpkt, p)) { @@ -459,7 +462,8 @@ _skip: if (flags & PFR_FLAG_FEEDBACK) bcopy(&ad, addr + i, sizeof(ad)); } - pfr_enqueue_addrs(kt, &delq, &xdel, ENQUEUE_UNMARKED_ONLY); + if (flags & PFR_FLAG_DONE) + pfr_enqueue_addrs(kt, &delq, &xdel, ENQUEUE_UNMARKED_ONLY); if ((flags & PFR_FLAG_FEEDBACK) && *size2) { if (*size2 < size+xdel) { *size2 = size+xdel; @@ -2071,7 +2075,7 @@ pfr_lookup_table(struct pfr_table *tbl) (struct pfr_ktable *)tbl)); } -static struct pfr_kentry * +struct pfr_kentry * pfr_kentry_byaddr(struct pfr_ktable *kt, struct pf_addr *a, sa_family_t af, int exact) { |
