summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorDavid Gwynne <dlg@cvs.openbsd.org>2009-12-24 04:24:20 +0000
committerDavid Gwynne <dlg@cvs.openbsd.org>2009-12-24 04:24:20 +0000
commit7001b649cdee874ad66c599677ad39df4b2a2083 (patch)
treecd88547d521be94dac2e76ac1ab500651f4e408f /sys
parentd3a7b3d0c46469ce0d5a34038d8cbf4f09c6501a (diff)
add support to pf for filtering a packet by the interface it was received
on. use the received-on IFNAME filter option on a pf.conf rule to restrict which packet the interface had to be received on. eg: pass out on em0 from $foo to $bar received-on fxp0 ive been running this in production for a week now. i find it particularly usefull with interface groups. no objections, and a few "i like"s from henning, claudio, deraadt, mpf
Diffstat (limited to 'sys')
-rw-r--r--sys/net/pf.c29
-rw-r--r--sys/net/pf_ioctl.c24
-rw-r--r--sys/net/pfvar.h4
3 files changed, 54 insertions, 3 deletions
diff --git a/sys/net/pf.c b/sys/net/pf.c
index 6602cb57b69..ff086df53b6 100644
--- a/sys/net/pf.c
+++ b/sys/net/pf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pf.c,v 1.679 2009/12/14 12:31:45 henning Exp $ */
+/* $OpenBSD: pf.c,v 1.680 2009/12/24 04:24:19 dlg Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -233,6 +233,7 @@ struct pf_state *pf_find_state(struct pfi_kif *,
struct pf_state_key_cmp *, u_int, struct mbuf *);
int pf_src_connlimit(struct pf_state **);
int pf_check_congestion(struct ifqueue *);
+int pf_match_rcvif(struct mbuf *, struct pf_rule *);
extern struct pool pfr_ktable_pl;
extern struct pool pfr_kentry_pl;
@@ -2260,6 +2261,30 @@ pf_match_tag(struct mbuf *m, struct pf_rule *r, int *tag)
}
int
+pf_match_rcvif(struct mbuf *m, struct pf_rule *r)
+{
+ struct ifnet *ifp = m->m_pkthdr.rcvif;
+ struct pfi_kif *kif;
+
+ if (ifp == NULL)
+ return (0);
+
+ if (ifp->if_type == IFT_CARP && ifp->if_carpdev)
+ kif = (struct pfi_kif *)ifp->if_carpdev->if_pf_kif;
+ else
+ kif = (struct pfi_kif *)ifp->if_pf_kif;
+
+ if (kif == NULL) {
+ DPFPRINTF(PF_DEBUG_URGENT,
+ ("pf_test_via: kif == NULL, @%d via %s\n", r->nr,
+ r->rcv_ifname));
+ return (0);
+ }
+
+ return (pfi_kif_match(r->rcv_kif, kif));
+}
+
+int
pf_tag_packet(struct mbuf *m, int tag, int rtableid)
{
if (tag <= 0 && rtableid < 0)
@@ -2843,6 +2868,8 @@ pf_test_rule(struct pf_rule **rm, struct pf_state **sm, int direction,
r = TAILQ_NEXT(r, entries);
else if (r->match_tag && !pf_match_tag(m, r, &tag))
r = TAILQ_NEXT(r, entries);
+ else if (r->rcv_kif && !pf_match_rcvif(m, r))
+ r = TAILQ_NEXT(r, entries);
else if (r->os_fingerprint != PF_OSFP_ANY &&
(pd->proto != IPPROTO_TCP || !pf_osfp_match(
pf_osfp_fingerprint(pd, m, off, th),
diff --git a/sys/net/pf_ioctl.c b/sys/net/pf_ioctl.c
index 30a5a0fc091..e0c11d9f95e 100644
--- a/sys/net/pf_ioctl.c
+++ b/sys/net/pf_ioctl.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pf_ioctl.c,v 1.229 2009/12/14 12:31:45 henning Exp $ */
+/* $OpenBSD: pf_ioctl.c,v 1.230 2009/12/24 04:24:19 dlg Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -366,6 +366,7 @@ pf_rm_rule(struct pf_rulequeue *rulequeue, struct pf_rule *rule)
if (rule->overload_tbl)
pfr_detach_table(rule->overload_tbl);
}
+ pfi_kif_unref(rule->rcv_kif, PFI_KIF_REF_RULE);
pfi_kif_unref(rule->kif, PFI_KIF_REF_RULE);
pf_anchor_remove(rule);
pf_empty_pool(&rule->rdr.list);
@@ -773,6 +774,7 @@ pf_hash_rule(MD5_CTX *ctx, struct pf_rule *rule)
pf_hash_rule_addr(ctx, &rule->dst);
PF_MD5_UPD_STR(rule, label);
PF_MD5_UPD_STR(rule, ifname);
+ PF_MD5_UPD_STR(rule, rcv_ifname);
PF_MD5_UPD_STR(rule, match_tagname);
PF_MD5_UPD_HTONS(rule, match_tag, x); /* dup? */
PF_MD5_UPD_HTONL(rule, os_fingerprint, y);
@@ -1076,6 +1078,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
rule->cpid = p->p_pid;
rule->anchor = NULL;
rule->kif = NULL;
+ rule->rcv_kif = NULL;
TAILQ_INIT(&rule->rdr.list);
TAILQ_INIT(&rule->nat.list);
TAILQ_INIT(&rule->route.list);
@@ -1115,6 +1118,13 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
}
pfi_kif_ref(rule->kif, PFI_KIF_REF_RULE);
}
+ if (rule->rcv_ifname[0]) {
+ rule->rcv_kif = pfi_kif_get(rule->rcv_ifname);
+ if (rule->rcv_kif == NULL) {
+ error = EINVAL;
+ } else
+ pfi_kif_ref(rule->rcv_kif, PFI_KIF_REF_RULE);
+ }
if (rule->rtableid > 0 && !rtable_exists(rule->rtableid))
error = EBUSY;
@@ -1347,6 +1357,18 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
} else
newrule->kif = NULL;
+ if (newrule->rcv_ifname[0]) {
+ newrule->rcv_kif =
+ pfi_kif_get(newrule->rcv_ifname);
+ if (newrule->rcv_kif == NULL) {
+ error = EINVAL;
+ } else {
+ pfi_kif_ref(newrule->rcv_kif,
+ PFI_KIF_REF_RULE);
+ }
+ } else
+ newrule->kif = NULL;
+
if (newrule->rtableid > 0 &&
!rtable_exists(newrule->rtableid))
error = EBUSY;
diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h
index 0be8bd29c10..596e44f9277 100644
--- a/sys/net/pfvar.h
+++ b/sys/net/pfvar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: pfvar.h,v 1.302 2009/12/14 12:31:45 henning Exp $ */
+/* $OpenBSD: pfvar.h,v 1.303 2009/12/24 04:24:19 dlg Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -529,6 +529,7 @@ struct pf_rule {
char label[PF_RULE_LABEL_SIZE];
#define PF_QNAME_SIZE 64
char ifname[IFNAMSIZ];
+ char rcv_ifname[IFNAMSIZ];
char qname[PF_QNAME_SIZE];
char pqname[PF_QNAME_SIZE];
#define PF_TAG_NAME_SIZE 64
@@ -547,6 +548,7 @@ struct pf_rule {
u_int64_t bytes[2];
struct pfi_kif *kif;
+ struct pfi_kif *rcv_kif;
struct pf_anchor *anchor;
struct pfr_ktable *overload_tbl;