首页 > 系统相关 >Linux 网络编程—— libnet 使用指南

Linux 网络编程—— libnet 使用指南

时间:2022-09-28 20:04:17浏览次数:55  
标签:libnet int16 ptag ip Linux 使用指南 数据包 int8


概述

​通过《原始套接字实例:发送 UDP 数据包》的学习​​,我们组 UDP 数据包时常考虑字节流顺序、校验和计算等问题,有时候会比较繁琐,那么,有没有一种更简单的方法呢?答案是:借助 libnet 函数库。


libnet 是一个小型的接口函数库,主要用 C 语言写成,提供了低层网络数据包的构造、处理和发送功能。


libnet 的开发目的是:建立一个简单统一的网络编程接口以屏蔽不同操作系统底层网络编程的差别,使得程序员将精力集中在解决关键问题上。


libnet 库提供的接口函数包含 15 种数据包生成器和两种数据包发送器(IP 层和数据链路层)。 

提供的接口函数包括:

1)内存管理(分配和释放)函数

2)地址解析函数

3)各种协议类型的数据包构造函数

4)数据包发送函数(IP层和链路层)

5)一些辅助函数,如产生随机数、错误报告、端口列表管理等

​详情请看《libnet 函数列表》。​


libnet 的安装

Linux 网络编程—— libnet 使用指南_网络编程


流程

利用libnet函数库开发应用程序的基本步骤:

1)数据包内存初始化

2)构造数据包

3)发送数据

4)释放资源


以发送 UDP 数据包为例,流程图如下:

Linux 网络编程—— libnet 使用指南_网络编程_02


这里需要注意的是组包的顺序,由上层再到底层,这里为 udp -> ip -> mac,不能反过来。


常用函数介绍

以下函数的使用需要包含头文件: libnet.h


libnet_t *libnet_init(int injection_type, char *device, char *err_buf);

功能:

数据包内存初始化及环境建立

参数:

injection_type:构造的类型

LIBNET_LINK,链路层

LIBNET_RAW4,网络接口层(网络层)
LIBNET_LINK_ADV,链路层高级版本

LIBNET_RAW4_ADV,   网络层高级版本

device:网络接口,如 "eth0",或 IP 地址,亦可为 NULL (自动查询搜索)

err_buf:存放出错的信息 

返回值:

成功:一个 libnet * 类型的指针,后面的操作都得使用这个指针 

失败:NULL


void libnet_destroy(libnet_t *l);

功能:

释放资源

参数:

l:libnet_init() 返回的 libnet * 指针

返回值:


char* libnet_addr2name4(u_int32_t in, u_int8_t use_name);

功能:

将网络字节序转换成点分十进制数串

参数:

in:网络字节序的 ip 地址        

use_name:

LIBNET_RESOLVE,  对应主机名

LIBNET_DONT_RESOLVE,对应点分十进制 IPv4 地址

返回值:

成功:点分十进制 ip 地址 

失败:NULL


u_int32_t libnet_name2addr4(libnet_t *l,  char *host_name,  u_int8_t use_name);

功能:

将点分十进制数串转换为网络字节序 ip 地址

参数:

l:libnet_init() 返回的 libnet * 指针

host_name:

LIBNET_RESOLVE,  对应主机名

LIBNET_DONT_RESOLVE,对应点分十进制 IPv4 地址


返回值:

成功:网络字节序 ip 地址

失败:-1


u_int32_t libnet_get_ipaddr4(libnet_t *l);

功能:

获取接口设备 ip 地址

参数:

l:libnet_init() 返回的 libnet * 指针

返回值:

成功:网络字节序的 ip 地址

失败:-1


struct libnet_ether_addr* libnet_get_hwaddr(libnet_t *l);

功能:

获取接口设备硬件地址

参数:

l:libnet_init() 返回的 libnet * 指针

返回值:

成功:指向 MAC 地址的指针

失败:NULL


libnet_ptag_t libnet_build_udp(

u_int16_t sp, u_int16_t dp,

u_int16_t len, u_int16_t sum,

u_int8_t *payload, u_int32_t payload_s,

libnet_t *l, libnet_ptag_t ptag);

功能:

构造 udp 数据包

参数:

sp: 源端口号

dp:目的端口号

len:udp 包总长度

sum:校验和,设为 0,libnet 自动填充

payload:负载,为给应用程序发送的文本内容,没有内容时可设置为 NULL

payload_s:负载长度,给应用程序发送文本内容的长度,或为 0

l:libnet_init() 返回的 libnet * 指针

ptag:协议标记,第一次组新的发送包时,这里写 0,同一个应用程序,下一次再组包时,这个位置的值写此函数的返回值。

返回值:


成功:协议标记


失败:-1


libnet_ptag_t libnet_build_tcp(

u_int16_t sp, u_int16_t dp,

u_int32_t seq, u_int32_t ack,

u_int8_t control, u_int16_t win

u_int16_t sum, u_int16_t urg,

u_int16_t len, u_int8_t *payload,

u_int32_t payload_s, libnet_t *l,

libnet_ptag_t ptag );

