libnet库的常用函数

984 阅读7分钟

常用函数

libnet_init()

作用

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

函数原型

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

返回值

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

参数详解

  • injection_type:构造的类型
    LIBNET_LINK,链路层
    LIBNET_RAW4,网络接口层(网络层)
    LIBNET_LINK_ADV,链路层高级版本
    LIBNET_RAW4_ADV, 网络层高级版本
  • device:网络接口,如 "eth0",或 IP 地址,亦可为 NULL (自动查询搜索)
  • err_buf:存放出错的信息

C语言代码示例

//无

libnet_destroy()

作用

释放资源

函数原型

void libnet_destroy(libnet_t *l);

返回值

参数详解

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

C语言代码示例

//无

libnet_addr2name4()

作用

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

函数原型

char* libnet_addr2name4(u_int32_t in, u_int8_t use_name);

返回值

成功:点分十进制 ip 地址
失败:NULL

参数详解

  • in:网络字节序的 ip 地址
  • use_name:
    LIBNET_RESOLVE, 对应主机名。
    LIBNET_DONT_RESOLVE,对应点分十进制 IPv4 地址。
    一般都指定该函数的第二个参数为LIBNET_RESOLVE。

C语言代码示例

//无

libnet_name2addr4()

作用

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

函数原型

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

返回值

成功:网络字节序 ip 地址
失败:-1

参数详解

  • l:libnet_init() 返回的 libnet * 指针
  • host_name:点分十进制的IP字符串
  • use_name:
    LIBNET_RESOLVE, 对应主机名。
    LIBNET_DONT_RESOLVE,对应点分十进制 IPv4 地址。
    一般都指定该函数的第二个参数为LIBNET_RESOLVE。

C语言代码示例

//无

libnet_get_ipaddr4()

作用

获取接口设备 ip 地址

函数原型

u_int32_t libnet_get_ipaddr4(libnet_t *l);

返回值

成功:网络字节序的 ip 地址
失败:-1

参数详解

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

C语言代码示例

//无

libnet_get_hwaddr()

作用

获取接口设备硬件地址

函数原型

struct libnet_ether_addr* libnet_get_hwaddr(libnet_t *l);

返回值

成功:指向 MAC 地址的指针
失败:NULL

参数详解

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

C语言代码示例

//无

libnet_build_udp()

作用

构造 udp 数据包

函数原型

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);

返回值

成功:协议标记
失败:-1

参数详解

  • sp: 源端口号
  • dp:目的端口号
  • len:udp 包总长度
  • sum:校验和,设为 0,libnet 自动填充
  • payload:负载,为给应用程序发送的文本内容,没有内容时可设置为 NULL
  • payload_s:负载长度,给应用程序发送文本内容的长度,或为 0
  • l:libnet_init() 返回的 libnet * 指针
  • ptag:协议标记,第一次组新的发送包时,这里写 0,同一个应用程序,下一次再组包时,这个位置的值写此函数的返回值。

C语言代码示例

//无

libnet_build_tcp()

作用

构造 tcp 数据包

函数原型

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);

返回值

成功:协议标记
失败:-1

参数详解

  • sp:源端口号
  • dp:目的端口号
  • seq:序号
  • ack:ack 标记
  • control:控制标记
  • win:窗口大小
  • sum:校验和,设为 0,libnet 自动填充
  • urg:紧急指针
  • len:tcp包长度
  • payload:负载,为给应用程序发送的文本内容,可设置为 NULL
  • payload_s:负载长度,或为 0
  • l:libnet_init() 返回的 libnet * 指针
  • ptag:协议标记,第一次组新的发送包时,这里写 0,同一个应用程序,下一次再组包时,这个位置的值写此函数的返回值。

C语言代码示例

//无

libnet_build_tcp_options()

作用

构造 tcp 选项数据包

函数原型

libnet_ptag_t libnet_build_tcp_options(u_int8_t *options, u_int32_t options_s, libnet_t *l, libnet_ptag_t ptag);

返回值

成功:协议标记
失败:-1

参数详解

  • options:tcp 选项字符串
  • options_s:选项长度
  • l:libnet 句柄,libnet_init() 返回的 libnet * 指针
  • ptag:协议标记,第一次组新的发送包时,这里写 0,同一个应用程序,下一次再组包时,这个位置的值写此函数的返回值。

C语言代码示例

//无

libnet_build_ipv4()

作用

构造一个 IPv4 数据包

函数原型

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);

返回值

成功:协议标记
失败:-1

参数详解

  • 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,同一个应用程序,下一次再组包时,这个位置的值写此函数的返回值。

C语言代码示例

//无

