004.UDP--拼接UDP數據包,構造ip頭和udp頭通信(使用原始套接字)


一.大致流程:

    建立一個client端,一個server端,自己構建IP頭和UDP頭,寫入數據(hello,world!)后通過原始套接字(SOCK_RAW)將包發出去。

server端收到數據后,打印UDP數據並發送確認消息(yes),client收到yes后將其打印。

二.其中:

client端IP:192.168.11.104 端口:8600

server端IP:192.168.11.105 端口:8686

三.注意事項:

1.運行原始套接字socket需要有root權限。

2.注意主機字節序和網絡字節序的

四.涉及的數據結構

1.ip部分的結構圖:

2.ip結構體定義: 

struct iphdr       /* 該結構體在<netinet/ip.h>中定義 */
  {
#if __BYTE_ORDER == __LITTLE_ENDIAN  /* 如果是小端字節序 */
    unsigned int ihl:4;     /*首部長度*/
    unsigned int version:4; /* 版本 */
#elif __BYTE_ORDER == __BIG_ENDIAN
    unsigned int version:4;
    unsigned int ihl:4;
#else
# error    "Please fix <bits/endian.h>"
#endif
    u_int8_t tos;           /* 區分服務 */
    u_int16_t tot_len;      /* 總長度 */
    u_int16_t id;           /* 標識 */
    u_int16_t frag_off;     /* 標志(3位)+片偏移(13位) */
    u_int8_t ttl;           /* 生存時間 */
    u_int8_t protocol;      /* 協議 */
    u_int16_t check;        /* 首部檢驗和 */
    u_int32_t saddr;        /* 源地址 */
    u_int32_t daddr;        /* 目的地址 */
    /*The options start here. */
  };

 3.udp數據包的結構圖: 

4.udp結構體定義: 

struct udphdr  /* 該結構體在<netiniet/udp.h>中定義 */
{
  u_int16_t source;  /*源端口*/
  u_int16_t dest;    /*目的端口*/
  u_int16_t len;     /*長度*/
  u_int16_t check;   /*校驗和*/
};

  

五.實現如下:

