首页 > 代码库 > 第二十七、二十八天:网络数据封装及各层数据的发送
第二十七、二十八天:网络数据封装及各层数据的发送
这几天的课程给了我们足够多的时间编写代码,让我们更熟练使用套接字编程。课程的代码也更多了。几个要实现的代码:编写抓包程序,封装网络数据包,网络层数据发送,编写简易的web服务器,arp应用层数据分析,实现ftp客户端。使用http实现简单的文件下载器。
为了对网络五层有更加深入的了解,通过下面的程序对网卡的数据进行抓包分析。实现类似与wireshark的功能。
1 #include <stdio.h> 2 #include <unistd.h> 3 #include <linux/if_ether.h> 4 #include <linux/ip.h> 5 #include <linux/udp.h> 6 #include <linux/tcp.h> 7 #include <netinet/in.h> 8 #include <stdlib.h> 9 #include <string.h> 10 11 #pragma pack(1) 12 struct my_arphdr{ 13 unsigned short h_type; 14 unsigned short p_type; 15 unsigned char h_len; 16 unsigned char p_len; 17 unsigned short op; 18 unsigned char source_mac[6]; 19 unsigned long source_ip; 20 unsigned char dest_mac[6]; 21 unsigned long dest_ip; 22 }; 23 void show_mac(const unsigned char *data); 24 void show_ip(const unsigned char *data); 25 void show_arp(const unsigned char *data); 26 void show_tcp(const unsigned char *data); 27 void show_udp(const unsigned char *data); 28 void show_app(const unsigned char *data); 29 30 int main() 31 { 32 int fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));//接收所有通过网卡的数据包 33 if(fd < 0){ 34 perror("socket"); 35 return 1; 36 } 37 38 int ret = 0; 39 int i = 0; 40 unsigned char buff[1024] = {0}; 41 while(1){ 42 memset(buff, 0, 1024); 43 ret = read(fd, buff, 1024);//将数据包的内容保存到数组中 44 if(ret < 0){ 45 perror("read"); 46 continue; 47 } 48 if(ret < 42)//不处理错误包 49 continue; 50 show_mac(buff); 51 printf("\n\n\n"); 52 } 53 54 } 55 56 void show_mac(const unsigned char *data){ 57 struct ethhdr *eth = (struct ethhdr *)data; 58 printf("--------------数据链路-----------\n"); 59 printf("dest mac is %02x:%02x:%02x:%02x:%02x:%02x\n", 60 eth->h_dest[0], eth->h_dest[1], 61 eth->h_dest[2], eth->h_dest[3], 62 eth->h_dest[4], eth->h_dest[5] 63 ); 64 printf("src mac is %02x:%02x:%02x:%02x:%02x:%02x\n", 65 eth->h_source[0], eth->h_source[1], 66 eth->h_source[2], eth->h_source[3], 67 eth->h_source[4], eth->h_source[5] 68 ); 69 printf("nework proto is %04x\n", ntohs(eth->h_proto)); 70 if(ntohs(eth->h_proto)==0x0800) 71 show_ip(data+sizeof(struct ethhdr)); 72 if(ntohs(eth->h_proto)==0x0806) 73 show_arp(data+sizeof(struct ethhdr)); 74 } 75 void show_ip(const unsigned char *data){ 76 struct iphdr *ipth = (struct iphdr *)data; 77 printf("--------------网络层-----------\n"); 78 printf("version is %d\n",ipth->version); 79 printf("ip leng is %d\n",ipth->ihl * ipth->version); 80 printf("tos is %d\n",ipth->tos); 81 printf("tot_len is %04d\n",ntohs(ipth->tot_len)); 82 printf("id is %04d\n",ntohs(ipth->id)); 83 printf("frag_off is %04d\n",ntohs(ipth->frag_off)); 84 printf("ttl is %d\n",ipth->ttl); 85 printf("protocol is %d\n",ipth->protocol); 86 printf("check is %04d\n",ntohs(ipth->check)); 87 printf("sourre ip is %s\n",inet_ntoa(ipth->saddr)); 88 printf("dest ip is %s\n",inet_ntoa(ipth->daddr)); 89 if(ipth->protocol==6) 90 show_tcp(data+sizeof(struct iphdr)); 91 if(ipth->protocol==17) 92 show_udp(data+sizeof(struct iphdr)); 93 } 94 void show_arp(const unsigned char *data){ 95 printf("--------------arp-----------\n"); 96 struct my_arphdr *my_arp = (struct my_arphdr *)data; 97 printf("h_type is %d\n",ntohs(my_arp->h_type)); 98 printf("p_type is %d\n",ntohs(my_arp->p_type)); 99 printf("h_len is %d\n",my_arp->h_len);100 printf("p_len is %d\n",my_arp->h_len);101 printf("op is %d\n",ntohs(my_arp->op));102 printf("src_mac is %02x:%02x:%02x:%02x:%02x:%02x\n", 103 my_arp->source_mac[0],my_arp->source_mac[1],104 my_arp->source_mac[2],my_arp->source_mac[3],105 my_arp->source_mac[4],my_arp->source_mac[5]106 );107 printf("sourre ip is %s\n",inet_ntoa(my_arp->source_ip));108 printf("dest_mac is %02x:%02x:%02x:%02x:%02x:%02x\n", 109 my_arp->dest_mac[0],my_arp->dest_mac[1],110 my_arp->dest_mac[2],my_arp->dest_mac[3],111 my_arp->dest_mac[4],my_arp->dest_mac[5]112 );113 printf("sourre ip is %s\n",inet_ntoa(my_arp->dest_ip));114 115 116 117 }118 void show_udp(const unsigned char *data){119 struct udphdr *udpth = (struct udphdr *)data;120 printf("--------------传输层-----------\n");121 printf("source port is %d\n",ntohs(udpth->source));122 printf("dest port is %d\n",ntohs(udpth->dest));123 printf("len is %04d\n",ntohs(udpth->len));124 printf("check is %04d\n",ntohs(udpth->check));125 show_app(data+sizeof(struct udphdr));126 }127 void show_tcp(const unsigned char *data){128 struct tcphdr *tcpth = (struct tcphdr *)data;129 printf("--------------传输层-----------\n");130 printf("source port is %d\n",ntohs(tcpth->source));131 printf("dest port is %d\n",ntohs(tcpth->dest));132 printf("seq is %d\n",ntohl(tcpth->seq));133 printf("ack_seq is %d\n",ntohl(tcpth->ack_seq));134 show_app(data+sizeof(struct tcphdr));135 136 }137 void show_app(const unsigned char *data){138 printf("--------------应用层-----------\n");139 int i = 0;140 for(i=0;i<20;i++)141 printf("%c",*(data+i));142 printf("\n");143 }
对于网络抓包程序的编写,主要是要熟练掌握几个协议的首部。了解其中的运作机制。在学习过程中,还对校验和使用的回滚算法进行编写。下面是回滚算法的实现:
1 #include<stdio.h> 2 #include<stdlib.h> 3 4 unsigned short check_sum(unsigned char *data,int len); 5 int main() 6 { 7 unsigned char data[1024] ={ 8 0x45, 0x00, 9 0x00, 0x20, 0x00, 0x00, 0x40, 0x00, 0x40, 0x11,10 0x00, 0x00, 0xc0, 0xa8, 0x1f, 0x72, 0xc0, 0xa8,11 0x1f, 0x7a12 };13 unsigned short ret = 0;14 ret = check_sum(data,20);15 printf("check sum is %x\n",htons(ret));16 17 } 18 unsigned short check_sum(unsigned char *data,int len){19 unsigned short ret = 0;20 unsigned long retsum = 0;21 unsigned short *buff = (unsigned short*)data;22 // 以两字节为单位反复累加23 while(len > 1){24 retsum = retsum + *buff++;25 len = len -2; 26 }27 //如果是单数的话,加最后一个28 if(len){29 retsum = retsum + *buff; 30 }31 // 将位累加和的高位与低位第一次相加32 retsum = ((retsum >>16) & 0xffff) +(retsum & 0xffff);33 return ~ret;34 }
下面的代码是对于数据包的封装,以及发送网络层数据。
1 #include<stdlib.h> 2 #include<stdio.h> 3 #include<sys/socket.h> 4 #include<netinet/in.h> 5 #include<string.h> 6 #pragma pack(1) 7 struct udphdr{ 8 unsigned short source; 9 unsigned short dest;10 unsigned short len;11 unsigned short check;12 };13 struct iphdr{14 unsigned char ihl : 4;15 unsigned char version : 4;16 unsigned char tos ;17 unsigned short tot_len ;18 unsigned short id ;19 unsigned short frag_off;20 unsigned char ttl ;21 unsigned char protocol;22 unsigned short check;23 unsigned long saddr ;24 unsigned long daddr ;25 };26 void encapsulation_ip(char *buff,unsigned short tolen);27 void encapsulation_udp(char *buff,unsigned short udp_len);28 void encapsulation_app(char *buff,char *data,unsigned short data_len);29 30 int main(void)31 {32 unsigned char *data = http://www.mamicode.com/"hello";33 unsigned char buff[1024] = {0};34 unsigned short tolen = sizeof(struct iphdr)+sizeof(struct udphdr) + strlen(data);35 unsigned short udp_len=sizeof(struct udphdr)+strlen(data);36 unsigned short data_len=sizeof(struct udphdr)+sizeof(struct iphdr);37 38 encapsulation_ip(buff,tolen);39 encapsulation_udp(buff+sizeof(struct iphdr),udp_len);40 encapsulation_app(buff+data_len,data,data_len);41 int fd = socket(AF_INET,SOCK_RAW,IPPROTO_UDP);//创建套接字,使用的是原始数据。42 if(fd < 0){43 perror("socket");44 return 1;45 }46 struct sockaddr_in recv;47 recv.sin_family = AF_INET;48 recv.sin_port = htons(9527);49 recv.sin_addr.s_addr = inet_addr("192.168.1.10");50 51 int ret = 0;52 int value = http://www.mamicode.com/1;53 int len = 4;54 ret = setsockopt(fd,IPPROTO_IP,IP_HDRINCL,&value,len);//设置套机字,从网络层发送数据,如果value为0,则从传输层发送数据。55 if (ret < 0){56 perror("setsockopt");57 return 1; 58 }59 ret = sendto(fd,buff,tolen,0,(struct sockaddr*)&recv,sizeof(struct sockaddr));//发送数据给接收端60 if (ret < 0){61 perror("sendto");62 return 1; 63 }64 }65 66 67 void encapsulation_ip( char *buff,unsigned short tolen){68 struct iphdr *ipth = (struct iphdr *)buff;69 ipth->version = 4;70 ipth->ihl = 5;71 ipth->tos = 0;72 ipth->tot_len = htons(tolen);73 ipth->id = htons(0);74 ipth->frag_off = htons(0);75 ipth->ttl = 64;76 ipth->protocol = 17;77 ipth->check = htons(0);78 ipth->saddr = inet_addr("192.168.1.10");79 ipth->daddr = inet_addr("192.168.1.10");80 81 }82 void encapsulation_udp(char *buff,unsigned short udp_len){83 struct udphdr *udp = (struct udphdr *)buff;84 udp->source = htons(9999);85 udp->dest = htons(9527);86 udp->len = htons(udp_len);87 udp->check = htons(0);//填零系统会自动计算校验和88 }89 90 void encapsulation_app(char *buff,char *data,unsigned short data_len){91 92 char * newbuff = NULL;93 newbuff =memmove(buff,data,strlen(data));//使用memcopy可能会产生数据重叠,所以一般使用memmove函数。94 if(newbuff == NULL){95 perror("memmove");96 exit(EXIT_FAILURE);97 }98 99 }
第二十七、二十八天:网络数据封装及各层数据的发送
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。