summaryrefslogtreecommitdiffstats
path: root/sys/contrib
diff options
context:
space:
mode:
Diffstat (limited to 'sys/contrib')
-rw-r--r--sys/contrib/pf/net/if_pfsync.c4
-rw-r--r--sys/contrib/pf/net/if_pfsync.h2
-rw-r--r--sys/contrib/pf/net/pf.c460
-rw-r--r--sys/contrib/pf/net/pfvar.h5
4 files changed, 296 insertions, 175 deletions
diff --git a/sys/contrib/pf/net/if_pfsync.c b/sys/contrib/pf/net/if_pfsync.c
index 0925edb..9466118 100644
--- a/sys/contrib/pf/net/if_pfsync.c
+++ b/sys/contrib/pf/net/if_pfsync.c
@@ -465,7 +465,7 @@ pfsync_insert_net_state(struct pfsync_state *sp, u_int8_t chksum_flag)
st->direction = sp->direction;
st->log = sp->log;
st->timeout = sp->timeout;
- st->allow_opts = sp->allow_opts;
+ st->state_flags = sp->state_flags;
bcopy(sp->id, &st->id, sizeof(st->id));
st->creatorid = sp->creatorid;
@@ -1578,7 +1578,7 @@ pfsync_pack_state(u_int8_t action, struct pf_state *st, int flags)
sp->proto = st->proto;
sp->direction = st->direction;
sp->log = st->log;
- sp->allow_opts = st->allow_opts;
+ sp->state_flags = st->state_flags;
sp->timeout = st->timeout;
if (flags & PFSYNC_FLAG_STALE)
diff --git a/sys/contrib/pf/net/if_pfsync.h b/sys/contrib/pf/net/if_pfsync.h
index f7edca3..f306610 100644
--- a/sys/contrib/pf/net/if_pfsync.h
+++ b/sys/contrib/pf/net/if_pfsync.h
@@ -80,7 +80,7 @@ struct pfsync_state {
u_int8_t proto;
u_int8_t direction;
u_int8_t log;
- u_int8_t allow_opts;
+ u_int8_t state_flags;
u_int8_t timeout;
u_int8_t sync_flags;
u_int8_t updates;
diff --git a/sys/contrib/pf/net/pf.c b/sys/contrib/pf/net/pf.c
index e8031ac..ebe73c2 100644
--- a/sys/contrib/pf/net/pf.c
+++ b/sys/contrib/pf/net/pf.c
@@ -253,6 +253,13 @@ 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_track_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_tcp_track_sloppy(struct pf_state_peer *,
+ struct pf_state_peer *, struct pf_state **,
+ struct pf_pdesc *, u_short *);
int pf_test_state_tcp(struct pf_state **, int,
struct pfi_kif *, struct mbuf *, int,
void *, struct pf_pdesc *, u_short *);
@@ -3528,7 +3535,10 @@ cleanup:
s->nat_rule.ptr = nr;
s->anchor.ptr = a;
STATE_INC_COUNTERS(s);
- s->allow_opts = r->allow_opts;
+ if (r->allow_opts)
+ s->state_flags |= PFSTATE_ALLOWOPTS;
+ if (r->rule_flag & PFRULE_STATESLOPPY)
+ s->state_flags |= PFSTATE_SLOPPY;
s->log = r->log & PF_LOG_ALL;
if (nr != NULL)
s->log |= nr->log & PF_LOG_ALL;
@@ -3925,7 +3935,10 @@ cleanup:
s->nat_rule.ptr = nr;
s->anchor.ptr = a;
STATE_INC_COUNTERS(s);
- s->allow_opts = r->allow_opts;
+ if (r->allow_opts)
+ s->state_flags |= PFSTATE_ALLOWOPTS;
+ if (r->rule_flag & PFRULE_STATESLOPPY)
+ s->state_flags |= PFSTATE_SLOPPY;
s->log = r->log & PF_LOG_ALL;
if (nr != NULL)
s->log |= nr->log & PF_LOG_ALL;
@@ -4238,7 +4251,10 @@ cleanup:
s->nat_rule.ptr = nr;
s->anchor.ptr = a;
STATE_INC_COUNTERS(s);
- s->allow_opts = r->allow_opts;
+ if (r->allow_opts)
+ s->state_flags |= PFSTATE_ALLOWOPTS;
+ if (r->rule_flag & PFRULE_STATESLOPPY)
+ s->state_flags |= PFSTATE_SLOPPY;
s->log = r->log & PF_LOG_ALL;
if (nr != NULL)
s->log |= nr->log & PF_LOG_ALL;
@@ -4525,7 +4541,10 @@ cleanup:
s->nat_rule.ptr = nr;
s->anchor.ptr = a;
STATE_INC_COUNTERS(s);
- s->allow_opts = r->allow_opts;
+ if (r->allow_opts)
+ s->state_flags |= PFSTATE_ALLOWOPTS;
+ if (r->rule_flag & PFRULE_STATESLOPPY)
+ s->state_flags |= PFSTATE_SLOPPY;
s->log = r->log & PF_LOG_ALL;
if (nr != NULL)
s->log |= nr->log & PF_LOG_ALL;
@@ -4666,165 +4685,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_track_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_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;
-
- key.af = pd->af;
- key.proto = IPPROTO_TCP;
- if (direction == PF_IN) {
- PF_ACPY(&key.ext.addr, pd->src, key.af);
- PF_ACPY(&key.gwy.addr, pd->dst, key.af);
- key.ext.port = th->th_sport;
- key.gwy.port = th->th_dport;
- } else {
- PF_ACPY(&key.lan.addr, pd->src, key.af);
- PF_ACPY(&key.ext.addr, pd->dst, key.af);
- key.lan.port = th->th_sport;
- key.ext.port = th->th_dport;
- }
-
- STATE_LOOKUP();
-
- if (direction == (*state)->direction) {
- src = &(*state)->src;
- dst = &(*state)->dst;
- } else {
- src = &(*state)->dst;
- dst = &(*state)->src;
- }
-
- 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);
- }
-#ifdef __FreeBSD__
- pf_send_tcp(NULL, (*state)->rule.ptr, pd->af, pd->dst,
-#else
- pf_send_tcp((*state)->rule.ptr, pd->af, pd->dst,
-#endif
- 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) {
- struct pf_state_host *src, *dst;
-
- if (direction == PF_OUT) {
- src = &(*state)->gwy;
- dst = &(*state)->ext;
- } else {
- src = &(*state)->ext;
- dst = &(*state)->lan;
- }
- 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());
-#ifdef __FreeBSD__
- pf_send_tcp(NULL, (*state)->rule.ptr, pd->af,
- &src->addr,
-#else
- pf_send_tcp((*state)->rule.ptr, pd->af, &src->addr,
-#endif
- &dst->addr, src->port, dst->port,
- (*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);
-#ifdef __FreeBSD__
- pf_send_tcp(NULL, (*state)->rule.ptr, pd->af, pd->dst,
-#else
- pf_send_tcp((*state)->rule.ptr, pd->af, pd->dst,
-#endif
- 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);
-#ifdef __FreeBSD__
- pf_send_tcp(NULL, (*state)->rule.ptr, pd->af,
- &src->addr,
-#else
- pf_send_tcp((*state)->rule.ptr, pd->af, &src->addr,
-#endif
- &dst->addr, src->port, dst->port,
- (*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);
- }
+ 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;
if (src->wscale && dst->wscale && !(th->th_flags & TH_SYN)) {
sws = src->wscale & PF_WSCALE_MASK;
@@ -4863,7 +4732,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);
}
@@ -4915,7 +4784,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)
@@ -4961,7 +4830,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;
}
@@ -4980,7 +4849,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);
}
@@ -5082,7 +4951,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);
}
@@ -5132,7 +5001,11 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif,
pf_print_state(*state);
pf_print_flags(th->th_flags);
printf(" seq=%u (%u) ack=%u len=%u ackskew=%d "
+#ifdef notyet
"pkts=%llu:%llu dir=%s,%s\n",
+#else
+ "pkts=%llu:%llu%s\n",
+#endif
seq, orig_seq, ack, pd->p_len, ackskew,
#ifdef __FreeBSD__
(unsigned long long)(*state)->packets[0],
@@ -5140,8 +5013,12 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif,
#else
(*state)->packets[0], (*state)->packets[1],
#endif
+#ifdef notyet
direction == PF_IN ? "in" : "out",
direction == (*state)->direction ? "fwd" : "rev");
+#else
+ "");
+#endif
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)) ?
@@ -5156,6 +5033,246 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif,
}
/* Any packets which have gotten here are to be passed */
+ return (PF_PASS);
+}
+
+int
+pf_tcp_track_sloppy(struct pf_state_peer *src, struct pf_state_peer *dst,
+ struct pf_state **state, struct pf_pdesc *pd, u_short *reason)
+{
+ struct tcphdr *th = pd->hdr.tcp;
+
+ if (th->th_flags & TH_SYN)
+ if (src->state < TCPS_SYN_SENT)
+ src->state = TCPS_SYN_SENT;
+ if (th->th_flags & TH_FIN)
+ if (src->state < TCPS_CLOSING)
+ src->state = TCPS_CLOSING;
+ if (th->th_flags & TH_ACK) {
+ if (dst->state == TCPS_SYN_SENT) {
+ dst->state = TCPS_ESTABLISHED;
+ if (src->state == TCPS_ESTABLISHED &&
+ (*state)->src_node != NULL &&
+ pf_src_connlimit(state)) {
+ REASON_SET(reason, PFRES_SRCLIMIT);
+ return (PF_DROP);
+ }
+ } else if (dst->state == TCPS_CLOSING) {
+ dst->state = TCPS_FIN_WAIT_2;
+ } else if (src->state == TCPS_SYN_SENT &&
+ dst->state < TCPS_SYN_SENT) {
+ /*
+ * Handle a special sloppy case where we only see one
+ * half of the connection. If there is a ACK after
+ * the initial SYN without ever seeing a packet from
+ * the destination, set the connection to established.
+ */
+ dst->state = src->state = TCPS_ESTABLISHED;
+ if ((*state)->src_node != NULL &&
+ pf_src_connlimit(state)) {
+ REASON_SET(reason, PFRES_SRCLIMIT);
+ return (PF_DROP);
+ }
+ } else if (src->state == TCPS_CLOSING &&
+ dst->state == TCPS_ESTABLISHED &&
+ dst->seqlo == 0) {
+ /*
+ * Handle the closing of half connections where we
+ * don't see the full bidirectional FIN/ACK+ACK
+ * handshake.
+ */
+ dst->state = TCPS_CLOSING;
+ }
+ }
+ if (th->th_flags & TH_RST)
+ src->state = dst->state = TCPS_TIME_WAIT;
+
+ /* update expire time */
+ (*state)->expire = time_second;
+ if (src->state >= TCPS_FIN_WAIT_2 &&
+ dst->state >= TCPS_FIN_WAIT_2)
+ (*state)->timeout = PFTM_TCP_CLOSED;
+ else if (src->state >= TCPS_CLOSING &&
+ dst->state >= TCPS_CLOSING)
+ (*state)->timeout = PFTM_TCP_FIN_WAIT;
+ else if (src->state < TCPS_ESTABLISHED ||
+ dst->state < TCPS_ESTABLISHED)
+ (*state)->timeout = PFTM_TCP_OPENING;
+ else if (src->state >= TCPS_CLOSING ||
+ dst->state >= TCPS_CLOSING)
+ (*state)->timeout = PFTM_TCP_CLOSING;
+ else
+ (*state)->timeout = PFTM_TCP_ESTABLISHED;
+
+ 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_cmp key;
+ struct tcphdr *th = pd->hdr.tcp;
+ int copyback = 0;
+ struct pf_state_peer *src, *dst;
+
+ key.af = pd->af;
+ key.proto = IPPROTO_TCP;
+ if (direction == PF_IN) {
+ PF_ACPY(&key.ext.addr, pd->src, key.af);
+ PF_ACPY(&key.gwy.addr, pd->dst, key.af);
+ key.ext.port = th->th_sport;
+ key.gwy.port = th->th_dport;
+ } else {
+ PF_ACPY(&key.lan.addr, pd->src, key.af);
+ PF_ACPY(&key.ext.addr, pd->dst, key.af);
+ key.lan.port = th->th_sport;
+ key.ext.port = th->th_dport;
+ }
+
+ STATE_LOOKUP();
+
+ if (direction == (*state)->direction) {
+ src = &(*state)->src;
+ dst = &(*state)->dst;
+ } else {
+ src = &(*state)->dst;
+ dst = &(*state)->src;
+ }
+
+ 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);
+ }
+#ifdef __FreeBSD__
+ pf_send_tcp(NULL, (*state)->rule.ptr, pd->af, pd->dst,
+#else
+ pf_send_tcp((*state)->rule.ptr, pd->af, pd->dst,
+#endif
+ 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) {
+ struct pf_state_host *src, *dst;
+
+ if (direction == PF_OUT) {
+ src = &(*state)->gwy;
+ dst = &(*state)->ext;
+ } else {
+ src = &(*state)->ext;
+ dst = &(*state)->lan;
+ }
+ 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());
+#ifdef __FreeBSD__
+ pf_send_tcp(NULL, (*state)->rule.ptr, pd->af,
+ &src->addr,
+#else
+ pf_send_tcp((*state)->rule.ptr, pd->af, &src->addr,
+#endif
+ &dst->addr, src->port, dst->port,
+ (*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);
+#ifdef __FreeBSD__
+ pf_send_tcp(NULL, (*state)->rule.ptr, pd->af, pd->dst,
+#else
+ pf_send_tcp((*state)->rule.ptr, pd->af, pd->dst,
+#endif
+ 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);
+#ifdef __FreeBSD__
+ pf_send_tcp(NULL, (*state)->rule.ptr, pd->af,
+ &src->addr,
+#else
+ pf_send_tcp((*state)->rule.ptr, pd->af, &src->addr,
+#endif
+ &dst->addr, src->port, dst->port,
+ (*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 ((*state)->state_flags & PFSTATE_SLOPPY) {
+ if (pf_tcp_track_sloppy(src, dst, state, pd, reason) == PF_DROP)
+ return (PF_DROP);
+ } else {
+ if (pf_tcp_track_full(src, dst, state, kif, m, off, pd, reason,
+ &copyback) == PF_DROP)
+ return (PF_DROP);
+ }
/* translate source/destination address, if necessary */
if (STATE_TRANSLATE(*state)) {
@@ -5533,8 +5650,9 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
copyback = 1;
}
- if (!SEQ_GEQ(src->seqhi, seq) ||
- !SEQ_GEQ(seq, src->seqlo - (dst->max_win << dws))) {
+ if (!((*state)->state_flags & PFSTATE_SLOPPY) &&
+ (!SEQ_GEQ(src->seqhi, seq) ||
+ !SEQ_GEQ(seq, src->seqlo - (dst->max_win << dws)))) {
if (pf_status.debug >= PF_DEBUG_MISC) {
printf("pf: BAD ICMP %d:%d ",
icmptype, pd->hdr.icmp->icmp_code);
@@ -7052,7 +7170,7 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0,
done:
if (action == PF_PASS && h->ip_hl > 5 &&
- !((s && s->allow_opts) || r->allow_opts)) {
+ !((s && s->state_flags & PFSTATE_ALLOWOPTS) || r->allow_opts)) {
action = PF_DROP;
REASON_SET(&reason, PFRES_IPOPTIONS);
log = 1;
@@ -7513,7 +7631,7 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0,
done:
/* handle dangerous IPv6 extension headers. */
if (action == PF_PASS && rh_cnt &&
- !((s && s->allow_opts) || r->allow_opts)) {
+ !((s && s->state_flags & PFSTATE_ALLOWOPTS) || r->allow_opts)) {
action = PF_DROP;
REASON_SET(&reason, PFRES_IPOPTIONS);
log = 1;
diff --git a/sys/contrib/pf/net/pfvar.h b/sys/contrib/pf/net/pfvar.h
index 32e721c..de175b1 100644
--- a/sys/contrib/pf/net/pfvar.h
+++ b/sys/contrib/pf/net/pfvar.h
@@ -700,6 +700,7 @@ struct pf_rule {
/* rule flags again */
#define PFRULE_IFBOUND 0x00010000 /* if-bound */
+#define PFRULE_STATESLOPPY 0x00020000 /* sloppy state tracking */
#define PFSTATE_HIWAT 10000 /* default state table size */
#define PFSTATE_ADAPT_START 6000 /* default adaptive timeout start */
@@ -800,7 +801,9 @@ struct pf_state {
u_int8_t pad;
#endif
u_int8_t log;
- u_int8_t allow_opts;
+ u_int8_t state_flags;
+#define PFSTATE_ALLOWOPTS 0x01
+#define PFSTATE_SLOPPY 0x02
u_int8_t timeout;
u_int8_t sync_flags;
#define PFSTATE_NOSYNC 0x01
OpenPOWER on IntegriCloud