zoukankan      html  css  js  c++  java
  • TCP被动打开 之 第二次握手-发送SYN+ACK

    假定客户端执行主动打开,发送syn包到服务器,服务器执行完该包的第一次握手操作后,调用af_ops->send_synack向客户端发送syn+ack包,该回调实际调用tcp_v4_send_synack函数;

     1 int tcp_conn_request(struct request_sock_ops *rsk_ops,
     2              const struct tcp_request_sock_ops *af_ops,
     3              struct sock *sk, struct sk_buff *skb)
     4 {
     5         /* 第一次握手的服务器处理 */
     6  
     7         /* 发送syn+ack */
     8         af_ops->send_synack(sk, dst, &fl, req, &foc,
     9                     !want_cookie ? TCP_SYNACK_NORMAL :
    10                            TCP_SYNACK_COOKIE);
    11     return 0;
    12 }

    tcp_v4_send_synack完成路由查找,构造syn+ack包,构造ip包,然后发送出去;

     1 /*
     2  *    Send a SYN-ACK after having received a SYN.
     3  *    This still operates on a request_sock only, not on a big
     4  *    socket.
     5  */
     6 static int tcp_v4_send_synack(const struct sock *sk, struct dst_entry *dst,
     7                   struct flowi *fl,
     8                   struct request_sock *req,
     9                   struct tcp_fastopen_cookie *foc,
    10                   enum tcp_synack_type synack_type)
    11 {
    12     const struct inet_request_sock *ireq = inet_rsk(req);
    13     struct flowi4 fl4;
    14     int err = -1;
    15     struct sk_buff *skb;
    16 
    17     /* First, grab a route. */
    18     /* 路由为空则查路由 */
    19     if (!dst && (dst = inet_csk_route_req(sk, &fl4, req)) == NULL)
    20         return -1;
    21 
    22     /* 构造syn+ack包 */
    23     skb = tcp_make_synack(sk, dst, req, foc, synack_type);
    24 
    25     if (skb) {
    26         /* 生成校验码 */
    27         __tcp_v4_send_check(skb, ireq->ir_loc_addr, ireq->ir_rmt_addr);
    28 
    29         /* 构造ip包并发送 */
    30         err = ip_build_and_send_pkt(skb, sk, ireq->ir_loc_addr,
    31                         ireq->ir_rmt_addr,
    32                         ireq->opt);
    33 
    34         /* 返回错误是否为本地阻塞判断 */
    35         err = net_xmit_eval(err);
    36     }
    37 
    38     return err;
    39 }

    tcp_make_synack函数完成skb分配,tcp首部的构造;

      1 struct sk_buff *tcp_make_synack(const struct sock *sk, struct dst_entry *dst,
      2                 struct request_sock *req,
      3                 struct tcp_fastopen_cookie *foc,
      4                 enum tcp_synack_type synack_type)
      5 {
      6     struct inet_request_sock *ireq = inet_rsk(req);
      7     const struct tcp_sock *tp = tcp_sk(sk);
      8     struct tcp_md5sig_key *md5 = NULL;
      9     struct tcp_out_options opts;
     10     struct sk_buff *skb;
     11     int tcp_header_size;
     12     struct tcphdr *th;
     13     int mss;
     14 
     15     /* 分配skb */
     16     skb = alloc_skb(MAX_TCP_HEADER, GFP_ATOMIC);
     17     if (unlikely(!skb)) {
     18         dst_release(dst);
     19         return NULL;
     20     }
     21     /* Reserve space for headers. */
     22     /* 保留头部空间 */
     23     skb_reserve(skb, MAX_TCP_HEADER);
     24 
     25     switch (synack_type) {
     26     case TCP_SYNACK_NORMAL:
     27         /* skb关联控制块 */
     28         skb_set_owner_w(skb, req_to_sk(req));
     29         break;
     30     case TCP_SYNACK_COOKIE:
     31         /* Under synflood, we do not attach skb to a socket,
     32          * to avoid false sharing.
     33          */
     34         break;
     35     case TCP_SYNACK_FASTOPEN:
     36         /* sk is a const pointer, because we want to express multiple
     37          * cpu might call us concurrently.
     38          * sk->sk_wmem_alloc in an atomic, we can promote to rw.
     39          */
     40         skb_set_owner_w(skb, (struct sock *)sk);
     41         break;
     42     }
     43 
     44     /* 设置路由缓存 */
     45     skb_dst_set(skb, dst);
     46 
     47     /* mss取从路由表中查询的mss与user_mss之间的较小值 */
     48     mss = tcp_mss_clamp(tp, dst_metric_advmss(dst));
     49 
     50     memset(&opts, 0, sizeof(opts));
     51 #ifdef CONFIG_SYN_COOKIES
     52     if (unlikely(req->cookie_ts))
     53         skb->skb_mstamp.stamp_jiffies = cookie_init_timestamp(req);
     54     else
     55 #endif
     56 
     57     /* 获取时间戳 */
     58     skb_mstamp_get(&skb->skb_mstamp);
     59 
     60 #ifdef CONFIG_TCP_MD5SIG
     61     rcu_read_lock();
     62     md5 = tcp_rsk(req)->af_specific->req_md5_lookup(sk, req_to_sk(req));
     63 #endif
     64 
     65     /* 设置hash */
     66     skb_set_hash(skb, tcp_rsk(req)->txhash, PKT_HASH_TYPE_L4);
     67     /* 设置tcp选项 */
     68     tcp_header_size = tcp_synack_options(req, mss, skb, &opts, md5, foc) +
     69               sizeof(*th);
     70 
     71     /* 构造填充tcp头 */
     72     skb_push(skb, tcp_header_size);
     73     skb_reset_transport_header(skb);
     74 
     75     th = (struct tcphdr *)skb->data;
     76     memset(th, 0, sizeof(struct tcphdr));
     77     /* 设置syn+ack标记 */
     78     th->syn = 1;
     79     th->ack = 1;
     80     tcp_ecn_make_synack(req, th);
     81     /* 设置源目的端口 */
     82     th->source = htons(ireq->ir_num);
     83     th->dest = ireq->ir_rmt_port;
     84     /* Setting of flags are superfluous here for callers (and ECE is
     85      * not even correctly set)
     86      */
     87 
     88     /* 初始化无数据的skb,标志为syn+ack */
     89     tcp_init_nondata_skb(skb, tcp_rsk(req)->snt_isn,
     90                  TCPHDR_SYN | TCPHDR_ACK);
     91 
     92     /* 设置序号和确认序号 */
     93     th->seq = htonl(TCP_SKB_CB(skb)->seq);
     94     /* XXX data is queued and acked as is. No buffer/window check */
     95     th->ack_seq = htonl(tcp_rsk(req)->rcv_nxt);
     96 
     97     /* RFC1323: The window in SYN & SYN/ACK segments is never scaled. */
     98     /* 设置窗口 */
     99     th->window = htons(min(req->rsk_rcv_wnd, 65535U));
    100 
    101     /* 写入选项 */
    102     tcp_options_write((__be32 *)(th + 1), NULL, &opts);
    103 
    104     /* 设置首部长度 */
    105     th->doff = (tcp_header_size >> 2);
    106     __TCP_INC_STATS(sock_net(sk), TCP_MIB_OUTSEGS);
    107 
    108 #ifdef CONFIG_TCP_MD5SIG
    109     /* Okay, we have all we need - do the md5 hash if needed */
    110     if (md5)
    111         tcp_rsk(req)->af_specific->calc_md5_hash(opts.hash_location,
    112                            md5, req_to_sk(req), skb);
    113     rcu_read_unlock();
    114 #endif
    115 
    116     /* Do not fool tcpdump (if any), clean our debris */
    117     skb->tstamp = 0;
    118     return skb;
    119 }
  • 相关阅读:
    [BZOJ 2457] 双端队列 (思维)
    字符串划分 [Bitset 字符串Dp]
    POJ2947 Widget Factory [高斯消元]
    数字串 [分治+哈希+扩展KMP]
    POJ3590 The shuffle Problem [置换+dp]
    P1970 花匠 [权值线段树优化dp, NOIp2003, Y]
    UVA306 Cipher[循环节]
    POJ3270 Cow Sorting [置换]
    POJ 3128 Leonardo's Notebook[置换群幂相关]
    VMware 11 设置U盘启动,总是找不到physicalDrive1
  • 原文地址:https://www.cnblogs.com/wanpengcoder/p/11750789.html
Copyright © 2011-2022 走看看