Download raw body.
pf(4) add timeout option to ip address tables
Hello,
diff below should help people who use 'overload' action in their
firewall configuration. This is how pf.conf(5) describes the
overload option:
Because the 3-way handshake ensures that the source address is not being
spoofed, more aggressive action can be taken based on these limits. With
the overload <table> state option, source IP addresses which hit either
of the limits on established connections will be added to the named
table. This table can be used in the ruleset to block further activity
from the offending host, redirect it to a tarpit process, or restrict its
bandwidth.
As you can see pf(4) keeps adding addresses to table. Administrator
must clear the table which is used by 'overload' option.
The newly added 'Source Limiter' suffers from the same issue.
Source limiter may add the source IP address which exceeds
the limit to table. However administrator can not define
any duration how long the IP address should be kept in
table referred by limiter.
Diff below adds 'timeout' option for table, so administrator
can define duration in seconds for how long the IP address
is kept in table.
I think it's been pointed out by dlg@ long time ago similar
feature is missing in pf(4).
OK ?
thanks and
regards
sashan
--------8<---------------8<---------------8<------------------8<--------
diff --git a/sbin/pfctl/parse.y b/sbin/pfctl/parse.y
index 92764edcf3b..afb6dce4eef 100644
--- a/sbin/pfctl/parse.y
+++ b/sbin/pfctl/parse.y
@@ -348,6 +348,7 @@ struct queue_opts {
struct table_opts {
int flags;
int init_addr;
+ uint32_t timeout;
struct node_tinithead init_nodes;
} table_opts;
@@ -1401,6 +1402,16 @@ table_opt : STRING {
entries);
table_opts.init_addr = 1;
}
+ | TIMEOUT '(' NUMBER ')' {
+ /*
+ * timeout tables are intended for 'overload' action in
+ * rules and limiters. They are not supposed to be
+ * either constant nor manged from command line
+ * (persistent). Also no support for counters.
+ */
+ table_opts.flags = PFR_TFLAG_TIMEOUT;
+ table_opts.timeout = $3;
+ }
;
tablespec : xhost optweight {
@@ -4508,7 +4519,7 @@ process_tabledef(char *name, struct table_opts *opts, int popts)
}
if (pf->opts & PF_OPT_VERBOSE)
print_tabledef(name, opts->flags, opts->init_addr,
- &opts->init_nodes);
+ opts->timeout, &opts->init_nodes);
if (!(pf->opts & PF_OPT_NOACTION) ||
(pf->opts & PF_OPT_DUMMYACTION))
warn_duplicate_tables(name, pf->anchor->path);
@@ -4533,7 +4544,8 @@ process_tabledef(char *name, struct table_opts *opts, int popts)
if (!(pf->opts & PF_OPT_NOACTION) &&
pfctl_define_table(name, opts->flags, opts->init_addr,
- pf->anchor->path, &ab, pf->anchor->ruleset.tticket, ukt)) {
+ pf->anchor->path, opts->timeout, &ab, pf->anchor->ruleset.tticket,
+ ukt)) {
yyerror("cannot define table %s: %s", name,
pf_strerror(errno));
goto _error;
@@ -5027,7 +5039,7 @@ collapse_redirspec(struct pf_pool *rpool, struct pf_rule *r,
if (pf->opts & PF_OPT_VERBOSE)
print_tabledef(tbl->pt_name,
PFR_TFLAG_CONST | tbl->pt_flags,
- 1, &tbl->pt_nodes);
+ 1, 0, &tbl->pt_nodes);
memset(&rpool->addr, 0, sizeof(rpool->addr));
rpool->addr.type = PF_ADDR_TABLE;
diff --git a/sbin/pfctl/pfctl_optimize.c b/sbin/pfctl/pfctl_optimize.c
index fff28c97f3f..d4a78af1297 100644
--- a/sbin/pfctl/pfctl_optimize.c
+++ b/sbin/pfctl/pfctl_optimize.c
@@ -564,7 +564,7 @@ combine_rules(struct pfctl *pf, struct superblock *block)
if (pf->opts & PF_OPT_VERBOSE)
print_tabledef(p1->por_src_tbl->pt_name,
- PFR_TFLAG_CONST, 1,
+ PFR_TFLAG_CONST, 1, 0,
&p1->por_src_tbl->pt_nodes);
memset(&p1->por_rule.src.addr, 0,
@@ -595,7 +595,7 @@ combine_rules(struct pfctl *pf, struct superblock *block)
if (pf->opts & PF_OPT_VERBOSE)
print_tabledef(p1->por_dst_tbl->pt_name,
- PFR_TFLAG_CONST, 1,
+ PFR_TFLAG_CONST, 1, 0,
&p1->por_dst_tbl->pt_nodes);
memset(&p1->por_rule.dst.addr, 0,
@@ -1288,7 +1288,7 @@ 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, 0, tbl->pt_buf, pf->astack[0]->ruleset.tticket,
NULL)) {
warn("failed to create table %s in %s",
tbl->pt_name, pf->astack[0]->name);
diff --git a/sbin/pfctl/pfctl_parser.c b/sbin/pfctl/pfctl_parser.c
index f47ee3e8568..cd3be69a590 100644
--- a/sbin/pfctl/pfctl_parser.c
+++ b/sbin/pfctl/pfctl_parser.c
@@ -1229,7 +1229,7 @@ print_rule(struct pfctl *pf, struct pf_rule *r, const char *anchor_call,
}
void
-print_tabledef(const char *name, int flags, int addrs,
+print_tabledef(const char *name, int flags, int addrs, uint32_t timeout,
struct node_tinithead *nodes)
{
struct node_tinit *ti, *nti;
@@ -1242,6 +1242,8 @@ print_tabledef(const char *name, int flags, int addrs,
printf(" persist");
if (flags & PFR_TFLAG_COUNTERS)
printf(" counters");
+ if (flags & PFR_TFLAG_TIMEOUT)
+ printf(" timeout(%u)", timeout);
SIMPLEQ_FOREACH(ti, nodes, entries) {
if (ti->file) {
printf(" file \"%s\"", ti->file);
diff --git a/sbin/pfctl/pfctl_parser.h b/sbin/pfctl/pfctl_parser.h
index c65a805ad90..c569530c332 100644
--- a/sbin/pfctl/pfctl_parser.h
+++ b/sbin/pfctl/pfctl_parser.h
@@ -276,17 +276,19 @@ int pfctl_load_queues(struct pfctl *);
int pfctl_add_queue(struct pfctl *, struct pf_queuespec *);
struct pfctl_qsitem * pfctl_find_queue(char *, struct pf_qihead *);
-void print_pool(struct pf_pool *, u_int16_t, u_int16_t, sa_family_t, int, int);
+void print_pool(struct pf_pool *, u_int16_t, u_int16_t, sa_family_t, int,
+ int);
void print_src_node(struct pf_src_node *, int);
void print_statelim(const struct pfioc_statelim *);
void print_sourcelim(const struct pfioc_sourcelim *);
void print_rule(struct pfctl *pf, struct pf_rule *, const char *, int);
-void print_tabledef(const char *, int, int, struct node_tinithead *);
+void print_tabledef(const char *, int, int, uint32_t,
+ struct node_tinithead *);
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, struct pfr_uktable *);
+int pfctl_define_table(char *, int, int, const char *, u_int32_t,
+ struct pfr_buffer *, u_int32_t, struct pfr_uktable *);
void pfctl_expand_label_nr(struct pf_rule *, unsigned int);
void pfctl_clear_fingerprints(int, int);
diff --git a/sbin/pfctl/pfctl_table.c b/sbin/pfctl/pfctl_table.c
index e460adf5f23..3eb25beedd0 100644
--- a/sbin/pfctl/pfctl_table.c
+++ b/sbin/pfctl/pfctl_table.c
@@ -57,7 +57,7 @@ extern void usage(void);
static void print_table(struct pfr_table *, int, int);
static void print_tstats(struct pfr_tstats *, int);
static int load_addr(struct pfr_buffer *, int, char *[], char *, int, int);
-static void print_addrx(struct pfr_addr *, struct pfr_addr *, int);
+static void print_addrx(struct pfr_addr *, struct pfr_addr *, int, int);
static void print_astats(struct pfr_astats *, int);
static void xprintf(int, const char *, ...);
static void print_iface(struct pfi_kif *, int);
@@ -208,7 +208,7 @@ pfctl_table(int argc, char *argv[], char *tname, const char *command,
if (opts & PF_OPT_VERBOSE2 ||
a->pfra_fback != PFR_FB_NONE)
print_addrx(a, NULL,
- opts & PF_OPT_USEDNS);
+ opts & PF_OPT_USEDNS, 0);
} else if (!strcmp(command, "delete")) {
b.pfrb_type = PFRB_ADDRS;
if (load_addr(&b, argc, argv, file, 0, opts))
@@ -223,7 +223,7 @@ pfctl_table(int argc, char *argv[], char *tname, const char *command,
if (opts & PF_OPT_VERBOSE2 ||
a->pfra_fback != PFR_FB_NONE)
print_addrx(a, NULL,
- opts & PF_OPT_USEDNS);
+ opts & PF_OPT_USEDNS, 0);
} else if (!strcmp(command, "replace")) {
b.pfrb_type = PFRB_ADDRS;
if (load_addr(&b, argc, argv, file, 0, opts))
@@ -255,7 +255,7 @@ pfctl_table(int argc, char *argv[], char *tname, const char *command,
if (opts & PF_OPT_VERBOSE2 ||
a->pfra_fback != PFR_FB_NONE)
print_addrx(a, NULL,
- opts & PF_OPT_USEDNS);
+ opts & PF_OPT_USEDNS, 0);
} else if (!strcmp(command, "expire")) {
const char *errstr;
u_int lifetime;
@@ -294,7 +294,7 @@ pfctl_table(int argc, char *argv[], char *tname, const char *command,
if (opts & PF_OPT_VERBOSE2 ||
a->pfra_fback != PFR_FB_NONE)
print_addrx(a, NULL,
- opts & PF_OPT_USEDNS);
+ opts & PF_OPT_USEDNS, 0);
} else if (!strcmp(command, "show")) {
b.pfrb_type = (opts & PF_OPT_VERBOSE) ?
PFRB_ASTATS : PFRB_ADDRS;
@@ -316,7 +316,7 @@ pfctl_table(int argc, char *argv[], char *tname, const char *command,
if (opts & PF_OPT_VERBOSE)
print_astats(p, opts & PF_OPT_USEDNS);
else
- print_addrx(p, NULL, opts & PF_OPT_USEDNS);
+ print_addrx(p, NULL, opts & PF_OPT_USEDNS, 0);
} else if (!strcmp(command, "test")) {
b.pfrb_type = PFRB_ADDRS;
b2.pfrb_type = PFRB_ADDRS;
@@ -336,12 +336,12 @@ pfctl_table(int argc, char *argv[], char *tname, const char *command,
PFRB_FOREACH(a, &b)
if (a->pfra_fback == PFR_FB_MATCH)
print_addrx(a, NULL,
- opts & PF_OPT_USEDNS);
+ opts & PF_OPT_USEDNS, 0);
if (opts & PF_OPT_VERBOSE2) {
a2 = NULL;
PFRB_FOREACH(a, &b) {
a2 = pfr_buf_next(&b2, a2);
- print_addrx(a2, a, opts & PF_OPT_USEDNS);
+ print_addrx(a2, a, opts & PF_OPT_USEDNS, 0);
}
}
if (nmatch < b.pfrb_size)
@@ -360,7 +360,7 @@ pfctl_table(int argc, char *argv[], char *tname, const char *command,
if (opts & PF_OPT_VERBOSE2 ||
a->pfra_fback != PFR_FB_NONE)
print_addrx(a, NULL,
- opts & PF_OPT_USEDNS);
+ opts & PF_OPT_USEDNS, 0);
} else if (!strcmp(command, "zero")) {
flags |= PFR_FLAG_ADDRSTOO;
RVTEST(pfr_clr_tstats(&table, 1, &nzero, flags));
@@ -383,18 +383,21 @@ print_table(struct pfr_table *ta, int verbose, int debug)
if (!debug && !(ta->pfrt_flags & PFR_TFLAG_ACTIVE))
return;
if (verbose)
- printf("%c%c%c%c%c%c%c\t",
+ printf("%c%c%c%c%c%c%c%c\t",
(ta->pfrt_flags & PFR_TFLAG_CONST) ? 'c' : '-',
(ta->pfrt_flags & PFR_TFLAG_PERSIST) ? 'p' : '-',
(ta->pfrt_flags & PFR_TFLAG_ACTIVE) ? 'a' : '-',
(ta->pfrt_flags & PFR_TFLAG_INACTIVE) ? 'i' : '-',
(ta->pfrt_flags & PFR_TFLAG_REFERENCED) ? 'r' : '-',
(ta->pfrt_flags & PFR_TFLAG_REFDANCHOR) ? 'h' : '-',
+ (ta->pfrt_flags & PFR_TFLAG_TIMEOUT) ? 't' : '-',
(ta->pfrt_flags & PFR_TFLAG_COUNTERS) ? 'C' : '-');
printf("%s", ta->pfrt_name);
if (ta->pfrt_anchor[0] != '\0')
printf("@%s", ta->pfrt_anchor);
+ if (verbose && ta->pfrt_flags & PFR_TFLAG_TIMEOUT)
+ printf(" timeout(%u)", ta->pfrt_timeout);
printf("\n");
}
@@ -452,11 +455,19 @@ load_addr(struct pfr_buffer *b, int argc, char *argv[], char *file,
}
void
-print_addrx(struct pfr_addr *ad, struct pfr_addr *rad, int dns)
+print_addrx(struct pfr_addr *ad, struct pfr_addr *rad, int dns, int verbose)
{
char ch, buf[256] = "{error}";
char fb[] = { ' ', 'M', 'A', 'D', 'C', 'Z', 'X', ' ', 'Y', ' ' };
unsigned int fback, hostnet;
+ time_t now = time(NULL);
+
+ /*
+ * do not print expired addresses, those are printed in verbose output
+ * only.
+ */
+ if (verbose == 0 && ad->pfra_expire != 0 && ad->pfra_expire < now)
+ return;
fback = (rad != NULL) ? rad->pfra_fback : ad->pfra_fback;
ch = (fback < sizeof(fb)/sizeof(*fb)) ? fb[fback] : '?';
@@ -499,6 +510,13 @@ print_addrx(struct pfr_addr *ad, struct pfr_addr *rad, int dns)
}
if (ad->pfra_ifname[0] != '\0')
printf("@%s", ad->pfra_ifname);
+ if (verbose != 0 && ad->pfra_expire != 0) {
+ if (ad->pfra_expire < now)
+ printf("\t[ expired %llds ago ]",
+ now - ad->pfra_expire);
+ else
+ printf("\t[ expires in %llds ]", ad->pfra_expire - now);
+ }
printf("\n");
}
@@ -510,7 +528,7 @@ print_astats(struct pfr_astats *as, int dns)
char *ct;
ct = ctime(&time);
- print_addrx(&as->pfras_a, NULL, dns);
+ print_addrx(&as->pfras_a, NULL, dns, 1);
if (ct)
printf("\tCleared: %s", ctime(&time));
else
@@ -533,7 +551,8 @@ 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_uktable *ukt)
+ u_int32_t timeout, struct pfr_buffer *ab, u_int32_t ticket,
+ struct pfr_uktable *ukt)
{
struct pfr_table tbl_buf;
struct pfr_table *tbl;
@@ -563,8 +582,9 @@ pfctl_define_table(char *name, int flags, int addrs, const char *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);
+ tbl->pfrt_timeout = timeout;
+ DBGPRINT("%s %s@%s [%x] (%u)\n", __func__, tbl->pfrt_name,
+ tbl->pfrt_anchor, tbl->pfrt_flags, tbl->pfrt_timeout);
/*
* non-root anchors processed by parse.y are loaded to kernel later.
diff --git a/share/man/man5/pf.conf.5 b/share/man/man5/pf.conf.5
index 3a383b23517..59ece54039b 100644
--- a/share/man/man5/pf.conf.5
+++ b/share/man/man5/pf.conf.5
@@ -1822,6 +1822,15 @@ The
flag forces the kernel to keep the table even when no rules refer to it.
If the flag is not set, the kernel will automatically remove the table
when the last rule referring to it is flushed.
+.It timeout
+The
+.Cm timeout
+option sets timeout (in seconds) for which the IP address is kept in table.
+This is meant for tables used by
+.Cm overload
+action either in rule or in limiter.
+After the timeout elapses the IP address is removed from the table where
+timeout is set.
.El
.Pp
This example creates a table called
@@ -3021,7 +3030,8 @@ antispoof-rule = "antispoof" [ "log" ] [ "quick" ]
table-rule = "table" "<" string ">" [ tableopts ]
tableopts = tableopt [ tableopts ]
tableopt = "persist" | "const" | "counters" |
- "file" string | "{" [ tableaddrs ] "}"
+ "timeout" "(" number ")" | "file" string |
+ "{" [ tableaddrs ] "}"
tableaddrs = tableaddr-spec [ [ "," ] tableaddrs ]
tableaddr-spec = [ "!" ] tableaddr [ "/" mask-bits ]
tableaddr = hostname | ifspec | "self" |
diff --git a/sys/net/pf.c b/sys/net/pf.c
index 3ec43778805..702bd278ef3 100644
--- a/sys/net/pf.c
+++ b/sys/net/pf.c
@@ -1967,6 +1967,7 @@ pf_purge(void *null)
pf_purge_expired_src_nodes();
pf_source_purge();
+ pfr_purge_overload();
PF_UNLOCK();
diff --git a/sys/net/pf_table.c b/sys/net/pf_table.c
index 45c5533e55b..51182660df7 100644
--- a/sys/net/pf_table.c
+++ b/sys/net/pf_table.c
@@ -118,7 +118,8 @@ struct pfr_walktree {
PFRW_GET_ADDRS,
PFRW_GET_ASTATS,
PFRW_POOL_GET,
- PFRW_DYNADDR_UPDATE
+ PFRW_DYNADDR_UPDATE,
+ PFRW_ENQUEUE_EXPIRED
} pfrw_op;
union {
struct pfr_addr *pfrw1_addr;
@@ -129,6 +130,7 @@ struct pfr_walktree {
} pfrw_1;
int pfrw_free;
int pfrw_flags;
+ time_t pfrw_now;
};
#define pfrw_addr pfrw_1.pfrw1_addr
#define pfrw_astats pfrw_1.pfrw1_astats
@@ -1137,8 +1139,11 @@ pfr_insert_kentry(struct pfr_ktable *kt, struct pfr_addr *ad, time_t tzero)
int rv;
p = pfr_lookup_addr(kt, ad, 1);
- if (p != NULL)
+ if (p != NULL) {
+ if (kt->pfrkt_flags & PFR_TFLAG_TIMEOUT)
+ p->pfrke_expire = tzero + kt->pfrkt_timeout;
return (0);
+ }
p = pfr_create_kentry(ad);
if (p == NULL)
return (EINVAL);
@@ -1148,6 +1153,8 @@ pfr_insert_kentry(struct pfr_ktable *kt, struct pfr_addr *ad, time_t tzero)
return (rv);
p->pfrke_tzero = tzero;
+ if (kt->pfrkt_flags & PFR_TFLAG_TIMEOUT)
+ p->pfrke_expire = tzero + kt->pfrkt_timeout;
if (p->pfrke_type == PFRKE_COST)
kt->pfrkt_refcntcost++;
kt->pfrkt_cnt++;
@@ -1353,6 +1360,7 @@ pfr_copyout_addr(struct pfr_addr *ad, struct pfr_kentry *ke)
ad->pfra_af = ke->pfrke_af;
ad->pfra_net = ke->pfrke_net;
ad->pfra_type = ke->pfrke_type;
+ ad->pfra_expire = ke->pfrke_expire;
if (ke->pfrke_flags & PFRKE_FLAG_NOT)
ad->pfra_not = 1;
@@ -1408,7 +1416,6 @@ pfr_walktree(struct radix_node *rn, void *arg, u_int id)
case PFRW_GET_ADDRS:
if (w->pfrw_free-- > 0) {
struct pfr_addr ad;
-
pfr_copyout_addr(&ad, ke);
if (copyout(&ad, w->pfrw_addr, sizeof(ad)))
return (EFAULT);
@@ -1473,6 +1480,12 @@ pfr_walktree(struct radix_node *rn, void *arg, u_int id)
unhandled_af(ke->pfrke_af);
}
break;
+ case PFRW_ENQUEUE_EXPIRED:
+ if (ke->pfrke_expire != 0 && ke->pfrke_expire < w->pfrw_now) {
+ SLIST_INSERT_HEAD(w->pfrw_workq, ke, pfrke_workq);
+ w->pfrw_cnt++;
+ }
+ break;
}
return (0);
}
@@ -2421,6 +2434,21 @@ pfr_lookup_table(struct pfr_table *tbl)
(struct pfr_ktable *)tbl));
}
+int
+pfr_kentry_expired(struct pfr_kentry *ke)
+{
+ time_t now;
+ int expired;
+
+ if (ke->pfrke_expire != 0) {
+ now = gettime();
+ expired = (ke->pfrke_expire < now);
+ } else
+ expired = 0;
+
+ return (expired);
+}
+
int
pfr_match_addr(struct pfr_ktable *kt, struct pf_addr *a, sa_family_t af)
{
@@ -2430,10 +2458,15 @@ pfr_match_addr(struct pfr_ktable *kt, struct pf_addr *a, sa_family_t af)
ke = pfr_kentry_byaddr(kt, a, af, 0);
match = (ke && !(ke->pfrke_flags & PFRKE_FLAG_NOT));
- if (match)
+ if (match && pfr_kentry_expired(ke) == 0)
kt->pfrkt_match++;
- else
+ else {
kt->pfrkt_nomatch++;
+ if (ke != NULL) {
+ match = 0;
+ kt->pfrkt_flags |= PFR_TFLAG_NEED_PURGE;
+ }
+ }
return (match);
}
@@ -2913,3 +2946,25 @@ pfr_ktable_select_active(struct pfr_ktable *kt)
return (kt);
}
+
+void
+pfr_purge_overload(void)
+{
+ struct pfr_ktable *kt;
+ struct pfr_kentryworkq workq;
+ struct pfr_walktree w;
+
+ RB_FOREACH(kt, pfr_ktablehead, &pfr_ktables) {
+ if (kt->pfrkt_flags & PFR_TFLAG_NEED_PURGE) {
+ bzero(&w, sizeof(w));
+ w.pfrw_op = PFRW_ENQUEUE_EXPIRED;
+ w.pfrw_now = gettime();
+ w.pfrw_workq = &workq;
+ SLIST_INIT(&workq);
+ rn_walktree(kt->pfrkt_ip4, pfr_walktree, &w);
+ rn_walktree(kt->pfrkt_ip6, pfr_walktree, &w);
+ pfr_remove_kentries(kt, &workq);
+ kt->pfrkt_flags &= ~PFR_TFLAG_NEED_PURGE;
+ }
+ }
+}
diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h
index 750fe0ef144..5cc0bb8c3c9 100644
--- a/sys/net/pfvar.h
+++ b/sys/net/pfvar.h
@@ -872,15 +872,18 @@ RB_PROTOTYPE(pf_anchor_node, pf_anchor, entry_node, pf_anchor_compare)
#define PFR_TFLAG_REFERENCED 0x00000010
#define PFR_TFLAG_REFDANCHOR 0x00000020
#define PFR_TFLAG_COUNTERS 0x00000040
+#define PFR_TFLAG_TIMEOUT 0x00000080
+#define PFR_TFLAG_NEED_PURGE 0x00000100
/* Adjust masks below when adding flags. */
-#define PFR_TFLAG_USRMASK 0x00000043
-#define PFR_TFLAG_SETMASK 0x0000003C
-#define PFR_TFLAG_ALLMASK 0x0000007F
+#define PFR_TFLAG_USRMASK 0x000000C3
+#define PFR_TFLAG_SETMASK 0x0000013C
+#define PFR_TFLAG_ALLMASK 0x000001FF
struct pfr_table {
char pfrt_anchor[PATH_MAX];
char pfrt_name[PF_TABLE_NAME_SIZE];
u_int32_t pfrt_flags;
+ u_int32_t pfrt_timeout;
u_int8_t pfrt_fback;
};
@@ -894,6 +897,7 @@ struct pfr_addr {
struct in6_addr _pfra_ip6addr;
} pfra_u;
char pfra_ifname[IFNAMSIZ];
+ time_t pfra_expire;
u_int32_t pfra_states;
u_int16_t pfra_weight;
u_int8_t pfra_af;
@@ -932,6 +936,7 @@ struct pfr_tstats {
};
#define pfrts_name pfrts_t.pfrt_name
#define pfrts_flags pfrts_t.pfrt_flags
+#define pfrts_timeout pfrts_t.pfrt_timeout
struct pfr_kcounters {
u_int64_t pfrkc_packets[PFR_DIR_MAX][PFR_OP_ADDR_MAX];
@@ -958,6 +963,7 @@ struct _pfr_kentry {
SLIST_ENTRY(pfr_kentry) _pfrke_ioq;
struct pfr_kcounters *_pfrke_counters;
time_t _pfrke_tzero;
+ time_t _pfrke_expire;
u_int8_t _pfrke_af;
u_int8_t _pfrke_net;
u_int8_t _pfrke_flags;
@@ -981,6 +987,7 @@ struct pfr_kentry {
#define pfrke_ioq u._ke._pfrke_ioq
#define pfrke_counters u._ke._pfrke_counters
#define pfrke_tzero u._ke._pfrke_tzero
+#define pfrke_expire u._ke._pfrke_expire
#define pfrke_af u._ke._pfrke_af
#define pfrke_net u._ke._pfrke_net
#define pfrke_flags u._ke._pfrke_flags
@@ -1047,6 +1054,7 @@ struct pfr_ktable {
#define pfrkt_match pfrkt_ts.pfrts_match
#define pfrkt_nomatch pfrkt_ts.pfrts_nomatch
#define pfrkt_tzero pfrkt_ts.pfrts_tzero
+#define pfrkt_timeout pfrkt_ts.pfrts_timeout
RB_HEAD(pfi_ifhead, pfi_kif);
@@ -1895,6 +1903,7 @@ int pfr_ina_define(struct pfr_table *, struct pfr_addr *, int, int *,
int *, u_int32_t, int);
struct pfr_ktable
*pfr_ktable_select_active(struct pfr_ktable *);
+void pfr_purge_overload(void);
extern struct pfi_kif *pfi_all;
pf(4) add timeout option to ip address tables