使用底层套接字解码底层流量,是这次做的重点工作。

首先来捕获第一个包

# coding:utf-8import socket

# 监听的主机IP
host = "192.168.1.100" socket_protocol = socket.IPPROTO_ICMP sniffer = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket_protocol)
sniffer.bind((host, 0))
sniffer.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1) raw_buffer = sniffer.recvfrom(65535)
print raw_buffer

下面一行一行解释上面代码的意思。

1. 导入socket包

2. 需要监听的本机ip地址

3. 给socket_protocol变量赋值icmp变量

4. 为sniffer变量创建一个soket对象,该对象为ipv4 原始套接字并指定其协议为icmp

5. 绑定到指定地址和端口进行监听

6. 为sniffer套接字设置选项参数,使其携带ip头

7. 将监听端口的套接字收到的原始数据赋值给raw_buffer

8. 打印raw_buffer的值

这个时候,我们使用root权限运行这个脚本,并且开启另外一个terminal对任意一个地址发送icmp包,我们监听的接口的recvfrom 会收到回监听回包到指定地址。recvfrom与recv不同的是 recvfrom会同时接收回包地址。(string, address)的格式

这个时候我们可以看到打印出来的值,是一堆完全看不懂的东西,因为是没有解码的状态,下面我们将对ip头进行解码。

使用python的struct和ctypes两个库实现这一点。

# coding:utf-8import socket
import struct
from ctypes import * # 监听的主机IPhost = "192.168.1.100" # IP头定义
class IP(Structure):
_fields_ = [
("ihl", c_ubyte, 4),
("version", c_ubyte, 4),
("tos", c_ubyte),
("len", c_ushort),
("id", c_ushort),
("offset", c_ushort),
("ttl", c_ubyte),
("protocol_num", c_ubyte),
("sum", c_ushort),
("src", c_uint),
("dst", c_uint),
] def __new__(self, socket_buffer=None):
return self.from_buffer_copy(socket_buffer) def __init__(self, socket_buffer=None):
self.protocol_map = {1: "ICMP", 6: "TCP", 17: "UDP"} # readable ip address
self.src_address = socket.inet_ntoa(struct.pack("<I", self.src))
self.dst_address = socket.inet_ntoa(struct.pack("<I", self.dst)) # type of protocol
try:
self.protocol = self.protocol_map[self.protocol_num]
except:
self.protocol = str(self.protocol_num) socket_protocol = socket.IPPROTO_ICMP sniffer = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket_protocol)
sniffer.bind((host, 0))
sniffer.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1) try:
while True:
raw_buffer = sniffer.recvfrom(65535)[0] ip_header = IP(raw_buffer[:20]) print "Protocol: %s %s -> %s " % (ip_header.protocol, ip_header.src_address, ip_header.dst_address) except KeyboardInterrupt:
pass

1. 导入各模块

2. 监听的本机ip地址

3. 使用ctypes 构造一个解析ip头的结构体(structure) IP

4. 使用from_buffer_copy方法在__new__方法将收到的数据生成一个IP class的实例

5. __init__方法初始化一部分数据保存到对应的实例属性值中。

6. 特别说明下面代码, 使用了python struct库的pack方法 用指定的格式化参数将src 和dst的long型数值转换为字符串,然后使用socket.inet_ntoa方法将字符串的一串数字转换为对应的ip格式。最后赋值给对应的src或者dst变量

# readable ip address
self.src_address = socket.inet_ntoa(struct.pack("<I", self.src))
self.dst_address = socket.inet_ntoa(struct.pack("<I", self.dst))

7. 一个接收icmp包的服务器,没什么说的。

8. 无限循环监听指定端口,将recvfrom收到的数据的第一部分 也就是不要ip地址的部分传递给raw_buffer

9. ip头raw_buffer的前20个字节传递给结构体进行解码。

10. 然后打印。

可以看到大致思路就是,将原型socket数据拿过来,然后通过模拟c语言的结构体,使用python的库对这个格式的包进行一一对应的解码,将解码之后的数据打印出来。

到此为止可以看到,在ip层已经可以解析出数据包从哪儿去哪儿的信息。

