阅读go语言工具源码系列之gopacket(谷歌出品)----第一集 DLL的go封装

gopacket项目是google出品的golang第三方库,项目源码地址google/gopacket: Provides packet processing capabilities for Go (github.com)

gopacket核心是对经典的抓包工具libpcap(linux平台)和npcap(windows平台)的go封装,提供了更方便的go语言操作接口,里面如何实现的,接下来的文章中会有介绍。

windows平台和linux平台的go封装有些不一样
我们先从windows平台讲起吧(笔者常用操作系统为windows系统)

第一集 DLL的go封装

windows系统中使用的抓包工具是npcap,请提前到Npcap: Windows Packet Capture Library & Driver下载安装,安装完成后可在安装文件夹中看到在这里插入图片描述
其中wpcap.dll是本集中所要绑定的dll库

DLL(Dynamic Link Library)文件为动态链接库文件,又称“应用程序拓展”,是软件文件类型。在Windows中,许多应用程序并不是一个完整的可执行文件,它们被分割成一些相对独立的动态链接库,即DLL文件,放置于系统中。当我们执行某一个程序时,相应的DLL文件就会被调用。一个应用程序可使用多个DLL文件,一个DLL文件也可能被不同的应用程序使用,这样的DLL文件被称为共享DLL文件。

在golang中使用syscall库来进行调用底层操作系统 API 的包。gopacket中采用的方式就是使用syscall来调用DLL文件。

├─afpacket          
├─bsdbpf            
├─bytediff
├─defrag
│  └─lcmdefrag      
├─dumpcommand
├─examples
│  ├─bidirectional
│  ├─bytediff
│  ├─httpassembly
│  ├─pcapdump
│  ├─pcaplay
│  ├─pfdump
│  ├─reassemblydump
│  ├─snoopread
│  ├─statsassembly
│  ├─synscan
│  └─util
├─ip4defrag
├─layers
│  └─testdata
│      └─fuzz
│          └─FuzzDecodeFromBytes
├─macs
├─pcap
│  └─gopacket_benchmark
├─pcapgo
│  └─tests
│      ├─be
│      └─le
├─pfring
├─reassembly
├─routing
└─tcpassembly└─tcpreader

在项目文件中pcap -> pcap_windows.go中即是对wpcap.dll的go封装代码

我们来看一下里面的构造

不知道大家看golang工具源码的时候是怎么一个顺序,个人比较喜欢按照执行顺序来先了解大致要干啥的逻辑,所以首先我们看一下init函数:

// init函数是每个文件首先执行的,甚至于在main.go 中也会早于main函数执行
func init() {  LoadWinPCAP()  
}

这个函数其实点明了本文件的主旨LoadWinPCAP导入winpcap。
按照执行顺序执行到了LoadWinPCAP()函数

