summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHenning Brauer <henning@cvs.openbsd.org>2003-05-13 17:45:25 +0000
committerHenning Brauer <henning@cvs.openbsd.org>2003-05-13 17:45:25 +0000
commit145b808dbc73406ed1dbde195f498ba3a81fd6e3 (patch)
tree076d837d00a93d5d218e74e5e4c5dfa428519e0f
parente380529842cc691499fd34a570de15345a56484a (diff)
add support for tagging packets with arbitary tags and filtering based on
those tags later on. ok dhartmei@ pb@ mcbride@ frantzen@
-rw-r--r--sys/net/pf.c58
-rw-r--r--sys/net/pf_ioctl.c83
-rw-r--r--sys/net/pfvar.h21
3 files changed, 159 insertions, 3 deletions
diff --git a/sys/net/pf.c b/sys/net/pf.c
index 02687cb2e9d..ad6af22982f 100644
--- a/sys/net/pf.c
+++ b/sys/net/pf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pf.c,v 1.348 2003/05/12 22:53:47 frantzen Exp $ */
+/* $OpenBSD: pf.c,v 1.349 2003/05/13 17:45:23 henning Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -99,6 +99,7 @@ struct pf_palist pf_pabuf;
struct pf_altqqueue *pf_altqs_active;
struct pf_altqqueue *pf_altqs_inactive;
struct pf_status pf_status;
+struct pf_tagnames pf_tagnames;
struct ifnet *status_ifp;
u_int32_t ticket_altqs_active;
@@ -180,6 +181,7 @@ void *pf_pull_hdr(struct mbuf *, int, void *, int,
void pf_calc_skip_steps(struct pf_rulequeue *);
void pf_rule_set_qid(struct pf_rulequeue *);
u_int32_t pf_qname_to_qid(char *);
+int pf_match_tag(struct mbuf *, struct pf_rule *);
#ifdef INET6
void pf_poolmask(struct pf_addr *, struct pf_addr*,
@@ -1343,6 +1345,20 @@ pf_match_gid(u_int8_t op, gid_t a1, gid_t a2, gid_t g)
return (pf_match(op, a1, a2, g));
}
+int
+pf_match_tag(struct mbuf *m, struct pf_rule *r)
+{
+ struct m_tag *mtag;
+ struct pf_tag *pftag;
+
+ if ((mtag = m_tag_find(m, PACKET_TAG_PF_TAG, NULL)) != NULL) {
+ pftag = (struct pf_tag *)(mtag + 1);
+ if (pftag->tag == r->match_tag)
+ return (1);
+ }
+ return (0);
+}
+
#define PF_STEP_INTO_ANCHOR(r, a, s, n) \
do { \
if ((r) == NULL || (r)->anchor == NULL || \
@@ -2012,6 +2028,8 @@ pf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction,
r = TAILQ_NEXT(r, entries);
else if (r->anchorname[0] && r->anchor == NULL)
r = TAILQ_NEXT(r, entries);
+ else if (r->match_tag && !pf_match_tag(m, r))
+ r = TAILQ_NEXT(r, entries);
else {
if (r->anchor == NULL) {
*rm = r;
@@ -2270,6 +2288,8 @@ pf_test_udp(struct pf_rule **rm, struct pf_state **sm, int direction,
!pf_match_gid(r->gid.op, r->gid.gid[0], r->gid.gid[1],
gid))
r = TAILQ_NEXT(r, entries);
+ else if (r->match_tag && !pf_match_tag(m, r))
+ r = TAILQ_NEXT(r, entries);
else if (r->anchorname[0] && r->anchor == NULL)
r = TAILQ_NEXT(r, entries);
else {
@@ -2526,6 +2546,8 @@ pf_test_icmp(struct pf_rule **rm, struct pf_state **sm, int direction,
r = TAILQ_NEXT(r, entries);
else if (r->rule_flag & PFRULE_FRAGMENT)
r = TAILQ_NEXT(r, entries);
+ else if (r->match_tag && !pf_match_tag(m, r))
+ r = TAILQ_NEXT(r, entries);
else if (r->anchorname[0] && r->anchor == NULL)
r = TAILQ_NEXT(r, entries);
else {
@@ -2720,6 +2742,8 @@ pf_test_other(struct pf_rule **rm, struct pf_state **sm, int direction,
r = TAILQ_NEXT(r, entries);
else if (r->rule_flag & PFRULE_FRAGMENT)
r = TAILQ_NEXT(r, entries);
+ else if (r->match_tag && !pf_match_tag(m, r))
+ r = TAILQ_NEXT(r, entries);
else if (r->anchorname[0] && r->anchor == NULL)
r = TAILQ_NEXT(r, entries);
else {
@@ -2891,6 +2915,8 @@ pf_test_fragment(struct pf_rule **rm, int direction, struct ifnet *ifp,
else if (r->src.port_op || r->dst.port_op ||
r->flagset || r->type || r->code)
r = TAILQ_NEXT(r, entries);
+ else if (r->match_tag && !pf_match_tag(m, r))
+ r = TAILQ_NEXT(r, entries);
else if (r->anchorname[0] && r->anchor == NULL)
r = TAILQ_NEXT(r, entries);
else {
@@ -4392,6 +4418,7 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0)
{
u_short action, reason = 0, log = 0;
struct mbuf *m = *m0;
+ struct m_tag *mtag;
struct ip *h;
struct pf_rule *a = NULL, *r = &pf_default_rule;
struct pf_state *s = NULL;
@@ -4571,6 +4598,20 @@ done:
("pf: dropping packet with ip options\n"));
}
+ if (action != PF_DROP && r->tag) {
+ struct pf_tag *pftag;
+
+ mtag = m_tag_get(PACKET_TAG_PF_TAG, sizeof(*pftag), M_NOWAIT);
+ if (mtag == NULL) {
+ action = PF_DROP;
+ REASON_SET(&reason, PFRES_MEMORY);
+ } else {
+ pftag = (struct pf_tag *)(mtag + 1);
+ pftag->tag = r->tag;
+ m_tag_prepend(m, mtag);
+ }
+ }
+
#ifdef ALTQ
if (action != PF_DROP && r->qid) {
struct m_tag *mtag;
@@ -4608,6 +4649,7 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0)
{
u_short action, reason = 0, log = 0;
struct mbuf *m = *m0;
+ struct m_tag *mtag;
struct ip6_hdr *h;
struct pf_rule *a = NULL, *r = &pf_default_rule;
struct pf_state *s = NULL;
@@ -4785,6 +4827,20 @@ done:
/* XXX handle IPv6 options, if not allowed. not implemented. */
+ if (action != PF_DROP && r->tag) {
+ struct pf_tag *pftag;
+
+ mtag = m_tag_get(PACKET_TAG_PF_TAG, sizeof(*pftag), M_NOWAIT);
+ if (mtag == NULL) {
+ action = PF_DROP;
+ REASON_SET(&reason, PFRES_MEMORY);
+ } else {
+ pftag = (struct pf_tag *)(mtag + 1);
+ pftag->tag = r->tag;
+ m_tag_prepend(m, mtag);
+ }
+ }
+
#ifdef ALTQ
if (action != PF_DROP && r->qid) {
struct m_tag *mtag;
diff --git a/sys/net/pf_ioctl.c b/sys/net/pf_ioctl.c
index 701a0125883..6ddee7d769d 100644
--- a/sys/net/pf_ioctl.c
+++ b/sys/net/pf_ioctl.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pf_ioctl.c,v 1.63 2003/05/12 17:43:29 mcbride Exp $ */
+/* $OpenBSD: pf_ioctl.c,v 1.64 2003/05/13 17:45:24 henning Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -83,11 +83,18 @@ void pf_remove_if_empty_ruleset(struct pf_ruleset *);
void pf_mv_pool(struct pf_palist *, struct pf_palist *);
void pf_empty_pool(struct pf_palist *);
int pfioctl(dev_t, u_long, caddr_t, int, struct proc *);
+u_int16_t pf_tagname2tag(char *);
+void pf_tag_unref(u_int16_t);
+void pf_tag_purge(void);
extern struct timeout pf_expire_to;
struct pf_rule pf_default_rule;
+#define TAGID_MAX 50000
+static u_int16_t tagid = 0;
+TAILQ_HEAD(pf_tags, pf_tagname) pf_tags = TAILQ_HEAD_INITIALIZER(pf_tags);
+
#define DPFPRINTF(n, x) if (pf_status.debug >= (n)) printf x
void
@@ -397,6 +404,8 @@ pf_rm_rule(struct pf_rulequeue *rulequeue, struct pf_rule *rule)
rule->entries.tqe_prev = NULL;
rule->nr = -1;
}
+ pf_tag_unref(rule->tag);
+ pf_tag_unref(rule->match_tag);
if (rule->states > 0 || rule->entries.tqe_prev != NULL)
return;
pf_dynaddr_remove(&rule->src.addr);
@@ -407,6 +416,70 @@ pf_rm_rule(struct pf_rulequeue *rulequeue, struct pf_rule *rule)
pool_put(&pf_rule_pl, rule);
}
+u_int16_t
+pf_tagname2tag(char *tagname)
+{
+ struct pf_tagname *tag, *p;
+ int wrapped = 0;
+
+ TAILQ_FOREACH(tag, &pf_tags, entries)
+ if (strcmp(tagname, tag->name) == 0) {
+ tag->ref++;
+ return (tag->tag);
+ }
+ /* new entry */
+ if (++tagid > TAGID_MAX) /* > 50000 reserved for special use */
+ tagid = wrapped = 1;
+ for (p = TAILQ_FIRST(&pf_tags); p != NULL; p = TAILQ_NEXT(p, entries))
+ if (p->tag == tagid) {
+ if (++tagid > TAGID_MAX) {
+ if (wrapped)
+ return (0);
+ else
+ tagid = wrapped = 1;
+ }
+ p = TAILQ_FIRST(&pf_tags);
+ }
+
+ tag = (struct pf_tagname *)malloc(sizeof(struct pf_tagname),
+ M_TEMP, M_NOWAIT);
+ if (tag == NULL)
+ return (0);
+ bzero(tag, sizeof(struct pf_tagname));
+ strlcpy(tag->name, tagname, sizeof(tag->name));
+ tag->tag = tagid;
+ tag->ref++;
+ TAILQ_INSERT_TAIL(&pf_tags, tag, entries);
+ return (tag->tag);
+}
+
+void
+pf_tag_unref(u_int16_t tag)
+{
+ struct pf_tagname *p;
+
+ if (tag > 0)
+ TAILQ_FOREACH(p, &pf_tags, entries)
+ if (tag == p->tag) {
+ p->ref--;
+ return;
+ }
+}
+
+void
+pf_tag_purge(void)
+{
+ struct pf_tagname *p;
+
+ TAILQ_FOREACH_REVERSE(p, &pf_tags, entries, pf_tagnames)
+ if (p->ref == 0) {
+ if (p->tag == tagid)
+ tagid--;
+ TAILQ_REMOVE(&pf_tags, p, entries);
+ free(p, M_TEMP);
+ }
+}
+
int
pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
{
@@ -606,6 +679,13 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
}
}
+ if (rule->tagname[0])
+ if ((rule->tag = pf_tagname2tag(rule->tagname)) == 0)
+ error = EBUSY;
+ if (rule->match_tagname[0])
+ if ((rule->match_tag =
+ pf_tagname2tag(rule->match_tagname)) == 0)
+ error = EBUSY;
if (rule->rt && !rule->direction)
error = EINVAL;
if (pf_dynaddr_setup(&rule->src.addr, rule->af))
@@ -678,6 +758,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
pf_rm_rule(old_rules, rule);
pf_remove_if_empty_ruleset(ruleset);
pf_update_anchor_rules();
+ pf_tag_purge();
splx(s);
break;
}
diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h
index 182c6659f7b..b18c4f23422 100644
--- a/sys/net/pfvar.h
+++ b/sys/net/pfvar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: pfvar.h,v 1.146 2003/05/12 22:11:18 dhartmei Exp $ */
+/* $OpenBSD: pfvar.h,v 1.147 2003/05/13 17:45:24 henning Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -345,6 +345,10 @@ struct pf_rule {
char pqname[PF_QNAME_SIZE];
#define PF_ANCHOR_NAME_SIZE 16
char anchorname[PF_ANCHOR_NAME_SIZE];
+#define PF_TAG_NAME_SIZE 16
+ char tagname[PF_TAG_NAME_SIZE];
+ char match_tagname[PF_TAG_NAME_SIZE];
+
TAILQ_ENTRY(pf_rule) entries;
struct pf_pool rpool;
@@ -365,6 +369,8 @@ struct pf_rule {
u_int16_t return_icmp;
u_int16_t return_icmp6;
u_int16_t max_mss;
+ u_int16_t tag;
+ u_int16_t match_tag;
struct pf_rule_uid uid;
struct pf_rule_gid gid;
@@ -755,6 +761,19 @@ struct pf_altq {
u_int32_t qid; /* return value */
};
+struct pf_tag {
+ u_int16_t tag; /* tag id */
+};
+
+struct pf_tagname {
+ TAILQ_ENTRY(pf_tagname) entries;
+ char name[PF_TAG_NAME_SIZE];
+ u_int16_t tag;
+ int ref;
+};
+
+TAILQ_HEAD(pf_tagnames, pf_tagname);
+
#define PFFRAG_FRENT_HIWAT 5000 /* Number of fragment entries */
#define PFFRAG_FRAG_HIWAT 1000 /* Number of fragmented packets */
#define PFFRAG_FRCENT_HIWAT 50000 /* Number of fragment cache entries */