aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Dumazet <edumazet@google.com>2015-03-22 13:22:22 -0400
committerDavid S. Miller <davem@davemloft.net>2015-03-23 16:52:26 -0400
commit26e3736090e1037ac929787df21c05497479b77f (patch)
tree99e322f42cb097a9f09a1d118cc635e5f4dda193
parentb282705336e03fc7b9377a278939594870a40f96 (diff)
ipv4: tcp: handle ICMP messages on TCP_NEW_SYN_RECV request sockets
tcp_v4_err() can restrict lookups to ehash table, and not to listeners. Note this patch creates the infrastructure, but this means that ICMP messages for request sockets are ignored until complete conversion. New tcp_req_err() helper is exported so that we can use it in IPv6 in following patch. Signed-off-by: Eric Dumazet <edumazet@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/net/tcp.h1
-rw-r--r--net/ipv4/tcp_ipv4.c69
2 files changed, 35 insertions, 35 deletions
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 1876262afd59..fe60e00e1919 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -447,6 +447,7 @@ const u8 *tcp_parse_md5sig_option(const struct tcphdr *th);
447 447
448void tcp_v4_send_check(struct sock *sk, struct sk_buff *skb); 448void tcp_v4_send_check(struct sock *sk, struct sk_buff *skb);
449void tcp_v4_mtu_reduced(struct sock *sk); 449void tcp_v4_mtu_reduced(struct sock *sk);
450void tcp_req_err(struct sock *sk, u32 seq);
450int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb); 451int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb);
451struct sock *tcp_create_openreq_child(struct sock *sk, 452struct sock *tcp_create_openreq_child(struct sock *sk,
452 struct request_sock *req, 453 struct request_sock *req,
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 8028ad5920a4..a57615062b66 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -310,6 +310,34 @@ static void do_redirect(struct sk_buff *skb, struct sock *sk)
310 dst->ops->redirect(dst, sk, skb); 310 dst->ops->redirect(dst, sk, skb);
311} 311}
312 312
313
314/* handle ICMP messages on TCP_NEW_SYN_RECV request sockets */
315void tcp_req_err(struct sock *sk, u32 seq)
316{
317 struct request_sock *req = inet_reqsk(sk);
318 struct net *net = sock_net(sk);
319
320 /* ICMPs are not backlogged, hence we cannot get
321 * an established socket here.
322 */
323 WARN_ON(req->sk);
324
325 if (seq != tcp_rsk(req)->snt_isn) {
326 NET_INC_STATS_BH(net, LINUX_MIB_OUTOFWINDOWICMPS);
327 } else {
328 /*
329 * Still in SYN_RECV, just remove it silently.
330 * There is no good way to pass the error to the newly
331 * created socket, and POSIX does not want network
332 * errors returned from accept().
333 */
334 inet_csk_reqsk_queue_drop(req->rsk_listener, req);
335 NET_INC_STATS_BH(net, LINUX_MIB_LISTENDROPS);
336 }
337 reqsk_put(req);
338}
339EXPORT_SYMBOL(tcp_req_err);
340
313/* 341/*
314 * This routine is called by the ICMP module when it gets some 342 * This routine is called by the ICMP module when it gets some
315 * sort of error condition. If err < 0 then the socket should 343 * sort of error condition. If err < 0 then the socket should
@@ -343,8 +371,9 @@ void tcp_v4_err(struct sk_buff *icmp_skb, u32 info)
343 int err; 371 int err;
344 struct net *net = dev_net(icmp_skb->dev); 372 struct net *net = dev_net(icmp_skb->dev);
345 373
346 sk = inet_lookup(net, &tcp_hashinfo, iph->daddr, th->dest, 374 sk = __inet_lookup_established(net, &tcp_hashinfo, iph->daddr,
347 iph->saddr, th->source, inet_iif(icmp_skb)); 375 th->dest, iph->saddr, ntohs(th->source),
376 inet_iif(icmp_skb));
348 if (!sk) { 377 if (!sk) {
349 ICMP_INC_STATS_BH(net, ICMP_MIB_INERRORS); 378 ICMP_INC_STATS_BH(net, ICMP_MIB_INERRORS);
350 return; 379 return;
@@ -353,6 +382,9 @@ void tcp_v4_err(struct sk_buff *icmp_skb, u32 info)
353 inet_twsk_put(inet_twsk(sk)); 382 inet_twsk_put(inet_twsk(sk));
354 return; 383 return;
355 } 384 }
385 seq = ntohl(th->seq);
386 if (sk->sk_state == TCP_NEW_SYN_RECV)
387 return tcp_req_err(sk, seq);
356 388
357 bh_lock_sock(sk); 389 bh_lock_sock(sk);
358 /* If too many ICMPs get dropped on busy 390 /* If too many ICMPs get dropped on busy
@@ -374,7 +406,6 @@ void tcp_v4_err(struct sk_buff *icmp_skb, u32 info)
374 406
375 icsk = inet_csk(sk); 407 icsk = inet_csk(sk);
376 tp = tcp_sk(sk); 408 tp = tcp_sk(sk);
377 seq = ntohl(th->seq);
378 /* XXX (TFO) - tp->snd_una should be ISN (tcp_create_openreq_child() */ 409 /* XXX (TFO) - tp->snd_una should be ISN (tcp_create_openreq_child() */
379 fastopen = tp->fastopen_rsk; 410 fastopen = tp->fastopen_rsk;
380 snd_una = fastopen ? tcp_rsk(fastopen)->snt_isn : tp->snd_una; 411 snd_una = fastopen ? tcp_rsk(fastopen)->snt_isn : tp->snd_una;
@@ -458,38 +489,6 @@ void tcp_v4_err(struct sk_buff *icmp_skb, u32 info)
458 } 489 }
459 490
460 switch (sk->sk_state) { 491 switch (sk->sk_state) {
461 struct request_sock *req;
462 case TCP_LISTEN:
463 if (sock_owned_by_user(sk))
464 goto out;
465
466 req = inet_csk_search_req(sk, th->dest,
467 iph->daddr, iph->saddr);
468 if (!req)
469 goto out;
470
471 /* ICMPs are not backlogged, hence we cannot get
472 an established socket here.
473 */
474 WARN_ON(req->sk);
475
476 if (seq != tcp_rsk(req)->snt_isn) {
477 NET_INC_STATS_BH(net, LINUX_MIB_OUTOFWINDOWICMPS);
478 reqsk_put(req);
479 goto out;
480 }
481
482 /*
483 * Still in SYN_RECV, just remove it silently.
484 * There is no good way to pass the error to the newly
485 * created socket, and POSIX does not want network
486 * errors returned from accept().
487 */
488 inet_csk_reqsk_queue_drop(sk, req);
489 NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS);
490 reqsk_put(req);
491 goto out;
492
493 case TCP_SYN_SENT: 492 case TCP_SYN_SENT:
494 case TCP_SYN_RECV: 493 case TCP_SYN_RECV:
495 /* Only in fast or simultaneous open. If a fast open socket is 494 /* Only in fast or simultaneous open. If a fast open socket is