// LoadWinPCAP attempts to dynamically load the wpcap DLL and resolve necessary functions// 动态导入wpcap.dll库  
func LoadWinPCAP() error {  
// 首先通过pcapLoaded变量来判断winpcap是否导入过,pcapLoaded变量初始化时为bool  
if pcapLoaded {  
return nil  
}  
// syscall.LoadLibrary 来导入kernel32.dll  
kernel32, err := syscall.LoadLibrary("kernel32.dll")  
if err != nil {  
return fmt.Errorf("couldn't load kernel32.dll")  
}  
//延迟释放kernel32.dll  
defer syscall.FreeLibrary(kernel32)  //设置路径为npcap所在路径  
initDllPath(kernel32)  
// 使用syscall.GetProcAddress来获取kernel32中的AddDllDirectory函数  
if haveSearch, _ := syscall.GetProcAddress(kernel32, "AddDllDirectory"); haveSearch != 0 {  
// 如果存在 AddDllDirectory,我们可以将 LOAD_LIBRARY_* 的东西与 LoadLibraryEx 一起使用,以避免 wpcap .dll劫持  
// if AddDllDirectory is present, we can use LOAD_LIBRARY_* stuff with LoadLibraryEx to avoid wpcap.dll hijacking  
// see: https://msdn.microsoft.com/en-us/library/ff919712%28VS.85%29.aspx  
const LOAD_LIBRARY_SEARCH_USER_DIRS = 0x00000400  
const LOAD_LIBRARY_SEARCH_SYSTEM32 = 0x00000800  
wpcapHandle, err = windows.LoadLibraryEx("wpcap.dll", 0, LOAD_LIBRARY_SEARCH_USER_DIRS|LOAD_LIBRARY_SEARCH_SYSTEM32)  
if err != nil {  
return fmt.Errorf("couldn't load wpcap.dll")  
}  
} else {  
// otherwise fall back to load it with the unsafe search cause by SetDllDirectory  
// 否则回退以使用 SetDllDirectory 导致的不安全搜索加载它  
wpcapHandle, err = windows.LoadLibrary("wpcap.dll")  
if err != nil {  
return fmt.Errorf("couldn't load wpcap.dll")  
}  
}  
initLoadedDllPath(kernel32)  
// 导入 msvcrt 动态库  
msvcrtHandle, err = syscall.LoadLibrary("msvcrt.dll")  
if err != nil {  
return fmt.Errorf("couldn't load msvcrt.dll")  
}  
// 引入calloc函数  
callocPtr, err = syscall.GetProcAddress(msvcrtHandle, "calloc")  
if err != nil {  
return fmt.Errorf("couldn't get calloc function")  
}  // 将wpcap库函数进行绑定
// It returns an error message string corresponding to error.  
pcapStrerrorPtr = mustLoad("pcap_strerror")  
// get a string for an error or warning status code  
pcapStatustostrPtr = mightLoad("pcap_statustostr") // not available on winpcap  
// get a handle for a live capture  
pcapOpenLivePtr = mustLoad("pcap_open_live")  
pcapOpenOfflinePtr = mustLoad("pcap_open_offline")  
pcapClosePtr = mustLoad("pcap_close")  
pcapGeterrPtr = mustLoad("pcap_geterr")  
pcapStatsPtr = mustLoad("pcap_stats")  
pcapCompilePtr = mustLoad("pcap_compile")  
pcapFreecodePtr = mustLoad("pcap_freecode")  
pcapLookupnetPtr = mustLoad("pcap_lookupnet")  
pcapOfflineFilterPtr = mustLoad("pcap_offline_filter")  
pcapSetfilterPtr = mustLoad("pcap_setfilter")  
pcapListDatalinksPtr = mustLoad("pcap_list_datalinks")  
pcapFreeDatalinksPtr = mustLoad("pcap_free_datalinks")  
pcapDatalinkValToNamePtr = mustLoad("pcap_datalink_val_to_name")  
pcapDatalinkValToDescriptionPtr = mustLoad("pcap_datalink_val_to_description")  
pcapOpenDeadPtr = mustLoad("pcap_open_dead")  
pcapNextExPtr = mustLoad("pcap_next_ex")  
pcapDatalinkPtr = mustLoad("pcap_datalink")  
pcapSetDatalinkPtr = mustLoad("pcap_set_datalink")  
pcapDatalinkNameToValPtr = mustLoad("pcap_datalink_name_to_val")  
pcapLibVersionPtr = mustLoad("pcap_lib_version")  
pcapFreealldevsPtr = mustLoad("pcap_freealldevs")  
pcapFindalldevsPtr = mustLoad("pcap_findalldevs")  
pcapSendpacketPtr = mustLoad("pcap_sendpacket")  
pcapSetdirectionPtr = mustLoad("pcap_setdirection")  
pcapSnapshotPtr = mustLoad("pcap_snapshot")  
//libpcap <1.2 doesn't have pcap_*_tstamp_* functions  
pcapTstampTypeValToNamePtr = mightLoad("pcap_tstamp_type_val_to_name")  
pcapTstampTypeNameToValPtr = mightLoad("pcap_tstamp_type_name_to_val")  
pcapListTstampTypesPtr = mightLoad("pcap_list_tstamp_types")  
pcapFreeTstampTypesPtr = mightLoad("pcap_free_tstamp_types")  
pcapSetTstampTypePtr = mightLoad("pcap_set_tstamp_type")  
pcapGetTstampPrecisionPtr = mightLoad("pcap_get_tstamp_precision")  
pcapSetTstampPrecisionPtr = mightLoad("pcap_set_tstamp_precision")  
pcapOpenOfflineWithTstampPrecisionPtr = mightLoad("pcap_open_offline_with_tstamp_precision")  
pcapHOpenOfflineWithTstampPrecisionPtr = mightLoad("pcap_hopen_offline_with_tstamp_precision")  
pcapActivatePtr = mustLoad("pcap_activate")  
pcapCreatePtr = mustLoad("pcap_create")  
pcapSetSnaplenPtr = mustLoad("pcap_set_snaplen")  
pcapSetPromiscPtr = mustLoad("pcap_set_promisc")  
pcapSetTimeoutPtr = mustLoad("pcap_set_timeout")  
//winpcap does not support rfmon  
pcapCanSetRfmonPtr = mightLoad("pcap_can_set_rfmon")  
pcapSetRfmonPtr = mightLoad("pcap_set_rfmon")  
pcapSetBufferSizePtr = mustLoad("pcap_set_buffer_size")  
//libpcap <1.5 does not have pcap_set_immediate_mode  
pcapSetImmediateModePtr = mightLoad("pcap_set_immediate_mode")  
pcapHopenOfflinePtr = mustLoad("pcap_hopen_offline")  pcapLoaded = true  
return nil  
}

