Download raw body.
let's make pf(4) anchors and tables better friends
Hello,
the change presented in diff below allows user to define table
inside the anchor. Consider rules here:
--------8<---------------8<---------------8<------------------8<--------
match in all scrub (no-df random-id)
pass out log proto tcp from self to any port 12345
anchor "relayd/*"
anchor "test" {
pass out log proto tcp from self to any port 12346
anchor "foo" {
table <allow> persist { 192.168.2.10 }
pass out log proto tcp from <allow> to <foo> port 12348
}
pass out log proto tcp from self to any port 12349
}
pass out log proto tcp from self to any port 12347
--------8<---------------8<---------------8<------------------8<--------
using pfctl(8) in current to load rules above I get errors as
follows:
lifty# pfctl -f /tmp/pf-anchors.conf
/tmp/pf-anchors.conf:7: syntax error
/tmp/pf-anchors.conf:9: syntax error
/tmp/pf-anchors.conf:11: syntax error
pfctl: Syntax error in config file: pf rules not loaded
This is pfctl's parser limitation which I believe most people
have never ever noticed. One can workaround limitation of
the parser by creating table allow@test/foo using a pfctl(8).
The idea is as follows: remove definition of <allow> table
from config file so it loads. Load the file and then
run command as follows:
pfctl -a test/foo -t allow -T add 192.168.2.10
Using 'pfctl -a "*" -g -v -sT' we can see the result in pf(4):
--------8<---------------8<---------------8<------------------8<--------
lifty# pfctl -f /tmp/pf-anchors-workaround.conf
lifty# pfctl -a test/foo -t allow -T add 192.168.2.10
1/1 addresses added.
lifty# pfctl -a "*" -g -v -sT
-pa---- allow@test/foo
----r-- foo@test/foo
-----h- allow
-----h- foo
--------8<---------------8<---------------8<------------------8<--------
Trying to load the rules where anchor <allow> is defined using
fixed pfctl(8) we see table allow@test/foo differs lacks flag p (persistent)
and flag a (active). On the other hand table got flag 'r' to
indicate it is referenced by rule.
--------8<---------------8<---------------8<------------------8<--------
lifty# ./pfctl -f /tmp/pf-anchors.conf
lifty# pfctl -a "*" -g -v -sT
----r-- allow@test/foo
----r-- foo@test/foo
-----h- allow
-----h- foo
--------8<---------------8<---------------8<------------------8<--------
Stop reading here if you are not interested in details around
tables and anchors.
What's also worth to note is the sample ruleset here creates two
pairs of tables:
allow and allow@test/foo
foo and foo@test/foo
the pair of tables linked together via member ->pfrkt_root
in pf(4) code. Tables foo and allow which belong to main anchor
(root) have ->pfrkt_root set to NULL. In tables allow@test/foo
and foo@test/foo member ->pfrkt_root refers to tables allow and
foo found in main anchor. If there will be table foo@test
then ->pfrkt_root in such table will refer to table foo in
main anchor too.
So how tables are attached to tables? Well tables are not
attached to anchors at all. Both those objects (anchors and
tables) are kept in their own respective trees. This what happens
once table gets `attached` to non-root anchor. Consider we use
command:
pfctl -a test -t allow -T add 172.16.1.10
In this case pfctl(8) tries to create two instances of allow table:
allow `attached` to root anchor, this time the allow table is
already there, so function spits a warning about conflict,
the allow table found in tree already is left there.
and table allow@test `attached` to test anchor
RB tree which keeps tables in pf(4) uses compare function as
follows:
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));
}
If table names do match function compares the anchor. The
pfrkt_anchor holds the path from root to anchor. So in the case
of allow table those might be allow@test vs. allow@test/foo
Now you might be asking: so shall we just stop using tables
in non-root anchors and remove that semi-working code completely?
The answers is: that semi-working code is actually being used
by relayd(8), spamd(8) and perhaps some other daemons which manage
pf(4) at runtime. Those daemons keep their tables attached to non-root
anchors.
In my opinion code around tables deserves some love. The fix to
parser is the first step. The next step I'd like to do is
to get rid off global pfr_ktables tree. Instead of global
pfr_ktables tree each pf_anchor will get its own. This is far
more complex change, but I think it's worth the effort. Because
it makes reasoning about code and rules bit easier (I think, but
I might be biased). Another benefit of such change is that it
will allow us to let anchors to define a scope for each table in
the same fashion as we use scope for local variables in C.
The diff which moves pfr_ktables into pf_anchor is still work in
progress. Today I'm just sharing the fix to parser.
sorry for long email.
OK to commit?
thanks and
regards
sashan
--------8<---------------8<---------------8<------------------8<--------
diff --git a/sbin/pfctl/parse.y b/sbin/pfctl/parse.y
index ee5c00f3b8b..39f33aef327 100644
--- a/sbin/pfctl/parse.y
+++ b/sbin/pfctl/parse.y
@@ -379,6 +379,8 @@ int getservice(char *);
int rule_label(struct pf_rule *, char *);
void mv_rules(struct pf_ruleset *, struct pf_ruleset *);
+void mv_tables(struct pfctl *, struct pfr_ktablehead *,
+ struct pf_anchor *, struct pf_anchor *);
void decide_address_family(struct node_host *, sa_family_t *);
int invalid_redirect(struct node_host *, sa_family_t);
u_int16_t parseicmpspec(char *, sa_family_t);
@@ -827,6 +829,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'
@@ -853,7 +856,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 '}'
@@ -899,6 +902,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;
@@ -3976,6 +3980,7 @@ process_tabledef(char *name, struct table_opts *opts, int popts)
{
struct pfr_buffer ab;
struct node_tinit *ti;
+ struct pfr_uktable *ukt;
bzero(&ab, sizeof(ab));
ab.pfrb_type = PFRB_ADDRS;
@@ -4006,12 +4011,51 @@ 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);
- if (!(pf->opts & PF_OPT_NOACTION) &&
- pfctl_define_table(name, opts->flags, opts->init_addr,
- pf->anchor->path, &ab, pf->anchor->ruleset.tticket)) {
- yyerror("cannot define table %s: %s", name,
- pf_strerror(errno));
- goto _error;
+
+ if (!(pf->opts & PF_OPT_NOACTION)) {
+ /*
+ * 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 (pfctl_define_table(name, opts->flags, opts->init_addr,
+ pf->anchor->path, &ab, pf->anchor->ruleset.tticket, ukt)) {
+ yyerror("cannot define table %s: %s", name,
+ pf_strerror(errno));
+ 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);
@@ -5555,6 +5599,51 @@ mv_rules(struct pf_ruleset *src, struct pf_ruleset *dst)
TAILQ_CONCAT(dst->rules.inactive.ptr, src->rules.inactive.ptr, entries);
}
+void
+mv_tables(struct pfctl *pf, struct pfr_ktablehead *ktables,
+ struct pf_anchor *a, struct pf_anchor *alast)
+{
+
+ struct pfr_ktable *kt, *kt_safe;
+ char new_path[PF_ANCHOR_MAXPATH];
+ char *path_cut;
+ int sz;
+
+ /*
+ * 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.
+ */
+ 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));
+ if (RB_INSERT(pfr_ktablehead, ktables, kt) != NULL)
+ errx(1, "%s@%s exists already\n",
+ kt->pfrkt_name, kt->pfrkt_anchor);
+ }
+ }
+}
+
void
decide_address_family(struct node_host *n, sa_family_t *af)
{
@@ -5711,7 +5800,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;
@@ -5720,7 +5809,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 27cc175c871..f0133530fd6 100644
--- a/sbin/pfctl/pfctl.c
+++ b/sbin/pfctl/pfctl.c
@@ -1424,6 +1424,40 @@ pfctl_check_qassignments(struct pf_ruleset *rs)
return (errs);
}
+static int
+pfctl_load_tables(struct pfctl *pf, char *path, struct pf_anchor *a)
+{
+ struct pfr_ktable *kt, *ktw;
+ struct pfr_uktable *ukt;
+ uint32_t ticket = pfctl_get_ticket(pf->trans, PF_TRANS_TABLE, path);
+ 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, ticket,
+ 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 pf_ruleset *rs,
int depth)
@@ -1469,6 +1503,8 @@ pfctl_load_ruleset(struct pfctl *pf, char *path, struct pf_ruleset *rs,
if ((error = pfctl_load_ruleset(pf, path,
&r->anchor->ruleset, depth + 1)))
goto error;
+ if ((error = pfctl_load_tables(pf, path, r->anchor)))
+ goto error;
} else if (pf->opts & PF_OPT_VERBOSE)
printf("\n");
free(r);
@@ -1495,8 +1531,11 @@ pfctl_load_rule(struct pfctl *pf, char *path, struct pf_rule *r, int depth)
bzero(&pr, sizeof(pr));
/* set up anchor before adding to path for anchor_call */
- if ((pf->opts & PF_OPT_NOACTION) == 0)
+ if ((pf->opts & PF_OPT_NOACTION) == 0) {
+ if (pf->trans == NULL)
+ errx(1, "pfctl_load_rule: no transaction");
pr.ticket = pfctl_get_ticket(pf->trans, PF_TRANS_RULESET, path);
+ }
if (strlcpy(pr.anchor, path, sizeof(pr.anchor)) >= sizeof(pr.anchor))
errx(1, "pfctl_load_rule: strlcpy");
@@ -1535,8 +1574,8 @@ int
pfctl_rules(int dev, char *filename, int opts, int optimize,
char *anchorname, struct pfr_buffer *trans)
{
-#define ERR(x) do { warn(x); goto _error; } while(0)
-#define ERRX(x) do { warnx(x); goto _error; } while(0)
+#define ERR(...) do { warn(__VA_ARGS__); goto _error; } while(0)
+#define ERRX(...) do { warnx(__VA_ARGS__); goto _error; } while(0)
struct pfr_buffer *t, buf;
struct pfctl pf;
@@ -1549,9 +1588,13 @@ 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));
+
if (trans == NULL) {
bzero(&buf, sizeof(buf));
buf.pfrb_type = PFRB_TRANS;
+ pf.trans = &buf;
t = &buf;
osize = 0;
} else {
@@ -1559,20 +1602,18 @@ pfctl_rules(int dev, char *filename, int opts, int optimize,
osize = t->pfrb_size;
}
- memset(&pf, 0, sizeof(pf));
- memset(&trs, 0, sizeof(trs));
if ((path = calloc(1, PATH_MAX)) == NULL)
- ERRX("pfctl_rules: calloc");
+ ERR("%s: calloc", __func__);
if (strlcpy(trs.pfrt_anchor, anchorname,
sizeof(trs.pfrt_anchor)) >= sizeof(trs.pfrt_anchor))
- ERRX("pfctl_rules: strlcpy");
+ ERRX("%s: strlcpy", __func__);
pf.dev = dev;
pf.opts = opts;
pf.optimize = optimize;
/* non-brace anchor, create without resolving the path */
if ((pf.anchor = calloc(1, sizeof(*pf.anchor))) == NULL)
- ERRX("pfctl_rules: calloc");
+ ERR("%s: calloc", __func__);
rs = &pf.anchor->ruleset;
pf_init_ruleset(rs);
rs->anchor = pf.anchor;
@@ -1637,7 +1678,7 @@ pfctl_rules(int dev, char *filename, int opts, int optimize,
/*
* process "load anchor" directives that might have used queues
*/
- if (pfctl_load_anchors(dev, &pf, t) == -1)
+ if (pfctl_load_anchors(dev, &pf) == -1)
ERRX("load anchors");
pfctl_clear_queues(&qspecs);
pfctl_clear_queues(&rootqs);
diff --git a/sbin/pfctl/pfctl.h b/sbin/pfctl/pfctl.h
index 253b8242d45..19920f0fa1e 100644
--- a/sbin/pfctl/pfctl.h
+++ b/sbin/pfctl/pfctl.h
@@ -33,6 +33,12 @@
#ifndef _PFCTL_H_
#define _PFCTL_H_
+#ifdef PFCTL_DEBUG
+#define DBGPRINT(...) fprintf(stderr, __VA_ARGS__)
+#else
+#define DBGPRINT(...) (void)(0)
+#endif
+
enum pfctl_show { PFCTL_SHOW_RULES, PFCTL_SHOW_LABELS, PFCTL_SHOW_NOTHING };
enum { PFRB_TABLES = 1, PFRB_TSTATS, PFRB_ADDRS, PFRB_ASTATS,
@@ -54,6 +60,17 @@ struct pfr_anchoritem {
char *pfra_anchorname;
};
+struct pfr_uktable {
+ struct pfr_ktable pfrukt_kt;
+ struct pfr_buffer pfrukt_addrs;
+ int pfrukt_init_addr;
+};
+
+#define pfrukt_t pfrukt_kt.pfrkt_ts.pfrts_t
+#define pfrukt_name pfrukt_kt.pfrkt_t.pfrt_name
+
+extern struct pfr_ktablehead pfr_ktables;
+
SLIST_HEAD(pfr_anchors, pfr_anchoritem);
int pfr_clr_tables(struct pfr_table *, int *, int);
diff --git a/sbin/pfctl/pfctl_optimize.c b/sbin/pfctl/pfctl_optimize.c
index dc93b882bef..c1bd6f6f6cc 100644
--- a/sbin/pfctl/pfctl_optimize.c
+++ b/sbin/pfctl/pfctl_optimize.c
@@ -1288,7 +1288,8 @@ again:
tablenum++;
if (pfctl_define_table(tbl->pt_name, PFR_TFLAG_CONST | tbl->pt_flags, 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 146580db2b8..bff3f640421 100644
--- a/sbin/pfctl/pfctl_parser.h
+++ b/sbin/pfctl/pfctl_parser.h
@@ -85,6 +85,7 @@ struct pfctl {
struct pfioc_queue *pqueue;
struct pfr_buffer *trans;
struct pf_anchor *anchor, *alast;
+ struct pfr_ktablehead pfr_ktlast;
const char *ruleset;
/* 'set foo' options */
@@ -211,6 +212,8 @@ struct pfctl_watermarks {
u_int32_t lo;
};
+struct pfr_uktable;
+
void copy_satopfaddr(struct pf_addr *, struct sockaddr *);
int pfctl_rules(int, char *, int, int, char *, struct pfr_buffer *);
@@ -234,7 +237,7 @@ int pfctl_set_interface_flags(struct pfctl *, char *, int, int);
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 *);
int pfctl_load_queues(struct pfctl *);
int pfctl_add_queue(struct pfctl *, struct pf_queuespec *);
@@ -248,7 +251,7 @@ void print_status(struct pf_status *, struct pfctl_watermarks *, int);
void print_queuespec(struct pf_queuespec *);
int pfctl_define_table(char *, int, int, const char *, struct pfr_buffer *,
- u_int32_t);
+ u_int32_t, struct pfr_uktable *);
void pfctl_expand_label_nr(struct pf_rule *, unsigned int);
void pfctl_clear_fingerprints(int, int);
@@ -298,5 +301,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 446329daf9e..4823d19efb8 100644
--- a/sbin/pfctl/pfctl_radix.c
+++ b/sbin/pfctl/pfctl_radix.c
@@ -55,6 +55,18 @@ 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));
+}
int
pfr_clr_tables(struct pfr_table *filter, int *ndel, int flags)
@@ -352,6 +364,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 6443126900e..6f4acfeec82 100644
--- a/sbin/pfctl/pfctl_table.c
+++ b/sbin/pfctl/pfctl_table.c
@@ -520,18 +520,47 @@ 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;
-
- 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;
+ 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;
+ }
- return pfr_ina_define(&tbl, ab->pfrb_caddr, ab->pfrb_size, NULL,
+ 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);
}
let's make pf(4) anchors and tables better friends