// 4月16日添加IP、TCP/UDP校验和模块,4月17日提交新实验报告。 /************************************************ * TCP/UDP实验 * * 2016年4月16日 * * 130342132 * ************************************************/ #include "pcap.h" #pragma comment(lib, "wpcap.lib") #pragma comment(lib, "ws2_32.lib") #pragma pack(2) typedef unsigned char u8_t; // 无符号8bit长度类型 typedef unsigned short u16_t; // 无符号16 bit长度类型 typedef unsigned long u32_t; // 无符号32 bit长度类型 // 以太网头部 struct ether_header { u8_t ether_dhost[6]; // 目的以太网地址6B u8_t ether_shost[6]; // 源以太网地址6B u16_t ether_type; // 以太网类型字段2B }; // ARP头部 struct arp_header { u16_t hardType; // 硬件类型(0x0001) u16_t protoType; // 协议类型(IP协议0x0800) u8_t hardLen; // 硬件地址长度0x06 u8_t protoLen; // IP地址长度0x04 u16_t operCode; // arp报文类型(1请求2应答)0x0001 u8_t s_hardAddr[6]; // 源MAC(6B) u8_t s_ipAddr[4]; // 源IP 4B u8_t d_hardAddr[6]; // 目的MAC 6B u8_t d_ipAddr[4]; // 目的IP 4B }; // IP格式 struct ip_header { u8_t ver_HeadLen; // Version (4 bits) + Internet header length (4 bits) u8_t serType; // Type of service u16_t lenSum; // Total length u16_t identification; // Identification 标识 u16_t flags_Offset; // Flags (3 bits) + Fragment offset (13 bits) 标志+分片偏移 u8_t _TTL; // Time to live u8_t proto; // Protocol u16_t checksum; // Header checksum u8_t s_ipAddr[4]; // 源IP 4B u8_t d_ipAddr[4]; // 目的IP 4B }; // TCP头部 struct tcp_header { u16_t sPort; // u16_t dPort; // u32_t seq; // 序列号 u32_t ack; // 确认号 u8_t offset_; // 数据偏移(4)+保留(前4) u8_t _flag; // 保留(后2)+flags u16_t win; // 窗口大小 u16_t checkSum; // 校验和 u16_t urgPointer; // 紧急指针 }; // UDP头部 struct udp_header { u16_t sPort; // u16_t dPort; u16_t len; // 长度 u16_t checkSum; // }; //伪首部结构 struct f_header { u8_t s_ipAddr[4]; // 源IP 4B u8_t d_ipAddr[4]; // 目的IP 4B u8_t zero; // 全零字节 u8_t proto; // IP报中协议字段 u16_t len; // IP携带数据包的长度 }; void packet_handler(u_char *user_data, const struct pcap_pkthdr *header, const u_char *pkt_content); void arp_handler(const u_char *pkt_content); void ip_handler(const u_char *pkt_content); void f_handler(const struct ip_header *ip, struct f_header *f); void tcp_handler(struct ip_header *ip, const u_char *pkt_content, int i); void udp_handler(struct ip_header *ip, const u_char *pkt_content, int i); u16_t CheckSum(u16_t* buffer, int size); u16_t tcpCheckSum(const u8_t *ip); int main() { pcap_if_t *alldevs; pcap_if_t *d; int inum; int i=0; pcap_t *adhandle; char errbuf[PCAP_ERRBUF_SIZE]; // 获取本机设备列表 if (pcap_findalldevs(&alldevs, errbuf) == -1) { fprintf(stderr,"Error in pcap_findalldevs: %s\n", errbuf); exit(1); } // 打印列表 for(d=alldevs; d; d=d->next) { printf("%d. %s", ++i, d->name); if (d->description) printf(" (%s)\n", d->description); else printf(" (No description available)\n"); } if(i==0) { printf("\nNo interfaces found! Make sure WinPcap is installed.\n"); return -1; } printf("Enter the interface number (1-%d):",i); scanf("%d", &inum); if(inum < 1 || inum > i) { printf("\nInterface number out of range.\n"); // 释放设备列表 pcap_freealldevs(alldevs); return -1; } // 跳转到选中的适配器 for(d=alldevs, i=0; i< inum-1 ;d=d->next, i++); // 打开设备 if ( (adhandle= pcap_open_live(d->name, // 设备名 65536, // 65535保证能捕获到不同数据链路层上的每个数据包的全部内容 1, // 混杂模式 1000, // 读取超时时间 // NULL, // 远程机器验证 errbuf // 错误缓冲池 ) ) == NULL) { fprintf(stderr,"\nUnable to open the adapter. %s is not supported by WinPcap\n", d->name); // 释放设备列表 pcap_freealldevs(alldevs); return -1; } // 释放设备列表 pcap_freealldevs(alldevs); pcap_loop(adhandle, 0, packet_handler, NULL); pcap_close(adhandle); return 0; } void packet_handler(u_char *user_data, const struct pcap_pkthdr *header, const u_char *pkt_content) { u_short ethernet_type; // 以太网类型 struct ether_header *ethernet_protocol; u_char *mac_addr; static int packet_number=1; ethernet_protocol=(struct ether_header*)pkt_content; printf("****************************************\n"); printf("序号\t\t%d\n", packet_number); printf("包长度\t\t%d\n", header->len); printf("捕获时间\t%s\n", ctime((const time_t*)&header->ts.tv_sec)); printf("源MAC地址\t"); mac_addr = ethernet_protocol->ether_shost; printf("%02x:%02x:%02x:%02x:%02x:%02x\n", *mac_addr, *(mac_addr + 1), *(mac_addr + 2), *(mac_addr + 3), *(mac_addr + 4), *(mac_addr + 5)); printf("目的MAC地址\t"); mac_addr = ethernet_protocol->ether_dhost; printf("%02x:%02x:%02x:%02x:%02x:%02x\n", *mac_addr, *(mac_addr + 1), *(mac_addr + 2), *(mac_addr + 3), *(mac_addr + 4), *(mac_addr + 5)); ethernet_protocol = (struct ether_header*)pkt_content; ethernet_type = ntohs(ethernet_protocol->ether_type); printf("\n\t%04x ", ethernet_type); switch(ethernet_type) { case 0x0800: printf("IP报文\n"); ip_handler(pkt_content + 14); break; case 0x0806: printf("ARP报文\n"); arp_handler(pkt_content + 14); break; default: printf("其他协议\n"); break; } packet_number++; system("pause"); } void arp_handler(const u_char *pkt_content) { u16_t opCode; struct arp_header *sarp_pkt; u_char *ip_addr; sarp_pkt = (struct arp_header*)pkt_content; printf("报文类型\t"); opCode = ntohs(sarp_pkt->operCode); switch(opCode) { case 0x0001: printf("ARP请求\n"); break; case 0x0002: printf("ARP应答\n"); break; } printf("源IP\t\t"); ip_addr = sarp_pkt->s_ipAddr; printf("%i.%i.%i.%i\n", *ip_addr, *(ip_addr + 1), *(ip_addr + 2), *(ip_addr + 3)); printf("目的IP\t\t"); ip_addr = sarp_pkt->d_ipAddr; printf("%i.%i.%i.%i\n", *ip_addr, *(ip_addr + 1), *(ip_addr + 2), *(ip_addr + 3)); } void ip_handler(const u_char *pkt_content) { struct ip_header *sip_pkt; u_char *ip_addr; u8_t version; u8_t headLen; u16_t f_o; u8_t DF, MF; u16_t offset; u8_t proto; int flag_ck; sip_pkt = (struct ip_header*)pkt_content; // IP首部 version = sip_pkt->ver_HeadLen >> 4; printf("版本\t\t%d\n", version); // 头部长度 headLen = (sip_pkt->ver_HeadLen & 0x0f) *4; printf("头部长度\t%d\n", headLen); // 总长度 printf("总长度\t\t%d\n", ntohs(sip_pkt->lenSum)); // 标识符 printf("标识\t\t%d\n", ntohs(sip_pkt->identification)); f_o = ntohs(sip_pkt->flags_Offset); // 标志位 DF = (f_o >> 14) & 0x03; MF = (f_o >> 13) & 0x01; printf("标志位\t\tDF = %d, MF = %d\n", DF, MF); // IP片偏移 offset = f_o & 0x1fff; printf("片偏移\t\t%d\n", offset); // TTL printf("TTL\t\t%d\n", sip_pkt->_TTL); // IP协议类型 proto = sip_pkt->proto; printf("协议类型\t%d,", proto); switch (proto) { case 1: printf("ICMP\n"); break; case 2: printf("IGMP\n"); break; case 4: printf("IP\n"); break; case 6: printf("TCP\n"); break; case 8: printf("EGP\n"); break; case 9: printf("IGP\n"); break; case 17: printf("UDP\n"); break; case 41: printf("IPv6\n"); break; case 50: printf("ESP\n"); break; case 89: printf("OSPF\n"); break; default: printf("其他类型\n"); } // 首部校验和 printf("首部校验和\t0x%0x\t", ntohs(sip_pkt->checksum)); flag_ck = CheckSum((u16_t*)sip_pkt, sizeof(struct ip_header)) % 2; if(flag_ck) printf("校验和不正确\n"); else printf("校验和正确\n"); // printf("源IP\t\t"); ip_addr = sip_pkt->s_ipAddr; printf("源IP\t\t%i.%i.%i.%i\n", *ip_addr, *(ip_addr + 1), *(ip_addr + 2), *(ip_addr + 3)); // printf("目的IP\t\t"); ip_addr = sip_pkt->d_ipAddr; printf("目的IP\t\t%i.%i.%i.%i\n", *ip_addr, *(ip_addr + 1), *(ip_addr + 2), *(ip_addr + 3)); flag_ck = tcpCheckSum((const u8_t*)sip_pkt) %2; switch (proto) { case 6: tcp_handler(sip_pkt, pkt_content + headLen, flag_ck); break; case 17: udp_handler(sip_pkt, pkt_content + headLen, flag_ck); break; } } void f_handler(const struct ip_header *ip, struct f_header *f) { u8_t headLen; u16_t lenSum; int i; for(i = 0; i < 4; i++) { f->s_ipAddr[i] = ip->s_ipAddr[i]; f->d_ipAddr[i] = ip->d_ipAddr[i]; } f->zero = 0; f->proto = ip->proto; headLen = (ip->ver_HeadLen & 0x0f) *4; // 总长度 lenSum = ntohs(ip->lenSum); f->len = lenSum - headLen; f->len = htons(f->len); } void tcp_handler(struct ip_header *ip, const u_char *pkt_content, int i) { struct tcp_header *stcp_pkt; u8_t offset_; u8_t flag; // 保留(后2)+flags u16_t len; stcp_pkt = (struct tcp_header*)pkt_content; printf("\n\tTCP首部\n"); printf("源端口\t\t%d\n", ntohs(stcp_pkt->sPort)); printf("目的端口\t%d\n", ntohs(stcp_pkt->dPort)); printf("序号\t\t%d\n", ntohs(stcp_pkt->seq)); printf("确认号\t\t%d\n", ntohs(stcp_pkt->ack)); offset_ = stcp_pkt->offset_; len = (offset_ >> 4) * 4; printf("首部长度\t%d\n", len); printf("标志位\n"); flag = stcp_pkt->_flag; printf("URG\tACK\tPSH\tRST\tSYN\tFIN\n"); printf("%d\t%d\t%d\t%d\t%d\t%d\n", (flag >> 5) & 0x1, (flag >> 4) & 0x1, (flag >> 3) & 0x1, (flag >> 2) & 0x1, (flag >> 1) & 0x1, flag & 0x1); printf("窗口大小\t%d\n", ntohs(stcp_pkt->win)); printf("校验和\t\t0x%0x\t", ntohs(stcp_pkt->checkSum)); if(i) printf("校验和不正确\n"); else printf("校验和正确\n"); printf("紧急指针\t%d\n", ntohs(stcp_pkt->urgPointer)); } void udp_handler(struct ip_header *ip, const u_char *pkt_content, int i) { struct udp_header *sudp_pkt; sudp_pkt = (struct udp_header*)pkt_content; printf("\n\tUDP首部\n"); printf("源端口\t\t%d\n", ntohs(sudp_pkt->sPort)); printf("目的端口\t%d\n", ntohs(sudp_pkt->dPort)); printf("长度\t\t%d\n", ntohs(sudp_pkt->len)); printf("检验和\t\t0x%0x\t", ntohs(sudp_pkt->checkSum)); if(i) printf("检验和不正确\n"); else printf("检验和正确\n"); } u16_t CheckSum(u16_t* buffer, int size) { u32_t cksum = 0; while(size>1) { cksum += *buffer++; size -= sizeof(u16_t); } if(size) { cksum += *(u8_t*)buffer; } cksum = (cksum>>16) + (cksum&0xffff); //将高16bit与低16bit相加 cksum += (cksum>>16); //将进位到高位的16bit与低16bit再相加 return (u16_t)(~cksum); } u16_t tcpCheckSum(const u8_t *ip) { struct f_header f; struct ip_header *ipk = (struct ip_header *)ip; u8_t *check_buff; // 待校验的数据包 int check_buff_len; // 校验缓冲区长度 u16_t checksum; f_handler(ipk, &f); check_buff_len = sizeof(struct f_header) + ntohs(f.len); check_buff = (u8_t *)malloc(check_buff_len); if(check_buff == NULL) { fprintf(stderr, "\ncann't allocate memory for check_buff\n"); return -5; } memset(check_buff, 0, check_buff_len); // 将以TCP/UDP伪首部结构体拷贝到校验缓冲区中 memcpy(check_buff, &f, sizeof(struct f_header)); // 将TCP/UDP报文拷贝到校验缓冲区中 memcpy(check_buff + sizeof(struct f_header), ip+sizeof(struct ip_header), ntohs(f.len)); // 计算TCP报文校验和 checksum = (CheckSum((u16_t *)(check_buff), check_buff_len)); free(check_buff); return checksum; }
