diff options
author | Henning Brauer <henning@cvs.openbsd.org> | 2003-05-13 17:45:25 +0000 |
---|---|---|
committer | Henning Brauer <henning@cvs.openbsd.org> | 2003-05-13 17:45:25 +0000 |
commit | 145b808dbc73406ed1dbde195f498ba3a81fd6e3 (patch) | |
tree | 076d837d00a93d5d218e74e5e4c5dfa428519e0f | |
parent | e380529842cc691499fd34a570de15345a56484a (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.c | 58 | ||||
-rw-r--r-- | sys/net/pf_ioctl.c | 83 | ||||
-rw-r--r-- | sys/net/pfvar.h | 21 |
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 */ |