summaryrefslogtreecommitdiff
path: root/sbin/pfctl
diff options
context:
space:
mode:
authorKristof Provost <kp@FreeBSD.org>2018-04-28 13:16:58 +0000
committerKristof Provost <kp@FreeBSD.org>2018-04-28 13:16:58 +0000
commitc5e105655b92fa48726fc8f1bb1a00d39983e4f4 (patch)
tree92013c098a1145c96653326fe1a6c74ee32b9fb3 /sbin/pfctl
parente2a08f166a388aa3683e3d344be027eff6e3f8d4 (diff)
downloadsrc-test-c5e105655b92fa48726fc8f1bb1a00d39983e4f4.tar.gz
src-test-c5e105655b92fa48726fc8f1bb1a00d39983e4f4.zip
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
Notes
Notes: svn path=/head/; revision=333084
Diffstat (limited to 'sbin/pfctl')
-rw-r--r--sbin/pfctl/pfctl.c47
1 files changed, 46 insertions, 1 deletions
diff --git a/sbin/pfctl/pfctl.c b/sbin/pfctl/pfctl.c
index 5b4c67de66299..98564ab1ca33f 100644
--- a/sbin/pfctl/pfctl.c
+++ b/sbin/pfctl/pfctl.c
@@ -67,6 +67,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 *);
@@ -106,6 +109,7 @@ const char *pfctl_lookup_option(char *, const char * const *);
static struct pf_anchor_global pf_anchors;
static struct pf_anchor pf_main_anchor;
+static struct pfr_buffer skip_b;
static const char *clearopt;
static char *rulesopt;
@@ -295,6 +299,44 @@ pfctl_clear_stats(int dev, int opts)
}
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)
{
struct pfioc_iface pi;
@@ -1479,6 +1521,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))) ||
@@ -1889,6 +1933,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);
@@ -2347,7 +2392,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)) &&