zoukankan      html  css  js  c++  java
  • TCP连接建立系列 — 服务端接收ACK段(一)

     
    http://blog.csdn.net/zhangskd/article/details/17923917
    分类: Linux TCP/IP Linux Kernel

    目录(?)[+]

    本文主要分析:三次握手中最后一个ACK段到达时,服务器端的处理路径。

    内核版本:3.6

    Author:zhangskd @ csdn blog

    函数路径

    以下是第三次握手时,服务端接收到ACK后的处理路径。

    接收入口

    1. 状态为ESTABLISHED时,用tcp_rcv_established()接收处理。

    2. 状态为LISTEN时,说明这个sock处于监听状态,用于被动打开的接收处理,包括SYN和ACK。

    3. 当状态不为ESTABLISHED或TIME_WAIT时,用tcp_rcv_state_process()处理。

    1. int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb)  
    2. {  
    3.     struct sock *rsk;  
    4.   
    5. #ifdef CONFIG_TCP_MD5SIG  
    6.     /* We really want to reject the packet as early as possible if : 
    7.      * We're expecting an MD5'd packet and this is no MD5 tcp option. 
    8.      * There is an MD5 option and we're not expecting one. 
    9.      */  
    10.     if (tcp_v4_inbound_md5_hash(sk, skb))  
    11.         goto discard;  
    12. #endif  
    13.   
    14.     /* 当状态为ESTABLISHED时,用tcp_rcv_established()接收处理 */  
    15.     if (sk->sk_state == TCP_ESTABLISHED) { /* Fast path */  
    16.         struct dst_entry *dst = sk->sk_rx_dst;  
    17.         sock_rps_save_rxhash(sk, skb);  
    18.   
    19.         if (dst) {  
    20.             if (inet_sk(sk)->rx_dst_ifindex != skb->skb_iif || dst->ops->check(dst, 0) == NULL) {  
    21.                 dst_release(dst);  
    22.                 sk->sk_rx_dst = NULL;  
    23.             }  
    24.         }  
    25.    
    26.         /* 连接已建立时的处理路径 */  
    27.         if (tcp_rcv_established(sk, skb, tcp_hdr(skb), skb->len)) {  
    28.             rsk = sk;  
    29.             goto reset;  
    30.         }  
    31.         return 0;  
    32.     }  
    33.   
    34.     /* 检查报文长度、报文校验和 */  
    35.     if (skb->len < tcp_hdrlen(skb) || tcp_checksum_complete(skb))  
    36.         goto csum_err;  
    37.   
    38.     /* 如果这个sock处于监听状态,被动打开时的处理,包括收到SYN或ACK */  
    39.     if (sk->sk_state == TCP_LISTEN) {  
    40.         /* 返回值: 
    41.          * NULL,错误 
    42.          * nsk == sk,接收到SYN 
    43.          * nsk != sk,接收到ACK 
    44.          */  
    45.         struct sock *nsk = tcp_v4_hnd_req(sk, skb); /* 接收ACK的处理 */  
    46.   
    47.         if (! nsk)  
    48.             goto discard;  
    49.   
    50.         if (nsk != sk) { /* 接收到ACK时 */  
    51.             sock_rps_save_rxhash(nsk, skb);  
    52.   
    53.             if (tcp_child_process(sk, nsk, skb)) { /* 处理新的sock */  
    54.                 rsk = nsk;  
    55.                 goto reset;  
    56.             }  
    57.             return 0;  
    58.         }  
    59.     } else  
    60.         sock_rps_save_rx(sk, skb);  
    61.   
    62.     /* 处理除了ESTABLISHED和TIME_WAIT之外的所有状态 */  
    63.     if (tcp_rcv_state_process(sk, skb, tcp_hdr(skb), skb->len)) {  
    64.         rsk = sk;  
    65.         goto reset;  
    66.     }  
    67.     return 0;  
    68.   
    69. reset:  
    70.     tcp_v4_send_reset(rsk, skb); /* 发送RST包 */  
    71.   
    72. discard:  
    73.     kfree_skb(skb);  
    74.     return 0;  
    75.   
    76. csum_err:  
    77.     TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_INERRS);  
    78.     goto discard;  
    79. }  

    收到SYN段后,服务器端会分配一个连接请求块,并初始化这个连接请求块。

    构造和发送SYNACK段。

    然后把这个连接请求块链入半连接队列中,启动超时定时器。

    之后如果再收到ACK,就能完成三次握手了。

    1. static struct sock *tcp_v4_hnd_req(struct sock *sk, struct sk_buff *skb)  
    2. {  
    3.     struct tcphdr *th = tcp_hdr(skb);  
    4.     const struct iphdr *iph = ip_hdr(skb);  
    5.     struct sock *nsk;  
    6.     struct request_sock **prev;  
    7.   
    8.     /* 在半连接队列中查找是否已有符合的连接请求块,如果有,则说明这是三次握手的最后一个ACK。*/  
    9.     struct request_sock *req = inet_csk_search_req(sk, &prev, th->source, iph->saddr, iph->daddr);  
    10.     if (req)  
    11.         return tcp_check_req(sk, skb, req, prev); /* 服务器端处理三次握手的最后一个ACK */  
    12.   
    13.     /* 如果在半连接队列中没找到,则在ESTABLISHED状态的哈希表中查找。*/  
    14.     nsk = inet_lookup_established(sock_net(sk), &tcp_hashinfo, iph->saddr, th->source,  
    15.               iph->daddr, th->dest, inet_iif(skb));  
    16.   
    17.     if (nsk) { /* 如果在ehash表中找到对应的sock,且不处于TIME_WAIT状态 */  
    18.         if (nsk->sk_state != TCP_TIME_WAIT) {  
    19.             bh_lock_sock(nsk);  
    20.             return nsk;  
    21.         }  
    22.   
    23.         inet_twsk_put(inet_twsk(nsk)); /* 释放tw结构体 */  
    24.         return NULL;  
    25.     }  
    26.   
    27. #ifdef CONFIG_SYN_COOKIES  
    28.     /* 如果使用SYN Cookie,则检查cookie是否合法,合法则直接完成三次握手 */  
    29.     if (! th->syn)   
    30.         sk = cookie_v4_check(sk, skb, &(IPCB(skb)->opt));  
    31. #endif  
    32.   
    33.     return sk;  
    34. }  

    在表示半连接队列的哈希表中,寻找符合条件的连接请求块。

    1. struct request_sock *inet_csk_search_req(const struct sock *sk, struct request_sock ***prevp,  
    2.                 const __be16 rport, const __be32 raddr, const __be32 laddr)  
    3. {  
    4.     const struct inet_connection_sock *icsk = inet_csk(sk);  
    5.     struct listen_sock *lopt = icsk->icsk_accept_queue.listen_opt; /* 半连接队列 */  
    6.     struct request_sock *req, **prev;  
    7.   
    8.     /* 通过哈希值,找到哈希桶,然后遍历哈希桶寻找符合条件的连接请求块 */  
    9.     for(prev = &lopt->syn_table[inet_synq_hash(raddr, rport, lopt->hash_rnd, lopt->nr_table_entries)];  
    10.         (req = *prev) != NULL; prev = &req->dl_next) {  
    11.         const struct inet_request_sock *ireq = inet_rsk(req);  
    12.   
    13.         if (ireq->rmt_port == rport && ireq->rmt_addr == raddr && ireq->loc_addr = laddr  
    14.             && AF_INET_FAMILY(req->rsk_ops->family)) {  
    15.             WARN_ON(req->sk); /* 连接尚未建立,sk应该为NULL */  
    16.             *prevp = prev; /* 保存此req指针的指针 */  
    17.             break;  
    18.         }  
    19.     }  
    20.   
    21.     return req;  
    22. }  

    第三次握手

    inet_csk_search_req()在半连接队列中查找是否已有符合的连接请求块,如果有,则说明这可能是三次握手的最后一个ACK。

    接着调用tcp_check_req()来进行验证,如果合法,则完成三次握手。

    1. /* Process an incoming packet for SYN_RECV sockets represented as a request_sock. */  
    2. struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb, struct request_sock *req,  
    3.     struct request_sock **prev)  
    4. {  
    5.     struct tcp_options_received tmp_opt;  
    6.     const u8 *hash_location;  
    7.     struct sock *child;  
    8.     const struct tcphdr *th = tcp_hdr(skb);  
    9.     __be32 flg = tcp_flag_word(th) & (TCP_FLAG_RST | TCP_FLAG_SYN | TCP_FLAG_ACK);  
    10.     bool paws_reject = false;  
    11.   
    12.     tmp_opt.saw_tstamp = 0;  
    13.   
    14.     /* 如果此ACK带有选项 */  
    15.     if (th->doff > (sizeof(struct tcphdr) >> 2)) {  
    16.         tcp_parse_options(skb, &tmp_opt, &hash_location, 0, NULL); /* 解析TCP选项,保存到实例中 */  
    17.         if (tmp_opt.saw_tstamp) {  
    18.             tmp_opt.ts_recent = req->ts_recent; /* 客户端发送SYN段的时间 */  
    19.   
    20.             /* We do not store true stamp, but it is not required, 
    21.              * it can be estimated (approximately) from another data. 
    22.              */  
    23.             tmp_opt.ts_recent_stamp = get_seconds() - ((TCP_TIMEOUT_INIT/HZ) << req->retrans);  
    24.             paws_reject = tcp_paws_reject(&tmp_opt, th->rst); /* 检查客户端时间戳是否回绕 */  
    25.         }  
    26.     }  
    27.   
    28.     /* Check for pure retransmitted SYN. 处理重传的SYN */  
    29.     if (TCP_SKB_CB(skb)->seq == tcp_rsk(req)->rcv_isn && flg == TCP_FLAG_SYN  
    30.         && ! paws_reject) {  
    31.         /* 重新发送SYNACK。 
    32.          * 实例为tcp_request_sock_ops,调用tcp_v4_rtx_synack() 
    33.          */  
    34.         req->rsk_ops->rtx_syn_ack(sk, req, NULL);  
    35.         return NULL;  
    36.     }  
    37.    
    38.   
    39.     /* 如果接收段包含ACK标志,但确认序号不对,则返回监听sock。 
    40.      * 然后在tcp_v4_do_rcv()中发送RST段。 
    41.      */  
    42.     if ((flg & TCP_FLAG_ACK) && (TCP_SKB_CB(skb)->ack_seq !=   
    43.          tcp_rsk(req)->snt_isn + 1 + tcp_s_data_size(tcp_sk(sk))))  
    44.         return sk;  
    45.   
    46.     /* 如果发生了回绕,或者接收序号不在接收窗口内 */  
    47.     if (paws_reject || ! tcp_in_window(TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq,  
    48.           tcp_rsk(req)->rcv_isn + 1, tcp_rsk(req)->rcv_isn + 1 + req->rcv_wnd)) {  
    49.         /* Out of window: send ACK and drop. */  
    50.         if (! (flg & TCP_FLAG_RST))  
    51.             /* 发送ACK段。 
    52.              * 实例为tcp_request_sock_ops,调用tcp_v4_reqsk_send_ack() 
    53.              */  
    54.             req->rsk_ops->send_ack(sk, skb, req);  
    55.   
    56.         if (paws_reject)  
    57.             NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_PAWSESTABREJECTED);  
    58.   
    59.         return NULL;  
    60.     }  
    61.   
    62.     /* In sequence, PAWS is ok. */  
    63.     if (tmp_opt.saw_tstamp && ! after(TCP_SKB_CB(skb)->seq, tcp_rsk(req)->rcv_isn + 1))  
    64.         req->ts_recent = tmp_opt.rcv_tsval; /* 保存ACK段的时间戳 */  
    65.   
    66.     if (TCP_SKB_CB(skb)->seq == tcp_rsk(req)->rcv_isn) {  
    67.         /* Truncate SYN, it is out of window starting at tcp_rsk(req)->rcv_isn + 1 */  
    68.         flg &= ~TCP_FLAG_SYN;  
    69.     }  
    70.   
    71.     if (flg & (TCP_FLAG_RST | TCP_FLAG_SYN)) {  
    72.         TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_ATTEMPTFAILS);  
    73.         goto embryonic_reset;  
    74.     }  
    75.   
    76.     /* ACK sequence verified above, just make sure ACK is set. 
    77.      * If ACK not set, just silently drop the packet. 
    78.      */  
    79.     if (! (flg & TCP_FLAG_ACK))  
    80.         return NULL;  
    81.   
    82.     /* 如果设置了TCP_DEFER_ACCEPT选项,则不接收纯ACK,等待有负荷的数据包到达后, 
    83.      * 再建立连接。直接丢弃纯ACK。 
    84.      */  
    85.     if (req->retrans < inet_csk(sk)->icsk_accept_queue.rskq_defer_accept &&  
    86.         TCP_SKB_CB(skb)->end_seq == tcp_rsk(req)->rcv_isn + 1) {  
    87.         inet_rsk(req)->acked = 1;  
    88.         NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPDEFERACCEPTDROP);  
    89.         return NULL;  
    90.     }  
    91.   
    92.     if (tmp_opt.saw_tstamp && tmp_opt.rcv_tsecr)  
    93.         tcp_rsk(req)->snt_synack = tmp_opt.rcv_tsecr;  
    94.     else if (req->retrans) /* don't take RTT sample if retrans && ~TS */  
    95.         tcp_rsk(req)->snt_synack = 0;  
    96.   
    97.     /* OK, ACK is valid, create big socket and feed this segment to it. 
    98.      * This segment must move socket to established state. If it will be dropped 
    99.      * after socket is created, wait for troubles. 
    100.      */  
    101.     /*  三次握手完成以后,调用tcp_v4_syn_recv_sock()创建和初始化一个新的传输控制块 */  
    102.     child = inet_csk(sk)->icsk_af_ops->syn_recv_sock(sk, skb, req, NULL);  
    103.   
    104.     if (child == NULL)  
    105.         goto listen_overflow;  
    106.   
    107.     inet_csk_reqsk_queue_unlink(sk, req, prev); /* 把连接请求块从半连接队列中删除 */  
    108.     inet_csk_reqsk_queue_removed(sk, req); /* 更新半连接队列的长度,如果为0,则删除定时器 */  
    109.   
    110.     /* 把完成三次握手的连接请求块,和新的sock关联起来,并把它移入全连接队列中 */  
    111.     inet_csk_reqsk_queue_add(sk, req, child);  
    112.   
    113.     return child;  
    114.   
    115. listen_overflow:  
    116.     /* tcp_abort_on_overflow表示全连接队列满了,是给客户端发RST段,还是默默丢弃 */  
    117.     if (! sysctl_tcp_abort_on_overflow) {  
    118.         inet_rsk(req)->acked = 1;  
    119.         return NULL;  
    120.     }  
    121.   
    122. embryonic_reset:  
    123.     NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_EMBRYONICRSTS);  
    124.     if (! (flg & TCP_FLAG_RST))  
    125.         /* 实例为tcp_request_sock_ops,调用tcp_v4_send_reset()。*/  
    126.         req->rsk_ops->send_reset(sk, skb);  
    127.   
    128.     /* 把连接请求块从半连接队列中删除,更新半连接队列 */  
    129.     inet_csk_reqsk_queue_drop(sk, req, prev);  
    130.   
    131.     return NULL;  
    132. }   

    是否发生了回绕。

    1. static inline bool tcp_paws_reject(const struct tcp_options_received *rx_opt, int rst)  
    2. {  
    3.     if (tcp_paws_check(rx_opt, 0))  
    4.         return false;  
    5.   
    6.     /* ACK段包含RST标志 */  
    7.     if (rst && get_seconds() >= rx_opt->ts_recent_stamp + TCP_PAWS_MSL)  
    8.         return false;  
    9.   
    10.     return true;  
    11. }  

    检查客户端的时间戳是否合法。

    要求客户端发送SYN的时间戳 <= 客户端重传SYN的时间戳 、客户端发送ACK的时间戳。

    1. static inline bool tcp_paws_check(const struct tcp_options_received *rx_opt, int paws_win)  
    2. {  
    3.     if ((s32) (rx_opt->ts_recent - rx_opt->rcv_tsval) <= paws_win)  
    4.         return true;  
    5.   
    6.     /* 重传时间超过24天?*/  
    7.     if (unlikely(get_seconds() >= rx_opt->ts_recent_stamp + TCP_PAWS_24DAYS))  
    8.         return true;  
    9.   
    10.     /* Some OSes send SYN and SYNACK messages with tsval = 0 tsecr = 0, 
    11.      * then following tcp messages have valid values. Ignore 0 value, or else 'negative' 
    12.      * tsval might forbid us to accept their packets. 
    13.      */  
    14.     if (! rx_opt->ts_recent)  
    15.         return true;  
    16. }  

    检查序号是否合法。

    1. /* @seq:接收段的序号。 
    2.  * @end_seq:接收段的结束序号。 
    3.  * @s_win:接收窗口的起始序号。 
    4.  * @e_win:接收窗口的结束序号。 
    5.  */  
    6. static bool tcp_in_window(u32 seq, u32 end_seq, u32 s_win, u32 e_win)  
    7. {  
    8.     if (seq == s_win)  
    9.         return true;  
    10.   
    11.     if (after(end_seq, s_win) && before(seq, e_win))  
    12.         return true;  
    13.   
    14.     return seq == e_win && seq == end_seq;  
    15. }  

    连接请求块操作

    request_sock_ops为处理连接请求块的函数指针表,对于TCP,它的实例为tcp_request_sock_ops。

    1. struct request_sock_ops tcp_request_sock_ops __read_mostly = {  
    2.     .family = PF_INET,  
    3.     .obj_size = sizeof(struct tcp_request_sock),  
    4.     .rtx_syn_ack = tcp_v4_rtx_synack, /* 重传SYNACK段 */  
    5.     .send_ack = tcp_v4_reqsk_send_ack, /* 发送ACK段 */  
    6.     .destructor = tcp_v4_reqsk_destructor,  
    7.     .send_reset = tcp_v4_send_reset, /* 发送RST段 */  
    8.     .syn_ack_timeout = tcp_syn_ack_timeout, /* SYNACK段超时处理 */  
    9. };  

    (1) 重传SYNACK段

    1. static int tcp_v4_rtx_synack(struct sock *sk, struct request_sock *req, struct request_values *rvp)  
    2. {  
    3.     TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_RETRANSSEGS);  
    4.     return tcp_v4_send_synack(sk, NULL, req, rvp, 0, false);  
    5. }  

    我们在上一篇中已分析过tcp_v4_send_synack(),它主要用于构造和发送SYNACK段。

    (2) 发送ACK段 

    在tcp_check_req()中,如果接收到的ACK段时间戳不合法、或者序号不在接收窗口内,且不含RST标志,

    则需要给客户端发送一个ACK。

    1. static void tcp_v4_reqsk_send_ack(struct sock *sk, struct sk_buff *skb, struct request_sock *req)  
    2. {  
    3.     tcp_v4_send_ack(skb, tcp_rsk(req)->snt_isn + 1, tcp_rsk(req)->rcv_isn + 1,  
    4.         req->rcv_wnd, req->ts_recent, 0,   
    5.         tcp_md5_do_lookup(sk, (union tcp_md5_addr *) &ip_hdr(skb)->daddr, AF_INET),  
    6.         inet_rsk(req)->no_srccheck ? IP_REPLY_ARG_NOSRCCHECK : 0, ip_hdr(skb)->tos);  
    7. }  
    1. static void tcp_v4_send_ack(struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 ts, int oif,  
    2.     struct tcp_md5sig_key *key, int reply_flags, u8 tos)  
    3. {  
    4.     const struct tcphdr *th = tcp_hdr(skb);  
    5.     struct {  
    6.         struct tcphdr th;  
    7.         __be32 opt[(TCPOLEN_TSTAMP_ALIGNED >> 2)  
    8. #ifdef CONFIG_TCP_MD5SIG  
    9.             + (TCPOLEN_MD5SIG_ALIGNED >> 2)  
    10. #endif  
    11.             ];  
    12.     } rep;  
    13.   
    14.     struct ip_reply_arg arg;  
    15.     struct net *net = dev_net(skb_dst(skb)->dev);  
    16.     memset(&rep.th, 0, sizeof(struct tcphdr));  
    17.     memset(&arg, 0, sizeof(arg));  
    18.   
    19.     arg.iov[0].iov_base = (unsigned char *) &rep;  
    20.     arg.iov[0].iov_len = sizeof(rep.th);  
    21.   
    22.     if (ts) { /* 时间戳 */  
    23.         rep.opt[0] = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) | (TCPOPT_TIMESTAMP << 8) |  
    24.                            TCPOLEN_TIMESTAMP);  
    25.         rep.opt[1] = htonl(tcp_time_stamp);  
    26.         rep.opt[2] = htonl(ts);  
    27.         arg.iov[0].iov_len += TCPOLEN_TSTAMP_ALIGNED;  
    28.     }  
    29.   
    30.     /* Swap the send and the receive. */  
    31.     rep.th.dest = th->source;  
    32.     rep.th.source = th->dest;  
    33.     rep.th.doff = arg.iov[0].iov_len / 4;  
    34.     rep.th.seq = htonl(seq);  
    35.     rep.th.ack_seq = htonl(ack);  
    36.     rep.th.ack = 1;  
    37.     rep.th.window = htons(win);  
    38.   
    39. #ifdef CONFIG_TCP_MD5SIG  
    40.     if (key) {  
    41.         int offset = (ts) ? 3 : 0;  
    42.         rep.opt[offset++] = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) |  
    43.                                 (TCPOPT_MD5SIG << 8) | TCPOLEN_MD5SIG);  
    44.         arg.iov[0].iov_len += TCPOLEN_MD5SIG_ALIGNED;  
    45.         rep.th.doff = arg.iov[0].iov_len / 4;  
    46.   
    47.         tcp_v4_md5_hash_addr((__u8 *) &rep.opt[offset], key, ip_hdr(skb)->saddr,   
    48.             ip_hdr(skb)->daddr, &rep.th);  
    49.     }  
    50. #endif  
    51.   
    52.     arg.flags = reply_flags;  
    53.     arg.csum = csum_tcpudp_nofold(ip_hdr(skb)->daddr, ip_hdr(skb)->saddr,  
    54.                     arg.iov[0].iov_len, IPPROTO_TCP, 0); /* 累加伪首部 */  
    55.     arg.csumoffset = offsetof(struct tcphdr, check) / 2;  
    56.     if (oif)  
    57.         arg.bound_dev_if = oif;  
    58.     arg.tos = tos;  
    59.   
    60.     /* 调用IP层函数,发送此ACK段 */  
    61.     ip_send_unicast_reply(net, skb, ip_hdr(skb)->saddr, ip_hdr(skb)->daddr, &arg, arg.iov[0].iov_len);  
    62.     TCP_INC_STATS_BH(net, TCP_MIB_OUTSEGS);  
    63. }  
    1. struct ip_reply_arg {  
    2.    struct kvec iov[1];  
    3.    int flags;  
    4.    __wsum csum;  
    5.    int csumoffset; /* u16 offset of csum in iov[0].iov_base */  
    6.    int bound_dev_if;  
    7.    u8 tos;  
    8. };  
    9.   
    10. struct kvec {  
    11.    void *iov_base;  
    12.    size_t iov_len;  
    13.   
    14. };  

    (3) 发送RST段

    检测到对端异常时,发送RST段。

    1. static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb)  
    2. {  
    3.     const struct tcphdr *th = tcp_hdr(skb);  
    4.     struct {  
    5.         struct tcphdr th;  
    6. #ifdef CONFIG_TCP_MD5SIG  
    7.         __be32 opt[(TCPOLEN_MD5SIG_ALIGNED >> 2) ];  
    8. #endif  
    9.     } rep;  
    10.     struct ip_reply_arg arg; /* 数据报的控制信息 */  
    11. #ifdef CONFIG_TCP_MD5SIG  
    12.     struct tcp_md5sig_key *key;  
    13.     const __u8 *hash_location = NULL;  
    14.     unsigned char newhash[16];  
    15.     int genhash;  
    16.     struct sock *sk1 = NULL;  
    17. #endif  
    18.     struct net *net;  
    19.   
    20.     /* Never send a reset in response to a reset. */  
    21.     if (th->rst)  
    22.         return;  
    23.   
    24.     if (skb_rtable(skb)->rt_type != RTN_LOCAL)  
    25.         return;  
    26.   
    27.     /* Swap the send and the receive. */  
    28.     memset(&rep, 0, sizeof(rep));  
    29.     rep.th.dest = th->source;  
    30.     rep.th.source = th->dest;  
    31.     rep.th.doff = sizeof(struct tcphdr) / 4;  
    32.     rep.th.rst = 1;  
    33.   
    34.     if (th->ack) {  
    35.         rep.th.seq = th->ack_seq;  
    36.     } else {  
    37.         rep.th.ack = 1;  
    38.         rep.th.ack_seq = htonl(ntohl(th->seq) + th->syn + th->fin + skb->len - (th->doff << 2));  
    39.     }  
    40.   
    41.     memset(&arg, 0, sizeof(arg));  
    42.     arg.iov[0].iov_base = (unsigned char *) &rep;  
    43.     arg.iov[0].iov_len = sizeof(rep.th);  
    44.   
    45. #ifdef CONFIG_TCP_MD5SIG  
    46.     /* 此处省略MD5选项的处理 */  
    47.     ...  
    48. #endif  
    49.   
    50.     arg.csum = csum_tcpudp_nofold(ip_hdr(skb)->daddr, ip_hdr(skb)->saddr,  
    51.                    arg.iov[0].iov_len, IPPROTO_TCP, 0);  
    52.     arg.csumoffset = offsetof(struct tcphdr, check) / 2;  
    53.     arg.flags = (sk && inet_sk(sk)->transparent) ? IP_REPLY_ARG_NOSRCCHECK : 0;  
    54.     /* When socket is gone, all binding information is lost. 
    55.      * routing might fail in this case. No choice here, if we choose to force input interface, 
    56.      * we will misroute in case of asymmetric route. 
    57.      */  
    58.     if (sk)  
    59.         arg.bound_dev_if = sk->sk_bound_dev_if;  
    60.     net = dev_net(skb_dst(skb)->dev);  
    61.     arg.tos = ip_hdr(skb)->tos;  
    62.   
    63.     /* 调用IP层函数发送 */  
    64.     ip_send_unicast_reply(net, skb, ip_hdr(skb)->saddr, ip_hdr(skb)->daddr, &arg, arg.iov[0].iov_len);  
    65.   
    66.     TCP_INC_STATS_BH(net, TCP_MIB_OUTSEGS);  
    67.     TCP_INC_STATS_BH(net, TCP_MIB_OUTRSTS);  
    68.   
    69. #ifdef CONFIG_TCP_MD5SIG  
    70.     /* 省略MD5处理 */  
    71.     ...  
    72. #endif   
    73. }  

    (4) 析构函数

    释放request_sock实例前调用。

    1. /* IPv4 request_sock destructor. */  
    2. static void tcp_v4_reqsk_destructor(struct request_sock *req)  
    3. {  
    4.     kfree(inet_rsk(req)->opt); /* 释放IP选项实例 */  
    5. }  

    (5) 超时处理函数

    不是真正的SYNACK超时处理函数,简单更新下统计变量。

    1. void tcp_syn_ack_timeout(struct sock *sk, struct request_sock *req)  
    2. {  
    3.     NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPTIMEOUTS);  
    4. }  
  • 相关阅读:
    Assembly 学习随笔——第一章
    实验 9 根据材料编程
    实验五 编写、调试具有多个段的程序
    汇编实验四 [bx]和loop的使用
    汇编实验 三 编程、编译、连接、跟踪
    汇编实验二 用机器指令和汇编指令编程
    实验一 查看CPU和内存,使用机器语言和汇编语言进行编程
    汇编第一章
    sqlmap的安装
    sql注入-输入’or 1=1#
  • 原文地址:https://www.cnblogs.com/mull/p/4477863.html
Copyright © 2011-2022 走看看