73 lines
2.3 KiB
Python
73 lines
2.3 KiB
Python
#!/usr/bin/python
|
|
# -*- coding:utf-8 _*-
|
|
"""
|
|
@author: pengtao
|
|
@file: mping.py
|
|
@time: 2020/03/26
|
|
"""
|
|
|
|
import os
|
|
import socket
|
|
import struct
|
|
import array
|
|
|
|
|
|
class Pinger(object):
|
|
def __init__(self, timeout=3):
|
|
self.timeout = timeout
|
|
self.__id = os.getpid()
|
|
self.__data = struct.pack('h', 1) # h代表2个字节与头部8个字节组成偶数可进行最短校验
|
|
|
|
@property
|
|
def __icmpSocket(self): # 返回一个可以利用的icmp原对象,当做属性使用
|
|
icmp = socket.getprotobyname("icmp") # 指定服务
|
|
sock = socket.socket(socket.AF_INET, socket.SOCK_RAW, icmp) # socket.SOCK_RAW原生包
|
|
return sock
|
|
|
|
|
|
def __doCksum(self, packet): # 校验和运算
|
|
words = array.array('h', packet) # 将包分割成2个字节为一组的网络序列
|
|
sum = 0
|
|
for word in words:
|
|
sum += (word & 0xffff) # 每2个字节相加
|
|
sum = (sum >> 16) + (sum & 0xffff) # 因为sum有可能溢出16位所以将最高位和低位sum相加重复二遍
|
|
sum += (sum >> 16) # 为什么这里的sum不需要再 & 0xffff 因为这里的sum已经是16位的不会溢出,可以手动测试超过65535的十进制数字就溢出了
|
|
return (~sum) & 0xffff # 最后取反返回完成校验
|
|
|
|
@property
|
|
def __icmpPacket(self): # icmp包的构造
|
|
header = struct.pack('bbHHh', 8, 0, 0, self.__id, 0)
|
|
packet = header + self.__data
|
|
cksum = self.__doCksum(packet)
|
|
header = struct.pack('bbHHh', 8, 0, cksum, self.__id, 0) # 将校验带入原有包,这里才组成头部,数据部分只是用来做校验所以返回的时候需要返回头部和数据相加
|
|
return header + self.__data
|
|
|
|
|
|
def sendPing(self, target_host):
|
|
|
|
try:
|
|
socket.gethostbyname(target_host)
|
|
|
|
sock = self.__icmpSocket
|
|
sock.settimeout(self.timeout)
|
|
|
|
packet = self.__icmpPacket
|
|
|
|
sock.sendto(packet, (target_host, 1)) # 发送icmp包
|
|
|
|
ac_ip = sock.recvfrom(1024)[1][0]
|
|
print('[+] %s active' % (ac_ip))
|
|
except Exception:
|
|
sock.close()
|
|
return False
|
|
return True
|
|
|
|
|
|
def main():
|
|
pp = Pinger()
|
|
pp.sendPing('192.168.100.20')
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|