基于ICMP协议的ping命令,icmp协议 ping

  基于ICMP协议的ping命令,icmp协议 ping

  一、ICMP协议分析ICMP:互联网控制报文协议。由于IP协议不是一个可靠的协议,它不能保证数据的成功传输。那么,我们如何确保数据的可靠传递呢?这里需要用到一个重要的协议模块ICMP(网络控制消息)协议。它传输错误消息和其他需要注意的信息,通常由IP层或更高层协议(TCP或UDP)使用。因此它通常被认为是IP层不可分割的一部分。其在IP数据消息中的封装如下:

  ICMP的数据报文格式如下。所有消息的前4个字节都是相同的,其他的由于消息类型不同而不同。类型字段可以有15个不同的值来描述不同的ICMP消息。校验和字段包含整个ICMP消息,并使用与IP报头校验和相同的算法。有关详细信息,请搜索TCP/IP校验和算法。

  不同类型的消息由类型字段和代码字段共同确定。下表显示了各种类型的ICMP消息。

  根据上表,ICMP协议大致可以分为两类,一类是查询报文,一类是错误报文。查询由一对请求和响应定义,通常有以下用途:

  Ping子网掩码查询(用于无盘工作站初始化自身时初始化子网掩码)时间戳查询(可用于同步时间),错误消息通常包含导致错误的IP数据报第一个片段的IP头(和选项),加上片段数据部分的前8个字节。RFC 792规范中定义的这8个字节包含了数据包传输层报头的所有解复用信息,这样传输层协议就可以将ICMP错误消息提交给正确的进程。

  当IP包传输出现错误时,如主机不可达、端口不可达等。ICMP协议会将错误信息打包,然后发送回主机。给主机一个处理错误的机会,这也是基于IP层的协议能够安全的原因。从上面可以看出,互联网控制报文协议由8位错误类型、8位代码和16位校验和组成,前16位组成ICMP想要传输的信息。数据链路层可以发送的最大数据帧,即MTU(最大传输单位)是1500。很容易计算出ICMP协议在实际传输中的数据包为:20字节IP头,8字节ICMP头,1472字节(数据大小)。

  虽然在大多数情况下,ICMP消息应该在错误的数据包传输中给出,但在特殊情况下,ICMP错误消息不会生成。如下

  ICMP错误消息不会生成ICMP错误消息(传出IMCP查询消息)(防止IMCP的无限生成和传输)。目的地址是广播地址或多播地址的IP数据报。作为链路层的数据报广播。不是IP碎片化的第一块。源地址不是单一主机的数据报。也就是说,源地址不能是零地址、环回地址、广播地址或组播地址。

  二、ping程序原理分析ping程序是Mike Muuss写的,用来测试另一台主机是否可达。现在它已经成为一个常用的网络状态检查工具。该程序向远程主机发送ICMP回应请求消息,并等待ICMP回应回复。借助ping的原理,出现了很多基于ping的网络扫描器,如nmap、arping、f ping、hp3等。因此,随着互联网安全意识的增强,可以设置一些提供访问控制策略的路由器和防火墙来过滤特定的ICMP消息请求。因此,无法通过简单的ping命令来判断远程主机是否在线。

  Ping使用icmp协议,该协议向目的主机发送ICMP回应请求消息。ICMP协议规定,目的主机必须向源主机返回ICMP回应回复消息。如果源主机在一定时间内收到应答,则认为该主机是可到达的。的大多数TCP/IP实现都支持直接在内核中Ping服务器,ICMP回应请求和回应回复消息如下图所示。

  ping的原理是使用类型代码为0的ICMP发送请求,而被请求的主机使用类型代码为8的ICMP进行响应。通过计算ICMP响应消息的数量和收发消息的时间差,可以判断当前的网络状态。往返时间的计算方法如下:ping命令发送ICMP报文时,将当前时间值存储在ICMP报文中并发送出去;当回复消息返回时,它使用当前时间值减去存储在ICMP消息数据中的时间值来计算往返时间。通过ping返回接收到的数据消息的字节大小、TTL值和往返时间。

  Unix在执行ping程序时,将ICMP消息中的标识符字段设置为发送进程的id号。这样,即使ping程序的多个实例同时在同一台主机上运行,ping程序也可以识别返回的信息。

  三。应用ICMP - TracerouteTraceroute是检测从主机到目的地的路由的一个重要和最方便的工具。如前所述,虽然ping工具也可以检测,但由于ip头的限制,ping无法完整记录其经过的路由器。所以Traceroute正好填补了这个空白。

  Traceroute的原理非常非常有趣。在收到目的主机的IP后,它首先向目的主机发送一个TTL=1(还记得TTL是什么吗?),而第一个路由器收到这个数据包后,会自动将TTL减1,TTL变为0后,路由器会丢弃这个数据包,同时会生成一个主机无法到达的ICMP数据,上报给主机。主机收到这个数据报后,再向目的主机发送一个TTL=2的UDP数据报,然后刺激第二个路由器向主机发送ICMP数据报。依此类推,直到到达目的主机。这样,traceroute就获得了所有路由器的ip地址。从而避免了ip头只能记录有限的路由IP的问题。

  有人要问了,我怎么知道UDP有没有到达目的主机?这涉及到一个技术问题。TCP和UDP协议都有一个端口号定义,而普通的网络程序只监控少数几个端口号较小的端口,比如80、23等等。Traceroute发送的UDP数据报端口号为30000(异常),所以到达目的主机时,目的主机只能向主机发送一个不可达端口的ICMP数据报。主人接到这个报告后,知道主人到了。所以说Traceroute是骗子一点都不为过。

  Traceroute程序提供了一些非常有用的选项,甚至包括IP路由的选项。这些请参考man文档了解,这里就不赘述了。

  第四,python实现ping程序方法。首先,简单实现了使用python脚本调用系统中的ping命令。

  导入子流程

  导入shlex

  cmd=ping -c 1 www.baidu.com

  args=shlex.split(cmd)

  尝试:

  subprocess.check_call(args,stdout=subprocess。管道,stderr=子进程。管道)

  打印“百度服务器启动!”

  除了子流程。CalledProcessError:

  “打印”未能获得ping但是,在许多情况下,系统中的ping可执行文件是不可用或不可访问的。此时,您需要使用纯python检查脚本。下面是ICMP ping的python实现脚本。该脚本定义了一个Pinger类,它使用do_checksum()方法检查总和,使用send_ping()方法发送ping数据消息,使用receive_ping()方法接受ping数据消息,使用ping () main方法执行该类。下面是具体代码。

  #定义Pinger类,初始化并创建实例。

  导入操作系统

  导入argparse

  导入插座

  导入结构

  导入选择

  导入时间

  ICMP_ECHO_REQUEST=8 #特定于平台

  DEFAULT_TIMEOUT=2

  默认计数=4

  类Pinger(对象):

   Pings主机Pythonic方式

  def __init__(self,target_host,count=DEFAULT_COUNT,timeout=DEFAULT_TIMEOUT):

  self.target_host=目标主机

  self.count=计数

  self . time out=time out do _ checksum()方法定义如下,用于检查和验证总和。验证方法如下:

  把校验和字段置为0将网间控制报文协议包(包括页眉和数据)以16位(2个字节)为一组,并将所有组相加(二进制求和)若高16位不为0,则将高16位与低16位反复相加,直到高16位的值为0,从而获得一个只有16位长度的值将此16位值进行按位求反操作,将所得值替换到校验和字段具体算法可以搜索:【TCP/IP】检验和算法。

  定义do_checksum(自身,源字符串):

  验证数据包完整性

  总和=0

  max _ count=(len(source _ string)/2)* 2

  计数=0

  同时计数最大计数:#分割数据每两比特(16位)为一组

  val=ord(source _ string[count 1])* 256 ord(source _ string[count])

  总和=总和值

  总和=总和0xffffffff

  计数=计数2

  if max _ count len(source _ string):span #如果数据长度为基数,则将最后一位单独相加/span

  sum=sum ord(source _ string[len(source _ string)-1])

  总和=总和0xffffffff

  总和=(总和16)(总和0xffff) #将高16位与低16位相加直到高16位为0

  sum=sum (sum 16)

  答案=~总和

  答案=答案0xffff

  答案=答案8 (答案80xff00)

  返回答案#返回的是十进制整数下面是接受网间控制报文协议(互联网控制消息协议)类型码为8的网间控制报文协议(互联网控制消息协议)回应报文的方法。在未到达超时时间之前窝处于阻塞状态一直等待响应,当有数据传回时就接受响应,然后提取包含标识符身份的网间控制报文协议(互联网控制消息协议)报文首部和包含发送时间值的网间控制报文协议(互联网控制消息协议)内容部分,计算请求-响应的延时间隔。

  def receive_ping(self,sock,ID,timeout):

  从套接字接收平.

  剩余时间=超时

  虽然正确:

  start_time=time.time()

  readable=select.select([sock],[],[],time_remaining)

  时间花费=(时间。时间()-开始时间)

  如果可读[0]==[]: #超时

  返回

  time_received=time.time()

  recv_packet,addr=sock.recvfrom(1024)

  icmp_header=recv_packet[20:28]

  类型、代码、校验和、packet_ID、sequence=struct.unpack(

  bbHHh ,icmp_header

  )

  如果数据包ID==ID:

  bytes _ In _ double=struct计算大小( d )

  time_sent=struct.unpack(d ,recv _ packet[28:28 bytes _ In _ double])[0]

  返回接收时间-发送时间

  剩余时间=剩余时间-花费的时间

  如果剩余时间=0:

  返回下面定义的send_ping()方法,获取远程主机的域名服务器(域名服务器)主机名,然后使用结构体模块创建一个ICMP _回应_请求数据包,将查验请求的数据发送到目标主机。在此发送前也需要进行do_checksum()方法的校验。

  def send_ping(self,sock,ID):

  向目标主机发送砰命令

  target _ addr=套接字。gethostbyname(self。目标_主机)

  我的校验和=0

  #创建一个校验和为0的虚拟海德尔.

  header=struct.pack(bbHHh ,ICMP_ECHO_REQUEST,0,my_checksum,ID,1)

  bytes _ In _ double=struct计算大小( d )

  数据=(192字节双精度)* Q

  data=struct.pack(d ,time.time())数据

  #获取数据和伪报头的校验和。

  我的校验和=self.do_checksum(头数据)

  header=struct.pack(

  bbHHh ,ICMP_ECHO_REQUEST,0,socket.htons(my_checksum),ID,1

  )

  数据包=标题数据

  sock.sendto(packet,(target_addr,1))下面定义了一个ping_once()方法,向远程主机发送一次查验:将网间控制报文协议(互联网控制消息协议)协议传给插座()方法,创建一个原始的网间控制报文协议(互联网控制消息协议)套接字。由于砰程序需要使用袜子_RAW来构建数据包,所以需要根权限才能运行这个程序。因此,本程序需要使用根权限运行,下面的异常处理部分就是来负责未使用根运行时抛出的异常。

  定义ping_once(自身):

  超时时返回延迟(秒)或无。

  icmp=套接字。getprotobyname( icmp )

  尝试:

  sock=socket.socket(插座.AF_INET,插座.SOCK_RAW,icmp)

  除了socket.error,(errno,msg):

  如果errno==1:

  #不是超级用户,因此不允许操作

  msg=ICMP消息只能从根用户进程发送

  引发套接字.错误(消息)

  除了例外,e:

  "打印"异常:% s"%"(e)

  my_ID=os.getpid()0xFFFF

  self.send_ping(sock,my_ID)

  delay=self.receive_ping(sock,my_ID,self.timeout)

  sock.close()

  返回延迟下面这个ping()是执行这个类的主要方法。在为循环中调用ping_once()方法,发送砰数据报文,并返回结果。

  定义乒(自己):

  运行砰进程

  对于润智中的我(自我。计数):

  打印" Ping % s . "% self.target _主机

  尝试:

  delay=self.ping_once()

  除了socket.gaierror,e:

  "打印“平失败。(套接字错误:" % s")"% e[1]

  破裂

  如果延迟==无:

  "打印“平失败%ssec内超时% self.timeout

  否则:

  延迟=延迟* 1000

  打印"在% 0.4毫秒内获得平”延迟

  if __name__==__main__ :

  parser=argparse .ArgumentParser(描述=Python ping )

  解析器。add _ argument(-target-host ,action=store ,dest=target_host ,required=True)

  given_args=parser.parse_args()

  目标主机=给定参数。目标主机

  pinger=Pinger(目标主机=目标主机)

  pinger.ping()完整代码

  参考参考1

  参考2

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: