From nobody Wed Sep 17 14:15:39 2025 X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4cRglv4Qfxz67ScB; Wed, 17 Sep 2025 14:15:39 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R12" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4cRglv4C4Wz4485; Wed, 17 Sep 2025 14:15:39 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1758118539; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=OPKAj5onG4oumD/QL70yfix6Lq3aV99Lywa8FvvhtEw=; b=wYDx2nLTQ4i7fJwiT/G2aWsc0uCn0wqmyNJ9+HUCCTpte4xNM4Vp8y0bfR1pHPG1k3VqJm 572m1y/D4lQI+QDB3hGMiKi4+PnIM+zTSwnGRWYjyPGOyxTmMp6CBng08aigE2nfvKcuvO fkzzvM7WllJA+FJ9Q9MY5B4Z/WZfXu93rBZ7AZHnCbgFo87klySQ3VvEDCyTuTL6jGMqJO oA834ROnsWPjjTl80TBwEm5O3cYXRMXgJ399ARnMnKRq06SFB2A3NVeppuqvKnLF4/cUev wBCoQG7+SNleptMYjf7xi6tWE9dBxpNlVGQJ6is73MJFubzwP7tqaij6Dq+Tvg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1758118539; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=OPKAj5onG4oumD/QL70yfix6Lq3aV99Lywa8FvvhtEw=; b=FNWTtbF2zC2hQAwn15eUNObsoyATymsjkECROJ7JBCtuddpms2zZVVs/IqtGeBc0m1hv15 Ud0aUwzDbZNMv5iiXmgbjQX8dHAZh8ZZltgR1wqfUz5OnqKuzVNyjXjOZnfIwJwW2YIDIV 88QqcQisHJtMMzYbvd2gWjlsQ0SjStEiMtWzjlDl6uSaIbw3AVB7ryyWztZSOB4+S/K6Ho fve21D06IymWUk1ngMXYgPYOeYsf9G6B3oFuFQyu85vHr23rRMAfaFM9gYe2xWN+7mq0XX MJXhDBEyfO0UHDcoSo8F/FkdX7xhJ7Ml0yHvHHViwS0tHr+8LR4wHqUJIUgE0g== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1758118539; a=rsa-sha256; cv=none; b=aQlcEcrCwq1P7Lee28o8R3N35svcUKdjwrSCkvU8hnVfzY5Va3zBpJPjGxOsqEidmbloVN +qosTHFWRkq6n44QagJLaK3PzbIlSngd6I5uslbRBEa6vbB7HotzFqsnfo0o2Imua6tF0N cUCAEvgX61FefT+fyYvOxUCoHcNvQz2qqhYZxHRx9kK5KCg0k/Lk5JTd+d/waVtMuS8fsv 9U0j+H5i/i7ZyVAA53MkiL+Le4eFggue8M+rgV0OApogIumqspNLouvAp9ZI9u0msjhh/f tMFWsTJrY5mJg61hy5gh9sJXJZXuqzmZSYLcrfnGiIuNw8jZDbqx+u6p8X/kaA== ARC-Authentication-Results: i=1; mx1.freebsd.org; none Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4cRglv3SPNzTZs; Wed, 17 Sep 2025 14:15:39 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.18.1/8.18.1) with ESMTP id 58HEFdER010143; Wed, 17 Sep 2025 14:15:39 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.18.1/8.18.1/Submit) id 58HEFdN0010140; Wed, 17 Sep 2025 14:15:39 GMT (envelope-from git) Date: Wed, 17 Sep 2025 14:15:39 GMT Message-Id: <202509171415.58HEFdN0010140@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Kristof Provost Subject: git: 9dfc5e03da50 - main - pfctl: allow tables to be defined inside anchors List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-all@freebsd.org Sender: owner-dev-commits-src-all@FreeBSD.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: kp X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 9dfc5e03da50d12f02c2b481139acf9f089d504f Auto-Submitted: auto-generated The branch main has been updated by kp: URL: https://cgit.FreeBSD.org/src/commit/?id=9dfc5e03da50d12f02c2b481139acf9f089d504f commit 9dfc5e03da50d12f02c2b481139acf9f089d504f Author: Kristof Provost AuthorDate: 2025-08-22 11:34:39 +0000 Commit: Kristof Provost CommitDate: 2025-09-17 14:15:13 +0000 pfctl: allow tables to be defined inside anchors This change allows user to define table inside the anchor like that: anchor foo { table { 192.168.1.1 } pass in from to } Without this diff one must either create table in main ruleset (root) or use 'pfctl -a foo -t bar -T add 192.168.1.1' This glitch is hard to notice. Not many human admins try to attach tables to non-global anchors. Deamons which configure pf(4) automatically at run time such as relayd(8) and spamd(8) create tables attached to thair anchors (for example 'relayd/*') but the deamons use way similar to pfctl(8) to add and manage those tables. The reason why I'd like to seal this gap is that my long term goal is to turn global `pfr_ktable` in pf(4) into member of pf_anchor. So each ruleset will get its own tree of tables. feedback and OK bluhm@ Obtained from: OpenBSD, sashan , 30269bc362 Sponsored by: Rubicon Communications, LLC ("Netgate") --- sbin/pfctl/parse.y | 104 ++++++++++++++++++++++++++++++++++++++++++-- sbin/pfctl/pfctl.c | 52 +++++++++++++++++++--- sbin/pfctl/pfctl.h | 41 +++++++++++++++++ sbin/pfctl/pfctl_optimize.c | 3 +- sbin/pfctl/pfctl_parser.h | 12 ++++- sbin/pfctl/pfctl_radix.c | 15 +++++++ sbin/pfctl/pfctl_table.c | 51 +++++++++++++++++----- 7 files changed, 256 insertions(+), 22 deletions(-) diff --git a/sbin/pfctl/parse.y b/sbin/pfctl/parse.y index 46e9f60fe48e..0628b387b4b3 100644 --- a/sbin/pfctl/parse.y +++ b/sbin/pfctl/parse.y @@ -420,6 +420,8 @@ int rt_tableid_max(void); void mv_rules(struct pfctl_ruleset *, struct pfctl_ruleset *); void mv_eth_rules(struct pfctl_eth_ruleset *, struct pfctl_eth_ruleset *); +void mv_tables(struct pfctl *, struct pfr_ktablehead *, + struct pfctl_anchor *, struct pfctl_anchor *); void decide_address_family(struct node_host *, sa_family_t *); void remove_invalid_hosts(struct node_host **, sa_family_t *); int invalid_redirect(struct node_host *, sa_family_t); @@ -949,6 +951,7 @@ anchorname : STRING { pfa_anchorlist : /* empty */ | pfa_anchorlist '\n' + | pfa_anchorlist tabledef '\n' | pfa_anchorlist pfrule '\n' | pfa_anchorlist anchorrule '\n' | pfa_anchorlist include '\n' @@ -974,7 +977,7 @@ pfa_anchor : '{' snprintf(ta, PF_ANCHOR_NAME_SIZE, "_%d", pf->bn); rs = pf_find_or_create_ruleset(ta); if (rs == NULL) - err(1, "pfa_anchor: pf_find_or_create_ruleset"); + err(1, "pfa_anchor: pf_find_or_create_ruleset (%s)", ta); pf->astack[pf->asd] = rs->anchor; pf->anchor = rs->anchor; } '\n' pfa_anchorlist '}' @@ -1026,6 +1029,7 @@ anchorrule : ANCHOR anchorname dir quick interface af proto fromto } mv_rules(&pf->alast->ruleset, &r.anchor->ruleset); + mv_tables(pf, &pfr_ktables, r.anchor, pf->alast); } pf_remove_if_empty_ruleset(&pf->alast->ruleset); pf->alast = r.anchor; @@ -5456,6 +5460,7 @@ process_tabledef(char *name, struct table_opts *opts, int popts) { struct pfr_buffer ab; struct node_tinit *ti; + struct pfr_uktable *ukt; unsigned long maxcount; size_t s = sizeof(maxcount); @@ -5488,9 +5493,23 @@ process_tabledef(char *name, struct table_opts *opts, int popts) else if (pf->opts & PF_OPT_VERBOSE) fprintf(stderr, "%s:%d: skipping duplicate table checks" " for <%s>\n", file->name, yylval.lineno, name); + /* + * postpone definition of non-root tables to moment + * when path is fully resolved. + */ + if (pf->asd > 0) { + ukt = calloc(1, sizeof(struct pfr_uktable)); + if (ukt == NULL) { + DBGPRINT( + "%s:%d: not enough memory for <%s>\n", file->name, + yylval.lineno, name); + goto _error; + } + } else + ukt = NULL; if (!(pf->opts & PF_OPT_NOACTION) && pfctl_define_table(name, opts->flags, opts->init_addr, - pf->anchor->path, &ab, pf->anchor->ruleset.tticket)) { + pf->anchor->path, &ab, pf->anchor->ruleset.tticket, ukt)) { if (sysctlbyname("net.pf.request_maxcount", &maxcount, &s, NULL, 0) == -1) @@ -5506,6 +5525,28 @@ process_tabledef(char *name, struct table_opts *opts, int popts) goto _error; } + + if (ukt != NULL) { + ukt->pfrukt_init_addr = opts->init_addr; + if (RB_INSERT(pfr_ktablehead, &pfr_ktables, + &ukt->pfrukt_kt) != NULL) { + /* + * I think this should not happen, because + * pfctl_define_table() above does the same check + * effectively. + */ + DBGPRINT( + "%s:%d table %s already exists in %s\n", + file->name, yylval.lineno, + ukt->pfrukt_name, pf->anchor->path); + free(ukt); + goto _error; + } + DBGPRINT("%s %s@%s inserted to tree\n", + __func__, ukt->pfrukt_name, pf->anchor->path); + } else + DBGPRINT("%s ukt is null\n", __func__); + pf->tdirty = 1; pfr_buf_clear(&ab); return (0); @@ -7276,6 +7317,61 @@ mv_eth_rules(struct pfctl_eth_ruleset *src, struct pfctl_eth_ruleset *dst) src->anchor->match = 0; } +void +mv_tables(struct pfctl *pf, struct pfr_ktablehead *ktables, + struct pfctl_anchor *a, struct pfctl_anchor *alast) +{ + struct pfr_ktable *kt, *kt_safe; + char new_path[PF_ANCHOR_MAXPATH]; + char *path_cut; + int sz; + struct pfr_uktable *ukt; + SLIST_HEAD(, pfr_uktable) ukt_list; + + /* + * Here we need to rename anchor path from temporal names such as + * _1/_2/foo to _1/bar/foo etc. + * + * This also means we need to remove and insert table to ktables + * tree as anchor path is being updated. + */ + SLIST_INIT(&ukt_list); + DBGPRINT("%s [ %s ] (%s)\n", __func__, a->path, alast->path); + RB_FOREACH_SAFE(kt, pfr_ktablehead, ktables, kt_safe) { + path_cut = strstr(kt->pfrkt_anchor, alast->path); + if (path_cut != NULL) { + path_cut += strlen(alast->path); + if (*path_cut) + sz = snprintf(new_path, sizeof (new_path), + "%s%s", a->path, path_cut); + else + sz = snprintf(new_path, sizeof (new_path), + "%s", a->path); + if (sz >= sizeof (new_path)) + errx(1, "new path is too long for %s@%s\n", + kt->pfrkt_name, kt->pfrkt_anchor); + + DBGPRINT("%s %s@%s -> %s@%s\n", __func__, + kt->pfrkt_name, kt->pfrkt_anchor, + kt->pfrkt_name, new_path); + RB_REMOVE(pfr_ktablehead, ktables, kt); + strlcpy(kt->pfrkt_anchor, new_path, + sizeof(kt->pfrkt_anchor)); + SLIST_INSERT_HEAD(&ukt_list, (struct pfr_uktable *)kt, + pfrukt_entry); + } + } + + while ((ukt = SLIST_FIRST(&ukt_list)) != NULL) { + SLIST_REMOVE_HEAD(&ukt_list, pfrukt_entry); + if (RB_INSERT(pfr_ktablehead, ktables, + (struct pfr_ktable *)ukt) != NULL) + errx(1, "%s@%s exists already\n", + ukt->pfrukt_name, + ukt->pfrukt_anchor); + } +} + void decide_address_family(struct node_host *n, sa_family_t *af) { @@ -7485,7 +7581,7 @@ parseport(char *port, struct range *r, int extensions) } int -pfctl_load_anchors(int dev, struct pfctl *pf, struct pfr_buffer *trans) +pfctl_load_anchors(int dev, struct pfctl *pf) { struct loadanchors *la; @@ -7494,7 +7590,7 @@ pfctl_load_anchors(int dev, struct pfctl *pf, struct pfr_buffer *trans) fprintf(stderr, "\nLoading anchor %s from %s\n", la->anchorname, la->filename); if (pfctl_rules(dev, la->filename, pf->opts, pf->optimize, - la->anchorname, trans) == -1) + la->anchorname, pf->trans) == -1) return (-1); } diff --git a/sbin/pfctl/pfctl.c b/sbin/pfctl/pfctl.c index 2c12387ee388..601b7651e40b 100644 --- a/sbin/pfctl/pfctl.c +++ b/sbin/pfctl/pfctl.c @@ -2065,6 +2065,41 @@ pfctl_load_eth_rule(struct pfctl *pf, char *path, struct pfctl_eth_rule *r, return (0); } +static int +pfctl_load_tables(struct pfctl *pf, char *path, struct pfctl_anchor *a, + int rs_num) +{ + struct pfr_ktable *kt, *ktw; + struct pfr_uktable *ukt; + char anchor_path[PF_ANCHOR_MAXPATH]; + int e; + + RB_FOREACH_SAFE(kt, pfr_ktablehead, &pfr_ktables, ktw) { + if (strcmp(kt->pfrkt_anchor, a->path) != 0) + continue; + + if (path != NULL && *path) { + strlcpy(anchor_path, kt->pfrkt_anchor, + sizeof(anchor_path)); + snprintf(kt->pfrkt_anchor, PF_ANCHOR_MAXPATH, "%s/%s", + path, anchor_path); + } + ukt = (struct pfr_uktable *)kt; + e = pfr_ina_define(&ukt->pfrukt_t, ukt->pfrukt_addrs.pfrb_caddr, + ukt->pfrukt_addrs.pfrb_size, NULL, NULL, + pf->anchor->ruleset.tticket, + ukt->pfrukt_init_addr ? PFR_FLAG_ADDRSTOO : 0); + if (e != 0) + err(1, "%s pfr_ina_define() %s@%s", __func__, + kt->pfrkt_name, kt->pfrkt_anchor); + RB_REMOVE(pfr_ktablehead, &pfr_ktables, kt); + pfr_buf_clear(&ukt->pfrukt_addrs); + free(ukt); + } + + return (0); +} + int pfctl_load_ruleset(struct pfctl *pf, char *path, struct pfctl_ruleset *rs, int rs_num, int depth) @@ -2113,6 +2148,8 @@ pfctl_load_ruleset(struct pfctl *pf, char *path, struct pfctl_ruleset *rs, if ((error = pfctl_load_ruleset(pf, path, &r->anchor->ruleset, rs_num, depth + 1))) goto error; + if ((error = pfctl_load_tables(pf, path, r->anchor, rs_num))) + goto error; } else if (pf->opts & PF_OPT_VERBOSE) printf("\n"); free(r); @@ -2135,15 +2172,17 @@ pfctl_load_rule(struct pfctl *pf, char *path, struct pfctl_rule *r, int depth) { u_int8_t rs_num = pf_get_ruleset_number(r->action); char *name; - u_int32_t ticket; char anchor[PF_ANCHOR_NAME_SIZE]; int len = strlen(path); int error; bool was_present; /* set up anchor before adding to path for anchor_call */ - if ((pf->opts & PF_OPT_NOACTION) == 0) - ticket = pfctl_get_ticket(pf->trans, rs_num, path); + if ((pf->opts & PF_OPT_NOACTION) == 0) { + if (pf->trans == NULL) + errx(1, "pfctl_load_rule: no transaction"); + pf->anchor->ruleset.tticket = pfctl_get_ticket(pf->trans, rs_num, path); + } if (strlcpy(anchor, path, sizeof(anchor)) >= sizeof(anchor)) errx(1, "pfctl_load_rule: strlcpy"); @@ -2175,7 +2214,7 @@ pfctl_load_rule(struct pfctl *pf, char *path, struct pfctl_rule *r, int depth) return (1); if (pfctl_add_pool(pf, &r->route, PF_RT)) return (1); - error = pfctl_add_rule_h(pf->h, r, anchor, name, ticket, + error = pfctl_add_rule_h(pf->h, r, anchor, name, pf->anchor->ruleset.tticket, pf->paddr.ticket); switch (error) { case 0: @@ -2245,6 +2284,8 @@ pfctl_rules(int dev, char *filename, int opts, int optimize, RB_INIT(&pf_anchors); memset(&pf_main_anchor, 0, sizeof(pf_main_anchor)); pf_init_ruleset(&pf_main_anchor.ruleset); + memset(&pf, 0, sizeof(pf)); + memset(&trs, 0, sizeof(trs)); pf_main_anchor.ruleset.anchor = &pf_main_anchor; memset(&pf_eth_main_anchor, 0, sizeof(pf_eth_main_anchor)); @@ -2254,6 +2295,7 @@ pfctl_rules(int dev, char *filename, int opts, int optimize, if (trans == NULL) { bzero(&buf, sizeof(buf)); buf.pfrb_type = PFRB_TRANS; + pf.trans = &buf; t = &buf; osize = 0; } else { @@ -2364,7 +2406,7 @@ pfctl_rules(int dev, char *filename, int opts, int optimize, if (trans == NULL) { /* process "load anchor" directives */ - if (pfctl_load_anchors(dev, &pf, t) == -1) + if (pfctl_load_anchors(dev, &pf) == -1) ERRX("load anchors"); if ((opts & PF_OPT_NOACTION) == 0) { diff --git a/sbin/pfctl/pfctl.h b/sbin/pfctl/pfctl.h index 37e06e93dde6..136f51ea08f9 100644 --- a/sbin/pfctl/pfctl.h +++ b/sbin/pfctl/pfctl.h @@ -36,6 +36,12 @@ #include +#ifdef PFCTL_DEBUG +#define DBGPRINT(...) fprintf(stderr, __VA_ARGS__) +#else +#define DBGPRINT(...) (void)(0) +#endif + extern struct pfctl_handle *pfh; struct pfctl; @@ -55,6 +61,41 @@ struct pfr_buffer { (var) != NULL; \ (var) = pfr_buf_next((buf), (var))) +RB_HEAD(pfr_ktablehead, pfr_ktable); +struct pfr_ktable { + struct pfr_tstats pfrkt_ts; + RB_ENTRY(pfr_ktable) pfrkt_tree; + SLIST_ENTRY(pfr_ktable) pfrkt_workq; + struct radix_node_head *pfrkt_ip4; + struct radix_node_head *pfrkt_ip6; + struct pfr_ktable *pfrkt_shadow; + struct pfr_ktable *pfrkt_root; + struct pf_kruleset *pfrkt_rs; + long pfrkt_larg; + int pfrkt_nflags; +}; +#define pfrkt_t pfrkt_ts.pfrts_t +#define pfrkt_name pfrkt_t.pfrt_name +#define pfrkt_anchor pfrkt_t.pfrt_anchor +#define pfrkt_ruleset pfrkt_t.pfrt_ruleset +#define pfrkt_flags pfrkt_t.pfrt_flags +#define pfrkt_cnt pfrkt_kts.pfrkts_cnt +#define pfrkt_refcnt pfrkt_kts.pfrkts_refcnt +#define pfrkt_tzero pfrkt_kts.pfrkts_tzero + +struct pfr_uktable { + struct pfr_ktable pfrukt_kt; + struct pfr_buffer pfrukt_addrs; + int pfrukt_init_addr; + SLIST_ENTRY(pfr_uktable) pfrukt_entry; +}; + +#define pfrukt_t pfrukt_kt.pfrkt_ts.pfrts_t +#define pfrukt_name pfrukt_kt.pfrkt_t.pfrt_name +#define pfrukt_anchor pfrukt_kt.pfrkt_t.pfrt_anchor + +extern struct pfr_ktablehead pfr_ktables; + struct pfr_anchoritem { SLIST_ENTRY(pfr_anchoritem) pfra_sle; char *pfra_anchorname; diff --git a/sbin/pfctl/pfctl_optimize.c b/sbin/pfctl/pfctl_optimize.c index 1d2a60555f19..2d16bbd22b39 100644 --- a/sbin/pfctl/pfctl_optimize.c +++ b/sbin/pfctl/pfctl_optimize.c @@ -1331,7 +1331,8 @@ again: if (pfctl_define_table(tbl->pt_name, PFR_TFLAG_CONST, 1, - pf->astack[0]->path, tbl->pt_buf, pf->astack[0]->ruleset.tticket)) { + pf->astack[0]->path, tbl->pt_buf, pf->astack[0]->ruleset.tticket, + NULL)) { warn("failed to create table %s in %s", tbl->pt_name, pf->astack[0]->name); return (1); diff --git a/sbin/pfctl/pfctl_parser.h b/sbin/pfctl/pfctl_parser.h index 58d3abc36691..e96ff0195e03 100644 --- a/sbin/pfctl/pfctl_parser.h +++ b/sbin/pfctl/pfctl_parser.h @@ -36,6 +36,8 @@ #include +#include + #define PF_OSFP_FILE "/etc/pf.os" #define PF_OPT_DISABLE 0x00001 @@ -90,6 +92,7 @@ struct pfctl { struct pfioc_queue *pqueue; struct pfr_buffer *trans; struct pfctl_anchor *anchor, *alast; + struct pfr_ktablehead pfr_ktlast; int eth_nr; struct pfctl_eth_anchor *eanchor, *ealast; struct pfctl_eth_anchor *eastack[PFCTL_ANCHOR_STACK_DEPTH]; @@ -277,6 +280,8 @@ struct pf_opt_rule { TAILQ_HEAD(pf_opt_queue, pf_opt_rule); +struct pfr_uktable; + void copy_satopfaddr(struct pf_addr *, struct sockaddr *); int pfctl_rules(int, char *, int, int, char *, struct pfr_buffer *); @@ -303,7 +308,7 @@ int pfctl_cfg_syncookies(struct pfctl *, uint8_t, struct pfctl_watermarks *); int parse_config(char *, struct pfctl *); int parse_flags(char *); -int pfctl_load_anchors(int, struct pfctl *, struct pfr_buffer *); +int pfctl_load_anchors(int, struct pfctl *); void print_pool(struct pfctl_pool *, u_int16_t, u_int16_t, int); void print_src_node(struct pfctl_src_node *, int); @@ -324,7 +329,7 @@ void print_queue(const struct pf_altq *, unsigned, struct node_queue_bw *, int, struct node_queue_opt *); int pfctl_define_table(char *, int, int, const char *, struct pfr_buffer *, - u_int32_t); + u_int32_t, struct pfr_uktable *); void pfctl_clear_fingerprints(int, int); int pfctl_file_fingerprints(int, int, const char *); @@ -380,5 +385,8 @@ struct node_host *host(const char *, int); int append_addr(struct pfr_buffer *, char *, int, int); int append_addr_host(struct pfr_buffer *, struct node_host *, int, int); +int pfr_ktable_compare(struct pfr_ktable *, + struct pfr_ktable *); +RB_PROTOTYPE(pfr_ktablehead, pfr_ktable, pfrkt_tree, pfr_ktable_compare); #endif /* _PFCTL_PARSER_H_ */ diff --git a/sbin/pfctl/pfctl_radix.c b/sbin/pfctl/pfctl_radix.c index 398c5e998330..98f907738d95 100644 --- a/sbin/pfctl/pfctl_radix.c +++ b/sbin/pfctl/pfctl_radix.c @@ -48,6 +48,7 @@ #include #include "pfctl.h" +#include "pfctl_parser.h" #define BUF_SIZE 256 @@ -55,6 +56,19 @@ extern int dev; static int pfr_next_token(char buf[BUF_SIZE], FILE *); +struct pfr_ktablehead pfr_ktables = { 0 }; +RB_GENERATE(pfr_ktablehead, pfr_ktable, pfrkt_tree, pfr_ktable_compare); + +int +pfr_ktable_compare(struct pfr_ktable *p, struct pfr_ktable *q) +{ + int d; + + if ((d = strncmp(p->pfrkt_name, q->pfrkt_name, PF_TABLE_NAME_SIZE))) + return (d); + return (strcmp(p->pfrkt_anchor, q->pfrkt_anchor)); +} + static void pfr_report_error(struct pfr_table *tbl, struct pfioc_table *io, const char *err) @@ -256,6 +270,7 @@ pfr_ina_define(struct pfr_table *tbl, struct pfr_addr *addr, int size, struct pfioc_table io; if (tbl == NULL || size < 0 || (size && addr == NULL)) { + DBGPRINT("%s %p %d %p\n", __func__, tbl, size, addr); errno = EINVAL; return (-1); } diff --git a/sbin/pfctl/pfctl_table.c b/sbin/pfctl/pfctl_table.c index 745ab84b3159..4955e1791fd7 100644 --- a/sbin/pfctl/pfctl_table.c +++ b/sbin/pfctl/pfctl_table.c @@ -570,19 +570,50 @@ print_astats(struct pfr_astats *as, int dns) int pfctl_define_table(char *name, int flags, int addrs, const char *anchor, - struct pfr_buffer *ab, u_int32_t ticket) + struct pfr_buffer *ab, u_int32_t ticket, struct pfr_uktable *ukt) { - struct pfr_table tbl; + struct pfr_table tbl_buf; + struct pfr_table *tbl; + + if (ukt == NULL) { + bzero(&tbl_buf, sizeof(tbl_buf)); + tbl = &tbl_buf; + } else { + if (ab->pfrb_size != 0) { + /* + * copy IP addresses which come with table from + * temporal buffer to buffer attached to table. + */ + ukt->pfrukt_addrs = *ab; + ab->pfrb_size = 0; + ab->pfrb_msize = 0; + ab->pfrb_caddr = NULL; + } else + memset(&ukt->pfrukt_addrs, 0, + sizeof(struct pfr_buffer)); + + tbl = &ukt->pfrukt_t; + } - bzero(&tbl, sizeof(tbl)); - if (strlcpy(tbl.pfrt_name, name, sizeof(tbl.pfrt_name)) >= - sizeof(tbl.pfrt_name) || strlcpy(tbl.pfrt_anchor, anchor, - sizeof(tbl.pfrt_anchor)) >= sizeof(tbl.pfrt_anchor)) - errx(1, "pfctl_define_table: strlcpy"); - tbl.pfrt_flags = flags; + if (strlcpy(tbl->pfrt_name, name, sizeof(tbl->pfrt_name)) >= + sizeof(tbl->pfrt_name) || + strlcpy(tbl->pfrt_anchor, anchor, sizeof(tbl->pfrt_anchor)) >= + sizeof(tbl->pfrt_anchor)) + errx(1, "%s: strlcpy", __func__); + tbl->pfrt_flags = flags; + DBGPRINT("%s %s@%s [%x]\n", __func__, tbl->pfrt_name, tbl->pfrt_anchor, + tbl->pfrt_flags); + + /* + * non-root anchors processed by parse.y are loaded to kernel later. + * Here we load tables, which are either created for root anchor + * or by 'pfctl -t ... -T ...' command. + */ + if (ukt != NULL) + return (0); - return pfr_ina_define(&tbl, ab->pfrb_caddr, ab->pfrb_size, NULL, - NULL, ticket, addrs ? PFR_FLAG_ADDRSTOO : 0); + return (pfr_ina_define(tbl, ab->pfrb_caddr, ab->pfrb_size, NULL, NULL, + ticket, addrs ? PFR_FLAG_ADDRSTOO : 0)); } void