这一段代码是将wpcap代码进行进行绑定的关键
首先导入kernel.dll库

kernel32, err := syscall.LoadLibrary("kernel32.dll")  

然后从kernel.dll中调用AddDllDirectory方法,并以此为判断是使用LoadLibraryEx函数还是LoadLibrary函数来进行wpcap.dll调用
LoadLibraryEx函数相比于LoadLibrary函数多了一个LOAD_LIBRARY_* 标识,来防止dll劫持攻击。
导入wpcap.dll库

wpcapHandle, err = windows.LoadLibraryEx("wpcap.dll", 0,LOAD_LIBRARY_SEARCH_USER_DIRS|LOAD_LIBRARY_SEARCH_SYSTEM32)  

导入了wpcap.dll库后,然后将该动态库的函数都进行了绑定,在文件中它封装了两个load函数如下:

// 必须导入
func mustLoad(fun string) uintptr {  
addr, err := windows.GetProcAddress(wpcapHandle, fun)  
if err != nil {  
panic(fmt.Sprintf("Couldn't load function %s from %s", fun, loadedDllPath))  
}  
return addr  
}  
// 可能导入  
func mightLoad(fun string) uintptr {  
addr, err := windows.GetProcAddress(wpcapHandle, fun)  
if err != nil {  
return 0  
}  
return addr  
}

它导入的函数有以下几种

