带你认识!通用网络安全开发包(Libdnet)

Libdnet是一个通用网络安全开发包,在实际的网络安全程序设计中,经常碰到一些基本而有的操作,例如:地址的管理、地址格式的转换等等,这些常见的操作在网络安全开发中很是频繁的使用,所有前人们开发了Libdnet开发包,下面让我们一起认识这个网络安全开发包!

使用Libdnet能干什么

Libdnet功能非常多,不仅仅是地址操作,还有很多非常有用的功能。

  • 在实际网络中,如果我们想操作网络接口,要对网络接口进行设置管理,例如:修改网络接口,使它具备某一功能或者不具备某一功能。
  • Libdnet还可以对路由表和ARP表的管理和配置,查看路由表的信息,修改、删除、增加路由表信息等等。
  • 使用Libdnet还可以对防火墙的管理和配置进行操作,例如:查看、修改、删除、增加防火墙规则。
  • 还有一个重要的功能,就是Libdnet可以构造和发送网络数据包,构造数据包的方式有两类,一是基于原始IP包,二是以太网帧类型。基于原始IP包的方式可以发送所有的基于IP协议的数据包,如 ICMP、TCP、UDP等。基于以太网类型的方式可以发送各种基于以太网的数据包,如ARP、IP等。

Libdnet安装

认识网络安全开发包,那我们得找个系统来安装它,在linux下对下载好的源码Libdnet-1.11.tar.gz安装包进行压缩,使用如下命令。
在这里插入图片描述

进入Libdnet目录,运行配置命令。

在这里插入图片描述
运行编译命令(make)及执行安装命令(make install)
在这里插入图片描述

安装完毕后,Libdnet本身有自带的测试程序,其命令是dnet,它自带很多参数,我们可以通过命令进行查看。

man dnet

在这里插入图片描述
Libdnet数据结构

在Libdnet中定义了各种各样的数据结构,这些数据结构在具体的功能实现过程中都要用到,它们全都定义在头文件中。
在这里插入图片描述

  • addr.h 定义关于地址操作的数据结构和函数声明。
struct addr {
	uint16_t		addr_type;
	uint16_t		addr_bits;
	union {
		eth_addr_t	__eth;
		ip_addr_t	__ip;
		ip6_addr_t	__ip6;
		
		uint8_t		__data8[16];
		uint16_t	__data16[8];
		uint32_t	__data32[4];
	} __addr_u;
};
  • arp.h 定义关于ARP操作的数据结构和函数声明。
/*
 * ARP header
 */
struct arp_hdr {
	uint16_t	ar_hrd;	/* format of hardware address */
	uint16_t	ar_pro;	/* format of protocol address */
	uint8_t		ar_hln;	/* length of hardware address (ETH_ADDR_LEN) */
	uint8_t		ar_pln;	/* length of protocol address (IP_ADDR_LEN) */
	uint16_t	ar_op;	/* operation */
};

/*
 * Hardware address format
 */
#define ARP_HRD_ETH 	0x0001	/* ethernet hardware */
#define ARP_HRD_IEEE802	0x0006	/* IEEE 802 hardware */

/*
 * Protocol address format
 */
#define ARP_PRO_IP	0x0800	/* IP protocol */

/*
 * ARP operation
 */
#define	ARP_OP_REQUEST		1	/* request to resolve ha given pa */
#define	ARP_OP_REPLY		2	/* response giving hardware address */
#define	ARP_OP_REVREQUEST	3	/* request to resolve pa given ha */
#define	ARP_OP_REVREPLY		4	/* response giving protocol address */

/*
 * Ethernet/IP ARP message
 */
struct arp_ethip {
	uint8_t		ar_sha[ETH_ADDR_LEN];	/* sender hardware address */
	uint8_t		ar_spa[IP_ADDR_LEN];	/* sender protocol address */
	uint8_t		ar_tha[ETH_ADDR_LEN];	/* target hardware address */
	uint8_t		ar_tpa[IP_ADDR_LEN];	/* target protocol address */
};

/*
 * ARP cache entry
 */
struct arp_entry {
	struct addr	arp_pa;			/* protocol address */
	struct addr	arp_ha;			/* hardware address */
};

arp_t	*arp_open(void);
int	 arp_add(arp_t *arp, const struct arp_entry *entry);
int	 arp_delete(arp_t *arp, const struct arp_entry *entry);
int	 arp_get(arp_t *arp, struct arp_entry *entry);
int	 arp_loop(arp_t *arp, arp_handler callback, void *arg);
arp_t	*arp_close(arp_t *arp);
  • blob.h 定义关于数据块的数据结构和函数声明。
typedef struct blob {
	u_char		*base;		/* start of data */
	int		 off;		/* offset into data */
	int		 end;		/* end of data */
	int		 size;		/* size of allocation */
} blob_t;



  • eth.h 定义了以太网协议的数据结构和函数声明。
typedef struct eth_addr {
	uint8_t		data[ETH_ADDR_LEN];
} eth_addr_t;

struct eth_hdr {
	eth_addr_t	eth_dst;	/* destination address */
	eth_addr_t	eth_src;	/* source address */
	uint16_t	eth_type;	/* payload type */
};

eth_t	*eth_open(const char *device);
int	 eth_get(eth_t *e, eth_addr_t *ea);
int	 eth_set(eth_t *e, const eth_addr_t *ea);
ssize_t	 eth_send(eth_t *e, const void *buf, size_t len);
eth_t	*eth_close(eth_t *e);
char	*eth_ntop(const eth_addr_t *eth, char *dst, size_t len);
int	 eth_pton(const char *src, eth_addr_t *dst);
char	*eth_ntoa(const eth_addr_t *eth);
  • fw.h 定义了关于防火墙操作的数据结构和函数声明。
struct fw_rule {
	char		fw_device[INTF_NAME_LEN]; /* interface name */
	uint8_t		fw_op;			  /* operation */
	uint8_t		fw_dir;			  /* direction */
	uint8_t		fw_proto;		  /* IP protocol */
	struct addr	fw_src;			  /* src address / net */
	struct addr	fw_dst;			  /* dst address / net */
	uint16_t	fw_sport[2];		  /* range / ICMP type */
	uint16_t	fw_dport[2];		  /* range / ICMP code */
};

fw_t	*fw_open(void);
int	 fw_add(fw_t *f, const struct fw_rule *rule);
int	 fw_delete(fw_t *f, const struct fw_rule *rule);
int	 fw_loop(fw_t *f, fw_handler callback, void *arg);
fw_t	*fw_close(fw_t *f);
  • icmp.h 定义了ICMP协议的数据结构和函数声明。
/*
 * ICMP header
 */
struct icmp_hdr {
	uint8_t		icmp_type;	/* type of message, see below */
	uint8_t		icmp_code;	/* type sub code */
	uint16_t	icmp_cksum;	/* ones complement cksum of struct */
};

/*
 * Echo message data
 */
struct icmp_msg_echo {
	uint16_t	icmp_id;
	uint16_t	icmp_seq;
	uint8_t		icmp_data __flexarr;	/* optional data */
};
  • ip.h 定义了IPv4协议数据结构和函数成名。
/*
 * IP header, without options
 */
struct ip_hdr {
#if DNET_BYTESEX == DNET_BIG_ENDIAN
	uint8_t		ip_v:4,		/* version */
			ip_hl:4;	/* header length (incl any options) */
#elif DNET_BYTESEX == DNET_LIL_ENDIAN
	uint8_t		ip_hl:4,
			ip_v:4;
#else
# error "need to include <dnet.h>"	
#endif
	uint8_t		ip_tos;		/* type of service */
	uint16_t	ip_len;		/* total length (incl header) */
	uint16_t	ip_id;		/* identification */
	uint16_t	ip_off;		/* fragment offset and flags */
	uint8_t		ip_ttl;		/* time to live */
	uint8_t		ip_p;		/* protocol */
	uint16_t	ip_sum;		/* checksum */
	ip_addr_t	ip_src;		/* source address */
	ip_addr_t	ip_dst;		/* destination address */
};

ip_t	*ip_open(void);
ssize_t	 ip_send(ip_t *i, const void *buf, size_t len);
ip_t	*ip_close(ip_t *i);

