/*说明 本程序是使用原始套接字编写的简单抓包程序,将网卡设置为混杂模式,可以接收到网络上任意的数据包可以获取ETHERNET包头/IP包头ARP包头/RARP包头/TCP包头/UDP包头ICMP包头的数据时间 20111228邮箱 lxgwm2008@foxmail.com1、增加filter过滤功能,使用BPF(BSD packet filter)码,类似于tcpdump的过滤机制,直接在底层过滤,减少上层过滤引起的压力*/
#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <sys/socket.h>#include <sys/types.h>#include <sys/ioctl.h>#include <netinet/in.h>#include <netinet/ip.h>#include <netinet/tcp.h>#include <netinet/udp.h>#include <netinet/ip_icmp.h>#include <net/ethernet.h>#include <net/if_arp.h>#include <net/if.h>#include <arpa/inet.h>#include <linux/filter.h>#include <errno.h>#define EXIT_FIILURE -1#define EXIT_SUCCESS 0extern int errno;void DisplayEthernet(struct ether_header *_pEtherheader){#if 0struct ether_header{ u_int8_t ether_dhost[ETH_ALEN];// destination eth addr u_int8_t ether_shost[ETH_ALEN];// source ether addru_int16_t ether_type; // packet type ID field} __attribute__ ((__packed__));#endifchar *ethertypeStr = NULL;unsigned short ethertype = ntohs(_pEtherheader->ether_type);switch(ethertype){case 0x0200:ethertypeStr = "ETHERTYPE_PUP";break;case 0x0800:ethertypeStr = "ETHERTYPE_IP";break;case 0x0806:ethertypeStr = "ETHERTYPE_ARP";break;case 0x0835:ethertypeStr = "ETHERTYPE_REVARP";break;default:ethertypeStr = "Unrecognized";break;}fprintf(stdout, "------this is a ethernet header------\n");fprintf(stdout, "ether_dhost= %02X:%02X:%02X:%02X:%02X:%02X\n", _pEtherheader->ether_dhost[0], _pEtherheader->ether_dhost[1], _pEtherheader->ether_dhost[2], _pEtherheader->ether_dhost[3], _pEtherheader->ether_dhost[4], _pEtherheader->ether_dhost[5]);fprintf(stdout, "ether_shost= %02X:%02X:%02X:%02X:%02X:%02X\n", _pEtherheader->ether_shost[0], _pEtherheader->ether_shost[1], _pEtherheader->ether_shost[2], _pEtherheader->ether_shost[3], _pEtherheader->ether_shost[4], _pEtherheader->ether_shost[5]);fprintf(stdout, "ether_type= %#04x(%s)\n", ethertype, ethertypeStr);fprintf(stdout, "------end---------------------------\n");}void DisplayIp(struct ip *_pIPheader){#if 0struct ip {#if __BYTE_ORDER == __LITTLE_ENDIAN unsigned int ip_hl:4;/* header length */ unsigned int ip_v:4;/* version */#endif#if __BYTE_ORDER == __BIG_ENDIAN unsigned int ip_v:4;/* version */ unsigned int ip_hl:4;/* header length */#endif u_int8_t ip_tos;/* type of service */ u_short ip_len;/* total length */ u_short ip_id;/* identification */ u_short ip_off;/* fragment offset field */#defineIP_RF 0x8000/* reserved fragment flag */#defineIP_DF 0x4000/* dont fragment flag */#defineIP_MF 0x2000/* more fragments flag */#defineIP_OFFMASK 0x1fff/* mask for fragmenting bits */ u_int8_t ip_ttl;/* time to live */ u_int8_t ip_p;/* protocol */ u_short ip_sum;/* checksum */ struct in_addr ip_src, ip_dst;/* source and dest address */ };#endifchar *pStr = NULL;unsigned char p = _pIPheader->ip_p;switch(p){case 0:pStr = "IPPROTO_IP";break;case 1:pStr = "IPPROTO_ICMP";break;case 2:pStr = "IPPROTO_IGMP";break;case 6:pStr = "IPPROTO_TCP";break;case 17:pStr = "IPPROTO_UDP";break;default:pStr = "Unrecognized";break;}fprintf(stdout, "------this is a IP header------\n");fprintf(stdout, "ip_hl = %u\n", _pIPheader->ip_hl << 2);fprintf(stdout, "ip_v = %u\n", _pIPheader->ip_v);fprintf(stdout, "ip_tos = %u\n", _pIPheader->ip_tos);fprintf(stdout, "ip_len = %u\n", ntohs(_pIPheader->ip_len));fprintf(stdout, "ip_id = %u\n", ntohs(_pIPheader->ip_id));fprintf(stdout, "ip_off = %u\n", ntohs(_pIPheader->ip_off));fprintf(stdout, "ip_ttl = %u\n", _pIPheader->ip_ttl);fprintf(stdout, "ip_p = %u(%s)\n", p, pStr);fprintf(stdout, "ip_sum = %u\n", ntohs(_pIPheader->ip_sum));fprintf(stdout, "ip_src = %s\n", inet_ntoa(_pIPheader->ip_src));fprintf(stdout, "ip_dst = %s\n", inet_ntoa(_pIPheader->ip_dst));fprintf(stdout, "------end---------------------------\n");}void DisplayArp(struct arphdr *_pArpheader){#if 0struct arphdr { unsigned short int ar_hrd;// Format of hardware address. unsigned short int ar_pro;// Format of protocol address. unsigned char ar_hln;// Length of hardware address. unsigned char ar_pln;// Length of protocol address.unsigned short int ar_op;// ARP opcode (command).};#endifstatic const char *hardwaretype[] = {"ARPHRD_NETROM", "ARPHRD_ETHER","ARPHRD_EETHER","ARPHRD_AX25","ARPHRD_PRONET","ARPHRD_CHAOS","ARPHRD_IEEE802","ARPHRD_ARCNET","ARPHRD_APPLETLK"};char *ptStr = NULL;unsigned short ht = ntohs(_pArpheader->ar_hrd);unsigned short pt = ntohs(_pArpheader->ar_pro);switch(pt){case 0x0800:ptStr = "IP";break;case 0x0806:ptStr = "ARP";break;case 0x0835:ptStr = "REVARP";break;default:ptStr = "Unrecognized";break;}char *opStr = NULL;unsigned short op = ntohs(_pArpheader->ar_op);switch(op){case 1:opStr = "ARPOP_REQUEST";break;case 2:opStr = "ARPOP_REPLY";break;default:opStr = "Unrecognized";break;}fprintf(stdout, "------this is a arp header------\n");fprintf(stdout, "ar_hrd = %#02X(%s)\n", ht, hardwaretype[ht]);fprintf(stdout, "ar_pro = %#02X(%s)\n", pt, ptStr);fprintf(stdout, "ar_hln = %u\n", _pArpheader->ar_hln);fprintf(stdout, "ar_pln = %u\n", _pArpheader->ar_pln);fprintf(stdout, "ar_op = %#02X(%s)\n", op, opStr);fprintf(stdout, "------end---------------------------\n");}void DisplayRarp(struct arphdr *_pRarpheader){static const char *hardwaretype[] = {"ARPHRD_NETROM", "ARPHRD_ETHER","ARPHRD_EETHER","ARPHRD_AX25","ARPHRD_PRONET","ARPHRD_CHAOS","ARPHRD_IEEE802","ARPHRD_ARCNET","ARPHRD_APPLETLK"};char *ptStr = NULL;unsigned short ht = ntohs(_pRarpheader->ar_hrd);unsigned short pt = ntohs(_pRarpheader->ar_pro);switch(pt){case 0x0800:ptStr = "IP";break;case 0x0806:ptStr = "ARP";break;case 0x0835:ptStr = "REVARP";break;default:ptStr = "Unrecognized";break;}char *opStr = NULL;unsigned short op = ntohs(_pRarpheader->ar_op);switch(op){case 3:opStr = "ARPOP_RREQUEST";break;case 4:opStr = "ARPOP_RREPLY";break;default:opStr = "Unrecognized";break;}fprintf(stdout, "------this is a rarp header------\n");fprintf(stdout, "ar_hrd = %#02X(%s)\n", ht, hardwaretype[ht]);fprintf(stdout, "ar_pro = %#02X(%s)\n", pt, ptStr);fprintf(stdout, "ar_hln = %u\n", _pRarpheader->ar_hln);fprintf(stdout, "ar_pln = %u\n", _pRarpheader->ar_pln);fprintf(stdout, "ar_op = %#02X(%s)\n", op, opStr);fprintf(stdout, "------end---------------------------\n");}void DisplayTcp(struct tcphdr *_pTcpheader){#if 0struct tcphdr { u_int16_t source; u_int16_t dest; u_int32_t seq; u_int32_t ack_seq;# if __BYTE_ORDER == __LITTLE_ENDIAN u_int16_t res1:4; u_int16_t doff:4; u_int16_t fin:1; u_int16_t syn:1; u_int16_t rst:1; u_int16_t psh:1; u_int16_t ack:1; u_int16_t urg:1; u_int16_t res2:2;# elif __BYTE_ORDER == __BIG_ENDIAN u_int16_t doff:4; u_int16_t res1:4; u_int16_t res2:2; u_int16_t urg:1; u_int16_t ack:1; u_int16_t psh:1; u_int16_t rst:1; u_int16_t syn:1; u_int16_t fin:1;# else# error "Adjust your <bits/endian.h> defines"# endif u_int16_t window; u_int16_t check; u_int16_t urg_ptr;};#endiffprintf(stdout, "------this is a tcp header------\n");fprintf(stdout, "source = %u\n", ntohs(_pTcpheader->source));fprintf(stdout, "dest = %u\n", ntohs(_pTcpheader->dest));fprintf(stdout, "seq = %u\n", ntohl(_pTcpheader->seq));fprintf(stdout, "ack_seq= %u\n", ntohl(_pTcpheader->ack_seq));fprintf(stdout, "res1 = %u\n", _pTcpheader->res1);fprintf(stdout, "doff = %u\n", _pTcpheader->doff);fprintf(stdout, "fin = %u\n", _pTcpheader->fin);fprintf(stdout, "syn = %u\n", _pTcpheader->syn);fprintf(stdout, "rst = %u\n", _pTcpheader->rst);fprintf(stdout, "psh = %u\n", _pTcpheader->psh);fprintf(stdout, "ack = %u\n", _pTcpheader->ack);fprintf(stdout, "urg = %u\n", _pTcpheader->urg);fprintf(stdout, "res2 = %u\n", _pTcpheader->res2);fprintf(stdout, "window = %u\n", ntohs(_pTcpheader->window));fprintf(stdout, "check = %u\n", ntohs(_pTcpheader->check));fprintf(stdout, "urg = %u\n", ntohs(_pTcpheader->urg_ptr));fprintf(stdout, "------end---------------------------\n");}void DisplayUdp(struct udphdr *_pUdpheader){#if 0struct udphdr{ u_int16_t source; u_int16_t dest; u_int16_t len; u_int16_t check;};#endiffprintf(stdout, "------this is a udp header------\n");fprintf(stdout, "source = %u\n", ntohs(_pUdpheader->source));fprintf(stdout, "dest = %u\n", ntohs(_pUdpheader->dest));fprintf(stdout, "len = %u\n", ntohs(_pUdpheader->len));fprintf(stdout, "check= %u\n", ntohs(_pUdpheader->check));fprintf(stdout, "------end---------------------------\n");}void DisplayIcmp(struct icmphdr *_pIcmpheader){#if 0struct icmphdr{ u_int8_t type;/* message type */ u_int8_t code;/* type sub-code */ u_int16_t checksum; union{ struct{ u_int16_tid; u_int16_tsequence; } echo;/* echo datagram */ u_int32_tgateway;/* gateway address */ struct{ u_int16_t__unused; u_int16_tmtu; } frag;/* path mtu discovery */ }un;};#endifconst char *typeStr = NULL;const char *codeStr = NULL;static const char *codeDestUnreachStr[] = {"ICMP_UNREACH_NET","ICMP_UNREACH_HOST","ICMP_UNREACH_PROTOCOL","ICMP_UNREACH_PORT","ICMP_UNREACH_NEEDFRAG","ICMP_UNREACH_SRCFAIL","ICMP_UNREACH_NET_UNKNOWN","ICMP_UNREACH_HOST_UNKNOWN","ICMP_UNREACH_ISOLATED","ICMP_UNREACH_NET_PROHIB","ICMP_UNREACH_HOST_PROHIB","ICMP_UNREACH_TOSNET","ICMP_UNREACH_TOSHOST","ICMP_UNREACH_FILTER_PROHIB","ICMP_UNREACH_HOST_PRECEDENCE","ICMP_UNREACH_PRECEDENCE_CUTOFF"};static const char *codeRedirectStr[] = {"ICMP_REDIRECT_NET","ICMP_REDIRECT_HOST","ICMP_REDIRECT_TOSNET","ICMP_REDIRECT_TOSHOST"};static const char *codeTimeExceedStr[] = {"ICMP_TIMXCEED_INTRANS","ICMP_TIMXCEED_REASS"};static const char *codeParaProb[] = {"ICMP_PARAMPROB_BADIP","ICMP_PARAMPROB_OPTABSENT"};switch(_pIcmpheader->type){case 0:typeStr = "ICMP_ECHOREPLY";break;case 3:typeStr = "ICMP_DEST_UNREACH";if(_pIcmpheader->code <= 15){codeStr = codeDestUnreachStr[_pIcmpheader->code];}else{codeStr = "Unrecognized";}break;case 4:typeStr = "ICMP_SOURCE_QUENCH";break;case 5:typeStr = "ICMP_REDIRECT";if(_pIcmpheader->code <= 3){codeStr = codeRedirectStr[_pIcmpheader->code];}else{codeStr = "Unrecognized";}break;case 8:typeStr = "ICMP_ECHO";break;case 11:typeStr = "ICMP_TIME_EXCEEDED";if(_pIcmpheader->code <= 1){codeStr = codeTimeExceedStr[_pIcmpheader->code];}else{codeStr = "Unrecognized";}break;case 12:typeStr = "ICMP_PARAMETERPROB";if(_pIcmpheader->code <= 1){codeStr = codeParaProb[_pIcmpheader->code];}else{codeStr = "Unrecognized";}break;case 13:typeStr = "ICMP_TIMESTAMP";break;case 14:typeStr = "ICMP_TIMESTAMPREPLY";break;case 15:typeStr = "ICMP_INFO_REQUEST";break;case 16:typeStr = "ICMP_INFO_REPLY";break;case 17:typeStr = "ICMP_ADDRESS";break;case 18:typeStr = "ICMP_ADDRESSREPLY";break;default:typeStr = "Unrecognized";break;}fprintf(stdout, "------this is a icmp header------\n");fprintf(stdout, "type = %u(%s)\n", _pIcmpheader->type, typeStr);fprintf(stdout, "code = %u(%s)\n", _pIcmpheader->code, codeStr);fprintf(stdout, "checksum = %u\n", ntohs(_pIcmpheader->checksum));fprintf(stdout, "------end---------------------------\n");}/*设置网卡为混杂模式*/int SetIfPromisc(int _sockfd, char *_pcIfname){struct ifreq ifr;memset(&ifr, 0, sizeof(ifr));strncpy(ifr.ifr_name, _pcIfname, IF_NAMESIZE);if(ioctl(_sockfd, SIOCGIFFLAGS, &ifr) < 0){fprintf(stdout, "%03d----%02d----%s\n", __LINE__, errno, strerror(errno));return EXIT_FIILURE;}ifr.ifr_flags |= IFF_PROMISC;if(ioctl(_sockfd, SIOCSIFFLAGS, &ifr) < 0){fprintf(stdout, "%03d----%02d----%s\n", __LINE__, errno, strerror(errno));return EXIT_FIILURE;}return EXIT_SUCCESS;}/*取消网卡的混杂模式*/int UnsetIfPromisc(int _sockfd, char *_pcIfname){struct ifreq ifr;memset(&ifr, 0, sizeof(ifr));strncpy(ifr.ifr_name, _pcIfname, IF_NAMESIZE);if(ioctl(_sockfd, SIOCGIFFLAGS, &ifr) < 0){fprintf(stdout, "%03d----%02d----%s\n", __LINE__, errno, strerror(errno));return EXIT_FIILURE;}ifr.ifr_flags &= ~IFF_PROMISC;if(ioctl(_sockfd, SIOCSIFFLAGS, &ifr) < 0){fprintf(stdout, "%03d----%02d----%s\n", __LINE__, errno, strerror(errno));return EXIT_FIILURE;}return EXIT_SUCCESS;}/*设置过滤器*/int SetFilter(int _sockfd){/*BPF code generated by tcpdump -dd host 150.150.150.15{ 0x28, 0, 0, 0x0000000c },{ 0x15, 0, 4, 0x00000800 },{ 0x20, 0, 0, 0x0000001a },{ 0x15, 8, 0, 0x96969610 },{ 0x20, 0, 0, 0x0000001e },{ 0x15, 6, 7, 0x96969610 },{ 0x15, 1, 0, 0x00000806 },{ 0x15, 0, 5, 0x00008035 },{ 0x20, 0, 0, 0x0000001c },{ 0x15, 2, 0, 0x96969610 },{ 0x20, 0, 0, 0x00000026 },{ 0x15, 0, 1, 0x96969610 },{ 0x6, 0, 0, 0x00000060 },{ 0x6, 0, 0, 0x00000000 },*/struct sock_filter BPF_code[]= {{ 0x28, 0, 0, 0x0000000c },{ 0x15, 0, 4, 0x00000800 },{ 0x20, 0, 0, 0x0000001a },{ 0x15, 8, 0, 0x96969610 },{ 0x20, 0, 0, 0x0000001e },{ 0x15, 6, 7, 0x96969610 },{ 0x15, 1, 0, 0x00000806 },{ 0x15, 0, 5, 0x00008035 },{ 0x20, 0, 0, 0x0000001c },{ 0x15, 2, 0, 0x96969610 },{ 0x20, 0, 0, 0x00000026 },{ 0x15, 0, 1, 0x96969610 },{ 0x6, 0, 0, 0x00000060 },{ 0x6, 0, 0, 0x00000000 }};struct sock_fprog Filter;Filter.len = 14;Filter.filter = BPF_code;if(setsockopt(_sockfd, SOL_SOCKET, SO_ATTACH_FILTER, &Filter, sizeof(Filter))<0){fprintf(stdout, "%03d----%02d----%s\n", __LINE__, errno, strerror(errno));return EXIT_FIILURE;}return EXIT_SUCCESS;}int main(){int sockfd;char buf[2048];ssize_t nRet;struct ether_header *etherheader;unsigned short ethertype;struct ip *ipheader;struct arphdr *arpheader;struct tcphdr *tcpheader;struct udphdr *udpheader;struct icmphdr *icmpheader;//sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_TCP);//sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_UDP);sockfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));if(-1 == sockfd){fprintf(stdout, "%03d----%02d----%s\n", __LINE__, errno, strerror(errno));exit(EXIT_FIILURE);}if(EXIT_SUCCESS != SetIfPromisc(sockfd, "eth0")){exit(EXIT_FIILURE);}//if(EXIT_SUCCESS != SetFilter(sockfd)){//exit(EXIT_FIILURE);//}while(1){memset(buf, 0, 2048);nRet = recvfrom(sockfd, buf, 2048, 0, NULL, NULL);if(-1 == nRet){fprintf(stdout, "%03d----%02d----%s\n", __LINE__, errno, strerror(errno));exit(EXIT_FIILURE);}if(nRet < sizeof(struct ether_header)){continue;}etherheader = (struct ether_header *)buf;DisplayEthernet(etherheader);ethertype = ntohs(etherheader->ether_type);if(ethertype == ETHERTYPE_IP){if(nRet < sizeof(struct ether_header) + sizeof(struct ip)){continue;}ipheader = (struct ip *)(buf + sizeof(struct ether_header));DisplayIp(ipheader);if(ipheader->ip_p == IPPROTO_TCP){if(nRet < sizeof(struct ether_header) + sizeof(struct ip) + sizeof(struct tcphdr)){continue;}tcpheader = (struct tcphdr *)(buf + sizeof(struct ether_header) + sizeof(struct ip));DisplayTcp(tcpheader);}else if(ipheader->ip_p == IPPROTO_UDP){if(nRet < sizeof(struct ether_header) + sizeof(struct ip) + sizeof(struct udphdr)){continue;}udpheader = (struct udphdr *)(buf + sizeof(struct ether_header) + sizeof(struct ip));DisplayUdp(udpheader);}else if(ipheader->ip_p == IPPROTO_ICMP){if(nRet < sizeof(struct ether_header) + sizeof(struct ip) + sizeof(struct icmphdr)){continue;}icmpheader = (struct icmphdr *)(buf + sizeof(struct ether_header) + sizeof(struct ip));DisplayIcmp(icmpheader);}}else if(ethertype == ETHERTYPE_ARP){if(nRet < sizeof(struct ether_header) + sizeof(struct arphdr)){continue;}arpheader = (struct arphdr *)(buf + sizeof(struct ether_header));DisplayArp(arpheader);}else if(ethertype == ETHERTYPE_REVARP){if(nRet < sizeof(struct ether_header) + sizeof(struct arphdr)){continue;}arpheader = (struct arphdr *)(buf + sizeof(struct ether_header));DisplayRarp(arpheader);}else{fprintf(stdout, "ethertype not support:%#02x\n", ethertype);}sleep(1);}exit(EXIT_SUCCESS);