功能:

构造 tcp 数据包

参数:

sp:源端口号

dp:目的端口号

seq:序号

ack:ack 标记

control:控制标记

win:窗口大小

sum:校验和,设为 0,libnet 自动填充

urg:紧急指针

len:tcp包长度

payload:负载,为给应用程序发送的文本内容,可设置为 NULL

payload_s:负载长度,或为 0

l:libnet_init() 返回的 libnet * 指针

ptag:协议标记,第一次组新的发送包时,这里写 0,同一个应用程序,下一次再组包时,这个位置的值写此函数的返回值。

返回值:

成功:协议标记


失败:-1


libnet_ptag_t libnet_build_tcp_options(

u_int8_t *options,  

u_int32_t options_s,

libnet_t *l, 

libnet_ptag_t ptag );

功能:

构造 tcp 选项数据包

参数:

options:tcp 选项字符串

options_s:选项长度

l:libnet 句柄,libnet_init() 返回的 libnet * 指针

ptag:协议标记,第一次组新的发送包时,这里写 0,同一个应用程序,下一次再组包时,这个位置的值写此函数的返回值。

返回值:

成功:协议标记

失败:-1


libnet_ptag_t libnet_build_ipv4(


u_int16_t ip_len, u_int8_t tos,

u_int16_t id, u_int16_t flag,

u_int8_t ttl, u_int8_t prot,

u_int16 sum, u_int32_t src,

u_int32_t dst, u_int8_t *payload,

u_int32_t payload_s,libnet_t *l,

libnet_ptag_t ptag );

功能:


构造一个 IPv4 数据包

参数:


ip_len:ip 包总长


tos:服务类型


id:ip 标识


flag:片偏移


ttl:生存时间


prot:上层协议


sum:校验和,设为 0,libnet 自动填充


src:源 ip 地址


dst:目的ip地址


payload:负载,可设置为 NULL(这里通常写 NULL)


payload_s:负载长度,或为 0(这里通常写 0 )


l:libnet 句柄,libnet_init() 返回的 libnet * 指针


ptag:协议标记,第一次组新的发送包时,这里写 0,同一个应用程序,下一次再组包时,这个位置的值写此函数的返回值。

返回值:


成功:协议标记  


失败:-1


libnet_ptag_t libnet_build_ipv4_options(


u_int8_t*options, u_int32_t options,

libnet_t*l, libnet_ptag_t ptag);

功能:


构造 IPv4 选项数据包

参数:


options:tcp 选项字符串


options_s:选项长度


l:libnet 句柄,libnet_init() 返回的 libnet * 指针


ptag:协议标记,若为 0,建立一个新的协议

返回值:


成功:协议标记


失败:-1


libnet_ptag_t libnet_build_arp(


u_int16_t hrd, u_int16_t pro,


u_int8_t hln, u_int8_t pln,


u_int16_t op, u_int8_t *sha,


u_int8_t *spa, u_int8_t *tha,


u_int8_t *tpa, u_int8_t *payload,


u_int32_t payload_s, libnet_t *l,


libnet_ptag_t ptag );

功能:


构造 arp 数据包

参数:


hrd:硬件地址格式,ARPHRD_ETHER(以太网)


pro:协议地址格式,ETHERTYPE_IP( IP协议)


hln:硬件地址长度


pln:协议地址长度


op:ARP协议操作类型(1:ARP请求,2:ARP回应,3:RARP请求,4:RARP回应)


sha:发送者硬件地址


spa:发送者协议地址


tha:目标硬件地址


tpa:目标协议地址


payload:负载,可设置为 NULL(这里通常写 NULL)


payload_s:负载长度,或为 0(这里通常写 0 )


l:libnet 句柄,libnet_init() 返回的 libnet * 指针


ptag:协议标记,第一次组新的发送包时,这里写 0,同一个应用程序,下一次再组包时,这个位置的值写此函数的返回值。

返回值:


成功:协议标记


失败:-1


libnet_ptag_t libnet_build_ethernet(


u_int8_t*dst, u_int8_t *src,


u_int16_ttype, u_int8_t*payload,


u_int32_tpayload_s, libnet_t*l,


libnet_ptag_t ptag );

功能:


构造一个以太网数据包

参数: 


dst:目的 mac


src:源 mac


type:上层协议类型


payload:负载,即附带的数据,可设置为 NULL(这里通常写 NULL)


payload_s:负载长度,或为 0(这里通常写 0 )


l:libnet 句柄,libnet_init() 返回的 libnet * 指针


ptag:协议标记,第一次组新的发送包时,这里写 0,同一个应用程序,下一次再组包时,这个位置的值写此函数的返回值。

返回值:


成功:协议标记


失败:-1


int libnet_write(libnet_t * l);

功能:

发送数据包

参数:

l:libnet 句柄,libnet_init() 返回的 libnet * 指针

返回值:

成功:发送数据包的长度

失败:返回 -1


使用实例

这里是在 ubuntu 下通过原始套接字组一个 udp 数据包,给 PC 机的网络调试助手发送信息(对比:《​​原始套接字实例:发送 UDP 数据包​​》):


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <libnet.h>

