006.udp转发包并代理访问服务器总结
背景:
当加速器(client)拦截了游戏客户端发送的完整数据包(package)时,将package传给中间服务器(mid_server),经过自己的链路传输数据之后,中间服务器模拟游戏客户端将数据发给游戏服务器(end_server),目的服务器收到请求后回应,回应的包以同样的方式返回,直到游戏客户端收到数据包。
原理及实现:
1.我们需要三个主机来模拟这个请求:
client_server: IP:192.168.11.104
mid_server: IP:192.168.11.105
end_server: IP:192.168.11.106
程序的流程图:
其中:
1.client_server只是充当普通的udp客户端,不同的是我们发送的数据是一个完整的udp类型的IP数据包
2.end_server模拟的是一台普通的游戏服务器,当有客户请求的时候,它就会回应
3.mid_server代替游戏客户端的请求,将数据包中替换了请求IP和port后发给游戏服务器,获得服务。
当游戏服务器回应数据后,同样再次将数据封装成一个完整的udp的IP数据包,填入相应的服务器IP,服务器端口,客户端IP,客户端端口,将这个数据包作为数据发给client_server
4.client_server将完整的数据包发给游戏服务器。
代码实现:
1.client_server部分:
/*
============================================================================
Name : udp_client.c
Author : huh
Version :
Copyright : ---notice---
Description : Hello World in C, Ansi-style
============================================================================
*/ #include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/ip_icmp.h>
#include <netinet/udp.h> #define MAXLINE 1024*10 int make_message(char *mesg, char sendbuf[], int send_buf_len, uint32_t src_ip, u_int16_t src_port, uint32_t des_ip, u_int16_t des_port); int main()
{
int server_sockfd;
char send_message[MAXLINE];
char recv_message[MAXLINE];
struct sockaddr_in server_address; server_sockfd = socket(AF_INET, SOCK_DGRAM, ); bzero(&server_address,sizeof(server_address));
server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = inet_addr("192.168.11.105");
server_address.sin_port = htons(); int mesg_len;
bzero(&send_message, MAXLINE);
mesg_len = make_message("hello world!", send_message, MAXLINE, inet_addr("192.168.11.104"), , inet_addr("192.168.11.106"), ); //printf("send message len:%d\n",strlen(send_message));
sendto(server_sockfd, send_message, mesg_len, , (struct sockaddr *)&server_address, sizeof(server_address)); //将包发出去 bzero(&recv_message, sizeof(recv_message));
int len = recvfrom(server_sockfd, recv_message, MAXLINE, , NULL, NULL);
printf("当前收到的IP数据包的内容:\n");
struct iphdr *ip;
ip = (struct iphdr *)recv_message;
struct udphdr *udp;
udp = (struct udphdr *)(recv_message + sizeof(struct iphdr));
struct in_addr ad;
ad.s_addr = ip->saddr;
printf("src_ip:%s\n",inet_ntoa(ad));
printf("src_port:%d\n",ntohs(udp->source)); ad.s_addr = ip->daddr;
printf("des_ip:%s\n",inet_ntoa(ad));
printf("des_port:%d\n",ntohs(udp->dest));
printf("data:%s\ndata len:%d\n",(recv_message+),len); close(server_sockfd);
return ;
}
udp_client.c
/*
* make_message.c
*
* Created on: 2015年11月18日
* Author: root
*/ #include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/ip_icmp.h>
#include <netinet/udp.h> #define MAXLINE 1024*10 struct udp_front //udp
{
uint32_t srcip;
uint32_t desip;
u_int8_t zero;
u_int8_t protocol;
u_int16_t len;
}; u_int16_t in_chksum(u_int16_t *addr, int len);
u_int16_t udp_check(char *sendbuf, int len, const struct udp_front front);
int make_message(char *mesg, char sendbuf[], int send_buf_len, uint32_t src_ip, u_int16_t src_port, uint32_t des_ip, u_int16_t des_port); //拼接IP数据报
int make_message(char *mesg, char sendbuf[], int send_buf_len, uint32_t src_ip, u_int16_t src_port, uint32_t des_ip, u_int16_t des_port)
{
char message[MAXLINE];
bzero(message, sizeof(message));
strcpy(message,mesg);
printf("message len:%d\n",strlen(message));
struct iphdr *ip;
ip = (struct iphdr *)sendbuf;
ip->ihl = sizeof(struct iphdr) >> ; //首部长度
ip->version = ; //ip协议版本
ip->tos = ; //服务类型字段
ip->tot_len = ; //总长度
ip->id = ; //
ip->frag_off = ;
ip->ttl = ;
ip->protocol = IPPROTO_UDP;
ip->check = ; //内核会算相应的效验和
ip->saddr = src_ip;
ip->daddr = des_ip; struct udp_front front;
front.srcip = src_ip;
front.desip = des_ip;
front.len = htons(+strlen(message));
front.protocol = ;
front.zero = ; struct udphdr *udp;
udp = (struct udphdr *)(sendbuf + sizeof(struct iphdr));
udp->source = htons(src_port); //源端口
udp->dest = htons(des_port); //目的端口
udp->check = ; //效验和,效验整个udp数据报
strcpy((sendbuf++), message);
udp->len = htons(+strlen(message)); //udp数据报总长度 udp->check = udp_check((sendbuf+), +strlen(message), front); ip->tot_len = ( + + strlen(message)); //总长度
printf("ip->tot_len:%d\n",ip->tot_len);
ip->check = in_chksum((unsigned short *)sendbuf, ); return (ip->tot_len);
} //计算udp效验和
unsigned short udp_check(char *sendbuf, int len, const struct udp_front front)
{
char str[MAXLINE];
bzero(&str, MAXLINE);
bcopy(&front, str, sizeof(front));
bcopy(sendbuf, str+sizeof(front), len);
struct udp_front *ptr;
ptr = (struct udp_front *)str;
char *s;
s = (str+);
return in_chksum((unsigned short *)str, sizeof(front)+len);
} //效验和算法
uint16_t in_chksum(uint16_t *addr, int len)
{
int nleft = len;
uint32_t sum = ;
uint16_t *w = addr;
uint16_t answer = ;
//把ICMP报头二进制数据以2字节为单位累加起来
while (nleft > )
{
sum += *w++;
nleft -= ;
}
if (nleft == )
{
*(unsigned char *)(&answer) = *(unsigned char *)w;
sum += answer;
}
sum = (sum>>) + (sum&0xffff);
sum += (sum>>);
answer = ~sum;
return answer;
}
make_message.c
2.mid_server部分:
/*
============================================================================
Name : udp_mid_server.c
Author : huh
Version :
Copyright : ---notice---
Description : Hello World in C, Ansi-style
============================================================================
*/ #include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/ip_icmp.h>
#include <netinet/udp.h> #define MAXLINE 1024*50 #define SERVER_IP "192.168.11.105" //本服务器IP
#define TO_CLI_PORT 8600 //本服务器监听client_server端口
#define TO_END_PORT 8601 //本服务器监听end_server端口 #define END_SERVER_IP "192.168.11.106" //end_server的ip
#define END_SERVER_PORT 8686 //end_server的port struct udp_front //udp
{
uint32_t srcip;
uint32_t desip;
u_int8_t zero;
u_int8_t protocol;
u_int16_t len;
}; uint32_t client_ip;
int client_port; extern u_int16_t in_chksum(u_int16_t *addr, int len);
extern u_int16_t udp_check(char *sendbuf, int len, const struct udp_front front);
extern int make_message(char *mesg, char sendbuf[], int send_buf_len, uint32_t src_ip, u_int16_t src_port, uint32_t des_ip, u_int16_t des_port); void change_src(char sendbuf[], int len, uint32_t src_ip, int src_port)
{
struct iphdr *ip;
ip = (struct iphdr *)sendbuf;
ip->check = ; //内核会算相应的效验和
client_ip = ip->saddr;
ip->saddr = src_ip;
ip->check = in_chksum((unsigned short *)sendbuf, );
;
struct udp_front front;
front.srcip = src_ip;
front.desip = ip->daddr;
front.len = htons(len-);
front.protocol = ;
front.zero = ; struct udphdr *udp;
udp = (struct udphdr *)(sendbuf + sizeof(struct iphdr));
client_port = ntohs(udp->source);
udp->source = htons(src_port); //源端口
udp->check = ; //效验和,效验整个udp数据报
udp->check = udp_check((sendbuf+), len-, front);
} void send_1(int raw_sockfd, char *send_message, int len)
{
struct sockaddr_in server_addr;
bzero(&server_addr,sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = inet_addr(END_SERVER_IP); change_src(send_message, len, inet_addr(SERVER_IP), TO_END_PORT);
sendto(raw_sockfd, send_message, len, , (struct sockaddr *) &server_addr, sizeof(server_addr)); //将包发出去
printf("前往end_server的包已经出发!\n");
} int main()
{
int size = *;
int server_len, client_len;
struct sockaddr_in server_address;
struct sockaddr_in client_address; //接收client_server端数据的套接字
//监听端口:8600
int server_sockfd;
server_sockfd = socket(AF_INET, SOCK_DGRAM, );
bzero(&server_address,sizeof(server_address));
server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = inet_addr(SERVER_IP);
server_address.sin_port = htons(TO_CLI_PORT);
server_len = sizeof(server_address);
bind(server_sockfd, (struct sockaddr *)&server_address, server_len); //发送给end_server的原始套接字
int raw_sockfd;
raw_sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_UDP);
setsockopt(raw_sockfd, IPPROTO_IP, IP_HDRINCL, &size, sizeof(size)); //接收end_server端数据的套接字
//监听端口:8601
int end_sockfd;
end_sockfd = socket(AF_INET, SOCK_DGRAM, );
bzero(&server_address,sizeof(server_address));
server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = inet_addr(SERVER_IP);
server_address.sin_port = htons(TO_END_PORT);
server_len = sizeof(server_address);
bind(end_sockfd, (struct sockaddr *)&server_address, server_len); char recv_mesg[MAXLINE];
char send_mesg[MAXLINE];
for( ; ; )
{
int len;
client_len = sizeof(struct sockaddr_in);
printf("server waiting!\n");
//接收来自client_server的包
bzero(&client_address, sizeof(client_address));
len = recvfrom(server_sockfd, recv_mesg, MAXLINE, , (struct sockaddr *) &client_address, (socklen_t *) &client_len);
printf("来自client_server的IP数据包的长度为:%d\n",len); //将接收到的数据作为一个完整的IP包发给end_server
send_1(raw_sockfd, recv_mesg, len); //接收来自end_server的回应包,并将数据存在recv_mesg里面
bzero(recv_mesg, sizeof(recv_mesg));
len = recvfrom(end_sockfd, recv_mesg, MAXLINE, , NULL, NULL);
printf("收到来自end_server的应答:%s,长度:%d\n",recv_mesg,len); //现在将end_server给我的包拼接好后发给client_server.
printf("client:%d\n",client_port);
bzero(send_mesg,sizeof(send_mesg));
int mesg_len = make_message(recv_mesg, send_mesg, MAXLINE, inet_addr(END_SERVER_IP), END_SERVER_PORT, client_ip, client_port);
sendto(server_sockfd, send_mesg, mesg_len, , (struct sockaddr *) &client_address, client_len); }
return ;
}
udp_mid_server.c
/*
* make_message.c
*
* Created on: 2015年11月18日
* Author: root
*/ #include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/ip_icmp.h>
#include <netinet/udp.h> #define MAXLINE 1024*10 struct udp_front //udp
{
uint32_t srcip;
uint32_t desip;
u_int8_t zero;
u_int8_t protocol;
u_int16_t len;
}; u_int16_t in_chksum(u_int16_t *addr, int len);
u_int16_t udp_check(char *sendbuf, int len, const struct udp_front front); //拼接IP数据报
int make_message(char *mesg, char sendbuf[], int send_buf_len, uint32_t src_ip, u_int16_t src_port, uint32_t des_ip, u_int16_t des_port)
{
char message[MAXLINE];
bzero(message, sizeof(message));
strcpy(message,mesg);
printf("message len:%d\n",strlen(message));
struct iphdr *ip;
ip = (struct iphdr *)sendbuf;
ip->ihl = sizeof(struct iphdr) >> ; //首部长度
ip->version = ; //ip协议版本
ip->tos = ; //服务类型字段
ip->tot_len = ; //总长度
ip->id = ; //
ip->frag_off = ;
ip->ttl = ;
ip->protocol = IPPROTO_UDP;
ip->check = ; //内核会算相应的效验和
ip->saddr = src_ip;
ip->daddr = des_ip; struct udp_front front;
front.srcip = src_ip;
front.desip = des_ip;
front.len = htons(+strlen(message));
front.protocol = ;
front.zero = ; struct udphdr *udp;
udp = (struct udphdr *)(sendbuf + sizeof(struct iphdr));
udp->source = htons(src_port); //源端口
udp->dest = htons(des_port); //目的端口
udp->check = ; //效验和,效验整个udp数据报
strcpy((sendbuf++), message);
udp->len = htons(+strlen(message)); //udp数据报总长度 udp->check = udp_check((sendbuf+), +strlen(message), front); ip->tot_len = ( + + strlen(message)); //总长度
printf("ip->tot_len:%d\n",ip->tot_len);
ip->check = in_chksum((unsigned short *)sendbuf, ); return (ip->tot_len);
} //计算udp效验和
unsigned short udp_check(char *sendbuf, int len, const struct udp_front front)
{
char str[MAXLINE];
bzero(&str, MAXLINE);
bcopy(&front, str, sizeof(front));
bcopy(sendbuf, str+sizeof(front), len);
struct udp_front *ptr;
ptr = (struct udp_front *)str;
char *s;
s = (str+);
return in_chksum((unsigned short *)str, sizeof(front)+len);
} //效验和算法
uint16_t in_chksum(uint16_t *addr, int len)
{
int nleft = len;
uint32_t sum = ;
uint16_t *w = addr;
uint16_t answer = ;
//把ICMP报头二进制数据以2字节为单位累加起来
while (nleft > )
{
sum += *w++;
nleft -= ;
}
if (nleft == )
{
*(unsigned char *)(&answer) = *(unsigned char *)w;
sum += answer;
}
sum = (sum>>) + (sum&0xffff);
sum += (sum>>);
answer = ~sum;
return answer;
}
make_message.c
3.end_srever部分:
/*
============================================================================
Name : udp_end_server.c
Author : huh
Version :
Copyright : ---notice---
Description : Hello World in C, Ansi-style
============================================================================
*/ #include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h> #define MAXLINE 1024*50 #define SERVER_IP "192.168.11.106" //本服务器IP
#define SERVER_PORT 8686 //本服务器监听端口 int main()
{
int server_sockfd;
char recv_mesg[MAXLINE];
int server_len, client_len;
struct sockaddr_in server_address;
struct sockaddr_in client_address; server_sockfd = socket(AF_INET, SOCK_DGRAM, );
server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = inet_addr(SERVER_IP);
server_address.sin_port = htons(SERVER_PORT);
server_len = sizeof(server_address);
bind(server_sockfd, (struct sockaddr *)&server_address, server_len); //我们会将收到的数据加上"by end server!",再返回给客户端
while()
{
int len;
client_len = sizeof(struct sockaddr_in);
printf("end server waiting!\n");
bzero(recv_mesg, sizeof(recv_mesg));
len = recvfrom(server_sockfd, recv_mesg, MAXLINE, , (struct sockaddr *) &client_address, (socklen_t *) &client_len);
printf("收到mid_server包的长度为:%d,内容为:%s\n", len, recv_mesg);
strcpy(recv_mesg+len," by end_server!");
len = strlen(recv_mesg);
sendto(server_sockfd, recv_mesg, len, , (struct sockaddr *) &client_address, client_len); //将包发出去
printf("往mid_server回应的包已经出发!\n");
}
return ;
}
udp_end_server.c
监听中间服务器显示的结果:
[root@mid_server ~]# tcpdump -nn udp and host 192.168.11.105
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes
22:25:24.085794 IP 192.168.11.104.45375 > 192.168.11.105.8600: UDP, length 40
22:25:24.086092 IP 192.168.11.105.8601 > 192.168.11.106.8686: UDP, length 12
22:25:24.086632 IP 192.168.11.106.8686 > 192.168.11.105.8601: UDP, length 27
22:25:24.086891 IP 192.168.11.105.8600 > 192.168.11.104.45375: UDP, length 55
006.udp转发包并代理访问服务器总结的更多相关文章
- Py之Crawler:爬虫利用随机选取代理访问服务器的方法实现下载某网址上所有的图片到指定文件夹——Jason niu
#Py之Crawler:爬虫利用随机选取代理访问服务器的方法实现下载某网址上所有的图片到指定文件夹 import urllib.request import os import random def ...
- python使用代理访问服务器
python使用代理访问服务器主要有一下3个步骤: 1.创建一个代理处理器ProxyHandler: proxy_support = urllib.request.ProxyHandler(),Pro ...
- UDP协议发包的使用(DatagramSocket、DatagramPacket)
1.UDP 是User Datagram Protocol的简称, 中文名是用户数据报协议,是OSI(Open System Interconnection,开放式系统互联) 参考模型中一种无连接的传 ...
- 【http代理报文】通过发包实现代理请求网页内容
工作中,我们难免需要通过TCP/IP协议发送报文来直接请求网页内容(比如爬虫工具),有同学问如何通过HTTP代理来请求网页,其实我们只需要把报文稍稍修改下,发送给代理服务器即可实现. 基础不过关的朋友 ...
- udp之关于linux udp收发包缓冲区大小
1.修订单个socket的缓冲区大小:通过setsockopt使用SO_RCVBUF来设置接收缓冲区,该参数在设置的时候不会与rmem_max进行对比校验,但是如果设置的大小超过rmem_max的话, ...
- 记录一个UDP收包丢包的问题
这几天写GB28181平台接入层代码,对收到的PS包进行解包时,总是出现误码,最终导致rtsp点播服务中画面花屏. 分析了码流抓包数据之后,发现网络上没有丢包,遂认为PS流解包代码有bug,于是埋头分 ...
- ss与udp转发的释疑
转载: http://shadowsocks.info/shadowsocks-udp/ VPS购买地址 udp是什么:UDP 是User Datagram Protocol的简称, 中文名是用户数据 ...
- python--socket/Socketerver并发/udp
Socketerve并发 基于tcp套接字,关键就是两个循环,一个链接循环,一个通讯循环 Socketserver模块中分两个大类:server类(解决链接问题)和request类(解决通信问题) s ...
- 网络游戏程序员须知 UDP vs TCP(转)
本文为作者原创或翻译,转载请注明,不得用于商业用途. 作者:rellikt@gmail.com 首发链接:http://blog.csdn.net/rellikt/archive/2010/08/21 ...
随机推荐
- mysql易混淆知识点
1,join 和 union join连接属于表之间的水平操作,而union 是表之间的垂直操作.简单讲就是水平操作主要是为了获得列数据,垂直操作是为了获得行数据 cross join ...
- ubuntu 下安装redis 以及php扩展
下载redis wget http://download.redis.io/redis-stable.tar.gz tar xzf redis-stable.tar.gz cd redis-s ...
- Photoshop和WPF双剑配合,打造炫酷个性的进度条控件
现在如果想打造一款专业的App,UI的设计和操作的简便性相当重要.UI设计可以借助Photoshop或者AI等设计工具,之前了解到WPF设计工具Expression Blend可以直接导入PSD文件或 ...
- 设计人员应该看的15个很酷的 iOS 8 设计
苹果新一代智能手机 iPhone 6 发布已经有一段时间了,一些创意设计师已经开始在设计中采用 iOS 8 设计理念.当然,其中有些是对于未来的展望和大胆的设计.我在这里收集了15个很酷的 iOS 8 ...
- HTML5 Maker – 在线轻松制作 HTML5 动画效果
HTML5 Maker 是一个在线动画制作工具,帮助你使用 HTML,CSS 和 JavaScript 创建动态,互动的内容.它非常容易使用,同时可以帮你实现非常好的效果.它可以制作跨浏览器的动画内容 ...
- Ratatype - 在线打字教程,提高打字速度
Ratatype 是一个在线的打字教程网站,帮助人们提高键盘输入速度.开始掌握你的技能,挑战你的朋友或得到一个打字的证书.如果打字慢会浪费你宝贵的时间.如果你的打字速度提高30%,您可以每天节省20分 ...
- JavaScript 事件入门
一.事件介绍 JavaScript 有三种事件模型:内联模型.脚本模型和 DOM2 模型. 二.内联模型 //在 HTML 中把事件处理函数作为属性执行 JS 代码 <input type=&q ...
- 【小贴士】虚拟键盘与fixed带给移动端的痛!
前言 今天来公司的主要目的就是研究虚拟键盘与fixed的问题,期间因为同事问起闭包与事件委托(阻止冒泡)相关问题,便穿插了一篇别的: [小贴士]工作中的”闭包“与事件委托的”阻止冒泡“,有兴趣的朋友可 ...
- 10本Java经典书目推荐
本文列出的10本书是我个人非常喜欢的Java书籍,当我有时间的时候,我就会将它们捧在手里阅读.甚至有些书我反复读过很多遍,每次重新读的时候总会有新的收获.因此这些书也是大部分Java程序员喜欢的书籍. ...
- Jquery+Ajax下拉框级联查询