TCP畅谈

背景

本文是基于对以太网帧(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:ac
source_mac   00:1f:c6:9c:63:24
type         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 ACCEPT
2.禁止接收tcp上8090端口的数据
iptables -A INPUT -p tcp --sport 8070 -j DROP
3.允许发送tcp上8090端口的数据
iptables -A OUTPUT -p tcp --sport 8090 -j ACCEPT
4.禁止发送tcp上8090端口的数据
iptables -A OUTPUT -p tcp --sport 8090 -j DROP
5.保存
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来启动。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

酷咪哥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值