// It returns an error message string corresponding to error.  
pcapStrerrorPtr = mustLoad("pcap_strerror")  
// get a string for an error or warning status code  
pcapStatustostrPtr = mightLoad("pcap_statustostr") // not available on winpcap  
// get a handle for a live capture  
pcapOpenLivePtr = mustLoad("pcap_open_live")  
//  
pcapOpenOfflinePtr = mustLoad("pcap_open_offline")  
pcapClosePtr = mustLoad("pcap_close")  
pcapGeterrPtr = mustLoad("pcap_geterr")  
pcapStatsPtr = mustLoad("pcap_stats")  
pcapCompilePtr = mustLoad("pcap_compile")  
pcapFreecodePtr = mustLoad("pcap_freecode")  
pcapLookupnetPtr = mustLoad("pcap_lookupnet")  
pcapOfflineFilterPtr = mustLoad("pcap_offline_filter")  
pcapSetfilterPtr = mustLoad("pcap_setfilter")  
pcapListDatalinksPtr = mustLoad("pcap_list_datalinks")  
pcapFreeDatalinksPtr = mustLoad("pcap_free_datalinks")  
pcapDatalinkValToNamePtr = mustLoad("pcap_datalink_val_to_name")  
pcapDatalinkValToDescriptionPtr = mustLoad("pcap_datalink_val_to_description")  
pcapOpenDeadPtr = mustLoad("pcap_open_dead")  
pcapNextExPtr = mustLoad("pcap_next_ex")  
pcapDatalinkPtr = mustLoad("pcap_datalink")  
pcapSetDatalinkPtr = mustLoad("pcap_set_datalink")  
pcapDatalinkNameToValPtr = mustLoad("pcap_datalink_name_to_val")  
pcapLibVersionPtr = mustLoad("pcap_lib_version")  
pcapFreealldevsPtr = mustLoad("pcap_freealldevs")  
pcapFindalldevsPtr = mustLoad("pcap_findalldevs")  
pcapSendpacketPtr = mustLoad("pcap_sendpacket")  
pcapSetdirectionPtr = mustLoad("pcap_setdirection")  
pcapSnapshotPtr = mustLoad("pcap_snapshot")  
//libpcap <1.2 doesn't have pcap_*_tstamp_* functions  
pcapTstampTypeValToNamePtr = mightLoad("pcap_tstamp_type_val_to_name")  
pcapTstampTypeNameToValPtr = mightLoad("pcap_tstamp_type_name_to_val")  
pcapListTstampTypesPtr = mightLoad("pcap_list_tstamp_types")  
pcapFreeTstampTypesPtr = mightLoad("pcap_free_tstamp_types")  
pcapSetTstampTypePtr = mightLoad("pcap_set_tstamp_type")  
pcapGetTstampPrecisionPtr = mightLoad("pcap_get_tstamp_precision")  
pcapSetTstampPrecisionPtr = mightLoad("pcap_set_tstamp_precision")  
pcapOpenOfflineWithTstampPrecisionPtr = mightLoad("pcap_open_offline_with_tstamp_precision")  
pcapHOpenOfflineWithTstampPrecisionPtr = mightLoad("pcap_hopen_offline_with_tstamp_precision")  
pcapActivatePtr = mustLoad("pcap_activate")  
pcapCreatePtr = mustLoad("pcap_create")  
pcapSetSnaplenPtr = mustLoad("pcap_set_snaplen")  
pcapSetPromiscPtr = mustLoad("pcap_set_promisc")  
pcapSetTimeoutPtr = mustLoad("pcap_set_timeout")  
//winpcap does not support rfmon  
pcapCanSetRfmonPtr = mightLoad("pcap_can_set_rfmon")  
pcapSetRfmonPtr = mightLoad("pcap_set_rfmon")  
pcapSetBufferSizePtr = mustLoad("pcap_set_buffer_size")  
//libpcap <1.5 does not have pcap_set_immediate_mode  
pcapSetImmediateModePtr = mightLoad("pcap_set_immediate_mode")  
pcapHopenOfflinePtr = mustLoad("pcap_hopen_offline")  
//绑定后将pcapLoaded改为true  
pcapLoaded = true  
return nil

整体大致流程:
使用syscall.LoadLibrary先导入kernel.dll库,然后在使用kernel的AddDllDirectory函数做1次判断,然后导入wpcap.dll库并绑定wpcap库函数到go的uintptr变量中,方便下一步的调用。

本集总结:
本集主要介绍了gopacket中对于wpcap.dll这个windows动态链接库进行绑定的方法,使用到了go语言的syscall和golang.org/x/sys/windows两个针对底层系统调用的基础库,在进行绑定的时候首先需要使用syscall.LoadLibrary导入dll,然后使用windows.GetProcAddress获取dll中的函数。

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

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

相关文章

嵌入式linux学习之系统烧录

1.所需文件 1. 开发板为正点原子stm32mp157,文件可按照linux驱动教程编译&#xff0c;也可在正点原子文档->08、系统镜像\02、出厂系统镜像中找到&#xff1a; 2.烧录 1.拨码开关为000(usb启动)&#xff0c;otg接口接入虚拟机&#xff0c;打开stm32cubeProgrammer: 2.页面…

