免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: platinum
打印 上一主题 下一主题

应如何正确计算 TCP 序号? [复制链接]

论坛徽章:
36
IT运维版块每日发帖之星
日期:2016-04-10 06:20:00IT运维版块每日发帖之星
日期:2016-04-16 06:20:0015-16赛季CBA联赛之广东
日期:2016-04-16 19:59:32IT运维版块每日发帖之星
日期:2016-04-18 06:20:00IT运维版块每日发帖之星
日期:2016-04-19 06:20:00每日论坛发贴之星
日期:2016-04-19 06:20:00IT运维版块每日发帖之星
日期:2016-04-25 06:20:00IT运维版块每日发帖之星
日期:2016-05-06 06:20:00IT运维版块每日发帖之星
日期:2016-05-08 06:20:00IT运维版块每日发帖之星
日期:2016-05-13 06:20:00IT运维版块每日发帖之星
日期:2016-05-28 06:20:00每日论坛发贴之星
日期:2016-05-28 06:20:00
31 [报告]
发表于 2008-10-30 19:41 |只看该作者
听各位高手授课,受益匪浅啊。

论坛徽章:
36
IT运维版块每日发帖之星
日期:2016-04-10 06:20:00IT运维版块每日发帖之星
日期:2016-04-16 06:20:0015-16赛季CBA联赛之广东
日期:2016-04-16 19:59:32IT运维版块每日发帖之星
日期:2016-04-18 06:20:00IT运维版块每日发帖之星
日期:2016-04-19 06:20:00每日论坛发贴之星
日期:2016-04-19 06:20:00IT运维版块每日发帖之星
日期:2016-04-25 06:20:00IT运维版块每日发帖之星
日期:2016-05-06 06:20:00IT运维版块每日发帖之星
日期:2016-05-08 06:20:00IT运维版块每日发帖之星
日期:2016-05-13 06:20:00IT运维版块每日发帖之星
日期:2016-05-28 06:20:00每日论坛发贴之星
日期:2016-05-28 06:20:00
32 [报告]
发表于 2008-10-30 19:42 |只看该作者
另外,你拍的很不错,洗了很多张


白金兄什么时候可以上小弟们看一下啊

论坛徽章:
0
33 [报告]
发表于 2008-10-30 23:35 |只看该作者
原帖由 Au_Hank 于 2008-10-30 19:01 发表
你可能有多次的数据修改,这样一来你需要记住多个的 (ORI_SEQ,N)偶对。如何消除旧的(ORI_SEQ,N)偶对是个问题。我觉得原则是已经被ACK过的ORI_SEQ可以被删除,但是如何知道 ACK被另外一端收到了是个问题(因为ACK可能被你的设备收到了,但是RELAY给接收方的时候丢失了)。

还有一个难办的是selective ack,要崩溃了。我觉得还不如在用户空间socket转接算了,简单多了,但是性能差了。

我在想,内核代码中有 NAT 代码,NAT 部分是重新计算 TCP 的 SEQ 和 WIN 的,能否直接利用他们的东西呢?
不同的是,我是桥,不是 NAT
kernel/net/netfilter/nf_conntrack_proto_tcp.c

  1. /* TCP connection tracking based on 'Real Stateful TCP Packet Filtering
  2.    in IP Filter' by Guido van Rooij.

  3.    [url]http://www.nluug.nl/events/sane2000/papers.html[/url]
  4.    [url]http://www.iae.nl/users/guido/papers/tcp_filtering.ps.gz[/url]

  5.    The boundaries and the conditions are changed according to RFC793:
  6.    the packet must intersect the window (i.e. segments may be
  7.    after the right or before the left edge) and thus receivers may ACK
  8.    segments after the right edge of the window.

  9.         td_maxend = max(sack + max(win,1)) seen in reply packets
  10.         td_maxwin = max(max(win, 1)) + (sack - ack) seen in sent packets
  11.         td_maxwin += seq + len - sender.td_maxend
  12.                         if seq + len > sender.td_maxend
  13.         td_end    = max(seq + len) seen in sent packets

  14.    I.   Upper bound for valid data:     seq <= sender.td_maxend
  15.    II.  Lower bound for valid data:     seq + len >= sender.td_end - receiver.td_maxwin
  16.    III. Upper bound for valid ack:      sack <= receiver.td_end
  17.    IV.  Lower bound for valid ack:      ack >= receiver.td_end - MAXACKWINDOW

  18.    where sack is the highest right edge of sack block found in the packet.

  19.    The upper bound limit for a valid ack is not ignored -
  20.    we doesn't have to deal with fragments.
  21. */

  22. static inline __u32 segment_seq_plus_len(__u32 seq,
  23.                                          size_t len,
  24.                                          unsigned int dataoff,
  25.                                          struct tcphdr *tcph)
  26. {
  27.         /* XXX Should I use payload length field in IP/IPv6 header ?
  28.          * - YK */
  29.         return (seq + len - dataoff - tcph->doff*4
  30.                 + (tcph->syn ? 1 : 0) + (tcph->fin ? 1 : 0));
  31. }

  32. /* Fixme: what about big packets? */
  33. #define MAXACKWINCONST                  66000
  34. #define MAXACKWINDOW(sender)                                            \
  35.         ((sender)->td_maxwin > MAXACKWINCONST ? (sender)->td_maxwin     \
  36.                                               : MAXACKWINCONST)
