python使用原始套接字 解析原始ip头数据
使用底层套接字解码底层流量,是这次做的重点工作。
首先来捕获第一个包
# 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头数据的更多相关文章
- C++ Win 32 使用原始套接字获取所有ip数据包并分析(包括ping包)
/*页面编码:GBK 开发环境 VS2019 */ #define _WINSOCK_DEPRECATED_NO_WARNINGS#include <iostream>#include&l ...
- Linux原始套接字实现分析---转
http://blog.chinaunix.net/uid-27074062-id-3388166.html 本文从IPV4协议栈原始套接字的分类入手,详细介绍了链路层和网络层原始套接字的特点及其内核 ...
- Linux基础(11)原始套接字
一边接收函数返回一边判断返回值时一定要把接收的优先级加()提高再去判断 例 if((sockfd = socket()) < 0) 问题: 如何实现SYN扫描器扫描端口 , 比如AB两个设备要进 ...
- Linux Socket 原始套接字编程
对于linux网络编程来说,可以简单的分为标准套接字编程和原始套接字编程,标准套接字主要就是应用层数据的传输,原始套接字则是可以获得不止是应用层的其他层不同协议的数据.与标准套接字相区别的主要是要开发 ...
- Linux系统编程(37)—— socket编程之原始套接字
原始套接字的特点 原始套接字(SOCK_RAW)可以用来自行组装IP数据包,然后将数据包发送到其他终端.也就是说原始套接字是基于IP数据包的编程(SOCK_PACKET是基于数据链路层的编程).另外, ...
- 关于linux 原始套接字编程
关于linux 网络编程最权威的书是<<unix网络编程>>,但是看这本书时有些内容你可能理解的不是很深刻,或者说只知其然而不知其所以然,那么如果你想搞懂的话那么我建议你可以看 ...
- 浅谈原始套接字 SOCK_RAW 的内幕及其应用(port scan, packet sniffer, syn flood, icmp flood)
一.SOCK_RAW 内幕 首先在讲SOCK_RAW 之前,先来看创建socket 的函数: int socket(int domain, int type, int protocol); domai ...
- Linux网络编程——原始套接字编程
原始套接字编程和之前的 UDP 编程差不多,无非就是创建一个套接字后,通过这个套接字接收数据或者发送数据.区别在于,原始套接字可以自行组装数据包(伪装本地 IP,本地 MAC),可以接收本机网卡上所有 ...
- Linux网络编程——原始套接字能干什么?
通常情况下程序员接所接触到的套接字(Socket)为两类: (1)流式套接字(SOCK_STREAM):一种面向连接的 Socket,针对于面向连接的TCP 服务应用: (2)数据报式套接字(SOCK ...
随机推荐
- go标准库的学习-text/template
参考:https://studygolang.com/pkgdoc 导入方式: import "text/template" template包实现了数据驱动的用于生成文本输出的模 ...
- oracle 查询 归档日志最大值和平均值
select max(ss.size_GB), avg(ss.size_GB) from (select s.*, rownum rn2 from (select a.* ...
- oracle备份信息查询
SELECT TRIM(START_TIME || '#'), TRIM(END_TIME || '#'), TRIM(CASE OUTPUT_DEVICE_TYPE ...
- Ubuntu16.04下安装配置phpmyadmin
在项目配置了阿里的druid,可以监控session,spring和详细sql的执行情况以及具体到表等信息,但是仍然发现不够详细,而且作为一个半吊子dba,一直用linux命令分配权限和管理数据库,效 ...
- 浅淡个人学习嵌入式Linux过程
我专业是电子信息工程,在初入大学的时候,我们的班主任便要我们多多去了解一些关于电子方面的知识.后来我了解到了嵌入式,继而了解到了嵌入式Linux.其实我们学习linux差不多就学习linux内核,但是 ...
- MySQL(九)插入、更新和删除
常用的SQL语句,除了select用于查询,还有insert.update.delete等. 一.insert insert:用来插入(或添加)行到数据库中,常见方式有以下几种: ①插入完整的行: ② ...
- sql实时提交事务
public void deleteByHbtlidAndDept(String class_id,String depart_id) { Session session = this.getHibe ...
- 【转】Oracle virtual column(虚拟列)
为什么要使用虚拟列 (1)可以为虚拟列创建索引(Oracle为其创建function index) (2)可以搜集虚拟列的统计信息statistics,为CBO提供一定的采样分析. (3)可以在whe ...
- 【强化学习】python 实现 q-learning 例四(例二改写)
将例二改写成面向对象模式,并加了环境! 不过更新环境的过程中,用到了清屏命令,play()的时候,会有点问题.learn()的时候可以勉强看到:P 0.效果图 1.完整代码 相对于例一,修改的地方: ...
- Sql_join left right
1.内连接inner join 只返回两张表中所有满足连接条件的行,即使用比较运算符根据每个表中共有的列的值匹配两个表中的行.(inner关键字是可省略的) ①传统的连接写法: 在FROM子句中列出所 ...