char	*ip_ntop(const ip_addr_t *ip, char *dst, size_t len);
int	 ip_pton(const char *src, ip_addr_t *dst);
char	*ip_ntoa(const ip_addr_t *ip);
#define	 ip_aton ip_pton

ssize_t	 ip_add_option(void *buf, size_t len,
	    int proto, const void *optbuf, size_t optlen);
void	 ip_checksum(void *buf, size_t len);

int	 ip_cksum_add(const void *buf, size_t len, int cksum);
  • intf.h 定义了网络接口的数据结构和函数声明。
struct intf_entry {
	u_int		intf_len;		    /* length of entry */
	char		intf_name[INTF_NAME_LEN];   /* interface name */
	u_short		intf_type;		    /* interface type (r/o) */
	u_short		intf_flags;		    /* interface flags */
	u_int		intf_mtu;		    /* interface MTU */
	struct addr	intf_addr;		    /* interface address */
	struct addr	intf_dst_addr;		    /* point-to-point dst */
	struct addr	intf_link_addr;		    /* link-layer address */
	u_int		intf_alias_num;		    /* number of aliases */
	struct addr	intf_alias_addrs __flexarr; /* array of aliases */
};

intf_t	*intf_open(void);
int	 intf_get(intf_t *i, struct intf_entry *entry);
int	 intf_get_src(intf_t *i, struct intf_entry *entry, struct addr *src);
int	 intf_get_dst(intf_t *i, struct intf_entry *entry, struct addr *dst);
int	 intf_set(intf_t *i, const struct intf_entry *entry);
int	 intf_loop(intf_t *i, intf_handler callback, void *arg);
intf_t	*intf_close(intf_t *i);
  • rand.h 定义了随机数操作的相关数据结构和函数声明。
struct rand_handle {
	uint8_t		 i;
	uint8_t		 j;
	uint8_t		 s[256];
	u_char		*tmp;
	int		 tmplen;
};

rand_t	*rand_open(void);

int	 rand_get(rand_t *r, void *buf, size_t len);
int	 rand_set(rand_t *r, const void *seed, size_t len);
int	 rand_add(rand_t *r, const void *buf, size_t len);
uint8_t	 rand_uint8(rand_t *r);
uint16_t rand_uint16(rand_t *r);
uint32_t rand_uint32(rand_t *r);
int	 rand_shuffle(rand_t *r, void *base, size_t nmemb, size_t size);
rand_t	*rand_close(rand_t *r);
  • route.h 定义了路由表操作的数据结构和函数声明。
struct route_entry {
	struct addr	route_dst;	/* destination address */
	struct addr	route_gw;	/* gateway address */
};

route_t	*route_open(void);
int	 route_add(route_t *r, const struct route_entry *entry);
int	 route_delete(route_t *r, const struct route_entry *entry);
int	 route_get(route_t *r, struct route_entry *entry);
int	 route_loop(route_t *r, route_handler callback, void *arg);
route_t	*route_close(route_t *r);
  • tcp.h 定义了TCP协议的数据结构和函数声明。
/*
 * TCP header, without options
 */
struct tcp_hdr {
	uint16_t	th_sport;	/* source port */
	uint16_t	th_dport;	/* destination port */
	uint32_t	th_seq;		/* sequence number */
	uint32_t	th_ack;		/* acknowledgment number */
#if DNET_BYTESEX == DNET_BIG_ENDIAN
	uint8_t		th_off:4,	/* data offset */
			th_x2:4;	/* (unused) */
#elif DNET_BYTESEX == DNET_LIL_ENDIAN
	uint8_t		th_x2:4,
			th_off:4;
#else
# error "need to include <dnet.h>"
#endif
	uint8_t		th_flags;	/* control flags */
	uint16_t	th_win;		/* window */
	uint16_t	th_sum;		/* checksum */
	uint16_t	th_urp;		/* urgent pointer */
};

/*
 * TCP option (following TCP header)
 */
