summaryrefslogtreecommitdiff
path: root/sys/net/pf.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/net/pf.c')
-rw-r--r--sys/net/pf.c507
1 files changed, 8 insertions, 499 deletions
diff --git a/sys/net/pf.c b/sys/net/pf.c
index 62bafb7d481..a56f33f5c36 100644
--- a/sys/net/pf.c
+++ b/sys/net/pf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pf.c,v 1.113 2001/07/15 23:05:04 dhartmei Exp $ */
+/* $OpenBSD: pf.c,v 1.114 2001/07/17 20:34:51 provos Exp $ */
/*
* Copyright (c) 2001, Daniel Hartmeier
@@ -45,7 +45,6 @@
#include <net/if_types.h>
#include <net/bpf.h>
#include <net/route.h>
-#include <net/pfvar.h>
#include <net/if_pflog.h>
#include <netinet/in.h>
@@ -58,6 +57,8 @@
#include <netinet/udp.h>
#include <netinet/ip_icmp.h>
+#include <net/pfvar.h>
+
#include "bpfilter.h"
#include "pflog.h"
@@ -69,11 +70,7 @@ int pf_debug = 0;
*/
struct pf_tree_node {
- struct pf_tree_key {
- struct in_addr addr[2];
- u_int16_t port[2];
- u_int8_t proto;
- } key;
+ struct pf_tree_key key;
struct pf_state *state;
struct pf_tree_node *parent;
struct pf_tree_node *left;
@@ -81,34 +78,13 @@ struct pf_tree_node {
int balance;
};
-struct pf_frent {
- LIST_ENTRY(pf_frent) fr_next;
- struct ip *fr_ip;
- struct mbuf *fr_m;
-};
-
-#define PFFRAG_SEENLAST 0x0001 /* Seen the last fragment for this */
-
-struct pf_fragment {
- TAILQ_ENTRY(pf_fragment) frag_next;
- struct in_addr fr_src;
- struct in_addr fr_dst;
- u_int8_t fr_p; /* protocol of this fragment */
- u_int8_t fr_flags; /* status flags */
- u_int16_t fr_id; /* fragment id for reassemble */
- u_int16_t fr_max; /* fragment data max */
- struct timeval fr_timeout;
- LIST_HEAD(pf_fragq, pf_frent) fr_queue;
-};
-
/*
* Global variables
*/
-TAILQ_HEAD(pf_fragqueue, pf_fragment) pf_fragqueue;
-TAILQ_HEAD(pf_rulequeue, pf_rule) pf_rules[2];
TAILQ_HEAD(pf_natqueue, pf_nat) pf_nats[2];
TAILQ_HEAD(pf_rdrqueue, pf_rdr) pf_rdrs[2];
+struct pf_rulequeue pf_rules[2];
struct pf_rulequeue *pf_rules_active;
struct pf_rulequeue *pf_rules_inactive;
struct pf_natqueue *pf_nats_active;
@@ -116,7 +92,6 @@ struct pf_natqueue *pf_nats_inactive;
struct pf_rdrqueue *pf_rdrs_active;
struct pf_rdrqueue *pf_rdrs_inactive;
struct pf_tree_node *tree_lan_ext, *tree_ext_gwy;
-struct pf_tree_node *tree_fragment;
struct timeval pftv;
struct pf_status pf_status;
struct ifnet *status_ifp;
@@ -132,24 +107,16 @@ u_int16_t pf_next_port_tcp = 50001;
u_int16_t pf_next_port_udp = 50001;
struct pool pf_tree_pl, pf_rule_pl, pf_nat_pl;
-struct pool pf_rdr_pl, pf_state_pl, pf_frent_pl, pf_frag_pl;
-int pf_nfrents;
+struct pool pf_rdr_pl, pf_state_pl;
int pf_tree_key_compare(struct pf_tree_key *,
struct pf_tree_key *);
void pf_tree_rotate_left(struct pf_tree_node **);
void pf_tree_rotate_right(struct pf_tree_node **);
-int pf_tree_insert(struct pf_tree_node **,
- struct pf_tree_node *, struct pf_tree_key *,
- struct pf_state *);
-int pf_tree_remove(struct pf_tree_node **,
- struct pf_tree_node *, struct pf_tree_key *);
struct pf_tree_node *pf_tree_first(struct pf_tree_node *);
struct pf_tree_node *pf_tree_next(struct pf_tree_node *);
struct pf_tree_node *pf_tree_search(struct pf_tree_node *,
struct pf_tree_key *);
-struct pf_state *pf_find_state(struct pf_tree_node *,
- struct pf_tree_key *);
void pf_insert_state(struct pf_state *);
void pf_purge_expired_states(void);
@@ -171,8 +138,6 @@ void pf_change_icmp(u_int32_t *, u_int16_t *, u_int32_t *,
u_int16_t *, u_int16_t *);
void pf_send_reset(struct ip *, int, struct tcphdr *);
void pf_send_icmp(struct mbuf *, u_int8_t, u_int8_t);
-int pf_match_addr(u_int8_t, u_int32_t, u_int32_t,
- u_int32_t);
int pf_match_port(u_int8_t, u_int16_t, u_int16_t,
u_int16_t);
u_int16_t pf_map_port_range(struct pf_rdr *, u_int16_t);
@@ -199,20 +164,6 @@ int pf_test_state_icmp(struct pf_state **, int,
struct ip *, struct icmp *);
void *pf_pull_hdr(struct mbuf *, int, void *, int,
u_short *, u_short *);
-int pflog_packet(struct mbuf *, int, u_short, u_short,
- struct pf_rule *);
-
-int pf_normalize_ip(struct mbuf **, int, struct ifnet *,
- u_short *);
-
-void pf_purge_expired_fragments(void);
-void pf_ip2key(struct pf_tree_key *, struct ip *);
-void pf_remove_fragment(struct pf_fragment *);
-void pf_flush_fragments(void);
-void pf_free_fragment(struct pf_fragment *);
-struct pf_fragment *pf_find_fragment(struct ip *);
-struct mbuf *pf_reassemble(struct mbuf **, struct pf_fragment *,
- struct pf_frent *, int);
#if NPFLOG > 0
#define PFLOG_PACKET(x,a,b,c,d,e) \
@@ -227,20 +178,6 @@ struct mbuf *pf_reassemble(struct mbuf **, struct pf_fragment *,
#define PFLOG_PACKET
#endif
-#define MATCH_TUPLE(h,r,d,i) \
- ( \
- (r->direction == d) && \
- (r->ifp == NULL || r->ifp == i) && \
- (!r->proto || r->proto == h->ip_p) && \
- (!r->src.mask || pf_match_addr(r->src.not, r->src.addr, \
- r->src.mask, h->ip_src.s_addr)) && \
- (!r->dst.mask || pf_match_addr(r->dst.not, r->dst.addr, \
- r->dst.mask, h->ip_dst.s_addr)) \
- )
-
-#define PFFRAG_FRENT_HIWAT 5000 /* Number of fragment entries */
-#define PFFRAG_FRAG_HIWAT 1000 /* Number of fragmented packets */
-
int
pf_tree_key_compare(struct pf_tree_key *a, struct pf_tree_key *b)
{
@@ -669,15 +606,7 @@ pfattach(int num)
0, NULL, NULL, 0);
pool_init(&pf_state_pl, sizeof(struct pf_state), 0, 0, 0, "pfstatepl",
0, NULL, NULL, 0);
- pool_init(&pf_frent_pl, sizeof(struct pf_frent), 0, 0, 0, "pffrent",
- 0, NULL, NULL, 0);
- pool_init(&pf_frag_pl, sizeof(struct pf_fragment), 0, 0, 0, "pffrag",
- 0, NULL, NULL, 0);
-
- pool_sethiwat(&pf_frag_pl, PFFRAG_FRAG_HIWAT);
- pool_sethardlimit(&pf_frent_pl, PFFRAG_FRENT_HIWAT, NULL, 0);
- TAILQ_INIT(&pf_fragqueue);
TAILQ_INIT(&pf_rules[0]);
TAILQ_INIT(&pf_rules[1]);
TAILQ_INIT(&pf_nats[0]);
@@ -690,6 +619,8 @@ pfattach(int num)
pf_nats_inactive = &pf_nats[1];
pf_rdrs_active = &pf_rdrs[0];
pf_rdrs_inactive = &pf_rdrs[1];
+
+ pf_normalize_init();
}
int
@@ -1440,20 +1371,6 @@ pf_get_rdr(struct ifnet *ifp, u_int8_t proto, u_int32_t saddr, u_int32_t daddr,
return (rm);
}
-#define ACTION_SET(a, x) \
- do { \
- if ((a) != NULL) \
- *(a) = (x); \
- } while (0)
-
-#define REASON_SET(a, x) \
- do { \
- if ((a) != NULL) \
- *(a) = (x); \
- if (x < PFRES_MAX) \
- pf_status.counters[x]++; \
- } while (0)
-
u_int16_t
pf_map_port_range(struct pf_rdr *rdr, u_int16_t port)
{
@@ -2314,414 +2231,6 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct ifnet *ifp,
}
}
-#define FRAG_EXPIRE 30
-
-void
-pf_purge_expired_fragments(void)
-{
- struct pf_fragment *frag;
- struct timeval now, expire;
-
- microtime(&now);
-
- timerclear(&expire);
- expire.tv_sec = FRAG_EXPIRE;
- timersub(&now, &expire, &expire);
-
- while ((frag = TAILQ_LAST(&pf_fragqueue, pf_fragqueue)) != NULL) {
- if (timercmp(&frag->fr_timeout, &expire, >))
- break;
-
- DPFPRINTF((__FUNCTION__": expiring %p\n", frag));
- pf_free_fragment(frag);
- }
-}
-
-/*
- * Try to flush old fragments to make space for new ones
- */
-
-void
-pf_flush_fragments(void)
-{
- struct pf_fragment *frag;
- int goal = pf_nfrents * 9 / 10;
-
- DPFPRINTF((__FUNCTION__": trying to free > %d frents\n",
- pf_nfrents - goal));
-
- while (goal < pf_nfrents) {
- frag = TAILQ_LAST(&pf_fragqueue, pf_fragqueue);
- if (frag == NULL)
- break;
- pf_free_fragment(frag);
- }
-}
-
-/* Frees the fragments and all associated entries */
-
-void
-pf_free_fragment(struct pf_fragment *frag)
-{
- struct pf_frent *frent;
-
- /* Free all fragments */
- for (frent = LIST_FIRST(&frag->fr_queue); frent;
- frent = LIST_FIRST(&frag->fr_queue)) {
- LIST_REMOVE(frent, fr_next);
-
- m_freem(frent->fr_m);
- pool_put(&pf_frent_pl, frent);
- pf_nfrents--;
- }
-
- pf_remove_fragment(frag);
-}
-
-void
-pf_ip2key(struct pf_tree_key *key, struct ip *ip)
-{
- key->proto = ip->ip_p;
- key->addr[0] = ip->ip_src;
- key->addr[1] = ip->ip_dst;
- key->port[0] = ip->ip_id;
- key->port[1] = 0;
-}
-
-struct pf_fragment *
-pf_find_fragment(struct ip *ip)
-{
- struct pf_tree_key key;
- struct pf_fragment *frag;
-
- pf_ip2key(&key, ip);
-
- frag = (struct pf_fragment *)pf_find_state(tree_fragment, &key);
-
- if (frag != NULL) {
- microtime(&frag->fr_timeout);
- TAILQ_REMOVE(&pf_fragqueue, frag, frag_next);
- TAILQ_INSERT_HEAD(&pf_fragqueue, frag, frag_next);
- }
-
- return (frag);
-}
-
-/* Removes a fragment from the fragment queue and frees the fragment */
-
-void
-pf_remove_fragment(struct pf_fragment *frag)
-{
- struct pf_tree_key key;
-
- key.proto = frag->fr_p;
- key.addr[0] = frag->fr_src;
- key.addr[1] = frag->fr_dst;
- key.port[0] = frag->fr_id;
- key.port[1] = 0;
-
- pf_tree_remove(&tree_fragment, NULL, &key);
- TAILQ_REMOVE(&pf_fragqueue, frag, frag_next);
-
- pool_put(&pf_frag_pl, frag);
-}
-
-struct mbuf *
-pf_reassemble(struct mbuf **m0, struct pf_fragment *frag,
- struct pf_frent *frent, int mff)
-{
- struct mbuf *m = *m0, *m2;
- struct pf_frent *frep, *frea, *next;
- struct ip *ip = frent->fr_ip;
- int hlen = ip->ip_hl << 2;
- u_int16_t off = ip->ip_off;
- u_int16_t max = ip->ip_len + off;
-
- /* Strip off ip header */
- m->m_data += hlen;
- m->m_len -= hlen;
-
- /* Create a new reassembly queue for this packet */
- if (frag == NULL) {
- struct pf_tree_key key;
-
- frag = pool_get(&pf_frag_pl, M_NOWAIT);
- if (frag == NULL) {
- pf_flush_fragments();
- frag = pool_get(&pf_frag_pl, M_NOWAIT);
- if (frag == NULL)
- goto drop_fragment;
- }
-
- frag->fr_flags = 0;
- frag->fr_max = 0;
- frag->fr_src = frent->fr_ip->ip_src;
- frag->fr_dst = frent->fr_ip->ip_dst;
- frag->fr_p = frent->fr_ip->ip_p;
- frag->fr_id = frent->fr_ip->ip_id;
- LIST_INIT(&frag->fr_queue);
-
- pf_ip2key(&key, frent->fr_ip);
-
- pf_tree_insert(&tree_fragment, NULL, &key,
- (struct pf_state *)frag);
- TAILQ_INSERT_HEAD(&pf_fragqueue, frag, frag_next);
-
- /* We do not have a previous fragment */
- frep = NULL;
- goto insert;
- }
-
- /*
- * Find a fragment after the current one:
- * - off contains the real shifted offset.
- */
- LIST_FOREACH(frea, &frag->fr_queue, fr_next) {
- if (frea->fr_ip->ip_off > off)
- break;
- frep = frea;
- }
-
- KASSERT(frep != NULL || frea != NULL);
-
- if (frep != NULL) {
- u_int16_t precut;
-
- precut = frep->fr_ip->ip_off + frep->fr_ip->ip_len - off;
- if (precut > ip->ip_len)
- goto drop_fragment;
- if (precut) {
- m_adj(frent->fr_m, precut);
-
- DPFPRINTF((__FUNCTION__": overlap -%d\n", precut));
- /* Enforce 8 byte boundaries */
- off = ip->ip_off += precut;
- ip->ip_len -= precut;
- }
- }
-
- for (; frea != NULL && ip->ip_len + off > frea->fr_ip->ip_off;
- frea = next) {
- u_int16_t aftercut;
-
- aftercut = (ip->ip_len + off) - frea->fr_ip->ip_off;
- DPFPRINTF((__FUNCTION__": adjust overlap %d\n", aftercut));
- if (aftercut < frea->fr_ip->ip_len) {
- frea->fr_ip->ip_len -= aftercut;
- frea->fr_ip->ip_off += aftercut;
- m_adj(frea->fr_m, aftercut);
- break;
- }
-
- /* This fragment is completely overlapped, loose it */
- next = LIST_NEXT(frea, fr_next);
- m_freem(frea->fr_m);
- LIST_REMOVE(frea, fr_next);
- pool_put(&pf_frent_pl, frea);
- pf_nfrents--;
- }
-
- insert:
- /* Update maxmimum data size */
- if (frag->fr_max < max)
- frag->fr_max = max;
- /* This is the last segment */
- if (!mff)
- frag->fr_flags |= PFFRAG_SEENLAST;
-
- if (frep == NULL)
- LIST_INSERT_HEAD(&frag->fr_queue, frent, fr_next);
- else
- LIST_INSERT_AFTER(frep, frent, fr_next);
-
- /* Check if we are completely reassembled */
- if (!(frag->fr_flags & PFFRAG_SEENLAST))
- return (NULL);
-
- /* Check if we have all the data */
- off = 0;
- for (frep = LIST_FIRST(&frag->fr_queue); frep; frep = next) {
- next = LIST_NEXT(frep, fr_next);
-
- off += frep->fr_ip->ip_len;
- if (off < frag->fr_max &&
- (next == NULL || next->fr_ip->ip_off != off)) {
- DPFPRINTF((__FUNCTION__": missing fragment at %d, next %d, max %d\n",
- off, next == NULL ? -1 : next->fr_ip->ip_off, frag->fr_max));
- return (NULL);
- }
- }
- DPFPRINTF((__FUNCTION__": %d < %d?\n", off, frag->fr_max));
- if (off < frag->fr_max)
- return (NULL);
-
- /* We have all the data */
- frent = LIST_FIRST(&frag->fr_queue);
- KASSERT(frent != NULL);
- if ((frent->fr_ip->ip_hl << 2) + off > IP_MAXPACKET) {
- DPFPRINTF((__FUNCTION__": drop: too big: %d\n", off));
- pf_free_fragment(frag);
- return (NULL);
- }
- next = LIST_NEXT(frent, fr_next);
-
- /* Magic from ip_input */
- ip = frent->fr_ip;
- m = frent->fr_m;
- m2 = m->m_next;
- m->m_next = NULL;
- m_cat(m, m2);
- pool_put(&pf_frent_pl, frent);
- pf_nfrents--;
- for (frent = next; frent != NULL; frent = next) {
- next = LIST_NEXT(frent, fr_next);
-
- m2 = frent->fr_m;
- pool_put(&pf_frent_pl, frent);
- pf_nfrents--;
- m_cat(m, m2);
- }
-
- ip->ip_src = frag->fr_src;
- ip->ip_dst = frag->fr_dst;
-
- /* Remove from fragment queue */
- pf_remove_fragment(frag);
-
- hlen = ip->ip_hl << 2;
- ip->ip_len = off + hlen;
- m->m_len += hlen;
- m->m_data -= hlen;
-
- /* some debugging cruft by sklower, below, will go away soon */
- /* XXX this should be done elsewhere */
- if (m->m_flags & M_PKTHDR) {
- int plen = 0;
- for (m2 = m; m2; m2 = m2->m_next)
- plen += m2->m_len;
- m->m_pkthdr.len = plen;
- }
-
- DPFPRINTF((__FUNCTION__": complete: %p(%d)\n", m, ip->ip_len));
- return (m);
-
- drop_fragment:
- /* Oops - fail safe - drop packet */
- m_freem(m);
- return (NULL);
-}
-
-int
-pf_normalize_ip(struct mbuf **m0, int dir, struct ifnet *ifp, u_short *reason)
-{
- struct mbuf *m = *m0;
- struct pf_rule *r;
- struct pf_frent *frent;
- struct pf_fragment *frag;
- struct ip *h = mtod(m, struct ip *);
- int mff = (h->ip_off & IP_MF), hlen = h->ip_hl << 2;
- u_int16_t fragoff = (h->ip_off & IP_OFFMASK) << 3;
- u_int16_t max;
-
- TAILQ_FOREACH(r, pf_rules_active, entries) {
- if ((r->action == PF_SCRUB) &&
- MATCH_TUPLE(h, r, dir, ifp))
- break;
- }
-
- if (r == NULL)
- return (PF_PASS);
-
- /* Check for illegal packets */
- if (hlen < sizeof(struct ip))
- goto drop;
-
- if (hlen > h->ip_len)
- goto drop;
-
- /* We will need other tests here */
- if (!fragoff && !mff)
- goto no_fragment;
-
- /* Now we are dealing with a fragmented packet */
- frag = pf_find_fragment(h);
-
- /* This can not happen */
- if (h->ip_off & IP_DF) {
- DPFPRINTF((__FUNCTION__": IP_DF\n"));
- goto bad;
- }
-
- h->ip_len -= hlen;
- h->ip_off <<= 3;
-
- /* All fragments are 8 byte aligned */
- if (mff && (h->ip_len & 0x7)) {
- DPFPRINTF((__FUNCTION__": mff and %d\n", h->ip_len));
- goto bad;
- }
-
- max = fragoff + h->ip_len;
- /* Respect maximum length */
- if (max > IP_MAXPACKET) {
- DPFPRINTF((__FUNCTION__": max packet %d\n", max));
- goto bad;
- }
- /* Check if we saw the last fragment already */
- if (frag != NULL && (frag->fr_flags & PFFRAG_SEENLAST) &&
- max > frag->fr_max)
- goto bad;
-
- /* Get an entry for the fragment queue */
- frent = pool_get(&pf_frent_pl, PR_NOWAIT);
- if (frent == NULL) {
- /* Try to clean up old fragments */
- pf_flush_fragments();
- frent = pool_get(&pf_frent_pl, PR_NOWAIT);
- if (frent == NULL) {
- REASON_SET(reason, PFRES_MEMORY);
- return (PF_DROP);
- }
- }
- pf_nfrents++;
- frent->fr_ip = h;
- frent->fr_m = m;
-
- /* Might return a completely reassembled mbuf, or NULL */
- DPFPRINTF((__FUNCTION__": reass frag %d @ %d\n", h->ip_id, fragoff));
- *m0 = m = pf_reassemble(m0, frag, frent, mff);
-
- if (m == NULL)
- return (PF_DROP);
-
- h = mtod(m, struct ip *);
-
- no_fragment:
- if (dir != PF_OUT)
- return (PF_PASS);
-
- return (PF_PASS);
-
- drop:
- REASON_SET(reason, PFRES_NORM);
- if (r != NULL && r->log)
- PFLOG_PACKET(h, m, AF_INET, dir, *reason, r);
- return (PF_DROP);
-
- bad:
- DPFPRINTF((__FUNCTION__": dropping bad fragment\n"));
-
- /* Free assoicated fragments */
- if (frag != NULL)
- pf_free_fragment(frag);
-
- REASON_SET(reason, PFRES_FRAG);
- if (r != NULL && r->log)
- PFLOG_PACKET(h, m, AF_INET, dir, *reason, r);
-
- return (PF_DROP);
-}
-
/*
* ipoff and off are measured from the start of the mbuf chain.
* h must be at "ipoff" on the mbuf chain.