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

python 发送和发送ICMP数据包

root3年前 (2021-11-01)python852

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

分享给朋友:

相关文章

python2 安装 mysqlclient

python2 安装 mysqlclient

ubuntu 20.04 python2.7安装mysqlclient 遇见问题解决方案:sudo apt-get install libmysqlclient-dev apt-get ...

flask的websocket的简单用例

flask的websocket的简单用例

后端代码flask Flask, render_template, request flask_socketio SocketIO, emit app (__name__,...

python 连接rabbitmq出现的诡异进程盗取消息

python 连接rabbitmq出现的诡异进程盗取消息

本文在py2下执行,由来:    因业务需要,python创建子线程后再次创建子进程(用于执行shell命令)。没错就是在子线程里面创建子进程。都知道py2的坑还是蛮多的。问题出现:在某次运行中出现了...

python简单的加密解密

rsa 是非对称加密公钥加密,私钥解密pip install rsaimport rsa from binascii import b2a_hex, a2b_hex class&nb...

python 装饰器 之打印函数执行时间

在实际开发中 遇见很多需要排查函数执行时间定位性能瓶颈点用装饰器获取函数执行的时间还是比较方便的import inspect import time def timethis(func):  ...

雪花算法 Snowflake python 实现代码

import time import logging # 分配位置 WORKER_BITS = 5 DATACENTER_BITS = 5 SEQUENCE...