复制代码

  1. static int tcp_in_window(struct nf_conn *ct,
  2.                          struct ip_ct_tcp *state,
  3.                          enum ip_conntrack_dir dir,
  4.                          unsigned int index,
  5.                          const struct sk_buff *skb,
  6.                          unsigned int dataoff,
  7.                          struct tcphdr *tcph,
  8.                          int pf)
  9. {
  10.         struct ip_ct_tcp_state *sender = &state->seen[dir];
  11.         struct ip_ct_tcp_state *receiver = &state->seen[!dir];
  12.         struct nf_conntrack_tuple *tuple = &ct->tuplehash[dir].tuple;
  13.         __u32 seq, ack, sack, end, win, swin;
  14.         int res;

  15.         /*
  16.          * Get the required data from the packet.
  17.          */
  18.         seq = ntohl(tcph->seq);
  19.         ack = sack = ntohl(tcph->ack_seq);
  20.         win = ntohs(tcph->window);
  21.         end = segment_seq_plus_len(seq, skb->len, dataoff, tcph);

  22.         if (receiver->flags & IP_CT_TCP_FLAG_SACK_PERM)
  23.                 tcp_sack(skb, dataoff, tcph, &sack);

  24.         pr_debug("tcp_in_window: START\n");
  25.         pr_debug("tcp_in_window: ");
  26.         NF_CT_DUMP_TUPLE(tuple);
  27.         pr_debug("seq=%u ack=%u sack=%u win=%u end=%u\n",
  28.                  seq, ack, sack, win, end);
  29.         pr_debug("tcp_in_window: sender end=%u maxend=%u maxwin=%u scale=%i "
  30.                  "receiver end=%u maxend=%u maxwin=%u scale=%i\n",
  31.                  sender->td_end, sender->td_maxend, sender->td_maxwin,
  32.                  sender->td_scale,
  33.                  receiver->td_end, receiver->td_maxend, receiver->td_maxwin,
  34.                  receiver->td_scale);

  35.         if (sender->td_end == 0) {
  36.                 /*
  37.                  * Initialize sender data.
  38.                  */
  39.                 if (tcph->syn && tcph->ack) {
  40.                         /*
  41.                          * Outgoing SYN-ACK in reply to a SYN.
  42.                          */
  43.                         sender->td_end =
  44.                         sender->td_maxend = end;
  45.                         sender->td_maxwin = (win == 0 ? 1 : win);

  46.                         tcp_options(skb, dataoff, tcph, sender);
  47.                         /*
  48.                          * RFC 1323:
  49.                          * Both sides must send the Window Scale option
  50.                          * to enable window scaling in either direction.
  51.                          */
  52.                         if (!(sender->flags & IP_CT_TCP_FLAG_WINDOW_SCALE
  53.                               && receiver->flags & IP_CT_TCP_FLAG_WINDOW_SCALE))
  54.                                 sender->td_scale =
  55.                                 receiver->td_scale = 0;
  56.                 } else {
  57.                         /*
  58.                          * We are in the middle of a connection,
  59.                          * its history is lost for us.
  60.                          * Let's try to use the data from the packet.
  61.                          */
  62.                         sender->td_end = end;
  63.                         sender->td_maxwin = (win == 0 ? 1 : win);
  64.                         sender->td_maxend = end + sender->td_maxwin;
  65.                 }
  66.         } else if (((state->state == TCP_CONNTRACK_SYN_SENT
  67.                      && dir == IP_CT_DIR_ORIGINAL)
  68.                    || (state->state == TCP_CONNTRACK_SYN_RECV
  69.                      && dir == IP_CT_DIR_REPLY))
  70.                    && after(end, sender->td_end)) {
  71.                 /*
  72.                  * RFC 793: "if a TCP is reinitialized ... then it need
  73.                  * not wait at all; it must only be sure to use sequence
  74.                  * numbers larger than those recently used."
  75.                  */
  76.                 sender->td_end =
  77.                 sender->td_maxend = end;
  78.                 sender->td_maxwin = (win == 0 ? 1 : win);

  79.                 tcp_options(skb, dataoff, tcph, sender);
  80.         }

  81.         if (!(tcph->ack)) {
  82.                 /*
  83.                  * If there is no ACK, just pretend it was set and OK.
  84.                  */
  85.                 ack = sack = receiver->td_end;
  86.         } else if (((tcp_flag_word(tcph) & (TCP_FLAG_ACK|TCP_FLAG_RST)) ==
  87.                     (TCP_FLAG_ACK|TCP_FLAG_RST))
  88.                    && (ack == 0)) {
  89.                 /*
  90.                  * Broken TCP stacks, that set ACK in RST packets as well
  91.                  * with zero ack value.
  92.                  */
  93.                 ack = sack = receiver->td_end;
  94.         }

  95.         if (seq == end
  96.             && (!tcph->rst
  97.                 || (seq == 0 && state->state == TCP_CONNTRACK_SYN_SENT)))
  98.                 /*
  99.                  * Packets contains no data: we assume it is valid
  100.                  * and check the ack value only.
  101.                  * However RST segments are always validated by their
  102.                  * SEQ number, except when seq == 0 (reset sent answering
  103.                  * SYN.
  104.                  */
  105.                 seq = end = sender->td_end;

  106.         pr_debug("tcp_in_window: ");
  107.         NF_CT_DUMP_TUPLE(tuple);
  108.         pr_debug("seq=%u ack=%u sack =%u win=%u end=%u\n",
  109.                  seq, ack, sack, win, end);
  110.         pr_debug("tcp_in_window: sender end=%u maxend=%u maxwin=%u scale=%i "
  111.                  "receiver end=%u maxend=%u maxwin=%u scale=%i\n",
  112.                  sender->td_end, sender->td_maxend, sender->td_maxwin,
  113.                  sender->td_scale,
  114.                  receiver->td_end, receiver->td_maxend, receiver->td_maxwin,
  115.                  receiver->td_scale);

  116.         pr_debug("tcp_in_window: I=%i II=%i III=%i IV=%i\n",
  117.                  before(seq, sender->td_maxend + 1),
  118.                  after(end, sender->td_end - receiver->td_maxwin - 1),
  119.                  before(sack, receiver->td_end + 1),
  120.                  after(ack, receiver->td_end - MAXACKWINDOW(sender)));

  121.         if (before(seq, sender->td_maxend + 1) &&
  122.             after(end, sender->td_end - receiver->td_maxwin - 1) &&
  123.             before(sack, receiver->td_end + 1) &&
  124.             after(ack, receiver->td_end - MAXACKWINDOW(sender))) {
  125.                 /*
  126.                  * Take into account window scaling (RFC 1323).
  127.                  */
  128.                 if (!tcph->syn)
  129.                         win <<= sender->td_scale;

  130.                 /*
  131.                  * Update sender data.
  132.                  */
  133.                 swin = win + (sack - ack);
  134.                 if (sender->td_maxwin < swin)
  135.                         sender->td_maxwin = swin;
  136.                 if (after(end, sender->td_end))
  137.                         sender->td_end = end;
  138.                 /*
  139.                  * Update receiver data.
  140.                  */
  141.                 if (after(end, sender->td_maxend))
  142.                         receiver->td_maxwin += end - sender->td_maxend;
  143.                 if (after(sack + win, receiver->td_maxend - 1)) {
  144.                         receiver->td_maxend = sack + win;
  145.                         if (win == 0)
  146.                                 receiver->td_maxend++;
  147.                 }

  148.                 /*
  149.                  * Check retransmissions.
  150.                  */
  151.                 if (index == TCP_ACK_SET) {
  152.                         if (state->last_dir == dir
  153.                             && state->last_seq == seq
  154.                             && state->last_ack == ack
  155.                             && state->last_end == end
  156.                             && state->last_win == win)
  157.                                 state->retrans++;
  158.                         else {
  159.                                 state->last_dir = dir;
  160.                                 state->last_seq = seq;
  161.                                 state->last_ack = ack;
  162.                                 state->last_end = end;
  163.                                 state->last_win = win;
  164.                                 state->retrans = 0;
  165.                         }
  166.                 }
  167.                 res = 1;
  168.         } else {
  169.                 res = 0;
  170.                 if (sender->flags & IP_CT_TCP_FLAG_BE_LIBERAL ||
  171.                     nf_ct_tcp_be_liberal)
  172.                         res = 1;
  173.                 if (!res && LOG_INVALID(IPPROTO_TCP))
  174.                         nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
  175.                         "nf_ct_tcp: %s ",
  176.                         before(seq, sender->td_maxend + 1) ?
  177.                         after(end, sender->td_end - receiver->td_maxwin - 1) ?
  178.                         before(sack, receiver->td_end + 1) ?
  179.                         after(ack, receiver->td_end - MAXACKWINDOW(sender)) ? "BUG"
  180.                         : "ACK is under the lower bound (possible overly delayed ACK)"
  181.                         : "ACK is over the upper bound (ACKed data not seen yet)"
  182.                         : "SEQ is under the lower bound (already ACKed data retransmitted)"
  183.                         : "SEQ is over the upper bound (over the window of the receiver)");
  184.         }

  185.         pr_debug("tcp_in_window: res=%i sender end=%u maxend=%u maxwin=%u "
  186.                  "receiver end=%u maxend=%u maxwin=%u\n",
  187.                  res, sender->td_end, sender->td_maxend, sender->td_maxwin,
  188.                  receiver->td_end, receiver->td_maxend, receiver->td_maxwin);

  189.         return res;
  190. }
