协议的分析需要参考前一篇文章以太网帧格式,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); }