ss-libev 源码解析udp篇 (4)
本篇分析remote_recv_cb,这是整个udp转发的反方向,即读取从后端发送过来的数据再发送给前端。对于ss-server,读取到的数据是目标地址的udp服务器发送回来的响应数据,ss-server需要将其包装成ss的格式并加密发送给ss-local;对于ss-local接收到的数据就是ss-server发送过来的加密数据,ss-local解密后需要再将其包装成socks5的格式发送给socks5客户端,至此整个udp转发过程完成。
下面具体分析:
- 首先是接收数据
struct sockaddr_storage src_addr;
socklen_t src_addr_len = sizeof(struct sockaddr_storage);
memset(&src_addr, 0, src_addr_len);
buffer_t *buf = ss_malloc(sizeof(buffer_t));
balloc(buf, buf_size);
// recv
r = recvfrom(remote_ctx->fd, buf->data, buf_size, 0, (struct sockaddr *)&src_addr, &src_addr_len);
buf->len = r;
- 下面是ss-local的处理,对于读取到的,来自remote的数据解密。并分析addr header。但这儿的分析只是为了检查addr header是否合法,不需要再获取到addr,因为remote_ctx里面已经有src_addr
#ifdef MODULE_LOCAL
int err = server_ctx->crypto->decrypt_all(buf, server_ctx->crypto->cipher, buf_size);
int len = parse_udprealy_header(buf->data, buf->len, NULL, NULL, NULL);
之后local会将解密的数据加上3个字节的0,构造成socks5的udp包格式。因为ss的加密前的udp包格式和socks5的格式只相差3个字节,而这三个字节前两个RSV固定为0,第三个FRAG对于ss来说只支持0,所以这儿加上3个0字节就构成了socks5格式的udp包。代码如下:
// Construct packet
brealloc(buf, buf->len + 3, buf_size);
memmove(buf->data + 3, buf->data, buf->len);
memset(buf->data, 0, 3);
buf->len += 3;
- 下面是ss-server的处理,首先remote_ctx中已经记录了addr_header,但是对于ip地址,ss又重新构造了addr header,填入的是前面recvfrom获取到的目的服务器的addr。也就是说对于域名的情况,直接使用之前保存的addr header。这儿我也不清楚作者为什么要对于ip地址的情况重新构造。之后将addr header附加到接收到的数据前面,并加密,准备发送往ss-local。
#ifdef MODULE_REMOTE
rx += buf->len; //统计接收到的下行数据量
char addr_header_buf[512];
char *addr_header = remote_ctx->addr_header;
int addr_header_len = remote_ctx->addr_header_len;
//如果是ip地址从src_addr中构造出addr header
if (remote_ctx->af == AF_INET || remote_ctx->af == AF_INET6) {
addr_header_len = construct_udprealy_header(&src_addr, addr_header_buf);
addr_header = addr_header_buf;
}
// Construct packet
brealloc(buf, buf->len + addr_header_len, buf_size);
memmove(buf->data + addr_header_len, buf->data, buf->len);
memcpy(buf->data, addr_header, addr_header_len);
buf->len += addr_header_len;
int err = server_ctx->crypto->encrypt_all(buf, server_ctx->crypto->cipher, buf_size);
if (err) {
// drop the packet silently
goto CLEAN_UP;
}
#endif
- 之后就是发送数据了,local和server的代码一样:
int s = sendto(server_ctx->fd, buf->data, buf->len, 0,
(struct sockaddr *)&remote_ctx->src_addr, remote_src_addr_len);
if (s == -1) {
ERROR("[udp] remote_recv_sendto");
goto CLEAN_UP;
}
- 最后还要重置timeout timer:
// handle the UDP packet successfully,
// triger the timer
ev_timer_again(EV_A_ & remote_ctx->watcher);
- 小结:udp和tcp不同的地方在于,tcp是流,udp是数据包;ss处理tcp是不光要监听读事件还要监听写事件,因为数据是不断从流里面过来,要持续的读写才能完成转发;而udp只需要监听读事件,因为一次recvfrom就是一个完整的udp包,所以对应一个sendto发出去即可,不需要考虑写了一部分这种事情。udp转发就分析到这儿了,总体看来比TCP简单很多。
ss-libev 源码解析udp篇 (4)的更多相关文章
- ss-libev 源码解析udp篇 (3)
本篇分析server_recv_cb,这个是udp转发中最重要的函数. server_recv_cb: 当ss-local或ss-server接收到来自前端的udp数据包时调用.这个函数代码比较多,除 ...
- ss-libev 源码解析udp篇 (2)
UDP relay的代码基本都在udprelay.c中,无论ss-local还是ss-server的代码都在一起,使用宏MODULE_LOCAL,MODULE_REMOTE等区分开.代码虽然不是很多, ...
- ss-libev 源码解析udp篇 (1)
shadowsocks-libev udp转发原理简介 ss_local作为一个sock5服务器,接收来自socks5客户端的数据包.在ss_local启动后,即创建一个udp socket,并bin ...
- jQuery2.x源码解析(缓存篇)
jQuery2.x源码解析(构建篇) jQuery2.x源码解析(设计篇) jQuery2.x源码解析(回调篇) jQuery2.x源码解析(缓存篇) 缓存是jQuery中的又一核心设计,jQuery ...
- jQuery2.x源码解析(构建篇)
jQuery2.x源码解析(构建篇) jQuery2.x源码解析(设计篇) jQuery2.x源码解析(回调篇) jQuery2.x源码解析(缓存篇) 笔者阅读了园友艾伦 Aaron的系列博客< ...
- jQuery2.x源码解析(设计篇)
jQuery2.x源码解析(构建篇) jQuery2.x源码解析(设计篇) jQuery2.x源码解析(回调篇) jQuery2.x源码解析(缓存篇) 这一篇笔者主要以设计的角度探索jQuery的源代 ...
- jQuery2.x源码解析(回调篇)
jQuery2.x源码解析(构建篇) jQuery2.x源码解析(设计篇) jQuery2.x源码解析(回调篇) jQuery2.x源码解析(缓存篇) 通过艾伦的博客,我们能看出,jQuery的pro ...
- Shiro源码解析-Session篇
上一篇Shiro源码解析-登录篇中提到了在登录验证成功后有对session的处理,但未详细分析,本文对此部分源码详细分析下. 1. 分析切入点:DefaultSecurityManger的login方 ...
- myBatis源码解析-类型转换篇(5)
前言 开始分析Type包前,说明下使用场景.数据构建语句使用PreparedStatement,需要输入的是jdbc类型,但我们一般写的是java类型.同理,数据库结果集返回的是jdbc类型,而我们需 ...
随机推荐
- Sqoop相关
# sqoop安装 1. 常规步骤(安装在一台节点上即可) 由于sqoop2配置相对比较麻烦,此次使用的是sqoop1进行演示. 上传sqoop-1.4.4.bin_hadoop-2.0.4-alph ...
- Redis中RedisTemplate和Redisson管道的使用
当对Redis进行高频次的命令发送时,由于网络IO的原因,会耗去大量的时间.所以Redis提供了管道技术,就是将命令一次性批量的发送给Redis,从而减少IO. 一.Jedis对redis的管道进行操 ...
- Mybatis中使用自定义的类型处理器处理枚举enum类型
知识点:在使用Mybatis的框架中,使用自定义的类型处理器处理枚举enum类型 应用:利用枚举类,处理字段有限,可以用状态码,代替的字段,本实例,给员工状态字段设置了一个枚举类 状态码,直接赋值给对 ...
- 【尺度不变性】An Analysis of Scale Invariance in Object Detection – SNIP 论文解读
前言 本来想按照惯例来一个overview的,结果看到1篇十分不错而且详细的介绍,因此copy过来,自己在前面大体总结一下论文,细节不做赘述,引用文章讲得很详细,另外这篇paper引用十分详细,如果做 ...
- 【目标检测】R-CNN系列与SPP-Net总结
目录 1. 前言 2. R-CNN 2.0 论文链接 2.1 概述 2.2 pre-training 2.3 不同阶段正负样本的IOU阈值 2.4 关于fine-tuning 2.5 对文章的一些思考 ...
- Mac与Widow下编译与运行java文件引入多个外部jar包
记录下,以后万一用得着呢 1.MAC环境下: 前提:在终端跳转到当前的源文件目录(cd xx), 并且配置好jdk,这里面不是重点 编译命令:注意连接用 : 号 javac -cp commons ...
- Openssl VS编译方法
工具: 1. 编译环境win10+vs2015专业版 2. ActivePerl工具,官网下载链接:http://www.activestate.com/activeperl/downloads 3. ...
- Vuex访问状态对象的方法
除了<Vuex最基本样例>中的方法外,还有两种方法访问状态对象state: 只需要改app.vue文件 方法一:引入computed <template> <div id ...
- SPSS 分布类型的检验
假设检验的标准步骤: 1.建立假设:根据问题的需要提出原假设H0,以及其对立面备择假设H1. 2.确立检验水准:即设立小概率事件的界值α. 3.进行试验:得到用于统计分析的样本,以该试验的结果作为假设 ...
- POJ3768 Katu Puzzle
本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...