libnet_build_ipv4_options()

作用

构造 IPv4 选项数据包

函数原型

libnet_ptag_t libnet_build_ipv4_options(u_int8_t*options, u_int32_t options, libnet_t*l, libnet_ptag_t ptag);

返回值

成功:协议标记
失败:-1

参数详解

  • options:tcp 选项字符串
  • options_s:选项长度
  • l:libnet 句柄,libnet_init() 返回的 libnet * 指针
  • ptag:协议标记,若为 0,建立一个新的协议

C语言代码示例

//无

libnet_build_arp()

作用

构造 arp 数据包

函数原型

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);

返回值

成功:协议标记
失败:-1

参数详解

  • 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,同一个应用程序,下一次再组包时,这个位置的值写此函数的返回值。

C语言代码示例

//无

libnet_build_ethernet()

作用

构造一个以太网数据包

函数原型

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);

返回值

成功:协议标记
失败:-1

参数详解

  • dst:目的 mac
  • src:源 mac
  • type:上层协议类型
  • payload:负载,即附带的数据,可设置为 NULL(这里通常写 NULL)
  • payload_s:负载长度,或为 0(这里通常写 0 )
  • l:libnet 句柄,libnet_init() 返回的 libnet * 指针
  • ptag:协议标记,第一次组新的发送包时,这里写 0,同一个应用程序,下一次再组包时,这个位置的值写此函数的返回值。

C语言代码示例

//无

libnet_write();

作用

发送数据包

函数原型

int libnet_write(libnet_t * l);

返回值

成功:发送数据包的长度
失败:返回 -1

参数详解

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

C语言代码示例

//无

综合例子

C语言代码

发送数据

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

int main(int argc, char *argv[]){
    int res = 0;
    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,0x86,0x24,0xf8};     //发送者网卡地址00:0c:29:86:24:f8
    unsigned char dst_mac[6] = {0x00,0x0c,0x29,0x86,0x24,0xf8};     //接收者网卡地址00:0c:29:86:24:f8
    char *src_ip_str = "192.168.8.23";      //源主机IP地址
    char *dst_ip_str = "192.168.8.23";      //目的主机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, "ens33", err_buf); 
    if(lib_net == NULL){
        perror("libnet_init error!");
        return -1;
    }

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

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

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

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

    //销毁资源
    libnet_destroy(lib_net); 

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

接收数据

#include <pcap.h>
#include <time.h>
#include <stdlib.h>
#include <stdio.h>
#include <netinet/ip.h>
#include <netinet/if_ether.h>
#include <netinet/tcp.h>
#include <netinet/udp.h>
#include <net/ethernet.h>

/* 以太网头总是正好14个字节 */
#define SIZE_ETHERNET 14

/* UDP头总是正好8个字节 */
#define SIZE_UDP 8
 
void getPacket(u_char *arg, const struct pcap_pkthdr *pkthdr, const u_char *packet){
    struct ethernet *ethernet;      // 以太网头
    struct ip *ip;                  // IP协议头
    struct tcphdr *tcp;             // TCP协议头
    struct udphdr *udp;             // UDP协议头         
    char *payload;                  // 数据

    u_int size_ip;
    //u_int size_tcp;

    //ethernet = (struct ethernet*)(packet);
    ip = (struct ip*)(packet + SIZE_ETHERNET);
    size_ip = (ip->ip_hl)*4;
    if (size_ip < 20) {
        printf("* Invalid IP header length: %u bytes\n", size_ip);
        return;
    }
    //udp = (struct udphdr*)(packet + SIZE_ETHERNET + size_ip);

    payload = (u_char *)(packet + SIZE_ETHERNET + size_ip + SIZE_UDP);

    printf("message:%s\n", payload);
}
 
int main(){
    char errBuf[PCAP_ERRBUF_SIZE];
    char *dev;
    pcap_t * handle;
    struct bpf_program filter;
    int id = 0;

    dev = pcap_lookupdev(errBuf);

    if(dev){
        printf("success: device: %s\n", dev);
    }
    else{
        printf("error: %s\n", errBuf);
        return 1;
    }

    handle = pcap_open_live(dev, 65535, 1, 0, errBuf);

    if(!handle){
        printf("error: pcap_open_live(): %s\n", errBuf);
        exit(1);
    }

    pcap_compile(handle, &filter, "src host 192.168.8.23 and port 8080", 1, 0);

    pcap_setfilter(handle, &filter);

    pcap_loop(handle, -1, getPacket, (u_char*)&id);

    pcap_close(handle);

    return 0;
}

运行结果

发送数据的运行截图

image.png

接受数据的运行截图

image.png