From 41548092d06dedb1938ea974298a48322f14caa2 Mon Sep 17 00:00:00 2001 From: kp Date: Wed, 2 May 2018 22:36:10 +0000 Subject: [PATCH] MFC r333084: pfctl: Don't break connections on skipped interfaces on reload On reload we used to first flush everything, including the list of skipped interfaces. This can lead to termination of these connections if they send packets before the new configuration is applied. Note that this doesn't currently happen on 12 or 11, because of special EACCES handling introduced in r315514. This special behaviour in tcp_output() may change, hence the fix in pfctl. PR: 214613 Submitted by: Andreas Longwitz git-svn-id: svn://svn.freebsd.org/base/stable/10@333187 ccf9f872-aa2e-dd11-9fc8-001c23d0bc1f --- sbin/pfctl/pfctl.c | 47 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/sbin/pfctl/pfctl.c b/sbin/pfctl/pfctl.c index ea95320dd..a9d49d708 100644 --- a/sbin/pfctl/pfctl.c +++ b/sbin/pfctl/pfctl.c @@ -68,6 +68,9 @@ void usage(void); int pfctl_enable(int, int); int pfctl_disable(int, int); int pfctl_clear_stats(int, int); +int pfctl_get_skip_ifaces(void); +int pfctl_check_skip_ifaces(char *); +int pfctl_clear_skip_ifaces(struct pfctl *); int pfctl_clear_interface_flags(int, int); int pfctl_clear_rules(int, int, char *); int pfctl_clear_nat(int, int, char *); @@ -107,6 +110,7 @@ const char *pfctl_lookup_option(char *, const char **); struct pf_anchor_global pf_anchors; struct pf_anchor pf_main_anchor; +static struct pfr_buffer skip_b; const char *clearopt; char *rulesopt; @@ -297,6 +301,44 @@ pfctl_clear_stats(int dev, int opts) return (0); } +int +pfctl_get_skip_ifaces(void) +{ + bzero(&skip_b, sizeof(skip_b)); + skip_b.pfrb_type = PFRB_IFACES; + for (;;) { + pfr_buf_grow(&skip_b, skip_b.pfrb_size); + skip_b.pfrb_size = skip_b.pfrb_msize; + if (pfi_get_ifaces(NULL, skip_b.pfrb_caddr, &skip_b.pfrb_size)) + err(1, "pfi_get_ifaces"); + if (skip_b.pfrb_size <= skip_b.pfrb_msize) + break; + } + return (0); +} + +int +pfctl_check_skip_ifaces(char *ifname) +{ + struct pfi_kif *p; + + PFRB_FOREACH(p, &skip_b) + if ((p->pfik_flags & PFI_IFLAG_SKIP) && !strcmp(ifname, p->pfik_name)) + p->pfik_flags &= ~PFI_IFLAG_SKIP; + return (0); +} + +int +pfctl_clear_skip_ifaces(struct pfctl *pf) +{ + struct pfi_kif *p; + + PFRB_FOREACH(p, &skip_b) + if (p->pfik_flags & PFI_IFLAG_SKIP) + pfctl_set_interface_flags(pf, p->pfik_name, PFI_IFLAG_SKIP, 0); + return (0); +} + int pfctl_clear_interface_flags(int dev, int opts) { @@ -1482,6 +1524,8 @@ pfctl_rules(int dev, char *filename, int opts, int optimize, else goto _error; } + if (loadopt & PFCTL_FLAG_OPTION) + pfctl_clear_skip_ifaces(&pf); if ((pf.loadopt & PFCTL_FLAG_FILTER && (pfctl_load_ruleset(&pf, path, rs, PF_RULESET_SCRUB, 0))) || @@ -1890,6 +1934,7 @@ pfctl_set_interface_flags(struct pfctl *pf, char *ifname, int flags, int how) } else { if (ioctl(pf->dev, DIOCSETIFFLAG, &pi)) err(1, "DIOCSETIFFLAG"); + pfctl_check_skip_ifaces(ifname); } } return (0); @@ -2348,7 +2393,7 @@ main(int argc, char *argv[]) if ((rulesopt != NULL) && (loadopt & PFCTL_FLAG_OPTION) && !anchorname[0]) - if (pfctl_clear_interface_flags(dev, opts | PF_OPT_QUIET)) + if (pfctl_get_skip_ifaces()) error = 1; if (rulesopt != NULL && !(opts & (PF_OPT_MERGE|PF_OPT_NOACTION)) && -- 2.45.0