TCP畅谈

来源:互联网 发布:网络集成公司贵州 编辑:程序博客网 时间:2024/04/30 18:31

背景

本文是基于对以太网帧(FRAME)的研究,其中又对TCP的报文进行了ACK应答,丢包重传机制的补充,本文将对这些技术做一个大概的阐述。另外本文将用到wireshark抓包工具,具体使用细节由读者自己研究。系统:UBUNTU 16.04 64bit

1.以太网FRAME头

1.1.格式

| dest_mac(6 byte) | source_mac(6 byte) | type(2 byte ) |

  • type:类型用于指出该包是IP,ARP,IPV6数据报的类型;

1.2.存储格式

dest_mac     50:5e:49:20:4f:acsource_mac   00:1f:c6:9c:63:24type         0x0800(IPv4)存放格式:50 5e 49 20 4f ac 00 1f c6 9c 63 24 05 08 00   

1.IP头

1.1.IPV4头

    | 4bit version | 4bit headerlen |     8bit TOS     |16bit totallen(byte)|    |          16bit id         |3bit flags|       13bit frag_offset      |    | 8bit TTL     | 8bit protocol  |         16bit checksum                  |    |                                32bit source_ip                          |    |                                32bit dest_ip                            |    |                                (option)                                 |    version:版本号,一般为4    headerlen:IP头长度,右移2位,即若值为5,则长度为5<<2=20;    tos:服务类型,一般为0x00    totallen:总长度,包括IP头+IP数据    id,flags,frag_offset:这三项只有在IP包进行分片时,重组时会用到    TTL:生存时间。数据报每经过一个路由器,该值减1,直到为0,会将该数据报丢掉    protocol:用于标识传输协议类型,如TCP(6),UDP,ICMP,IGMP    checksum:校验和    source_ip:源IP地址    dest_ip:目的IP地址

1.2.校验和算法

  • 把校验和字段置为0;
  • 对IP头部中的每16bit进行二进制求和;
  • 如果和的高16bit不为0,则将和的高16bit和低16bit反复相加,直到和的高16bit为0,从而获得一个16bit的值;
  • 将该16bit的值取反,存入校验和字段。
  • 当接收IP包时,需要对报头进行确认,检查IP头是否有误,算法同上2、3步,然后判断取反的结果是否为0,是则正确,否则有错。
unsigned short msnet_api_checksum(unsigned short *addr,int bytes){    unsigned int sum=0;    while(bytes>1){        sum+=*addr++;        bytes-=2;     }    if(bytes==1){        sum+=*(unsigned char*)addr;    }    sum=((sum&0xffff0000)>>16)+(sum&0xffff);      sum+=((sum&0xffff0000)>>16);       sum=(~sum);    sum=((sum&0xff00)>>8|(sum&0xff)<<8);    return sum;}

2.TCP报文知识

2.1.TCP头

    |           16bit source_port     |       16bit dest_port            |    |                         32bit seq_num                          |    |                         32bit ack_num                          |    |4bit headerlen|6bit res |6bit flags |    16bit window_size          |    |           16bit checksum        |       16bit urgent_point         |    |                              (option)                              |    |                                data                                |

2.2.校验和算法

  • 把TCP报头中的校验和字段置为0
  • 伪首部+TCP报头+TCP数据分为16位的字,如果总长度为奇数个字节,则在最后增添一个位都为0的字节。
  • 用反码相加法累加所有的16位字(进位也要累加)。
  • 对计算结果取反,作为TCP的校验和。
uint16 msframe_api_tcpchecksum(ETHERContext *pether_ctt,uint08 *tcpheader_buf)  {    FRAMEContext *pframe_ctt=&pether_ctt->frame_ctt;    IPHEADERContext *pipheader_ctt=&pether_ctt->ipheader_ctt;    TCPHEADERContext *ptcpheader_ctt=&pether_ctt->tcpheader_ctt;    unsigned char tcpcheck_buf[2048]={0};    /*----extern  header----*/    //source_ip    ms_network_4b(&(tcpcheck_buf[0]), pipheader_ctt->source_ip);    //dest_ip    ms_network_4b(&(tcpcheck_buf[4]), pipheader_ctt->dest_ip);    //0    tcpcheck_buf[8]=0;    //protocol    tcpcheck_buf[9]=pipheader_ctt->protocol;    //len    ms_network_2b(&(tcpcheck_buf[10]), (ptcpheader_ctt->header_len*4+pether_ctt->size));    /*header*/    ms_memcpy(&tcpcheck_buf[12], tcpheader_buf, ptcpheader_ctt->header_len*4);    /*data*/    ms_memcpy(&tcpcheck_buf[12+ptcpheader_ctt->header_len*4], pether_ctt->data, pether_ctt->size);    return msnet_api_checksum((uint16 * )tcpcheck_buf, 12+ptcpheader_ctt->header_len*4+pether_ctt->size);   }

2.3.快速丢包重传

  • 当对端检测到有数据包丢失时,对端返回的ACK的选项中将带有SACK标志
  • 发送端接收到该SACK包后,根据ACK的ack_num以及选项SACK中的已接收到数据范围,确定那些数据包被丢失了;
  • 发送端迅速将丢失包进行重传;
  • 对端在接收到重传包前,将一直返回SACK包,其中ack_num不变,选项SACK中的已接收到数据范围将一直增加,直到将缓冲区填满;
  • 对端在接收到重传包后,将返回ACK包,ack_num为选项SACK中的已接收到数据范围的最大值;

3.问题解决

3.1.wireshark和tcpdump抓TCP包时,出现tcp的校验和失败,禁用网卡的offload功能即可:

sudo ethtool –offload eth0 rx off tx off sg off tso off

3.2.使用iptables禁用端口

3.2.1.选项

-A  添加一条INPUT/OUTPUT的规则-p  指定协议类型,如udp或者tcp--dport 目标端口--sport 源端口-s <ip> 根据IP地址进行控制-j  就是指定是 ACCEPT 接收 或者 DROP 不接收-L -n   查看

3.2.2.例子

1.允许接收tcp上8090端口的数据iptables -A INPUT -p tcp --dport 8090 -j ACCEPT2.禁止接收tcp上8090端口的数据iptables -A INPUT -p tcp --sport 8070 -j DROP3.允许发送tcp上8090端口的数据iptables -A OUTPUT -p tcp --sport 8090 -j ACCEPT4.禁止发送tcp上8090端口的数据iptables -A OUTPUT -p tcp --sport 8090 -j DROP5.保存service iptables save

3.3.当FRAME帧长度大于1514时,发送失败?

在1998年,Alteon Networks公司提出把Data Link Layer最大能传输的数据从1500 bytes 增加到9000 bytes,这个提议虽然没有得到IEEE 802.3 Working Group的同意,但是大多数设备厂商都已经支持
1500bytes 不包含18字节(14+4CRC),这种帧叫Jumbo frames,可以通过设置MTU来启动。

原创粉丝点击