libpcap之socket创建

一、 lipcap回调注册

在libpcap中,最重要的就是打开接口,其中关键函数为pcap_activate。这里只关注Linux平台。
只分析通用平台。

pcap_t *
pcap_create(const char *device, char *errbuf)
{
...
p = pcap_create_interface(device_str, errbuf);
...
}
// pcap-linux.c
pcap_t *
pcap_create_interface(const char *device, char *ebuf)
{pcap_t *handle;handle = pcap_create_common(ebuf, sizeof (struct pcap_linux));if (handle == NULL)return NULL;handle->activate_op = pcap_activate_linux;...

二、libpcap激活接口 - step1

int
pcap_activate(pcap_t *p)
{
...
status = p->activate_op(p);
...
}
static int
pcap_activate_linux(pcap_t *handle)
{...handle->inject_op = pcap_inject_linux;handle->setfilter_op = pcap_setfilter_linux;handle->setdirection_op = pcap_setdirection_linux;handle->set_datalink_op = pcap_set_datalink_linux;handle->getnonblock_op = pcap_getnonblock_fd;handle->setnonblock_op = pcap_setnonblock_fd;handle->cleanup_op = pcap_cleanup_linux;handle->read_op = pcap_read_linux;handle->stats_op = pcap_stats_linux;...ret = activate_new(handle);
static int
activate_new(pcap_t *handle)
{
.../** Open a socket with protocol family packet. If the* "any" device was specified, we open a SOCK_DGRAM* socket for the cooked interface, otherwise we first* try a SOCK_RAW socket for the raw interface.*/sock_fd = is_any_device ?socket(PF_PACKET, SOCK_DGRAM, protocol) :socket(PF_PACKET, SOCK_RAW, protocol);

只考虑抓取某个特定网卡的流量,因此 socket_fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))

三、进入kernel 创建socket

int sock_create(int family, int type, int protocol, struct socket **res)
{return __sock_create(current->nsproxy->net_ns, family, type, protocol, res, 0);
}int __sock_create(struct net *net, int family, int type, int protocol,struct socket **res, int kern)
{int err;struct socket *sock;const struct net_proto_family *pf;.../**	Allocate the socket and allow the family to set things up. if*	the protocol is 0, the family is instructed to select an appropriate*	default.*/sock = sock_alloc();...sock->type = type;...pf = rcu_dereference(net_families[family]);
...err = pf->create(net, sock, protocol, kern);
...*res = sock;return 0;
...
}

首先根据family获取对应的协议族处理函数,然后通过回调create函数进行实际的创建
这里create的回调为packet_create

static int packet_create(struct net *net, struct socket *sock, int protocol,int kern)
{struct sock *sk;struct packet_sock *po;__be16 proto = (__force __be16)protocol; /* weird, but documented */int err;if (!capable(CAP_NET_RAW))return -EPERM;if (sock->type != SOCK_DGRAM && sock->type != SOCK_RAW &&sock->type != SOCK_PACKET)return -ESOCKTNOSUPPORT;sock->state = SS_UNCONNECTED;err = -ENOBUFS;sk = sk_alloc(net, PF_PACKET, GFP_KERNEL, &packet_proto);if (sk == NULL)goto out;sock->ops = &packet_ops;if (sock->type == SOCK_PACKET)sock->ops = &packet_ops_spkt;sock_init_data(sock, sk);po = pkt_sk(sk);sk->sk_family = PF_PACKET;po->num = proto;sk->sk_destruct = packet_sock_destruct;sk_refcnt_debug_inc(sk);/**	Attach a protocol block*/spin_lock_init(&po->bind_lock);mutex_init(&po->pg_vec_lock);po->prot_hook.func = packet_rcv;if (sock->type == SOCK_PACKET)po->prot_hook.func = packet_rcv_spkt;po->prot_hook.af_packet_priv = sk;if (proto) {po->prot_hook.type = proto;register_prot_hook(sk);}spin_lock_bh(&net->packet.sklist_lock);sk_add_node_rcu(sk, &net->packet.sklist);sock_prot_inuse_add(net, &packet_proto, 1);spin_unlock_bh(&net->packet.sklist_lock);return 0;
out:return err;
}

这里关键是设置了po->prot_hook.func = packet_rcv;, 后续处理数据就是这个入口
以及register_prot_hook将回调注册到ptype_all链表中

static void register_prot_hook(struct sock *sk)
{struct packet_sock *po = pkt_sk(sk);if (!po->running) {...dev_add_pack(&po->prot_hook);...po->running = 1;}
}
// net/core/dev.c
static inline struct list_head *ptype_head(const struct packet_type *pt)
{if (pt->type == htons(ETH_P_ALL))return &ptype_all;elsereturn &ptype_base[ntohs(pt->type) & PTYPE_HASH_MASK];
}
void dev_add_pack(struct packet_type *pt)
{struct list_head *head = ptype_head(pt);spin_lock(&ptype_lock);list_add_rcu(&pt->list, head);spin_unlock(&ptype_lock);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/86704.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【性能测试】JMeter:集合点,同步定时器的应用实例!

一、集合点的定义 在性能测试过程中,为了真实模拟多个用户同时进行操作以度量服务器的处理能力,可以考虑同步虚拟用户以便恰好在同一时刻执行操作或发送请求。 通过插入集合点可以较真实模拟多个用户并发操作。 (注意:虽然通过加入集合点可…

Go内置函数make和new的区别?

首先纠正一下make 和 new 是内置函数,不是关键字。 变量初始化,一般分为2步,变量声明变量内存分配,var 关键字就是用来声明变量的,new和make 函数主要是用来分配内存的。 var 声明值类型的变量时,系统会默…

利用Socks5代理IP加强跨界电商爬虫的网络安全

随着跨界电商的兴起,爬虫技术在这个领域变得越来越重要。然而,网络安全一直是一个值得关注的问题。在本文中,我们将讨论如何利用代理IP和Socks5代理来增强跨界电商爬虫的网络安全,确保稳定和可靠的数据采集,同时避免封…

Leetcode13. 罗马数字转整数

力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台 罗马数字包含以下七种字符: I, V, X, L,C,D 和 M。 字符 数值 I 1 V 5 X 10 L 5…

Vector Art - 矢量艺术

什么是矢量艺术? 矢量图形允许创意人员构建高质量的艺术作品,具有干净的线条和形状,可以缩放到任何大小。探索这种文件格式如何为各种规模的项目提供创造性的机会。 什么是矢量艺术作品? 矢量艺术是由矢量图形组成的艺术。这些图形是基于…

后端面试关键问题大总结

一、Java基础 1.HashMap的底层原理 2.说一下List的特点 3.介绍一下Java的基本数据类型 (问到这个问题说明你触碰到面试官的技术能力水平底线了) 二、线程 1.说一下线程的4种创建方式 2.线程池的两种创建方式,包括jdk方式和spring方式 …

怒刷LeetCode的第3天(Java版)

目录 第一题 题目来源 题目内容 解决方法 方法一:动态规划 第二题 题目来源 题目内容 解决方法 方法一:模拟 方法二:数学规律 方法三:分组 第三题 题目来源 题目内容 解决方法 方法一:数学方法 方法…

QT:使用行编辑器、文本编辑器、单选按钮、水平布局、垂直布局做一个小项目

widget.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QLineEdit> //行编辑器 #include <QTextEdit> //文本编辑器 #include <QRadioButton> //单选按钮class Widget : public QWidget {Q_OBJECTpublic:Widget(QWidget *pare…

USB总线-Linux内核USB3.0主机控制器驱动框架分析(十二)

1.概述 如下图所示&#xff0c;Linux内核中USB主机体系结构由五部分组成&#xff0c;分别为Application Software、USB Class Driver、USB Core(USB Driver)、USB Host Controller Driver、USB Host Controller。应用程序处于用户空间&#xff0c;通过系统调用访问Class Drive…

关于计算机找不到d3dx9_43.dll,无法继续执行代码修复方法

d3dx9_43.dll是一个动态链接库文件&#xff0c;它是DirectX的一个组件&#xff0c;主要用于处理游戏中的图形、声音等多媒体元素。当这个文件丢失时&#xff0c;可能会导致以下问题&#xff1a; 1. 游戏无法正常运行&#xff1a;由于d3dx9_43.dll负责处理游戏中的多媒体元素&a…

Jumpserver堡垒机

一、堡垒机概述 1、堡垒机的基本概念 堡垒机也是一台服务器&#xff0c;在一个特定的网络环境下&#xff0c;为了保障网络和数据不受来自外部和内部用户的入侵和破坏&#xff0c;而运用各种技术手段实时收集、监控网络环境中每一个组成部分&#xff08;服务器&#xff09;的系…

springboot使用SSE

1、pom文件 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency> 2、前端代码 <!DOCTYPE html> <html lang"en"> <head><meta ch…

C进阶-数据的存储

数据类型介绍 内置类型&#xff1a; //数据类型中的内置类型 // char //字符数据类型 // short //短整型 // int //整型 // long //长整型 // long long //更长的整型 // float //单精度浮点数 // double //双精度浮点数 //数据类型中的内置类型 单位是字节 // char //字…

大厂面试之算法篇

目录 前言 算法对于前端来说重要吗&#xff1f; 期待你的答案 算法 如何学习算法 算法基础知识 时间复杂度 空间复杂度 前端 数据结构 数组 最长递增子序列 买卖股票问题 买卖股票之交易明细 硬币找零问题 数组拼接最小值 奇偶排序 两数之和 三数之和 四数之…

速码!!BGP最全学习笔记:IBGP和EBGP基本配置

实验1&#xff1a;配置IBGP和EBGP 实验目的 熟悉IBGP和EBGP的应用场景掌握IBGP和EBGP的配置方法 实验拓扑 想要华为数通配套实验拓扑和配置笔记的朋友们点赞关注&#xff0c;评论区留下邮箱发给你! 实验步骤 1.IP地址的配置 R1的配置 <Huawei>system-view …

【SpringMVC】@RequestMapping注解

RequestMapping注解的功能 RequestMapping的作用&#xff1a;就是将请求&#xff08;request&#xff09;和处理请求的控制器方法&#xff08;控制层&#xff09;关联起来&#xff0c;建立一个映射关系&#xff0c;SpringMVC接收到指定的请求&#xff0c;就会找到在映射关系中…

Android之AMessage机制存/取原理(四十四)

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 人生格言: 人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药. 更多原创,欢迎关注:Android…

全局的键盘监听事件

一、设定全局键盘监听事件 放在vue 的created()或者mounted ()中&#xff0c;可对整个文档进行键盘事件监听。 new Vue({ created() { window.addEventListener(keydown, this.handleKeydown); }, beforeDestroy() { window.removeEventListener(keydown, this.handleK…

Fiddler抓包工具配置+Jmeter基本使用

一、Fiddler抓包工具的配置和使用 在编写网关自动化脚本之前&#xff0c;得先学会如何抓包&#xff0c;这里以Fiddler为例。会抓包的同学可以跳过这一步&#xff0c;当然看看也是没坏处的…… 局域网络配置 将要进行抓包的手机与电脑连入同一局域网&#xff0c;电脑才能够抓到…

Elasticsearch(Es搜索(简单使用、全文查询、复合查询)、地理位置查询、特殊查询、聚合操作、桶聚合、管道聚合)

Elasticsearch&#xff08;三&#xff09;——Es搜索&#xff08;简单使用、全文查询、复合查询&#xff09;、地理位置查询、特殊查询、聚合操作、桶聚合、管道聚合 一、Es搜索 这里的 Es 数据博主自己上网找的&#xff0c;为了练习 Es 搜索。 1、Elasticsearch 搜索入门 …