summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorNiels Provos <provos@cvs.openbsd.org>2001-08-01 23:07:37 +0000
committerNiels Provos <provos@cvs.openbsd.org>2001-08-01 23:07:37 +0000
commit303a1a630d3f99e0a1c4cd6840818f4f6af7f984 (patch)
treebbf73b0a5ae38bd25cd877499184386c38061bca /sys
parent5e71be6b58dcee1cc6afa33ae5cdea487cf6b5fc (diff)
stateless tcp normalization along the lines of the normalization paper by
handley, paxon and kreibich; okay deraadt@
Diffstat (limited to 'sys')
-rw-r--r--sys/net/pf.c9
-rw-r--r--sys/net/pf_norm.c102
-rw-r--r--sys/net/pfvar.h3
3 files changed, 109 insertions, 5 deletions
diff --git a/sys/net/pf.c b/sys/net/pf.c
index 90757da31ae..be4fa7cc86f 100644
--- a/sys/net/pf.c
+++ b/sys/net/pf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pf.c,v 1.121 2001/07/30 23:00:37 deraadt Exp $ */
+/* $OpenBSD: pf.c,v 1.122 2001/08/01 23:07:36 provos Exp $ */
/*
* Copyright (c) 2001, Daniel Hartmeier
@@ -145,8 +145,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_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);
struct pf_nat *pf_get_nat(struct ifnet *, u_int8_t, u_int32_t,
u_int32_t);
@@ -178,6 +176,8 @@ int pf_get_sport(u_int8_t, u_int16_t, u_int16_t,
void pf_put_sport(u_int8_t, u_int16_t);
int pf_add_sport(struct pf_port_list *, u_int16_t);
int pf_chk_sport(struct pf_port_list *, u_int16_t);
+int pf_normalize_tcp(int, struct ifnet *, struct mbuf *,
+ int, int, struct ip *, struct tcphdr *);
#if NPFLOG > 0
#define PFLOG_PACKET(x,a,b,c,d,e) \
@@ -2599,6 +2599,9 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0)
log = action != PF_PASS;
goto done;
}
+ action = pf_normalize_tcp(dir, ifp, m, 0, off, h, &th);
+ if (action == PF_DROP)
+ break;
action = pf_test_state_tcp(&s, dir, ifp, m, 0, off, h , &th);
if (action == PF_PASS) {
r = s->rule;
diff --git a/sys/net/pf_norm.c b/sys/net/pf_norm.c
index b9759a0e9d9..1063bb1f7db 100644
--- a/sys/net/pf_norm.c
+++ b/sys/net/pf_norm.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pf_norm.c,v 1.3 2001/07/17 22:22:14 provos Exp $ */
+/* $OpenBSD: pf_norm.c,v 1.4 2001/08/01 23:07:36 provos Exp $ */
/*
* Copyright 2001 Niels Provos <provos@citi.umich.edu>
@@ -86,6 +86,9 @@ 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);
+u_int16_t pf_cksum_fixup(u_int16_t, u_int16_t, u_int16_t);
+int pf_normalize_tcp(int, struct ifnet *, struct mbuf *,
+ int, int, struct ip *, struct tcphdr *);
#define PFFRAG_FRENT_HIWAT 5000 /* Number of fragment entries */
#define PFFRAG_FRAG_HIWAT 1000 /* Number of fragmented packets */
@@ -542,3 +545,100 @@ pf_normalize_ip(struct mbuf **m0, int dir, struct ifnet *ifp, u_short *reason)
return (PF_DROP);
}
+int
+pf_normalize_tcp(int dir, struct ifnet *ifp, struct mbuf *m, int ipoff,
+ int off, struct ip *h, struct tcphdr *th)
+{
+ struct pf_rule *r, *rm = NULL;
+ int rewrite = 0, reason;
+ u_int8_t flags;
+
+ r = TAILQ_FIRST(pf_rules_active);
+ while (r != NULL) {
+ if (r->action != PF_SCRUB) {
+ r = TAILQ_NEXT(r, entries);
+ continue;
+ }
+ if (r->proto && r->proto != h->ip_p)
+ r = r->skip[0];
+ else if (r->src.mask && !pf_match_addr(r->src.not,
+ r->src.addr, r->src.mask, h->ip_src.s_addr))
+ r = r->skip[1];
+ else if (r->src.port_op && !pf_match_port(r->src.port_op,
+ r->src.port[0], r->src.port[1], th->th_sport))
+ r = r->skip[2];
+ else if (r->dst.mask && !pf_match_addr(r->dst.not,
+ r->dst.addr, r->dst.mask, h->ip_dst.s_addr))
+ r = r->skip[3];
+ else if (r->dst.port_op && !pf_match_port(r->dst.port_op,
+ r->dst.port[0], r->dst.port[1], th->th_dport))
+ r = r->skip[4];
+ else if (r->direction != dir)
+ r = TAILQ_NEXT(r, entries);
+ else if (r->ifp != NULL && r->ifp != ifp)
+ r = TAILQ_NEXT(r, entries);
+ else {
+ rm = r;
+ break;
+ }
+ }
+
+ if (rm == NULL)
+ return (PF_PASS);
+
+ flags = th->th_flags;
+ if (flags & TH_SYN) {
+ /* Illegal packet */
+ if (flags & TH_RST)
+ goto tcp_drop;
+
+ if (flags & TH_FIN)
+ flags &= ~TH_FIN;
+ } else {
+ /* Illegal packet */
+ if (!(flags & (TH_ACK|TH_RST)))
+ goto tcp_drop;
+ }
+
+ if (!(flags & TH_ACK)) {
+ /* These flags are only valid if ACK is set */
+ if ((flags & TH_FIN) || (flags & TH_PUSH) || (flags & TH_URG))
+ goto tcp_drop;
+ }
+
+ /* Check for illegal header length */
+ if (th->th_off < (sizeof(struct tcphdr) >> 2))
+ goto tcp_drop;
+
+ /* If flags changed, or reserved data set, then adjust */
+ if (flags != th->th_flags || th->th_x2 != 0) {
+ u_int16_t ov, nv;
+
+ ov = *(u_int16_t *)(&th->th_ack + 1);
+ th->th_flags = flags;
+ th->th_x2 = 0;
+ nv = *(u_int16_t *)(&th->th_ack + 1);
+
+ th->th_sum = pf_cksum_fixup(th->th_sum, ov, nv);
+ rewrite = 1;
+ }
+
+ /* Remove urgent pointer, if TH_URG is not set */
+ if (!(flags & TH_URG) && th->th_urp) {
+ th->th_sum = pf_cksum_fixup(th->th_sum, th->th_urp, 0);
+ th->th_urp = 0;
+ rewrite = 1;
+ }
+
+ /* copy back packet headers if we sanitized */
+ if (rewrite)
+ m_copyback(m, off, sizeof(*th), (caddr_t)th);
+
+ return (PF_PASS);
+
+ tcp_drop:
+ REASON_SET(&reason, PFRES_NORM);
+ if (rm != NULL && rm->log)
+ PFLOG_PACKET(h, m, AF_INET, dir, reason, rm);
+ return (PF_DROP);
+}
diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h
index ecf72e05326..fff97b45bf0 100644
--- a/sys/net/pfvar.h
+++ b/sys/net/pfvar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: pfvar.h,v 1.37 2001/07/29 12:53:17 dhartmei Exp $ */
+/* $OpenBSD: pfvar.h,v 1.38 2001/08/01 23:07:36 provos Exp $ */
/*
* Copyright (c) 2001, Daniel Hartmeier
@@ -308,6 +308,7 @@ int pf_tree_remove(struct pf_tree_node **, struct pf_tree_node *,
int pflog_packet(struct mbuf *, int, u_short, u_short, struct pf_rule *);
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);
void pf_normalize_init(void);
int pf_normalize_ip(struct mbuf **, int, struct ifnet *, u_short *);