int main(int argc, char *argv[])
{
char send_msg[1000] = "";
char err_buf[100] = "";
libnet_t *lib_net = NULL;
int lens = 0;
libnet_ptag_t lib_t = 0;
unsigned char src_mac[6] = {0x00,0x0c,0x29,0x97,0xc7,0xc1};//发送者网卡地址00:0c:29:97:c7:c1
unsigned char dst_mac[6] = {0x74,0x27,0xea,0xb5,0xff,0xd8};//接收者网卡地址‎74-27-EA-B5-FF-D8
char *src_ip_str = "192.168.31.163"; //源主机IP地址
char *dst_ip_str = "192.168.31.248"; //目的主机IP地址
unsigned long src_ip,dst_ip = 0;

lens = sprintf(send_msg, "%s", "this is for the udp test");

lib_net = libnet_init(LIBNET_LINK_ADV, "eth0", err_buf); //初始化
if(NULL == lib_net)
{
perror("libnet_init");
exit(-1);
}

src_ip = libnet_name2addr4(lib_net,src_ip_str,LIBNET_RESOLVE); //将字符串类型的ip转换为顺序网络字节流
dst_ip = libnet_name2addr4(lib_net,dst_ip_str,LIBNET_RESOLVE);

lib_t = libnet_build_udp( //构造udp数据包
8080,
8080,
8+lens,
0,
send_msg,
lens,
lib_net,
0
);

lib_t = libnet_build_ipv4( //构造ip数据包
20+8+lens,
0,
500,
0,
10,
17,
0,
src_ip,
dst_ip,
NULL,
0,
lib_net,
0
);

lib_t = libnet_build_ethernet( //构造以太网数据包
(u_int8_t *)dst_mac,
(u_int8_t *)src_mac,
0x800, // 或者,ETHERTYPE_IP
NULL,
0,
lib_net,
0
);
int res = 0;
res = libnet_write(lib_net); //发送数据包
if(-1 == res)
{
perror("libnet_write");
exit(-1);
}

libnet_destroy(lib_net); //销毁资源

printf("----ok-----\n");
return 0;
}



编译代码时,需要加上 -lnet:

Linux 网络编程—— libnet 使用指南_应用程序_03


标签:libnet,int16,ptag,ip,Linux,使用指南,数据包,int8
From: https://blog.51cto.com/u_3002289/5720759

相关文章

  • Linux 网络编程——网络字节序、地址转换
    网络字节序故事的起源“endian”这个词出自《格列佛游记》。小人国的内战就源于吃鸡蛋时是究竟从大头(Big-Endian)敲开还是从小头(Little-Endian)敲开,由此曾发生过六次叛乱,其中......
  • Linux 进程调度浅析
    概述操作系统要实现多进程,进程调度必不可少。有人说,进程调度是操作系统中最为重要的一个部分。我觉得这种说法说得太绝对了一点,就像很多人动辄就说“某某函数比某某函数效率......
  • Linux 网络编程——原始套接字实例:发送 UDP 数据包
    以太网报文格式:IP报文格式:UDP报文格式:校验和函数:/*******************************************************功能:校验和函数参数:buf:需要校验数据的首地址nword:......
  • libnet 函数列表
    libnet提供的接口函数按其作用可分为四类:*内存管理(分配和释放)函数*地址解析函数*数据包构造函数*数据包发送函数以下分别列出这些接口函数及其功能(其参数含义简单易......
  • Linux磁盘管理与文件系统
    了解磁盘盘片:硬盘有多个盘片,每盘片2面磁头:每面一个磁头扇区:盘片被分为多个扇形区域,每个扇区存放512字节的数据,硬盘的最小存储单位磁道:同一盘片不同半径的同心圆,......
  • 如何在linux下检测(自身)IP冲突
    最近遇到一个需求,或者说是一个用户现场问题。我们设备先安装,设置dhcp模式获取ip进行联网,后来又安装了其他设备,但该设备是手动设置的静态ip地址,正好与我们设备冲突......
  • Linux make编译
    安装问题linux编译流程linux开发部分一般来说著名的linux系统基本上分两大类:RedHat系列:Redhat、Centos、Fedora等Debian系列:Debian、Ubuntu等RedHat系列常见的......
  • Linux下Docker方式在线安装Jenkins容器
    一、Docker在线安装https://www.cnblogs.com/dabao150114/p/16739213.html二、portainer容器在线安装https://www.cnblogs.com/dabao150114/p/16739217.html三、安装Je......
  • Linux下Jenkins离线安装(war包)
    1、下载Jenkins.war包地址:https://mirrors.jenkins.io/war-stable/2.346.3/2、将Jenkins.war包上传到/usr/local/tomcat/webapps3、浏览器访问:http://192.168.150.128......
  • Linux下Gitlab服务器(docker安装)
    一、Docker在线安装https://www.cnblogs.com/dabao150114/p/16739213.html二、portainer容器在线安装https://www.cnblogs.com/dabao150114/p/16739217.html三、GitLab......