复制代码

  1. #ifdef CONFIG_NF_NAT_NEEDED
  2. /* Update sender->td_end after NAT successfully mangled the packet */
  3. /* Caller must linearize skb at tcp header. */
  4. void nf_conntrack_tcp_update(struct sk_buff *skb,
  5.                              unsigned int dataoff,
  6.                              struct nf_conn *conntrack,
  7.                              int dir)
  8. {
  9.         struct tcphdr *tcph = (void *)skb->data + dataoff;
  10.         struct ip_ct_tcp_state *sender = &conntrack->proto.tcp.seen[dir];
  11.         struct ip_ct_tcp_state *receiver = &conntrack->proto.tcp.seen[!dir];
  12.         __u32 end;

  13.         end = segment_seq_plus_len(ntohl(tcph->seq), skb->len, dataoff, tcph);

  14.         write_lock_bh(&tcp_lock);
  15.         /*
  16.          * We have to worry for the ack in the reply packet only...
  17.          */
  18.         if (after(end, conntrack->proto.tcp.seen[dir].td_end))
  19.                 conntrack->proto.tcp.seen[dir].td_end = end;
  20.         conntrack->proto.tcp.last_end = end;
  21.         write_unlock_bh(&tcp_lock);
  22.         pr_debug("tcp_update: sender end=%u maxend=%u maxwin=%u scale=%i "
  23.                  "receiver end=%u maxend=%u maxwin=%u scale=%i\n",
  24.                  sender->td_end, sender->td_maxend, sender->td_maxwin,
  25.                  sender->td_scale,
  26.                  receiver->td_end, receiver->td_maxend, receiver->td_maxwin,
  27.                  receiver->td_scale);
  28. }
  29. EXPORT_SYMBOL_GPL(nf_conntrack_tcp_update);
  30. #endif
