首页 > 代码库 > 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协议