|
@@ -4691,6 +4691,67 @@ out:
|
|
|
}
|
|
|
#endif /* CONFIG_NET_DMA */
|
|
|
|
|
|
+/* Does PAWS and seqno based validation of an incoming segment, flags will
|
|
|
+ * play significant role here.
|
|
|
+ */
|
|
|
+static int tcp_validate_incoming(struct sock *sk, struct sk_buff *skb,
|
|
|
+ struct tcphdr *th, int syn_inerr)
|
|
|
+{
|
|
|
+ struct tcp_sock *tp = tcp_sk(sk);
|
|
|
+
|
|
|
+ /* RFC1323: H1. Apply PAWS check first. */
|
|
|
+ if (tcp_fast_parse_options(skb, th, tp) && tp->rx_opt.saw_tstamp &&
|
|
|
+ tcp_paws_discard(sk, skb)) {
|
|
|
+ if (!th->rst) {
|
|
|
+ NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_PAWSESTABREJECTED);
|
|
|
+ tcp_send_dupack(sk, skb);
|
|
|
+ goto discard;
|
|
|
+ }
|
|
|
+ /* Reset is accepted even if it did not pass PAWS. */
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Step 1: check sequence number */
|
|
|
+ if (!tcp_sequence(tp, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq)) {
|
|
|
+ /* RFC793, page 37: "In all states except SYN-SENT, all reset
|
|
|
+ * (RST) segments are validated by checking their SEQ-fields."
|
|
|
+ * And page 69: "If an incoming segment is not acceptable,
|
|
|
+ * an acknowledgment should be sent in reply (unless the RST
|
|
|
+ * bit is set, if so drop the segment and return)".
|
|
|
+ */
|
|
|
+ if (!th->rst)
|
|
|
+ tcp_send_dupack(sk, skb);
|
|
|
+ goto discard;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Step 2: check RST bit */
|
|
|
+ if (th->rst) {
|
|
|
+ tcp_reset(sk);
|
|
|
+ goto discard;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* ts_recent update must be made after we are sure that the packet
|
|
|
+ * is in window.
|
|
|
+ */
|
|
|
+ tcp_replace_ts_recent(tp, TCP_SKB_CB(skb)->seq);
|
|
|
+
|
|
|
+ /* step 3: check security and precedence [ignored] */
|
|
|
+
|
|
|
+ /* step 4: Check for a SYN in window. */
|
|
|
+ if (th->syn && !before(TCP_SKB_CB(skb)->seq, tp->rcv_nxt)) {
|
|
|
+ if (syn_inerr)
|
|
|
+ TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_INERRS);
|
|
|
+ NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPABORTONSYN);
|
|
|
+ tcp_reset(sk);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 1;
|
|
|
+
|
|
|
+discard:
|
|
|
+ __kfree_skb(skb);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* TCP receive function for the ESTABLISHED state.
|
|
|
*
|
|
@@ -4718,6 +4779,7 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
|
|
|
struct tcphdr *th, unsigned len)
|
|
|
{
|
|
|
struct tcp_sock *tp = tcp_sk(sk);
|
|
|
+ int res;
|
|
|
|
|
|
/*
|
|
|
* Header prediction.
|
|
@@ -4898,52 +4960,13 @@ slow_path:
|
|
|
if (len < (th->doff << 2) || tcp_checksum_complete_user(sk, skb))
|
|
|
goto csum_error;
|
|
|
|
|
|
- /*
|
|
|
- * RFC1323: H1. Apply PAWS check first.
|
|
|
- */
|
|
|
- if (tcp_fast_parse_options(skb, th, tp) && tp->rx_opt.saw_tstamp &&
|
|
|
- tcp_paws_discard(sk, skb)) {
|
|
|
- if (!th->rst) {
|
|
|
- NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_PAWSESTABREJECTED);
|
|
|
- tcp_send_dupack(sk, skb);
|
|
|
- goto discard;
|
|
|
- }
|
|
|
- /* Resets are accepted even if PAWS failed.
|
|
|
-
|
|
|
- ts_recent update must be made after we are sure
|
|
|
- that the packet is in window.
|
|
|
- */
|
|
|
- }
|
|
|
-
|
|
|
/*
|
|
|
* Standard slow path.
|
|
|
*/
|
|
|
|
|
|
- if (!tcp_sequence(tp, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq)) {
|
|
|
- /* RFC793, page 37: "In all states except SYN-SENT, all reset
|
|
|
- * (RST) segments are validated by checking their SEQ-fields."
|
|
|
- * And page 69: "If an incoming segment is not acceptable,
|
|
|
- * an acknowledgment should be sent in reply (unless the RST bit
|
|
|
- * is set, if so drop the segment and return)".
|
|
|
- */
|
|
|
- if (!th->rst)
|
|
|
- tcp_send_dupack(sk, skb);
|
|
|
- goto discard;
|
|
|
- }
|
|
|
-
|
|
|
- if (th->rst) {
|
|
|
- tcp_reset(sk);
|
|
|
- goto discard;
|
|
|
- }
|
|
|
-
|
|
|
- tcp_replace_ts_recent(tp, TCP_SKB_CB(skb)->seq);
|
|
|
-
|
|
|
- if (th->syn && !before(TCP_SKB_CB(skb)->seq, tp->rcv_nxt)) {
|
|
|
- TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_INERRS);
|
|
|
- NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPABORTONSYN);
|
|
|
- tcp_reset(sk);
|
|
|
- return 1;
|
|
|
- }
|
|
|
+ res = tcp_validate_incoming(sk, skb, th, 1);
|
|
|
+ if (res <= 0)
|
|
|
+ return -res;
|
|
|
|
|
|
step5:
|
|
|
if (th->ack)
|
|
@@ -5225,6 +5248,7 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
|
|
|
struct tcp_sock *tp = tcp_sk(sk);
|
|
|
struct inet_connection_sock *icsk = inet_csk(sk);
|
|
|
int queued = 0;
|
|
|
+ int res;
|
|
|
|
|
|
tp->rx_opt.saw_tstamp = 0;
|
|
|
|
|
@@ -5277,42 +5301,9 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
- if (tcp_fast_parse_options(skb, th, tp) && tp->rx_opt.saw_tstamp &&
|
|
|
- tcp_paws_discard(sk, skb)) {
|
|
|
- if (!th->rst) {
|
|
|
- NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_PAWSESTABREJECTED);
|
|
|
- tcp_send_dupack(sk, skb);
|
|
|
- goto discard;
|
|
|
- }
|
|
|
- /* Reset is accepted even if it did not pass PAWS. */
|
|
|
- }
|
|
|
-
|
|
|
- /* step 1: check sequence number */
|
|
|
- if (!tcp_sequence(tp, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq)) {
|
|
|
- if (!th->rst)
|
|
|
- tcp_send_dupack(sk, skb);
|
|
|
- goto discard;
|
|
|
- }
|
|
|
-
|
|
|
- /* step 2: check RST bit */
|
|
|
- if (th->rst) {
|
|
|
- tcp_reset(sk);
|
|
|
- goto discard;
|
|
|
- }
|
|
|
-
|
|
|
- tcp_replace_ts_recent(tp, TCP_SKB_CB(skb)->seq);
|
|
|
-
|
|
|
- /* step 3: check security and precedence [ignored] */
|
|
|
-
|
|
|
- /* step 4:
|
|
|
- *
|
|
|
- * Check for a SYN in window.
|
|
|
- */
|
|
|
- if (th->syn && !before(TCP_SKB_CB(skb)->seq, tp->rcv_nxt)) {
|
|
|
- NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPABORTONSYN);
|
|
|
- tcp_reset(sk);
|
|
|
- return 1;
|
|
|
- }
|
|
|
+ res = tcp_validate_incoming(sk, skb, th, 0);
|
|
|
+ if (res <= 0)
|
|
|
+ return -res;
|
|
|
|
|
|
/* step 5: check the ACK field */
|
|
|
if (th->ack) {
|