使用原始套接字SOCK_RAW捕捉网络数据包并简单分析

协议的分析需要参考前一篇文章以太网帧格式,IP包头,TCP头格式说明。

抓取网络上的数据包需要设置网卡为混杂模式,调用recvfrom在创建的SOCK_RAW类型的socket上接收来自kernel的信息,然后再按照帧格式,IP头,TCP头格式,指针移动到相应位置并分析。

附上的小程序由于其他原因还在UDP9001端口监听了来自客户端的消息,这与本文无关。

#include 
    //for printf
#include 
   //for exit
#include 
   // for strcmp
#include 
   //for socket,address
#include 
  
#include 
  
#include

  
#include 
  
#include 
   //for ioctl
#include

  

#define INTERFACE "eth0"
#define BUFFLEN 2048
#define UDPPORT 9001
#define REQUEST 0
#define RESPONSE 1
#define RESERVE 2
#define z_print(fmt,args...) \
 printf("[%s %d]"fmt"\n",__FILE__,__LINE__,##args)
typedef struct {
 uint8_t version;
 uint8_t type;
 uint8_t len;
 uint16_t number;
 char data[255];
} datasend;

void* ch_hanlder();
uint8_t randvalue();
#include "zhao_sock.h"

int main(int argc,char *argv[])
{
	int sockfd;
	int len;
	int proto;
	int port_s;
	int port_d;
	char recvbuff[BUFFLEN];
	unsigned char type[4];
	unsigned char *ethhead = NULL;
	unsigned char *iphead = NULL;
	unsigned char *p = NULL;
	struct ifreq ifr;
	pthread_t thread_ch;

	pthread_create(&thread_ch,NULL,&ch_hanlder,NULL);

	sockfd = socket(PF_PACKET,SOCK_RAW,htons(ETH_P_ALL));
	if (sockfd < 0)
	{
		z_print("socket create error");
		exit(1);
	}
	strcpy(ifr.ifr_name,INTERFACE);
	if (ioctl(sockfd,SIOCGIFFLAGS,&ifr) == -1)
	{
		z_print("set PROMISC fail!\n");
		exit(1);
	}
	ifr.ifr_flags |= IFF_PROMISC;
	if (ioctl(sockfd,SIOCGIFFLAGS,&ifr) == -1)
	{
		z_print("set PROMISC fail!");
		exit(1);
	}
	while(1)
	{
		len = recvfrom(sockfd,recvbuff,sizeof(recvbuff),0,NULL,NULL);
		if (len < 42)
		{
			z_print("receive error!");
			continue;
		}
		ethhead = recvbuff;  //frame head point
		p = ethhead;
		sprintf(type,"%02x%02x",p[12],p[13]);  //frame type
		if (strcmp(type,"0800") != 0)  //0800 is IP frame
		{
			if (strcmp(type,"0806") == 0)
				printf("protocol: ARP\n");
			else if (strcmp(type,"8035") == 0)
				printf("protocol: RARP\n");
			else
				printf("protocol: unknow\n");
			printf("MAC:%.2x:%.2x:%.2x:%.2x:%.2x:%.2x==>%.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n\n", \
				p[6],p[7],p[8],p[9],p[10],p[11],p[0],p[1],p[2],p[3],p[4],p[5]);  //mac address
			continue;
		}
		iphead = ethhead + 14;  //ip head point
		p = iphead + 12; //ip address
		printf("IP:%d.%d.%d.%d==>%d.%d.%d.%d\n", \
			p[0],p[1],p[2],p[3],p[4],p[5],p[6],p[7]);
		proto = (iphead + 9)[0];  //ip protocol
		p = iphead + 20; //ip port
		switch(proto)
		{
			case IPPROTO_ICMP:
			printf("protocol: ICMP\n");
			break;
			case IPPROTO_IGMP:
			printf("protocol: IGMP\n");
			break;
			case IPPROTO_IPIP:
			printf("protocol: IPIP\n");
			break;
			case IPPROTO_TCP:
			case IPPROTO_UDP:
			printf("protocol: %s\n",(proto == IPPROTO_TCP) ? "TCP":"UDP");
			port_s = (p[0]<<8)&0XFF00 | p[1]&0XFF;  //source port
			port_d = (p[2]<<8)&0XFF00 | p[3]&0XFF;  // dest port
			printf("source port:%u,",port_s);
			printf("dest port:%u\n",port_d);
			if (port_s == 80 || port_d == 80)
				printf("protocol: HTTP\n");
			else if (port_s == 67 || port_d == 67)
				printf("protocol: DHCP\n");
			else if (port_s == 21 || port_d == 21)
				printf("protocol: FTP\n");
			else if (port_s == 23 || port_d == 23)
				printf("protocol: TELNET\n");
			else if (port_s == 53 || port_d == 53)
				printf("protocol: DNS\n");
			else if (port_s == 137 || port_d == 137 || port_s == 138 || port_d == 138)
				printf("protocol: NetBIOS/SMB\n");
			else
				printf("protocol: other\n");
			break;
			case IPPROTO_RAW:
			printf("RAW\n");
			break;
			default:
			printf("protocol:unknow(%d)\n",proto);
		}
		printf("\n");
	}
}

void* ch_hanlder()
{
	int sockfd;
	int len;
	int flag_close = 0;
	socklen_t addrlen;
	datasend msg_send;
	datasend msg_recv;
	struct sockaddr_in servaddr;

	memset(&msg_send,0,sizeof(datasend));
	memset(&msg_recv,0,sizeof(datasend));
	bzero(&servaddr, sizeof(servaddr));

	msg_send.version = 1;
	msg_send.type = RESPONSE;
	sprintf(msg_send.data,"%s","received!");

	sockfd = socket(AF_INET, SOCK_DGRAM, 0); 

	servaddr.sin_family = AF_INET;
	servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
	servaddr.sin_port = htons(UDPPORT);

	addrlen = sizeof(struct sockaddr_in);
	if (bind(sockfd, (struct sockaddr *)&servaddr, addrlen) == -1)
	{
		perror("bind error");
		exit(1);
	}
	while (1)
	{
		len = recvfrom(sockfd, &msg_recv, sizeof(datasend),0,(struct sockaddr*)&servaddr, &addrlen);
		printf("version:%3d\n",msg_recv.version);
		printf("type:%d\n",msg_recv.type);
		printf("len:%d\n",msg_recv.len);
		printf("number:%d\n",msg_recv.number);
		printf("data:%s\n",msg_recv.data);
		if (strcmp(msg_recv.data,"close") == 0)
		{
			sprintf(msg_send.data,"%s","close");
			flag_close = 1;
		}
		msg_send.number = msg_recv.number + 1;
		msg_send.len = randvalue();
		sendto(sockfd,&msg_send,sizeof(datasend),0,(struct sockaddr*)&servaddr,addrlen);
		if (flag_close)
			break;
	}
	return;
}

uint8_t randvalue()
{
	srand(time(0));
	return (rand() % 255);
}
#include "zhao_sock.h"

int main(int argc, char *argv[])
{
	int sockfd;
	int len;
	socklen_t addrlen;
	struct sockaddr_in cliaddr;
	FILE *fd;
	datasend msg_send;
	datasend msg_recv;

	fd = fopen("/root/zhao_log.txt","a");
	memset(&msg_send,0,sizeof(datasend));
	memset(&msg_recv,0,sizeof(datasend));
	bzero(&cliaddr, sizeof(cliaddr));

	msg_send.version = 1;
	msg_send.type = REQUEST;
	msg_send.number = 1;
	msg_send.len = randvalue();
	sockfd = socket(AF_INET, SOCK_DGRAM, 0);

	cliaddr.sin_family = AF_INET;
	cliaddr.sin_port = htons(UDPPORT);
	cliaddr.sin_addr.s_addr = inet_addr("127.0.0.1");

	addrlen = sizeof(struct sockaddr_in);

	while (1)
	{
	printf("please input send msg:");
	scanf("%s",msg_send.data);

	sendto(sockfd,&msg_send,sizeof(datasend),0,(struct sockaddr*)&cliaddr,addrlen);
	len = recvfrom(sockfd, &msg_recv, sizeof(datasend),0,(struct sockaddr*)&cliaddr, &addrlen);
	msg_send.number = msg_recv.number + 1;
	msg_send.len = randvalue();
	printf("version:%3d\n",msg_recv.version);
	printf("type:%d\n",msg_recv.type);
	printf("len:%d\n",msg_recv.len);
	printf("number:%d\n",msg_recv.number);
	printf("data:%s\n",msg_recv.data);

	fprintf(fd,"version:%d\n",msg_recv.version);
	fprintf(fd,"type:%d\n",msg_recv.type);
	fprintf(fd,"len:%d\n",msg_recv.len);
	fprintf(fd,"number:%d\n",msg_recv.number);
	fprintf(fd,"data:%s\n",msg_recv.data);
	if (strcmp(msg_recv.data,"close") == 0)
		break;
	}
	fclose(fd);
	return 0;
}

uint8_t randvalue()
{
	srand(time(0)+1);
	return (rand() % 255);
}

 

你可能感兴趣的:(c,职场,笔记,休闲,vin_do,vin_do学习笔记)