Skip to content

Commit 0a8de36

Browse files
edumazetdavem330
authored andcommitted
tcp: no longer abort SYN_SENT when receiving some ICMP
Currently, non fatal ICMP messages received on behalf of SYN_SENT sockets do call tcp_ld_RTO_revert() to implement RFC 6069, but immediately call tcp_done(), thus aborting the connect() attempt. This violates RFC 1122 following requirement: 4.2.3.9 ICMP Messages ... o Destination Unreachable -- codes 0, 1, 5 Since these Unreachable messages indicate soft error conditions, TCP MUST NOT abort the connection, and it SHOULD make the information available to the application. This patch makes sure non 'fatal' ICMP[v6] messages do not abort the connection attempt. It enables RFC 6069 for SYN_SENT sockets as a result. Signed-off-by: Eric Dumazet <edumazet@google.com> Cc: David Morley <morleyd@google.com> Cc: Neal Cardwell <ncardwell@google.com> Cc: Yuchung Cheng <ycheng@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 14dd92d commit 0a8de36

File tree

2 files changed

+12
-3
lines changed

2 files changed

+12
-3
lines changed

net/ipv4/tcp_ipv4.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -482,6 +482,7 @@ int tcp_v4_err(struct sk_buff *skb, u32 info)
482482
const int code = icmp_hdr(skb)->code;
483483
struct sock *sk;
484484
struct request_sock *fastopen;
485+
bool harderr = false;
485486
u32 seq, snd_una;
486487
int err;
487488
struct net *net = dev_net(skb->dev);
@@ -555,6 +556,7 @@ int tcp_v4_err(struct sk_buff *skb, u32 info)
555556
goto out;
556557
case ICMP_PARAMETERPROB:
557558
err = EPROTO;
559+
harderr = true;
558560
break;
559561
case ICMP_DEST_UNREACH:
560562
if (code > NR_ICMP_UNREACH)
@@ -579,6 +581,7 @@ int tcp_v4_err(struct sk_buff *skb, u32 info)
579581
}
580582

581583
err = icmp_err_convert[code].errno;
584+
harderr = icmp_err_convert[code].fatal;
582585
/* check if this ICMP message allows revert of backoff.
583586
* (see RFC 6069)
584587
*/
@@ -604,6 +607,9 @@ int tcp_v4_err(struct sk_buff *skb, u32 info)
604607

605608
ip_icmp_error(sk, skb, err, th->dest, info, (u8 *)th);
606609

610+
if (!harderr)
611+
break;
612+
607613
if (!sock_owned_by_user(sk)) {
608614
WRITE_ONCE(sk->sk_err, err);
609615

net/ipv6/tcp_ipv6.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -381,7 +381,7 @@ static int tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
381381
struct tcp_sock *tp;
382382
__u32 seq, snd_una;
383383
struct sock *sk;
384-
bool fatal;
384+
bool harderr;
385385
int err;
386386

387387
sk = __inet6_lookup_established(net, net->ipv4.tcp_death_row.hashinfo,
@@ -402,9 +402,9 @@ static int tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
402402
return 0;
403403
}
404404
seq = ntohl(th->seq);
405-
fatal = icmpv6_err_convert(type, code, &err);
405+
harderr = icmpv6_err_convert(type, code, &err);
406406
if (sk->sk_state == TCP_NEW_SYN_RECV) {
407-
tcp_req_err(sk, seq, fatal);
407+
tcp_req_err(sk, seq, harderr);
408408
return 0;
409409
}
410410

@@ -489,6 +489,9 @@ static int tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
489489

490490
ipv6_icmp_error(sk, skb, err, th->dest, ntohl(info), (u8 *)th);
491491

492+
if (!harderr)
493+
break;
494+
492495
if (!sock_owned_by_user(sk)) {
493496
WRITE_ONCE(sk->sk_err, err);
494497
sk_error_report(sk); /* Wake people up to see the error (see connect in sock.c) */

0 commit comments

Comments
 (0)