struct tcp_opt {
	uint8_t		opt_type;	/* option type */
	uint8_t		opt_len;	/* option length >= TCP_OPT_LEN */
	union tcp_opt_data {
		uint16_t	mss;		/* TCP_OPT_MSS */
		uint8_t		wscale;		/* TCP_OPT_WSCALE */
		uint16_t	sack[19];	/* TCP_OPT_SACK */
		uint32_t	echo;		/* TCP_OPT_ECHO{REPLY} */
		uint32_t	timestamp[2];	/* TCP_OPT_TIMESTAMP */
		uint32_t	cc;		/* TCP_OPT_CC{NEW,ECHO} */
		uint8_t		cksum;		/* TCP_OPT_ALTSUM */
		uint8_t		md5[16];	/* TCP_OPT_MD5 */
		uint8_t		data8[TCP_OPT_LEN_MAX - TCP_OPT_LEN];
	} opt_data;
} __attribute__((__packed__));



  • tun.h 定义了IP隧道的数据结构和函数声明。
struct tun {
	int fd;
	intf_t *intf;
	struct ifreq ifr;
};

tun_t	   *tun_open(struct addr *src, struct addr *dst, int mtu);
int	    tun_fileno(tun_t *tun);
const char *tun_name(tun_t *tun);
ssize_t	    tun_send(tun_t *tun, const void *buf, size_t size);
ssize_t	    tun_recv(tun_t *tun, void *buf, size_t size);
tun_t	   *tun_close(tun_t *tun);
  • udp.h 定义了UDP协议的数据结构和相关的函数声明。
struct udp_hdr {
	uint16_t	uh_sport;	/* source port */
	uint16_t	uh_dport;	/* destination port */
	uint16_t	uh_ulen;	/* udp length (including header) */
	uint16_t	uh_sum;		/* udp checksum */
};

这些协议的结构主要在构造和发送它们时要用到, 感兴趣的朋友,可以查看源码了解。

Libdnet开发包的简单使用

发送IP数据包

下面我们来写一个功能,就是发送一个IP数据包,此数据包由一段数据组成,可以任意填充,我们这里用一个字符串来表示,用十六进制进行显示。

下面我们用到这三个函数:

ip_t	*ip_open(void);
ssize_t	 ip_send(ip_t *i, const void *buf, size_t len);
ip_t	*ip_close(ip_t *i);

发送IP数据包的过程主要由三个步骤组成:首先利用ip_open()函数打开IP协议操作,并对其进行初始化。然后使用ip_send()函数发送数据,最后利用函数ip_close()关闭IP协议操作功能。

#include <sys/types.h>
#include <dnet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

int main(int argc, char **argv)
{
	ip_t *handle;
	/*数据的形式是以十六进制的形式给出的*/
	u_char ip_content[9] = "\x23\x00\x34\xce\x12\x00\xff\x89"; 
	
	int ip_length = 8; /*IP 协议头长度为8个字节*/
	
	handle = ip_open();
	
	/*发送IP数据包*/
	
	ip_send(handle,ip_content,ip_length);
	
	ip_close(handle);
	
	return 0;
}

最后我们可以使用tcpdump工具的分析结果分析。

ARP缓存操作

ARP缓存放了IP地址到以太网地址之间的映射记录,有了ARP缓存,ARP协议运行的效率就会提高。

#include <sys/types.h>
#include <dnet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

int show_arp_cache(const struct arp_entry *object, void *p)
{
    printf("IP %s at MAC %s\n ", addr_ntoa(&object->arp_pa), addr_ntoa(&object->arp_ha));
    /* 显示IP地址和以太网地址对 */
    return (0);
}