python使用原始套接字 解析原始ip头数据的更多相关文章

  1. C++ Win 32 使用原始套接字获取所有ip数据包并分析(包括ping包)

    /*页面编码:GBK 开发环境 VS2019 */ #define _WINSOCK_DEPRECATED_NO_WARNINGS#include <iostream>#include&l ...

  2. Linux原始套接字实现分析---转

    http://blog.chinaunix.net/uid-27074062-id-3388166.html 本文从IPV4协议栈原始套接字的分类入手,详细介绍了链路层和网络层原始套接字的特点及其内核 ...

  3. Linux基础(11)原始套接字

    一边接收函数返回一边判断返回值时一定要把接收的优先级加()提高再去判断 例 if((sockfd = socket()) < 0) 问题: 如何实现SYN扫描器扫描端口 , 比如AB两个设备要进 ...

  4. Linux Socket 原始套接字编程

    对于linux网络编程来说,可以简单的分为标准套接字编程和原始套接字编程,标准套接字主要就是应用层数据的传输,原始套接字则是可以获得不止是应用层的其他层不同协议的数据.与标准套接字相区别的主要是要开发 ...

  5. Linux系统编程(37)—— socket编程之原始套接字

    原始套接字的特点 原始套接字(SOCK_RAW)可以用来自行组装IP数据包,然后将数据包发送到其他终端.也就是说原始套接字是基于IP数据包的编程(SOCK_PACKET是基于数据链路层的编程).另外, ...

  6. 关于linux 原始套接字编程

    关于linux 网络编程最权威的书是<<unix网络编程>>,但是看这本书时有些内容你可能理解的不是很深刻,或者说只知其然而不知其所以然,那么如果你想搞懂的话那么我建议你可以看 ...

  7. 浅谈原始套接字 SOCK_RAW 的内幕及其应用(port scan, packet sniffer, syn flood, icmp flood)

    一.SOCK_RAW 内幕 首先在讲SOCK_RAW 之前,先来看创建socket 的函数: int socket(int domain, int type, int protocol); domai ...

  8. Linux网络编程——原始套接字编程

    原始套接字编程和之前的 UDP 编程差不多,无非就是创建一个套接字后,通过这个套接字接收数据或者发送数据.区别在于,原始套接字可以自行组装数据包(伪装本地 IP,本地 MAC),可以接收本机网卡上所有 ...

  9. Linux网络编程——原始套接字能干什么?

    通常情况下程序员接所接触到的套接字(Socket)为两类: (1)流式套接字(SOCK_STREAM):一种面向连接的 Socket,针对于面向连接的TCP 服务应用: (2)数据报式套接字(SOCK ...

随机推荐

  1. go标准库的学习-strconv-字符串转换

    参考:https://studygolang.com/pkgdoc 导入: import "strconv" strconv包实现了基本数据类型和其字符串表示的相互转换. 1)ap ...

  2. python opencv画图可视化

    画直线 import numpy as np import cv2 # Create a black image img = np.zeros((512,512,3), np.uint8) # Dra ...

  3. C++ 实现strcpy

    strcpy库函数的原型: // 把src字符串拷贝到dest,并返回dest char *strcpy(char *dest, const char *src) 注意点: 1.形参src用const ...

  4. linux gcc nginx

    1.安装GCC[root@rekfan.com opt]# rpm -ivh cpp-4.1.2-48.el5.i386.rpm[root@rekfan.com opt]# rpm -ivh kern ...

  5. 看think in java 随笔

    java的方法是运行期动态绑定上去的,可以根据自己真正实例化的类来判断调用哪个方法,比如子类重写了父类方法,会调用子类方法. 而利用final关键字可以让方法不能重写,就可以在编译期就绑定,这样就可以 ...

  6. HashMap 的实现原理

    hashMap用了一个名字为table的数组:还有若干个名字为entry的链表.看hashMap是如何应用这些数据结构的.用插 入<key,value>举例:hashMap首先会通过key ...

  7. 人生苦短之学习Python50本书籍(包涵基础、算法、机器学习、模块、爬虫框架、树莓派等)总有你想要的书籍

    很多小伙伴说想学习想学习但是没有学习书籍,我给大家分享一大波学习书籍,具体的可以自己往下翻 ​<"笨办法学"Python3> Zed Shaw 著 (2018年5月) ...

  8. Luogu4622 COCI2012-2013#6 JEDAN 组合、DP

    传送门 题意:给出一个$N$个数的序列$a_i$,其中$a_i=-1$表示第$i$个位置数字未知,问有多少种用非负整数代替$a_i$中$-1$的方法使得从全$0$序列经过以下操作若干次得到序列$a_i ...

  9. 生成线上用https证书,支持通配符和多域名,初学Let’s Encrypt用于IIS,纯本地手动

    自简书发布的上篇<生成本地测试用https证书,支持通配符和多域名,初学OpenSSL>以来,本地测试用https用的妥妥的. 线上一直用的腾讯云的免费证书(每个域名都要一个证书(滑稽), ...

  10. Quartz.Net分布式任务管理平台

           无关主题:一段时间没有更新文章了,与自己心里的坚持还是背驰,虽然这期间在公司做了统计分析,由于资源分配问题,自己或多或少的原因,确实拖得有点久了,自己这段时间也有点松懈,借口就不说那么多 ...