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

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

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值