int main(int argc ,char **argv)
{
    struct arp_entry arp_object;
    arp_t *arp_handle;
    arp_handle = arp_open();

    printf("show the arp cache\n");
    arp_loop(arp_handle, show_arp_cache, NULL);
    /*
     * 注册回调函数show_arp_cache,作用是循环调用回调函数对每个ARP缓存记录进行操作。此处是显示每个ARP缓存记录。
     */
    printf("Add a arp \n");
    addr_pton("192.168.227.4", &arp_object.arp_pa);
    addr_pton("11:11:11:11:11:11", &arp_object.arp_ha);
    arp_add(arp_handle, &arp_object);   
    /* 增加一个ARP缓存记录 */
    
    printf("a arp added\n");
    addr_pton("192.168.227.5", &arp_object.arp_pa);
    addr_pton("22:22:22:22:22:22", &arp_object.arp_ha);
    arp_add(arp_handle, &arp_object);
    /* 增加一个ARP缓存记录 */
    
    printf("a arp added\n");
    printf("show the arp cache again\n");
    arp_loop(arp_handle, show_arp_cache, NULL);

    
    printf("Delete a arp \n");
    addr_pton("192.168.227.4", &arp_object.arp_pa);
    arp_delete(arp_handle, &arp_object);    
    /* 删除一个ARP缓存记录 */
    
    printf("a arp deleted\n");
    printf("show the arp cache again\n");
    arp_loop(arp_handle, show_arp_cache, NULL);
    /* 显示每个ARP缓存记录 */
    arp_close(arp_handle);

}

编译运行

在这里插入图片描述

运行的结果可以看出,Libdnet提供了对ARP缓存操作的功能,它可以查看ARP缓存内容,添加ARP缓存的记录,也可以删除ARP缓存记录。

网络路由表操作

在Libdnet实现对网络路由表的操作,下面我们写一个例子测试一下Libdnet路由表的使用。

#include <sys/types.h>
#include <dnet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

int show_route_rule(const struct route_entry *entry, void *arg)
{
    printf("Destination :%s  =======  Gateway :%s\n", addr_ntoa(&entry->route_dst), addr_ntoa(&entry->route_gw));
    /* 显示路由表记录 */
    return (0);
}
int main(int argc, char *argv[])
{
    struct route_entry entry;    /* 路由表的数据结构的变量 */

    route_t *handle;
    handle = route_open();    /* 打开路由表操作 */

    printf("Show the route rules:\n");
    printf("Route rules :\n");
    printf("Destination IP  ----------------------- Gateway IP\n");
    route_loop(handle, show_route_rule, NULL);

    printf("Show the route rules about the Destination IP:\n");
    addr_aton("192.168.12.4", &entry.route_dst);

    route_get(handle, &entry);    /* 根据地址获取其路由表信息 */

    printf("Destination is :\n");
    printf("%s\n", addr_ntoa(&entry.route_dst));    /* 输出目的地址 */

    printf("Gateway is: \n");
    printf("%s\n", addr_ntoa(&entry.route_gw));    /* 输出网关地址 */
    printf("Add a route rule :\n");
    addr_aton("192.168.12.10", &entry.route_gw);

    route_add(handle, &entry);    /* 添加路由表记录 */
    printf("Destination :%s Gateway :%s added:\n", addr_ntoa(&entry.route_dst), addr_ntoa(&entry.route_gw));
    printf("Add a route rule :\n");
    addr_aton("192.168.12.6", &entry.route_dst);
    addr_aton("192.168.12.20", &entry.route_gw);
	
    route_add(handle, &entry);    /* 添加路由表记录 */
    printf("Destination :%s Gateway :%s added:\n", addr_ntoa(&entry.route_dst), addr_ntoa(&entry.route_gw));
    printf("Show the route rules:\n");
    printf("Route rules :\n");
    printf("Destination IP  ----------------------- Gateway IP\n");
	
    route_loop(handle, show_route_rule, NULL);    /* 显示所有路由表记录 */
    printf("Delete a route rule :\n");
    addr_aton("192.168.12.5", &entry.route_dst);
	
    route_delete(handle, &entry);/* 删除路由表记录 */
    printf("Destination :%s deleted\n", addr_ntoa(&entry.route_dst));
    printf("Show the route rules:\n");
    printf("Route rules :\n");
    printf("Destination IP  ----------------------- Gateway IP\n");
	
    route_loop(handle, show_route_rule, NULL);/* 再显示所有路由表记录 */ 
    route_close(handle);

}

编译运行:
在这里插入图片描述

总结

Libdnet是一个应用非常广泛的通用网络开发包,特别在网络安全方面应用很多。使用Libdnet开发的网络程序有很多,例如:arpscan,Firewalk,RING,Fragroute等等。

欢迎关注微信公众号【程序猿编码】,欢迎添加本人微信号(17865354792),交个朋友,咱们一起学习进步!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值