@ -1,4 +1,9 @@
|
|||||||
proxy更新日志
|
proxy更新日志
|
||||||
|
v5.2
|
||||||
|
1.修复了HTTP(S)\SPS反向代理无法正常工作的问题.
|
||||||
|
2.优化了智能判断,减少不必要的DNS解析.
|
||||||
|
3.重构了SOCKS和SPS的UDP功能,基于UDP的游戏加速嗖嗖的.
|
||||||
|
|
||||||
v5.1
|
v5.1
|
||||||
1.优化了kcp默认mtu配置,调整为450.
|
1.优化了kcp默认mtu配置,调整为450.
|
||||||
2.优化了HTTP(S)\SOCKS5代理智能判断,更加精确。
|
2.优化了HTTP(S)\SOCKS5代理智能判断,更加精确。
|
||||||
|
|||||||
50
README.md
50
README.md
@ -6,7 +6,24 @@ Proxy is a high performance HTTP, HTTPS, HTTPS, websocket, TCP, UDP, Socks5 prox
|
|||||||
|
|
||||||
[](https://github.com/snail007/goproxy/) []() [](https://github.com/snail007/goproxy/releases) [](https://github.com/snail007/goproxy/releases)
|
[](https://github.com/snail007/goproxy/) []() [](https://github.com/snail007/goproxy/releases) [](https://github.com/snail007/goproxy/releases)
|
||||||
|
|
||||||
[中文手册](/README_ZH.md) **[全平台GUI版本](/gui/README.md)** **[全平台SDK](/sdk/README.md)**
|
**[中文手册](/README_ZH.md)**
|
||||||
|
|
||||||
|
**[全平台图形界面版本](/gui/README.md)**
|
||||||
|
|
||||||
|
**[全平台SDK](/sdk/README.md)**
|
||||||
|
|
||||||
|
|
||||||
|
### How to use the source code?
|
||||||
|
|
||||||
|
Pull Request is welcomed.
|
||||||
|
Recommend go1.10.1.
|
||||||
|
`go get github.com/snail007/goproxy`
|
||||||
|
use command cd to enter your go SRC directory
|
||||||
|
then cd to enter `github.com/snail007/goproxy`.
|
||||||
|
Direct compilation:`go build -o proxy`
|
||||||
|
execution: `go run *.go`
|
||||||
|
`utils` is a toolkit, and `service` is a specific service class.
|
||||||
|
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
- chain-style proxy: the program itself can be a primary proxy, and if a parent proxy is set, it can be used as a second level proxy or even a N level proxy.
|
- chain-style proxy: the program itself can be a primary proxy, and if a parent proxy is set, it can be used as a second level proxy or even a N level proxy.
|
||||||
@ -37,27 +54,7 @@ Proxy is a high performance HTTP, HTTPS, HTTPS, websocket, TCP, UDP, Socks5 prox
|
|||||||
- ...
|
- ...
|
||||||
|
|
||||||
|
|
||||||
This page is the v5.1 manual, and the other version of the manual can be checked by the following link.
|
This page is the v5.2 manual, and the other version of the manual can be checked by the following [link](docs/old-release.md).
|
||||||
- [v5.1 manual](https://github.com/snail007/goproxy/tree/v5.1)
|
|
||||||
- [v4.9 manual](https://github.com/snail007/goproxy/tree/v4.9)
|
|
||||||
- [v4.8 manual](https://github.com/snail007/goproxy/tree/v4.8)
|
|
||||||
- [v4.7 manual](https://github.com/snail007/goproxy/tree/v4.7)
|
|
||||||
- [v4.6 manual](https://github.com/snail007/goproxy/tree/v4.6)
|
|
||||||
- [v4.5 manual](https://github.com/snail007/goproxy/tree/v4.5)
|
|
||||||
- [v4.4 manual](https://github.com/snail007/goproxy/tree/v4.4)
|
|
||||||
- [v4.3 manual](https://github.com/snail007/goproxy/tree/v4.3)
|
|
||||||
- [v4.2 manual](https://github.com/snail007/goproxy/tree/v4.2)
|
|
||||||
- [v4.0-4.1 manual](https://github.com/snail007/goproxy/tree/v4.1)
|
|
||||||
- [v3.9 manual](https://github.com/snail007/goproxy/tree/v3.9)
|
|
||||||
- [v3.8 manual](https://github.com/snail007/goproxy/tree/v3.8)
|
|
||||||
- [v3.6-v3.7 manual](https://github.com/snail007/goproxy/tree/v3.6)
|
|
||||||
- [v3.5 manual](https://github.com/snail007/goproxy/tree/v3.5)
|
|
||||||
- [v3.4 manual](https://github.com/snail007/goproxy/tree/v3.4)
|
|
||||||
- [v3.3 manual](https://github.com/snail007/goproxy/tree/v3.3)
|
|
||||||
- [v3.2 manual](https://github.com/snail007/goproxy/tree/v3.2)
|
|
||||||
- [v3.1 manual](https://github.com/snail007/goproxy/tree/v3.1)
|
|
||||||
- [v3.0 manual](https://github.com/snail007/goproxy/tree/v3.0)
|
|
||||||
- [v2.x manual](https://github.com/snail007/goproxy/tree/v2.2)
|
|
||||||
|
|
||||||
### How to find the organization?
|
### How to find the organization?
|
||||||
[Click to join the proxy group of gitter](https://gitter.im/go-proxy/Lobby?utm_source=share-link&utm_medium=link&utm_campaign=share-link)
|
[Click to join the proxy group of gitter](https://gitter.im/go-proxy/Lobby?utm_source=share-link&utm_medium=link&utm_campaign=share-link)
|
||||||
@ -1088,15 +1085,6 @@ First, you need to clone the project to your account, and then modify the code o
|
|||||||
Finally, Pull Request to dev branch of goproxy project, and contribute code for efficiency.
|
Finally, Pull Request to dev branch of goproxy project, and contribute code for efficiency.
|
||||||
PR needs to explain what changes have been made and why you change them.
|
PR needs to explain what changes have been made and why you change them.
|
||||||
|
|
||||||
### How to use the source code?
|
|
||||||
Recommend go1.10.1.
|
|
||||||
`go get github.com/snail007/goproxy`
|
|
||||||
use command cd to enter your go SRC directory
|
|
||||||
then cd to enter `github.com/snail007/goproxy`.
|
|
||||||
Direct compilation:`go build -o proxy`
|
|
||||||
execution: `go run *.go`
|
|
||||||
`utils` is a toolkit, and `service` is a specific service class.
|
|
||||||
|
|
||||||
### License
|
### License
|
||||||
Proxy is licensed under GPLv3 license.
|
Proxy is licensed under GPLv3 license.
|
||||||
### Contact
|
### Contact
|
||||||
|
|||||||
30
README_ZH.md
30
README_ZH.md
@ -7,7 +7,17 @@ Proxy是golang实现的高性能http,https,websocket,tcp,udp,socks5代理服务
|
|||||||
|
|
||||||
[](https://github.com/snail007/goproxy/) []() [](https://github.com/snail007/goproxy/releases) [](https://github.com/snail007/goproxy/releases)
|
[](https://github.com/snail007/goproxy/) []() [](https://github.com/snail007/goproxy/releases) [](https://github.com/snail007/goproxy/releases)
|
||||||
|
|
||||||
**[English Manual](/README.md)** **[全平台GUI版本](/gui/README.md)** **[全平台SDK](/sdk/README.md)**
|
**[English Manual](/README.md)**
|
||||||
|
|
||||||
|
**[全平台图形界面版本](/gui/README.md)**
|
||||||
|
|
||||||
|
**[全平台SDK](/sdk/README.md)**
|
||||||
|
|
||||||
|
### 如何贡献代码(Pull Request)?
|
||||||
|
|
||||||
|
欢迎加入一起发展壮大proxy.首先需要clone本项目到自己的帐号下面,
|
||||||
|
然后在dev分支上面修改代码,最后发Pull Request到goproxy项目的dev分支即可,
|
||||||
|
为了高效贡献代码,pr的时候需要说明做了什么变更,原因是什么.
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
- 链式代理,程序本身可以作为一级代理,如果设置了上级代理那么可以作为二级代理,乃至N级代理.
|
- 链式代理,程序本身可以作为一级代理,如果设置了上级代理那么可以作为二级代理,乃至N级代理.
|
||||||
@ -38,7 +48,7 @@ Proxy是golang实现的高性能http,https,websocket,tcp,udp,socks5代理服务
|
|||||||
- ...
|
- ...
|
||||||
|
|
||||||
|
|
||||||
本页是v5.1手册,其他版本手册请点击[这里](docs/old-release.md)查看.
|
本页是v5.2手册,其他版本手册请点击[这里](docs/old-release.md)查看.
|
||||||
|
|
||||||
|
|
||||||
### 怎么找到组织?
|
### 怎么找到组织?
|
||||||
@ -689,7 +699,14 @@ server连接到bridge的时候,如果同时有多个client连接到同一个brid
|
|||||||
`./proxy help client`
|
`./proxy help client`
|
||||||
|
|
||||||
### **5.SOCKS5代理**
|
### **5.SOCKS5代理**
|
||||||
提示:SOCKS5代理,支持CONNECT,UDP协议,不支持BIND,支持用户名密码认证.
|
提示:
|
||||||
|
|
||||||
|
SOCKS5代理,支持CONNECT,UDP协议,不支持BIND,支持用户名密码认证.
|
||||||
|
|
||||||
|
***如果你的VPS是阿里云,腾讯云这种VPS,就是ifconfig看不见你的公网IP,只能看见内网IP,***
|
||||||
|
|
||||||
|
***那么需要加上`-g VPS公网IP`参数,SOCKS5代理的UDP功能才能正常工作。***
|
||||||
|
|
||||||
#### **5.1.普通SOCKS5代理**
|
#### **5.1.普通SOCKS5代理**
|
||||||
`./proxy socks -t tcp -p "0.0.0.0:38080"`
|
`./proxy socks -t tcp -p "0.0.0.0:38080"`
|
||||||
|
|
||||||
@ -1109,11 +1126,6 @@ fast3:`--nodelay=1 --interval=10 --resend=2 --nc=1`
|
|||||||
- http(s)代理增加pac支持?
|
- http(s)代理增加pac支持?
|
||||||
- 欢迎加群反馈...
|
- 欢迎加群反馈...
|
||||||
|
|
||||||
### 如何贡献代码(Pull Request)?
|
|
||||||
首先需要clone本项目到自己的帐号下面,然后在dev分支上面修改代码,
|
|
||||||
最后发Pull Request到goproxy项目的dev分支即可,为了高效贡献代码,
|
|
||||||
pr的时候需要说明做了什么变更,原因是什么.
|
|
||||||
|
|
||||||
### 如何使用源码?
|
### 如何使用源码?
|
||||||
建议go1.10.1.
|
建议go1.10.1.
|
||||||
`go get github.com/snail007/goproxy`
|
`go get github.com/snail007/goproxy`
|
||||||
@ -1133,5 +1145,3 @@ QQ交流群:189618940
|
|||||||
如果proxy帮助你解决了很多问题,你可以通过下面的捐赠更好的支持proxy.
|
如果proxy帮助你解决了很多问题,你可以通过下面的捐赠更好的支持proxy.
|
||||||
<img src="https://github.com/snail007/goproxy/blob/master/docs/images/alipay.jpg?raw=true" width="200"/>
|
<img src="https://github.com/snail007/goproxy/blob/master/docs/images/alipay.jpg?raw=true" width="200"/>
|
||||||
<img src="https://github.com/snail007/goproxy/blob/master/docs/images/wxpay.jpg?raw=true" width="200"/>
|
<img src="https://github.com/snail007/goproxy/blob/master/docs/images/wxpay.jpg?raw=true" width="200"/>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -198,8 +198,6 @@ func initConfig() (err error) {
|
|||||||
socksArgs.ParentType = socks.Flag("parent-type", "parent protocol type <tls|tcp|kcp|ssh>").Default("tcp").Short('T').Enum("tls", "tcp", "kcp", "ssh")
|
socksArgs.ParentType = socks.Flag("parent-type", "parent protocol type <tls|tcp|kcp|ssh>").Default("tcp").Short('T').Enum("tls", "tcp", "kcp", "ssh")
|
||||||
socksArgs.LocalType = socks.Flag("local-type", "local protocol type <tls|tcp|kcp>").Default("tcp").Short('t').Enum("tls", "tcp", "kcp")
|
socksArgs.LocalType = socks.Flag("local-type", "local protocol type <tls|tcp|kcp>").Default("tcp").Short('t').Enum("tls", "tcp", "kcp")
|
||||||
socksArgs.Local = socks.Flag("local", "local ip:port to listen").Short('p').Default(":33080").String()
|
socksArgs.Local = socks.Flag("local", "local ip:port to listen").Short('p').Default(":33080").String()
|
||||||
socksArgs.UDPParent = socks.Flag("udp-parent", "udp parent address, such as: \"23.32.32.19:33090\"").Default("").Short('X').String()
|
|
||||||
socksArgs.UDPLocal = socks.Flag("udp-local", "udp local ip:port to listen").Short('x').Default(":33090").String()
|
|
||||||
socksArgs.CertFile = socks.Flag("cert", "cert file for tls").Short('C').Default("proxy.crt").String()
|
socksArgs.CertFile = socks.Flag("cert", "cert file for tls").Short('C').Default("proxy.crt").String()
|
||||||
socksArgs.CaCertFile = socks.Flag("ca", "ca cert file for tls").Default("").String()
|
socksArgs.CaCertFile = socks.Flag("ca", "ca cert file for tls").Default("").String()
|
||||||
socksArgs.KeyFile = socks.Flag("key", "key file for tls").Short('K').Default("proxy.key").String()
|
socksArgs.KeyFile = socks.Flag("key", "key file for tls").Short('K').Default("proxy.key").String()
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
# Old Versions of Proxy
|
# Old Versions of Proxy
|
||||||
|
|
||||||
|
- [v5.1手册](https://github.com/snail007/goproxy/tree/v5.1)
|
||||||
- [v5.0手册](https://github.com/snail007/goproxy/tree/v5.0)
|
- [v5.0手册](https://github.com/snail007/goproxy/tree/v5.0)
|
||||||
- [v4.9手册](https://github.com/snail007/goproxy/tree/v4.9)
|
- [v4.9手册](https://github.com/snail007/goproxy/tree/v4.9)
|
||||||
- [v4.8手册](https://github.com/snail007/goproxy/tree/v4.8)
|
- [v4.8手册](https://github.com/snail007/goproxy/tree/v4.8)
|
||||||
|
|||||||
@ -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/v5.1/proxy-linux-amd64.tar.gz
|
wget https://github.com/snail007/goproxy/releases/download/v5.2/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
@ -9,7 +9,7 @@ import (
|
|||||||
"github.com/snail007/goproxy/services"
|
"github.com/snail007/goproxy/services"
|
||||||
)
|
)
|
||||||
|
|
||||||
const APP_VERSION = "5.1"
|
const APP_VERSION = "5.2"
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
err := initConfig()
|
err := initConfig()
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
VER="5.1"
|
VER="5.2"
|
||||||
RELEASE="release-${VER}"
|
RELEASE="release-${VER}"
|
||||||
rm -rf .cert
|
rm -rf .cert
|
||||||
mkdir .cert
|
mkdir .cert
|
||||||
|
|||||||
@ -76,7 +76,7 @@ func (s *DNS) InitService() (err error) {
|
|||||||
nil,
|
nil,
|
||||||
&net.Dialer{
|
&net.Dialer{
|
||||||
Timeout: 5 * time.Second,
|
Timeout: 5 * time.Second,
|
||||||
KeepAlive: 5 * time.Second,
|
KeepAlive: 2 * time.Second,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@ -194,8 +194,6 @@ func Start(serviceID, serviceArgsStr string) (errStr string) {
|
|||||||
socksArgs.ParentType = socks.Flag("parent-type", "parent protocol type <tls|tcp|kcp|ssh>").Default("tcp").Short('T').Enum("tls", "tcp", "kcp", "ssh")
|
socksArgs.ParentType = socks.Flag("parent-type", "parent protocol type <tls|tcp|kcp|ssh>").Default("tcp").Short('T').Enum("tls", "tcp", "kcp", "ssh")
|
||||||
socksArgs.LocalType = socks.Flag("local-type", "local protocol type <tls|tcp|kcp>").Default("tcp").Short('t').Enum("tls", "tcp", "kcp")
|
socksArgs.LocalType = socks.Flag("local-type", "local protocol type <tls|tcp|kcp>").Default("tcp").Short('t').Enum("tls", "tcp", "kcp")
|
||||||
socksArgs.Local = socks.Flag("local", "local ip:port to listen").Short('p').Default(":33080").String()
|
socksArgs.Local = socks.Flag("local", "local ip:port to listen").Short('p').Default(":33080").String()
|
||||||
socksArgs.UDPParent = socks.Flag("udp-parent", "udp parent address, such as: \"23.32.32.19:33090\"").Default("").Short('X').String()
|
|
||||||
socksArgs.UDPLocal = socks.Flag("udp-local", "udp local ip:port to listen").Short('x').Default(":33090").String()
|
|
||||||
socksArgs.CertFile = socks.Flag("cert", "cert file for tls").Short('C').Default("proxy.crt").String()
|
socksArgs.CertFile = socks.Flag("cert", "cert file for tls").Short('C').Default("proxy.crt").String()
|
||||||
socksArgs.CaCertFile = socks.Flag("ca", "ca cert file for tls").Default("").String()
|
socksArgs.CaCertFile = socks.Flag("ca", "ca cert file for tls").Default("").String()
|
||||||
socksArgs.KeyFile = socks.Flag("key", "key file for tls").Short('K').Default("proxy.key").String()
|
socksArgs.KeyFile = socks.Flag("key", "key file for tls").Short('K').Default("proxy.key").String()
|
||||||
|
|||||||
@ -277,10 +277,11 @@ func (s *HTTP) callback(inConn net.Conn) {
|
|||||||
} else if *s.cfg.Always {
|
} else if *s.cfg.Always {
|
||||||
useProxy = true
|
useProxy = true
|
||||||
} else {
|
} else {
|
||||||
k := s.Resolve(address)
|
var isInMap bool
|
||||||
s.checker.Add(address, k)
|
useProxy, isInMap, _, _ = s.checker.IsBlocked(address)
|
||||||
//var n, m uint
|
if !isInMap {
|
||||||
useProxy, _, _ = s.checker.IsBlocked(k)
|
s.checker.Add(address, s.Resolve(address))
|
||||||
|
}
|
||||||
//s.log.Printf("blocked ? : %v, %s , fail:%d ,success:%d", useProxy, address, n, m)
|
//s.log.Printf("blocked ? : %v, %s , fail:%d ,success:%d", useProxy, address, n, m)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -344,7 +345,6 @@ func (s *HTTP) OutToTCP(useProxy bool, address string, inConn *net.Conn, req *ut
|
|||||||
Password: *s.cfg.ParentKey,
|
Password: *s.cfg.ParentKey,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
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") {
|
||||||
@ -353,8 +353,8 @@ func (s *HTTP) OutToTCP(useProxy bool, address string, inConn *net.Conn, req *ut
|
|||||||
} else {
|
} else {
|
||||||
//https或者http,上级是代理,proxy需要转发
|
//https或者http,上级是代理,proxy需要转发
|
||||||
outConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
outConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||||
//直连目标或上级非代理,清理HTTP头部的代理头信息
|
//直连目标或上级非代理或非SNI,清理HTTP头部的代理头信息.
|
||||||
if !useProxy || *s.cfg.ParentType == "ssh" {
|
if (!useProxy || *s.cfg.ParentType == "ssh") && !req.IsSNI {
|
||||||
_, err = outConn.Write(utils.RemoveProxyHeaders(req.HeadBuf))
|
_, err = outConn.Write(utils.RemoveProxyHeaders(req.HeadBuf))
|
||||||
} else {
|
} else {
|
||||||
_, err = outConn.Write(req.HeadBuf)
|
_, err = outConn.Write(req.HeadBuf)
|
||||||
@ -524,6 +524,7 @@ func (s *HTTP) Resolve(address string) string {
|
|||||||
ip, err := s.domainResolver.Resolve(address)
|
ip, err := s.domainResolver.Resolve(address)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.log.Printf("dns error %s , ERR:%s", address, err)
|
s.log.Printf("dns error %s , ERR:%s", address, err)
|
||||||
|
return address
|
||||||
}
|
}
|
||||||
return ip
|
return ip
|
||||||
}
|
}
|
||||||
|
|||||||
@ -88,7 +88,7 @@ func (s *MuxBridge) StopService() {
|
|||||||
(*(*s.sc).Listener).Close()
|
(*(*s.sc).Listener).Close()
|
||||||
}
|
}
|
||||||
for _, g := range s.clientControlConns.Items() {
|
for _, g := range s.clientControlConns.Items() {
|
||||||
for _, session := range g.(utils.ConcurrentMap).Items() {
|
for _, session := range g.(*utils.ConcurrentMap).Items() {
|
||||||
(session.(*smux.Session)).Close()
|
(session.(*smux.Session)).Close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,6 +3,7 @@ package socks
|
|||||||
import (
|
import (
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
logger "log"
|
logger "log"
|
||||||
"net"
|
"net"
|
||||||
@ -13,7 +14,6 @@ import (
|
|||||||
"github.com/snail007/goproxy/services"
|
"github.com/snail007/goproxy/services"
|
||||||
"github.com/snail007/goproxy/services/kcpcfg"
|
"github.com/snail007/goproxy/services/kcpcfg"
|
||||||
"github.com/snail007/goproxy/utils"
|
"github.com/snail007/goproxy/utils"
|
||||||
"github.com/snail007/goproxy/utils/aes"
|
|
||||||
"github.com/snail007/goproxy/utils/conncrypt"
|
"github.com/snail007/goproxy/utils/conncrypt"
|
||||||
"github.com/snail007/goproxy/utils/socks"
|
"github.com/snail007/goproxy/utils/socks"
|
||||||
"golang.org/x/crypto/ssh"
|
"golang.org/x/crypto/ssh"
|
||||||
@ -48,8 +48,6 @@ type SocksArgs struct {
|
|||||||
AuthURLTimeout *int
|
AuthURLTimeout *int
|
||||||
AuthURLRetry *int
|
AuthURLRetry *int
|
||||||
KCP kcpcfg.KCPConfigArgs
|
KCP kcpcfg.KCPConfigArgs
|
||||||
UDPParent *string
|
|
||||||
UDPLocal *string
|
|
||||||
LocalIPS *[]string
|
LocalIPS *[]string
|
||||||
DNSAddress *string
|
DNSAddress *string
|
||||||
DNSTTL *int
|
DNSTTL *int
|
||||||
@ -59,27 +57,31 @@ type SocksArgs struct {
|
|||||||
ParentCompress *bool
|
ParentCompress *bool
|
||||||
}
|
}
|
||||||
type Socks struct {
|
type Socks struct {
|
||||||
cfg SocksArgs
|
cfg SocksArgs
|
||||||
checker utils.Checker
|
checker utils.Checker
|
||||||
basicAuth utils.BasicAuth
|
basicAuth utils.BasicAuth
|
||||||
sshClient *ssh.Client
|
sshClient *ssh.Client
|
||||||
lockChn chan bool
|
lockChn chan bool
|
||||||
udpSC utils.ServerChannel
|
udpSC utils.ServerChannel
|
||||||
sc *utils.ServerChannel
|
sc *utils.ServerChannel
|
||||||
domainResolver utils.DomainResolver
|
domainResolver utils.DomainResolver
|
||||||
isStop bool
|
isStop bool
|
||||||
userConns utils.ConcurrentMap
|
userConns utils.ConcurrentMap
|
||||||
log *logger.Logger
|
log *logger.Logger
|
||||||
|
udpRelatedPacketConns utils.ConcurrentMap
|
||||||
|
udpLocalKey []byte
|
||||||
|
udpParentKey []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSocks() services.Service {
|
func NewSocks() services.Service {
|
||||||
return &Socks{
|
return &Socks{
|
||||||
cfg: SocksArgs{},
|
cfg: SocksArgs{},
|
||||||
checker: utils.Checker{},
|
checker: utils.Checker{},
|
||||||
basicAuth: utils.BasicAuth{},
|
basicAuth: utils.BasicAuth{},
|
||||||
lockChn: make(chan bool, 1),
|
lockChn: make(chan bool, 1),
|
||||||
isStop: false,
|
isStop: false,
|
||||||
userConns: utils.NewConcurrentMap(),
|
userConns: utils.NewConcurrentMap(),
|
||||||
|
udpRelatedPacketConns: utils.NewConcurrentMap(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,17 +105,6 @@ func (s *Socks) CheckArgs() (err error) {
|
|||||||
err = fmt.Errorf("parent type unkown,use -T <tls|tcp|ssh|kcp>")
|
err = fmt.Errorf("parent type unkown,use -T <tls|tcp|ssh|kcp>")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
host, _, e := net.SplitHostPort(*s.cfg.Parent)
|
|
||||||
if e != nil {
|
|
||||||
err = fmt.Errorf("parent format error : %s", e)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if *s.cfg.UDPParent == "" {
|
|
||||||
*s.cfg.UDPParent = net.JoinHostPort(host, "33090")
|
|
||||||
}
|
|
||||||
if strings.HasPrefix(*s.cfg.UDPParent, ":") {
|
|
||||||
*s.cfg.UDPParent = net.JoinHostPort(host, strings.TrimLeft(*s.cfg.UDPParent, ":"))
|
|
||||||
}
|
|
||||||
if *s.cfg.ParentType == "ssh" {
|
if *s.cfg.ParentType == "ssh" {
|
||||||
if *s.cfg.SSHUser == "" {
|
if *s.cfg.SSHUser == "" {
|
||||||
err = fmt.Errorf("ssh user required")
|
err = fmt.Errorf("ssh user required")
|
||||||
@ -145,6 +136,9 @@ func (s *Socks) CheckArgs() (err error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
s.udpLocalKey = s.LocalUDPKey()
|
||||||
|
s.udpParentKey = s.ParentUDPKey()
|
||||||
|
//s.log.Printf("udpLocalKey : %v , udpParentKey : %v", s.udpLocalKey, s.udpParentKey)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
func (s *Socks) InitService() (err error) {
|
func (s *Socks) InitService() (err error) {
|
||||||
@ -186,14 +180,6 @@ func (s *Socks) InitService() (err error) {
|
|||||||
}
|
}
|
||||||
if *s.cfg.ParentType == "ssh" {
|
if *s.cfg.ParentType == "ssh" {
|
||||||
s.log.Printf("warn: socks udp not suppored for ssh")
|
s.log.Printf("warn: socks udp not suppored for ssh")
|
||||||
} else {
|
|
||||||
s.udpSC = utils.NewServerChannelHost(*s.cfg.UDPLocal, s.log)
|
|
||||||
e := s.udpSC.ListenUDP(s.udpCallback)
|
|
||||||
if e != nil {
|
|
||||||
err = fmt.Errorf("init udp service fail, ERR: %s", e)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
s.log.Printf("udp socks proxy on %s", s.udpSC.UDPListener.LocalAddr())
|
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -220,6 +206,9 @@ func (s *Socks) StopService() {
|
|||||||
for _, c := range s.userConns.Items() {
|
for _, c := range s.userConns.Items() {
|
||||||
(*c.(*net.Conn)).Close()
|
(*c.(*net.Conn)).Close()
|
||||||
}
|
}
|
||||||
|
for _, c := range s.udpRelatedPacketConns.Items() {
|
||||||
|
(*c.(*net.UDPConn)).Close()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
func (s *Socks) Start(args interface{}, log *logger.Logger) (err error) {
|
func (s *Socks) Start(args interface{}, log *logger.Logger) (err error) {
|
||||||
s.log = log
|
s.log = log
|
||||||
@ -234,9 +223,6 @@ func (s *Socks) Start(args interface{}, log *logger.Logger) (err error) {
|
|||||||
if *s.cfg.Parent != "" {
|
if *s.cfg.Parent != "" {
|
||||||
s.log.Printf("use %s parent %s", *s.cfg.ParentType, *s.cfg.Parent)
|
s.log.Printf("use %s parent %s", *s.cfg.ParentType, *s.cfg.Parent)
|
||||||
}
|
}
|
||||||
if *s.cfg.UDPParent != "" {
|
|
||||||
s.log.Printf("use socks udp parent %s", *s.cfg.UDPParent)
|
|
||||||
}
|
|
||||||
sc := utils.NewServerChannelHost(*s.cfg.Local, s.log)
|
sc := utils.NewServerChannelHost(*s.cfg.Local, s.log)
|
||||||
if *s.cfg.LocalType == "tcp" {
|
if *s.cfg.LocalType == "tcp" {
|
||||||
err = sc.ListenTCP(s.socksConnCallback)
|
err = sc.ListenTCP(s.socksConnCallback)
|
||||||
@ -255,165 +241,7 @@ func (s *Socks) Start(args interface{}, log *logger.Logger) (err error) {
|
|||||||
func (s *Socks) Clean() {
|
func (s *Socks) Clean() {
|
||||||
s.StopService()
|
s.StopService()
|
||||||
}
|
}
|
||||||
func (s *Socks) UDPKey() []byte {
|
|
||||||
return s.cfg.KeyBytes[:32]
|
|
||||||
}
|
|
||||||
func (s *Socks) udpCallback(b []byte, localAddr, srcAddr *net.UDPAddr) {
|
|
||||||
rawB := b
|
|
||||||
var err error
|
|
||||||
if *s.cfg.LocalType == "tls" {
|
|
||||||
//decode b
|
|
||||||
rawB, err = goaes.Decrypt(s.UDPKey(), b)
|
|
||||||
if err != nil {
|
|
||||||
s.log.Printf("decrypt udp packet fail from %s", srcAddr.String())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
p, err := socks.ParseUDPPacket(rawB)
|
|
||||||
s.log.Printf("udp revecived:%v", len(p.Data()))
|
|
||||||
if err != nil {
|
|
||||||
s.log.Printf("parse udp packet fail, ERR:%s", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
//防止死循环
|
|
||||||
if s.IsDeadLoop((*localAddr).String(), p.Host()) {
|
|
||||||
s.log.Printf("dead loop detected , %s", p.Host())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
//s.log.Printf("##########udp to -> %s:%s###########", p.Host(), p.Port())
|
|
||||||
if *s.cfg.Parent != "" {
|
|
||||||
//有上级代理,转发给上级
|
|
||||||
if *s.cfg.ParentType == "tls" {
|
|
||||||
//encode b
|
|
||||||
rawB, err = goaes.Encrypt(s.UDPKey(), rawB)
|
|
||||||
if err != nil {
|
|
||||||
s.log.Printf("encrypt udp data fail to %s", *s.cfg.Parent)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
parent := *s.cfg.UDPParent
|
|
||||||
if parent == "" {
|
|
||||||
parent = *s.cfg.Parent
|
|
||||||
}
|
|
||||||
dstAddr, err := net.ResolveUDPAddr("udp", s.Resolve(parent))
|
|
||||||
if err != nil {
|
|
||||||
s.log.Printf("can't resolve address: %s", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
clientSrcAddr := &net.UDPAddr{IP: net.IPv4zero, Port: 0}
|
|
||||||
conn, err := net.DialUDP("udp", clientSrcAddr, dstAddr)
|
|
||||||
if err != nil {
|
|
||||||
s.log.Printf("connect to udp %s fail,ERR:%s", dstAddr.String(), err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout*5)))
|
|
||||||
_, err = conn.Write(rawB)
|
|
||||||
conn.SetDeadline(time.Time{})
|
|
||||||
s.log.Printf("udp request:%v", len(rawB))
|
|
||||||
if err != nil {
|
|
||||||
s.log.Printf("send udp packet to %s fail,ERR:%s", dstAddr.String(), err)
|
|
||||||
conn.Close()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
//s.log.Printf("send udp packet to %s success", dstAddr.String())
|
|
||||||
buf := make([]byte, 10*1024)
|
|
||||||
conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
|
||||||
length, _, err := conn.ReadFromUDP(buf)
|
|
||||||
conn.SetDeadline(time.Time{})
|
|
||||||
if err != nil {
|
|
||||||
s.log.Printf("read udp response from %s fail ,ERR:%s", dstAddr.String(), err)
|
|
||||||
conn.Close()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
respBody := buf[0:length]
|
|
||||||
s.log.Printf("udp response:%v", len(respBody))
|
|
||||||
//s.log.Printf("revecived udp packet from %s", dstAddr.String())
|
|
||||||
if *s.cfg.ParentType == "tls" {
|
|
||||||
//decode b
|
|
||||||
respBody, err = goaes.Decrypt(s.UDPKey(), respBody)
|
|
||||||
if err != nil {
|
|
||||||
s.log.Printf("encrypt udp data fail to %s", *s.cfg.Parent)
|
|
||||||
conn.Close()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if *s.cfg.LocalType == "tls" {
|
|
||||||
d, err := goaes.Encrypt(s.UDPKey(), respBody)
|
|
||||||
if err != nil {
|
|
||||||
s.log.Printf("encrypt udp data fail from %s", dstAddr.String())
|
|
||||||
conn.Close()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
s.udpSC.UDPListener.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
|
||||||
s.udpSC.UDPListener.WriteToUDP(d, srcAddr)
|
|
||||||
s.udpSC.UDPListener.SetDeadline(time.Time{})
|
|
||||||
s.log.Printf("udp reply:%v", len(d))
|
|
||||||
d = nil
|
|
||||||
} else {
|
|
||||||
s.udpSC.UDPListener.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
|
||||||
s.udpSC.UDPListener.WriteToUDP(respBody, srcAddr)
|
|
||||||
s.udpSC.UDPListener.SetDeadline(time.Time{})
|
|
||||||
s.log.Printf("udp reply:%v", len(respBody))
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
//本地代理
|
|
||||||
dstAddr, err := net.ResolveUDPAddr("udp", net.JoinHostPort(s.Resolve(p.Host()), p.Port()))
|
|
||||||
if err != nil {
|
|
||||||
s.log.Printf("can't resolve address: %s", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
clientSrcAddr := &net.UDPAddr{IP: net.IPv4zero, Port: 0}
|
|
||||||
conn, err := net.DialUDP("udp", clientSrcAddr, dstAddr)
|
|
||||||
if err != nil {
|
|
||||||
s.log.Printf("connect to udp %s fail,ERR:%s", dstAddr.String(), err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout*3)))
|
|
||||||
_, err = conn.Write(p.Data())
|
|
||||||
conn.SetDeadline(time.Time{})
|
|
||||||
s.log.Printf("udp send:%v", len(p.Data()))
|
|
||||||
if err != nil {
|
|
||||||
s.log.Printf("send udp packet to %s fail,ERR:%s", dstAddr.String(), err)
|
|
||||||
conn.Close()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
//s.log.Printf("send udp packet to %s success", dstAddr.String())
|
|
||||||
buf := make([]byte, 10*1024)
|
|
||||||
conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
|
||||||
length, _, err := conn.ReadFromUDP(buf)
|
|
||||||
conn.SetDeadline(time.Time{})
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
s.log.Printf("read udp response from %s fail ,ERR:%s", dstAddr.String(), err)
|
|
||||||
conn.Close()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
respBody := buf[0:length]
|
|
||||||
//封装来自真实服务器的数据,返回给访问者
|
|
||||||
respPacket := p.NewReply(respBody)
|
|
||||||
//s.log.Printf("revecived udp packet from %s", dstAddr.String())
|
|
||||||
if *s.cfg.LocalType == "tls" {
|
|
||||||
d, err := goaes.Encrypt(s.UDPKey(), respPacket)
|
|
||||||
if err != nil {
|
|
||||||
s.log.Printf("encrypt udp data fail from %s", dstAddr.String())
|
|
||||||
conn.Close()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
s.udpSC.UDPListener.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
|
||||||
s.udpSC.UDPListener.WriteToUDP(d, srcAddr)
|
|
||||||
s.udpSC.UDPListener.SetDeadline(time.Time{})
|
|
||||||
d = nil
|
|
||||||
} else {
|
|
||||||
s.udpSC.UDPListener.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
|
||||||
s.udpSC.UDPListener.WriteToUDP(respPacket, srcAddr)
|
|
||||||
s.udpSC.UDPListener.SetDeadline(time.Time{})
|
|
||||||
}
|
|
||||||
s.log.Printf("udp reply:%v", len(respPacket))
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
func (s *Socks) socksConnCallback(inConn net.Conn) {
|
func (s *Socks) socksConnCallback(inConn net.Conn) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := recover(); err != nil {
|
if err := recover(); err != nil {
|
||||||
@ -438,7 +266,9 @@ func (s *Socks) socksConnCallback(inConn net.Conn) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
methodReq.Reply(socks.Method_NONE_ACCEPTABLE)
|
methodReq.Reply(socks.Method_NONE_ACCEPTABLE)
|
||||||
utils.CloseConn(&inConn)
|
utils.CloseConn(&inConn)
|
||||||
s.log.Printf("new methods request fail,ERR: %s", err)
|
if err != io.EOF {
|
||||||
|
s.log.Printf("new methods request fail,ERR: %s", err)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -526,16 +356,7 @@ func (s *Socks) socksConnCallback(inConn net.Conn) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
func (s *Socks) proxyUDP(inConn *net.Conn, methodReq socks.MethodsRequest, request socks.Request) {
|
|
||||||
if *s.cfg.ParentType == "ssh" {
|
|
||||||
utils.CloseConn(inConn)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
host, _, _ := net.SplitHostPort((*inConn).LocalAddr().String())
|
|
||||||
_, port, _ := net.SplitHostPort(s.udpSC.UDPListener.LocalAddr().String())
|
|
||||||
s.log.Printf("proxy udp on %s", net.JoinHostPort(host, port))
|
|
||||||
request.UDPReply(socks.REP_SUCCESS, net.JoinHostPort(host, port))
|
|
||||||
}
|
|
||||||
func (s *Socks) proxyTCP(inConn *net.Conn, methodReq socks.MethodsRequest, request socks.Request) {
|
func (s *Socks) proxyTCP(inConn *net.Conn, methodReq socks.MethodsRequest, request socks.Request) {
|
||||||
var outConn net.Conn
|
var outConn net.Conn
|
||||||
var err interface{}
|
var err interface{}
|
||||||
@ -554,7 +375,7 @@ func (s *Socks) proxyTCP(inConn *net.Conn, methodReq socks.MethodsRequest, reque
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if *s.cfg.Always {
|
if *s.cfg.Always {
|
||||||
outConn, err = s.getOutConn(methodReq.Bytes(), request.Bytes(), request.Addr())
|
outConn, err = s.getOutConn(methodReq.Bytes(), request.Bytes(), request.Addr(), true)
|
||||||
} else {
|
} else {
|
||||||
if *s.cfg.Parent != "" {
|
if *s.cfg.Parent != "" {
|
||||||
host, _, _ := net.SplitHostPort(request.Addr())
|
host, _, _ := net.SplitHostPort(request.Addr())
|
||||||
@ -562,12 +383,14 @@ func (s *Socks) proxyTCP(inConn *net.Conn, methodReq socks.MethodsRequest, reque
|
|||||||
if utils.IsIternalIP(host, *s.cfg.Always) {
|
if utils.IsIternalIP(host, *s.cfg.Always) {
|
||||||
useProxy = false
|
useProxy = false
|
||||||
} else {
|
} else {
|
||||||
k := s.Resolve(request.Addr())
|
var isInMap bool
|
||||||
s.checker.Add(request.Addr(), k)
|
useProxy, isInMap, _, _ = s.checker.IsBlocked(request.Addr())
|
||||||
useProxy, _, _ = s.checker.IsBlocked(k)
|
if !isInMap {
|
||||||
|
s.checker.Add(request.Addr(), s.Resolve(request.Addr()))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if useProxy {
|
if useProxy {
|
||||||
outConn, err = s.getOutConn(methodReq.Bytes(), request.Bytes(), request.Addr())
|
outConn, err = s.getOutConn(methodReq.Bytes(), request.Bytes(), request.Addr(), true)
|
||||||
} else {
|
} else {
|
||||||
outConn, err = utils.ConnectHost(s.Resolve(request.Addr()), *s.cfg.Timeout)
|
outConn, err = utils.ConnectHost(s.Resolve(request.Addr()), *s.cfg.Timeout)
|
||||||
}
|
}
|
||||||
@ -607,7 +430,7 @@ func (s *Socks) proxyTCP(inConn *net.Conn, methodReq socks.MethodsRequest, reque
|
|||||||
}
|
}
|
||||||
s.userConns.Set(inAddr, inConn)
|
s.userConns.Set(inAddr, inConn)
|
||||||
}
|
}
|
||||||
func (s *Socks) getOutConn(methodBytes, reqBytes []byte, host string) (outConn net.Conn, err interface{}) {
|
func (s *Socks) getOutConn(methodBytes, reqBytes []byte, host string, handshake bool) (outConn net.Conn, err interface{}) {
|
||||||
switch *s.cfg.ParentType {
|
switch *s.cfg.ParentType {
|
||||||
case "kcp":
|
case "kcp":
|
||||||
fallthrough
|
fallthrough
|
||||||
@ -635,6 +458,9 @@ func (s *Socks) getOutConn(methodBytes, reqBytes []byte, host string) (outConn n
|
|||||||
Password: *s.cfg.ParentKey,
|
Password: *s.cfg.ParentKey,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
if !handshake {
|
||||||
|
return
|
||||||
|
}
|
||||||
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)))
|
outConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||||
@ -804,6 +630,7 @@ func (s *Socks) Resolve(address string) string {
|
|||||||
ip, err := s.domainResolver.Resolve(address)
|
ip, err := s.domainResolver.Resolve(address)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.log.Printf("dns error %s , ERR:%s", address, err)
|
s.log.Printf("dns error %s , ERR:%s", address, err)
|
||||||
|
return address
|
||||||
}
|
}
|
||||||
return ip
|
return ip
|
||||||
}
|
}
|
||||||
|
|||||||
321
services/socks/udp.go
Normal file
321
services/socks/udp.go
Normal file
@ -0,0 +1,321 @@
|
|||||||
|
package socks
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/md5"
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"runtime/debug"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/snail007/goproxy/utils"
|
||||||
|
goaes "github.com/snail007/goproxy/utils/aes"
|
||||||
|
"github.com/snail007/goproxy/utils/socks"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s *Socks) ParentUDPKey() (key []byte) {
|
||||||
|
switch *s.cfg.ParentType {
|
||||||
|
case "tcp":
|
||||||
|
if *s.cfg.ParentKey != "" {
|
||||||
|
v := fmt.Sprintf("%x", md5.Sum([]byte(*s.cfg.ParentKey)))
|
||||||
|
return []byte(v)[:24]
|
||||||
|
}
|
||||||
|
case "tls":
|
||||||
|
return s.cfg.KeyBytes[:24]
|
||||||
|
case "kcp":
|
||||||
|
v := fmt.Sprintf("%x", md5.Sum([]byte(*s.cfg.KCP.Key)))
|
||||||
|
return []byte(v)[:24]
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
func (s *Socks) LocalUDPKey() (key []byte) {
|
||||||
|
switch *s.cfg.LocalType {
|
||||||
|
case "tcp":
|
||||||
|
if *s.cfg.LocalKey != "" {
|
||||||
|
v := fmt.Sprintf("%x", md5.Sum([]byte(*s.cfg.LocalKey)))
|
||||||
|
return []byte(v)[:24]
|
||||||
|
}
|
||||||
|
case "tls":
|
||||||
|
return s.cfg.KeyBytes[:24]
|
||||||
|
case "kcp":
|
||||||
|
v := fmt.Sprintf("%x", md5.Sum([]byte(*s.cfg.KCP.Key)))
|
||||||
|
return []byte(v)[:24]
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
func (s *Socks) proxyUDP(inConn *net.Conn, methodReq socks.MethodsRequest, request socks.Request) {
|
||||||
|
defer func() {
|
||||||
|
if e := recover(); e != nil {
|
||||||
|
s.log.Printf("udp local->out io copy crashed:\n%s\n%s", e, string(debug.Stack()))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
if *s.cfg.ParentType == "ssh" {
|
||||||
|
utils.CloseConn(inConn)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
srcIP, _, _ := net.SplitHostPort((*inConn).RemoteAddr().String())
|
||||||
|
inconnRemoteAddr := (*inConn).RemoteAddr().String()
|
||||||
|
localAddr := &net.UDPAddr{IP: net.IPv4zero, Port: 0}
|
||||||
|
udpListener, err := net.ListenUDP("udp", localAddr)
|
||||||
|
if err != nil {
|
||||||
|
(*inConn).Close()
|
||||||
|
udpListener.Close()
|
||||||
|
s.log.Printf("udp bind fail , %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
host, _, _ := net.SplitHostPort((*inConn).LocalAddr().String())
|
||||||
|
_, port, _ := net.SplitHostPort(udpListener.LocalAddr().String())
|
||||||
|
if len(*s.cfg.LocalIPS) > 0 {
|
||||||
|
host = (*s.cfg.LocalIPS)[0]
|
||||||
|
}
|
||||||
|
s.log.Printf("proxy udp on %s , for %s", net.JoinHostPort(host, port), inconnRemoteAddr)
|
||||||
|
request.UDPReply(socks.REP_SUCCESS, net.JoinHostPort(host, port))
|
||||||
|
s.userConns.Set(inconnRemoteAddr, inConn)
|
||||||
|
var (
|
||||||
|
outUDPConn *net.UDPConn
|
||||||
|
outconn net.Conn
|
||||||
|
outconnLocalAddr string
|
||||||
|
isClosedErr = func(err error) bool {
|
||||||
|
return err != nil && strings.Contains(err.Error(), "use of closed network connection")
|
||||||
|
}
|
||||||
|
destAddr *net.UDPAddr
|
||||||
|
)
|
||||||
|
var clean = func(msg, err string) {
|
||||||
|
raddr := ""
|
||||||
|
if outUDPConn != nil {
|
||||||
|
raddr = outUDPConn.RemoteAddr().String()
|
||||||
|
outUDPConn.Close()
|
||||||
|
}
|
||||||
|
if msg != "" {
|
||||||
|
if raddr != "" {
|
||||||
|
s.log.Printf("%s , %s , %s -> %s", msg, err, inconnRemoteAddr, raddr)
|
||||||
|
} else {
|
||||||
|
s.log.Printf("%s , %s , from : %s", msg, err, inconnRemoteAddr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(*inConn).Close()
|
||||||
|
udpListener.Close()
|
||||||
|
s.userConns.Remove(inconnRemoteAddr)
|
||||||
|
if outconn != nil {
|
||||||
|
outconn.Close()
|
||||||
|
}
|
||||||
|
if outconnLocalAddr != "" {
|
||||||
|
s.userConns.Remove(outconnLocalAddr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
defer clean("", "")
|
||||||
|
go func() {
|
||||||
|
defer func() {
|
||||||
|
if e := recover(); e != nil {
|
||||||
|
s.log.Printf("udp related client tcp conn read crashed:\n%s\n%s", e, string(debug.Stack()))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
buf := make([]byte, 1)
|
||||||
|
(*inConn).SetReadDeadline(time.Time{})
|
||||||
|
if _, err := (*inConn).Read(buf); err != nil {
|
||||||
|
clean("udp related tcp conn disconnected with read", err.Error())
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
go func() {
|
||||||
|
defer func() {
|
||||||
|
if e := recover(); e != nil {
|
||||||
|
s.log.Printf("udp related client tcp conn write crashed:\n%s\n%s", e, string(debug.Stack()))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
for {
|
||||||
|
(*inConn).SetWriteDeadline(time.Now().Add(time.Second * 5))
|
||||||
|
if _, err := (*inConn).Write([]byte{0x00}); err != nil {
|
||||||
|
clean("udp related tcp conn disconnected with write", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
(*inConn).SetWriteDeadline(time.Time{})
|
||||||
|
time.Sleep(time.Second * 5)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
useProxy := true
|
||||||
|
if *s.cfg.Parent != "" {
|
||||||
|
dstHost, _, _ := net.SplitHostPort(request.Addr())
|
||||||
|
if utils.IsIternalIP(dstHost, *s.cfg.Always) {
|
||||||
|
useProxy = false
|
||||||
|
} else {
|
||||||
|
var isInMap bool
|
||||||
|
useProxy, isInMap, _, _ = s.checker.IsBlocked(request.Addr())
|
||||||
|
if !isInMap {
|
||||||
|
s.checker.Add(request.Addr(), s.Resolve(request.Addr()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
useProxy = false
|
||||||
|
}
|
||||||
|
if useProxy {
|
||||||
|
//parent proxy
|
||||||
|
outconn, err := s.getOutConn(nil, nil, "", false)
|
||||||
|
if err != nil {
|
||||||
|
clean("connnect fail", fmt.Sprintf("%s", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
client := socks.NewClientConn(&outconn, "udp", request.Addr(), time.Millisecond*time.Duration(*s.cfg.Timeout), nil, nil)
|
||||||
|
if err = client.Handshake(); err != nil {
|
||||||
|
clean("handshake fail", fmt.Sprintf("%s", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
//outconnRemoteAddr := outconn.RemoteAddr().String()
|
||||||
|
outconnLocalAddr = outconn.LocalAddr().String()
|
||||||
|
s.userConns.Set(outconnLocalAddr, &outconn)
|
||||||
|
go func() {
|
||||||
|
defer func() {
|
||||||
|
if e := recover(); e != nil {
|
||||||
|
s.log.Printf("udp related parent tcp conn read crashed:\n%s\n%s", e, string(debug.Stack()))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
buf := make([]byte, 1)
|
||||||
|
outconn.SetReadDeadline(time.Time{})
|
||||||
|
if _, err := outconn.Read(buf); err != nil {
|
||||||
|
clean("udp parent tcp conn disconnected", fmt.Sprintf("%s", err))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
//forward to parent udp
|
||||||
|
//s.log.Printf("parent udp address %s", client.UDPAddr)
|
||||||
|
destAddr, _ = net.ResolveUDPAddr("udp", client.UDPAddr)
|
||||||
|
}
|
||||||
|
s.log.Printf("use proxy %v : udp %s", useProxy, request.Addr())
|
||||||
|
//relay
|
||||||
|
for {
|
||||||
|
buf := utils.LeakyBuffer.Get()
|
||||||
|
defer utils.LeakyBuffer.Put(buf)
|
||||||
|
n, srcAddr, err := udpListener.ReadFromUDP(buf)
|
||||||
|
if err != nil {
|
||||||
|
s.log.Printf("udp listener read fail, %s", err.Error())
|
||||||
|
if isClosedErr(err) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
srcIP0, _, _ := net.SplitHostPort(srcAddr.String())
|
||||||
|
//IP not match drop it
|
||||||
|
if srcIP != srcIP0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
p := socks.NewPacketUDP()
|
||||||
|
//convert data to raw
|
||||||
|
if len(s.udpLocalKey) > 0 {
|
||||||
|
var v []byte
|
||||||
|
v, err = goaes.Decrypt(s.udpLocalKey, buf[:n])
|
||||||
|
if err == nil {
|
||||||
|
err = p.Parse(v)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
err = p.Parse(buf[:n])
|
||||||
|
}
|
||||||
|
//err = p.Parse(buf[:n])
|
||||||
|
if err != nil {
|
||||||
|
s.log.Printf("udp listener parse packet fail, %s", err.Error())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
port, _ := strconv.Atoi(p.Port())
|
||||||
|
|
||||||
|
if v, ok := s.udpRelatedPacketConns.Get(srcAddr.String()); !ok {
|
||||||
|
if destAddr == nil {
|
||||||
|
destAddr = &net.UDPAddr{IP: net.ParseIP(p.Host()), Port: port}
|
||||||
|
}
|
||||||
|
outUDPConn, err = net.DialUDP("udp", localAddr, destAddr)
|
||||||
|
if err != nil {
|
||||||
|
s.log.Printf("create out udp conn fail , %s , from : %s", err, srcAddr)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
s.udpRelatedPacketConns.Set(srcAddr.String(), outUDPConn)
|
||||||
|
go func() {
|
||||||
|
defer func() {
|
||||||
|
if e := recover(); e != nil {
|
||||||
|
s.log.Printf("udp out->local io copy crashed:\n%s\n%s", e, string(debug.Stack()))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
defer s.udpRelatedPacketConns.Remove(srcAddr.String())
|
||||||
|
//out->local io copy
|
||||||
|
buf := utils.LeakyBuffer.Get()
|
||||||
|
defer utils.LeakyBuffer.Put(buf)
|
||||||
|
for {
|
||||||
|
n, err := outUDPConn.Read(buf)
|
||||||
|
if err != nil {
|
||||||
|
s.log.Printf("read out udp data fail , %s , from : %s", err, srcAddr)
|
||||||
|
if isClosedErr(err) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
//var dlen = n
|
||||||
|
if useProxy {
|
||||||
|
//forward to local
|
||||||
|
var v []byte
|
||||||
|
//convert parent data to raw
|
||||||
|
if len(s.udpParentKey) > 0 {
|
||||||
|
v, err = goaes.Decrypt(s.udpParentKey, buf[:n])
|
||||||
|
if err != nil {
|
||||||
|
s.log.Printf("udp outconn parse packet fail, %s", err.Error())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
v = buf[:n]
|
||||||
|
}
|
||||||
|
//now v is raw, try convert v to local
|
||||||
|
if len(s.udpLocalKey) > 0 {
|
||||||
|
v, _ = goaes.Encrypt(s.udpLocalKey, v)
|
||||||
|
}
|
||||||
|
_, err = udpListener.WriteTo(v, srcAddr)
|
||||||
|
// _, err = udpListener.WriteTo(buf[:n], srcAddr)
|
||||||
|
} else {
|
||||||
|
rp := socks.NewPacketUDP()
|
||||||
|
rp.Build(destAddr.String(), buf[:n])
|
||||||
|
v := rp.Bytes()
|
||||||
|
//dlen = len(v)
|
||||||
|
//rp.Bytes() v is raw, try convert to local
|
||||||
|
if len(s.udpLocalKey) > 0 {
|
||||||
|
v, _ = goaes.Encrypt(s.udpLocalKey, v)
|
||||||
|
}
|
||||||
|
_, err = udpListener.WriteTo(v, srcAddr)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
s.udpRelatedPacketConns.Remove(srcAddr.String())
|
||||||
|
s.log.Printf("write out data to local fail , %s , from : %s", err, srcAddr)
|
||||||
|
if isClosedErr(err) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
//s.log.Printf("send udp data to local success , len %d, for : %s", dlen, srcAddr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
} else {
|
||||||
|
outUDPConn = v.(*net.UDPConn)
|
||||||
|
}
|
||||||
|
//local->out io copy
|
||||||
|
if useProxy {
|
||||||
|
//forward to parent
|
||||||
|
//p is raw, now convert it to parent
|
||||||
|
var v []byte
|
||||||
|
if len(s.udpParentKey) > 0 {
|
||||||
|
v, _ = goaes.Encrypt(s.udpParentKey, p.Bytes())
|
||||||
|
} else {
|
||||||
|
v = p.Bytes()
|
||||||
|
}
|
||||||
|
_, err = outUDPConn.Write(v)
|
||||||
|
// _, err = outUDPConn.Write(p.Bytes())
|
||||||
|
} else {
|
||||||
|
_, err = outUDPConn.Write(p.Data())
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
if isClosedErr(err) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
s.log.Printf("send out udp data fail , %s , from : %s", err, srcAddr)
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
//s.log.Printf("send udp data to remote success , len %d, for : %s", len(p.Data()), srcAddr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
306
services/sps/socksudp.go
Normal file
306
services/sps/socksudp.go
Normal file
@ -0,0 +1,306 @@
|
|||||||
|
package sps
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/md5"
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"runtime/debug"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/snail007/goproxy/utils"
|
||||||
|
goaes "github.com/snail007/goproxy/utils/aes"
|
||||||
|
"github.com/snail007/goproxy/utils/conncrypt"
|
||||||
|
"github.com/snail007/goproxy/utils/socks"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s *SPS) ParentUDPKey() (key []byte) {
|
||||||
|
switch *s.cfg.ParentType {
|
||||||
|
case "tcp":
|
||||||
|
if *s.cfg.ParentKey != "" {
|
||||||
|
v := fmt.Sprintf("%x", md5.Sum([]byte(*s.cfg.ParentKey)))
|
||||||
|
return []byte(v)[:24]
|
||||||
|
}
|
||||||
|
case "tls":
|
||||||
|
return s.cfg.KeyBytes[:24]
|
||||||
|
case "kcp":
|
||||||
|
v := fmt.Sprintf("%x", md5.Sum([]byte(*s.cfg.KCP.Key)))
|
||||||
|
return []byte(v)[:24]
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
func (s *SPS) LocalUDPKey() (key []byte) {
|
||||||
|
switch *s.cfg.LocalType {
|
||||||
|
case "tcp":
|
||||||
|
if *s.cfg.LocalKey != "" {
|
||||||
|
v := fmt.Sprintf("%x", md5.Sum([]byte(*s.cfg.LocalKey)))
|
||||||
|
return []byte(v)[:24]
|
||||||
|
}
|
||||||
|
case "tls":
|
||||||
|
return s.cfg.KeyBytes[:24]
|
||||||
|
case "kcp":
|
||||||
|
v := fmt.Sprintf("%x", md5.Sum([]byte(*s.cfg.KCP.Key)))
|
||||||
|
return []byte(v)[:24]
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
func (s *SPS) proxyUDP(inConn *net.Conn, serverConn *socks.ServerConn) {
|
||||||
|
defer func() {
|
||||||
|
if e := recover(); e != nil {
|
||||||
|
s.log.Printf("udp local->out io copy crashed:\n%s\n%s", e, string(debug.Stack()))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
if *s.cfg.ParentType == "ssh" {
|
||||||
|
utils.CloseConn(inConn)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
srcIP, _, _ := net.SplitHostPort((*inConn).RemoteAddr().String())
|
||||||
|
inconnRemoteAddr := (*inConn).RemoteAddr().String()
|
||||||
|
localAddr := &net.UDPAddr{IP: net.IPv4zero, Port: 0}
|
||||||
|
udpListener := serverConn.UDPConnListener
|
||||||
|
s.log.Printf("proxy udp on %s , for %s", udpListener.LocalAddr(), inconnRemoteAddr)
|
||||||
|
s.userConns.Set(inconnRemoteAddr, inConn)
|
||||||
|
var (
|
||||||
|
outUDPConn *net.UDPConn
|
||||||
|
outconn net.Conn
|
||||||
|
outconnLocalAddr string
|
||||||
|
isClosedErr = func(err error) bool {
|
||||||
|
return err != nil && strings.Contains(err.Error(), "use of closed network connection")
|
||||||
|
}
|
||||||
|
destAddr *net.UDPAddr
|
||||||
|
)
|
||||||
|
var clean = func(msg, err string) {
|
||||||
|
raddr := ""
|
||||||
|
if outUDPConn != nil {
|
||||||
|
raddr = outUDPConn.RemoteAddr().String()
|
||||||
|
outUDPConn.Close()
|
||||||
|
}
|
||||||
|
if msg != "" {
|
||||||
|
if raddr != "" {
|
||||||
|
s.log.Printf("%s , %s , %s -> %s", msg, err, inconnRemoteAddr, raddr)
|
||||||
|
} else {
|
||||||
|
s.log.Printf("%s , %s , from : %s", msg, err, inconnRemoteAddr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(*inConn).Close()
|
||||||
|
udpListener.Close()
|
||||||
|
s.userConns.Remove(inconnRemoteAddr)
|
||||||
|
if outconn != nil {
|
||||||
|
outconn.Close()
|
||||||
|
}
|
||||||
|
if outconnLocalAddr != "" {
|
||||||
|
s.userConns.Remove(outconnLocalAddr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
defer clean("", "")
|
||||||
|
go func() {
|
||||||
|
defer func() {
|
||||||
|
if e := recover(); e != nil {
|
||||||
|
s.log.Printf("udp related client tcp conn read crashed:\n%s\n%s", e, string(debug.Stack()))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
buf := make([]byte, 1)
|
||||||
|
(*inConn).SetReadDeadline(time.Time{})
|
||||||
|
if _, err := (*inConn).Read(buf); err != nil {
|
||||||
|
clean("udp related tcp conn disconnected with read", err.Error())
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
go func() {
|
||||||
|
defer func() {
|
||||||
|
if e := recover(); e != nil {
|
||||||
|
s.log.Printf("udp related client tcp conn write crashed:\n%s\n%s", e, string(debug.Stack()))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
for {
|
||||||
|
(*inConn).SetWriteDeadline(time.Now().Add(time.Second * 5))
|
||||||
|
if _, err := (*inConn).Write([]byte{0x00}); err != nil {
|
||||||
|
clean("udp related tcp conn disconnected with write", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
(*inConn).SetWriteDeadline(time.Time{})
|
||||||
|
time.Sleep(time.Second * 5)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
//parent proxy
|
||||||
|
outconn, err := s.outPool.Get()
|
||||||
|
//outconn, err := s.GetParentConn(nil, nil, "", false)
|
||||||
|
if err != nil {
|
||||||
|
clean("connnect fail", fmt.Sprintf("%s", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if *s.cfg.ParentCompress {
|
||||||
|
outconn = utils.NewCompConn(outconn)
|
||||||
|
}
|
||||||
|
if *s.cfg.ParentKey != "" {
|
||||||
|
outconn = conncrypt.New(outconn, &conncrypt.Config{
|
||||||
|
Password: *s.cfg.ParentKey,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
s.log.Printf("connect %s for udp", serverConn.Target())
|
||||||
|
//socks client
|
||||||
|
var client *socks.ClientConn
|
||||||
|
auth := serverConn.AuthData()
|
||||||
|
if *s.cfg.ParentAuth != "" {
|
||||||
|
a := strings.Split(*s.cfg.ParentAuth, ":")
|
||||||
|
if len(a) != 2 {
|
||||||
|
err = fmt.Errorf("parent auth data format error")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
client = socks.NewClientConn(&outconn, "udp", serverConn.Target(), time.Millisecond*time.Duration(*s.cfg.Timeout), &socks.Auth{User: a[0], Password: a[1]}, nil)
|
||||||
|
} else {
|
||||||
|
if !s.IsBasicAuth() && auth.Password != "" && auth.User != "" {
|
||||||
|
client = socks.NewClientConn(&outconn, "udp", serverConn.Target(), time.Millisecond*time.Duration(*s.cfg.Timeout), &auth, nil)
|
||||||
|
} else {
|
||||||
|
client = socks.NewClientConn(&outconn, "udp", serverConn.Target(), time.Millisecond*time.Duration(*s.cfg.Timeout), nil, nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = client.Handshake(); err != nil {
|
||||||
|
clean("handshake fail", fmt.Sprintf("%s", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//outconnRemoteAddr := outconn.RemoteAddr().String()
|
||||||
|
outconnLocalAddr = outconn.LocalAddr().String()
|
||||||
|
s.userConns.Set(outconnLocalAddr, &outconn)
|
||||||
|
go func() {
|
||||||
|
defer func() {
|
||||||
|
if e := recover(); e != nil {
|
||||||
|
s.log.Printf("udp related parent tcp conn read crashed:\n%s\n%s", e, string(debug.Stack()))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
buf := make([]byte, 1)
|
||||||
|
outconn.SetReadDeadline(time.Time{})
|
||||||
|
if _, err := outconn.Read(buf); err != nil {
|
||||||
|
clean("udp parent tcp conn disconnected", fmt.Sprintf("%s", err))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
//forward to parent udp
|
||||||
|
//s.log.Printf("parent udp address %s", client.UDPAddr)
|
||||||
|
destAddr, _ = net.ResolveUDPAddr("udp", client.UDPAddr)
|
||||||
|
//relay
|
||||||
|
buf := utils.LeakyBuffer.Get()
|
||||||
|
defer utils.LeakyBuffer.Put(buf)
|
||||||
|
for {
|
||||||
|
n, srcAddr, err := udpListener.ReadFromUDP(buf)
|
||||||
|
if err != nil {
|
||||||
|
s.log.Printf("udp listener read fail, %s", err.Error())
|
||||||
|
if isClosedErr(err) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
srcIP0, _, _ := net.SplitHostPort(srcAddr.String())
|
||||||
|
//IP not match drop it
|
||||||
|
if srcIP != srcIP0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
p := socks.NewPacketUDP()
|
||||||
|
//convert data to raw
|
||||||
|
if len(s.udpLocalKey) > 0 {
|
||||||
|
var v []byte
|
||||||
|
v, err = goaes.Decrypt(s.udpLocalKey, buf[:n])
|
||||||
|
if err == nil {
|
||||||
|
err = p.Parse(v)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
err = p.Parse(buf[:n])
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
s.log.Printf("udp listener parse packet fail, %s", err.Error())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
port, _ := strconv.Atoi(p.Port())
|
||||||
|
|
||||||
|
if v, ok := s.udpRelatedPacketConns.Get(srcAddr.String()); !ok {
|
||||||
|
if destAddr == nil {
|
||||||
|
destAddr = &net.UDPAddr{IP: net.ParseIP(p.Host()), Port: port}
|
||||||
|
}
|
||||||
|
outUDPConn, err = net.DialUDP("udp", localAddr, destAddr)
|
||||||
|
if err != nil {
|
||||||
|
s.log.Printf("create out udp conn fail , %s , from : %s", err, srcAddr)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
s.udpRelatedPacketConns.Set(srcAddr.String(), outUDPConn)
|
||||||
|
go func() {
|
||||||
|
defer func() {
|
||||||
|
if e := recover(); e != nil {
|
||||||
|
s.log.Printf("udp out->local io copy crashed:\n%s\n%s", e, string(debug.Stack()))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
defer s.udpRelatedPacketConns.Remove(srcAddr.String())
|
||||||
|
//out->local io copy
|
||||||
|
buf := utils.LeakyBuffer.Get()
|
||||||
|
defer utils.LeakyBuffer.Put(buf)
|
||||||
|
for {
|
||||||
|
outUDPConn.SetReadDeadline(time.Now().Add(time.Second * 5))
|
||||||
|
n, err := outUDPConn.Read(buf)
|
||||||
|
outUDPConn.SetReadDeadline(time.Time{})
|
||||||
|
if err != nil {
|
||||||
|
s.log.Printf("read out udp data fail , %s , from : %s", err, srcAddr)
|
||||||
|
if isClosedErr(err) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
//var dlen = n
|
||||||
|
//forward to local
|
||||||
|
var v []byte
|
||||||
|
//convert parent data to raw
|
||||||
|
if len(s.udpParentKey) > 0 {
|
||||||
|
v, err = goaes.Decrypt(s.udpParentKey, buf[:n])
|
||||||
|
if err != nil {
|
||||||
|
s.log.Printf("udp outconn parse packet fail, %s", err.Error())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
v = buf[:n]
|
||||||
|
}
|
||||||
|
//now v is raw, try convert v to local
|
||||||
|
if len(s.udpLocalKey) > 0 {
|
||||||
|
v, _ = goaes.Encrypt(s.udpLocalKey, v)
|
||||||
|
}
|
||||||
|
_, err = udpListener.WriteTo(v, srcAddr)
|
||||||
|
// _, err = udpListener.WriteTo(buf[:n], srcAddr)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
s.udpRelatedPacketConns.Remove(srcAddr.String())
|
||||||
|
s.log.Printf("write out data to local fail , %s , from : %s", err, srcAddr)
|
||||||
|
if isClosedErr(err) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
//s.log.Printf("send udp data to local success , len %d, for : %s", dlen, srcAddr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
} else {
|
||||||
|
outUDPConn = v.(*net.UDPConn)
|
||||||
|
}
|
||||||
|
//local->out io copy
|
||||||
|
//forward to parent
|
||||||
|
//p is raw, now convert it to parent
|
||||||
|
var v []byte
|
||||||
|
if len(s.udpParentKey) > 0 {
|
||||||
|
v, _ = goaes.Encrypt(s.udpParentKey, p.Bytes())
|
||||||
|
} else {
|
||||||
|
v = p.Bytes()
|
||||||
|
}
|
||||||
|
_, err = outUDPConn.Write(v)
|
||||||
|
// _, err = outUDPConn.Write(p.Bytes())
|
||||||
|
if err != nil {
|
||||||
|
if isClosedErr(err) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
s.log.Printf("send out udp data fail , %s , from : %s", err, srcAddr)
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
//s.log.Printf("send udp data to remote success , len %d, for : %s", len(p.Data()), srcAddr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -17,6 +17,7 @@ import (
|
|||||||
"github.com/snail007/goproxy/services/kcpcfg"
|
"github.com/snail007/goproxy/services/kcpcfg"
|
||||||
"github.com/snail007/goproxy/utils"
|
"github.com/snail007/goproxy/utils"
|
||||||
"github.com/snail007/goproxy/utils/conncrypt"
|
"github.com/snail007/goproxy/utils/conncrypt"
|
||||||
|
"github.com/snail007/goproxy/utils/sni"
|
||||||
"github.com/snail007/goproxy/utils/socks"
|
"github.com/snail007/goproxy/utils/socks"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -52,22 +53,26 @@ type SPSArgs struct {
|
|||||||
DisableSocks5 *bool
|
DisableSocks5 *bool
|
||||||
}
|
}
|
||||||
type SPS struct {
|
type SPS struct {
|
||||||
outPool utils.OutConn
|
outPool utils.OutConn
|
||||||
cfg SPSArgs
|
cfg SPSArgs
|
||||||
domainResolver utils.DomainResolver
|
domainResolver utils.DomainResolver
|
||||||
basicAuth utils.BasicAuth
|
basicAuth utils.BasicAuth
|
||||||
serverChannels []*utils.ServerChannel
|
serverChannels []*utils.ServerChannel
|
||||||
userConns utils.ConcurrentMap
|
userConns utils.ConcurrentMap
|
||||||
log *logger.Logger
|
log *logger.Logger
|
||||||
|
udpRelatedPacketConns utils.ConcurrentMap
|
||||||
|
udpLocalKey []byte
|
||||||
|
udpParentKey []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSPS() services.Service {
|
func NewSPS() services.Service {
|
||||||
return &SPS{
|
return &SPS{
|
||||||
outPool: utils.OutConn{},
|
outPool: utils.OutConn{},
|
||||||
cfg: SPSArgs{},
|
cfg: SPSArgs{},
|
||||||
basicAuth: utils.BasicAuth{},
|
basicAuth: utils.BasicAuth{},
|
||||||
serverChannels: []*utils.ServerChannel{},
|
serverChannels: []*utils.ServerChannel{},
|
||||||
userConns: utils.NewConcurrentMap(),
|
userConns: utils.NewConcurrentMap(),
|
||||||
|
udpRelatedPacketConns: utils.NewConcurrentMap(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func (s *SPS) CheckArgs() (err error) {
|
func (s *SPS) CheckArgs() (err error) {
|
||||||
@ -92,6 +97,8 @@ func (s *SPS) CheckArgs() (err error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
s.udpLocalKey = s.LocalUDPKey()
|
||||||
|
s.udpParentKey = s.ParentUDPKey()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
func (s *SPS) InitService() (err error) {
|
func (s *SPS) InitService() (err error) {
|
||||||
@ -209,6 +216,11 @@ func (s *SPS) callback(inConn net.Conn) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
func (s *SPS) OutToTCP(inConn *net.Conn) (err error) {
|
func (s *SPS) OutToTCP(inConn *net.Conn) (err error) {
|
||||||
|
enableUDP := *s.cfg.ParentServiceType == "socks"
|
||||||
|
udpIP, _, _ := net.SplitHostPort((*inConn).LocalAddr().String())
|
||||||
|
if len(*s.cfg.LocalIPS) > 0 {
|
||||||
|
udpIP = (*s.cfg.LocalIPS)[0]
|
||||||
|
}
|
||||||
bInConn := utils.NewBufferedConn(*inConn)
|
bInConn := utils.NewBufferedConn(*inConn)
|
||||||
//important
|
//important
|
||||||
//action read will regist read event to system,
|
//action read will regist read event to system,
|
||||||
@ -218,7 +230,7 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (err error) {
|
|||||||
bInConn.ReadByte()
|
bInConn.ReadByte()
|
||||||
bInConn.UnreadByte()
|
bInConn.UnreadByte()
|
||||||
|
|
||||||
n := 8
|
n := 2048
|
||||||
if n > bInConn.Buffered() {
|
if n > bInConn.Buffered() {
|
||||||
n = bInConn.Buffered()
|
n = bInConn.Buffered()
|
||||||
}
|
}
|
||||||
@ -228,12 +240,12 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (err error) {
|
|||||||
(*inConn).Close()
|
(*inConn).Close()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
isSNI, _ := sni.ServerNameFromBytes(h)
|
||||||
*inConn = bInConn
|
*inConn = bInConn
|
||||||
address := ""
|
address := ""
|
||||||
var auth socks.Auth
|
var auth socks.Auth
|
||||||
var forwardBytes []byte
|
var forwardBytes []byte
|
||||||
//fmt.Printf("%v", header)
|
//fmt.Printf("%v", h)
|
||||||
if utils.IsSocks5(h) {
|
if utils.IsSocks5(h) {
|
||||||
if *s.cfg.DisableSocks5 {
|
if *s.cfg.DisableSocks5 {
|
||||||
(*inConn).Close()
|
(*inConn).Close()
|
||||||
@ -242,16 +254,20 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (err error) {
|
|||||||
//socks5 server
|
//socks5 server
|
||||||
var serverConn *socks.ServerConn
|
var serverConn *socks.ServerConn
|
||||||
if s.IsBasicAuth() {
|
if s.IsBasicAuth() {
|
||||||
serverConn = socks.NewServerConn(inConn, time.Millisecond*time.Duration(*s.cfg.Timeout), &s.basicAuth, "", nil)
|
serverConn = socks.NewServerConn(inConn, time.Millisecond*time.Duration(*s.cfg.Timeout), &s.basicAuth, enableUDP, udpIP, nil)
|
||||||
} else {
|
} else {
|
||||||
serverConn = socks.NewServerConn(inConn, time.Millisecond*time.Duration(*s.cfg.Timeout), nil, "", nil)
|
serverConn = socks.NewServerConn(inConn, time.Millisecond*time.Duration(*s.cfg.Timeout), nil, enableUDP, udpIP, nil)
|
||||||
}
|
}
|
||||||
if err = serverConn.Handshake(); err != nil {
|
if err = serverConn.Handshake(); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
address = serverConn.Target()
|
address = serverConn.Target()
|
||||||
auth = serverConn.AuthData()
|
auth = serverConn.AuthData()
|
||||||
} else if utils.IsHTTP(h) {
|
if serverConn.IsUDP() {
|
||||||
|
s.proxyUDP(inConn, serverConn)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else if utils.IsHTTP(h) || isSNI != "" {
|
||||||
if *s.cfg.DisableHTTP {
|
if *s.cfg.DisableHTTP {
|
||||||
(*inConn).Close()
|
(*inConn).Close()
|
||||||
return
|
return
|
||||||
@ -495,6 +511,7 @@ func (s *SPS) Resolve(address string) string {
|
|||||||
ip, err := s.domainResolver.Resolve(address)
|
ip, err := s.domainResolver.Resolve(address)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.log.Printf("dns error %s , ERR:%s", address, err)
|
s.log.Printf("dns error %s , ERR:%s", address, err)
|
||||||
|
return address
|
||||||
}
|
}
|
||||||
return ip
|
return ip
|
||||||
}
|
}
|
||||||
|
|||||||
@ -73,7 +73,7 @@ func CreateSignCert(rootCa *x509.Certificate, rootKey *rsa.PrivateKey, domainOrI
|
|||||||
|
|
||||||
buf := x509.MarshalPKCS1PrivateKey(priKey)
|
buf := x509.MarshalPKCS1PrivateKey(priKey)
|
||||||
keyPem := &pem.Block{
|
keyPem := &pem.Block{
|
||||||
Type: "PRIVATE KEY",
|
Type: "RSA PRIVATE KEY",
|
||||||
Bytes: buf,
|
Bytes: buf,
|
||||||
}
|
}
|
||||||
keyBytes = pem.EncodeToMemory(keyPem)
|
keyBytes = pem.EncodeToMemory(keyPem)
|
||||||
|
|||||||
@ -12,8 +12,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
//Confg defaults
|
//Confg defaults
|
||||||
const DefaultIterations = 2048
|
const DefaultIterations = 1024
|
||||||
const DefaultKeySize = 32 //256bits
|
const DefaultKeySize = 24 //256bits
|
||||||
var DefaultHashFunc = sha256.New
|
var DefaultHashFunc = sha256.New
|
||||||
var DefaultSalt = []byte(`
|
var DefaultSalt = []byte(`
|
||||||
(;QUHj.BQ?RXzYSO]ifkXp/G!kFmWyXyEV6Nt!d|@bo+N$L9+<d$|g6e26T}
|
(;QUHj.BQ?RXzYSO]ifkXp/G!kFmWyXyEV6Nt!d|@bo+N$L9+<d$|g6e26T}
|
||||||
|
|||||||
@ -17,7 +17,6 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
|
||||||
|
|
||||||
"github.com/snail007/goproxy/services/kcpcfg"
|
"github.com/snail007/goproxy/services/kcpcfg"
|
||||||
|
|
||||||
@ -209,98 +208,6 @@ func CloseConn(conn *net.Conn) {
|
|||||||
(*conn).Close()
|
(*conn).Close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func Keygen() (err error) {
|
|
||||||
CList := []string{"AD", "AE", "AF", "AG", "AI", "AL", "AM", "AO", "AR", "AT", "AU", "AZ", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BL", "BM", "BN", "BO", "BR", "BS", "BW", "BY", "BZ", "CA", "CF", "CG", "CH", "CK", "CL", "CM", "CN", "CO", "CR", "CS", "CU", "CY", "CZ", "DE", "DJ", "DK", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FR", "GA", "GB", "GD", "GE", "GF", "GH", "GI", "GM", "GN", "GR", "GT", "GU", "GY", "HK", "HN", "HT", "HU", "ID", "IE", "IL", "IN", "IQ", "IR", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KP", "KR", "KT", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "MG", "ML", "MM", "MN", "MO", "MS", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PF", "PG", "PH", "PK", "PL", "PR", "PT", "PY", "QA", "RO", "RU", "SA", "SB", "SC", "SD", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SO", "SR", "ST", "SV", "SY", "SZ", "TD", "TG", "TH", "TJ", "TM", "TN", "TO", "TR", "TT", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "YE", "YU", "ZA", "ZM", "ZR", "ZW"}
|
|
||||||
domainSubfixList := []string{".com", ".edu", ".gov", ".int", ".mil", ".net", ".org", ".biz", ".info", ".pro", ".name", ".museum", ".coop", ".aero", ".xxx", ".idv", ".ac", ".ad", ".ae", ".af", ".ag", ".ai", ".al", ".am", ".an", ".ao", ".aq", ".ar", ".as", ".at", ".au", ".aw", ".az", ".ba", ".bb", ".bd", ".be", ".bf", ".bg", ".bh", ".bi", ".bj", ".bm", ".bn", ".bo", ".br", ".bs", ".bt", ".bv", ".bw", ".by", ".bz", ".ca", ".cc", ".cd", ".cf", ".cg", ".ch", ".ci", ".ck", ".cl", ".cm", ".cn", ".co", ".cr", ".cu", ".cv", ".cx", ".cy", ".cz", ".de", ".dj", ".dk", ".dm", ".do", ".dz", ".ec", ".ee", ".eg", ".eh", ".er", ".es", ".et", ".eu", ".fi", ".fj", ".fk", ".fm", ".fo", ".fr", ".ga", ".gd", ".ge", ".gf", ".gg", ".gh", ".gi", ".gl", ".gm", ".gn", ".gp", ".gq", ".gr", ".gs", ".gt", ".gu", ".gw", ".gy", ".hk", ".hm", ".hn", ".hr", ".ht", ".hu", ".id", ".ie", ".il", ".im", ".in", ".io", ".iq", ".ir", ".is", ".it", ".je", ".jm", ".jo", ".jp", ".ke", ".kg", ".kh", ".ki", ".km", ".kn", ".kp", ".kr", ".kw", ".ky", ".kz", ".la", ".lb", ".lc", ".li", ".lk", ".lr", ".ls", ".lt", ".lu", ".lv", ".ly", ".ma", ".mc", ".md", ".mg", ".mh", ".mk", ".ml", ".mm", ".mn", ".mo", ".mp", ".mq", ".mr", ".ms", ".mt", ".mu", ".mv", ".mw", ".mx", ".my", ".mz", ".na", ".nc", ".ne", ".nf", ".ng", ".ni", ".nl", ".no", ".np", ".nr", ".nu", ".nz", ".om", ".pa", ".pe", ".pf", ".pg", ".ph", ".pk", ".pl", ".pm", ".pn", ".pr", ".ps", ".pt", ".pw", ".py", ".qa", ".re", ".ro", ".ru", ".rw", ".sa", ".sb", ".sc", ".sd", ".se", ".sg", ".sh", ".si", ".sj", ".sk", ".sl", ".sm", ".sn", ".so", ".sr", ".st", ".sv", ".sy", ".sz", ".tc", ".td", ".tf", ".tg", ".th", ".tj", ".tk", ".tl", ".tm", ".tn", ".to", ".tp", ".tr", ".tt", ".tv", ".tw", ".tz", ".ua", ".ug", ".uk", ".um", ".us", ".uy", ".uz", ".va", ".vc", ".ve", ".vg", ".vi", ".vn", ".vu", ".wf", ".ws", ".ye", ".yt", ".yu", ".yr", ".za", ".zm", ".zw"}
|
|
||||||
C := CList[int(RandInt(4))%len(CList)]
|
|
||||||
ST := RandString(int(RandInt(4) % 10))
|
|
||||||
O := RandString(int(RandInt(4) % 10))
|
|
||||||
CN := strings.ToLower(RandString(int(RandInt(4)%10)) + domainSubfixList[int(RandInt(4))%len(domainSubfixList)])
|
|
||||||
//log.Printf("C: %s, ST: %s, O: %s, CN: %s", C, ST, O, CN)
|
|
||||||
var out []byte
|
|
||||||
if len(os.Args) == 3 && os.Args[2] == "ca" {
|
|
||||||
cmd := exec.Command("sh", "-c", "openssl genrsa -out ca.key 2048")
|
|
||||||
out, err = cmd.CombinedOutput()
|
|
||||||
if err != nil {
|
|
||||||
logger.Printf("err:%s", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
fmt.Println(string(out))
|
|
||||||
|
|
||||||
cmdStr := fmt.Sprintf("openssl req -new -key ca.key -x509 -days 36500 -out ca.crt -subj /C=%s/ST=%s/O=%s/CN=%s", C, ST, O, "*."+CN)
|
|
||||||
cmd = exec.Command("sh", "-c", cmdStr)
|
|
||||||
out, err = cmd.CombinedOutput()
|
|
||||||
if err != nil {
|
|
||||||
logger.Printf("err:%s", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
fmt.Println(string(out))
|
|
||||||
} else if len(os.Args) == 5 && os.Args[2] == "ca" && os.Args[3] != "" && os.Args[4] != "" {
|
|
||||||
certBytes, _ := ioutil.ReadFile("ca.crt")
|
|
||||||
block, _ := pem.Decode(certBytes)
|
|
||||||
if block == nil || certBytes == nil {
|
|
||||||
panic("failed to parse ca certificate PEM")
|
|
||||||
}
|
|
||||||
x509Cert, _ := x509.ParseCertificate(block.Bytes)
|
|
||||||
if x509Cert == nil {
|
|
||||||
panic("failed to parse block")
|
|
||||||
}
|
|
||||||
name := os.Args[3]
|
|
||||||
days := os.Args[4]
|
|
||||||
cmd := exec.Command("sh", "-c", "openssl genrsa -out "+name+".key 2048")
|
|
||||||
out, err = cmd.CombinedOutput()
|
|
||||||
if err != nil {
|
|
||||||
logger.Printf("err:%s", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
fmt.Println(string(out))
|
|
||||||
|
|
||||||
cmdStr := fmt.Sprintf("openssl req -new -key %s.key -out %s.csr -subj /C=%s/ST=%s/O=%s/CN=%s", name, name, C, ST, O, CN)
|
|
||||||
fmt.Printf("%s", cmdStr)
|
|
||||||
cmd = exec.Command("sh", "-c", cmdStr)
|
|
||||||
out, err = cmd.CombinedOutput()
|
|
||||||
if err != nil {
|
|
||||||
logger.Printf("err:%s", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
fmt.Println(string(out))
|
|
||||||
|
|
||||||
cmdStr = fmt.Sprintf("openssl x509 -req -days %s -in %s.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out %s.crt", days, name, name)
|
|
||||||
fmt.Printf("%s", cmdStr)
|
|
||||||
cmd = exec.Command("sh", "-c", cmdStr)
|
|
||||||
out, err = cmd.CombinedOutput()
|
|
||||||
if err != nil {
|
|
||||||
logger.Printf("err:%s", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Println(string(out))
|
|
||||||
} else if len(os.Args) == 3 && os.Args[2] == "usage" {
|
|
||||||
fmt.Println(`proxy keygen //generate proxy.crt and proxy.key
|
|
||||||
proxy keygen ca //generate ca.crt and ca.key
|
|
||||||
proxy keygen ca client0 30 //generate client0.crt client0.key and use ca.crt sign it with 30 days
|
|
||||||
`)
|
|
||||||
} else if len(os.Args) == 2 {
|
|
||||||
cmd := exec.Command("sh", "-c", "openssl genrsa -out proxy.key 2048")
|
|
||||||
out, err = cmd.CombinedOutput()
|
|
||||||
if err != nil {
|
|
||||||
logger.Printf("err:%s", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
fmt.Println(string(out))
|
|
||||||
|
|
||||||
cmdStr := fmt.Sprintf("openssl req -new -key proxy.key -x509 -days 36500 -out proxy.crt -subj /C=%s/ST=%s/O=%s/CN=%s", C, ST, O, CN)
|
|
||||||
cmd = exec.Command("sh", "-c", cmdStr)
|
|
||||||
out, err = cmd.CombinedOutput()
|
|
||||||
if err != nil {
|
|
||||||
logger.Printf("err:%s", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
fmt.Println(string(out))
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
func GetAllInterfaceAddr() ([]net.IP, error) {
|
func GetAllInterfaceAddr() ([]net.IP, error) {
|
||||||
|
|
||||||
ifaces, err := net.Interfaces()
|
ifaces, err := net.Interfaces()
|
||||||
|
|||||||
@ -33,7 +33,7 @@ type ClientConn struct {
|
|||||||
timeout time.Duration
|
timeout time.Duration
|
||||||
addr string
|
addr string
|
||||||
network string
|
network string
|
||||||
udpAddr string
|
UDPAddr string
|
||||||
}
|
}
|
||||||
|
|
||||||
// SOCKS5 returns a Dialer that makes SOCKSv5 connections to the given address
|
// SOCKS5 returns a Dialer that makes SOCKSv5 connections to the given address
|
||||||
@ -168,14 +168,14 @@ func (s *ClientConn) Handshake() error {
|
|||||||
}
|
}
|
||||||
p := binary.BigEndian.Uint16([]byte{buf[0], buf[1]})
|
p := binary.BigEndian.Uint16([]byte{buf[0], buf[1]})
|
||||||
//log.Printf("%v", p)
|
//log.Printf("%v", p)
|
||||||
s.udpAddr = net.JoinHostPort(ipStr, fmt.Sprintf("%d", p))
|
s.UDPAddr = net.JoinHostPort(ipStr, fmt.Sprintf("%d", p))
|
||||||
//log.Printf("%v", s.udpAddr)
|
//log.Printf("%v", s.udpAddr)
|
||||||
(*s.conn).SetDeadline(time.Time{})
|
(*s.conn).SetDeadline(time.Time{})
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
func (s *ClientConn) SendUDP(data []byte, addr string) (respData []byte, err error) {
|
func (s *ClientConn) SendUDP(data []byte, addr string) (respData []byte, err error) {
|
||||||
|
|
||||||
c, err := net.DialTimeout("udp", s.udpAddr, s.timeout)
|
c, err := net.DialTimeout("udp", s.UDPAddr, s.timeout)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,10 +2,11 @@ package socks
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/snail007/goproxy/utils"
|
|
||||||
"net"
|
"net"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/snail007/goproxy/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -54,26 +55,27 @@ type ServerConn struct {
|
|||||||
methods []uint8
|
methods []uint8
|
||||||
method uint8
|
method uint8
|
||||||
//request
|
//request
|
||||||
cmd uint8
|
cmd uint8
|
||||||
reserve uint8
|
reserve uint8
|
||||||
addressType uint8
|
addressType uint8
|
||||||
dstAddr string
|
dstAddr string
|
||||||
dstPort string
|
dstPort string
|
||||||
dstHost string
|
dstHost string
|
||||||
udpAddress string
|
UDPConnListener *net.UDPConn
|
||||||
|
enableUDP bool
|
||||||
|
udpIP string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewServerConn(conn *net.Conn, timeout time.Duration, auth *utils.BasicAuth, udpAddress string, header []byte) *ServerConn {
|
func NewServerConn(conn *net.Conn, timeout time.Duration, auth *utils.BasicAuth, enableUDP bool, udpHost string, header []byte) *ServerConn {
|
||||||
if udpAddress == "" {
|
|
||||||
udpAddress = "0.0.0.0:16666"
|
|
||||||
}
|
|
||||||
s := &ServerConn{
|
s := &ServerConn{
|
||||||
conn: conn,
|
conn: conn,
|
||||||
timeout: timeout,
|
timeout: timeout,
|
||||||
auth: auth,
|
auth: auth,
|
||||||
header: header,
|
header: header,
|
||||||
ver: VERSION_V5,
|
ver: VERSION_V5,
|
||||||
udpAddress: udpAddress,
|
enableUDP: enableUDP,
|
||||||
|
udpIP: udpHost,
|
||||||
}
|
}
|
||||||
return s
|
return s
|
||||||
|
|
||||||
@ -84,6 +86,12 @@ func (s *ServerConn) Close() {
|
|||||||
func (s *ServerConn) AuthData() Auth {
|
func (s *ServerConn) AuthData() Auth {
|
||||||
return Auth{s.user, s.password}
|
return Auth{s.user, s.password}
|
||||||
}
|
}
|
||||||
|
func (s *ServerConn) IsUDP() bool {
|
||||||
|
return s.cmd == CMD_ASSOCIATE
|
||||||
|
}
|
||||||
|
func (s *ServerConn) IsTCP() bool {
|
||||||
|
return s.cmd == CMD_CONNECT
|
||||||
|
}
|
||||||
func (s *ServerConn) Method() uint8 {
|
func (s *ServerConn) Method() uint8 {
|
||||||
return s.method
|
return s.method
|
||||||
}
|
}
|
||||||
@ -205,11 +213,29 @@ func (s *ServerConn) Handshake() (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
case CMD_ASSOCIATE:
|
case CMD_ASSOCIATE:
|
||||||
err = request.UDPReply(REP_SUCCESS, s.udpAddress)
|
if !s.enableUDP {
|
||||||
|
request.UDPReply(REP_UNKNOWN, "0.0.0.0:0")
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("UDPReply REP_UNKNOWN to %s fail,ERR: %s", remoteAddr, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = fmt.Errorf("cmd associate not supported, form: %s", remoteAddr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
a, _ := net.ResolveUDPAddr("udp", ":0")
|
||||||
|
s.UDPConnListener, err = net.ListenUDP("udp", a)
|
||||||
|
if err != nil {
|
||||||
|
request.UDPReply(REP_UNKNOWN, "0.0.0.0:0")
|
||||||
|
err = fmt.Errorf("udp bind fail,ERR: %s , for %s", err, remoteAddr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, port, _ := net.SplitHostPort(s.UDPConnListener.LocalAddr().String())
|
||||||
|
err = request.UDPReply(REP_SUCCESS, net.JoinHostPort(s.udpIP, port))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = fmt.Errorf("UDPReply REP_SUCCESS to %s fail,ERR: %s", remoteAddr, err)
|
err = fmt.Errorf("UDPReply REP_SUCCESS to %s fail,ERR: %s", remoteAddr, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//fill socks info
|
//fill socks info
|
||||||
|
|||||||
@ -33,15 +33,11 @@ type Checker struct {
|
|||||||
log *logger.Logger
|
log *logger.Logger
|
||||||
}
|
}
|
||||||
type CheckerItem struct {
|
type CheckerItem struct {
|
||||||
IsHTTPS bool
|
|
||||||
Method string
|
|
||||||
URL string
|
|
||||||
Domain string
|
Domain string
|
||||||
Host string
|
Address string
|
||||||
Data []byte
|
|
||||||
SuccessCount uint
|
SuccessCount uint
|
||||||
FailCount uint
|
FailCount uint
|
||||||
Key string
|
Lasttime int64
|
||||||
}
|
}
|
||||||
|
|
||||||
//NewChecker args:
|
//NewChecker args:
|
||||||
@ -101,17 +97,23 @@ func (c *Checker) start() {
|
|||||||
//log.Printf("check %s", item.Host)
|
//log.Printf("check %s", item.Host)
|
||||||
var conn net.Conn
|
var conn net.Conn
|
||||||
var err error
|
var err error
|
||||||
conn, err = ConnectHost(item.Host, c.timeout)
|
var now = time.Now().Unix()
|
||||||
|
conn, err = ConnectHost(item.Address, c.timeout)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
conn.SetDeadline(time.Now().Add(time.Millisecond))
|
conn.SetDeadline(time.Now().Add(time.Millisecond))
|
||||||
conn.Close()
|
conn.Close()
|
||||||
}
|
}
|
||||||
|
if now-item.Lasttime > 1800 {
|
||||||
|
item.FailCount = 0
|
||||||
|
item.SuccessCount = 0
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
item.FailCount = item.FailCount + 1
|
item.FailCount = item.FailCount + 1
|
||||||
} else {
|
} else {
|
||||||
item.SuccessCount = item.SuccessCount + 1
|
item.SuccessCount = item.SuccessCount + 1
|
||||||
}
|
}
|
||||||
c.data.Set(item.Host, item)
|
item.Lasttime = now
|
||||||
|
c.data.Set(item.Domain, item)
|
||||||
}
|
}
|
||||||
}(v.(CheckerItem))
|
}(v.(CheckerItem))
|
||||||
}
|
}
|
||||||
@ -124,32 +126,37 @@ func (c *Checker) start() {
|
|||||||
}
|
}
|
||||||
func (c *Checker) isNeedCheck(item CheckerItem) bool {
|
func (c *Checker) isNeedCheck(item CheckerItem) bool {
|
||||||
var minCount uint = 5
|
var minCount uint = 5
|
||||||
if (item.SuccessCount >= minCount && item.SuccessCount > item.FailCount) ||
|
var now = time.Now().Unix()
|
||||||
(item.FailCount >= minCount && item.SuccessCount > item.FailCount) ||
|
if (item.SuccessCount >= minCount && item.SuccessCount > item.FailCount && now-item.Lasttime < 1800) ||
|
||||||
c.domainIsInMap(item.Host, false) ||
|
(item.FailCount >= minCount && item.SuccessCount > item.FailCount && now-item.Lasttime < 1800) ||
|
||||||
c.domainIsInMap(item.Host, true) {
|
c.domainIsInMap(item.Domain, false) ||
|
||||||
|
c.domainIsInMap(item.Domain, true) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
func (c *Checker) IsBlocked(address string) (blocked bool, failN, successN uint) {
|
func (c *Checker) IsBlocked(domain string) (blocked, isInMap bool, failN, successN uint) {
|
||||||
if c.domainIsInMap(address, true) {
|
h, _, _ := net.SplitHostPort(domain)
|
||||||
//log.Printf("%s in blocked ? true", address)
|
if h != "" {
|
||||||
return true, 0, 0
|
domain = h
|
||||||
}
|
}
|
||||||
if c.domainIsInMap(address, false) {
|
if c.domainIsInMap(domain, true) {
|
||||||
|
//log.Printf("%s in blocked ? true", address)
|
||||||
|
return true, true, 0, 0
|
||||||
|
}
|
||||||
|
if c.domainIsInMap(domain, false) {
|
||||||
//log.Printf("%s in direct ? true", address)
|
//log.Printf("%s in direct ? true", address)
|
||||||
return false, 0, 0
|
return false, true, 0, 0
|
||||||
}
|
}
|
||||||
|
|
||||||
_item, ok := c.data.Get(address)
|
_item, ok := c.data.Get(domain)
|
||||||
if !ok {
|
if !ok {
|
||||||
//log.Printf("%s not in map, blocked true", address)
|
//log.Printf("%s not in map, blocked true", address)
|
||||||
return true, 0, 0
|
return true, false, 0, 0
|
||||||
}
|
}
|
||||||
item := _item.(CheckerItem)
|
item := _item.(CheckerItem)
|
||||||
|
|
||||||
return item.FailCount >= item.SuccessCount, item.FailCount, item.SuccessCount
|
return (item.FailCount >= item.SuccessCount) && (time.Now().Unix()-item.Lasttime < 1800), true, item.FailCount, item.SuccessCount
|
||||||
}
|
}
|
||||||
func (c *Checker) domainIsInMap(address string, blockedMap bool) bool {
|
func (c *Checker) domainIsInMap(address string, blockedMap bool) bool {
|
||||||
u, err := url.Parse("http://" + address)
|
u, err := url.Parse("http://" + address)
|
||||||
@ -174,16 +181,20 @@ func (c *Checker) domainIsInMap(address string, blockedMap bool) bool {
|
|||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
func (c *Checker) Add(key, address string) {
|
func (c *Checker) Add(domain, address string) {
|
||||||
if c.domainIsInMap(key, false) || c.domainIsInMap(key, true) {
|
h, _, _ := net.SplitHostPort(domain)
|
||||||
|
if h != "" {
|
||||||
|
domain = h
|
||||||
|
}
|
||||||
|
if c.domainIsInMap(domain, false) || c.domainIsInMap(domain, true) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var item CheckerItem
|
var item CheckerItem
|
||||||
item = CheckerItem{
|
item = CheckerItem{
|
||||||
Host: address,
|
Domain: domain,
|
||||||
Key: key,
|
Address: address,
|
||||||
}
|
}
|
||||||
c.data.SetIfAbsent(item.Host, item)
|
c.data.SetIfAbsent(item.Domain, item)
|
||||||
}
|
}
|
||||||
|
|
||||||
type BasicAuth struct {
|
type BasicAuth struct {
|
||||||
@ -329,6 +340,7 @@ type HTTPRequest struct {
|
|||||||
isBasicAuth bool
|
isBasicAuth bool
|
||||||
basicAuth *BasicAuth
|
basicAuth *BasicAuth
|
||||||
log *logger.Logger
|
log *logger.Logger
|
||||||
|
IsSNI bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewHTTPRequest(inConn *net.Conn, bufSize int, isBasicAuth bool, basicAuth *BasicAuth, log *logger.Logger, header ...[]byte) (req HTTPRequest, err error) {
|
func NewHTTPRequest(inConn *net.Conn, bufSize int, isBasicAuth bool, basicAuth *BasicAuth, log *logger.Logger, header ...[]byte) (req HTTPRequest, err error) {
|
||||||
@ -360,6 +372,7 @@ func NewHTTPRequest(inConn *net.Conn, bufSize int, isBasicAuth bool, basicAuth *
|
|||||||
//sni success
|
//sni success
|
||||||
req.Method = "SNI"
|
req.Method = "SNI"
|
||||||
req.hostOrURL = "https://" + serverName + ":443"
|
req.hostOrURL = "https://" + serverName + ":443"
|
||||||
|
req.IsSNI = true
|
||||||
} else {
|
} else {
|
||||||
//sni fail , try http
|
//sni fail , try http
|
||||||
index := bytes.IndexByte(req.HeadBuf, '\n')
|
index := bytes.IndexByte(req.HeadBuf, '\n')
|
||||||
|
|||||||
Reference in New Issue
Block a user