#include <stdio.h> #include <stdlib.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <netinet/ip.h> #include <string.h> #include <netdb.h> #include <netinet/tcp.h> #include <netinet/udp.h> #include <stdlib.h> #include <unistd.h> #include <signal.h> #include <net/if.h> #include <sys/ioctl.h> #include <sys/stat.h> #include <fcntl.h> #include <linux/if_ether.h> #include <net/ethernet.h> void die(char *why, int n) { perror(why); exit(n); } int do_promisc(char *nif, int sock ) { struct ifreq ifr; strncpy(ifr.ifr_name, nif,strlen(nif)+1); if((ioctl(sock, SIOCGIFFLAGS, &ifr) == -1)) //获得flag { die("ioctl", 2); } ifr.ifr_flags |= IFF_PROMISC; //重置flag标志 if(ioctl(sock, SIOCSIFFLAGS, &ifr) == -1 ) //改变模式 { die("ioctl", 3); } return 0; } //修改网卡成PROMISC(混杂)模式 /* =============================================================================================================下面是实现捕获和分析UDP协议数据包的函数定义 =============================================================================================================*/ void udp_protocol_packet_callback( u_char *packet_content) { struct udphdr *udp_protocol; // UDP协议数据变量 u_short source_port; // 源端口号 u_short destination_port; // 目的端口号 udp_protocol = (struct udphdr*)(packet_content + 14+20); // 获得UDP协议数据内容 source_port = ntohs(udp_protocol->source); // 获得源端口号 destination_port = ntohs(udp_protocol->dest); // 获得目的端口号 printf("---------- UDP Protocol (Transport Layer) ----------\n"); printf("Source port:%d\n", source_port); printf("Destination port:%d\n", destination_port); switch (destination_port) //根据端口号判断应用层协议类型 { case 138: printf("NETBIOS Datagram Service\n"); break; // 端口号为138,表示上层协议为NETBIOS 数据报服务 case 137: printf("NETBIOS Name Service\n"); break; // 端口号为137,表示上层协议为NETBIOS 名字服务 case 139: printf("NETBIOS session service\n"); break; // 端口号为139,表示上层协议为NETBIOS 会话服务 case 53: printf("name-domain server \n"); break; // 端口号为53,表示上层协议为域名服务 case 4000: printf("QQ server \n"); break; case 1863: printf("MSN server \n"); break; case 9001: printf("OTHERS \n"); break; default: printf("NOT WELL-KNOWN PROTOCOL.\n"); break; //其他没有分析 } } /* =============================================================================================================下面是实现捕获和分析TCP协议数据包的函数定义 ============================================================================================================= */ void tcp_protocol_packet_callback( u_char *packet_content) { struct tcphdr *tcp_protocol; // TCP协议数据变量 u_short source_port; // 源端口号 u_short destination_port; // 目的端口号 tcp_protocol = (struct tcphdr*)(packet_content + 14+20); // 获得UDP协议数据内容 source_port = ntohs(tcp_protocol->source); // 获得源端口号 destination_port = ntohs(tcp_protocol->dest); // 获得目的端口号 printf("---------- TCP Protocol (Transport Layer) ----------\n"); printf("Source port:%d\n", source_port); printf("Destination port:%d\n", destination_port); switch (destination_port) //根据端口号判断应用层协议类型 { case 7: printf("ECHO server \n"); break; case 21: printf("FTP server \n"); break; case 23: printf("TELNET server \n"); break; case 25: printf("SMTP server \n"); break; case 53: printf("DNS server \n"); break; case 80: printf("HTTP server \n"); break; case 2049: printf("NFS server \n"); break; case 6667: printf("IRCD server \n"); break; default: printf("NOT WELL-KNOWN PROTOCOL.\n"); break; //其他没有分析 } } /* ============================================================================================================= 下面是分析IP协议的函数的定义 ============================================================================================================= */ void ip_protocol_packet_callback( u_char *packet_content) { struct iphdr *ip_protocol; // IP协议变量 printf("---------- IP Protocol (Network Layer) ----------\n"); ip_protocol = (struct iphdr*)(packet_content + 14); //获得IP协议数据内容 printf("Protocol:%d\n", ip_protocol->protocol); //获得协议类型 switch (ip_protocol->protocol) // 根据协议类型判断 { case IPPROTO_TCP: printf("The Transport Layer Protocol is TCP\n"); break; /* 上层协议为TCP协议 */ case IPPROTO_UDP: printf("The Transport Layer Protocol is UDP\n"); break; /* 上层协议为UDP协议 */ case IPPROTO_ICMP: printf("The Transport Layer Protocol is ICMP\n"); break; /* 上层协议为ICMP协议 */ case IPPROTO_IGMP: printf("The Transport Layer Protocol is IGMP\n"); break; default: break; } printf("TCP pkt :FORM:[%s]\n",inet_ntoa(*(struct in_addr*)&(ip_protocol->saddr))); printf("TCP pkt :TO: [%s]\n",inet_ntoa(*(struct in_addr*)&(ip_protocol->daddr))); switch (ip_protocol->protocol) { case IPPROTO_TCP: tcp_protocol_packet_callback(packet_content); break; case IPPROTO_UDP: udp_protocol_packet_callback(packet_content); break; default: break; } } /* ============================================================================================================= 下面是分析以太网协议的回调函数的定义 ============================================================================================================= */ void ethernet_protocol_packet_callback( u_char *packet_content) { u_short ethernet_type; /* 以太网类型 */ struct ether_header *ethernet_protocol; /* 以太网协议变量 */ u_char *mac_string; /* 以太网地址 */ static int packet_number = 1; printf("**************************************************\n"); printf("The %d packet is captured.\n", packet_number); printf("-------- Ehternet Protocol (Link Layer) --------\n"); ethernet_protocol = (struct ether_header*)packet_content; /* 获得以太网协议数据内容 */ printf("Ethernet type is :\n"); ethernet_type = ntohs(ethernet_protocol->ether_type); /* 获得以太网类型 */ printf("%04x\n", ethernet_type); switch (ethernet_type) { case 0x0800: printf("The network layer is IP protocol\n"); break; /* 上层协议为IP协议 */ case 0x0806: printf("The network layer is ARP protocol\n"); printf("---------- ARP Protocol (Network Layer) ----------\n"); break; /* 上层协议为ARP协议 */ case 0x8035: printf("The network layer is RARP protocol\n"); printf("---------- RARP Protocol (Network Layer) ----------\n"); break; /* 上层协议为RARP协议 */ default: break; } switch (ethernet_type) { case 0x0800: ip_protocol_packet_callback( packet_content); break; // 上层协议为IP协议,就调用分析IP 协议的函数,注意参数的传递 default: printf("Mac Source Address is : \n"); mac_string = ethernet_protocol->ether_shost; printf("%02x:%02x:%02x:%02x:%02x:%02x\n", *mac_string, *(mac_string + 1), *(mac_string + 2), *(mac_string + 3), *(mac_string + 4), *(mac_string + 5)); //获得源以太网地址 printf("Mac Destination Address is : \n"); mac_string = ethernet_protocol->ether_dhost; printf("%02x:%02x:%02x:%02x:%02x:%02x\n", *mac_string, *(mac_string + 1), *(mac_string + 2), *(mac_string + 3), *(mac_string + 4), *(mac_string + 5)); // 获得目的以太网地址 break; } printf("**************************************************\n"); packet_number++; } char buf[40960]; int main() { struct sockaddr_in addr; int sock; int r = 0; socklen_t len = 0; u_char *ptemp; if((sock = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) == -1) //建立socket ,man socket可以看到上面几个宏的意思 { die("socket", 1); } do_promisc("eth0", sock); //eth0为网卡名称 system("ifconfig"); for(;;) { len = sizeof(addr); if(recvfrom(sock,(char *)buf,sizeof(buf), 0, (struct sockaddr *)&addr,&len) > 0){ } else{ continue; } //成功则返回接收到的字符数,失败返回-1,调试的时候可以增加一个输出r的语句判断是否抓到包 buf[r] = 0; ptemp = buf; ethernet_protocol_packet_callback(ptemp);//调用以太网协议的回调函数 usleep(1000); // perror("dump"); } return 0; }