AP5101C 高压线性 LED恒流驱动器 DFN2*2 LED灯汽车雾灯转向灯

产品描述 AP5101C 是一款高压线性 LED 恒流芯片 &#xff0c; 简单 、 内置功率管 &#xff0c; 适用于6- 100V 输入的高精度降压 LED 恒流驱动芯片。电流2.0A。AP5101C 可实现内置MOS 做 2.0A,外置 MOS 可做 3.0A 的。AP5101C 内置温度保护功能 &#xff0c;温度保护点为 130 …

CQ 社区版 2.8.0 | 支持TiDB、StarRocks,新增列过滤算法、导出模式设置等

Hello&#xff0c;CloudQuery 社区版 2.8.0 已发布&#xff0c;本文将带大家详细解析本次更新的功能~&#xff08;完整的讲解视频可点击 &#x1f449;&#x1f3fb; CloudQuery 社区版2.8.0 功能讲解演示 本期亮点更新 新增支持数据源 TiDB、StarRocks数据保护新增列过滤脱敏…

cmd命令行输出的内容复制粘贴到文本中

cmd程序执行完后按任意键进行结束&#xff0c;无法直接复制命令行里输出的内容&#xff0c;如下图&#xff0c;在Windows系统里按ctrlC&#xff0c;然后该窗口就关闭了&#xff0c;内容也没有复制成功到粘贴板。 解决办法如下&#xff1a; 在上方打开设置 然后在“交互”里打…

JDBC 总结

一、JDBC概述 JDBC&#xff08;Java DataBase Connectivity&#xff09;java数据库连接是一种用于执行SQL语句的Java API&#xff0c;可以为多种关系型数据库提供统一访问&#xff0c; 它由一组用Java语言编写的类和接口组成。有了JDBC,java开发人员只需要编写一次程序,就可以…

Linux系统中虚拟文件系统原理与方法

在 Unix 的世界里&#xff0c;有句很经典的话&#xff1a;一切对象皆是文件。这句话的意思是说&#xff0c;可以将 Unix 操作系统中所有的对象都当成文件&#xff0c;然后使用操作文件的接口来操作它们。Linux 作为一个类 Unix 操作系统&#xff0c;也努力实现这个目标。 虚拟文…

E4 基于Mysql的游标定义和应用

一、实验目的: 熟练使用MySQL游标的定义和应用。 二、实验要求: 1、基本硬件配置:英特尔Pentium III 以上,大于4G内存&#xff1b; 2、软件要求:Mysql&#xff1b; 3、时间:1小时&#xff1b; 4、撰写实验报告并按时提交。 三、实验内容: 问题1&#xff1a;请写一个存储…

MTP与管理壳(AAS)有异曲同工之妙

在过去的几年中&#xff0c;流程工业中的不同部门&#xff08;例如制药、精细化学品以及食品和饮料部门&#xff09;遇到了一系列共同且可比较的新兴挑战。这些挑战包括&#xff1a; 新产品的需求迅速接连不断&#xff0c;更快交货和更低价格的压力&#xff0c;更多定制产品&a…

【Java并发】聊聊Future如何提升商品查询速度

java中可以通过new thread、实现runnable来进行实现线程。但是唯一的缺点是没有返回值、以及抛出异常&#xff0c;而callable就可以解决这个问题。通过配合使用futuretask来进行使用。 并且Future提供了对任务的操作&#xff0c;取消&#xff0c;查询是否完成&#xff0c;获取结…

代理模式-C#实现

该实例基于WPF实现&#xff0c;直接上代码&#xff0c;下面为三层架构的代码。 目录 一 Model 二 View 三 ViewModel 一 Model using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks;namespace 设计模式练…

【Linux】进程间通信——信号量

