在三次握手阶段有两种情况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_conn