6.1 序列号与确认号

  由前文可知,TCP的序列号(seq)与确认号(ack_seq)都是无符号32的整数。seq用于为每一字节TCP数据编号(SYN和FIN标记位也会占用一个seq);ack_seq用于告知数据发送端:“接收端已经收到了ack_seq - 1号数据,请发送ack_seq号数据”。下面我们重温一下TCP连接建立和数据传输过程,在这个过程中探究一下seq和ack_seq是如何使用的。首先来介绍一下tcp_sock中与seq和ack_seq相关的主要成员:

34 struct tcp_sock {
135     /* inet_connection_sock has to be the first member of tcp_sock */
136     struct inet_connection_sock inet_conn;
...
151     u32 rcv_nxt;    /* What we want to receive next     */
152     u32 copied_seq; /* Head of yet unread data      */
153     u32 rcv_wup;    /* rcv_nxt on last window update sent   */
154     u32 snd_nxt;    /* Next sequence we send        */
155 
156     u32 snd_una;    /* First byte we want an ack for    */
157     u32 snd_sml;    /* Last byte of the most recently transmitted small packet */
...
182     u32 snd_wl1;    /* Sequence for window update       */
...
240     u32 write_seq;  /* Tail(+1) of data held in tcp send buffer */
241     u32 pushed_seq; /* Last pushed seq, required to talk to windows */
...
281     u32 urg_seq;    /* Seq of received urgent pointer */
...
  这些成员的作用都有英文注释来说明,就不翻译了。

  TCP连接的首个SYN包中的序列号被称为初始序列号(ISN),来看看ISN是如何生成的,先看发送SYN时:

 142 int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
 143 {
...
 237     if (!tp->write_seq && likely(!tp->repair))
 238         tp->write_seq = secure_tcp_sequence_number(inet->inet_saddr,
 239                                inet->inet_daddr,
 240                                inet->inet_sport,
 241                                usin->sin_port); //生成初始序列号
...
  ISN的生成用到了源|目的IP和源|目的端口,这样就保证了“连接不同但ISN相同”的概率是很低的。来看secure_tcp_sequence_number函数:

105 __u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr,
106                  __be16 sport, __be16 dport)
107 {        
108     u32 hash[MD5_DIGEST_WORDS]; 
109 
110     hash[0] = (__force u32)saddr;
111     hash[1] = (__force u32)daddr;
112     hash[2] = ((__force u16)sport << 16) + (__force u16)dport;
113     hash[3] = net_secret[15];
114 
115     md5_transform(hash, net_secret);
116 
117     return seq_scale(hash[0]);
118 }    
  其中,md5_transform函数所使用的net_secret是个全局变量,其中的数据由net_secret_init函数来随机填充:

 13 static u32 net_secret[MD5_MESSAGE_BYTES / 4] ____cacheline_aligned;
 14 
 15 void net_secret_init(void)
 16 {
 17     get_random_bytes(net_secret, sizeof(net_secret));
 18 }
  net_secret_init函数由build_ehash_secret函数调用,而socket系统调用在使用inet_create函数时会调用build_ehash_secret:
 277 static int inet_create(struct net *net, struct socket *sock, int protocol,
 278                int kern)
 279 {
 280     struct sock *sk;
 281     struct inet_protosw *answer;
 282     struct inet_sock *inet;
 283     struct proto *answer_prot;
 284     unsigned char answer_flags;
 285     char answer_no_check;
 286     int try_loading_module = 0;
 287     int err;
 288 
 289     if (unlikely(!inet_ehash_secret))
 290         if (sock->type != SOCK_RAW && sock->type != SOCK_DGRAM)
 291             build_ehash_secret();
...
  这样对于任意一个TCP scoket,其ISN与另一个TCP socket相同的概率都是很低的。如果攻击者需要猜对ISN才能实施攻击的话,这个特性会大大增加攻击难度,因为攻报文的seq不合法会被丢弃。

  接下来我们看ISN是如何使用的:

2925 int tcp_connect(struct sock *sk)
2926 {
2927     struct tcp_sock *tp = tcp_sk(sk);
2928     struct sk_buff *buff;
2929     int err;
2930 
2931     tcp_connect_init(sk);
...
2945     tcp_init_nondata_skb(buff, tp->write_seq++, TCPHDR_SYN);
...
2947     tcp_connect_queue_skb(sk, buff); //将SYN放入队列中
...
2951     err = tp->fastopen_req ? tcp_send_syn_data(sk, buff) :
2952           tcp_transmit_skb(sk, buff, 1, sk->sk_allocation); //发送SYN
2953     if (err == -ECONNREFUSED)
2954         return err;
2955 
2956     /* We change tp->snd_nxt after the tcp_transmit_skb() call
2957      * in order to make this packet get counted in tcpOutSegs.
2958      */
2959     tp->snd_nxt = tp->write_seq; //snd_nxt = ISN + 1
2960     tp->pushed_seq = tp->write_seq;
...
  tcp_connect_init函数中会初始化一些与seq相关的成员:

2752 void tcp_connect_init(struct sock *sk)
2753 {
...
2803     tcp_init_wl(tp, 0); //tp->snd_wl1 = 0
2804     tp->snd_una = tp->write_seq;
2805     tp->snd_sml = tp->write_seq;
2806     tp->snd_up = tp->write_seq;
2807     tp->snd_nxt = tp->write_seq;
...
 tcp_init_nondata_skb函数会将seq记录在skb中:

 356 static void tcp_init_nondata_skb(struct sk_buff *skb, u32 seq, u8 flags)
 357 {
 ... 
 368     TCP_SKB_CB(skb)->seq = seq;
 369     if (flags & (TCPHDR_SYN | TCPHDR_FIN))
 370         seq++;  //SYN和FIN都会占用一个seq
 371     TCP_SKB_CB(skb)->end_seq = seq; 
 372 }
 tcp_connect_queue_skb函数不只是将skb加入到发送队列中:
2821 static void tcp_connect_queue_skb(struct sock *sk, struct sk_buff *skb)
2822 {
2823     struct tcp_sock *tp = tcp_sk(sk);
2824     struct tcp_skb_cb *tcb = TCP_SKB_CB(skb);
2825 
2826     tcb->end_seq += skb->len; //如果有数据则将数据编号;end_seq实际上是下一个字节数据的seq
2827     skb_header_release(skb);
2828     __tcp_add_write_queue_tail(sk, skb); //加入到发送队列
2829     sk->sk_wmem_queued += skb->truesize; //更新队列中缓存占用总大小
2830     sk_mem_charge(sk, skb->truesize); //更新socket中已申请内存的信息
2831     tp->write_seq = tcb->end_seq; //记录已经写入发送缓存的最后一个字节的seq
2832     tp->packets_out += tcp_skb_pcount(skb); //记录TCP发送出去但未被接收的报文的数量
2833 }
  tcp_transmit_skb函数在发送skb时会将seq和ack_seq写入报文:
 828 static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it,
 829                 gfp_t gfp_mask)
 830 {
 831     const struct inet_connection_sock *icsk = inet_csk(sk);
...
 898     th->seq         = htonl(tcb->seq);
 899     th->ack_seq     = htonl(tp->rcv_nxt);
...
  client发送的SYN到达server端后,server的TCP也要选择序列号作为SYN|ACK的ISN,同时需要设置ack_seq。看看这些是怎么做的:
1465 int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
1466 {
...
1523     tcp_openreq_init(req, &tmp_opt, skb);
...
1576         isn = tcp_v4_init_sequence(skb);
1577     }
1578     tcp_rsk(req)->snt_isn = isn;
...
1598     skb_synack = tcp_make_synack(sk, dst, req,
1599         fastopen_cookie_present(&valid_foc) ? &valid_foc : NULL);
...
  在连接建立完成之前,server端保存连接信息的是request_sock,tcp_openreq_init函数负责对其进行初始化:

1075 static inline void tcp_openreq_init(struct request_sock *req,
1076                     struct tcp_options_received *rx_opt,
1077                     struct sk_buff *skb)
1078 {
1079     struct inet_request_sock *ireq = inet_rsk(req);
...
1083     tcp_rsk(req)->rcv_isn = TCP_SKB_CB(skb)->seq;
1084     tcp_rsk(req)->rcv_nxt = TCP_SKB_CB(skb)->seq + 1;  //期望接收SYN的下一个字节
...
  ISN由tcp_v4_init_sequence函数生成:
 101 static inline __u32 tcp_v4_init_sequence(const struct sk_buff *skb)
 102 {
 103     return secure_tcp_sequence_number(ip_hdr(skb)->daddr,
 104                       ip_hdr(skb)->saddr,
 105                       tcp_hdr(skb)->dest,
 106                       tcp_hdr(skb)->source);
 107 }
  可见ISN的生成方法与生成SYN时是一样的。

  tcp_make_synack函数生成SYN|ACK报文:

2654 struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst,
2655                 struct request_sock *req,
2656                 struct tcp_fastopen_cookie *foc)
2657 {   
...
2726     tcp_init_nondata_skb(skb, tcp_rsk(req)->snt_isn,
2727                  TCPHDR_SYN | TCPHDR_ACK);
2728 
2729     th->seq = htonl(TCP_SKB_CB(skb)->seq);
2730     /* XXX data is queued and acked as is. No buffer/window check */
2731     th->ack_seq = htonl(tcp_rsk(req)->rcv_nxt);
...
  这样ISN和ack_seq就写入到SYN|ACK报文中。

  收到SYN|ACK时:

5373 static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb,
5374                      const struct tcphdr *th, unsigned int len)
5375 {
...
5385     if (th->ack) {
...
5437         tcp_init_wl(tp, TCP_SKB_CB(skb)->seq);
5438         tcp_ack(sk, skb, FLAG_SLOWPATH);
5439 
5440         /* Ok.. it's good. Set up sequence numbers and
5441          * move to established.
5442          */
5443         tp->rcv_nxt = TCP_SKB_CB(skb)->seq + 1;
5444         tp->rcv_wup = TCP_SKB_CB(skb)->seq + 1;
...
5476         tp->copied_seq = tp->rcv_nxt;
...
  5438:慢速路径下tcp_ack会调用tcp_ack_update_window更新snd_una:

3325 static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
3326 {
3327     struct inet_connection_sock *icsk = inet_csk(sk);
3328     struct tcp_sock *tp = tcp_sk(sk);
3329     u32 prior_snd_una = tp->snd_una;
3330     u32 ack_seq = TCP_SKB_CB(skb)->seq;
3331     u32 ack = TCP_SKB_CB(skb)->ack_seq;
...
3392         flag |= tcp_ack_update_window(sk, skb, ack, ack_seq);
...

3218 static int tcp_ack_update_window(struct sock *sk, const struct sk_buff *skb, u32 ack,
3219                  u32 ack_seq)
3220 {
...
3248     tp->snd_una = ack;
3249 
3250     return flag;
3251 }
  即tp->snd_una = TCP_SKB_CB(skb)->ack_seq。

  发送ACK时会使用tcp_send_ack函数:

3027 void tcp_send_ack(struct sock *sk)
3028 {  
...
3050     tcp_init_nondata_skb(buff, tcp_acceptable_seq(sk), TCPHDR_ACK); //将tcp_acceptable_seq(sk)的返回值作为ACK的seq
...
3054     tcp_transmit_skb(sk, buff, 0, sk_gfp_atomic(sk, GFP_ATOMIC)); //ACK的ack_seq会使用tp->rcv_nxt
3055 }
  tcp_acceptable_seq函数得到一个可用的seq:
  94 static inline __u32 tcp_acceptable_seq(const struct sock *sk)
  95 {
  96     const struct tcp_sock *tp = tcp_sk(sk);
  97 
  98     if (!before(tcp_wnd_end(tp), tp->snd_nxt)) //snd_nxt <= 窗口右边缘
  99         return tp->snd_nxt;
 100     else
 101         return tcp_wnd_end(tp);
 102 }
  发送无数据的ACK时tp->snd_nxt不需要增加,因为AK标记不占用seq。

  综上可知,TCP连接双方的ISN是独立选择的,从而seq空间也是独立的,但ack_seq与对端的seq相关。也就是说,一个TCP通信端自己的seq与ack_seq是无关的。

  下面来看数据的发送和接收过程中seq和ack_seq是如何使用的。首先是数据发送:

1016 int tcp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
1017         size_t size)
1018 {   
...
1133                 skb_entail(sk, skb); //将skb放入发送队列
...
1192             tp->write_seq += copy; //写入了copy个字节
1193             TCP_SKB_CB(skb)->end_seq += copy; //skb增加了copy个字节长的数据
...
  如果TCP选择已经在队列中但还未发送且有剩余空间的skb来写入数据,则不会调用skb_entail函数。但1192和1193行的代码会调到。

  新申请skb时则会调用skb_entail函数:

 596 static inline void skb_entail(struct sock *sk, struct sk_buff *skb)
 597 {
 598     struct tcp_sock *tp = tcp_sk(sk);
 599     struct tcp_skb_cb *tcb = TCP_SKB_CB(skb);
 600 
 601     skb->csum    = 0;
 602     tcb->seq     = tcb->end_seq = tp->write_seq; //设置seq的值,end_seq会在copy完数据后更新
 603     tcb->tcp_flags = TCPHDR_ACK; //设置ACK标记位
 604     tcb->sacked  = 0;
 605     skb_header_release(skb);
 606     tcp_add_write_queue_tail(sk, skb); //将skb加入到发送队列中
 607     sk->sk_wmem_queued += skb->truesize;
 608     sk_mem_charge(sk, skb->truesize);
 609     if (tp->nonagle & TCP_NAGLE_PUSH)
 610         tp->nonagle &= ~TCP_NAGLE_PUSH;
 611 }
  调用tcp_write_xmit发送数据时:
1811 static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle,
1812                int push_one, gfp_t gfp)
1813 {
...
1832     while ((skb = tcp_send_head(sk))) { //sk->sk_send_head指针非空,则意味着有skb尚未发送
...
1884         if (unlikely(tcp_transmit_skb(sk, skb, 1, gfp)))
1885             break;
...    //发送成功
1891         tcp_event_new_data_sent(sk, skb);
...
  tcp_transmit_skb发送数据时会用TCP_SKB_CB(skb)->seq作为包的seq,用tp->rcv_nxt作为ack_seq。

  tcp_event_new_data_sent函数处理发送数据成功的事件:

 72 static void tcp_event_new_data_sent(struct sock *sk, const struct sk_buff *skb)
  73 {
  74     struct inet_connection_sock *icsk = inet_csk(sk);
  75     struct tcp_sock *tp = tcp_sk(sk);
  76     unsigned int prior_packets = tp->packets_out;
  77 
  78     tcp_advance_send_head(sk, skb); //sk->sk_send_head指针指向发送队列中下一个skb
  79     tp->snd_nxt = TCP_SKB_CB(skb)->end_seq; //更新snd_nxt,因为skb中的数据已经发送出去
  80 
  81     tp->packets_out += tcp_skb_pcount(skb); //有更多的包发送出去了,更新一下“在网络中”的包数
  82     if (!prior_packets || icsk->icsk_pending == ICSK_TIME_EARLY_RETRANS ||
  83         icsk->icsk_pending == ICSK_TIME_LOSS_PROBE) {
  84         tcp_rearm_rto(sk); //重设重传定时器,更新RTO估计量
  85     }
  86 }
  TCP收到数据或ACK时:
1961 int tcp_v4_rcv(struct sk_buff *skb)
1962 {
...
1994     TCP_SKB_CB(skb)->seq = ntohl(th->seq);
1995     TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin +
1996                     skb->len - th->doff * 4); //IP报文段数据长度减去TCP报头长度为TCP数据长度
1997     TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq);
...
  需要检查序列号是否合法:
4985 static bool tcp_validate_incoming(struct sock *sk, struct sk_buff *skb, 
4986                   const struct tcphdr *th, int syn_inerr)
4987 {
...
5001     /* Step 1: check sequence number */
5002     if (!tcp_sequence(tp, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq)) {
5003         /* RFC793, page 37: "In all states except SYN-SENT, all reset
5004          * (RST) segments are validated by checking their SEQ-fields."
5005          * And page 69: "If an incoming segment is not acceptable,
5006          * an acknowledgment should be sent in reply (unless the RST
5007          * bit is set, if so drop the segment and return)".
5008          */
5009         if (!th->rst) {  
5010             if (th->syn) 
5011                 goto syn_challenge;            
5012             tcp_send_dupack(sk, skb);      
5013         }                
5014         goto discard;    
5015     }
...
  一个合法数据段的seq和end_seq之间的数据必须有一部分在窗口之中:
3738 static inline bool tcp_sequence(const struct tcp_sock *tp, u32 seq, u32 end_seq)
3739 {  
3740     return  !before(end_seq, tp->rcv_wup) &&  //end_seq >= rcv_wup
3741         !after(seq, tp->rcv_nxt + tcp_receive_window(tp)); //seq <= rcv_nxt + rcv_win
3742 }

  end_seq < rcv_wup意味着报文的全部数据都是旧的,seq > rcv_nxt + rcv_win则是数据全部位于窗口之外,这两种报文是必须丢弃的。

  如果seq通过了tcp_sequence的检查则会进入tcp_data_queue函数;如果seq等于rcv_nxt则tcp_data_queue函数会设置tp->rcv_nxt,否则会执行更严格的检查:

4300 static void tcp_data_queue(struct sock *sk, struct sk_buff *skb)
4301 {
...
4321     if (TCP_SKB_CB(skb)->seq == tp->rcv_nxt) { //skb的seq正好就是期望接收的seq
...
4352         tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq; //更新rcv_nxt
...
4380     if (!after(TCP_SKB_CB(skb)->end_seq, tp->rcv_nxt)) { //end_seq <= rcv_nxt
4381         /* A retransmit, 2nd most common case.  Force an immediate ack. */
4382         NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_DELAYEDACKLOST);
4383         tcp_dsack_set(sk, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq);
4384 
4385 out_of_window:
4386         tcp_enter_quickack_mode(sk);
4387         inet_csk_schedule_ack(sk);
4388 drop:
4389         __kfree_skb(skb);
4390         return;
4391     }
4392 
4393     /* Out of window. F.e. zero window probe. */
4394     if (!before(TCP_SKB_CB(skb)->seq, tp->rcv_nxt + tcp_receive_window(tp))) //seq >= rcv_nxt + rcv_win
4395         goto out_of_window;
4396 
4397     tcp_enter_quickack_mode(sk);
4398 
4399     if (before(TCP_SKB_CB(skb)->seq, tp->rcv_nxt)) { //seq < rcv_nxt;这时skb中有一部分数据是旧的,一部分是新的
4400         /* Partial packet, seq < rcv_next < end_seq */
4401         SOCK_DEBUG(sk, "partial packet: rcv_next %X seq %X - %X\n",
4402                tp->rcv_nxt, TCP_SKB_CB(skb)->seq,
4403                TCP_SKB_CB(skb)->end_seq);
4404 
4405         tcp_dsack_set(sk, TCP_SKB_CB(skb)->seq, tp->rcv_nxt);
4406 
4407         /* If window is closed, drop tail of packet. But after
4408          * remembering D-SACK for its head made in previous line.
4409          */
4410         if (!tcp_receive_window(tp))
4411             goto out_of_window;
4412         goto queue_and_out; //也会去更新rcv_nxt
4413     }
4414  //seq > tp->rcv_nxt,且报文没有在窗口之外,则是乱序数据
4415     tcp_data_queue_ofo(sk, skb);
4416 }

  应用进程在使用tcp_recvmsg函数读取数据时会利用tp->copied_seq记录下一次要copy的数据的seq:

1545 int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
1546         size_t len, int nonblock, int flags, int *addr_len)
1547 {
1548     struct tcp_sock *tp = tcp_sk(sk);
1549     int copied = 0;
1550     u32 peek_seq;
1551     u32 *seq;
...
1588     seq = &tp->copied_seq;
...
1781             if (tp->rcv_nxt == tp->copied_seq && //没有待copy的数据了
1782                 !skb_queue_empty(&tp->ucopy.prequeue)) {
1783 do_prequeue:
1784                 tcp_prequeue_process(sk);
...
1855             {
1856                 err = skb_copy_datagram_iovec(skb, offset,
1857                         msg->msg_iov, used);
1858                 if (err) {
1859                     /* Exception. Bailout! */
1860                     if (!copied)
1861                         copied = -EFAULT;
1862                     break;
1863                 }
1864             }
1865         }
1866
1867         *seq += used; //已经copy完了used字节
1868         copied += used;
...
1889     found_fin_ok:
1890         /* Process the FIN. */
1891         ++*seq; //读取FIN时copied_seq也要加1
...

  tcp_ack函数会对报文的ack_seq进行检查:

3325 static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
3326 {
3327     struct inet_connection_sock *icsk = inet_csk(sk);
3328     struct tcp_sock *tp = tcp_sk(sk);
3329     u32 prior_snd_una = tp->snd_una;
3330     u32 ack_seq = TCP_SKB_CB(skb)->seq;
3331     u32 ack = TCP_SKB_CB(skb)->ack_seq;
...
3343     if (before(ack, prior_snd_una)) { //ack_seq < tp->snd_una
3344         /* RFC 5961 5.2 [Blind Data Injection Attack].[Mitigation] */
3345         if (before(ack, prior_snd_una - tp->max_window)) {
3346             tcp_send_challenge_ack(sk);
3347             return -1;
3348         }
3349         goto old_ack;
3350     }
3351 
3352     /* If the ack includes data we haven't sent yet, discard
3353      * this segment (RFC793 Section 3.9).
3354      */
3355     if (after(ack, tp->snd_nxt)) //ack_seq > tp->snd_nxt
3356         goto invalid_ack;
...
3380         tp->snd_una = ack;
...
  一个合法的ack_seq必须满足:snd_una < ack_seq <= snd_nxt。ack_seq <= snd_una则是重复的ACK。ack_seq < tp->snd_una则ack_seq太旧了;ack_seq > tp->snd_nxt则是ack_seq确认了尚未发送的数据,也是非法的。如果ack_seq合法则tcp_ack会设置tp->snd_una = ack_seq。

  TCP使用before和after来比较seq和ack_seq的大小:

 300 static inline bool before(__u32 seq1, __u32 seq2)
 301 {
 302         return (__s32)(seq1-seq2) < 0;
 303 }
 304 #define after(seq2, seq1)   before(seq1, seq2)
  before为真则可以认为seq1 < seq2,after为真则可以认为seq2 > seq1。由于seq是无符号32位整数,seq大于2^32 - 1会出现回绕,所以如果seq1 < seq2 < (seq1 + 2^31) mod 2^32 - 1,则before(seq1, seq2)为真;否则如果seq2 < seq1 < (seq2 + 2^31) mod 2^32 - 1,则before(seq2, seq1)为真.也就是说,32bit的序列号空间只有一半(2^31)的序列号可用。当数据发送很快时,序列号会迅速出现回绕,这时靠before和after这种单纯比较序列号来判断报文新旧的方法容易出现错误,这个问题需要靠时间戳来解决。

  判断报文段中的数据是否合法还需要知道接收窗口的大小。关于窗口下节详细分析。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值