summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHenning Brauer <henning@cvs.openbsd.org>2008-06-08 21:30:45 +0000
committerHenning Brauer <henning@cvs.openbsd.org>2008-06-08 21:30:45 +0000
commit33a8458ce59a76e8a62afb0f345de03580fb9c5a (patch)
treef828be9953636b57959587040fc44c7dbb266322
parent642354cf1836e9e971e04fcd75aac119840a9185 (diff)
factor out the tcp sequence number tracking from pf_test_state_tcp
ok mcbride
-rw-r--r--sys/net/pf.c301
1 files changed, 157 insertions, 144 deletions
diff --git a/sys/net/pf.c b/sys/net/pf.c
index b221da330e1..4ee915b2e83 100644
--- a/sys/net/pf.c
+++ b/sys/net/pf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pf.c,v 1.580 2008/06/08 17:23:19 henning Exp $ */
+/* $OpenBSD: pf.c,v 1.581 2008/06/08 21:30:44 henning Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -183,6 +183,10 @@ int pf_test_fragment(struct pf_rule **, int,
struct pfi_kif *, struct mbuf *, void *,
struct pf_pdesc *, struct pf_rule **,
struct pf_ruleset **);
+int pf_tcp_seqtrack_full(struct pf_state_peer *,
+ struct pf_state_peer *, struct pf_state **,
+ struct pfi_kif *, struct mbuf *, int,
+ struct pf_pdesc *, u_short *, int *);
int pf_test_state_tcp(struct pf_state **, int,
struct pfi_kif *, struct mbuf *, int,
void *, struct pf_pdesc *, u_short *);
@@ -3644,143 +3648,15 @@ pf_test_fragment(struct pf_rule **rm, int direction, struct pfi_kif *kif,
}
int
-pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif,
- struct mbuf *m, int off, void *h, struct pf_pdesc *pd,
- u_short *reason)
+pf_tcp_seqtrack_full(struct pf_state_peer *src, struct pf_state_peer *dst,
+ struct pf_state **state, struct pfi_kif *kif, struct mbuf *m, int off,
+ struct pf_pdesc *pd, u_short *reason, int *copyback)
{
- struct pf_state_key_cmp key;
struct tcphdr *th = pd->hdr.tcp;
u_int16_t win = ntohs(th->th_win);
u_int32_t ack, end, seq, orig_seq;
u_int8_t sws, dws;
int ackskew;
- int copyback = 0;
- struct pf_state_peer *src, *dst;
- struct pf_state_key *sk;
-
- key.af = pd->af;
- key.proto = IPPROTO_TCP;
- if (direction == PF_IN) { /* wire side, straight */
- PF_ACPY(&key.addr[0], pd->src, key.af);
- PF_ACPY(&key.addr[1], pd->dst, key.af);
- key.port[0] = th->th_sport;
- key.port[1] = th->th_dport;
- } else { /* stack side, reverse */
- PF_ACPY(&key.addr[1], pd->src, key.af);
- PF_ACPY(&key.addr[0], pd->dst, key.af);
- key.port[1] = th->th_sport;
- key.port[0] = th->th_dport;
- }
-
- STATE_LOOKUP(kif, &key, direction, *state);
-
- if (direction == (*state)->direction) {
- src = &(*state)->src;
- dst = &(*state)->dst;
- } else {
- src = &(*state)->dst;
- dst = &(*state)->src;
- }
-
- sk = (*state)->key[pd->didx];
-
- if ((*state)->src.state == PF_TCPS_PROXY_SRC) {
- if (direction != (*state)->direction) {
- REASON_SET(reason, PFRES_SYNPROXY);
- return (PF_SYNPROXY_DROP);
- }
- if (th->th_flags & TH_SYN) {
- if (ntohl(th->th_seq) != (*state)->src.seqlo) {
- REASON_SET(reason, PFRES_SYNPROXY);
- return (PF_DROP);
- }
- pf_send_tcp((*state)->rule.ptr, pd->af, pd->dst,
- pd->src, th->th_dport, th->th_sport,
- (*state)->src.seqhi, ntohl(th->th_seq) + 1,
- TH_SYN|TH_ACK, 0, (*state)->src.mss, 0, 1,
- 0, NULL, NULL);
- REASON_SET(reason, PFRES_SYNPROXY);
- return (PF_SYNPROXY_DROP);
- } else if (!(th->th_flags & TH_ACK) ||
- (ntohl(th->th_ack) != (*state)->src.seqhi + 1) ||
- (ntohl(th->th_seq) != (*state)->src.seqlo + 1)) {
- REASON_SET(reason, PFRES_SYNPROXY);
- return (PF_DROP);
- } else if ((*state)->src_node != NULL &&
- pf_src_connlimit(state)) {
- REASON_SET(reason, PFRES_SRCLIMIT);
- return (PF_DROP);
- } else
- (*state)->src.state = PF_TCPS_PROXY_DST;
- }
- if ((*state)->src.state == PF_TCPS_PROXY_DST) {
- if (direction == (*state)->direction) {
- if (((th->th_flags & (TH_SYN|TH_ACK)) != TH_ACK) ||
- (ntohl(th->th_ack) != (*state)->src.seqhi + 1) ||
- (ntohl(th->th_seq) != (*state)->src.seqlo + 1)) {
- REASON_SET(reason, PFRES_SYNPROXY);
- return (PF_DROP);
- }
- (*state)->src.max_win = MAX(ntohs(th->th_win), 1);
- if ((*state)->dst.seqhi == 1)
- (*state)->dst.seqhi = htonl(arc4random());
- pf_send_tcp((*state)->rule.ptr, pd->af,
- &sk->addr[pd->sidx], &sk->addr[pd->didx],
- sk->port[pd->sidx], sk->port[pd->didx],
- (*state)->dst.seqhi, 0, TH_SYN, 0,
- (*state)->src.mss, 0, 0, (*state)->tag, NULL, NULL);
- REASON_SET(reason, PFRES_SYNPROXY);
- return (PF_SYNPROXY_DROP);
- } else if (((th->th_flags & (TH_SYN|TH_ACK)) !=
- (TH_SYN|TH_ACK)) ||
- (ntohl(th->th_ack) != (*state)->dst.seqhi + 1)) {
- REASON_SET(reason, PFRES_SYNPROXY);
- return (PF_DROP);
- } else {
- (*state)->dst.max_win = MAX(ntohs(th->th_win), 1);
- (*state)->dst.seqlo = ntohl(th->th_seq);
- pf_send_tcp((*state)->rule.ptr, pd->af, pd->dst,
- pd->src, th->th_dport, th->th_sport,
- ntohl(th->th_ack), ntohl(th->th_seq) + 1,
- TH_ACK, (*state)->src.max_win, 0, 0, 0,
- (*state)->tag, NULL, NULL);
- pf_send_tcp((*state)->rule.ptr, pd->af,
- &sk->addr[pd->sidx], &sk->addr[pd->didx],
- sk->port[pd->sidx], sk->port[pd->didx],
- (*state)->src.seqhi + 1, (*state)->src.seqlo + 1,
- TH_ACK, (*state)->dst.max_win, 0, 0, 1,
- 0, NULL, NULL);
- (*state)->src.seqdiff = (*state)->dst.seqhi -
- (*state)->src.seqlo;
- (*state)->dst.seqdiff = (*state)->src.seqhi -
- (*state)->dst.seqlo;
- (*state)->src.seqhi = (*state)->src.seqlo +
- (*state)->dst.max_win;
- (*state)->dst.seqhi = (*state)->dst.seqlo +
- (*state)->src.max_win;
- (*state)->src.wscale = (*state)->dst.wscale = 0;
- (*state)->src.state = (*state)->dst.state =
- TCPS_ESTABLISHED;
- REASON_SET(reason, PFRES_SYNPROXY);
- return (PF_SYNPROXY_DROP);
- }
- }
-
- if (((th->th_flags & (TH_SYN|TH_ACK)) == TH_SYN) &&
- dst->state >= TCPS_FIN_WAIT_2 &&
- src->state >= TCPS_FIN_WAIT_2) {
- if (pf_status.debug >= PF_DEBUG_MISC) {
- printf("pf: state reuse ");
- pf_print_state(*state);
- pf_print_flags(th->th_flags);
- printf("\n");
- }
- /* XXX make sure it's the same direction ?? */
- (*state)->src.state = (*state)->dst.state = TCPS_CLOSED;
- pf_unlink_state(*state);
- *state = NULL;
- return (PF_DROP);
- }
if (src->wscale && dst->wscale && !(th->th_flags & TH_SYN)) {
sws = src->wscale & PF_WSCALE_MASK;
@@ -3815,7 +3691,7 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif,
pf_change_a(&th->th_seq, &th->th_sum, htonl(seq +
src->seqdiff), 0);
pf_change_a(&th->th_ack, &th->th_sum, htonl(ack), 0);
- copyback = 1;
+ *copyback = 1;
} else {
ack = ntohl(th->th_ack);
}
@@ -3867,7 +3743,7 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif,
pf_change_a(&th->th_seq, &th->th_sum, htonl(seq +
src->seqdiff), 0);
pf_change_a(&th->th_ack, &th->th_sum, htonl(ack), 0);
- copyback = 1;
+ *copyback = 1;
}
end = seq + pd->p_len;
if (th->th_flags & TH_SYN)
@@ -3913,7 +3789,7 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif,
*/
if (dst->seqdiff && (th->th_off << 2) > sizeof(struct tcphdr)) {
if (pf_modulate_sack(m, off, pd, th, dst))
- copyback = 1;
+ *copyback = 1;
}
@@ -3933,7 +3809,7 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif,
if (dst->scrub || src->scrub) {
if (pf_normalize_tcp_stateful(m, off, pd, reason, th,
- *state, src, dst, &copyback))
+ *state, src, dst, copyback))
return (PF_DROP);
}
@@ -4026,14 +3902,13 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif,
"pkts=%llu:%llu dir=%s,%s\n", seq, orig_seq, ack,
pd->p_len, ackskew, (*state)->packets[0],
(*state)->packets[1],
- direction == PF_IN ? "in" : "out",
- direction == (*state)->direction ?
- "fwd" : "rev");
+ pd->dir == PF_IN ? "in" : "out",
+ pd->dir == (*state)->direction ? "fwd" : "rev");
}
if (dst->scrub || src->scrub) {
if (pf_normalize_tcp_stateful(m, off, pd, reason, th,
- *state, src, dst, &copyback))
+ *state, src, dst, copyback))
return (PF_DROP);
}
@@ -4082,9 +3957,8 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif,
"pkts=%llu:%llu dir=%s,%s\n",
seq, orig_seq, ack, pd->p_len, ackskew,
(*state)->packets[0], (*state)->packets[1],
- direction == PF_IN ? "in" : "out",
- direction == (*state)->direction ?
- "fwd" : "rev");
+ pd->dir == PF_IN ? "in" : "out",
+ pd->dir == (*state)->direction ? "fwd" : "rev");
printf("pf: State failure on: %c %c %c %c | %c %c\n",
SEQ_GEQ(src->seqhi, end) ? ' ' : '1',
SEQ_GEQ(seq, src->seqlo - (dst->max_win << dws)) ?
@@ -4098,8 +3972,147 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif,
return (PF_DROP);
}
- /* Any packets which have gotten here are to be passed */
+ return (PF_PASS);
+}
+
+int
+pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif,
+ struct mbuf *m, int off, void *h, struct pf_pdesc *pd,
+ u_short *reason)
+{
+ struct pf_state_key_cmp key;
+ struct tcphdr *th = pd->hdr.tcp;
+ int copyback = 0;
+ struct pf_state_peer *src, *dst;
+ struct pf_state_key *sk;
+
+ key.af = pd->af;
+ key.proto = IPPROTO_TCP;
+ if (direction == PF_IN) { /* wire side, straight */
+ PF_ACPY(&key.addr[0], pd->src, key.af);
+ PF_ACPY(&key.addr[1], pd->dst, key.af);
+ key.port[0] = th->th_sport;
+ key.port[1] = th->th_dport;
+ } else { /* stack side, reverse */
+ PF_ACPY(&key.addr[1], pd->src, key.af);
+ PF_ACPY(&key.addr[0], pd->dst, key.af);
+ key.port[1] = th->th_sport;
+ key.port[0] = th->th_dport;
+ }
+
+ STATE_LOOKUP(kif, &key, direction, *state);
+
+ if (direction == (*state)->direction) {
+ src = &(*state)->src;
+ dst = &(*state)->dst;
+ } else {
+ src = &(*state)->dst;
+ dst = &(*state)->src;
+ }
+
+ sk = (*state)->key[pd->didx];
+ if ((*state)->src.state == PF_TCPS_PROXY_SRC) {
+ if (direction != (*state)->direction) {
+ REASON_SET(reason, PFRES_SYNPROXY);
+ return (PF_SYNPROXY_DROP);
+ }
+ if (th->th_flags & TH_SYN) {
+ if (ntohl(th->th_seq) != (*state)->src.seqlo) {
+ REASON_SET(reason, PFRES_SYNPROXY);
+ return (PF_DROP);
+ }
+ pf_send_tcp((*state)->rule.ptr, pd->af, pd->dst,
+ pd->src, th->th_dport, th->th_sport,
+ (*state)->src.seqhi, ntohl(th->th_seq) + 1,
+ TH_SYN|TH_ACK, 0, (*state)->src.mss, 0, 1,
+ 0, NULL, NULL);
+ REASON_SET(reason, PFRES_SYNPROXY);
+ return (PF_SYNPROXY_DROP);
+ } else if (!(th->th_flags & TH_ACK) ||
+ (ntohl(th->th_ack) != (*state)->src.seqhi + 1) ||
+ (ntohl(th->th_seq) != (*state)->src.seqlo + 1)) {
+ REASON_SET(reason, PFRES_SYNPROXY);
+ return (PF_DROP);
+ } else if ((*state)->src_node != NULL &&
+ pf_src_connlimit(state)) {
+ REASON_SET(reason, PFRES_SRCLIMIT);
+ return (PF_DROP);
+ } else
+ (*state)->src.state = PF_TCPS_PROXY_DST;
+ }
+ if ((*state)->src.state == PF_TCPS_PROXY_DST) {
+ if (direction == (*state)->direction) {
+ if (((th->th_flags & (TH_SYN|TH_ACK)) != TH_ACK) ||
+ (ntohl(th->th_ack) != (*state)->src.seqhi + 1) ||
+ (ntohl(th->th_seq) != (*state)->src.seqlo + 1)) {
+ REASON_SET(reason, PFRES_SYNPROXY);
+ return (PF_DROP);
+ }
+ (*state)->src.max_win = MAX(ntohs(th->th_win), 1);
+ if ((*state)->dst.seqhi == 1)
+ (*state)->dst.seqhi = htonl(arc4random());
+ pf_send_tcp((*state)->rule.ptr, pd->af,
+ &sk->addr[pd->sidx], &sk->addr[pd->didx],
+ sk->port[pd->sidx], sk->port[pd->didx],
+ (*state)->dst.seqhi, 0, TH_SYN, 0,
+ (*state)->src.mss, 0, 0, (*state)->tag, NULL, NULL);
+ REASON_SET(reason, PFRES_SYNPROXY);
+ return (PF_SYNPROXY_DROP);
+ } else if (((th->th_flags & (TH_SYN|TH_ACK)) !=
+ (TH_SYN|TH_ACK)) ||
+ (ntohl(th->th_ack) != (*state)->dst.seqhi + 1)) {
+ REASON_SET(reason, PFRES_SYNPROXY);
+ return (PF_DROP);
+ } else {
+ (*state)->dst.max_win = MAX(ntohs(th->th_win), 1);
+ (*state)->dst.seqlo = ntohl(th->th_seq);
+ pf_send_tcp((*state)->rule.ptr, pd->af, pd->dst,
+ pd->src, th->th_dport, th->th_sport,
+ ntohl(th->th_ack), ntohl(th->th_seq) + 1,
+ TH_ACK, (*state)->src.max_win, 0, 0, 0,
+ (*state)->tag, NULL, NULL);
+ pf_send_tcp((*state)->rule.ptr, pd->af,
+ &sk->addr[pd->sidx], &sk->addr[pd->didx],
+ sk->port[pd->sidx], sk->port[pd->didx],
+ (*state)->src.seqhi + 1, (*state)->src.seqlo + 1,
+ TH_ACK, (*state)->dst.max_win, 0, 0, 1,
+ 0, NULL, NULL);
+ (*state)->src.seqdiff = (*state)->dst.seqhi -
+ (*state)->src.seqlo;
+ (*state)->dst.seqdiff = (*state)->src.seqhi -
+ (*state)->dst.seqlo;
+ (*state)->src.seqhi = (*state)->src.seqlo +
+ (*state)->dst.max_win;
+ (*state)->dst.seqhi = (*state)->dst.seqlo +
+ (*state)->src.max_win;
+ (*state)->src.wscale = (*state)->dst.wscale = 0;
+ (*state)->src.state = (*state)->dst.state =
+ TCPS_ESTABLISHED;
+ REASON_SET(reason, PFRES_SYNPROXY);
+ return (PF_SYNPROXY_DROP);
+ }
+ }
+
+ if (((th->th_flags & (TH_SYN|TH_ACK)) == TH_SYN) &&
+ dst->state >= TCPS_FIN_WAIT_2 &&
+ src->state >= TCPS_FIN_WAIT_2) {
+ if (pf_status.debug >= PF_DEBUG_MISC) {
+ printf("pf: state reuse ");
+ pf_print_state(*state);
+ pf_print_flags(th->th_flags);
+ printf("\n");
+ }
+ /* XXX make sure it's the same direction ?? */
+ (*state)->src.state = (*state)->dst.state = TCPS_CLOSED;
+ pf_unlink_state(*state);
+ *state = NULL;
+ return (PF_DROP);
+ }
+
+ if (pf_tcp_seqtrack_full(src, dst, state, kif, m, off, pd, reason,
+ &copyback) == PF_DROP)
+ return (PF_DROP);
/* translate source/destination address, if necessary */
if ((*state)->key[PF_SK_WIRE] != (*state)->key[PF_SK_STACK]) {