复制代码

根据提示,我找到了这个文档,里面详细讲了应如何计算 SEQ 和 WIN
没想到这样的问题会导致像自己做一个 TCP 栈一样……
内核目前有这些,我能否利用他们呢?能力有限没能滤清思路……

tcp_filtering.pdf

78.71 KB, 下载次数: 80

论坛徽章:
0
34 [报告]
发表于 2008-10-30 23:36 |只看该作者
原帖由 Godbach 于 2008-10-30 19:42 发表


白金兄什么时候可以上小弟们看一下啊

好,回头给你看

论坛徽章:
0
35 [报告]
发表于 2008-10-31 07:34 |只看该作者

回复 #33 platinum 的帖子

IP FILTER/NAT里面,并没有对用户数据进行修改,比如插入或者删除数据。被修改的是协议数据,比如IP地址和TCP/UDP端口。要进行重新计算的只是校验和,而SEQ/ACK并不需要进行修改啊。我的理解是这样的,呆会做个NAT的测试看看是否SEQ/ACK变化了。

另外你给的那篇文章,里面只谈到如何根据SEQ/ACK进行状态跟踪,并没有对SEQ/ACK进行修改操作。也证明IP FILTER其实是不需要对SEQ/ACK修改的。

如果要借用代码,我觉得还是到TCP SOCKET那里去找比较好,它拥有对TCP SESSION管理的全套功能。我曾经也有做TCP SESSION重建的想法,思路就是在TCP SOCKET管理那里做,无奈没有时间和精力去弄。

