|
@@ -100,6 +100,7 @@ int sysctl_tcp_thin_dupack __read_mostly;
|
|
|
|
|
|
int sysctl_tcp_moderate_rcvbuf __read_mostly = 1;
|
|
|
int sysctl_tcp_early_retrans __read_mostly = 3;
|
|
|
+int sysctl_tcp_invalid_ratelimit __read_mostly = HZ/2;
|
|
|
|
|
|
#define FLAG_DATA 0x01 /* Incoming frame contained data. */
|
|
|
#define FLAG_WIN_UPDATE 0x02 /* Incoming ACK was a window update. */
|
|
@@ -3321,13 +3322,22 @@ static int tcp_ack_update_window(struct sock *sk, const struct sk_buff *skb, u32
|
|
|
}
|
|
|
|
|
|
/* RFC 5961 7 [ACK Throttling] */
|
|
|
-static void tcp_send_challenge_ack(struct sock *sk)
|
|
|
+static void tcp_send_challenge_ack(struct sock *sk, const struct sk_buff *skb)
|
|
|
{
|
|
|
/* unprotected vars, we dont care of overwrites */
|
|
|
static u32 challenge_timestamp;
|
|
|
static unsigned int challenge_count;
|
|
|
- u32 now = jiffies / HZ;
|
|
|
+ struct tcp_sock *tp = tcp_sk(sk);
|
|
|
+ u32 now;
|
|
|
+
|
|
|
+ /* First check our per-socket dupack rate limit. */
|
|
|
+ if (tcp_oow_rate_limited(sock_net(sk), skb,
|
|
|
+ LINUX_MIB_TCPACKSKIPPEDCHALLENGE,
|
|
|
+ &tp->last_oow_ack_time))
|
|
|
+ return;
|
|
|
|
|
|
+ /* Then check the check host-wide RFC 5961 rate limit. */
|
|
|
+ now = jiffies / HZ;
|
|
|
if (now != challenge_timestamp) {
|
|
|
challenge_timestamp = now;
|
|
|
challenge_count = 0;
|
|
@@ -3423,7 +3433,7 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
|
|
|
if (before(ack, prior_snd_una)) {
|
|
|
/* RFC 5961 5.2 [Blind Data Injection Attack].[Mitigation] */
|
|
|
if (before(ack, prior_snd_una - tp->max_window)) {
|
|
|
- tcp_send_challenge_ack(sk);
|
|
|
+ tcp_send_challenge_ack(sk, skb);
|
|
|
return -1;
|
|
|
}
|
|
|
goto old_ack;
|
|
@@ -4992,7 +5002,10 @@ static bool tcp_validate_incoming(struct sock *sk, struct sk_buff *skb,
|
|
|
tcp_paws_discard(sk, skb)) {
|
|
|
if (!th->rst) {
|
|
|
NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_PAWSESTABREJECTED);
|
|
|
- tcp_send_dupack(sk, skb);
|
|
|
+ if (!tcp_oow_rate_limited(sock_net(sk), skb,
|
|
|
+ LINUX_MIB_TCPACKSKIPPEDPAWS,
|
|
|
+ &tp->last_oow_ack_time))
|
|
|
+ tcp_send_dupack(sk, skb);
|
|
|
goto discard;
|
|
|
}
|
|
|
/* Reset is accepted even if it did not pass PAWS. */
|
|
@@ -5009,7 +5022,10 @@ static bool tcp_validate_incoming(struct sock *sk, struct sk_buff *skb,
|
|
|
if (!th->rst) {
|
|
|
if (th->syn)
|
|
|
goto syn_challenge;
|
|
|
- tcp_send_dupack(sk, skb);
|
|
|
+ if (!tcp_oow_rate_limited(sock_net(sk), skb,
|
|
|
+ LINUX_MIB_TCPACKSKIPPEDSEQ,
|
|
|
+ &tp->last_oow_ack_time))
|
|
|
+ tcp_send_dupack(sk, skb);
|
|
|
}
|
|
|
goto discard;
|
|
|
}
|
|
@@ -5025,7 +5041,7 @@ static bool tcp_validate_incoming(struct sock *sk, struct sk_buff *skb,
|
|
|
if (TCP_SKB_CB(skb)->seq == tp->rcv_nxt)
|
|
|
tcp_reset(sk);
|
|
|
else
|
|
|
- tcp_send_challenge_ack(sk);
|
|
|
+ tcp_send_challenge_ack(sk, skb);
|
|
|
goto discard;
|
|
|
}
|
|
|
|
|
@@ -5039,7 +5055,7 @@ syn_challenge:
|
|
|
if (syn_inerr)
|
|
|
TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_INERRS);
|
|
|
NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPSYNCHALLENGE);
|
|
|
- tcp_send_challenge_ack(sk);
|
|
|
+ tcp_send_challenge_ack(sk, skb);
|
|
|
goto discard;
|
|
|
}
|
|
|
|