forked from mirrors/linux
		
	tcp/dccp: fix behavior of stale SYN_RECV request sockets
When a TCP/DCCP listener is closed, its pending SYN_RECV request sockets
become stale, meaning 3WHS can not complete.
But current behavior is wrong :
incoming packets finding such stale sockets are dropped.
We need instead to cleanup the request socket and perform another
lookup :
- Incoming ACK will give a RST answer,
- SYN rtx might find another listener if available.
- We expedite cleanup of request sockets and old listener socket.
Fixes: 079096f103 ("tcp/dccp: install syn_recv requests into ehash table")
Signed-off-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
			
			
This commit is contained in:
		
							parent
							
								
									bbb300eb97
								
							
						
					
					
						commit
						4bdc3d6614
					
				
					 4 changed files with 26 additions and 18 deletions
				
			
		| 
						 | 
				
			
			@ -799,15 +799,10 @@ static int dccp_v4_rcv(struct sk_buff *skb)
 | 
			
		|||
				  DCCP_SKB_CB(skb)->dccpd_ack_seq);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Step 2:
 | 
			
		||||
	 *	Look up flow ID in table and get corresponding socket */
 | 
			
		||||
lookup:
 | 
			
		||||
	sk = __inet_lookup_skb(&dccp_hashinfo, skb,
 | 
			
		||||
			       dh->dccph_sport, dh->dccph_dport);
 | 
			
		||||
	/*
 | 
			
		||||
	 * Step 2:
 | 
			
		||||
	 *	If no socket ...
 | 
			
		||||
	 */
 | 
			
		||||
	if (sk == NULL) {
 | 
			
		||||
	if (!sk) {
 | 
			
		||||
		dccp_pr_debug("failed to look up flow ID in table and "
 | 
			
		||||
			      "get corresponding socket\n");
 | 
			
		||||
		goto no_dccp_socket;
 | 
			
		||||
| 
						 | 
				
			
			@ -830,8 +825,12 @@ static int dccp_v4_rcv(struct sk_buff *skb)
 | 
			
		|||
		struct sock *nsk = NULL;
 | 
			
		||||
 | 
			
		||||
		sk = req->rsk_listener;
 | 
			
		||||
		if (sk->sk_state == DCCP_LISTEN)
 | 
			
		||||
		if (likely(sk->sk_state == DCCP_LISTEN)) {
 | 
			
		||||
			nsk = dccp_check_req(sk, skb, req);
 | 
			
		||||
		} else {
 | 
			
		||||
			inet_csk_reqsk_queue_drop(sk, req);
 | 
			
		||||
			goto lookup;
 | 
			
		||||
		}
 | 
			
		||||
		if (!nsk) {
 | 
			
		||||
			reqsk_put(req);
 | 
			
		||||
			goto discard_it;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -656,16 +656,11 @@ static int dccp_v6_rcv(struct sk_buff *skb)
 | 
			
		|||
	else
 | 
			
		||||
		DCCP_SKB_CB(skb)->dccpd_ack_seq = dccp_hdr_ack_seq(skb);
 | 
			
		||||
 | 
			
		||||
	/* Step 2:
 | 
			
		||||
	 *	Look up flow ID in table and get corresponding socket */
 | 
			
		||||
lookup:
 | 
			
		||||
	sk = __inet6_lookup_skb(&dccp_hashinfo, skb,
 | 
			
		||||
			        dh->dccph_sport, dh->dccph_dport,
 | 
			
		||||
				inet6_iif(skb));
 | 
			
		||||
	/*
 | 
			
		||||
	 * Step 2:
 | 
			
		||||
	 *	If no socket ...
 | 
			
		||||
	 */
 | 
			
		||||
	if (sk == NULL) {
 | 
			
		||||
	if (!sk) {
 | 
			
		||||
		dccp_pr_debug("failed to look up flow ID in table and "
 | 
			
		||||
			      "get corresponding socket\n");
 | 
			
		||||
		goto no_dccp_socket;
 | 
			
		||||
| 
						 | 
				
			
			@ -688,8 +683,12 @@ static int dccp_v6_rcv(struct sk_buff *skb)
 | 
			
		|||
		struct sock *nsk = NULL;
 | 
			
		||||
 | 
			
		||||
		sk = req->rsk_listener;
 | 
			
		||||
		if (sk->sk_state == DCCP_LISTEN)
 | 
			
		||||
		if (likely(sk->sk_state == DCCP_LISTEN)) {
 | 
			
		||||
			nsk = dccp_check_req(sk, skb, req);
 | 
			
		||||
		} else {
 | 
			
		||||
			inet_csk_reqsk_queue_drop(sk, req);
 | 
			
		||||
			goto lookup;
 | 
			
		||||
		}
 | 
			
		||||
		if (!nsk) {
 | 
			
		||||
			reqsk_put(req);
 | 
			
		||||
			goto discard_it;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1572,6 +1572,7 @@ int tcp_v4_rcv(struct sk_buff *skb)
 | 
			
		|||
	TCP_SKB_CB(skb)->ip_dsfield = ipv4_get_dsfield(iph);
 | 
			
		||||
	TCP_SKB_CB(skb)->sacked	 = 0;
 | 
			
		||||
 | 
			
		||||
lookup:
 | 
			
		||||
	sk = __inet_lookup_skb(&tcp_hashinfo, skb, th->source, th->dest);
 | 
			
		||||
	if (!sk)
 | 
			
		||||
		goto no_tcp_socket;
 | 
			
		||||
| 
						 | 
				
			
			@ -1587,8 +1588,12 @@ int tcp_v4_rcv(struct sk_buff *skb)
 | 
			
		|||
		sk = req->rsk_listener;
 | 
			
		||||
		if (tcp_v4_inbound_md5_hash(sk, skb))
 | 
			
		||||
			goto discard_and_relse;
 | 
			
		||||
		if (sk->sk_state == TCP_LISTEN)
 | 
			
		||||
		if (likely(sk->sk_state == TCP_LISTEN)) {
 | 
			
		||||
			nsk = tcp_check_req(sk, skb, req, false);
 | 
			
		||||
		} else {
 | 
			
		||||
			inet_csk_reqsk_queue_drop(sk, req);
 | 
			
		||||
			goto lookup;
 | 
			
		||||
		}
 | 
			
		||||
		if (!nsk) {
 | 
			
		||||
			reqsk_put(req);
 | 
			
		||||
			goto discard_it;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1363,6 +1363,7 @@ static int tcp_v6_rcv(struct sk_buff *skb)
 | 
			
		|||
	th = tcp_hdr(skb);
 | 
			
		||||
	hdr = ipv6_hdr(skb);
 | 
			
		||||
 | 
			
		||||
lookup:
 | 
			
		||||
	sk = __inet6_lookup_skb(&tcp_hashinfo, skb, th->source, th->dest,
 | 
			
		||||
				inet6_iif(skb));
 | 
			
		||||
	if (!sk)
 | 
			
		||||
| 
						 | 
				
			
			@ -1382,8 +1383,12 @@ static int tcp_v6_rcv(struct sk_buff *skb)
 | 
			
		|||
			reqsk_put(req);
 | 
			
		||||
			goto discard_it;
 | 
			
		||||
		}
 | 
			
		||||
		if (sk->sk_state == TCP_LISTEN)
 | 
			
		||||
		if (likely(sk->sk_state == TCP_LISTEN)) {
 | 
			
		||||
			nsk = tcp_check_req(sk, skb, req, false);
 | 
			
		||||
		} else {
 | 
			
		||||
			inet_csk_reqsk_queue_drop(sk, req);
 | 
			
		||||
			goto lookup;
 | 
			
		||||
		}
 | 
			
		||||
		if (!nsk) {
 | 
			
		||||
			reqsk_put(req);
 | 
			
		||||
			goto discard_it;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue