当前位置:首页 > python > 正文内容

python 发送和发送ICMP数据包

root4年前 (2021-11-01)python1564

ICMP协议在实际传输中数据包:20字节IP首部 + 8字节ICMP首部+ 1472字节<数据大小>38字节。对于ICMP首部细分为8位类型+8位代码+16位校验和+16位标识符+16位序列号

其中类型的取值如下,我们比较关注的是请求(取值为8)和应答(取值为0)


类型代码取值描述

00Echo Reply——回显应答(ping应答)

30Network Unreachable——网络不可达

31Host Unreachable——主机不可达

32Protocol Unreachable——协议不可达

33Port Unreachable——端口不可达

34Fragmentation needed but no frag. bit set——需要进行分片但设置不分片比特

35Source routing failed——源站选路失败

36Destination network unknown——目的网络未知

37Destination host unknown——目的主机未知

38Source host isolated(obsolete)——源主机被隔离(作废不用)

39Destination network administratively prohibited——目的网络被强制禁止

310Destination host administratively prohibited——目的主机被强制禁止

311Network unreachable for TOS——由于服务器型TOS,网络不可达

312Host unreachable for TOS——由于服务器型TOS,主机不可达

313Communication administratively pro hibited by filtering——由于过滤,通信被强制禁止

314Host precedence violation——主机越权

315Precedence cutoff effect——优先中止生效

40Source quench——源端被关闭(基本流控制)

50Redirect for network——对网络重定向

51Redirect for host—— 对主机重定向

52Redirect for TOS and network——对服务类型和网络重定向

53Redirect for TOS and host—— 对服务类型和主机重定向

80Echo request——回显请求(ping请求)

90Router advertisement——路由器通告

100Router solicitation—— 路由器请求

110TTL equals 0 during transit——传输期间生存时间为0

111TTL equals 0 during reassembly——再数据报组装期间生存时间为0

120IP header bad(catchall error)——坏的IP首部(包括各种差错)

121Required options missing——缺少必需的选项

130Timestamp request(obsolete)——时间戳请求(作废不用)

14Timestamp reply(obsolete)——时间戳应答(作废不用)

150Information request(obsolete)——信息请求(作废不用)

160Information reply(obsolete)——信息应答(作废不用)

170Address mask request——地址掩码请求

180Address mask reply——地址掩码应答

899843-20180510090410171-1299602822.png

SOCK_RAW 是指原始套接字

接收

import socket
import sys

while True:
    r = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.getprotobyname('ICMP'))
    r.settimeout(5)

    if sys.platform == 'win32':
        # windows对raw socket有限制,需要bind一个地址
        # https://docs.microsoft.com/en-us/windows/win32/winsock/tcp-ip-raw-sockets-2
        r.bind(("192.168.2.12", 0))
        # 设置混杂模式
        r.ioctl(socket.SIO_RCVALL, socket.RCVALL_ON)
    try:
        packet, address = r.recvfrom(1024)
        ipHeaderPacket = packet[0:20]
        sourceIp = "%d.%d.%d.%d" % (ipHeaderPacket[16], ipHeaderPacket[17], ipHeaderPacket[18], ipHeaderPacket[19])
        icmpHeaderPacket = packet[20:28]
        icmpType = icmpHeaderPacket[0]
        icmpCode = icmpHeaderPacket[1]
        print(f"{sourceIp}, {icmpType}, {icmpCode}")
    except Exception as e:
        print(e)

获取到请求数据包时,前20个字节是ip包,第12-15字节是当前接收机器ip,第16-19字节是发送ping机器的ip

icmp 包是ip包后面8字节,其中第一个字节是icmp的类型,第二字节是取值


发送

# coding=utf-8

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包
            result = sock.recvfrom(1024)
            ac_ip = result[1][0]
            print('[+] %s active' % (ac_ip))
        except Exception as e:
            print(e)
            sock.close()
        sock.close()

s = Pinger()
s.sendPing('192.168.2.12')


下面是参考文档


icmp类型和取值参考

icmp接收参考

icmp协议参考

icmp发送参考


扫描二维码推送至手机访问。

版权声明:本文由一叶知秋发布,如需转载请注明出处。

本文链接:https://zhiqiu.top/?id=170

分享给朋友:

相关文章

falsk &django +uwsgi 的配置文件

flask的uwsgi配置文件[uwsgi]pythonpath=/usr/bin/python3  #uwsgi采用的py版本,如果项目采用的py版本跟系统默认一直可以不用写base=/***/***/***  &nb...

自定义logger 模块使调用打印日志的文件为调用文件而不是logger模块

更新logging 源码1248行f f f.f_back替换为f f f.f_back     f_2 f.f_back   ...

python 的configparser 读取配置文件遇到%特殊符号

test.ini 配置文件中有mysql的密码,且密码含有“%”这个特殊符号因为%在py是转义符的含义需要对该字符转义即修改  %  为 %%用%对%进行转义...

selenium控制webdriver  设置请求头。只能设置简单的。自定义和固定的格式无法修改成功

selenium控制webdriver 设置请求头。只能设置简单的。自定义和固定的格式无法修改成功

time selenium webdriver options webdriver.() options.() options.( options.() browser webdriver....

pip 升级到指定版本,但是py2的pip版本务必在20版本以内包含20版本

python3 -m pip install --user --upgrade pip==9.0.3(换成你想要的版本编号)如果python2的只能升级到20+版本。超过会出现不支持的情况...

cmd启动python交互模式 出现UnicodeDecodeError: 'gbk' codec can't decode byte 0x9a in position 533

这是因为在python交互模式的中输出了中文,且是个输出被记录在.python_history中删除历史记录文件C:\Users\Administrator\.python_history...