004.原始套接字,拼接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.注意主机字节序和网络字节序的转

实现如下:

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 = (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 (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端:

 1 /*
 2  ============================================================================
 3  Name        : test_server.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
20 #define MAXLINE 1024*50
21
22 int main()
23 {
24     int server_sockfd;
25     int server_len, client_len;
26     struct sockaddr_in server_address;
27     struct sockaddr_in client_address;
28
29     server_sockfd = socket(AF_INET, SOCK_DGRAM, 0);
30
31     server_address.sin_family = AF_INET;
32     server_address.sin_addr.s_addr = inet_addr("192.168.11.105");
33     server_address.sin_port = htons(8686);
34
35     server_len = sizeof(server_address);
36     bind(server_sockfd, (struct sockaddr *)&server_address, server_len);
37
38     for( ; ; )
39     {
40         int len;
41         char recv_mesg[MAXLINE];
42         char send_mesg[20];
43         client_len = sizeof(struct sockaddr_in);
44         printf("server2 waiting!\n");
45         len = recvfrom(server_sockfd, recv_mesg, MAXLINE, 0, (struct sockaddr *) &client_address, (socklen_t *) &client_len);
46         printf("收到包的长度为:%d\n",len);
47         printf("%s\n",recv_mesg);
48         strcpy(send_mesg,"yes");
49         sendto(server_sockfd, send_mesg, strlen(send_mesg), 0, (struct sockaddr *) &client_address, client_len);  //将包发出去
50         ;
51     }
52     return 0;
53 }
时间: 2024-12-20 09:11:54

004.原始套接字,拼接UDP数据包,通信的相关文章

原始套接字SOCK_RAW

原始套接字SOCK_RAW 实际上,我们常用的网络编程都是在应用层的报文的收发操作,也就是大多数程序员接触到的流式套接字(SOCK_STREAM)和数据包式套接字(SOCK_DGRAM).而这些数据包都是由系统提供的协议栈实现,用户只需要填充应用层报文即可,由系统完成底层报文头的填充并发送.然而在某些情况下需要执行更底层的操作,比如修改报文头.避开系统协议栈等.这个时候就需要使用其他的方式来实现. 一 原始套接字 原始套接字(SOCK_RAW)是一种不同于SOCK_STREAM.SOCK_DGR

Linux 网络编程——原始套接字实例:发送 UDP 数据包

以太网报文格式: 详细的说明,请看<MAC 头部报文分析>. IP 报文格式: 详细的说明,请看<IP 数据报格式详解>. UDP 报文格式: 详细的说明,请看<UDP 数据报格式详解>. 校验和函数: /******************************************************* 功能: 校验和函数 参数: buf: 需要校验数据的首地址 nword: 需要校验数据长度的一半 返回值: 校验和 ********************

python使用原始套接字 解析原始ip头数据

使用底层套接字解码底层流量,是这次做的重点工作. 首先来捕获第一个包 # coding:utf-8import socket # 监听的主机IP host = "192.168.1.100" socket_protocol = socket.IPPROTO_ICMP sniffer = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket_protocol) sniffer.bind((host, 0)) sniffer.setso

利用原始套接字实现一个简单的采集网络数据包

//利用原始套接字实现一个简单的采集网络数据包,并进行反向解析IP,MAC地址#include <stdio.h>#include <sys/socket.h>#include <unistd.h>#include <sys/types.h>#include <linux/if_ether.h>#include <linux/in.h> #define BUFFER_MAX 2048 int main(int argc, char *

Linux网络编程——原始套接字实例:简单版网络数据分析器

通过<Linux网络编程--原始套接字编程>得知,我们可以通过原始套接字以及 recvfrom( ) 可以获取链路层的数据包,那我们接收的链路层数据包到底长什么样的呢? 链路层封包格式 MAC 头部(有线局域网) 注意:CRC.PAD 在组包时可以忽略 链路层数据包的其中一种情况: unsigned char msg[1024] = { //--------------组MAC--------14------ 0xb8, 0x88, 0xe3, 0xe1, 0x10, 0xe6, // dst

linux原始套接字(3)-构造IP_TCP发送与接收

一.概述                                                    tcp报文封装在ip报文中,创建tcp的原始套接字如下: 1 sockfd = socket(PF_INET, SOCK_RAW, IPPROTO_TCP); 此时只能构造tcp报文,如果想进一步构造ip首部,那么就要开启sockfd的IP_HDRINCL选项: 1 int on = 1; 2 setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL, &on

关于linux 原始套接字编程

关于linux 网络编程最权威的书是<<unix网络编程>>,但是看这本书时有些内容你可能理解的不是很深刻,或者说只知其然而不知其所以然,那么如果你想搞懂的话那么我建议你可以看看网络协议栈的实现. 函数原型是 int socket(int domain, int type, int protocol); 其中domain 中AF_INET , AF_UNIT 较为常用,分别创建inet 域套接字和unix域套接字,unix套接字与文件相关.平时80%用的套接字都是AF_INET.这

原始套接字(SOCK_RAW)

本文转载:http://www.cnblogs.com/duzouzhe/archive/2009/06/19/1506699.html,在此感谢 原始套接字(SOCK_RAW). 应用原始套接字,我们可以编写出由TCP和UDP套接字不能够实现的功能. 注意原始套接字只能够由有 root权限的人创建. 10.1 原始套接字的创建 int sockfd(AF_INET,SOCK_RAW,protocol) 可以创建一个原始套接字.根据协议的类型不同我们可以创建不同类型的原始套接字 比如:IPPRO

原始套接字基础(原始套接字系列二)

在进入Raw Socket多种强大的应用之前,我们先讲解怎样建立一个Raw Socket及怎样用建立的Raw Socket发送和接收IP包. 建立Raw Socket 在Windows平台上,为了使用Raw Socket,需先初始化WINSOCK: // 启动 WinsockWSAData wsaData;if (WSAStartup(MAKEWORD(2, 1), &wsaData) != 0){ cerr << "Failed to find Winsock 2.1 or