在Unix系統平臺上的網絡安全工具開發中,目前最爲流行的C API library有libnet、libpcap、libnids和libicmp等。它們分別從不同層次和角度提供了不同的功能函數。使網絡開發人員能夠忽略網絡底層細節的實現,從而專注於程序本身具體功能的設計與開發。其中,
* libnet提供的接口函數主要實現和封裝了數據包的構造和發送過程。
* libpcap提供的接口函數主要實現和封裝了與數據包截獲有關的過程。
* libnids提供的接口函數主要實現了開發網絡入侵監測系統所必須的一些結構框架。
* libicmp等相對較爲簡單,它封裝的是ICMP數據包的主要處理過程(構造、發送、接收等)。 利用這些C函數庫的接口,網絡安全工具開發人員可以很方便地編寫出具有結構化強、健壯性好、可移植性高等特點的程序,如scanner、sniffer、firewall、IDS等。
---[[ libnet ]]------------------------------------------
libnet庫的最新版本爲1.0.0(最新版已經到1.1.6),它一共約7600行C源代碼,33個源程序文件,12個C頭文件,50餘個自定義函數,提供的接口函數包含15種數據包生成器和兩種數據包發送器(IP層和數據鏈路層)。目前只支持IPv4,不支持IPv6。已經過測試的系統平臺包括:
* OpenBSD 2.6snap, 2.5, 2.4, 2.3, 2.2 (i386)
* FreeBSD 4.0-STABLE, 3.3-STABLE, 3.2-RELEASE, 3.1-CURRENT, 3.0, 2.2 (i386)
* NetBSD 1.3.2 (i386)
* BSD/OS 3.x (i386)
* BSDi 3.0 (i386)
* Linux 2.2.x, 2.0.3x, 2.1.124 (i386, alpha) (libc: 2.4.x, glibc: 2.0.x)
* Solaris 7 (SPARC, gcc 2.7.2[13], 2.8.2), 2.6 (SPARC, gcc 2.8.2),
2.5.x (SPARC, gcc 2.7.2[13])
* IRIX 6.2
* MacOS 5.3rhapsody (powerpc)
libnet提供的接口函數按其作用可分爲四類:
* 內存管理(分配和釋放)函數
* 地址解析函數
* 數據包構造函數
* 數據包發送函數
以下分別列出這些接口函數及其功能(其參數含義簡單易懂,不再解釋):
★ 內存管理函數
單數據包內存初始化:(這1.1.6版本中這些函數已經被去掉)
int libnet_init_packet(u_short packet_size, u_char **buf);
單數據包內存釋放:
void libnet_destroy_packet(u_char **buf);
多數據包內存初始化:
int libnet_init_packet_arena(struct libnet_arena **arena,
u_short packet_num, u_short packet_size);
訪問多數據包內存中的下一個數據包:
u_char *libnet_next_packet_from_arena(struct libnet_arena **arena,
u_short packet_size);
多數據包內存釋放:
void libnet_destroy_packet_arena(struct libnet_arena **arena);
★ 地址解析函數
解析主機名:
u_char *libnet_host_lookup(u_long ip, u_short use_name);
解析主機名(可重入函數):
void libnet_host_lookup_r(u_long ip, u_short use_name, u_char *buf);
域名解析:
u_long libnet_name_resolve(u_char *ip, u_short use_name);
獲取接口設備IP地址:
u_long libnet_get_ipaddr(struct libnet_link_int *l,
const u_char *device, const u_char *ebuf);
獲取接口設備硬件地址:
struct ether_addr *libnet_get_hwaddr(struct libnet_link_int *l,
const u_char *device,
const u_char *ebuf);
★ 數據包構造函數
ARP協議數據包:
int libnet_build_arp(u_short hrdw, u_short prot, u_short h_len,
u_short p_len, u_short op, u_char *s_ha,
u_char *s_pa, u_char *t_ha, u_char *t_pa,
const u_char *payload, int payload_len,
u_char *packet_buf);
DNS協議數據包:
int libnet_build_dns(u_short id, u_short flags, u_short num_q,
u_short num_answ_rr, u_short num_auth_rr,
u_short num_add_rr, const u_char * payload,
int payload_len, u_char *packet_buf);
以太網協議數據包:
int libnet_build_ethernet(u_char *daddr, u_char *saddr, u_short id,
const u_char *payload, int payload_len,
u_char *packet_buf);
ICMP協議數據包(ICMP_ECHO / ICMP_ECHOREPLY):
int libnet_build_icmp_echo(u_char type, u_char code, u_short id,
u_short seq, const u_char *payload,
int payload_len, u_char *packet_buf);
ICMP協議數據包(ICMP_MASKREQ / ICMP_MASKREPLY):
int libnet_build_icmp_mask(u_char type, u_char code, u_short id,
u_short seq, u_long mask,
const u_char *payload, int payload_len,
u_char *packet_buf);
ICMP協議數據包(ICMP_UNREACH):
int libnet_build_icmp_unreach(u_char type, u_char code,
u_short orig_len, u_char orig_tos,
u_short orig_id, u_short orig_frag,
u_char orig_ttl, u_char orig_prot,
u_long orig_saddr, u_long orig_daddr,
const u_char *payload, int payload_len,
u_char *packet_buf);
ICMP協議數據包(ICMP_TIMEXCEED):
int libnet_build_icmp_timeexceed(u_char type, u_char code,
u_short orig_len, u_char orig_tos,
u_short orig_id, u_short orig_frag,
u_char orig_ttl, u_char orig_prot,
u_long orig_saddr, u_long orig_daddr,
const u_char *payload, int payload_len,
u_char *packet_buf);
ICMP協議數據包(ICMP_REDIRECT):
int libnet_build_icmp_redirect(u_char type, u_char code, u_long gateway,
u_short orig_len, u_char orig_tos,
u_short orig_id, u_short orig_frag,
u_char orig_ttl, u_char orig_prot,
u_long orig_saddr, u_long orig_daddr,
const u_char *payload, int payload_len,
u_char *packet_buf);
ICMP協議數據包(ICMP_TSTAMP / ICMP_TSTAMPREPLY):
int libnet_build_icmp_timestamp(u_char type, u_char code, u_short id,
u_short seq, n_time otime, n_time rtime,
n_time ttime, const u_char *payload,
int payload_len, u_char *packet_buf);
IGMP協議數據包:
int libnet_build_igmp(u_char type, u_char code, u_long ip,
const u_char *payload, int payload_len,
u_char *packet_buf);
IP協議數據包:
int libnet_build_ip(u_short len, u_char tos, u_short ip_id, u_short frag,
u_char ttl, u_char protocol, u_long saddr,
u_long daddr, const u_char *payload, int payload_len,
u_char *packet_buf);
OSPF路由協議數據包:
int libnet_build_ospf(u_short len, u_char type, u_long router_id,
u_long area_id, u_short auth_type,
const char *payload, int payload_s, u_char *buf);
OSPF路由協議數據包(Hello):
int libnet_build_ospf_hello(u_long netmask, u_short interval,
u_char options, u_char priority,
u_int dead_interval, u_long des_router,
u_long backup, u_long neighbor,
const char *payload, int payload_s,
u_char *buf);
OSPF路由協議數據包(DataBase Description (DBD)):
int libnet_build_ospf_dbd(u_short len, u_char options, u_char type,
u_int sequence_num, const char *payload,
int payload_s, u_char *buf);
OSPF路由協議數據包(Link State Request (LSR)):
int libnet_build_ospf_lsr(u_int type, u_int ls_id, u_long adv_router,
const char *payload, int payload_s,
u_char *buf);
OSPF路由協議數據包(Link State Update (LSU)):
int libnet_build_ospf_lsu(u_int num, const char *payload,
int payload_s, u_char *buf);
OSPF路由協議數據包(Link State Acknowledgement (LSA)):
int libnet_build_ospf_lsa(u_short age, u_char options, u_char type,
u_int ls_id, u_long adv_router,
u_int sequence_num, u_short len,
const char *payload, int payload_s,
u_char *buf);
OSPF路由協議數據包(OSPF Link Sate NetworkLink State Router):
int libnet_build_ospf_lsa_net(u_long netmask, u_int router_id,
const char *payload, int payload_s,
u_char *buf);
OSPF路由協議數據包(Link State Router):
int libnet_build_ospf_lsa_rtr(u_short flags, u_short num, u_int id,
u_int data, u_char type, u_char tos,
u_short metric, const char *payload,
int payload_s, u_char *buf);
OSPF路由協議數據包(Link State Summary):
int libnet_build_ospf_lsa_sum(u_long netmask, u_int metric, u_int tos,
const char *payload, int payload_s,
u_char *buf);
OSPF路由協議數據包(Link State AS External):
int libnet_build_ospf_lsa_as(u_long netmask, u_int metric,
u_long fwd_addr, u_int tag,
const char *payload, int payload_s,
u_char *buf);
RIP路由協議數據包:
int libnet_build_rip(u_char cmd, u_char ver, u_short domain,
u_short addr_fam, u_short route_tag, u_long ip,
u_long mask, u_long next_hop, u_long metric,
const u_char *payload, int payload_len,
u_char *packet_buf);
TCP協議數據包:
int libnet_build_tcp(u_short th_sport, u_short th_dport, u_long th_seq,
u_long th_ack, u_char th_flags, u_short th_win,
u_short th_urg, const u_char *payload,
int payload_len, u_char *packet_buf);
UDP協議數據包:
int libnet_build_udp(u_short sport, u_short dport, const u_char *payload,
int payload_len, u_char *packet_buf);
IP協議數據包選項:
int libnet_insert_ipo(struct ipoption *opt, u_char opt_len,
u_char *packet_buf);
TCP協議數據包選項:
int libnet_insert_tcpo(struct tcpoption *opt, u_char opt_len,
u_char *packet_buf);
★ 數據包發送函數
打開raw socket:
int libnet_open_raw_sock(int protocol);
關閉raw socket:
int libnet_close_raw_sock(int socket);
選擇接口設備:
int libnet_select_device(struct sockaddr_in *sin,
u_char **device, u_char *ebuf);
打開鏈路層接口設備:
struct libnet_link_int *libnet_open_link_interface(char *device,
char *ebuf);
關閉鏈路層接口設備:
int libnet_close_link_interface(struct libnet_link_int *l);
發送IP數據包:
int libnet_write_ip(int socket, u_char *packet, int packet_size);
發送鏈路層數據包:
int libnet_write_link_layer(struct libnet_link_int *l,
const u_char *device, u_char *packet,
int packet_size);
檢驗和計算:
int libnet_do_checksum(u_char *packet, int protocol, int packet_size);
★ 相關的支持函數
隨機數種子生成器:
int libnet_seed_prand();
獲取隨機數:
u_long libnet_get_prand(int modulus);
16進制數據輸出:
void libnet_hex_dump(u_char * buf, int len, int swap, FILE *stream);
端口列表鏈初始化:
int libnet_plist_chain_new(struct libnet_plist_chain **plist,
char *token_list);
獲取端口列表鏈的下一項(端口範圍):
int libnet_plist_chain_next_pair(struct libnet_plist_chain *plist,
u_short *bport, u_short *eport);
端口列表鏈輸出顯示:
int libnet_plist_chain_dump(struct libnet_plist_chain *plist);
獲取端口列表鏈:
u_char *libnet_plist_chain_dump_string(struct libnet_plist_chain *plist);
端口列表鏈內存釋放:
void libnet_plist_chain_free(struct libnet_plist_chain *plist);
★ 數據常量
==================================================================================
數據包頭大小定義:
常量名 數值(字節數)
LIBNET_ARP_H 28
LIBNET_DNS_H 12
LIBNET_ETH_H 14
LIBNET_ICMP_H 4
LIBNET_ICMP_ECHO_H 8
LIBNET_ICMP_MASK_H 12
LIBNET_ICMP_UNREACH_H 8
LIBNET_ICMP_TIMXCEED_H 8
LIBNET_ICMP_REDIRECT_H 8
LIBNET_ICMP_TS_H 20
LIBNET_IGMP_H 8
LIBNET_IP_H 20
LIBNET_RIP_H 24
LIBNET_TCP_H 20
LIBNET_UDP_H 8
==================================================================================
數據包內存常量:
常量名 含義
LIBNET_PACKET TCP/UDP數據包頭 + IP數據包頭使用的內存
LIBNET_OPTS IP或TCP選項使用的內存
LIBNET_MAX_PACKET IP_MAXPACKET (65535字節)使用的內存
==================================================================================
隨機數發生器常量(libnet_get_prand()函數使用):
常量名 數值
LIBNET_PRAND_MAX 65535
LIBNET_PR2 0 - 2
LIBNET_PR8 0 - 255
LIBNET_PR16 0 - 32767
LIBNET_PRu16 0 - 65535
LIBNET_PR32 0 - 2147483647
LIBNET_PRu32 0 - 4294967295
==================================================================================
錯誤消息常量(libnet_error()函數使用):
常量名 含義
LIBNET_ERR_WARNING 警告類型消息
LIBNET_ERR_CRITICAL 緊急類型消息
LIBNET_ERR_FATAL 致命錯誤消息
==================================================================================
libnet_host_lookup()、libnet_host_lookup_r()和libnet_name_resolve()函數使用的常量:
常量名 含義
LIBNET_DONT_RESOLVE 不將IP地址解析爲FQDN名
LIBNET_RESOLVE 嘗試將IP地址解析爲FQDN名
==================================================================================
宏定義
宏名 功能
LIBNET_GET_ARENA_SIZE(arena) 返回多數據包內存緩衝區大小(字節數)
LIBNET_GET_ARENA_REMAINING_BYTES(arena) 返回多數據包內存緩衝區剩餘空間大小(字節數)
LIBNET_PRINT_ETH_ADDR(e) 輸出顯示ether_addr結構中的以太網地址
==================================================================================
---[[ libnet應用實例 ]]----------------------------------
利用libnet函數庫開發應用程序的基本步驟非常簡單:
1、數據包內存初始化;
2、網絡接口初始化;
3、構造所需數據包;
4、計算數據包檢驗和;
5、發送數據包;
6、關閉網絡接口;
7、釋放數據包內存。
以下是四個使用了libnet接口函數編寫的數據包發送程序。在編譯前必須確保libnet庫已成功安裝。
例一:
- /* Example 1 [raw socket api - TCP packet] */
- /* gcc -Wall `libnet-config --defines` libnet-example-x.c -o libnet-example-x \
- `libnet-config --libs` */
- #include <libnet.h>
- void usage(char *);
- int main(int argc, char **argv)
- {
- int network, /* our network interface */
- packet_size, /* packet size */
- c; /* misc */
- u_long src_ip, dst_ip; /* ip addresses */
- u_short src_prt, dst_prt; /* ports */
- u_char *cp, *packet; /* misc / packet */
- printf("libnet example code:\tmodule 1\n\n");
- printf("packet injection interface:\traw socket\n");
- printf("packet type:\t\t\tTCP [no payload]\n");
- src_ip = 0;
- dst_ip = 0;
- src_prt = 0;
- dst_prt = 0;
- while((c = getopt(argc, argv, "d:s:")) != EOF)
- {
- switch (c)
- {
- /*
- * We expect the input to be of the form `ip.ip.ip.ip.port`. We
- * point cp to the last dot of the IP address/port string and
- * then seperate them with a NULL byte. The optarg now points to
- * just the IP address, and cp points to the port.
- */
- case 'd':
- if (!(cp = strrchr(optarg, '.')))
- {
- usage(argv[0]);
- }
- *cp++ = 0;
- dst_prt = (u_short)atoi(cp);
- if (!(dst_ip = libnet_name_resolve(optarg, LIBNET_RESOLVE)))
- {
- libnet_error(LIBNET_ERR_FATAL,
- "Bad destination IP address: %s\n", optarg);
- }
- break;
- case 's':
- if (!(cp = strrchr(optarg, '.')))
- {
- usage(argv[0]);
- }
- *cp++ = 0;
- src_prt = (u_short)atoi(cp);
- if (!(src_ip = libnet_name_resolve(optarg, LIBNET_RESOLVE)))
- {
- libnet_error(LIBNET_ERR_FATAL,
- "Bad source IP address: %s\n", optarg);
- }
- break;
- }
- }
- if (!src_ip || !src_prt || !dst_ip || !dst_prt)
- {
- usage(argv[0]);
- exit(EXIT_FAILURE);
- }
- /*
- * We're just going to build a TCP packet with no payload using the
- * raw sockets API, so we only need memory for a TCP header and an IP
- * header.
- */
- packet_size = LIBNET_IP_H + LIBNET_TCP_H;
- /*
- * Step 1: Memory initialization (interchangable with step 2).
- */
- libnet_init_packet(packet_size, &packet);
- if (packet == NULL)
- {
- libnet_error(LIBNET_ERR_FATAL, "libnet_init_packet failed\n");
- }
- /*
- * Step 2: Network initialization (interchangable with step 1).
- */
- network = libnet_open_raw_sock(IPPROTO_RAW);
- if (network == -1)
- {
- libnet_error(LIBNET_ERR_FATAL, "Can't open network.\n");
- }
- /*
- * Step 3: Packet construction (IP header).
- */
- libnet_build_ip(LIBNET_TCP_H, /* size of the packet sans IP header */
- IPTOS_LOWDELAY, /* IP tos */
- 242, /* IP ID */
- 0, /* frag stuff */
- 48, /* TTL */
- IPPROTO_TCP, /* transport protocol */
- src_ip, /* source IP */
- dst_ip, /* destination IP */
- NULL, /* payload (none) */
- 0, /* payload length */
- packet); /* packet header memory */
- /*
- * Step 3: Packet construction (TCP header).
- */
- libnet_build_tcp(src_prt, /* source TCP port */
- dst_prt, /* destination TCP port */
- 0xa1d95, /* sequence number */
- 0x53, /* acknowledgement number */
- TH_SYN, /* control flags */
- 1024, /* window size */
- 0, /* urgent pointer */
- NULL, /* payload (none) */
- 0, /* payload length */
- packet + LIBNET_IP_H); /* packet header memory */
- /*
- * Step 4: Packet checksums (TCP header only).
- */
- if (libnet_do_checksum(packet, IPPROTO_TCP, LIBNET_TCP_H) == -1)
- {
- libnet_error(LIBNET_ERR_FATAL, "libnet_do_checksum failed\n");
- }
- /*
- * Step 5: Packet injection.
- */
- c = libnet_write_ip(network, packet, packet_size);
- if (c < packet_size)
- {
- libnet_error(LN_ERR_WARNING,
- "libnet_write_ip only wrote %d bytes\n", c);
- }
- else
- {
- printf("construction and injection completed, wrote all %d bytes\n", c);
- }
- /*
- * Shut down the interface.
- */
- if (libnet_close_raw_sock(network) == -1)
- {
- libnet_error(LN_ERR_WARNING,
- "libnet_close_raw_sock couldn't close the interface");
- }
- /*
- * Free packet memory.
- */
- libnet_destroy_packet(&packet);
- return (c == -1 ? EXIT_FAILURE : EXIT_SUCCESS);
- }
- void usage(char *name)
- {
- fprintf(stderr, "usage: %s -s s_ip.s_port -d d_ip.d_port\n", name);
- }
例二:
- /* Example 2 [link layer api - ICMP_MASK] */
- /* gcc -Wall `libnet-config --defines` libnet-example-x.c -o libnet-example-x `libnet-config --libs` */
- #include <libnet.h>
- void usage(char *);
- u_char enet_src[6] = {0x0d, 0x0e, 0x0a, 0x0d, 0x00, 0x00};
- u_char enet_dst[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
- int
- main(int argc, char *argv[])
- {
- int packet_size, /* size of our packet */
- c; /* misc */
- u_long src_ip, dst_ip; /* source ip, dest ip */
- u_char *packet; /* pointer to our packet buffer */
- char err_buf[LIBNET_ERRBUF_SIZE]; /* error buffer */
- u_char *device; /* pointer to the device to use */
- struct libnet_link_int *network; /* pointer to link interface struct */
- printf("libnet example code:\tmodule 2\n\n");
- printf("packet injection interface:\tlink layer\n");
- printf("packet type:\t\t\tICMP net mask [no payload]\n");
- device = NULL;
- src_ip = 0;
- dst_ip = 0;
- while ((c = getopt(argc, argv, "i:d:s:")) != EOF)
- {
- switch (c)
- {
- case 'd':
- if (!(dst_ip = libnet_name_resolve(optarg, LIBNET_RESOLVE)))
- {
- libnet_error(LIBNET_ERR_FATAL,
- "Bad destination IP address: %s\n", optarg);
- }
- break;
- case 'i':
- device = optarg;
- break;
- case 's':
- if (!(src_ip = libnet_name_resolve(optarg, LIBNET_RESOLVE)))
- {
- libnet_error(LIBNET_ERR_FATAL,
- "Bad source IP address: %s\n", optarg);
- }
- break;
- default:
- exit(EXIT_FAILURE);
- }
- }
- if (!src_ip || !dst_ip)
- {
- usage(argv[0]);
- exit(EXIT_FAILURE);
- }
- /*
- * Step 1: Network Initialization (interchangable with step 2).
- */
- if (device == NULL)
- {
- struct sockaddr_in sin;
- /*
- * Try to locate a device.
- */
- if (libnet_select_device(&sin, &device, err_buf) == -1)
- {
- libnet_error(LIBNET_ERR_FATAL,
- "libnet_select_device failed: %s\n", err_buf);
- }
- printf("device:\t\t\t\t%s\n", device);
- }
- if ((network = libnet_open_link_interface(device, err_buf)) == NULL)
- {
- libnet_error(LIBNET_ERR_FATAL,
- "libnet_open_link_interface: %s\n", err_buf);
- }
- /*
- * We're going to build an ICMP packet with no payload using the
- * link-layer API, so this time we need memory for a ethernet header
- * as well as memory for the ICMP and IP headers.
- */
- packet_size = LIBNET_IP_H + LIBNET_ETH_H + LIBNET_ICMP_MASK_H;
- /*
- * Step 2: Memory Initialization (interchangable with step 1).
- */
- if (libnet_init_packet(packet_size, &packet) == -1)
- {
- libnet_error(LIBNET_ERR_FATAL, "libnet_init_packet failed\n");
- }
- /*
- * Step 3: Packet construction (ethernet header).
- */
- libnet_build_ethernet(enet_dst,
- enet_src,
- ETHERTYPE_IP,
- NULL,
- 0,
- packet);
- /*
- * Step 3: Packet construction (ICMP header).
- */
- libnet_build_icmp_mask(ICMP_MASKREPLY, /* type */
- 0, /* code */
- 242, /* id */
- 0, /* seq */
- 0xffffffff, /* mask */
- NULL, /* payload */
- 0, /* payload_s */
- packet + LIBNET_ETH_H + LIBNET_IP_H);
- /*
- * Step 3: Packet construction (IP header).
- */
- libnet_build_ip(ICMP_MASK_H,
- 0, /* IP tos */
- 242, /* IP ID */
- 0, /* Frag */
- 64, /* TTL */
- IPPROTO_ICMP, /* Transport protocol */
- src_ip, /* Source IP */
- dst_ip, /* Destination IP */
- NULL, /* Pointer to payload (none) */
- 0,
- packet + LIBNET_ETH_H); /* Packet header memory */
- /*
- * Step 4: Packet checksums (ICMP header *AND* IP header).
- */
- if (libnet_do_checksum(packet + ETH_H, IPPROTO_ICMP, LIBNET_ICMP_MASK_H) == -1)
- {
- libnet_error(LIBNET_ERR_FATAL, "libnet_do_checksum failed\n");
- }
- if (libnet_do_checksum(packet + ETH_H, IPPROTO_IP, LIBNET_IP_H) == -1)
- {
- libnet_error(LIBNET_ERR_FATAL, "libnet_do_checksum failed\n");
- }
- /*
- * Step 5: Packet injection.
- */
- c = libnet_write_link_layer(network, device, packet, packet_size);
- if (c < packet_size)
- {
- libnet_error(LN_ERR_WARNING,
- "libnet_write_link_layer only wrote %d bytes\n", c);
- }
- else
- {
- printf("construction and injection completed, wrote all %d bytes\n", c);
- }
- /*
- * Shut down the interface.
- */
- if (libnet_close_link_interface(network) == -1)
- {
- libnet_error(LN_ERR_WARNING,
- "libnet_close_link_interface couldn't close the interface");
- }
- /*
- * Free packet memory.
- */
- libnet_destroy_packet(&packet);
- return (c == -1 ? EXIT_FAILURE : EXIT_SUCCESS);
- }
- void usage(char *name)
- {
- fprintf(stderr, "usage: %s [-i interface] -s s_ip -d d_ip\n", name);
- }
例三:
- /* Example 3 [raw socket api - ICMP_ECHO using an arena] */
- /* gcc -Wall `libnet-config --defines` libnet-example-x.c -o libnet-example-x \
- `libnet-config --libs` */
- #include <libnet.h>
- void usage(char *);
- int main(int argc, char **argv)
- {
- int network, n, c, number_of_packets, packet_size;
- struct libnet_arena arena, *arena_p;
- u_char *packets[10];
- u_long src_ip, dst_ip;
- printf("libnet example code:\tmodule 3\n\n");
- printf("packet injection interface:\tlink layer\n");
- printf("packet type:\t\t\tICMP_ECHO [no payload] using an arena\n");
- src_ip = 0;
- dst_ip = 0;
- while((c = getopt(argc, argv, "d:s:")) != EOF)
- {
- switch (c)
- {
- case 'd':
- if (!(dst_ip = libnet_name_resolve(optarg, LIBNET_RESOLVE)))
- {
- libnet_error(LIBNET_ERR_FATAL,
- "Bad destination IP address: %s\n", optarg);
- }
- break;
- case 's':
- if (!(src_ip = libnet_name_resolve(optarg, LIBNET_RESOLVE)))
- {
- libnet_error(LIBNET_ERR_FATAL,
- "Bad source IP address: %s\n", optarg);
- }
- break;
- }
- }
- if (!src_ip || !dst_ip)
- {
- usage(argv[0]);
- exit(EXIT_FAILURE);
- }
- /*
- * We're just going to build an ICMP packet with no payload using the
- * raw sockets API, so we only need memory for a ICMP header and an IP
- * header.
- */
- packet_size = LIBNET_IP_H + LIBNET_ICMP_ECHO_H;
- /*
- * Let's just build say, 10 packets.
- */
- number_of_packets = 10;
- arena_p = &arena;
- if (libnet_init_packet_arena(&arena_p, number_of_packets, packet_size) == -1)
- {
- libnet_error(LIBNET_ERR_FATAL, "libnet_init_packet_arena failed\n");
- }
- else
- {
- printf("Allocated an arena of %ld bytes..\n",
- LIBNET_GET_ARENA_SIZE(arena));
- }
- network = libnet_open_raw_sock(IPPROTO_RAW);
- if (network == -1)
- {
- libnet_error(LIBNET_ERR_FATAL, "Can't open the network.\n");
- }
- for (n = 0; n < number_of_packets; n++)
- {
- printf("%ld bytes remaining in arena\n",
- LIBNET_GET_ARENA_REMAINING_BYTES(arena));
- packets[n] = libnet_next_packet_from_arena(&arena_p, packet_size);
- if (!packets[n])
- {
- libnet_error(LIBNET_ERR_WARNING, "Arena is empty\n");
- continue;
- }
- libnet_build_ip(ICMP_ECHO_H, /* Size of the payload */
- IPTOS_LOWDELAY | IPTOS_THROUGHPUT, /* IP tos */
- 242, /* IP ID */
- 0, /* frag stuff */
- 48, /* TTL */
- IPPROTO_ICMP, /* transport protocol */
- src_ip, /* source IP */
- dst_ip, /* destination IP */
- NULL, /* pointer to payload */
- 0, /* payload length */
- packets[n]); /* packet header memory */
- libnet_build_icmp_echo(ICMP_ECHO, /* type */
- 0, /* code */
- 242, /* id */
- 5, /* seq */
- NULL, /* pointer to payload */
- 0, /* payload length */
- packets[n] + LIBNET_IP_H); /* packet header memory */
- if (libnet_do_checksum(packets[n], IPPROTO_ICMP, LIBNET_ICMP_ECHO_H) == -1)
- {
- libnet_error(LIBNET_ERR_FATAL, "libnet_do_checksum failed\n");
- }
- c = libnet_write_ip(network, packets[n], packet_size);
- if (c < packet_size)
- {
- libnet_error(LN_ERR_WARNING,
- "libnet_write_ip only wrote %d bytes\n", c);
- }
- else
- {
- printf("construction and injection of packet %d of %d completed, wrote all %d bytes\n",
- n + 1, number_of_packets, c);
- }
- }
- libnet_destroy_packet_arena(&arena_p);
- return (c == -1 ? EXIT_FAILURE : EXIT_SUCCESS);
- }
- void usage(char *name)
- {
- fprintf(stderr, "usage: %s -s source_ip -d destination_ip\n ", name);
- }
例四:
- /* Example 4 [link-layer api - UDP packet using port list chaining] */
- /* gcc -Wall `libnet-config --defines` libnet-example-x.c -o libnet-example-x \
- `libnet-config --libs` */
- #include <libnet.h>
- #define MAX_PAYLOAD_SIZE 1024
- void usage(char *);
- u_char enet_src[6] = {0x0d, 0x0e, 0x0a, 0x0d, 0x00, 0x00};
- u_char enet_dst[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
- int main(int argc, char *argv[])
- {
- int packet_size, /* size of our packet */
- payload_size, /* size of our packet */
- c; /* misc */
- u_long src_ip, dst_ip; /* source ip, dest ip */
- u_short bport, eport; /* beginning and end ports */
- u_short cport; /* current port */
- u_char payload[MAX_PAYLOAD_SIZE]; /* packet payload */
- u_char *packet; /* pointer to our packet buffer */
- char err_buf[LIBNET_ERRBUF_SIZE]; /* error buffer */
- u_char *device; /* pointer to the device to use */
- struct libnet_link_int *network; /* pointer to link interface struct */
- struct libnet_plist_chain plist; /* plist chain */
- struct libnet_plist_chain *plist_p; /* plist chain pointer */
- printf("libnet example code:\tmodule 4\n\n");
- printf("packet injection interface:\tlink layer\n");
- printf("packet type:\t\t\tUDP [with payload] using port list chaining\n");
- plist_p = NULL;
- device = NULL;
- src_ip = 0;
- dst_ip = 0;
- while ((c = getopt(argc, argv, "i:d:s:p:")) != EOF)
- {
- switch (c)
- {
- case 'd':
- if (!(dst_ip = libnet_name_resolve(optarg, LIBNET_RESOLVE)))
- {
- libnet_error(LIBNET_ERR_FATAL,
- "Bad destination IP address: %s\n", optarg);
- }
- break;
- case 'i':
- device = optarg;
- break;
- case 's':
- if (!(src_ip = libnet_name_resolve(optarg, LIBNET_RESOLVE)))
- {
- libnet_error(LIBNET_ERR_FATAL,
- "Bad source IP address: %s\n", optarg);
- }
- break;
- case 'p':
- plist_p = &plist;
- if (libnet_plist_chain_new(&plist_p, optarg) == -1)
- {
- libnet_error(LIBNET_ERR_FATAL,
- "Could not build port list\n");
- }
- break;
- default:
- usage(argv[0]);
- exit(EXIT_FAILURE);
- }
- }
- if (!src_ip || !dst_ip || !plist_p)
- {
- usage(argv[0]);
- exit(EXIT_FAILURE);
- }
- c = argc - optind;
- if (c != 1)
- {
- usage(argv[0]);
- exit(EXIT_FAILURE);
- }
- memset(payload, 0, sizeof(payload));
- strncpy(payload, argv[optind], strlen(argv[optind]));
- /*
- * Step 1: Network Initialization (interchangable with step 2).
- */
- if (device == NULL)
- {
- struct sockaddr_in sin;
- /*
- * Try to locate a device.
- */
- if (libnet_select_device(&sin, &device, err_buf) == -1)
- {
- libnet_error(LIBNET_ERR_FATAL,
- "libnet_select_device failed: %s\n", err_buf);
- }
- printf("device:\t\t\t\t%s\n", device);
- }
- if ((network = libnet_open_link_interface(device, err_buf)) == NULL)
- {
- libnet_error(LIBNET_ERR_FATAL,
- "libnet_open_link_interface: %s\n", err_buf);
- }
- /*
- * Get the payload from the user. Hrm. This might fail on a Sparc
- * if byte alignment is off...
- */
- payload_size = strlen(payload);
- /*
- * We're going to build a UDP packet with a payload using the
- * link-layer API, so this time we need memory for a ethernet header
- * as well as memory for the ICMP and IP headers and our payload.
- */
- packet_size = LIBNET_IP_H + LIBNET_ETH_H + LIBNET_UDP_H + payload_size;
- /*
- * Step 2: Memory Initialization (interchangable with step 1).
- */
- if (libnet_init_packet(packet_size, &packet) == -1)
- {
- libnet_error(LIBNET_ERR_FATAL, "libnet_init_packet failed\n");
- }
- /*
- * Step 3: Packet construction (ethernet header).
- */
- libnet_build_ethernet(enet_dst,
- enet_src,
- ETHERTYPE_IP,
- NULL,
- 0,
- packet);
- /*
- * Step 3: Packet construction (IP header).
- */
- libnet_build_ip(LIBNET_UDP_H + payload_size,
- 0, /* IP tos */
- 242, /* IP ID */
- 0, /* Frag */
- 64, /* TTL */
- IPPROTO_UDP, /* Transport protocol */
- src_ip, /* Source IP */
- dst_ip, /* Destination IP */
- NULL, /* Pointer to payload (none) */
- 0,
- packet + LIBNET_ETH_H); /* Packet header memory */
- while (libnet_plist_chain_next_pair(plist_p, &bport, &eport))
- {
- while (!(bport > eport) && bport != 0)
- {
- cport = bport++;
- /*
- * Step 3: Packet construction (UDP header).
- */
- libnet_build_udp(242, /* source port */
- cport, /* dest. port */
- payload, /* payload */
- payload_size, /* payload length */
- packet + LIBNET_ETH_H + LIBNET_IP_H);
- /*
- * Step 4: Packet checksums (ICMP header *AND* IP header).
- */
- if (libnet_do_checksum(packet + ETH_H, IPPROTO_UDP, LIBNET_UDP_H + payload_size) == -1)
- {
- libnet_error(LIBNET_ERR_FATAL, "libnet_do_checksum failed\n");
- }
- if (libnet_do_checksum(packet + ETH_H, IPPROTO_IP, LIBNET_IP_H) == -1)
- {
- libnet_error(LIBNET_ERR_FATAL, "libnet_do_checksum failed\n");
- }
- /*
- * Step 5: Packet injection.
- */
- c = libnet_write_link_layer(network, device, packet, packet_size);
- if (c < packet_size)
- {
- libnet_error(LN_ERR_WARNING,
- "libnet_write_link_layer only wrote %d bytes\n", c);
- }
- else
- {
- printf("construction and injection completed, wrote all %d bytes, port %d\n",
- c, cport);
- }
- }
- }
- /*
- * Shut down the interface.
- */
- if (libnet_close_link_interface(network) == -1)
- {
- libnet_error(LN_ERR_WARNING,
- "libnet_close_link_interface couldn't close the interface");
- }
- /*
- * Free packet memory.
- */
- libnet_destroy_packet(&packet);
- return (c == -1 ? EXIT_FAILURE : EXIT_SUCCESS);
- }
- void usage(char *name)
- {
- fprintf(stderr, "usage: %s [-i interface] -s s_ip -d d_ip -p port list payload\n", name);
- }
例五:
- 給出一個綜合應用libnet和libpcap的簡單例程,其功能是在接收到一個來自特定主機的ARP請求報文之後,發出ARP迴應報文,通知該主機請求的IP地址對應的MAC地址。這個程序實現了標準的ARP協議,但是卻不同於操作系統內核中標準的實現方法:該程序利用了libpcap在數據鏈路層抓包,利用了libnet向數據鏈路層發包,是使用libnet和libpcap構造TCP/IP協議軟件的一個例程。該程序很簡單,但已經可以說明libnet和libpcap的綜合使用方法:
- /* tell destination host with ip 'dstip' that the host with
- * request ip 'srcip' is with mac address srcmac
- * author: white cpf 2003.5.15.
- * compile: gcc arp.c -lnet -lpcap -o arp
- */
- #include "/usr/include/libnet.h"
- #include <pcap.h>
- void usage(char * exename){
- printf(" tell dstip with dstmac that srcip is at srcmac. \n");
- printf(" usage: %s -d dstip -s srcip -D dstmac -S srcmac \n",exename);
- return ;
- }
- //程序輸入:來自命令行參數
- u_char ip_src[4],ip_dst[4];
- u_char enet_src[6],enet_dst[6];
- extern int mac_strtochar6(u_char * enet,char * macstr);
- //將字符串格式的MAC地址轉換爲6字節類型r
- int get_cmdline(int argc,char *argv[]);//命令行參數處理函數
- int main(int argc, char *argv[]){
- libnet_t *l;
- libnet_ptag_t t;
- u_char *packet;
- u_long packet_s;
- char device[5]="eth0";
- char errbuf[LIBNET_ERRBUF_SIZE];
- char filter_str[100]="";
- struct bpf_program fp; /* hold compiled program */
- char *dev;
- pcap_t* descr;
- struct pcap_pkthdr hdr; /* pcap.h */
- u_char * packet;
- bpf_u_int32 maskp; /* subnet mask */
- bpf_u_int32 netp; /* ip */
- int promisc=0; /* set to promisc mode? */
- int pcap_time_out=5;
- int c, ret;
- u_long i;
- if(get_cmdline(argc,argv)<=0){
- usage(argv[0]);
- exit(0);
- }
- dev = pcap_lookupdev(errbuf);
- if(dev == NULL){
- fprintf(stderr,"%s\n",errbuf);
- return -1;
- }
- ret=pcap_lookupnet(dev,&netp,&maskp,errbuf);
- if(ret==-1){
- fprintf(stderr,"%s\n",errbuf);
- return -1;
- }
- descr = pcap_open_live(dev,BUFSIZ,promisc,pcap_time_out,errbuf);
- if(descr == NULL){
- printf("pcap_open_live(): %s\n",errbuf);
- return -1;
- }
- sprintf(filter_str,"arp and (src net %d.%d.%d.%d)",ip_dst[0],ip_dst[1],
- ip_dst[2],ip_dst[3]);
- if(pcap_compile(descr,&fp,filter_str,0,netp) == -1){
- printf("Error calling pcap_compile\n");
- return -1;
- }
- if(pcap_setfilter(descr,&fp) == -1){
- printf("Error setting filter\n");
- return -1;
- }
- while(1){
- printf("wait packet:filter:%s\n",filter_str);
- packet=pcap_next(descr, &hdr);
- if(packet == NULL){
- continue;
- }
- l = libnet_init(LIBNET_LINK_ADV,device,errbuf);
- if (l == NULL){
- fprintf(stderr, "libnet_init() failed: %s", errbuf);
- exit(EXIT_FAILURE);
- }
- t = libnet_build_arp(
- ARPHRD_ETHER, /* hardware addr */
- ETHERTYPE_IP, /* protocol addr */
- 6, /* hardware addr size */
- 4, /* protocol addr size */
- ARPOP_REPLY, /* operation type */
- enet_src, /* sender hardware addr */
- ip_src, /* sender protocol addr */
- enet_dst, /* target hardware addr */
- ip_dst, /* target protocol addr */
- NULL, /* payload */
- 0, /* payload size */
- l, /* libnet handle */
- 0); /* libnet id */
- if (t == -1){
- fprintf(stderr, "Can't build ARP header: %s\n", libnet_geterror(l));
- goto bad;
- }
- t = libnet_autobuild_ethernet(
- enet_dst, /* ethernet destination */
- ETHERTYPE_ARP, /* protocol type */
- l); /* libnet handle */
- if (t == -1){
- fprintf(stderr, "Can't build ethernet header: %s\n", libnet_geterror(l));
- goto bad;
- }
- c = libnet_adv_cull_packet(l, &packet, &packet_s);
- if (c == -1){
- fprintf(stderr, "libnet_adv_cull_packet: %s\n", libnet_geterror(l));
- goto bad;
- }
- c = libnet_write(l);
- if (c == -1){
- fprintf(stderr, "Write error: %s\n", libnet_geterror(l));
- goto bad;
- }
- continue;
- bad:
- libnet_destroy(l);
- return (EXIT_FAILURE);
- }
- libnet_destroy(l);
- return (EXIT_FAILURE);
- }
- int get_cmdline(int argc,char *argv[]){
- char c;
- char string[]="d:s:D:S:h";
- while((c = getopt(argc, argv, string)) != EOF){
- if(c=='d')
- *((unsigned int*)ip_dst)=(unsigned int)inet_addr(optarg);
- else if(c== 's')
- *((unsigned int*)ip_src)=(unsigned int)inet_addr(optarg);
- else if(c=='D')
- mac_strtochar6(enet_dst,optarg);
- else if(c=='S')
- mac_strtochar6(enet_dst,optarg);
- else if(c=='h')
- return 0;
- else
- return -1;
- }
- return 1;
- }
例六:
- #include <win32/libnet.h>
- #pragma comment(lib, "libnet.lib")
- void main()
- {
- int packet_size;//存放數據包長度的變量
- libnet_t *l;//libnet句柄
- libnet_ptag_t protocol_tag;//協議塊標記
- char *device = NULL;//設備名字,此時爲NULL
- char error_information[LIBNET_ERRBUF_SIZE];//用來存放錯誤信息
- char *destination_ip_str = "192.168.0.2";//目的IP地址字符串變量,可以指定任意一個合法的IP地址
- char *source_ip_str = "192.168.0.3";//源IP地址字符串變量,可以指定任意一個合法的IP地址
- u_char hardware_source[6] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06};//源MAC地址,可以是任意指定
- u_char hardware_destination[6] ={0x06, 0x05, 0x04, 0x03, 0x02, 0x01};//目的MAC地址,可以是任意指定
- u_long destination_ip;// 目的IP地址
- u_long source_ip;//源IP地址
- l = libnet_init(
- LIBNET_LINK_ADV,//libnet類型 */
- device,//網絡設備
- error_information);
- destination_ip = libnet_name2addr4(l,destination_ip_str, LIBNET_RESOLVE);
- //把目的IP地址字符串形式轉化成網絡順序字節形式的數據
- source_ip = libnet_name2addr4(l, source_ip_str, LIBNET_RESOLVE);
- //把源IP地址字符串形式轉化成網絡順序字節形式的數據
- protocol_tag = libnet_build_arp(
- //構造ARP協議塊,函數的返回值是代表新生成的ARP協議塊的一個協議塊標記
- ARPHRD_ETHER,
- // 硬件地址類型,在這裏是以太網
- ETHERTYPE_IP,
- //協議地址類型,在這裏是IP協議
- 6,
- //硬件地址長度,MAC地址的長度爲6
- 4,
- //協議地址長度,IP地址的長度爲4
- ARPOP_REPLY,
- //操作類型,在這裏是ARP應答類型
- hardware_source,
- //源硬件地址
- (u_int8_t*) &source_ip,
- //源IP地址
- hardware_destination,
- //目標硬件地址
- (u_int8_t*) &destination_ip,
- //目標協議地址
- NULL,
- //負載,此時爲NULL
- 0,
- //負載的長度,此時爲0
- l,
- //libnet句柄,此句柄由libnet_init()函數生成
- 0
- //協議塊標記,此時爲0,表示構造一個新的ARP協議塊,而不是修改已經存在的協議塊
- );
- protocol_tag = libnet_autobuild_ethernet(
- // 以auto的形式構造一個以太網協議塊,返回一個指向此協議塊的標記
- hardware_destination,
- //目的硬件地址
- ETHERTYPE_ARP,
- //以太網上層協議類型,此時爲ARP類型
- l //libnet句柄
- );
- packet_size = libnet_write(l);//發送已經構造的ARP數據包
- printf("發送一個%d字節長度的ARP應答數據包 ", packet_size);//輸出發送的ARP數據包的字節數
- libnet_destroy(l);//銷燬libnet
- }