首页 > 代码库 > tcp/ip协议学习 第三章 IP协议
tcp/ip协议学习 第三章 IP协议
派猴子来的救兵
关于IP的RFC文档在此!
IP的头文件还是先贴一下, 总是记不住.
0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |Version| IHL |Type of Service| Total Length | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Identification |Flags| Fragment Offset | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Time to Live | Protocol | Header Checksum | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Source Address | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Destination Address | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Options | Padding | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
网络和子网划分
不太明白ABCD四类地址划分的意义,除了在路由选择的匹配中会配合子网划分用到.
路由表, 路由选择
以前本科的时候, IP配置好之后, 学校内网是可以访问的. 如果想访问外网, 需要拨号.但拨号之后内网就不方便上了.
学校网站有个小程序, 可以傻瓜式的修改系统路由. 拨号之后内网外网一起上.
当时不明白这是个什么东西, 其实现在也想不太明白怎么回事, 也没条件回学校试验下了. 但至少现在也算大概明白路由表以及路由选择了.
之前为了学习, 拿公司的网络实验了一把. osx下面的双网卡路由配置
来段程序吧
python
用程序发送raw IP包的时候, Total Length 和 Checksum 会由内核自动生成. 至于为啥,可能看到tcpip协议详解下(实现)的时候就知道了吧.
Checksum 算法在模拟后面协议的时候就要自己实现了.ICMP、IGMP、UDP和TCP都采用相同的检验和算法.
有个不同点是: 首部检验和字段是根据IP头计算的检验和码。它不对body进行计算。 ICMP、 IGMP、UDP和TCP的checksum覆盖首部和数据。
#!/usr/bin/env python# -*- coding: utf-8 -*-‘‘‘发送一个裸的IP包, 20字节的IP头, 后面跟一个随便写的字符串.还不知道IP包的ID应该根据什么生成, 就随便写了一个54321IP头里面: IP包总长度属性和checksum属性都是内核自动生成的. 协议是用的socket.IPPROTO_TCP,也就是6.但没什么用,IP包里面就随便的字符串,不是按TCP协议来的.‘‘‘import socketfrom struct import packimport sysdef main(): try: s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_RAW) except socket.error as msg: print ‘Socket could not be created. Error Code : ‘ + str(msg[0]) + ‘ Message ‘ + msg[1] return packet = ‘‘ source_ip = ‘127.0.0.1‘ dest_ip = ‘127.0.0.1‘ # ip header fields ip_ver = 4 ip_ihl = 5 ip_tos = 0 ip_tot_len = 0 # kernel will fill the correct total length ip_id = 54321 ip_frag_off = 0 ip_ttl = 32 ip_proto = socket.IPPROTO_TCP # no use in this case ip_checksum = 0 # kernel will fill the correct checksum ip_saddr = socket.inet_aton(source_ip) ip_daddr = socket.inet_aton(dest_ip) ip_ihl_ver = (ip_ver << 4) + ip_ihl # the ! in the pack format string means network order ip_header = pack( ‘!BBHHHBBH4s4s‘, ip_ihl_ver, ip_tos, ip_tot_len, ip_id, ip_frag_off, ip_ttl, ip_proto, ip_checksum, ip_saddr, ip_daddr) user_data = http://www.mamicode.com/sys.argv[1] if sys.argv[1:] else ‘0123456789‘>
抓包. 运行环境, ubuntu12.04
% sudo tcpdump -i lo -x -vvv -t -c 1 ?tcpdump: listening on lo, link-type EN10MB (Ethernet), capture size 65535 bytesIP (tos 0x0, ttl 32, id 54321, offset 0, flags [none], proto TCP (6), length 30) localhost.12337 > localhost.12851: tcp 10 [bad hdr length 0 - too short, < 20] 0x0000: 4500 001e d431 0000 2006 c8a6 7f00 0001 0x0010: 7f00 0001 3031 3233 3435 3637 38391 packet captured2 packets received by filter0 packets dropped by kernel
tcp 10 [bad hdr length 0 - too short, < 20] 是说IP body里面的字节数太少, 只有10, 小于TCP header应有的20字节.
1字节, 45, 4代表Version, 5代表Header Length, 单位是4Byte.
2字节, 00, OTS(Type of Service), 代表此IP包的最小时延,最大吞吐量,最高可靠性, 最小费用等特征. 比如用于FTP的控制的IP包, 应该是最小时延, 用于FTP的数据的IP包, 则应该是最大吞吐量.书中提到:
现在大多数的TCP/IP实现都不支持TOS特性,但是自4.3BSD Reno以后的新版系统都对它
进行了设置。另外,新的路由协议如 OSPF和IS-IS都能根据这些字段的值进行路由决策。
3,4字节, 001e, Total Length. 0x1e = 30; 发送的01234567890+20字节的IP Header.
因为一些数据链路(如以太网)需要填充一些数据以达到最小长度。尽管以太网的最小帧长为 46字节,但是IP数据可能会更短,像我们就是30。如果没有总长度字段,那么IP层就不知道46字节中有多少是IP数据报的内容。所以IP包总长度这个字段是一定需要的.5,6字节, Identification. 0xd431=54321.
7,8字节, 0000.
9字节, 20. TTL. 路由转发此IP包的时候就把这个数值减1, 减到0的时候就直接丢弃, 并发送ICMP通知主机. trouceroute即利用了这个.
10字节, 06, 代表TCP协议.
11,12字节 c8a6. Checksum.
13–16字节, 7f00 0001. Source Address. 代表127.0.0.1
17–20字节, 7f00 0001. Destination Address. 代表127.0.0.1
Checksum是内核帮我们算好的, 但以后的TCP等就要自己算了, 这里先看一下算法.
首先把检验和字段置为 0。然后,对首部中每个 16 bit 进行二进制反码求和(整个首部看成是由一串 16 bit的字组成)
def checksum(ip_header): ip_header += chr(0x00)*(len(ip_header)%2) r = 0 while ip_header: # 因为ip_header已经是网络序了, 所以这里用H. 否则需要用!H r += unpack(‘H‘,ip_header[:2])[0] ip_header = ip_header[2:] if r > 0xffff: r = r&0xffff + (r>>16); return ~r
tcp/ip协议学习 第三章 IP协议