当前位置:文档之家› 网络协议分析软件编写

网络协议分析软件编写

网络协议分析软件编写前一阵子要写一个简单的arp协议的分析程序,在翻阅了一些资料以后,决定使用libpcap库来实现,但是后来涉及到写链路层数据的缘故(另外一个程序,这个程序就是发送一个假冒的arp request,在本文没有实现,今后有空再吧),所以放弃了libpcap。

由于本人使用的是solaris环境,所以无法使用bpf,但是sun公司仍然为开发者提供了一个与设备底层无关的接口DLPI,DLPI的全称是Data Link Provider Interface,通过DLPI开发者可以访问数据链路层的数据包,在早期的sunos系统中基本上采用的是NIT设备,但是现在solaris系统都使用了DLPI.关于DLPI的具体介绍大家可以访问网站.opengroup/pubs/catalog/c811.htm,我这里就不多说了。

在搜索了许多资料之后发现目前关于DLPI的编程资料不多,没有具体的过程,后来翻阅了Neal Nuckolls写的一篇文章How toUse theSTREAMS DataLinkProviderInterface(DLPI),根据例子做了修改(主要是提供了协议分析的部分),现在把编写一个DLPI过程共享一下,希望能对大家有所帮助。

建议大家可以先看看Neal Nuckolls的文章,其中有部分涉及到流编程的,可以参考docs.sun./app/docs/doc/816-4855的streams programmingguide(不过这不是必须的)。