client端: 

  1 /*
  2  ============================================================================
  3  Name        : test_client.c
  4  Author      : huh
  5  Version     :
  6  Copyright   : ---notice---
  7  Description : Hello World in C, Ansi-style
  8  ============================================================================
  9  */
 10 
 11 #include <sys/types.h>
 12 #include <sys/socket.h>
 13 #include <stdio.h>
 14 #include <netinet/in.h>
 15 #include <arpa/inet.h>
 16 #include <unistd.h>
 17 #include <stdlib.h>
 18 #include <string.h>
 19 #include <netinet/ip_icmp.h>
 20 #include <netinet/udp.h>
 21 
 22 #define MAXLINE 1024*10
 23 
 24 struct udp_front  //udp
 25 {
 26     uint32_t srcip;
 27     uint32_t desip;
 28     u_int8_t zero;
 29     u_int8_t protocol;
 30     u_int16_t len;
 31 };
 32 
 33 u_int16_t in_chksum(u_int16_t *addr, int len);
 34 u_int16_t udp_check(char *sendbuf, int len, const struct udp_front front);
 35 int make_message(char sendbuf[], int send_buf_len, uint32_t src_ip, u_int16_t src_port, uint32_t des_ip, u_int16_t des_port);
 36 
 37 int main()
 38 {
 39     int raw_sockfd;
 40     int size = 1024*50;
 41     char send_message[MAXLINE];
 42     struct sockaddr_in server_address;
 43     //創建原始套接字
 44     raw_sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_UDP);
 45     //創建套接字地址
 46     bzero(&server_address,sizeof(server_address));
 47     server_address.sin_family = AF_INET;
 48     server_address.sin_addr.s_addr = inet_addr("192.168.11.105");
 49     //設置套接字為隨數據包含IP首部(設置這個選項后需要我們手動寫入IP頭)
 50     setsockopt(raw_sockfd, IPPROTO_IP, IP_HDRINCL, &size, sizeof(size));
 51 
 52     int len;
 53     bzero(&send_message, sizeof(send_message));
 54     //拼接完整的UDP數據包(IP頭+UDP頭+數據)
 55     int mesg_len = make_message(send_message, MAXLINE, inet_addr("192.168.11.104"), 8600, inet_addr("192.168.11.105"), 8686);
 56     //將IP數據包發送出去
 57     sendto(raw_sockfd, send_message, mesg_len, 0, (struct sockaddr *)&server_address, sizeof(server_address));
 58     close(raw_sockfd);
 59     //
 60     //下面我們開始接受服務器返回的包
 61     int client_sockfd;
 62     int server_len;
 63     char recv_message[MAXLINE];
 64     struct sockaddr_in server_addr;
 65     client_sockfd = socket(AF_INET, SOCK_DGRAM, 0);
 66     server_addr.sin_family = AF_INET;
 67     server_addr.sin_addr.s_addr = inet_addr("192.168.11.104");
 68     server_addr.sin_port = htons(8600);
 69     server_len = sizeof(server_address);
 70     bind(client_sockfd, (struct sockaddr *)&server_addr, server_len);
 71 
 72     bzero(&recv_message, sizeof(recv_message));
 73        len = recvfrom(client_sockfd, recv_message, MAXLINE, 0, NULL, NULL);
 74        printf("收到的應答:%s\n",recv_message);
 75     return 0;
 76 }
 77 
 78 //拼接IP數據報
 79 int make_message(char sendbuf[], int send_buf_len, uint32_t src_ip, u_int16_t src_port, uint32_t des_ip, u_int16_t des_port)
 80 {
 81     char message[1005];
 82     bzero(message, sizeof(message));
 83     strcpy(message,"hello,world!");
 84     printf("message len:%d\n",strlen(message));
 85     struct iphdr *ip;
 86     ip = (struct iphdr *)sendbuf;
 87     ip->ihl = sizeof(struct iphdr) >> 2; //首部長度
 88     ip->version = 4;   //ip協議版本
 89     ip->tos = 0;   //服務類型字段
 90     ip->tot_len = 0;   //總長度
 91     ip->id = 1000;   //
 92     ip->frag_off = 0;
 93     ip->ttl = 128;
 94     ip->protocol = IPPROTO_UDP;
 95     ip->check = 0;  //內核會算相應的效驗和
 96     ip->saddr = src_ip;
 97     ip->daddr = des_ip;
 98 
 99     struct udp_front front;
100     front.srcip = src_ip;
101     front.desip = des_ip;
102     front.len = htons(8+strlen(message));
103     front.protocol = 17;
104     front.zero = 0;
105 
106     struct udphdr *udp;
107     udp = (struct udphdr *)(sendbuf + sizeof(struct iphdr));
108     udp->source = htons(src_port);  //源端口
109     udp->dest = htons(des_port);    //目的端口
110     udp->check = 0;   //效驗和,效驗整個udp數據報
111     strcpy((sendbuf+20+8), message);
112     udp->len = htons(8+strlen(message)); //udp數據報總長度
113 
114     udp->check = udp_check((sendbuf+20), 8+strlen(message), front);
115 
116     ip->tot_len = htons(20 + 8 + strlen(message));   //總長度
117     printf("ip->tot_len:%d\n",ip->tot_len);
118     ip->check = in_chksum((unsigned short *)sendbuf, 20);
119 
120     return ntohs(ip->tot_len);
121 }
122 
123 //計算udp效驗和
124 unsigned short udp_check(char *sendbuf, int len, const struct udp_front front)
125 {
126     char str[MAXLINE];
127     bzero(&str, MAXLINE);
128     bcopy(&front, str, sizeof(front));
129     bcopy(sendbuf, str+sizeof(front), len);
130     struct udp_front *ptr;
131     ptr = (struct udp_front *)str;
132     char *s;
133     s = (str+20);
134     return in_chksum((unsigned short *)str, sizeof(front)+len);
135 }
136 
137 //效驗和算法
138 uint16_t in_chksum(uint16_t *addr, int len)
139 {
140     int nleft = len;
141     uint32_t sum = 0;
142     uint16_t *w = addr;
143     uint16_t answer = 0;
144     //把ICMP報頭二進制數據以2字節為單位累加起來
145     while (nleft > 1)
146     {
147         sum += *w++;
148         nleft -= 2;
149     }
150     if (nleft == 1)
151     {
152         *(unsigned char *)(&answer) = *(unsigned char *)w;
153         sum += answer;
154     }
155     sum = (sum>>16) + (sum&0xffff);
156     sum += (sum>>16);
157     answer = ~sum;
158     return answer;
159 }

  

server端:

server端是一個簡單的收包服務器,監聽8686端口,當有udp數據包到來時,打印信息並返回給client一個信息。

 

 1 #include <sys/types.h>
 2 #include <sys/socket.h>
 3 #include <stdio.h>
 4 #include <netinet/in.h>
 5 #include <arpa/inet.h>
 6 #include <unistd.h>
 7 #include <stdlib.h>
 8 #include <string.h>
 9 
10 #define HOST_IP "192.168.11.105"
11 #define HOST_PORT 8686
12 
13 #define MAXLINE 1024*50
14 
15 int main()
16 {
17     int server_sockfd;
18     int server_len, client_len;
19     struct sockaddr_in server_address;
20     struct sockaddr_in client_address;
21 
22     server_sockfd = socket(AF_INET, SOCK_DGRAM, 0);
23 
24     server_address.sin_family = AF_INET;
25     server_address.sin_addr.s_addr = inet_addr(HOST_IP);
26     server_address.sin_port = htons(HOST_PORT);
27 
28     server_len = sizeof(server_address);
29     bind(server_sockfd, (struct sockaddr *)&server_address, server_len);
30 
31     for( ; ; )
32     {
33         int len;
34         char recv_mesg[MAXLINE];
35         char send_mesg[20];
36         client_len = sizeof(struct sockaddr_in);
37         printf("server2 waiting!\n");
38         len = recvfrom(server_sockfd, recv_mesg, MAXLINE, 0, (struct sockaddr *) &client_address, (socklen_t *) &client_len);
39         printf("收到包的長度為:%d\n",len);
40         printf("%s\n",recv_mesg);
41         strcpy(send_mesg,"yes");
42         sendto(server_sockfd, send_mesg, strlen(send_mesg), 0, (struct sockaddr *) &client_address, client_len);  //將包發出去
43     }
44     return 0;
45 }
server.c

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM