├── .gitignore
├── README-zh.md
├── README.md
├── config
├── autostart
├── autostart.exe
├── config.ini
├── proxysetting.exe
└── wininet.dll
├── data
├── proxy.json
└── services.json
├── docs
└── image
│ ├── add.png
│ ├── delete.png
│ ├── empty.jpg
│ ├── log.png
│ ├── login.png
│ ├── preview.png
│ ├── setting.png
│ ├── start.jpg
│ └── update.png
├── go.mod
├── go.sum
├── lib
├── goproxy
│ ├── sdk
│ │ └── android-ios
│ │ │ ├── .gitignore
│ │ │ ├── dns.go
│ │ │ ├── release_android.sh
│ │ │ ├── release_ios.sh
│ │ │ └── sdk.go
│ ├── services
│ │ ├── http
│ │ │ └── http.go
│ │ ├── kcpcfg
│ │ │ └── args.go
│ │ ├── mux
│ │ │ ├── mux_bridge.go
│ │ │ ├── mux_client.go
│ │ │ └── mux_server.go
│ │ ├── service.go
│ │ ├── socks
│ │ │ ├── socks.go
│ │ │ └── udp.go
│ │ ├── sps
│ │ │ ├── socksudp.go
│ │ │ └── sps.go
│ │ ├── tcp
│ │ │ └── tcp.go
│ │ ├── tunnel
│ │ │ ├── tunnel_bridge.go
│ │ │ ├── tunnel_client.go
│ │ │ └── tunnel_server.go
│ │ └── udp
│ │ │ └── udp.go
│ └── utils
│ │ ├── aes
│ │ └── aes.go
│ │ ├── conncrypt
│ │ └── conncrypt.go
│ │ ├── functions.go
│ │ ├── id
│ │ └── xid.go
│ │ ├── io-limiter.go
│ │ ├── leakybuf.go
│ │ ├── map.go
│ │ ├── serve-channel.go
│ │ ├── sni
│ │ └── sni.go
│ │ ├── socks
│ │ ├── client.go
│ │ ├── server.go
│ │ └── structs.go
│ │ └── structs.go
└── webtail
│ └── webtail.go
├── main.go
├── release.sh
├── resource.syso
├── school.ico
├── server
├── log.go
├── login.go
├── proxy.go
└── server.go
├── static
├── .DS_Store
├── css
│ ├── bootstrap-theme.min.css
│ ├── bootstrap-theme.min.css.map
│ ├── bootstrap.min.css
│ ├── bootstrap.min.css.map
│ └── price.css
├── fonts
│ ├── glyphicons-halflings-regular.eot
│ ├── glyphicons-halflings-regular.svg
│ ├── glyphicons-halflings-regular.ttf
│ ├── glyphicons-halflings-regular.woff
│ └── glyphicons-halflings-regular.woff2
├── images
│ └── NX-Desktop-BG.png
├── js
│ ├── bootstrap.min.js
│ ├── jquery-1.12.4.min.js
│ ├── layer.js
│ ├── notify.js
│ ├── npm.js
│ └── theme
│ │ └── default
│ │ ├── icon-ext.png
│ │ ├── icon.png
│ │ ├── layer.css
│ │ ├── loading-0.gif
│ │ ├── loading-1.gif
│ │ └── loading-2.gif
└── webupload
│ ├── Uploader.swf
│ ├── demo.js
│ ├── webuploader.css
│ ├── webuploader.js
│ └── webuploader.min.js
├── utils
├── always.go
├── compress.go
├── config.go
├── convert.go
├── data.go
└── error.go
├── versioninfo.json
└── view
├── index.html
└── login.html
/.gitignore:
--------------------------------------------------------------------------------
1 | proxy-web
2 | proxy-web.exe
3 | *.exe~
4 | /db/bucket/
5 | /upload/
6 | /data/services/
7 | /tmp/
8 | .idea/
9 | /log/
10 | .DS_Store
11 |
--------------------------------------------------------------------------------
/README-zh.md:
--------------------------------------------------------------------------------
1 | # proxy-web详细介绍
2 | proxy-web是用go语言写的,基于[snail007/goproxy](https://github.com/snail007/goproxy/)完成的可视化网页应用
3 |
4 | ---
5 | [](https://github.com/snail007/goproxy/)
6 |
7 | ### 使用前须知
8 | - [作用](#作用)
9 | - [下载](#下载)
10 | - [更新](#更新)
11 | - [配置](#配置)
12 | - [依赖包](#依赖包)
13 |
14 | ### 手册目录
15 | - [1. 使用](#1使用)
16 | - [2. 参数介绍](#2参数介绍)
17 |
18 | ### 作用
19 | 1、 用web界面的方式使用goproxy,更加方便
20 | 2、 监控goproxy运行情况
21 | 3、 实时显示goproxy产生的日志
22 | 4、 启动proxy-web后能自启动goproxy
23 | 5、 能自开机自启动proxy-web
24 | 6、 可以设置linux,mac,windows全局http代理,需要root权限
25 | 7、 页面全新升级
26 |
27 | ### 下载
28 | [下载地址](https://github.com/yincongcyincong/proxy-web/releases)
29 |
30 | ### 更新
31 | v 2.0 全面更新
32 | 可以自由配置参数
33 | 开机自启动proxy-web
34 | 全局http代理设置
35 | 使用goproxy提供的sdk,不再依赖goproxy二进制程序
36 |
37 | ### 配置
38 | 配置文件为config/config.ini
39 | 可以配置的属性有:端口(默认48080),登录账号和密码(都为admin)
40 |
41 |
42 | ### 依赖包
43 | [github.com/snail007/goproxy/sdk](https://github.com/snail007/goproxy/blob/master/sdk/README.md)goproxy的sdk
44 | [github.com/Unknwon/goconfig](https://github.com/Unknwon/goconfig)解析配置文件
45 | [github.com/astaxie/beego/tree/master/session](https://github.com/astaxie/beego/tree/master/session) session模块
46 | 这些依赖已经在源码内解决,无需go get
47 |
48 | ### 1.使用
49 | 使用48080端口进入页面(如:localhost:48080),首先到登录页面
50 |
51 | 账号密码都为admin,登录进入
52 |
53 | 点击,添加代理,显示添加代理的弹框,可以选择代理是否开启proxy-web服务时也自动启动
54 |
55 | 修改操作
56 |
57 | 启动操作
58 |
59 | 查看日志操作
60 |
61 | 删除操作
62 |
63 | 设置全局http代理和是否开机自启动,这两个操作需要root权限
64 |
65 |
66 | ### 2.参数介绍
67 | 名称:代理的名称。
68 | 参数:指[snail007/goproxy](https://github.com/snail007/goproxy/)中的各种参数。
69 |
70 | ### 源码使用
71 | - 使用非windows编译,请删除resource.syso
72 | - git下载源码
73 |
74 | ### TODO
75 | - -查找bug
76 |
77 | ### License
78 | - under GPLv3 license
79 |
80 | ### Contact
81 | - QQ群:189618940
82 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # proxy-web introduction
2 | proxy-web is a webview proxy application written by Golang,base on [snail007/goproxy](https://github.com/snail007/goproxy/)
3 | 中文介绍:[proxy-web](https://github.com/yincongcyincong/proxy-web/blob/master/README-zh.md)
4 | ---
5 | [](https://github.com/snail007/goproxy/)
6 |
7 | ### Notice before use
8 | - [Function](#Function)
9 | - [Download](#Download)
10 | - [Update](#Update)
11 | - [Conf](#Conf)
12 | - [Dependence](#Dependence)
13 |
14 | ### Handbook Catalog
15 | - [1. usage](#1usage)
16 | - [2. param introduction](#2param introduction)
17 |
18 | ### Function
19 | 1. Using goproxy through a web interface is more convenient
20 | 2. Monitor the running status of goproxy
21 | 3. Real time display of logs generated by goproxy
22 | 4. After starting proxy web, goproxy can be started automatically
23 | 5. Capable of booting up and booting proxy web on its own
24 | 6. Linux, Mac, and Windows global HTTP proxies can be set, requiring root privileges
25 | 7. New page upgrade
26 |
27 | ### Download
28 | [download websit](https://github.com/yincongcyincong/proxy-web/releases)
29 |
30 | ### Update
31 | v 2.0 overall update
32 | Can freely configure parameters
33 | Power on and self start proxy web
34 | Global HTTP proxy settings
35 | Use the SDK provided by goproxy and no longer rely on goproxy binary programs
36 |
37 | ### Configure
38 | The configuration file is config/config.ini
39 | The configurable properties include: port (default 48080), login account, and password (all admin)
40 |
41 |
42 | ### Dependence
43 | [github.com/snail007/goproxy/sdk](https://github.com/snail007/goproxy/blob/master/sdk/README.md)
44 | [github.com/Unknwon/goconfig](https://github.com/Unknwon/goconfig)
45 | [github.com/astaxie/beego/tree/master/session](https://github.com/astaxie/beego/tree/master/session)
46 |
47 | ### 1.Usage
48 | Use port 48080 to enter the page (e.g. localhost:48080), first go to the login page
49 |
50 | both username and password are admin,then login
51 |
52 | Click to add the proxy and display a pop-up box for adding the proxy. You can choose whether the proxy will automatically start when the proxy web service is enabled
53 |
54 | update
55 |
56 | start
57 |
58 | check out log
59 |
60 | delete
61 |
62 | Setting the global HTTP proxy and whether to boot automatically requires root privileges
63 |
64 |
65 | ### 2.param introduction
66 | name:proxy name。
67 | param:[snail007/goproxy](https://github.com/snail007/goproxy/) have more param detail, please refer。
68 |
69 | ### Usage of source code
70 | - Using non Windows compilation, please remove resource.syso
71 | - git download source code
72 |
73 | ### TODO
74 | - -check out bug
75 |
76 | ### License
77 | - under GPLv3 license
78 |
79 |
80 |
--------------------------------------------------------------------------------
/config/autostart:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yincongcyincong/proxy-web/c4a955db0958186ea1253697411db4eee32e7605/config/autostart
--------------------------------------------------------------------------------
/config/autostart.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yincongcyincong/proxy-web/c4a955db0958186ea1253697411db4eee32e7605/config/autostart.exe
--------------------------------------------------------------------------------
/config/config.ini:
--------------------------------------------------------------------------------
1 | [proxy_server]
2 | port = :48080
3 | username = admin
4 | password = admin
5 | services = /data/services.json
6 |
7 | [config]
8 | auto_start = true
9 | proxy = false
10 |
11 |
--------------------------------------------------------------------------------
/config/proxysetting.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yincongcyincong/proxy-web/c4a955db0958186ea1253697411db4eee32e7605/config/proxysetting.exe
--------------------------------------------------------------------------------
/config/wininet.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yincongcyincong/proxy-web/c4a955db0958186ea1253697411db4eee32e7605/config/wininet.dll
--------------------------------------------------------------------------------
/data/proxy.json:
--------------------------------------------------------------------------------
1 | {"ip":"127.0.0.1","port":"18080"}
--------------------------------------------------------------------------------
/data/services.json:
--------------------------------------------------------------------------------
1 | {"1533439640321":"yes"}
--------------------------------------------------------------------------------
/docs/image/add.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yincongcyincong/proxy-web/c4a955db0958186ea1253697411db4eee32e7605/docs/image/add.png
--------------------------------------------------------------------------------
/docs/image/delete.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yincongcyincong/proxy-web/c4a955db0958186ea1253697411db4eee32e7605/docs/image/delete.png
--------------------------------------------------------------------------------
/docs/image/empty.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yincongcyincong/proxy-web/c4a955db0958186ea1253697411db4eee32e7605/docs/image/empty.jpg
--------------------------------------------------------------------------------
/docs/image/log.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yincongcyincong/proxy-web/c4a955db0958186ea1253697411db4eee32e7605/docs/image/log.png
--------------------------------------------------------------------------------
/docs/image/login.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yincongcyincong/proxy-web/c4a955db0958186ea1253697411db4eee32e7605/docs/image/login.png
--------------------------------------------------------------------------------
/docs/image/preview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yincongcyincong/proxy-web/c4a955db0958186ea1253697411db4eee32e7605/docs/image/preview.png
--------------------------------------------------------------------------------
/docs/image/setting.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yincongcyincong/proxy-web/c4a955db0958186ea1253697411db4eee32e7605/docs/image/setting.png
--------------------------------------------------------------------------------
/docs/image/start.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yincongcyincong/proxy-web/c4a955db0958186ea1253697411db4eee32e7605/docs/image/start.jpg
--------------------------------------------------------------------------------
/docs/image/update.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yincongcyincong/proxy-web/c4a955db0958186ea1253697411db4eee32e7605/docs/image/update.png
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/yincongcyincong/proxy-web
2 |
3 | go 1.18
4 |
5 | require (
6 | github.com/Unknwon/goconfig v0.0.0-20180308125533-ef1e4c783f8f
7 | github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc
8 | github.com/astaxie/beego v1.9.3-0.20171218111859-f16688817aa4
9 | github.com/gobwas/ws v0.1.1-0.20180527201045-2c0cb1ddcc09
10 | github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db
11 | github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb
12 | github.com/julienschmidt/httprouter v1.1.1-0.20180411154501-adbc77eec0d9
13 | github.com/miekg/dns v0.0.0-20180701183735-3e6e47bc11bc
14 | github.com/pkg/errors v0.8.1-0.20180311214515-816c9085562c
15 | github.com/pmylund/go-cache v2.1.1-0.20180527043350-9f6ff22cfff8+incompatible
16 | github.com/xtaci/kcp-go v2.0.4-0.20180203133237-42bc1dfefff5+incompatible
17 | golang.org/x/crypto v0.21.0
18 | golang.org/x/net v0.22.0
19 | golang.org/x/time v0.5.0
20 | gopkg.in/alecthomas/kingpin.v2 v2.2.6
21 | )
22 |
23 | require (
24 | github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf // indirect
25 | github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee // indirect
26 | github.com/gobwas/pool v0.2.0 // indirect
27 | github.com/klauspost/cpuid v1.2.0 // indirect
28 | github.com/klauspost/reedsolomon v0.0.0-20180630081529-3133c51b912e // indirect
29 | github.com/smartystreets/goconvey v1.8.1 // indirect
30 | github.com/stretchr/testify v1.9.0 // indirect
31 | github.com/templexxx/cpufeat v0.0.0-20170927014610-3794dfbfb047 // indirect
32 | github.com/templexxx/xor v0.0.0-20170926022130-0af8e873c554 // indirect
33 | github.com/tjfoc/gmsm v1.0.2-0.20180622091801-881917d33b84 // indirect
34 | golang.org/x/sys v0.18.0 // indirect
35 | )
36 |
--------------------------------------------------------------------------------
/go.sum:
--------------------------------------------------------------------------------
1 | github.com/Unknwon/goconfig v0.0.0-20180308125533-ef1e4c783f8f h1:2h0zBHX3qNDltgnb2FiMJWYTcqJVDdUeHQU2/5CTc5w=
2 | github.com/Unknwon/goconfig v0.0.0-20180308125533-ef1e4c783f8f/go.mod h1:wngxua9XCNjvHjDiTiV26DaKDT+0c63QR6H5hjVUUxw=
3 | github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc h1:cAKDfWh5VpdgMhJosfJnn5/FoN2SRZ4p7fJNX58YPaU=
4 | github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
5 | github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf h1:qet1QNfXsQxTZqLG4oE62mJzwPIB8+Tee4RNCL9ulrY=
6 | github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
7 | github.com/astaxie/beego v1.9.3-0.20171218111859-f16688817aa4 h1:dNIynF6ICiq1NghlpIBxljb2JbyC61/JqWB5A9cfUfo=
8 | github.com/astaxie/beego v1.9.3-0.20171218111859-f16688817aa4/go.mod h1:0R4++1tUqERR0WYFWdfkcrsyoVBCG4DgpDGokT3yb+U=
9 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
10 | github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0=
11 | github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo=
12 | github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8=
13 | github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
14 | github.com/gobwas/ws v0.1.1-0.20180527201045-2c0cb1ddcc09 h1:GMq0fofcJ2Y57HIQC7gYFXyV5/scIzQSGpla0dfvfG4=
15 | github.com/gobwas/ws v0.1.1-0.20180527201045-2c0cb1ddcc09/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM=
16 | github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pOkfl+p/TAqKOfFu+7KPlMVpok/w=
17 | github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
18 | github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g=
19 | github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb h1:b5rjCoWHc7eqmAS4/qyk21ZsHyb6Mxv/jykxvNTkU4M=
20 | github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
21 | github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
22 | github.com/julienschmidt/httprouter v1.1.1-0.20180411154501-adbc77eec0d9 h1:fYQgw8kxM2StYZLTlDcpfXWm0trPjcJzDtYzwIr02SM=
23 | github.com/julienschmidt/httprouter v1.1.1-0.20180411154501-adbc77eec0d9/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
24 | github.com/klauspost/cpuid v1.2.0 h1:NMpwD2G9JSFOE1/TJjGSo5zG7Yb2bTe7eq1jH+irmeE=
25 | github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
26 | github.com/klauspost/reedsolomon v0.0.0-20180630081529-3133c51b912e h1:PU55RoO5I45ARU29WnEiub4UbSw/dwt2RPuA3JgxNEs=
27 | github.com/klauspost/reedsolomon v0.0.0-20180630081529-3133c51b912e/go.mod h1:CwCi+NUr9pqSVktrkN+Ondf06rkhYZ/pcNv7fu+8Un4=
28 | github.com/miekg/dns v0.0.0-20180701183735-3e6e47bc11bc h1:/hpKsb38tsHA7imIvePK+FrunsKXZI5OyA5N4E3jYPc=
29 | github.com/miekg/dns v0.0.0-20180701183735-3e6e47bc11bc/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
30 | github.com/pkg/errors v0.8.1-0.20180311214515-816c9085562c h1:SZvPVPsWE261bl8uxQ6Siq+ExNmYomz4CTU9E0ALgj4=
31 | github.com/pkg/errors v0.8.1-0.20180311214515-816c9085562c/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
32 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
33 | github.com/pmylund/go-cache v2.1.1-0.20180527043350-9f6ff22cfff8+incompatible h1:yDaaUQeNjNPFE5yPKv8x9fkqLJpU2gveyGV1o5oUo6A=
34 | github.com/pmylund/go-cache v2.1.1-0.20180527043350-9f6ff22cfff8+incompatible/go.mod h1:hmz95dGvINpbRZGsqPcd7B5xXY5+EKb5PpGhQY3NTHk=
35 | github.com/smarty/assertions v1.15.0 h1:cR//PqUBUiQRakZWqBiFFQ9wb8emQGDb0HeGdqGByCY=
36 | github.com/smartystreets/goconvey v1.8.1 h1:qGjIddxOk4grTu9JPOU31tVfq3cNdBlNa5sSznIX1xY=
37 | github.com/smartystreets/goconvey v1.8.1/go.mod h1:+/u4qLyY6x1jReYOp7GOM2FSt8aP9CzCZL03bI28W60=
38 | github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
39 | github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
40 | github.com/templexxx/cpufeat v0.0.0-20170927014610-3794dfbfb047 h1:K+jtWCOuZgCra7eXZ/VWn2FbJmrA/D058mTXhh2rq+8=
41 | github.com/templexxx/cpufeat v0.0.0-20170927014610-3794dfbfb047/go.mod h1:wM7WEvslTq+iOEAMDLSzhVuOt5BRZ05WirO+b09GHQU=
42 | github.com/templexxx/xor v0.0.0-20170926022130-0af8e873c554 h1:pexgSe+JCFuxG+uoMZLO+ce8KHtdHGhst4cs6rw3gmk=
43 | github.com/templexxx/xor v0.0.0-20170926022130-0af8e873c554/go.mod h1:5XA7W9S6mni3h5uvOC75dA3m9CCCaS83lltmc0ukdi4=
44 | github.com/tjfoc/gmsm v1.0.2-0.20180622091801-881917d33b84 h1:vRHy5P+8dmQKnXoQ+hIdD6tZGW00LQEn0/sPcBbbRzU=
45 | github.com/tjfoc/gmsm v1.0.2-0.20180622091801-881917d33b84/go.mod h1:XxO4hdhhrzAd+G4CjDqaOkd0hUzmtPR/d3EiBBMn/wc=
46 | github.com/xtaci/kcp-go v2.0.4-0.20180203133237-42bc1dfefff5+incompatible h1:hygiAxAfy0/0B2lqN7XDHWFarQgyd2agMExOzFXgnbw=
47 | github.com/xtaci/kcp-go v2.0.4-0.20180203133237-42bc1dfefff5+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45a+AZwO7eyRCmEIbtvE=
48 | golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
49 | golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
50 | golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc=
51 | golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
52 | golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
53 | golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
54 | golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8=
55 | golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
56 | golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
57 | gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc=
58 | gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
59 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
60 |
--------------------------------------------------------------------------------
/lib/goproxy/sdk/android-ios/.gitignore:
--------------------------------------------------------------------------------
1 | *.jar
2 | *.aar
3 | *.tar.gz
4 | ios
5 | android
6 | Proxy.framework
7 |
--------------------------------------------------------------------------------
/lib/goproxy/sdk/android-ios/dns.go:
--------------------------------------------------------------------------------
1 | package proxy
2 |
3 | import (
4 | "crypto/md5"
5 | "encoding/hex"
6 | "fmt"
7 | services2 "github.com/yincongcyincong/proxy-web/lib/goproxy/services"
8 | kcpcfg2 "github.com/yincongcyincong/proxy-web/lib/goproxy/services/kcpcfg"
9 | logger "log"
10 | "net"
11 | "runtime/debug"
12 | "time"
13 |
14 | "golang.org/x/net/proxy"
15 |
16 | "github.com/miekg/dns"
17 | gocache "github.com/pmylund/go-cache"
18 | )
19 |
20 | type DNSArgs struct {
21 | ParentServiceType *string
22 | ParentType *string
23 | Parent *string
24 | ParentAuth *string
25 | ParentKey *string
26 | ParentCompress *bool
27 | KCP kcpcfg2.KCPConfigArgs
28 | CertFile *string
29 | KeyFile *string
30 | CaCertFile *string
31 | Local *string
32 | Timeout *int
33 | RemoteDNSAddress *string
34 | DNSTTL *int
35 | CacheFile *string
36 | LocalSocks5Port *string
37 | }
38 | type DNS struct {
39 | cfg DNSArgs
40 | log *logger.Logger
41 | cache *gocache.Cache
42 | exitSig chan bool
43 | serviceKey string
44 | dialer proxy.Dialer
45 | }
46 |
47 | func NewDNS() services2.Service {
48 | return &DNS{
49 | cfg: DNSArgs{},
50 | exitSig: make(chan bool, 1),
51 | serviceKey: "dns-service-" + fmt.Sprintf("%d", time.Now().UnixNano()),
52 | }
53 | }
54 | func (s *DNS) CheckArgs() (err error) {
55 | return
56 | }
57 | func (s *DNS) InitService() (err error) {
58 | s.cache = gocache.New(time.Second*time.Duration(*s.cfg.DNSTTL), time.Second*60)
59 | s.cache.LoadFile(*s.cfg.CacheFile)
60 | go func() {
61 | for {
62 | select {
63 | case <-s.exitSig:
64 | return
65 | case <-time.After(time.Second * 60):
66 | err := s.cache.SaveFile(*s.cfg.CacheFile)
67 | if err == nil {
68 | //s.log.Printf("cache saved: %s", *s.cfg.CacheFile)
69 | } else {
70 | s.log.Printf("cache save failed: %s, %s", *s.cfg.CacheFile, err)
71 | }
72 | }
73 | }
74 | }()
75 | s.dialer, err = proxy.SOCKS5("tcp", *s.cfg.Parent,
76 | nil,
77 | &net.Dialer{
78 | Timeout: 5 * time.Second,
79 | KeepAlive: 2 * time.Second,
80 | },
81 | )
82 | if err != nil {
83 | return
84 | }
85 |
86 | sdkArgs := fmt.Sprintf("sps -S %s -T %s -P %s -C %s -K %s -i %d -p 127.0.0.1:%s --disable-http",
87 | *s.cfg.ParentServiceType,
88 | *s.cfg.ParentType,
89 | *s.cfg.Parent,
90 | *s.cfg.CertFile,
91 | *s.cfg.KeyFile,
92 | *s.cfg.Timeout,
93 | *s.cfg.LocalSocks5Port,
94 | )
95 | if *s.cfg.ParentKey != "" {
96 | sdkArgs += " -Z " + *s.cfg.ParentKey
97 | }
98 | if *s.cfg.ParentAuth != "" {
99 | sdkArgs += " -A " + *s.cfg.ParentAuth
100 | }
101 | if *s.cfg.CaCertFile != "" {
102 | sdkArgs += " --ca " + *s.cfg.CaCertFile
103 | }
104 | if *s.cfg.ParentCompress {
105 | sdkArgs += " -M"
106 | }
107 | s.log.Printf("start sps with : %s", sdkArgs)
108 | errStr := Start(s.serviceKey, sdkArgs)
109 | if errStr != "" {
110 | err = fmt.Errorf("start sps service fail,%s", errStr)
111 | }
112 | return
113 | }
114 | func (s *DNS) StopService() {
115 | defer func() {
116 | e := recover()
117 | if e != nil {
118 | s.log.Printf("stop dns service crashed,%s", e)
119 | } else {
120 | s.log.Printf("service dns stopped")
121 | }
122 | }()
123 | Stop(s.serviceKey)
124 | s.cache.Flush()
125 | s.exitSig <- true
126 | }
127 | func (s *DNS) Start(args interface{}, log *logger.Logger) (err error) {
128 | s.log = log
129 | s.cfg = args.(DNSArgs)
130 | if err = s.CheckArgs(); err != nil {
131 | return
132 | }
133 | if err = s.InitService(); err != nil {
134 | return
135 | }
136 | dns.HandleFunc(".", s.callback)
137 | go func() {
138 | log.Printf("dns server on udp %s", *s.cfg.Local)
139 | err := dns.ListenAndServe(*s.cfg.Local, "udp", nil)
140 | if err != nil {
141 | log.Printf("dns listen error: %s", err)
142 | }
143 | }()
144 | return
145 | }
146 |
147 | func (s *DNS) Clean() {
148 | s.StopService()
149 | }
150 | func (s *DNS) callback(w dns.ResponseWriter, req *dns.Msg) {
151 | defer func() {
152 | if err := recover(); err != nil {
153 | s.log.Printf("dns handler crashed with err : %s \nstack: %s", err, string(debug.Stack()))
154 | }
155 | }()
156 | var (
157 | key string
158 | m *dns.Msg
159 | err error
160 | data []byte
161 | id uint16
162 | query []string
163 | questions []dns.Question
164 | )
165 | if req.MsgHdr.Response == true {
166 | return
167 | }
168 | query = make([]string, len(req.Question))
169 | for i, q := range req.Question {
170 | if q.Qtype != dns.TypeAAAA {
171 | questions = append(questions, q)
172 | }
173 | query[i] = fmt.Sprintf("(%s %s %s)", q.Name, dns.ClassToString[q.Qclass], dns.TypeToString[q.Qtype])
174 | }
175 |
176 | if len(questions) == 0 {
177 | return
178 | }
179 |
180 | req.Question = questions
181 | id = req.Id
182 | req.Id = 0
183 | key = s.toMd5(req.String())
184 | req.Id = id
185 | if reply, ok := s.cache.Get(key); ok {
186 | data, _ = reply.([]byte)
187 | }
188 | if data != nil && len(data) > 0 {
189 | m = &dns.Msg{}
190 | m.Unpack(data)
191 | m.Id = id
192 | err = w.WriteMsg(m)
193 | s.log.Printf("id: %5d cache: HIT %v", id, query)
194 | return
195 |
196 | } else {
197 | s.log.Printf("id: %5d cache: MISS %v", id, query)
198 | }
199 |
200 | s.log.Printf("id: %5d resolve: %v %s", id, query, *s.cfg.RemoteDNSAddress)
201 |
202 | rawConn, err := s.dialer.Dial("tcp", *s.cfg.RemoteDNSAddress)
203 | if err != nil {
204 | s.log.Printf("dail to %s fail,%s", *s.cfg.RemoteDNSAddress, err)
205 | return
206 | }
207 | defer rawConn.Close()
208 | co := new(dns.Conn)
209 | co.Conn = rawConn
210 | defer co.Close()
211 | if err = co.WriteMsg(req); err != nil {
212 | s.log.Printf("write dns query fail,%s", err)
213 | return
214 | }
215 | m, err = co.ReadMsg()
216 | if err == nil && m.Id != req.Id {
217 | s.log.Printf("id: %5d mismath", id)
218 | return
219 | }
220 | if err != nil || len(m.Answer) == 0 {
221 | s.log.Printf("dns query fail,%s", err)
222 | return
223 | }
224 | data, err = m.Pack()
225 | if err != nil {
226 | s.log.Printf("dns query fail,%s", err)
227 | return
228 | }
229 |
230 | _, err = w.Write(data)
231 | if err != nil {
232 | s.log.Printf("dns query fail,%s", err)
233 | return
234 | }
235 | m.Id = 0
236 | data, _ = m.Pack()
237 | ttl := 0
238 | if len(m.Answer) > 0 {
239 | if *s.cfg.DNSTTL > 0 {
240 | ttl = *s.cfg.DNSTTL
241 | } else {
242 | ttl = int(m.Answer[0].Header().Ttl)
243 | if ttl < 0 {
244 | ttl = *s.cfg.DNSTTL
245 | }
246 | }
247 | }
248 | s.cache.Set(key, data, time.Second*time.Duration(ttl))
249 | m.Id = id
250 | s.log.Printf("id: %5d cache: CACHED %v TTL %v", id, query, ttl)
251 | }
252 | func (s *DNS) toMd5(data string) string {
253 | m := md5.New()
254 | m.Write([]byte(data))
255 | return hex.EncodeToString(m.Sum(nil))
256 | }
257 |
--------------------------------------------------------------------------------
/lib/goproxy/sdk/android-ios/release_android.sh:
--------------------------------------------------------------------------------
1 | #/bin/bash
2 | VER="v5.3"
3 | rm -rf sdk-android-*.tar.gz
4 | rm -rf android
5 | mkdir android
6 |
7 | #android ; jdk,android ndk & android sdk required, install gomobile go1.10 required
8 | #export GOPATH="$HOME/go"
9 | #export GOROOT="/usr/local/go"
10 | #export PATH="$GOROOT/bin:$GOPATH/bin:$PATH"
11 | #export ANDROID_HOME="$HOME/Android/Sdk"
12 | #export NDK_ROOT="$HOME/Android/Sdk/ndk-bundle"
13 | #export PATH="$ANDROID_HOME/tools:$ANDROID_HOME/platform-tools:$NDK_ROOT:$PATH"
14 | #go get -v golang.org/x/mobile/cmd/gomobile
15 | #gomobile init
16 |
17 | gomobile bind -v -target=android -javapkg=snail007 -ldflags="-s -w"
18 | mv proxy.aar android/snail007.goproxy.sdk.aar
19 | mv proxy-sources.jar android/snail007.goproxy.sdk-sources.jar
20 | cp ../README.md android
21 | tar zcfv sdk-android-${VER}.tar.gz android
22 | rm -rf android
23 |
24 | echo "done."
25 |
--------------------------------------------------------------------------------
/lib/goproxy/sdk/android-ios/release_ios.sh:
--------------------------------------------------------------------------------
1 | #/bin/bash
2 | VER="v5.3"
3 | rm -rf sdk-ios-*.tar.gz
4 | rm -rf ios
5 | mkdir ios
6 |
7 | #ios XCode required
8 | gomobile bind -v -target=ios -ldflags="-s -w"
9 | mv Proxy.framework ios
10 | cp ../README.md ios
11 | tar zcfv sdk-ios-${VER}.tar.gz ios
12 | rm -rf ios
13 |
14 | echo "done."
15 |
--------------------------------------------------------------------------------
/lib/goproxy/services/kcpcfg/args.go:
--------------------------------------------------------------------------------
1 | package kcpcfg
2 |
3 | import kcp "github.com/xtaci/kcp-go"
4 |
5 | type KCPConfigArgs struct {
6 | Key *string
7 | Crypt *string
8 | Mode *string
9 | MTU *int
10 | SndWnd *int
11 | RcvWnd *int
12 | DataShard *int
13 | ParityShard *int
14 | DSCP *int
15 | NoComp *bool
16 | AckNodelay *bool
17 | NoDelay *int
18 | Interval *int
19 | Resend *int
20 | NoCongestion *int
21 | SockBuf *int
22 | KeepAlive *int
23 | Block kcp.BlockCrypt
24 | }
25 |
--------------------------------------------------------------------------------
/lib/goproxy/services/mux/mux_bridge.go:
--------------------------------------------------------------------------------
1 | package mux
2 |
3 | import (
4 | "bufio"
5 | "fmt"
6 | services2 "github.com/yincongcyincong/proxy-web/lib/goproxy/services"
7 | kcpcfg2 "github.com/yincongcyincong/proxy-web/lib/goproxy/services/kcpcfg"
8 | utils2 "github.com/yincongcyincong/proxy-web/lib/goproxy/utils"
9 | "io"
10 | logger "log"
11 | "math/rand"
12 | "net"
13 | "strconv"
14 | "strings"
15 | "sync"
16 | "time"
17 |
18 | //"github.com/xtaci/smux"
19 | smux "github.com/hashicorp/yamux"
20 | )
21 |
22 | const (
23 | CONN_SERVER = uint8(4)
24 | CONN_CLIENT = uint8(5)
25 | )
26 |
27 | type MuxBridgeArgs struct {
28 | CertFile *string
29 | KeyFile *string
30 | CertBytes []byte
31 | KeyBytes []byte
32 | Local *string
33 | LocalType *string
34 | Timeout *int
35 | IsCompress *bool
36 | KCP kcpcfg2.KCPConfigArgs
37 | }
38 | type MuxBridge struct {
39 | cfg MuxBridgeArgs
40 | clientControlConns utils2.ConcurrentMap
41 | serverConns utils2.ConcurrentMap
42 | router utils2.ClientKeyRouter
43 | l *sync.Mutex
44 | isStop bool
45 | sc *utils2.ServerChannel
46 | log *logger.Logger
47 | }
48 |
49 | func NewMuxBridge() services2.Service {
50 | b := &MuxBridge{
51 | cfg: MuxBridgeArgs{},
52 | clientControlConns: utils2.NewConcurrentMap(),
53 | serverConns: utils2.NewConcurrentMap(),
54 | l: &sync.Mutex{},
55 | isStop: false,
56 | }
57 | b.router = utils2.NewClientKeyRouter(&b.clientControlConns, 50000)
58 | return b
59 | }
60 |
61 | func (s *MuxBridge) InitService() (err error) {
62 | return
63 | }
64 | func (s *MuxBridge) CheckArgs() (err error) {
65 | if *s.cfg.CertFile == "" || *s.cfg.KeyFile == "" {
66 | err = fmt.Errorf("cert and key file required")
67 | return
68 | }
69 | if *s.cfg.LocalType == "tls" {
70 | s.cfg.CertBytes, s.cfg.KeyBytes, err = utils2.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
71 | if err != nil {
72 | return
73 | }
74 | }
75 | return
76 | }
77 | func (s *MuxBridge) StopService() {
78 | defer func() {
79 | e := recover()
80 | if e != nil {
81 | s.log.Printf("stop bridge service crashed,%s", e)
82 | } else {
83 | s.log.Printf("service bridge stopped")
84 | }
85 | }()
86 | s.isStop = true
87 | if s.sc != nil && (*s.sc).Listener != nil {
88 | (*(*s.sc).Listener).Close()
89 | }
90 | for _, g := range s.clientControlConns.Items() {
91 | for _, session := range g.(*utils2.ConcurrentMap).Items() {
92 | (session.(*smux.Session)).Close()
93 | }
94 | }
95 | for _, c := range s.serverConns.Items() {
96 | (*c.(*net.Conn)).Close()
97 | }
98 | }
99 | func (s *MuxBridge) Start(args interface{}, log *logger.Logger) (err error) {
100 | s.log = log
101 | s.cfg = args.(MuxBridgeArgs)
102 | if err = s.CheckArgs(); err != nil {
103 | return
104 | }
105 | if err = s.InitService(); err != nil {
106 | return
107 | }
108 |
109 | host, port, _ := net.SplitHostPort(*s.cfg.Local)
110 | p, _ := strconv.Atoi(port)
111 | sc := utils2.NewServerChannel(host, p, s.log)
112 | if *s.cfg.LocalType == "tcp" {
113 | err = sc.ListenTCP(s.handler)
114 | } else if *s.cfg.LocalType == "tls" {
115 | err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, nil, s.handler)
116 | } else if *s.cfg.LocalType == "kcp" {
117 | err = sc.ListenKCP(s.cfg.KCP, s.handler, s.log)
118 | }
119 | if err != nil {
120 | return
121 | }
122 | s.sc = &sc
123 | s.log.Printf("%s bridge on %s", *s.cfg.LocalType, (*sc.Listener).Addr())
124 | return
125 | }
126 | func (s *MuxBridge) Clean() {
127 | s.StopService()
128 | }
129 | func (s *MuxBridge) handler(inConn net.Conn) {
130 | reader := bufio.NewReader(inConn)
131 |
132 | var err error
133 | var connType uint8
134 | var key string
135 | inConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
136 | err = utils2.ReadPacket(reader, &connType, &key)
137 | inConn.SetDeadline(time.Time{})
138 | if err != nil {
139 | s.log.Printf("read error,ERR:%s", err)
140 | return
141 | }
142 | switch connType {
143 | case CONN_SERVER:
144 | var serverID string
145 | inAddr := inConn.RemoteAddr().String()
146 | inConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
147 | err = utils2.ReadPacketData(reader, &serverID)
148 | inConn.SetDeadline(time.Time{})
149 | if err != nil {
150 | s.log.Printf("read error,ERR:%s", err)
151 | return
152 | }
153 | s.log.Printf("server connection %s %s connected", serverID, key)
154 | if c, ok := s.serverConns.Get(inAddr); ok {
155 | (*c.(*net.Conn)).Close()
156 | }
157 | s.serverConns.Set(inAddr, &inConn)
158 | session, err := smux.Server(inConn, nil)
159 | if err != nil {
160 | utils2.CloseConn(&inConn)
161 | s.log.Printf("server session error,ERR:%s", err)
162 | return
163 | }
164 | for {
165 | if s.isStop {
166 | return
167 | }
168 | stream, err := session.AcceptStream()
169 | if err != nil {
170 | session.Close()
171 | utils2.CloseConn(&inConn)
172 | s.serverConns.Remove(inAddr)
173 | s.log.Printf("server connection %s %s released", serverID, key)
174 | return
175 | }
176 | go func() {
177 | defer func() {
178 | if e := recover(); e != nil {
179 | s.log.Printf("bridge callback crashed,err: %s", e)
180 | }
181 | }()
182 | s.callback(stream, serverID, key)
183 | }()
184 | }
185 | case CONN_CLIENT:
186 | s.log.Printf("client connection %s connected", key)
187 | session, err := smux.Client(inConn, nil)
188 | if err != nil {
189 | utils2.CloseConn(&inConn)
190 | s.log.Printf("client session error,ERR:%s", err)
191 | return
192 | }
193 | keyInfo := strings.Split(key, "-")
194 | if len(keyInfo) != 2 {
195 | utils2.CloseConn(&inConn)
196 | s.log.Printf("client key format error,key:%s", key)
197 | return
198 | }
199 | groupKey := keyInfo[0]
200 | index := keyInfo[1]
201 | s.l.Lock()
202 | defer s.l.Unlock()
203 | if !s.clientControlConns.Has(groupKey) {
204 | item := utils2.NewConcurrentMap()
205 | s.clientControlConns.Set(groupKey, &item)
206 | }
207 | _group, _ := s.clientControlConns.Get(groupKey)
208 | group := _group.(*utils2.ConcurrentMap)
209 | if v, ok := group.Get(index); ok {
210 | v.(*smux.Session).Close()
211 | }
212 | group.Set(index, session)
213 | // s.clientControlConns.Set(key, session)
214 | go func() {
215 | for {
216 | if s.isStop {
217 | return
218 | }
219 | if session.IsClosed() {
220 | s.l.Lock()
221 | defer s.l.Unlock()
222 | if sess, ok := group.Get(index); ok && sess.(*smux.Session).IsClosed() {
223 | group.Remove(index)
224 | s.log.Printf("client connection %s released", key)
225 | }
226 | if group.IsEmpty() {
227 | s.clientControlConns.Remove(groupKey)
228 | }
229 | break
230 | }
231 | time.Sleep(time.Second * 5)
232 | }
233 | }()
234 | //s.log.Printf("set client session,key: %s", key)
235 | }
236 |
237 | }
238 | func (s *MuxBridge) callback(inConn net.Conn, serverID, key string) {
239 | try := 20
240 | for {
241 | if s.isStop {
242 | return
243 | }
244 | try--
245 | if try == 0 {
246 | break
247 | }
248 | if key == "*" {
249 | key = s.router.GetKey()
250 | }
251 | _group, ok := s.clientControlConns.Get(key)
252 | if !ok {
253 | s.log.Printf("client %s session not exists for server stream %s, retrying...", key, serverID)
254 | time.Sleep(time.Second * 3)
255 | continue
256 | }
257 | group := _group.(*utils2.ConcurrentMap)
258 | keys := group.Keys()
259 | keysLen := len(keys)
260 | i := 0
261 | if keysLen > 0 {
262 | i = rand.Intn(keysLen)
263 | } else {
264 | s.log.Printf("client %s session empty for server stream %s, retrying...", key, serverID)
265 | time.Sleep(time.Second * 3)
266 | continue
267 | }
268 | index := keys[i]
269 | s.log.Printf("select client : %s-%s", key, index)
270 | session, _ := group.Get(index)
271 | //session.(*smux.Session).SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
272 | stream, err := session.(*smux.Session).OpenStream()
273 | //session.(*smux.Session).SetDeadline(time.Time{})
274 | if err != nil {
275 | s.log.Printf("%s client session open stream %s fail, err: %s, retrying...", key, serverID, err)
276 | time.Sleep(time.Second * 3)
277 | continue
278 | } else {
279 | s.log.Printf("stream %s -> %s created", serverID, key)
280 | die1 := make(chan bool, 1)
281 | die2 := make(chan bool, 1)
282 | go func() {
283 | io.Copy(stream, inConn)
284 | die1 <- true
285 | }()
286 | go func() {
287 | io.Copy(inConn, stream)
288 | die2 <- true
289 | }()
290 | select {
291 | case <-die1:
292 | case <-die2:
293 | }
294 | stream.Close()
295 | inConn.Close()
296 | s.log.Printf("%s server %s stream released", key, serverID)
297 | break
298 | }
299 | }
300 |
301 | }
302 |
--------------------------------------------------------------------------------
/lib/goproxy/services/mux/mux_client.go:
--------------------------------------------------------------------------------
1 | package mux
2 |
3 | import (
4 | "crypto/tls"
5 | "fmt"
6 | services2 "github.com/yincongcyincong/proxy-web/lib/goproxy/services"
7 | kcpcfg2 "github.com/yincongcyincong/proxy-web/lib/goproxy/services/kcpcfg"
8 | utils2 "github.com/yincongcyincong/proxy-web/lib/goproxy/utils"
9 | "io"
10 | logger "log"
11 | "net"
12 | "time"
13 |
14 | "github.com/golang/snappy"
15 | //"github.com/xtaci/smux"
16 | smux "github.com/hashicorp/yamux"
17 | )
18 |
19 | type MuxClientArgs struct {
20 | Parent *string
21 | ParentType *string
22 | CertFile *string
23 | KeyFile *string
24 | CertBytes []byte
25 | KeyBytes []byte
26 | Key *string
27 | Timeout *int
28 | IsCompress *bool
29 | SessionCount *int
30 | KCP kcpcfg2.KCPConfigArgs
31 | }
32 | type MuxClient struct {
33 | cfg MuxClientArgs
34 | isStop bool
35 | sessions utils2.ConcurrentMap
36 | log *logger.Logger
37 | }
38 |
39 | func NewMuxClient() services2.Service {
40 | return &MuxClient{
41 | cfg: MuxClientArgs{},
42 | isStop: false,
43 | sessions: utils2.NewConcurrentMap(),
44 | }
45 | }
46 |
47 | func (s *MuxClient) InitService() (err error) {
48 | return
49 | }
50 |
51 | func (s *MuxClient) CheckArgs() (err error) {
52 | if *s.cfg.Parent != "" {
53 | s.log.Printf("use tls parent %s", *s.cfg.Parent)
54 | } else {
55 | err = fmt.Errorf("parent required")
56 | return
57 | }
58 | if *s.cfg.CertFile == "" || *s.cfg.KeyFile == "" {
59 | err = fmt.Errorf("cert and key file required")
60 | return
61 | }
62 | if *s.cfg.ParentType == "tls" {
63 | s.cfg.CertBytes, s.cfg.KeyBytes, err = utils2.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
64 | if err != nil {
65 | return
66 | }
67 | }
68 | return
69 | }
70 | func (s *MuxClient) StopService() {
71 | defer func() {
72 | e := recover()
73 | if e != nil {
74 | s.log.Printf("stop client service crashed,%s", e)
75 | } else {
76 | s.log.Printf("service client stopped")
77 | }
78 | }()
79 | s.isStop = true
80 | for _, sess := range s.sessions.Items() {
81 | sess.(*smux.Session).Close()
82 | }
83 | }
84 | func (s *MuxClient) Start(args interface{}, log *logger.Logger) (err error) {
85 | s.log = log
86 | s.cfg = args.(MuxClientArgs)
87 | if err = s.CheckArgs(); err != nil {
88 | return
89 | }
90 | if err = s.InitService(); err != nil {
91 | return
92 | }
93 | s.log.Printf("client started")
94 | count := 1
95 | if *s.cfg.SessionCount > 0 {
96 | count = *s.cfg.SessionCount
97 | }
98 | for i := 1; i <= count; i++ {
99 | key := fmt.Sprintf("worker[%d]", i)
100 | s.log.Printf("session %s started", key)
101 | go func(i int) {
102 | defer func() {
103 | e := recover()
104 | if e != nil {
105 | s.log.Printf("session worker crashed: %s", e)
106 | }
107 | }()
108 | for {
109 | if s.isStop {
110 | return
111 | }
112 | conn, err := s.getParentConn()
113 | if err != nil {
114 | s.log.Printf("connection err: %s, retrying...", err)
115 | time.Sleep(time.Second * 3)
116 | continue
117 | }
118 | conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
119 | _, err = conn.Write(utils2.BuildPacket(CONN_CLIENT, fmt.Sprintf("%s-%d", *s.cfg.Key, i)))
120 | conn.SetDeadline(time.Time{})
121 | if err != nil {
122 | conn.Close()
123 | s.log.Printf("connection err: %s, retrying...", err)
124 | time.Sleep(time.Second * 3)
125 | continue
126 | }
127 | session, err := smux.Server(conn, nil)
128 | if err != nil {
129 | s.log.Printf("session err: %s, retrying...", err)
130 | conn.Close()
131 | time.Sleep(time.Second * 3)
132 | continue
133 | }
134 | if _sess, ok := s.sessions.Get(key); ok {
135 | _sess.(*smux.Session).Close()
136 | }
137 | s.sessions.Set(key, session)
138 | for {
139 | if s.isStop {
140 | return
141 | }
142 | stream, err := session.AcceptStream()
143 | if err != nil {
144 | s.log.Printf("accept stream err: %s, retrying...", err)
145 | session.Close()
146 | time.Sleep(time.Second * 3)
147 | break
148 | }
149 | go func() {
150 | defer func() {
151 | e := recover()
152 | if e != nil {
153 | s.log.Printf("stream handler crashed: %s", e)
154 | }
155 | }()
156 | var ID, clientLocalAddr, serverID string
157 | stream.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
158 | err = utils2.ReadPacketData(stream, &ID, &clientLocalAddr, &serverID)
159 | stream.SetDeadline(time.Time{})
160 | if err != nil {
161 | s.log.Printf("read stream signal err: %s", err)
162 | stream.Close()
163 | return
164 | }
165 | s.log.Printf("worker[%d] signal revecived,server %s stream %s %s", i, serverID, ID, clientLocalAddr)
166 | protocol := clientLocalAddr[:3]
167 | localAddr := clientLocalAddr[4:]
168 | if protocol == "udp" {
169 | s.ServeUDP(stream, localAddr, ID)
170 | } else {
171 | s.ServeConn(stream, localAddr, ID)
172 | }
173 | }()
174 | }
175 | }
176 | }(i)
177 | }
178 | return
179 | }
180 | func (s *MuxClient) Clean() {
181 | s.StopService()
182 | }
183 | func (s *MuxClient) getParentConn() (conn net.Conn, err error) {
184 | if *s.cfg.ParentType == "tls" {
185 | var _conn tls.Conn
186 | _conn, err = utils2.TlsConnectHost(*s.cfg.Parent, *s.cfg.Timeout, s.cfg.CertBytes, s.cfg.KeyBytes, nil)
187 | if err == nil {
188 | conn = net.Conn(&_conn)
189 | }
190 | } else if *s.cfg.ParentType == "kcp" {
191 | conn, err = utils2.ConnectKCPHost(*s.cfg.Parent, s.cfg.KCP)
192 | } else {
193 | conn, err = utils2.ConnectHost(*s.cfg.Parent, *s.cfg.Timeout)
194 | }
195 | return
196 | }
197 | func (s *MuxClient) ServeUDP(inConn *smux.Stream, localAddr, ID string) {
198 |
199 | for {
200 | if s.isStop {
201 | return
202 | }
203 | inConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
204 | srcAddr, body, err := utils2.ReadUDPPacket(inConn)
205 | inConn.SetDeadline(time.Time{})
206 | if err != nil {
207 | s.log.Printf("udp packet revecived fail, err: %s", err)
208 | s.log.Printf("connection %s released", ID)
209 | inConn.Close()
210 | break
211 | } else {
212 | //s.log.Printf("udp packet revecived:%s,%v", srcAddr, body)
213 | go func() {
214 | defer func() {
215 | if e := recover(); e != nil {
216 | s.log.Printf("client processUDPPacket crashed,err: %s", e)
217 | }
218 | }()
219 | s.processUDPPacket(inConn, srcAddr, localAddr, body)
220 | }()
221 |
222 | }
223 |
224 | }
225 | // }
226 | }
227 | func (s *MuxClient) processUDPPacket(inConn *smux.Stream, srcAddr, localAddr string, body []byte) {
228 | dstAddr, err := net.ResolveUDPAddr("udp", localAddr)
229 | if err != nil {
230 | s.log.Printf("can't resolve address: %s", err)
231 | inConn.Close()
232 | return
233 | }
234 | clientSrcAddr := &net.UDPAddr{IP: net.IPv4zero, Port: 0}
235 | conn, err := net.DialUDP("udp", clientSrcAddr, dstAddr)
236 | if err != nil {
237 | s.log.Printf("connect to udp %s fail,ERR:%s", dstAddr.String(), err)
238 | return
239 | }
240 | conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
241 | _, err = conn.Write(body)
242 | conn.SetDeadline(time.Time{})
243 | if err != nil {
244 | s.log.Printf("send udp packet to %s fail,ERR:%s", dstAddr.String(), err)
245 | return
246 | }
247 | //s.log.Printf("send udp packet to %s success", dstAddr.String())
248 | buf := make([]byte, 1024)
249 | conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
250 | length, _, err := conn.ReadFromUDP(buf)
251 | conn.SetDeadline(time.Time{})
252 | if err != nil {
253 | s.log.Printf("read udp response from %s fail ,ERR:%s", dstAddr.String(), err)
254 | return
255 | }
256 | respBody := buf[0:length]
257 | //s.log.Printf("revecived udp packet from %s , %v", dstAddr.String(), respBody)
258 | bs := utils2.UDPPacket(srcAddr, respBody)
259 | (*inConn).SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
260 | _, err = (*inConn).Write(bs)
261 | (*inConn).SetDeadline(time.Time{})
262 | if err != nil {
263 | s.log.Printf("send udp response fail ,ERR:%s", err)
264 | inConn.Close()
265 | return
266 | }
267 | //s.log.Printf("send udp response success ,from:%s ,%d ,%v", dstAddr.String(), len(bs), bs)
268 | }
269 | func (s *MuxClient) ServeConn(inConn *smux.Stream, localAddr, ID string) {
270 | var err error
271 | var outConn net.Conn
272 | i := 0
273 | for {
274 | if s.isStop {
275 | return
276 | }
277 | i++
278 | outConn, err = utils2.ConnectHost(localAddr, *s.cfg.Timeout)
279 | if err == nil || i == 3 {
280 | break
281 | } else {
282 | if i == 3 {
283 | s.log.Printf("connect to %s err: %s, retrying...", localAddr, err)
284 | time.Sleep(2 * time.Second)
285 | continue
286 | }
287 | }
288 | }
289 | if err != nil {
290 | inConn.Close()
291 | utils2.CloseConn(&outConn)
292 | s.log.Printf("build connection error, err: %s", err)
293 | return
294 | }
295 |
296 | s.log.Printf("stream %s created", ID)
297 | if *s.cfg.IsCompress {
298 | die1 := make(chan bool, 1)
299 | die2 := make(chan bool, 1)
300 | go func() {
301 | io.Copy(outConn, snappy.NewReader(inConn))
302 | die1 <- true
303 | }()
304 | go func() {
305 | io.Copy(snappy.NewWriter(inConn), outConn)
306 | die2 <- true
307 | }()
308 | select {
309 | case <-die1:
310 | case <-die2:
311 | }
312 | outConn.Close()
313 | inConn.Close()
314 | s.log.Printf("%s stream %s released", *s.cfg.Key, ID)
315 | } else {
316 | utils2.IoBind(inConn, outConn, func(err interface{}) {
317 | s.log.Printf("stream %s released", ID)
318 | }, s.log)
319 | }
320 | }
321 |
--------------------------------------------------------------------------------
/lib/goproxy/services/service.go:
--------------------------------------------------------------------------------
1 | package services
2 |
3 | import (
4 | "fmt"
5 | logger "log"
6 | "runtime/debug"
7 | )
8 |
9 | type Service interface {
10 | Start(args interface{}, log *logger.Logger) (err error)
11 | Clean()
12 | }
13 | type ServiceItem struct {
14 | S Service
15 | Args interface{}
16 | Name string
17 | Log *logger.Logger
18 | }
19 |
20 | var servicesMap = map[string]*ServiceItem{}
21 |
22 | func Regist(name string, s Service, args interface{}, log *logger.Logger) {
23 | Stop(name)
24 | servicesMap[name] = &ServiceItem{
25 | S: s,
26 | Args: args,
27 | Name: name,
28 | Log: log,
29 | }
30 | }
31 | func GetService(name string) *ServiceItem {
32 | if s, ok := servicesMap[name]; ok && s.S != nil {
33 | return s
34 | }
35 | return nil
36 |
37 | }
38 | func Stop(name string) {
39 | if s, ok := servicesMap[name]; ok && s.S != nil {
40 | s.S.Clean()
41 | }
42 | }
43 | func Run(name string, args interface{}) (service *ServiceItem, err error) {
44 | service, ok := servicesMap[name]
45 | if ok {
46 | defer func() {
47 | e := recover()
48 | if e != nil {
49 | err = fmt.Errorf("%s servcie crashed, ERR: %s\ntrace:%s", name, e, string(debug.Stack()))
50 | }
51 | }()
52 | if args != nil {
53 | err = service.S.Start(args, service.Log)
54 | } else {
55 | err = service.S.Start(service.Args, service.Log)
56 | }
57 | if err != nil {
58 | err = fmt.Errorf("%s servcie fail, ERR: %s", name, err)
59 | }
60 | } else {
61 | err = fmt.Errorf("service %s not found", name)
62 | }
63 | return
64 | }
65 |
--------------------------------------------------------------------------------
/lib/goproxy/services/socks/udp.go:
--------------------------------------------------------------------------------
1 | package socks
2 |
3 | import (
4 | "crypto/md5"
5 | "fmt"
6 | utils2 "github.com/yincongcyincong/proxy-web/lib/goproxy/utils"
7 | goaes2 "github.com/yincongcyincong/proxy-web/lib/goproxy/utils/aes"
8 | socks2 "github.com/yincongcyincong/proxy-web/lib/goproxy/utils/socks"
9 | "net"
10 | "runtime/debug"
11 | "strconv"
12 | "strings"
13 | "time"
14 | )
15 |
16 | func (s *Socks) ParentUDPKey() (key []byte) {
17 | switch *s.cfg.ParentType {
18 | case "tcp":
19 | if *s.cfg.ParentKey != "" {
20 | v := fmt.Sprintf("%x", md5.Sum([]byte(*s.cfg.ParentKey)))
21 | return []byte(v)[:24]
22 | }
23 | case "tls":
24 | return s.cfg.KeyBytes[:24]
25 | case "kcp":
26 | v := fmt.Sprintf("%x", md5.Sum([]byte(*s.cfg.KCP.Key)))
27 | return []byte(v)[:24]
28 | }
29 | return
30 | }
31 | func (s *Socks) LocalUDPKey() (key []byte) {
32 | switch *s.cfg.LocalType {
33 | case "tcp":
34 | if *s.cfg.LocalKey != "" {
35 | v := fmt.Sprintf("%x", md5.Sum([]byte(*s.cfg.LocalKey)))
36 | return []byte(v)[:24]
37 | }
38 | case "tls":
39 | return s.cfg.KeyBytes[:24]
40 | case "kcp":
41 | v := fmt.Sprintf("%x", md5.Sum([]byte(*s.cfg.KCP.Key)))
42 | return []byte(v)[:24]
43 | }
44 | return
45 | }
46 | func (s *Socks) proxyUDP(inConn *net.Conn, methodReq socks2.MethodsRequest, request socks2.Request) {
47 | defer func() {
48 | if e := recover(); e != nil {
49 | s.log.Printf("udp local->out io copy crashed:\n%s\n%s", e, string(debug.Stack()))
50 | }
51 | }()
52 | if *s.cfg.ParentType == "ssh" {
53 | utils2.CloseConn(inConn)
54 | return
55 | }
56 | srcIP, _, _ := net.SplitHostPort((*inConn).RemoteAddr().String())
57 | inconnRemoteAddr := (*inConn).RemoteAddr().String()
58 | localAddr := &net.UDPAddr{IP: net.IPv4zero, Port: 0}
59 | udpListener, err := net.ListenUDP("udp", localAddr)
60 | if err != nil {
61 | (*inConn).Close()
62 | udpListener.Close()
63 | s.log.Printf("udp bind fail , %s", err)
64 | return
65 | }
66 | host, _, _ := net.SplitHostPort((*inConn).LocalAddr().String())
67 | _, port, _ := net.SplitHostPort(udpListener.LocalAddr().String())
68 | if len(*s.cfg.LocalIPS) > 0 {
69 | host = (*s.cfg.LocalIPS)[0]
70 | }
71 | s.log.Printf("proxy udp on %s , for %s", net.JoinHostPort(host, port), inconnRemoteAddr)
72 | request.UDPReply(socks2.REP_SUCCESS, net.JoinHostPort(host, port))
73 | s.userConns.Set(inconnRemoteAddr, inConn)
74 | var (
75 | outUDPConn *net.UDPConn
76 | outconn net.Conn
77 | outconnLocalAddr string
78 | isClosedErr = func(err error) bool {
79 | return err != nil && strings.Contains(err.Error(), "use of closed network connection")
80 | }
81 | destAddr *net.UDPAddr
82 | )
83 | var clean = func(msg, err string) {
84 | raddr := ""
85 | if outUDPConn != nil {
86 | raddr = outUDPConn.RemoteAddr().String()
87 | outUDPConn.Close()
88 | }
89 | if msg != "" {
90 | if raddr != "" {
91 | s.log.Printf("%s , %s , %s -> %s", msg, err, inconnRemoteAddr, raddr)
92 | } else {
93 | s.log.Printf("%s , %s , from : %s", msg, err, inconnRemoteAddr)
94 | }
95 | }
96 | (*inConn).Close()
97 | udpListener.Close()
98 | s.userConns.Remove(inconnRemoteAddr)
99 | if outconn != nil {
100 | outconn.Close()
101 | }
102 | if outconnLocalAddr != "" {
103 | s.userConns.Remove(outconnLocalAddr)
104 | }
105 | }
106 | defer clean("", "")
107 | go func() {
108 | defer func() {
109 | if e := recover(); e != nil {
110 | s.log.Printf("udp related client tcp conn read crashed:\n%s\n%s", e, string(debug.Stack()))
111 | }
112 | }()
113 | buf := make([]byte, 1)
114 | (*inConn).SetReadDeadline(time.Time{})
115 | if _, err := (*inConn).Read(buf); err != nil {
116 | clean("udp related tcp conn disconnected with read", err.Error())
117 | }
118 | }()
119 | go func() {
120 | defer func() {
121 | if e := recover(); e != nil {
122 | s.log.Printf("udp related client tcp conn write crashed:\n%s\n%s", e, string(debug.Stack()))
123 | }
124 | }()
125 | for {
126 | (*inConn).SetWriteDeadline(time.Now().Add(time.Second * 5))
127 | if _, err := (*inConn).Write([]byte{0x00}); err != nil {
128 | clean("udp related tcp conn disconnected with write", err.Error())
129 | return
130 | }
131 | (*inConn).SetWriteDeadline(time.Time{})
132 | time.Sleep(time.Second * 5)
133 | }
134 | }()
135 | useProxy := true
136 | if *s.cfg.Parent != "" {
137 | dstHost, _, _ := net.SplitHostPort(request.Addr())
138 | if utils2.IsIternalIP(dstHost, *s.cfg.Always) {
139 | useProxy = false
140 | } else {
141 | var isInMap bool
142 | useProxy, isInMap, _, _ = s.checker.IsBlocked(request.Addr())
143 | if !isInMap {
144 | s.checker.Add(request.Addr(), s.Resolve(request.Addr()))
145 | }
146 | }
147 | } else {
148 | useProxy = false
149 | }
150 | if useProxy {
151 | //parent proxy
152 | outconn, err := s.getOutConn(nil, nil, "", false)
153 | if err != nil {
154 | clean("connnect fail", fmt.Sprintf("%s", err))
155 | return
156 | }
157 | client := socks2.NewClientConn(&outconn, "udp", request.Addr(), time.Millisecond*time.Duration(*s.cfg.Timeout), nil, nil)
158 | if err = client.Handshake(); err != nil {
159 | clean("handshake fail", fmt.Sprintf("%s", err))
160 | return
161 | }
162 | //outconnRemoteAddr := outconn.RemoteAddr().String()
163 | outconnLocalAddr = outconn.LocalAddr().String()
164 | s.userConns.Set(outconnLocalAddr, &outconn)
165 | go func() {
166 | defer func() {
167 | if e := recover(); e != nil {
168 | s.log.Printf("udp related parent tcp conn read crashed:\n%s\n%s", e, string(debug.Stack()))
169 | }
170 | }()
171 | buf := make([]byte, 1)
172 | outconn.SetReadDeadline(time.Time{})
173 | if _, err := outconn.Read(buf); err != nil {
174 | clean("udp parent tcp conn disconnected", fmt.Sprintf("%s", err))
175 | }
176 | }()
177 | //forward to parent udp
178 | //s.log.Printf("parent udp address %s", client.UDPAddr)
179 | destAddr, _ = net.ResolveUDPAddr("udp", client.UDPAddr)
180 | }
181 | s.log.Printf("use proxy %v : udp %s", useProxy, request.Addr())
182 | //relay
183 | for {
184 | buf := utils2.LeakyBuffer.Get()
185 | defer utils2.LeakyBuffer.Put(buf)
186 | n, srcAddr, err := udpListener.ReadFromUDP(buf)
187 | if err != nil {
188 | s.log.Printf("udp listener read fail, %s", err.Error())
189 | if isClosedErr(err) {
190 | return
191 | }
192 | continue
193 | }
194 | srcIP0, _, _ := net.SplitHostPort(srcAddr.String())
195 | //IP not match drop it
196 | if srcIP != srcIP0 {
197 | continue
198 | }
199 | p := socks2.NewPacketUDP()
200 | //convert data to raw
201 | if len(s.udpLocalKey) > 0 {
202 | var v []byte
203 | v, err = goaes2.Decrypt(s.udpLocalKey, buf[:n])
204 | if err == nil {
205 | err = p.Parse(v)
206 | }
207 | } else {
208 | err = p.Parse(buf[:n])
209 | }
210 | //err = p.Parse(buf[:n])
211 | if err != nil {
212 | s.log.Printf("udp listener parse packet fail, %s", err.Error())
213 | continue
214 | }
215 |
216 | port, _ := strconv.Atoi(p.Port())
217 |
218 | if v, ok := s.udpRelatedPacketConns.Get(srcAddr.String()); !ok {
219 | if destAddr == nil {
220 | destAddr = &net.UDPAddr{IP: net.ParseIP(p.Host()), Port: port}
221 | }
222 | outUDPConn, err = net.DialUDP("udp", localAddr, destAddr)
223 | if err != nil {
224 | s.log.Printf("create out udp conn fail , %s , from : %s", err, srcAddr)
225 | continue
226 | }
227 | s.udpRelatedPacketConns.Set(srcAddr.String(), outUDPConn)
228 | go func() {
229 | defer func() {
230 | if e := recover(); e != nil {
231 | s.log.Printf("udp out->local io copy crashed:\n%s\n%s", e, string(debug.Stack()))
232 | }
233 | }()
234 | defer s.udpRelatedPacketConns.Remove(srcAddr.String())
235 | //out->local io copy
236 | buf := utils2.LeakyBuffer.Get()
237 | defer utils2.LeakyBuffer.Put(buf)
238 | for {
239 | n, err := outUDPConn.Read(buf)
240 | if err != nil {
241 | s.log.Printf("read out udp data fail , %s , from : %s", err, srcAddr)
242 | if isClosedErr(err) {
243 | return
244 | }
245 | continue
246 | }
247 | //var dlen = n
248 | if useProxy {
249 | //forward to local
250 | var v []byte
251 | //convert parent data to raw
252 | if len(s.udpParentKey) > 0 {
253 | v, err = goaes2.Decrypt(s.udpParentKey, buf[:n])
254 | if err != nil {
255 | s.log.Printf("udp outconn parse packet fail, %s", err.Error())
256 | continue
257 | }
258 | } else {
259 | v = buf[:n]
260 | }
261 | //now v is raw, try convert v to local
262 | if len(s.udpLocalKey) > 0 {
263 | v, _ = goaes2.Encrypt(s.udpLocalKey, v)
264 | }
265 | _, err = udpListener.WriteTo(v, srcAddr)
266 | // _, err = udpListener.WriteTo(buf[:n], srcAddr)
267 | } else {
268 | rp := socks2.NewPacketUDP()
269 | rp.Build(destAddr.String(), buf[:n])
270 | v := rp.Bytes()
271 | //dlen = len(v)
272 | //rp.Bytes() v is raw, try convert to local
273 | if len(s.udpLocalKey) > 0 {
274 | v, _ = goaes2.Encrypt(s.udpLocalKey, v)
275 | }
276 | _, err = udpListener.WriteTo(v, srcAddr)
277 | }
278 |
279 | if err != nil {
280 | s.udpRelatedPacketConns.Remove(srcAddr.String())
281 | s.log.Printf("write out data to local fail , %s , from : %s", err, srcAddr)
282 | if isClosedErr(err) {
283 | return
284 | }
285 | continue
286 | } else {
287 | //s.log.Printf("send udp data to local success , len %d, for : %s", dlen, srcAddr)
288 | }
289 | }
290 | }()
291 | } else {
292 | outUDPConn = v.(*net.UDPConn)
293 | }
294 | //local->out io copy
295 | if useProxy {
296 | //forward to parent
297 | //p is raw, now convert it to parent
298 | var v []byte
299 | if len(s.udpParentKey) > 0 {
300 | v, _ = goaes2.Encrypt(s.udpParentKey, p.Bytes())
301 | } else {
302 | v = p.Bytes()
303 | }
304 | _, err = outUDPConn.Write(v)
305 | // _, err = outUDPConn.Write(p.Bytes())
306 | } else {
307 | _, err = outUDPConn.Write(p.Data())
308 | }
309 | if err != nil {
310 | if isClosedErr(err) {
311 | return
312 | }
313 | s.log.Printf("send out udp data fail , %s , from : %s", err, srcAddr)
314 | continue
315 | } else {
316 | //s.log.Printf("send udp data to remote success , len %d, for : %s", len(p.Data()), srcAddr)
317 | }
318 | }
319 |
320 | }
321 |
--------------------------------------------------------------------------------
/lib/goproxy/services/sps/socksudp.go:
--------------------------------------------------------------------------------
1 | package sps
2 |
3 | import (
4 | "crypto/md5"
5 | "fmt"
6 | utils2 "github.com/yincongcyincong/proxy-web/lib/goproxy/utils"
7 | goaes2 "github.com/yincongcyincong/proxy-web/lib/goproxy/utils/aes"
8 | conncrypt2 "github.com/yincongcyincong/proxy-web/lib/goproxy/utils/conncrypt"
9 | socks2 "github.com/yincongcyincong/proxy-web/lib/goproxy/utils/socks"
10 | "net"
11 | "runtime/debug"
12 | "strconv"
13 | "strings"
14 | "time"
15 | )
16 |
17 | func (s *SPS) ParentUDPKey() (key []byte) {
18 | switch *s.cfg.ParentType {
19 | case "tcp":
20 | if *s.cfg.ParentKey != "" {
21 | v := fmt.Sprintf("%x", md5.Sum([]byte(*s.cfg.ParentKey)))
22 | return []byte(v)[:24]
23 | }
24 | case "tls":
25 | return s.cfg.KeyBytes[:24]
26 | case "kcp":
27 | v := fmt.Sprintf("%x", md5.Sum([]byte(*s.cfg.KCP.Key)))
28 | return []byte(v)[:24]
29 | }
30 | return
31 | }
32 | func (s *SPS) LocalUDPKey() (key []byte) {
33 | switch *s.cfg.LocalType {
34 | case "tcp":
35 | if *s.cfg.LocalKey != "" {
36 | v := fmt.Sprintf("%x", md5.Sum([]byte(*s.cfg.LocalKey)))
37 | return []byte(v)[:24]
38 | }
39 | case "tls":
40 | return s.cfg.KeyBytes[:24]
41 | case "kcp":
42 | v := fmt.Sprintf("%x", md5.Sum([]byte(*s.cfg.KCP.Key)))
43 | return []byte(v)[:24]
44 | }
45 | return
46 | }
47 | func (s *SPS) proxyUDP(inConn *net.Conn, serverConn *socks2.ServerConn) {
48 | defer func() {
49 | if e := recover(); e != nil {
50 | s.log.Printf("udp local->out io copy crashed:\n%s\n%s", e, string(debug.Stack()))
51 | }
52 | }()
53 | if *s.cfg.ParentType == "ssh" {
54 | utils2.CloseConn(inConn)
55 | return
56 | }
57 | srcIP, _, _ := net.SplitHostPort((*inConn).RemoteAddr().String())
58 | inconnRemoteAddr := (*inConn).RemoteAddr().String()
59 | localAddr := &net.UDPAddr{IP: net.IPv4zero, Port: 0}
60 | udpListener := serverConn.UDPConnListener
61 | s.log.Printf("proxy udp on %s , for %s", udpListener.LocalAddr(), inconnRemoteAddr)
62 | s.userConns.Set(inconnRemoteAddr, inConn)
63 | var (
64 | outUDPConn *net.UDPConn
65 | outconn net.Conn
66 | outconnLocalAddr string
67 | isClosedErr = func(err error) bool {
68 | return err != nil && strings.Contains(err.Error(), "use of closed network connection")
69 | }
70 | destAddr *net.UDPAddr
71 | )
72 | var clean = func(msg, err string) {
73 | raddr := ""
74 | if outUDPConn != nil {
75 | raddr = outUDPConn.RemoteAddr().String()
76 | outUDPConn.Close()
77 | }
78 | if msg != "" {
79 | if raddr != "" {
80 | s.log.Printf("%s , %s , %s -> %s", msg, err, inconnRemoteAddr, raddr)
81 | } else {
82 | s.log.Printf("%s , %s , from : %s", msg, err, inconnRemoteAddr)
83 | }
84 | }
85 | (*inConn).Close()
86 | udpListener.Close()
87 | s.userConns.Remove(inconnRemoteAddr)
88 | if outconn != nil {
89 | outconn.Close()
90 | }
91 | if outconnLocalAddr != "" {
92 | s.userConns.Remove(outconnLocalAddr)
93 | }
94 | }
95 | defer clean("", "")
96 | go func() {
97 | defer func() {
98 | if e := recover(); e != nil {
99 | s.log.Printf("udp related client tcp conn read crashed:\n%s\n%s", e, string(debug.Stack()))
100 | }
101 | }()
102 | buf := make([]byte, 1)
103 | (*inConn).SetReadDeadline(time.Time{})
104 | if _, err := (*inConn).Read(buf); err != nil {
105 | clean("udp related tcp conn disconnected with read", err.Error())
106 | }
107 | }()
108 | go func() {
109 | defer func() {
110 | if e := recover(); e != nil {
111 | s.log.Printf("udp related client tcp conn write crashed:\n%s\n%s", e, string(debug.Stack()))
112 | }
113 | }()
114 | for {
115 | (*inConn).SetWriteDeadline(time.Now().Add(time.Second * 5))
116 | if _, err := (*inConn).Write([]byte{0x00}); err != nil {
117 | clean("udp related tcp conn disconnected with write", err.Error())
118 | return
119 | }
120 | (*inConn).SetWriteDeadline(time.Time{})
121 | time.Sleep(time.Second * 5)
122 | }
123 | }()
124 | //parent proxy
125 | outconn, err := s.outPool.Get()
126 | //outconn, err := s.GetParentConn(nil, nil, "", false)
127 | if err != nil {
128 | clean("connnect fail", fmt.Sprintf("%s", err))
129 | return
130 | }
131 | if *s.cfg.ParentCompress {
132 | outconn = utils2.NewCompConn(outconn)
133 | }
134 | if *s.cfg.ParentKey != "" {
135 | outconn = conncrypt2.New(outconn, &conncrypt2.Config{
136 | Password: *s.cfg.ParentKey,
137 | })
138 | }
139 |
140 | s.log.Printf("connect %s for udp", serverConn.Target())
141 | //socks client
142 | var client *socks2.ClientConn
143 | auth := serverConn.AuthData()
144 | if *s.cfg.ParentAuth != "" {
145 | a := strings.Split(*s.cfg.ParentAuth, ":")
146 | if len(a) != 2 {
147 | err = fmt.Errorf("parent auth data format error")
148 | return
149 | }
150 | client = socks2.NewClientConn(&outconn, "udp", serverConn.Target(), time.Millisecond*time.Duration(*s.cfg.Timeout), &socks2.Auth{User: a[0], Password: a[1]}, nil)
151 | } else {
152 | if !s.IsBasicAuth() && auth.Password != "" && auth.User != "" {
153 | client = socks2.NewClientConn(&outconn, "udp", serverConn.Target(), time.Millisecond*time.Duration(*s.cfg.Timeout), &auth, nil)
154 | } else {
155 | client = socks2.NewClientConn(&outconn, "udp", serverConn.Target(), time.Millisecond*time.Duration(*s.cfg.Timeout), nil, nil)
156 | }
157 | }
158 |
159 | if err = client.Handshake(); err != nil {
160 | clean("handshake fail", fmt.Sprintf("%s", err))
161 | return
162 | }
163 |
164 | //outconnRemoteAddr := outconn.RemoteAddr().String()
165 | outconnLocalAddr = outconn.LocalAddr().String()
166 | s.userConns.Set(outconnLocalAddr, &outconn)
167 | go func() {
168 | defer func() {
169 | if e := recover(); e != nil {
170 | s.log.Printf("udp related parent tcp conn read crashed:\n%s\n%s", e, string(debug.Stack()))
171 | }
172 | }()
173 | buf := make([]byte, 1)
174 | outconn.SetReadDeadline(time.Time{})
175 | if _, err := outconn.Read(buf); err != nil {
176 | clean("udp parent tcp conn disconnected", fmt.Sprintf("%s", err))
177 | }
178 | }()
179 | //forward to parent udp
180 | //s.log.Printf("parent udp address %s", client.UDPAddr)
181 | destAddr, _ = net.ResolveUDPAddr("udp", client.UDPAddr)
182 | //relay
183 | buf := utils2.LeakyBuffer.Get()
184 | defer utils2.LeakyBuffer.Put(buf)
185 | for {
186 | n, srcAddr, err := udpListener.ReadFromUDP(buf)
187 | if err != nil {
188 | s.log.Printf("udp listener read fail, %s", err.Error())
189 | if isClosedErr(err) {
190 | return
191 | }
192 | continue
193 | }
194 | srcIP0, _, _ := net.SplitHostPort(srcAddr.String())
195 | //IP not match drop it
196 | if srcIP != srcIP0 {
197 | continue
198 | }
199 | p := socks2.NewPacketUDP()
200 | //convert data to raw
201 | if len(s.udpLocalKey) > 0 {
202 | var v []byte
203 | v, err = goaes2.Decrypt(s.udpLocalKey, buf[:n])
204 | if err == nil {
205 | err = p.Parse(v)
206 | }
207 | } else {
208 | err = p.Parse(buf[:n])
209 | }
210 | if err != nil {
211 | s.log.Printf("udp listener parse packet fail, %s", err.Error())
212 | continue
213 | }
214 |
215 | port, _ := strconv.Atoi(p.Port())
216 |
217 | if v, ok := s.udpRelatedPacketConns.Get(srcAddr.String()); !ok {
218 | if destAddr == nil {
219 | destAddr = &net.UDPAddr{IP: net.ParseIP(p.Host()), Port: port}
220 | }
221 | outUDPConn, err = net.DialUDP("udp", localAddr, destAddr)
222 | if err != nil {
223 | s.log.Printf("create out udp conn fail , %s , from : %s", err, srcAddr)
224 | continue
225 | }
226 | s.udpRelatedPacketConns.Set(srcAddr.String(), outUDPConn)
227 | go func() {
228 | defer func() {
229 | if e := recover(); e != nil {
230 | s.log.Printf("udp out->local io copy crashed:\n%s\n%s", e, string(debug.Stack()))
231 | }
232 | }()
233 | defer s.udpRelatedPacketConns.Remove(srcAddr.String())
234 | //out->local io copy
235 | buf := utils2.LeakyBuffer.Get()
236 | defer utils2.LeakyBuffer.Put(buf)
237 | for {
238 | outUDPConn.SetReadDeadline(time.Now().Add(time.Second * 5))
239 | n, err := outUDPConn.Read(buf)
240 | outUDPConn.SetReadDeadline(time.Time{})
241 | if err != nil {
242 | s.log.Printf("read out udp data fail , %s , from : %s", err, srcAddr)
243 | if isClosedErr(err) {
244 | return
245 | }
246 | continue
247 | }
248 | //var dlen = n
249 | //forward to local
250 | var v []byte
251 | //convert parent data to raw
252 | if len(s.udpParentKey) > 0 {
253 | v, err = goaes2.Decrypt(s.udpParentKey, buf[:n])
254 | if err != nil {
255 | s.log.Printf("udp outconn parse packet fail, %s", err.Error())
256 | continue
257 | }
258 | } else {
259 | v = buf[:n]
260 | }
261 | //now v is raw, try convert v to local
262 | if len(s.udpLocalKey) > 0 {
263 | v, _ = goaes2.Encrypt(s.udpLocalKey, v)
264 | }
265 | _, err = udpListener.WriteTo(v, srcAddr)
266 | // _, err = udpListener.WriteTo(buf[:n], srcAddr)
267 |
268 | if err != nil {
269 | s.udpRelatedPacketConns.Remove(srcAddr.String())
270 | s.log.Printf("write out data to local fail , %s , from : %s", err, srcAddr)
271 | if isClosedErr(err) {
272 | return
273 | }
274 | continue
275 | } else {
276 | //s.log.Printf("send udp data to local success , len %d, for : %s", dlen, srcAddr)
277 | }
278 | }
279 | }()
280 | } else {
281 | outUDPConn = v.(*net.UDPConn)
282 | }
283 | //local->out io copy
284 | //forward to parent
285 | //p is raw, now convert it to parent
286 | var v []byte
287 | if len(s.udpParentKey) > 0 {
288 | v, _ = goaes2.Encrypt(s.udpParentKey, p.Bytes())
289 | } else {
290 | v = p.Bytes()
291 | }
292 | _, err = outUDPConn.Write(v)
293 | // _, err = outUDPConn.Write(p.Bytes())
294 | if err != nil {
295 | if isClosedErr(err) {
296 | return
297 | }
298 | s.log.Printf("send out udp data fail , %s , from : %s", err, srcAddr)
299 | continue
300 | } else {
301 | //s.log.Printf("send udp data to remote success , len %d, for : %s", len(p.Data()), srcAddr)
302 | }
303 | }
304 |
305 | }
306 |
--------------------------------------------------------------------------------
/lib/goproxy/services/tcp/tcp.go:
--------------------------------------------------------------------------------
1 | package tcp
2 |
3 | import (
4 | "bufio"
5 | "fmt"
6 | services2 "github.com/yincongcyincong/proxy-web/lib/goproxy/services"
7 | kcpcfg2 "github.com/yincongcyincong/proxy-web/lib/goproxy/services/kcpcfg"
8 | utils2 "github.com/yincongcyincong/proxy-web/lib/goproxy/utils"
9 | "io"
10 | logger "log"
11 | "net"
12 | "runtime/debug"
13 | "time"
14 |
15 | "strconv"
16 | )
17 |
18 | type TCPArgs struct {
19 | Parent *string
20 | CertFile *string
21 | KeyFile *string
22 | CertBytes []byte
23 | KeyBytes []byte
24 | Local *string
25 | ParentType *string
26 | LocalType *string
27 | Timeout *int
28 | CheckParentInterval *int
29 | KCP kcpcfg2.KCPConfigArgs
30 | }
31 |
32 | type TCP struct {
33 | outPool utils2.OutConn
34 | cfg TCPArgs
35 | sc *utils2.ServerChannel
36 | isStop bool
37 | userConns utils2.ConcurrentMap
38 | log *logger.Logger
39 | }
40 |
41 | func NewTCP() services2.Service {
42 | return &TCP{
43 | outPool: utils2.OutConn{},
44 | cfg: TCPArgs{},
45 | isStop: false,
46 | userConns: utils2.NewConcurrentMap(),
47 | }
48 | }
49 | func (s *TCP) CheckArgs() (err error) {
50 | if *s.cfg.Parent == "" {
51 | err = fmt.Errorf("parent required for %s %s", *s.cfg.LocalType, *s.cfg.Local)
52 | return
53 | }
54 | if *s.cfg.ParentType == "" {
55 | err = fmt.Errorf("parent type unkown,use -T ")
56 | return
57 | }
58 | if *s.cfg.ParentType == "tls" || *s.cfg.LocalType == "tls" {
59 | s.cfg.CertBytes, s.cfg.KeyBytes, err = utils2.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
60 | if err != nil {
61 | return
62 | }
63 | }
64 | return
65 | }
66 | func (s *TCP) InitService() (err error) {
67 | s.InitOutConnPool()
68 | return
69 | }
70 | func (s *TCP) StopService() {
71 | defer func() {
72 | e := recover()
73 | if e != nil {
74 | s.log.Printf("stop tcp service crashed,%s", e)
75 | } else {
76 | s.log.Printf("service tcp stopped")
77 | }
78 | }()
79 | s.isStop = true
80 | if s.sc.Listener != nil && *s.sc.Listener != nil {
81 | (*s.sc.Listener).Close()
82 | }
83 | if s.sc.UDPListener != nil {
84 | (*s.sc.UDPListener).Close()
85 | }
86 | for _, c := range s.userConns.Items() {
87 | (*c.(*net.Conn)).Close()
88 | }
89 | }
90 | func (s *TCP) Start(args interface{}, log *logger.Logger) (err error) {
91 | s.log = log
92 | s.cfg = args.(TCPArgs)
93 | if err = s.CheckArgs(); err != nil {
94 | return
95 | }
96 | if err = s.InitService(); err != nil {
97 | return
98 | }
99 | s.log.Printf("use %s parent %s", *s.cfg.ParentType, *s.cfg.Parent)
100 | host, port, _ := net.SplitHostPort(*s.cfg.Local)
101 | p, _ := strconv.Atoi(port)
102 | sc := utils2.NewServerChannel(host, p, s.log)
103 |
104 | if *s.cfg.LocalType == "tcp" {
105 | err = sc.ListenTCP(s.callback)
106 | } else if *s.cfg.LocalType == "tls" {
107 | err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, nil, s.callback)
108 | } else if *s.cfg.LocalType == "kcp" {
109 | err = sc.ListenKCP(s.cfg.KCP, s.callback, s.log)
110 | }
111 | if err != nil {
112 | return
113 | }
114 | s.log.Printf("%s proxy on %s", *s.cfg.LocalType, (*sc.Listener).Addr())
115 | s.sc = &sc
116 | return
117 | }
118 |
119 | func (s *TCP) Clean() {
120 | s.StopService()
121 | }
122 | func (s *TCP) callback(inConn net.Conn) {
123 | defer func() {
124 | if err := recover(); err != nil {
125 | s.log.Printf("%s conn handler crashed with err : %s \nstack: %s", *s.cfg.LocalType, err, string(debug.Stack()))
126 | }
127 | }()
128 | var err error
129 | switch *s.cfg.ParentType {
130 | case "kcp":
131 | fallthrough
132 | case "tcp":
133 | fallthrough
134 | case "tls":
135 | err = s.OutToTCP(&inConn)
136 | case "udp":
137 | err = s.OutToUDP(&inConn)
138 | default:
139 | err = fmt.Errorf("unkown parent type %s", *s.cfg.ParentType)
140 | }
141 | if err != nil {
142 | s.log.Printf("connect to %s parent %s fail, ERR:%s", *s.cfg.ParentType, *s.cfg.Parent, err)
143 | utils2.CloseConn(&inConn)
144 | }
145 | }
146 | func (s *TCP) OutToTCP(inConn *net.Conn) (err error) {
147 | var outConn net.Conn
148 | outConn, err = s.outPool.Get()
149 | if err != nil {
150 | s.log.Printf("connect to %s , err:%s", *s.cfg.Parent, err)
151 | utils2.CloseConn(inConn)
152 | return
153 | }
154 | inAddr := (*inConn).RemoteAddr().String()
155 | //inLocalAddr := (*inConn).LocalAddr().String()
156 | outAddr := outConn.RemoteAddr().String()
157 | //outLocalAddr := outConn.LocalAddr().String()
158 | utils2.IoBind((*inConn), outConn, func(err interface{}) {
159 | s.log.Printf("conn %s - %s released", inAddr, outAddr)
160 | s.userConns.Remove(inAddr)
161 | }, s.log)
162 | s.log.Printf("conn %s - %s connected", inAddr, outAddr)
163 | if c, ok := s.userConns.Get(inAddr); ok {
164 | (*c.(*net.Conn)).Close()
165 | }
166 | s.userConns.Set(inAddr, inConn)
167 | return
168 | }
169 | func (s *TCP) OutToUDP(inConn *net.Conn) (err error) {
170 | s.log.Printf("conn created , remote : %s ", (*inConn).RemoteAddr())
171 | for {
172 | if s.isStop {
173 | (*inConn).Close()
174 | return
175 | }
176 | srcAddr, body, err := utils2.ReadUDPPacket(bufio.NewReader(*inConn))
177 | if err == io.EOF || err == io.ErrUnexpectedEOF {
178 | //s.log.Printf("connection %s released", srcAddr)
179 | utils2.CloseConn(inConn)
180 | break
181 | }
182 | //log.Debugf("udp packet revecived:%s,%v", srcAddr, body)
183 | dstAddr, err := net.ResolveUDPAddr("udp", *s.cfg.Parent)
184 | if err != nil {
185 | s.log.Printf("can't resolve address: %s", err)
186 | utils2.CloseConn(inConn)
187 | break
188 | }
189 | clientSrcAddr := &net.UDPAddr{IP: net.IPv4zero, Port: 0}
190 | conn, err := net.DialUDP("udp", clientSrcAddr, dstAddr)
191 | if err != nil {
192 | s.log.Printf("connect to udp %s fail,ERR:%s", dstAddr.String(), err)
193 | continue
194 | }
195 | conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
196 | _, err = conn.Write(body)
197 | if err != nil {
198 | s.log.Printf("send udp packet to %s fail,ERR:%s", dstAddr.String(), err)
199 | continue
200 | }
201 | //log.Debugf("send udp packet to %s success", dstAddr.String())
202 | buf := make([]byte, 512)
203 | len, _, err := conn.ReadFromUDP(buf)
204 | if err != nil {
205 | s.log.Printf("read udp response from %s fail ,ERR:%s", dstAddr.String(), err)
206 | continue
207 | }
208 | respBody := buf[0:len]
209 | //log.Debugf("revecived udp packet from %s , %v", dstAddr.String(), respBody)
210 | _, err = (*inConn).Write(utils2.UDPPacket(srcAddr, respBody))
211 | if err != nil {
212 | s.log.Printf("send udp response fail ,ERR:%s", err)
213 | utils2.CloseConn(inConn)
214 | break
215 | }
216 | //s.log.Printf("send udp response success ,from:%s", dstAddr.String())
217 | }
218 | return
219 |
220 | }
221 | func (s *TCP) InitOutConnPool() {
222 | if *s.cfg.ParentType == "tls" || *s.cfg.ParentType == "tcp" || *s.cfg.ParentType == "kcp" {
223 | //dur int, isTLS bool, certBytes, keyBytes []byte,
224 | //parent string, timeout int, InitialCap int, MaxCap int
225 | s.outPool = utils2.NewOutConn(
226 | *s.cfg.CheckParentInterval,
227 | *s.cfg.ParentType,
228 | s.cfg.KCP,
229 | s.cfg.CertBytes, s.cfg.KeyBytes, nil,
230 | *s.cfg.Parent,
231 | *s.cfg.Timeout,
232 | )
233 | }
234 | }
235 |
--------------------------------------------------------------------------------
/lib/goproxy/services/tunnel/tunnel_bridge.go:
--------------------------------------------------------------------------------
1 | package tunnel
2 |
3 | import (
4 | "bytes"
5 | "fmt"
6 | services2 "github.com/yincongcyincong/proxy-web/lib/goproxy/services"
7 | utils2 "github.com/yincongcyincong/proxy-web/lib/goproxy/utils"
8 | logger "log"
9 | "net"
10 | "os"
11 | "strconv"
12 | "time"
13 |
14 | //"github.com/xtaci/smux"
15 | smux "github.com/hashicorp/yamux"
16 | )
17 |
18 | const (
19 | CONN_CLIENT_CONTROL = uint8(1)
20 | CONN_SERVER = uint8(4)
21 | CONN_CLIENT = uint8(5)
22 | )
23 |
24 | type TunnelBridgeArgs struct {
25 | Parent *string
26 | CertFile *string
27 | KeyFile *string
28 | CertBytes []byte
29 | KeyBytes []byte
30 | Local *string
31 | Timeout *int
32 | Mux *bool
33 | }
34 | type ServerConn struct {
35 | //ClientLocalAddr string //tcp:2.2.22:333@ID
36 | Conn *net.Conn
37 | }
38 | type TunnelBridge struct {
39 | cfg TunnelBridgeArgs
40 | serverConns utils2.ConcurrentMap
41 | clientControlConns utils2.ConcurrentMap
42 | isStop bool
43 | log *logger.Logger
44 | }
45 |
46 | func NewTunnelBridge() services2.Service {
47 | return &TunnelBridge{
48 | cfg: TunnelBridgeArgs{},
49 | serverConns: utils2.NewConcurrentMap(),
50 | clientControlConns: utils2.NewConcurrentMap(),
51 | isStop: false,
52 | }
53 | }
54 |
55 | func (s *TunnelBridge) InitService() (err error) {
56 | return
57 | }
58 | func (s *TunnelBridge) CheckArgs() (err error) {
59 | if *s.cfg.CertFile == "" || *s.cfg.KeyFile == "" {
60 | err = fmt.Errorf("cert and key file required")
61 | return
62 | }
63 | s.cfg.CertBytes, s.cfg.KeyBytes, err = utils2.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
64 | return
65 | }
66 | func (s *TunnelBridge) StopService() {
67 | defer func() {
68 | e := recover()
69 | if e != nil {
70 | s.log.Printf("stop tbridge service crashed,%s", e)
71 | } else {
72 | s.log.Printf("service tbridge stopped")
73 | }
74 | }()
75 | s.isStop = true
76 | for _, sess := range s.clientControlConns.Items() {
77 | (*sess.(*net.Conn)).Close()
78 | }
79 | for _, sess := range s.serverConns.Items() {
80 | (*sess.(ServerConn).Conn).Close()
81 | }
82 | }
83 | func (s *TunnelBridge) Start(args interface{}, log *logger.Logger) (err error) {
84 | s.log = log
85 | s.cfg = args.(TunnelBridgeArgs)
86 | if err = s.CheckArgs(); err != nil {
87 | return
88 | }
89 | if err = s.InitService(); err != nil {
90 | return
91 | }
92 | host, port, _ := net.SplitHostPort(*s.cfg.Local)
93 | p, _ := strconv.Atoi(port)
94 | sc := utils2.NewServerChannel(host, p, s.log)
95 |
96 | err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, nil, s.callback)
97 | if err != nil {
98 | return
99 | }
100 | s.log.Printf("proxy on tunnel bridge mode %s", (*sc.Listener).Addr())
101 | return
102 | }
103 | func (s *TunnelBridge) Clean() {
104 | s.StopService()
105 | }
106 | func (s *TunnelBridge) callback(inConn net.Conn) {
107 | var err error
108 | //s.log.Printf("connection from %s ", inConn.RemoteAddr())
109 | sess, err := smux.Server(inConn, &smux.Config{
110 | AcceptBacklog: 256,
111 | EnableKeepAlive: true,
112 | KeepAliveInterval: 9 * time.Second,
113 | ConnectionWriteTimeout: 3 * time.Second,
114 | MaxStreamWindowSize: 512 * 1024,
115 | LogOutput: os.Stderr,
116 | })
117 | if err != nil {
118 | s.log.Printf("new mux server conn error,ERR:%s", err)
119 | return
120 | }
121 | inConn, err = sess.AcceptStream()
122 | if err != nil {
123 | s.log.Printf("mux server conn accept error,ERR:%s", err)
124 | return
125 | }
126 |
127 | var buf = make([]byte, 1024)
128 | n, _ := inConn.Read(buf)
129 | reader := bytes.NewReader(buf[:n])
130 | //reader := bufio.NewReader(inConn)
131 |
132 | var connType uint8
133 | err = utils2.ReadPacket(reader, &connType)
134 | if err != nil {
135 | s.log.Printf("read error,ERR:%s", err)
136 | return
137 | }
138 | switch connType {
139 | case CONN_SERVER:
140 | var key, ID, clientLocalAddr, serverID string
141 | err = utils2.ReadPacketData(reader, &key, &ID, &clientLocalAddr, &serverID)
142 | if err != nil {
143 | s.log.Printf("read error,ERR:%s", err)
144 | return
145 | }
146 | packet := utils2.BuildPacketData(ID, clientLocalAddr, serverID)
147 | s.log.Printf("server connection, key: %s , id: %s %s %s", key, ID, clientLocalAddr, serverID)
148 |
149 | //addr := clientLocalAddr + "@" + ID
150 | s.serverConns.Set(ID, ServerConn{
151 | Conn: &inConn,
152 | })
153 | for {
154 | if s.isStop {
155 | return
156 | }
157 | item, ok := s.clientControlConns.Get(key)
158 | if !ok {
159 | s.log.Printf("client %s control conn not exists", key)
160 | time.Sleep(time.Second * 3)
161 | continue
162 | }
163 | (*item.(*net.Conn)).SetWriteDeadline(time.Now().Add(time.Second * 3))
164 | _, err := (*item.(*net.Conn)).Write(packet)
165 | (*item.(*net.Conn)).SetWriteDeadline(time.Time{})
166 | if err != nil {
167 | s.log.Printf("%s client control conn write signal fail, err: %s, retrying...", key, err)
168 | time.Sleep(time.Second * 3)
169 | continue
170 | } else {
171 | // s.cmServer.Add(serverID, ID, &inConn)
172 | break
173 | }
174 | }
175 | case CONN_CLIENT:
176 | var key, ID, serverID string
177 | err = utils2.ReadPacketData(reader, &key, &ID, &serverID)
178 | if err != nil {
179 | s.log.Printf("read error,ERR:%s", err)
180 | return
181 | }
182 | s.log.Printf("client connection , key: %s , id: %s, server id:%s", key, ID, serverID)
183 |
184 | serverConnItem, ok := s.serverConns.Get(ID)
185 | if !ok {
186 | inConn.Close()
187 | s.log.Printf("server conn %s exists", ID)
188 | return
189 | }
190 | serverConn := serverConnItem.(ServerConn).Conn
191 | utils2.IoBind(*serverConn, inConn, func(err interface{}) {
192 | s.serverConns.Remove(ID)
193 | // s.cmClient.RemoveOne(key, ID)
194 | // s.cmServer.RemoveOne(serverID, ID)
195 | s.log.Printf("conn %s released", ID)
196 | }, s.log)
197 | // s.cmClient.Add(key, ID, &inConn)
198 | s.log.Printf("conn %s created", ID)
199 |
200 | case CONN_CLIENT_CONTROL:
201 | var key string
202 | err = utils2.ReadPacketData(reader, &key)
203 | if err != nil {
204 | s.log.Printf("read error,ERR:%s", err)
205 | return
206 | }
207 | s.log.Printf("client control connection, key: %s", key)
208 | if s.clientControlConns.Has(key) {
209 | item, _ := s.clientControlConns.Get(key)
210 | (*item.(*net.Conn)).Close()
211 | }
212 | s.clientControlConns.Set(key, &inConn)
213 | s.log.Printf("set client %s control conn", key)
214 | }
215 | }
216 |
--------------------------------------------------------------------------------
/lib/goproxy/services/tunnel/tunnel_client.go:
--------------------------------------------------------------------------------
1 | package tunnel
2 |
3 | import (
4 | "crypto/tls"
5 | "fmt"
6 | services2 "github.com/yincongcyincong/proxy-web/lib/goproxy/services"
7 | utils2 "github.com/yincongcyincong/proxy-web/lib/goproxy/utils"
8 | "io"
9 | logger "log"
10 | "net"
11 | "os"
12 | "time"
13 |
14 | //"github.com/xtaci/smux"
15 | smux "github.com/hashicorp/yamux"
16 | )
17 |
18 | const (
19 | CONN_SERVER_MUX = uint8(6)
20 | CONN_CLIENT_MUX = uint8(7)
21 | )
22 |
23 | type TunnelClientArgs struct {
24 | Parent *string
25 | CertFile *string
26 | KeyFile *string
27 | CertBytes []byte
28 | KeyBytes []byte
29 | Key *string
30 | Timeout *int
31 | Mux *bool
32 | }
33 | type TunnelClient struct {
34 | cfg TunnelClientArgs
35 | ctrlConn net.Conn
36 | isStop bool
37 | userConns utils2.ConcurrentMap
38 | log *logger.Logger
39 | }
40 |
41 | func NewTunnelClient() services2.Service {
42 | return &TunnelClient{
43 | cfg: TunnelClientArgs{},
44 | userConns: utils2.NewConcurrentMap(),
45 | isStop: false,
46 | }
47 | }
48 |
49 | func (s *TunnelClient) InitService() (err error) {
50 | return
51 | }
52 |
53 | func (s *TunnelClient) CheckArgs() (err error) {
54 | if *s.cfg.Parent != "" {
55 | s.log.Printf("use tls parent %s", *s.cfg.Parent)
56 | } else {
57 | err = fmt.Errorf("parent required")
58 | return
59 | }
60 | if *s.cfg.CertFile == "" || *s.cfg.KeyFile == "" {
61 | err = fmt.Errorf("cert and key file required")
62 | return
63 | }
64 | s.cfg.CertBytes, s.cfg.KeyBytes, err = utils2.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
65 | return
66 | }
67 | func (s *TunnelClient) StopService() {
68 | defer func() {
69 | e := recover()
70 | if e != nil {
71 | s.log.Printf("stop tclient service crashed,%s", e)
72 | } else {
73 | s.log.Printf("service tclient stopped")
74 | }
75 | }()
76 | s.isStop = true
77 | if s.ctrlConn != nil {
78 | s.ctrlConn.Close()
79 | }
80 | for _, c := range s.userConns.Items() {
81 | (*c.(*net.Conn)).Close()
82 | }
83 | }
84 | func (s *TunnelClient) Start(args interface{}, log *logger.Logger) (err error) {
85 | s.log = log
86 | s.cfg = args.(TunnelClientArgs)
87 | if err = s.CheckArgs(); err != nil {
88 | return
89 | }
90 | if err = s.InitService(); err != nil {
91 | return
92 | }
93 | s.log.Printf("proxy on tunnel client mode")
94 |
95 | for {
96 | if s.isStop {
97 | return
98 | }
99 | if s.ctrlConn != nil {
100 | s.ctrlConn.Close()
101 | }
102 |
103 | s.ctrlConn, err = s.GetInConn(CONN_CLIENT_CONTROL, *s.cfg.Key)
104 | if err != nil {
105 | s.log.Printf("control connection err: %s, retrying...", err)
106 | time.Sleep(time.Second * 3)
107 | if s.ctrlConn != nil {
108 | s.ctrlConn.Close()
109 | }
110 | continue
111 | }
112 | for {
113 | if s.isStop {
114 | return
115 | }
116 | var ID, clientLocalAddr, serverID string
117 | err = utils2.ReadPacketData(s.ctrlConn, &ID, &clientLocalAddr, &serverID)
118 | if err != nil {
119 | if s.ctrlConn != nil {
120 | s.ctrlConn.Close()
121 | }
122 | s.log.Printf("read connection signal err: %s, retrying...", err)
123 | break
124 | }
125 | s.log.Printf("signal revecived:%s %s %s", serverID, ID, clientLocalAddr)
126 | protocol := clientLocalAddr[:3]
127 | localAddr := clientLocalAddr[4:]
128 | if protocol == "udp" {
129 | go s.ServeUDP(localAddr, ID, serverID)
130 | } else {
131 | go s.ServeConn(localAddr, ID, serverID)
132 | }
133 | }
134 | }
135 | }
136 | func (s *TunnelClient) Clean() {
137 | s.StopService()
138 | }
139 | func (s *TunnelClient) GetInConn(typ uint8, data ...string) (outConn net.Conn, err error) {
140 | outConn, err = s.GetConn()
141 | if err != nil {
142 | err = fmt.Errorf("connection err: %s", err)
143 | return
144 | }
145 | _, err = outConn.Write(utils2.BuildPacket(typ, data...))
146 | if err != nil {
147 | err = fmt.Errorf("write connection data err: %s ,retrying...", err)
148 | utils2.CloseConn(&outConn)
149 | return
150 | }
151 | return
152 | }
153 | func (s *TunnelClient) GetConn() (conn net.Conn, err error) {
154 | var _conn tls.Conn
155 | _conn, err = utils2.TlsConnectHost(*s.cfg.Parent, *s.cfg.Timeout, s.cfg.CertBytes, s.cfg.KeyBytes, nil)
156 | if err == nil {
157 | conn = net.Conn(&_conn)
158 | c, e := smux.Client(conn, &smux.Config{
159 | AcceptBacklog: 256,
160 | EnableKeepAlive: true,
161 | KeepAliveInterval: 9 * time.Second,
162 | ConnectionWriteTimeout: 3 * time.Second,
163 | MaxStreamWindowSize: 512 * 1024,
164 | LogOutput: os.Stderr,
165 | })
166 | if e != nil {
167 | s.log.Printf("new mux client conn error,ERR:%s", e)
168 | err = e
169 | return
170 | }
171 | conn, e = c.OpenStream()
172 | if e != nil {
173 | s.log.Printf("mux client conn open stream error,ERR:%s", e)
174 | err = e
175 | return
176 | }
177 | }
178 | return
179 | }
180 | func (s *TunnelClient) ServeUDP(localAddr, ID, serverID string) {
181 | var inConn net.Conn
182 | var err error
183 | // for {
184 | for {
185 | if s.isStop {
186 | if inConn != nil {
187 | inConn.Close()
188 | }
189 | return
190 | }
191 | // s.cm.RemoveOne(*s.cfg.Key, ID)
192 | inConn, err = s.GetInConn(CONN_CLIENT, *s.cfg.Key, ID, serverID)
193 | if err != nil {
194 | utils2.CloseConn(&inConn)
195 | s.log.Printf("connection err: %s, retrying...", err)
196 | time.Sleep(time.Second * 3)
197 | continue
198 | } else {
199 | break
200 | }
201 | }
202 | // s.cm.Add(*s.cfg.Key, ID, &inConn)
203 | s.log.Printf("conn %s created", ID)
204 |
205 | for {
206 | if s.isStop {
207 | return
208 | }
209 | srcAddr, body, err := utils2.ReadUDPPacket(inConn)
210 | if err == io.EOF || err == io.ErrUnexpectedEOF {
211 | s.log.Printf("connection %s released", ID)
212 | utils2.CloseConn(&inConn)
213 | break
214 | } else if err != nil {
215 | s.log.Printf("udp packet revecived fail, err: %s", err)
216 | } else {
217 | //s.log.Printf("udp packet revecived:%s,%v", srcAddr, body)
218 | go s.processUDPPacket(&inConn, srcAddr, localAddr, body)
219 | }
220 |
221 | }
222 | // }
223 | }
224 | func (s *TunnelClient) processUDPPacket(inConn *net.Conn, srcAddr, localAddr string, body []byte) {
225 | dstAddr, err := net.ResolveUDPAddr("udp", localAddr)
226 | if err != nil {
227 | s.log.Printf("can't resolve address: %s", err)
228 | utils2.CloseConn(inConn)
229 | return
230 | }
231 | clientSrcAddr := &net.UDPAddr{IP: net.IPv4zero, Port: 0}
232 | conn, err := net.DialUDP("udp", clientSrcAddr, dstAddr)
233 | if err != nil {
234 | s.log.Printf("connect to udp %s fail,ERR:%s", dstAddr.String(), err)
235 | return
236 | }
237 | conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
238 | _, err = conn.Write(body)
239 | if err != nil {
240 | s.log.Printf("send udp packet to %s fail,ERR:%s", dstAddr.String(), err)
241 | return
242 | }
243 | //s.log.Printf("send udp packet to %s success", dstAddr.String())
244 | buf := make([]byte, 1024)
245 | length, _, err := conn.ReadFromUDP(buf)
246 | if err != nil {
247 | s.log.Printf("read udp response from %s fail ,ERR:%s", dstAddr.String(), err)
248 | return
249 | }
250 | respBody := buf[0:length]
251 | //s.log.Printf("revecived udp packet from %s , %v", dstAddr.String(), respBody)
252 | bs := utils2.UDPPacket(srcAddr, respBody)
253 | _, err = (*inConn).Write(bs)
254 | if err != nil {
255 | s.log.Printf("send udp response fail ,ERR:%s", err)
256 | utils2.CloseConn(inConn)
257 | return
258 | }
259 | //s.log.Printf("send udp response success ,from:%s ,%d ,%v", dstAddr.String(), len(bs), bs)
260 | }
261 | func (s *TunnelClient) ServeConn(localAddr, ID, serverID string) {
262 | var inConn, outConn net.Conn
263 | var err error
264 | for {
265 | if s.isStop {
266 | return
267 | }
268 | inConn, err = s.GetInConn(CONN_CLIENT, *s.cfg.Key, ID, serverID)
269 | if err != nil {
270 | utils2.CloseConn(&inConn)
271 | s.log.Printf("connection err: %s, retrying...", err)
272 | time.Sleep(time.Second * 3)
273 | continue
274 | } else {
275 | break
276 | }
277 | }
278 |
279 | i := 0
280 | for {
281 | if s.isStop {
282 | return
283 | }
284 | i++
285 | outConn, err = utils2.ConnectHost(localAddr, *s.cfg.Timeout)
286 | if err == nil || i == 3 {
287 | break
288 | } else {
289 | if i == 3 {
290 | s.log.Printf("connect to %s err: %s, retrying...", localAddr, err)
291 | time.Sleep(2 * time.Second)
292 | continue
293 | }
294 | }
295 | }
296 | if err != nil {
297 | utils2.CloseConn(&inConn)
298 | utils2.CloseConn(&outConn)
299 | s.log.Printf("build connection error, err: %s", err)
300 | return
301 | }
302 | inAddr := inConn.RemoteAddr().String()
303 | utils2.IoBind(inConn, outConn, func(err interface{}) {
304 | s.log.Printf("conn %s released", ID)
305 | s.userConns.Remove(inAddr)
306 | }, s.log)
307 | if c, ok := s.userConns.Get(inAddr); ok {
308 | (*c.(*net.Conn)).Close()
309 | }
310 | s.userConns.Set(inAddr, &inConn)
311 | s.log.Printf("conn %s created", ID)
312 | }
313 |
--------------------------------------------------------------------------------
/lib/goproxy/services/udp/udp.go:
--------------------------------------------------------------------------------
1 | package udp
2 |
3 | import (
4 | "bufio"
5 | "fmt"
6 | services2 "github.com/yincongcyincong/proxy-web/lib/goproxy/services"
7 | kcpcfg2 "github.com/yincongcyincong/proxy-web/lib/goproxy/services/kcpcfg"
8 | utils2 "github.com/yincongcyincong/proxy-web/lib/goproxy/utils"
9 | "hash/crc32"
10 | "io"
11 | logger "log"
12 | "net"
13 | "runtime/debug"
14 | "strconv"
15 | "strings"
16 | "time"
17 | )
18 |
19 | type UDPArgs struct {
20 | Parent *string
21 | CertFile *string
22 | KeyFile *string
23 | CertBytes []byte
24 | KeyBytes []byte
25 | Local *string
26 | ParentType *string
27 | Timeout *int
28 | CheckParentInterval *int
29 | }
30 | type UDP struct {
31 | p utils2.ConcurrentMap
32 | outPool utils2.OutConn
33 | cfg UDPArgs
34 | sc *utils2.ServerChannel
35 | isStop bool
36 | log *logger.Logger
37 | }
38 |
39 | func NewUDP() services2.Service {
40 | return &UDP{
41 | outPool: utils2.OutConn{},
42 | p: utils2.NewConcurrentMap(),
43 | isStop: false,
44 | }
45 | }
46 | func (s *UDP) CheckArgs() (err error) {
47 | if *s.cfg.Parent == "" {
48 | err = fmt.Errorf("parent required for udp %s", *s.cfg.Local)
49 | return
50 | }
51 | if *s.cfg.ParentType == "" {
52 | err = fmt.Errorf("parent type unkown,use -T ")
53 | return
54 | }
55 | if *s.cfg.ParentType == "tls" {
56 | s.cfg.CertBytes, s.cfg.KeyBytes, err = utils2.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
57 | if err != nil {
58 | return
59 | }
60 | }
61 | return
62 | }
63 | func (s *UDP) InitService() (err error) {
64 | if *s.cfg.ParentType != "udp" {
65 | s.InitOutConnPool()
66 | }
67 | return
68 | }
69 | func (s *UDP) StopService() {
70 | defer func() {
71 | e := recover()
72 | if e != nil {
73 | s.log.Printf("stop udp service crashed,%s", e)
74 | } else {
75 | s.log.Printf("service udp stopped")
76 | }
77 | }()
78 | s.isStop = true
79 | if s.sc.Listener != nil && *s.sc.Listener != nil {
80 | (*s.sc.Listener).Close()
81 | }
82 | if s.sc.UDPListener != nil {
83 | (*s.sc.UDPListener).Close()
84 | }
85 | }
86 | func (s *UDP) Start(args interface{}, log *logger.Logger) (err error) {
87 | s.log = log
88 | s.cfg = args.(UDPArgs)
89 | if err = s.CheckArgs(); err != nil {
90 | return
91 | }
92 | s.log.Printf("use %s parent %s", *s.cfg.ParentType, *s.cfg.Parent)
93 | if err = s.InitService(); err != nil {
94 | return
95 | }
96 | host, port, _ := net.SplitHostPort(*s.cfg.Local)
97 | p, _ := strconv.Atoi(port)
98 | sc := utils2.NewServerChannel(host, p, s.log)
99 | s.sc = &sc
100 | err = sc.ListenUDP(s.callback)
101 | if err != nil {
102 | return
103 | }
104 | s.log.Printf("udp proxy on %s", (*sc.UDPListener).LocalAddr())
105 | return
106 | }
107 |
108 | func (s *UDP) Clean() {
109 | s.StopService()
110 | }
111 | func (s *UDP) callback(packet []byte, localAddr, srcAddr *net.UDPAddr) {
112 | defer func() {
113 | if err := recover(); err != nil {
114 | s.log.Printf("udp conn handler crashed with err : %s \nstack: %s", err, string(debug.Stack()))
115 | }
116 | }()
117 | var err error
118 | switch *s.cfg.ParentType {
119 | case "tcp":
120 | fallthrough
121 | case "tls":
122 | err = s.OutToTCP(packet, localAddr, srcAddr)
123 | case "udp":
124 | err = s.OutToUDP(packet, localAddr, srcAddr)
125 | default:
126 | err = fmt.Errorf("unkown parent type %s", *s.cfg.ParentType)
127 | }
128 | if err != nil {
129 | s.log.Printf("connect to %s parent %s fail, ERR:%s", *s.cfg.ParentType, *s.cfg.Parent, err)
130 | }
131 | }
132 | func (s *UDP) GetConn(connKey string) (conn net.Conn, isNew bool, err error) {
133 | isNew = !s.p.Has(connKey)
134 | var _conn interface{}
135 | if isNew {
136 | _conn, err = s.outPool.Get()
137 | if err != nil {
138 | return nil, false, err
139 | }
140 | s.p.Set(connKey, _conn)
141 | } else {
142 | _conn, _ = s.p.Get(connKey)
143 | }
144 | conn = _conn.(net.Conn)
145 | return
146 | }
147 | func (s *UDP) OutToTCP(packet []byte, localAddr, srcAddr *net.UDPAddr) (err error) {
148 | numLocal := crc32.ChecksumIEEE([]byte(localAddr.String()))
149 | numSrc := crc32.ChecksumIEEE([]byte(srcAddr.String()))
150 | mod := uint32(10)
151 | if mod == 0 {
152 | mod = 10
153 | }
154 | connKey := uint64((numLocal/10)*10 + numSrc%mod)
155 | conn, isNew, err := s.GetConn(fmt.Sprintf("%d", connKey))
156 | if err != nil {
157 | s.log.Printf("upd get conn to %s parent %s fail, ERR:%s", *s.cfg.ParentType, *s.cfg.Parent, err)
158 | return
159 | }
160 | if isNew {
161 | go func() {
162 | defer func() {
163 | if err := recover(); err != nil {
164 | s.log.Printf("udp conn handler out to tcp crashed with err : %s \nstack: %s", err, string(debug.Stack()))
165 | }
166 | }()
167 | s.log.Printf("conn %d created , local: %s", connKey, srcAddr.String())
168 | for {
169 | if s.isStop {
170 | conn.Close()
171 | return
172 | }
173 | srcAddrFromConn, body, err := utils2.ReadUDPPacket(bufio.NewReader(conn))
174 | if err == io.EOF || err == io.ErrUnexpectedEOF {
175 | //s.log.Printf("connection %d released", connKey)
176 | s.p.Remove(fmt.Sprintf("%d", connKey))
177 | break
178 | }
179 | if err != nil {
180 | s.log.Printf("parse revecived udp packet fail, err: %s", err)
181 | continue
182 | }
183 | //s.log.Printf("udp packet revecived over parent , local:%s", srcAddrFromConn)
184 | _srcAddr := strings.Split(srcAddrFromConn, ":")
185 | if len(_srcAddr) != 2 {
186 | s.log.Printf("parse revecived udp packet fail, addr error : %s", srcAddrFromConn)
187 | continue
188 | }
189 | port, _ := strconv.Atoi(_srcAddr[1])
190 | dstAddr := &net.UDPAddr{IP: net.ParseIP(_srcAddr[0]), Port: port}
191 | _, err = s.sc.UDPListener.WriteToUDP(body, dstAddr)
192 | if err != nil {
193 | s.log.Printf("udp response to local %s fail,ERR:%s", srcAddr, err)
194 | continue
195 | }
196 | //s.log.Printf("udp response to local %s success", srcAddr)
197 | }
198 | }()
199 | }
200 | //s.log.Printf("select conn %d , local: %s", connKey, srcAddr.String())
201 | writer := bufio.NewWriter(conn)
202 | //fmt.Println(conn, writer)
203 | writer.Write(utils2.UDPPacket(srcAddr.String(), packet))
204 | err = writer.Flush()
205 | if err != nil {
206 | s.log.Printf("write udp packet to %s fail ,flush err:%s", *s.cfg.Parent, err)
207 | return
208 | }
209 | //s.log.Printf("write packet %v", packet)
210 | return
211 | }
212 | func (s *UDP) OutToUDP(packet []byte, localAddr, srcAddr *net.UDPAddr) (err error) {
213 | //s.log.Printf("udp packet revecived:%s,%v", srcAddr, packet)
214 | dstAddr, err := net.ResolveUDPAddr("udp", *s.cfg.Parent)
215 | if err != nil {
216 | s.log.Printf("resolve udp addr %s fail fail,ERR:%s", dstAddr.String(), err)
217 | return
218 | }
219 | clientSrcAddr := &net.UDPAddr{IP: net.IPv4zero, Port: 0}
220 | conn, err := net.DialUDP("udp", clientSrcAddr, dstAddr)
221 | if err != nil {
222 | s.log.Printf("connect to udp %s fail,ERR:%s", dstAddr.String(), err)
223 | return
224 | }
225 | conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
226 | _, err = conn.Write(packet)
227 | if err != nil {
228 | s.log.Printf("send udp packet to %s fail,ERR:%s", dstAddr.String(), err)
229 | return
230 | }
231 | //s.log.Printf("send udp packet to %s success", dstAddr.String())
232 | buf := make([]byte, 512)
233 | len, _, err := conn.ReadFromUDP(buf)
234 | if err != nil {
235 | s.log.Printf("read udp response from %s fail ,ERR:%s", dstAddr.String(), err)
236 | return
237 | }
238 | //s.log.Printf("revecived udp packet from %s , %v", dstAddr.String(), respBody)
239 | _, err = s.sc.UDPListener.WriteToUDP(buf[0:len], srcAddr)
240 | if err != nil {
241 | s.log.Printf("send udp response to cluster fail ,ERR:%s", err)
242 | return
243 | }
244 | //s.log.Printf("send udp response to cluster success ,from:%s", dstAddr.String())
245 | return
246 | }
247 | func (s *UDP) InitOutConnPool() {
248 | if *s.cfg.ParentType == "tls" || *s.cfg.ParentType == "tcp" {
249 | //dur int, isTLS bool, certBytes, keyBytes []byte,
250 | //parent string, timeout int, InitialCap int, MaxCap int
251 | s.outPool = utils2.NewOutConn(
252 | *s.cfg.CheckParentInterval,
253 | *s.cfg.ParentType,
254 | kcpcfg2.KCPConfigArgs{},
255 | s.cfg.CertBytes, s.cfg.KeyBytes, nil,
256 | *s.cfg.Parent,
257 | *s.cfg.Timeout,
258 | )
259 | }
260 | }
261 |
--------------------------------------------------------------------------------
/lib/goproxy/utils/aes/aes.go:
--------------------------------------------------------------------------------
1 | // Playbook - http://play.golang.org/p/3wFl4lacjX
2 |
3 | package goaes
4 |
5 | import (
6 | "bytes"
7 | "crypto/aes"
8 | "crypto/cipher"
9 | "crypto/rand"
10 | "errors"
11 | "io"
12 | "strings"
13 | )
14 |
15 | func addBase64Padding(value string) string {
16 | m := len(value) % 4
17 | if m != 0 {
18 | value += strings.Repeat("=", 4-m)
19 | }
20 |
21 | return value
22 | }
23 |
24 | func removeBase64Padding(value string) string {
25 | return strings.Replace(value, "=", "", -1)
26 | }
27 |
28 | func Pad(src []byte) []byte {
29 | padding := aes.BlockSize - len(src)%aes.BlockSize
30 | padtext := bytes.Repeat([]byte{byte(padding)}, padding)
31 | return append(src, padtext...)
32 | }
33 |
34 | func Unpad(src []byte) ([]byte, error) {
35 | length := len(src)
36 | unpadding := int(src[length-1])
37 |
38 | if unpadding > length {
39 | return nil, errors.New("unpad error. This could happen when incorrect encryption key is used")
40 | }
41 |
42 | return src[:(length - unpadding)], nil
43 | }
44 |
45 | func Encrypt(key []byte, text []byte) ([]byte, error) {
46 | block, err := aes.NewCipher(key)
47 | if err != nil {
48 | return nil, err
49 | }
50 |
51 | msg := Pad(text)
52 | ciphertext := make([]byte, aes.BlockSize+len(msg))
53 | iv := ciphertext[:aes.BlockSize]
54 | if _, err := io.ReadFull(rand.Reader, iv); err != nil {
55 | return nil, err
56 | }
57 |
58 | cfb := cipher.NewCFBEncrypter(block, iv)
59 | cfb.XORKeyStream(ciphertext[aes.BlockSize:], []byte(msg))
60 |
61 | return ciphertext, nil
62 | }
63 |
64 | func Decrypt(key []byte, text []byte) ([]byte, error) {
65 | block, err := aes.NewCipher(key)
66 | if err != nil {
67 | return nil, err
68 | }
69 | if (len(text) % aes.BlockSize) != 0 {
70 | return nil, errors.New("blocksize must be multipe of decoded message length")
71 | }
72 | iv := text[:aes.BlockSize]
73 | msg := text[aes.BlockSize:]
74 |
75 | cfb := cipher.NewCFBDecrypter(block, iv)
76 | cfb.XORKeyStream(msg, msg)
77 |
78 | unpadMsg, err := Unpad(msg)
79 | if err != nil {
80 | return nil, err
81 | }
82 |
83 | return unpadMsg, nil
84 | }
85 |
--------------------------------------------------------------------------------
/lib/goproxy/utils/conncrypt/conncrypt.go:
--------------------------------------------------------------------------------
1 | package conncrypt
2 |
3 | import (
4 | "crypto/aes"
5 | "crypto/cipher"
6 | "crypto/sha256"
7 | "hash"
8 | "io"
9 | "net"
10 |
11 | "golang.org/x/crypto/pbkdf2"
12 | )
13 |
14 | //Confg defaults
15 | const DefaultIterations = 1024
16 | const DefaultKeySize = 24 //256bits
17 | var DefaultHashFunc = sha256.New
18 | var DefaultSalt = []byte(`
19 | (;QUHj.BQ?RXzYSO]ifkXp/G!kFmWyXyEV6Nt!d|@bo+N$L9+SOd,6acYKY_ec+(x"R";\'4&fTAVu92GVA-wxBptOTM^2,iP5%)wnhW
21 | hwk=]Snsgymt!3gbP2pe=J//}1a?lp9ej=&TB!C_V(cT2?z8wyoL_-13fd[]
22 | `) //salt must be predefined in order to derive the same key
23 |
24 | //Config stores the PBKDF2 key generation parameters
25 | type Config struct {
26 | Password string
27 | Salt []byte
28 | Iterations int
29 | KeySize int
30 | HashFunc func() hash.Hash
31 | }
32 |
33 | //New creates an AES encrypted net.Conn by generating
34 | //a key using PBKDF2 with the provided configuration
35 | func New(conn net.Conn, c *Config) net.Conn {
36 | //set defaults
37 | if len(c.Salt) == 0 {
38 | c.Salt = DefaultSalt
39 | }
40 | if c.Iterations == 0 {
41 | c.Iterations = DefaultIterations
42 | }
43 | if c.KeySize != 16 && c.KeySize != 24 && c.KeySize != 32 {
44 | c.KeySize = DefaultKeySize
45 | }
46 | if c.HashFunc == nil {
47 | c.HashFunc = DefaultHashFunc
48 | }
49 |
50 | //generate key
51 | key := pbkdf2.Key([]byte(c.Password), c.Salt, c.Iterations, c.KeySize, c.HashFunc)
52 |
53 | // could use scrypt, but it's a bit slow...
54 | // dk, err := scrypt.Key([]byte(c.Password), c.Salt, 16384, 8, 1, 32)
55 |
56 | //key will be always be the correct size so this will never error
57 | conn, _ = NewFromKey(conn, key)
58 | return conn
59 | }
60 |
61 | //NewFromKey creates an AES encrypted net.Conn using the provided key
62 | func NewFromKey(conn net.Conn, key []byte) (net.Conn, error) {
63 | block, err := aes.NewCipher([]byte(key))
64 | if err != nil {
65 | return nil, err
66 | }
67 | //hash(key) -> read IV
68 | riv := DefaultHashFunc().Sum(key)
69 | rstream := cipher.NewCFBDecrypter(block, riv[:aes.BlockSize])
70 | reader := &cipher.StreamReader{S: rstream, R: conn}
71 | //hash(read IV) -> write IV
72 | wiv := DefaultHashFunc().Sum(riv)
73 | wstream := cipher.NewCFBEncrypter(block, wiv[:aes.BlockSize])
74 | writer := &cipher.StreamWriter{S: wstream, W: conn}
75 |
76 | return &cryptoConn{
77 | Conn: conn,
78 | r: reader,
79 | w: writer,
80 | }, nil
81 | }
82 |
83 | type cryptoConn struct {
84 | net.Conn
85 | r io.Reader
86 | w io.Writer
87 | }
88 |
89 | //replace read and write methods
90 | func (c *cryptoConn) Read(p []byte) (int, error) {
91 | return c.r.Read(p)
92 | }
93 | func (c *cryptoConn) Write(p []byte) (int, error) {
94 | return c.w.Write(p)
95 | }
96 |
--------------------------------------------------------------------------------
/lib/goproxy/utils/id/xid.go:
--------------------------------------------------------------------------------
1 | // Package xid is a globally unique id generator suited for web scale
2 | //
3 | // Xid is using Mongo Object ID algorithm to generate globally unique ids:
4 | // https://docs.mongodb.org/manual/reference/object-id/
5 | //
6 | // - 4-byte value representing the seconds since the Unix epoch,
7 | // - 3-byte machine identifier,
8 | // - 2-byte process id, and
9 | // - 3-byte counter, starting with a random value.
10 | //
11 | // The binary representation of the id is compatible with Mongo 12 bytes Object IDs.
12 | // The string representation is using base32 hex (w/o padding) for better space efficiency
13 | // when stored in that form (20 bytes). The hex variant of base32 is used to retain the
14 | // sortable property of the id.
15 | //
16 | // Xid doesn't use base64 because case sensitivity and the 2 non alphanum chars may be an
17 | // issue when transported as a string between various systems. Base36 wasn't retained either
18 | // because 1/ it's not standard 2/ the resulting size is not predictable (not bit aligned)
19 | // and 3/ it would not remain sortable. To validate a base32 `xid`, expect a 20 chars long,
20 | // all lowercase sequence of `a` to `v` letters and `0` to `9` numbers (`[0-9a-v]{20}`).
21 | //
22 | // UUID is 16 bytes (128 bits), snowflake is 8 bytes (64 bits), xid stands in between
23 | // with 12 bytes with a more compact string representation ready for the web and no
24 | // required configuration or central generation server.
25 | //
26 | // Features:
27 | //
28 | // - Size: 12 bytes (96 bits), smaller than UUID, larger than snowflake
29 | // - Base32 hex encoded by default (16 bytes storage when transported as printable string)
30 | // - Non configured, you don't need set a unique machine and/or data center id
31 | // - K-ordered
32 | // - Embedded time with 1 second precision
33 | // - Unicity guaranted for 16,777,216 (24 bits) unique ids per second and per host/process
34 | //
35 | // Best used with xlog's RequestIDHandler (https://godoc.org/github.com/rs/xlog#RequestIDHandler).
36 | //
37 | // References:
38 | //
39 | // - http://www.slideshare.net/davegardnerisme/unique-id-generation-in-distributed-systems
40 | // - https://en.wikipedia.org/wiki/Universally_unique_identifier
41 | // - https://blog.twitter.com/2010/announcing-snowflake
42 | package xid
43 |
44 | import (
45 | "crypto/md5"
46 | "crypto/rand"
47 | "database/sql/driver"
48 | "encoding/binary"
49 | "errors"
50 | "fmt"
51 | "os"
52 | "sync/atomic"
53 | "time"
54 | )
55 |
56 | // Code inspired from mgo/bson ObjectId
57 |
58 | // ID represents a unique request id
59 | type ID [rawLen]byte
60 |
61 | const (
62 | encodedLen = 20 // string encoded len
63 | decodedLen = 15 // len after base32 decoding with the padded data
64 | rawLen = 12 // binary raw len
65 |
66 | // encoding stores a custom version of the base32 encoding with lower case
67 | // letters.
68 | encoding = "0123456789abcdefghijklmnopqrstuv"
69 | )
70 |
71 | // ErrInvalidID is returned when trying to unmarshal an invalid ID
72 | var ErrInvalidID = errors.New("xid: invalid ID")
73 |
74 | // objectIDCounter is atomically incremented when generating a new ObjectId
75 | // using NewObjectId() function. It's used as a counter part of an id.
76 | // This id is initialized with a random value.
77 | var objectIDCounter = randInt()
78 |
79 | // machineId stores machine id generated once and used in subsequent calls
80 | // to NewObjectId function.
81 | var machineID = readMachineID()
82 |
83 | // pid stores the current process id
84 | var pid = os.Getpid()
85 |
86 | // dec is the decoding map for base32 encoding
87 | var dec [256]byte
88 |
89 | func init() {
90 | for i := 0; i < len(dec); i++ {
91 | dec[i] = 0xFF
92 | }
93 | for i := 0; i < len(encoding); i++ {
94 | dec[encoding[i]] = byte(i)
95 | }
96 | }
97 |
98 | // readMachineId generates machine id and puts it into the machineId global
99 | // variable. If this function fails to get the hostname, it will cause
100 | // a runtime error.
101 | func readMachineID() []byte {
102 | id := make([]byte, 3)
103 | if hostname, err := os.Hostname(); err == nil {
104 | hw := md5.New()
105 | hw.Write([]byte(hostname))
106 | copy(id, hw.Sum(nil))
107 | } else {
108 | // Fallback to rand number if machine id can't be gathered
109 | if _, randErr := rand.Reader.Read(id); randErr != nil {
110 | panic(fmt.Errorf("xid: cannot get hostname nor generate a random number: %v; %v", err, randErr))
111 | }
112 | }
113 | return id
114 | }
115 |
116 | // randInt generates a random uint32
117 | func randInt() uint32 {
118 | b := make([]byte, 3)
119 | if _, err := rand.Reader.Read(b); err != nil {
120 | panic(fmt.Errorf("xid: cannot generate random number: %v;", err))
121 | }
122 | return uint32(b[0])<<16 | uint32(b[1])<<8 | uint32(b[2])
123 | }
124 |
125 | // New generates a globaly unique ID
126 | func New() ID {
127 | var id ID
128 | // Timestamp, 4 bytes, big endian
129 | binary.BigEndian.PutUint32(id[:], uint32(time.Now().Unix()))
130 | // Machine, first 3 bytes of md5(hostname)
131 | id[4] = machineID[0]
132 | id[5] = machineID[1]
133 | id[6] = machineID[2]
134 | // Pid, 2 bytes, specs don't specify endianness, but we use big endian.
135 | id[7] = byte(pid >> 8)
136 | id[8] = byte(pid)
137 | // Increment, 3 bytes, big endian
138 | i := atomic.AddUint32(&objectIDCounter, 1)
139 | id[9] = byte(i >> 16)
140 | id[10] = byte(i >> 8)
141 | id[11] = byte(i)
142 | return id
143 | }
144 |
145 | // FromString reads an ID from its string representation
146 | func FromString(id string) (ID, error) {
147 | i := &ID{}
148 | err := i.UnmarshalText([]byte(id))
149 | return *i, err
150 | }
151 |
152 | // String returns a base32 hex lowercased with no padding representation of the id (char set is 0-9, a-v).
153 | func (id ID) String() string {
154 | text := make([]byte, encodedLen)
155 | encode(text, id[:])
156 | return string(text)
157 | }
158 |
159 | // MarshalText implements encoding/text TextMarshaler interface
160 | func (id ID) MarshalText() ([]byte, error) {
161 | text := make([]byte, encodedLen)
162 | encode(text, id[:])
163 | return text, nil
164 | }
165 |
166 | // encode by unrolling the stdlib base32 algorithm + removing all safe checks
167 | func encode(dst, id []byte) {
168 | dst[0] = encoding[id[0]>>3]
169 | dst[1] = encoding[(id[1]>>6)&0x1F|(id[0]<<2)&0x1F]
170 | dst[2] = encoding[(id[1]>>1)&0x1F]
171 | dst[3] = encoding[(id[2]>>4)&0x1F|(id[1]<<4)&0x1F]
172 | dst[4] = encoding[id[3]>>7|(id[2]<<1)&0x1F]
173 | dst[5] = encoding[(id[3]>>2)&0x1F]
174 | dst[6] = encoding[id[4]>>5|(id[3]<<3)&0x1F]
175 | dst[7] = encoding[id[4]&0x1F]
176 | dst[8] = encoding[id[5]>>3]
177 | dst[9] = encoding[(id[6]>>6)&0x1F|(id[5]<<2)&0x1F]
178 | dst[10] = encoding[(id[6]>>1)&0x1F]
179 | dst[11] = encoding[(id[7]>>4)&0x1F|(id[6]<<4)&0x1F]
180 | dst[12] = encoding[id[8]>>7|(id[7]<<1)&0x1F]
181 | dst[13] = encoding[(id[8]>>2)&0x1F]
182 | dst[14] = encoding[(id[9]>>5)|(id[8]<<3)&0x1F]
183 | dst[15] = encoding[id[9]&0x1F]
184 | dst[16] = encoding[id[10]>>3]
185 | dst[17] = encoding[(id[11]>>6)&0x1F|(id[10]<<2)&0x1F]
186 | dst[18] = encoding[(id[11]>>1)&0x1F]
187 | dst[19] = encoding[(id[11]<<4)&0x1F]
188 | }
189 |
190 | // UnmarshalText implements encoding/text TextUnmarshaler interface
191 | func (id *ID) UnmarshalText(text []byte) error {
192 | if len(text) != encodedLen {
193 | return ErrInvalidID
194 | }
195 | for _, c := range text {
196 | if dec[c] == 0xFF {
197 | return ErrInvalidID
198 | }
199 | }
200 | decode(id, text)
201 | return nil
202 | }
203 |
204 | // decode by unrolling the stdlib base32 algorithm + removing all safe checks
205 | func decode(id *ID, src []byte) {
206 | id[0] = dec[src[0]]<<3 | dec[src[1]]>>2
207 | id[1] = dec[src[1]]<<6 | dec[src[2]]<<1 | dec[src[3]]>>4
208 | id[2] = dec[src[3]]<<4 | dec[src[4]]>>1
209 | id[3] = dec[src[4]]<<7 | dec[src[5]]<<2 | dec[src[6]]>>3
210 | id[4] = dec[src[6]]<<5 | dec[src[7]]
211 | id[5] = dec[src[8]]<<3 | dec[src[9]]>>2
212 | id[6] = dec[src[9]]<<6 | dec[src[10]]<<1 | dec[src[11]]>>4
213 | id[7] = dec[src[11]]<<4 | dec[src[12]]>>1
214 | id[8] = dec[src[12]]<<7 | dec[src[13]]<<2 | dec[src[14]]>>3
215 | id[9] = dec[src[14]]<<5 | dec[src[15]]
216 | id[10] = dec[src[16]]<<3 | dec[src[17]]>>2
217 | id[11] = dec[src[17]]<<6 | dec[src[18]]<<1 | dec[src[19]]>>4
218 | }
219 |
220 | // Time returns the timestamp part of the id.
221 | // It's a runtime error to call this method with an invalid id.
222 | func (id ID) Time() time.Time {
223 | // First 4 bytes of ObjectId is 32-bit big-endian seconds from epoch.
224 | secs := int64(binary.BigEndian.Uint32(id[0:4]))
225 | return time.Unix(secs, 0)
226 | }
227 |
228 | // Machine returns the 3-byte machine id part of the id.
229 | // It's a runtime error to call this method with an invalid id.
230 | func (id ID) Machine() []byte {
231 | return id[4:7]
232 | }
233 |
234 | // Pid returns the process id part of the id.
235 | // It's a runtime error to call this method with an invalid id.
236 | func (id ID) Pid() uint16 {
237 | return binary.BigEndian.Uint16(id[7:9])
238 | }
239 |
240 | // Counter returns the incrementing value part of the id.
241 | // It's a runtime error to call this method with an invalid id.
242 | func (id ID) Counter() int32 {
243 | b := id[9:12]
244 | // Counter is stored as big-endian 3-byte value
245 | return int32(uint32(b[0])<<16 | uint32(b[1])<<8 | uint32(b[2]))
246 | }
247 |
248 | // Value implements the driver.Valuer interface.
249 | func (id ID) Value() (driver.Value, error) {
250 | b, err := id.MarshalText()
251 | return string(b), err
252 | }
253 |
254 | // Scan implements the sql.Scanner interface.
255 | func (id *ID) Scan(value interface{}) (err error) {
256 | switch val := value.(type) {
257 | case string:
258 | return id.UnmarshalText([]byte(val))
259 | case []byte:
260 | return id.UnmarshalText(val)
261 | default:
262 | return fmt.Errorf("xid: scanning unsupported type: %T", value)
263 | }
264 | }
265 |
--------------------------------------------------------------------------------
/lib/goproxy/utils/io-limiter.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import (
4 | "context"
5 | "io"
6 | "time"
7 |
8 | "golang.org/x/time/rate"
9 | )
10 |
11 | const burstLimit = 1000 * 1000 * 1000
12 |
13 | type Reader struct {
14 | r io.Reader
15 | limiter *rate.Limiter
16 | ctx context.Context
17 | }
18 |
19 | type Writer struct {
20 | w io.Writer
21 | limiter *rate.Limiter
22 | ctx context.Context
23 | }
24 |
25 | // NewReader returns a reader that implements io.Reader with rate limiting.
26 | func NewReader(r io.Reader) *Reader {
27 | return &Reader{
28 | r: r,
29 | ctx: context.Background(),
30 | }
31 | }
32 |
33 | // NewReaderWithContext returns a reader that implements io.Reader with rate limiting.
34 | func NewReaderWithContext(r io.Reader, ctx context.Context) *Reader {
35 | return &Reader{
36 | r: r,
37 | ctx: ctx,
38 | }
39 | }
40 |
41 | // NewWriter returns a writer that implements io.Writer with rate limiting.
42 | func NewWriter(w io.Writer) *Writer {
43 | return &Writer{
44 | w: w,
45 | ctx: context.Background(),
46 | }
47 | }
48 |
49 | // NewWriterWithContext returns a writer that implements io.Writer with rate limiting.
50 | func NewWriterWithContext(w io.Writer, ctx context.Context) *Writer {
51 | return &Writer{
52 | w: w,
53 | ctx: ctx,
54 | }
55 | }
56 |
57 | // SetRateLimit sets rate limit (bytes/sec) to the reader.
58 | func (s *Reader) SetRateLimit(bytesPerSec float64) {
59 | s.limiter = rate.NewLimiter(rate.Limit(bytesPerSec), burstLimit)
60 | s.limiter.AllowN(time.Now(), burstLimit) // spend initial burst
61 | }
62 |
63 | // Read reads bytes into p.
64 | func (s *Reader) Read(p []byte) (int, error) {
65 | if s.limiter == nil {
66 | return s.r.Read(p)
67 | }
68 | n, err := s.r.Read(p)
69 | if err != nil {
70 | return n, err
71 | }
72 | if err := s.limiter.WaitN(s.ctx, n); err != nil {
73 | return n, err
74 | }
75 | return n, nil
76 | }
77 |
78 | // SetRateLimit sets rate limit (bytes/sec) to the writer.
79 | func (s *Writer) SetRateLimit(bytesPerSec float64) {
80 | s.limiter = rate.NewLimiter(rate.Limit(bytesPerSec), burstLimit)
81 | s.limiter.AllowN(time.Now(), burstLimit) // spend initial burst
82 | }
83 |
84 | // Write writes bytes from p.
85 | func (s *Writer) Write(p []byte) (int, error) {
86 | if s.limiter == nil {
87 | return s.w.Write(p)
88 | }
89 | n, err := s.w.Write(p)
90 | if err != nil {
91 | return n, err
92 | }
93 | if err := s.limiter.WaitN(s.ctx, n); err != nil {
94 | return n, err
95 | }
96 | return n, err
97 | }
98 |
--------------------------------------------------------------------------------
/lib/goproxy/utils/leakybuf.go:
--------------------------------------------------------------------------------
1 | // Provides leaky buffer, based on the example in Effective Go.
2 | package utils
3 |
4 | type LeakyBuf struct {
5 | bufSize int // size of each buffer
6 | freeList chan []byte
7 | }
8 |
9 | const LeakyBufSize = 2048 // data.len(2) + hmacsha1(10) + data(4096)
10 | const maxNBuf = 2048
11 |
12 | var LeakyBuffer = NewLeakyBuf(maxNBuf, LeakyBufSize)
13 |
14 | // NewLeakyBuf creates a leaky buffer which can hold at most n buffer, each
15 | // with bufSize bytes.
16 | func NewLeakyBuf(n, bufSize int) *LeakyBuf {
17 | return &LeakyBuf{
18 | bufSize: bufSize,
19 | freeList: make(chan []byte, n),
20 | }
21 | }
22 |
23 | // Get returns a buffer from the leaky buffer or create a new buffer.
24 | func (lb *LeakyBuf) Get() (b []byte) {
25 | select {
26 | case b = <-lb.freeList:
27 | default:
28 | b = make([]byte, lb.bufSize)
29 | }
30 | return
31 | }
32 |
33 | // Put add the buffer into the free buffer pool for reuse. Panic if the buffer
34 | // size is not the same with the leaky buffer's. This is intended to expose
35 | // error usage of leaky buffer.
36 | func (lb *LeakyBuf) Put(b []byte) {
37 | if len(b) != lb.bufSize {
38 | panic("invalid buffer size that's put into leaky buffer")
39 | }
40 | select {
41 | case lb.freeList <- b:
42 | default:
43 | }
44 | return
45 | }
46 |
--------------------------------------------------------------------------------
/lib/goproxy/utils/map.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import (
4 | "encoding/json"
5 | "sync"
6 | )
7 |
8 | var SHARD_COUNT = 32
9 |
10 | // A "thread" safe map of type string:Anything.
11 | // To avoid lock bottlenecks this map is dived to several (SHARD_COUNT) map shards.
12 | type ConcurrentMap []*ConcurrentMapShared
13 |
14 | // A "thread" safe string to anything map.
15 | type ConcurrentMapShared struct {
16 | items map[string]interface{}
17 | sync.RWMutex // Read Write mutex, guards access to internal map.
18 | }
19 |
20 | // Creates a new concurrent map.
21 | func NewConcurrentMap() ConcurrentMap {
22 | m := make(ConcurrentMap, SHARD_COUNT)
23 | for i := 0; i < SHARD_COUNT; i++ {
24 | m[i] = &ConcurrentMapShared{items: make(map[string]interface{})}
25 | }
26 | return m
27 | }
28 |
29 | // Returns shard under given key
30 | func (m ConcurrentMap) GetShard(key string) *ConcurrentMapShared {
31 | return m[uint(fnv32(key))%uint(SHARD_COUNT)]
32 | }
33 |
34 | func (m ConcurrentMap) MSet(data map[string]interface{}) {
35 | for key, value := range data {
36 | shard := m.GetShard(key)
37 | shard.Lock()
38 | shard.items[key] = value
39 | shard.Unlock()
40 | }
41 | }
42 |
43 | // Sets the given value under the specified key.
44 | func (m ConcurrentMap) Set(key string, value interface{}) {
45 | // Get map shard.
46 | shard := m.GetShard(key)
47 | shard.Lock()
48 | shard.items[key] = value
49 | shard.Unlock()
50 | }
51 |
52 | // Callback to return new element to be inserted into the map
53 | // It is called while lock is held, therefore it MUST NOT
54 | // try to access other keys in same map, as it can lead to deadlock since
55 | // Go sync.RWLock is not reentrant
56 | type UpsertCb func(exist bool, valueInMap interface{}, newValue interface{}) interface{}
57 |
58 | // Insert or Update - updates existing element or inserts a new one using UpsertCb
59 | func (m ConcurrentMap) Upsert(key string, value interface{}, cb UpsertCb) (res interface{}) {
60 | shard := m.GetShard(key)
61 | shard.Lock()
62 | v, ok := shard.items[key]
63 | res = cb(ok, v, value)
64 | shard.items[key] = res
65 | shard.Unlock()
66 | return res
67 | }
68 |
69 | // Sets the given value under the specified key if no value was associated with it.
70 | func (m ConcurrentMap) SetIfAbsent(key string, value interface{}) bool {
71 | // Get map shard.
72 | shard := m.GetShard(key)
73 | shard.Lock()
74 | _, ok := shard.items[key]
75 | if !ok {
76 | shard.items[key] = value
77 | }
78 | shard.Unlock()
79 | return !ok
80 | }
81 |
82 | // Retrieves an element from map under given key.
83 | func (m ConcurrentMap) Get(key string) (interface{}, bool) {
84 | // Get shard
85 | shard := m.GetShard(key)
86 | shard.RLock()
87 | // Get item from shard.
88 | val, ok := shard.items[key]
89 | shard.RUnlock()
90 | return val, ok
91 | }
92 |
93 | // Returns the number of elements within the map.
94 | func (m ConcurrentMap) Count() int {
95 | count := 0
96 | for i := 0; i < SHARD_COUNT; i++ {
97 | shard := m[i]
98 | shard.RLock()
99 | count += len(shard.items)
100 | shard.RUnlock()
101 | }
102 | return count
103 | }
104 |
105 | // Looks up an item under specified key
106 | func (m ConcurrentMap) Has(key string) bool {
107 | // Get shard
108 | shard := m.GetShard(key)
109 | shard.RLock()
110 | // See if element is within shard.
111 | _, ok := shard.items[key]
112 | shard.RUnlock()
113 | return ok
114 | }
115 |
116 | // Removes an element from the map.
117 | func (m ConcurrentMap) Remove(key string) {
118 | // Try to get shard.
119 | shard := m.GetShard(key)
120 | shard.Lock()
121 | delete(shard.items, key)
122 | shard.Unlock()
123 | }
124 |
125 | // Removes an element from the map and returns it
126 | func (m ConcurrentMap) Pop(key string) (v interface{}, exists bool) {
127 | // Try to get shard.
128 | shard := m.GetShard(key)
129 | shard.Lock()
130 | v, exists = shard.items[key]
131 | delete(shard.items, key)
132 | shard.Unlock()
133 | return v, exists
134 | }
135 |
136 | // Checks if map is empty.
137 | func (m ConcurrentMap) IsEmpty() bool {
138 | return m.Count() == 0
139 | }
140 |
141 | // Used by the Iter & IterBuffered functions to wrap two variables together over a channel,
142 | type Tuple struct {
143 | Key string
144 | Val interface{}
145 | }
146 |
147 | // Returns an iterator which could be used in a for range loop.
148 | //
149 | // Deprecated: using IterBuffered() will get a better performence
150 | func (m ConcurrentMap) Iter() <-chan Tuple {
151 | chans := snapshot(m)
152 | ch := make(chan Tuple)
153 | go fanIn(chans, ch)
154 | return ch
155 | }
156 |
157 | // Returns a buffered iterator which could be used in a for range loop.
158 | func (m ConcurrentMap) IterBuffered() <-chan Tuple {
159 | chans := snapshot(m)
160 | total := 0
161 | for _, c := range chans {
162 | total += cap(c)
163 | }
164 | ch := make(chan Tuple, total)
165 | go fanIn(chans, ch)
166 | return ch
167 | }
168 |
169 | // Returns a array of channels that contains elements in each shard,
170 | // which likely takes a snapshot of `m`.
171 | // It returns once the size of each buffered channel is determined,
172 | // before all the channels are populated using goroutines.
173 | func snapshot(m ConcurrentMap) (chans []chan Tuple) {
174 | chans = make([]chan Tuple, SHARD_COUNT)
175 | wg := sync.WaitGroup{}
176 | wg.Add(SHARD_COUNT)
177 | // Foreach shard.
178 | for index, shard := range m {
179 | go func(index int, shard *ConcurrentMapShared) {
180 | // Foreach key, value pair.
181 | shard.RLock()
182 | chans[index] = make(chan Tuple, len(shard.items))
183 | wg.Done()
184 | for key, val := range shard.items {
185 | chans[index] <- Tuple{key, val}
186 | }
187 | shard.RUnlock()
188 | close(chans[index])
189 | }(index, shard)
190 | }
191 | wg.Wait()
192 | return chans
193 | }
194 |
195 | // fanIn reads elements from channels `chans` into channel `out`
196 | func fanIn(chans []chan Tuple, out chan Tuple) {
197 | wg := sync.WaitGroup{}
198 | wg.Add(len(chans))
199 | for _, ch := range chans {
200 | go func(ch chan Tuple) {
201 | for t := range ch {
202 | out <- t
203 | }
204 | wg.Done()
205 | }(ch)
206 | }
207 | wg.Wait()
208 | close(out)
209 | }
210 |
211 | // Returns all items as map[string]interface{}
212 | func (m ConcurrentMap) Items() map[string]interface{} {
213 | tmp := make(map[string]interface{})
214 |
215 | // Insert items to temporary map.
216 | for item := range m.IterBuffered() {
217 | tmp[item.Key] = item.Val
218 | }
219 |
220 | return tmp
221 | }
222 |
223 | // Iterator callback,called for every key,value found in
224 | // maps. RLock is held for all calls for a given shard
225 | // therefore callback sess consistent view of a shard,
226 | // but not across the shards
227 | type IterCb func(key string, v interface{})
228 |
229 | // Callback based iterator, cheapest way to read
230 | // all elements in a map.
231 | func (m ConcurrentMap) IterCb(fn IterCb) {
232 | for idx := range m {
233 | shard := (m)[idx]
234 | shard.RLock()
235 | for key, value := range shard.items {
236 | fn(key, value)
237 | }
238 | shard.RUnlock()
239 | }
240 | }
241 |
242 | // Return all keys as []string
243 | func (m ConcurrentMap) Keys() []string {
244 | count := m.Count()
245 | ch := make(chan string, count)
246 | go func() {
247 | // Foreach shard.
248 | wg := sync.WaitGroup{}
249 | wg.Add(SHARD_COUNT)
250 | for _, shard := range m {
251 | go func(shard *ConcurrentMapShared) {
252 | // Foreach key, value pair.
253 | shard.RLock()
254 | for key := range shard.items {
255 | ch <- key
256 | }
257 | shard.RUnlock()
258 | wg.Done()
259 | }(shard)
260 | }
261 | wg.Wait()
262 | close(ch)
263 | }()
264 |
265 | // Generate keys
266 | keys := make([]string, 0, count)
267 | for k := range ch {
268 | keys = append(keys, k)
269 | }
270 | return keys
271 | }
272 |
273 | //Reviles ConcurrentMap "private" variables to json marshal.
274 | func (m ConcurrentMap) MarshalJSON() ([]byte, error) {
275 | // Create a temporary map, which will hold all item spread across shards.
276 | tmp := make(map[string]interface{})
277 |
278 | // Insert items to temporary map.
279 | for item := range m.IterBuffered() {
280 | tmp[item.Key] = item.Val
281 | }
282 | return json.Marshal(tmp)
283 | }
284 |
285 | func fnv32(key string) uint32 {
286 | hash := uint32(2166136261)
287 | const prime32 = uint32(16777619)
288 | for i := 0; i < len(key); i++ {
289 | hash *= prime32
290 | hash ^= uint32(key[i])
291 | }
292 | return hash
293 | }
294 |
295 | // Concurrent map uses Interface{} as its value, therefor JSON Unmarshal
296 | // will probably won't know which to type to unmarshal into, in such case
297 | // we'll end up with a value of type map[string]interface{}, In most cases this isn't
298 | // out value type, this is why we've decided to remove this functionality.
299 |
300 | // func (m *ConcurrentMap) UnmarshalJSON(b []byte) (err error) {
301 | // // Reverse process of Marshal.
302 |
303 | // tmp := make(map[string]interface{})
304 |
305 | // // Unmarshal into a single map.
306 | // if err := json.Unmarshal(b, &tmp); err != nil {
307 | // return nil
308 | // }
309 |
310 | // // foreach key,value pair in temporary map insert into our concurrent map.
311 | // for key, val := range tmp {
312 | // m.Set(key, val)
313 | // }
314 | // return nil
315 | // }
316 |
--------------------------------------------------------------------------------
/lib/goproxy/utils/serve-channel.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import (
4 | "crypto/tls"
5 | "crypto/x509"
6 | "errors"
7 | "fmt"
8 | kcpcfg2 "github.com/yincongcyincong/proxy-web/lib/goproxy/services/kcpcfg"
9 | logger "log"
10 | "net"
11 | "runtime/debug"
12 | "strconv"
13 |
14 | kcp "github.com/xtaci/kcp-go"
15 | )
16 |
17 | type ServerChannel struct {
18 | ip string
19 | port int
20 | Listener *net.Listener
21 | UDPListener *net.UDPConn
22 | errAcceptHandler func(err error)
23 | log *logger.Logger
24 | }
25 |
26 | func NewServerChannel(ip string, port int, log *logger.Logger) ServerChannel {
27 | return ServerChannel{
28 | ip: ip,
29 | port: port,
30 | log: log,
31 | errAcceptHandler: func(err error) {
32 | log.Printf("accept error , ERR:%s", err)
33 | },
34 | }
35 | }
36 | func NewServerChannelHost(host string, log *logger.Logger) ServerChannel {
37 | h, port, _ := net.SplitHostPort(host)
38 | p, _ := strconv.Atoi(port)
39 | return ServerChannel{
40 | ip: h,
41 | port: p,
42 | log: log,
43 | errAcceptHandler: func(err error) {
44 | log.Printf("accept error , ERR:%s", err)
45 | },
46 | }
47 | }
48 | func (sc *ServerChannel) SetErrAcceptHandler(fn func(err error)) {
49 | sc.errAcceptHandler = fn
50 | }
51 | func (sc *ServerChannel) ListenTls(certBytes, keyBytes, caCertBytes []byte, fn func(conn net.Conn)) (err error) {
52 | sc.Listener, err = sc.listenTls(sc.ip, sc.port, certBytes, keyBytes, caCertBytes)
53 | if err == nil {
54 | go func() {
55 | defer func() {
56 | if e := recover(); e != nil {
57 | sc.log.Printf("ListenTls crashed , err : %s , \ntrace:%s", e, string(debug.Stack()))
58 | }
59 | }()
60 | for {
61 | var conn net.Conn
62 | conn, err = (*sc.Listener).Accept()
63 | if err == nil {
64 | go func() {
65 | defer func() {
66 | if e := recover(); e != nil {
67 | sc.log.Printf("tls connection handler crashed , err : %s , \ntrace:%s", e, string(debug.Stack()))
68 | }
69 | }()
70 | fn(conn)
71 | }()
72 | } else {
73 | sc.errAcceptHandler(err)
74 | (*sc.Listener).Close()
75 | break
76 | }
77 | }
78 | }()
79 | }
80 | return
81 | }
82 | func (sc *ServerChannel) listenTls(ip string, port int, certBytes, keyBytes, caCertBytes []byte) (ln *net.Listener, err error) {
83 |
84 | var cert tls.Certificate
85 | cert, err = tls.X509KeyPair(certBytes, keyBytes)
86 | if err != nil {
87 | return
88 | }
89 | clientCertPool := x509.NewCertPool()
90 | caBytes := certBytes
91 | if caCertBytes != nil {
92 | caBytes = caCertBytes
93 | }
94 | ok := clientCertPool.AppendCertsFromPEM(caBytes)
95 | if !ok {
96 | err = errors.New("failed to parse root certificate")
97 | }
98 | config := &tls.Config{
99 | ClientCAs: clientCertPool,
100 | Certificates: []tls.Certificate{cert},
101 | ClientAuth: tls.RequireAndVerifyClientCert,
102 | }
103 | _ln, err := tls.Listen("tcp", fmt.Sprintf("%s:%d", ip, port), config)
104 | if err == nil {
105 | ln = &_ln
106 | }
107 | return
108 | }
109 | func (sc *ServerChannel) ListenTCP(fn func(conn net.Conn)) (err error) {
110 | var l net.Listener
111 | l, err = net.Listen("tcp", fmt.Sprintf("%s:%d", sc.ip, sc.port))
112 | if err == nil {
113 | sc.Listener = &l
114 | go func() {
115 | defer func() {
116 | if e := recover(); e != nil {
117 | sc.log.Printf("ListenTCP crashed , err : %s , \ntrace:%s", e, string(debug.Stack()))
118 | }
119 | }()
120 | for {
121 | var conn net.Conn
122 | conn, err = (*sc.Listener).Accept()
123 | if err == nil {
124 | go func() {
125 | defer func() {
126 | if e := recover(); e != nil {
127 | sc.log.Printf("tcp connection handler crashed , err : %s , \ntrace:%s", e, string(debug.Stack()))
128 | }
129 | }()
130 | fn(conn)
131 | }()
132 | } else {
133 | sc.errAcceptHandler(err)
134 | break
135 | }
136 | }
137 | }()
138 | }
139 | return
140 | }
141 | func (sc *ServerChannel) ListenUDP(fn func(packet []byte, localAddr, srcAddr *net.UDPAddr)) (err error) {
142 | addr := &net.UDPAddr{IP: net.ParseIP(sc.ip), Port: sc.port}
143 | l, err := net.ListenUDP("udp", addr)
144 | if err == nil {
145 | sc.UDPListener = l
146 | go func() {
147 | defer func() {
148 | if e := recover(); e != nil {
149 | sc.log.Printf("ListenUDP crashed , err : %s , \ntrace:%s", e, string(debug.Stack()))
150 | }
151 | }()
152 | for {
153 | var buf = make([]byte, 2048)
154 | n, srcAddr, err := (*sc.UDPListener).ReadFromUDP(buf)
155 | if err == nil {
156 | packet := buf[0:n]
157 | go func() {
158 | defer func() {
159 | if e := recover(); e != nil {
160 | sc.log.Printf("udp data handler crashed , err : %s , \ntrace:%s", e, string(debug.Stack()))
161 | }
162 | }()
163 | fn(packet, addr, srcAddr)
164 | }()
165 | } else {
166 | sc.errAcceptHandler(err)
167 | break
168 | }
169 | }
170 | }()
171 | }
172 | return
173 | }
174 | func (sc *ServerChannel) ListenKCP(config kcpcfg2.KCPConfigArgs, fn func(conn net.Conn), log *logger.Logger) (err error) {
175 | lis, err := kcp.ListenWithOptions(fmt.Sprintf("%s:%d", sc.ip, sc.port), config.Block, *config.DataShard, *config.ParityShard)
176 | if err == nil {
177 | if err = lis.SetDSCP(*config.DSCP); err != nil {
178 | log.Println("SetDSCP:", err)
179 | return
180 | }
181 | if err = lis.SetReadBuffer(*config.SockBuf); err != nil {
182 | log.Println("SetReadBuffer:", err)
183 | return
184 | }
185 | if err = lis.SetWriteBuffer(*config.SockBuf); err != nil {
186 | log.Println("SetWriteBuffer:", err)
187 | return
188 | }
189 | sc.Listener = new(net.Listener)
190 | *sc.Listener = lis
191 | go func() {
192 | defer func() {
193 | if e := recover(); e != nil {
194 | sc.log.Printf("ListenKCP crashed , err : %s , \ntrace:%s", e, string(debug.Stack()))
195 | }
196 | }()
197 | for {
198 | //var conn net.Conn
199 | conn, err := lis.AcceptKCP()
200 | if err == nil {
201 | go func() {
202 | defer func() {
203 | if e := recover(); e != nil {
204 | sc.log.Printf("kcp connection handler crashed , err : %s , \ntrace:%s", e, string(debug.Stack()))
205 | }
206 | }()
207 | conn.SetStreamMode(true)
208 | conn.SetWriteDelay(true)
209 | conn.SetNoDelay(*config.NoDelay, *config.Interval, *config.Resend, *config.NoCongestion)
210 | conn.SetMtu(*config.MTU)
211 | conn.SetWindowSize(*config.SndWnd, *config.RcvWnd)
212 | conn.SetACKNoDelay(*config.AckNodelay)
213 | if *config.NoComp {
214 | fn(conn)
215 | } else {
216 | cconn := NewCompStream(conn)
217 | fn(cconn)
218 | }
219 | }()
220 | } else {
221 | sc.errAcceptHandler(err)
222 | break
223 | }
224 | }
225 | }()
226 | }
227 | return
228 | }
229 |
--------------------------------------------------------------------------------
/lib/goproxy/utils/sni/sni.go:
--------------------------------------------------------------------------------
1 | package sni
2 |
3 | import (
4 | "bufio"
5 | "bytes"
6 | "errors"
7 | "io"
8 | "net"
9 | )
10 |
11 | func ServerNameFromBytes(data []byte) (sn string, err error) {
12 | reader := bytes.NewReader(data)
13 | bufferedReader := bufio.NewReader(reader)
14 | c := bufferedConn{bufferedReader, nil, nil}
15 | sn, _, err = ServerNameFromConn(c)
16 | return
17 | }
18 |
19 | type bufferedConn struct {
20 | r *bufio.Reader
21 | rout io.Reader
22 | net.Conn
23 | }
24 |
25 | func newBufferedConn(c net.Conn) bufferedConn {
26 | return bufferedConn{bufio.NewReader(c), nil, c}
27 | }
28 |
29 | func (b bufferedConn) Peek(n int) ([]byte, error) {
30 | return b.r.Peek(n)
31 | }
32 |
33 | func (b bufferedConn) Read(p []byte) (int, error) {
34 | if b.rout != nil {
35 | return b.rout.Read(p)
36 | }
37 | return b.r.Read(p)
38 | }
39 |
40 | var malformedError = errors.New("malformed client hello")
41 |
42 | func getHello(b []byte) (string, error) {
43 | rest := b[5:]
44 |
45 | if len(rest) == 0 {
46 | return "", malformedError
47 | }
48 |
49 | current := 0
50 | handshakeType := rest[0]
51 | current += 1
52 | if handshakeType != 0x1 {
53 | return "", errors.New("Not a ClientHello")
54 | }
55 |
56 | // Skip over another length
57 | current += 3
58 | // Skip over protocolversion
59 | current += 2
60 | // Skip over random number
61 | current += 4 + 28
62 |
63 | if current > len(rest) {
64 | return "", malformedError
65 | }
66 |
67 | // Skip over session ID
68 | sessionIDLength := int(rest[current])
69 | current += 1
70 | current += sessionIDLength
71 |
72 | if current+1 > len(rest) {
73 | return "", malformedError
74 | }
75 |
76 | cipherSuiteLength := (int(rest[current]) << 8) + int(rest[current+1])
77 | current += 2
78 | current += cipherSuiteLength
79 |
80 | if current > len(rest) {
81 | return "", malformedError
82 | }
83 | compressionMethodLength := int(rest[current])
84 | current += 1
85 | current += compressionMethodLength
86 |
87 | if current > len(rest) {
88 | return "", errors.New("no extensions")
89 | }
90 |
91 | current += 2
92 |
93 | hostname := ""
94 | for current+4 < len(rest) && hostname == "" {
95 | extensionType := (int(rest[current]) << 8) + int(rest[current+1])
96 | current += 2
97 |
98 | extensionDataLength := (int(rest[current]) << 8) + int(rest[current+1])
99 | current += 2
100 |
101 | if extensionType == 0 {
102 |
103 | // Skip over number of names as we're assuming there's just one
104 | current += 2
105 | if current > len(rest) {
106 | return "", malformedError
107 | }
108 |
109 | nameType := rest[current]
110 | current += 1
111 | if nameType != 0 {
112 | return "", errors.New("Not a hostname")
113 | }
114 | if current+1 > len(rest) {
115 | return "", malformedError
116 | }
117 | nameLen := (int(rest[current]) << 8) + int(rest[current+1])
118 | current += 2
119 | if current+nameLen > len(rest) {
120 | return "", malformedError
121 | }
122 | hostname = string(rest[current : current+nameLen])
123 | }
124 |
125 | current += extensionDataLength
126 | }
127 | if hostname == "" {
128 | return "", errors.New("No hostname")
129 | }
130 | return hostname, nil
131 |
132 | }
133 |
134 | func getHelloBytes(c bufferedConn) ([]byte, error) {
135 | b, err := c.Peek(5)
136 | if err != nil {
137 | return []byte{}, err
138 | }
139 |
140 | if b[0] != 0x16 {
141 | return []byte{}, errors.New("not TLS")
142 | }
143 |
144 | restLengthBytes := b[3:]
145 | restLength := (int(restLengthBytes[0]) << 8) + int(restLengthBytes[1])
146 |
147 | return c.Peek(5 + restLength)
148 |
149 | }
150 |
151 | func getServername(c bufferedConn) (string, []byte, error) {
152 | all, err := getHelloBytes(c)
153 | if err != nil {
154 | return "", nil, err
155 | }
156 | name, err := getHello(all)
157 | if err != nil {
158 | return "", nil, err
159 | }
160 | return name, all, err
161 |
162 | }
163 |
164 | // Uses SNI to get the name of the server from the connection. Returns the ServerName and a buffered connection that will not have been read off of.
165 | func ServerNameFromConn(c net.Conn) (string, net.Conn, error) {
166 | bufconn := newBufferedConn(c)
167 | sn, helloBytes, err := getServername(bufconn)
168 | if err != nil {
169 | return "", nil, err
170 | }
171 | bufconn.rout = io.MultiReader(bytes.NewBuffer(helloBytes), c)
172 | return sn, bufconn, nil
173 | }
174 |
--------------------------------------------------------------------------------
/lib/goproxy/utils/socks/client.go:
--------------------------------------------------------------------------------
1 | package socks
2 |
3 | import (
4 | "encoding/binary"
5 | "errors"
6 | "fmt"
7 | "io"
8 | "net"
9 | "strconv"
10 | "time"
11 | )
12 |
13 | var socks5Errors = []string{
14 | "",
15 | "general failure",
16 | "connection forbidden",
17 | "network unreachable",
18 | "host unreachable",
19 | "connection refused",
20 | "TTL expired",
21 | "command not supported",
22 | "address type not supported",
23 | }
24 |
25 | type Auth struct {
26 | User, Password string
27 | }
28 | type ClientConn struct {
29 | user string
30 | password string
31 | conn *net.Conn
32 | header []byte
33 | timeout time.Duration
34 | addr string
35 | network string
36 | UDPAddr string
37 | }
38 |
39 | // SOCKS5 returns a Dialer that makes SOCKSv5 connections to the given address
40 | // with an optional username and password. See RFC 1928 and RFC 1929.
41 | // target must be a canonical address with a host and port.
42 | // network : tcp udp
43 | func NewClientConn(conn *net.Conn, network, target string, timeout time.Duration, auth *Auth, header []byte) *ClientConn {
44 | s := &ClientConn{
45 | conn: conn,
46 | network: network,
47 | timeout: timeout,
48 | }
49 | if auth != nil {
50 | s.user = auth.User
51 | s.password = auth.Password
52 | }
53 | if header != nil && len(header) > 0 {
54 | s.header = header
55 | }
56 | if network == "udp" && target == "" {
57 | target = "0.0.0.0:1"
58 | }
59 | s.addr = target
60 | return s
61 | }
62 |
63 | // connect takes an existing connection to a socks5 proxy server,
64 | // and commands the server to extend that connection to target,
65 | // which must be a canonical address with a host and port.
66 | func (s *ClientConn) Handshake() error {
67 | host, portStr, err := net.SplitHostPort(s.addr)
68 | if err != nil {
69 | return err
70 | }
71 | port, err := strconv.Atoi(portStr)
72 | if err != nil {
73 | return errors.New("proxy: failed to parse port number: " + portStr)
74 | }
75 | if s.network == "tcp" && (port < 1 || port > 0xffff) {
76 | return errors.New("proxy: port number out of range: " + portStr)
77 | }
78 |
79 | if err := s.handshake(host); err != nil {
80 | return err
81 | }
82 | buf := []byte{}
83 | if s.network == "tcp" {
84 | buf = append(buf, VERSION_V5, CMD_CONNECT, 0 /* reserved */)
85 |
86 | } else {
87 | buf = append(buf, VERSION_V5, CMD_ASSOCIATE, 0 /* reserved */)
88 | }
89 | if ip := net.ParseIP(host); ip != nil {
90 | if ip4 := ip.To4(); ip4 != nil {
91 | buf = append(buf, ATYP_IPV4)
92 | ip = ip4
93 | } else {
94 | buf = append(buf, ATYP_IPV6)
95 | }
96 | buf = append(buf, ip...)
97 | } else {
98 | if len(host) > 255 {
99 | return errors.New("proxy: destination host name too long: " + host)
100 | }
101 | buf = append(buf, ATYP_DOMAIN)
102 | buf = append(buf, byte(len(host)))
103 | buf = append(buf, host...)
104 | }
105 | buf = append(buf, byte(port>>8), byte(port))
106 | (*s.conn).SetDeadline(time.Now().Add(s.timeout))
107 | if _, err := (*s.conn).Write(buf); err != nil {
108 | return errors.New("proxy: failed to write connect request to SOCKS5 proxy at " + s.addr + ": " + err.Error())
109 | }
110 | (*s.conn).SetDeadline(time.Time{})
111 | (*s.conn).SetDeadline(time.Now().Add(s.timeout))
112 | if _, err := io.ReadFull((*s.conn), buf[:4]); err != nil {
113 | return errors.New("proxy: failed to read connect reply from SOCKS5 proxy at " + s.addr + ": " + err.Error())
114 | }
115 | (*s.conn).SetDeadline(time.Time{})
116 | failure := "unknown error"
117 | if int(buf[1]) < len(socks5Errors) {
118 | failure = socks5Errors[buf[1]]
119 | }
120 |
121 | if len(failure) > 0 {
122 | return errors.New("proxy: SOCKS5 proxy at " + s.addr + " failed to connect: " + failure)
123 | }
124 |
125 | bytesToDiscard := 0
126 | switch buf[3] {
127 | case ATYP_IPV4:
128 | bytesToDiscard = net.IPv4len
129 | case ATYP_IPV6:
130 | bytesToDiscard = net.IPv6len
131 | case ATYP_DOMAIN:
132 | (*s.conn).SetDeadline(time.Now().Add(s.timeout))
133 | _, err := io.ReadFull((*s.conn), buf[:1])
134 | (*s.conn).SetDeadline(time.Time{})
135 | if err != nil {
136 | return errors.New("proxy: failed to read domain length from SOCKS5 proxy at " + s.addr + ": " + err.Error())
137 | }
138 | bytesToDiscard = int(buf[0])
139 | default:
140 | return errors.New("proxy: got unknown address type " + strconv.Itoa(int(buf[3])) + " from SOCKS5 proxy at " + s.addr)
141 | }
142 |
143 | if cap(buf) < bytesToDiscard {
144 | buf = make([]byte, bytesToDiscard)
145 | } else {
146 | buf = buf[:bytesToDiscard]
147 | }
148 | (*s.conn).SetDeadline(time.Now().Add(s.timeout))
149 | if _, err := io.ReadFull((*s.conn), buf); err != nil {
150 | return errors.New("proxy: failed to read address from SOCKS5 proxy at " + s.addr + ": " + err.Error())
151 | }
152 | (*s.conn).SetDeadline(time.Time{})
153 | var ip net.IP
154 | ip = buf
155 | ipStr := ""
156 | if bytesToDiscard == net.IPv4len || bytesToDiscard == net.IPv6len {
157 | if ipv4 := ip.To4(); ipv4 != nil {
158 | ipStr = ipv4.String()
159 | } else {
160 | ipStr = ip.To16().String()
161 | }
162 | }
163 | //log.Printf("%v", ipStr)
164 | // Also need to discard the port number
165 | (*s.conn).SetDeadline(time.Now().Add(s.timeout))
166 | if _, err := io.ReadFull((*s.conn), buf[:2]); err != nil {
167 | return errors.New("proxy: failed to read port from SOCKS5 proxy at " + s.addr + ": " + err.Error())
168 | }
169 | p := binary.BigEndian.Uint16([]byte{buf[0], buf[1]})
170 | //log.Printf("%v", p)
171 | s.UDPAddr = net.JoinHostPort(ipStr, fmt.Sprintf("%d", p))
172 | //log.Printf("%v", s.udpAddr)
173 | (*s.conn).SetDeadline(time.Time{})
174 | return nil
175 | }
176 | func (s *ClientConn) SendUDP(data []byte, addr string) (respData []byte, err error) {
177 |
178 | c, err := net.DialTimeout("udp", s.UDPAddr, s.timeout)
179 | if err != nil {
180 | return
181 | }
182 | conn := c.(*net.UDPConn)
183 |
184 | p := NewPacketUDP()
185 | p.Build(addr, data)
186 | conn.SetDeadline(time.Now().Add(s.timeout))
187 | conn.Write(p.Bytes())
188 | conn.SetDeadline(time.Time{})
189 |
190 | buf := make([]byte, 1024)
191 | conn.SetDeadline(time.Now().Add(s.timeout))
192 | n, _, err := conn.ReadFrom(buf)
193 | conn.SetDeadline(time.Time{})
194 | if err != nil {
195 | return
196 | }
197 | respData = buf[:n]
198 | return
199 | }
200 | func (s *ClientConn) handshake(host string) error {
201 |
202 | // the size here is just an estimate
203 | buf := make([]byte, 0, 6+len(host))
204 |
205 | buf = append(buf, VERSION_V5)
206 | if len(s.user) > 0 && len(s.user) < 256 && len(s.password) < 256 {
207 | buf = append(buf, 2 /* num auth methods */, Method_NO_AUTH, Method_USER_PASS)
208 | } else {
209 | buf = append(buf, 1 /* num auth methods */, Method_NO_AUTH)
210 | }
211 | (*s.conn).SetDeadline(time.Now().Add(s.timeout))
212 | if _, err := (*s.conn).Write(buf); err != nil {
213 | return errors.New("proxy: failed to write greeting to SOCKS5 proxy at " + s.addr + ": " + err.Error())
214 | }
215 | (*s.conn).SetDeadline(time.Time{})
216 |
217 | (*s.conn).SetDeadline(time.Now().Add(s.timeout))
218 | if _, err := io.ReadFull((*s.conn), buf[:2]); err != nil {
219 | return errors.New("proxy: failed to read greeting from SOCKS5 proxy at " + s.addr + ": " + err.Error())
220 | }
221 | (*s.conn).SetDeadline(time.Time{})
222 |
223 | if buf[0] != 5 {
224 | return errors.New("proxy: SOCKS5 proxy at " + s.addr + " has unexpected version " + strconv.Itoa(int(buf[0])))
225 | }
226 | if buf[1] == 0xff {
227 | return errors.New("proxy: SOCKS5 proxy at " + s.addr + " requires authentication")
228 | }
229 |
230 | // See RFC 1929
231 | if buf[1] == Method_USER_PASS {
232 | buf = buf[:0]
233 | buf = append(buf, 1 /* password protocol version */)
234 | buf = append(buf, uint8(len(s.user)))
235 | buf = append(buf, s.user...)
236 | buf = append(buf, uint8(len(s.password)))
237 | buf = append(buf, s.password...)
238 | (*s.conn).SetDeadline(time.Now().Add(s.timeout))
239 | if _, err := (*s.conn).Write(buf); err != nil {
240 | return errors.New("proxy: failed to write authentication request to SOCKS5 proxy at " + s.addr + ": " + err.Error())
241 | }
242 | (*s.conn).SetDeadline(time.Time{})
243 | (*s.conn).SetDeadline(time.Now().Add(s.timeout))
244 | if _, err := io.ReadFull((*s.conn), buf[:2]); err != nil {
245 | return errors.New("proxy: failed to read authentication reply from SOCKS5 proxy at " + s.addr + ": " + err.Error())
246 | }
247 | (*s.conn).SetDeadline(time.Time{})
248 | if buf[1] != 0 {
249 | return errors.New("proxy: SOCKS5 proxy at " + s.addr + " rejected username/password")
250 | }
251 | }
252 | return nil
253 | }
254 |
--------------------------------------------------------------------------------
/lib/goproxy/utils/socks/server.go:
--------------------------------------------------------------------------------
1 | package socks
2 |
3 | import (
4 | "fmt"
5 | utils2 "github.com/yincongcyincong/proxy-web/lib/goproxy/utils"
6 | "net"
7 | "strings"
8 | "time"
9 | )
10 |
11 | const (
12 | Method_NO_AUTH = uint8(0x00)
13 | Method_GSSAPI = uint8(0x01)
14 | Method_USER_PASS = uint8(0x02)
15 | Method_IANA = uint8(0x7F)
16 | Method_RESVERVE = uint8(0x80)
17 | Method_NONE_ACCEPTABLE = uint8(0xFF)
18 | VERSION_V5 = uint8(0x05)
19 | CMD_CONNECT = uint8(0x01)
20 | CMD_BIND = uint8(0x02)
21 | CMD_ASSOCIATE = uint8(0x03)
22 | ATYP_IPV4 = uint8(0x01)
23 | ATYP_DOMAIN = uint8(0x03)
24 | ATYP_IPV6 = uint8(0x04)
25 | REP_SUCCESS = uint8(0x00)
26 | REP_REQ_FAIL = uint8(0x01)
27 | REP_RULE_FORBIDDEN = uint8(0x02)
28 | REP_NETWOR_UNREACHABLE = uint8(0x03)
29 | REP_HOST_UNREACHABLE = uint8(0x04)
30 | REP_CONNECTION_REFUSED = uint8(0x05)
31 | REP_TTL_TIMEOUT = uint8(0x06)
32 | REP_CMD_UNSUPPORTED = uint8(0x07)
33 | REP_ATYP_UNSUPPORTED = uint8(0x08)
34 | REP_UNKNOWN = uint8(0x09)
35 | RSV = uint8(0x00)
36 | )
37 |
38 | var (
39 | ZERO_IP = []byte{0x00, 0x00, 0x00, 0x00}
40 | ZERO_PORT = []byte{0x00, 0x00}
41 | )
42 |
43 | type ServerConn struct {
44 | target string
45 | user string
46 | password string
47 | conn *net.Conn
48 | timeout time.Duration
49 | auth *utils2.BasicAuth
50 | header []byte
51 | ver uint8
52 | //method
53 | methodsCount uint8
54 | methods []uint8
55 | method uint8
56 | //request
57 | cmd uint8
58 | reserve uint8
59 | addressType uint8
60 | dstAddr string
61 | dstPort string
62 | dstHost string
63 | UDPConnListener *net.UDPConn
64 | enableUDP bool
65 | udpIP string
66 | }
67 |
68 | func NewServerConn(conn *net.Conn, timeout time.Duration, auth *utils2.BasicAuth, enableUDP bool, udpHost string, header []byte) *ServerConn {
69 |
70 | s := &ServerConn{
71 | conn: conn,
72 | timeout: timeout,
73 | auth: auth,
74 | header: header,
75 | ver: VERSION_V5,
76 | enableUDP: enableUDP,
77 | udpIP: udpHost,
78 | }
79 | return s
80 |
81 | }
82 | func (s *ServerConn) Close() {
83 | utils2.CloseConn(s.conn)
84 | }
85 | func (s *ServerConn) AuthData() Auth {
86 | return Auth{s.user, s.password}
87 | }
88 | func (s *ServerConn) IsUDP() bool {
89 | return s.cmd == CMD_ASSOCIATE
90 | }
91 | func (s *ServerConn) IsTCP() bool {
92 | return s.cmd == CMD_CONNECT
93 | }
94 | func (s *ServerConn) Method() uint8 {
95 | return s.method
96 | }
97 | func (s *ServerConn) Target() string {
98 | return s.target
99 | }
100 | func (s *ServerConn) Handshake() (err error) {
101 | remoteAddr := (*s.conn).RemoteAddr()
102 | //协商开始
103 | //method select request
104 | var methodReq MethodsRequest
105 | (*s.conn).SetReadDeadline(time.Now().Add(time.Second * s.timeout))
106 |
107 | methodReq, e := NewMethodsRequest((*s.conn), s.header)
108 | (*s.conn).SetReadDeadline(time.Time{})
109 | if e != nil {
110 | (*s.conn).SetReadDeadline(time.Now().Add(time.Second * s.timeout))
111 | methodReq.Reply(Method_NONE_ACCEPTABLE)
112 | (*s.conn).SetReadDeadline(time.Time{})
113 | err = fmt.Errorf("new methods request fail,ERR: %s", e)
114 | return
115 | }
116 | //log.Printf("%v,s.auth == %v && methodReq.Select(Method_NO_AUTH) %v", methodReq.methods, s.auth, methodReq.Select(Method_NO_AUTH))
117 | if s.auth == nil && methodReq.Select(Method_NO_AUTH) && !methodReq.Select(Method_USER_PASS) {
118 | // if !methodReq.Select(Method_NO_AUTH) {
119 | // (*s.conn).SetReadDeadline(time.Now().Add(time.Second * s.timeout))
120 | // methodReq.Reply(Method_NONE_ACCEPTABLE)
121 | // (*s.conn).SetReadDeadline(time.Time{})
122 | // err = fmt.Errorf("none method found : Method_NO_AUTH")
123 | // return
124 | // }
125 | s.method = Method_NO_AUTH
126 | //method select reply
127 | (*s.conn).SetReadDeadline(time.Now().Add(time.Second * s.timeout))
128 | err = methodReq.Reply(Method_NO_AUTH)
129 | (*s.conn).SetReadDeadline(time.Time{})
130 | if err != nil {
131 | err = fmt.Errorf("reply answer data fail,ERR: %s", err)
132 | return
133 | }
134 | // err = fmt.Errorf("% x", methodReq.Bytes())
135 | } else {
136 | //auth
137 | if !methodReq.Select(Method_USER_PASS) {
138 | (*s.conn).SetReadDeadline(time.Now().Add(time.Second * s.timeout))
139 | methodReq.Reply(Method_NONE_ACCEPTABLE)
140 | (*s.conn).SetReadDeadline(time.Time{})
141 | err = fmt.Errorf("none method found : Method_USER_PASS")
142 | return
143 | }
144 | s.method = Method_USER_PASS
145 | //method reply need auth
146 | (*s.conn).SetReadDeadline(time.Now().Add(time.Second * s.timeout))
147 | err = methodReq.Reply(Method_USER_PASS)
148 | (*s.conn).SetReadDeadline(time.Time{})
149 | if err != nil {
150 | err = fmt.Errorf("reply answer data fail,ERR: %s", err)
151 | return
152 | }
153 | //read auth
154 | buf := make([]byte, 500)
155 | var n int
156 | (*s.conn).SetReadDeadline(time.Now().Add(time.Second * s.timeout))
157 | n, err = (*s.conn).Read(buf)
158 | (*s.conn).SetReadDeadline(time.Time{})
159 | if err != nil {
160 | err = fmt.Errorf("read auth info fail,ERR: %s", err)
161 | return
162 | }
163 | r := buf[:n]
164 | s.user = string(r[2 : r[1]+2])
165 | s.password = string(r[2+r[1]+1:])
166 | //err = fmt.Errorf("user:%s,pass:%s", user, pass)
167 | //auth
168 | _addr := strings.Split(remoteAddr.String(), ":")
169 | if s.auth == nil || s.auth.CheckUserPass(s.user, s.password, _addr[0], "") {
170 | (*s.conn).SetDeadline(time.Now().Add(time.Millisecond * time.Duration(s.timeout)))
171 | _, err = (*s.conn).Write([]byte{0x01, 0x00})
172 | (*s.conn).SetDeadline(time.Time{})
173 | if err != nil {
174 | err = fmt.Errorf("answer auth success to %s fail,ERR: %s", remoteAddr, err)
175 | return
176 | }
177 | } else {
178 | (*s.conn).SetDeadline(time.Now().Add(time.Millisecond * time.Duration(s.timeout)))
179 | _, err = (*s.conn).Write([]byte{0x01, 0x01})
180 | (*s.conn).SetDeadline(time.Time{})
181 | if err != nil {
182 | err = fmt.Errorf("answer auth fail to %s fail,ERR: %s", remoteAddr, err)
183 | return
184 | }
185 | err = fmt.Errorf("auth fail from %s", remoteAddr)
186 | return
187 | }
188 | }
189 | //request detail
190 | (*s.conn).SetReadDeadline(time.Now().Add(time.Second * s.timeout))
191 | request, e := NewRequest(*s.conn)
192 | (*s.conn).SetReadDeadline(time.Time{})
193 | if e != nil {
194 | err = fmt.Errorf("read request data fail,ERR: %s", e)
195 | return
196 | }
197 | //协商结束
198 |
199 | switch request.CMD() {
200 | case CMD_BIND:
201 | err = request.TCPReply(REP_UNKNOWN)
202 | if err != nil {
203 | err = fmt.Errorf("TCPReply REP_UNKNOWN to %s fail,ERR: %s", remoteAddr, err)
204 | return
205 | }
206 | err = fmt.Errorf("cmd bind not supported, form: %s", remoteAddr)
207 | return
208 | case CMD_CONNECT:
209 | err = request.TCPReply(REP_SUCCESS)
210 | if err != nil {
211 | err = fmt.Errorf("TCPReply REP_SUCCESS to %s fail,ERR: %s", remoteAddr, err)
212 | return
213 | }
214 | case CMD_ASSOCIATE:
215 | if !s.enableUDP {
216 | request.UDPReply(REP_UNKNOWN, "0.0.0.0:0")
217 | if err != nil {
218 | err = fmt.Errorf("UDPReply REP_UNKNOWN to %s fail,ERR: %s", remoteAddr, err)
219 | return
220 | }
221 | err = fmt.Errorf("cmd associate not supported, form: %s", remoteAddr)
222 | return
223 | }
224 | a, _ := net.ResolveUDPAddr("udp", ":0")
225 | s.UDPConnListener, err = net.ListenUDP("udp", a)
226 | if err != nil {
227 | request.UDPReply(REP_UNKNOWN, "0.0.0.0:0")
228 | err = fmt.Errorf("udp bind fail,ERR: %s , for %s", err, remoteAddr)
229 | return
230 | }
231 | _, port, _ := net.SplitHostPort(s.UDPConnListener.LocalAddr().String())
232 | err = request.UDPReply(REP_SUCCESS, net.JoinHostPort(s.udpIP, port))
233 | if err != nil {
234 | err = fmt.Errorf("UDPReply REP_SUCCESS to %s fail,ERR: %s", remoteAddr, err)
235 | return
236 | }
237 |
238 | }
239 |
240 | //fill socks info
241 | s.target = request.Addr()
242 | s.methodsCount = methodReq.MethodsCount()
243 | s.methods = methodReq.Methods()
244 | s.cmd = request.CMD()
245 | s.reserve = request.reserve
246 | s.addressType = request.addressType
247 | s.dstAddr = request.dstAddr
248 | s.dstHost = request.dstHost
249 | s.dstPort = request.dstPort
250 | return
251 | }
252 |
--------------------------------------------------------------------------------
/lib/goproxy/utils/socks/structs.go:
--------------------------------------------------------------------------------
1 | package socks
2 |
3 | import (
4 | "bytes"
5 | "encoding/binary"
6 | "errors"
7 | "fmt"
8 | "io"
9 | "net"
10 | "strconv"
11 | )
12 |
13 | type Request struct {
14 | ver uint8
15 | cmd uint8
16 | reserve uint8
17 | addressType uint8
18 | dstAddr string
19 | dstPort string
20 | dstHost string
21 | bytes []byte
22 | rw io.ReadWriter
23 | }
24 |
25 | func NewRequest(rw io.ReadWriter, header ...[]byte) (req Request, err interface{}) {
26 | var b = make([]byte, 1024)
27 | var n int
28 | req = Request{rw: rw}
29 | if header != nil && len(header) == 1 && len(header[0]) > 1 {
30 | b = header[0]
31 | n = len(header[0])
32 | } else {
33 | n, err = rw.Read(b[:])
34 | if err != nil {
35 | err = fmt.Errorf("read req data fail,ERR: %s", err)
36 | return
37 | }
38 | }
39 | req.ver = uint8(b[0])
40 | req.cmd = uint8(b[1])
41 | req.reserve = uint8(b[2])
42 | req.addressType = uint8(b[3])
43 | if b[0] != 0x5 {
44 | err = fmt.Errorf("sosck version supported")
45 | req.TCPReply(REP_REQ_FAIL)
46 | return
47 | }
48 | switch b[3] {
49 | case 0x01: //IP V4
50 | req.dstHost = net.IPv4(b[4], b[5], b[6], b[7]).String()
51 | case 0x03: //域名
52 | req.dstHost = string(b[5 : n-2]) //b[4]表示域名的长度
53 | case 0x04: //IP V6
54 | req.dstHost = net.IP{b[4], b[5], b[6], b[7], b[8], b[9], b[10], b[11], b[12], b[13], b[14], b[15], b[16], b[17], b[18], b[19]}.String()
55 | }
56 | req.dstPort = strconv.Itoa(int(b[n-2])<<8 | int(b[n-1]))
57 | req.dstAddr = net.JoinHostPort(req.dstHost, req.dstPort)
58 | req.bytes = b[:n]
59 | return
60 | }
61 | func (s *Request) Bytes() []byte {
62 | return s.bytes
63 | }
64 | func (s *Request) Addr() string {
65 | return s.dstAddr
66 | }
67 | func (s *Request) Host() string {
68 | return s.dstHost
69 | }
70 | func (s *Request) Port() string {
71 | return s.dstPort
72 | }
73 | func (s *Request) AType() uint8 {
74 | return s.addressType
75 | }
76 | func (s *Request) CMD() uint8 {
77 | return s.cmd
78 | }
79 |
80 | func (s *Request) TCPReply(rep uint8) (err error) {
81 | _, err = s.rw.Write(s.NewReply(rep, "0.0.0.0:0"))
82 | return
83 | }
84 | func (s *Request) UDPReply(rep uint8, addr string) (err error) {
85 | _, err = s.rw.Write(s.NewReply(rep, addr))
86 | return
87 | }
88 | func (s *Request) NewReply(rep uint8, addr string) []byte {
89 | var response bytes.Buffer
90 | host, port, _ := net.SplitHostPort(addr)
91 | ip := net.ParseIP(host)
92 | ipb := ip.To4()
93 | atyp := ATYP_IPV4
94 | ipv6 := ip.To16()
95 | zeroiIPv6 := fmt.Sprintf("%d%d%d%d%d%d%d%d%d%d%d%d",
96 | ipv6[0], ipv6[1], ipv6[2], ipv6[3],
97 | ipv6[4], ipv6[5], ipv6[6], ipv6[7],
98 | ipv6[8], ipv6[9], ipv6[10], ipv6[11],
99 | )
100 | if ipb == nil && ipv6 != nil && "0000000000255255" != zeroiIPv6 {
101 | atyp = ATYP_IPV6
102 | ipb = ip.To16()
103 | }
104 | porti, _ := strconv.Atoi(port)
105 | portb := make([]byte, 2)
106 | binary.BigEndian.PutUint16(portb, uint16(porti))
107 | // log.Printf("atyp : %v", atyp)
108 | // log.Printf("ip : %v", []byte(ip))
109 | response.WriteByte(VERSION_V5)
110 | response.WriteByte(rep)
111 | response.WriteByte(RSV)
112 | response.WriteByte(atyp)
113 | response.Write(ipb)
114 | response.Write(portb)
115 | return response.Bytes()
116 | }
117 |
118 | type MethodsRequest struct {
119 | ver uint8
120 | methodsCount uint8
121 | methods []uint8
122 | bytes []byte
123 | rw *io.ReadWriter
124 | }
125 |
126 | func NewMethodsRequest(r io.ReadWriter, header ...[]byte) (s MethodsRequest, err interface{}) {
127 | defer func() {
128 | if err == nil {
129 | err = recover()
130 | }
131 | }()
132 | s = MethodsRequest{}
133 | s.rw = &r
134 | var buf = make([]byte, 300)
135 | var n int
136 | if header != nil && len(header) == 1 && len(header[0]) > 1 {
137 | buf = header[0]
138 | n = len(header[0])
139 | } else {
140 | n, err = r.Read(buf)
141 | if err != nil {
142 | return
143 | }
144 | }
145 | if buf[0] != 0x05 {
146 | err = fmt.Errorf("socks version not supported")
147 | return
148 | }
149 | if n != int(buf[1])+int(2) {
150 | err = fmt.Errorf("socks methods data length error")
151 | return
152 | }
153 | s.ver = buf[0]
154 | s.methodsCount = buf[1]
155 | s.methods = buf[2:n]
156 | s.bytes = buf[:n]
157 | return
158 | }
159 | func (s *MethodsRequest) Version() uint8 {
160 | return s.ver
161 | }
162 | func (s *MethodsRequest) MethodsCount() uint8 {
163 | return s.methodsCount
164 | }
165 | func (s *MethodsRequest) Methods() []uint8 {
166 | return s.methods
167 | }
168 | func (s *MethodsRequest) Select(method uint8) bool {
169 | for _, m := range s.methods {
170 | if m == method {
171 | return true
172 | }
173 | }
174 | return false
175 | }
176 | func (s *MethodsRequest) Reply(method uint8) (err error) {
177 | _, err = (*s.rw).Write([]byte{byte(VERSION_V5), byte(method)})
178 | return
179 | }
180 | func (s *MethodsRequest) Bytes() []byte {
181 | return s.bytes
182 | }
183 |
184 | func ParseUDPPacket(b []byte) (p UDPPacket, err error) {
185 | p = UDPPacket{}
186 | p.frag = uint8(b[2])
187 | p.bytes = b
188 | if p.frag != 0 {
189 | err = fmt.Errorf("FRAG only support for 0 , %v ,%v", p.frag, b[:4])
190 | return
191 | }
192 | portIndex := 0
193 | p.atype = b[3]
194 | switch p.atype {
195 | case ATYP_IPV4: //IP V4
196 | p.dstHost = net.IPv4(b[4], b[5], b[6], b[7]).String()
197 | portIndex = 8
198 | case ATYP_DOMAIN: //域名
199 | domainLen := uint8(b[4])
200 | p.dstHost = string(b[5 : 5+domainLen]) //b[4]表示域名的长度
201 | portIndex = int(5 + domainLen)
202 | case ATYP_IPV6: //IP V6
203 | p.dstHost = net.IP{b[4], b[5], b[6], b[7], b[8], b[9], b[10], b[11], b[12], b[13], b[14], b[15], b[16], b[17], b[18], b[19]}.String()
204 | portIndex = 20
205 | }
206 | p.dstPort = strconv.Itoa(int(b[portIndex])<<8 | int(b[portIndex+1]))
207 | p.data = b[portIndex+2:]
208 | p.header = b[:portIndex+2]
209 | return
210 | }
211 |
212 | type UDPPacket struct {
213 | rsv uint16
214 | frag uint8
215 | atype uint8
216 | dstHost string
217 | dstPort string
218 | data []byte
219 | header []byte
220 | bytes []byte
221 | }
222 |
223 | func (s *UDPPacket) Header() []byte {
224 | return s.header
225 | }
226 | func (s *UDPPacket) NewReply(data []byte) []byte {
227 | var buf bytes.Buffer
228 | buf.Write(s.header)
229 | buf.Write(data)
230 | return buf.Bytes()
231 | }
232 | func (s *UDPPacket) Host() string {
233 | return s.dstHost
234 | }
235 |
236 | func (s *UDPPacket) Port() string {
237 | return s.dstPort
238 | }
239 | func (s *UDPPacket) Data() []byte {
240 | return s.data
241 | }
242 |
243 | type PacketUDP struct {
244 | rsv uint16
245 | frag uint8
246 | atype uint8
247 | dstHost string
248 | dstPort string
249 | data []byte
250 | }
251 |
252 | func NewPacketUDP() (p PacketUDP) {
253 | return PacketUDP{}
254 | }
255 | func (p *PacketUDP) Build(destAddr string, data []byte) (err error) {
256 | host, port, err := net.SplitHostPort(destAddr)
257 | if err != nil {
258 | return
259 | }
260 | p.rsv = 0
261 | p.frag = 0
262 | p.dstHost = host
263 | p.dstPort = port
264 | p.atype = ATYP_IPV4
265 | if ip := net.ParseIP(host); ip != nil {
266 | if ip4 := ip.To4(); ip4 != nil {
267 | p.atype = ATYP_IPV4
268 | ip = ip4
269 | } else {
270 | p.atype = ATYP_IPV6
271 | }
272 | } else {
273 | if len(host) > 255 {
274 | err = errors.New("proxy: destination host name too long: " + host)
275 | return
276 | }
277 | p.atype = ATYP_DOMAIN
278 | }
279 | p.data = data
280 |
281 | return
282 | }
283 | func (p *PacketUDP) Parse(b []byte) (err error) {
284 | p.frag = uint8(b[2])
285 | if p.frag != 0 {
286 | err = fmt.Errorf("FRAG only support for 0 , %v ,%v", p.frag, b[:4])
287 | return
288 | }
289 | portIndex := 0
290 | p.atype = b[3]
291 | switch p.atype {
292 | case ATYP_IPV4: //IP V4
293 | p.dstHost = net.IPv4(b[4], b[5], b[6], b[7]).String()
294 | portIndex = 8
295 | case ATYP_DOMAIN: //域名
296 | domainLen := uint8(b[4])
297 | p.dstHost = string(b[5 : 5+domainLen]) //b[4]表示域名的长度
298 | portIndex = int(5 + domainLen)
299 | case ATYP_IPV6: //IP V6
300 | p.dstHost = net.IP{b[4], b[5], b[6], b[7], b[8], b[9], b[10], b[11], b[12], b[13], b[14], b[15], b[16], b[17], b[18], b[19]}.String()
301 | portIndex = 20
302 | }
303 | p.dstPort = strconv.Itoa(int(b[portIndex])<<8 | int(b[portIndex+1]))
304 | p.data = b[portIndex+2:]
305 | return
306 | }
307 | func (p *PacketUDP) Header() []byte {
308 | header := new(bytes.Buffer)
309 | header.Write([]byte{0x00, 0x00, p.frag, p.atype})
310 | if p.atype == ATYP_IPV4 {
311 | ip := net.ParseIP(p.dstHost)
312 | header.Write(ip.To4())
313 | } else if p.atype == ATYP_IPV6 {
314 | ip := net.ParseIP(p.dstHost)
315 | header.Write(ip.To16())
316 | } else if p.atype == ATYP_DOMAIN {
317 | hBytes := []byte(p.dstHost)
318 | header.WriteByte(byte(len(hBytes)))
319 | header.Write(hBytes)
320 | }
321 | port, _ := strconv.ParseUint(p.dstPort, 10, 64)
322 | portBytes := new(bytes.Buffer)
323 | binary.Write(portBytes, binary.BigEndian, port)
324 | header.Write(portBytes.Bytes()[portBytes.Len()-2:])
325 | return header.Bytes()
326 | }
327 | func (p *PacketUDP) Bytes() []byte {
328 | packBytes := new(bytes.Buffer)
329 | packBytes.Write(p.Header())
330 | packBytes.Write(p.data)
331 | return packBytes.Bytes()
332 | }
333 | func (p *PacketUDP) Host() string {
334 | return p.dstHost
335 | }
336 |
337 | func (p *PacketUDP) Port() string {
338 | return p.dstPort
339 | }
340 | func (p *PacketUDP) Data() []byte {
341 | return p.data
342 | }
343 |
--------------------------------------------------------------------------------
/lib/webtail/webtail.go:
--------------------------------------------------------------------------------
1 | package webtail
2 |
3 | import (
4 | "bufio"
5 | "errors"
6 | "fmt"
7 | "io"
8 | "log"
9 | "net"
10 | "os"
11 | "strings"
12 | "time"
13 |
14 | "net/http"
15 |
16 | "github.com/alecthomas/template"
17 | "github.com/gobwas/ws"
18 | "github.com/gobwas/ws/wsutil"
19 | "github.com/julienschmidt/httprouter"
20 | )
21 |
22 | func home(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
23 | filename := ps.ByName("name")
24 | if strings.Contains(filename, "/") || filename == "" {
25 | log.Printf("invalid log file name : %s", filename)
26 | r.Body.Close()
27 | return
28 | }
29 | homeTemplate.Execute(w, "ws://"+r.Host+"/log/"+filename)
30 | }
31 | func ViewLog(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
32 | filename := ps.ByName("name")
33 | if strings.Contains(filename, "/") || filename == "" {
34 | log.Printf("invalid log file name : %s", filename)
35 | r.Body.Close()
36 | return
37 | }
38 | logfile := fmt.Sprintf("%s/%s.log", basedir, filename)
39 |
40 | ft, err := os.Stat(logfile)
41 | if err != nil {
42 | log.Printf("can not access file %s , %s", logfile, err)
43 | r.Body.Close()
44 | return
45 | }
46 | conn, _, _, err := ws.UpgradeHTTP(r, w, nil)
47 | if err != nil {
48 | log.Printf("ws upgrade fail , %s", err)
49 | r.Body.Close()
50 | return
51 | }
52 | var (
53 | state = ws.StateServerSide
54 | writer = wsutil.NewWriter(conn, state, ws.OpText)
55 | )
56 | log.Printf("client online , %s", conn.RemoteAddr())
57 | content, _ := TailN(logfile, 10)
58 | if content != "" {
59 | _, err := writer.Write([]byte(content))
60 | if err != nil {
61 | conn.Close()
62 | log.Printf("client offline with write , %s", err)
63 | return
64 | }
65 | err = writer.Flush()
66 | if err != nil {
67 | conn.Close()
68 | log.Printf("client offline with flush , %s", err)
69 | return
70 | }
71 | }
72 | file, err := os.Open(logfile)
73 | if err != nil {
74 | conn.Close()
75 | log.Printf("open log file fail , %s", err)
76 | return
77 | }
78 | file.Seek(ft.Size(), 0)
79 | if err != nil {
80 | conn.Close()
81 | file.Close()
82 | log.Printf("sedd log file stat fail , %s", err)
83 | }
84 | reader := bufio.NewReader(file)
85 | timer := time.NewTicker(time.Millisecond * 200)
86 | go func() {
87 | defer func() {
88 | conn.Close()
89 | file.Close()
90 | timer.Stop()
91 | }()
92 | for {
93 | select {
94 | case <-timer.C:
95 | line, err := reader.ReadString('\n')
96 | if line != "" {
97 | if err != nil && err == io.EOF && !strings.Contains(line, "\n") {
98 | line += "\n"
99 | }
100 | _, err = writer.Write([]byte(line))
101 | if err != nil {
102 | log.Printf("client offline with write, %s", err)
103 | return
104 | }
105 | err = writer.Flush()
106 | if err != nil {
107 | log.Printf("client offline with flush , %s", err)
108 | return
109 | }
110 | }
111 | }
112 |
113 | }
114 | }()
115 | go func() {
116 | _, _, err := wsutil.ReadClientData(conn)
117 | if err != nil {
118 | log.Printf("client offline with read , %s", err)
119 | conn.Close()
120 | file.Close()
121 | timer.Stop()
122 | return
123 | }
124 | }()
125 | }
126 |
127 | var (
128 | basedir string
129 | )
130 |
131 | func Serve(address, logDir string) (listener *net.Listener, err error) {
132 | basedir = logDir
133 | l, err := net.Listen("tcp", address)
134 | if err != nil {
135 | return
136 | }
137 | router := httprouter.New()
138 | router.GET("/log/:name", ViewLog)
139 | router.GET("/show/:name", home)
140 | log.Printf("WS Log Server on %s", l.Addr())
141 | go func() { log.Fatal(http.Serve(l, router)) }()
142 | listener = &l
143 | return
144 | }
145 |
146 | func TailN(filename string, numLines int) (string, error) {
147 | //MAKE SURE FILENAME IS GIVEN
148 | //actually, a path to the file
149 | if numLines == 0 {
150 | numLines = 10
151 | }
152 | if len(filename) == 0 {
153 | return "", errors.New("You must provide the path to a file")
154 | }
155 |
156 | //OPEN FILE
157 | file, err := os.Open(filename)
158 | if err != nil {
159 | return "", err
160 | }
161 | defer file.Close()
162 |
163 | //SEEK BACKWARD CHARACTER BY CHARACTER ADDING UP NEW LINES
164 | //offset must start at "-1" otherwise we are already at the EOF
165 | //"-1" from numLines since we ignore "last" newline in a file
166 | numNewLines := 0
167 | var offset int64 = -1
168 | var finalReadStartPos int64
169 | for numNewLines <= numLines-1 {
170 | //seek to new position in file
171 | startPos, err := file.Seek(offset, 2)
172 | if err != nil {
173 | return "", err
174 | }
175 |
176 | //make sure start position can never be less than 0
177 | //aka, you cannot read from before the file starts
178 | if startPos == 0 {
179 | //set to -1 since we +1 to this below
180 | //the position will then start from the first character
181 | finalReadStartPos = -1
182 | break
183 | }
184 |
185 | //read the character at this position
186 | b := make([]byte, 1)
187 | _, err = file.ReadAt(b, startPos)
188 | if err != nil {
189 | return "", err
190 | }
191 |
192 | //ignore if first character being read is a newline
193 | if offset == int64(-1) && string(b) == "\n" {
194 | offset--
195 | continue
196 | }
197 |
198 | //if the character is a newline
199 | //add this to the number of lines read
200 | //and remember position in case we have reached our target number of lines
201 | if string(b) == "\n" {
202 | numNewLines++
203 | finalReadStartPos = startPos
204 | }
205 |
206 | //decrease offset for reading next character
207 | //remember, we are reading backward!
208 | offset--
209 | }
210 |
211 | //READ TO END OF FILE
212 | //add "1" here to move offset from the newline position to first character in line of text
213 | //this position should be the first character in the "first" line of data we want
214 | b := make([]byte, 4096)
215 | n, err := file.ReadAt(b, finalReadStartPos+1)
216 | if n > 0 {
217 | return string(b[:n]), nil
218 | }
219 | return "", err
220 | }
221 |
222 | var homeTemplate = template.Must(template.New("").Parse(`
223 |
224 |
225 |
226 |
227 |
231 |
232 |
233 |
234 |
280 |
281 |
282 | `))
283 |
--------------------------------------------------------------------------------
/main.go:
--------------------------------------------------------------------------------
1 | //go:generate goversioninfo -icon=school.ico
2 | package main
3 |
4 | import (
5 | "github.com/yincongcyincong/proxy-web/server"
6 | _ "net/http/pprof"
7 | )
8 |
9 |
10 | func main() {
11 | server.StartServer()
12 | //clean()
13 | }
14 |
15 |
16 |
--------------------------------------------------------------------------------
/release.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | rm -rf ./zip
3 | mkdir ./zip
4 | set CGO_ENABLED=0
5 | #linux
6 | GOOS=linux GOARCH=386 go build && mv proxy-web proxy/proxy-web/proxy-web && cd proxy && tar zcfv "../zip/proxy-web-linux-386.tar.gz" proxy-web && cd ..
7 | GOOS=linux GOARCH=amd64 go build && mv proxy-web proxy/proxy-web/proxy-web && cd proxy && tar zcfv "../zip/proxy-web-linux-amd64.tar.gz" proxy-web && cd ..
8 | #darwin
9 | GOOS=darwin GOARCH=386 go build go build && mv proxy-web proxy/proxy-web/proxy-web && cd proxy && tar zcfv "../zip/proxy-web-darwin-386.tar.gz" proxy-web && cd ..
10 | GOOS=darwin GOARCH=amd64 go build && mv proxy-web proxy/proxy-web/proxy-web && cd proxy && tar zcfv "../zip/proxy-web-darwin-amd64.tar.gz" proxy-web && cd ..
11 | GOOS=darwin GOARCH=arm go build && mv proxy-web proxy/proxy-web/proxy-web && cd proxy && tar zcfv "../zip/proxy-web-darwin-arm.tar.gz" proxy-web && cd ..
12 | GOOS=darwin GOARCH=arm64 go build && mv proxy-web proxy/proxy-web/proxy-web && cd proxy && tar zcfv "../zip/proxy-web-darwin-arm64.tar.gz"proxy-web && cd ..
13 | #windows
14 | cd proxy/proxy-web
15 | rm -rf proxy-web
16 | cd ..
17 | cd ..
18 | GOOS=windows GOARCH=386 go build -ldflags "-H windowsgui" && mv proxy-web.exe proxy/proxy-web/proxy-web.exe && cd proxy && tar zcfv "../zip/proxy-web-windows-386.tar.gz" proxy-web && cd ..
19 | GOOS=windows GOARCH=amd64 go build -ldflags "-H windowsgui" && mv proxy-web.exe proxy/proxy-web/proxy-web.exe && cd proxy && tar zcfv "../zip/proxy-web-windows-amd64.tar.gz" proxy-web && cd ..
20 |
21 | rm -rf proxy-web proxy-web.exe
22 |
--------------------------------------------------------------------------------
/resource.syso:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yincongcyincong/proxy-web/c4a955db0958186ea1253697411db4eee32e7605/resource.syso
--------------------------------------------------------------------------------
/school.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yincongcyincong/proxy-web/c4a955db0958186ea1253697411db4eee32e7605/school.ico
--------------------------------------------------------------------------------
/server/log.go:
--------------------------------------------------------------------------------
1 | package server
2 |
3 | import (
4 | "github.com/yincongcyincong/proxy-web/lib/webtail"
5 | "log"
6 | )
7 |
8 | func InitShowLog(){
9 | address := ":8822"
10 | basedir := "./log"
11 | listener, err := webtail.Serve(address, basedir)
12 | if err != nil {
13 | log.Fatal(err)
14 | }
15 | log.Printf("tail server on %s",(*listener).Addr())
16 | }
--------------------------------------------------------------------------------
/server/login.go:
--------------------------------------------------------------------------------
1 | package server
2 |
3 | import (
4 | "net/http"
5 | "io"
6 | "github.com/yincongcyincong/proxy-web/utils"
7 | "html/template"
8 | )
9 |
10 | func login(v http.ResponseWriter, r *http.Request) {
11 | t, err := template.ParseFiles(dir + "/view/login.html")
12 | if err != nil {
13 | io.WriteString(v, err.Error())
14 | return
15 | }
16 | t.Execute(v, nil)
17 | }
18 |
19 | func doLogin(v http.ResponseWriter, r *http.Request) {
20 | r.ParseForm()
21 | username, password, err := utils.NewConfig().GetUsernameAndPassword()
22 | if err != nil {
23 | v.WriteHeader(http.StatusInternalServerError)
24 | utils.ReturnJson(err.Error(), "", v)
25 | return
26 | }
27 | sess, _ := globalSessions.SessionStart(v, r)
28 | newSessionId := sess.SessionID()
29 | if lock && (sessionId != newSessionId && sessionId != "") {
30 | v.WriteHeader(http.StatusInternalServerError)
31 | utils.ReturnJson("已有人登陆", "", v)
32 | return
33 | }
34 | if (r.Form.Get("username") == username) && (r.Form.Get("password") == password) {
35 | lock = true
36 | sessionId = sess.SessionID()
37 | defer sess.SessionRelease(v)
38 | utils.ReturnJson("success", "", v)
39 | return
40 | }
41 |
42 | v.WriteHeader(http.StatusInternalServerError)
43 | utils.ReturnJson("登陆失败", "", v)
44 | }
45 |
46 | func logout(v http.ResponseWriter, r *http.Request){
47 | r.ParseForm()
48 | logoutType := r.Form.Get("type")
49 | if logoutType == "1" {
50 | lock = false
51 | sessionId = ""
52 | } else {
53 | lock = false
54 | }
55 |
56 | utils.ReturnJson("success", "", v)
57 | }
58 |
--------------------------------------------------------------------------------
/server/proxy.go:
--------------------------------------------------------------------------------
1 | package server
2 |
3 | import (
4 | "fmt"
5 | "github.com/yincongcyincong/proxy-web/utils"
6 | "html/template"
7 | "io"
8 | "io/ioutil"
9 | "net/http"
10 | "os"
11 | "os/exec"
12 | "path"
13 | "runtime"
14 | "strconv"
15 | "strings"
16 | "time"
17 |
18 | "github.com/yincongcyincong/proxy-web/lib/goproxy/sdk/android-ios"
19 | )
20 |
21 | func add(v http.ResponseWriter, r *http.Request) {
22 | r.ParseForm()
23 | name := r.Form.Get("name")
24 | command := r.Form.Get("command")
25 | autoStart := r.Form.Get("auto")
26 | keyFile := r.Form.Get("key")
27 | crtFile := r.Form.Get("crt")
28 | log := r.Form.Get("log")
29 |
30 | serviceId, err := utils.SaveParams(name, command, autoStart, keyFile, crtFile, log)
31 | if err != nil {
32 | v.WriteHeader(http.StatusInternalServerError)
33 | utils.ReturnJson(err.Error(), "", v)
34 | return
35 | }
36 |
37 | data := make(map[string]interface{})
38 | data["id"] = serviceId
39 | data["command"] = command
40 | data["auto_start"] = autoStart
41 | data["name"] = name
42 | data["log"] = log
43 | data["status"] = "close"
44 | utils.ReturnJson("success", data, v)
45 | }
46 |
47 | func show(w http.ResponseWriter, r *http.Request) {
48 | if r.Method == "GET" {
49 | t, err := template.ParseFiles(dir + "/view/index.html")
50 | if err != nil {
51 | io.WriteString(w, err.Error())
52 | return
53 | }
54 | autoStart := utils.NewConfig().GetAutoStart()
55 | isProxy := utils.NewConfig().GetProxySetting()
56 | proxySetting, _ := utils.GetProxy()
57 | var ip, port string
58 | if _, ok := proxySetting["ip"]; ok {
59 | ip = proxySetting["ip"]
60 | }
61 | if _, ok := proxySetting["port"]; ok {
62 | port = proxySetting["port"]
63 | }
64 |
65 | proxyVersion := proxy.Version()
66 | data := map[string]interface{}{"auto_start": autoStart, "proxy_version": proxyVersion, "version": version, "proxy": isProxy, "ip": ip, "port": port}
67 |
68 | t.Execute(w, data)
69 | }
70 | }
71 |
72 | func getData(v http.ResponseWriter, r *http.Request) {
73 | var data interface{}
74 | var err error
75 | r.ParseForm()
76 | id := r.Form.Get("id")
77 |
78 | if id == "0" {
79 | data, err = utils.GetAllParams()
80 | } else {
81 | data, err = utils.GetParamsById(id)
82 | }
83 | if err != nil {
84 | v.WriteHeader(http.StatusInternalServerError)
85 | utils.ReturnJson(err.Error(), "", v)
86 | return
87 | }
88 | utils.ReturnJson("success", data, v)
89 | }
90 |
91 | func link(v http.ResponseWriter, r *http.Request) {
92 | if r.Method == "POST" {
93 | r.ParseForm()
94 | var command string
95 | var err error
96 | id := r.Form.Get("id")
97 | command, err = getCommand(id)
98 | if err != nil {
99 | v.WriteHeader(http.StatusInternalServerError)
100 | utils.ReturnJson(err.Error(), "", v)
101 | return
102 | }
103 | fmt.Println(command)
104 | errStr := proxy.Start(id, command)
105 | if errStr != "" {
106 | v.WriteHeader(http.StatusInternalServerError)
107 | utils.ReturnJson(errStr, "", v)
108 | return
109 | }
110 | utils.ChangeParameterDataById(id, "open")
111 | utils.ReturnJson("success", "", v)
112 | }
113 | }
114 |
115 | func getCommand(id string) (command string, err error) {
116 | parameter, err := utils.GetParamsById(id)
117 | if err != nil {
118 | return "", err
119 | }
120 |
121 | command += parameter["command"].(string)
122 | command = strings.Replace(command, "\n", " ", -1)
123 | command = strings.Replace(command, "\r", " ", -1)
124 | command = strings.Replace(command, " ", " ", -1)
125 |
126 | if parameter["key_file"].(string) != "" {
127 | command += " -K " + parameter["key_file"].(string)
128 | }
129 | if parameter["crt_file"].(string) != "" {
130 | command += " -C " + parameter["crt_file"].(string)
131 | }
132 | if parameter["log"] == "yes" {
133 | command += " --log ./log/" + parameter["id"].(string) + ".log"
134 | }
135 | s, err := os.Stat("./log/")
136 | if err != nil || !s.IsDir() {
137 | os.Mkdir("./log/", os.ModePerm)
138 | }
139 | return command, nil
140 | }
141 |
142 | func close(v http.ResponseWriter, r *http.Request) {
143 | r.ParseForm()
144 | id := r.Form.Get("id")
145 | if id == "undefined" {
146 | v.WriteHeader(http.StatusInternalServerError)
147 | utils.ReturnJson("id not found", "", v)
148 | return
149 | }
150 | err := utils.ChangeParameterDataById(id, "close")
151 | if err != nil {
152 | v.WriteHeader(http.StatusInternalServerError)
153 | utils.ReturnJson(err.Error(), "", v)
154 | return
155 | }
156 | proxy.Stop(id)
157 | utils.ReturnJson("success", "", v)
158 | return
159 | }
160 |
161 | func uploade(v http.ResponseWriter, r *http.Request) {
162 | if r.Method == "POST" {
163 | file, head, err := r.FormFile("file")
164 | fileSuffix := path.Ext(head.Filename)
165 | if err != nil {
166 | v.WriteHeader(http.StatusInternalServerError)
167 | utils.ReturnJson(err.Error(), "", v)
168 | return
169 | }
170 | defer file.Close()
171 | t := time.Now().Unix()
172 | fw, err := os.Create(dir + "/upload/" + strconv.FormatInt(t, 10) + fileSuffix)
173 | defer fw.Close()
174 | if err != nil {
175 | v.WriteHeader(http.StatusInternalServerError)
176 | utils.ReturnJson(err.Error(), "", v)
177 | return
178 | }
179 | _, err = io.Copy(fw, file)
180 | if err != nil {
181 | v.WriteHeader(http.StatusInternalServerError)
182 | utils.ReturnJson(err.Error(), "", v)
183 | return
184 | }
185 | name := fw.Name()
186 | utils.ReturnJson("", name, v)
187 | return
188 | }
189 | }
190 |
191 | func update(v http.ResponseWriter, r *http.Request) {
192 | r.ParseForm()
193 | id := r.Form.Get("id")
194 | name := r.Form.Get("name")
195 | command := r.Form.Get("command")
196 | autoStart := r.Form.Get("auto")
197 | keyFile := r.Form.Get("key")
198 | crtFile := r.Form.Get("crt")
199 | log := r.Form.Get("log")
200 |
201 | err := utils.UpdateParams(id, name, command, autoStart, keyFile, crtFile, log)
202 | if err != nil {
203 | v.WriteHeader(http.StatusInternalServerError)
204 | utils.ReturnJson(err.Error(), "", v)
205 | return
206 | }
207 | utils.ReturnJson("success", "", v)
208 | }
209 |
210 | func deleteParameter(v http.ResponseWriter, r *http.Request) {
211 | r.ParseForm()
212 | id := r.Form.Get("id")
213 | err := utils.DeleteParam(id)
214 | if err != nil {
215 | v.WriteHeader(http.StatusInternalServerError)
216 | utils.ReturnJson(err.Error(), "", v)
217 | }
218 | utils.ReturnJson("success", "", v)
219 | }
220 |
221 | func saveSetting(v http.ResponseWriter, r *http.Request) {
222 | r.ParseForm()
223 | auto := r.Form.Get("auto")
224 | proxy := r.Form.Get("proxy")
225 | ip := r.Form.Get("ip")
226 | port := r.Form.Get("port")
227 |
228 | config := utils.NewConfig()
229 | isAutoStart := config.GetAutoStart()
230 | isProxy := config.GetProxySetting()
231 |
232 | // 判断是否开启全局代理
233 | if proxy == "proxy" {
234 | if !isProxy {
235 | err := utils.StartProxy(ip, port)
236 | if err != nil {
237 | v.WriteHeader(http.StatusInternalServerError)
238 | utils.ReturnJson("修改配置失败,请使用root权限操作", err.Error(), v)
239 | return
240 | }
241 | }
242 |
243 | } else {
244 | if isProxy {
245 | utils.StopProxy(ip, port)
246 | }
247 | }
248 |
249 | switch runtime.GOOS {
250 | case "windows":
251 |
252 | if auto == "auto" {
253 | if !isAutoStart {
254 | command := dir + `/config/autostart.exe enable -k proxy-web -n proxy-web -c`
255 | commandSlice := strings.Split(command, " ")
256 | commandSlice = append(commandSlice, dir+`/proxy-web.exe c:`)
257 | cmd := exec.Command(commandSlice[0], commandSlice[1:]...)
258 | output, _ := cmd.CombinedOutput()
259 | outputStr := string(output)
260 | if !strings.Contains(outputStr, "Done") {
261 | v.WriteHeader(http.StatusInternalServerError)
262 | utils.ReturnJson("修改配置失败,请使用root权限操作", outputStr, v)
263 | return
264 | }
265 | is_success := utils.NewConfig().UpdateAutoStart("true")
266 | if !is_success {
267 | v.WriteHeader(http.StatusInternalServerError)
268 | utils.ReturnJson("修改配置失败,请使用root权限操作", "", v)
269 | return
270 | }
271 | }
272 |
273 | } else {
274 | if isAutoStart {
275 | command := dir + `/config/autostart.exe disable -k proxy-web`
276 | commandSlice := strings.Split(command, " ")
277 | cmd := exec.Command(commandSlice[0], commandSlice[1:]...)
278 | output, _ := cmd.CombinedOutput()
279 | outputStr := string(output)
280 | if !strings.Contains(outputStr, "Done") {
281 | v.WriteHeader(http.StatusInternalServerError)
282 | utils.ReturnJson("修改配置失败,请使用root权限操作", outputStr, v)
283 | return
284 | }
285 | is_success := utils.NewConfig().UpdateAutoStart("false")
286 | if !is_success {
287 | v.WriteHeader(http.StatusInternalServerError)
288 | utils.ReturnJson("修改配置失败,请使用root权限操作", "", v)
289 | return
290 | }
291 | }
292 | }
293 |
294 | case "darwin":
295 | if auto == "auto" {
296 | if !isAutoStart {
297 | command := dir + `/config/autostart enable -k proxy -n proxy -c`
298 | commandSlice := strings.Split(command, " ")
299 | commandSlice = append(commandSlice, dir+"/proxy-web")
300 | cmd := exec.Command(commandSlice[0], commandSlice[1:]...)
301 | output, err := cmd.CombinedOutput()
302 | if err != nil {
303 | v.WriteHeader(http.StatusInternalServerError)
304 | utils.ReturnJson("修改配置失败,请使用root权限操作", string(output), v)
305 | return
306 | }
307 | is_success := utils.NewConfig().UpdateAutoStart("true")
308 | if !is_success {
309 | v.WriteHeader(http.StatusInternalServerError)
310 | utils.ReturnJson("修改配置失败,请使用root权限操作", "", v)
311 | return
312 | }
313 | }
314 | } else {
315 | if isAutoStart {
316 | command := dir + `/config/autostart disable -k proxy`
317 | commandSlice := strings.Split(command, " ")
318 | cmd := exec.Command(commandSlice[0], commandSlice[1:]...)
319 | output, _ := cmd.CombinedOutput()
320 | is_success := utils.NewConfig().UpdateAutoStart("false")
321 | if !is_success {
322 | v.WriteHeader(http.StatusInternalServerError)
323 | utils.ReturnJson("修改配置失败,请使用root权限操作", string(output), v)
324 | return
325 | }
326 | }
327 | }
328 | case "linux":
329 | if auto == "auto" {
330 | if !isAutoStart {
331 | data := `#!/bin/sh
332 | ` + dir + `/proxy-web`
333 | err := ioutil.WriteFile(dir+"/config/autostart.sh", []byte(data), 0777)
334 | if err != nil {
335 | v.WriteHeader(http.StatusInternalServerError)
336 | utils.ReturnJson("修改配置失败,请使用root权限操作", "", v)
337 | return
338 | }
339 | fd, err := os.OpenFile("/etc/crontab", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0777)
340 | if err != nil {
341 | v.WriteHeader(http.StatusInternalServerError)
342 | utils.ReturnJson("修改配置失败,请使用root权限操作", "", v)
343 | return
344 | }
345 | defer fd.Close()
346 | fileData, _ := ioutil.ReadAll(fd)
347 | if !strings.Contains(string(fileData), dir+"/config/autostart.sh") {
348 | fd.Write([]byte(`@reboot root ` + dir + `/config/autostart.sh
349 | `))
350 | }
351 |
352 | is_success := utils.NewConfig().UpdateAutoStart("true")
353 | if !is_success {
354 | v.WriteHeader(http.StatusInternalServerError)
355 | utils.ReturnJson("修改配置失败,请使用root权限操作", "", v)
356 | return
357 | }
358 | }
359 | } else {
360 | if isAutoStart {
361 | os.Remove(dir + "/config/autostart.sh")
362 | is_success := utils.NewConfig().UpdateAutoStart("false")
363 | if !is_success {
364 | v.WriteHeader(http.StatusInternalServerError)
365 | utils.ReturnJson("修改配置失败,请使用root权限操作", "", v)
366 | return
367 | }
368 | }
369 | }
370 |
371 | }
372 |
373 | // 修改数据
374 | if proxy == "proxy" {
375 | if !isProxy {
376 | is_success := utils.NewConfig().UpdateProxy("true")
377 | if !is_success {
378 | v.WriteHeader(http.StatusInternalServerError)
379 | utils.ReturnJson("修改配置失败,请使用root权限操作", "", v)
380 | return
381 | }
382 | err := utils.UpdateProxy(ip, port)
383 | if err != nil {
384 | v.WriteHeader(http.StatusInternalServerError)
385 | utils.ReturnJson(err.Error(), "", v)
386 | return
387 | }
388 | }
389 | } else {
390 | if isProxy {
391 | is_success := utils.NewConfig().UpdateProxy("false")
392 | if !is_success {
393 | v.WriteHeader(http.StatusInternalServerError)
394 | utils.ReturnJson("修改配置失败,请使用root权限操作", "", v)
395 | return
396 | }
397 | }
398 | }
399 |
400 | utils.ReturnJson("success", "", v)
401 | return
402 | }
403 |
--------------------------------------------------------------------------------
/server/server.go:
--------------------------------------------------------------------------------
1 | package server
2 |
3 | import (
4 | "fmt"
5 | proxy "github.com/yincongcyincong/proxy-web/lib/goproxy/sdk/android-ios"
6 | "log"
7 | "net/http"
8 | "os"
9 | "path/filepath"
10 | "strings"
11 |
12 | "github.com/astaxie/beego/session"
13 | "github.com/yincongcyincong/proxy-web/utils"
14 | )
15 |
16 | var globalSessions *session.Manager
17 | var version = "v2.0"
18 | var lock = false
19 | var sessionId string
20 | var dir string
21 |
22 | func basicAuth(handler func(http.ResponseWriter, *http.Request)) http.Handler {
23 | return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
24 | sess, _ := globalSessions.SessionStart(w, r)
25 | newSessionId := sess.SessionID()
26 | if sessionId != newSessionId {
27 | login(w, r)
28 | return
29 | }
30 | handler(w, r)
31 | })
32 | }
33 |
34 | func StartServer() {
35 | // 文件路径
36 | dir, _ = filepath.Abs(filepath.Dir(os.Args[0]))
37 | dir = strings.Replace(dir, "\\", "/", -1)
38 |
39 | // 启动一个websocket,判断是否有人登陆
40 | //go StartWebscoket()
41 | SetProxy()
42 | AutoStart()
43 | InitShowLog()
44 | initSession()
45 | http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir(dir+"/static"))))
46 | http.Handle("/", basicAuth(show))
47 | http.HandleFunc("/add", add)
48 | http.HandleFunc("/update", update)
49 | http.HandleFunc("/close", close)
50 | http.HandleFunc("/link", link)
51 | http.HandleFunc("/getData", getData)
52 | http.HandleFunc("/uploade", uploade)
53 | http.HandleFunc("/delete", deleteParameter)
54 | http.HandleFunc("/saveSetting", saveSetting)
55 | http.HandleFunc("/login", login)
56 | http.HandleFunc("/doLogin", doLogin)
57 | http.HandleFunc("/logout", logout)
58 | //http.Handle("/keygen", basicAuth(keygen))
59 | port, err := utils.NewConfig().GetServerPort()
60 | if err != nil {
61 | log.Fatal("get port failure: ", err)
62 | }
63 | fmt.Println("proxy-web: 127.0.0.1" + port)
64 | err = http.ListenAndServe(port, nil)
65 | if err != nil {
66 | log.Fatal("listen port failure", err)
67 | }
68 | }
69 |
70 | func AutoStart() {
71 | datas, err := utils.InitParams()
72 | if err != nil {
73 | return
74 | }
75 | for _, data := range datas {
76 | var command string
77 | command += data["command"].(string)
78 | command = strings.Replace(command, "\n", "", -1)
79 | command = strings.Replace(command, "\r", "", -1)
80 | command = strings.Replace(command, " ", " ", -1)
81 | if data["key_file"].(string) != "" {
82 | command += " -K " + data["key_file"].(string)
83 | }
84 | if data["crt_file"].(string) != "" {
85 | command += " -C " + data["crt_file"].(string)
86 | }
87 | if data["log"] == "yes" {
88 | command += " --log " + dir + "/log/" + data["id"].(string) + ".log"
89 | }
90 | s, err := os.Stat(dir + "/log/")
91 | if err != nil || !s.IsDir() {
92 | os.Mkdir(dir+"/log/", os.ModePerm)
93 | }
94 | go autoRunCommand(data["id"].(string), command)
95 | }
96 | }
97 |
98 | func autoRunCommand(id, command string) {
99 | fmt.Println(command)
100 | errStr := proxy.Start(id, command)
101 | if errStr != "" {
102 | utils.ChangeParameterDataById(id, "close")
103 | }
104 | }
105 |
106 | func initSession() {
107 | sessionConfig := &session.ManagerConfig{
108 | CookieName: "sessionid",
109 | EnableSetCookie: true,
110 | Gclifetime: 360000,
111 | Maxlifetime: 360000,
112 | Secure: false,
113 | CookieLifeTime: 360000,
114 | ProviderConfig: dir + "/tmp",
115 | }
116 | globalSessions, _ = session.NewManager("file", sessionConfig)
117 | go globalSessions.GC()
118 | }
119 |
120 | func SetProxy() {
121 | data, err := utils.GetProxy()
122 | if err != nil {
123 | return
124 | }
125 | proxy := utils.NewConfig().GetProxySetting()
126 | if !proxy {
127 | return
128 | }
129 | utils.StartProxy(data["ip"], data["port"])
130 | }
131 |
132 | //func StartWebscoket() {
133 | // http.Handle("/websocket", websocket.Handler(svrConnHandler))
134 | // log.Fatal(http.ListenAndServe(":8222", nil))
135 | //}
136 | //
137 | //func svrConnHandler(conn *websocket.Conn) {
138 | // request := make([]byte, 128)
139 | // defer conn.Close()
140 | // readLen, err := conn.Read(request)
141 | // if err != nil {
142 | // return
143 | // }
144 | //
145 | // if string(request[:readLen]) == "close" {
146 | // lock = false
147 | // } else {
148 | // lock = true
149 | // }
150 | //
151 | //}
152 |
--------------------------------------------------------------------------------
/static/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yincongcyincong/proxy-web/c4a955db0958186ea1253697411db4eee32e7605/static/.DS_Store
--------------------------------------------------------------------------------
/static/css/price.css:
--------------------------------------------------------------------------------
1 | body{
2 | background-image: url(../images/NX-Desktop-BG.png);
3 | }
4 |
5 | #pricing-table {
6 | margin: 100px auto;
7 | text-align: center;
8 | width: 0px; /* total computed width = 222 x 3 + 226 */
9 | }
10 |
11 | #pricing-table .plan {
12 | font: 12px 'Lucida Sans', 'trebuchet MS', Arial, Helvetica;
13 | text-shadow: 0 1px rgba(255,255,255,.8);
14 | background: #fff;
15 | border: 1px solid #ddd;
16 | color: #333;
17 | padding: 20px;
18 | width: 200px; /* plan width = 180 + 20 + 20 + 1 + 1 = 222px */
19 | float: left;
20 | position: relative;
21 | }
22 |
23 | #pricing-table #most-popular {
24 | z-index: 2;
25 | top: -13px;
26 | border-width: 3px;
27 | padding: 30px 20px;
28 | -moz-border-radius: 5px;
29 | -webkit-border-radius: 5px;
30 | border-radius: 5px;
31 | -moz-box-shadow: 20px 0 10px -10px rgba(0, 0, 0, .15), -20px 0 10px -10px rgba(0, 0, 0, .15);
32 | -webkit-box-shadow: 20px 0 10px -10px rgba(0, 0, 0, .15), -20px 0 10px -10px rgba(0, 0, 0, .15);
33 | box-shadow: 20px 0 10px -10px rgba(0, 0, 0, .15), -20px 0 10px -10px rgba(0, 0, 0, .15);
34 | }
35 |
36 | #pricing-table .plan:nth-child(1) {
37 | -moz-border-radius: 5px 0 0 5px;
38 | -webkit-border-radius: 5px 0 0 5px;
39 | border-radius: 5px 0 0 5px;
40 | }
41 |
42 | #pricing-table .plan:nth-child(4) {
43 | -moz-border-radius: 0 5px 5px 0;
44 | -webkit-border-radius: 0 5px 5px 0;
45 | border-radius: 0 5px 5px 0;
46 | }
47 |
48 | /* --------------- */
49 |
50 | #pricing-table h3 {
51 | font-size: 20px;
52 | font-weight: normal;
53 | padding: 20px;
54 | margin: -20px -20px 50px -20px;
55 | background-color: #eee;
56 | background-image: -moz-linear-gradient(#000,#74ebe6);
57 | background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#eee));
58 | background-image: -webkit-linear-gradient(#fff, #eee);
59 | background-image: -o-linear-gradient(#fff, #eee);
60 | background-image: -ms-linear-gradient(#fff, #eee);
61 | background-image: linear-gradient(#000,#74ebe6);
62 | }
63 |
64 | #pricing-table #most-popular h3 {
65 | background-color: #ddd;
66 | background-image: -moz-linear-gradient(#eee,#ddd);
67 | background-image: -webkit-gradient(linear, left top, left bottom, from(#eee), to(#ddd));
68 | background-image: -webkit-linear-gradient(#eee, #ddd);
69 | background-image: -o-linear-gradient(#eee, #ddd);
70 | background-image: -ms-linear-gradient(#eee, #ddd);
71 | background-image: linear-gradient(#000,#74ebe6);
72 | margin-top: -30px;
73 | padding-top: 30px;
74 | -moz-border-radius: 5px 5px 0 0;
75 | -webkit-border-radius: 5px 5px 0 0;
76 | border-radius: 5px 5px 0 0;
77 | }
78 |
79 | #pricing-table .plan:nth-child(1) h3 {
80 | -moz-border-radius: 5px 0 0 0;
81 | -webkit-border-radius: 5px 0 0 0;
82 | border-radius: 5px 0 0 0;
83 | }
84 |
85 | #pricing-table .plan:nth-child(4) h3 {
86 | -moz-border-radius: 0 5px 0 0;
87 | -webkit-border-radius: 0 5px 0 0;
88 | border-radius: 0 5px 0 0;
89 | }
90 |
91 | #pricing-table h3 span {
92 | display: block;
93 | cursor:pointer;
94 | font: bold 25px/100px Georgia, Serif;
95 | color: #777;
96 | background: #fff;
97 | border: 5px solid #fff;
98 | height: 100px;
99 | width: 100px;
100 | margin: 10px auto -65px;
101 | -moz-border-radius: 100px;
102 | -webkit-border-radius: 100px;
103 | border-radius: 100px;
104 | -moz-box-shadow: 0 5px 20px #ddd inset, 0 3px 0 #999 inset;
105 | -webkit-box-shadow: 0 5px 20px #ddd inset, 0 3px 0 #999 inset;
106 | box-shadow: 0 5px 20px #ddd inset, 0 3px 0 #999 inset;
107 | }
108 |
109 | /* --------------- */
110 |
111 | #pricing-table ul {
112 | margin: 20px 0 0 0;
113 | padding: 0;
114 | list-style: none;
115 | }
116 |
117 | #pricing-table li {
118 | border-top: 1px solid #ddd;
119 | padding: 10px 0;
120 | }
121 |
122 | /* --------------- */
123 |
124 | .signup {
125 | position: relative;
126 | padding: 8px 13px;
127 | margin: 20px 0 10px 0;
128 | color: #74ebe6 !important;
129 | text-transform: uppercase;
130 | text-decoration: none !important;
131 | display: inline-block;
132 | cursor:pointer;
133 | background-color: #000;
134 | background-image: -moz-linear-gradient(#72ce3f, #62bc30);
135 | background-image: -webkit-gradient(linear, left top, left bottom, from(#72ce3f), to(#62bc30));
136 | background-image: -webkit-linear-gradient(#72ce3f, #62bc30);
137 | background-image: -o-linear-gradient(#72ce3f, #62bc30);
138 | background-image: -ms-linear-gradient(#72ce3f, #62bc30);
139 | background-image: linear-gradient(#000, #000);
140 | -moz-border-radius: 3px;
141 | -webkit-border-radius: 3px;
142 | border-radius: 3px;
143 | text-shadow: 0 1px 0 rgba(0,0,0,.3);
144 | -moz-box-shadow: 0 1px 0 rgba(255, 255, 255, .5), 0 2px 0 rgba(0, 0, 0, .7);
145 | -webkit-box-shadow: 0 1px 0 rgba(255, 255, 255, .5), 0 2px 0 rgba(0, 0, 0, .7);
146 | box-shadow: 0 1px 0 rgba(255, 255, 255, .5), 0 2px 0 rgba(0, 0, 0, .7);
147 | }
148 |
149 |
150 | .signupNoMargin {
151 | position: relative;
152 | padding: 8px 20px;
153 | color: #74ebe6;
154 | text-transform: uppercase;
155 | text-decoration: none;
156 | display: inline-block;
157 | cursor:pointer;
158 | background-color: #000;
159 | background-image: -moz-linear-gradient(#72ce3f, #62bc30);
160 | background-image: -webkit-gradient(linear, left top, left bottom, from(#72ce3f), to(#62bc30));
161 | background-image: -webkit-linear-gradient(#72ce3f, #62bc30);
162 | background-image: -o-linear-gradient(#72ce3f, #62bc30);
163 | background-image: -ms-linear-gradient(#72ce3f, #62bc30);
164 | background-image: linear-gradient(#000, #000);
165 | -moz-border-radius: 3px;
166 | -webkit-border-radius: 3px;
167 | border-radius: 3px;
168 | text-shadow: 0 1px 0 rgba(0,0,0,.3);
169 | -moz-box-shadow: 0 1px 0 rgba(255, 255, 255, .5), 0 2px 0 rgba(0, 0, 0, .7);
170 | -webkit-box-shadow: 0 1px 0 rgba(255, 255, 255, .5), 0 2px 0 rgba(0, 0, 0, .7);
171 | box-shadow: 0 1px 0 rgba(255, 255, 255, .5), 0 2px 0 rgba(0, 0, 0, .7);
172 | }
173 |
174 | .signupNoMargin:hover{
175 | color: #74ebe6;
176 | text-decoration : none;
177 | cursor:pointer;
178 | }
179 |
180 | .modal-header{
181 | background-image: linear-gradient(#000,#74ebe6);
182 | }
183 |
184 | #exampleModalLabel{
185 | color:#fff;
186 | }
187 |
188 | .modal-header span{
189 | color:#fff;
190 | }
191 |
192 | .signupNoMarginPadding {
193 | position: relative;
194 | color: #74ebe6;
195 | text-transform: uppercase;
196 | text-decoration: none;
197 | display: inline-block;
198 | cursor:pointer;
199 | background-color: #000;
200 | background-image: -moz-linear-gradient(#72ce3f, #62bc30);
201 | background-image: -webkit-gradient(linear, left top, left bottom, from(#72ce3f), to(#62bc30));
202 | background-image: -webkit-linear-gradient(#72ce3f, #62bc30);
203 | background-image: -o-linear-gradient(#72ce3f, #62bc30);
204 | background-image: -ms-linear-gradient(#72ce3f, #62bc30);
205 | background-image: linear-gradient(#000, #000);
206 | -moz-border-radius: 3px;
207 | -webkit-border-radius: 3px;
208 | border-radius: 3px;
209 | text-shadow: 0 1px 0 rgba(0,0,0,.3);
210 | -moz-box-shadow: 0 1px 0 rgba(255, 255, 255, .5), 0 2px 0 rgba(0, 0, 0, .7);
211 | -webkit-box-shadow: 0 1px 0 rgba(255, 255, 255, .5), 0 2px 0 rgba(0, 0, 0, .7);
212 | box-shadow: 0 1px 0 rgba(255, 255, 255, .5), 0 2px 0 rgba(0, 0, 0, .7);
213 | }
214 |
215 | .signupNoMarginPadding:hover{
216 | color: #74ebe6;
217 | text-decoration : none;
218 | cursor:pointer;
219 | }
220 |
221 | #pricing-table .signup:active, #pricing-table .signup:focus {
222 | background: #000;
223 | top: 2px;
224 | -moz-box-shadow: 0 0 3px rgba(0, 0, 0, .7) inset;
225 | -webkit-box-shadow: 0 0 3px rgba(0, 0, 0, .7) inset;
226 | box-shadow: 0 0 3px rgba(0, 0, 0, .7) inset;
227 | }
228 |
229 | /* --------------- */
230 |
231 | .clear:before, .clear:after {
232 | content:"";
233 | display:table
234 | }
235 |
236 | .clear:after {
237 | clear:both
238 | }
239 |
240 | .clear {
241 | zoom:1
242 | }
243 |
244 | .plan span{
245 | word-wrap:break-word;
246 | }
247 |
248 | .commandSpan {
249 | height: 50px;
250 | }
251 |
--------------------------------------------------------------------------------
/static/fonts/glyphicons-halflings-regular.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yincongcyincong/proxy-web/c4a955db0958186ea1253697411db4eee32e7605/static/fonts/glyphicons-halflings-regular.eot
--------------------------------------------------------------------------------
/static/fonts/glyphicons-halflings-regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yincongcyincong/proxy-web/c4a955db0958186ea1253697411db4eee32e7605/static/fonts/glyphicons-halflings-regular.ttf
--------------------------------------------------------------------------------
/static/fonts/glyphicons-halflings-regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yincongcyincong/proxy-web/c4a955db0958186ea1253697411db4eee32e7605/static/fonts/glyphicons-halflings-regular.woff
--------------------------------------------------------------------------------
/static/fonts/glyphicons-halflings-regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yincongcyincong/proxy-web/c4a955db0958186ea1253697411db4eee32e7605/static/fonts/glyphicons-halflings-regular.woff2
--------------------------------------------------------------------------------
/static/images/NX-Desktop-BG.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yincongcyincong/proxy-web/c4a955db0958186ea1253697411db4eee32e7605/static/images/NX-Desktop-BG.png
--------------------------------------------------------------------------------
/static/js/npm.js:
--------------------------------------------------------------------------------
1 | // This file is autogenerated via the `commonjs` Grunt task. You can require() this file in a CommonJS environment.
2 | require('../../js/transition.js')
3 | require('../../js/alert.js')
4 | require('../../js/button.js')
5 | require('../../js/carousel.js')
6 | require('../../js/collapse.js')
7 | require('../../js/dropdown.js')
8 | require('../../js/modal.js')
9 | require('../../js/tooltip.js')
10 | require('../../js/popover.js')
11 | require('../../js/scrollspy.js')
12 | require('../../js/tab.js')
13 | require('../../js/affix.js')
--------------------------------------------------------------------------------
/static/js/theme/default/icon-ext.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yincongcyincong/proxy-web/c4a955db0958186ea1253697411db4eee32e7605/static/js/theme/default/icon-ext.png
--------------------------------------------------------------------------------
/static/js/theme/default/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yincongcyincong/proxy-web/c4a955db0958186ea1253697411db4eee32e7605/static/js/theme/default/icon.png
--------------------------------------------------------------------------------
/static/js/theme/default/loading-0.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yincongcyincong/proxy-web/c4a955db0958186ea1253697411db4eee32e7605/static/js/theme/default/loading-0.gif
--------------------------------------------------------------------------------
/static/js/theme/default/loading-1.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yincongcyincong/proxy-web/c4a955db0958186ea1253697411db4eee32e7605/static/js/theme/default/loading-1.gif
--------------------------------------------------------------------------------
/static/js/theme/default/loading-2.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yincongcyincong/proxy-web/c4a955db0958186ea1253697411db4eee32e7605/static/js/theme/default/loading-2.gif
--------------------------------------------------------------------------------
/static/webupload/Uploader.swf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yincongcyincong/proxy-web/c4a955db0958186ea1253697411db4eee32e7605/static/webupload/Uploader.swf
--------------------------------------------------------------------------------
/static/webupload/webuploader.css:
--------------------------------------------------------------------------------
1 | .webuploader-container {
2 | position: relative;
3 | }
4 | .webuploader-element-invisible {
5 | position: absolute !important;
6 | clip: rect(1px 1px 1px 1px); /* IE6, IE7 */
7 | clip: rect(1px,1px,1px,1px);
8 | }
9 | .webuploader-pick {
10 | position: relative;
11 | display: inline-block;
12 | cursor: pointer;
13 | background: #00b7ee;
14 | padding: 10px 15px;
15 | color: #fff;
16 | text-align: center;
17 | border-radius: 3px;
18 | overflow: hidden;
19 | }
20 | .webuploader-pick-hover {
21 | background: #00a2d4;
22 | }
23 |
24 | .webuploader-pick-disable {
25 | opacity: 0.6;
26 | pointer-events:none;
27 | }
28 |
29 |
--------------------------------------------------------------------------------
/utils/always.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | func AlwaysCommand(always string, level int) string {
4 | if always == "1" && level == 2 {
5 | return " --always"
6 | }
7 | return ""
8 | }
9 |
--------------------------------------------------------------------------------
/utils/compress.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | func CompressCommand(compress string) string {
4 | if compress == "1" {
5 | return " --c"
6 | }
7 | return ""
8 | }
9 |
--------------------------------------------------------------------------------
/utils/config.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import (
4 | "log"
5 | "os"
6 | "path/filepath"
7 | "strings"
8 |
9 | "github.com/Unknwon/goconfig"
10 | )
11 |
12 | type Config struct {
13 | File *goconfig.ConfigFile
14 | }
15 |
16 | func NewConfig() *Config {
17 | dir, _ := filepath.Abs(filepath.Dir(os.Args[0]))
18 | dir = strings.Replace(dir, "\\", "/", -1)
19 | config, err := goconfig.LoadConfigFile(dir + "/config/config.ini")
20 | if err != nil {
21 | log.Fatal(err.Error())
22 | }
23 | return &Config{
24 | File: config,
25 | }
26 | }
27 |
28 | func (c *Config) GetServerPath() (string, error) {
29 | path, err := c.File.GetValue("proxy_server", "path")
30 | if err != nil {
31 | return "", err
32 | }
33 | return path, nil
34 | }
35 |
36 | func (c *Config) GetServerPort() (string, error) {
37 | path, err := c.File.GetValue("proxy_server", "port")
38 | if err != nil {
39 | return "", err
40 | }
41 | return path, nil
42 | }
43 |
44 | func (c *Config) GetUsernameAndPassword() (string, string, error) {
45 | username, err := c.File.GetValue("proxy_server", "username")
46 | if err != nil {
47 | return "", "", err
48 | }
49 | password, err := c.File.GetValue("proxy_server", "password")
50 | if err != nil {
51 | return "", "", err
52 | }
53 | return username, password, nil
54 | }
55 |
56 | func (c *Config) GetServicesFilePath() (string, error) {
57 | serviceFile, err := c.File.GetValue("proxy_server", "services")
58 | if err != nil {
59 | return "", err
60 | }
61 | return dir + serviceFile, nil
62 | }
63 |
64 | func (c *Config) UpdateAutoStart(autoStart string) (isSuccess bool) {
65 | c.File.DeleteKey("config", "auto_start")
66 | isSuccess = c.File.SetValue("config", "auto_start", autoStart)
67 | goconfig.SaveConfigFile(c.File, dir+"/config/config.ini")
68 | return
69 | }
70 |
71 | func (c *Config) UpdateProxy(proxy string) (isSuccess bool) {
72 | c.File.DeleteKey("config", "proxy")
73 | isSuccess = c.File.SetValue("config", "proxy", proxy)
74 | goconfig.SaveConfigFile(c.File, dir+"/config/config.ini")
75 | return
76 | }
77 |
78 | func (c *Config) GetAutoStart() (autoStart bool) {
79 | autoStart = c.File.MustBool("config", "auto_start")
80 | return
81 | }
82 |
83 | func (c *Config) GetProxySetting() (proxy bool) {
84 | proxy = c.File.MustBool("config", "proxy")
85 | return
86 | }
87 |
--------------------------------------------------------------------------------
/utils/convert.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import (
4 | "strconv"
5 | "reflect"
6 | "fmt"
7 | )
8 |
9 | type Convert struct{}
10 |
11 | func NewConvert() *Convert {
12 | return &Convert{}
13 | }
14 |
15 | // bool 转化为字符串
16 | func (convert *Convert) BoolToString(boolValue bool) string {
17 | if boolValue == true {
18 | return "true"
19 | } else {
20 | return "false"
21 | }
22 | }
23 |
24 | //bool 转化为 int
25 | func (convert *Convert) BoolToInt(boolValue bool) int {
26 | if boolValue == true {
27 | return 1
28 | } else {
29 | return 0
30 | }
31 | }
32 |
33 | //int 转化为 bool
34 | func (convert *Convert) IntToBool(number int) bool {
35 | if number == 0 {
36 | return false
37 | } else {
38 | return true
39 | }
40 | }
41 |
42 | //int 转化为字符串
43 | //base 范围 2-32 进制
44 | func (convert *Convert) IntToString(number int64, base int) string {
45 | return strconv.FormatInt(number, base)
46 | }
47 |
48 | //string to int(10进制)
49 | func (convert *Convert) StringToInt(str string) int {
50 | intValue, _ := strconv.Atoi(str)
51 | return intValue
52 | }
53 |
54 | // string to int64(10进制)
55 | func (convert *Convert) StringToInt64(str string) int64 {
56 | intValue, _ := strconv.ParseInt(str, 10, 64)
57 | return intValue
58 | }
59 |
60 | // int 转化为10进制字符串 IntToString(number, 10)
61 | func (convert *Convert) IntToTenString(number int) string {
62 | return strconv.Itoa(number)
63 | }
64 |
65 | // float 转化为字符串
66 | func (convert *Convert) FloatToString(f float64, fmt byte, prec, bitSize int) string {
67 | return strconv.FormatFloat(f, fmt, prec, bitSize)
68 | }
69 |
70 | // 转化任何的数为 int64
71 | func (convert *Convert) ToInt64(value interface{}) (d int64, err error) {
72 | val := reflect.ValueOf(value)
73 | switch value.(type) {
74 | case int, int8, int16, int32, int64:
75 | d = val.Int()
76 | case uint, uint8, uint16, uint32, uint64:
77 | d = int64(val.Uint())
78 | default:
79 | err = fmt.Errorf("ToInt64 need numeric not `%T`", value)
80 | }
81 | return
82 | }
--------------------------------------------------------------------------------
/utils/data.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import (
4 | "encoding/json"
5 | "io/ioutil"
6 | "os"
7 | "os/exec"
8 | "path/filepath"
9 | "runtime"
10 | "strings"
11 | "time"
12 |
13 | "github.com/pkg/errors"
14 | )
15 |
16 | var dataFilePath string
17 | var dir string
18 |
19 | func init() {
20 | dir, _ = filepath.Abs(filepath.Dir(os.Args[0]))
21 | dir = strings.Replace(dir, "\\", "/", -1)
22 | dataFilePath = dir + "/data/services/"
23 | }
24 |
25 | func SaveParams(name, command, auto_start, key_file, crt_file, log string) (serviceIdStr string, err error) {
26 | serviceId := time.Now().UnixNano() / 1000000
27 | serviceIdStr = NewConvert().IntToString(serviceId, 10)
28 | filePath, err := NewConfig().GetServicesFilePath()
29 | if err != nil {
30 | return
31 | }
32 | fd, err := os.OpenFile(filePath, os.O_RDWR|os.O_CREATE, 0644)
33 | if err != nil {
34 | return
35 | }
36 | data, err := ioutil.ReadAll(fd)
37 | if err != nil {
38 | return
39 | }
40 | fd.Close()
41 | dataMap := make(map[string]interface{})
42 | json.Unmarshal(data, &dataMap)
43 | dataMap[serviceIdStr] = auto_start
44 | data, _ = json.Marshal(dataMap)
45 | ioutil.WriteFile(filePath, data, 0644)
46 |
47 | // 判断有没有services文件夹
48 | s, err := os.Stat(dataFilePath)
49 | if err != nil || !s.IsDir() {
50 | os.Mkdir(dataFilePath, os.ModePerm)
51 | }
52 |
53 | fd, err = os.OpenFile(dataFilePath+serviceIdStr+".json", os.O_RDWR|os.O_CREATE, 0644)
54 | if err != nil {
55 | return
56 | }
57 | params := make(map[string]string)
58 | params["name"] = name
59 | params["command"] = command
60 | params["auto_start"] = auto_start
61 | params["key_file"] = key_file
62 | params["crt_file"] = crt_file
63 | params["id"] = serviceIdStr
64 | params["status"] = "close"
65 | params["log"] = log
66 | paramJson, _ := json.Marshal(params)
67 | fd.Write(paramJson)
68 | fd.Close()
69 | return
70 | }
71 |
72 | func UpdateParams(serviceId, name, command, auto_start, key_file, crt_file, log string) (err error) {
73 | filePath, err := NewConfig().GetServicesFilePath()
74 | if err != nil {
75 | return
76 | }
77 | fd, err := os.OpenFile(filePath, os.O_RDWR|os.O_CREATE, 0644)
78 | if err != nil {
79 | return
80 | }
81 | data, err := ioutil.ReadAll(fd)
82 | if err != nil {
83 | return
84 | }
85 | fd.Close()
86 | dataMap := make(map[string]interface{})
87 | json.Unmarshal(data, &dataMap)
88 | dataMap[serviceId] = auto_start
89 | data, _ = json.Marshal(dataMap)
90 | ioutil.WriteFile(filePath, data, 0644)
91 |
92 | // 判断有没有services文件夹
93 | s, err := os.Stat(dataFilePath)
94 | if err != nil || !s.IsDir() {
95 | os.Mkdir(dataFilePath, os.ModePerm)
96 | }
97 |
98 | fd, err = os.OpenFile(dataFilePath+serviceId+".json", os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
99 | if err != nil {
100 | return
101 | }
102 | params := make(map[string]string)
103 | params["name"] = name
104 | params["command"] = command
105 | params["auto_start"] = auto_start
106 | params["key_file"] = key_file
107 | params["crt_file"] = crt_file
108 | params["id"] = serviceId
109 | params["status"] = "close"
110 | params["log"] = log
111 | paramJson, _ := json.Marshal(params)
112 | fd.Write(paramJson)
113 | fd.Close()
114 | return
115 | }
116 |
117 | func DeleteParam(serviceId string) (err error) {
118 | filePath, err := NewConfig().GetServicesFilePath()
119 | if err != nil {
120 | return
121 | }
122 | fd, err := os.OpenFile(filePath, os.O_RDWR|os.O_CREATE, 0644)
123 | if err != nil {
124 | return
125 | }
126 | defer fd.Close()
127 |
128 | allData, err := ioutil.ReadAll(fd)
129 | if err != nil {
130 | return
131 | }
132 | dataMap := make(map[string]interface{})
133 | err = json.Unmarshal(allData, &dataMap)
134 | if err != nil {
135 | return
136 | }
137 | delete(dataMap, serviceId)
138 | dataByte, _ := json.Marshal(dataMap)
139 | ioutil.WriteFile(filePath, dataByte, 0644)
140 | os.Remove(dataFilePath + serviceId + ".json")
141 | return
142 | }
143 |
144 | func InitParams() (datas []map[string]interface{}, err error) {
145 | filePath, err := NewConfig().GetServicesFilePath()
146 | fd, err := os.OpenFile(filePath, os.O_RDWR|os.O_CREATE, 0644)
147 | if err != nil {
148 | return
149 | }
150 | defer fd.Close()
151 |
152 | allData, err := ioutil.ReadAll(fd)
153 | if err != nil {
154 | return
155 | }
156 | dataMap := make(map[string]interface{})
157 | err = json.Unmarshal(allData, &dataMap)
158 | if err != nil {
159 | return
160 | }
161 |
162 | for serviceId, auto_start := range dataMap {
163 | data := make(map[string]interface{})
164 | fd1, err := os.OpenFile(dataFilePath+serviceId+".json", os.O_RDWR|os.O_CREATE, 0644)
165 | if err != nil {
166 | continue
167 | }
168 | dataByte, err := ioutil.ReadAll(fd1)
169 | if err != nil {
170 | continue
171 | }
172 | json.Unmarshal(dataByte, &data)
173 |
174 | if auto_start == "yes" {
175 | data["status"] = "open"
176 | datas = append(datas, data)
177 | } else {
178 | data["status"] = "close"
179 | }
180 |
181 | dataByte, _ = json.Marshal(data)
182 | ioutil.WriteFile(dataFilePath+serviceId+".json", dataByte, 0644)
183 | fd1.Close()
184 | }
185 |
186 | return
187 | }
188 |
189 | func GetAllParams() (datas []map[string]interface{}, err error) {
190 | datas = make([]map[string]interface{}, 0)
191 | filePath, err := NewConfig().GetServicesFilePath()
192 | fd, err := os.OpenFile(filePath, os.O_RDWR|os.O_CREATE, 0644)
193 | if err != nil {
194 | return
195 | }
196 | defer fd.Close()
197 |
198 | allData, err := ioutil.ReadAll(fd)
199 | if err != nil || len(allData) == 0 {
200 | return
201 | }
202 | dataMap := make(map[string]interface{})
203 | err = json.Unmarshal(allData, &dataMap)
204 | if err != nil {
205 | return
206 | }
207 |
208 | var closeData []map[string]interface{}
209 | for serviceId, _ := range dataMap {
210 | data := make(map[string]interface{})
211 | fd, err := os.Open(dataFilePath + serviceId + ".json")
212 | if err != nil {
213 | continue
214 | }
215 | dataByte, err := ioutil.ReadAll(fd)
216 | if err != nil {
217 | continue
218 | }
219 | json.Unmarshal(dataByte, &data)
220 | if data["status"] == "open" {
221 | datas = append(datas, data)
222 | } else {
223 | closeData = append(closeData, data)
224 | }
225 |
226 | fd.Close()
227 | }
228 |
229 | datas = append(datas, closeData...)
230 |
231 | return
232 | }
233 |
234 | func GetParamsById(id string) (data map[string]interface{}, err error) {
235 | fd, err := os.OpenFile(dataFilePath+id+".json", os.O_RDWR|os.O_CREATE, 0644)
236 | if err != nil {
237 | return
238 | }
239 | defer fd.Close()
240 |
241 | allData, err := ioutil.ReadAll(fd)
242 | if err != nil {
243 | return
244 | }
245 | err = json.Unmarshal(allData, &data)
246 |
247 | return
248 | }
249 |
250 | func ChangeParameterDataById(serviceId, status string) (err error) {
251 | fd, err := os.OpenFile(dataFilePath+serviceId+".json", os.O_RDWR|os.O_CREATE, 0644)
252 | if err != nil {
253 | return
254 | }
255 | defer fd.Close()
256 | data, err := ioutil.ReadAll(fd)
257 | if err != nil {
258 | return
259 | }
260 | params := make(map[string]string)
261 | err = json.Unmarshal(data, ¶ms)
262 | if err != nil {
263 | return
264 | }
265 | params["status"] = status
266 | paramJson, _ := json.Marshal(params)
267 | ioutil.WriteFile(dataFilePath+serviceId+".json", paramJson, 0644)
268 | return
269 | }
270 |
271 | func UpdateProxy(ip, port string) (err error) {
272 | data := make(map[string]interface{})
273 | data["ip"] = ip
274 | data["port"] = port
275 | dataByte, err := json.Marshal(data)
276 | if err != nil {
277 | return
278 | }
279 |
280 | err = ioutil.WriteFile(dir+"/data/proxy.json", dataByte, 0644)
281 | return
282 | }
283 |
284 | func GetProxy() (data map[string]string, err error) {
285 | dataByte, err := ioutil.ReadFile(dir + "/data/proxy.json")
286 | if err != nil {
287 | return
288 | }
289 |
290 | err = json.Unmarshal(dataByte, &data)
291 | return
292 | }
293 |
294 | func StartProxy(ip, port string) (err error) {
295 | switch runtime.GOOS {
296 | case "windows":
297 | addr := ip + ":" + port
298 | command := dir + "/config/proxysetting.exe http=" + addr + " https=" + addr
299 | commandSlice := strings.Split(command, " ")
300 | cmd := exec.Command(commandSlice[0], commandSlice[1:]...)
301 | output, _ := cmd.CombinedOutput()
302 | outputStr := string(output)
303 | if outputStr != "" {
304 | return errors.New(outputStr)
305 | }
306 |
307 | case "darwin":
308 | cmd := exec.Command("/bin/bash", "-c", dir+"/config/httpProxy.sh "+ip+" "+port)
309 | output, _ := cmd.CombinedOutput()
310 | outputStr := string(output)
311 | if !strings.Contains(outputStr, "successfully") {
312 | return errors.New(outputStr)
313 | }
314 | case "linux":
315 | addr := ip + ":" + port
316 | home := os.Getenv("HOME")
317 | var contentByte []byte
318 | contentByte, _ = ioutil.ReadFile(home + "/.bashrc")
319 | if err != nil {
320 | return
321 | }
322 | content := string(contentByte)
323 | if !strings.Contains(content, dir+"/config/linux_proxy.sh") {
324 | content = content + `
325 | . ` + dir + `/config/linux_proxy.sh`
326 | err = ioutil.WriteFile(home+"/.bashrc", []byte(content), 0777)
327 | if err != nil {
328 | return err
329 | }
330 | }
331 | shContent := `#!/bin/sh
332 | export http_proxy=` + addr + `
333 | export https_proxy=` + addr
334 | err = ioutil.WriteFile(dir+"/config/linux_proxy.sh", []byte(shContent), 0777)
335 | if err != nil {
336 | return err
337 | }
338 | }
339 | return
340 | }
341 |
342 | func StopProxy(ip, port string) (err error) {
343 | switch runtime.GOOS {
344 | case "windows":
345 | command := dir + "/config/proxysetting.exe stop"
346 | commandSlice := strings.Split(command, " ")
347 | cmd := exec.Command(commandSlice[0], commandSlice[1:]...)
348 | output, _ := cmd.CombinedOutput()
349 | outputStr := string(output)
350 | if outputStr != "" {
351 | return errors.New(outputStr)
352 | }
353 | case "darwin":
354 | cmd := exec.Command("/bin/bash", "-c", dir+"/config/httpProxy.sh "+ip+" "+port+" close")
355 | output, _ := cmd.CombinedOutput()
356 | outputStr := string(output)
357 | if !strings.Contains(outputStr, "successfully") {
358 | return errors.New(outputStr)
359 | }
360 | case "linux":
361 | os.Remove(dir + "/config/linux_proxy.sh")
362 | }
363 |
364 | return
365 | }
366 |
--------------------------------------------------------------------------------
/utils/error.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import (
4 | "encoding/json"
5 | "net/http"
6 | )
7 |
8 | type Result struct {
9 | Msg string `json:"msg"`
10 | Data interface{} `json:"data"`
11 | }
12 |
13 | func ReturnJson(msg string, data interface{}, v http.ResponseWriter) {
14 | r := Result{Msg: msg, Data: data}
15 | json.NewEncoder(v).Encode(r)
16 | }
17 |
--------------------------------------------------------------------------------
/versioninfo.json:
--------------------------------------------------------------------------------
1 | {
2 | "FixedFileInfo": {
3 | "FileVersion": {
4 | "Major": 2,
5 | "Minor": 0,
6 | "Patch": 0,
7 | "Build": 0
8 | },
9 | "ProductVersion": {
10 | "Major": 2,
11 | "Minor": 0,
12 | "Patch": 0,
13 | "Build": 0
14 | },
15 | "FileFlagsMask": "3f",
16 | "FileFlags ": "00",
17 | "FileOS": "040004",
18 | "FileType": "01",
19 | "FileSubType": "00"
20 | },
21 | "StringFileInfo": {
22 | "Comments": "proxy-web",
23 | "CompanyName": "yc",
24 | "FileDescription": "proxy-web启动器",
25 | "FileVersion": "2.0",
26 | "InternalName": "proxy-web.exe",
27 | "LegalCopyright": "648588267@qq.com",
28 | "LegalTrademarks": "",
29 | "OriginalFilename": "proxy-web.exe",
30 | "PrivateBuild": "",
31 | "ProductName": "proxy-web",
32 | "ProductVersion": "v2.0",
33 | "SpecialBuild": ""
34 | },
35 | "VarFileInfo": {
36 | "Translation": {
37 | "LangID": "0409",
38 | "CharsetID": "04B0"
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------