首页 > 代码库 > 第二十七、二十八天:网络数据封装及各层数据的发送

第二十七、二十八天:网络数据封装及各层数据的发送

    这几天的课程给了我们足够多的时间编写代码,让我们更熟练使用套接字编程。课程的代码也更多了。几个要实现的代码:编写抓包程序,封装网络数据包,网络层数据发送,编写简易的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 }

 

第二十七、二十八天:网络数据封装及各层数据的发送