让大家久等啦&#xff0c;本期我们来讲讲Linux系统中的信号量 目录 一、引入 二、认识信号量 2.1 信号量的概念 2.2 信号量的内核结构 三、关于信号量的接口 3.1 semget 3.2 ipcs -s 3.3 ipcrm -s 3.4 semctl 3.5 semop 四、理解IPC 一、引入 在开始之前我们先来认…

2023.1.21 关于 Redis 主从复制详解

目录 引言 单点问题 分布式系统 主从模式 配置 Redis 主从结构 断开主从关系 切换主从关系 补充知识点一 只读 网络延迟 拓扑结构 一主一从 一主多从 树形主从结构 主从复制的基本流程 数据同步 replicationid offset pzync 运行流程 具体流程 补充知识点二…

C. Doremy‘s City Construction(二分图问题)

思路&#xff1a;把集合划分成两部分,一部分中每个数都比另一部分小,这两部分连成一个完全二分图,这种情况是最优的,还需要特判所有数都相等的情况. 代码&#xff1a; void solve(){int n;cin >> n;vector<int>a(n 1);for(int i 1;i < n;i )cin >> a[…

如何使用iPhone或iPad上的二维码共享Wi-Fi密码?这里有详细步骤

你有没有想过在不泄露网络密码的情况下与客人共享你的家庭或工作Wi-Fi?你肯定不是第一个这样想的人,我们很高兴地通知你,多亏了以下这个的变通方法,你现在可以使用iPhone或iPad做到这一点。 通常,如果你想让其他人访问网络,你需要共享你的Wi-Fi密码。苹果通过引入与任何…

python 学习之 re库的基本使用(正则匹配)上

目录 一、基本用法 二、函数介绍 1、match函数 2、search 函数 3、compile 函数 4、findall 和 finditer 函数 5、sub 函数和 subn 函数 6、split 函数 一、基本用法 首先我们需要引入 re 库 代码基本框架使用两行代码实现 测试代码&#xff1a; import reret re.m…

vue 本地中导入 maptalks

1、进入 github 中 maptalks 文件下载页面&#xff08;https://github.com/maptalks/maptalks.js/releases&#xff09; 这里可能会有朋友应为网络问题打不开 github &#xff0c;可以查看作者另一篇关于解决该问题的文章&#x1f449;GitHub 打不开问题解决 2、将下载好的文件…

5V摄像机镜头驱动芯片GC6208,为什么可以替代AN41908,适用于摄像机镜头上

GC6208是一个镜头电机驱动IC摄像机和安全摄像机。该装置集成了一个由PID控制的可变光圈直流电机驱动器和两个通道的扫描隧道显微镜电机驱动器&#xff0c;用于变焦和聚焦控制。AN41908A是一款用于摄像机和安全摄像机的镜头马达驱动IC&#xff0c;具有lris控制功能。电压驱动系统…

.zip 文件和 .tar.gz文件 的区别

tgz和zip两种压缩格式,其实这两个压缩文件里面包含的内容是一样的,只是压缩格式不一样. tar.gz格式的文件比zip文件要小不少。tar.gz压缩格式用于unix的操作系统, 而zip用于windows的操作系统,但在windows系统中WinRar工具同样可以解压缩tar.gz格式的。 扩展&#xff1a; z…

仿真机器人-深度学习CV和激光雷达感知(项目2)day5【作业1与答案1】

文章目录 前言作业1答案1 前言 &#x1f4ab;你好&#xff0c;我是辰chen&#xff0c;本文旨在准备考研复试或就业 &#x1f4ab;本文内容是我为复试准备的第二个项目 &#x1f4ab;欢迎大家的关注&#xff0c;我的博客主要关注于考研408以及AIoT的内容 &#x1f31f; 预置知识…

在Rust中编写自定义Error

前言 之前我们聊过&#xff0c;Result<T, E> 类型可以方便地用于错误传导&#xff0c;Result<T, E>是模板类型&#xff0c;实例化后可以是各种类型&#xff0c;但 Rust 要求传导的 Result 中的 E 是相同类型的&#xff0c;或者能够自动转化为相同类型。比如&#…