├── .gitignore
├── README.md
├── tls-client.c
├── tls-client.service
├── tls-server.c
└── tls-server.service
/.gitignore:
--------------------------------------------------------------------------------
1 | *.o
2 | *.h
3 | tls-server
4 | tls-client
5 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # TLS-Proxy
2 | **本软件仅供内部学习交流,严禁用于任何商业用途,严禁违反国家相关法律法规,请于测试后 24 小时内删除,谢谢!**
3 |
4 | ## 简单介绍
5 | `tls-proxy` 可以看作为 V2Ray 的 `WebSocket + TLS + Web` 方案的 C 语言极简实现版,使用 `libevent2` 轻量级事件通知库编写。在硬件资源有限的环境中(如树莓派 3B,这也是我写 tls-proxy 的根本原因),tls-proxy 的资源占用更少,且代理速度比同等条件下的 v2ray 快的多(速度基本与 ss/ssr-libev 持平),同时又不降低安全性。
6 |
7 | `tls-proxy` 支持 TCP 和 UDP 协议的代理(与 v2ray 一样,UDP 流量使用 TCP 传输,尽可能减少特征),通信过程:
8 | **`source-socket <-> tls-client <-> web-server(eg: nginx) <-> tls-server <-> destination-socket`**
9 | `tls-client` 与 `web-server` 之间使用 HTTPS 协议(TLS1.2),`web-server` 与 `tls-server` 之间使用 websocket 协议。
10 |
11 | ## 版本历史
12 | **tls-proxy v1.0**
13 | 初始版本,TCP 和 UDP 都有问题(TCP 套接字处理不当,导致尾部数据丢失;UDP 实现过于简单粗暴,不支持 QUIC 协议),基本无法正常使用,所以此版本仅供娱乐。
14 |
15 | **tls-proxy v1.1**
16 | 当前版本,在 v1.0 的基础上修复了 TCP 缓冲区数据残留问题,修正了 UDP 的代理逻辑,支持 QUIC 等"有状态"的 UDP 上层协议(LRU Cache),暂未发现日常使用问题。
17 |
18 | ## 相关依赖
19 | **`tls-server`**:
20 | - [uthash](https://github.com/troydhanson/uthash)
21 | - [base64](https://github.com/aklomp/base64)
22 | - [libevent](https://github.com/libevent/libevent)
23 |
24 | **`tls-client`**:
25 | - [uthash](https://github.com/troydhanson/uthash)
26 | - [base64](https://github.com/aklomp/base64)
27 | - [openssl](https://github.com/openssl/openssl)
28 | - [libevent](https://github.com/libevent/libevent)
29 |
30 | ## 编译方法
31 | > 本地编译,以 linux x86_64 为例
32 |
33 | ```bash
34 | # uthash
35 | cd /tmp
36 | git clone https://github.com/troydhanson/uthash
37 |
38 | # base64
39 | cd /tmp
40 | git clone https://github.com/aklomp/base64
41 | cd base64
42 | make
43 |
44 | # openssl
45 | cd /tmp
46 | wget https://www.openssl.org/source/openssl-1.1.0i.tar.gz
47 | tar xvf openssl-1.1.0i.tar.gz
48 | cd openssl-1.1.0i
49 | ./Configure linux-x86_64 --prefix=/tmp/openssl --openssldir=/tmp/openssl no-shared # for linux x86_64
50 | make -j`nproc` && make install -j`nproc`
51 |
52 | # libevent
53 | cd /tmp
54 | git clone https://github.com/libevent/libevent libevent-sources
55 | cd libevent-sources
56 | ./autogen.sh
57 | ./configure --prefix=/tmp/libevent --enable-shared=no --enable-static=yes --disable-samples --disable-debug-mode --disable-malloc-replacement CPPFLAGS='-I/tmp/openssl/include' LDFLAGS='-L/tmp/openssl/lib' LIBS='-lssl -lcrypto -ldl'
58 | make && make install
59 |
60 | # tls-proxy
61 | cd /tmp
62 | git clone https://github.com/zfl9/tls-proxy
63 | cd tls-proxy
64 | gcc -I/tmp/uthash/include -I/tmp/base64/include -I/tmp/libevent/include -std=c11 -Wall -Wextra -Wno-format-overflow -O3 -s -pthread -o tls-server tls-server.c /tmp/base64/lib/libbase64.o /tmp/libevent/lib/libevent.a
65 | gcc -I/tmp/uthash/include -I/tmp/base64/include -I/tmp/libevent/include -I/tmp/openssl/include -std=c11 -Wall -Wextra -Wno-format-overflow -O3 -s -pthread -o tls-client tls-client.c /tmp/base64/lib/libbase64.o /tmp/libevent/lib/libevent.a /tmp/libevent/lib/libevent_openssl.a /tmp/openssl/lib/libssl.a /tmp/openssl/lib/libcrypto.a -ldl
66 | cp -af tls-client tls-server /usr/local/bin
67 |
68 | # delete files
69 | cd /
70 | rm -fr /tmp/uthash
71 | rm -fr /tmp/base64
72 | rm -fr /tmp/openssl*
73 | rm -fr /tmp/libevent*
74 | rm -fr /tmp/tls-proxy
75 | ```
76 |
77 | > 交叉编译,在 linux x86_64 上编译 linux aarch64 上用的 tls-proxy(RPi3B)
78 |
79 | ```bash
80 | # 交叉编译工具链的前缀
81 | ARCH='aarch64-linux-gnu'
82 |
83 | # uthash
84 | cd /tmp
85 | git clone https://github.com/troydhanson/uthash
86 |
87 | # base64
88 | cd /tmp
89 | git clone https://github.com/aklomp/base64
90 | cd base64
91 | make CC=$ARCH-gcc LD=$ARCH-ld OBJCOPY=$ARCH-objcopy
92 |
93 | # openssl
94 | cd /tmp
95 | wget https://www.openssl.org/source/openssl-1.1.0i.tar.gz
96 | tar xvf openssl-1.1.0i.tar.gz
97 | cd openssl-1.1.0i
98 | ./Configure linux-aarch64 --prefix=/tmp/openssl --openssldir=/tmp/openssl no-shared
99 | make CC=$ARCH-gcc RANLIB=$ARCH-ranlib -j`nproc` && make install -j`nproc`
100 |
101 | # libevent
102 | cd /tmp
103 | git clone https://github.com/libevent/libevent libevent-sources
104 | cd libevent-sources
105 | ./autogen.sh
106 | ./configure --host=$ARCH --prefix=/tmp/libevent --enable-shared=no --enable-static=yes --disable-samples --disable-debug-mode --disable-malloc-replacement CPPFLAGS='-I/tmp/openssl/include' LDFLAGS='-L/tmp/openssl/lib' LIBS='-lssl -lcrypto -ldl'
107 | make && make install
108 |
109 | # tls-proxy
110 | cd /tmp
111 | git clone https://github.com/zfl9/tls-proxy
112 | cd tls-proxy
113 | $ARCH-gcc -I/tmp/uthash/include -I/tmp/base64/include -I/tmp/libevent/include -std=c11 -Wall -Wextra -Wno-format-overflow -O3 -s -pthread -o tls-server tls-server.c /tmp/base64/lib/libbase64.o /tmp/libevent/lib/libevent.a
114 | $ARCH-gcc -I/tmp/uthash/include -I/tmp/base64/include -I/tmp/libevent/include -I/tmp/openssl/include -std=c11 -Wall -Wextra -Wno-format-overflow -O3 -s -pthread -o tls-client tls-client.c /tmp/base64/lib/libbase64.o /tmp/libevent/lib/libevent.a /tmp/libevent/lib/libevent_openssl.a /tmp/openssl/lib/libssl.a /tmp/openssl/lib/libcrypto.a -ldl
115 | ```
116 |
117 | > 交叉编译,在 linux x86_64 上编译 Android 8.1.0 (aarch64) 上用的 tls-proxy
118 |
119 | ```bash
120 | # 交叉编译工具链的前缀
121 | ARCH='aarch64-linux-android'
122 |
123 | # uthash
124 | cd /tmp
125 | git clone https://github.com/troydhanson/uthash
126 |
127 | # base64
128 | cd /tmp
129 | git clone https://github.com/aklomp/base64
130 | cd base64
131 | make CC=$ARCH-gcc LD=$ARCH-ld OBJCOPY=$ARCH-objcopy
132 |
133 | # openssl
134 | cd /tmp
135 | wget https://www.openssl.org/source/openssl-1.1.0i.tar.gz
136 | tar xvf openssl-1.1.0i.tar.gz
137 | cd openssl-1.1.0i
138 | ./Configure linux-aarch64 --prefix=/tmp/openssl --openssldir=/tmp/openssl no-shared
139 | make CC=$ARCH-gcc RANLIB=$ARCH-ranlib -j`nproc` && make install -j`nproc`
140 |
141 | # libevent
142 | cd /tmp
143 | git clone https://github.com/libevent/libevent libevent-sources
144 | cd libevent-sources
145 | ./autogen.sh
146 | ./configure --host=$ARCH --prefix=/tmp/libevent --enable-shared=no --enable-static=yes --disable-samples --disable-debug-mode --disable-malloc-replacement CPPFLAGS='-I/tmp/openssl/include' LDFLAGS='-L/tmp/openssl/lib' LIBS='-lssl -lcrypto -ldl'
147 | make && make install
148 |
149 | # tls-proxy
150 | cd /tmp
151 | git clone https://github.com/zfl9/tls-proxy
152 | cd tls-proxy
153 | $ARCH-gcc -I/tmp/uthash/include -I/tmp/base64/include -I/tmp/libevent/include -std=c11 -Wall -Wextra -Wno-format-overflow -O3 -s -pie -fPIE -pthread -o tls-server tls-server.c /tmp/base64/lib/libbase64.o /tmp/libevent/lib/libevent.a
154 | $ARCH-gcc -I/tmp/uthash/include -I/tmp/base64/include -I/tmp/libevent/include -I/tmp/openssl/include -std=c11 -Wall -Wextra -Wno-format-overflow -O3 -s -pie -fPIE -pthread -o tls-client tls-client.c /tmp/base64/lib/libbase64.o /tmp/libevent/lib/libevent.a /tmp/libevent/lib/libevent_openssl.a /tmp/openssl/lib/libssl.a /tmp/openssl/lib/libcrypto.a -ldl
155 | ```
156 |
157 | ## 使用方法
158 | > 如果你会使用 v2ray 的 websocket + tls + web 模式,那么 tls-proxy 对你来说很容易上手,因为使用方法基本一致。
159 |
160 | **前提条件**
161 | - 一个域名
162 | - 一个 SSL 证书
163 | - 一个 Web 服务器
164 |
165 | SSL 证书免费的有很多,如果你没有 SSL 证书,请先申请一张(不建议使用自签发的 SSL 证书,因为不会被 tls-client 所信任,除非你将自签发的根证书添加到 tls-client 主机的 CA 文件中);为什么需要一个域名?因为 tls-client 强制校验 SSL 证书对应的域名,如果 SSL 证书上的域名与指定的域名不一致,则会断开与 Web 服务器的连接;Web 服务器需要配置 HTTPS,以下的 Web 服务器均以 Nginx 为例,其它服务器请自行斟酌。
166 |
167 | **配置 Nginx**
168 |
169 | 1、修改 `/etc/nginx/nginx.conf`,在 `http` 配置段中添加如下配置(根据情况自行修改):
170 | ```nginx
171 | http {
172 | ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # 禁用 SSLv2、SSLv3
173 | ssl_dhparam /etc/nginx/ssl/dhparam.pem; # 指定 DH-param 文件
174 | ssl_session_cache shared:SSL:50m; # 启用 SSL 会话缓存,50 MB
175 | ssl_session_timeout 60m; # 设置 SSL 会话缓存超时时间,60 min
176 | ssl_session_tickets on; # 启用 SSL Session Ticket 会话恢复功能
177 | resolver 8.8.8.8; # 设置 DNS 域名解析服务器
178 | ssl_stapling on; # 启用 OCSP Stapling,优化 TLS 握手
179 | ssl_stapling_verify on; # 启用对 OCSP responses 响应结果的校验
180 | ssl_prefer_server_ciphers on; # 进行 TLS 握手时,优先选择服务器的加密套件
181 | ssl_ciphers "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA";
182 | add_header Strict-Transport-Security "max-age=63072000" always;
183 | add_header X-Frame-Options SAMEORIGIN;
184 | add_header X-Content-Type-Options nosniff;
185 | }
186 | ```
187 |
188 | 2、使用 openssl 生成 dhparam.pem 文件(`/etc/nginx/ssl/dhparam.pem`)
189 | ```bash
190 | # 需要执行很长时间,请不要中断它
191 | mkdir -p /etc/nginx/ssl
192 | cd /etc/nginx/ssl
193 | openssl dhparam -out dhparam.pem 4096
194 | ```
195 |
196 | 3、配置与 tls-server 相关的 vhost,根据实际情况修改
197 | ```nginx
198 | server {
199 | listen 80 reuseport fastopen=3 default_server;
200 | server_name www.example.com;
201 | return 301 https://www.example.com$request_uri;
202 | }
203 |
204 | server {
205 | listen 443 ssl reuseport fastopen=3 default_server;
206 | server_name www.example.com;
207 |
208 | root /srv/http/www.example.com;
209 | index index.html;
210 |
211 | ssl on;
212 | ssl_certificate "/etc/nginx/ssl/www.example.com.crt";
213 | ssl_certificate_key "/etc/nginx/ssl/www.example.com.key";
214 |
215 | location ~* \.(jpg|jpeg|png|gif|ico|(css|js)(\?v=.*)?)$ {
216 | expires 60d;
217 | }
218 |
219 | ## tls-proxy
220 | location /tls-proxy {
221 | if ($http_some_header != 'some_header_value') {
222 | return 404;
223 | }
224 | proxy_http_version 1.1;
225 | proxy_read_timeout 3650d;
226 | proxy_send_timeout 3650d;
227 | proxy_connect_timeout 3s;
228 | proxy_pass http://127.0.0.1:60080;
229 | proxy_set_header Connection "Upgrade";
230 | proxy_set_header Upgrade $http_upgrade;
231 | }
232 | }
233 | ```
234 | `/tls-proxy` 可以改为你喜欢的任意 URI;`tls-server` 默认监听地址为 `127.0.0.1:60080/tcp`;说明一下 `$http_some_header` 语句的作用:即使别人知道你的 URI,如果它没有设置正确的 HTTP 头部(在这里就是 `Some-Header` 咯,去掉开头的 `http_`,下划线换成连字符,大小写不敏感),并且对应的头部的值不是 `some_header_value`(这就相当于你的密码了,请任意发挥),那么还是白搭,Nginx 会返回 404 Not Found 给它(这种情况也适合于 GFW 的主动探测)。
235 |
236 | 在上面的配置中,我们的自定义头部(为叙述方便,以下将自定义头部称为 **认证头部**、**密码头部**)只有一个 value(可以理解为只有一个密码),实际上我们可以为密码头部设置多个密码(即多个 value),假设我们的密码头部仍然为 `Some-Header`,现在我们需要为 tls-proxy 设置两个访问密码,一个是 `some_header_value_a`、一个是 `some_header_value_b`,则将上面的 `location /tls-proxy` 配置块改为:
237 |
238 | ```nginx
239 | location /tls-proxy {
240 | set $verified 0;
241 | if ($http_some_header = 'some_header_value_a') {
242 | set $verified 1;
243 | }
244 | if ($http_some_header = 'some_header_value_b') {
245 | set $verified 1;
246 | }
247 | if ($verified != 1) {
248 | return 404;
249 | }
250 | proxy_http_version 1.1;
251 | proxy_read_timeout 3650d;
252 | proxy_send_timeout 3650d;
253 | proxy_connect_timeout 3s;
254 | proxy_pass http://127.0.0.1:60080;
255 | proxy_set_header Connection "Upgrade";
256 | proxy_set_header Upgrade $http_upgrade;
257 | }
258 | ```
259 |
260 | 依此类推,如果想要设置三个访问密码,再添加一个类似的 `if ($http_some_header = 'some_header_value_c')` 语句即可。
261 |
262 | 4、使用 `nginx -t` 检查配置文件是否有语法错误,然后 `systemctl reload nginx.service` 使其生效。
263 |
264 | **配置 tls-server**
265 |
266 | 将 `tls-proxy` 目录下的 `tls-server.service` systemd 服务文件拷贝到 `/etc/systemd/system/` 目录下,然后执行 `systemctl daemon-reload` 使其生效。`tls-server` 默认只启用一个工作线程(`-j` 参数),而在 `tls-server.service` 服务文件中,默认设置的是 `-j2`,也就是两个工作线程,一般推荐使用 `1 ~ 4` 个工作线程,再多也没啥用,浪费资源。如果需要修改线程数,请编辑 `/etc/systemd/system/tls-server.service` 服务文件,将 `-j2` 改为 `-jN`(N 为你想设置的线程数),注意,修改 service 文件之后需要执行 `systemctl daemon-reload` 生效。最后,执行 `systemctl start tls-server.service` 来启动 tls-server。
267 |
268 | **配置 tls-client**
269 |
270 | 将 `tls-proxy` 目录下的 `tls-client.service` systemd 服务文件拷贝到 `/etc/systemd/system/` 目录下,然后使用文本编辑器打开 `/etc/systemd/system/tls-client.service` 文件,主要需要修改 tls-client 的命令行参数,目前 tls-client 的命令行参数有:
271 | ```bash
272 | $ tls-client -h
273 | usage: tls-client . OPTIONS have these:
274 | -s server host. can't use IP address
275 | -p server port. the default port is 443
276 | -c CA file location. eg: /etc/ssl/cert.pem
277 | -P websocket request line uri. eg: /tls-proxy
278 | -H websocket request headers. allow multi line
279 | -b tcp & udp listen address. default: 127.0.0.1
280 | -t tcp port (iptables xt_tproxy). default: 60080
281 | -u udp port (iptables xt_tproxy). default: 60080
282 | -j number of worker thread (for tcp). default: 1
283 | -T disable tcp transparent proxy
284 | -U disable udp transparent proxy
285 | -v show version and exit
286 | -h show help and exit
287 | ```
288 | 其中必须要指定的参数有:`-s` 指定服务器的域名、`-c` 指定本机 CA 文件路径、`-P` 指定请求的 URI。因为我们在 Nginx 中配置了自定义头部 `Some-Header: some_header_value\r\n`,所以还需要指定一个 `-H` 参数,注意,此参数指定的 HTTP 头部必须以 `\r\n` 结尾,且必须放在 `$''` 里面(否则不会进行转义),即 `-H $'Some-Header: some_header_value\r\n'`,`-H` 参数中允许设置多个自定义头部(HTTP 协议使用 `\r\n` 作为行结束符)。如果头部设置不正确,则 `tls-client` 会因为收到 `404 Not Found` 响应而提示 `bad response`。tls-client 和 tls-server 一样,默认都是启用一个工作线程,所以如果你需要启用多个线程,请指定 `-j` 参数(不要奇怪 tls-client 的 UDP 监听线程为什么只有一个,因为我需要在内部保持 UDP 的状态,所以必须只能有一个 UDP 套接字,也就是说,tls-client 的 -j 参数只针对 TCP 代理套接字)。
289 |
290 | 关于 tls-client 的 `-c ` 参数:前面说了,tls-client 会对 SSL 证书进行校验,确认 SSL 证书是否可信,所以 tls-client 需要知道本机的 CA 文件路径(每个发行版的 CA file 文件路径都不太相同,ArchLinux 中是 `/etc/ssl/cert.pem`)。为什么不取消证书验证这个步骤?原因不用我说吧,一切都是为了安全啊。如果你不知道当前系统的 CA 文件路径,请在 Bash 中执行 `curl -v https://www.baidu.com |& awk '/CAfile:/ {print $3}'` 命令,输出的字符串即为本机的 CA 文件路径(别跟我说 curl command not found,要么装 curl,要么自己找 CA file 去)。
291 |
292 | 最后,执行 `systemctl daemon-reload` 重载服务文件,然后执行 `systemctl start tls-client.service` 启动 tls-client。
293 |
294 | **配置 iptables 规则**
295 |
296 | `tls-client` 默认监听地址:`127.0.0.1:60080/tcp`、`127.0.0.1:60080/udp`;TCP 和 UDP 的透明代理都必须使用 iptables-TPROXY 方式(注意不是 iptables-REDIRECT);这里给个简单的 bash 脚本,示例如何使用 iptables-TPROXY 来透明代理本机以及内网的 TCP 和 UDP 流量(没错,tls-client 一般用在 Linux 网关上,提供全局透明代理,当然也可以在普通 Linux 主机上使用,代理本机的 TCP 和 UDP)。注意,此脚本只是作为一个例子,实际上我们还需要配置分流规则(如 gfwlist、chnroute),如果你需要分流的话,请使用 [ss-tproxy](https://github.com/zfl9/ss-tproxy) 代理脚本。
297 |
298 | ```bash
299 | #!/bin/bash
300 |
301 | server='www.example.com' # 服务器的域名
302 | intranet_nic='lan0' # 本机内网网卡
303 | extranet_nic='wan0' # 本机外网网卡
304 |
305 | function start {
306 | systemctl start tls-client.service
307 |
308 | iptables -t mangle -N SETMARK
309 | iptables -t mangle -A SETMARK -d 0/8 -j RETURN
310 | iptables -t mangle -A SETMARK -d 10/8 -j RETURN
311 | iptables -t mangle -A SETMARK -d 127/8 -j RETURN
312 | iptables -t mangle -A SETMARK -d 169.254/16 -j RETURN
313 | iptables -t mangle -A SETMARK -d 172.16/12 -j RETURN
314 | iptables -t mangle -A SETMARK -d 192.168/16 -j RETURN
315 | iptables -t mangle -A SETMARK -d 224/4 -j RETURN
316 | iptables -t mangle -A SETMARK -d 240/4 -j RETURN
317 | iptables -t mangle -A SETMARK -d $server -j RETURN
318 | iptables -t mangle -A SETMARK -j MARK --set-mark 0x2333
319 |
320 | iptables -t mangle -A OUTPUT -o $extranet_nic -p tcp -j SETMARK
321 | iptables -t mangle -A OUTPUT -o $extranet_nic -p udp -j SETMARK
322 |
323 | iptables -t mangle -A PREROUTING -i $intranet_nic -p tcp -j SETMARK
324 | iptables -t mangle -A PREROUTING -i $intranet_nic -p udp -j SETMARK
325 |
326 | iptables -t mangle -A PREROUTING -m mark --mark 0x2333 -p tcp -j TPROXY --on-ip 127.0.0.1 --on-port 60080
327 | iptables -t mangle -A PREROUTING -m mark --mark 0x2333 -p udp -j TPROXY --on-ip 127.0.0.1 --on-port 60080
328 |
329 | ip route add local 0/0 dev lo table 100
330 | ip rule add fwmark 0x2333 table 100
331 | }
332 |
333 | function stop {
334 | ip rule del table 100 &>/dev/null
335 | ip route flush table 100 &>/dev/null
336 |
337 | iptables -t mangle -F
338 | iptables -t mangle -X
339 |
340 | systemctl stop tls-client.service
341 | }
342 |
343 | case $1 in
344 | start) start;;
345 | stop) stop;;
346 | *) echo "usage: $(basename $0) start|stop"; exit 1;;
347 | esac
348 | ```
349 |
350 | 本机的 DNS 需要修改为 `8.8.8.8`、`8.8.4.4` 等国外 DNS 服务器(`/etc/resolv.conf`),然后 `curl ip.cn` 测试吧。
351 |
352 | **查看 tls-proxy 的日志**
353 | - `tls-client`:执行命令 `journalctl -afu tls-client.service`
354 | - `tls-server`:执行命令 `journalctl -afu tls-server.service`
355 |
--------------------------------------------------------------------------------
/tls-client.c:
--------------------------------------------------------------------------------
1 | #define _GNU_SOURCE
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 | #include
18 | #include
19 | #include
20 | #include
21 | #include
22 | #include
23 | #include
24 | #include
25 | #include "libbase64.h"
26 | #include "uthash.h"
27 |
28 | #define PRINT_COMMAND_HELP \
29 | printf("usage: tls-client . OPTIONS have these:\n"\
30 | " -s server host. can't use IP address\n"\
31 | " -p server port. the default port is 443\n"\
32 | " -c CA file location. eg: /etc/ssl/cert.pem\n"\
33 | " -P websocket request line uri. eg: /tls-proxy\n"\
34 | " -H websocket request headers. allow multi line\n"\
35 | " -b tcp & udp listen address. default: 127.0.0.1\n"\
36 | " -t tcp port (iptables xt_tproxy). default: 60080\n"\
37 | " -u udp port (iptables xt_tproxy). default: 60080\n"\
38 | " -j number of worker thread (for tcp). default: 1\n"\
39 | " -T disable tcp transparent proxy\n"\
40 | " -U disable udp transparent proxy\n"\
41 | " -v show version and exit\n"\
42 | " -h show help and exit\n")
43 |
44 | #define TCP_TYPE_GEN 1
45 | #define TCP_TYPE_SSL 2
46 | #define UDP_HASH_PRE 10
47 | #define UDP_HASH_LEN 500
48 | #define UDP_RAW_BUFSIZ 1472
49 | #define UDP_ENC_BUFSIZ 1960
50 | #define BUFSIZ_FOR_BEV 65536
51 | #define WEBSOCKET_STATUS_LINE "HTTP/1.1 101 Switching Protocols"
52 | #define SSL_CIPHERS "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-CHACHA20-POLY1305"
53 |
54 | void *service(void *arg);
55 |
56 | void tcp_read_cb(struct bufferevent *bev, void *arg);
57 | void tcp_write_cb(struct bufferevent *bev, void *arg);
58 | void tcp_events_cb(struct bufferevent *bev, short events, void *arg);
59 | void tcp_timeout_cb(int sock, short events, void *arg);
60 | void tcp_recvres_cb(struct bufferevent *bev, void *arg);
61 | void tcp_newconn_cb(struct evconnlistener *listener, int sock, struct sockaddr *addr, int addrlen, void *arg);
62 |
63 | void udp_sendreq_cb(struct bufferevent *bev, short events, void *arg);
64 | void udp_recvres_cb(struct bufferevent *bev, void *arg);
65 | void udp_timeout_cb(int sock, short events, void *arg);
66 | void udp_release_cb(int sock, short events, void *arg);
67 | void udp_request_cb(int sock, short events, void *arg);
68 | void udp_response_cb(struct bufferevent *bev, void *arg);
69 |
70 | typedef struct {
71 | struct event *ev;
72 | struct bufferevent *bev;
73 | char type;
74 | } EVArg;
75 |
76 | typedef struct {
77 | char addr[16];
78 | char port[6];
79 | struct bufferevent *bev;
80 | char type;
81 | } TCPArg;
82 |
83 | typedef struct {
84 | char addr[22];
85 | int port;
86 | struct event *ev;
87 | UT_hash_handle hh;
88 | } UDPNode;
89 |
90 | /* UDP Proxy 全局数据 */
91 | static void *udprbuff = NULL;
92 | static char *udpebuff = NULL;
93 | static int udplsock = -1;
94 | static struct event *udplev = NULL;
95 | static struct event *udptev = NULL;
96 | static struct bufferevent *udpbev = NULL;
97 | static UDPNode *udphash = NULL;
98 | static struct event_base *udpbase = NULL;
99 | static char udpcntl[64] = {0};
100 |
101 | void udpnode_put(char *addr, int port) {
102 | UDPNode *node = NULL;
103 | HASH_FIND_STR(udphash, addr, node);
104 | if (node == NULL) {
105 | node = calloc(1, sizeof(UDPNode));
106 | strcpy(node->addr, addr);
107 | node->port = port;
108 | node->ev = event_new(udpbase, -1, EV_TIMEOUT, udp_timeout_cb, node->addr);
109 | struct timeval tv = {180, 0};
110 | event_add(node->ev, &tv);
111 | HASH_ADD_STR(udphash, addr, node);
112 | if (HASH_COUNT(udphash) > UDP_HASH_LEN) {
113 | int cnt = 0;
114 | UDPNode *node = NULL, *temp = NULL;
115 | HASH_ITER(hh, udphash, node, temp) {
116 | HASH_DEL(udphash, node);
117 | event_free(node->ev);
118 | free(node);
119 | if (++cnt == UDP_HASH_PRE) return;
120 | }
121 | }
122 | } else {
123 | node->port = port;
124 | struct timeval tv = {180, 0};
125 | event_add(node->ev, &tv);
126 | HASH_DEL(udphash, node);
127 | HASH_ADD_STR(udphash, addr, node);
128 | }
129 | }
130 |
131 | UDPNode *udpnode_get(char *addr) {
132 | UDPNode *node = NULL;
133 | HASH_FIND_STR(udphash, addr, node);
134 | if (node == NULL) return node;
135 | struct timeval tv = {180, 0};
136 | event_add(node->ev, &tv);
137 | HASH_DEL(udphash, node);
138 | HASH_ADD_STR(udphash, addr, node);
139 | return node;
140 | }
141 |
142 | int udpnode_getport(char *addr) {
143 | UDPNode *node = udpnode_get(addr);
144 | return (node == NULL) ? 0 : (node->port);
145 | }
146 |
147 | void udpnode_del(char *addr) {
148 | UDPNode *node = NULL;
149 | HASH_FIND_STR(udphash, addr, node);
150 | if (node == NULL) return;
151 | HASH_DEL(udphash, node);
152 | event_free(node->ev);
153 | free(node);
154 | }
155 |
156 | void udpnode_clear() {
157 | UDPNode *node = NULL, *temp = NULL;
158 | HASH_ITER(hh, udphash, node, temp) {
159 | HASH_DEL(udphash, node);
160 | event_free(node->ev);
161 | free(node);
162 | }
163 | }
164 |
165 | /* 线程共享的全局数据 */
166 | static char *servhost = NULL;
167 | static int servport = 443;
168 | static struct sockaddr_in servaddr = {0};
169 | static char *cafile = NULL;
170 | static char servreq[256] = {0};
171 | static struct sockaddr_in tcpladdr = {0};
172 | static struct sockaddr_in udpladdr = {0};
173 |
174 | /* 线程私有的全局数据 */
175 | typedef struct {
176 | pthread_t tid;
177 | SSL_CTX *ctx;
178 | SSL_SESSION *sess;
179 | } THREAD_DATA;
180 |
181 | static int thread_nums = 1;
182 | static THREAD_DATA *thread_datas = NULL;
183 |
184 | /* 获取当前线程的 SSL_CTX */
185 | SSL_CTX *get_ssl_ctx() {
186 | pthread_t tid = pthread_self();
187 | for (int i = 0; i < thread_nums; ++i) {
188 | if (thread_datas[i].tid == tid) {
189 | return thread_datas[i].ctx;
190 | }
191 | }
192 | return NULL;
193 | }
194 | /* 设置当前线程的 SSL_CTX */
195 | void set_ssl_ctx(SSL_CTX *ctx) {
196 | pthread_t tid = pthread_self();
197 | for (int i = 0; i < thread_nums; ++i) {
198 | if (thread_datas[i].tid == tid) {
199 | thread_datas[i].ctx = ctx;
200 | return;
201 | }
202 | }
203 | }
204 |
205 | /* 获取当前线程的 SSL_SESSION */
206 | SSL_SESSION *get_ssl_sess() {
207 | pthread_t tid = pthread_self();
208 | for (int i = 0; i < thread_nums; ++i) {
209 | if (thread_datas[i].tid == tid) {
210 | return thread_datas[i].sess;
211 | }
212 | }
213 | return NULL;
214 | }
215 | /* 设置当前线程的 SSL_SESSION */
216 | void set_ssl_sess(SSL_SESSION *sess) {
217 | pthread_t tid = pthread_self();
218 | for (int i = 0; i < thread_nums; ++i) {
219 | if (thread_datas[i].tid == tid) {
220 | thread_datas[i].sess = sess;
221 | return;
222 | }
223 | }
224 | }
225 |
226 | // sizeof(str) = 36
227 | char *loginf(char *str) {
228 | time_t rawtime;
229 | time(&rawtime);
230 | struct tm curtm;
231 | localtime_r(&rawtime, &curtm);
232 | sprintf(str, "\e[1;32m%04d-%02d-%02d %02d:%02d:%02d INF:\e[0m",
233 | curtm.tm_year + 1900, curtm.tm_mon + 1, curtm.tm_mday,
234 | curtm.tm_hour, curtm.tm_min, curtm.tm_sec);
235 | return str;
236 | }
237 |
238 | // sizeof(str) = 36
239 | char *logerr(char *str) {
240 | time_t rawtime;
241 | time(&rawtime);
242 | struct tm curtm;
243 | localtime_r(&rawtime, &curtm);
244 | sprintf(str, "\e[1;35m%04d-%02d-%02d %02d:%02d:%02d ERR:\e[0m",
245 | curtm.tm_year + 1900, curtm.tm_mon + 1, curtm.tm_mday,
246 | curtm.tm_hour, curtm.tm_min, curtm.tm_sec);
247 | return str;
248 | }
249 |
250 | void setsockopt_tcp(int sock) {
251 | char ctime[36] = {0};
252 | char error[64] = {0};
253 |
254 | int optval = 1;
255 | if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &optval, sizeof(optval)) == -1) {
256 | printf("%s [tcp] setsockopt(TCP_NODELAY) for %d: (%d) %s\n", logerr(ctime), sock, errno, strerror_r(errno, error, 64));
257 | }
258 |
259 | if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) == -1) {
260 | printf("%s [tcp] setsockopt(SO_REUSEADDR) for %d: (%d) %s\n", logerr(ctime), sock, errno, strerror_r(errno, error, 64));
261 | }
262 |
263 | if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(optval)) == -1) {
264 | printf("%s [tcp] setsockopt(SO_KEEPALIVE) for %d: (%d) %s\n", logerr(ctime), sock, errno, strerror_r(errno, error, 64));
265 | }
266 |
267 | optval = 15;
268 | if (setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, &optval, sizeof(optval)) == -1) {
269 | printf("%s [tcp] setsockopt(TCP_KEEPIDLE) for %d: (%d) %s\n", logerr(ctime), sock, errno, strerror_r(errno, error, 64));
270 | }
271 |
272 | if (setsockopt(sock, IPPROTO_TCP, TCP_KEEPINTVL, &optval, sizeof(optval)) == -1) {
273 | printf("%s [tcp] setsockopt(TCP_KEEPINTVL) for %d: (%d) %s\n", logerr(ctime), sock, errno, strerror_r(errno, error, 64));
274 | }
275 |
276 | optval = 2;
277 | if (setsockopt(sock, IPPROTO_TCP, TCP_KEEPCNT, &optval, sizeof(optval)) == -1) {
278 | printf("%s [tcp] setsockopt(TCP_KEEPCNT) for %d: (%d) %s\n", logerr(ctime), sock, errno, strerror_r(errno, error, 64));
279 | }
280 | }
281 |
282 | int main(int argc, char *argv[]) {
283 | signal(SIGPIPE, SIG_IGN);
284 | setvbuf(stdout, NULL, _IONBF, 0);
285 |
286 | char *requri = NULL;
287 | char *reqext = NULL;
288 | char *listen = "127.0.0.1";
289 | int tcport = 60080;
290 | int udport = 60080;
291 |
292 | opterr = 0;
293 | char *optstr = "s:p:c:P:H:b:t:u:j:TUvh";
294 | int opt = -1;
295 | while ((opt = getopt(argc, argv, optstr)) != -1) {
296 | switch (opt) {
297 | case 'v':
298 | printf("tls-client v1.1\n");
299 | return 0;
300 | case 'h':
301 | PRINT_COMMAND_HELP;
302 | return 0;
303 | case 'T':
304 | tcport = 0;
305 | break;
306 | case 'U':
307 | udport = 0;
308 | break;
309 | case 's':
310 | servhost = optarg;
311 | break;
312 | case 'p':
313 | servport = strtol(optarg, NULL, 10);
314 | if (servport <= 0 || servport > 65535) {
315 | printf("invalid server port: %d\n", servport);
316 | PRINT_COMMAND_HELP;
317 | return 1;
318 | }
319 | break;
320 | case 'c':
321 | cafile = optarg;
322 | if (access(cafile, F_OK) == -1) {
323 | printf("CA file can't access: %s\n", cafile);
324 | PRINT_COMMAND_HELP;
325 | return 1;
326 | }
327 | break;
328 | case 'P':
329 | requri = optarg;
330 | break;
331 | case 'H':
332 | reqext = optarg;
333 | break;
334 | case 'b':
335 | listen = optarg;
336 | break;
337 | case 't':
338 | tcport = strtol(optarg, NULL, 10);
339 | if (tcport <= 0 || tcport > 65535) {
340 | printf("invalid tcp port: %d\n", tcport);
341 | PRINT_COMMAND_HELP;
342 | return 1;
343 | }
344 | break;
345 | case 'u':
346 | udport = strtol(optarg, NULL, 10);
347 | if (udport <= 0 || udport > 65535) {
348 | printf("invalid udp port: %d\n", udport);
349 | PRINT_COMMAND_HELP;
350 | return 1;
351 | }
352 | break;
353 | case 'j':
354 | thread_nums = strtol(optarg, NULL, 10);
355 | if (thread_nums < 1) {
356 | printf("invalid thread nums: %d\n", thread_nums);
357 | PRINT_COMMAND_HELP;
358 | return 1;
359 | }
360 | break;
361 | case '?':
362 | if (strchr(optstr, optopt) == NULL) {
363 | printf("unknown option '-%c'\n", optopt);
364 | PRINT_COMMAND_HELP;
365 | return 1;
366 | } else {
367 | printf("missing optval '-%c'\n", optopt);
368 | PRINT_COMMAND_HELP;
369 | return 1;
370 | }
371 | }
372 | }
373 |
374 | if (tcport == 0 && udport == 0) {
375 | printf("nothing to do (-TU)\n");
376 | return 0;
377 | }
378 | if (servhost == NULL) {
379 | printf("missing option '-s'\n");
380 | PRINT_COMMAND_HELP;
381 | return 1;
382 | }
383 | if (cafile == NULL) {
384 | printf("missing option '-c'\n");
385 | PRINT_COMMAND_HELP;
386 | return 1;
387 | }
388 | if (requri == NULL) {
389 | printf("missing option '-P'\n");
390 | PRINT_COMMAND_HELP;
391 | return 1;
392 | }
393 |
394 | strcpy(servreq + strlen(servreq), "GET ");
395 | strcpy(servreq + strlen(servreq), requri);
396 | strcpy(servreq + strlen(servreq), " HTTP/1.1\r\n");
397 | strcpy(servreq + strlen(servreq), "Host: ");
398 | strcpy(servreq + strlen(servreq), servhost);
399 | strcpy(servreq + strlen(servreq), "\r\n");
400 | strcpy(servreq + strlen(servreq), "Upgrade: websocket\r\n");
401 | strcpy(servreq + strlen(servreq), "Connection: Upgrade\r\n");
402 | if (reqext != NULL) {
403 | strcpy(servreq + strlen(servreq), reqext); // must end with '\r\n'
404 | }
405 |
406 | SSL_library_init();
407 | SSL_load_error_strings();
408 |
409 | struct hostent *ent = gethostbyname(servhost);
410 | if (ent == NULL) {
411 | printf("can't resolve host %s: (%d) %s\n", servhost, errno, strerror(errno));
412 | return errno;
413 | }
414 | servaddr.sin_family = AF_INET;
415 | memcpy(&servaddr.sin_addr, ent->h_addr_list[0], ent->h_length);
416 | servaddr.sin_port = htons(servport);
417 |
418 | if (tcport != 0) {
419 | tcpladdr.sin_family = AF_INET;
420 | tcpladdr.sin_addr.s_addr = inet_addr(listen);
421 | tcpladdr.sin_port = htons(tcport);
422 | }
423 |
424 | if (udport != 0) {
425 | udpladdr.sin_family = AF_INET;
426 | udpladdr.sin_addr.s_addr = inet_addr(listen);
427 | udpladdr.sin_port = htons(udport);
428 |
429 | udprbuff = calloc(1, UDP_RAW_BUFSIZ);
430 | udpebuff = calloc(1, UDP_ENC_BUFSIZ);
431 | }
432 |
433 | char ctime[36] = {0};
434 | printf("%s [srv] thread nums: %d\n", loginf(ctime), thread_nums);
435 | printf("%s [srv] server host: %s\n", loginf(ctime), servhost);
436 | printf("%s [srv] server addr: %s:%d\n", loginf(ctime), inet_ntoa(servaddr.sin_addr), servport);
437 | if (tcport != 0) printf("%s [srv] tcp address: %s:%d\n", loginf(ctime), listen, tcport);
438 | if (udport != 0) printf("%s [srv] udp address: %s:%d\n", loginf(ctime), listen, udport);
439 |
440 | thread_datas = calloc(thread_nums, sizeof(THREAD_DATA));
441 | thread_datas[0].tid = pthread_self();
442 | if (tcport != 0) {
443 | for (int i = 1; i < thread_nums; ++i) {
444 | if (pthread_create(&thread_datas[i].tid, NULL, service, NULL) != 0) {
445 | printf("%s [srv] create thread: (%d) %s\n", logerr(ctime), errno, strerror(errno));
446 | return errno;
447 | }
448 | }
449 | if (udport == 0) service(NULL); // tcponly
450 | if (udport != 0) service((void *)1); // tcp&udp
451 | } else {
452 | service((void *)2); // udponly
453 | }
454 |
455 | if (tcport != 0) {
456 | for (int i = 1; i < thread_nums; ++i) {
457 | pthread_join(thread_datas[i].tid, NULL);
458 | }
459 | }
460 |
461 | if (udport != 0) {
462 | free(udprbuff);
463 | free(udpebuff);
464 | }
465 |
466 | free(thread_datas);
467 | ERR_free_strings();
468 | EVP_cleanup();
469 |
470 | return 0;
471 | }
472 |
473 | // arg = 0 -> tcponly
474 | // arg = 1 -> tcp&udp
475 | // arg = 2 -> udponly
476 | void *service(void *arg) {
477 | char ctime[36] = {0};
478 | char error[64] = {0};
479 |
480 | SSL_CTX *ctx = SSL_CTX_new(TLS_client_method());
481 | SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
482 | SSL_CTX_set_verify_depth(ctx, 4);
483 | SSL_CTX_load_verify_locations(ctx, cafile, NULL);
484 | SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_COMPRESSION);
485 | SSL_CTX_set_cipher_list(ctx, SSL_CIPHERS);
486 | set_ssl_ctx(ctx);
487 |
488 | struct event_config *cfg = event_config_new();
489 | event_config_set_flag(cfg, EVENT_BASE_FLAG_NOLOCK | EVENT_BASE_FLAG_IGNORE_ENV);
490 | struct event_base *base = event_base_new_with_config(cfg);
491 | event_config_free(cfg);
492 | if (arg != NULL) udpbase = base;
493 |
494 | int optval = 1;
495 | struct evconnlistener *tcplistener = NULL;
496 |
497 | if (arg != (void *)2) {
498 | tcplistener = evconnlistener_new_bind(
499 | base, tcp_newconn_cb, NULL,
500 | LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE | LEV_OPT_REUSEABLE_PORT,
501 | SOMAXCONN, (struct sockaddr *)&tcpladdr, sizeof(struct sockaddr_in)
502 | );
503 |
504 | if (tcplistener == NULL) {
505 | printf("%s [tcp] listen socket: (%d) %s\n", logerr(ctime), errno, strerror_r(errno, error, 64));
506 | exit(errno);
507 | }
508 |
509 | if (setsockopt(evconnlistener_get_fd(tcplistener), SOL_IP, IP_TRANSPARENT, &optval, sizeof(optval)) == -1) {
510 | printf("%s [tcp] setsockopt(IP_TRANSPARENT) for %d: (%d) %s\n", logerr(ctime), evconnlistener_get_fd(tcplistener), errno, strerror_r(errno, error, 64));
511 | exit(errno);
512 | }
513 | }
514 |
515 | if (arg != NULL) {
516 | udplsock = socket(AF_INET, SOCK_DGRAM, 0);
517 | evutil_make_socket_nonblocking(udplsock);
518 |
519 | if (setsockopt(udplsock, SOL_IP, IP_TRANSPARENT, &optval, sizeof(optval)) == -1) {
520 | printf("%s [udp] setsockopt(IP_TRANSPARENT) for %d: (%d) %s\n", logerr(ctime), udplsock, errno, strerror_r(errno, error, 64));
521 | exit(errno);
522 | }
523 | if (setsockopt(udplsock, IPPROTO_IP, IP_RECVORIGDSTADDR, &optval, sizeof(optval)) == -1) {
524 | printf("%s [udp] setsockopt(IP_RECVORIGDSTADDR) for %d: (%d) %s\n", logerr(ctime), udplsock, errno, strerror_r(errno, error, 64));
525 | exit(errno);
526 | }
527 |
528 | if (bind(udplsock, (struct sockaddr *)&udpladdr, sizeof(udpladdr)) == -1) {
529 | printf("%s [udp] bind socket: (%d) %s\n", logerr(ctime), errno, strerror_r(errno, error, 64));
530 | exit(errno);
531 | }
532 |
533 | udptev = event_new(base, -1, EV_TIMEOUT, udp_release_cb, NULL);
534 | udplev = event_new(base, udplsock, EV_READ | EV_PERSIST, udp_request_cb, NULL);
535 |
536 | SSL *ssl = SSL_new(ctx);
537 | SSL_set_tlsext_host_name(ssl, servhost);
538 | X509_VERIFY_PARAM_set1_host(SSL_get0_param(ssl), servhost, 0);
539 | if (get_ssl_sess() != NULL) SSL_set_session(ssl, get_ssl_sess());
540 |
541 | udpbev = bufferevent_openssl_socket_new(base, -1, ssl, BUFFEREVENT_SSL_CONNECTING, BEV_OPT_CLOSE_ON_FREE);
542 | bufferevent_setcb(udpbev, NULL, NULL, udp_sendreq_cb, NULL);
543 | bufferevent_enable(udpbev, EV_READ | EV_WRITE);
544 | bufferevent_setwatermark(udpbev, EV_READ, 0, BUFSIZ_FOR_BEV);
545 | printf("%s [udp] connecting to %s:%d\n", loginf(ctime), servhost, servport);
546 | bufferevent_socket_connect(udpbev, (struct sockaddr *)&servaddr, sizeof(servaddr));
547 | setsockopt_tcp(bufferevent_getfd(udpbev));
548 | }
549 |
550 | event_base_dispatch(base);
551 |
552 | if (arg != NULL) {
553 | udpnode_clear();
554 | close(udplsock);
555 | event_free(udplev);
556 | event_free(udptev);
557 | bufferevent_free(udpbev);
558 | }
559 |
560 | if (arg != (void *)2) {
561 | evconnlistener_free(tcplistener);
562 | }
563 |
564 | event_base_free(base);
565 | libevent_global_shutdown();
566 |
567 | if (get_ssl_sess() != NULL) SSL_SESSION_free(get_ssl_sess());
568 | SSL_CTX_free(ctx);
569 |
570 | return NULL;
571 | }
572 |
573 | void tcp_newconn_cb(struct evconnlistener *listener, int sock, struct sockaddr *addr, int addrlen, void *arg) {
574 | (void) listener; (void) sock; (void) addr; (void) addrlen; (void) arg;
575 |
576 | char ctime[36] = {0};
577 | setsockopt_tcp(sock);
578 |
579 | struct sockaddr_in *clntaddr = (struct sockaddr_in *)addr;
580 | printf("%s [tcp] new connect: %s:%d\n", loginf(ctime), inet_ntoa(clntaddr->sin_addr), ntohs(clntaddr->sin_port));
581 |
582 | struct sockaddr_in destaddr = {0};
583 | getsockname(sock, (struct sockaddr *)&destaddr, (socklen_t *)&addrlen);
584 | printf("%s [tcp] dest address: %s:%d\n", loginf(ctime), inet_ntoa(destaddr.sin_addr), ntohs(destaddr.sin_port));
585 |
586 | SSL *ssl = SSL_new(get_ssl_ctx());
587 | SSL_set_tlsext_host_name(ssl, servhost);
588 | X509_VERIFY_PARAM_set1_host(SSL_get0_param(ssl), servhost, 0);
589 | if (get_ssl_sess() != NULL) SSL_set_session(ssl, get_ssl_sess());
590 |
591 | struct bufferevent *clntbev = bufferevent_socket_new(evconnlistener_get_base(listener), sock, BEV_OPT_CLOSE_ON_FREE);
592 | struct bufferevent *destbev = bufferevent_openssl_socket_new(evconnlistener_get_base(listener), -1, ssl, BUFFEREVENT_SSL_CONNECTING, BEV_OPT_CLOSE_ON_FREE);
593 |
594 | TCPArg *clntarg = calloc(1, sizeof(TCPArg));
595 | strcpy(clntarg->addr, inet_ntoa(destaddr.sin_addr));
596 | sprintf(clntarg->port, "%d", ntohs(destaddr.sin_port));
597 | clntarg->bev = destbev;
598 | clntarg->type = TCP_TYPE_GEN;
599 |
600 | TCPArg *destarg = calloc(1, sizeof(TCPArg));
601 | strcpy(destarg->addr, inet_ntoa(destaddr.sin_addr));
602 | sprintf(destarg->port, "%d", ntohs(destaddr.sin_port));
603 | destarg->bev = clntbev;
604 | destarg->type = TCP_TYPE_SSL;
605 |
606 | bufferevent_setcb(clntbev, NULL, NULL, tcp_events_cb, clntarg);
607 | bufferevent_setcb(destbev, NULL, NULL, tcp_events_cb, destarg);
608 |
609 | bufferevent_enable(clntbev, EV_WRITE);
610 | bufferevent_enable(destbev, EV_READ | EV_WRITE);
611 |
612 | bufferevent_setwatermark(clntbev, EV_READ, 0, BUFSIZ_FOR_BEV);
613 | bufferevent_setwatermark(destbev, EV_READ, 0, BUFSIZ_FOR_BEV);
614 |
615 | printf("%s [tcp] connecting to: %s:%d\n", loginf(ctime), servhost, servport);
616 | bufferevent_socket_connect(destbev, (struct sockaddr *)&servaddr, sizeof(servaddr));
617 | setsockopt_tcp(bufferevent_getfd(destbev));
618 | }
619 |
620 | void tcp_events_cb(struct bufferevent *bev, short events, void *arg) {
621 | (void) bev; (void) events; (void) arg;
622 |
623 | char ctime[36] = {0};
624 | TCPArg *thisarg = arg;
625 |
626 | if (events & BEV_EVENT_CONNECTED) {
627 | printf("%s [tcp] connected to %s:%d\n", loginf(ctime), servhost, servport);
628 | printf("%s [tcp] send request to %s:%d\n", loginf(ctime), servhost, servport);
629 |
630 | bufferevent_write(bev, servreq, strlen(servreq));
631 | bufferevent_write(bev, "ConnectionType: tcp; addr=", strlen("ConnectionType: tcp; addr="));
632 | bufferevent_write(bev, thisarg->addr, strlen(thisarg->addr));
633 | bufferevent_write(bev, "; port=", strlen("; port="));
634 | bufferevent_write(bev, thisarg->port, strlen(thisarg->port));
635 | bufferevent_write(bev, "\r\n\r\n", 4);
636 | bufferevent_setcb(bev, tcp_recvres_cb, NULL, tcp_events_cb, arg);
637 |
638 | if (get_ssl_sess() != NULL) SSL_SESSION_free(get_ssl_sess());
639 | set_ssl_sess(SSL_get1_session(bufferevent_openssl_get_ssl(bev)));
640 | return;
641 | }
642 |
643 | if (events & BEV_EVENT_ERROR) {
644 | unsigned long sslerror = bufferevent_get_openssl_error(bev);
645 | if (sslerror != 0) {
646 | printf("%s [tcp] openssl error: (%lu) %s\n", logerr(ctime), sslerror, ERR_reason_error_string(sslerror));
647 | } else {
648 | if (errno != 0) {
649 | char error[64] = {0};
650 | printf("%s [tcp] socket error: (%d) %s\n", logerr(ctime), errno, strerror_r(errno, error, 64));
651 | }
652 | }
653 | }
654 |
655 | if (events & (BEV_EVENT_EOF | BEV_EVENT_ERROR)) {
656 | struct sockaddr_in thisaddr = {0};
657 | struct sockaddr_in othraddr = {0};
658 | socklen_t addrlen = sizeof(struct sockaddr_in);
659 |
660 | getpeername(bufferevent_getfd(bev), (struct sockaddr *)&thisaddr, &addrlen);
661 | getpeername(bufferevent_getfd(thisarg->bev), (struct sockaddr *)&othraddr, &addrlen);
662 |
663 | if (thisarg->type == TCP_TYPE_SSL) {
664 | printf("%s [tcp] closed connect: %s:%d\n", loginf(ctime), servhost, servport);
665 | printf("%s [tcp] closed connect: %s:%d\n", loginf(ctime), inet_ntoa(othraddr.sin_addr), ntohs(othraddr.sin_port));
666 | SSL *ssl = bufferevent_openssl_get_ssl(bev);
667 | SSL_set_shutdown(ssl, SSL_RECEIVED_SHUTDOWN);
668 | SSL_shutdown(ssl);
669 | } else {
670 | printf("%s [tcp] closed connect: %s:%d\n", loginf(ctime), inet_ntoa(thisaddr.sin_addr), ntohs(thisaddr.sin_port));
671 | printf("%s [tcp] closed connect: %s:%d\n", loginf(ctime), servhost, servport);
672 | }
673 |
674 | TCPArg *othrarg = NULL;
675 | bufferevent_getcb(thisarg->bev, NULL, NULL, NULL, (void **)&othrarg);
676 |
677 | bufferevent_free(bev);
678 | bufferevent_setcb(thisarg->bev, NULL, NULL, NULL, NULL);
679 |
680 | EVArg *evarg = calloc(1, sizeof(EVArg));
681 | struct event *ev = event_new(bufferevent_get_base(thisarg->bev), -1, EV_TIMEOUT, tcp_timeout_cb, evarg);
682 | evarg->ev = ev; evarg->bev = thisarg->bev; evarg->type = othrarg->type;
683 | struct timeval tv = {3, 0};
684 | event_add(ev, &tv);
685 |
686 | free(thisarg);
687 | free(othrarg);
688 | }
689 | }
690 |
691 | void tcp_recvres_cb(struct bufferevent *bev, void *arg) {
692 | (void) bev; (void) arg;
693 |
694 | char ctime[36] = {0};
695 | TCPArg *thisarg = arg;
696 |
697 | struct evbuffer *input = bufferevent_get_input(bev);
698 | char *statusline = evbuffer_readln(input, NULL, EVBUFFER_EOL_CRLF);
699 | evbuffer_drain(input, evbuffer_get_length(input));
700 |
701 | struct sockaddr_in clntaddr = {0};
702 | socklen_t addrlen = sizeof(clntaddr);
703 | getpeername(bufferevent_getfd(thisarg->bev), (struct sockaddr *)&clntaddr, &addrlen);
704 |
705 | if (statusline == NULL || strcmp(statusline, WEBSOCKET_STATUS_LINE) != 0) {
706 | free(statusline);
707 |
708 | printf("%s [tcp] bad response: %s:%d\n", logerr(ctime), servhost, servport);
709 | printf("%s [tcp] closed connect: %s:%d\n", loginf(ctime), servhost, servport);
710 | printf("%s [tcp] closed connect: %s:%d\n", loginf(ctime), inet_ntoa(clntaddr.sin_addr), ntohs(clntaddr.sin_port));
711 |
712 | SSL *ssl = bufferevent_openssl_get_ssl(bev);
713 | SSL_set_shutdown(ssl, SSL_RECEIVED_SHUTDOWN);
714 | SSL_shutdown(ssl);
715 |
716 | TCPArg *othrarg = NULL;
717 | bufferevent_getcb(thisarg->bev, NULL, NULL, NULL, (void **)&othrarg);
718 |
719 | bufferevent_free(bev);
720 | bufferevent_free(thisarg->bev);
721 |
722 | free(thisarg);
723 | free(othrarg);
724 | return;
725 | }
726 |
727 | free(statusline);
728 | printf("%s [tcp] %s:%d <-> %s:%s\n", loginf(ctime), inet_ntoa(clntaddr.sin_addr), ntohs(clntaddr.sin_port), thisarg->addr, thisarg->port);
729 | bufferevent_setcb(bev, tcp_read_cb, NULL, tcp_events_cb, arg);
730 |
731 | TCPArg *othrarg = NULL;
732 | bufferevent_getcb(thisarg->bev, NULL, NULL, NULL, (void **)&othrarg);
733 | bufferevent_setcb(thisarg->bev, tcp_read_cb, NULL, tcp_events_cb, othrarg);
734 | bufferevent_enable(thisarg->bev, EV_READ);
735 | }
736 |
737 | void tcp_read_cb(struct bufferevent *bev, void *arg) {
738 | TCPArg *thisarg = arg;
739 | struct evbuffer *input = bufferevent_get_input(bev);
740 | struct evbuffer *output = bufferevent_get_output(thisarg->bev);
741 | evbuffer_add_buffer(output, input);
742 | if (evbuffer_get_length(output) >= BUFSIZ_FOR_BEV) {
743 | TCPArg *othrarg = NULL;
744 | bufferevent_getcb(thisarg->bev, NULL, NULL, NULL, (void **)&othrarg);
745 | bufferevent_disable(bev, EV_READ);
746 | bufferevent_setwatermark(thisarg->bev, EV_WRITE, BUFSIZ_FOR_BEV / 2, 0);
747 | bufferevent_setcb(thisarg->bev, tcp_read_cb, tcp_write_cb, tcp_events_cb, othrarg);
748 | }
749 | }
750 |
751 | void tcp_write_cb(struct bufferevent *bev, void *arg) {
752 | TCPArg *thisarg = arg;
753 | bufferevent_enable(thisarg->bev, EV_READ);
754 | bufferevent_setwatermark(bev, EV_WRITE, 0, 0);
755 | bufferevent_setcb(bev, tcp_read_cb, NULL, tcp_events_cb, arg);
756 | }
757 |
758 | void tcp_timeout_cb(int sock, short events, void *arg) {
759 | (void) sock; (void) events;
760 | EVArg *evarg = arg;
761 | if (evarg->type == TCP_TYPE_SSL) {
762 | SSL *ssl = bufferevent_openssl_get_ssl(evarg->bev);
763 | SSL_set_shutdown(ssl, SSL_RECEIVED_SHUTDOWN);
764 | SSL_shutdown(ssl);
765 | }
766 | bufferevent_free(evarg->bev);
767 | event_free(evarg->ev);
768 | free(evarg);
769 | }
770 |
771 | void udp_sendreq_cb(struct bufferevent *bev, short events, void *arg) {
772 | (void) bev; (void) events; (void) arg;
773 | char ctime[36] = {0};
774 |
775 | if (events & BEV_EVENT_CONNECTED) {
776 | printf("%s [udp] connected to %s:%d\n", loginf(ctime), servhost, servport);
777 | printf("%s [udp] send request to %s:%d\n", loginf(ctime), servhost, servport);
778 |
779 | bufferevent_write(bev, servreq, strlen(servreq));
780 | bufferevent_write(bev, "ConnectionType: udp\r\n\r\n", strlen("ConnectionType: udp\r\n\r\n"));
781 | bufferevent_setcb(bev, udp_recvres_cb, NULL, udp_sendreq_cb, NULL);
782 |
783 | if (get_ssl_sess() != NULL) SSL_SESSION_free(get_ssl_sess());
784 | set_ssl_sess(SSL_get1_session(bufferevent_openssl_get_ssl(bev)));
785 | return;
786 | }
787 |
788 | if (events & BEV_EVENT_ERROR) {
789 | unsigned long sslerror = bufferevent_get_openssl_error(bev);
790 | if (sslerror != 0) {
791 | printf("%s [udp] openssl error: (%lu) %s\n", logerr(ctime), sslerror, ERR_reason_error_string(sslerror));
792 | } else {
793 | if (errno != 0) {
794 | char error[64] = {0};
795 | printf("%s [udp] socket error: (%d) %s\n", logerr(ctime), errno, strerror_r(errno, error, 64));
796 | }
797 | }
798 | }
799 |
800 | if (events & (BEV_EVENT_EOF | BEV_EVENT_ERROR)) {
801 | printf("%s [udp] closed connect: %s:%d\n", loginf(ctime), servhost, servport);
802 | SSL *ssl = bufferevent_openssl_get_ssl(bev);
803 | SSL_set_shutdown(ssl, SSL_RECEIVED_SHUTDOWN);
804 | SSL_shutdown(ssl);
805 |
806 | udpnode_clear();
807 | bufferevent_free(bev);
808 | if (event_pending(udplev, EV_READ, NULL)) event_del(udplev);
809 | if (event_pending(udptev, EV_TIMEOUT, NULL)) event_del(udptev);
810 |
811 | ssl = SSL_new(get_ssl_ctx());
812 | SSL_set_tlsext_host_name(ssl, servhost);
813 | X509_VERIFY_PARAM_set1_host(SSL_get0_param(ssl), servhost, 0);
814 | if (get_ssl_sess() != NULL) SSL_set_session(ssl, get_ssl_sess());
815 |
816 | udpbev = bufferevent_openssl_socket_new(udpbase, -1, ssl, BUFFEREVENT_SSL_CONNECTING, BEV_OPT_CLOSE_ON_FREE);
817 | bufferevent_setcb(udpbev, NULL, NULL, udp_sendreq_cb, NULL);
818 | bufferevent_enable(udpbev, EV_READ | EV_WRITE);
819 | bufferevent_setwatermark(udpbev, EV_READ, 0, BUFSIZ_FOR_BEV);
820 | printf("%s [udp] connecting to %s:%d\n", loginf(ctime), servhost, servport);
821 | bufferevent_socket_connect(udpbev, (struct sockaddr *)&servaddr, sizeof(servaddr));
822 | setsockopt_tcp(bufferevent_getfd(udpbev));
823 | }
824 | }
825 |
826 | void udp_recvres_cb(struct bufferevent *bev, void *arg) {
827 | (void) arg;
828 | char ctime[36] = {0};
829 |
830 | struct evbuffer *input = bufferevent_get_input(bev);
831 | char *statusline = evbuffer_readln(input, NULL, EVBUFFER_EOL_CRLF);
832 | evbuffer_drain(input, evbuffer_get_length(input));
833 |
834 | if (statusline == NULL || strcmp(statusline, WEBSOCKET_STATUS_LINE) != 0) {
835 | free(statusline);
836 | printf("%s [udp] bad response: %s:%d\n", logerr(ctime), servhost, servport);
837 | printf("%s [udp] closed connect: %s:%d\n", loginf(ctime), servhost, servport);
838 |
839 | SSL *ssl = bufferevent_openssl_get_ssl(bev);
840 | SSL_set_shutdown(ssl, SSL_RECEIVED_SHUTDOWN);
841 | SSL_shutdown(ssl);
842 |
843 | udpnode_clear();
844 | bufferevent_free(bev);
845 | if (event_pending(udplev, EV_READ, NULL)) event_del(udplev);
846 | if (event_pending(udptev, EV_TIMEOUT, NULL)) event_del(udptev);
847 |
848 | ssl = SSL_new(get_ssl_ctx());
849 | SSL_set_tlsext_host_name(ssl, servhost);
850 | X509_VERIFY_PARAM_set1_host(SSL_get0_param(ssl), servhost, 0);
851 | if (get_ssl_sess() != NULL) SSL_set_session(ssl, get_ssl_sess());
852 |
853 | udpbev = bufferevent_openssl_socket_new(udpbase, -1, ssl, BUFFEREVENT_SSL_CONNECTING, BEV_OPT_CLOSE_ON_FREE);
854 | bufferevent_setcb(udpbev, NULL, NULL, udp_sendreq_cb, NULL);
855 | bufferevent_enable(udpbev, EV_READ | EV_WRITE);
856 | bufferevent_setwatermark(udpbev, EV_READ, 0, BUFSIZ_FOR_BEV);
857 | printf("%s [udp] connecting to %s:%d\n", loginf(ctime), servhost, servport);
858 | bufferevent_socket_connect(udpbev, (struct sockaddr *)&servaddr, sizeof(servaddr));
859 | setsockopt_tcp(bufferevent_getfd(udpbev));
860 | return;
861 | }
862 | free(statusline);
863 |
864 | struct sockaddr_in selfaddr = {0};
865 | socklen_t addrlen = sizeof(selfaddr);
866 | getsockname(bufferevent_getfd(bev), (struct sockaddr *)&selfaddr, &addrlen);
867 | printf("%s [udp] %s:%d <-> %s:%d\n", loginf(ctime), inet_ntoa(selfaddr.sin_addr), ntohs(selfaddr.sin_port), servhost, servport);
868 |
869 | struct timeval tv = {900, 0};
870 | event_add(udptev, &tv);
871 | event_add(udplev, NULL);
872 | bufferevent_setcb(bev, udp_response_cb, NULL, udp_sendreq_cb, NULL);
873 | }
874 |
875 | void udp_request_cb(int sock, short events, void *arg) {
876 | (void) sock; (void) events; (void) arg;
877 | memset(udpcntl, 0, sizeof(udpcntl));
878 | char ctime[36] = {0};
879 | char error[64] = {0};
880 |
881 | struct sockaddr_in clntaddr = {0};
882 | socklen_t addrlen = sizeof(clntaddr);
883 | struct iovec iov = {udprbuff, UDP_RAW_BUFSIZ};
884 |
885 | struct msghdr msg = {0};
886 | msg.msg_name = &clntaddr;
887 | msg.msg_namelen = addrlen;
888 | msg.msg_control = udpcntl;
889 | msg.msg_controllen = 64;
890 | msg.msg_iov = &iov;
891 | msg.msg_iovlen = 1;
892 | msg.msg_flags = 0;
893 |
894 | int rawlen = recvmsg(sock, &msg, 0);
895 | if (rawlen == -1) {
896 | printf("%s [udp] recvmsg socket: (%d) %s\n", logerr(ctime), errno, strerror_r(errno, error, 64));
897 | return;
898 | }
899 | printf("%s [udp] recv %d bytes data from %s:%d\n", loginf(ctime), rawlen, inet_ntoa(clntaddr.sin_addr), ntohs(clntaddr.sin_port));
900 |
901 | int found = 0;
902 | struct sockaddr_in destaddr = {0};
903 | for (struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
904 | if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_RECVORIGDSTADDR) {
905 | memcpy(&destaddr, CMSG_DATA(cmsg), addrlen);
906 | found = 1;
907 | break;
908 | }
909 | }
910 | if (!found) {
911 | printf("%s [udp] can't get destaddr of %s:%d\n", logerr(ctime), inet_ntoa(clntaddr.sin_addr), ntohs(clntaddr.sin_port));
912 | return;
913 | }
914 | char iaddrstr[22] = {0};
915 | sprintf(iaddrstr, "%s:%d", inet_ntoa(clntaddr.sin_addr), ntohs(clntaddr.sin_port));
916 |
917 | size_t enclen = 0;
918 | base64_encode(udprbuff, rawlen, udpebuff, &enclen, 0);
919 | udpebuff[enclen] = 0;
920 |
921 | char eportstr[6] = {0};
922 | sprintf(eportstr, "%d", udpnode_getport(iaddrstr));
923 |
924 | char raddrstr[22] = {0};
925 | sprintf(raddrstr, "%s:%d", inet_ntoa(destaddr.sin_addr), ntohs(destaddr.sin_port));
926 |
927 | bufferevent_write(udpbev, iaddrstr, strlen(iaddrstr));
928 | bufferevent_write(udpbev, ":", 1);
929 | bufferevent_write(udpbev, raddrstr, strlen(raddrstr));
930 | bufferevent_write(udpbev, ":", 1);
931 | bufferevent_write(udpbev, eportstr, strlen(eportstr));
932 | bufferevent_write(udpbev, ":", 1);
933 | bufferevent_write(udpbev, udpebuff, strlen(udpebuff));
934 | bufferevent_write(udpbev, "\r\n", 2);
935 |
936 | printf("%s [udp] send %d bytes data to %s\n", loginf(ctime), rawlen, raddrstr);
937 | }
938 |
939 | void udp_response_cb(struct bufferevent *bev, void *arg) {
940 | (void) bev; (void) arg;
941 | char ctime[36] = {0};
942 |
943 | char *response = NULL;
944 | struct evbuffer *input = bufferevent_get_input(bev);
945 | while ((response = evbuffer_readln(input, NULL, EVBUFFER_EOL_CRLF)) != NULL) {
946 | int colon_cnt = 0;
947 | for (int i = 0, l = strlen(response); i < l; ++i) {
948 | if (response[i] == ':') ++colon_cnt;
949 | }
950 |
951 | if (colon_cnt != 5 || strlen(response) < 23) {
952 | printf("%s [udp] bad response: %s:%d\n", logerr(ctime), servhost, servport);
953 | free(response);
954 | continue;
955 | }
956 |
957 | char *iaddrptr = response;
958 | char *iportptr = strchr(iaddrptr, ':'); *iportptr = 0; ++iportptr;
959 | char *raddrptr = strchr(iportptr, ':'); *raddrptr = 0; ++raddrptr;
960 | char *rportptr = strchr(raddrptr, ':'); *rportptr = 0; ++rportptr;
961 | char *eportptr = strchr(rportptr, ':'); *eportptr = 0; ++eportptr;
962 | char *edataptr = strchr(eportptr, ':'); *edataptr = 0; ++edataptr;
963 |
964 | if (strlen(iaddrptr) < 7 || strlen(iaddrptr) > 15) {
965 | printf("%s [udp] bad response: %s:%d\n", logerr(ctime), servhost, servport);
966 | free(response);
967 | continue;
968 | }
969 |
970 | if (strlen(iportptr) < 1 || strlen(iportptr) > 5) {
971 | printf("%s [udp] bad response: %s:%d\n", logerr(ctime), servhost, servport);
972 | free(response);
973 | continue;
974 | }
975 |
976 | if (strlen(raddrptr) < 7 || strlen(raddrptr) > 15) {
977 | printf("%s [udp] bad response: %s:%d\n", logerr(ctime), servhost, servport);
978 | free(response);
979 | continue;
980 | }
981 |
982 | if (strlen(rportptr) < 1 || strlen(rportptr) > 5) {
983 | printf("%s [udp] bad response: %s:%d\n", logerr(ctime), servhost, servport);
984 | free(response);
985 | continue;
986 | }
987 |
988 | if (strlen(eportptr) < 1 || strlen(eportptr) > 5) {
989 | printf("%s [udp] bad response: %s:%d\n", logerr(ctime), servhost, servport);
990 | free(response);
991 | continue;
992 | }
993 |
994 | if (strlen(edataptr) < 1) {
995 | printf("%s [udp] bad response: %s:%d\n", logerr(ctime), servhost, servport);
996 | free(response);
997 | continue;
998 | }
999 |
1000 | uint32_t iaddr = inet_addr(iaddrptr);
1001 | if (iaddr == INADDR_NONE) {
1002 | printf("%s [udp] bad response: %s:%d\n", logerr(ctime), servhost, servport);
1003 | free(response);
1004 | continue;
1005 | }
1006 |
1007 | uint16_t iport = htons(strtol(iportptr, NULL, 10));
1008 | if (iport == 0) {
1009 | printf("%s [udp] bad response: %s:%d\n", logerr(ctime), servhost, servport);
1010 | free(response);
1011 | continue;
1012 | }
1013 |
1014 | uint32_t raddr = inet_addr(raddrptr);
1015 | if (raddr == INADDR_NONE) {
1016 | printf("%s [udp] bad response: %s:%d\n", logerr(ctime), servhost, servport);
1017 | free(response);
1018 | continue;
1019 | }
1020 |
1021 | uint16_t rport = htons(strtol(rportptr, NULL, 10));
1022 | if (rport == 0) {
1023 | printf("%s [udp] bad response: %s:%d\n", logerr(ctime), servhost, servport);
1024 | free(response);
1025 | continue;
1026 | }
1027 |
1028 | int eport = strtol(eportptr, NULL, 10);
1029 | if (eport <= 0 || eport > 65535) {
1030 | printf("%s [udp] bad response: %s:%d\n", logerr(ctime), servhost, servport);
1031 | free(response);
1032 | continue;
1033 | }
1034 |
1035 | size_t rawlen = 0;
1036 | if (base64_decode(edataptr, strlen(edataptr), udprbuff, &rawlen, 0) != 1) {
1037 | printf("%s [udp] bad response: %s:%d\n", logerr(ctime), servhost, servport);
1038 | free(response);
1039 | continue;
1040 | }
1041 | printf("%s [udp] recv %ld bytes data from %s:%s\n", loginf(ctime), rawlen, raddrptr, rportptr);
1042 |
1043 | *--iportptr = ':';
1044 | udpnode_put(iaddrptr, eport);
1045 |
1046 | struct sockaddr_in clntaddr = {0};
1047 | clntaddr.sin_family = AF_INET;
1048 | clntaddr.sin_addr.s_addr = iaddr;
1049 | clntaddr.sin_port = iport;
1050 |
1051 | struct sockaddr_in destaddr = {0};
1052 | destaddr.sin_family = AF_INET;
1053 | destaddr.sin_addr.s_addr = raddr;
1054 | destaddr.sin_port = rport;
1055 |
1056 | int destsock = socket(AF_INET, SOCK_DGRAM, 0);
1057 | evutil_make_socket_nonblocking(destsock);
1058 |
1059 | int optval = 1;
1060 | setsockopt(destsock, SOL_IP, IP_TRANSPARENT, &optval, sizeof(optval));
1061 |
1062 | if (bind(destsock, (struct sockaddr *)&destaddr, sizeof(destaddr)) == -1) {
1063 | char error[64] = {0};
1064 | printf("%s [udp] bind socket: (%d) %s\n", logerr(ctime), errno, strerror_r(errno, error, 64));
1065 | close(destsock);
1066 | free(response);
1067 | continue;
1068 | }
1069 |
1070 | if (sendto(destsock, udprbuff, rawlen, 0, (struct sockaddr *)&clntaddr, sizeof(clntaddr)) == -1) {
1071 | char error[64] = {0};
1072 | printf("%s [udp] sendto socket: (%d) %s\n", logerr(ctime), errno, strerror_r(errno, error, 64));
1073 | close(destsock);
1074 | free(response);
1075 | continue;
1076 | }
1077 |
1078 | printf("%s [udp] send %ld bytes data to %s\n", loginf(ctime), rawlen, iaddrptr);
1079 | close(destsock);
1080 | free(response);
1081 | }
1082 | }
1083 |
1084 | void udp_release_cb(int sock, short events, void *arg) {
1085 | (void) sock; (void) events; (void) arg;
1086 |
1087 | char ctime[36] = {0};
1088 | printf("%s [udp] tunnel timeout: %s:%d\n", loginf(ctime), servhost, servport);
1089 | printf("%s [udp] closed connect: %s:%d\n", loginf(ctime), servhost, servport);
1090 |
1091 | SSL *ssl = bufferevent_openssl_get_ssl(udpbev);
1092 | SSL_set_shutdown(ssl, SSL_RECEIVED_SHUTDOWN);
1093 | SSL_shutdown(ssl);
1094 |
1095 | udpnode_clear();
1096 | bufferevent_free(udpbev);
1097 | if (event_pending(udplev, EV_READ, NULL)) event_del(udplev);
1098 |
1099 | ssl = SSL_new(get_ssl_ctx());
1100 | SSL_set_tlsext_host_name(ssl, servhost);
1101 | X509_VERIFY_PARAM_set1_host(SSL_get0_param(ssl), servhost, 0);
1102 | if (get_ssl_sess() != NULL) SSL_set_session(ssl, get_ssl_sess());
1103 |
1104 | udpbev = bufferevent_openssl_socket_new(udpbase, -1, ssl, BUFFEREVENT_SSL_CONNECTING, BEV_OPT_CLOSE_ON_FREE);
1105 | bufferevent_setcb(udpbev, NULL, NULL, udp_sendreq_cb, NULL);
1106 | bufferevent_enable(udpbev, EV_READ | EV_WRITE);
1107 | bufferevent_setwatermark(udpbev, EV_READ, 0, BUFSIZ_FOR_BEV);
1108 | printf("%s [udp] connecting to %s:%d\n", loginf(ctime), servhost, servport);
1109 | bufferevent_socket_connect(udpbev, (struct sockaddr *)&servaddr, sizeof(servaddr));
1110 | setsockopt_tcp(bufferevent_getfd(udpbev));
1111 | }
1112 |
1113 | void udp_timeout_cb(int sock, short events, void *arg) {
1114 | (void) sock; (void) events;
1115 | char ctime[36] = {0};
1116 | printf("%s [udp] socket timeout: %s\n", loginf(ctime), (char *)arg);
1117 | udpnode_del(arg);
1118 | }
1119 |
--------------------------------------------------------------------------------
/tls-client.service:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=tls-client
3 | Requires=network.target network-online.target
4 | After=network.target network-online.target
5 |
6 | [Service]
7 | Type=simple
8 | ExecStart=/bin/sh -c "/usr/local/bin/tls-client -j2 -s www.example.com -c /etc/ssl/cert.pem -P /tls-proxy -H $'Some-Header: some_header_value\r\n'"
9 | Restart=always
10 |
11 | [Install]
12 | WantedBy=multi-user.target
13 |
--------------------------------------------------------------------------------
/tls-server.c:
--------------------------------------------------------------------------------
1 | #define _GNU_SOURCE
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 | #include
18 | #include
19 | #include
20 | #include "libbase64.h"
21 | #include "uthash.h"
22 |
23 | #define PRINT_COMMAND_HELP \
24 | printf("usage: tls-server . OPTIONS have these:\n"\
25 | " -b listen addr. default: 127.0.0.1\n"\
26 | " -l listen port. default: 60080\n"\
27 | " -j thread nums. default: 1\n"\
28 | " -v show version and exit\n"\
29 | " -h show help and exit\n")
30 |
31 | #define WEBSOCKET_RESPONSE "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\n\r\n"
32 | #define BUFSIZ_FOR_BEV 65536
33 | #define UDP_RAW_BUFSIZ 1472
34 | #define UDP_ENC_BUFSIZ 1960
35 | #define UDP_HASH_LEN 500
36 | #define UDP_HASH_PRE 10
37 |
38 | static struct sockaddr_in servaddr;
39 | void *service(void *arg);
40 |
41 | void new_accept_cb(struct evconnlistener *listener, int sock, struct sockaddr *addr, int addrlen, void *arg);
42 | void new_fstreq_cb(struct bufferevent *bev, void *arg);
43 | void new_events_cb(struct bufferevent *bev, short events, void *arg);
44 |
45 | void tcp_read_cb(struct bufferevent *bev, void *arg);
46 | void tcp_write_cb(struct bufferevent *bev, void *arg);
47 | void tcp_events_cb(struct bufferevent *bev, short events, void *arg);
48 | void tcp_timeout_cb(int sock, short events, void *arg);
49 |
50 | void udp_events_cb(struct bufferevent *bev, short events, void *arg);
51 | void udp_request_cb(struct bufferevent *bev, void *arg);
52 | void udp_response_cb(int sock, short events, void *arg);
53 |
54 | typedef struct {
55 | struct event *ev;
56 | struct bufferevent *bev;
57 | } EVArg;
58 |
59 | typedef struct {
60 | int port;
61 | struct event *ev;
62 | UT_hash_handle hh;
63 | } UDPNode;
64 |
65 | typedef struct {
66 | char addr[16];
67 | char port[6];
68 | UDPNode *hash;
69 | struct bufferevent *bev;
70 | } UDPArg;
71 |
72 | UDPNode *udpnode_init() {
73 | UDPNode *hash = NULL;
74 | UDPNode *node = calloc(1, sizeof(UDPNode));
75 | HASH_ADD_INT(hash, port, node);
76 | return hash;
77 | }
78 |
79 | void udpnode_put(UDPNode *hash, int port, struct event *ev) {
80 | if (port == 0) return;
81 | UDPNode *node = NULL;
82 | HASH_FIND_INT(hash, &port, node);
83 | if (node == NULL) {
84 | node = calloc(1, sizeof(UDPNode));
85 | node->port = port;
86 | node->ev = ev;
87 | HASH_ADD_INT(hash, port, node);
88 | if (HASH_COUNT(hash) > UDP_HASH_LEN) {
89 | int cnt = 0;
90 | UDPNode *head = hash->hh.next;
91 | UDPNode *node = NULL, *temp = NULL;
92 | HASH_ITER(hh, head, node, temp) {
93 | HASH_DEL(hash, node);
94 | free(event_get_callback_arg(node->ev));
95 | close(event_get_fd(node->ev));
96 | event_free(node->ev);
97 | free(node);
98 | if (++cnt == UDP_HASH_PRE) return;
99 | }
100 | }
101 | } else {
102 | free(event_get_callback_arg(node->ev));
103 | close(event_get_fd(node->ev));
104 | event_free(node->ev);
105 | node->ev = ev;
106 | HASH_DEL(hash, node);
107 | HASH_ADD_INT(hash, port, node);
108 | }
109 | }
110 |
111 | UDPNode *udpnode_get(UDPNode *hash, int port) {
112 | if (port == 0) return NULL;
113 | UDPNode *node = NULL;
114 | HASH_FIND_INT(hash, &port, node);
115 | if (node == NULL) return NULL;
116 | HASH_DEL(hash, node);
117 | HASH_ADD_INT(hash, port, node);
118 | return node;
119 | }
120 |
121 | struct event *udpnode_getev(UDPNode *hash, int port) {
122 | if (port == 0) return NULL;
123 | UDPNode *node = udpnode_get(hash, port);
124 | return (node == NULL) ? NULL : (node->ev);
125 | }
126 |
127 | void udpnode_del(UDPNode *hash, int port) {
128 | if (port == 0) return;
129 | UDPNode *node = NULL;
130 | HASH_FIND_INT(hash, &port, node);
131 | if (node == NULL) return;
132 | HASH_DEL(hash, node);
133 | free(event_get_callback_arg(node->ev));
134 | close(event_get_fd(node->ev));
135 | event_free(node->ev);
136 | free(node);
137 | }
138 |
139 | void udpnode_clear(UDPNode *hash) {
140 | UDPNode *node = NULL, *temp = NULL;
141 | HASH_ITER(hh, hash, node, temp) {
142 | HASH_DEL(hash, node);
143 | if (node->port != 0) {
144 | free(event_get_callback_arg(node->ev));
145 | close(event_get_fd(node->ev));
146 | event_free(node->ev);
147 | }
148 | free(node);
149 | }
150 | }
151 |
152 | // sizeof(str) = 36
153 | char *loginf(char *str) {
154 | time_t rawtime;
155 | time(&rawtime);
156 | struct tm curtm;
157 | localtime_r(&rawtime, &curtm);
158 | sprintf(str, "\e[1;32m%04d-%02d-%02d %02d:%02d:%02d INF:\e[0m",
159 | curtm.tm_year + 1900, curtm.tm_mon + 1, curtm.tm_mday,
160 | curtm.tm_hour, curtm.tm_min, curtm.tm_sec);
161 | return str;
162 | }
163 |
164 | // sizeof(str) = 36
165 | char *logerr(char *str) {
166 | time_t rawtime;
167 | time(&rawtime);
168 | struct tm curtm;
169 | localtime_r(&rawtime, &curtm);
170 | sprintf(str, "\e[1;35m%04d-%02d-%02d %02d:%02d:%02d ERR:\e[0m",
171 | curtm.tm_year + 1900, curtm.tm_mon + 1, curtm.tm_mday,
172 | curtm.tm_hour, curtm.tm_min, curtm.tm_sec);
173 | return str;
174 | }
175 |
176 | void setsockopt_tcp(int sock) {
177 | char ctime[36] = {0};
178 | char error[64] = {0};
179 |
180 | int optval = 1;
181 | if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &optval, sizeof(optval)) == -1) {
182 | printf("%s [tcp] setsockopt(TCP_NODELAY) for %d: (%d) %s\n", logerr(ctime), sock, errno, strerror_r(errno, error, 64));
183 | }
184 |
185 | if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) == -1) {
186 | printf("%s [tcp] setsockopt(SO_REUSEADDR) for %d: (%d) %s\n", logerr(ctime), sock, errno, strerror_r(errno, error, 64));
187 | }
188 |
189 | if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(optval)) == -1) {
190 | printf("%s [tcp] setsockopt(SO_KEEPALIVE) for %d: (%d) %s\n", logerr(ctime), sock, errno, strerror_r(errno, error, 64));
191 | }
192 |
193 | optval = 15;
194 | if (setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, &optval, sizeof(optval)) == -1) {
195 | printf("%s [tcp] setsockopt(TCP_KEEPIDLE) for %d: (%d) %s\n", logerr(ctime), sock, errno, strerror_r(errno, error, 64));
196 | }
197 |
198 | if (setsockopt(sock, IPPROTO_TCP, TCP_KEEPINTVL, &optval, sizeof(optval)) == -1) {
199 | printf("%s [tcp] setsockopt(TCP_KEEPINTVL) for %d: (%d) %s\n", logerr(ctime), sock, errno, strerror_r(errno, error, 64));
200 | }
201 |
202 | optval = 2;
203 | if (setsockopt(sock, IPPROTO_TCP, TCP_KEEPCNT, &optval, sizeof(optval)) == -1) {
204 | printf("%s [tcp] setsockopt(TCP_KEEPCNT) for %d: (%d) %s\n", logerr(ctime), sock, errno, strerror_r(errno, error, 64));
205 | }
206 | }
207 |
208 | int main(int argc, char *argv[]) {
209 | signal(SIGPIPE, SIG_IGN);
210 | setvbuf(stdout, NULL, _IONBF, 0);
211 |
212 | char *listen_addr = "127.0.0.1";
213 | int listen_port = 60080;
214 | int thread_nums = 1;
215 |
216 | opterr = 0;
217 | char *optstr = "b:l:j:vh";
218 | int opt = -1;
219 | while ((opt = getopt(argc, argv, optstr)) != -1) {
220 | switch (opt) {
221 | case 'v':
222 | printf("tls-server v1.1\n");
223 | return 0;
224 | case 'h':
225 | PRINT_COMMAND_HELP;
226 | return 0;
227 | case 'b':
228 | listen_addr = optarg;
229 | break;
230 | case 'l':
231 | listen_port = strtol(optarg, NULL, 10);
232 | if (listen_port <= 0 || listen_port > 65535) {
233 | printf("invalid listen port: %d\n", listen_port);
234 | PRINT_COMMAND_HELP;
235 | return 1;
236 | }
237 | break;
238 | case 'j':
239 | thread_nums = strtol(optarg, NULL, 10);
240 | if (thread_nums < 1) {
241 | printf("invalid thread nums: %d\n", thread_nums);
242 | PRINT_COMMAND_HELP;
243 | return 1;
244 | }
245 | break;
246 | case '?':
247 | if (strchr(optstr, optopt) == NULL) {
248 | printf("unknown option '-%c'\n", optopt);
249 | PRINT_COMMAND_HELP;
250 | return 1;
251 | } else {
252 | printf("missing optval '-%c'\n", optopt);
253 | PRINT_COMMAND_HELP;
254 | return 1;
255 | }
256 | }
257 | }
258 |
259 | servaddr.sin_family = AF_INET;
260 | servaddr.sin_addr.s_addr = inet_addr(listen_addr);
261 | servaddr.sin_port = htons(listen_port);
262 |
263 | char ctime[36] = {0};
264 | printf("%s [srv] thread numbers: %d\n", loginf(ctime), thread_nums);
265 | printf("%s [srv] listen address: %s:%d\n", loginf(ctime), listen_addr, listen_port);
266 |
267 | pthread_t tids[--thread_nums];
268 | for (int i = 0; i < thread_nums; ++i) {
269 | if (pthread_create(tids + i, NULL, service, NULL) != 0) {
270 | printf("%s [srv] create thread: (%d) %s\n", logerr(ctime), errno, strerror(errno));
271 | return errno;
272 | }
273 | }
274 | service(NULL);
275 |
276 | for (int i = 0; i < thread_nums; ++i) {
277 | pthread_join(tids[i], NULL);
278 | }
279 |
280 | return 0;
281 | }
282 |
283 | void *service(void *arg) {
284 | (void) arg;
285 |
286 | struct event_config *cfg = event_config_new();
287 | event_config_set_flag(cfg, EVENT_BASE_FLAG_NOLOCK | EVENT_BASE_FLAG_IGNORE_ENV);
288 | struct event_base *base = event_base_new_with_config(cfg);
289 | event_config_free(cfg);
290 |
291 | struct evconnlistener *listener = evconnlistener_new_bind(
292 | base, new_accept_cb, NULL,
293 | LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE | LEV_OPT_REUSEABLE_PORT,
294 | SOMAXCONN, (struct sockaddr *)&servaddr, sizeof(struct sockaddr_in)
295 | );
296 | if (listener == NULL) {
297 | char ctime[36] = {0};
298 | char error[64] = {0};
299 | printf("%s [srv] listen socket: %s:%d: (%d) %s\n", logerr(ctime), inet_ntoa(servaddr.sin_addr), ntohs(servaddr.sin_port), errno, strerror_r(errno, error, 64));
300 | exit(errno);
301 | }
302 | event_base_dispatch(base);
303 |
304 | evconnlistener_free(listener);
305 | event_base_free(base);
306 | libevent_global_shutdown();
307 |
308 | return NULL;
309 | }
310 |
311 | void new_accept_cb(struct evconnlistener *listener, int sock, struct sockaddr *addr, int addrlen, void *arg) {
312 | (void) listener; (void) sock; (void) addr; (void) addrlen; (void) arg;
313 |
314 | char ctime[36] = {0};
315 | setsockopt_tcp(sock);
316 | struct sockaddr_in *clntaddr = (struct sockaddr_in *)addr;
317 | printf("%s [srv] new connect: %s:%d\n", loginf(ctime), inet_ntoa(clntaddr->sin_addr), htons(clntaddr->sin_port));
318 |
319 | struct bufferevent *bev = bufferevent_socket_new(evconnlistener_get_base(listener), sock, BEV_OPT_CLOSE_ON_FREE);
320 | bufferevent_setcb(bev, new_fstreq_cb, NULL, new_events_cb, NULL);
321 | bufferevent_enable(bev, EV_READ | EV_WRITE);
322 | bufferevent_setwatermark(bev, EV_READ, 0, BUFSIZ_FOR_BEV);
323 | }
324 |
325 | void new_events_cb(struct bufferevent *bev, short events, void *arg) {
326 | (void) bev; (void) events; (void) arg;
327 |
328 | char ctime[36] = {0};
329 | struct sockaddr_in clntaddr = {0};
330 | socklen_t addrlen = sizeof(clntaddr);
331 | getpeername(bufferevent_getfd(bev), (struct sockaddr *)&clntaddr, &addrlen);
332 |
333 | if (events & BEV_EVENT_ERROR && errno != 0) {
334 | char error[64] = {0};
335 | printf("%s [srv] error on %s:%d: (%d) %s\n", logerr(ctime), inet_ntoa(clntaddr.sin_addr), ntohs(clntaddr.sin_port), errno, strerror_r(errno, error, 64));
336 | }
337 |
338 | if (events & (BEV_EVENT_EOF | BEV_EVENT_ERROR)) {
339 | printf("%s [srv] closed connect: %s:%d\n", loginf(ctime), inet_ntoa(clntaddr.sin_addr), ntohs(clntaddr.sin_port));
340 | bufferevent_free(bev);
341 | }
342 | }
343 |
344 | void new_fstreq_cb(struct bufferevent *bev, void *arg) {
345 | (void) bev; (void) arg;
346 |
347 | char ctime[36] = {0};
348 | struct sockaddr_in clntaddr = {0};
349 | socklen_t addrlen = sizeof(clntaddr);
350 | getpeername(bufferevent_getfd(bev), (struct sockaddr *)&clntaddr, &addrlen);
351 |
352 | char *reqline = NULL;
353 | struct evbuffer *input = bufferevent_get_input(bev);
354 | while ((reqline = evbuffer_readln(input, NULL, EVBUFFER_EOL_CRLF)) != NULL) {
355 | char *header = strstr(reqline, "ConnectionType: ");
356 |
357 | if (header == reqline) {
358 | header += strlen("ConnectionType: ");
359 | evbuffer_drain(input, evbuffer_get_length(input));
360 |
361 | if (strlen(header) < 3) {
362 | printf("%s [srv] bad request: %s:%d\n", logerr(ctime), inet_ntoa(clntaddr.sin_addr), ntohs(clntaddr.sin_port));
363 | printf("%s [srv] closed connect: %s:%d\n", loginf(ctime), inet_ntoa(clntaddr.sin_addr), ntohs(clntaddr.sin_port));
364 | bufferevent_free(bev);
365 | free(reqline);
366 | return;
367 | }
368 |
369 | char type[4] = {0};
370 | strncpy(type, header, 3);
371 |
372 | if (strcmp(type, "udp") == 0) {
373 | printf("%s [udp] new connect: %s:%d\n", loginf(ctime), inet_ntoa(clntaddr.sin_addr), ntohs(clntaddr.sin_port));
374 | bufferevent_write(bev, WEBSOCKET_RESPONSE, strlen(WEBSOCKET_RESPONSE));
375 | bufferevent_setcb(bev, udp_request_cb, NULL, udp_events_cb, udpnode_init());
376 | free(reqline);
377 | return;
378 | }
379 |
380 | if (strcmp(type, "tcp") == 0) {
381 | char *addrptr = strstr(header, "tcp; addr=");
382 |
383 | if (addrptr != header) {
384 | printf("%s [tcp] bad request: %s:%d\n", logerr(ctime), inet_ntoa(clntaddr.sin_addr), ntohs(clntaddr.sin_port));
385 | printf("%s [tcp] closed connect: %s:%d\n", loginf(ctime), inet_ntoa(clntaddr.sin_addr), ntohs(clntaddr.sin_port));
386 | bufferevent_free(bev);
387 | free(reqline);
388 | return;
389 | }
390 |
391 | addrptr += strlen("tcp; addr=");
392 | char *portptr = strstr(addrptr, "; port=");
393 |
394 | if (portptr == addrptr || portptr == NULL) {
395 | printf("%s [tcp] bad request: %s:%d\n", logerr(ctime), inet_ntoa(clntaddr.sin_addr), ntohs(clntaddr.sin_port));
396 | printf("%s [tcp] closed connect: %s:%d\n", loginf(ctime), inet_ntoa(clntaddr.sin_addr), ntohs(clntaddr.sin_port));
397 | bufferevent_free(bev);
398 | free(reqline);
399 | return;
400 | }
401 |
402 | *portptr = 0;
403 | portptr += strlen("; port=");
404 |
405 | if (strlen(portptr) == 0 || strlen(portptr) > 5) {
406 | printf("%s [tcp] bad request: %s:%d\n", logerr(ctime), inet_ntoa(clntaddr.sin_addr), ntohs(clntaddr.sin_port));
407 | printf("%s [tcp] closed connect: %s:%d\n", loginf(ctime), inet_ntoa(clntaddr.sin_addr), ntohs(clntaddr.sin_port));
408 | bufferevent_free(bev);
409 | free(reqline);
410 | return;
411 | }
412 |
413 | uint32_t addr = inet_addr(addrptr);
414 | if (addr == INADDR_NONE) {
415 | printf("%s [tcp] bad request: %s:%d\n", logerr(ctime), inet_ntoa(clntaddr.sin_addr), ntohs(clntaddr.sin_port));
416 | printf("%s [tcp] closed connect: %s:%d\n", loginf(ctime), inet_ntoa(clntaddr.sin_addr), ntohs(clntaddr.sin_port));
417 | bufferevent_free(bev);
418 | free(reqline);
419 | return;
420 | }
421 |
422 | uint16_t port = htons(strtol(portptr, NULL, 10));
423 | if (port == 0) {
424 | printf("%s [tcp] bad request: %s:%d\n", logerr(ctime), inet_ntoa(clntaddr.sin_addr), ntohs(clntaddr.sin_port));
425 | printf("%s [tcp] closed connect: %s:%d\n", loginf(ctime), inet_ntoa(clntaddr.sin_addr), ntohs(clntaddr.sin_port));
426 | bufferevent_free(bev);
427 | free(reqline);
428 | return;
429 | }
430 |
431 | struct sockaddr_in destaddr = {0};
432 | destaddr.sin_family = AF_INET;
433 | destaddr.sin_addr.s_addr = addr;
434 | destaddr.sin_port = port;
435 |
436 | struct bufferevent *destbev = bufferevent_socket_new(bufferevent_get_base(bev), -1, BEV_OPT_CLOSE_ON_FREE);
437 | bufferevent_setcb(destbev, NULL, NULL, tcp_events_cb, bev);
438 | bufferevent_enable(destbev, EV_READ | EV_WRITE);
439 | bufferevent_setwatermark(destbev, EV_READ, 0, BUFSIZ_FOR_BEV);
440 | printf("%s [tcp] connecting to %s:%s\n", loginf(ctime), addrptr, portptr);
441 | bufferevent_socket_connect(destbev, (struct sockaddr *)&destaddr, sizeof(destaddr));
442 | setsockopt_tcp(bufferevent_getfd(destbev));
443 |
444 | bufferevent_setcb(bev, NULL, NULL, tcp_events_cb, destbev);
445 | bufferevent_disable(bev, EV_READ);
446 | free(reqline);
447 | return;
448 | }
449 |
450 | printf("%s [srv] bad request: %s:%d\n", logerr(ctime), inet_ntoa(clntaddr.sin_addr), ntohs(clntaddr.sin_port));
451 | printf("%s [srv] closed connect: %s:%d\n", loginf(ctime), inet_ntoa(clntaddr.sin_addr), ntohs(clntaddr.sin_port));
452 | bufferevent_free(bev);
453 | free(reqline);
454 | return;
455 | }
456 |
457 | free(reqline);
458 | }
459 |
460 | printf("%s [srv] bad request: %s:%d\n", logerr(ctime), inet_ntoa(clntaddr.sin_addr), ntohs(clntaddr.sin_port));
461 | printf("%s [srv] closed connect: %s:%d\n", loginf(ctime), inet_ntoa(clntaddr.sin_addr), ntohs(clntaddr.sin_port));
462 | bufferevent_free(bev);
463 | }
464 |
465 | void tcp_read_cb(struct bufferevent *bev, void *arg) {
466 | struct evbuffer *input = bufferevent_get_input(bev);
467 | struct evbuffer *output = bufferevent_get_output(arg);
468 | evbuffer_add_buffer(output, input);
469 | if (evbuffer_get_length(output) >= BUFSIZ_FOR_BEV) {
470 | bufferevent_disable(bev, EV_READ);
471 | bufferevent_setwatermark(arg, EV_WRITE, BUFSIZ_FOR_BEV / 2, 0);
472 | bufferevent_setcb(arg, tcp_read_cb, tcp_write_cb, tcp_events_cb, bev);
473 | }
474 | }
475 |
476 | void tcp_write_cb(struct bufferevent *bev, void *arg) {
477 | bufferevent_enable(arg, EV_READ);
478 | bufferevent_setwatermark(bev, EV_WRITE, 0, 0);
479 | bufferevent_setcb(bev, tcp_read_cb, NULL, tcp_events_cb, arg);
480 | }
481 |
482 | void tcp_events_cb(struct bufferevent *bev, short events, void *arg) {
483 | char ctime[36] = {0};
484 | struct sockaddr_in thisaddr = {0};
485 | socklen_t addrlen = sizeof(thisaddr);
486 | getpeername(bufferevent_getfd(bev), (struct sockaddr *)&thisaddr, &addrlen);
487 |
488 | if (events & BEV_EVENT_CONNECTED) {
489 | printf("%s [tcp] connected to %s:%d\n", loginf(ctime), inet_ntoa(thisaddr.sin_addr), ntohs(thisaddr.sin_port));
490 | bufferevent_write(arg, WEBSOCKET_RESPONSE, strlen(WEBSOCKET_RESPONSE));
491 | bufferevent_setcb(bev, tcp_read_cb, NULL, tcp_events_cb, arg);
492 | bufferevent_setcb(arg, tcp_read_cb, NULL, tcp_events_cb, bev);
493 | bufferevent_enable(arg, EV_READ);
494 | return;
495 | }
496 |
497 | if (events & BEV_EVENT_ERROR && errno != 0) {
498 | char error[64] = {0};
499 | printf("%s [tcp] error on %s:%d: (%d) %s\n", logerr(ctime), inet_ntoa(thisaddr.sin_addr), ntohs(thisaddr.sin_port), errno, strerror_r(errno, error, 64));
500 | }
501 |
502 | if (events & (BEV_EVENT_EOF | BEV_EVENT_ERROR)) {
503 | struct sockaddr_in othraddr = {0};
504 | getpeername(bufferevent_getfd(arg), (struct sockaddr *)&othraddr, &addrlen);
505 | printf("%s [tcp] closed connect: %s:%d\n", loginf(ctime), inet_ntoa(thisaddr.sin_addr), ntohs(thisaddr.sin_port));
506 | printf("%s [tcp] closed connect: %s:%d\n", loginf(ctime), inet_ntoa(othraddr.sin_addr), ntohs(othraddr.sin_port));
507 | bufferevent_free(bev);
508 | bufferevent_setcb(arg, NULL, NULL, NULL, NULL);
509 |
510 | EVArg *evarg = calloc(1, sizeof(EVArg));
511 | struct event *ev = event_new(bufferevent_get_base(arg), -1, EV_TIMEOUT, tcp_timeout_cb, evarg);
512 | evarg->ev = ev; evarg->bev = arg;
513 | struct timeval tv = {3, 0};
514 | event_add(ev, &tv);
515 | }
516 | }
517 |
518 | void tcp_timeout_cb(int sock, short events, void *arg) {
519 | (void) sock; (void) events;
520 | EVArg *evarg = arg;
521 | bufferevent_free(evarg->bev);
522 | event_free(evarg->ev);
523 | free(evarg);
524 | }
525 |
526 | void udp_events_cb(struct bufferevent *bev, short events, void *arg) {
527 | char ctime[36] = {0};
528 | struct sockaddr_in clntaddr = {0};
529 | socklen_t addrlen = sizeof(clntaddr);
530 | getpeername(bufferevent_getfd(bev), (struct sockaddr *)&clntaddr, &addrlen);
531 |
532 | if (events & BEV_EVENT_ERROR && errno != 0) {
533 | char error[64] = {0};
534 | printf("%s [udp] error on %s:%d: (%d) %s\n", logerr(ctime), inet_ntoa(clntaddr.sin_addr), ntohs(clntaddr.sin_port), errno, strerror_r(errno, error, 64));
535 | }
536 |
537 | if (events & (BEV_EVENT_EOF | BEV_EVENT_ERROR)) {
538 | printf("%s [udp] closed connect: %s:%d\n", loginf(ctime), inet_ntoa(clntaddr.sin_addr), ntohs(clntaddr.sin_port));
539 | bufferevent_free(bev);
540 | udpnode_clear(arg);
541 | }
542 | }
543 |
544 | void udp_request_cb(struct bufferevent *bev, void *arg) {
545 | char ctime[36] = {0};
546 | struct sockaddr_in clntaddr = {0};
547 | socklen_t addrlen = sizeof(clntaddr);
548 | getpeername(bufferevent_getfd(bev), (struct sockaddr *)&clntaddr, &addrlen);
549 |
550 | char *request = NULL;
551 | struct evbuffer *input = bufferevent_get_input(bev);
552 | while ((request = evbuffer_readln(input, NULL, EVBUFFER_EOL_CRLF)) != NULL) {
553 | int colon_cnt = 0;
554 | for (int i = 0, l = strlen(request); i < l; ++i) {
555 | if (request[i] == ':') ++colon_cnt;
556 | }
557 |
558 | if (colon_cnt != 5 || strlen(request) < 23) {
559 | printf("%s [udp] bad request: %s:%d\n", logerr(ctime), inet_ntoa(clntaddr.sin_addr), ntohs(clntaddr.sin_port));
560 | free(request);
561 | continue;
562 | }
563 |
564 | char *iaddrptr = request;
565 | char *iportptr = strchr(iaddrptr, ':'); *iportptr = 0; ++iportptr;
566 | char *raddrptr = strchr(iportptr, ':'); *raddrptr = 0; ++raddrptr;
567 | char *rportptr = strchr(raddrptr, ':'); *rportptr = 0; ++rportptr;
568 | char *eportptr = strchr(rportptr, ':'); *eportptr = 0; ++eportptr;
569 | char *edataptr = strchr(eportptr, ':'); *edataptr = 0; ++edataptr;
570 |
571 | if (strlen(iaddrptr) < 7 || strlen(iaddrptr) > 15) {
572 | printf("%s [udp] bad request: %s:%d\n", logerr(ctime), inet_ntoa(clntaddr.sin_addr), ntohs(clntaddr.sin_port));
573 | free(request);
574 | continue;
575 | }
576 |
577 | if (strlen(iportptr) < 1 || strlen(iportptr) > 5) {
578 | printf("%s [udp] bad request: %s:%d\n", logerr(ctime), inet_ntoa(clntaddr.sin_addr), ntohs(clntaddr.sin_port));
579 | free(request);
580 | continue;
581 | }
582 |
583 | if (strlen(raddrptr) < 7 || strlen(raddrptr) > 15) {
584 | printf("%s [udp] bad request: %s:%d\n", logerr(ctime), inet_ntoa(clntaddr.sin_addr), ntohs(clntaddr.sin_port));
585 | free(request);
586 | continue;
587 | }
588 |
589 | if (strlen(rportptr) < 1 || strlen(rportptr) > 5) {
590 | printf("%s [udp] bad request: %s:%d\n", logerr(ctime), inet_ntoa(clntaddr.sin_addr), ntohs(clntaddr.sin_port));
591 | free(request);
592 | continue;
593 | }
594 |
595 | if (strlen(eportptr) < 1 || strlen(eportptr) > 5) {
596 | printf("%s [udp] bad request: %s:%d\n", logerr(ctime), inet_ntoa(clntaddr.sin_addr), ntohs(clntaddr.sin_port));
597 | free(request);
598 | continue;
599 | }
600 |
601 | if (strlen(edataptr) < 1) {
602 | printf("%s [udp] bad request: %s:%d\n", logerr(ctime), inet_ntoa(clntaddr.sin_addr), ntohs(clntaddr.sin_port));
603 | free(request);
604 | continue;
605 | }
606 |
607 | uint32_t raddr = inet_addr(raddrptr);
608 | if (raddr == INADDR_NONE) {
609 | printf("%s [udp] bad request: %s:%d\n", logerr(ctime), inet_ntoa(clntaddr.sin_addr), ntohs(clntaddr.sin_port));
610 | free(request);
611 | continue;
612 | }
613 |
614 | uint16_t rport = htons(strtol(rportptr, NULL, 10));
615 | if (rport == 0) {
616 | printf("%s [udp] bad request: %s:%d\n", logerr(ctime), inet_ntoa(clntaddr.sin_addr), ntohs(clntaddr.sin_port));
617 | free(request);
618 | continue;
619 | }
620 |
621 | int eport = strtol(eportptr, NULL, 10);
622 | if (eport < 0 || eport > 65535) {
623 | printf("%s [udp] bad request: %s:%d\n", logerr(ctime), inet_ntoa(clntaddr.sin_addr), ntohs(clntaddr.sin_port));
624 | free(request);
625 | continue;
626 | }
627 |
628 | size_t rawlen = 0;
629 | void *rawbuf = malloc(strlen(edataptr));
630 | if (base64_decode(edataptr, strlen(edataptr), rawbuf, &rawlen, 0) != 1) {
631 | printf("%s [udp] bad request: %s:%d\n", logerr(ctime), inet_ntoa(clntaddr.sin_addr), ntohs(clntaddr.sin_port));
632 | free(request);
633 | free(rawbuf);
634 | continue;
635 | }
636 | printf("%s [udp] recv %ld bytes data from %s:%d\n", loginf(ctime), rawlen, inet_ntoa(clntaddr.sin_addr), ntohs(clntaddr.sin_port));
637 |
638 | int esock = -1;
639 | if (eport != 0) {
640 | struct event *ev = udpnode_getev(arg, eport);
641 | if (ev != NULL) esock = event_get_fd(ev);
642 | }
643 |
644 | if (esock == -1) {
645 | esock = socket(AF_INET, SOCK_DGRAM, 0);
646 | evutil_make_socket_nonblocking(esock);
647 |
648 | struct sockaddr_in esrcaddr = {0};
649 | esrcaddr.sin_family = AF_INET;
650 | esrcaddr.sin_addr.s_addr = 0;
651 | esrcaddr.sin_port = 0;
652 |
653 | if (bind(esock, (struct sockaddr *)&esrcaddr, sizeof(esrcaddr)) == -1) {
654 | char error[64] = {0};
655 | printf("%s [udp] bind socket (any port): (%d) %s\n", logerr(ctime), errno, strerror_r(errno, error, 64));
656 | free(request);
657 | free(rawbuf);
658 | close(esock);
659 | continue;
660 | }
661 |
662 | memset(&esrcaddr, 0, addrlen);
663 | getsockname(esock, (struct sockaddr *)&esrcaddr, &addrlen);
664 | eport = ntohs(esrcaddr.sin_port);
665 |
666 | UDPArg *udparg = calloc(1, sizeof(UDPArg));
667 | strcpy(udparg->addr, iaddrptr);
668 | strcpy(udparg->port, iportptr);
669 | udparg->hash = arg;
670 | udparg->bev = bev;
671 |
672 | struct event *ev = event_new(bufferevent_get_base(bev), esock, EV_READ | EV_TIMEOUT | EV_PERSIST, udp_response_cb, udparg);
673 | struct timeval tv = {180, 0};
674 | event_add(ev, &tv);
675 |
676 | udpnode_put(arg, eport, ev);
677 | }
678 |
679 | struct sockaddr_in destaddr = {0};
680 | destaddr.sin_family = AF_INET;
681 | destaddr.sin_addr.s_addr = raddr;
682 | destaddr.sin_port = rport;
683 |
684 | if (sendto(esock, rawbuf, rawlen, 0, (struct sockaddr *)&destaddr, addrlen) == -1) {
685 | char error[64] = {0};
686 | printf("%s [udp] sendto %s:%s: (%d) %s\n", logerr(ctime), raddrptr, rportptr, errno, strerror_r(errno, error, 64));
687 | free(request);
688 | free(rawbuf);
689 | continue;
690 | }
691 | printf("%s [udp] send %ld bytes data to %s:%s\n", loginf(ctime), rawlen, raddrptr, rportptr);
692 | free(rawbuf);
693 | free(request);
694 | }
695 | }
696 |
697 | void udp_response_cb(int sock, short events, void *arg) {
698 | char ctime[36] = {0};
699 | UDPArg *udparg = arg;
700 | struct sockaddr_in esrcaddr = {0};
701 | socklen_t addrlen = sizeof(esrcaddr);
702 | getsockname(sock, (struct sockaddr *)&esrcaddr, &addrlen);
703 |
704 | if (events & EV_TIMEOUT) {
705 | printf("%s [udp] socket timeout: %s:%d\n", loginf(ctime), inet_ntoa(esrcaddr.sin_addr), ntohs(esrcaddr.sin_port));
706 | udpnode_del(udparg->hash, ntohs(esrcaddr.sin_port));
707 | return;
708 | }
709 |
710 | struct sockaddr_in destaddr = {0};
711 | void *rawbuf = malloc(UDP_RAW_BUFSIZ);
712 | int rawlen = recvfrom(sock, rawbuf, UDP_RAW_BUFSIZ, 0, (struct sockaddr *)&destaddr, &addrlen);
713 | if (rawlen == -1) {
714 | char error[64] = {0};
715 | printf("%s [udp] recv udp data: (%d) %s\n", logerr(ctime), errno, strerror_r(errno, error, 64));
716 | free(rawbuf);
717 | return;
718 | }
719 | printf("%s [udp] recv %d bytes data from %s:%d\n", loginf(ctime), rawlen, inet_ntoa(destaddr.sin_addr), ntohs(destaddr.sin_port));
720 |
721 | size_t enclen = 0;
722 | char *encbuf = malloc(UDP_ENC_BUFSIZ);
723 | base64_encode(rawbuf, rawlen, encbuf, &enclen, 0);
724 | encbuf[enclen] = 0;
725 | free(rawbuf);
726 |
727 | char raddr[16] = {0};
728 | char rport[6] = {0};
729 | char eport[6] = {0};
730 | strcpy(raddr, inet_ntoa(destaddr.sin_addr));
731 | sprintf(rport, "%d", ntohs(destaddr.sin_port));
732 | sprintf(eport, "%d", ntohs(esrcaddr.sin_port));
733 |
734 | bufferevent_write(udparg->bev, udparg->addr, strlen(udparg->addr));
735 | bufferevent_write(udparg->bev, ":", 1);
736 | bufferevent_write(udparg->bev, udparg->port, strlen(udparg->port));
737 | bufferevent_write(udparg->bev, ":", 1);
738 | bufferevent_write(udparg->bev, raddr, strlen(raddr));
739 | bufferevent_write(udparg->bev, ":", 1);
740 | bufferevent_write(udparg->bev, rport, strlen(rport));
741 | bufferevent_write(udparg->bev, ":", 1);
742 | bufferevent_write(udparg->bev, eport, strlen(eport));
743 | bufferevent_write(udparg->bev, ":", 1);
744 | bufferevent_write(udparg->bev, encbuf, strlen(encbuf));
745 | bufferevent_write(udparg->bev, "\r\n", 2);
746 | free(encbuf);
747 |
748 | memset(&destaddr, 0, addrlen);
749 | getpeername(bufferevent_getfd(udparg->bev), (struct sockaddr *)&destaddr, &addrlen);
750 | printf("%s [udp] send %d bytes data to %s:%d\n", loginf(ctime), rawlen, inet_ntoa(destaddr.sin_addr), ntohs(destaddr.sin_port));
751 | }
752 |
--------------------------------------------------------------------------------
/tls-server.service:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=tls-server
3 | Requires=network.target
4 | After=network.target
5 |
6 | [Service]
7 | Type=simple
8 | ExecStart=/usr/local/bin/tls-server -j2
9 | Restart=always
10 |
11 | [Install]
12 | WantedBy=multi-user.target
13 |
--------------------------------------------------------------------------------