Merge branch 'dev'
This commit is contained in:
@ -1,4 +1,10 @@
|
|||||||
proxy更新日志
|
proxy更新日志
|
||||||
|
v4.6
|
||||||
|
1.sps,http(s),socks5,内网穿透都做了大量的超时优化处理,更加稳定.
|
||||||
|
2.sps增加了强大的树形级联认证支持,可以轻松构建你的认证代理网络.
|
||||||
|
3.手册增加了6.6对sps认证功能的介绍.
|
||||||
|
|
||||||
|
|
||||||
v4.5
|
v4.5
|
||||||
1.优化了mux内网穿透连接管理逻辑,增强了稳定性.
|
1.优化了mux内网穿透连接管理逻辑,增强了稳定性.
|
||||||
2.mux内网穿透增加了tcp和kcp协议支持,之前是tls,现在支持三种协议tcp,tls,kcp.
|
2.mux内网穿透增加了tcp和kcp协议支持,之前是tls,现在支持三种协议tcp,tls,kcp.
|
||||||
|
|||||||
54
README.md
54
README.md
@ -22,7 +22,7 @@ Proxy is a high performance HTTP, HTTPS, HTTPS, websocket, TCP, UDP, Socks5 prox
|
|||||||
- The integrated external API, HTTP (S): SOCKS5 proxy authentication can be integrated with the external HTTP API, which can easily control the user's access through the external system.
|
- The integrated external API, HTTP (S): SOCKS5 proxy authentication can be integrated with the external HTTP API, which can easily control the user's access through the external system.
|
||||||
- Reverse proxy: goproxy supports directly parsing the domain to proxy monitor IP, and then proxy will help you to access the HTTP (S) site that you need to access.
|
- Reverse proxy: goproxy supports directly parsing the domain to proxy monitor IP, and then proxy will help you to access the HTTP (S) site that you need to access.
|
||||||
- Transparent proxy: with the iptables, goproxy can directly forward the 80 and 443 port's traffic to proxy in the gateway, and can realize the unaware intelligent router proxy.
|
- Transparent proxy: with the iptables, goproxy can directly forward the 80 and 443 port's traffic to proxy in the gateway, and can realize the unaware intelligent router proxy.
|
||||||
- Protocol conversion: The existing HTTP (S) or SOCKS5 proxy can be converted to a proxy which support both HTTP (S) and SOCKS5 by one port, but the converted SOCKS5 proxy does not support the UDP function.
|
- Protocol conversion: The existing HTTP (S) or SOCKS5 proxy can be converted to a proxy which support both HTTP (S) and SOCKS5 by one port, but the converted SOCKS5 proxy does not support the UDP function.Also support powerful cascading authentication.
|
||||||
|
|
||||||
### Why need these?
|
### Why need these?
|
||||||
- Because for some reason, we cannot access our services elsewhere. We can build a secure tunnel to access our services through multiple connected proxy nodes.
|
- Because for some reason, we cannot access our services elsewhere. We can build a secure tunnel to access our services through multiple connected proxy nodes.
|
||||||
@ -34,7 +34,8 @@ Proxy is a high performance HTTP, HTTPS, HTTPS, websocket, TCP, UDP, Socks5 prox
|
|||||||
- ...
|
- ...
|
||||||
|
|
||||||
|
|
||||||
This page is the v4.5 manual, and the other version of the manual can be checked by the following link.
|
This page is the v4.6 manual, and the other version of the manual can be checked by the following link.
|
||||||
|
- [v4.5 manual](https://github.com/snail007/goproxy/tree/v4.5)
|
||||||
- [v4.4 manual](https://github.com/snail007/goproxy/tree/v4.4)
|
- [v4.4 manual](https://github.com/snail007/goproxy/tree/v4.4)
|
||||||
- [v4.3 manual](https://github.com/snail007/goproxy/tree/v4.3)
|
- [v4.3 manual](https://github.com/snail007/goproxy/tree/v4.3)
|
||||||
- [v4.2 manual](https://github.com/snail007/goproxy/tree/v4.2)
|
- [v4.2 manual](https://github.com/snail007/goproxy/tree/v4.2)
|
||||||
@ -127,7 +128,8 @@ This page is the v4.5 manual, and the other version of the manual can be checked
|
|||||||
- [6.3 SOCKS5 to HTTP(S) + SOCKS5](#63socks5-to-http-socks5)
|
- [6.3 SOCKS5 to HTTP(S) + SOCKS5](#63socks5-to-http-socks5)
|
||||||
- [6.4 Chain style connection](#64chain-style-connection)
|
- [6.4 Chain style connection](#64chain-style-connection)
|
||||||
- [6.5 Listening on multiple ports](#65listening-on-multiple-ports)
|
- [6.5 Listening on multiple ports](#65listening-on-multiple-ports)
|
||||||
- [6.6 View Help](#56transfer-through-ssh)
|
- [6.6 Authentication](#66authentication)
|
||||||
|
- [6.7 View Help](#67view-help)
|
||||||
- [7.KCP Configuration](#7kcp-configuration)
|
- [7.KCP Configuration](#7kcp-configuration)
|
||||||
- [7.1 Configuration introduction](#71configuration-introduction)
|
- [7.1 Configuration introduction](#71configuration-introduction)
|
||||||
- [7.2 Configuration details](#72configuration-details)
|
- [7.2 Configuration details](#72configuration-details)
|
||||||
@ -149,7 +151,7 @@ If the installation fails or your VPS is not a linux64 system, please follow the
|
|||||||
Download address: https://github.com/snail007/goproxy/releases
|
Download address: https://github.com/snail007/goproxy/releases
|
||||||
```shell
|
```shell
|
||||||
cd /root/proxy/
|
cd /root/proxy/
|
||||||
wget https://github.com/snail007/goproxy/releases/download/v4.5/proxy-linux-amd64.tar.gz
|
wget https://github.com/snail007/goproxy/releases/download/v4.6/proxy-linux-amd64.tar.gz
|
||||||
```
|
```
|
||||||
#### **2.Download the automatic installation script**
|
#### **2.Download the automatic installation script**
|
||||||
```shell
|
```shell
|
||||||
@ -731,7 +733,49 @@ finish。
|
|||||||
In general, listening one port is enough, but if you need to monitor 80 and 443 ports at the same time as a reverse proxy, the -p parameter can support it.
|
In general, listening one port is enough, but if you need to monitor 80 and 443 ports at the same time as a reverse proxy, the -p parameter can support it.
|
||||||
The format is:`-p 0.0.0.0:80,0.0.0.0:443`, Multiple bindings are separated by a comma.
|
The format is:`-p 0.0.0.0:80,0.0.0.0:443`, Multiple bindings are separated by a comma.
|
||||||
|
|
||||||
#### **6.6.view help**
|
#### **6.6.Authentication**
|
||||||
|
SPS supports HTTP(s)\socks5 proxy authentication, which can concatenate authentication, there are four important information:
|
||||||
|
1:Users send authentication information`user-auth`。
|
||||||
|
2:Local authentication information set up`local-auth`。
|
||||||
|
3:Set the authentication information accessing to the father proxy`parent-auth`。
|
||||||
|
4:The final authentication information sent to the father proxy`auth-info-to-parent`。
|
||||||
|
The relationship between them is as follows:
|
||||||
|
|
||||||
|
| user-auth | local-auth | parent-auth | auth-info-to-paren
|
||||||
|
| ------ | ------ | ------ | ------
|
||||||
|
| yes/no | yes | yes | come from parent-auth
|
||||||
|
| yes/no | no | yes | come from parent-auth
|
||||||
|
| yes/no | yes | no | no
|
||||||
|
| no | no | no | no
|
||||||
|
| yes | no | no | come from user-auth
|
||||||
|
|
||||||
|
For SPS proxy we can have username and password to authenticate, and the authentication username and password can be specified on the command line
|
||||||
|
`./proxy sps -S http -T tcp -P 127.0.0.1:8080 -t tcp -p ":33080" -a "user1:pass1" -a "user2:pass2"`
|
||||||
|
if there are multiple users, repeat the -a parameters.
|
||||||
|
It can also be placed in a file, which is a line to a username: password, and then specified in -F parameter.
|
||||||
|
`./proxy sps -S http -T tcp -P 127.0.0.1:8080 -t tcp -p ":33080" -F auth-file.txt`
|
||||||
|
|
||||||
|
If the father proxy is authenticated, the lower level can set the authentication information through the -A parameters, such as:
|
||||||
|
father proxy:`./proxy sps -S http -T tcp -P 127.0.0.1:8080 -t tcp -p ":33080" -a "user1:pass1" -a "user2:pass2"`
|
||||||
|
local proxy:`./proxy sps -S http -T tcp -P 127.0.0.1:8080 -A "user1:pass1" -t tcp -p ":33080" `
|
||||||
|
|
||||||
|
In addition, SPS proxy, local authentication is integrated with external HTTP API authentication, and we can specify a HTTP URL interface address through the --auth-url parameter,
|
||||||
|
Then, when there is a user connection, proxy will request this URL by GET way, with the following four parameters, and if the HTTP state code 204 is returned, the authentication is successful.
|
||||||
|
Other cases consider authentication failure.
|
||||||
|
for example:
|
||||||
|
`./proxy sps -S http -T tcp -P 127.0.0.1:8080 -t tcp -p ":33080" --auth-url "http://test.com/auth.php"`
|
||||||
|
When the user is connected, proxy will request this URL by GET way("http://test.com/auth.php"),
|
||||||
|
Four parameters with user, pass, IP, and target:
|
||||||
|
http://test.com/auth.php?user={USER}&pass={PASS}&ip={IP}&target={TARGET}
|
||||||
|
user:username
|
||||||
|
pass:password
|
||||||
|
ip:user's ip,for example:192.168.1.200
|
||||||
|
target: if the client is the HTTP (s) proxy request, this represents the complete URL of the request, and the other cases are empty.
|
||||||
|
|
||||||
|
If there is no -a or -F or --auth-url parameters, local authentication is closed.
|
||||||
|
If there is no -A parameter, the connection to the father proxy does not use authentication.
|
||||||
|
|
||||||
|
#### **6.7.view help**
|
||||||
`./proxy help sps`
|
`./proxy help sps`
|
||||||
|
|
||||||
### **7.KCP Configuration**
|
### **7.KCP Configuration**
|
||||||
|
|||||||
56
README_ZH.md
56
README_ZH.md
@ -23,7 +23,7 @@ Proxy是golang实现的高性能http,https,websocket,tcp,udp,socks5代理服务
|
|||||||
- 集成外部API,HTTP(S),SOCKS5代理认证功能可以与外部HTTP API集成,可以方便的通过外部系统控制代理用户.
|
- 集成外部API,HTTP(S),SOCKS5代理认证功能可以与外部HTTP API集成,可以方便的通过外部系统控制代理用户.
|
||||||
- 反向代理,支持直接把域名解析到proxy监听的ip,然后proxy就会帮你代理访问需要访问的HTTP(S)网站.
|
- 反向代理,支持直接把域名解析到proxy监听的ip,然后proxy就会帮你代理访问需要访问的HTTP(S)网站.
|
||||||
- 透明HTTP(S)代理,配合iptables,在网关直接把出去的80,443方向的流量转发到proxy,就能实现无感知的智能路由器代理.
|
- 透明HTTP(S)代理,配合iptables,在网关直接把出去的80,443方向的流量转发到proxy,就能实现无感知的智能路由器代理.
|
||||||
- 协议转换,可以把已经存在的HTTP(S)或SOCKS5代理转换为一个端口同时支持HTTP(S)和SOCKS5代理,转换后的SOCKS5代理不支持UDP功能。
|
- 协议转换,可以把已经存在的HTTP(S)或SOCKS5代理转换为一个端口同时支持HTTP(S)和SOCKS5代理,转换后的SOCKS5代理不支持UDP功能,同时支持强大的级联认证功能。
|
||||||
|
|
||||||
### Why need these?
|
### Why need these?
|
||||||
- 当由于某某原因,我们不能访问我们在其它地方的服务,我们可以通过多个相连的proxy节点建立起一个安全的隧道访问我们的服务.
|
- 当由于某某原因,我们不能访问我们在其它地方的服务,我们可以通过多个相连的proxy节点建立起一个安全的隧道访问我们的服务.
|
||||||
@ -35,7 +35,8 @@ Proxy是golang实现的高性能http,https,websocket,tcp,udp,socks5代理服务
|
|||||||
- ...
|
- ...
|
||||||
|
|
||||||
|
|
||||||
本页是v4.5手册,其他版本手册请点击下面链接查看.
|
本页是v4.6手册,其他版本手册请点击下面链接查看.
|
||||||
|
- [v4.5手册](https://github.com/snail007/goproxy/tree/v4.5)
|
||||||
- [v4.4手册](https://github.com/snail007/goproxy/tree/v4.4)
|
- [v4.4手册](https://github.com/snail007/goproxy/tree/v4.4)
|
||||||
- [v4.3手册](https://github.com/snail007/goproxy/tree/v4.3)
|
- [v4.3手册](https://github.com/snail007/goproxy/tree/v4.3)
|
||||||
- [v4.2手册](https://github.com/snail007/goproxy/tree/v4.2)
|
- [v4.2手册](https://github.com/snail007/goproxy/tree/v4.2)
|
||||||
@ -126,7 +127,8 @@ Proxy是golang实现的高性能http,https,websocket,tcp,udp,socks5代理服务
|
|||||||
- [6.3 SOCKS5转HTTP(S)+SOCKS5](#63-socks5转httpssocks5)
|
- [6.3 SOCKS5转HTTP(S)+SOCKS5](#63-socks5转httpssocks5)
|
||||||
- [6.4 链式连接](#64-链式连接)
|
- [6.4 链式连接](#64-链式连接)
|
||||||
- [6.5 监听多个端口](#65-监听多个端口)
|
- [6.5 监听多个端口](#65-监听多个端口)
|
||||||
- [6.6 查看帮助](#66-查看帮助)
|
- [6.6 认证功能](#66-认证功能)
|
||||||
|
- [6.7 查看帮助](#67-查看帮助)
|
||||||
- [7. KCP配置](#7kcp配置)
|
- [7. KCP配置](#7kcp配置)
|
||||||
- [7.1 配置介绍](#71-配置介绍)
|
- [7.1 配置介绍](#71-配置介绍)
|
||||||
- [7.2 详细配置](#72-详细配置)
|
- [7.2 详细配置](#72-详细配置)
|
||||||
@ -147,7 +149,7 @@ curl -L https://raw.githubusercontent.com/snail007/goproxy/master/install_auto.s
|
|||||||
下载地址:https://github.com/snail007/goproxy/releases
|
下载地址:https://github.com/snail007/goproxy/releases
|
||||||
```shell
|
```shell
|
||||||
cd /root/proxy/
|
cd /root/proxy/
|
||||||
wget https://github.com/snail007/goproxy/releases/download/v4.5/proxy-linux-amd64.tar.gz
|
wget https://github.com/snail007/goproxy/releases/download/v4.6/proxy-linux-amd64.tar.gz
|
||||||
```
|
```
|
||||||
#### **2.下载自动安装脚本**
|
#### **2.下载自动安装脚本**
|
||||||
```shell
|
```shell
|
||||||
@ -598,7 +600,7 @@ server连接到bridge的时候,如果同时有多个client连接到同一个brid
|
|||||||

|

|
||||||
使用本地端口8090,假设上级SOCKS5代理是`22.22.22.22:8080`
|
使用本地端口8090,假设上级SOCKS5代理是`22.22.22.22:8080`
|
||||||
`./proxy socks -t tcp -p "0.0.0.0:8090" -T tcp -P "22.22.22.22:8080" `
|
`./proxy socks -t tcp -p "0.0.0.0:8090" -T tcp -P "22.22.22.22:8080" `
|
||||||
我们还可以指定网站域名的黑白名单文件,一行一个域名,匹配规则是最右匹配,比如:baidu.com,匹配的是*.*.baidu.com,黑名单的域名域名直接走上级代理,白名单的域名不走上级代理.
|
我们还可以指定网站域名的黑白名单文件,一行一个域名,匹配规则是最右匹配,比如:baidu.com,匹配的是*.*.baidu.com,黑名单的域名域名直接走上级代理,白名单的域名不走上级代理;如果域名即在黑名单又在白名单中,那么黑名单起作用.
|
||||||
`./proxy socks -p "0.0.0.0:8090" -T tcp -P "22.22.22.22:8080" -b blocked.txt -d direct.txt`
|
`./proxy socks -p "0.0.0.0:8090" -T tcp -P "22.22.22.22:8080" -b blocked.txt -d direct.txt`
|
||||||
|
|
||||||
#### **5.3.SOCKS二级代理(加密)**
|
#### **5.3.SOCKS二级代理(加密)**
|
||||||
@ -735,7 +737,49 @@ vps02:3.3.3.3
|
|||||||
一般情况下监听一个端口就可以,不过如果作为反向代理需要同时监听80和443两个端口,那么-p参数是支持的,
|
一般情况下监听一个端口就可以,不过如果作为反向代理需要同时监听80和443两个端口,那么-p参数是支持的,
|
||||||
格式是:`-p 0.0.0.0:80,0.0.0.0:443`,多个绑定用逗号分隔即可。
|
格式是:`-p 0.0.0.0:80,0.0.0.0:443`,多个绑定用逗号分隔即可。
|
||||||
|
|
||||||
#### **6.6 查看帮助**
|
#### **6.6 认证功能**
|
||||||
|
sps支持http(s)\socks5代理认证,可以级联认证,有四个重要的信息:
|
||||||
|
1:用户发送认证信息`user-auth`。
|
||||||
|
2:设置的本地认证信息`local-auth`。
|
||||||
|
3:设置的连接上级使用的认证信息`parent-auth`。
|
||||||
|
4:最终发送给上级的认证信息`auth-info-to-parent`。
|
||||||
|
他们的情况关系如下:
|
||||||
|
|
||||||
|
| user-auth | local-auth | parent-auth | auth-info-to-paren
|
||||||
|
| ------ | ------ | ------ | ------
|
||||||
|
| 有/没有 | 有 | 有 | 来自parent-auth
|
||||||
|
| 有/没有 | 没有 | 有 | 来自parent-auth
|
||||||
|
| 有/没有 | 有 | 没有 | 无
|
||||||
|
| 没有 | 没有 | 没有 | 无
|
||||||
|
| 有 | 没有 | 没有 | 来自user-auth
|
||||||
|
|
||||||
|
对于sps代理我们可以进行用户名密码认证,认证的用户名和密码可以在命令行指定
|
||||||
|
`./proxy sps -S http -T tcp -P 127.0.0.1:8080 -t tcp -p ":33080" -a "user1:pass1" -a "user2:pass2"`
|
||||||
|
多个用户,重复-a参数即可.
|
||||||
|
也可以放在文件中,格式是一行一个"用户名:密码",然后用-F指定.
|
||||||
|
`./proxy sps -S http -T tcp -P 127.0.0.1:8080 -t tcp -p ":33080" -F auth-file.txt`
|
||||||
|
|
||||||
|
如果上级有认证,下级可以通过-A参数设置认证信息,比如:
|
||||||
|
上级:`./proxy sps -S http -T tcp -P 127.0.0.1:8080 -t tcp -p ":33080" -a "user1:pass1" -a "user2:pass2"`
|
||||||
|
下级:`./proxy sps -S http -T tcp -P 127.0.0.1:8080 -A "user1:pass1" -t tcp -p ":33080" `
|
||||||
|
|
||||||
|
另外,sps代理,本地认证集成了外部HTTP API认证,我们可以通过--auth-url参数指定一个http url接口地址,
|
||||||
|
然后有用户连接的时候,proxy会GET方式请求这url,带上下面四个参数,如果返回HTTP状态码204,代表认证成功
|
||||||
|
其它情况认为认证失败.
|
||||||
|
比如:
|
||||||
|
`./proxy sps -S http -T tcp -P 127.0.0.1:8080 -t tcp -p ":33080" --auth-url "http://test.com/auth.php"`
|
||||||
|
用户连接的时候,proxy会GET方式请求这url("http://test.com/auth.php"),
|
||||||
|
带上user,pass,ip,target四个参数:
|
||||||
|
http://test.com/auth.php?user={USER}&pass={PASS}&ip={IP}&target={TARGET}
|
||||||
|
user:用户名
|
||||||
|
pass:密码
|
||||||
|
ip:用户的IP,比如:192.168.1.200
|
||||||
|
target:如果客户端是http(s)代理请求,这里代表的是请求的完整url,其它情况为空.
|
||||||
|
|
||||||
|
如果没有-a或-F或--auth-url参数,就是关闭本地认证.
|
||||||
|
如果没有-A参数,连接上级不使用认证.
|
||||||
|
|
||||||
|
#### **6.7 查看帮助**
|
||||||
`./proxy help sps`
|
`./proxy help sps`
|
||||||
|
|
||||||
### **7.KCP配置**
|
### **7.KCP配置**
|
||||||
|
|||||||
@ -223,7 +223,14 @@ func initConfig() (err error) {
|
|||||||
spsArgs.ParentServiceType = sps.Flag("parent-service-type", "parent service type <http|socks>").Short('S').Enum("http", "socks")
|
spsArgs.ParentServiceType = sps.Flag("parent-service-type", "parent service type <http|socks>").Short('S').Enum("http", "socks")
|
||||||
spsArgs.DNSAddress = sps.Flag("dns-address", "if set this, proxy will use this dns for resolve doamin").Short('q').Default("").String()
|
spsArgs.DNSAddress = sps.Flag("dns-address", "if set this, proxy will use this dns for resolve doamin").Short('q').Default("").String()
|
||||||
spsArgs.DNSTTL = sps.Flag("dns-ttl", "caching seconds of dns query result").Short('e').Default("300").Int()
|
spsArgs.DNSTTL = sps.Flag("dns-ttl", "caching seconds of dns query result").Short('e').Default("300").Int()
|
||||||
|
spsArgs.AuthFile = sps.Flag("auth-file", "http basic auth file,\"username:password\" each line in file").Short('F').String()
|
||||||
|
spsArgs.Auth = sps.Flag("auth", "socks auth username and password, mutiple user repeat -a ,such as: -a user1:pass1 -a user2:pass2").Short('a').Strings()
|
||||||
|
spsArgs.LocalIPS = sps.Flag("local bind ips", "if your host behind a nat,set your public ip here avoid dead loop").Short('g').Strings()
|
||||||
|
spsArgs.AuthURL = sps.Flag("auth-url", "auth username and password will send to this url,response http code equal to 'auth-code' means ok,others means fail.").Default("").String()
|
||||||
|
spsArgs.AuthURLTimeout = sps.Flag("auth-timeout", "access 'auth-url' timeout milliseconds").Default("3000").Int()
|
||||||
|
spsArgs.AuthURLOkCode = sps.Flag("auth-code", "access 'auth-url' success http code").Default("204").Int()
|
||||||
|
spsArgs.AuthURLRetry = sps.Flag("auth-retry", "access 'auth-url' fail and retry count").Default("0").Int()
|
||||||
|
spsArgs.ParentAuth = sps.Flag("parent-auth", "parent socks auth username and password, such as: -A user1:pass1").Short('A').String()
|
||||||
//parse args
|
//parse args
|
||||||
serviceName := kingpin.MustParse(app.Parse(os.Args[1:]))
|
serviceName := kingpin.MustParse(app.Parse(os.Args[1:]))
|
||||||
|
|
||||||
|
|||||||
@ -5,7 +5,7 @@ if [ -e /tmp/proxy ]; then
|
|||||||
fi
|
fi
|
||||||
mkdir /tmp/proxy
|
mkdir /tmp/proxy
|
||||||
cd /tmp/proxy
|
cd /tmp/proxy
|
||||||
wget https://github.com/snail007/goproxy/releases/download/v4.5/proxy-linux-amd64.tar.gz
|
wget https://github.com/snail007/goproxy/releases/download/v4.6/proxy-linux-amd64.tar.gz
|
||||||
|
|
||||||
# #install proxy
|
# #install proxy
|
||||||
tar zxvf proxy-linux-amd64.tar.gz
|
tar zxvf proxy-linux-amd64.tar.gz
|
||||||
|
|||||||
2
main.go
2
main.go
@ -8,7 +8,7 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
)
|
)
|
||||||
|
|
||||||
const APP_VERSION = "4.5"
|
const APP_VERSION = "4.6"
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
err := initConfig()
|
err := initConfig()
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
VER="4.5"
|
VER="4.6"
|
||||||
RELEASE="release-${VER}"
|
RELEASE="release-${VER}"
|
||||||
rm -rf .cert
|
rm -rf .cert
|
||||||
mkdir .cert
|
mkdir .cert
|
||||||
|
|||||||
@ -215,6 +215,14 @@ type SPSArgs struct {
|
|||||||
ParentServiceType *string
|
ParentServiceType *string
|
||||||
DNSAddress *string
|
DNSAddress *string
|
||||||
DNSTTL *int
|
DNSTTL *int
|
||||||
|
AuthFile *string
|
||||||
|
Auth *[]string
|
||||||
|
AuthURL *string
|
||||||
|
AuthURLOkCode *int
|
||||||
|
AuthURLTimeout *int
|
||||||
|
AuthURLRetry *int
|
||||||
|
LocalIPS *[]string
|
||||||
|
ParentAuth *string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *SPSArgs) Protocol() string {
|
func (a *SPSArgs) Protocol() string {
|
||||||
|
|||||||
@ -94,7 +94,9 @@ func (s *HTTP) InitService() {
|
|||||||
for {
|
for {
|
||||||
conn, err := utils.ConnectHost(s.Resolve(*s.cfg.Parent), *s.cfg.Timeout*2)
|
conn, err := utils.ConnectHost(s.Resolve(*s.cfg.Parent), *s.cfg.Timeout*2)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||||
_, err = conn.Write([]byte{0})
|
_, err = conn.Write([]byte{0})
|
||||||
|
conn.SetDeadline(time.Time{})
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if s.sshClient != nil {
|
if s.sshClient != nil {
|
||||||
@ -237,16 +239,16 @@ func (s *HTTP) OutToTCP(useProxy bool, address string, inConn *net.Conn, req *ut
|
|||||||
utils.CloseConn(inConn)
|
utils.CloseConn(inConn)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
outAddr := outConn.RemoteAddr().String()
|
outAddr := outConn.RemoteAddr().String()
|
||||||
//outLocalAddr := outConn.LocalAddr().String()
|
//outLocalAddr := outConn.LocalAddr().String()
|
||||||
|
|
||||||
if req.IsHTTPS() && (!useProxy || *s.cfg.ParentType == "ssh") {
|
if req.IsHTTPS() && (!useProxy || *s.cfg.ParentType == "ssh") {
|
||||||
//https无上级或者上级非代理,proxy需要响应connect请求,并直连目标
|
//https无上级或者上级非代理,proxy需要响应connect请求,并直连目标
|
||||||
err = req.HTTPSReply()
|
err = req.HTTPSReply()
|
||||||
} else {
|
} else {
|
||||||
//https或者http,上级是代理,proxy需要转发
|
//https或者http,上级是代理,proxy需要转发
|
||||||
|
outConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||||
_, err = outConn.Write(req.HeadBuf)
|
_, err = outConn.Write(req.HeadBuf)
|
||||||
|
outConn.SetDeadline(time.Time{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("write to %s , err:%s", *s.cfg.Parent, err)
|
log.Printf("write to %s , err:%s", *s.cfg.Parent, err)
|
||||||
utils.CloseConn(inConn)
|
utils.CloseConn(inConn)
|
||||||
|
|||||||
@ -75,7 +75,9 @@ func (s *MuxBridge) handler(inConn net.Conn) {
|
|||||||
var err error
|
var err error
|
||||||
var connType uint8
|
var connType uint8
|
||||||
var key string
|
var key string
|
||||||
|
inConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||||
err = utils.ReadPacket(reader, &connType, &key)
|
err = utils.ReadPacket(reader, &connType, &key)
|
||||||
|
inConn.SetDeadline(time.Time{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("read error,ERR:%s", err)
|
log.Printf("read error,ERR:%s", err)
|
||||||
return
|
return
|
||||||
@ -83,7 +85,9 @@ func (s *MuxBridge) handler(inConn net.Conn) {
|
|||||||
switch connType {
|
switch connType {
|
||||||
case CONN_SERVER:
|
case CONN_SERVER:
|
||||||
var serverID string
|
var serverID string
|
||||||
|
inConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||||
err = utils.ReadPacketData(reader, &serverID)
|
err = utils.ReadPacketData(reader, &serverID)
|
||||||
|
inConn.SetDeadline(time.Time{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("read error,ERR:%s", err)
|
log.Printf("read error,ERR:%s", err)
|
||||||
return
|
return
|
||||||
@ -128,6 +132,9 @@ func (s *MuxBridge) handler(inConn net.Conn) {
|
|||||||
}
|
}
|
||||||
_group, _ := s.clientControlConns.Get(groupKey)
|
_group, _ := s.clientControlConns.Get(groupKey)
|
||||||
group := _group.(*utils.ConcurrentMap)
|
group := _group.(*utils.ConcurrentMap)
|
||||||
|
if v, ok := group.Get(index); ok {
|
||||||
|
v.(*smux.Session).Close()
|
||||||
|
}
|
||||||
group.Set(index, session)
|
group.Set(index, session)
|
||||||
// s.clientControlConns.Set(key, session)
|
// s.clientControlConns.Set(key, session)
|
||||||
go func() {
|
go func() {
|
||||||
@ -180,7 +187,9 @@ func (s *MuxBridge) callback(inConn net.Conn, serverID, key string) {
|
|||||||
index := keys[i]
|
index := keys[i]
|
||||||
log.Printf("select client : %s-%s", key, index)
|
log.Printf("select client : %s-%s", key, index)
|
||||||
session, _ := group.Get(index)
|
session, _ := group.Get(index)
|
||||||
|
session.(*smux.Session).SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||||
stream, err := session.(*smux.Session).OpenStream()
|
stream, err := session.(*smux.Session).OpenStream()
|
||||||
|
session.(*smux.Session).SetDeadline(time.Time{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("%s client session open stream %s fail, err: %s, retrying...", key, serverID, err)
|
log.Printf("%s client session open stream %s fail, err: %s, retrying...", key, serverID, err)
|
||||||
time.Sleep(time.Second * 3)
|
time.Sleep(time.Second * 3)
|
||||||
|
|||||||
@ -68,7 +68,9 @@ func (s *MuxClient) Start(args interface{}) (err error) {
|
|||||||
time.Sleep(time.Second * 3)
|
time.Sleep(time.Second * 3)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||||
_, err = conn.Write(utils.BuildPacket(CONN_CLIENT, fmt.Sprintf("%s-%d", *s.cfg.Key, i)))
|
_, err = conn.Write(utils.BuildPacket(CONN_CLIENT, fmt.Sprintf("%s-%d", *s.cfg.Key, i)))
|
||||||
|
conn.SetDeadline(time.Time{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
conn.Close()
|
conn.Close()
|
||||||
log.Printf("connection err: %s, retrying...", err)
|
log.Printf("connection err: %s, retrying...", err)
|
||||||
@ -98,7 +100,9 @@ func (s *MuxClient) Start(args interface{}) (err error) {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
var ID, clientLocalAddr, serverID string
|
var ID, clientLocalAddr, serverID string
|
||||||
|
stream.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||||
err = utils.ReadPacketData(stream, &ID, &clientLocalAddr, &serverID)
|
err = utils.ReadPacketData(stream, &ID, &clientLocalAddr, &serverID)
|
||||||
|
stream.SetDeadline(time.Time{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("read stream signal err: %s", err)
|
log.Printf("read stream signal err: %s", err)
|
||||||
stream.Close()
|
stream.Close()
|
||||||
@ -140,7 +144,9 @@ func (s *MuxClient) getParentConn() (conn net.Conn, err error) {
|
|||||||
func (s *MuxClient) ServeUDP(inConn *smux.Stream, localAddr, ID string) {
|
func (s *MuxClient) ServeUDP(inConn *smux.Stream, localAddr, ID string) {
|
||||||
|
|
||||||
for {
|
for {
|
||||||
|
inConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||||
srcAddr, body, err := utils.ReadUDPPacket(inConn)
|
srcAddr, body, err := utils.ReadUDPPacket(inConn)
|
||||||
|
inConn.SetDeadline(time.Time{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("udp packet revecived fail, err: %s", err)
|
log.Printf("udp packet revecived fail, err: %s", err)
|
||||||
log.Printf("connection %s released", ID)
|
log.Printf("connection %s released", ID)
|
||||||
@ -169,13 +175,16 @@ func (s *MuxClient) processUDPPacket(inConn *smux.Stream, srcAddr, localAddr str
|
|||||||
}
|
}
|
||||||
conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||||
_, err = conn.Write(body)
|
_, err = conn.Write(body)
|
||||||
|
conn.SetDeadline(time.Time{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("send udp packet to %s fail,ERR:%s", dstAddr.String(), err)
|
log.Printf("send udp packet to %s fail,ERR:%s", dstAddr.String(), err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
//log.Printf("send udp packet to %s success", dstAddr.String())
|
//log.Printf("send udp packet to %s success", dstAddr.String())
|
||||||
buf := make([]byte, 1024)
|
buf := make([]byte, 1024)
|
||||||
|
conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||||
length, _, err := conn.ReadFromUDP(buf)
|
length, _, err := conn.ReadFromUDP(buf)
|
||||||
|
conn.SetDeadline(time.Time{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("read udp response from %s fail ,ERR:%s", dstAddr.String(), err)
|
log.Printf("read udp response from %s fail ,ERR:%s", dstAddr.String(), err)
|
||||||
return
|
return
|
||||||
@ -183,7 +192,9 @@ func (s *MuxClient) processUDPPacket(inConn *smux.Stream, srcAddr, localAddr str
|
|||||||
respBody := buf[0:length]
|
respBody := buf[0:length]
|
||||||
//log.Printf("revecived udp packet from %s , %v", dstAddr.String(), respBody)
|
//log.Printf("revecived udp packet from %s , %v", dstAddr.String(), respBody)
|
||||||
bs := utils.UDPPacket(srcAddr, respBody)
|
bs := utils.UDPPacket(srcAddr, respBody)
|
||||||
|
(*inConn).SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||||
_, err = (*inConn).Write(bs)
|
_, err = (*inConn).Write(bs)
|
||||||
|
(*inConn).SetDeadline(time.Time{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("send udp response fail ,ERR:%s", err)
|
log.Printf("send udp response fail ,ERR:%s", err)
|
||||||
inConn.Close()
|
inConn.Close()
|
||||||
|
|||||||
@ -227,7 +227,9 @@ func (s *MuxServer) GetOutConn() (outConn net.Conn, ID string, err error) {
|
|||||||
remoteAddr = "udp:" + *s.cfg.Remote
|
remoteAddr = "udp:" + *s.cfg.Remote
|
||||||
}
|
}
|
||||||
ID = utils.Uniqueid()
|
ID = utils.Uniqueid()
|
||||||
|
outConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||||
_, err = outConn.Write(utils.BuildPacketData(ID, remoteAddr, s.cfg.Mgr.serverID))
|
_, err = outConn.Write(utils.BuildPacketData(ID, remoteAddr, s.cfg.Mgr.serverID))
|
||||||
|
outConn.SetDeadline(time.Time{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("write stream data err: %s ,retrying...", err)
|
log.Printf("write stream data err: %s ,retrying...", err)
|
||||||
utils.CloseConn(&outConn)
|
utils.CloseConn(&outConn)
|
||||||
@ -253,7 +255,9 @@ func (s *MuxServer) GetConn(index string) (conn net.Conn, err error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
c.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||||
_, err = c.Write(utils.BuildPacket(CONN_SERVER, *s.cfg.Key, s.cfg.Mgr.serverID))
|
_, err = c.Write(utils.BuildPacket(CONN_SERVER, *s.cfg.Key, s.cfg.Mgr.serverID))
|
||||||
|
c.SetDeadline(time.Time{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Close()
|
c.Close()
|
||||||
return
|
return
|
||||||
@ -266,14 +270,6 @@ func (s *MuxServer) GetConn(index string) (conn net.Conn, err error) {
|
|||||||
}
|
}
|
||||||
s.sessions.Set(index, session)
|
s.sessions.Set(index, session)
|
||||||
log.Printf("session[%s] created", index)
|
log.Printf("session[%s] created", index)
|
||||||
} else {
|
|
||||||
session = _session.(*smux.Session)
|
|
||||||
}
|
|
||||||
conn, err = session.OpenStream()
|
|
||||||
if err != nil {
|
|
||||||
session.Close()
|
|
||||||
s.sessions.Remove(index)
|
|
||||||
} else {
|
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
if session.IsClosed() {
|
if session.IsClosed() {
|
||||||
@ -283,8 +279,14 @@ func (s *MuxServer) GetConn(index string) (conn net.Conn, err error) {
|
|||||||
time.Sleep(time.Second * 5)
|
time.Sleep(time.Second * 5)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
} else {
|
||||||
|
session = _session.(*smux.Session)
|
||||||
|
}
|
||||||
|
conn, err = session.OpenStream()
|
||||||
|
if err != nil {
|
||||||
|
session.Close()
|
||||||
|
s.sessions.Remove(index)
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
func (s *MuxServer) getParentConn() (conn net.Conn, err error) {
|
func (s *MuxServer) getParentConn() (conn net.Conn, err error) {
|
||||||
@ -329,7 +331,9 @@ func (s *MuxServer) UDPConnDeamon() {
|
|||||||
// outConn.Close()
|
// outConn.Close()
|
||||||
}()
|
}()
|
||||||
for {
|
for {
|
||||||
|
outConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||||
srcAddrFromConn, body, err := utils.ReadUDPPacket(outConn)
|
srcAddrFromConn, body, err := utils.ReadUDPPacket(outConn)
|
||||||
|
outConn.SetDeadline(time.Time{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("parse revecived udp packet fail, err: %s ,%v", err, body)
|
log.Printf("parse revecived udp packet fail, err: %s ,%v", err, body)
|
||||||
log.Printf("UDP deamon connection %s exited", ID)
|
log.Printf("UDP deamon connection %s exited", ID)
|
||||||
@ -343,7 +347,9 @@ func (s *MuxServer) UDPConnDeamon() {
|
|||||||
}
|
}
|
||||||
port, _ := strconv.Atoi(_srcAddr[1])
|
port, _ := strconv.Atoi(_srcAddr[1])
|
||||||
dstAddr := &net.UDPAddr{IP: net.ParseIP(_srcAddr[0]), Port: port}
|
dstAddr := &net.UDPAddr{IP: net.ParseIP(_srcAddr[0]), Port: port}
|
||||||
|
s.sc.UDPListener.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||||
_, err = s.sc.UDPListener.WriteToUDP(body, dstAddr)
|
_, err = s.sc.UDPListener.WriteToUDP(body, dstAddr)
|
||||||
|
s.sc.UDPListener.SetDeadline(time.Time{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("udp response to local %s fail,ERR:%s", srcAddrFromConn, err)
|
log.Printf("udp response to local %s fail,ERR:%s", srcAddrFromConn, err)
|
||||||
continue
|
continue
|
||||||
|
|||||||
@ -104,7 +104,9 @@ func (s *Socks) InitService() {
|
|||||||
for {
|
for {
|
||||||
conn, err := utils.ConnectHost(s.Resolve(*s.cfg.Parent), *s.cfg.Timeout*2)
|
conn, err := utils.ConnectHost(s.Resolve(*s.cfg.Parent), *s.cfg.Timeout*2)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||||
_, err = conn.Write([]byte{0})
|
_, err = conn.Write([]byte{0})
|
||||||
|
conn.SetDeadline(time.Time{})
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if s.sshClient != nil {
|
if s.sshClient != nil {
|
||||||
@ -216,6 +218,7 @@ func (s *Socks) udpCallback(b []byte, localAddr, srcAddr *net.UDPAddr) {
|
|||||||
}
|
}
|
||||||
conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout*5)))
|
conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout*5)))
|
||||||
_, err = conn.Write(rawB)
|
_, err = conn.Write(rawB)
|
||||||
|
conn.SetDeadline(time.Time{})
|
||||||
log.Printf("udp request:%v", len(rawB))
|
log.Printf("udp request:%v", len(rawB))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("send udp packet to %s fail,ERR:%s", dstAddr.String(), err)
|
log.Printf("send udp packet to %s fail,ERR:%s", dstAddr.String(), err)
|
||||||
@ -225,7 +228,9 @@ func (s *Socks) udpCallback(b []byte, localAddr, srcAddr *net.UDPAddr) {
|
|||||||
|
|
||||||
//log.Printf("send udp packet to %s success", dstAddr.String())
|
//log.Printf("send udp packet to %s success", dstAddr.String())
|
||||||
buf := make([]byte, 10*1024)
|
buf := make([]byte, 10*1024)
|
||||||
|
conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||||
length, _, err := conn.ReadFromUDP(buf)
|
length, _, err := conn.ReadFromUDP(buf)
|
||||||
|
conn.SetDeadline(time.Time{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("read udp response from %s fail ,ERR:%s", dstAddr.String(), err)
|
log.Printf("read udp response from %s fail ,ERR:%s", dstAddr.String(), err)
|
||||||
conn.Close()
|
conn.Close()
|
||||||
@ -250,10 +255,14 @@ func (s *Socks) udpCallback(b []byte, localAddr, srcAddr *net.UDPAddr) {
|
|||||||
conn.Close()
|
conn.Close()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
s.udpSC.UDPListener.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||||
s.udpSC.UDPListener.WriteToUDP(d, srcAddr)
|
s.udpSC.UDPListener.WriteToUDP(d, srcAddr)
|
||||||
|
s.udpSC.UDPListener.SetDeadline(time.Time{})
|
||||||
log.Printf("udp reply:%v", len(d))
|
log.Printf("udp reply:%v", len(d))
|
||||||
} else {
|
} else {
|
||||||
|
s.udpSC.UDPListener.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||||
s.udpSC.UDPListener.WriteToUDP(respBody, srcAddr)
|
s.udpSC.UDPListener.WriteToUDP(respBody, srcAddr)
|
||||||
|
s.udpSC.UDPListener.SetDeadline(time.Time{})
|
||||||
log.Printf("udp reply:%v", len(respBody))
|
log.Printf("udp reply:%v", len(respBody))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -272,6 +281,7 @@ func (s *Socks) udpCallback(b []byte, localAddr, srcAddr *net.UDPAddr) {
|
|||||||
}
|
}
|
||||||
conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout*3)))
|
conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout*3)))
|
||||||
_, err = conn.Write(p.Data())
|
_, err = conn.Write(p.Data())
|
||||||
|
conn.SetDeadline(time.Time{})
|
||||||
log.Printf("udp send:%v", len(p.Data()))
|
log.Printf("udp send:%v", len(p.Data()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("send udp packet to %s fail,ERR:%s", dstAddr.String(), err)
|
log.Printf("send udp packet to %s fail,ERR:%s", dstAddr.String(), err)
|
||||||
@ -280,7 +290,10 @@ func (s *Socks) udpCallback(b []byte, localAddr, srcAddr *net.UDPAddr) {
|
|||||||
}
|
}
|
||||||
//log.Printf("send udp packet to %s success", dstAddr.String())
|
//log.Printf("send udp packet to %s success", dstAddr.String())
|
||||||
buf := make([]byte, 10*1024)
|
buf := make([]byte, 10*1024)
|
||||||
|
conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||||
length, _, err := conn.ReadFromUDP(buf)
|
length, _, err := conn.ReadFromUDP(buf)
|
||||||
|
conn.SetDeadline(time.Time{})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("read udp response from %s fail ,ERR:%s", dstAddr.String(), err)
|
log.Printf("read udp response from %s fail ,ERR:%s", dstAddr.String(), err)
|
||||||
conn.Close()
|
conn.Close()
|
||||||
@ -297,9 +310,13 @@ func (s *Socks) udpCallback(b []byte, localAddr, srcAddr *net.UDPAddr) {
|
|||||||
conn.Close()
|
conn.Close()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
s.udpSC.UDPListener.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||||
s.udpSC.UDPListener.WriteToUDP(d, srcAddr)
|
s.udpSC.UDPListener.WriteToUDP(d, srcAddr)
|
||||||
|
s.udpSC.UDPListener.SetDeadline(time.Time{})
|
||||||
} else {
|
} else {
|
||||||
|
s.udpSC.UDPListener.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||||
s.udpSC.UDPListener.WriteToUDP(respPacket, srcAddr)
|
s.udpSC.UDPListener.WriteToUDP(respPacket, srcAddr)
|
||||||
|
s.udpSC.UDPListener.SetDeadline(time.Time{})
|
||||||
}
|
}
|
||||||
log.Printf("udp reply:%v", len(respPacket))
|
log.Printf("udp reply:%v", len(respPacket))
|
||||||
}
|
}
|
||||||
@ -371,9 +388,15 @@ func (s *Socks) socksConnCallback(inConn net.Conn) {
|
|||||||
//auth
|
//auth
|
||||||
_addr := strings.Split(inConn.RemoteAddr().String(), ":")
|
_addr := strings.Split(inConn.RemoteAddr().String(), ":")
|
||||||
if s.basicAuth.CheckUserPass(user, pass, _addr[0], "") {
|
if s.basicAuth.CheckUserPass(user, pass, _addr[0], "") {
|
||||||
|
inConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||||
inConn.Write([]byte{0x01, 0x00})
|
inConn.Write([]byte{0x01, 0x00})
|
||||||
|
inConn.SetDeadline(time.Time{})
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
inConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||||
inConn.Write([]byte{0x01, 0x01})
|
inConn.Write([]byte{0x01, 0x01})
|
||||||
|
inConn.SetDeadline(time.Time{})
|
||||||
|
|
||||||
utils.CloseConn(&inConn)
|
utils.CloseConn(&inConn)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -496,25 +519,32 @@ func (s *Socks) getOutConn(methodBytes, reqBytes []byte, host string) (outConn n
|
|||||||
}
|
}
|
||||||
var buf = make([]byte, 1024)
|
var buf = make([]byte, 1024)
|
||||||
//var n int
|
//var n int
|
||||||
|
outConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||||
_, err = outConn.Write(methodBytes)
|
_, err = outConn.Write(methodBytes)
|
||||||
|
outConn.SetDeadline(time.Time{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = fmt.Errorf("write method fail,%s", err)
|
err = fmt.Errorf("write method fail,%s", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
outConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||||
_, err = outConn.Read(buf)
|
_, err = outConn.Read(buf)
|
||||||
|
outConn.SetDeadline(time.Time{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = fmt.Errorf("read method reply fail,%s", err)
|
err = fmt.Errorf("read method reply fail,%s", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
//resp := buf[:n]
|
//resp := buf[:n]
|
||||||
//log.Printf("resp:%v", resp)
|
//log.Printf("resp:%v", resp)
|
||||||
|
outConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||||
_, err = outConn.Write(reqBytes)
|
_, err = outConn.Write(reqBytes)
|
||||||
|
outConn.SetDeadline(time.Time{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = fmt.Errorf("write req detail fail,%s", err)
|
err = fmt.Errorf("write req detail fail,%s", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
outConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||||
_, err = outConn.Read(buf)
|
_, err = outConn.Read(buf)
|
||||||
|
outConn.SetDeadline(time.Time{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = fmt.Errorf("read req reply fail,%s", err)
|
err = fmt.Errorf("read req reply fail,%s", err)
|
||||||
return
|
return
|
||||||
|
|||||||
194
services/sps.go
194
services/sps.go
@ -2,6 +2,7 @@ package services
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"encoding/base64"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
@ -12,18 +13,21 @@ import (
|
|||||||
"snail007/proxy/utils/socks"
|
"snail007/proxy/utils/socks"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type SPS struct {
|
type SPS struct {
|
||||||
outPool utils.OutPool
|
outPool utils.OutPool
|
||||||
cfg SPSArgs
|
cfg SPSArgs
|
||||||
domainResolver utils.DomainResolver
|
domainResolver utils.DomainResolver
|
||||||
|
basicAuth utils.BasicAuth
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSPS() Service {
|
func NewSPS() Service {
|
||||||
return &SPS{
|
return &SPS{
|
||||||
outPool: utils.OutPool{},
|
outPool: utils.OutPool{},
|
||||||
cfg: SPSArgs{},
|
cfg: SPSArgs{},
|
||||||
|
basicAuth: utils.BasicAuth{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func (s *SPS) CheckArgs() {
|
func (s *SPS) CheckArgs() {
|
||||||
@ -46,6 +50,10 @@ func (s *SPS) CheckArgs() {
|
|||||||
}
|
}
|
||||||
func (s *SPS) InitService() {
|
func (s *SPS) InitService() {
|
||||||
s.InitOutConnPool()
|
s.InitOutConnPool()
|
||||||
|
if *s.cfg.DNSAddress != "" {
|
||||||
|
(*s).domainResolver = utils.NewDomainResolver(*s.cfg.DNSAddress, *s.cfg.DNSTTL)
|
||||||
|
}
|
||||||
|
s.InitBasicAuth()
|
||||||
}
|
}
|
||||||
func (s *SPS) InitOutConnPool() {
|
func (s *SPS) InitOutConnPool() {
|
||||||
if *s.cfg.ParentType == TYPE_TLS || *s.cfg.ParentType == TYPE_TCP || *s.cfg.ParentType == TYPE_KCP {
|
if *s.cfg.ParentType == TYPE_TLS || *s.cfg.ParentType == TYPE_TCP || *s.cfg.ParentType == TYPE_KCP {
|
||||||
@ -117,7 +125,7 @@ func (s *SPS) callback(inConn net.Conn) {
|
|||||||
err = fmt.Errorf("unkown parent type %s", *s.cfg.ParentType)
|
err = fmt.Errorf("unkown parent type %s", *s.cfg.ParentType)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("connect to %s parent %s fail, ERR:%s", *s.cfg.ParentType, *s.cfg.Parent, err)
|
log.Printf("connect to %s parent %s fail, ERR:%s from %s", *s.cfg.ParentType, *s.cfg.Parent, err, inConn.RemoteAddr())
|
||||||
utils.CloseConn(&inConn)
|
utils.CloseConn(&inConn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -131,51 +139,32 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
address := ""
|
address := ""
|
||||||
|
var auth socks.Auth
|
||||||
var forwardBytes []byte
|
var forwardBytes []byte
|
||||||
//fmt.Printf("%v", header)
|
//fmt.Printf("%v", header)
|
||||||
if header[0] == socks.VERSION_V5 {
|
if header[0] == socks.VERSION_V5 {
|
||||||
//socks
|
//socks5 server
|
||||||
methodReq, e := socks.NewMethodsRequest(*inConn, header)
|
var serverConn *socks.ServerConn
|
||||||
if e != nil {
|
if s.IsBasicAuth() {
|
||||||
log.Printf("new method request err:%s", e)
|
serverConn = socks.NewServerConn(inConn, time.Millisecond*time.Duration(*s.cfg.Timeout), &s.basicAuth, "", header)
|
||||||
utils.CloseConn(inConn)
|
} else {
|
||||||
err = e.(error)
|
serverConn = socks.NewServerConn(inConn, time.Millisecond*time.Duration(*s.cfg.Timeout), nil, "", header)
|
||||||
|
}
|
||||||
|
if err = serverConn.Handshake(); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !methodReq.Select(socks.Method_NO_AUTH) {
|
address = serverConn.Target()
|
||||||
methodReq.Reply(socks.Method_NONE_ACCEPTABLE)
|
auth = serverConn.AuthData()
|
||||||
utils.CloseConn(inConn)
|
|
||||||
log.Printf("none method found : Method_NO_AUTH")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
//method select reply
|
|
||||||
err = methodReq.Reply(socks.Method_NO_AUTH)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("reply answer data fail,ERR: %s", err)
|
|
||||||
utils.CloseConn(inConn)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
//request detail
|
|
||||||
request, e := socks.NewRequest(*inConn)
|
|
||||||
if e != nil {
|
|
||||||
log.Printf("read request data fail,ERR: %s", e)
|
|
||||||
utils.CloseConn(inConn)
|
|
||||||
err = e.(error)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if request.CMD() != socks.CMD_CONNECT {
|
|
||||||
//只支持tcp
|
|
||||||
request.TCPReply(socks.REP_UNKNOWN)
|
|
||||||
utils.CloseConn(inConn)
|
|
||||||
err = errors.New("cmd not supported")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
address = request.Addr()
|
|
||||||
request.TCPReply(socks.REP_SUCCESS)
|
|
||||||
} else if bytes.IndexByte(header, '\n') != -1 {
|
} else if bytes.IndexByte(header, '\n') != -1 {
|
||||||
//http
|
//http
|
||||||
var request utils.HTTPRequest
|
var request utils.HTTPRequest
|
||||||
|
(*inConn).SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||||
|
if s.IsBasicAuth() {
|
||||||
|
request, err = utils.NewHTTPRequest(inConn, 1024, true, &s.basicAuth, header)
|
||||||
|
} else {
|
||||||
request, err = utils.NewHTTPRequest(inConn, 1024, false, nil, header)
|
request, err = utils.NewHTTPRequest(inConn, 1024, false, nil, header)
|
||||||
|
}
|
||||||
|
(*inConn).SetDeadline(time.Time{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("new http request fail,ERR: %s", err)
|
log.Printf("new http request fail,ERR: %s", err)
|
||||||
utils.CloseConn(inConn)
|
utils.CloseConn(inConn)
|
||||||
@ -189,6 +178,17 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (err error) {
|
|||||||
forwardBytes = request.HeadBuf
|
forwardBytes = request.HeadBuf
|
||||||
}
|
}
|
||||||
address = request.Host
|
address = request.Host
|
||||||
|
var userpass string
|
||||||
|
if s.IsBasicAuth() {
|
||||||
|
userpass, err = request.GetAuthDataStr()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
userpassA := strings.Split(userpass, ":")
|
||||||
|
if len(userpassA) == 2 {
|
||||||
|
auth = socks.Auth{User: userpassA[0], Password: userpassA[1]}
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
log.Printf("unknown request from: %s,%s", (*inConn).RemoteAddr(), string(header))
|
log.Printf("unknown request from: %s,%s", (*inConn).RemoteAddr(), string(header))
|
||||||
utils.CloseConn(inConn)
|
utils.CloseConn(inConn)
|
||||||
@ -207,12 +207,42 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (err error) {
|
|||||||
utils.CloseConn(inConn)
|
utils.CloseConn(inConn)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
//ask parent for connect to target address
|
//ask parent for connect to target address
|
||||||
if *s.cfg.ParentServiceType == "http" {
|
if *s.cfg.ParentServiceType == "http" {
|
||||||
//http parent
|
//http parent
|
||||||
fmt.Fprintf(outConn, "CONNECT %s HTTP/1.1\r\n", address)
|
pb := new(bytes.Buffer)
|
||||||
|
pb.Write([]byte(fmt.Sprintf("CONNECT %s HTTP/1.1\r\nProxy-Connection: Keep-Alive\r\n", address)))
|
||||||
|
//Proxy-Authorization:\r\n
|
||||||
|
u := ""
|
||||||
|
if *s.cfg.ParentAuth != "" {
|
||||||
|
a := strings.Split(*s.cfg.ParentAuth, ":")
|
||||||
|
if len(a) != 2 {
|
||||||
|
err = fmt.Errorf("parent auth data format error")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
u = fmt.Sprintf("%s:%s", a[0], a[1])
|
||||||
|
} else {
|
||||||
|
if !s.IsBasicAuth() && auth.Password != "" && auth.User != "" {
|
||||||
|
u = fmt.Sprintf("%s:%s", auth.User, auth.Password)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if u != "" {
|
||||||
|
pb.Write([]byte(fmt.Sprintf("Proxy-Authorization:Basic %s\r\n", base64.StdEncoding.EncodeToString([]byte(u)))))
|
||||||
|
}
|
||||||
|
outConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||||
|
_, err = outConn.Write(pb.Bytes())
|
||||||
|
outConn.SetDeadline(time.Time{})
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("write CONNECT to %s , err:%s", *s.cfg.Parent, err)
|
||||||
|
utils.CloseConn(inConn)
|
||||||
|
utils.CloseConn(&outConn)
|
||||||
|
return
|
||||||
|
}
|
||||||
reply := make([]byte, 100)
|
reply := make([]byte, 100)
|
||||||
n, err = outConn.Read(reply)
|
outConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||||
|
_, err = outConn.Read(reply)
|
||||||
|
outConn.SetDeadline(time.Time{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("read reply from %s , err:%s", *s.cfg.Parent, err)
|
log.Printf("read reply from %s , err:%s", *s.cfg.Parent, err)
|
||||||
utils.CloseConn(inConn)
|
utils.CloseConn(inConn)
|
||||||
@ -222,53 +252,25 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (err error) {
|
|||||||
//log.Printf("reply: %s", string(reply[:n]))
|
//log.Printf("reply: %s", string(reply[:n]))
|
||||||
} else {
|
} else {
|
||||||
log.Printf("connect %s", address)
|
log.Printf("connect %s", address)
|
||||||
//socks parent
|
//socks client
|
||||||
//send auth type
|
var clientConn *socks.ClientConn
|
||||||
_, err = outConn.Write([]byte{0x05, 0x01, 0x00})
|
if *s.cfg.ParentAuth != "" {
|
||||||
if err != nil {
|
a := strings.Split(*s.cfg.ParentAuth, ":")
|
||||||
log.Printf("write method to %s fail, err:%s", *s.cfg.Parent, err)
|
if len(a) != 2 {
|
||||||
utils.CloseConn(inConn)
|
err = fmt.Errorf("parent auth data format error")
|
||||||
utils.CloseConn(&outConn)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
//read reply
|
clientConn = socks.NewClientConn(&outConn, "tcp", address, time.Millisecond*time.Duration(*s.cfg.Timeout), &socks.Auth{User: a[0], Password: a[1]}, header)
|
||||||
reply := make([]byte, 512)
|
} else {
|
||||||
n, err = outConn.Read(reply)
|
if !s.IsBasicAuth() && auth.Password != "" && auth.User != "" {
|
||||||
if err != nil {
|
clientConn = socks.NewClientConn(&outConn, "tcp", address, time.Millisecond*time.Duration(*s.cfg.Timeout), &auth, header)
|
||||||
log.Printf("read reply from %s , err:%s", *s.cfg.Parent, err)
|
} else {
|
||||||
utils.CloseConn(inConn)
|
clientConn = socks.NewClientConn(&outConn, "tcp", address, time.Millisecond*time.Duration(*s.cfg.Timeout), nil, header)
|
||||||
utils.CloseConn(&outConn)
|
}
|
||||||
|
}
|
||||||
|
if err = clientConn.Handshake(); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
//log.Printf("method reply %v", reply[:n])
|
|
||||||
|
|
||||||
//build request
|
|
||||||
buf, err = s.buildRequest(address)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("build request to %s fail , err:%s", *s.cfg.Parent, err)
|
|
||||||
utils.CloseConn(inConn)
|
|
||||||
utils.CloseConn(&outConn)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
//send address request
|
|
||||||
_, err = outConn.Write(buf)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("write request to %s fail, err:%s", *s.cfg.Parent, err)
|
|
||||||
utils.CloseConn(inConn)
|
|
||||||
utils.CloseConn(&outConn)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
//read reply
|
|
||||||
reply = make([]byte, 512)
|
|
||||||
n, err = outConn.Read(reply)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("read reply from %s , err:%s", *s.cfg.Parent, err)
|
|
||||||
utils.CloseConn(inConn)
|
|
||||||
utils.CloseConn(&outConn)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
//log.Printf("request reply %v", reply[:n])
|
|
||||||
}
|
}
|
||||||
//forward client data to target,if necessary.
|
//forward client data to target,if necessary.
|
||||||
if len(forwardBytes) > 0 {
|
if len(forwardBytes) > 0 {
|
||||||
@ -283,6 +285,34 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (err error) {
|
|||||||
log.Printf("conn %s - %s connected", inAddr, outAddr)
|
log.Printf("conn %s - %s connected", inAddr, outAddr)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
func (s *SPS) InitBasicAuth() (err error) {
|
||||||
|
if *s.cfg.DNSAddress != "" {
|
||||||
|
s.basicAuth = utils.NewBasicAuth(&(*s).domainResolver)
|
||||||
|
} else {
|
||||||
|
s.basicAuth = utils.NewBasicAuth(nil)
|
||||||
|
}
|
||||||
|
if *s.cfg.AuthURL != "" {
|
||||||
|
s.basicAuth.SetAuthURL(*s.cfg.AuthURL, *s.cfg.AuthURLOkCode, *s.cfg.AuthURLTimeout, *s.cfg.AuthURLRetry)
|
||||||
|
log.Printf("auth from %s", *s.cfg.AuthURL)
|
||||||
|
}
|
||||||
|
if *s.cfg.AuthFile != "" {
|
||||||
|
var n = 0
|
||||||
|
n, err = s.basicAuth.AddFromFile(*s.cfg.AuthFile)
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("auth-file ERR:%s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Printf("auth data added from file %d , total:%d", n, s.basicAuth.Total())
|
||||||
|
}
|
||||||
|
if len(*s.cfg.Auth) > 0 {
|
||||||
|
n := s.basicAuth.Add(*s.cfg.Auth)
|
||||||
|
log.Printf("auth data added %d, total:%d", n, s.basicAuth.Total())
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
func (s *SPS) IsBasicAuth() bool {
|
||||||
|
return *s.cfg.AuthFile != "" || len(*s.cfg.Auth) > 0 || *s.cfg.AuthURL != ""
|
||||||
|
}
|
||||||
func (s *SPS) buildRequest(address string) (buf []byte, err error) {
|
func (s *SPS) buildRequest(address string) (buf []byte, err error) {
|
||||||
host, portStr, err := net.SplitHostPort(address)
|
host, portStr, err := net.SplitHostPort(address)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
253
utils/socks/client.go
Normal file
253
utils/socks/client.go
Normal file
@ -0,0 +1,253 @@
|
|||||||
|
package socks
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var socks5Errors = []string{
|
||||||
|
"",
|
||||||
|
"general failure",
|
||||||
|
"connection forbidden",
|
||||||
|
"network unreachable",
|
||||||
|
"host unreachable",
|
||||||
|
"connection refused",
|
||||||
|
"TTL expired",
|
||||||
|
"command not supported",
|
||||||
|
"address type not supported",
|
||||||
|
}
|
||||||
|
|
||||||
|
type Auth struct {
|
||||||
|
User, Password string
|
||||||
|
}
|
||||||
|
type ClientConn struct {
|
||||||
|
user string
|
||||||
|
password string
|
||||||
|
conn *net.Conn
|
||||||
|
header []byte
|
||||||
|
timeout time.Duration
|
||||||
|
addr string
|
||||||
|
network string
|
||||||
|
udpAddr string
|
||||||
|
}
|
||||||
|
|
||||||
|
// SOCKS5 returns a Dialer that makes SOCKSv5 connections to the given address
|
||||||
|
// with an optional username and password. See RFC 1928 and RFC 1929.
|
||||||
|
// target must be a canonical address with a host and port.
|
||||||
|
// network : tcp udp
|
||||||
|
func NewClientConn(conn *net.Conn, network, target string, timeout time.Duration, auth *Auth, header []byte) *ClientConn {
|
||||||
|
s := &ClientConn{
|
||||||
|
conn: conn,
|
||||||
|
network: network,
|
||||||
|
timeout: timeout,
|
||||||
|
}
|
||||||
|
if auth != nil {
|
||||||
|
s.user = auth.User
|
||||||
|
s.password = auth.Password
|
||||||
|
}
|
||||||
|
if header != nil && len(header) > 0 {
|
||||||
|
s.header = header
|
||||||
|
}
|
||||||
|
if network == "udp" && target == "" {
|
||||||
|
target = "0.0.0.0:1"
|
||||||
|
}
|
||||||
|
s.addr = target
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// connect takes an existing connection to a socks5 proxy server,
|
||||||
|
// and commands the server to extend that connection to target,
|
||||||
|
// which must be a canonical address with a host and port.
|
||||||
|
func (s *ClientConn) Handshake() error {
|
||||||
|
host, portStr, err := net.SplitHostPort(s.addr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
port, err := strconv.Atoi(portStr)
|
||||||
|
if err != nil {
|
||||||
|
return errors.New("proxy: failed to parse port number: " + portStr)
|
||||||
|
}
|
||||||
|
if port < 1 || port > 0xffff {
|
||||||
|
return errors.New("proxy: port number out of range: " + portStr)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := s.handshake(host); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
buf := []byte{}
|
||||||
|
if s.network == "tcp" {
|
||||||
|
buf = append(buf, VERSION_V5, CMD_CONNECT, 0 /* reserved */)
|
||||||
|
|
||||||
|
} else {
|
||||||
|
buf = append(buf, VERSION_V5, CMD_ASSOCIATE, 0 /* reserved */)
|
||||||
|
}
|
||||||
|
if ip := net.ParseIP(host); ip != nil {
|
||||||
|
if ip4 := ip.To4(); ip4 != nil {
|
||||||
|
buf = append(buf, ATYP_IPV4)
|
||||||
|
ip = ip4
|
||||||
|
} else {
|
||||||
|
buf = append(buf, ATYP_IPV6)
|
||||||
|
}
|
||||||
|
buf = append(buf, ip...)
|
||||||
|
} else {
|
||||||
|
if len(host) > 255 {
|
||||||
|
return errors.New("proxy: destination host name too long: " + host)
|
||||||
|
}
|
||||||
|
buf = append(buf, ATYP_DOMAIN)
|
||||||
|
buf = append(buf, byte(len(host)))
|
||||||
|
buf = append(buf, host...)
|
||||||
|
}
|
||||||
|
buf = append(buf, byte(port>>8), byte(port))
|
||||||
|
(*s.conn).SetDeadline(time.Now().Add(s.timeout))
|
||||||
|
if _, err := (*s.conn).Write(buf); err != nil {
|
||||||
|
return errors.New("proxy: failed to write connect request to SOCKS5 proxy at " + s.addr + ": " + err.Error())
|
||||||
|
}
|
||||||
|
(*s.conn).SetDeadline(time.Time{})
|
||||||
|
(*s.conn).SetDeadline(time.Now().Add(s.timeout))
|
||||||
|
if _, err := io.ReadFull((*s.conn), buf[:4]); err != nil {
|
||||||
|
return errors.New("proxy: failed to read connect reply from SOCKS5 proxy at " + s.addr + ": " + err.Error())
|
||||||
|
}
|
||||||
|
(*s.conn).SetDeadline(time.Time{})
|
||||||
|
failure := "unknown error"
|
||||||
|
if int(buf[1]) < len(socks5Errors) {
|
||||||
|
failure = socks5Errors[buf[1]]
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(failure) > 0 {
|
||||||
|
return errors.New("proxy: SOCKS5 proxy at " + s.addr + " failed to connect: " + failure)
|
||||||
|
}
|
||||||
|
|
||||||
|
bytesToDiscard := 0
|
||||||
|
switch buf[3] {
|
||||||
|
case ATYP_IPV4:
|
||||||
|
bytesToDiscard = net.IPv4len
|
||||||
|
case ATYP_IPV6:
|
||||||
|
bytesToDiscard = net.IPv6len
|
||||||
|
case ATYP_DOMAIN:
|
||||||
|
(*s.conn).SetDeadline(time.Now().Add(s.timeout))
|
||||||
|
_, err := io.ReadFull((*s.conn), buf[:1])
|
||||||
|
(*s.conn).SetDeadline(time.Time{})
|
||||||
|
if err != nil {
|
||||||
|
return errors.New("proxy: failed to read domain length from SOCKS5 proxy at " + s.addr + ": " + err.Error())
|
||||||
|
}
|
||||||
|
bytesToDiscard = int(buf[0])
|
||||||
|
default:
|
||||||
|
return errors.New("proxy: got unknown address type " + strconv.Itoa(int(buf[3])) + " from SOCKS5 proxy at " + s.addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
if cap(buf) < bytesToDiscard {
|
||||||
|
buf = make([]byte, bytesToDiscard)
|
||||||
|
} else {
|
||||||
|
buf = buf[:bytesToDiscard]
|
||||||
|
}
|
||||||
|
(*s.conn).SetDeadline(time.Now().Add(s.timeout))
|
||||||
|
if _, err := io.ReadFull((*s.conn), buf); err != nil {
|
||||||
|
return errors.New("proxy: failed to read address from SOCKS5 proxy at " + s.addr + ": " + err.Error())
|
||||||
|
}
|
||||||
|
(*s.conn).SetDeadline(time.Time{})
|
||||||
|
var ip net.IP
|
||||||
|
ip = buf
|
||||||
|
ipStr := ""
|
||||||
|
if bytesToDiscard == net.IPv4len || bytesToDiscard == net.IPv6len {
|
||||||
|
if ipv4 := ip.To4(); ipv4 != nil {
|
||||||
|
ipStr = ipv4.String()
|
||||||
|
} else {
|
||||||
|
ipStr = ip.To16().String()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//log.Printf("%v", ipStr)
|
||||||
|
// Also need to discard the port number
|
||||||
|
(*s.conn).SetDeadline(time.Now().Add(s.timeout))
|
||||||
|
if _, err := io.ReadFull((*s.conn), buf[:2]); err != nil {
|
||||||
|
return errors.New("proxy: failed to read port from SOCKS5 proxy at " + s.addr + ": " + err.Error())
|
||||||
|
}
|
||||||
|
p := binary.BigEndian.Uint16([]byte{buf[0], buf[1]})
|
||||||
|
//log.Printf("%v", p)
|
||||||
|
s.udpAddr = net.JoinHostPort(ipStr, fmt.Sprintf("%d", p))
|
||||||
|
//log.Printf("%v", s.udpAddr)
|
||||||
|
(*s.conn).SetDeadline(time.Time{})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func (s *ClientConn) SendUDP(data []byte, addr string) (respData []byte, err error) {
|
||||||
|
|
||||||
|
c, err := net.DialTimeout("udp", s.udpAddr, s.timeout)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
conn := c.(*net.UDPConn)
|
||||||
|
|
||||||
|
p := NewPacketUDP()
|
||||||
|
p.Build(addr, data)
|
||||||
|
conn.SetDeadline(time.Now().Add(s.timeout))
|
||||||
|
conn.Write(p.Bytes())
|
||||||
|
conn.SetDeadline(time.Time{})
|
||||||
|
|
||||||
|
buf := make([]byte, 1024)
|
||||||
|
conn.SetDeadline(time.Now().Add(s.timeout))
|
||||||
|
n, _, err := conn.ReadFrom(buf)
|
||||||
|
conn.SetDeadline(time.Time{})
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
respData = buf[:n]
|
||||||
|
return
|
||||||
|
}
|
||||||
|
func (s *ClientConn) handshake(host string) error {
|
||||||
|
|
||||||
|
// the size here is just an estimate
|
||||||
|
buf := make([]byte, 0, 6+len(host))
|
||||||
|
|
||||||
|
buf = append(buf, VERSION_V5)
|
||||||
|
if len(s.user) > 0 && len(s.user) < 256 && len(s.password) < 256 {
|
||||||
|
buf = append(buf, 2 /* num auth methods */, Method_NO_AUTH, Method_USER_PASS)
|
||||||
|
} else {
|
||||||
|
buf = append(buf, 1 /* num auth methods */, Method_NO_AUTH)
|
||||||
|
}
|
||||||
|
(*s.conn).SetDeadline(time.Now().Add(s.timeout))
|
||||||
|
if _, err := (*s.conn).Write(buf); err != nil {
|
||||||
|
return errors.New("proxy: failed to write greeting to SOCKS5 proxy at " + s.addr + ": " + err.Error())
|
||||||
|
}
|
||||||
|
(*s.conn).SetDeadline(time.Time{})
|
||||||
|
|
||||||
|
(*s.conn).SetDeadline(time.Now().Add(s.timeout))
|
||||||
|
if _, err := io.ReadFull((*s.conn), buf[:2]); err != nil {
|
||||||
|
return errors.New("proxy: failed to read greeting from SOCKS5 proxy at " + s.addr + ": " + err.Error())
|
||||||
|
}
|
||||||
|
(*s.conn).SetDeadline(time.Time{})
|
||||||
|
|
||||||
|
if buf[0] != 5 {
|
||||||
|
return errors.New("proxy: SOCKS5 proxy at " + s.addr + " has unexpected version " + strconv.Itoa(int(buf[0])))
|
||||||
|
}
|
||||||
|
if buf[1] == 0xff {
|
||||||
|
return errors.New("proxy: SOCKS5 proxy at " + s.addr + " requires authentication")
|
||||||
|
}
|
||||||
|
|
||||||
|
// See RFC 1929
|
||||||
|
if buf[1] == Method_USER_PASS {
|
||||||
|
buf = buf[:0]
|
||||||
|
buf = append(buf, 1 /* password protocol version */)
|
||||||
|
buf = append(buf, uint8(len(s.user)))
|
||||||
|
buf = append(buf, s.user...)
|
||||||
|
buf = append(buf, uint8(len(s.password)))
|
||||||
|
buf = append(buf, s.password...)
|
||||||
|
(*s.conn).SetDeadline(time.Now().Add(s.timeout))
|
||||||
|
if _, err := (*s.conn).Write(buf); err != nil {
|
||||||
|
return errors.New("proxy: failed to write authentication request to SOCKS5 proxy at " + s.addr + ": " + err.Error())
|
||||||
|
}
|
||||||
|
(*s.conn).SetDeadline(time.Time{})
|
||||||
|
(*s.conn).SetDeadline(time.Now().Add(s.timeout))
|
||||||
|
if _, err := io.ReadFull((*s.conn), buf[:2]); err != nil {
|
||||||
|
return errors.New("proxy: failed to read authentication reply from SOCKS5 proxy at " + s.addr + ": " + err.Error())
|
||||||
|
}
|
||||||
|
(*s.conn).SetDeadline(time.Time{})
|
||||||
|
if buf[1] != 0 {
|
||||||
|
return errors.New("proxy: SOCKS5 proxy at " + s.addr + " rejected username/password")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
226
utils/socks/server.go
Normal file
226
utils/socks/server.go
Normal file
@ -0,0 +1,226 @@
|
|||||||
|
package socks
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"snail007/proxy/utils"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
Method_NO_AUTH = uint8(0x00)
|
||||||
|
Method_GSSAPI = uint8(0x01)
|
||||||
|
Method_USER_PASS = uint8(0x02)
|
||||||
|
Method_IANA = uint8(0x7F)
|
||||||
|
Method_RESVERVE = uint8(0x80)
|
||||||
|
Method_NONE_ACCEPTABLE = uint8(0xFF)
|
||||||
|
VERSION_V5 = uint8(0x05)
|
||||||
|
CMD_CONNECT = uint8(0x01)
|
||||||
|
CMD_BIND = uint8(0x02)
|
||||||
|
CMD_ASSOCIATE = uint8(0x03)
|
||||||
|
ATYP_IPV4 = uint8(0x01)
|
||||||
|
ATYP_DOMAIN = uint8(0x03)
|
||||||
|
ATYP_IPV6 = uint8(0x04)
|
||||||
|
REP_SUCCESS = uint8(0x00)
|
||||||
|
REP_REQ_FAIL = uint8(0x01)
|
||||||
|
REP_RULE_FORBIDDEN = uint8(0x02)
|
||||||
|
REP_NETWOR_UNREACHABLE = uint8(0x03)
|
||||||
|
REP_HOST_UNREACHABLE = uint8(0x04)
|
||||||
|
REP_CONNECTION_REFUSED = uint8(0x05)
|
||||||
|
REP_TTL_TIMEOUT = uint8(0x06)
|
||||||
|
REP_CMD_UNSUPPORTED = uint8(0x07)
|
||||||
|
REP_ATYP_UNSUPPORTED = uint8(0x08)
|
||||||
|
REP_UNKNOWN = uint8(0x09)
|
||||||
|
RSV = uint8(0x00)
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ZERO_IP = []byte{0x00, 0x00, 0x00, 0x00}
|
||||||
|
ZERO_PORT = []byte{0x00, 0x00}
|
||||||
|
)
|
||||||
|
|
||||||
|
type ServerConn struct {
|
||||||
|
target string
|
||||||
|
user string
|
||||||
|
password string
|
||||||
|
conn *net.Conn
|
||||||
|
timeout time.Duration
|
||||||
|
auth *utils.BasicAuth
|
||||||
|
header []byte
|
||||||
|
ver uint8
|
||||||
|
//method
|
||||||
|
methodsCount uint8
|
||||||
|
methods []uint8
|
||||||
|
method uint8
|
||||||
|
//request
|
||||||
|
cmd uint8
|
||||||
|
reserve uint8
|
||||||
|
addressType uint8
|
||||||
|
dstAddr string
|
||||||
|
dstPort string
|
||||||
|
dstHost string
|
||||||
|
udpAddress string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewServerConn(conn *net.Conn, timeout time.Duration, auth *utils.BasicAuth, udpAddress string, header []byte) *ServerConn {
|
||||||
|
if udpAddress == "" {
|
||||||
|
udpAddress = "0.0.0.0:16666"
|
||||||
|
}
|
||||||
|
s := &ServerConn{
|
||||||
|
conn: conn,
|
||||||
|
timeout: timeout,
|
||||||
|
auth: auth,
|
||||||
|
header: header,
|
||||||
|
ver: VERSION_V5,
|
||||||
|
udpAddress: udpAddress,
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
|
||||||
|
}
|
||||||
|
func (s *ServerConn) Close() {
|
||||||
|
utils.CloseConn(s.conn)
|
||||||
|
}
|
||||||
|
func (s *ServerConn) AuthData() Auth {
|
||||||
|
return Auth{s.user, s.password}
|
||||||
|
}
|
||||||
|
func (s *ServerConn) Method() uint8 {
|
||||||
|
return s.method
|
||||||
|
}
|
||||||
|
func (s *ServerConn) Target() string {
|
||||||
|
return s.target
|
||||||
|
}
|
||||||
|
func (s *ServerConn) Handshake() (err error) {
|
||||||
|
remoteAddr := (*s.conn).RemoteAddr()
|
||||||
|
//协商开始
|
||||||
|
//method select request
|
||||||
|
var methodReq MethodsRequest
|
||||||
|
(*s.conn).SetReadDeadline(time.Now().Add(time.Second * s.timeout))
|
||||||
|
|
||||||
|
methodReq, e := NewMethodsRequest((*s.conn), s.header)
|
||||||
|
(*s.conn).SetReadDeadline(time.Time{})
|
||||||
|
if e != nil {
|
||||||
|
(*s.conn).SetReadDeadline(time.Now().Add(time.Second * s.timeout))
|
||||||
|
methodReq.Reply(Method_NONE_ACCEPTABLE)
|
||||||
|
(*s.conn).SetReadDeadline(time.Time{})
|
||||||
|
err = fmt.Errorf("new methods request fail,ERR: %s", e)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
//log.Printf("%v,s.auth == %v && methodReq.Select(Method_NO_AUTH) %v", methodReq.methods, s.auth, methodReq.Select(Method_NO_AUTH))
|
||||||
|
if s.auth == nil && methodReq.Select(Method_NO_AUTH) && !methodReq.Select(Method_USER_PASS) {
|
||||||
|
// if !methodReq.Select(Method_NO_AUTH) {
|
||||||
|
// (*s.conn).SetReadDeadline(time.Now().Add(time.Second * s.timeout))
|
||||||
|
// methodReq.Reply(Method_NONE_ACCEPTABLE)
|
||||||
|
// (*s.conn).SetReadDeadline(time.Time{})
|
||||||
|
// err = fmt.Errorf("none method found : Method_NO_AUTH")
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
s.method = Method_NO_AUTH
|
||||||
|
//method select reply
|
||||||
|
(*s.conn).SetReadDeadline(time.Now().Add(time.Second * s.timeout))
|
||||||
|
err = methodReq.Reply(Method_NO_AUTH)
|
||||||
|
(*s.conn).SetReadDeadline(time.Time{})
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("reply answer data fail,ERR: %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// err = fmt.Errorf("% x", methodReq.Bytes())
|
||||||
|
} else {
|
||||||
|
//auth
|
||||||
|
if !methodReq.Select(Method_USER_PASS) {
|
||||||
|
(*s.conn).SetReadDeadline(time.Now().Add(time.Second * s.timeout))
|
||||||
|
methodReq.Reply(Method_NONE_ACCEPTABLE)
|
||||||
|
(*s.conn).SetReadDeadline(time.Time{})
|
||||||
|
err = fmt.Errorf("none method found : Method_USER_PASS")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
s.method = Method_USER_PASS
|
||||||
|
//method reply need auth
|
||||||
|
(*s.conn).SetReadDeadline(time.Now().Add(time.Second * s.timeout))
|
||||||
|
err = methodReq.Reply(Method_USER_PASS)
|
||||||
|
(*s.conn).SetReadDeadline(time.Time{})
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("reply answer data fail,ERR: %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
//read auth
|
||||||
|
buf := make([]byte, 500)
|
||||||
|
var n int
|
||||||
|
(*s.conn).SetReadDeadline(time.Now().Add(time.Second * s.timeout))
|
||||||
|
n, err = (*s.conn).Read(buf)
|
||||||
|
(*s.conn).SetReadDeadline(time.Time{})
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("read auth info fail,ERR: %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r := buf[:n]
|
||||||
|
s.user = string(r[2 : r[1]+2])
|
||||||
|
s.password = string(r[2+r[1]+1:])
|
||||||
|
//err = fmt.Errorf("user:%s,pass:%s", user, pass)
|
||||||
|
//auth
|
||||||
|
_addr := strings.Split(remoteAddr.String(), ":")
|
||||||
|
if s.auth == nil || s.auth.CheckUserPass(s.user, s.password, _addr[0], "") {
|
||||||
|
(*s.conn).SetDeadline(time.Now().Add(time.Millisecond * time.Duration(s.timeout)))
|
||||||
|
_, err = (*s.conn).Write([]byte{0x01, 0x00})
|
||||||
|
(*s.conn).SetDeadline(time.Time{})
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("answer auth success to %s fail,ERR: %s", remoteAddr, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
(*s.conn).SetDeadline(time.Now().Add(time.Millisecond * time.Duration(s.timeout)))
|
||||||
|
_, err = (*s.conn).Write([]byte{0x01, 0x01})
|
||||||
|
(*s.conn).SetDeadline(time.Time{})
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("answer auth fail to %s fail,ERR: %s", remoteAddr, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = fmt.Errorf("auth fail from %s", remoteAddr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//request detail
|
||||||
|
(*s.conn).SetReadDeadline(time.Now().Add(time.Second * s.timeout))
|
||||||
|
request, e := NewRequest(*s.conn)
|
||||||
|
(*s.conn).SetReadDeadline(time.Time{})
|
||||||
|
if e != nil {
|
||||||
|
err = fmt.Errorf("read request data fail,ERR: %s", e)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
//协商结束
|
||||||
|
|
||||||
|
switch request.CMD() {
|
||||||
|
case CMD_BIND:
|
||||||
|
err = request.TCPReply(REP_UNKNOWN)
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("TCPReply REP_UNKNOWN to %s fail,ERR: %s", remoteAddr, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = fmt.Errorf("cmd bind not supported, form: %s", remoteAddr)
|
||||||
|
return
|
||||||
|
case CMD_CONNECT:
|
||||||
|
err = request.TCPReply(REP_SUCCESS)
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("TCPReply REP_SUCCESS to %s fail,ERR: %s", remoteAddr, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
case CMD_ASSOCIATE:
|
||||||
|
err = request.UDPReply(REP_SUCCESS, s.udpAddress)
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("UDPReply REP_SUCCESS to %s fail,ERR: %s", remoteAddr, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//fill socks info
|
||||||
|
s.target = request.Addr()
|
||||||
|
s.methodsCount = methodReq.MethodsCount()
|
||||||
|
s.methods = methodReq.Methods()
|
||||||
|
s.cmd = request.CMD()
|
||||||
|
s.reserve = request.reserve
|
||||||
|
s.addressType = request.addressType
|
||||||
|
s.dstAddr = request.dstAddr
|
||||||
|
s.dstHost = request.dstHost
|
||||||
|
s.dstPort = request.dstPort
|
||||||
|
return
|
||||||
|
}
|
||||||
@ -3,44 +3,13 @@ package socks
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"strconv"
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
Method_NO_AUTH = uint8(0x00)
|
|
||||||
Method_GSSAPI = uint8(0x01)
|
|
||||||
Method_USER_PASS = uint8(0x02)
|
|
||||||
Method_IANA = uint8(0x7F)
|
|
||||||
Method_RESVERVE = uint8(0x80)
|
|
||||||
Method_NONE_ACCEPTABLE = uint8(0xFF)
|
|
||||||
VERSION_V5 = uint8(0x05)
|
|
||||||
CMD_CONNECT = uint8(0x01)
|
|
||||||
CMD_BIND = uint8(0x02)
|
|
||||||
CMD_ASSOCIATE = uint8(0x03)
|
|
||||||
ATYP_IPV4 = uint8(0x01)
|
|
||||||
ATYP_DOMAIN = uint8(0x03)
|
|
||||||
ATYP_IPV6 = uint8(0x04)
|
|
||||||
REP_SUCCESS = uint8(0x00)
|
|
||||||
REP_REQ_FAIL = uint8(0x01)
|
|
||||||
REP_RULE_FORBIDDEN = uint8(0x02)
|
|
||||||
REP_NETWOR_UNREACHABLE = uint8(0x03)
|
|
||||||
REP_HOST_UNREACHABLE = uint8(0x04)
|
|
||||||
REP_CONNECTION_REFUSED = uint8(0x05)
|
|
||||||
REP_TTL_TIMEOUT = uint8(0x06)
|
|
||||||
REP_CMD_UNSUPPORTED = uint8(0x07)
|
|
||||||
REP_ATYP_UNSUPPORTED = uint8(0x08)
|
|
||||||
REP_UNKNOWN = uint8(0x09)
|
|
||||||
RSV = uint8(0x00)
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
ZERO_IP = []byte{0x00, 0x00, 0x00, 0x00}
|
|
||||||
ZERO_PORT = []byte{0x00, 0x00}
|
|
||||||
)
|
|
||||||
|
|
||||||
type Request struct {
|
type Request struct {
|
||||||
ver uint8
|
ver uint8
|
||||||
cmd uint8
|
cmd uint8
|
||||||
@ -57,7 +26,7 @@ func NewRequest(rw io.ReadWriter, header ...[]byte) (req Request, err interface{
|
|||||||
var b = make([]byte, 1024)
|
var b = make([]byte, 1024)
|
||||||
var n int
|
var n int
|
||||||
req = Request{rw: rw}
|
req = Request{rw: rw}
|
||||||
if len(header) == 1 {
|
if header != nil && len(header) == 1 && len(header[0]) > 1 {
|
||||||
b = header[0]
|
b = header[0]
|
||||||
n = len(header[0])
|
n = len(header[0])
|
||||||
} else {
|
} else {
|
||||||
@ -71,7 +40,6 @@ func NewRequest(rw io.ReadWriter, header ...[]byte) (req Request, err interface{
|
|||||||
req.cmd = uint8(b[1])
|
req.cmd = uint8(b[1])
|
||||||
req.reserve = uint8(b[2])
|
req.reserve = uint8(b[2])
|
||||||
req.addressType = uint8(b[3])
|
req.addressType = uint8(b[3])
|
||||||
|
|
||||||
if b[0] != 0x5 {
|
if b[0] != 0x5 {
|
||||||
err = fmt.Errorf("sosck version supported")
|
err = fmt.Errorf("sosck version supported")
|
||||||
req.TCPReply(REP_REQ_FAIL)
|
req.TCPReply(REP_REQ_FAIL)
|
||||||
@ -129,7 +97,7 @@ func (s *Request) NewReply(rep uint8, addr string) []byte {
|
|||||||
ipv6[4], ipv6[5], ipv6[6], ipv6[7],
|
ipv6[4], ipv6[5], ipv6[6], ipv6[7],
|
||||||
ipv6[8], ipv6[9], ipv6[10], ipv6[11],
|
ipv6[8], ipv6[9], ipv6[10], ipv6[11],
|
||||||
)
|
)
|
||||||
if ipv6 != nil && "0000000000255255" != zeroiIPv6 {
|
if ipb == nil && ipv6 != nil && "0000000000255255" != zeroiIPv6 {
|
||||||
atyp = ATYP_IPV6
|
atyp = ATYP_IPV6
|
||||||
ipb = ip.To16()
|
ipb = ip.To16()
|
||||||
}
|
}
|
||||||
@ -165,7 +133,7 @@ func NewMethodsRequest(r io.ReadWriter, header ...[]byte) (s MethodsRequest, err
|
|||||||
s.rw = &r
|
s.rw = &r
|
||||||
var buf = make([]byte, 300)
|
var buf = make([]byte, 300)
|
||||||
var n int
|
var n int
|
||||||
if len(header) == 1 {
|
if header != nil && len(header) == 1 && len(header[0]) > 1 {
|
||||||
buf = header[0]
|
buf = header[0]
|
||||||
n = len(header[0])
|
n = len(header[0])
|
||||||
} else {
|
} else {
|
||||||
@ -182,7 +150,6 @@ func NewMethodsRequest(r io.ReadWriter, header ...[]byte) (s MethodsRequest, err
|
|||||||
err = fmt.Errorf("socks methods data length error")
|
err = fmt.Errorf("socks methods data length error")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
s.ver = buf[0]
|
s.ver = buf[0]
|
||||||
s.methodsCount = buf[1]
|
s.methodsCount = buf[1]
|
||||||
s.methods = buf[2:n]
|
s.methods = buf[2:n]
|
||||||
@ -195,6 +162,9 @@ func (s *MethodsRequest) Version() uint8 {
|
|||||||
func (s *MethodsRequest) MethodsCount() uint8 {
|
func (s *MethodsRequest) MethodsCount() uint8 {
|
||||||
return s.methodsCount
|
return s.methodsCount
|
||||||
}
|
}
|
||||||
|
func (s *MethodsRequest) Methods() []uint8 {
|
||||||
|
return s.methods
|
||||||
|
}
|
||||||
func (s *MethodsRequest) Select(method uint8) bool {
|
func (s *MethodsRequest) Select(method uint8) bool {
|
||||||
for _, m := range s.methods {
|
for _, m := range s.methods {
|
||||||
if m == method {
|
if m == method {
|
||||||
@ -211,17 +181,6 @@ func (s *MethodsRequest) Bytes() []byte {
|
|||||||
return s.bytes
|
return s.bytes
|
||||||
}
|
}
|
||||||
|
|
||||||
type UDPPacket struct {
|
|
||||||
rsv uint16
|
|
||||||
frag uint8
|
|
||||||
atype uint8
|
|
||||||
dstHost string
|
|
||||||
dstPort string
|
|
||||||
data []byte
|
|
||||||
header []byte
|
|
||||||
bytes []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
func ParseUDPPacket(b []byte) (p UDPPacket, err error) {
|
func ParseUDPPacket(b []byte) (p UDPPacket, err error) {
|
||||||
p = UDPPacket{}
|
p = UDPPacket{}
|
||||||
p.frag = uint8(b[2])
|
p.frag = uint8(b[2])
|
||||||
@ -249,6 +208,18 @@ func ParseUDPPacket(b []byte) (p UDPPacket, err error) {
|
|||||||
p.header = b[:portIndex+2]
|
p.header = b[:portIndex+2]
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type UDPPacket struct {
|
||||||
|
rsv uint16
|
||||||
|
frag uint8
|
||||||
|
atype uint8
|
||||||
|
dstHost string
|
||||||
|
dstPort string
|
||||||
|
data []byte
|
||||||
|
header []byte
|
||||||
|
bytes []byte
|
||||||
|
}
|
||||||
|
|
||||||
func (s *UDPPacket) Header() []byte {
|
func (s *UDPPacket) Header() []byte {
|
||||||
return s.header
|
return s.header
|
||||||
}
|
}
|
||||||
@ -268,3 +239,104 @@ func (s *UDPPacket) Port() string {
|
|||||||
func (s *UDPPacket) Data() []byte {
|
func (s *UDPPacket) Data() []byte {
|
||||||
return s.data
|
return s.data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type PacketUDP struct {
|
||||||
|
rsv uint16
|
||||||
|
frag uint8
|
||||||
|
atype uint8
|
||||||
|
dstHost string
|
||||||
|
dstPort string
|
||||||
|
data []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewPacketUDP() (p PacketUDP) {
|
||||||
|
return PacketUDP{}
|
||||||
|
}
|
||||||
|
func (p *PacketUDP) Build(destAddr string, data []byte) (err error) {
|
||||||
|
host, port, err := net.SplitHostPort(destAddr)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
p.rsv = 0
|
||||||
|
p.frag = 0
|
||||||
|
p.dstHost = host
|
||||||
|
p.dstPort = port
|
||||||
|
p.atype = ATYP_IPV4
|
||||||
|
if ip := net.ParseIP(host); ip != nil {
|
||||||
|
if ip4 := ip.To4(); ip4 != nil {
|
||||||
|
p.atype = ATYP_IPV4
|
||||||
|
ip = ip4
|
||||||
|
} else {
|
||||||
|
p.atype = ATYP_IPV6
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if len(host) > 255 {
|
||||||
|
err = errors.New("proxy: destination host name too long: " + host)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
p.atype = ATYP_DOMAIN
|
||||||
|
}
|
||||||
|
p.data = data
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
func (p *PacketUDP) Parse(b []byte) (err error) {
|
||||||
|
p.frag = uint8(b[2])
|
||||||
|
if p.frag != 0 {
|
||||||
|
err = fmt.Errorf("FRAG only support for 0 , %v ,%v", p.frag, b[:4])
|
||||||
|
return
|
||||||
|
}
|
||||||
|
portIndex := 0
|
||||||
|
p.atype = b[3]
|
||||||
|
switch p.atype {
|
||||||
|
case ATYP_IPV4: //IP V4
|
||||||
|
p.dstHost = net.IPv4(b[4], b[5], b[6], b[7]).String()
|
||||||
|
portIndex = 8
|
||||||
|
case ATYP_DOMAIN: //域名
|
||||||
|
domainLen := uint8(b[4])
|
||||||
|
p.dstHost = string(b[5 : 5+domainLen]) //b[4]表示域名的长度
|
||||||
|
portIndex = int(5 + domainLen)
|
||||||
|
case ATYP_IPV6: //IP V6
|
||||||
|
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()
|
||||||
|
portIndex = 20
|
||||||
|
}
|
||||||
|
p.dstPort = strconv.Itoa(int(b[portIndex])<<8 | int(b[portIndex+1]))
|
||||||
|
p.data = b[portIndex+2:]
|
||||||
|
return
|
||||||
|
}
|
||||||
|
func (p *PacketUDP) Header() []byte {
|
||||||
|
header := new(bytes.Buffer)
|
||||||
|
header.Write([]byte{0x00, 0x00, p.frag, p.atype})
|
||||||
|
if p.atype == ATYP_IPV4 {
|
||||||
|
ip := net.ParseIP(p.dstHost)
|
||||||
|
header.Write(ip.To4())
|
||||||
|
} else if p.atype == ATYP_IPV6 {
|
||||||
|
ip := net.ParseIP(p.dstHost)
|
||||||
|
header.Write(ip.To16())
|
||||||
|
} else if p.atype == ATYP_DOMAIN {
|
||||||
|
hBytes := []byte(p.dstHost)
|
||||||
|
header.WriteByte(byte(len(hBytes)))
|
||||||
|
header.Write(hBytes)
|
||||||
|
}
|
||||||
|
port, _ := strconv.ParseUint(p.dstPort, 10, 64)
|
||||||
|
portBytes := new(bytes.Buffer)
|
||||||
|
binary.Write(portBytes, binary.BigEndian, port)
|
||||||
|
header.Write(portBytes.Bytes()[portBytes.Len()-2:])
|
||||||
|
return header.Bytes()
|
||||||
|
}
|
||||||
|
func (p *PacketUDP) Bytes() []byte {
|
||||||
|
packBytes := new(bytes.Buffer)
|
||||||
|
packBytes.Write(p.Header())
|
||||||
|
packBytes.Write(p.data)
|
||||||
|
return packBytes.Bytes()
|
||||||
|
}
|
||||||
|
func (p *PacketUDP) Host() string {
|
||||||
|
return p.dstHost
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PacketUDP) Port() string {
|
||||||
|
return p.dstPort
|
||||||
|
}
|
||||||
|
func (p *PacketUDP) Data() []byte {
|
||||||
|
return p.data
|
||||||
|
}
|
||||||
|
|||||||
@ -317,7 +317,7 @@ func NewHTTPRequest(inConn *net.Conn, bufSize int, isBasicAuth bool, basicAuth *
|
|||||||
req = HTTPRequest{
|
req = HTTPRequest{
|
||||||
conn: inConn,
|
conn: inConn,
|
||||||
}
|
}
|
||||||
if len(header) == 1 {
|
if header != nil && len(header) == 1 && len(header[0]) > 1 {
|
||||||
buf = header[0]
|
buf = header[0]
|
||||||
n = len(header[0])
|
n = len(header[0])
|
||||||
} else {
|
} else {
|
||||||
@ -402,17 +402,13 @@ func (req *HTTPRequest) IsHTTPS() bool {
|
|||||||
return req.Method == "CONNECT"
|
return req.Method == "CONNECT"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (req *HTTPRequest) BasicAuth() (err error) {
|
func (req *HTTPRequest) GetAuthDataStr() (basicInfo string, err error) {
|
||||||
|
|
||||||
// log.Printf("request :%s", string(req.HeadBuf))
|
// log.Printf("request :%s", string(req.HeadBuf))
|
||||||
code := "407"
|
|
||||||
authorization := req.getHeader("Proxy-Authorization")
|
authorization := req.getHeader("Proxy-Authorization")
|
||||||
// if authorization == "" {
|
|
||||||
// authorization = req.getHeader("Authorization")
|
authorization = strings.Trim(authorization, " \r\n\t")
|
||||||
// code = "401"
|
|
||||||
// }
|
|
||||||
if authorization == "" {
|
if authorization == "" {
|
||||||
fmt.Fprintf((*req.conn), "HTTP/1.1 %s Unauthorized\r\nWWW-Authenticate: Basic realm=\"\"\r\n\r\nUnauthorized", code)
|
fmt.Fprintf((*req.conn), "HTTP/1.1 %s Unauthorized\r\nWWW-Authenticate: Basic realm=\"\"\r\n\r\nUnauthorized", "407")
|
||||||
CloseConn(req.conn)
|
CloseConn(req.conn)
|
||||||
err = errors.New("require auth header data")
|
err = errors.New("require auth header data")
|
||||||
return
|
return
|
||||||
@ -430,6 +426,10 @@ func (req *HTTPRequest) BasicAuth() (err error) {
|
|||||||
CloseConn(req.conn)
|
CloseConn(req.conn)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
basicInfo = string(user)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
func (req *HTTPRequest) BasicAuth() (err error) {
|
||||||
addr := strings.Split((*req.conn).RemoteAddr().String(), ":")
|
addr := strings.Split((*req.conn).RemoteAddr().String(), ":")
|
||||||
URL := ""
|
URL := ""
|
||||||
if req.IsHTTPS() {
|
if req.IsHTTPS() {
|
||||||
@ -437,10 +437,14 @@ func (req *HTTPRequest) BasicAuth() (err error) {
|
|||||||
} else {
|
} else {
|
||||||
URL = req.getHTTPURL()
|
URL = req.getHTTPURL()
|
||||||
}
|
}
|
||||||
|
user, err := req.GetAuthDataStr()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
authOk := (*req.basicAuth).Check(string(user), addr[0], URL)
|
authOk := (*req.basicAuth).Check(string(user), addr[0], URL)
|
||||||
//log.Printf("auth %s,%v", string(user), authOk)
|
//log.Printf("auth %s,%v", string(user), authOk)
|
||||||
if !authOk {
|
if !authOk {
|
||||||
fmt.Fprintf((*req.conn), "HTTP/1.1 %s Unauthorized\r\n\r\nUnauthorized", code)
|
fmt.Fprintf((*req.conn), "HTTP/1.1 %s Unauthorized\r\n\r\nUnauthorized", "407")
|
||||||
CloseConn(req.conn)
|
CloseConn(req.conn)
|
||||||
err = fmt.Errorf("basic auth fail")
|
err = fmt.Errorf("basic auth fail")
|
||||||
return
|
return
|
||||||
|
|||||||
Reference in New Issue
Block a user