├── .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 | --------------------------------------------------------------------------------