iph->check = 0; iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl); size = ntohs( nskb->nh.iph->tot_len ) - ( nskb->nh.iph->ihl * 4 ); nskb->csum = 0; nskb->csum = csum_partial( nskb->h.raw + doff, size - doff, 0 ); th->check = tcp_v4_check(t...
/* tcp_v4_check累加伪首部,获取最终的校验和。 * csum_partial累加TCP报头。 * 那么skb->csum应该是TCP数据部分的累加,这是在从用户空间复制时顺便累加的。 */ th->check = tcp_v4_check(th, len, inet->saddr, inet->daddr, csum_partial((char *)th, th->doff << 2, skb->csum)); } } u...
首先会到 tcp_v4_hnd_req 去查看半连接队列。服务器第一次响应 SYN 的时候,半连接队列里必然是空空...
goto out;//根据监听套接字、连接请求块和路由构造SYN+ACK数据包skb =tcp_make_synack(sk, dst, req);if(skb) {structtcphdr*th =tcp_hdr(skb);//计算TCP校验和th->check =tcp_v4_check(skb->len, ireq->loc_addr, ireq->rmt_addr,csum_partial((char*)th, skb->len, skb->csum));//构造I...
tcp_tw_reuse设置的是内核变量sysctl_tcp_tw_reuse,这个变量位于_tcp_v4_check_established函数中,有且仅有一条调用路径tcp_v4_hash_connect—>__tcp_v4_check_established。从下图注释可以看出tcp_v4_hash_connect方法是在Socket客户端发起连接时调用,所以tcp_tw_reuse参数只能在Socket客户端主动建立TCP连接时生效。
void tcpv4_check_addr( __u16 * ppkgdata ) { char * indata; __u16 ippktlen, udppktlen,tcppktlen,wd; __u32 ipheadlen; __u32 sum,i,pl,el; struct psd_head psd; struct iphdr * ipd; struct tcphdr * tcpd; struct udphdr * udpd; ...
不过由于这已经是第三次握手了,半连接队列里会存在上次第一次握手时留下的半连接信息。所以 tcp_v4_hnd_req 的执行逻辑会不太一样。 inet_csk_search_req 负责在半连接队列里进行查找,找到以后返回一个半连接 request_sock 对象。然后进入到 tcp_check_req 中。
.send_check = tcp_v4_send_check, .rebuild_header = inet_sk_rebuild_header, .sk_rx_dst_set = inet_sk_rx_dst_set, .conn_request = tcp_v4_conn_request, .syn_recv_sock = tcp_v4_syn_recv_sock, .net_header_len =sizeof(structiphdr), ...
乱序的fin包根本没有进入tcp_rcv_state_process()函数,而是被外层的tcp_v4_rcv()函数按照TIMEWAIT流程直接处理,最终关闭连接。 显然,第二点很可能是导致复现失败的关键。 更加证明了我们先前的假设,如果fin能进入tcp_rcv_state_process()函数,应该就能复现出问题。但可能因为线上场景与复现场景存在某些配置差异,导致...
乱序的fin包根本没有进入tcp_rcv_state_process()函数,而是被外层的tcp_v4_rcv()函数按照TIMEWAIT流程直接处理,最终关闭连接。 显然,第二点很可能是导致复现失败的关键。 更加证明了我们先前的假设,如果fin能进入tcp_rcv_state_process()函数,应该就能复现出问题。但可能因为线上场景与复现场景存在某些配置差异,导致...