1,原理 注意:不是所有的包都可以嗅探到,它有这样几个条件 1,局域网内的主机是基于HUB模式的联通方式(因为HUB会把包发给所有的终端) 2,平常使用的终端,网卡都有了过滤模式,即如果不是本地MAC,它会丢弃掉。所以要把过滤模式关掉,即运行在混在模式 3,如果是交换机构建的局域网,它会根据MAC地址转发,即使你设置了混杂模式,你也看不到别人的包。(不过可以利用ARP欺骗的方式,来通过改变MAC地址,欺骗交换机把数据包发给自己。) 好,首先,就是要把网卡至于混杂模式,我们可以写个函数。 怎样才能把网卡至于混杂模式呢?用到函数ioctl,这个函数简单介绍一下 ioctl (int fd,int requres,void*arg) 定义:<sys/ioctl.h> 功能:控制I/O设备,提供一种获得设备信息和向设备发送控制参数的手段 从这个函数的功能中,可以看到它能够操作IO设备。 参数: fd,文件描述符,这个参数最重要,它是和ioctl要操作的硬件有关。稍后实例介绍 request,这是对设备要采取怎样的操作,是读取,是写入,等等,它是一个int型,被定义好了。 arg 这是一个内存指针,会保存在操作过程中获取的信息等等。 具体来看怎样设置网卡的混杂模式,下面给出一段代码:int set_promisc(char *interface ,int sockfd) { struct ifreq ifr; strncpy(ifr.ifr_name,interface,strlen(interface)+1); if((ioctl(sockfd,SIOCGIFFLAGS,&ifr))<0) oops("ioctl get"); ifr.ifr_flags|=IFF_PROMISC; if((ioctl(sockfd,SIOCSIFFLAGS,&ifr))<0) oops("ioctl save"); printf("set promisc scueess\n"); }
2,然后是捕获数据包,首先生成一个套接口,这个套接口捕获网络层的数据代码如下:int open_raw_socket() { int sockfd; if((sockfd=socket(AF_PACKET,SOCK_RAW,htons(ETH_P_IP)))<0) oops("socket create"); return sockfd; }
3,最后,对捕获的数据进行分析。代码:#include <stdio.h> #include <errno.h> #include <sys/socket.h> #include <sys/types.h> #include <stdlib.h> #include <sys/ioctl.h> #include <unistd.h> #include <string.h> #include <net/if.h> #include <netdb.h> #include <arpa/inet.h> #include <netinet/in.h> #include <netinet/ip.h> #include <netinet/tcp.h> #include <linux/udp.h> #include <linux/icmp.h> #include <linux/if_ether.h> #include <signal.h> #define oops(msg){perror(msg);exit(0);} int set_promisc(char *interface,int sockfd); int open_raw_socket(); void ethop(char*); void ipop(char*); void tcpop(char*); void udpop(char*); void icmpop(char*); void printresult(void); int tcp_count=0,udp_count=0,ip_count=0,arp_count=0,icmp_count=0,unkonw_count=0; int main(int ac,char**av) { if(ac!=2) oops("usage:interface name"); int sockfd=open_raw_socket(); set_promisc(av[1],sockfd); char buffer[2048]; char *data; int i=0; signal(SIGINT,printresult); while(1) { int n=recvfrom(sockfd,buffer,sizeof(buffer),0,NULL,NULL); if(n<42) { printf("incomplete packete \n"); continue; } printf("----------------------------------------------------------------------------------------------------------------------------------\n"); ethop(buffer); data=(char*)(buffer+sizeof(struct ethhdr)+sizeof(struct iphdr)+sizeof(struct tcphdr)); printf("data is %s\n",data); } } void printresult(void) { printf("IP=%d arp=%d unkonw=%d\n",ip_count,arp_count,unkonw_count); printf("tcp=%d,udp=%d,icmp=%d\n",tcp_count,udp_count,icmp_count); tcp_count=0,udp_count=0,ip_count=0,arp_count=0,icmp_count=0,unkonw_count=0; exit(0); } int set_promisc(char *interface ,int sockfd) { struct ifreq ifr; strncpy(ifr.ifr_name,interface,strlen(interface)+1); if((ioctl(sockfd,SIOCGIFFLAGS,&ifr))<0) oops("ioctl get"); ifr.ifr_flags|=IFF_PROMISC; if((ioctl(sockfd,SIOCSIFFLAGS,&ifr))<0) oops("ioctl save"); printf("set promisc scueess\n"); } int open_raw_socket() { int sockfd; if((sockfd=socket(AF_PACKET,SOCK_RAW,htons(ETH_P_IP)))<0) oops("socket create"); return sockfd; } void ethop(char *buffer) { struct ethhdr *eth; int i=0; eth=(struct ethhdr*)buffer; printf("Sourc Mac:"); for(i=0;i<6;i++) printf("%x ",eth->h_source[i]); printf("\nDest Mac:"); for(i=0;i<6;i++) printf("%x ",eth->h_dest[i]); printf("\neth type:"); short type=ntohs(eth->h_proto); switch(type) { case 0x0800: printf("type is ip packet\n"); ip_count++; ipop(buffer+sizeof(struct ethhdr)); break; case 0x0806: arp_count++; printf("type is arp packet\n"); break; default: unkonw_count++; printf("unkonw type\n"); break; } } void ipop(char *buffer) { struct iphdr*ip=(struct iphdr*)buffer; struct in_addr addr; addr.s_addr=ip->saddr; printf("---------ip source :%s\n",inet_ntoa(addr)); addr.s_addr=ip->daddr; printf("---------ip dest : %s\n",inet_ntoa(addr)); int type=ip->protocol; switch(type) { case 1: printf("---------ip type is ICMP packet\n"); icmp_count++; icmpop(buffer+sizeof(struct iphdr)); break; case 6: printf("---------ip type is TCP packet\n"); tcpop(buffer+sizeof(struct iphdr)); tcp_count++; break; case 17: printf("---------ip type is UDP packet\n"); udpop(buffer+sizeof(struct iphdr)); udp_count++; break; default: printf("---------unkown ip type\n"); break; } } void tcpop(char*buffer) { struct tcphdr *tcp=(struct tcphdr*)buffer; printf("-------------------------------tcp source port %d\n",ntohs(tcp->source)); printf("-------------------------------tcp dest port %d\n",ntohs(tcp->dest)); } void udpop(char*buffer) { struct udphdr *udp=(struct udphdr*)buffer; printf("-------------------------------udp source port%d\n",ntohs(udp->source)); printf("-------------------------------udp dest port %d\n",ntohs(udp->dest)); } void icmpop(char*buffer) { struct icmphdr*icmp=(struct icmphdr*)buffer; int type=icmp->type; switch(type) { case 0: printf("--------------------------------icmp type is request\n"); break; case 8: printf("--------------------------------icmp type is reply\n"); break; case 11: printf("---------------------------------icmp type is time-out\n"); break; default: printf("---------------------------------unkonw icmp type\n"); break; } }
4,最后,总结一下各个包头的位置和结构:...................................................................... #include <linux/udp.h> //udp struct udphdr { u_int16_t source; u_int16_t dest; u_int16_t len; u_int16_t check; }; ........................................................................ #include <linux/icmp.h> struct icmphdr { u_int8_t type;//0--reques,8---reply,11----timeout; u_int8_t code; u_int16_t checksum; ........ }; .......................................................................... #include <linux/ip.h> struct iphdr { #if defined(__LITTLE_ENDIAN_BITFIELD) __u8 ihl:4, version:4; #elif defined (__BIG_ENDIAN_BITFIELD) __u8 version:4, ihl:4; #else #error "Please fix <asm/byteorder.h>" #endif __u8 tos; __be16 tot_len; __be16 id; __be16 frag_off; __u8 ttl; __u8 protocol; // 1--icmp 6---tcp 17---udp __sum16 check; __be32 saddr; __be32 daddr; /*The options start here. */ }; ......................................................................... #include <linux/tcp.h> struct tcphdr { __be16 source; __be16 dest; __be32 seq; __be32 ack_seq; #if defined(__LITTLE_ENDIAN_BITFIELD) __u16 res1:4, doff:4, fin:1, syn:1, rst:1, psh:1, ack:1, urg:1, ece:1, cwr:1; #elif defined(__BIG_ENDIAN_BITFIELD) __u16 doff:4, res1:4, cwr:1, ece:1, urg:1, ack:1, psh:1, rst:1, syn:1, fin:1; #else #error "Adjust your <asm/byteorder.h> defines" #endif __be16 window; __sum16 check; __be16 urg_ptr; } ......................................................................... #include <linux/if_ether.h> struct ethhdr { unsigned char h_dest[6]; unsigned char h_source[6]; __be16 h_proto;//0x0806---arp,0x0800--ip,0x0835---rarp. } ......................................................................... #include <linux/if_arp.h> struct arphdr { __be16 ar_hrd; /* format of hardware address */ __be16 ar_pro; /* format of protocol address */ unsigned char ar_hln; /* length of hardware address */ unsigned char ar_pln; /* length of protocol address */ __be16 ar_op; /* ARP opcode (command) */ #if 0 /* * Ethernet looks like this : This bit is variable sized however... */ unsigned char ar_sha[ETH_ALEN]; /* sender hardware address */ unsigned char ar_sip[4]; /* sender IP address */ unsigned char ar_tha[ETH_ALEN]; /* target hardware address */ unsigned char ar_tip[4]; /* target IP address */ #endif }
参考:http://baike.baidu.com/view/121586.htm?fr=aladdin http://www.linuxidc.com/Linux/2010-12/30630.htm
(包头格式)http://blog.csdn.net/tigerjibo/article/details/7351992 (ARP详解)
网络数据包格式及位置+简单嗅探器
最新推荐文章于 2024-06-06 20:15:55 发布