diff options
author | David Gwynne <dlg@cvs.openbsd.org> | 2009-12-24 04:24:20 +0000 |
---|---|---|
committer | David Gwynne <dlg@cvs.openbsd.org> | 2009-12-24 04:24:20 +0000 |
commit | 7001b649cdee874ad66c599677ad39df4b2a2083 (patch) | |
tree | cd88547d521be94dac2e76ac1ab500651f4e408f /sys/net | |
parent | d3a7b3d0c46469ce0d5a34038d8cbf4f09c6501a (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/net')
-rw-r--r-- | sys/net/pf.c | 29 | ||||
-rw-r--r-- | sys/net/pf_ioctl.c | 24 | ||||
-rw-r--r-- | sys/net/pfvar.h | 4 |
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; |