summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/net/pf.c37
-rw-r--r--sys/net/pf_norm.c93
-rw-r--r--sys/net/pfvar.h25
3 files changed, 143 insertions, 12 deletions
diff --git a/sys/net/pf.c b/sys/net/pf.c
index f23be58515b..6f2fcf66365 100644
--- a/sys/net/pf.c
+++ b/sys/net/pf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pf.c,v 1.344 2003/05/11 01:17:15 dhartmei Exp $ */
+/* $OpenBSD: pf.c,v 1.345 2003/05/11 20:44:03 frantzen Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -166,7 +166,7 @@ int pf_test_fragment(struct pf_rule **, int,
struct pf_pdesc *, struct pf_rule **);
int pf_test_state_tcp(struct pf_state **, int,
struct ifnet *, struct mbuf *, int, int,
- void *, struct pf_pdesc *);
+ void *, struct pf_pdesc *, u_short *);
int pf_test_state_udp(struct pf_state **, int,
struct ifnet *, struct mbuf *, int, int,
void *, struct pf_pdesc *);
@@ -195,8 +195,6 @@ int pf_map_addr(u_int8_t, struct pf_pool *,
int pf_get_sport(sa_family_t, u_int8_t, struct pf_pool *,
struct pf_addr *, struct pf_addr *, u_int16_t,
struct pf_addr *, u_int16_t*, u_int16_t, u_int16_t);
-int pf_normalize_tcp(int, struct ifnet *, struct mbuf *,
- int, int, void *, struct pf_pdesc *);
void pf_route(struct mbuf **, struct pf_rule *, int,
struct ifnet *, struct pf_state *);
void pf_route6(struct mbuf **, struct pf_rule *, int,
@@ -480,6 +478,7 @@ pf_purge_expired_states(void)
if (--cur->state->anchor.ptr->states <= 0)
pf_rm_rule(NULL,
cur->state->anchor.ptr);
+ pf_normalize_tcp_cleanup(cur->state);
pool_put(&pf_state_pl, cur->state);
pool_put(&pf_tree_pl, cur);
pool_put(&pf_tree_pl, peer);
@@ -2126,7 +2125,15 @@ pf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction,
s->expire = s->creation + TIMEOUT(r, PFTM_TCP_FIRST_PACKET);
s->packets = 1;
s->bytes = pd->tot_len;
+
+ if ((pd->flags & PFDESC_TCP_NORM) && pf_normalize_tcp_init(m,
+ pd, th, &s->src, &s->dst)) {
+ REASON_SET(&reason, PFRES_MEMORY);
+ pool_put(&pf_state_pl, s);
+ return (PF_DROP);
+ }
if (pf_insert_state(s)) {
+ pf_normalize_tcp_cleanup(s);
REASON_SET(&reason, PFRES_MEMORY);
pool_put(&pf_state_pl, s);
return (PF_DROP);
@@ -2878,7 +2885,8 @@ pf_test_fragment(struct pf_rule **rm, int direction, struct ifnet *ifp,
int
pf_test_state_tcp(struct pf_state **state, int direction, struct ifnet *ifp,
- struct mbuf *m, int ipoff, int off, void *h, struct pf_pdesc *pd)
+ struct mbuf *m, int ipoff, int off, void *h, struct pf_pdesc *pd,
+ u_short *reason)
{
struct pf_tree_node key;
struct tcphdr *th = pd->hdr.tcp;
@@ -2921,6 +2929,14 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct ifnet *ifp,
if (src->seqlo == 0) {
/* First packet from this end. Set its state */
+ if ((pd->flags & PFDESC_TCP_NORM || dst->scrub) &&
+ src->scrub == NULL) {
+ if (pf_normalize_tcp_init(m, pd, th, src, dst)) {
+ REASON_SET(reason, PFRES_MEMORY);
+ return (PF_DROP);
+ }
+ }
+
/* Deferred generation of sequence number modulator */
if (dst->seqdiff) {
while ((src->seqdiff = arc4random()) == 0)
@@ -3149,6 +3165,11 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct ifnet *ifp,
return (PF_DROP);
}
+ if ((pd->flags & PFDESC_TCP_NORM) && (dst->scrub || src->scrub)) {
+ if (pf_normalize_tcp_stateful(m, pd, reason, th, src, dst))
+ return (PF_DROP);
+ }
+
/* Any packets which have gotten here are to be passed */
/* translate source/destination address, if needed */
@@ -4391,7 +4412,8 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0)
action = pf_normalize_tcp(dir, ifp, m, 0, off, h, &pd);
if (action == PF_DROP)
break;
- action = pf_test_state_tcp(&s, dir, ifp, m, 0, off, h, &pd);
+ action = pf_test_state_tcp(&s, dir, ifp, m, 0, off, h, &pd,
+ &reason);
if (action == PF_PASS) {
r = s->rule.ptr;
log = s->log;
@@ -4622,7 +4644,8 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0)
action = pf_normalize_tcp(dir, ifp, m, 0, off, h, &pd);
if (action == PF_DROP)
break;
- action = pf_test_state_tcp(&s, dir, ifp, m, 0, off, h, &pd);
+ action = pf_test_state_tcp(&s, dir, ifp, m, 0, off, h, &pd,
+ &reason);
if (action == PF_PASS) {
r = s->rule.ptr;
log = s->log;
diff --git a/sys/net/pf_norm.c b/sys/net/pf_norm.c
index e4dc2689e5d..a75942c42d8 100644
--- a/sys/net/pf_norm.c
+++ b/sys/net/pf_norm.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pf_norm.c,v 1.56 2003/04/05 20:20:58 cedric Exp $ */
+/* $OpenBSD: pf_norm.c,v 1.57 2003/05/11 20:44:03 frantzen Exp $ */
/*
* Copyright 2001 Niels Provos <provos@citi.umich.edu>
@@ -53,6 +53,10 @@
#include <netinet/udp.h>
#include <netinet/ip_icmp.h>
+#ifdef INET6
+#include <netinet/ip6.h>
+#endif /* INET6 */
+
#include <net/pfvar.h>
struct pf_frent {
@@ -120,6 +124,7 @@ int pf_normalize_tcpopt(struct pf_rule *, struct mbuf *,
/* Globals */
struct pool pf_frent_pl, pf_frag_pl, pf_cache_pl, pf_cent_pl;
+struct pool pf_state_scrub_pl;
int pf_nfrents, pf_ncache;
void
@@ -133,6 +138,8 @@ pf_normalize_init(void)
"pffrcache", NULL);
pool_init(&pf_cent_pl, sizeof(struct pf_frcache), 0, 0, 0, "pffrcent",
NULL);
+ pool_init(&pf_state_scrub_pl, sizeof(struct pf_state_scrub), 0, 0, 0,
+ "pfstscr", NULL);
pool_sethiwat(&pf_frag_pl, PFFRAG_FRAG_HIWAT);
pool_sethardlimit(&pf_frent_pl, PFFRAG_FRENT_HIWAT, NULL, 0);
@@ -1083,6 +1090,9 @@ pf_normalize_tcp(int dir, struct ifnet *ifp, struct mbuf *m, int ipoff,
if (rewrite)
m_copyback(m, off, sizeof(*th), (caddr_t)th);
+ /* Inform the state code to do stateful normalizations */
+ pd->flags |= PFDESC_TCP_NORM;
+
return (PF_PASS);
tcp_drop:
@@ -1093,6 +1103,87 @@ pf_normalize_tcp(int dir, struct ifnet *ifp, struct mbuf *m, int ipoff,
}
int
+pf_normalize_tcp_init(struct mbuf *m, struct pf_pdesc *pd,
+ struct tcphdr *th, struct pf_state_peer *src, struct pf_state_peer *dst)
+{
+ KASSERT(src->scrub == NULL);
+
+ src->scrub = pool_get(&pf_state_scrub_pl, PR_NOWAIT);
+ if (src->scrub == NULL)
+ return (1);
+
+ switch (pd->af) {
+#ifdef INET
+ case AF_INET: {
+ struct ip *h = mtod(m, struct ip *);
+ src->scrub->pfss_ttl = h->ip_ttl;
+ break;
+ }
+#endif /* INET */
+#ifdef INET6
+ case AF_INET6: {
+ struct ip6_hdr *h = mtod(m, struct ip6_hdr *);
+ src->scrub->pfss_ttl = h->ip6_hlim;
+ break;
+ }
+#endif /* INET6 */
+ }
+ return (0);
+}
+
+void
+pf_normalize_tcp_cleanup(struct pf_state *state)
+{
+ if (state->src.scrub)
+ pool_put(&pf_state_scrub_pl, state->src.scrub);
+ if (state->dst.scrub)
+ pool_put(&pf_state_scrub_pl, state->dst.scrub);
+
+ /* Someday... flush the TCP segment reassembly descriptors. */
+}
+
+int
+pf_normalize_tcp_stateful(struct mbuf *m, struct pf_pdesc *pd, u_short *reason,
+ struct tcphdr *th, struct pf_state_peer *src, struct pf_state_peer *dst)
+{
+ KASSERT(src->scrub || dst->scrub);
+
+
+ /*
+ * Enforce the minimum TTL seen for this connection. Negate a common
+ * technique to evade an intrusion detection system and confuse
+ * firewall state code.
+ */
+ switch (pd->af) {
+#ifdef INET
+ case AF_INET: {
+ if (src->scrub) {
+ struct ip *h = mtod(m, struct ip *);
+ if (h->ip_ttl > src->scrub->pfss_ttl)
+ src->scrub->pfss_ttl = h->ip_ttl;
+ h->ip_ttl = src->scrub->pfss_ttl;
+ }
+ break;
+ }
+#endif /* INET */
+#ifdef INET6
+ case AF_INET6: {
+ if (dst->scrub) {
+ struct ip6_hdr *h = mtod(m, struct ip6_hdr *);
+ if (h->ip6_hlim > src->scrub->pfss_ttl)
+ src->scrub->pfss_ttl = h->ip6_hlim;
+ h->ip6_hlim = src->scrub->pfss_ttl;
+ }
+ break;
+ }
+#endif /* INET6 */
+ }
+
+
+ /* I have a dream.... TCP segment reassembly.... */
+ return (0);
+}
+int
pf_normalize_tcpopt(struct pf_rule *r, struct mbuf *m, struct tcphdr *th,
int off)
{
diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h
index 8bbb3ca529f..17adab061bd 100644
--- a/sys/net/pfvar.h
+++ b/sys/net/pfvar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: pfvar.h,v 1.142 2003/04/30 12:30:27 cedric Exp $ */
+/* $OpenBSD: pfvar.h,v 1.143 2003/05/11 20:44:03 frantzen Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -399,6 +399,13 @@ struct pf_rule {
#define PFSTATE_HIWAT 10000 /* default state table size */
+
+struct pf_state_scrub {
+ u_int8_t pfss_ttl; /* stashed TTL */
+ u_int8_t pad;
+ u_int16_t pad2;
+};
+
struct pf_state_host {
struct pf_addr addr;
u_int16_t port;
@@ -409,9 +416,10 @@ struct pf_state_peer {
u_int32_t seqlo; /* Max sequence number sent */
u_int32_t seqhi; /* Max the other end ACKd + win */
u_int32_t seqdiff; /* Sequence number modulator */
- u_int16_t max_win;
- u_int8_t state;
- u_int8_t wscale;
+ u_int16_t max_win; /* largest window (pre scaling) */
+ u_int8_t state; /* active state level */
+ u_int8_t wscale; /* window scaling factor */
+ struct pf_state_scrub *scrub; /* state is scrubbed */
};
struct pf_state {
@@ -591,6 +599,7 @@ struct pf_pdesc {
u_int32_t p_len; /* total length of payload */
u_int16_t flags; /* Let SCRUB trigger behavior in
* state code. Easier than tags */
+#define PFDESC_TCP_NORM 0x0001 /* TCP was normalized */
sa_family_t af;
u_int8_t proto;
u_int8_t tos;
@@ -977,6 +986,7 @@ extern u_int32_t pf_qname_to_qid(char *);
extern void pf_update_anchor_rules(void);
extern struct pool pf_tree_pl, pf_rule_pl, pf_addr_pl;
extern struct pool pf_state_pl, pf_altq_pl, pf_pooladdr_pl;
+extern struct pool pf_state_scrub_pl;
extern void pf_purge_timeout(void *);
extern void pf_purge_expired_states(void);
extern int pf_insert_state(struct pf_state *);
@@ -1009,6 +1019,13 @@ int pf_match_gid(u_int8_t, gid_t, gid_t, gid_t);
void pf_normalize_init(void);
int pf_normalize_ip(struct mbuf **, int, struct ifnet *, u_short *);
+int pf_normalize_tcp(int, struct ifnet *, struct mbuf *, int, int, void *,
+ struct pf_pdesc *);
+void pf_normalize_tcp_cleanup(struct pf_state *);
+int pf_normalize_tcp_init(struct mbuf *, struct pf_pdesc *, struct tcphdr *,
+ struct pf_state_peer *, struct pf_state_peer *);
+int pf_normalize_tcp_stateful(struct mbuf *, struct pf_pdesc *, u_short *,
+ struct tcphdr *, struct pf_state_peer *, struct pf_state_peer *);
void pf_purge_expired_fragments(void);
int pf_routable(struct pf_addr *addr, sa_family_t af);
void pfr_initialize(void);