要求的專業知識:
一: 精通OSI參考模型,精通網絡五層:物理層,數據鏈路層,網絡層,傳
輸層,應用層。精通每一層的協議,數據報格式。精通網絡拓撲結構,
第一層,第二層,第三層的網絡互聯,數據的轉發和路由等。
二: 精通C語言程序設計,UNIX/LINUX程序設計,網絡程序設計。熟悉
UNIX/LINUX系統操作,熟悉著名服務的基本配置,特性及使用的端口
號。熟悉經典網絡命令的使用,如:netstat,ping,traceroute,
netcat,arp等。
三: 精通標準SQL語言,熟悉流行的數據庫使用,如:Oracle,Mysql等。
掌握數據庫與WEB語言的結合使用。
sniffer,我想大家都聽說過,不過是截獲數據報而已了。這樣的事情多是發生在局域
網內。因此我們要完全明白內網的工作原理。
由于寫這個文章的時候,用的多的是以太網,因此我們的實驗也在以太網環境里完成。
首先要知道是的局域網的互聯方式,目前使用的有第一層(物理層)的互聯,主要使用
轉發器,常用的轉發器就是集線器了,也就是我們常稱的HUB,用HUB互聯的網絡是一個總
線結構的網絡,在總線結構的網絡里,數據是廣播形式的傳送的。也就是兩臺主機間的通
信信息,其它的主機也可以收到,不過網絡設備檢查到目標物理地址并非是自己,便丟掉
這個數據包。但必境是收到了。
我們用程序把這些數據報全部復制一份保存下來,就是所謂的sniffer了。還要做的一
件事就是把網卡設為混雜模式(Linux里面可用命令#ifconfig ethx promisc),我們
將在程序里自己完成。
物理層互聯的局域網稱為共享式局域網。
但現在不少的局域網是在第二層(數據鏈路層)互聯的,使用的網絡設備多是網橋,最
出名的網橋叫交換機,想必你也聽說過了。這樣聯成的局域網叫交換式局域網。在這樣的
網內,數據不再是廣播了。
那我們如何才能sniffer呢?也就是如何讓別人的數據還能發到我們的機器上的網絡設
備上來呢?問題出來了,答案是ARP欺騙。留作后續。
進入我們的主題,如何寫程序把數據報從數據鏈路層copy過來。
Unix里常用的方法是:BSD的BPF(分組過濾器),SVR的DLPI(數據鏈路提供者接口),
Linux的SOCK_PACKET接口。
如果你沒有聽說過開放源代碼,那么你可能沒有必要再讀下去了。我可不想去重復已經
完成的工作。
libpcap,一個公開可得源碼的截獲函數庫,它在三種接口上都可以使用。因此我們將
使用這個函數庫來完成我們的程序。
53行,打開一個網絡設備用來嗅探。
59-64行,加入一條過濾規則,這里是只截UDP數據報。
74行,返回一個數據報。
我們用data_print函數分析打印出IP報頭的源IP和目的IP,UDP報頭中的源端口和目
標端口。
1 /* author : kf_701
2 * mtime : 2005
3 * email : kf_701@21cn.com
4 * address : 合肥大學生公寓
5 * school : ahau.edu
6 */
7
8 /* The program is used to capture data from data
9 * link layer,It is simply,only output ip address
10 * and port,read this code,then you will understand
11 * how to use libpcap functions.
12 * ****Best wishes to you !****
13 *
14 * if you want to use it ,please compile like:
15 * $gclearcase/" target="_blank" >cc -lpcap thisfile.c
16 */
17 #include<stdio.h>
18 #include<unistd.h>
19 #include<string.h>
20 #include<stdlib.h>
21 #include<pcap.h>
22
23 #include<arpa/inet.h>
24 #include<sys/socket.h>
25 #include<netinet/in_systm.h> /* required for ip.h */
26 #include<netinet/in.h>
27 #include<netinet/ip.h>
28 #include<netinet/udp.h>
29 #include<netinet/if_ether.h>
30 #include<net/if.h>
31
32 #define MAXLINE 255
33
34 static void data_print(char *,int);
35
36 int main(int argc,char **argv)
37 {
38 char *device;
39 pcap_t *pd;
40 int snlen=80,link_type;
41 uint32_t netip,netmask;
42 char errbuf[PCAP_ERRBUF_SIZE],cmd[MAXLINE];
43 int data_len; /* captured data length */
44 char *data_ptr; /* captured data ptr */
45 struct bpf_program fcode;
46 struct pcap_pkthdr pkthdr;
47 struct ether_header *eptr;
48
49 /* open device and init struct pcap */
50 if((device=pcap_lookupdev(errbuf)) == NULL)
51 printf("pcap_lookupdev: %s\n",errbuf),exit(1);
52
53 if((pd=pcap_open_live(device,snlen,1,500,errbuf)) == NULL)
54 printf("pcap_open_live: %s\n",errbuf),exit(1);
55
56 if(pcap_lookupnet(device,&netip,&netmask,errbuf)<0)
57 printf("pcap_lookupnet: %s\n",errbuf),exit(1);
58
59 strcpy(cmd,"udp");/* only capture UDP packet */
60 if(pcap_compile(pd,&fcode,cmd,0,netmask)<0)
61 printf("pcap_compile: %s\n",pcap_geterr(pd)),exit(1);
62
63 if(pcap_setfilter(pd,&fcode)<0)
64 pcap_perror(pd,"pcap_setfilter"),exit(1);
65
66 if((link_type=pcap_datalink(pd)) < 0)
67 pcap_perror(pd,"pcap_datalink"),exit(1);
68
69 printf("-----------------------------------\n\
70 kf_701 sniffer,listen on %s for udp packets...\n",
71 device);
72
73 while(1){ /* catpture data and print */
74 data_ptr=(char *)pcap_next(pd,&pkthdr);
75 if(data_ptr == NULL)
76 continue;
77 data_len = pkthdr.caplen;
78
79 switch(link_type){
80 case DLT_NULL: /* loopback header = 4 bytes */
81 data_print(data_ptr+4,data_len-4);
82 break;
83 case DLT_EN10MB: /* ether header = 14 bytes */
84 eptr = (struct ether_header *)data_ptr;
85 if(ntohs(eptr->ether_type) != ETHERTYPE_IP)
86 break;
87 data_print(data_ptr+14,data_len-14);
88 break;
89 case DLT_PPP: /* ppp header = 24 bytes */
90 data_print(data_ptr+24,data_len-24);
91 break;
92 default:
93 ;
94 }
95 }/* end while */
96 }
97
98 static void
99 data_print(char *ptr,int len)
100 {
101 int ip_hlen;
102 struct ip *ip;
103 struct udphdr *udp;
104 char *src,*dst;
105
106 printf("Captured a packet!----------------------------\n");
107
108 /* deal with part of ip head */
109 if(len < sizeof(struct ip)+sizeof(struct udphdr)){
110 printf("* error,data_len = %d\n",len);
111 return;
112 }
113 ip = (struct ip *)ptr;
114 if(ip->ip_v != 4){
115 printf("* error,not ipv4,dropped.\n");
116 return;
117 }
118 ip_hlen = ip->ip_hl << 2;
119 if(ip_hlen < sizeof(struct ip)){
120 printf("* error:ip_hl = %d\n",ip->ip_hl);
121 return;
122 }
123 src = malloc(sizeof(char)*20);
124 dst = malloc(sizeof(char)*20);
125 strncpy(src,inet_ntoa((struct in_addr)ip->ip_src),20);
126 strncpy(dst,inet_ntoa((struct in_addr)ip->ip_dst),20);
127 printf("* ip_src = %s,ip_dst = %s\n",src,dst);
128
129 /* deal with udp part of udp head */
130 if(len<ip_hlen+sizeof(struct udphdr)){
131 printf("* error:data_len = %d,ip_hlen = %d\n",len,ip_hlen);
132 return;
133 }
134 udp = (struct udphdr *)(ptr+ip_hlen);
135 printf("* source(port) = %d,dest(port) = %d,length(ip+udp+data) = %d\n",\
136 ntohs(udp->source),ntohs(udp->dest),ntohs(udp->len)+ip_hlen);
137
138 return;
139 }
關于libpcap函數庫的詳細使用,請自行查閱文章或手冊。
有問題請給我mail,謝謝。
*****待續*******