TCP被动打开 之 第二次握手-发送SYN+ACK

时间:2019-10-28
本文章向大家介绍TCP被动打开 之 第二次握手-发送SYN+ACK,主要包括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 }

原文地址:https://www.cnblogs.com/wanpengcoder/p/11750789.html