使用DLPI来访问数据链路层有几个步骤1、打开网络设备2、将一个流attach到一个特定的设备上,这里就是我们刚才打开的设备3、将设备设置为混杂模式(可选)4、把数据链路层sap绑定到流5、调用ioctl,设置raw模式6、配置其他模块(可选)7、刷新缓存8、接收数据进入分析阶段第一步,我们首先打开一个网络设备,在本例中我们打开的是/dev/bge设备,这是本机的网络接口,注意不是/dev/bge0,通过open调用打开,并且返回一个描述符fd=open(device,2)第二步,attach一个流到设备上,这是通过发送DL_ATTACH_REQ原语来完成的dlattachreq(fd,ppa)int fd;u_long ppa;{dl_attach_req_t attach_req;struct strbufctl;intflags;attach_req.dl_primitive=DL_ATTACH_REQ;attach_req.dl_p pa=ppa;ctl.maxlen=0;ctl.len=sizeof(attach_req);ctl.buf=(cha r*)&attach_req;flags=0;if(putmsg(fd,&ctl,(structstrbuf*)NULL,flags)使用DLPI编程并不难,关键在于大家要了解它的框架,没必要非得自己去写一个框架来,本文就是利用了Michael R.Widner的代码,今后如果要增加功能只需要往这个框架里填就可以了。

协议分析的过程是在函数filter完成的,函数申明如下void filter(register char*cp,register u_int pktlen);该函数接收两个参数,cp是直接从设备缓存里拷贝过来的待分析数据,是链路层的封装数据,pktlen是数据的长度。

在本文中由于操作环境是以太网,因此接收的数据链路层数据是以太网封装格式,如不清楚以太网封装的可以参考《TCP/IP详解卷一协议》,以太网封装三种标准的协议类型IP协议、ARP协议和RARP 协议。

14字节的以太网首部包括了6字节的目的地址,6字节的源地址和2字节的类型字段,IP的类型值为0x0800,ARP的类型值为0x0806,RARP的类型值为0x8035。

通过检查类型字段来区别接收到的数据是属于哪一种协议,函数实现代码如下void filter(cp,pktlen)register char*cp;register u_int pktlen;{register struct ip*ip;register structtcphdr*tcph;register structether_header*eth;char*head=cp;static longline_count=0;//计数器,用来记录接收的数据次数u_short EtherType=ntohs(((struct ether_header*)cp)->ether_type);//如果EtherType小于0x600说明这是一个符合802.3标准的数据格式,应当对数据作出调整if(EtherTypeether_shost);//Mac_info函数打印出物理地址fprintf(LOG,"(");Ip_info(&ip->ip_src);//Ip_info函数打印出IP地址fprintf(LOG,")");fprintf(LOG,"--->");Mac_info(e->ether_dhos t);fprintf(LOG,"(");Ip_info(&ip->ip_dst);fprintf(LOG,")");fprintf(LOG,"\n");}else if(EtherType==ARP_PROTO)//如果协议类型是ARP{cp+=SZETH;struct ether_arp*arp=(struct ether_arp*)cp;switch(ntohs(a rp->ea_hdr.ar_op))//检查arp的操作,case ARPOP_REQUEST://如果是arp请求fprintf(LOG,"arp request:who has");arp_ip_info(arp->arp_tpa);//打印arp报文信息中的地址fprintf(LOG,"tells");arp_ip_info(arp->arp_spa);fprintf(LOG,"\n");break;case ARPOP_REPLY://arp应答fprintf(LOG,"arp reply:");arp_ip_info(arp->arp_spa);fprintf(LOG,"is at");Mac_info((struct ether_addr*)&arp->arp_sha);fprintf(LOG,"\n");break;-//可以在这里添加代码打印出arp数据报的具体内容-}程序的具体实现代码如下/*程序sniffer.c的代码清单*/#include#include#include#include#include#include#include# include#include#include#include#include#include#include#inc lude#include#include#include#include#include#include#includ e#include#include#include#include#include#define MAXDLBUF32768#define MAXWAIT15#define MAXDLADDR1024#define BITSPERBYTE8#definebcopy(s1,s2,len)memcpy(s2,s1,len)#defineindex(s,c)strchr(s,c)#define rindex(s,c)strrchr(s,c)#define bcmp(s1,s2,len)(memcmp(s1,s2,len)!=0)#define ERRstderr char *device,*ProgName,*LogNa me;FILE*LOG;int debug=0;long databuf[MAXDLBUF];intsap=0;#define NIT_DEV"/dev/bge"#define CHUNKSIZE4096 int if_fd=-1;int Packet*CHUNKSIZE+32+;int promisc=1;int bufmod=0;int filter_flags=0;intmaxbuflen=128;void Pexit(err,msg)interr;char*msg;{perror(msg);exit(err);}void Zexit(err,msg)int err;char*msg;{fprintf(ERR,msg);exit(err);}#define ARP_PROTO (0x0806)#define IP((struct ip*)Packet)#define IP_OFFSET(0x1FFF)#define SZETH(sizeof(structether_header))#define ARPLEN(sizeof(structether_arp))#define MACLEN(6)#define IPALEN(4)#define IPLEN(ntohs(ip->ip_len))#define IPHLEN(ip->ip_hl)#define INET_ADDRSTRLEN16#define MAXBUFLEN(8192)time_t LastTIME=0;char*Ptm(t)registertime_t*t;{registerchar*p=ctime(t);p[strlen(p)-6]=0;return(p);}char*NOWtm(){ti me_t tm;time(&tm);return(Ptm(&tm));}voidprint_data(uchar_t*buf,int size){inti=0;char*p=buf;for(;iether_addr_octet[0],mac->ether_addr_octet[1],mac->ether_addr_octet[2], mac->ether_addr_octet[3],mac->ether_addr_octet[4],mac->ether_addr_octet[5]);}//打印ip地址charbuf[MAXDLBUF];void Ip_info(struct in_addr*ip){charstr[INET_ADDRSTRLEN];i_ntop(AF_INET,ip,str,sizeof(str));if( *str)fprintf(LOG,"%s",str);}//打印ip地址的另外一个版本void arp_ip_info(uchar_t pa[]){fprintf(LOG,"%d.%d.%d.%d",pa*0+,pa*1+,pa*2+,pa*3+);}void death(){register structCREC*CLe;fprintf(LOG,"\nLog endedat=>%s\n",NOWtm());fflush(LOG);if(LOG!=stdout) fclose(LOG);exit(1);}err(fmt,a1,a2,a3,a4)char*fmt;char*a1,*a2,*a3,*a4;{(void)fprintf(stderr,fmt,a1,a2,a3,a4);(void)fprintf(stderr,"\n" );(void)exit(1);}void sigalrm(){(void)err("sigalrm:TIMEOUT");}strgetmsg(fd,ctlp,datap,flagsp,caller)intfd;struct strbuf*ctlp,*datap;int*flagsp;char*caller;{int rc;staticcharerrmsg[80];(void)signal(SIGALRM,sigalrm);if(alarm(MAXWA IT)<0){(void)sprintf(errmsg,"%s:getmsg",caller);syserr(errmsg);}if(alarm(0)<0){(void)sprintf(errmsg,"%s:alarm",caller);syserr(errmsg);}if((rc&(MORECTL|MOREDATA))== (MORECTL|MOREDATA))err("%s:MORECTL|MOREDATA",caller);if(rc&MORECTL)err("%s: MORECTL",caller);if(rc&MOREDATA)err("%s:MOREDATA",caller);if(ctlp->lenlen);}expecting(prim,dlp)int prim;unionDL_primitives*dlp;{if(dlp->dl_primitive!=(u_long)prim){err( "unexpected dlprimerror\n");exit(1);}}strioctl(fd,cmd,timout,len,dp)int fd;int cmd;int timout;int len;char*dp;{struct strioctlsioc;intrc;sioc.ic_cmd=cmd;sioc.ic_timout=timout;sioc.ic_len=len;si oc.ic_dp=dp;rc=ioctl(fd,I_STR,&sioc);if(rc(1);}void filter(cp,pktlen)register char*cp;registeru_int pktlen;{register structip*ip;register structtcphdr*tcph;register structether_header*eth;char*head=cp;staticlongline_count=0;u_short EtherType=ntohs(((structether_header*)cp)->ether_type);if(EtherTypeether_shost);fprintf(LOG,"(");Ip_info(&ip->ip_src);fprintf(LOG,")");fprintf (LOG,"--->");Mac_info(e->ether_dhost);fprintf(LOG,"(");Ip_i nfo(&ip->ip_dst);fprintf(LOG,")");fprintf(LOG,"\n");}else if(EtherType==ARP_PROTO){cp+=SZETH;structether_arp*arp=(structether_arp*)cp;switch(ntohs(arp->ea_hdr.ar_op)),caseARPOP_REQUEST:fprintf(LOG,"arp request:who has");arp_ip_info(arp->arp_tpa);fprintf(LOG,"tells");arp_ip_info(arp->arp_spa);fprintf(LOG,"\n");break;case ARPOP_REPLY:fprintf(LOG,"arp reply:");arp_ip_info(arp->arp_spa);fprintf(LOG,"is at");Mac_info((structether_addr*)&arp->arp_sha);fprintf(LOG,"\n");break;-//打印出arp数据报的内容-}do_it(){longbuf[MAXDLBUF];char*device;int ppa;int fd;struct strbufdata;int flags;int i;int c;int offset;int len;struct timevalt;u_int chunksize=16*1024;structsb_hdr*bp;char*p,*limp;intmrwtmp;device="/dev/bge";ppa=0;sap=0x0806;if((fd=open(devic e,2))<0)syserr(device);dlattachreq(fd,ppa);dlokack(fd,buf); if(promisc){dlpromisconreq(fd,DL_PROMISC_PHYS);dlokack(fd,buf);}dlbindreq(fd,sap,0,DL_CLDLS,0,0);dlbindack (fd,buf);if(strioctl(fd,DLIOCRAW,-1,0,NULL)<0)syserr("DLIOCRAW");if( bufmod){if(ioctl(fd,I_PUSH,"bufmod")(1);--fprintf(ERR,"Using logicaldevice%s[%s]\n",device,NIT_DEV);fprintf(ERR,"Outputto%s.%s%s",(LOG)?LogName:"stdout", (debug)?"(debug)":"",(backg)?"Backgrounding":"\n");if(!LOG)LOG=stdout;signal(SIGINT,death);signal(SIGTERM,death);signal(SIGKILL,death);signal(SIGQUIT,death);if(backg&&debug),fprintf(ERR,"*Cannot bgwith debugon+\n");backg=0;-fprintf(LOG,"\nLogstartedat=>%s[pid%d]\n",NOWtm(),getpid());fflush(LOG);do_it();}编译运行#g-lsocket-lsnl-osniffersniffer.c#./sniffer同时在另一个终端上运行ping192.168.1.10Using logicaldevice/dev/bge[/dev/bge]Output tostdout.Log startedat=>Tue Jul1218:13:44[pid948]1arp request:who has192.168.1.22tells192.168.1.102arp request:who has192.168.1.22tells192.168.1.103arp request:who has192.168.1.22tells192.168.1.104arprequest:who has192.168.1.22tells192.168.1.105arp request:who has192.168.1.22tells192.168.1.10。

相关主题