网络数据包格式及位置+简单嗅探器

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详解)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值