mirror of
https://github.com/torvalds/linux.git
synced 2024-11-11 22:51:42 +00:00
tcp: Add tcp_validate_incoming & put duplicated code there
Large block of code duplication removed. Sadly, the return value thing is a bit tricky here but it seems the most sensible way to return positive from validator on success rather than negative. Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@helsinki.fi> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
23edcc4147
commit
cbe2d128a0
@ -4691,6 +4691,67 @@ out:
|
|||||||
}
|
}
|
||||||
#endif /* CONFIG_NET_DMA */
|
#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.
|
* 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 tcphdr *th, unsigned len)
|
||||||
{
|
{
|
||||||
struct tcp_sock *tp = tcp_sk(sk);
|
struct tcp_sock *tp = tcp_sk(sk);
|
||||||
|
int res;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Header prediction.
|
* Header prediction.
|
||||||
@ -4898,52 +4960,13 @@ slow_path:
|
|||||||
if (len < (th->doff << 2) || tcp_checksum_complete_user(sk, skb))
|
if (len < (th->doff << 2) || tcp_checksum_complete_user(sk, skb))
|
||||||
goto csum_error;
|
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.
|
* Standard slow path.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (!tcp_sequence(tp, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq)) {
|
res = tcp_validate_incoming(sk, skb, th, 1);
|
||||||
/* RFC793, page 37: "In all states except SYN-SENT, all reset
|
if (res <= 0)
|
||||||
* (RST) segments are validated by checking their SEQ-fields."
|
return -res;
|
||||||
* 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
step5:
|
step5:
|
||||||
if (th->ack)
|
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 tcp_sock *tp = tcp_sk(sk);
|
||||||
struct inet_connection_sock *icsk = inet_csk(sk);
|
struct inet_connection_sock *icsk = inet_csk(sk);
|
||||||
int queued = 0;
|
int queued = 0;
|
||||||
|
int res;
|
||||||
|
|
||||||
tp->rx_opt.saw_tstamp = 0;
|
tp->rx_opt.saw_tstamp = 0;
|
||||||
|
|
||||||
@ -5277,42 +5301,9 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tcp_fast_parse_options(skb, th, tp) && tp->rx_opt.saw_tstamp &&
|
res = tcp_validate_incoming(sk, skb, th, 0);
|
||||||
tcp_paws_discard(sk, skb)) {
|
if (res <= 0)
|
||||||
if (!th->rst) {
|
return -res;
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* step 5: check the ACK field */
|
/* step 5: check the ACK field */
|
||||||
if (th->ack) {
|
if (th->ack) {
|
||||||
|
Loading…
Reference in New Issue
Block a user