前言
本文主要介紹幾個在UNIX系統平臺上開發網絡安全工具時最常用的library。此外還提供一些如何使用這些開發庫進行網絡安全工具開發的設計框架和流程。希望能和對網絡安全工具開發有興趣的朋友共同交流,互相促進。
衆所周知,基於socket的網絡編程已成爲當今不可替代的編程方法。這種編程思想將網絡通訊當作“文件”描述字進行處理,對這個“網絡文件”(即 socket,套接字/套接口)的操作從編程者的角度來講與普通的文件操作(如讀、寫、打開、關閉等)大同小異,從而極大地簡化了網絡程序開發過程。
在衆多的網絡安全程序、工具和軟件中都是基於socket設計和開發的。由於在安全程序中通常需要對網絡通訊的細節(如連接雙 方地址/端口、服務類型、傳輸控制等)進行檢查、處理或控制,象數據包截獲、數據包頭分析、數據包重寫、甚至截斷連接等,都幾乎在每個網絡安全程序中必須 實現。爲了簡化網絡安全程序的編寫過程,提高網絡安全程序的性能和健壯性,同時使代碼更易重用與移植,最好的方法就是將最常用和最繁複的過程函數,如監聽 套接口的打開/關閉、數據包截獲、數據包構造/發送/接收等,封裝起來,以API library的方式提供給開發人員使用。
C開發庫簡介
在Unix系統平臺上的網絡安全工具開發中,目前最爲流行的C API library有libnet、libpcap、libnids和libicmp等。它們分別從不同層次和角度提供了不同的功能函數。使網絡開發人員能夠 忽略網絡底層細節的實現,從而專注於程序本身具體功能的設計與開發。其中,
* libnet提供的接口函數主要實現和封裝了數據包的構造和發送過程。
* libpcap提供的接口函數主要實現和封裝了與數據包截獲有關的過程。
* libnids提供的接口函數主要實現了開發網絡入侵監測系統所必須的一些結構框架。
* libicmp等相對較爲簡單,它封裝的是ICMP數據包的主要處理過程(構造、發送、接收等)。
利用這些C函數庫的接口,網絡安全工具開發人員可以很方便地編寫出具有結構化強、健壯性好、可移植性高等特點的程序,如scanner、sniffer、firewall、IDS等。
libnet
libnet庫的最新版本爲1.0.0,它一共約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提供的接口函數按其作用可分爲四類:
* 內存管理(分配和釋放)函數
* 地址解析函數
* 數據包構造函數
* 數據包發送函數
以下分別列出這些接口函數及其功能(其參數含義簡單易懂,不再解釋):
★ 內存管理函數
單數據包內存初始化:
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);