标签:
[创建时间:2015-08-27 22:15:17]
上篇我们回顾完了NetAnalyzer一些可有可无的历史,在本篇,我决定先不对NetAnalyzer做介绍,而是先要了解一些关于构建NetAnalyzer的基础知识,如系统中可以分析的一些网络协议,了解它们的分布方式,字段含义等。在了解了协议的基础上,开始对Winpcap进行一些介绍,在这过程中,学习配置Winpcap的开发环境,做一些简单的数据采集程序。第三部分着重介绍过滤表达式的一些基本语法结构。写下来则要介绍一下在开发NetAnalzyer过程中涉及到的一些数据结构与编程思想。
NetAnalyzer中的协议
在这里我并不想讲太多关于协议体系结构的问题,也不管什么OSI七层模型,也不论TCP/IP的四层结构,也为这些体系方面的知识很多,而且有在很多的书中都有介绍。而在此处讲的是,在NetAnalyzer中所能解析的数据,并对各数据字段给出相应的解释与说明,最终只是作为参考资料,方便NetAnalyzer后续的开发升级。因此在此处所有数据报文分析数据将依照NetAnalyzer中现有的数据解析结果,与整体解析层次作为参考进行协议说明。
在介绍具体协议之前先看看NetAnalyzer数据分析界面
(a) 上面为获取的数据包列表
(b) 左下角为具体的协议分析内容,也是该软件的核心区域
(c) 右下角为数据包的具体原始数据
本软件可以从网卡采集数据,也可以读取缓存文件获得,因为有些数据包不容易采集,所以可以到这里下载(不会博客传文件,所以给一个链接吧)
http://pan.baidu.com/s/1ntxi5dB
1.帧( Frame)
事实上,这并不是一个网络协议。这只是用来获取的一个数据报文的基本信息,这是Winpcap定义的一种数据格式,当其转为字符串时显示如图所示。在每个数据包被捕获到的时候,在内存中的存储数据如图2.1所示
图2.1 原始的数据报文
第一行包括冒号在内的第一个字段13309501:631439是一种时间戳标记方式。该时间戳记录以“:”为分隔符,分为秒计时,与毫秒计时。
秒计时:32位,一个UNIX格式的精确到秒时间值,用来记录数据包抓获的时间,记录方式是记录从格林尼治时间的1970年1月1日 00:00:00 到抓包时经过的秒数;
毫秒计时:32位,记录抓取数据包时的毫秒值。
在时间戳后面的字段,使用括号的包含起来的字段则是表示当前获取数据报文的大小。以字节文单位。其记录了所抓获的数据包的真实长度,如果文件中保存不是完整的数据包,那么这个值可能要比前面的数据包长度的值大,该字段中的数据数量是54字节。
第一行之后的数据为网络传输数据报文,为了方便在书中展示,此处使用十六进制的方式展示出来,在这些数据中,其中记录了各种协议的首部信息以及索要传递的数据内容。图2.2则是对整个数据报文的信息摘要。
图2.2 Frame中所要表达的数据信息
2 以太网协议(Ethernet)
在完成了数据报文基础信息的讲解,现在开始真正的协议分析。首先自然是链路层的以太网。因为目前大多数的网络都采用以太网进行构建。
以太网最早由Xerox(施乐)公司创建,于1980年DEC、lntel和Xerox三家公司联合开发成为一个标准。以太网是应用最为广泛的局域网,包括标准的以太网(10Mbit/s)、快速以太网(100Mbit/s)和10G(10Gbit/s)以太网,采用的是CSMA/CD访问控制法,它们都符合IEEE802.3。 IEEE 802.3标准 IEEE802.3规定了包括物理层的连线、电信号和介质访问层协议的内容。以太网是当前应用最普遍的局域网技术。它很大程度上取代了其他局域网标准,如令牌环、FDDI和ARCNET。历经100M以太网在上世纪末的飞速发展后,目前千兆以太网甚至10G以太网正在国际组织和领导企业的推动下不断拓展应用范围。
常见的802.3应用为:
10M: 10base-T (铜线UTP模式)
100M: 100base-TX (铜线UTP模式)
100base-FX(光纤线)
1000M: 1000base-T(铜线UTP模式)
ethernet采用无源的介质,按广播方式传播信息。它规定了物理层和数据链路层协议,规定了物理层和数据链路层的接口以及数据链路层与更高层的接口。
(1) 物理层
物理层规定了Ethernet的基本物理属性,如数据编码、时标、电频等。
(2) 数据链路层
数据链路层的主要功能是完成帧发送和帧接收,包括负责对用户数据进行帧的组装与分解,随时监测物理层的信息监测标志,了解信道的忙闲情况,实现数据链路的收发管理。
以太网首部格式,如图2.3所示,其首部共14个字节共112个bits,五个字段组成。
图2.3Ethernet 首部格式
在Ethernet帧字段的说明
字段 |
长度(bit) |
说明 |
目的硬件地址(Destination MAC Address) |
48 |
下一跳主机的硬件地址 |
源主机硬件地址(Source MAC Address) |
48 |
上一跳主机的硬件地址 |
网络层协议类型 |
16 |
所分装的上一层协议类型 |
数据字段 |
可变 |
|
FCS |
16 |
帧校验序列(CRC校验) |
表2-1 Eternet字段
(1) 硬件地址(MAC Address)
MAC(Medium/Media Access Control)地址,或称为 MAC位址、硬件地址,用来定义网络设备的位置,由48比特长,16进制数字组成,0到23位是组织唯一标识符,是识别LAN(局域网)结点的标志。在OSI模型中,第三层网络层负责 IP地址,第二层数据链路层则负责 MAC位址。因此一个网卡会有一个全球唯一固定的MAC地址,但可对应多个IP地址。其中24到47位是厂家自己分配的,第40位是组播地址标志位。
(2) 网络层协议类型(Type)
用于识别上一层分装数据的类型。如0x0080表示上一次即网络层的协议为IPv4,而0x0806则表示地址解析协议ARP。
(3) 数据(Data)
该字段表示当前传输的上层协议首部和分装的数据。其数据长度限制在46-1500个字节之间。
(4) FCS
FCS是802.3帧和Ethernet帧的最后一个字段,用于保存帧的CRC校验值,站4个字节。
NetAnalyzer中表示
在NetAnalyzer中所获取的原始数据效果如图2.4所示,在该段数据中,可以看出此数据报文的目的硬件地址(Destination Mac Address):94-0C-6D-32-40-82,源硬件地址(Source): 00-24-54-19-4B-2E,类型(Type):0x0800 即上册协议为IPv4。
图2.4 Eternet原始数据
在NetAnalyzer中分析结果如图2.5所示。
图2.5 Ehternet 在NetAnalyzer中的分析结果
3 地址解析协议(ARP)
ARP,即地址解析协议,实现通过IP地址得知其物理地址。在TCP/IP网络环境下,每个主机都分配了一个32位的IP地址,这种互联网地址是在网际范围标识主机的一种逻辑地址。为了让报文在物理网路上传送,必须知道对方目的主机的物理地址。这样就存在把IP地址变换成物理地址的地址转换问题。以以太网环境为例,为了正确地向目的主机传送报文,必须把目的主机的32位IP地址转换成为48位以太网的地址。这就需要在互连层有一组服务将IP地址转换为相应物理地址,这组协议就是ARP协议。另有电子防翻滚系统也称为ARP。
在以太网协议中规定,同一局域网中的一台主机要和另一台主机进行直接通信,必须要知道目标主机的MAC地址。而在TCP/IP协议栈中,网络层和传输层只关心目标主机的IP地址。这就导致在以太网中使用IP协议时,数据链路层的以太网协议接到上层IP协议提供的数据中,只包含目的主机的IP地址。 Bits
于是需要一种方法,根据目的主机的IP地址,获得其MAC地址。这就是ARP协议要做的事情。所谓地址解析(address resolution)就是主机在发送帧前将目标IP地址转换成目标MAC地址的过程。
ARP首部格式,如图2.6所
图2.6 ARP协议首部
(1) 硬件类型(Hardware Type)
对不同的链路层协议,使用不同的硬件接口类型,因此该字段用于指明当前使用的硬件接口类型,以太网的值为1。
(2) 协议类型(Protocol Type)
针对对于不同的网络层协议,该字段指明了发送方提供的高层协议类型,例如IP为0x0800。
(3) 硬件长度(Hardware Size)
指明当前链路层协议类型的地址长度。
(4) 协议长度(Protocol Size)
与硬件长度一样,该字段指明当前网络层协议使用的地址长度。
(5) 操作(Operation)
该字段字段用来表示这个报文的作用类型,ARP,如果是发出请求为1,响应则为2。
(6) 源主机硬件地址,目的主机硬件地址
确定源主机与目的主机在链路层通信使用的地址。
(7) 源主机协议地址,目的主机协议地址
表示源主机与目的主机的网络层使用的通信地址。
NetAnalyzer中的表示
图2.7 ARP原始数据
在NetAnalyzer中所得到的原始数据如图2.7所示,硬件类型 0x0001,为以太网;协议类型 0x0800因此网络层协议为IPv4;硬件长度0x06,以太网MAC地址站6个字节;协议长度 0x04,IPv4的地址站4个字节;操作:0x0001该数据报文是一个请求报文;之后便是一些地址信息。
NetAnalyzer中分析ARP协议的结果如图2.8
图2.8 ARP在NetAnalyzer中的分析结果
4 网际协议第四版(IPv4)
IPv4,是互联网协议(Internet Protocol,IP)的第四版,也是第一个被广泛使用,构成现今互联网技术的基石的协议。1981年 Jon Postel 在RFC791中定义了IP,Ipv4可以运行在各种各样的底层网络上,比如端对端的串行数据链路(PPP协议和SLIP协议) ,卫星链路等等。局域网中最常用的是以太网。
IPv4首部一般是20字节长。在以太网帧中,IPv4包首部紧跟着以太网帧首部,同时以太网帧首部中的协议类型值设置为0800。 IPv4提供不同,大部分是很少用的选项,使得IPv4包首部最长可扩展到60字节(总是4个字节4个字节的扩展) 。
IPv4首部格式如图2.9所示
图2.9 IPv4首部格式
(1) 版本(Version)
指出当前使用的 IP 版本,该协议版本文4。
(2) 首部长度(Head length)
IPv4的首部使用了选项字段,因此需要使用首部长度说明IP首部的偏移量。
(3) 区分服务
根据不同的使用情况,对数据传输方式进行传输质量区分,其指出上层协议对处理当前数据报所期望的服务质量,并对数据报按照重要性级别进行分配。这些8位字段用于分配优先级、延迟、吞吐量以及可靠性。
(4) 报文长度(Total Length)
指定整个 IP 数据包的字节长度,包括数据和协议头。其最大值为65,535字节。典型的主机可以接收576字节的数据报。
(5) 标识(Identification)
包含一个整数,用于识别当前数据报。该字段由发送端分配帮助接收端集中数据报分片。
(6) 标志(Flags)
由3位字段构成,其中低两位(最不重要)控制分片。中间位(DF)指出数据包是否可进行分片。低位(MF)指出在一系列分片数据包中数据包是否是最后的分片。第三位即最高位不使用。
(7) 片偏移量(Fragment Offset)
13位字段,指出与源数据报的起始端相关的分片数据位置,支持目标IP适当重建源数据报。
(8) 生存时间(Time to live)
是一种计数器,在丢弃数据报的每个点值依次减1直至减少为0。这样确保数据包无止境的环路过程。
(9) 协议(Protocol)
IP数据包分装的上一层协议的类型,如果为6,则上层协议为Tcp
(10) 首部校验和(Header Checksum)
帮助确保 IP 协议头的完整性。由于某些协议头字段的改变,如生存期(Time to Live),这就需要对每个点重新计算和检验。Internet 协议头需要进行处理。
(11) 源IP地址(Source Address),目的IP地址(Destination Address)
用于指定源主机的IP地址与目的主机的IP地址。
(12) 选项(Options)
IP 支持各种选项,该选项字段用来支持排错,测量以及安全等措施,此字段的长度可变,从1个字节到40个字节不等,取决于所选择的项目。
(13) 填充字段
该字段目的是解决因为选项字段不字节不确定而造成的IP首部不能对齐的问题,使用0填充确实的数据,使其成4字节对齐。
NetAnalyzer中获取的IPv4的原始数据如图2.10,
图2.10 IPv4原始数据
IPv4首部20个字节,没有选项字段,IP版本首部长度只用一个字节表示0x45,表示第四个版本,20个字节的首部;区分服务 0x00大多数IPv4报文并不设置该字段;报文长度 0x0028因此报文长度为40个字节;标识0x04B4;标志(010)2不需要分片,片偏移量(00000)2;生存时间0x40即64跳;协议0x06,表示上层协议为TCP,首部校验和0x0000这是一个无效的数据包;最后是两个方向的IP地址。
在NetAnalyzer中分析IPv4的结果如图2.11
图 2.11 IPv4在NetAnalyzer中分析的结果
5 网际协议第六版(IPv6)
IPv6是Internet Protocol Version 6的缩写,其中Internet Protocol译为“互联网协议”。IPv6是IETF(互联网工程任务组,Internet Engineering Task Force)设计的用于替代现行版本IP协议(IPv4)的下一代IP协议。目前IP协议的版本号是4(简称为IPv4),它的下一个版本就是IPv6。
IPv6的特点:
(1) IPV6地址长度为128比特,地址空间增大了2的9中国IPV6主干节点示意图
(2) [1]6次方倍;
(3) 灵活的IP报文头部格式。使用一系列固定格式的扩展头部取代了IPV4中可变长度的选项字段。IPV6中选项部分的出现方式也有所变化,使路由器可以简单路过选项而不做任何处理,加快了报文处理速度;
(4) IPV6简化了报文头部格式,字段只有8个,加快报文转发,提高了吞吐量;
(5) 提高安全性。身份认证和隐私权是IPV6的关键特性;
(6) 支持更多的服务类型;
(7) 允许协议继续演变,增加新的功能,使之适应未来技术的发展;
IPv6包由IPv6包头(40字节固定长度)、扩展包头和上层协议数据单元三部分组成。IPv6包扩展包头中的分段包头中指明了IPv6包的分段情况。其中不可分段部分包括:IPv6包头、Hop-by-Hop选项包头、目的地选项包头(适用于中转路由器)和路由包头;可分段部分包括:认证包头、ESP协议包头、目的地选项包头(适用于最终目的地)和上层协议数据单元。但是需要注意的是,在IPv6中,只有源节点才能对负载进行分段,并且IPv6超大包不能使用该项服务。
IPv6的固定首部格式
图2.12 IPv6固定首部
IPv6包头长度固定为40字节,去掉了IPv4中一切可选项,只包括8个必要的字段,因此尽管IPv6地址长度为IPv4的四倍,IPv6包头长度仅为IPv4包头长度的两倍。
(1) 版本(Version)
4位,IP协议版本号,值= 6。
(2) 通信量等级(Traffic Class)
8位,指示IPv6数据流通信类别或优先级。功能类似于IPv4的服务类型(TOS)字段。
(3) 游标记(Flow Label)
20位,IPv6新增字段,标记需要IPv6路由器特殊处理的数据流。该字段用于某些对连接的服务质量有特殊要求的通信,诸如音频或视频等实时数据传输。在IPv6中,同一信源和信宿之间可以有多种不同的数据流,彼此之间以非“0”流标记区分。如果不要求路由器做特殊处理,则该字段值置为“0”。
(4) 有效载荷(Payload Length)
16位负载长度。负载长度包括扩展头和上层PDU,16位最多可表示65535字节负载长度。超过这一字节数的负载,该字段值置为“0”,使用扩展头逐个跳段(Hop-by-Hop)选项中的巨量负载(Jumbo Payload)选项。
(5) 下个首部(Next Header)
8位,识别紧跟IPv6头后的包头类型,如扩展头(有的话)或某个传输层协议头(诸如TCP,UDP或着ICMPv6)。
(6) 跳数限制(Hop Limit)
8位,类似于IPv4的TTL(生命期)字段,用包在路由器之间的转发次数来限定包的生命期。包每经过一次转发,该字段减1,减到0时就把这个包丢弃。
(7) 源地址(Source Address)
128位,发送方主机地址。
(8) 目的地址(Destination Address)
128位,在大多数情况下,目的地址即信宿地址。但如果存在路由扩展头的话,目的地址可能是发送方路由表中下一个路由器接口。
扩展包头
IPv6包头设计中对原IPv4包头所做的一项重要改进就是将所有可选字段移出IPv6包头,置于扩展头中。由于除Hop-by-Hop选项扩展头外,其他扩展头不受中转路由器检查或处理,这样就能提高路由器处理包含选项的IPv6分组的性能。
NetAnalyzer中获取的IPv6原始数据如图2.13
图2.13 IPv6原始数据
NetAnalyzer中分析获取的IPv6的信息如图2.14
图 2.14 IPv6在Netanalyzer中的分析结果
6 网际控制报文协议(ICMP)
ICMP是(Internet Control Message Protocol)Internet控制报文协议。它是TCP/IP协议族的一个子协议,用于在IP主机、路由器之间传递控制消息。控制消息是指网络通不通、主机是否可达、路由是否可用等网络本身的消息。这些控制消息虽然并不传输用户数据,但是对于用户数据的传递起着重要的作用。
ICMP协议是一种面向无连接的协议,用于传输出错报告控制信息。它是一个非常重要的协议,它对于网络安全具有极其重要的意义。
它是TCP/IP协议族的一个子协议,属于网络层协议,主要用于在主机与路由器之间传递控制信息,包括报告错误、交换受限控制和状态信息等。当遇到IP数据无法访问目标、IP路由器无法按当前的传输速率转发数据包等情况时,会自动发送ICMP消息。
ICMP提供一致易懂的出错报告信息。发送的出错报文返回到发送原数据的设备,因为只有发送设备才是出错报文的逻辑接受者。发送设备随后可根据ICMP报文确定发生错误的类型,并确定如何才能更好地重发失败的数据包。但是ICMP唯一的功能是报告问题而不是纠正错误,纠正错误的任务由发送方完成。
我们在网络中经常会使用到ICMP协议,比如我们经常使用的用于检查网络通不通的Ping命令(Linux和Windows中均有),这个“Ping”的过程实际上就是ICMP协议工作的过程。还有其他的网络命令如跟踪路由的Tracert命令也是基于ICMP协议的。
ICMP首部格式
图2.15 ICMP报文格式
(1) 类型(Type)
用于定义ICMP报文的类型。
(2) 代码(Code)
用于定义标识发送这个特定报文类型的原因。
(3) 校验和(Check sum)
用于数据传输的差错控制,提供ICMP整个报文的校验和,其计算方法与IP首部的校验和计算方法类似。
(4) 首部其他部分
由报文类型来确定相应的内容,大部分差错报告未使用该字段。
(5) 数据(Data)
T提供了ICMP差错和状态报告信息,内容因报文类型而异。
7 传输控制协议(TCP)
TCP:Transmission Control Protocol 传输控制协议TCP是一种面向连接(连接导向)的、可靠的、基于字节流的运输层(Transport layer)通信协议,由IETF的RFC 793说明(specified)。在简化的计算机网络OSI模型中,它完成第四层传输层所指定的功能,UDP是同一层内另一个重要的传输协议。
在因特网协议族(Internet protocol suite)中,TCP层是位于IP层之上,应用层之下的运输层。不同主机的应用层之间经常需要可靠的、像管道一样的连接,但是IP层不提供这样的流机制,而是提供不可靠的包交换。
应用层向TCP层发送用于网间传输的、用8位字节表示的数据流,然后TCP把数据流分割成适当长度的报文段(通常受该计算机连接的网络的数据链路层的最大传送单元(MTU)的限制)。之后TCP把结果包传给IP层,由它来通过网络将包传送给接收端实体的TCP层。TCP为了保证不发生丢包,就给每个字节一个序号,同时序号也保证了传送到接收端实体的包的按序接收。然后接收端实体对已成功收到的字节发回一个相应的确认(ACK);如果发送端实体在合理的往返时延(RTT)内未收到确认,那么对应的数据(假设丢失了)将会被重传。TCP用一个校验和函数来检验数据是否有错误;在发送和接收时都要计算和校验。
首先,TCP建立连接之后,通信双方都同时可以进行数据的传输,其次,他是全双工的;在保证可靠性上,采用超时重传和捎带确认机制。
在流量控制上,采用滑动窗口协议,协议中规定,对于窗口内未经确认的分组需要重传。
在拥塞控制上,采用广受好评的TCP拥塞控制算法(也称AIMD算法),该算法主要包括三个主要部分:1,加性增、乘性减;2,慢启动;3,对超时事件做出反应。
TCP协议首部格式:
图2.16 Tcp协议首部格式
(1) 源端口(Source Port)
源主机进程的端口。
(2) 目的端口(Destination Port)
标识目的主机的进程端口号
(3) 序列号(Sequence Number)
在一个连接中用于确定该数据报文的偏移量。
(4) 确认序列号(Acknowledgement Number)
对对方主机发来的信息进行确认,从告诉对方已经成功获取的数据。
(5) 数据偏移量(Data Offset)
在一些书中也叫首部长度,因为TCP协议有扩展字段,所以需要使用该字段标注,无扩展字段时,为20。
(6) 保留字段
(7) 标志(Flags)
用于传递该报文的状态信息。
(8) 窗口大小(Window Size)
配合滑动窗口而设计的字段。
(9) 校验和(Check Sum)
对所传数据进行校验,以确定数据是否完整。
(10) 紧急指针(Urgent Pointer)
配合状态为标志URG使用,提醒主机尽快提交数据。
(11) 选项(Options)
用来完成如商议重新设定窗口大小等类似的任务。
NetAnalyzer中获取的TCP报文数据如图2.17,
图2.17 NetAnalyzer中获取的TCP原始数据
从图中可以看到该报文TCP字段有28个字节,所以TCP首部带有扩展字段。
NetAnalyzer中分析Tcp报文的结果如图2.18所示
图 2.18 TCP报文在NetAnalyzer中的分析结果
8 用户报文协议(UDP)
UDP 是User Datagram Protocol的简称, 中文名是用户数据包协议,是 OSI 参考模型中一种无连接的传输层协议,提供面向事务的简单不可靠信息传送服务。它是IETF RFC 768是UDP的正式规范。
UDP协议的全称是用户数据包协议,在网络中它与TCP协议一样用于处理
数据包,是一种无连接的协议。在OSI模型中,在第四层——传输层,处于IP协议的上一层。UDP有不提供数据包分组、组装和不能对数据包进行排序的缺点,也就是说,当报文发送之后,是无法得知其是否安全完整到达的。UDP用来支持那些需要在计算机之间传输数据的网络应用。包括网络视频会议系统在内的众多的客户/服务器模式的网络应用都需要使用UDP协议。UDP协议从问世至今已经被使用了很多年,虽然其最初的光彩已经被一些类似协议所掩盖,但是即使是在今天,UDP仍然不失为一项非常实用和可行的网络传输层协议。
与所熟知的TCP(传输控制协议)协议一样,UDP协议直接位于IP(网际协议)协议的顶层。根据OSI(开放系统互连)参考模型,UDP和TCP都属于传输层协议。
UDP协议的主要作用是将网络数据流量压缩成数据包的形式。一个典型的数据包就是一个二进制数据的传输单位。每一个数据包的前8个字节用来包含报头信息,剩余字节则用来包含具体的传输数据。
UDP首部格式
图2.19 UDP报文首部格式
(1) 源端口号(Source Port)
发送数据的主机端口号。
(2) 目的端口号(Destination Port)
接受数据的主机的端口号。
(3) 数据长度(Length)
整个报文的数据长度。
(4) 校验和(Checksum)
提取伪首部与UPD首部信息的校验和。
NetAnalyzer中获取的UDP原始数据如图2.20所示
图2.20 UDP报文原始数据
NetAnalyzer中获取的UDP报文首部如图2.21所示
图2.21 NetAnalyzer中获得的UDP首部信息
在这里只是对一些常用的网络协议做一些简单说明,事实上网络协议很多而且有些数据包也不会严格的按照OSI七层模型或TCP/IP的模型来执行,只有深入了理解他们,我们才可以进行后面的开发工作。我上面的文件都是自己搜集或做实验采集到的,文件格式为libpcap方式的pcap格式文件,你可以用著名Wirshark 打开,也可以用非著名的NetAnalyzer^_^,在这些文件中并没用加入SMTP和POP3两个著名的协议,老实说,我是故意的,因为通过抓包可以轻松的破解我的邮箱密码,所以我没放,你们可以试着去抓一下
SMTP 端口 53
POP3 端口 110
过滤表达式为: tcp port 53 or tcp port 110
具体怎么用,看帮助去吧
好了今天就写到这里,欢迎指正。
NetAnalzyer交流群:39753670 (PS 只提供交流平台,群主基本不说话^_^)
[转载请保留作者信息 作者:冯天文 网址:http://www.cnblogs.com/twzy/p/4762077.html]
标签:
原文地址:http://www.cnblogs.com/twzy/p/4762077.html