3.5 ICMP不可达报文的处理
来源:互联网 发布:美国最新非农数据分析 编辑:程序博客网 时间:2024/05/17 06:16
在三次握手阶段有两种情况TCP会收到ICMP“目的不可达”报文:
1、client端通过connect系统调用发送SYN请求到server端后,server没有进程在相应的地址或端口处理请求,这时client端会收到ICMP不可达报文
2、client端通过connect系统调用发送SYN请求后崩溃,server端收到SYN后发送SYN|ACK,client端收到SYN|ACK后会给server发送ICMP不可达报文
TCP在收到ICMP目的不可达报文后是如何处理的呢?Linux的TCP在系统启动时会向IP层注册一个数据结构——tcp_protocol:
1552 static const struct net_protocol tcp_protocol = {1553 .early_demux = tcp_v4_early_demux,1554 .handler = tcp_v4_rcv, 1555 .err_handler = tcp_v4_err,1556 .no_policy = 1, 1557 .netns_ok = 1, 1558 };其中,tcp_v4_rcv是TCP协议入口函数,而tcp_v4_err则是ICMP报文在TCP层的处理函数:
326 void tcp_v4_err(struct sk_buff *icmp_skb, u32 info) 327 { 328 const struct iphdr *iph = (const struct iphdr *)icmp_skb->data; 329 struct tcphdr *th = (struct tcphdr *)(icmp_skb->data + (iph->ihl << 2)); 330 struct inet_connection_sock *icsk; 331 struct tcp_sock *tp; 332 struct inet_sock *inet; 333 const int type = icmp_hdr(icmp_skb)->type; 334 const int code = icmp_hdr(icmp_skb)->code;... 348 sk = inet_lookup(net, &tcp_hashinfo, iph->daddr, th->dest, 349 iph->saddr, th->source, inet_iif(icmp_skb));... 377 icsk = inet_csk(sk); 378 tp = tcp_sk(sk); 379 req = tp->fastopen_rsk; 380 seq = ntohl(th->seq);...389 switch (type) {... 399 case ICMP_DEST_UNREACH: 400 if (code > NR_ICMP_UNREACH) 401 goto out; 402 403 if (code == ICMP_FRAG_NEEDED) { /* PMTU discovery (RFC1191) */... 418 goto out; 419 }... 440 skb = tcp_write_queue_head(sk); //获取在队列中的首包 441 BUG_ON(!skb); 442 443 remaining = icsk->icsk_rto - min(icsk->icsk_rto, 444 tcp_time_stamp - TCP_SKB_CB(skb)->when); //计算重传时间 445 446 if (remaining) { 447 inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, 448 remaining, TCP_RTO_MAX); //设置重传定时器,超时后重传首包 449 } else { 450 /* RTO revert clocked out retransmission. 451 * Will retransmit now */ 452 tcp_retransmit_timer(sk); //立即重传首包 453 } 454 455 break;... 471 switch (sk->sk_state) { 472 struct request_sock *req, **prev; 473 case TCP_LISTEN: //情况2会进入这里 474 if (sock_owned_by_user(sk)) 475 goto out; 476 477 req = inet_csk_search_req(sk, &prev, th->dest, //查找request_sock 478 iph->daddr, iph->saddr); 479 if (!req) 480 goto out; 481 482 /* ICMPs are not backlogged, hence we cannot get 483 an established socket here. 484 */ 485 WARN_ON(req->sk); 486 487 if (seq != tcp_rsk(req)->snt_isn) { 488 NET_INC_STATS_BH(net, LINUX_MIB_OUTOFWINDOWICMPS); 489 goto out; 490 } 491 492 /* 493 * Still in SYN_RECV, just remove it silently. 494 * There is no good way to pass the error to the newly 495 * created socket, and POSIX does not want network 496 * errors returned from accept(). 497 */ 498 inet_csk_reqsk_queue_drop(sk, req, prev); //移除request_sock 499 NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS); 500 goto out; 501 502 case TCP_SYN_SENT: //情况1会进入这里 503 case TCP_SYN_RECV: /* Cannot happen. 504 It can f.e. if SYNs crossed, 505 or Fast Open. 506 */ 507 if (!sock_owned_by_user(sk)) { 508 sk->sk_err = err; 509 510 sk->sk_error_report(sk); //调用sock_def_error_report唤醒在connect系统调用中睡眠的进程 511 512 tcp_done(sk); //释放TCP连接相关的一些资源,比如定时器 513 } else { 514 sk->sk_err_soft = err; 515 } 516 goto out; 517 }... 542 543 out: 544 bh_unlock_sock(sk); 545 sock_put(sk); 546 }403:这种情况是需要分片导致的ICMP报文,这与路径MTU有关,通常不会出现在三次握手过程中。关于路径MTU会在后续章节中讨论
507:如果socket没有被进程访问,则唤醒在connect系统调用中睡眠的进程,并设置TCP状态机为TCP_CLOSE,释放一些资源
514:情况1和情况2都不会走到这里
可见,tcp_v4_err函数能够在ICMP不可达报文到达后即时的设置TCP的状态机,释放一些资源,并唤醒睡眠的进程,从而使TCP的连接资源能够及时的回收。
0 0
- 3.5 ICMP不可达报文的处理
- ICMP报文分析:端口不可达
- ICMP报文的类型
- Nat 对 tcp , udp , icmp 报文的处理
- UNIX网络编程——ICMP报文分析:端口不可达
- ICMP报文的类型说明
- 关于ICMP报文的问题
- ICMP报文
- ICMP报文
- ICMP报文
- ICMP报文
- ICMP报文
- ICMP/ICMP报文分析
- 1205 对icmp报文的构造
- ICMP报文的格式和种类
- ICMP报文的格式和种类
- (Others)ICMP报文的实现
- Ping的整个过程。ICMP报文是什么
- poj 1959 Darts 允许重复组合
- const 详解
- SDL Event Handling 事件处理
- 冒泡排序
- 何新生—你是哪国人?
- 3.5 ICMP不可达报文的处理
- 什么是angular js指令
- [Leetcode]Merge k Sorted Lists
- 选项卡的制作和注意要点
- 省市县级联,使用ajax,并且使用ul模拟select下拉
- 猫猫学IOS(二)UI之按钮操作 点击变换 移动 放大缩小 旋转
- sgu 113 Nearly prime numbers
- 数学·包含学科的标准代码.
- 第一个javaServelt程序