go中网络流量分析gopacket库的使用

一、前言

        近来,笔者想学习下用go构造tcp数据包,这里涉及到gopacket库的使用,故这里记录下关于gopacket库的一些学习记录

二、介绍

        gopacket 是 Go 语言的网络数据包处理库,它提供了方便的 API 来读取、分析、修改和生成网络数据包。你可以使用这个库来修改数据包内容,以实现特定的网络测试或安全目的。

修改数据包的过程大致如下:

  1. 使用 gopacket 读取数据包并解码为特定协议的数据结构(如 IP、TCP 等)。

  2. 修改相应的字段,如源 IP 地址、目的 IP 地址、源端口、目的端口等。

  3. 将数据包编码为原始字节流并写回网络。

通过 gopacket 库可以很方便地实现数据包的修改。

三、使用

加载:go get -u github.com/google/gopacket

1、枚举所有网络设备

func GetAllDevs() {//获取所有设备信息devices, err := pcap.FindAllDevs()if err != nil {log.Fatal(err)}//打印设备信息fmt.Println("找到的Devices 信息:")for _, device := range devices {fmt.Println("\n名字:", device.Name)fmt.Println("描述信息:", device.Description)fmt.Println("Devices 地址信息:", device.Addresses) //网口地址信息列表包括IP 、 掩码、 广播地址 、P2Pfor _, address := range device.Addresses {fmt.Println("- IP 地址为:", address.IP)fmt.Println("- 掩码为:", address.Netmask)fmt.Println("- 广播地址为:", address.Broadaddr)fmt.Println("- P2P地址为:", address.P2P)fmt.Println()}}
}//获取所有有IP的网络设备名称
func GetAllDevsHaveAddress() (string, error) {pcapDevices, err := pcap.FindAllDevs()if err != nil {return "", errors.New(fmt.Sprintf("list pcapDevices failed: %s", err.Error()))}var buf strings.Builderfor _, dev := range pcapDevices {fmt.Sprint("Dev:", dev.Name, "\tDes:", dev.Description)buf.WriteString(dev.Name)if len(dev.Addresses) > 0 {for _, ips := range dev.Addresses {fmt.Sprint("\tAddr:", ips.IP.String())//buf.WriteString(ips.IP.String())}}buf.WriteString("\n")}return buf.String(), nil
}//通过IP获取设备名称
func GetDevByIp(ip net.IP) (devName string, err error) {devices, err := pcap.FindAllDevs()if err != nil {return}for _, d := range devices {for _, address := range d.Addresses {_ip := address.IP.To4()if _ip != nil && _ip.IsGlobalUnicast() && _ip.Equal(ip) {return d.Name, nil}}}return "", errors.New("can not find dev")
}

2、获取活动网卡IP、网卡MAC、网关、网关mac、活动网卡设备名称

         这里主要演示,根据目标IP获取活动网卡的IP、网卡mac、网关、网关mac,然后通过IP获取设备名称

package exampleimport ("errors""fmt""net""github.com/google/gopacket/pcap""github.com/google/gopacket/routing""github.com/jackpal/gateway""github.com/libp2p/go-netroute"
)// 查找与指定IP地址相匹配的本地IP地址和MAC地址,其实就是检测是否同网段
func GetIfaceMac(ifaceAddr net.IP) (src net.IP, mac net.HardwareAddr) {interfaces, _ := net.Interfaces()  //获取本地计算机上的网络接口信息for _, iface := range interfaces { //遍历所有网络接口if addrs, err := iface.Addrs(); err == nil { //获取接口的IP地址列表for _, addr := range addrs { //遍历该接口的IP地址if addr.(*net.IPNet).Contains(ifaceAddr) { //检查每个IP地址是否包含了给定的ifaceAddr(即传参),这里用的contains方法,检查给定IP和接口IP是否同一子网return addr.(*net.IPNet).IP, iface.HardwareAddr //匹配就返回接口IP和mac地址}}}}return nil, nil}// 通过IP获取网络设备名称
func GetDevByIp(ip net.IP) (devName string, err error) {devices, err := pcap.FindAllDevs() //获取所有网络设备if err != nil {return}for _, d := range devices {for _, address := range d.Addresses {_ip := address.IP.To4()                                   //检测IP是否位ipv4地址if _ip != nil && _ip.IsGlobalUnicast() && _ip.Equal(ip) { //满足地址为ipv4,地址等于传入IP、地址是全局单播地址 三个条件则符合return d.Name, nil}}}return "", errors.New("未能找到对应设备")}// 通过扫描的目标IP获取发包的网卡信息,返回源IP、源mac、网关IP、设备名称
func GetIpFromRouter(dstIp net.IP) (srcIp net.IP, srcMac net.HardwareAddr, gw net.IP, devName string, err error) {//先验证扫描IP是否同网段srcIp, srcMac = GetIfaceMac(dstIp)if srcIp == nil {//如果不是同网段,则查询路由var r routing.Router//创建一个 routing.Router 类型的变量,用于查询路由信息r, err = netroute.New() //初始化routing.Routerif err == nil {var iface *net.Interface //创建变量iface用于保存与路由相关的网络接口信息iface, gw, srcIp, err = r.Route(dstIp) //通过路由查询路由信息,包括目标IP地址 dstIp 对应的路由信息。iface 保存了与该路由信息关联的网络接口,gw 保存了网关IP地址,srcIp 保存了与该路由信息关联的本地IP地址if err == nil {if iface != nil {srcMac = iface.HardwareAddr //如果找到了与目标IP地址匹配的路由信息,即 iface 不为 nil,则设置 srcMac 为该网络接口的MAC地址。否则,继续下一步} else {_, srcMac = GetIfaceMac(srcIp)}}}//如果在之前的步骤中出现错误或者 srcMac 为 nil,它尝试取得第一个默认网关的信息。if err != nil || srcMac == nil {//取第一个默认路由gw, err = gateway.DiscoverGateway()//获取第一个默认网关的IP地址if err == nil {srcIp, srcMac = GetIfaceMac(gw)}}}gw = gw.To4()srcIp = srcIp.To4()devName, err = GetDevByIp(srcIp)if srcIp == nil || err != nil || srcMac == nil {if err == nil {err = fmt.Errorf("err")}return nil, nil, nil, "", fmt.Errorf("no router,%s", err)}return}

ps:笔者之前的思路想岔了,执迷于先获取到活动网卡的IP然后通过IP再去获取网卡设备名称,后来反省过来,针对扫描来说是通过目标IP来获取源IP,源mac,网卡信息 

3、抓取网卡数据包

var (device       string = "\\Device\\NPF_{111223-123344}" //网卡名称,也可使用FindAllDevs函数获得网卡名称,比如\NPF_{6A5F41。。。}snapshot_len int32  = 1024                                                   //每个数据包读取的最大长度promiscuous  bool   = false                                                  //是否将网口设置为混杂模式,即是否接收目的不为本机的包err          errortimeout      time.Duration = 30 * time.Second //设置抓包返回的超时时间,如果设置成30s,即每30s刷新下数据包,设置为负数,就立即刷新数据包handle       *pcap.Handle                     //是一个*Handle类型的返回值,可能作为gopacket其他函数调用时作为函数参数来传递 (一定记得释放掉)
)func GetPacp() {handle, err = pcap.OpenLive(device, snapshot_len, promiscuous, timeout) //打开网络设备并进行实时捕获数据包if err != nil {log.Fatal(err)}defer handle.Close() //最后一定要关闭handlepacketSource := gopacket.NewPacketSource(handle, handle.LinkType()) //第一个参数为OpenLive的返回值,指向Handle类型的指针变量handle。第二个参数为handle.LinkType()此参数默认是以太网链路,一般我们抓包,也是从2层以太网链路上抓取。//读取数据包,packetSource.Packets()是个channel类型,此处是从channel类型的数据通道中持续的读取网络数据包for packet := range packetSource.Packets() {fmt.Println(packet)}}

4、解码数据包各layer内容


import ("fmt""log""github.com/google/gopacket""github.com/google/gopacket/layers""github.com/google/gopacket/pcap"
)func DecodeLayers() {//打开devicehandle, err = pcap.OpenLive(device, snapshot_len, promiscuous, timeout)if err != nil {log.Fatal(err)}defer handle.Close()packetSource2 := gopacket.NewPacketSource(handle, handle.LinkType())for packet := range packetSource2.Packets() {printPacketInfo(packet)}
}func printPacketInfo(packet gopacket.Packet) {// 判断数据包是否为以太网数据包,可解析出源mac地址、目的mac地址、以太网类型(如ip类型)等ethernetLayer := packet.Layer(layers.LayerTypeEthernet)if ethernetLayer != nil {fmt.Println("检测到以太网数据包")ethernetPacket, _ := ethernetLayer.(*layers.Ethernet)fmt.Println("源 Mac 地址为:", ethernetPacket.SrcMAC)fmt.Println("目的 Mac地址为:", ethernetPacket.DstMAC)//以太网类型通常是 IPv4,但也可以是 ARP 或其他fmt.Println("以太网类型为:", ethernetPacket.EthernetType)fmt.Println(ethernetPacket.Payload)fmt.Println()}// 判断数据包是否为IP数据包,可解析出源ip、目的ip、协议号等ipLayer := packet.Layer(layers.LayerTypeIPv4) //这里抓取ipv4的数据包if ipLayer != nil {fmt.Println("检测到IP层数据包")ip, _ := ipLayer.(*layers.IPv4)// IP layer variables:// Version (Either 4 or 6)// IHL (IP Header Length in 32-bit words)// TOS, Length, Id, Flags, FragOffset, TTL, Protocol (TCP?),//Checksum,SrcIP, DstIPfmt.Printf("源ip为 %d 目的ip为 %d\n", ip.SrcIP, ip.DstIP)fmt.Println("协议版本为:", ip.Version)fmt.Println("首部长度为:", ip.IHL)fmt.Println("区分服务为:", ip.TOS)fmt.Println("总长度为:", ip.Length)fmt.Println("标识id为:", ip.Id)fmt.Println("标志为:", ip.Flags)fmt.Println("片偏移", ip.FragOffset)fmt.Println("TTL", ip.TTL)fmt.Println("协议Protocol为:", ip.Protocol)fmt.Println("校验和为:", ip.Checksum)fmt.Println("基础层", ip.BaseLayer)fmt.Println("内容contents:", ip.Contents)fmt.Println("可选字段为:", ip.Options)fmt.Println("填充为:", ip.Padding)fmt.Println()}// 判断数据包是否为TCP数据包,可解析源端口、目的端口、seq序列号、tcp标志位等tcpLayer := packet.Layer(layers.LayerTypeTCP)if tcpLayer != nil {fmt.Println("检测到tcp数据包")tcp, _ := tcpLayer.(*layers.TCP)// SrcPort, DstPort, Seq, Ack, DataOffset, Window, Checksum, Urgent// Bool flags: FIN, SYN, RST, PSH, ACK, URG, ECE, CWR, NSfmt.Printf("源端口为 %d 目的端口为 %d\n", tcp.SrcPort, tcp.DstPort)fmt.Println("序列号为:", tcp.Seq)fmt.Println("确认号为:", tcp.Ack)fmt.Println("数据偏移量:", tcp.DataOffset)fmt.Println("标志位:", tcp.CWR, tcp.ECE, tcp.URG, tcp.ACK, tcp.PSH, tcp.RST, tcp.SYN, tcp.FIN)fmt.Println("窗口大小:", tcp.Window)fmt.Println("校验值:", tcp.Checksum)fmt.Println("紧急指针:", tcp.Urgent)fmt.Println("tcp选项:", tcp.Options)fmt.Println("填充:", tcp.Padding)fmt.Println()}//检测数据包中所有的层数fmt.Println("所有 数据包 layer有:")for _, layer := range packet.Layers() {fmt.Println("--", layer.LayerType())}//检测判断layer是否存在错误if err := packet.ErrorLayer(); err != nil {fmt.Println("解码数据包的某些部分出错:", err)}}

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

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

相关文章

【Linux】安装配置解决CentosMobaXterm的使用及Linux常用命令命令模式

目录 一、介绍 1. 背景 2. 讲述&功能 二、Centos安装配置&MobaXterm 1. 创建 2. 安装 3. 配置 4. MobaXterm使用 三、Linux常用命令&模式 1. 常用命令 2. 三种模式 3. 命令使用&换源 4. 拍照备份 一、介绍 1. 背景 CentOS的背景可以追溯到200…

STM32F4X SDIO(二) SDIO协议

上一节简单介绍了SD卡的分类,本节将会介绍SD卡的通信协议,也就是SDIO协议。 STM32F4X SDIO(二)SDIO协议 SD 卡管脚和寄存器SD卡管脚分布SD卡通信协议SD卡寄存器SD卡内部结构 SDIO总线SDIO总线拓扑SDIO总线协议SDIO协议的基本结构…

java将list转为逗号隔开字符串,将逗号连接的字符串转成字符数组,​将逗号分隔的字符串转换为List​(Java逗号分隔-字符串与数组相互转换)

一、通过testList.stream().collect(Collectors.joining(",")) &#xff0c;通过流转换&#xff0c;将list转为逗号隔开字符串 List<String> testList new ArrayList<>(); testList.add("test1"); testList.add("test2"); testList…

Python的比较运算符查询表

据个人的编程开发经验&#xff0c;Python的比较运算符最常于条件判断&#xff0c;而条件判断是python编程中最常用的语法之一&#xff0c;与for或while的循环一样&#xff0c;功能十分强大&#xff01; 在机器学习当中&#xff0c;或深度学习当中&#xff0c;在运用算法对统计…

ArcGIS笔记12_ArcGIS搜索工具没法用?ArcGIS运行很慢很卡?

本文目录 前言Step 1 ArcGIS搜索工具没法用Step 2 ArcGIS运行很慢很卡 前言 这是笔者最近遇到的两个小问题&#xff0c;新换了台式机&#xff0c;安装上ArcGIS后发现搜索工具没法用&#xff0c;而且感觉还不如原来笔记本运行的流畅&#xff0c;加载图层很慢&#xff0c;编辑要…

web - 前段三剑客

目录 前言 一. HTML 常用标签演示 图片标签 ​编辑 表格标签(重点) ​编辑 表单标签 (重点) 布局标签 其余标签 二. CSS 2.1 . css的三种引入方式 2.2 . 三大选择器 2.3 . css样式 - 浮动 2.4 . css样式 - 定位 1.static 2.absolute(绝对位置) 3.relavite(相…

【PythonRS】Pyrsgis库安装+基础函数使用教程

pyrsgis库是一个用于处理地理信息系统(GIS)数据的Python库。它提供了一组功能强大的工具&#xff0c;可以帮助开发人员使用Python语言创建、处理、分析和可视化GIS数据。通过使用pyrsgis库&#xff0c;开发人员可以更轻松地理解和利用地理信息。 pyrsgis库包含了许多常见的GIS操…

Git: 仓库clone和用户配置

git clone 两种方式clone远程仓库到本地。 通过ssh 命令格式&#xff1a; git clone gitxxxxxx.git使用这种方法需要提前创建ssh秘钥。 首先打开一个git控制台&#xff0c;输入命令 ssh-keygen -t ed25519 -C “xxxxxxxxxx.com”输入命令后需要点击四次回车&#xff0c;其…

mysql 计算两个坐标距离

方式一&#xff1a;st_distance_sphere 计算结果单位米 SELECT *, st_distance_sphere(point(lng,lat),point(lng,lat)) as distance FROM table mysql 版本5.7 以上 方式二&#xff1a;st_distance 计算结果单位是度 SELECT *, (st_distance(point(lng,lat),point(lng4,lat…

自学SLAM(5)《第三讲:李群和李代数》作业

前言 小编研究生的研究方向是视觉SLAM&#xff0c;目前在自学&#xff0c;本篇文章为初学高翔老师课的第三次作业。 文章目录 前言1.群的性质2.验证向量叉乘的李代数性质3.推导 SE(3) 的指数映射4.伴随5.轨迹的描绘6.* 轨迹的误差(附加题) 1.群的性质 课上我们讲解了什么是群。…

Spring Security—Spring MVC 整合

目录 一、EnableWebMvcSecurity 二、MvcRequestMatcher 三、AuthenticationPrincipal 四、异步 Spring MVC 整合 五、Spring MVC 和 CSRF 整合 1、自动包含 Token 2、解析 CsrfToken Spring Security提供了一些与Spring MVC的可选整合。本节将进一步详细介绍这种整合。 …

UML中类之间的六种主要关系

UML中类之间的六种主要关系: 继承&#xff08;泛化&#xff09;&#xff08;Inheritance、Generalization&#xff09;, 实现&#xff08;Realization&#xff09;&#xff0c;关联&#xff08;Association)&#xff0c;聚合&#xff08;Aggregation&#xff09;&#xff0c;组…

Linux--进程替换

1.什么是进程替换 在fork函数之后&#xff0c;父子进程各自执行代码的一部分&#xff0c;但是如果子进程想要执行一份全新的程序呢&#xff1f; 通过进程替换来完成&#xff0c;进程替换就是父子进程代码发生写时拷贝&#xff0c;子进程执行自己的功能。 程序替换就是通过特定的…

python 笔记:h5py 读取HDF5文件

1 HDF5文件 HDF5 是 Hierarchical Data Format version 5 的缩写&#xff0c;是一种用于存储和管理大量数据的文件格式一个h5py文件可以看作是 “dataset” 和 “group” 二合一的容器 dataset : 数据集&#xff0c;像 numpy 数组一样工作group : 包含了其它 dataset 和 其它 …

GZ035 5G组网与运维赛题第4套

2023年全国职业院校技能大赛 GZ035 5G组网与运维赛项&#xff08;高职组&#xff09; 赛题第4套 一、竞赛须知 1.竞赛内容分布 竞赛模块1--5G公共网络规划部署与开通&#xff08;35分&#xff09; 子任务1&#xff1a;5G公共网络部署与调试&#xff08;15分&#xff09; 子…

C语言_断言assert详解

一、assert定义 assert() 的用法像是一种"契约式编程"&#xff0c;在我的理解中&#xff0c;其表达的意思就是&#xff0c;程序在我的假设条件下&#xff0c;能够正常良好的运作&#xff0c;其实就相当于一个 if 语句&#xff1a; if(假设成立) {程序正常运行&…

(免费领源码) Asp.Net#SQL Server校园在线投票系统10557-计算机毕业设计项目选题推荐

摘 要 随着互联网大趋势的到来&#xff0c;社会的方方面面&#xff0c;各行各业都在考虑利用互联网作为媒介将自己的信息更及时有效地推广出去&#xff0c;而其中最好的方式就是建立网络管理系统&#xff0c;并对其进行信息管理。由于现在网络的发达&#xff0c;校园投票通过网…

java - IDEA IDE - 设置字符串断点

文章目录 java - IDEA IDE - 设置字符串断点概述笔记END java - IDEA IDE - 设置字符串断点 概述 IDE环境为IDEA2022.3 在看一段序列化的代码, 想找出报错抛异常那个点, 理解一下代码实现. 因为序列化代码实现在第三方jar包中, 改不了(只读的). 根本数不清第几次才会开始报…

java基础之泛型

泛型 泛型是在JDK1.5增加的功能&#xff0c;在没有泛型之前&#xff0c;从集合中取出来的每一个对象都必须进行强制类型转换&#xff0c;如果有人插入了错误类型的对象&#xff0c;在运行时的转换就会出现问题&#xff0c;有了泛型之后&#xff0c;这些问题就会在编译期暴露出来…

OpenCV学习(五)——图像基本操作(访问图像像素值、图像属性、感兴趣区域ROI和图像边框)

图像基本操作 5. 图像基本操作5.1 访问像素值并修改5.2 访问图像属性5.2 图像感兴趣区域ROI5.3 拆分和合并图像通道5.4 为图像设置边框&#xff08;填充&#xff09; 5. 图像基本操作 访问像素值并修改访问图像属性设置感兴趣区域&#xff08;ROI&#xff09;分割和合并图像 …