├── .gitignore ├── README.md ├── cert ├── client │ ├── cli.cnf │ └── create_cli_crt.sh └── serv │ ├── create_serv_crt.sh │ ├── root.cnf │ └── serv.cnf ├── china_domain ├── china_ipv4 ├── client.json ├── dnsmasq_china_list.conf ├── ipv6_white_list ├── netfilter ├── ip6tables.save ├── iptables.save ├── load_iptables.sh ├── load_nft.sh ├── nft_ipv4.save └── nft_ipv6.save ├── server.json └── src └── go_proxy ├── conn ├── addr.go ├── client.go ├── config.go ├── connection.go ├── dns_util.go ├── frame.go └── server.go ├── exception └── err.go ├── go.mod ├── go.sum ├── local_proxy ├── connection_handler.go ├── handle_http.go ├── handle_iptables.go ├── handle_socks5.go └── local_proxy.go ├── main.go ├── server ├── tcp_server.go └── udp_server.go └── util ├── config.go ├── crypt.go └── logger.go /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | pkg 3 | golang.org 4 | 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 轻量级代理 2 | ====== 3 | 纯go实现的基于http,socks5代理,主要用于翻墙 4 | 5 | 6 | 使用方法 7 | ====== 8 | 修改文件目录下的go_proxy.json配置文件: 9 | ------- 10 | { 11 | 12 | "Udp_timeout":60, //udp超时时间 13 | "Ulimit":1024000, //linux最大打开文件数(最大打开连接数),取值范围0-1048576 14 | 15 | } 16 | 17 | 18 | 服务端 19 | ------- 20 | 任意linux系统 21 | 修改目录下的server.json配置文件 22 | 23 | { 24 | "Servers": [ // 数组 可以配置多个 25 | 26 | { 27 | "Tls": { 28 | "On": true, // 是否打开tls 29 | "Tcp_encrypt":false, //tcp封装tls之前是否加密,需要与客户端一致 30 | "Server_cert": "cert/serv/server.crt", //服务器证书链 31 | "Server_private_key": "cert/serv/server.key", //服务器私钥 32 | "Client_certs": [ //客户端证书 33 | "cert/client/client1.crt", 34 | "cert/client/client2.crt" 35 | ] 36 | }, 37 | "Tcp_listen_port": 9999, //tcp监听端口 38 | "Udp_listen_port": 9999, //udp监听端口 39 | "Enc_method": "chacha20", //加密方式,仅支持chacha20和aes-256-cfb 40 | "Password": "" //密码,必须为32个字符 41 | } 42 | 43 | ], 44 | 45 | } 46 | 47 | 执行 ./go_proxy -c server.json -s start 48 | 49 | 重启(仅支持linux) ./go_proxy -s restart 50 | 51 | 停止(仅支持linux) ./go_proxy -s stop 52 | 53 | 或者需要后台运行(仅支持linux) ./go_proxy -c server.json --daemon 54 | 55 | 56 | 如无意外 netstat -apn | grep LISTEN 能看到go_proxy进程监听的端口 57 | 58 | 59 | 客户端 本地代理 60 | ------ 61 | 62 | 修改client.json,支持http和socks5,http不能代理ftp 63 | 64 | { 65 | 66 | "Clients": [ //数组 可配置多个 67 | { 68 | "Mode": "http", //模式 本地代理只支持http和socks5 69 | "Ipv6": true, //是否打开ipv6支持 需要服务器支持ipv6 70 | "Local_addr": "0.0.0.0:1234", //本地监听地址 可以ip或域名 71 | "Tcp_server_addr": "ydx.com:4343", //tcp服务器地址 72 | "Udp_server_addr": "ydx.com:4343", //udp服务器地址,http代理可以不填 73 | "Front_proxy":"http://username:passwd@127.0.0.1:8080/" //前置代理 支持http socks5 74 | "Enc_method": "chacha20", //加密方式 75 | "Password": "", //密码 必须32个字符 76 | "Local_dns_addr": "114.114.114.114:53", //本地dns地址 77 | "Remote_dns_addr": "8.8.8.8:53", //远程dns地址 78 | "Connection_max_payload": 10, //单个远程链接最大负载 79 | "Domain_cache_time": 3600, //dns缓存时间 秒 0则不缓存 80 | "Udp_in_tcp": false, //是否用tcp发送udp包 如果flase且地址类型是域名,由远程服务器默认dns解释。 81 | "Tls": { 82 | "On": true, //是否打开tls 83 | "Server_name":"ydx.com", //证书域名,空则使用 Server_addr 84 | "Tcp_encrypt": false, //tcp封装tls之前是否加密,需要与服务端一致 85 | "Root_cert_path": "cert/serv/root.crt", //服务器根证书 86 | "Private_key": "cert/client/client.key", //客户端私钥 87 | "Certificate": "cert/client/client.crt" //客户端证书链 88 | } 89 | }, 90 | 91 | ], 92 | 93 | 94 | } 95 | 96 | china_domain 用于排除国内域名,来源于项目 https://github.com/felixonmars/dnsmasq-china-list 97 | 98 | china_ipv4 为中国大陆ip段,用于排除国内ip,来源于项目 https://github.com/17mon/china_ip_list 99 | 100 | ipv6_white_list 不走代理的ipv6地址 101 | 102 | 执行 ./go_proxy -c client.json -s start --china-ipv4=china_ipv4 --china-domain=china_domain --ipv6-white-list=ipv6_white_list 103 | 104 | 重启(仅支持linux) ./go_proxy -s restart 105 | 106 | 停止(仅支持linux) ./go_proxy -s stop 107 | 108 | 或者需要后台运行(仅支持linux) ./go_proxy -c client.json --daemon --china-ipv4=china_ipv4 --china-domain=china_domain --ipv6-white-list=ipv6_white_list 109 | 110 | 然后在系统代理或者一些浏览器插件上代理设置为对应ip和端口 111 | 112 | 113 | 客户端 iptables透明代理 仅支持linux 114 | ------ 115 | 建议在64位机运行,支持ipv4,ipv6。一般来说,作为路由至少要有两块网卡。假设eth0为连接公网接口,br0为局域网接口,ip为192.168.1.1。 116 | 首先确保linux内核不低于2.6且安装了dnsmasq,iptables,ipset,且通过br0接口的机器能正常访问公网 117 | 118 | 通常,linux做路由器要打开ip转发: 119 | 120 | 编辑/etc/sysctl.conf 121 | 添加三行 122 | 123 | net.ipv4.ip_forward=1 124 | 125 | net.ipv4.conf.all.rp_filter=0 126 | 127 | net.ipv4.conf.all.route_localnet=1 128 | 129 | 命令行执行 130 | 131 | sysctl -p 132 | 133 | 然后iptables设置: 134 | 135 | iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE 136 | 137 | 这样连接到br0的机器应该能访问公网了(这里省略dhcp地址获取等问题,没有配置dhcp服务器需要手动设置ip地址)。 138 | 139 | 140 | 修改client.json 141 | 142 | { 143 | "Clients": [ 144 | { 145 | "Mode": "iptables", //模式iptables 146 | "ipv6":false, //是否打开ipv6支持 需要服务器支持ipv6 147 | "Local_port": 3939, // 本地监听端口 148 | "Front_proxy":"http://username:passwd@127.0.0.1:8080/" //前置代理 支持http socks5 149 | "Interface":"br0", //接口名称 150 | "Tcp_server_addr": "ydx.com:4343", //tcp服务器地址 151 | "Udp_server_addr": "ydx.com:4343", //udp服务器地址 152 | "Enc_method": "chacha20", //加密方式 153 | "Password": "", //密码 必须32个字符 154 | "Remote_dns_addr": "8.8.4.4:53", //远程dns地址 155 | "Connection_max_payload": 10, //单个远程链接最大负载 156 | "Udp_in_tcp": false, //是否用tcp发送udp包 157 | "Tls": { 158 | "On": true, //是否打开tls 159 | "Server_name":"ydx.com", //证书域名,空则使用 Server_addr 160 | "Tcp_encrypt": false, //tcp封装tls之前是否加密,需要与服务端一致 161 | "Root_cert_path": "cert/serv/root.crt", //服务器根证书 162 | "Private_key": "cert/client/client.key", //客户端私钥 163 | "Certificate": "cert/client/client.crt" //客户端证书链 164 | } 165 | } 166 | 167 | ] 168 | } 169 | 170 | 首先修改dnsmasq配置文件: 171 | 172 | 编辑/etc/dnsmasq.conf: 173 | 174 | 取消no-resolv 和 bind-interfaces 注释 175 | 176 | 取消listen-address注释 并修改为 listen-address=127.0.0.1,192.168.1.1 //192.168.1.1 为br0网关地址 177 | 这里一定不要绑定为0.0.0.0,并且尽量不要有监听"0.0.0.0"或者":::"地址的udp套接字(因为udp回路实现是直接绑定原始目的地址端口发送(IP_TRANSPARENT) 如果某个端口监听0.0.0.0,导致地址冲突不能绑定) 178 | 179 | 在最后添加 180 | 181 | server=127.0.0.1#9999 //上游dns地址 9999修改为客户端监听的端口 182 | 183 | conf-dir=/etc/dnsmasq.d/ //dnsmasq规则文件的路径 184 | 185 | 复制dnsmasq_china_list.conf到dnsmasq规则文件的路径 来源于项目: https://github.com/felixonmars/dnsmasq-china-list 186 | 187 | 在这列表中的域名都会使用指定地址解析,其他域名都会使用上游地址解析。可以自行添加,格式:server=/域名/dns地址。 188 | 189 | 运行dnsmasq服务 190 | 191 | systemctl start dnsmasq 192 | 193 | 局域网的主机dns地址设置为192.168.1.1,则可以实现国内域名白名单 194 | 195 | 添加中国ip到ipset中: 196 | 197 | 在go_proxy2目录下执行(bash环境 不同shell语法不同) 198 | 199 | ipset create local hash:net 200 | 201 | ipset add local 99.99.99.99/32 //99.99.99.99换成服务端ip 202 | 203 | for line in `cat china_ipv4`; do ipset add local $line; done; 204 | 205 | 创建新链: 206 | 207 | iptables -t mangle -N GO_PROXY 208 | 209 | 210 | 局域网和服务端地址return,非中国ip tproxy到本地: 211 | 212 | iptables -t mangle -A GO_PROXY -m set --match-set local dst -j RETURN 213 | 214 | tcp透明代理: 215 | 216 | iptables -t mangle -A GO_PROXY -p tcp -j TPROXY --on-ip 127.0.0.1 --on-port 9999 --tproxy-mark 0x1/0x1 #9999改成客户端本地监听的端口 217 | 218 | iptables -t mangle -A PREROUTING -p tcp -j GO_PROXY 219 | 220 | 221 | udp透明代理: 222 | 223 | iptables -t mangle -A GO_PROXY -p udp -j TPROXY --on-ip 127.0.0.1 --on-port 9999 --tproxy-mark 0x1/0x1 #9999改成客户端本地监听的端口 224 | 225 | iptables -t mangle -A PREROUTING -p udp -j GO_PROXY 226 | 227 | 路由器本地流量tproxy: 228 | 229 | //由于路由器本身流量不走PREROUTING链,需要OUTPUT链set mark重新路由到PREROUTING 230 | 231 | iptables -t mangle -A OUTPUT -m set --match-set local dst -j RETURN 232 | 233 | iptables -t mangle -A OUTPUT -j MARK --set-mark 0x1/0x1 234 | 235 | 添加路由策略: 236 | 237 | ip rule add fwmark 0x1/0x1 table 100 238 | 239 | ip route add local default dev lo table 100 240 | 241 | 242 | ipv6 透明代理 243 | 244 | sysctl net.ipv6.conf.all.forwarding=1 245 | 246 | ipset create ipv6_whitelist hash:net family inet6 247 | 248 | for line in `cat ipv6_white_list`; do ipset add ipv6_whitelist $line; done; 249 | 250 | ip6tables -t mangle -N GO_PROXY 251 | 252 | ip6tables -t mangle -A GO_PROXY -m set --match-set ipv6_whitelist dst -j RETURN 253 | 254 | #tcp 255 | 256 | ip6tables -t mangle -A GO_PROXY -p tcp -j TPROXY --on-ip ::1 --on-port 9999 --tproxy-mark 0x1/0x1 #9999改成客户端本地监听的端口 257 | 258 | ip6tables -t mangle -A PREROUTING -p tcp -j GO_PROXY 259 | 260 | #udp 261 | 262 | ip6tables -t mangle -A GO_PROXY -p udp -j TPROXY --on-ip ::1 --on-port 9999 --tproxy-mark 0x1/0x1 #9999改成客户端本地监听的端口 263 | 264 | ip6tables -t mangle -A PREROUTING -p udp -j GO_PROXY 265 | 266 | #reroute 267 | 268 | ip6tables -t mangle -A OUTPUT -m set --match-set ipv6_whitelist dst -j RETURN 269 | 270 | ip6tables -t mangle -A OUTPUT -j MARK --set-mark 0x1/0x1 271 | 272 | #add route rule 273 | 274 | ip -6 rule add fwmark 0x1/0x1 table 100 275 | 276 | ip -6 route add local default dev lo table 100 277 | 278 | 执行: 279 | 280 | ./go_proxy -c client.json -s start 281 | 282 | 或者需要后台运行: 283 | 284 | ./go_proxy -c client.json --daemon 285 | 286 | 所有路由到192.168.1.1的设备理应都会通过代理访问 287 | 288 | 289 | 关于证书 290 | ------- 291 | 开启tls会进行双向校验,因此需要生成服务端与客户端的私钥与自签证书。 292 | 293 | 服务端需要自身证书与私钥,并添加客户端的证书作为校验。 294 | 295 | 客户端需要自身证书与私钥,并添加服务端的根证书信任。 296 | 297 | cert目录下包含生成证书的脚本。 298 | 299 | 切到cert/serv目录下修改cert/serv/serv.cnf 中 alt_names.IP.1 改为服务器ip 或者 alt_names.NDS.1改为服务器域名, 300 | 这里的值要与Client.Server_addr一致 301 | 302 | 执行 bash create_serv_crt.sh 生成证书与私钥,其中root.crt是根证书,server.crt 和 server.key 是服务器证书与私钥 303 | 304 | 切到cert/client目录下 执行 bash create_cli_crt.sh 生成单个客户端证书与私钥 305 | 306 | bash create_cli_crt.sh ${n} 批量生成 ${n}为整数 307 | 308 | 309 | -------------------------------------------------------------------------------- /cert/client/cli.cnf: -------------------------------------------------------------------------------- 1 | [ req ] 2 | default_bits = 2048 3 | prompt = no 4 | distinguished_name = dn 5 | 6 | [ dn ] 7 | C = CN 8 | ST = CN 9 | L = CN 10 | O = miku_fan 11 | OU = miku_fan 12 | 13 | 14 | 15 | 16 | [ v3_ext ] 17 | extendedKeyUsage=clientAuth 18 | 19 | -------------------------------------------------------------------------------- /cert/client/create_cli_crt.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | if [ "$#" -eq 0 ];then 5 | openssl genrsa -out client.key 2048 6 | 7 | openssl req -x509 -new -nodes -key client.key -days 3650 -out client.crt -config cli.cnf -extensions v3_ext 8 | 9 | exit 0 10 | fi 11 | 12 | re='^[0-9]+$' 13 | if ! [[ $1 =~ $re ]] ; then 14 | echo "param 1 must a number" 15 | exit 1 16 | fi 17 | 18 | for i in `seq 1 1 $1`;do 19 | 20 | openssl genrsa -out client_$i.key 2048 21 | 22 | openssl req -x509 -new -nodes -key client_$i.key -days 3650 -out client_$i.crt -config cli.cnf -extensions v3_ext 23 | 24 | 25 | done 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /cert/serv/create_serv_crt.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | echo "create root private key" 5 | echo 6 | openssl genrsa -out root.key 2048 7 | 8 | echo "create root cert" 9 | echo 10 | openssl req -x509 -new -nodes -key root.key -days 3650 -out root.crt -config root.cnf 11 | 12 | echo "create server private key" 13 | echo 14 | openssl genrsa -out server.key 2048 15 | 16 | echo "create server sign request" 17 | echo 18 | openssl req -new -key server.key -config serv.cnf -extensions v3_ext -out server.csr 19 | 20 | echo "sign" 21 | echo 22 | openssl x509 -req -days 3650 -in server.csr -CA root.crt -CAkey root.key -out server.crt -CAcreateserial -extensions v3_ext -extfile serv.cnf 23 | 24 | rm server.csr 25 | rm root.srl 26 | 27 | 28 | -------------------------------------------------------------------------------- /cert/serv/root.cnf: -------------------------------------------------------------------------------- 1 | [ req ] 2 | default_bits = 2048 3 | prompt = no 4 | distinguished_name = dn 5 | 6 | [ dn ] 7 | C = HK 8 | ST = HK 9 | L = HK 10 | O = root 11 | OU = root 12 | 13 | 14 | -------------------------------------------------------------------------------- /cert/serv/serv.cnf: -------------------------------------------------------------------------------- 1 | [ req ] 2 | default_bits = 2048 3 | prompt = no 4 | req_extensions = req_ext 5 | distinguished_name = dn 6 | 7 | [ dn ] 8 | C = HK 9 | ST = HK 10 | L = HK 11 | O = miku_fan 12 | OU = miku_fan 13 | 14 | 15 | [ req_ext ] 16 | subjectAltName = @alt_names 17 | 18 | [ alt_names ] 19 | DNS.1 = ydx.com 20 | DNS.2= cn1.vxtrans.link 21 | DNS.3= cn2.vxtrans.link 22 | IP.1 = 47.244.137.231 23 | 24 | [ v3_ext ] 25 | extendedKeyUsage=serverAuth 26 | subjectAltName=@alt_names 27 | -------------------------------------------------------------------------------- /client.json: -------------------------------------------------------------------------------- 1 | { 2 | 3 | "Clients": [ 4 | { 5 | "Mode": "http", 6 | "Ipv6": false, 7 | "Local_addr": "0.0.0.0:3939", 8 | "Front_proxy":"http://username:passwd@127.0.0.1:8080/", 9 | "Tcp_server_addr": "133.130.98.136:33999", 10 | "Enc_method": "chacha20", 11 | "Password": "12345678901234567890123456789012", 12 | "Local_dns_addr": "114.114.114.114:53", 13 | "Remote_dns_addr": "8.8.4.4:53", 14 | "Connection_max_payload": 10, 15 | "Domain_cache_time": 3600, 16 | "Tls": { 17 | "On": true, 18 | "Server_name":"ydx.com", 19 | "Tcp_encrypt": false, 20 | "Root_cert_path": "cert/serv/root.crt", 21 | "Private_key": "cert/client/client.key", 22 | "Certificate": "cert/client/client.crt" 23 | } 24 | }, 25 | { 26 | "Mode": "socks5", 27 | "Ipv6": false, 28 | "Local_addr": "0.0.0.0:19191", 29 | "Front_proxy":"http://username:passwd@127.0.0.1:8080/", 30 | "Tcp_server_addr": "133.130.98.136:33999", 31 | "Udp_server_addr": "133.130.98.136:9999", 32 | "Enc_method": "chacha20", 33 | "Password": "12345678901234567890123456789012", 34 | "Local_dns_addr": "114.114.114.114:53", 35 | "Remote_dns_addr": "8.8.8.8:53", 36 | "Connection_max_payload": 10, 37 | "Domain_cache_time": 3600, 38 | "Udp_in_tcp": false, 39 | "Tls": { 40 | "On": true, 41 | "Server_name":"ydx.com", 42 | "Tcp_encrypt": false, 43 | "Root_cert_path": "cert/serv/root.crt", 44 | "Private_key": "cert/client/client.key", 45 | "Certificate": "cert/client/client.crt" 46 | } 47 | }, 48 | { 49 | "Mode": "iptables", 50 | "Ipv6":false, 51 | "Interface": "wlan0", 52 | "Local_port": 9999, 53 | "Front_proxy":"http://username:passwd@127.0.0.1:8080/", 54 | "Tcp_server_addr": "133.130.98.136:33999", 55 | "Udp_server_addr": "133.130.98.136:9999", 56 | "Enc_method": "chacha20", 57 | "Password": "12345678901234567890123456789012", 58 | "Remote_dns_addr": "8.8.4.4:53", 59 | "Connection_max_payload": 10, 60 | "Udp_in_tcp": false, 61 | "Tls": { 62 | "On": true, 63 | "Server_name":"ydx.com", 64 | "Tcp_encrypt": false, 65 | "Root_cert_path": "cert/serv/root.crt", 66 | "Private_key": "cert/client/client.key", 67 | "Certificate": "cert/client/client.crt" 68 | } 69 | } 70 | 71 | ], 72 | 73 | "Ulimit": 1024000, 74 | "Udp_timeout": 30 75 | } 76 | -------------------------------------------------------------------------------- /ipv6_white_list: -------------------------------------------------------------------------------- 1 | ::1/128 2 | ::/128 3 | ::ffff:0:0/96 4 | 64:ff9b::/96 5 | 64:ff9b:1::/48 6 | 100::/64 7 | 2001::/23 8 | 2002::/16 9 | 2620:4f:8000::/48 10 | ff00::/8 11 | fc00::/7 12 | fe80::/10 13 | -------------------------------------------------------------------------------- /netfilter/ip6tables.save: -------------------------------------------------------------------------------- 1 | # Generated by ip6tables-save v1.8.3 on Wed Jan 22 14:34:50 2020 2 | *mangle 3 | :PREROUTING ACCEPT [76:68922] 4 | :INPUT ACCEPT [191:79068] 5 | :FORWARD ACCEPT [0:0] 6 | :OUTPUT ACCEPT [209:79600] 7 | :POSTROUTING ACCEPT [209:79600] 8 | :GO_PROXY - [0:0] 9 | -A PREROUTING -p tcp -j GO_PROXY 10 | -A PREROUTING -p udp -j GO_PROXY 11 | -A OUTPUT -m set --match-set ipv6_whitelist dst -j RETURN 12 | -A OUTPUT -j MARK --set-xmark 0x1/0x1 13 | -A GO_PROXY -m set --match-set ipv6_whitelist dst -j RETURN 14 | -A GO_PROXY -p tcp -j TPROXY --on-port 9999 --on-ip ::1 --tproxy-mark 0x1/0x1 15 | -A GO_PROXY -p udp -j TPROXY --on-port 9999 --on-ip ::1 --tproxy-mark 0x1/0x1 16 | COMMIT 17 | # Completed on Wed Jan 22 14:34:50 2020 18 | -------------------------------------------------------------------------------- /netfilter/iptables.save: -------------------------------------------------------------------------------- 1 | # Generated by iptables-save v1.8.3 on Wed Jan 22 14:34:53 2020 2 | *mangle 3 | :PREROUTING ACCEPT [44738:55661369] 4 | :INPUT ACCEPT [57821:56784725] 5 | :FORWARD ACCEPT [376:164933] 6 | :OUTPUT ACCEPT [46726:43396829] 7 | :POSTROUTING ACCEPT [47070:43554237] 8 | :GO_PROXY - [0:0] 9 | -A PREROUTING -p tcp -j GO_PROXY 10 | -A PREROUTING -p udp -j GO_PROXY 11 | -A OUTPUT -m set --match-set local dst -j RETURN 12 | -A OUTPUT -j MARK --set-xmark 0x1/0x1 13 | -A GO_PROXY -m set --match-set local dst -j RETURN 14 | -A GO_PROXY -p tcp -j TPROXY --on-port 9999 --on-ip 127.0.0.1 --tproxy-mark 0x1/0x1 15 | -A GO_PROXY -p udp -j TPROXY --on-port 9999 --on-ip 127.0.0.1 --tproxy-mark 0x1/0x1 16 | COMMIT 17 | # Completed on Wed Jan 22 14:34:53 2020 18 | # Generated by iptables-save v1.8.3 on Wed Jan 22 14:34:53 2020 19 | *filter 20 | :INPUT ACCEPT [57918:56802514] 21 | :FORWARD ACCEPT [376:164933] 22 | :OUTPUT ACCEPT [46873:43407519] 23 | COMMIT 24 | # Completed on Wed Jan 22 14:34:53 2020 25 | -------------------------------------------------------------------------------- /netfilter/load_iptables.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | server_addr_v4=(99.99.99.99 11.11.11.11) 5 | server_addr_v6=() 6 | cd "$(dirname "$0")" 7 | 8 | ##ipv4## 9 | ipset create local hash:net 10 | 11 | for i in ${server_addr_v4[@]} ; do ipset add local $i ; done; 12 | 13 | for i in `cat ../china_ipv4` ; do ipset add local $i ; done; 14 | 15 | iptables-restore iptables.save 16 | 17 | ip rule add fwmark 0x1 table 100 18 | ip route add local default dev lo table 100 19 | 20 | 21 | ##ipv6## 22 | ipset create ipv6_whitelist hash:net family inet6 23 | 24 | for i in `cat ../ipv6_white_list` ; do ipset add ipv6_whitelist $i ; done; 25 | 26 | for i in ${server_addr_v6[@]} ; do ipset add ipv6_whitelist $i ; done; 27 | 28 | ip6tables-restore ip6tables.save 29 | 30 | ip -6 rule add fwmark 0x1 table 100 31 | ip -6 route add local default dev lo table 100 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /netfilter/load_nft.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | server_addr_v4=(99.99.99.99 11.11.11.11 ) 6 | server_addr_v6=() 7 | 8 | cd "$(dirname "$0")" 9 | 10 | nft add table ip go_proxy 11 | 12 | nft add set ip go_proxy ipv4_whitelist \{type ipv4_addr\; flags constant,interval\;\} 13 | 14 | for i in `cat ../china_ipv4`; do nft add element go_proxy ipv4_whitelist \{ $i \} ; done; 15 | 16 | for i in ${server_addr_v4[@]} ; do nft add element go_proxy ipv4_whitelist \{ $i \} ; done; 17 | 18 | 19 | nft list set go_proxy ipv4_whitelist > nft_set_ipv4.save 20 | 21 | sed -i '1d' nft_set_ipv4.save 22 | sed -i '$d' nft_set_ipv4.save 23 | 24 | nft -I . -f nft_ipv4.save 25 | 26 | rm nft_set_ipv4.save 27 | 28 | ip rule add fwmark 0x1 table 100 29 | ip route add local default dev lo table 100 30 | 31 | nft add table ip6 go_proxy_ipv6 32 | 33 | nft add set ip6 go_proxy_ipv6 ipv6_whitelist \{type ipv6_addr\; flags constant,interval \; auto-merge auto-merge \; \} 34 | 35 | for i in `cat ../ipv6_white_list`; do nft add element ip6 go_proxy_ipv6 ipv6_whitelist \{ $i \} ; done; 36 | 37 | for i in ${server_addr_v6[@]} ; do nft add element ip6 go_proxy_ipv6 ipv6_whitelist \{ $i \} ; done; 38 | 39 | nft list set ip6 go_proxy_ipv6 ipv6_whitelist > nft_set_ipv6.save 40 | 41 | sed -i '1d' nft_set_ipv6.save 42 | sed -i '$d' nft_set_ipv6.save 43 | 44 | nft -I . -f nft_ipv6.save 45 | 46 | rm nft_set_ipv6.save 47 | 48 | ip -6 rule add fwmark 0x1 table 100 49 | ip -6 route add local default dev lo table 100 50 | -------------------------------------------------------------------------------- /netfilter/nft_ipv4.save: -------------------------------------------------------------------------------- 1 | 2 | table ip go_proxy { 3 | 4 | include "nft_set_ipv4.save" 5 | 6 | chain go_proxy { 7 | ip protocol udp tproxy to 127.0.0.1:9999 meta mark set 0x00000001 8 | ip protocol tcp tproxy to 127.0.0.1:9999 meta mark set 0x00000001 9 | } 10 | 11 | chain prerouting { 12 | type filter hook prerouting priority mangle ; policy accept; 13 | ip daddr @ipv4_whitelist return 14 | jump go_proxy 15 | } 16 | 17 | chain output { 18 | type route hook output priority 0; policy accept; 19 | ip daddr @ipv4_whitelist return 20 | meta mark set 0x00000001 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /netfilter/nft_ipv6.save: -------------------------------------------------------------------------------- 1 | 2 | table ip6 go_proxy_ipv6 { 3 | 4 | include "nft_set_ipv6.save" 5 | 6 | chain go_proxy { 7 | udp dport 1-65535 tproxy to [::1]:9999 meta mark set 0x00000001 8 | tcp dport 1-65535 tproxy to [::1]:9999 meta mark set 0x00000001 9 | } 10 | 11 | chain prerouting { 12 | type filter hook prerouting priority mangle ; policy accept; 13 | ip6 daddr @ipv6_whitelist return 14 | jump go_proxy 15 | } 16 | 17 | chain output { 18 | type route hook output priority 0; policy accept; 19 | ip6 daddr @ipv6_whitelist return 20 | meta mark set 0x00000001 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /server.json: -------------------------------------------------------------------------------- 1 | { 2 | 3 | "Servers": [ 4 | { 5 | "Tls": { 6 | "On": true, 7 | "Tcp_encrypt":false, 8 | "Server_cert": "cert/serv/server.crt", 9 | "Server_private_key": "cert/serv/server.key", 10 | "Client_certs": [ 11 | "cert/client/client.crt" 12 | ] 13 | }, 14 | "Tcp_listen_port": 9999, 15 | "Udp_listen_port": 9999, 16 | "Enc_method": "chacha20", 17 | "Password": "12345678901234567890123456789012" 18 | } 19 | ], 20 | 21 | "Ulimit": 1024000, 22 | "Udp_timeout": 30 23 | } 24 | -------------------------------------------------------------------------------- /src/go_proxy/conn/addr.go: -------------------------------------------------------------------------------- 1 | package conn 2 | 3 | import ( 4 | "encoding/binary" 5 | "fmt" 6 | "go_proxy/exception" 7 | "go_proxy/util" 8 | "math" 9 | "net" 10 | "strconv" 11 | "strings" 12 | "sync" 13 | ) 14 | 15 | var ( 16 | rlock = &sync.RWMutex{} 17 | ) 18 | 19 | type Addr interface { 20 | String() string 21 | StringWithPort() string 22 | ToHostBytes() []byte 23 | ToPortByte() []byte 24 | Type() int 25 | IsChinaAddr() bool 26 | IsDomain() bool 27 | ToPortInt() int 28 | } 29 | 30 | type AddrIPPort struct { 31 | ip []byte 32 | port [2]byte 33 | _type int 34 | is_cn bool 35 | is_cn_check bool 36 | } 37 | 38 | 39 | 40 | func (this *AddrIPPort) parseFromString(s string, _type int) (Addr, error) { 41 | var ( 42 | sp []string 43 | ip []byte 44 | ) 45 | ip_len := 0 46 | switch _type { 47 | case Addr_type_ipv4: 48 | sp = strings.Split(s, ":") 49 | ip = net.ParseIP(sp[0]).To4() 50 | if ip == nil { 51 | return nil, (&exception.AddrErr{}).New("ipv6 ip format illegal") 52 | } 53 | ip_len = 4 54 | 55 | case Addr_type_ipv6: 56 | sp = strings.Split(s, "]:") 57 | if len(sp[0])<1{ 58 | return nil, (&exception.AddrErr{}).New("ipv6 ip format illegal") 59 | } 60 | sp[0]=sp[0][1:] 61 | ip = net.ParseIP(sp[0]).To16() 62 | if ip == nil { 63 | return nil, (&exception.AddrErr{}).New("ipv6 ip format illegal") 64 | } 65 | ip_len = 16 66 | default: 67 | panic("unknow error") 68 | } 69 | 70 | port, err := strconv.Atoi(sp[1]) 71 | if err != nil || port > 65535 { 72 | return nil, (&exception.AddrErr{}).New("ipv4 port illegal") 73 | } 74 | this.ip = make([]byte, ip_len) 75 | for i := 0; i < ip_len; i++ { 76 | this.ip[i] = ip[i] 77 | } 78 | binary.BigEndian.PutUint16(this.port[:], uint16(port)) 79 | this._type = _type 80 | return this, nil 81 | } 82 | 83 | func (this *AddrIPPort) Type() int { 84 | return this._type 85 | } 86 | 87 | func (this *AddrIPPort) String() string { 88 | return net.IP(this.ip).String() 89 | } 90 | 91 | func (this *AddrIPPort) StringWithPort() string { 92 | if this._type == Addr_type_ipv6 { 93 | return fmt.Sprintf("[%s]:%d", net.IP(this.ip).String(), this.ToPortInt()) 94 | } else { 95 | return net.IP(this.ip).String() + ":" + strconv.Itoa(this.ToPortInt()) 96 | } 97 | 98 | } 99 | 100 | func (this *AddrIPPort) ToHostBytes() []byte { 101 | return this.ip 102 | } 103 | 104 | func (this *AddrIPPort) ToPortByte() []byte { 105 | return this.port[:] 106 | } 107 | 108 | func (this *AddrIPPort) ToPortInt() int { 109 | return (int(this.port[0])<<8)+int(this.port[1]) 110 | } 111 | 112 | func (this *AddrIPPort) IsDomain() bool { 113 | return false 114 | } 115 | 116 | func (this *AddrIPPort) IsChinaAddr() bool { 117 | if this.is_cn_check { 118 | return this.is_cn 119 | } 120 | defer func() { 121 | this.is_cn_check = true 122 | }() 123 | if this._type == Addr_type_ipv6 { 124 | for mask := 1; mask <= 128; mask++ { 125 | i := mask / 8 126 | j := mask % 8 127 | m := make([]byte, 16) 128 | k := 0 129 | for ; k < i; k++ { 130 | m[k] = 255 131 | } 132 | if j != 0 { 133 | m[k] = byte(math.Pow(2, float64(j))) - 1 134 | } 135 | 136 | ip := make([]byte, 16) 137 | copy(ip, this.ip) 138 | for l := 0; l < 16; l++ { 139 | ip[l] = this.ip[l] & m[l] 140 | } 141 | 142 | rlock.RLock() 143 | __mask, ok := util.Local_ipv6[net.IP(ip).To16().String()] 144 | rlock.RUnlock() 145 | if ok && __mask == mask { 146 | this.is_cn = true 147 | return true 148 | } 149 | 150 | } 151 | this.is_cn = false 152 | return false 153 | } else { 154 | l := uint(len(this.ip)) 155 | var dest_ipint uint = 0 156 | var i uint = 0 157 | for ; i < l; i++ { 158 | dest_ipint += uint(this.ip[i]) << uint(((l - i - 1) * 8)) 159 | } 160 | for mask := 1; mask <= 32; mask++ { 161 | rlock.RLock() 162 | v, ok := util.China_ipv4[dest_ipint&(uint((math.Pow(2, float64(mask)))-1)< 255 { 195 | return nil, (&exception.AddrErr{}).New("domain format illegal") 196 | } 197 | 198 | this.domain = d 199 | 200 | port, err := strconv.Atoi(sp[1]) 201 | if err != nil || port > 65535 || port <= 0 { 202 | return nil, (&exception.AddrErr{}).New("port illegal") 203 | } 204 | 205 | this.port = uint16(port) 206 | 207 | if try6 { 208 | this._type = Addr_domain_try_ipv6 209 | } else { 210 | this._type = Addr_domain 211 | } 212 | 213 | return this, nil 214 | } 215 | 216 | func (this *Domain) Type() int { 217 | return this._type 218 | } 219 | 220 | func (this *Domain) String() string { 221 | return this.domain 222 | } 223 | 224 | func (this *Domain) StringWithPort() string { 225 | return this.domain + ":" + strconv.Itoa(int(this.port)) 226 | } 227 | 228 | func (this *Domain) ToHostBytes() []byte { 229 | return []byte(this.domain) 230 | } 231 | 232 | func (this *Domain) ToPortByte() []byte { 233 | b := [2]byte{} 234 | binary.BigEndian.PutUint16(b[:], this.port) 235 | return b[:] 236 | } 237 | func (this *Domain) ToPortInt() int { 238 | return int(this.port) 239 | } 240 | 241 | 242 | func (this *Domain) IsChinaAddr() bool { 243 | if this.is_cn_check { 244 | return this.is_cn 245 | } 246 | defer func() { 247 | this.is_cn_check = true 248 | }() 249 | 250 | if this.domain == "" { 251 | this.is_cn=true 252 | return true 253 | } 254 | 255 | rlock.RLock() 256 | if _, ok := util.Cn_domain_map[this.String()];ok{ 257 | this.is_cn=true 258 | return true 259 | } 260 | rlock.RUnlock() 261 | 262 | _domain := strings.Split(this.domain, ".") 263 | if _domain[len(_domain)-1] == "cn" { 264 | this.is_cn=true 265 | return true 266 | } 267 | 268 | d := "" 269 | if len(_domain) == 1 { 270 | this.is_cn=true 271 | return true 272 | } else { 273 | d = strings.Join(_domain[len(_domain)-2:], ".") 274 | } 275 | rlock.RLock() 276 | _, ok := util.Cn_domain_map[d] 277 | rlock.RUnlock() 278 | 279 | this.is_cn = ok 280 | return ok 281 | } 282 | 283 | func (this *Domain) IsDomain() bool { 284 | return true 285 | } 286 | 287 | func NewAddrFromString(addr string, domain_try_ipv6 bool) (Addr, error) { 288 | if len(addr) < 4 { 289 | return nil, exception.AddrErr{}.New("addr format illegal") 290 | } 291 | ipv6:=false 292 | 293 | var sp []string 294 | if addr[0] == '[' { 295 | ipv6=true 296 | sp = strings.Split(addr, "]:") 297 | if len(sp[0])<1{ 298 | return nil, exception.AddrErr{}.New("addr format illegal") 299 | }else{ 300 | sp[0]=sp[0][1:] 301 | i:=strings.Index(sp[0],"%") 302 | if i!=-1{ 303 | sp[0]=sp[0][:i] 304 | } 305 | 306 | } 307 | 308 | } else { 309 | sp = strings.Split(addr, ":") 310 | } 311 | 312 | if len(sp) != 2 { 313 | return nil, exception.AddrErr{}.New("addr format illegal") 314 | } 315 | 316 | if ipv6{ 317 | addr=fmt.Sprintf("[%s]:%s",sp[0],sp[1]) 318 | return (&AddrIPPort{}).parseFromString(addr, Addr_type_ipv6) 319 | } 320 | 321 | if len(sp[0]) > 255 { 322 | return nil, exception.AddrErr{}.New("addr too long") 323 | } 324 | 325 | 326 | if net.ParseIP(sp[0]).To4() != nil { 327 | return (&AddrIPPort{}).parseFromString(addr, Addr_type_ipv4) 328 | } 329 | 330 | return (&Domain{}).parseFromString(addr, domain_try_ipv6) 331 | 332 | 333 | } 334 | 335 | func NewAddrFromByte(d, port []byte, _type int) (Addr, error) { 336 | 337 | var addr Addr 338 | if len(port) != 2 { 339 | return nil, exception.AddrErr{}.New(" port bytes len illegal") 340 | } 341 | switch _type { 342 | case Addr_type_ipv6: 343 | if len(d) != 16 { 344 | return nil, exception.AddrErr{}.New("ip bytes len illegal") 345 | } 346 | addr = &AddrIPPort{ 347 | ip: d, 348 | port: [2]byte{port[0], port[1]}, 349 | _type: _type, 350 | } 351 | 352 | case Addr_type_ipv4: 353 | if len(d) != 4 { 354 | return nil, exception.AddrErr{}.New("ip bytes len illegal") 355 | } 356 | addr = &AddrIPPort{ 357 | ip: d, 358 | port: [2]byte{port[0], port[1]}, 359 | _type: _type, 360 | } 361 | case Addr_domain_try_ipv6, Addr_domain: 362 | if len(d) > 255 { 363 | return nil, exception.AddrErr{}.New("domain len too long") 364 | } 365 | addr = &Domain{ 366 | domain: string(d), 367 | port: (uint16(port[0]) << 8) + uint16(port[1]), 368 | _type: _type, 369 | } 370 | 371 | default: 372 | return nil, exception.AddrErr{}.New("addr type illegal") 373 | } 374 | 375 | return addr, nil 376 | } 377 | 378 | -------------------------------------------------------------------------------- /src/go_proxy/conn/client.go: -------------------------------------------------------------------------------- 1 | package conn 2 | 3 | import ( 4 | "bufio" 5 | "bytes" 6 | "context" 7 | "crypto/rand" 8 | "crypto/tls" 9 | "encoding/base64" 10 | "encoding/binary" 11 | "errors" 12 | "fmt" 13 | "go_proxy/util" 14 | "golang.org/x/net/proxy" 15 | "io" 16 | "net" 17 | "net/http" 18 | "sync" 19 | "time" 20 | ) 21 | 22 | // local connection join to remote dispatch 23 | func (this *ConnectionHandler) Dispatch_client(local net.Conn) (*LocalConnection, error) { 24 | this.rwlock.Lock() 25 | defer this.rwlock.Unlock() 26 | 27 | if this.idle_queue.Len() != 0 { 28 | serv_con := this.idle_queue.Back().Value.(*ServerConnection) 29 | new_local_connection := &LocalConnection{ 30 | Local: local, 31 | } 32 | switch local.(type) { 33 | case *net.TCPConn: 34 | new_local_connection.Proto = Proto_tcp 35 | case *net.UDPConn: 36 | new_local_connection.Proto = Proto_udp 37 | default: 38 | return nil, errors.New("unknow connection type") 39 | } 40 | 41 | serv_con.local_new_notify <- new_local_connection 42 | select { 43 | case <-serv_con.ctx.Done(): 44 | return nil, errors.New("remote connection closed") 45 | case new_local_connection = <-serv_con.local_new_notify: 46 | return new_local_connection, nil 47 | } 48 | 49 | } else { // no idle connection in queue 50 | g := sync.WaitGroup{} 51 | g.Add(1) 52 | 53 | var ( 54 | serv_con net.Conn 55 | err error 56 | ) 57 | go func() { 58 | defer g.Done() 59 | serv_con, err = connection_to_server(this.config) 60 | return 61 | }() 62 | 63 | var ( 64 | id_chan = make(chan uint16, this.config.Connection_max_payload) 65 | local_close_notify = make(chan uint16, this.config.Connection_max_payload) 66 | local_new_notify = make(chan *LocalConnection) 67 | serv_recv_chan, local_recv_chan = make(chan Frame), make(chan Frame, 500) 68 | connection_id uint16 = 0 69 | sync_map = &sync.Map{} 70 | ctx, cancel = context.WithCancel(context.TODO()) 71 | ) 72 | 73 | sync_map.Store(connection_id, local_recv_chan) 74 | 75 | for i := 1; i < this.config.Connection_max_payload; i++ { 76 | id_chan <- uint16(i) 77 | } 78 | 79 | g.Wait() 80 | if err != nil { 81 | close(id_chan) 82 | close(serv_recv_chan) 83 | close(local_recv_chan) 84 | close(local_close_notify) 85 | return nil, err 86 | } 87 | 88 | rand_bytes := make([]byte, 16) 89 | rand.Read(rand_bytes) 90 | new_serv_con := &ServerConnection{ 91 | remote: serv_con, 92 | id_chan: id_chan, 93 | payload: 1, 94 | local_close_notify: local_close_notify, 95 | local_new_notify: local_new_notify, 96 | recvChan: serv_recv_chan, 97 | sendChan: sync_map, 98 | Id: fmt.Sprintf("%d:%x", this.config.Id, rand_bytes), 99 | idel_conn_remain_sec: this.config.Idle_connection_remain_time, 100 | handler: this, 101 | ctx: ctx, 102 | } 103 | 104 | new_local_connection := &LocalConnection{ 105 | Local: local, 106 | RecvChan: local_recv_chan, 107 | SendChan: serv_recv_chan, 108 | connection_map: sync_map, 109 | close_nofify: local_close_notify, 110 | ConnectionId: connection_id, 111 | Remote_ctx: ctx, 112 | remote_connection_id: new_serv_con.Id, 113 | } 114 | 115 | switch local.(type) { 116 | case *net.TCPConn: 117 | new_local_connection.Proto = Proto_tcp 118 | case *net.UDPConn: 119 | new_local_connection.Proto = Proto_udp 120 | default: 121 | return nil, errors.New("unknow connection type") 122 | } 123 | 124 | go new_serv_con.client_loop(cancel) 125 | 126 | if int(new_serv_con.payload) == this.config.Connection_max_payload { 127 | new_serv_con.ele = this.full_queue.PushFront(new_serv_con) 128 | go new_serv_con.dispatcher_in_full_queue() 129 | } else { 130 | new_serv_con.ele = this.idle_queue.PushFront(new_serv_con) 131 | go new_serv_con.dispatcher_in_idle_queue() 132 | } 133 | 134 | if util.Verbose_info { 135 | util.Print_verbose("%s new server connection ,payload:%d/%d,idle queue len:%d,full queue len:%d", 136 | new_serv_con.Id, 137 | new_serv_con.payload, 138 | new_serv_con.handler.config.Connection_max_payload, 139 | this.idle_queue.Len(), 140 | this.full_queue.Len()) 141 | } 142 | 143 | return new_local_connection, nil 144 | } 145 | 146 | } 147 | 148 | func (this *ServerConnection) client_loop(cancel func()) { 149 | go func() { 150 | for { 151 | select { 152 | case frame, ok := <-this.recvChan: 153 | if ok { 154 | if util.Verbose_info { 155 | if frame.GetFrameType() == Control_frame && frame.(*ControlFrame).Command == Command_close_conn { 156 | util.Print_verbose("%s (in %s queue) local connection %d send close", 157 | this.Id, 158 | "idle", 159 | frame.GetConnectionId()) 160 | } 161 | } 162 | this.write_to_remote(frame) 163 | } else { 164 | return 165 | } 166 | 167 | 168 | case <-this.ctx.Done(): 169 | return 170 | 171 | } 172 | } 173 | }() 174 | 175 | var err error 176 | defer func() { 177 | cancel() 178 | if util.Verbose_info { 179 | util.Print_verbose("%s client loop break:%s", this.Id, err.Error()) 180 | } 181 | }() 182 | 183 | for { 184 | var frame Frame 185 | frame, err = this.read_from_remote() 186 | if err != nil { 187 | return 188 | } 189 | ch, ok := this.sendChan.Load(frame.GetConnectionId()) 190 | if !ok { 191 | err = errors.New("recv an unknow connection id") 192 | return 193 | } 194 | ch.(chan Frame) <- frame 195 | } 196 | 197 | } 198 | 199 | func (this *ServerConnection) dispatcher_in_idle_queue() { 200 | 201 | ctx := context.TODO() 202 | 203 | var remove_and_close = func() { 204 | this.handler.rwlock.Lock() 205 | this.handler.idle_queue.Remove(this.ele) 206 | this.handler.rwlock.Unlock() 207 | this.close() 208 | return 209 | } 210 | 211 | for { 212 | select { 213 | case connection_id := <-this.local_close_notify: 214 | this.id_chan <- connection_id 215 | this.payload -= 1 216 | if this.payload == 0 { 217 | ctx, _ = context.WithTimeout(ctx, time.Duration(this.idel_conn_remain_sec)*time.Second) 218 | 219 | if util.Verbose_info { 220 | util.Print_verbose("%s (in %s queue) local connection %d remove ,payload:%d/%d,payload is 0,Countdown %d sec to close when no connection regist", 221 | this.Id, 222 | "idle", 223 | connection_id, 224 | this.payload, 225 | this.handler.config.Connection_max_payload, 226 | this.idel_conn_remain_sec) 227 | 228 | } 229 | 230 | } else { 231 | if util.Verbose_info { 232 | util.Print_verbose("%s (in %s queue) local connection %d remove ,payload:%d/%d", 233 | this.Id, 234 | "idle", 235 | connection_id, 236 | this.payload, 237 | this.handler.config.Connection_max_payload) 238 | } 239 | } 240 | case local := <-this.local_new_notify: 241 | var ( 242 | id = <-this.id_chan 243 | local_recv = make(chan Frame, 100) 244 | ) 245 | 246 | local.close_nofify = this.local_close_notify 247 | local.ConnectionId = id 248 | local.RecvChan = local_recv 249 | local.SendChan = this.recvChan 250 | local.connection_map = this.sendChan 251 | local.Remote_ctx = this.ctx 252 | local.remote_connection_id = this.Id 253 | this.sendChan.Store(id, local_recv) 254 | this.payload += 1 255 | if int(this.payload) == this.handler.config.Connection_max_payload { // full payload 256 | this.handler.idle_queue.Remove(this.ele) 257 | this.ele = this.handler.full_queue.PushFront(this) 258 | 259 | if util.Verbose_info { 260 | util.Print_verbose("%s (in %s queue) local connection %d regist to ,payload:%d/%d,payload is full move to full queue dispatche", 261 | this.Id, 262 | "idle", 263 | id, 264 | this.payload, 265 | this.handler.config.Connection_max_payload) 266 | } 267 | this.local_new_notify <- local 268 | 269 | go this.dispatcher_in_full_queue() 270 | 271 | return 272 | } 273 | ctx = context.TODO() 274 | this.local_new_notify <- local 275 | 276 | if util.Verbose_info { 277 | util.Print_verbose("%s local connection %d regist ,payload:%d/%d", 278 | this.Id, 279 | id, 280 | this.payload, 281 | this.handler.config.Connection_max_payload) 282 | } 283 | 284 | 285 | case <-ctx.Done(): 286 | remove_and_close() 287 | return 288 | case <-this.ctx.Done(): 289 | remove_and_close() 290 | return 291 | } 292 | } 293 | } 294 | 295 | func (this *ServerConnection) dispatcher_in_full_queue() { 296 | 297 | ctx := context.TODO() 298 | is_full := true 299 | 300 | var remove_and_close = func() { 301 | this.handler.rwlock.Lock() 302 | this.handler.full_queue.Remove(this.ele) 303 | this.handler.rwlock.Unlock() 304 | this.close() 305 | return 306 | } 307 | 308 | for { 309 | select { 310 | case connection_id := <-this.local_close_notify: 311 | this.id_chan <- connection_id 312 | this.payload -= 1 313 | if this.payload == 0 { 314 | remove_and_close() 315 | return 316 | } 317 | if is_full { 318 | ctx, _ = context.WithTimeout(ctx, time.Duration(this.idel_conn_remain_sec)*time.Second) 319 | is_full = false 320 | 321 | if util.Verbose_info { 322 | util.Print_verbose("%s (in %s queue) local connection %d remove from ,payload:%d/%d,payload is not full ,if local connection all remove during %d sec,it will close else it will dispatch to idle queue", 323 | this.Id, 324 | "full", 325 | connection_id, 326 | this.payload, 327 | this.handler.config.Connection_max_payload, 328 | this.idel_conn_remain_sec) 329 | } 330 | 331 | } else { 332 | if util.Verbose_info { 333 | util.Print_verbose(" %s (in %s queue) local connection %d remove ,payload:%d/%d", 334 | this.Id, 335 | "full", 336 | connection_id, 337 | this.payload, 338 | this.handler.config.Connection_max_payload) 339 | } 340 | } 341 | case <-ctx.Done(): 342 | this.handler.rwlock.Lock() 343 | this.handler.full_queue.Remove(this.ele) 344 | this.ele = this.handler.idle_queue.PushBack(this) 345 | this.handler.rwlock.Unlock() 346 | if util.Verbose_info { 347 | util.Print_verbose("%s (in %s queue) server connection ,payload:%d/%d,dispatch to idle queue", 348 | this.Id, 349 | "full", 350 | this.payload, 351 | this.handler.config.Connection_max_payload) 352 | } 353 | go this.dispatcher_in_idle_queue() 354 | return 355 | 356 | case <-this.ctx.Done(): 357 | remove_and_close() 358 | return 359 | } 360 | } 361 | } 362 | 363 | func NewClientConnectionHandler(conf *ClientConfig) *ConnectionHandler { 364 | return ConnectionHandler{}.new_connection_handler(conf) 365 | } 366 | 367 | const http_proxy_req = "CONNECT %s HTTP/1.1\r\n" + 368 | "Host: %s\r\n" 369 | 370 | func connection_to_server(conf *ClientConfig) (net.Conn, error) { 371 | var ( 372 | c net.Conn = nil 373 | err error 374 | ) 375 | close := true 376 | defer func() { 377 | if close && c != nil { 378 | c.Close() 379 | } 380 | }() 381 | 382 | if conf.Front_proxy.User_front_proxy { 383 | switch conf.Front_proxy.Front_proxy_schema { 384 | case util.Http: 385 | req := fmt.Sprintf(http_proxy_req, conf.Tcp_server_addr, conf.Tcp_server_addr) 386 | if conf.Front_proxy.Auth_need { 387 | req += fmt.Sprintf("Proxy-Authorization: Basic %s\r\n\r\n", 388 | base64.StdEncoding.EncodeToString([]byte( 389 | fmt.Sprintf("%s:%s", conf.Front_proxy.Username, conf.Front_proxy.Passwd)))) 390 | } else { 391 | req += "\r\n" 392 | } 393 | 394 | 395 | c, err = net.Dial("tcp", conf.Front_proxy.Front_proxy_addr) 396 | if err != nil { 397 | return nil, err 398 | } 399 | c.SetDeadline(time.Now().Add(time.Duration(util.Tcp_timeout) * time.Second)) 400 | if _, err := c.Write([]byte(req)); err != nil { 401 | return nil, err 402 | } 403 | 404 | resp, err := http.ReadResponse(bufio.NewReader(c), nil) 405 | if err != nil { 406 | return nil, err 407 | } 408 | if resp.StatusCode != 200 { 409 | return nil, errors.New(fmt.Sprintf("http proxy serv return state code %d", resp.StatusCode)) 410 | } 411 | 412 | 413 | case util.Socks5: 414 | var auth *proxy.Auth = nil 415 | if conf.Front_proxy.Auth_need { 416 | auth = &proxy.Auth{ 417 | User: conf.Front_proxy.Username, 418 | Password: conf.Front_proxy.Passwd, 419 | } 420 | } 421 | var d proxy.Dialer 422 | d, err = proxy.SOCKS5("tcp", conf.Front_proxy.Front_proxy_addr, auth, nil) 423 | if err != nil { 424 | return nil, err 425 | } 426 | c, err = d.Dial("tcp", conf.Tcp_server_addr) 427 | if err!=nil{ 428 | err=errors.New(err.Error()) 429 | } 430 | default: 431 | panic("unknow error") 432 | } 433 | } else { 434 | c, err = net.Dial("tcp", conf.Tcp_server_addr) 435 | } 436 | 437 | if err != nil { 438 | return nil, err 439 | } 440 | 441 | c.(*net.TCPConn).SetKeepAlive(true) 442 | c.(*net.TCPConn).SetKeepAlivePeriod(10 * time.Second) 443 | c.(*net.TCPConn).SetNoDelay(true) 444 | 445 | if conf.Tls_conf != nil { 446 | serv_con := tls.Client(c, conf.Tls_conf) 447 | if err := serv_con.Handshake(); err != nil { 448 | return nil, err 449 | } 450 | c = serv_con 451 | h := Handshake_info{ 452 | Rand_byte: []byte{}, 453 | Max_payload: uint16(conf.Connection_max_payload), 454 | Dns_addr: conf.Remoted_dns, 455 | } 456 | 457 | d := conf.Crypt.Encrypt(h.ToBytes()) 458 | l := make([]byte, 2) 459 | binary.BigEndian.PutUint16(l, uint16(len(d))) 460 | c.SetWriteDeadline(time.Now().Add(time.Duration(util.Tcp_timeout) * time.Second)) 461 | 462 | if _, err := c.Write(bytes.Join([][]byte{l, d}, nil)); err != nil { 463 | return nil, err 464 | } 465 | c.SetWriteDeadline(time.Time{}) 466 | 467 | } else { 468 | var i int = 0 469 | for _, v := range conf.Crypt.Get_passwd() { 470 | i += int(v) 471 | } 472 | i = (i % 100) + 64 473 | b := make([]byte, i) 474 | 475 | c.SetDeadline(time.Now().Add(time.Duration(util.Tcp_timeout) * time.Second)) 476 | 477 | if _, err := io.ReadAtLeast(c, b, i); err != nil { 478 | return nil, err 479 | } 480 | 481 | h := Handshake_info{ 482 | Rand_byte: b, 483 | Max_payload: uint16(conf.Connection_max_payload), 484 | Dns_addr: conf.Remoted_dns, 485 | } 486 | 487 | ed := conf.Crypt.Encrypt(h.ToBytes()) 488 | l := make([]byte, 2) 489 | binary.BigEndian.PutUint16(l, uint16(len(ed))) 490 | 491 | if _, err := c.Write(bytes.Join([][]byte{l, ed}, nil)); err != nil { 492 | return nil, err 493 | } 494 | 495 | c.SetDeadline(time.Time{}) 496 | } 497 | close = false 498 | return c, nil 499 | 500 | } 501 | -------------------------------------------------------------------------------- /src/go_proxy/conn/config.go: -------------------------------------------------------------------------------- 1 | package conn 2 | 3 | import ( 4 | "crypto/tls" 5 | "crypto/x509" 6 | "errors" 7 | "fmt" 8 | "io/ioutil" 9 | "log" 10 | "net" 11 | "net/url" 12 | "os" 13 | "runtime" 14 | "strconv" 15 | "strings" 16 | "sync" 17 | "time" 18 | 19 | . "go_proxy/util" 20 | "math" 21 | ) 22 | 23 | type ClientConfig struct { 24 | Id uint16 25 | Ipv6 bool 26 | Domain_cache_time int64 27 | Connection_max_payload int 28 | Mode string 29 | 30 | Local_dns_addr string 31 | 32 | Local_addr string 33 | Local_ip string 34 | Local_port int 35 | Zone_id uint32 36 | 37 | Front_proxy struct { 38 | User_front_proxy bool 39 | Front_proxy_schema string 40 | Front_proxy_path string 41 | Front_proxy_addr string 42 | Auth_need bool 43 | Username string 44 | Passwd string 45 | } 46 | 47 | Remoted_dns Addr 48 | 49 | Tcp_server_addr string 50 | Tcp_Server_Addr Addr 51 | 52 | Udp_server_addr string 53 | Udp_Server_Addr Addr 54 | 55 | Crypt Crypt_interface 56 | 57 | Udp_crypt Crypt_interface 58 | 59 | Tls_conf *tls.Config 60 | 61 | ConnectionHandler *ConnectionHandler 62 | 63 | Cn_domain_ip_map, Not_cn_domain_ip_map *sync.Map 64 | 65 | Idle_connection_remain_time int 66 | 67 | Udp_in_tcp bool 68 | } 69 | 70 | type ServConfig struct { 71 | Tcp_listen_port int 72 | Udp_listen_port int 73 | Tls_conf *tls.Config 74 | Crypt Crypt_interface 75 | Udp_crypt Crypt_interface 76 | ServConnectionHandler *ServerConnectionhandler 77 | Id uint16 78 | } 79 | 80 | func parse_local_string_addr(s string, conf *ClientConfig) (Addr, error) { 81 | addr, err := NewAddrFromString(s, conf.Ipv6) 82 | if err != nil { 83 | return nil, err 84 | } 85 | if addr.IsDomain() { 86 | ip, _type, err := Parse_local_domain(addr.String(), conf.Ipv6, conf.Local_dns_addr) 87 | if err != nil { 88 | return nil, err 89 | } 90 | if _type == Addr_type_ipv4 { 91 | addr, err = NewAddrFromString(net.IP(ip).String()+":"+strings.Split(addr.StringWithPort(), ":")[1], false) 92 | } else if _type == Addr_type_ipv6 { 93 | addr, err = NewAddrFromString(fmt.Sprintf("[%s]:%d", net.IP(ip).String(), addr.ToPortInt()), false) 94 | } else { 95 | panic("unknow error") 96 | } 97 | 98 | if err != nil { 99 | return nil, err 100 | } 101 | return addr, nil 102 | } else { 103 | return addr, nil 104 | } 105 | 106 | } 107 | 108 | func LoadClientConfig(client *Client, i uint16) (*ClientConfig, []string, error) { 109 | 110 | info := []string{} 111 | cli_conf := &ClientConfig{ 112 | Id: i, 113 | Ipv6: client.Ipv6, 114 | Udp_in_tcp: client.Udp_in_tcp, 115 | } 116 | if client.Connection_max_payload > 65535 { 117 | cli_conf.Connection_max_payload = 65500 118 | } else if client.Connection_max_payload < 1 { 119 | cli_conf.Connection_max_payload = 1 120 | } else { 121 | cli_conf.Connection_max_payload = client.Connection_max_payload 122 | } 123 | 124 | //check mode 125 | client.Mode = strings.ToLower(client.Mode) 126 | if client.Mode != Http && client.Mode != Socks5 && client.Mode != Iptables { 127 | return nil, nil, errors.New("client mode can only http|socks5|iptables") 128 | } 129 | if client.Mode == Iptables && runtime.GOOS != "linux" { 130 | fmt.Fprintf(os.Stderr, "iptables mode only support on linux\r\n") 131 | os.Exit(1) 132 | } 133 | cli_conf.Mode = client.Mode 134 | if cli_conf.Mode == Iptables { 135 | cli_conf.Domain_cache_time = 0 136 | } else if client.Domain_cache_time != 0 && client.Domain_cache_time < 60 { 137 | cli_conf.Domain_cache_time = 60 138 | } else if client.Domain_cache_time > 24*60*60 { 139 | client.Domain_cache_time = 24 * 60 * 60 140 | } else { 141 | cli_conf.Domain_cache_time = client.Domain_cache_time 142 | } 143 | 144 | info = append(info, fmt.Sprintf("%-25s : %v", "mode ", cli_conf.Mode)) 145 | info = append(info, fmt.Sprintf("%-25s : %v", "ipv6", cli_conf.Ipv6)) 146 | info = append(info, fmt.Sprintf("%-25s : %v", "domain cache time", cli_conf.Domain_cache_time)) 147 | info = append(info, fmt.Sprintf("%-25s : %v", "udp timeout", Config.Udp_timeout)) 148 | if client.Mode != Http { 149 | info = append(info, fmt.Sprintf("%-25s : %v", "udp in tcp ", cli_conf.Udp_in_tcp)) 150 | } 151 | 152 | //check local dns addr 153 | if cli_conf.Mode != Iptables { 154 | if client.Local_dns_addr != "" { 155 | addr, err := NewAddrFromString(client.Local_dns_addr, client.Ipv6) 156 | if err != nil { 157 | return nil, nil, errors.New("check local dns addr fail : " + err.Error()) 158 | } 159 | if addr.IsDomain() { 160 | ip, err := net.ResolveIPAddr("ip", addr.String()) 161 | if err != nil || len(ip.IP) == 0 { 162 | return nil, nil, errors.New("look up local dns addr fail : " + err.Error()) 163 | } 164 | 165 | addr, err = NewAddrFromString(ip.String()+":"+strings.Split(addr.StringWithPort(), ":")[1], client.Ipv6) 166 | if err != nil { 167 | return nil, nil, errors.New("parse local dns ip fail : " + err.Error()) 168 | } 169 | } 170 | 171 | cli_conf.Local_dns_addr = addr.StringWithPort() 172 | info = append(info, fmt.Sprintf("%-25s : %v", "local dns addr ", cli_conf.Local_dns_addr)) 173 | } else { 174 | info = append(info, fmt.Sprintf("%-25s : %v", "local dns addr ", "use default dns addr")) 175 | } 176 | } 177 | 178 | // check local addr 179 | 180 | if cli_conf.Mode == Iptables { 181 | if client.Local_Port > 65535 || client.Local_Port < 1 { 182 | return nil, nil, errors.New("local port illegal") 183 | } 184 | cli_conf.Local_port = client.Local_Port 185 | info = append(info, fmt.Sprintf("%-25s : %v", "listen port ", cli_conf.Local_port)) 186 | if client.Ipv6 { 187 | if client.Interface == "" { 188 | cli_conf.Zone_id = 0 189 | info = append(info, fmt.Sprintf("%-25s : %v", "interface", "not specific")) 190 | 191 | } else { 192 | i, err := net.InterfaceByName(client.Interface) 193 | if err != nil { 194 | return nil, nil, errors.New(err.Error()) 195 | } 196 | cli_conf.Zone_id = uint32(i.Index) 197 | info = append(info, fmt.Sprintf("%-25s : %v", "interface",client.Interface)) 198 | } 199 | info = append(info, fmt.Sprintf("%-25s : %v", "zone id", cli_conf.Zone_id)) 200 | } 201 | } else { 202 | if client.Local_addr == "" { 203 | return nil, nil, errors.New("local addr is nil") 204 | } 205 | addr, err := parse_local_string_addr(client.Local_addr, cli_conf) 206 | if err != nil { 207 | return nil, nil, errors.New("check local addr fail : " + err.Error()) 208 | } 209 | cli_conf.Local_addr = addr.StringWithPort() 210 | cli_conf.Local_ip = addr.String() 211 | cli_conf.Local_port=addr.ToPortInt() 212 | info = append(info, fmt.Sprintf("%-25s : %v", "local addr ", cli_conf.Local_addr)) 213 | } 214 | 215 | // check front proxy 216 | if client.Front_proxy != "" { 217 | 218 | default_port:=map[string]int{ 219 | Http:80, 220 | Socks5:1080, 221 | } 222 | 223 | url, err := url.Parse(client.Front_proxy) 224 | if err != nil { 225 | return nil, nil, errors.New("parse front proxy addr fail : " + err.Error()) 226 | } 227 | sch := strings.ToLower(url.Scheme) 228 | if sch != Http && sch != Socks5 { 229 | 230 | } 231 | port := 0 232 | 233 | switch sch { 234 | case Http,Socks5: 235 | if url.Port() == "" { 236 | port = default_port[sch] 237 | } else { 238 | p, err := strconv.ParseInt(url.Port(), 10, 0) 239 | if err != nil { 240 | return nil, nil, err 241 | } 242 | port = int(p) 243 | } 244 | if sch!=Socks5{ 245 | cli_conf.Front_proxy.Front_proxy_path=url.Path 246 | } 247 | 248 | default: 249 | return nil, nil, errors.New("front proxy proto not support") 250 | 251 | } 252 | 253 | addr,err:=parse_local_string_addr(fmt.Sprintf("%s:%d",url.Hostname(),port), cli_conf) 254 | if err!=nil{ 255 | return nil, nil, errors.New(fmt.Sprintf("front proxy address parse fail: %s",err.Error())) 256 | } 257 | 258 | cli_conf.Front_proxy.User_front_proxy=true 259 | cli_conf.Front_proxy.Front_proxy_schema=url.Scheme 260 | cli_conf.Front_proxy.Front_proxy_addr=addr.StringWithPort() 261 | 262 | if url.User.Username()!=""{ 263 | cli_conf.Front_proxy.Auth_need=true 264 | cli_conf.Front_proxy.Username=url.User.Username() 265 | p,ok:=url.User.Password() 266 | if ok{ 267 | cli_conf.Front_proxy.Passwd=p 268 | info = append(info, fmt.Sprintf("%-25s : %v", "front proxy", fmt.Sprintf( 269 | "%s://%s:%s@%s%s", 270 | cli_conf.Front_proxy.Front_proxy_schema, 271 | cli_conf.Front_proxy.Username, 272 | cli_conf.Front_proxy.Passwd, 273 | cli_conf.Front_proxy.Front_proxy_addr, 274 | cli_conf.Front_proxy.Front_proxy_path, 275 | ))) 276 | }else{ 277 | info = append(info, fmt.Sprintf("%-25s : %v", "front proxy", fmt.Sprintf( 278 | "%s://%s@%s%s", 279 | cli_conf.Front_proxy.Front_proxy_schema, 280 | cli_conf.Front_proxy.Username, 281 | cli_conf.Front_proxy.Front_proxy_addr, 282 | cli_conf.Front_proxy.Front_proxy_path, 283 | ))) 284 | } 285 | }else{ 286 | info = append(info, fmt.Sprintf("%-25s : %v", "front proxy", fmt.Sprintf( 287 | "%s://%s%s", 288 | cli_conf.Front_proxy.Front_proxy_schema, 289 | cli_conf.Front_proxy.Front_proxy_addr, 290 | cli_conf.Front_proxy.Front_proxy_path, 291 | ))) 292 | } 293 | 294 | } 295 | 296 | //check server 297 | tcp_server_addr := strings.TrimRight(strings.TrimLeft(client.Tcp_server_addr, ""), "") 298 | udp_server_addr := strings.TrimRight(strings.TrimLeft(client.Udp_server_addr, ""), "") 299 | 300 | tcp_addr, err := parse_local_string_addr(tcp_server_addr, cli_conf) 301 | if err != nil { 302 | return nil, nil, errors.New("check tcp server addr faile : " + err.Error()) 303 | } 304 | cli_conf.Tcp_Server_Addr = tcp_addr 305 | cli_conf.Tcp_server_addr = tcp_addr.StringWithPort() 306 | 307 | info = append(info, fmt.Sprintf("%-25s : %v", "tcp server addr ", cli_conf.Tcp_server_addr)) 308 | 309 | if cli_conf.Mode != Http { 310 | udp_addr, err := parse_local_string_addr(udp_server_addr, cli_conf) 311 | if err != nil { 312 | return nil, nil, errors.New("check udp server addr faile : " + err.Error()) 313 | } 314 | cli_conf.Udp_Server_Addr = udp_addr 315 | cli_conf.Udp_server_addr = udp_addr.StringWithPort() 316 | info = append(info, fmt.Sprintf("%-25s : %v", "udp server addr ", cli_conf.Udp_server_addr)) 317 | } 318 | 319 | //check remote dns addr 320 | if client.Remote_dns_addr != "" { 321 | addr, err := NewAddrFromString(client.Remote_dns_addr, client.Ipv6) 322 | if err != nil { 323 | return nil, nil, errors.New("check remote dns addr fail : " + err.Error()) 324 | } 325 | 326 | if addr.IsDomain() { 327 | ip, _type, err := Parse_local_domain(addr.String(), cli_conf.Ipv6, cli_conf.Local_dns_addr) 328 | if err != nil { 329 | return nil, nil, errors.New("look up remote dns addr ip fail : " + err.Error()) 330 | } 331 | addr, err = NewAddrFromByte(ip, addr.ToPortByte(), _type) 332 | if err != nil { 333 | return nil, nil, errors.New("parse remote dns addr fail : " + err.Error()) 334 | } 335 | } 336 | 337 | cli_conf.Remoted_dns = addr 338 | info = append(info, fmt.Sprintf("%-25s : %v", "remote dns addr ", addr.StringWithPort())) 339 | } else { 340 | cli_conf.Remoted_dns = nil 341 | info = append(info, fmt.Sprintf("%-25s : %v", "remote dns addr ", "use remote server default dns addr")) 342 | } 343 | 344 | //check crypt 345 | crypt, err := Get_crypt(client.Enc_method, client.Password) 346 | if err != nil { 347 | return nil, nil, errors.New("check crypt fail : " + err.Error()) 348 | } 349 | 350 | cli_conf.Crypt = crypt 351 | cli_conf.Udp_crypt = crypt 352 | 353 | if client.Tls.On { 354 | 355 | cert_pool := x509.NewCertPool() 356 | root_cert, err := ioutil.ReadFile(client.Tls.Root_cert_path) 357 | if err != nil { 358 | return nil, nil, errors.New("server root cert check fail : " + err.Error()) 359 | } 360 | 361 | cert_pool.AppendCertsFromPEM(root_cert) 362 | cert, err := tls.LoadX509KeyPair(client.Tls.Certificate, client.Tls.Private_key) 363 | if err != nil { 364 | return nil, nil, errors.New("load client cert fail : " + err.Error()) 365 | } 366 | cli_conf.Tls_conf = &tls.Config{ 367 | RootCAs: cert_pool, 368 | ServerName: tcp_addr.String(), 369 | Certificates: []tls.Certificate{cert}, 370 | MinVersion: tls.VersionTLS13, 371 | SessionTicketsDisabled: true, 372 | } 373 | if client.Tls.Server_name != "" { 374 | cli_conf.Tls_conf.ServerName = client.Tls.Server_name 375 | } 376 | info = append(info, fmt.Sprintf("%-25s : %v", "tls server name ", cli_conf.Tls_conf.ServerName)) 377 | 378 | if !client.Tls.Tcp_encrypt { 379 | cli_conf.Crypt = Get_none_crypt() 380 | } 381 | info = append(info, fmt.Sprintf("%-25s : %v", "tcp enc method ", cli_conf.Crypt.String())) 382 | } else { 383 | info = append(info, fmt.Sprintf("%-25s : %v", "tcp enc method ", cli_conf.Crypt.String())) 384 | } 385 | info = append(info, fmt.Sprintf("%-25s : %v", "udp enc method ", cli_conf.Udp_crypt.String())) 386 | info = append(info, fmt.Sprintf("%-25s : %v", "tls ", client.Tls.On)) 387 | 388 | if cli_conf.Connection_max_payload < 64 { 389 | cli_conf.Idle_connection_remain_time = 8 390 | } else { 391 | cli_conf.Idle_connection_remain_time = int(64.0 / math.Sqrt(float64(cli_conf.Connection_max_payload))) 392 | } 393 | 394 | info = append(info, fmt.Sprintf("%-25s : %v", "max connection payload", cli_conf.Connection_max_payload)) 395 | info = append(info, fmt.Sprintf("%-25s : %v", "idle conn reamin sec", cli_conf.Idle_connection_remain_time)) 396 | 397 | cli_conf.ConnectionHandler = NewClientConnectionHandler(cli_conf) 398 | 399 | if cli_conf.Domain_cache_time != 0 { 400 | cli_conf.Cn_domain_ip_map = &sync.Map{} 401 | cli_conf.Not_cn_domain_ip_map = &sync.Map{} 402 | go domain_cache_clean_scheduel(cli_conf.Cn_domain_ip_map, client.Domain_cache_time) 403 | go domain_cache_clean_scheduel(cli_conf.Not_cn_domain_ip_map, client.Domain_cache_time) 404 | 405 | } 406 | 407 | return cli_conf, info, nil 408 | 409 | } 410 | 411 | func LoadServerConfig(serve *Serve, i uint16) (*ServConfig, []string, error) { 412 | s := &ServConfig{} 413 | s.Tcp_listen_port = serve.Tcp_listen_port 414 | s.Udp_listen_port = serve.Udp_listen_port 415 | s.Id = i 416 | info := []string{fmt.Sprintf("%-25s : %v", "tcp listen port", s.Tcp_listen_port)} 417 | info = append(info, fmt.Sprintf("%-25s : %v", "udp listen port", s.Udp_listen_port)) 418 | 419 | crypt, err := Get_crypt(serve.Enc_method, serve.Password) 420 | if err != nil { 421 | return nil, nil, err 422 | } 423 | s.Crypt = crypt 424 | s.Udp_crypt = crypt 425 | 426 | if serve.Tls.On { 427 | if len(serve.Tls.Client_certs) == 0 { 428 | return nil, nil, errors.New("client cert is nil") 429 | } 430 | 431 | cert, err := tls.LoadX509KeyPair(serve.Tls.Server_cert, serve.Tls.Server_private_key) 432 | if err != nil { 433 | return nil, nil, errors.New("load server cert and private key exception:" + err.Error()) 434 | } 435 | 436 | cli_cert := x509.NewCertPool() 437 | for _, v := range serve.Tls.Client_certs { 438 | b, err := ioutil.ReadFile(v) 439 | if err != nil { 440 | log.Fatal("load client cert fail : " + err.Error()) 441 | } 442 | cli_cert.AppendCertsFromPEM(b) 443 | 444 | } 445 | 446 | s.Tls_conf = &tls.Config{ 447 | Certificates: []tls.Certificate{cert}, 448 | ClientAuth: tls.RequireAndVerifyClientCert, 449 | ClientCAs: cli_cert, 450 | MinVersion: tls.VersionTLS13, 451 | SessionTicketsDisabled: true, 452 | } 453 | if !serve.Tls.Tcp_encrypt { 454 | s.Crypt = Get_none_crypt() 455 | } 456 | info = append(info, fmt.Sprintf("%-25s : %v", "tcp enc method ", s.Crypt.String())) 457 | } else { 458 | info = append(info, fmt.Sprintf("%-25s : %v", "tcp enc method ", s.Crypt.String())) 459 | } 460 | info = append(info, fmt.Sprintf("%-25s : %v", "udp enc method ", s.Udp_crypt.String())) 461 | info = append(info, fmt.Sprintf("%-25s : %v", "tls ", serve.Tls.On)) 462 | 463 | s.ServConnectionHandler = ServerConnectionhandler{}.new_server_connection_handler(s) 464 | return s, info, nil 465 | } 466 | 467 | func domain_cache_clean_scheduel(domian_map *sync.Map, domian_cache_time int64) { 468 | var clean = func() { 469 | domian_map.Range(func(key, value interface{}) bool { 470 | if time.Now().Unix()-value.(*Domain_record).Time >= domian_cache_time { 471 | if Verbose_info { 472 | Print_verbose("domain %s (ip:%s) cache clean", key, net.IP(value.(*Domain_record).Ip).String()) 473 | } 474 | domian_map.Delete(key) 475 | } 476 | return true 477 | }) 478 | } 479 | 480 | time.Sleep(time.Duration(float64(domian_cache_time)*1.5) * time.Second) 481 | clean() 482 | 483 | for { 484 | time.Sleep(time.Duration(domian_cache_time/2) * time.Second) 485 | clean() 486 | } 487 | } 488 | -------------------------------------------------------------------------------- /src/go_proxy/conn/connection.go: -------------------------------------------------------------------------------- 1 | package conn 2 | 3 | import ( 4 | "bytes" 5 | "container/list" 6 | "context" 7 | "crypto/tls" 8 | "encoding/binary" 9 | "fmt" 10 | "go_proxy/util" 11 | "io" 12 | "net" 13 | "sync" 14 | "time" 15 | ) 16 | 17 | const Tcp_buf_size = 2048 18 | const Udp_buf_size = 65450 19 | 20 | type ServerConnection struct { 21 | Id string 22 | local_ip string 23 | payload uint16 24 | remote net.Conn 25 | id_chan chan uint16 26 | local_new_notify chan *LocalConnection 27 | local_close_notify chan uint16 28 | recvChan chan Frame 29 | sendChan *sync.Map 30 | ele *list.Element 31 | ctx context.Context 32 | idel_conn_remain_sec int 33 | handler *ConnectionHandler 34 | } 35 | 36 | func (this *ServerConnection) read_from_remote() (Frame, error) { 37 | return read_from_remote(this.remote, this.handler.config.Crypt) 38 | 39 | } 40 | 41 | func (this *ServerConnection) write_to_remote(frame Frame) error { 42 | return write_to_remote(this.remote, frame, this.handler.config.Crypt) 43 | } 44 | 45 | func (this *ServerConnection) close() { 46 | 47 | switch c := this.remote.(type) { 48 | case *net.TCPConn: 49 | CloseTcp(c) 50 | case *tls.Conn: 51 | c.CloseWrite() 52 | c.Close() 53 | } 54 | 55 | if util.Verbose_info { 56 | util.Print_verbose("server connection %s,closoing,recycling local connection id", this.Id) 57 | 58 | } 59 | 60 | ctx, _ := context.WithTimeout(context.TODO(), time.Duration(util.Resource_recycle_time_out)*time.Second) 61 | 62 | if this.payload == 0 { 63 | goto close 64 | } 65 | 66 | for { 67 | select { 68 | case connection_id := <-this.local_close_notify: 69 | this.payload -= 1 70 | if util.Verbose_info { 71 | util.Print_verbose("%s (closing) local connection %d remove ,payload:%d/%d", 72 | this.Id, 73 | connection_id, 74 | this.payload, 75 | this.handler.config.Connection_max_payload) 76 | } 77 | 78 | 79 | case <-ctx.Done(): 80 | panic(fmt.Sprintf("client %s id chan recycle timeout", this.Id)) 81 | } 82 | 83 | if int(this.payload) == 0 { 84 | goto close 85 | } 86 | } 87 | close: 88 | close(this.id_chan) 89 | close(this.recvChan) 90 | close(this.local_close_notify) 91 | close(this.local_new_notify) 92 | 93 | if util.Verbose_info { 94 | util.Print_verbose("server connection %s closed", this.Id) 95 | } 96 | 97 | return 98 | 99 | } 100 | 101 | type LocalConnection struct { 102 | Proto int 103 | Local net.Conn 104 | RecvChan chan Frame 105 | SendChan chan<- Frame 106 | close_nofify chan<- uint16 107 | connection_map *sync.Map 108 | ConnectionId uint16 109 | Remote_ctx context.Context 110 | Local_ctx context.Context 111 | remote_connection_id string 112 | } 113 | 114 | func (this *LocalConnection) Close(remote_close bool) { 115 | if this.Proto == Proto_tcp { 116 | CloseTcp(this.Local.(*net.TCPConn)) 117 | } 118 | if this.Local_ctx != nil { 119 | <-this.Local_ctx.Done() 120 | } 121 | if util.Verbose_info { 122 | util.Print_verbose("%s local connection %d waitting remote close", 123 | this.remote_connection_id, 124 | this.ConnectionId) 125 | } 126 | 127 | if !remote_close { 128 | recv_close: 129 | for { 130 | select { 131 | case frame := <-this.RecvChan: 132 | if frame.GetFrameType() == Control_frame && frame.(*ControlFrame).Command == Command_close_conn { 133 | break recv_close 134 | } else { 135 | continue 136 | } 137 | 138 | case <-this.Remote_ctx.Done(): 139 | break recv_close 140 | } 141 | 142 | } 143 | } 144 | 145 | this.connection_map.Delete(this.ConnectionId) 146 | close(this.RecvChan) 147 | this.close_nofify <- this.ConnectionId 148 | 149 | } 150 | 151 | type RemoteServerConnection struct { 152 | id string 153 | remote net.Conn 154 | local_close_notify chan uint16 155 | recvChan chan Frame 156 | sendChan map[uint16]chan <- Frame 157 | ctx context.Context 158 | payload int 159 | connection_info *Handshake_info 160 | lock *sync.RWMutex 161 | chan_lock *sync.RWMutex 162 | handler *ServerConnectionhandler 163 | } 164 | 165 | func (this *RemoteServerConnection) close_subconnection(connection_id uint16, local_close bool, local_recv_chan chan Frame) { 166 | defer func() { 167 | this.chan_lock.Lock() 168 | ch:=this.sendChan[connection_id] 169 | if ch==local_recv_chan{ 170 | delete(this.sendChan,connection_id) 171 | } 172 | this.chan_lock.Unlock() 173 | close(local_recv_chan) 174 | }() 175 | 176 | if !local_close { 177 | local_close: 178 | for { 179 | select { 180 | case frame := <-local_recv_chan: 181 | if frame.GetFrameType() == Control_frame && frame.(*ControlFrame).Command == Command_close_conn { 182 | break local_close 183 | } 184 | 185 | case <-this.ctx.Done(): 186 | break local_close 187 | } 188 | } 189 | } 190 | 191 | this.local_close_notify <- connection_id 192 | } 193 | 194 | func (this *RemoteServerConnection) write_to_remote(frame Frame) { 195 | write_to_remote(this.remote, frame, this.handler.config.Crypt) 196 | } 197 | 198 | func (this *RemoteServerConnection) read_from_remote() (Frame, error) { 199 | return read_from_remote(this.remote, this.handler.config.Crypt) 200 | 201 | } 202 | 203 | func (this *RemoteServerConnection) close() { 204 | 205 | switch c := this.remote.(type) { 206 | case *net.TCPConn: 207 | CloseTcp(c) 208 | case *tls.Conn: 209 | c.CloseWrite() 210 | c.Close() 211 | } 212 | 213 | if util.Verbose_info { 214 | util.Print_verbose("%s closing,recycling sub connection ", this.id) 215 | } 216 | 217 | ctx, _ := context.WithTimeout(context.TODO(), time.Duration(util.Resource_recycle_time_out)*time.Second) 218 | recycling: 219 | for { 220 | select { 221 | case <-this.local_close_notify: 222 | this.lock.Lock() 223 | this.payload -= 1 224 | this.lock.Unlock() 225 | case <-ctx.Done(): 226 | panic("recycling sub connection timeout") 227 | default: 228 | if this.payload == 0 { 229 | break recycling 230 | } 231 | } 232 | } 233 | close(this.local_close_notify) 234 | close(this.recvChan) 235 | 236 | if util.Verbose_info { 237 | this.handler.lock.Lock() 238 | this.handler.connection_count -= 1 239 | this.handler.lock.Unlock() 240 | util.Print_verbose("%s closed , payload %d", this.id, this.handler.connection_count) 241 | } 242 | } 243 | 244 | type ConnectionHandler struct { 245 | full_queue *list.List 246 | idle_queue *list.List 247 | rwlock *sync.RWMutex 248 | config *ClientConfig 249 | } 250 | 251 | func (this ConnectionHandler) new_connection_handler(conf *ClientConfig) *ConnectionHandler { 252 | this.rwlock = &sync.RWMutex{} 253 | this.idle_queue = list.New() 254 | this.full_queue = list.New() 255 | this.config = conf 256 | this.full_queue.Init() 257 | this.idle_queue.Init() 258 | return &this 259 | } 260 | 261 | type ServerConnectionhandler struct { 262 | config *ServConfig 263 | connection_count int 264 | lock *sync.RWMutex 265 | } 266 | 267 | func (this ServerConnectionhandler) new_server_connection_handler(config *ServConfig) *ServerConnectionhandler { 268 | this.lock = &sync.RWMutex{} 269 | this.config = config 270 | return &this 271 | } 272 | 273 | func CloseTcp(con *net.TCPConn) { 274 | con.CloseWrite() 275 | con.CloseRead() 276 | con.Close() 277 | } 278 | 279 | func write_to_remote(remote net.Conn, frame Frame, crypt util.Crypt_interface) error { 280 | enc_data := crypt.Encrypt(frame.ToBytes()) 281 | data_len := make([]byte, 2) 282 | binary.BigEndian.PutUint16(data_len, uint16(len(enc_data))) 283 | _, err := remote.Write(bytes.Join([][]byte{data_len, enc_data}, nil)) 284 | return err 285 | } 286 | 287 | func read_from_remote(remote net.Conn, crypt util.Crypt_interface) (Frame, error) { 288 | buf := make([]byte, 2) 289 | _, err := io.ReadAtLeast(remote, buf, 2) 290 | if err != nil { 291 | return nil, err 292 | } 293 | data_len := binary.BigEndian.Uint16(buf) 294 | buf = make([]byte, data_len) 295 | _, err = io.ReadAtLeast(remote, buf, int(data_len)) 296 | if err != nil { 297 | return nil, err 298 | } 299 | b, err := crypt.Decrypt(buf) 300 | if err != nil { 301 | return nil, err 302 | } 303 | 304 | return ParseBytesToFrame(b) 305 | 306 | } 307 | -------------------------------------------------------------------------------- /src/go_proxy/conn/dns_util.go: -------------------------------------------------------------------------------- 1 | package conn 2 | 3 | import ( 4 | "context" 5 | "go_proxy/exception" 6 | "net" 7 | "time" 8 | "go_proxy/util" 9 | ) 10 | 11 | type Domain_record struct { 12 | Ip []byte 13 | Time int64 14 | 15 | } 16 | 17 | 18 | 19 | func Parse_local_domain(domain string, ipv6 bool,dns_addr string) ([]byte, int, error) { 20 | var dial func(_ context.Context, _, _ string) (conn net.Conn, e error) = nil 21 | 22 | if dns_addr!=""{ 23 | dial=func(_ context.Context, _, _ string) (conn net.Conn, e error) { 24 | return net.Dial("udp", dns_addr) 25 | } 26 | } 27 | need_tcp_try_again:=dial!=nil 28 | tcp_try_again: 29 | 30 | ctx, _ := context.WithTimeout(context.TODO(), time.Duration(util.Config.Udp_timeout)*time.Second) 31 | ip, err := (&net.Resolver{ 32 | Dial: dial, 33 | PreferGo:true, 34 | }).LookupIPAddr(ctx, domain) 35 | if err != nil { 36 | if need_tcp_try_again{ 37 | need_tcp_try_again=false 38 | dial=func(_ context.Context, _, _ string) (conn net.Conn, e error) { 39 | return net.Dial("tcp", dns_addr) 40 | } 41 | goto tcp_try_again 42 | } 43 | return nil, 0, err 44 | } 45 | var ip4 net.IP = nil 46 | 47 | for _, v := range ip { 48 | if v.IP.To4() != nil { 49 | ip4 = v.IP.To4() 50 | if !ipv6 { 51 | return v.IP.To4(), Addr_type_ipv4, nil 52 | } 53 | } else if v.IP.To16() != nil && ipv6 { 54 | return v.IP.To16(), Addr_type_ipv6, nil 55 | 56 | }else{ 57 | continue 58 | } 59 | } 60 | if ip4 != nil { 61 | return ip4, Addr_type_ipv4, nil 62 | } 63 | return nil, 0, exception.DnsError{}.New("local domain "+ domain + " can not found A record") 64 | 65 | } 66 | -------------------------------------------------------------------------------- /src/go_proxy/conn/frame.go: -------------------------------------------------------------------------------- 1 | package conn 2 | 3 | import ( 4 | "bytes" 5 | "encoding/binary" 6 | "fmt" 7 | "go_proxy/exception" 8 | "syscall" 9 | ) 10 | 11 | const ( 12 | Verision = 0 13 | ) 14 | 15 | const ( 16 | Command_new_conn = 1 17 | Command_close_conn = 2 18 | Command_domain_ip = 3 19 | ) 20 | 21 | const ( 22 | Addr_type_ipv4 = 4 23 | Addr_type_ipv6 = 6 24 | Addr_domain = 1 25 | Addr_domain_try_ipv6 = 2 26 | Addr_none = 0 27 | ) 28 | 29 | const ( 30 | Proto_tcp = syscall.IPPROTO_TCP 31 | Proto_udp = syscall.IPPROTO_UDP 32 | ) 33 | 34 | 35 | //frame type 36 | const ( 37 | Control_frame = 1 38 | Data_frame = 2 39 | Udp_Frame = 3 40 | ) 41 | 42 | // 43 | const control_frame_least_header_len = 8 44 | const data_frame_least_header_len = 5 45 | const udp_frame_least_header_len = 8 46 | 47 | type Handshake_info struct { 48 | _const [2]byte 49 | Rand_byte []byte 50 | Max_payload uint16 51 | dns_addr_type byte 52 | dns_addr_len byte 53 | Dns_addr Addr 54 | } 55 | const handshake_info_least_byte = 6 56 | var handshake_info_const_byte = [2]byte{39,39} // 39 mean miku ~~ ~~ 57 | 58 | func (this *Handshake_info) ToBytes()[]byte{ 59 | max_payload:=[]byte{0,0} 60 | binary.BigEndian.PutUint16(max_payload,this.Max_payload) 61 | var addr = []byte{} 62 | if this.Dns_addr==nil{ 63 | this.dns_addr_type=Addr_none 64 | }else{ 65 | this.dns_addr_type=byte(this.Dns_addr.Type()) 66 | addr=bytes.Join([][]byte{this.Dns_addr.ToHostBytes(),this.Dns_addr.ToPortByte()},nil) 67 | } 68 | return bytes.Join([][]byte{ 69 | handshake_info_const_byte[:], 70 | this.Rand_byte, 71 | max_payload, 72 | {this.dns_addr_type}, 73 | {byte(len(addr))}, 74 | addr, 75 | },nil) 76 | } 77 | 78 | func Parse_handshake_info_from_byte(rand_enc_len int,d []byte)(*Handshake_info,error){ 79 | 80 | if len(d) 0 { 335 | f.Data = buf[:i] 336 | } 337 | select { 338 | case this.recvChan <- f: 339 | return 340 | case <-this.ctx.Done(): 341 | return 342 | } 343 | 344 | } else { 345 | select { 346 | case this.recvChan <- &DataFrame{ 347 | Version: 0, 348 | ConnectionId: connection_id, 349 | Data: buf[:i], 350 | }: 351 | break 352 | case <-this.ctx.Done(): 353 | return 354 | } 355 | } 356 | 357 | } 358 | 359 | }() 360 | 361 | for { 362 | select { 363 | 364 | case frame := <-local_recv_chan: 365 | 366 | switch frame.GetFrameType() { 367 | case Control_frame: 368 | frame := frame.(*ControlFrame) 369 | 370 | switch frame.Command { 371 | case Command_close_conn: 372 | local_close = true 373 | if len(frame.Data) != 0 { 374 | con.SetWriteDeadline(time.Now().Add(time.Duration(util.Tcp_timeout) * time.Second)) 375 | con.Write(frame.Data) 376 | } 377 | return local_close, nil 378 | default: 379 | return local_close, errors.New("recv an illegal command when subconnection established") 380 | 381 | } 382 | case Data_frame: 383 | con.SetWriteDeadline(time.Now().Add(time.Duration(util.Tcp_timeout) * time.Second)) 384 | if _, err := con.Write(frame.(*DataFrame).Data); err != nil { 385 | return local_close, err 386 | } 387 | default: 388 | return local_close, errors.New("recv an unknow frame type") 389 | } 390 | 391 | case <-local_ctx.Done(): 392 | return local_close, err 393 | case <-this.ctx.Done(): 394 | return local_close, nil 395 | } 396 | } 397 | } 398 | 399 | func (this *RemoteServerConnection) handle_new_udp_connection(frame *ControlFrame, local_recv_chan <-chan Frame) (bool, error) { 400 | var ( 401 | connection_id = frame.ConnectionId 402 | local_close = false 403 | route = &sync.Map{} 404 | ) 405 | 406 | ctx, cancel := context.WithCancel(context.TODO()) 407 | 408 | defer func() { 409 | cancel() 410 | 411 | g := &sync.WaitGroup{} 412 | g.Add(1) 413 | go func() { 414 | route.Range(func(_, value interface{}) bool { 415 | value.(*net.UDPConn).Close() 416 | return true 417 | }) 418 | g.Done() 419 | }() 420 | 421 | select { 422 | case this.recvChan <- &ControlFrame{ 423 | Version: 0, 424 | ConnectionId: connection_id, 425 | Command: Command_close_conn, 426 | }: 427 | case <-this.ctx.Done(): 428 | } 429 | 430 | g.Wait() 431 | for { 432 | i := 0 433 | route.Range(func(_, value interface{}) bool { 434 | i++ 435 | return true 436 | }) 437 | if i == 0 { 438 | break 439 | } 440 | time.Sleep(500 * time.Millisecond) 441 | } 442 | 443 | }() 444 | 445 | for { 446 | select { 447 | 448 | case frame := <-local_recv_chan: 449 | switch frame.GetFrameType() { 450 | case Control_frame: 451 | frame := frame.(*ControlFrame) 452 | switch frame.Command { 453 | case Command_close_conn: 454 | local_close = true 455 | return local_close, nil 456 | default: 457 | return local_close, errors.New("udp connection recv an illegal command") 458 | 459 | } 460 | case Udp_Frame: 461 | if frame.(*UdpFrame).local_addr_type == Addr_none || len(frame.(*UdpFrame).Data) == 0 { 462 | return local_close, errors.New("recv an unexpect udp frame") 463 | } 464 | go func(frame *UdpFrame) { 465 | 466 | var ( 467 | err error 468 | dest *net.UDPAddr 469 | ) 470 | switch frame.dest_addr_type { 471 | case Addr_type_ipv6, Addr_type_ipv4: 472 | dest = &net.UDPAddr{ 473 | IP: net.ParseIP(frame.Dest_addr.String()), 474 | Port: frame.Dest_addr.ToPortInt(), 475 | } 476 | 477 | case Addr_domain_try_ipv6, Addr_domain: 478 | 479 | var ( 480 | ip []byte 481 | ipv6 = frame.dest_addr_type == Addr_domain_try_ipv6 482 | ) 483 | 484 | if this.connection_info.dns_addr_type == Addr_none { 485 | ip, _, err = Parse_local_domain(frame.Dest_addr.String(), ipv6, "") 486 | } else { 487 | ip, _, err = Parse_local_domain(frame.Dest_addr.String(), ipv6, this.connection_info.Dns_addr.StringWithPort()) 488 | } 489 | if err != nil { 490 | break 491 | } 492 | dest = &net.UDPAddr{ 493 | IP: ip, 494 | Port: frame.Dest_addr.ToPortInt(), 495 | } 496 | 497 | default: 498 | util.Print_log_without_id("recv an unexpect udp frame") 499 | return 500 | } 501 | 502 | if err != nil { 503 | util.Print_log_without_id("dial udp fail: %s", err.Error()) 504 | return 505 | } 506 | 507 | lan_addr := frame.Local_addr.StringWithPort() 508 | 509 | con, ok := route.Load(lan_addr) 510 | if ok { 511 | con.(*net.UDPConn).WriteTo(frame.Data, dest) 512 | } else { 513 | con, err := net.ListenUDP("udp", nil) 514 | if err != nil { 515 | util.Print_log_without_id("listen udp fail: %s", err.Error()) 516 | return 517 | } 518 | 519 | defer func() { 520 | route.Delete(lan_addr) 521 | con.Close() 522 | }() 523 | 524 | route.Store(lan_addr, con) 525 | con.WriteTo(frame.Data, dest) 526 | 527 | for { 528 | con.SetReadDeadline(time.Now().Add(time.Duration(util.Config.Udp_timeout) * time.Second)) 529 | buf := make([]byte, Udp_buf_size) 530 | i, dest, err := con.ReadFrom(buf) 531 | if err != nil { 532 | return 533 | } 534 | 535 | dest_addr, err := NewAddrFromString(dest.String(), false) 536 | if err != nil { 537 | return 538 | } 539 | select { 540 | case <-this.ctx.Done(): 541 | return 542 | case <-ctx.Done(): 543 | return 544 | default: 545 | select { 546 | case this.recvChan <- &UdpFrame{ 547 | Version: 0, 548 | ConnectionId: connection_id, 549 | Local_addr: frame.Local_addr, 550 | Dest_addr: dest_addr, 551 | Data: buf[:i], 552 | }: 553 | continue 554 | case <-this.ctx.Done(): 555 | return 556 | case <-ctx.Done(): 557 | return 558 | } 559 | 560 | 561 | } 562 | 563 | } 564 | } 565 | 566 | }(frame.(*UdpFrame)) 567 | 568 | default: 569 | return local_close, errors.New("udp connection recv an unknow frame type") 570 | } 571 | 572 | case <-this.ctx.Done(): 573 | return local_close, nil 574 | } 575 | } 576 | 577 | } 578 | 579 | func client_hand_shake(serv_con net.Conn, conf *ServConfig) (*Handshake_info, error) { 580 | 581 | if conf.Tls_conf != nil { 582 | data_len := []byte{0, 0} 583 | if _, err := io.ReadAtLeast(serv_con, data_len, 2); err != nil { 584 | return nil, err 585 | } 586 | 587 | l := binary.BigEndian.Uint16(data_len) 588 | buf := make([]byte, l) 589 | if _, err := io.ReadAtLeast(serv_con, buf, int(l)); err != nil { 590 | return nil, err 591 | } 592 | data, err := conf.Crypt.Decrypt(buf) 593 | if err != nil { 594 | return nil, err 595 | } 596 | return Parse_handshake_info_from_byte(0, data) 597 | 598 | } else { 599 | var i int =0 600 | for _,v:=range conf.Crypt.Get_passwd(){ 601 | i+=int(v) 602 | } 603 | i=(i%100)+64 604 | b:=make([]byte,i) 605 | if _, err := rand.Read(b); err != nil { 606 | return nil, err 607 | } 608 | serv_con.SetDeadline(time.Now().Add(time.Duration(util.Tcp_timeout) * time.Second)) 609 | 610 | if _, err := serv_con.Write(b); err != nil { 611 | return nil, err 612 | } 613 | 614 | data_len := []byte{0, 0} 615 | if _, err := io.ReadAtLeast(serv_con, data_len, 2); err != nil { 616 | return nil, err 617 | } 618 | l := binary.BigEndian.Uint16(data_len) 619 | buf := make([]byte, l) 620 | if _, err := io.ReadAtLeast(serv_con, buf, int(l)); err != nil { 621 | return nil, err 622 | } 623 | 624 | data, err := conf.Crypt.Decrypt(buf) 625 | if err != nil { 626 | return nil, err 627 | } 628 | h, err := Parse_handshake_info_from_byte(len(b), data) 629 | if err != nil { 630 | return nil, err 631 | } 632 | 633 | if !bytes.Equal(h.Rand_byte, b) { 634 | return nil, errors.New("handshake fail,rand data not equal") 635 | } 636 | 637 | serv_con.SetDeadline(time.Time{}) 638 | return h, nil 639 | 640 | } 641 | } 642 | -------------------------------------------------------------------------------- /src/go_proxy/exception/err.go: -------------------------------------------------------------------------------- 1 | package exception 2 | 3 | 4 | type AddrErr struct { 5 | err string 6 | } 7 | 8 | func (this *AddrErr) Error() string { 9 | return "addr error : "+this.err 10 | } 11 | 12 | func (this AddrErr) New(err string) *AddrErr{ 13 | this.err=err 14 | return &this 15 | } 16 | 17 | 18 | type CryptErr struct { 19 | err string 20 | } 21 | 22 | func (this *CryptErr) Error() string { 23 | return "crypt error : "+this.err 24 | } 25 | 26 | func (this CryptErr) New(err string) *CryptErr{ 27 | this.err=err 28 | return &this 29 | } 30 | 31 | 32 | 33 | type FrameErr struct { 34 | err string 35 | } 36 | func (this *FrameErr) Error() string { 37 | return "frame error : "+this.err 38 | } 39 | 40 | func (this FrameErr) New(err string) *FrameErr{ 41 | this.err=err 42 | return &this 43 | } 44 | 45 | 46 | 47 | 48 | 49 | type DnsError struct{ 50 | err string 51 | } 52 | 53 | func (this *DnsError) Error() string { 54 | return "dns error : "+this.err 55 | } 56 | 57 | func (this DnsError) New(err string) *DnsError{ 58 | this.err=err 59 | return &this 60 | } 61 | -------------------------------------------------------------------------------- /src/go_proxy/go.mod: -------------------------------------------------------------------------------- 1 | module go_proxy 2 | 3 | go 1.13 4 | 5 | require ( 6 | golang.org/x/crypto v0.0.0-20200117160349-530e935923ad 7 | golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa 8 | ) 9 | -------------------------------------------------------------------------------- /src/go_proxy/go.sum: -------------------------------------------------------------------------------- 1 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 2 | golang.org/x/crypto v0.0.0-20200117160349-530e935923ad h1:Jh8cai0fqIK+f6nG0UgPW5wFk8wmiMhM3AyciDBdtQg= 3 | golang.org/x/crypto v0.0.0-20200117160349-530e935923ad/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 4 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 5 | golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa h1:F+8P+gmewFQYRk6JoLQLwjBCTu3mcIURZfNkVweuRKA= 6 | golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 7 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 8 | golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI= 9 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 10 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 11 | -------------------------------------------------------------------------------- /src/go_proxy/local_proxy/connection_handler.go: -------------------------------------------------------------------------------- 1 | package local_proxy 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "go_proxy/conn" 7 | "go_proxy/util" 8 | "io" 9 | "net" 10 | "time" 11 | ) 12 | 13 | func convert_addr(addr conn.Addr, config *conn.ClientConfig) (conn.Addr, bool, error) { 14 | if addr.IsDomain() { 15 | var( 16 | _ip interface{} 17 | ok bool = false 18 | ) 19 | if addr.IsChinaAddr() { 20 | is_cn := true 21 | if config.Domain_cache_time!=0{ 22 | _ip, ok = config.Cn_domain_ip_map.Load(addr.String()) 23 | } 24 | if ok { 25 | var ( 26 | new_addr conn.Addr 27 | err error 28 | ) 29 | 30 | if time.Now().Unix()-_ip.(*conn.Domain_record).Time > config.Domain_cache_time { 31 | config.Cn_domain_ip_map.Delete(addr.String()) 32 | goto china_addr_not_ok 33 | } 34 | ip := _ip.(*conn.Domain_record).Ip 35 | 36 | if len(ip) == 16 { 37 | new_addr, err = conn.NewAddrFromByte(ip, addr.ToPortByte(), conn.Addr_type_ipv6) 38 | if err != nil { 39 | return nil, is_cn, err 40 | } 41 | return convert_addr(new_addr, config) 42 | } else if len(ip) == 4 { 43 | new_addr, err = conn.NewAddrFromByte(ip, addr.ToPortByte(), conn.Addr_type_ipv4) 44 | } else { 45 | err = errors.New("cn domain map load an unknow ip type") 46 | } 47 | return new_addr, is_cn, err 48 | 49 | } 50 | china_addr_not_ok: 51 | ip, _type, err := conn.Parse_local_domain(addr.String(), config.Ipv6, config.Local_dns_addr) 52 | if err != nil { 53 | return nil, is_cn, err 54 | } 55 | 56 | if config.Domain_cache_time != 0 { 57 | config.Cn_domain_ip_map.Store(addr.String(), &conn.Domain_record{ 58 | Ip: ip, 59 | Time: time.Now().Unix(), 60 | }) 61 | } 62 | 63 | new_addr, err := conn.NewAddrFromByte(ip, addr.ToPortByte(), _type) 64 | if err != nil { 65 | return nil, is_cn, err 66 | } 67 | 68 | if _type == conn.Addr_type_ipv6 { 69 | return convert_addr(new_addr, config) 70 | } 71 | 72 | return new_addr, is_cn, nil 73 | 74 | } else { 75 | is_cn := false 76 | if config.Domain_cache_time!=0{ 77 | _ip, ok = config.Not_cn_domain_ip_map.Load(addr.String()) 78 | } 79 | 80 | if ok { 81 | if time.Now().Unix()-_ip.(*conn.Domain_record).Time>config.Domain_cache_time{ 82 | config.Not_cn_domain_ip_map.Delete(addr.String()) 83 | return addr, is_cn, nil 84 | } 85 | 86 | var ( 87 | new_addr conn.Addr 88 | err error 89 | ) 90 | 91 | ip := _ip.(*conn.Domain_record).Ip 92 | 93 | if len(ip) == 16 { 94 | new_addr, err = conn.NewAddrFromByte(ip, addr.ToPortByte(), conn.Addr_type_ipv6) 95 | } else if len(ip) == 4 { 96 | new_addr, err = conn.NewAddrFromByte(ip, addr.ToPortByte(), conn.Addr_type_ipv4) 97 | } else { 98 | err = errors.New("not cn domain map load an unknow ip type") 99 | return nil, is_cn, err 100 | } 101 | return new_addr, is_cn, err 102 | } else { 103 | return addr, is_cn, nil 104 | } 105 | } 106 | } else { 107 | if addr.IsChinaAddr() { 108 | return addr, true, nil 109 | } else { 110 | return addr, false, nil 111 | } 112 | } 113 | 114 | } 115 | 116 | func split_bytes(b []byte,size int)[][]byte{ 117 | if size<1 || size>=len(b){ 118 | return [][]byte{b} 119 | } 120 | r:=make([][]byte,0) 121 | i:=0 122 | for ;i<=len(b)-size;i+=size{ 123 | r=append(r,b[i:i+size]) 124 | } 125 | if i 0 { 304 | f.Data = buf[:i] 305 | } 306 | select { 307 | case local.SendChan <- f: 308 | return 309 | case <-local.Remote_ctx.Done(): 310 | return 311 | } 312 | 313 | } else { 314 | select { 315 | case local.SendChan <- &conn.DataFrame{ 316 | Version: 0, 317 | ConnectionId: local.ConnectionId, 318 | Data: buf[:i], 319 | }: 320 | 321 | break 322 | case <-local.Remote_ctx.Done(): 323 | return 324 | } 325 | } 326 | 327 | } 328 | 329 | }() 330 | 331 | for { 332 | select { 333 | case frame := <-local.RecvChan: 334 | switch frame.GetFrameType() { 335 | case conn.Data_frame: 336 | local.Local.SetWriteDeadline(time.Now().Add(time.Duration(util.Tcp_timeout) * time.Second)) 337 | if _, err := local.Local.Write(frame.(*conn.DataFrame).Data); err != nil { 338 | return err 339 | } 340 | 341 | case conn.Control_frame: 342 | frame := frame.(*conn.ControlFrame) 343 | switch frame.Command { 344 | case conn.Command_close_conn: 345 | remote_close = true 346 | if len(frame.Data) != 0 { 347 | local.Local.SetWriteDeadline(time.Now().Add(time.Duration(util.Tcp_timeout) * time.Second)) 348 | local.Local.Write(frame.Data) 349 | } 350 | return nil 351 | default: 352 | return errors.New("recv an unexpect frame") 353 | } 354 | default: 355 | return errors.New("recv an unexpect frame") 356 | } 357 | 358 | case <-local.Local_ctx.Done(): 359 | return err 360 | case <-local.Remote_ctx.Done(): 361 | return nil 362 | } 363 | 364 | } 365 | } 366 | -------------------------------------------------------------------------------- /src/go_proxy/local_proxy/handle_http.go: -------------------------------------------------------------------------------- 1 | package local_proxy 2 | 3 | import ( 4 | "bufio" 5 | "bytes" 6 | "errors" 7 | "go_proxy/conn" 8 | "io" 9 | "net" 10 | "net/http" 11 | "strings" 12 | ) 13 | 14 | const https_establish_reply = "HTTP/1.1 200 Connection Established\r\n\r\n" 15 | 16 | func handle_http_con(con *net.TCPConn, config *conn.ClientConfig) error { 17 | 18 | defer conn.CloseTcp(con) 19 | 20 | req, err := http.ReadRequest(bufio.NewReader(con)) 21 | if err != nil { 22 | conn.CloseTcp(con) 23 | return err 24 | } 25 | switch strings.ToLower(req.Method) { 26 | case "connect": 27 | addr, err := conn.NewAddrFromString(req.Host, config.Ipv6) 28 | if err != nil { 29 | return err 30 | } 31 | addr, is_cn, err := convert_addr(addr, config) 32 | if err != nil { 33 | return err 34 | } 35 | 36 | if is_cn { 37 | return handle_cn_connection(config,con, addr, nil, []byte(https_establish_reply)) 38 | } else { 39 | local, err := config.ConnectionHandler.Dispatch_client(con) 40 | if err != nil { 41 | return err 42 | } 43 | 44 | frame := &conn.ControlFrame{ 45 | Version: 0, 46 | ConnectionId: local.ConnectionId, 47 | Command: conn.Command_new_conn, 48 | Protocol: conn.Proto_tcp, 49 | Addr: addr, 50 | } 51 | 52 | return handle_not_cn_connection(local, frame, []byte(https_establish_reply), config) 53 | } 54 | 55 | default: 56 | host := req.Host 57 | if host==""{ 58 | return errors.New("http proxy can not determine host") 59 | } 60 | split := ":" 61 | if host[0] == '[' { 62 | split = "]:" 63 | } 64 | if len(strings.Split(host, split)) == 1 { 65 | host += ":80" 66 | } 67 | addr, err := conn.NewAddrFromString(host, config.Ipv6) 68 | if err != nil { 69 | return err 70 | } 71 | data, err := convert_to_close(req) 72 | if err != nil { 73 | return err 74 | } 75 | addr, is_cn, err := convert_addr(addr, config) 76 | if err != nil { 77 | return err 78 | } 79 | 80 | if is_cn { 81 | return handle_cn_connection(config,con, addr, data, nil) 82 | 83 | } else { 84 | local, err := config.ConnectionHandler.Dispatch_client(con) 85 | if err != nil { 86 | return err 87 | } 88 | frame := &conn.ControlFrame{ 89 | Version: 0, 90 | ConnectionId: local.ConnectionId, 91 | Command: conn.Command_new_conn, 92 | Protocol: conn.Proto_tcp, 93 | Addr: addr, 94 | Data: data, 95 | } 96 | 97 | return handle_not_cn_connection(local, frame, nil, config) 98 | } 99 | } 100 | 101 | } 102 | 103 | func convert_to_close(req *http.Request) ([]byte, error) { 104 | req.Header.Del("Proxy-Connection") 105 | req.Header.Del("proxy-connection") 106 | req.Header.Del("Connection") 107 | req.Header.Del("connection") 108 | req.Header.Add("Connection", "close") 109 | buf := &bytes.Buffer{} 110 | req.Write(buf) 111 | _buf := make([]byte, 1024) 112 | data := []byte{} 113 | for { 114 | i, err := buf.Read(_buf) 115 | if i > 0 { 116 | data = bytes.Join([][]byte{data, _buf[:i]}, nil) 117 | } 118 | if err != nil { 119 | if err == io.EOF { 120 | return data, nil 121 | } else { 122 | return nil, err 123 | } 124 | } 125 | } 126 | 127 | } 128 | -------------------------------------------------------------------------------- /src/go_proxy/local_proxy/handle_iptables.go: -------------------------------------------------------------------------------- 1 | package local_proxy 2 | 3 | import ( 4 | "context" 5 | "encoding/binary" 6 | "errors" 7 | "fmt" 8 | "go_proxy/conn" 9 | "go_proxy/util" 10 | "net" 11 | "syscall" 12 | "time" 13 | ) 14 | 15 | var ( 16 | //linux defined const 17 | 18 | //IPPROTO_IP =syscall.IPPROTO_IP 19 | //IPPROTO_IPV6 =syscall.IPPROTO_IPV6 20 | //IP_RECVORIGDSTADDR = syscall.IP_RECVORIGDSTADDR 21 | //IP_TRANSPARENT = syscall.IP_TRANSPARENT 22 | ) 23 | 24 | const ( 25 | SO_ORIGIN_DST = 80 26 | IPT6_SO_ORIGIN_DST = 80 27 | IPPROTO_IP = 0x0 28 | IPPROTO_IPV6 = 0x29 29 | SO_REUSEPORT = 15 30 | IP_RECVORIGDSTADDR = 0x14 31 | IPV6_RECVORIGDSTADDR = 0x4a 32 | IP_TRANSPARENT = 0x13 33 | ) 34 | 35 | func get_tcp_origin_dest(con *net.TCPConn) (conn.Addr, error) { 36 | return conn.NewAddrFromString(con.LocalAddr().String(), false) 37 | } 38 | 39 | func get_udp_origin_dest(oob []byte, ipv6 bool) (conn.Addr, error) { 40 | msgs, err := syscall.ParseSocketControlMessage(oob) 41 | if err != nil { 42 | return nil, errors.New(fmt.Sprintf("get udp destination addr fail: %s", err.Error())) 43 | } 44 | 45 | for _, msg := range msgs { 46 | if msg.Header.Type == IP_RECVORIGDSTADDR && !ipv6 { 47 | return conn.NewAddrFromByte(msg.Data[4:8], msg.Data[2:4], conn.Addr_type_ipv4) 48 | } 49 | if msg.Header.Type == IPV6_RECVORIGDSTADDR && ipv6 { 50 | return conn.NewAddrFromByte(msg.Data[8:24], msg.Data[2:4], conn.Addr_type_ipv6) 51 | } 52 | } 53 | 54 | return nil, errors.New("get udp destination addr fail: IP_RECVORIGDSTADDR not found in socket control message") 55 | } 56 | 57 | func handle_iptables(con *net.TCPConn, config *conn.ClientConfig) error { 58 | defer conn.CloseTcp(con) 59 | 60 | addr, err := get_tcp_origin_dest(con) 61 | if err != nil { 62 | return err 63 | } 64 | local, err := config.ConnectionHandler.Dispatch_client(con) 65 | if err != nil { 66 | return err 67 | } 68 | frame := &conn.ControlFrame{ 69 | Version: 0, 70 | ConnectionId: local.ConnectionId, 71 | Command: conn.Command_new_conn, 72 | Protocol: conn.Proto_tcp, 73 | Addr: addr, 74 | } 75 | return handle_not_cn_connection(local, frame, nil, config) 76 | } 77 | 78 | func handle_iptables_udp_forward_tcp(ul *net.UDPConn, config *conn.ClientConfig, ipv6 bool) { 79 | var data_chan = make(chan *conn.UdpFrame) 80 | var dns_data_chan = make(chan *conn.UdpFrame) 81 | 82 | go remote_udp_2_tcp_loop(data_chan, config, ul, false) 83 | go remote_udp_2_tcp_loop(dns_data_chan, config, ul, true) 84 | 85 | for { 86 | data, oob := make([]byte, conn.Udp_buf_size), make([]byte, 1024) 87 | i, oobi, _, addr, err := ul.ReadMsgUDP(data, oob) 88 | if err != nil { 89 | util.Print_log(config.Id, "udp read fail: %s", err.Error()) 90 | continue 91 | } 92 | 93 | go func(local_addr *net.UDPAddr, data, oob []byte) { 94 | dest_addr, err := get_udp_origin_dest(oob, ipv6) 95 | if err != nil { 96 | util.Print_log(config.Id, err.Error()) 97 | return 98 | } 99 | 100 | _local_addr, err := conn.NewAddrFromString(local_addr.String(), false) 101 | if err != nil { 102 | util.Print_log(config.Id, "convert local addr fail: %s ", err.Error()) 103 | return 104 | } 105 | 106 | if net.IP(dest_addr.ToHostBytes()).IsLoopback() { 107 | if dest_addr.ToPortInt() == config.Local_port { //dns request 108 | select { 109 | case <-time.After(time.Duration(util.Config.Udp_timeout) * time.Second): 110 | return 111 | case dns_data_chan <- &conn.UdpFrame{ 112 | Version: 0, 113 | Local_addr: _local_addr, 114 | Dest_addr: config.Remoted_dns, 115 | Data: data, 116 | }: 117 | return 118 | } 119 | 120 | } else { 121 | util.Print_log(config.Id, "recv an unexpect udp addr with loopback destination ip") 122 | } 123 | } else { 124 | if util.Verbose_info { 125 | util.Print_verbose("%s connect not cn udp addr:%s", _local_addr.String(), dest_addr.StringWithPort()) 126 | } 127 | select { 128 | case <-time.After(time.Duration(util.Config.Udp_timeout) * time.Second): 129 | return 130 | case data_chan <- &conn.UdpFrame{ 131 | Version: 0, 132 | Local_addr: _local_addr, 133 | Dest_addr: dest_addr, 134 | Data: data, 135 | }: 136 | return 137 | } 138 | 139 | } 140 | 141 | }(addr, data[:i], oob[:oobi]) 142 | 143 | } 144 | } 145 | 146 | func handle_iptables_udp_forward_udp(ul, remote, remote_dns *net.UDPConn, config *conn.ClientConfig, ipv6 bool) { 147 | go remote_udp_2_udp_loop(remote, ul, config, false) 148 | go remote_udp_2_udp_loop(remote_dns, ul, config, true) 149 | 150 | for { 151 | data, oob := make([]byte, conn.Udp_buf_size), make([]byte, 1024) 152 | i, oobi, _, addr, err := ul.ReadMsgUDP(data, oob) 153 | 154 | go func(data, oob []byte, addr *net.UDPAddr, err error) { 155 | if err != nil { 156 | util.Print_log(config.Id, "udp read from local fail: %s", err.Error()) 157 | return 158 | } 159 | 160 | dest_addr, err := get_udp_origin_dest(oob, ipv6) 161 | if err != nil { 162 | util.Print_log(config.Id, "udp get destination addr fail: %s", err.Error()) 163 | return 164 | } 165 | 166 | port := make([]byte, 2) 167 | binary.BigEndian.PutUint16(port, uint16(addr.Port)) 168 | local_addr, err := conn.NewAddrFromString(addr.String(), false) 169 | 170 | if err != nil { 171 | util.Print_log(config.Id, "udp local addr parse fail: %s", err.Error()) 172 | return 173 | } 174 | 175 | if err := write_to_remote(remote, remote_dns, config, data, local_addr, dest_addr); err != nil { 176 | util.Print_log(config.Id, err.Error()) 177 | return 178 | } 179 | 180 | }(data[:i], oob[:oobi], addr, err) 181 | 182 | } 183 | } 184 | 185 | func write_to_remote(remote, remote_dns *net.UDPConn, config *conn.ClientConfig, data []byte, local_addr, dest_addr conn.Addr) error { 186 | 187 | if net.IP(dest_addr.ToHostBytes()).IsLoopback() { 188 | if dest_addr.ToPortInt() == config.Local_port { //dns request 189 | remote_dns.WriteToUDP(config.Udp_crypt.Encrypt((&conn.UdpFrame{ 190 | Version: 0, 191 | Local_addr: local_addr, 192 | Dest_addr: config.Remoted_dns, 193 | Data: data, 194 | }).ToBytes()), &net.UDPAddr{ 195 | IP: config.Udp_Server_Addr.ToHostBytes(), 196 | Port: config.Udp_Server_Addr.ToPortInt(), 197 | Zone: "", 198 | }) 199 | return nil 200 | } else { 201 | return errors.New("recv an unexpect udp addr with loopback destination ip") 202 | } 203 | } else { 204 | if util.Verbose_info { 205 | util.Print_verbose("%s connect not cn udp addr:%s", local_addr.StringWithPort(), dest_addr.StringWithPort()) 206 | } 207 | 208 | remote.WriteToUDP(config.Udp_crypt.Encrypt((&conn.UdpFrame{ 209 | Version: 0, 210 | Local_addr: local_addr, 211 | Dest_addr: dest_addr, 212 | Data: data, 213 | }).ToBytes()), &net.UDPAddr{ 214 | IP: config.Udp_Server_Addr.ToHostBytes(), 215 | Port: config.Udp_Server_Addr.ToPortInt(), 216 | Zone: "", 217 | }) 218 | 219 | return nil 220 | } 221 | 222 | } 223 | 224 | func write_to_local(udp_frame *conn.UdpFrame,zone_id uint32) error { 225 | var ( 226 | fd int 227 | err error 228 | addr_to_sock_addr = func(addr conn.Addr) syscall.Sockaddr { 229 | switch addr.Type() { 230 | case conn.Addr_type_ipv6: 231 | var ip [16]byte 232 | for i, v := range addr.ToHostBytes() { 233 | ip[i] = v 234 | } 235 | 236 | return &syscall.SockaddrInet6{ 237 | Port: addr.ToPortInt(), 238 | Addr: ip, 239 | ZoneId:zone_id, 240 | } 241 | case conn.Addr_type_ipv4: 242 | var ip [4]byte 243 | for i, v := range addr.ToHostBytes() { 244 | ip[i] = v 245 | } 246 | return &syscall.SockaddrInet4{ 247 | Port: addr.ToPortInt(), 248 | Addr: ip, 249 | } 250 | default: 251 | return nil 252 | } 253 | } 254 | ) 255 | if udp_frame.Dest_addr == nil || udp_frame.Local_addr == nil { 256 | return errors.New("recv an unexpect udp frame") 257 | } 258 | 259 | switch udp_frame.Dest_addr.Type() { 260 | case conn.Addr_type_ipv6: 261 | fd, err = syscall.Socket(syscall.AF_INET6, syscall.SOCK_DGRAM, syscall.IPPROTO_UDP) 262 | if err != nil { 263 | return errors.New("create udp socket error:" + err.Error()) 264 | } 265 | defer syscall.Close(fd) 266 | 267 | if err := syscall.SetsockoptInt(fd, IPPROTO_IP, IP_TRANSPARENT, 1); err != nil { 268 | return err 269 | } 270 | if err := syscall.SetsockoptInt(fd, syscall.SOL_SOCKET, SO_REUSEPORT, 1); err != nil { 271 | return err 272 | } 273 | 274 | case conn.Addr_type_ipv4: 275 | fd, err = syscall.Socket(syscall.AF_INET, syscall.SOCK_DGRAM, syscall.IPPROTO_UDP) 276 | if err != nil { 277 | return errors.New("create udp socket error:" + err.Error()) 278 | } 279 | defer syscall.Close(fd) 280 | 281 | if err := syscall.SetsockoptInt(fd, IPPROTO_IP, IP_TRANSPARENT, 1); err != nil { 282 | return err 283 | } 284 | if err := syscall.SetsockoptInt(fd, syscall.SOL_SOCKET, SO_REUSEPORT, 1); err != nil { 285 | return err 286 | } 287 | 288 | default: 289 | return errors.New("recv an unexpect udp frame") 290 | } 291 | 292 | if err := syscall.Bind(fd, addr_to_sock_addr(udp_frame.Dest_addr)); err != nil { 293 | return errors.New("bind udp addr error:" + err.Error()) 294 | } 295 | 296 | if err := syscall.Connect(fd, addr_to_sock_addr(udp_frame.Local_addr)); err != nil { 297 | return errors.New("udp addr connect error:" + err.Error()) 298 | } 299 | syscall.Write(fd, udp_frame.Data) 300 | return nil 301 | } 302 | 303 | func remote_udp_2_udp_loop(remote, local *net.UDPConn, config *conn.ClientConfig, is_dns bool) { 304 | for { 305 | data := make([]byte, conn.Udp_buf_size) 306 | i, err := remote.Read(data) 307 | 308 | go func(data []byte, err error) { 309 | if err != nil { 310 | util.Print_log(config.Id, "udp read from remote fail: %s", err.Error()) 311 | return 312 | } 313 | 314 | b, err := config.Udp_crypt.Decrypt(data[:i]) 315 | 316 | if err != nil { 317 | util.Print_log(config.Id, err.Error()) 318 | return 319 | } 320 | 321 | frame, err := conn.ParseBytesToFrame(b) 322 | if err != nil { 323 | util.Print_log(config.Id, err.Error()) 324 | return 325 | } 326 | 327 | if frame.GetFrameType() != conn.Udp_Frame { 328 | util.Print_log(config.Id, "udp recv an unexpect frame") 329 | return 330 | } 331 | f := frame.(*conn.UdpFrame) 332 | 333 | if is_dns { 334 | local.WriteToUDP(f.Data, &net.UDPAddr{ 335 | IP: net.ParseIP(f.Local_addr.String()), 336 | Port: f.Local_addr.ToPortInt(), 337 | }) 338 | } else { 339 | if err := write_to_local(f,config.Zone_id); err != nil { 340 | util.Print_log(config.Id, err.Error()) 341 | return 342 | } 343 | } 344 | }(data[:i], err) 345 | } 346 | } 347 | 348 | func remote_udp_2_tcp_loop(data_chan chan *conn.UdpFrame, config *conn.ClientConfig, local *net.UDPConn, is_dns bool) { 349 | for { 350 | frame := <-data_chan 351 | remote, err := config.ConnectionHandler.Dispatch_client(local) 352 | if err != nil { 353 | util.Print_log(config.Id, "connect to remote fail: %s", err.Error()) 354 | continue 355 | } 356 | 357 | frame.ConnectionId = remote.ConnectionId 358 | 359 | select { 360 | case <-remote.Remote_ctx.Done(): 361 | continue 362 | case remote.SendChan <- &conn.ControlFrame{ 363 | Version: 0, 364 | ConnectionId: remote.ConnectionId, 365 | Command: conn.Command_new_conn, 366 | Protocol: conn.Proto_udp, 367 | }: 368 | } 369 | 370 | select { 371 | case <-remote.Remote_ctx.Done(): 372 | continue 373 | case remote.SendChan <- frame: 374 | } 375 | 376 | var cancel func() 377 | 378 | remote.Local_ctx, cancel = context.WithCancel(context.TODO()) 379 | t_ctx, _ := context.WithTimeout(context.TODO(), time.Duration(util.Config.Udp_timeout)*time.Second) 380 | ctx, cancel2 := context.WithCancel(context.TODO()) 381 | 382 | go func() { 383 | var remote_close = false 384 | 385 | defer func() { 386 | cancel2() 387 | remote.Close(remote_close) 388 | }() 389 | 390 | for { 391 | select { 392 | case frame := <-remote.RecvChan: 393 | switch frame.GetFrameType() { 394 | case conn.Udp_Frame: 395 | go func(frame *conn.UdpFrame) { 396 | if is_dns { 397 | local.WriteToUDP(frame.Data, &net.UDPAddr{ 398 | IP: net.ParseIP(frame.Local_addr.String()), 399 | Port: frame.Local_addr.ToPortInt(), 400 | }) 401 | } else { 402 | if err := write_to_local(frame,config.Zone_id); err != nil { 403 | util.Print_log(config.Id, err.Error()) 404 | return 405 | } 406 | } 407 | }(frame.(*conn.UdpFrame)) 408 | 409 | case conn.Control_frame: 410 | switch frame.(*conn.ControlFrame).Command { 411 | case conn.Command_close_conn: 412 | remote_close = true 413 | return 414 | default: 415 | util.Print_log(config.Id, "recv an unexpect command") 416 | return 417 | } 418 | 419 | default: 420 | util.Print_log(config.Id, "recv an unexpect frame type") 421 | return 422 | 423 | } 424 | 425 | case <-remote.Remote_ctx.Done(): 426 | return 427 | case <-remote.Local_ctx.Done(): 428 | return 429 | } 430 | } 431 | }() 432 | 433 | loop: 434 | for { 435 | select { 436 | case frame := <-data_chan: 437 | t_ctx, _ = context.WithTimeout(context.TODO(), time.Duration(util.Config.Udp_timeout)*time.Second) 438 | frame.ConnectionId = remote.ConnectionId 439 | select { 440 | case remote.SendChan <- frame: 441 | case <-remote.Remote_ctx.Done(): 442 | break loop 443 | case <-ctx.Done(): 444 | break loop 445 | } 446 | case <-remote.Remote_ctx.Done(): 447 | break loop 448 | case <-t_ctx.Done(): 449 | break loop 450 | case <-ctx.Done(): 451 | break loop 452 | } 453 | 454 | } 455 | 456 | select { 457 | case remote.SendChan <- &conn.ControlFrame{ 458 | Version: 0, 459 | ConnectionId: remote.ConnectionId, 460 | Command: conn.Command_close_conn, 461 | }: 462 | 463 | case <-remote.Remote_ctx.Done(): 464 | } 465 | 466 | cancel() 467 | 468 | } 469 | } 470 | -------------------------------------------------------------------------------- /src/go_proxy/local_proxy/handle_socks5.go: -------------------------------------------------------------------------------- 1 | package local_proxy 2 | 3 | import ( 4 | "bytes" 5 | "context" 6 | "encoding/binary" 7 | "errors" 8 | "fmt" 9 | "go_proxy/conn" 10 | "go_proxy/util" 11 | "io" 12 | "net" 13 | "sync" 14 | "time" 15 | ) 16 | 17 | var sockks5_reply = []byte{5, 0, 0, 1, 0, 0, 0, 0, 0, 0} 18 | 19 | func handle_socks5(con net.Conn, config *conn.ClientConfig) error { 20 | defer conn.CloseTcp(con.(*net.TCPConn)) 21 | 22 | buf := []byte{0, 0} 23 | _, err := io.ReadAtLeast(con, buf, 2) 24 | if err != nil { 25 | return err 26 | } 27 | if buf[0] != 5 { 28 | return errors.New("socks5 recv unexpect data") 29 | } 30 | methods_len := int(buf[1]) 31 | buf = make([]byte, methods_len) 32 | if _, err = io.ReadAtLeast(con, buf, methods_len); err != nil { 33 | return err 34 | } 35 | 36 | for _, v := range buf { 37 | if v == 0 { 38 | if _, err := con.Write([]byte{5, 0}); err != nil { 39 | return err 40 | } 41 | buf = make([]byte, 4) 42 | if _, err := io.ReadAtLeast(con, buf, 4); err != nil { 43 | return err 44 | } 45 | 46 | if buf[1] == 1 { 47 | return handle_socks5_tcp(con, config, buf[3]) 48 | } else if buf[1] == 3 { 49 | return handle_socks5_udp(con, config, buf[3]) 50 | } else { 51 | break 52 | } 53 | } 54 | } 55 | 56 | return errors.New("socks5 recv unexpect data") 57 | 58 | } 59 | 60 | func handle_socks5_tcp(con net.Conn, config *conn.ClientConfig, atype byte) error { 61 | addr, _, err := get_socks5_dest_addr(con, config, atype) 62 | 63 | if err != nil { 64 | return err 65 | } 66 | addr, is_cn, err := convert_addr(addr, config) 67 | if err != nil { 68 | return err 69 | } 70 | if is_cn { 71 | return handle_cn_connection(config, con, addr, nil, sockks5_reply) 72 | } else { 73 | local, err := config.ConnectionHandler.Dispatch_client(con) 74 | if err != nil { 75 | return err 76 | } 77 | frame := &conn.ControlFrame{ 78 | Version: 0, 79 | ConnectionId: local.ConnectionId, 80 | Command: conn.Command_new_conn, 81 | Protocol: conn.Proto_tcp, 82 | Addr: addr, 83 | } 84 | return handle_not_cn_connection(local, frame, sockks5_reply, config) 85 | } 86 | } 87 | 88 | func handle_socks5_udp(con net.Conn, config *conn.ClientConfig, atype byte) error { 89 | 90 | _, _, err := get_socks5_dest_addr(con, config, atype) 91 | if err != nil { 92 | return err 93 | } 94 | 95 | _addr := con.LocalAddr() 96 | addr, err := conn.NewAddrFromString(_addr.String(), false) 97 | if err != nil { 98 | return err 99 | } 100 | switch addr.Type() { 101 | case conn.Addr_type_ipv4: 102 | con.Write(bytes.Join([][]byte{{5, 0, 0, 1}, addr.ToHostBytes(), addr.ToPortByte()}, nil)) 103 | case conn.Addr_type_ipv6: 104 | con.Write(bytes.Join([][]byte{{5, 0, 0, 4}, addr.ToHostBytes(), addr.ToPortByte()}, nil)) 105 | default: 106 | return errors.New("unknow error") 107 | 108 | } 109 | buf := make([]byte, conn.Tcp_buf_size) 110 | for { 111 | if _, err := con.Read(buf); err != nil { 112 | return nil 113 | } 114 | } 115 | 116 | } 117 | 118 | func udp_reply(ul *net.UDPConn, udp_frame *conn.UdpFrame) { 119 | reply_data := bytes.Join([][]byte{{0, 0, 0, 0}, udp_frame.Dest_addr.ToHostBytes(), udp_frame.Dest_addr.ToPortByte(), udp_frame.Data}, nil) 120 | switch udp_frame.Dest_addr.Type() { 121 | case conn.Addr_type_ipv4: 122 | reply_data[3] = 1 123 | case conn.Addr_type_ipv6: 124 | reply_data[3] = 4 125 | default: 126 | util.Print_log_without_id("impossible error: ip addr resolve as domain") 127 | } 128 | 129 | ul.WriteToUDP(reply_data, &net.UDPAddr{ 130 | IP: udp_frame.Local_addr.ToHostBytes(), 131 | Port: udp_frame.Local_addr.ToPortInt(), 132 | }) 133 | } 134 | 135 | type socks5_frag struct { 136 | end bool 137 | position byte 138 | data []byte 139 | } 140 | 141 | // socks5 udp fragment, beta 142 | func handle_socks5_udp_frag(buf []byte, head_delimiter int, m *sync.Map, source *net.UDPAddr, dest conn.Addr, send_to_remote_func func(local_addr *net.UDPAddr, dest conn.Addr, data []byte)) { 143 | end := buf[2] >> 7 144 | position := buf[2] & 127 145 | ctx, ok := m.Load(concatnate_addr(source, dest)) 146 | if ok { 147 | ctx := ctx.(context.Context) 148 | ch := ctx.Value("ch").(chan *socks5_frag) 149 | select { 150 | case ch <- &socks5_frag{ 151 | end: end == 1, 152 | position: position, 153 | data: buf[head_delimiter:], 154 | }: 155 | case <-ctx.Done(): 156 | close(ch) 157 | } 158 | 159 | } else { 160 | ch := make(chan *socks5_frag, 100) 161 | ch <- &socks5_frag{ 162 | end: end == 1, 163 | position: position, 164 | data: buf[head_delimiter:], 165 | } 166 | ctx, cancel := context.WithTimeout(context.TODO(), time.Duration(util.Config.Udp_timeout)*time.Second) 167 | ctx = context.WithValue(ctx, "ch", ch) 168 | m.Store(concatnate_addr(source, dest), ctx) 169 | go udp_frag_reassembly(source, dest, ch, m, ctx, cancel, send_to_remote_func) 170 | } 171 | } 172 | 173 | func udp_frag_reassembly(local_addr *net.UDPAddr, dest conn.Addr, ch chan *socks5_frag, m *sync.Map, ctx context.Context, cancel func(), send_func func(*net.UDPAddr, conn.Addr, []byte)) { 174 | var ( 175 | current_position byte = 0 176 | data []byte 177 | ) 178 | 179 | defer func() { 180 | cancel() 181 | m.Delete(concatnate_addr(local_addr, dest)) 182 | }() 183 | 184 | l: 185 | for { 186 | select { 187 | case frag, ok := <-ch: 188 | if !ok { 189 | return 190 | } 191 | if frag.position > current_position { 192 | data = bytes.Join([][]byte{data, frag.data}, nil) 193 | } else { 194 | return 195 | } 196 | if frag.end { 197 | break l 198 | } 199 | case <-ctx.Done(): 200 | return 201 | } 202 | } 203 | go send_func(local_addr, dest, data) 204 | } 205 | 206 | func handle_socks5_udp_forward_tcp(ul *net.UDPConn, config *conn.ClientConfig) { 207 | var ( 208 | data_chan = make(chan *conn.UdpFrame) 209 | route = &sync.Map{} 210 | ) 211 | 212 | go func() { 213 | for { 214 | frame := <-data_chan 215 | local, err := config.ConnectionHandler.Dispatch_client(ul) 216 | if err != nil { 217 | util.Print_log(config.Id, "connect to remote fail: %s", err.Error()) 218 | continue 219 | } 220 | 221 | frame.ConnectionId = local.ConnectionId 222 | 223 | select { 224 | case local.SendChan <- &conn.ControlFrame{ 225 | Version: 0, 226 | ConnectionId: local.ConnectionId, 227 | Command: conn.Command_new_conn, 228 | Protocol: conn.Proto_udp, 229 | }: 230 | case <-local.Remote_ctx.Done(): 231 | continue 232 | } 233 | 234 | select { 235 | case local.SendChan <- frame: 236 | case <-local.Remote_ctx.Done(): 237 | continue 238 | } 239 | 240 | var cancel func() 241 | 242 | local.Local_ctx, cancel = context.WithCancel(context.TODO()) 243 | t_ctx, _ := context.WithTimeout(context.TODO(), time.Duration(util.Config.Udp_timeout)*time.Second) 244 | ctx, cancel2 := context.WithCancel(context.TODO()) 245 | 246 | go func() { 247 | var remote_close = false 248 | defer func() { 249 | cancel2() 250 | local.Close(remote_close) 251 | 252 | }() 253 | 254 | for { 255 | select { 256 | case frame := <-local.RecvChan: 257 | switch frame.GetFrameType() { 258 | case conn.Udp_Frame: 259 | udp_reply(ul, frame.(*conn.UdpFrame)) 260 | case conn.Control_frame: 261 | switch frame.(*conn.ControlFrame).Command { 262 | case conn.Command_close_conn: 263 | remote_close = true 264 | return 265 | default: 266 | util.Print_log(config.Id, "recv an unexpect command") 267 | return 268 | } 269 | 270 | default: 271 | util.Print_log(config.Id, "recv an unexpect frame type") 272 | return 273 | 274 | } 275 | 276 | case <-local.Remote_ctx.Done(): 277 | return 278 | case <-local.Local_ctx.Done(): 279 | return 280 | } 281 | } 282 | }() 283 | 284 | loop: 285 | for { 286 | select { 287 | case frame := <-data_chan: 288 | t_ctx, _ = context.WithTimeout(context.TODO(), time.Duration(util.Config.Udp_timeout)*time.Second) 289 | frame.ConnectionId = local.ConnectionId 290 | select { 291 | case local.SendChan <- frame: 292 | case <-local.Remote_ctx.Done(): 293 | break loop 294 | case <-ctx.Done(): 295 | break loop 296 | } 297 | case <-local.Remote_ctx.Done(): 298 | break loop 299 | case <-t_ctx.Done(): 300 | break loop 301 | case <-ctx.Done(): 302 | break loop 303 | } 304 | 305 | } 306 | 307 | select { 308 | case local.SendChan <- &conn.ControlFrame{ 309 | Version: 0, 310 | ConnectionId: local.ConnectionId, 311 | Command: conn.Command_close_conn, 312 | }: 313 | 314 | case <-local.Remote_ctx.Done(): 315 | } 316 | 317 | cancel() 318 | 319 | } 320 | }() 321 | 322 | var ( 323 | udp_source_ip_frag_channel_map = &sync.Map{} 324 | send_to_remote_func = func(local_addr *net.UDPAddr, dest conn.Addr, data []byte) { 325 | addr, is_cn, err := convert_addr(dest, config) 326 | if err != nil { 327 | util.Print_log(config.Id, "parse socks5 udp dest addr fail: %s ", err.Error()) 328 | return 329 | } 330 | if is_cn { 331 | if util.Verbose_info { 332 | util.Print_verbose("connect cn udp addr:%s", addr.StringWithPort()) 333 | } 334 | handle_cn_udp(config, route, local_addr, addr, data, ul) 335 | 336 | } else { 337 | if util.Verbose_info { 338 | util.Print_verbose("connect not cn udp addr:%s", addr.StringWithPort()) 339 | } 340 | _local_addr, err := conn.NewAddrFromString(local_addr.String(), config.Ipv6) 341 | if err != nil { 342 | util.Print_log(config.Id, "convert local addr fail: %s ", err.Error()) 343 | return 344 | } 345 | 346 | select { 347 | case <-time.After(time.Duration(util.Config.Udp_timeout) * time.Second): 348 | return 349 | case data_chan <- &conn.UdpFrame{ 350 | Version: 0, 351 | Local_addr: _local_addr, 352 | Dest_addr: addr, 353 | Data: data, 354 | }: 355 | return 356 | } 357 | 358 | } 359 | } 360 | ) 361 | for { 362 | buf := make([]byte, conn.Udp_buf_size) 363 | i, from, err := ul.ReadFromUDP(buf) 364 | if err != nil { 365 | util.Print_log(config.Id, "udp read fail: %s", err.Error()) 366 | continue 367 | } 368 | 369 | if i < 7 { 370 | util.Print_log(config.Id, "recv socks5 udp data too short") 371 | continue 372 | } 373 | 374 | addr, _i, err := get_socks5_dest_addr(bytes.NewReader(buf[4:]), config, buf[3]) 375 | 376 | if err != nil { 377 | util.Print_log(config.Id, "get socks5 udp dest addr fail: %s ", err.Error()) 378 | continue 379 | } 380 | 381 | if buf[2] != 0 { 382 | handle_socks5_udp_frag(buf[:i], _i+4, udp_source_ip_frag_channel_map, from, addr, send_to_remote_func) 383 | } else { 384 | go send_to_remote_func(from, addr, buf[_i+4:i]) 385 | } 386 | 387 | } 388 | } 389 | 390 | func handle_socks5_udp_forward_udp(ul, remote *net.UDPConn, config *conn.ClientConfig) { 391 | var ( 392 | cn_route = &sync.Map{} 393 | udp_source_ip_frag_channel_map = &sync.Map{} 394 | ) 395 | 396 | go func() { 397 | for { 398 | buf := make([]byte, conn.Udp_buf_size) 399 | i, err := remote.Read(buf) 400 | if err != nil { 401 | continue 402 | } 403 | go func(data []byte) { 404 | data, err := config.Udp_crypt.Decrypt(data) 405 | if err != nil { 406 | util.Print_log(config.Id, err.Error()) 407 | return 408 | } 409 | frame, err := conn.ParseBytesToFrame(data) 410 | 411 | if err != nil { 412 | util.Print_log(config.Id, "can not parse udp data to frame: %s", err.Error()) 413 | return 414 | } 415 | if frame.GetFrameType() != conn.Udp_Frame { 416 | util.Print_log(config.Id, "udp recv an not udp frame") 417 | return 418 | } 419 | udp_reply(ul, frame.(*conn.UdpFrame)) 420 | }(buf[:i]) 421 | 422 | } 423 | }() 424 | 425 | var send_to_remote_func = func(local_addr *net.UDPAddr, dest conn.Addr, data []byte) { 426 | addr, is_cn, err := convert_addr(dest, config) 427 | if err != nil { 428 | util.Print_log(config.Id, "parse socks5 udp dest addr fail: %s ", err.Error()) 429 | return 430 | } 431 | if is_cn { 432 | if util.Verbose_info { 433 | util.Print_verbose("connect cn udp addr:%s", addr.StringWithPort()) 434 | } 435 | handle_cn_udp(config, cn_route, local_addr, addr, data, ul) 436 | 437 | } else { 438 | if util.Verbose_info { 439 | util.Print_verbose("connect not cn udp addr:%s", addr.StringWithPort()) 440 | } 441 | __local_addr, err := conn.NewAddrFromString(local_addr.String(), false) 442 | if err != nil { 443 | util.Print_log(config.Id, "convert local addr fail: %s ", err.Error()) 444 | return 445 | } 446 | frame := &conn.UdpFrame{ 447 | Version: 0, 448 | Local_addr: __local_addr, 449 | Dest_addr: addr, 450 | Data: data, 451 | } 452 | 453 | remote.WriteToUDP(config.Udp_crypt.Encrypt(frame.ToBytes()), &net.UDPAddr{ 454 | IP: config.Udp_Server_Addr.ToHostBytes(), 455 | Port: config.Udp_Server_Addr.ToPortInt(), 456 | }) 457 | } 458 | 459 | } 460 | 461 | for { 462 | buf := make([]byte, conn.Udp_buf_size) 463 | i, from, err := ul.ReadFromUDP(buf) 464 | if err != nil { 465 | util.Print_log(config.Id, "udp read fail: %s", err.Error()) 466 | continue 467 | } 468 | 469 | if i < 7 { 470 | util.Print_log(config.Id, "recv socks5 udp data too short") 471 | continue 472 | } 473 | addr, _i, err := get_socks5_dest_addr(bytes.NewReader(buf[4:]), config, buf[3]) 474 | 475 | if err != nil { 476 | util.Print_log(config.Id, "get socks5 udp dest addr fail: %s ", err.Error()) 477 | continue 478 | } 479 | 480 | if buf[2] != 0 { 481 | handle_socks5_udp_frag(buf[:i], _i+4, udp_source_ip_frag_channel_map, from, addr, send_to_remote_func) 482 | } else { 483 | go send_to_remote_func(from, addr, buf[_i+4:i]) 484 | } 485 | 486 | } 487 | } 488 | 489 | func get_socks5_dest_addr(con io.Reader, config *conn.ClientConfig, atype byte) (addr conn.Addr, i int, err error) { 490 | i = 0 491 | switch atype { 492 | case 1: // ipv4 493 | ip_port := make([]byte, 6) 494 | if _, err = io.ReadAtLeast(con, ip_port, 6); err != nil { 495 | return 496 | } 497 | i += 6 498 | addr, err = conn.NewAddrFromByte(ip_port[:4], ip_port[4:], conn.Addr_type_ipv4) 499 | 500 | case 3: //domain 501 | domain_len := []byte{0} 502 | if _, err = io.ReadAtLeast(con, domain_len, 1); err != nil { 503 | return 504 | } 505 | if domain_len[0] == 0 { 506 | return nil, 0, errors.New("socks5 recv unexpect data") 507 | } 508 | domain := make([]byte, domain_len[0]) 509 | port := make([]byte, 2) 510 | 511 | if _, err = io.ReadAtLeast(con, domain, int(domain_len[0])); err != nil { 512 | return 513 | } 514 | 515 | if _, err = io.ReadAtLeast(con, port, 2); err != nil { 516 | return 517 | } 518 | 519 | _d := string(domain) 520 | d := net.ParseIP(_d) 521 | 522 | if d.To4() != nil { 523 | addr, err = conn.NewAddrFromString(fmt.Sprintf("%s:%d", _d, binary.BigEndian.Uint16(port)), config.Ipv6) 524 | } else if d.To16() != nil { 525 | addr, err = conn.NewAddrFromString(fmt.Sprintf("[%s]:%d", _d, binary.BigEndian.Uint16(port)), config.Ipv6) 526 | } else { 527 | addr, err = conn.NewAddrFromString(fmt.Sprintf("%s:%d", _d, binary.BigEndian.Uint16(port)), config.Ipv6) 528 | } 529 | i += 3 + int(domain_len[0]) 530 | 531 | case 4: // ipv6 532 | ip_port := make([]byte, 18) 533 | if _, err = io.ReadAtLeast(con, ip_port, 18); err != nil { 534 | return 535 | } 536 | addr, err = conn.NewAddrFromByte(ip_port[:16], ip_port[16:], conn.Addr_type_ipv6) 537 | i += 18 538 | default: 539 | return nil, 0, errors.New("socks5 recv unknow atype") 540 | } 541 | return 542 | } 543 | 544 | func concatnate_addr(lan_addr net.Addr, dest conn.Addr) string { 545 | return lan_addr.String() + "|" + dest.StringWithPort() 546 | } 547 | 548 | func handle_cn_udp(config *conn.ClientConfig, route *sync.Map, local_addr net.Addr, dest_addr conn.Addr, data []byte, ul *net.UDPConn) { 549 | key := concatnate_addr(local_addr, dest_addr) 550 | c, ok := route.Load(key) 551 | if ok { 552 | c.(net.Conn).Write(data) 553 | } else { 554 | c, err := net.Dial("udp", dest_addr.StringWithPort()) 555 | if err != nil { 556 | util.Print_log(config.Id, "connect cn udp fail: %s ", err.Error()) 557 | return 558 | } 559 | route.Store(key, c) 560 | defer func() { 561 | route.Delete(key) 562 | c.Close() 563 | }() 564 | 565 | c.Write(data) 566 | buf := make([]byte, conn.Udp_buf_size) 567 | u := c.(*net.UDPConn) 568 | for { 569 | u.SetReadDeadline(time.Now().Add(time.Duration(util.Config.Udp_timeout) * time.Second)) 570 | i, from, err := u.ReadFrom(buf) 571 | if err != nil { 572 | return 573 | } 574 | addr, err := conn.NewAddrFromString(from.String(), false) 575 | if err != nil { 576 | util.Print_log(config.Id, "udp addr resolve fail, udp addr: %s", from.String()) 577 | return 578 | } 579 | reply_data := bytes.Join([][]byte{{0, 0, 0, 0}, addr.ToHostBytes(), addr.ToPortByte(), buf[:i]}, nil) 580 | switch addr.Type() { 581 | case conn.Addr_type_ipv4: 582 | reply_data[3] = 1 583 | case conn.Addr_type_ipv6: 584 | reply_data[3] = 4 585 | default: 586 | util.Print_log_without_id("impossible error: ip addr resolve as domain") 587 | return 588 | } 589 | ul.WriteTo(reply_data, local_addr) 590 | } 591 | } 592 | } 593 | -------------------------------------------------------------------------------- /src/go_proxy/local_proxy/local_proxy.go: -------------------------------------------------------------------------------- 1 | package local_proxy 2 | 3 | import ( 4 | "fmt" 5 | "go_proxy/conn" 6 | "go_proxy/util" 7 | "io" 8 | "net" 9 | "os" 10 | "sync" 11 | "syscall" 12 | "time" 13 | ) 14 | 15 | func StartLocalproxy(config *conn.ClientConfig, g *sync.WaitGroup) { 16 | 17 | if config.Mode == util.Iptables { 18 | if config.Remoted_dns == nil { 19 | fmt.Fprintf(os.Stderr, "iptables mode must set a remote dns addr\r\n") 20 | os.Exit(1) 21 | } 22 | 23 | w := &sync.WaitGroup{} 24 | if config.Ipv6 { 25 | __l6, err := net.ListenTCP("tcp6", &net.TCPAddr{ 26 | IP: net.ParseIP("::1"), 27 | Port: config.Local_port, 28 | Zone:"lo", 29 | }) 30 | if err != nil { 31 | fmt.Fprintf(os.Stderr, err.Error()+"\r\n") 32 | os.Exit(1) 33 | } 34 | fd,err:=__l6.File() 35 | if err!=nil{ 36 | fmt.Fprintf(os.Stderr, err.Error()+"\r\n") 37 | os.Exit(1) 38 | } 39 | __l6.Close() 40 | if err := syscall.SetsockoptInt(int(fd.Fd()), IPPROTO_IP, IP_TRANSPARENT, 1); err != nil { 41 | fmt.Fprintf(os.Stderr, err.Error()+"\r\n") 42 | os.Exit(1) 43 | } 44 | _l6,err:=net.FileListener(fd) 45 | if err!=nil{ 46 | fmt.Fprintf(os.Stderr, err.Error()+"\r\n") 47 | os.Exit(1) 48 | } 49 | l6:=_l6.(*net.TCPListener) 50 | 51 | 52 | _ul6, err := net.ListenUDP("udp6", &net.UDPAddr{ 53 | IP: net.ParseIP("::1"), 54 | Port: config.Local_port, 55 | Zone:"lo", 56 | }) 57 | if err != nil { 58 | fmt.Fprintf(os.Stderr, err.Error()+"\r\n") 59 | os.Exit(1) 60 | } 61 | 62 | fd, err = _ul6.File() 63 | if err != nil { 64 | fmt.Fprintf(os.Stderr, err.Error()+"\r\n") 65 | os.Exit(1) 66 | } 67 | 68 | if err := syscall.SetsockoptInt(int(fd.Fd()), IPPROTO_IPV6, IPV6_RECVORIGDSTADDR, 1); err != nil { 69 | fmt.Fprintf(os.Stderr, err.Error()+"\r\n") 70 | os.Exit(1) 71 | } 72 | if err := syscall.SetsockoptInt(int(fd.Fd()), IPPROTO_IP, IP_TRANSPARENT, 1); err != nil { 73 | fmt.Fprintf(os.Stderr, err.Error()+"\r\n") 74 | os.Exit(1) 75 | } 76 | ul6, err := net.FileConn(os.NewFile(fd.Fd(), "")) 77 | if err != nil { 78 | fmt.Fprintf(os.Stderr, err.Error()+"\r\n") 79 | os.Exit(1) 80 | } 81 | _ul6.Close() 82 | 83 | go func() { 84 | for { 85 | con, err := l6.AcceptTCP() 86 | if err != nil { 87 | util.Print_log(config.Id, "accept tcp error:"+err.Error()) 88 | continue 89 | } 90 | go func(con *net.TCPConn) { 91 | con.SetKeepAlive(true) 92 | con.SetKeepAlivePeriod(10 * time.Second) 93 | con.SetNoDelay(true) 94 | 95 | if err := handle_iptables(con, config); err != nil { 96 | if _, ok := err.(net.Error); !ok && err != io.EOF && err != io.ErrUnexpectedEOF { 97 | util.Print_log(config.Id, err.Error()) 98 | } 99 | } 100 | 101 | }(con) 102 | } 103 | }() 104 | 105 | w.Add(1) 106 | 107 | go func() { 108 | defer w.Done() 109 | if config.Udp_in_tcp { 110 | go handle_iptables_udp_forward_tcp(ul6.(*net.UDPConn), config,true) 111 | } else { 112 | 113 | remote_connection, err := net.ListenUDP("udp", &net.UDPAddr{}) 114 | 115 | if err != nil { 116 | fmt.Fprintf(os.Stderr, err.Error()+"\r\n") 117 | os.Exit(1) 118 | } 119 | 120 | remote_dns_connection, err := net.ListenUDP("udp", &net.UDPAddr{}) 121 | if err != nil { 122 | fmt.Fprintf(os.Stderr, err.Error()+"\r\n") 123 | os.Exit(1) 124 | } 125 | 126 | go handle_iptables_udp_forward_udp(ul6.(*net.UDPConn), remote_connection, remote_dns_connection, config,true) 127 | } 128 | }() 129 | 130 | } 131 | 132 | __l4, err := net.ListenTCP("tcp4", &net.TCPAddr{ 133 | IP: []byte{127, 0, 0, 1}, 134 | Port: config.Local_port, 135 | }) 136 | if err != nil { 137 | fmt.Fprintf(os.Stderr, err.Error()+"\r\n") 138 | os.Exit(1) 139 | } 140 | 141 | fd,err:=__l4.File() 142 | if err!=nil{ 143 | fmt.Fprintf(os.Stderr, err.Error()+"\r\n") 144 | os.Exit(1) 145 | } 146 | __l4.Close() 147 | if err := syscall.SetsockoptInt(int(fd.Fd()), IPPROTO_IP, IP_TRANSPARENT, 1); err != nil { 148 | fmt.Fprintf(os.Stderr, err.Error()+"\r\n") 149 | os.Exit(1) 150 | } 151 | _l4,err:=net.FileListener(fd) 152 | if err!=nil{ 153 | fmt.Fprintf(os.Stderr, err.Error()+"\r\n") 154 | os.Exit(1) 155 | } 156 | l4:=_l4.(*net.TCPListener) 157 | 158 | _ul4, err := net.ListenUDP("udp4", &net.UDPAddr{ 159 | IP: []byte{127, 0, 0, 1}, 160 | Port: config.Local_port, 161 | }) 162 | if err != nil { 163 | fmt.Fprintf(os.Stderr, err.Error()+"\r\n") 164 | os.Exit(1) 165 | } 166 | fd, err = _ul4.File() 167 | if err != nil { 168 | fmt.Fprintf(os.Stderr, err.Error()+"\r\n") 169 | os.Exit(1) 170 | } 171 | if err := syscall.SetsockoptInt(int(fd.Fd()), IPPROTO_IP, IP_RECVORIGDSTADDR, 1); err != nil { 172 | fmt.Fprintf(os.Stderr, err.Error()+"\r\n") 173 | os.Exit(1) 174 | } 175 | if err := syscall.SetsockoptInt(int(fd.Fd()), IPPROTO_IP, IP_TRANSPARENT, 1); err != nil { 176 | fmt.Fprintf(os.Stderr, err.Error()+"\r\n") 177 | os.Exit(1) 178 | } 179 | ul4, err := net.FileConn(os.NewFile(fd.Fd(), "")) 180 | if err != nil { 181 | fmt.Fprintf(os.Stderr, err.Error()+"\r\n") 182 | os.Exit(1) 183 | } 184 | _ul4.Close() 185 | 186 | if config.Udp_in_tcp { 187 | go handle_iptables_udp_forward_tcp(ul4.(*net.UDPConn), config,false) 188 | } else { 189 | 190 | remote_connection, err := net.ListenUDP("udp", &net.UDPAddr{}) 191 | 192 | if err != nil { 193 | fmt.Fprintf(os.Stderr, err.Error()+"\r\n") 194 | os.Exit(1) 195 | } 196 | 197 | remote_dns_connection, err := net.ListenUDP("udp4", &net.UDPAddr{}) 198 | if err != nil { 199 | fmt.Fprintf(os.Stderr, err.Error()+"\r\n") 200 | os.Exit(1) 201 | } 202 | 203 | go handle_iptables_udp_forward_udp(ul4.(*net.UDPConn), remote_connection, remote_dns_connection, config,false) 204 | 205 | } 206 | 207 | w.Wait() 208 | g.Done() 209 | 210 | for { 211 | con, err := l4.AcceptTCP() 212 | if err != nil { 213 | util.Print_log(config.Id, "accept tcp error:"+err.Error()) 214 | continue 215 | } 216 | go func(con *net.TCPConn) { 217 | con.SetKeepAlive(true) 218 | con.SetKeepAlivePeriod(10 * time.Second) 219 | con.SetNoDelay(true) 220 | 221 | if err := handle_iptables(con, config); err != nil { 222 | if _, ok := err.(net.Error); !ok && err != io.EOF && err != io.ErrUnexpectedEOF { 223 | util.Print_log(config.Id, err.Error()) 224 | } 225 | } 226 | 227 | }(con) 228 | } 229 | 230 | } else { 231 | if config.Mode == util.Socks5 { // handle socks5 udp 232 | addr, err := conn.NewAddrFromString(config.Local_addr, false) 233 | if err != nil { 234 | fmt.Fprintf(os.Stderr, "unknow error \r\n") 235 | os.Exit(1) 236 | } 237 | ul, err := net.ListenUDP("udp", &net.UDPAddr{ 238 | Port: addr.ToPortInt(), 239 | }) 240 | if err != nil { 241 | fmt.Fprintf(os.Stderr, err.Error()+"\r\n") 242 | os.Exit(1) 243 | } 244 | 245 | if config.Udp_in_tcp { 246 | go handle_socks5_udp_forward_tcp(ul, config) 247 | } else { 248 | remote, err := net.ListenUDP("udp", &net.UDPAddr{}) 249 | if err != nil { 250 | fmt.Fprintf(os.Stderr, err.Error()+"\r\n") 251 | os.Exit(1) 252 | } 253 | go handle_socks5_udp_forward_udp(ul, remote, config) 254 | } 255 | } 256 | 257 | l, err := net.Listen("tcp", config.Local_addr) 258 | if err != nil { 259 | fmt.Fprintf(os.Stderr, err.Error()+"\r\n") 260 | os.Exit(1) 261 | } 262 | listen := l.(*net.TCPListener) 263 | g.Done() 264 | 265 | for { 266 | 267 | con, err := listen.AcceptTCP() 268 | if err != nil { 269 | util.Print_log(config.Id, "accept tcp error:"+err.Error()) 270 | continue 271 | } 272 | 273 | go func(con *net.TCPConn) { 274 | con.SetKeepAlive(true) 275 | con.SetKeepAlivePeriod(10 * time.Second) 276 | con.SetNoDelay(true) 277 | 278 | switch config.Mode { 279 | case util.Socks5: 280 | if err := handle_socks5(con, config); err != nil { 281 | if _, ok := err.(net.Error); !ok && err != io.EOF && err != io.ErrUnexpectedEOF { 282 | util.Print_log(config.Id, err.Error()) 283 | } 284 | } 285 | case util.Http: 286 | if err := handle_http_con(con, config); err != nil { 287 | if _, ok := err.(net.Error); !ok && err != io.EOF && err != io.ErrUnexpectedEOF { 288 | util.Print_log(config.Id, err.Error()) 289 | } 290 | } 291 | 292 | default: 293 | fmt.Fprintf(os.Stderr, "unknow error \r\n") 294 | os.Exit(1) 295 | } 296 | 297 | }(con) 298 | 299 | } 300 | 301 | } 302 | 303 | } 304 | -------------------------------------------------------------------------------- /src/go_proxy/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "go_proxy/conn" 6 | "go_proxy/local_proxy" 7 | "go_proxy/server" 8 | "go_proxy/util" 9 | "os" 10 | "os/signal" 11 | "runtime" 12 | "strconv" 13 | "syscall" 14 | "sync" 15 | "time" 16 | ) 17 | 18 | func main() { 19 | 20 | util.Check_pid_file() 21 | 22 | syscall.Setrlimit(syscall.RLIMIT_NOFILE, &syscall.Rlimit{ 23 | Cur: util.Config.Ulimit, 24 | Max: util.Config.Ulimit, 25 | }) 26 | 27 | if len(util.Config.Clients) > 65535 { 28 | fmt.Fprintf(os.Stderr, "client too more\r\n") 29 | os.Exit(1) 30 | } 31 | if len(util.Config.Servers) > 65535 { 32 | fmt.Fprintf(os.Stderr, "server too more\r\n") 33 | os.Exit(1) 34 | } 35 | 36 | g := &sync.WaitGroup{} 37 | s:=[]string{} 38 | for i, v := range util.Config.Clients { 39 | g.Add(1) 40 | s=append(s,"#########################################") 41 | s=append(s,fmt.Sprintf("configing client %d \r\n", uint16(i))) 42 | conf, info,err := conn.LoadClientConfig(&v, uint16(i)) 43 | if err != nil { 44 | fmt.Fprintf(os.Stderr, err.Error()+"\r\n") 45 | os.Exit(1) 46 | } 47 | go local_proxy.StartLocalproxy(conf, g) 48 | s=append(s,info...) 49 | 50 | } 51 | 52 | for i, v := range util.Config.Servers { 53 | g.Add(2) 54 | s=append(s,"#########################################") 55 | s=append(s,fmt.Sprintf("configing server %d \r\n", uint16(i))) 56 | conf,info, err := conn.LoadServerConfig(&v, uint16(i)) 57 | if err != nil { 58 | fmt.Fprintf(os.Stderr, err.Error()+"\r\n") 59 | os.Exit(1) 60 | } 61 | go server.Start_tcp_server(conf, g) 62 | go server.Start_udp_serv(conf, g) 63 | s=append(s,info...) 64 | } 65 | s=append(s,"#########################################") 66 | g.Wait() 67 | 68 | if runtime.GOOS=="linux"{ 69 | f, err := os.Create(util.Pid_file) 70 | if err != nil { 71 | fmt.Fprintf(os.Stderr, "create pid file fail: %s\r\n", err.Error()) 72 | os.Exit(1) 73 | } 74 | if _, err := f.WriteString(strconv.FormatInt(int64(os.Getpid()), 10)); err != nil { 75 | fmt.Fprintf(os.Stderr, "write pid file fail: %s\r\n", err.Error()) 76 | os.Exit(1) 77 | } 78 | } 79 | for _,v:=range s{ 80 | fmt.Println(v) 81 | } 82 | fmt.Println() 83 | fmt.Println("run successful") 84 | signal_notify := make(chan os.Signal, 1) 85 | ignore_signal:=make(chan os.Signal, 1) 86 | signal.Notify(signal_notify,syscall.SIGINT, syscall.SIGKILL, syscall.SIGSTOP, syscall.SIGABRT, syscall.SIGTERM, syscall.SIGUSR1) 87 | signal.Notify(ignore_signal,syscall.SIGPIPE) 88 | 89 | go func() { 90 | for{ 91 | <-ignore_signal 92 | util.Print_log_without_id("recv broken piple signal,ignored.\r\n") 93 | time.Sleep(10*time.Second) 94 | } 95 | 96 | }() 97 | 98 | <-signal_notify 99 | util.Print_log_without_id("recv notify signal, proxy exit.") 100 | 101 | if runtime.GOOS=="linux"{ 102 | if err := os.Remove(util.Pid_file); err != nil { 103 | util.Print_log_without_id("delete pid fail fail: %s\r\n", err.Error()) 104 | } 105 | } 106 | 107 | return 108 | 109 | } 110 | -------------------------------------------------------------------------------- /src/go_proxy/server/tcp_server.go: -------------------------------------------------------------------------------- 1 | package server 2 | 3 | import ( 4 | "crypto/tls" 5 | "fmt" 6 | "go_proxy/conn" 7 | "go_proxy/util" 8 | "net" 9 | "os" 10 | "time" 11 | "sync" 12 | ) 13 | 14 | func Start_tcp_server(config *conn.ServConfig,g *sync.WaitGroup){ 15 | listen,err:=net.ListenTCP("tcp",&net.TCPAddr{ 16 | Port: config.Tcp_listen_port, 17 | }) 18 | if err!=nil{ 19 | fmt.Fprintf(os.Stderr,err.Error()+"\r\n") 20 | os.Exit(1) 21 | } 22 | g.Done() 23 | for{ 24 | con,err:=listen.AcceptTCP() 25 | if err!=nil{ 26 | util.Print_log(config.Id,"server: accept tcp error:"+err.Error()) 27 | continue 28 | } 29 | go handle_connection(con,config) 30 | } 31 | 32 | } 33 | 34 | 35 | func handle_connection(con *net.TCPConn,config *conn.ServConfig){ 36 | con.SetKeepAlive(true) 37 | con.SetKeepAlivePeriod(10*time.Second) 38 | con.SetNoDelay(true) 39 | var conn net.Conn = con 40 | if config.Tls_conf!=nil{ 41 | conn=tls.Server(con,config.Tls_conf) 42 | } 43 | 44 | config.ServConnectionHandler.Dispatch_serv(conn) 45 | 46 | } -------------------------------------------------------------------------------- /src/go_proxy/server/udp_server.go: -------------------------------------------------------------------------------- 1 | package server 2 | 3 | import ( 4 | "fmt" 5 | "go_proxy/conn" 6 | "go_proxy/util" 7 | "net" 8 | "os" 9 | "sync" 10 | "time" 11 | ) 12 | 13 | var route = &sync.Map{} 14 | 15 | func Start_udp_serv(config *conn.ServConfig, g *sync.WaitGroup) { 16 | ul, err := net.ListenUDP("udp", &net.UDPAddr{ 17 | Port: config.Udp_listen_port, 18 | }) 19 | if err != nil { 20 | fmt.Fprintf(os.Stderr, err.Error()+"\r\n") 21 | os.Exit(1) 22 | } 23 | g.Done() 24 | 25 | var concatnate_addr = func (lan_addr conn.Addr,recv_from net.Addr) string{ 26 | return lan_addr.StringWithPort()+"|"+recv_from.String() 27 | } 28 | 29 | for { 30 | buf := make([]byte, conn.Udp_buf_size) 31 | i, addr, err := ul.ReadFrom(buf) 32 | if err!=nil{ 33 | util.Print_log(config.Id,"recv udp data fail: %s",err.Error()) 34 | continue 35 | } 36 | 37 | go func(recv_from_addr net.Addr,data []byte) { 38 | dec_data,err:=config.Udp_crypt.Decrypt(data) 39 | if err!=nil{ 40 | util.Print_log(config.Id,"udp data decrypt fail: %s",err.Error()) 41 | return 42 | } 43 | frame,err:=conn.ParseBytesToFrame(dec_data) 44 | if err!=nil{ 45 | util.Print_log(config.Id,err.Error()) 46 | return 47 | } 48 | if frame.GetFrameType()!=conn.Udp_Frame || frame.(*conn.UdpFrame).Dest_addr==nil ||frame.(*conn.UdpFrame).Local_addr==nil { 49 | util.Print_log(config.Id,"udp server recv an unexpect frame") 50 | return 51 | } 52 | 53 | var ( 54 | udp_frame=frame.(*conn.UdpFrame) 55 | ip []byte 56 | ) 57 | 58 | switch udp_frame.Dest_addr.Type(){ 59 | case conn.Addr_type_ipv4,conn.Addr_type_ipv6: 60 | ip=udp_frame.Dest_addr.ToHostBytes() 61 | case conn.Addr_domain,conn.Addr_domain_try_ipv6: 62 | ip, _, err = conn.Parse_local_domain(udp_frame.Dest_addr.String(), udp_frame.Dest_addr.Type()==conn.Addr_domain_try_ipv6, "") 63 | if err!=nil{ 64 | util.Print_log(config.Id,"can not reslove domain %s: %s",udp_frame.Dest_addr.String(),err.Error()) 65 | return 66 | } 67 | default: 68 | util.Print_log(config.Id,"udp server recv an unexpect frame") 69 | return 70 | } 71 | 72 | 73 | key:=concatnate_addr(udp_frame.Local_addr,addr) 74 | con,ok:=route.Load(key) 75 | if ok{ 76 | con.(*net.UDPConn).WriteTo(udp_frame.Data,&net.UDPAddr{ 77 | IP: ip, 78 | Port: udp_frame.Dest_addr.ToPortInt(), 79 | }) 80 | }else{ 81 | con,err:=net.ListenUDP("udp",nil) 82 | if err!=nil{ 83 | util.Print_log(config.Id,"listen udp fail: %s",err.Error()) 84 | return 85 | } 86 | route.Store(key,con) 87 | defer func() { 88 | con.Close() 89 | route.Delete(key) 90 | }() 91 | 92 | con.WriteTo(udp_frame.Data,&net.UDPAddr{ 93 | IP: ip, 94 | Port: udp_frame.Dest_addr.ToPortInt(), 95 | }) 96 | 97 | for{ 98 | buf:=make([]byte,conn.Udp_buf_size) 99 | con.SetReadDeadline(time.Now().Add(time.Duration(util.Config.Udp_timeout)*time.Second)) 100 | i,dest_addr,err:=con.ReadFrom(buf) 101 | if err!=nil{ 102 | return 103 | } 104 | dest,err:=conn.NewAddrFromString(dest_addr.String(),false) 105 | if err!=nil{ 106 | util.Print_log(config.Id,"parse remote recv addr: %s",err.Error()) 107 | return 108 | } 109 | frame:=&conn.UdpFrame{ 110 | Local_addr: udp_frame.Local_addr, 111 | Dest_addr: dest, 112 | Data: buf[:i], 113 | } 114 | ul.WriteTo(config.Udp_crypt.Encrypt(frame.ToBytes()),recv_from_addr) 115 | 116 | } 117 | 118 | } 119 | 120 | 121 | }(addr,buf[:i]) 122 | 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /src/go_proxy/util/config.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import ( 4 | "bufio" 5 | "bytes" 6 | "context" 7 | "encoding/json" 8 | "flag" 9 | "fmt" 10 | "io" 11 | "io/ioutil" 12 | "net" 13 | "os" 14 | "os/exec" 15 | "runtime" 16 | "strconv" 17 | "strings" 18 | "syscall" 19 | "time" 20 | ) 21 | 22 | var ( 23 | Config config 24 | 25 | China_ipv4 = map[uint]int{} 26 | Cn_domain_map = map[string]interface{}{} 27 | Local_ipv6 = map[string]int{} 28 | 29 | Verbose_info bool 30 | Resource_recycle_time_out = 600 31 | Tcp_timeout = 30 32 | ) 33 | 34 | const Pid_file = "/var/run/go_proxy.pid" 35 | 36 | const ( 37 | Enc_aes_256_cfb = "aes-256-cfb" 38 | Enc_chacha20 = "chacha20" 39 | Enc_none = "none" 40 | ) 41 | 42 | const ( 43 | Socks5 = "socks5" 44 | Http = "http" 45 | Iptables = "iptables" 46 | ) 47 | 48 | type Client struct { 49 | Mode string 50 | Front_proxy string 51 | Tls struct { 52 | On bool 53 | Server_name string 54 | Tcp_encrypt bool 55 | Root_cert_path string 56 | Private_key string 57 | Certificate string 58 | } 59 | Ipv6 bool 60 | Connection_max_payload int 61 | Local_addr string 62 | Local_Port int 63 | Interface string 64 | Tcp_server_addr string 65 | Udp_server_addr string 66 | Enc_method string 67 | Password string 68 | Remote_dns_addr string 69 | Local_dns_addr string 70 | Domain_cache_time int64 71 | Udp_in_tcp bool 72 | } 73 | 74 | type Serve struct { 75 | Tls struct { 76 | On bool 77 | Tcp_encrypt bool 78 | Server_private_key string 79 | Server_cert string 80 | Client_certs []string 81 | } 82 | Tcp_listen_port int 83 | Udp_listen_port int 84 | Enc_method string 85 | Password string 86 | } 87 | 88 | type config struct { 89 | Ulimit uint64 90 | Udp_timeout int64 91 | Clients []Client 92 | Servers []Serve 93 | } 94 | 95 | func init() { 96 | os.Setenv("GODEBUG", os.Getenv("GODEBUG")+",tls13=1") 97 | 98 | state := flag.String("s", "", "{ start | restart | stop }") 99 | config := flag.String("c", "", "json config file location") 100 | cn_ipv4 := flag.String("china-ipv4", "", "china ipv4 file") 101 | cn_domain := flag.String("china-domain", "", "china domain file") 102 | ipv6_white_list := flag.String("ipv6-white-list", "", "ipv6 white list addr list file") 103 | verbose_info := flag.Bool("verbose", false, "print more info to stdout") 104 | daemon := flag.Bool("daemon", false, "run background,only implement in linux") 105 | wd := flag.String("work-dir", "", "") 106 | 107 | flag.Parse() 108 | 109 | Verbose_info = *verbose_info 110 | 111 | var print_help = func() { 112 | fmt.Fprintln(os.Stderr, `useage: go_proxy -s {start|restart|stop} -c config-file [--china-ipv4="china ipv4 file"] [--china-domain="china domain file"] [--ipv6-white-list="ipv6 white list"] [--verbose]`) 113 | } 114 | 115 | var check_system = func() { 116 | if runtime.GOOS != "linux" { 117 | fmt.Fprintf(os.Stderr, "daemon just implement in linux\r\n") 118 | os.Exit(1) 119 | } 120 | 121 | } 122 | 123 | var getpid = func() int { 124 | check_system() 125 | f, err := os.Open(Pid_file) 126 | if err != nil { 127 | fmt.Fprintf(os.Stderr, "open pid file fail:%s\r\n", err.Error()) 128 | os.Exit(1) 129 | } 130 | defer f.Close() 131 | _pid, _, err := bufio.NewReader(f).ReadLine() 132 | if err != nil { 133 | fmt.Fprintf(os.Stderr, "open pid file fail:%s\r\n", err.Error()) 134 | os.Exit(1) 135 | } 136 | pid, err := strconv.Atoi(string(_pid)) 137 | if err != nil { 138 | print_help() 139 | os.Exit(1) 140 | } 141 | return pid 142 | } 143 | 144 | var stop = func(pid int) { 145 | check_system() 146 | fmt.Println("stoping process...\r\n") 147 | p := fmt.Sprintf("/proc/%d", pid) 148 | if err := syscall.Kill(pid, syscall.SIGUSR1); err != nil { 149 | fmt.Fprintf(os.Stderr, "stop fail: %s\r\n", err.Error()) 150 | os.Exit(1) 151 | } 152 | 153 | for i := 0; i < 10; i++ { 154 | _, err1 := os.Stat(Pid_file) 155 | _, err2 := os.Stat(p) 156 | 157 | if os.IsNotExist(err1) && os.IsNotExist(err2) { 158 | return 159 | } 160 | time.Sleep(1 * time.Second) 161 | } 162 | fmt.Fprintf(os.Stderr, "stop fail\r\n") 163 | os.Exit(1) 164 | 165 | } 166 | 167 | var daemon_run = func(exe string, args []string) { 168 | check_system() 169 | Check_pid_file() 170 | if config == nil { 171 | print_help() 172 | os.Exit(1) 173 | } 174 | 175 | cmd := exec.Command(exe, args...) 176 | var ( 177 | stdout bytes.Buffer 178 | stderr bytes.Buffer 179 | ) 180 | 181 | cmd.Stdout = &stdout 182 | cmd.Stderr = &stderr 183 | cmd.SysProcAttr = &syscall.SysProcAttr{ 184 | Setsid: true, 185 | } 186 | 187 | if err := cmd.Start(); err != nil { 188 | fmt.Fprintf(os.Stderr, "start fail: %s\r\n", err.Error()) 189 | os.Exit(1) 190 | } 191 | 192 | ctx, cancel := context.WithCancel(context.TODO()) 193 | timeout_ctx, _ := context.WithTimeout(context.TODO(), 60*time.Second) 194 | 195 | go func() { 196 | defer cancel() 197 | 198 | if err := cmd.Wait(); err == nil { 199 | fmt.Fprintf(os.Stderr, "start fail with unknow error\r\n") 200 | os.Exit(1) 201 | } 202 | 203 | }() 204 | pid := cmd.Process.Pid 205 | for { 206 | select { 207 | case <-ctx.Done(): 208 | buf := make([]byte, 4096) 209 | i, err := stderr.Read(buf) 210 | if i > 0 { 211 | fmt.Fprintf(os.Stderr, "start fail \r\n"+string(buf[:i])) 212 | } else { 213 | fmt.Fprintf(os.Stderr, "get stderr fail: %s\r\n", err.Error()) 214 | } 215 | 216 | os.Exit(1) 217 | case <-timeout_ctx.Done(): 218 | fmt.Fprintf(os.Stderr, "wait daemon start time out\r\n") 219 | os.Exit(1) 220 | default: 221 | _, err1 := os.Stat(Pid_file) 222 | _, err2 := os.Stat(fmt.Sprintf("/proc/%d", pid)) 223 | if os.IsNotExist(err1) || os.IsNotExist(err2) { 224 | continue 225 | } else { 226 | time.Sleep(2 * time.Second) 227 | buf := make([]byte, 10240) 228 | i, err := stdout.Read(buf) 229 | if i > 0 { 230 | fmt.Println(string(buf[:i])) 231 | } else { 232 | fmt.Fprintf(os.Stderr, "read stdout fail: %s\r\n", err.Error()) 233 | os.Exit(1) 234 | } 235 | 236 | return 237 | } 238 | 239 | time.Sleep(500 * time.Millisecond) 240 | 241 | } 242 | } 243 | 244 | } 245 | 246 | if !*daemon { 247 | switch *state { 248 | case "start": 249 | break 250 | case "stop": 251 | stop(getpid()) 252 | os.Exit(0) 253 | case "restart": 254 | check_system() 255 | pid := getpid() 256 | exe_path := fmt.Sprintf("/proc/%d/exe", pid) 257 | exe, err := os.Readlink(exe_path) 258 | if err != nil { 259 | fmt.Fprintf(os.Stderr, "get execution from %s fail: %s\r\n", exe_path, err.Error()) 260 | os.Exit(1) 261 | } 262 | args_path := fmt.Sprintf("/proc/%d/cmdline", pid) 263 | f, err := os.Open(args_path) 264 | if err != nil { 265 | fmt.Fprintf(os.Stderr, "get args from %s fail: %s\r\n", args_path, err.Error()) 266 | os.Exit(1) 267 | } 268 | _args, err := ioutil.ReadAll(f) 269 | if err != nil { 270 | fmt.Fprintf(os.Stderr, "get args from %s fail: %s\r\n", args_path, err.Error()) 271 | os.Exit(1) 272 | } 273 | args := strings.Split(string(_args), string([]byte{0})) 274 | 275 | if len(args) == 1 { 276 | fmt.Fprintf(os.Stderr, "restart fail\r\n") 277 | os.Exit(1) 278 | } 279 | 280 | stop(pid) 281 | daemon_run(exe, args[1:]) 282 | os.Exit(0) 283 | 284 | default: 285 | print_help() 286 | os.Exit(1) 287 | } 288 | } else { 289 | if state != nil && *state != "" { 290 | fmt.Fprintf(os.Stderr, "-s and -daemon ambiguous\r\n") 291 | os.Exit(1) 292 | } 293 | args := []string{} 294 | for _, v := range os.Args[1:] { 295 | if v == "--daemon" || v == "-daemon" || v == "--verbose" || v == "-verbose" { 296 | continue 297 | } 298 | args = append(args, v) 299 | } 300 | pwd, err := os.Getwd() 301 | if err != nil { 302 | fmt.Fprintf(os.Stderr, "get pwd fail: %s\r\n", err.Error()) 303 | os.Exit(1) 304 | } 305 | args = append(args, "-s", "start", "--work-dir", pwd) 306 | *wd = pwd 307 | daemon_run(os.Args[0], args) 308 | os.Exit(0) 309 | } 310 | 311 | if *wd != "" { 312 | os.Chdir(*wd) 313 | } 314 | 315 | if config == nil || *config == "" { 316 | print_help() 317 | os.Exit(1) 318 | } 319 | 320 | file, err := os.Open(*config) 321 | 322 | if err != nil { 323 | fmt.Fprintf(os.Stderr, "open config file fail: %s\r\n", err.Error()) 324 | os.Exit(1) 325 | } 326 | 327 | b, err := ioutil.ReadAll(file) 328 | if err != nil { 329 | fmt.Fprintf(os.Stderr, "open config file fail: %s\r\n", err.Error()) 330 | os.Exit(1) 331 | } 332 | 333 | if err := json.Unmarshal(b, &Config); err != nil { 334 | fmt.Fprintf(os.Stderr, "marshal config file fail: %s\r\n", err.Error()) 335 | os.Exit(1) 336 | } 337 | 338 | if Config.Ulimit < 1024 { 339 | Config.Ulimit = 1024 340 | } 341 | 342 | if Config.Udp_timeout > 120 { 343 | Config.Udp_timeout = 120 344 | } else if Config.Udp_timeout < 10 { 345 | Config.Udp_timeout = 10 346 | } 347 | 348 | if cn_ipv4 != nil && *cn_ipv4 != "" { 349 | china_ipv4_list, err := os.Open(*cn_ipv4) 350 | if err != nil { 351 | fmt.Fprintf(os.Stderr, "open china_ipv4 file fail: %s\r\n", err.Error()) 352 | os.Exit(1) 353 | } 354 | defer china_ipv4_list.Close() 355 | reader := bufio.NewReader(china_ipv4_list) 356 | for { 357 | line, _, err := reader.ReadLine() 358 | if err != nil { 359 | if err == io.EOF { 360 | break 361 | } else { 362 | fmt.Fprintf(os.Stderr, "open china_ipv4 file fail: %s\r\n", err.Error()) 363 | os.Exit(1) 364 | } 365 | } else { 366 | if len(line) == 0 { 367 | continue 368 | } 369 | ip_mask := strings.Split(string(line), "/") 370 | if len(ip_mask) != 2 { 371 | fmt.Printf("warnning : china_ipv4 format incorrect at %s , ignore \r\n", string(line)) 372 | continue 373 | } 374 | ip := net.ParseIP(ip_mask[0]).To4() 375 | if ip == nil { 376 | fmt.Printf("warnning : china_ipv4 format incorrect at %s , ignore \r\n", string(line)) 377 | continue 378 | } 379 | 380 | mask, err := strconv.Atoi(ip_mask[1]) 381 | if err != nil || mask > 32 || mask <= 0 { 382 | fmt.Printf("warnning : china_ipv4 format incorrect at %s , ignore \r\n", string(line)) 383 | continue 384 | } 385 | 386 | var ip_int uint = 0 387 | for i := 0; i < len(ip); i++ { 388 | ip_int += uint(ip[i]) << uint(((len(ip) - i - 1) * 8)) 389 | } 390 | 391 | China_ipv4[ip_int] = mask 392 | } 393 | } 394 | } 395 | 396 | if cn_domain != nil && *cn_domain != "" { 397 | cn_domain, err := os.Open(*cn_domain) 398 | if err != nil { 399 | fmt.Fprintf(os.Stderr, "open cn domain file fail: %s\r\n", err.Error()) 400 | os.Exit(1) 401 | } 402 | defer cn_domain.Close() 403 | r := bufio.NewReader(cn_domain) 404 | for { 405 | line, _, err := r.ReadLine() 406 | if err != nil { 407 | if err == io.EOF { 408 | break 409 | } else { 410 | fmt.Fprintf(os.Stderr, "open cn domain file fail: %s\r\n", err.Error()) 411 | os.Exit(1) 412 | } 413 | } else { 414 | if len(line) == 0 { 415 | continue 416 | } 417 | 418 | //if len(line) < 3 || line[0] == '.' || line[len(line)-1] == '.' || len(strings.Split(string(line), ".")) < 2 { 419 | // fmt.Printf("warnning : china domain format incorrect at %s , ignore \r\n", string(line)) 420 | //} 421 | 422 | Cn_domain_map[string(line)] = nil 423 | } 424 | } 425 | } 426 | 427 | if ipv6_white_list != nil && *ipv6_white_list != "" { 428 | f, err := os.Open(*ipv6_white_list) 429 | if err != nil { 430 | fmt.Fprintf(os.Stderr, "open ipv6 white list file fail: %s\r\n", err.Error()) 431 | os.Exit(1) 432 | } 433 | defer f.Close() 434 | r := bufio.NewReader(f) 435 | for { 436 | line, _, err := r.ReadLine() 437 | if err != nil { 438 | if err == io.EOF { 439 | break 440 | } else { 441 | fmt.Fprintf(os.Stderr, "open ipv6 black list file fail: %s\r\n", err.Error()) 442 | os.Exit(1) 443 | } 444 | } else { 445 | if len(line) == 0 { 446 | continue 447 | } 448 | 449 | ip_mask := strings.Split(string(line), "/") 450 | if len(ip_mask) != 2 { 451 | fmt.Printf("warnning : ipv6 black list format incorrect at %s , ignore \r\n", string(line)) 452 | continue 453 | } 454 | ip := net.ParseIP(ip_mask[0]).To16() 455 | if ip.To16() == nil { 456 | fmt.Printf("warnning : ipv6 black list format incorrect at %s , ignore \r\n", string(line)) 457 | continue 458 | } 459 | 460 | mask, err := strconv.Atoi(ip_mask[1]) 461 | if err != nil || mask <= 0 || mask > 128 { 462 | fmt.Printf("warnning : ipv6 black list format incorrect at %s , ignore \r\n", string(line)) 463 | continue 464 | } 465 | Local_ipv6[ip.To16().String()] = mask 466 | 467 | } 468 | } 469 | } 470 | 471 | } 472 | 473 | func Check_pid_file() { 474 | _, err := os.Stat(Pid_file) 475 | if !os.IsNotExist(err) { 476 | fmt.Fprintf(os.Stderr, "pid file is exist(in %s) , does the program run ? if you sure the program not run,delete the file and run again\r\n", Pid_file) 477 | os.Exit(1) 478 | } 479 | } 480 | -------------------------------------------------------------------------------- /src/go_proxy/util/crypt.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import ( 4 | "bytes" 5 | "crypto/aes" 6 | "crypto/cipher" 7 | "crypto/rand" 8 | "errors" 9 | "go_proxy/exception" 10 | "golang.org/x/crypto/chacha20poly1305" 11 | "log" 12 | ) 13 | 14 | var Crypt Crypt_interface 15 | 16 | type Crypt_interface interface { 17 | Encrypt([]byte) ([]byte) 18 | Decrypt([]byte) ([]byte, error) 19 | Get_passwd() ([]byte) 20 | String() string 21 | Get_enc_len_increase() int 22 | } 23 | 24 | type Chacha20 struct { 25 | Aead cipher.AEAD 26 | password []byte 27 | } 28 | 29 | func (cha *Chacha20) Get_enc_len_increase() int { 30 | return 36 31 | } 32 | 33 | func (cha *Chacha20) Get_passwd() []byte { 34 | return cha.password 35 | 36 | } 37 | 38 | func (cha *Chacha20) Encrypt(data []byte) []byte { 39 | 40 | nonce, addition_data := make([]byte, 12), make([]byte, 8) 41 | rand.Read(nonce) 42 | rand.Read(addition_data) 43 | dst := cha.Aead.Seal(nil, nonce, data, addition_data) 44 | return bytes.Join([][]byte{nonce, addition_data, dst}, nil) 45 | 46 | } 47 | 48 | 49 | func (cha *Chacha20) Decrypt(data []byte) ([]byte, error) { 50 | if len(data) < 12+8 { 51 | return nil, exception.CryptErr{}.New("chacha20 recv too short data len,may be crypt method not relate or password incorrect") 52 | } 53 | dst, err := cha.Aead.Open(nil, data[:12], data[12+8:], data[12:12+8]) 54 | if err != nil { 55 | return nil, exception.CryptErr{}.New("chacha20 can not decrypt data") 56 | } 57 | return dst, nil 58 | } 59 | 60 | func (cha *Chacha20) String() string { 61 | return Enc_chacha20 62 | } 63 | 64 | //========================================== 65 | 66 | type Aes256cfb struct { 67 | Block cipher.Block 68 | password []byte 69 | } 70 | 71 | func (aes256 *Aes256cfb) Get_enc_len_increase() int { 72 | return aes.BlockSize 73 | } 74 | 75 | func (aes256 *Aes256cfb) Get_passwd() []byte { 76 | return aes256.password 77 | 78 | } 79 | 80 | func (aes256 *Aes256cfb) Encrypt(data []byte) ([]byte) { 81 | iv := make([]byte, aes.BlockSize) 82 | 83 | rand.Read(iv) 84 | 85 | encrypt := cipher.NewCFBEncrypter(aes256.Block, iv) 86 | enc_data := make([]byte, len(data)) 87 | encrypt.XORKeyStream(enc_data, data) 88 | return bytes.Join([][]byte{iv, enc_data}, nil) 89 | } 90 | 91 | func (aes256 *Aes256cfb) Decrypt(data []byte) ([]byte, error) { 92 | if len(data) < aes.BlockSize { 93 | return nil, exception.CryptErr{}.New("aes-256-cfb recv too short data len,may be crypt method not relate or password incorrect") 94 | } 95 | iv := data[:aes.BlockSize] 96 | decrypt := cipher.NewCFBDecrypter(aes256.Block, iv) 97 | dec_data := make([]byte, len(data)-aes.BlockSize) 98 | decrypt.XORKeyStream(dec_data, data[aes.BlockSize:]) 99 | return dec_data, nil 100 | } 101 | 102 | func (*Aes256cfb) String() string { 103 | return Enc_aes_256_cfb 104 | } 105 | 106 | //=============================================================== 107 | 108 | type None struct { 109 | } 110 | 111 | func (*None) Get_enc_len_increase() int { 112 | return 0 113 | } 114 | 115 | func (*None) Encrypt(b []byte) ([]byte) { 116 | return b 117 | } 118 | 119 | func (*None) Decrypt(b []byte) ([]byte, error) { 120 | return b, nil 121 | } 122 | 123 | func (*None) Get_passwd() ([]byte) { 124 | return []byte{} 125 | } 126 | 127 | func (*None) String() string { 128 | return Enc_none 129 | } 130 | 131 | //=============================================================== 132 | func Get_none_crypt() Crypt_interface { 133 | return &None{} 134 | } 135 | 136 | func Get_crypt(method, password string) (Crypt_interface, error) { 137 | switch method { 138 | case Enc_chacha20: 139 | aead, err := chacha20poly1305.New([]byte(password)) 140 | if err != nil { 141 | return nil, err 142 | } 143 | return &Chacha20{ 144 | Aead: aead, 145 | password: []byte(password), 146 | }, nil 147 | 148 | case Enc_aes_256_cfb: 149 | block, err := aes.NewCipher([]byte(password)) 150 | if err != nil { 151 | log.Fatal(err) 152 | } 153 | 154 | return &Aes256cfb{ 155 | Block: block, 156 | password: []byte(password), 157 | }, nil 158 | 159 | default: 160 | return nil, errors.New("unsupport encrypt method") 161 | 162 | } 163 | 164 | } 165 | -------------------------------------------------------------------------------- /src/go_proxy/util/logger.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "os" 7 | "time" 8 | ) 9 | 10 | var Log_verbose = log.Logger{} 11 | 12 | func init() { 13 | Log_verbose.SetOutput(os.Stdout) 14 | } 15 | 16 | func Print_log(id uint16, log string, v ...interface{}) { 17 | 18 | file, err := os.OpenFile("go_proxy.log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0644) 19 | if err != nil { 20 | fmt.Println("can not open log file:" + err.Error()) 21 | return 22 | } 23 | fmt.Fprintf(file, time.Now().Format(time.RFC3339)+" "+fmt.Sprintf("id:%d", id)+" "+log+"\r\n", v...) 24 | file.Close() 25 | } 26 | 27 | func Print_log_without_id(log string, v ...interface{}) { 28 | 29 | file, err := os.OpenFile("go_proxy.log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0644) 30 | if err != nil { 31 | fmt.Println("can not open log file:" + err.Error()) 32 | return 33 | } 34 | fmt.Fprintf(file, time.Now().Format(time.RFC3339)+" "+log+"\r\n", v...) 35 | file.Close() 36 | } 37 | 38 | func Print_verbose(msg string, v ...interface{}) { 39 | Log_verbose.Printf(time.Now().Format(time.RFC3339)+" "+msg, v...) 40 | } 41 | --------------------------------------------------------------------------------