協議的分析須要參考前一篇文章以太網幀格式,IP包頭,TCP頭格式說明。linux
抓取網絡上的數據包須要設置網卡爲混雜模式,調用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);
}