论坛徽章:
0
36 [报告]
发表于 2008-10-31 08:56 |只看该作者
原帖由 Au_Hank 于 2008-10-31 07:34 发表
IP FILTER/NAT里面,并没有对用户数据进行修改,比如插入或者删除数据。被修改的是协议数据,比如IP地址和TCP/UDP端口。要进行重新计算的只是校验和,而SEQ/ACK并不需要进行修改啊。我的理解是这样的,呆会做个 ...

不,内容也修改了的
NAT 功能里有针对 FTP 被动模式的透传功能,它根据 RFC959 修改了 FTP command channel 里的请求数据,地址变化了
但唯一不同的是,他是 NAT 模式,而我是桥模式

kernel/net/netfilter/nf_conntrack_ftp.c
kernel/net/ipv4/netfilter/nf_nat_ftp.c

论坛徽章:
0
37 [报告]
发表于 2008-10-31 09:26 |只看该作者
原帖由 platinum 于 2008-10-31 08:56 发表

不,内容也修改了的
NAT 功能里有针对 FTP 被动模式的透传功能,它根据 RFC959 修改了 FTP command channel 里的请求数据,地址变化了
但唯一不同的是,他是 NAT 模式,而我是桥模式

kernel/net/netfilt ...


有道理,FTP是比较特殊,我没有考虑到。这样你可以把对应的SEQ管理的那部分代码抓过来用了

论坛徽章:
36
IT运维版块每日发帖之星
日期:2016-04-10 06:20:00IT运维版块每日发帖之星
日期:2016-04-16 06:20:0015-16赛季CBA联赛之广东
日期:2016-04-16 19:59:32IT运维版块每日发帖之星
日期:2016-04-18 06:20:00IT运维版块每日发帖之星
日期:2016-04-19 06:20:00每日论坛发贴之星
日期:2016-04-19 06:20:00IT运维版块每日发帖之星
日期:2016-04-25 06:20:00IT运维版块每日发帖之星
日期:2016-05-06 06:20:00IT运维版块每日发帖之星
日期:2016-05-08 06:20:00IT运维版块每日发帖之星
日期:2016-05-13 06:20:00IT运维版块每日发帖之星
日期:2016-05-28 06:20:00每日论坛发贴之星
日期:2016-05-28 06:20:00
38 [报告]
发表于 2008-10-31 10:31 |只看该作者
听各位讨论,越讨论越深入了。白金兄要做的是什么功能啊? 要对TCP做这么大动作,呵呵

论坛徽章:
0
39 [报告]
发表于 2008-10-31 10:35 |只看该作者
原帖由 Godbach 于 2008-10-31 10:31 发表
听各位讨论,越讨论越深入了。白金兄要做的是什么功能啊? 要对TCP做这么大动作,呵呵

是一个桥设备,用来篡改 client ---- server 之间传输的数据,看上去像是不好的用途

论坛徽章:
0
40 [报告]
发表于 2008-10-31 12:17 |只看该作者
比如说你在网上给白金转帐100,白金通过这个手段把金额改成10000
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP