diff options
author | Niels Provos <provos@cvs.openbsd.org> | 2001-08-01 23:07:37 +0000 |
---|---|---|
committer | Niels Provos <provos@cvs.openbsd.org> | 2001-08-01 23:07:37 +0000 |
commit | 303a1a630d3f99e0a1c4cd6840818f4f6af7f984 (patch) | |
tree | bbf73b0a5ae38bd25cd877499184386c38061bca /sys | |
parent | 5e71be6b58dcee1cc6afa33ae5cdea487cf6b5fc (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.c | 9 | ||||
-rw-r--r-- | sys/net/pf_norm.c | 102 | ||||
-rw-r--r-- | sys/net/pfvar.h | 3 |
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 *); |