66
README_ZH.md
66
README_ZH.md
@ -1,5 +1,5 @@
|
|||||||
<img src="https://github.com/snail007/goproxy/blob/master/docs/images/logo.jpg?raw=true" width="200"/>
|
<img src="https://github.com/snail007/goproxy/blob/master/docs/images/logo.jpg?raw=true" width="200"/>
|
||||||
Proxy是golang实现的高性能http,https,websocket,tcp,udp,socks5代理服务器,支持正向代理、反向代理、透明代理、内网穿透、TCP/UDP端口映射、SSH中转,TLS加密传输。
|
Proxy是golang实现的高性能http,https,websocket,tcp,udp,socks5代理服务器,支持正向代理、反向代理、透明代理、内网穿透、TCP/UDP端口映射、SSH中转,TLS加密传输,协议转换。
|
||||||
|
|
||||||
[点击下载](https://github.com/snail007/goproxy/releases) 官方QQ交流群:189618940
|
[点击下载](https://github.com/snail007/goproxy/releases) 官方QQ交流群:189618940
|
||||||
|
|
||||||
@ -23,6 +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功能。
|
||||||
|
|
||||||
### Why need these?
|
### Why need these?
|
||||||
- 当由于某某原因,我们不能访问我们在其它地方的服务,我们可以通过多个相连的proxy节点建立起一个安全的隧道访问我们的服务.
|
- 当由于某某原因,我们不能访问我们在其它地方的服务,我们可以通过多个相连的proxy节点建立起一个安全的隧道访问我们的服务.
|
||||||
@ -34,7 +35,8 @@ Proxy是golang实现的高性能http,https,websocket,tcp,udp,socks5代理服务
|
|||||||
- ...
|
- ...
|
||||||
|
|
||||||
|
|
||||||
本页是v4.3手册,其他版本手册请点击下面链接查看.
|
本页是v4.4手册,其他版本手册请点击下面链接查看.
|
||||||
|
- [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)
|
||||||
- [v4.0-v4.1手册](https://github.com/snail007/goproxy/tree/v4.1)
|
- [v4.0-v4.1手册](https://github.com/snail007/goproxy/tree/v4.1)
|
||||||
- [v3.9手册](https://github.com/snail007/goproxy/tree/v3.9)
|
- [v3.9手册](https://github.com/snail007/goproxy/tree/v3.9)
|
||||||
@ -117,6 +119,12 @@ Proxy是golang实现的高性能http,https,websocket,tcp,udp,socks5代理服务
|
|||||||
- [5.8 KCP协议传输](#58kcp协议传输)
|
- [5.8 KCP协议传输](#58kcp协议传输)
|
||||||
- [5.9 自定义DNS](#59自定义dns)
|
- [5.9 自定义DNS](#59自定义dns)
|
||||||
- [5.10 查看帮助](#510查看帮助)
|
- [5.10 查看帮助](#510查看帮助)
|
||||||
|
- [6. 代理协议转换](#6代理协议转换)
|
||||||
|
- [6.1 功能介绍](#61-功能介绍)
|
||||||
|
- [6.2 HTTP(S)转HTTP(S)+SOCKS5](#62-https转https+socks5)
|
||||||
|
- [6.3 SOCKS5转HTTP(S)+SOCKS5](#63-socks5转https+socks5)
|
||||||
|
- [6.4 链式连接](#64-链式连接)
|
||||||
|
- [6.5 查看帮助](#65-查看帮助)
|
||||||
|
|
||||||
### Fast Start
|
### Fast Start
|
||||||
提示:所有操作需要root权限.
|
提示:所有操作需要root权限.
|
||||||
@ -667,6 +675,60 @@ KCP协议需要-B参数设置一个密码用于加密解密数据
|
|||||||
#### **5.10.查看帮助**
|
#### **5.10.查看帮助**
|
||||||
`./proxy help socks`
|
`./proxy help socks`
|
||||||
|
|
||||||
|
### **6.代理协议转换**
|
||||||
|
|
||||||
|
#### **6.1 功能介绍**
|
||||||
|
代理协议转换使用的是sps子命令(socks+https的缩写),sps本身不提供代理功能,只是接受代理请求**转换并转发**给已经存在的http(s)代理或者socks5代理;sps可以把已经存在的http(s)代理或者socks5代理转换为一个端口同时支持http(s)和socks5代理,而且http(s)代理主持正向代理和反向代理(SNI);另外对于已经存在的http(s)代理或者socks5代理,支持tls、tcp、kcp三种模式,支持链式连接,也就是可以多个sps结点层级连接构建加密通道。
|
||||||
|
|
||||||
|
#### **6.2 HTTP(S)转HTTP(S)+SOCKS5**
|
||||||
|
假设已经存在一个普通的http(s)代理:127.0.0.1:8080,现在我们把它转为同时支持http(s)和socks5的普通代理,转换后的本地端口为18080。
|
||||||
|
命令如下:
|
||||||
|
`./proxy sps -S http -T tcp -P 127.0.0.1:8080 -t tcp -p :18080`
|
||||||
|
|
||||||
|
假设已经存在一个tls的http(s)代理:127.0.0.1:8080,现在我们把它转为同时支持http(s)和socks5的普通代理,转换后的本地端口为18080,tls需要证书文件。
|
||||||
|
命令如下:
|
||||||
|
`./proxy sps -S http -T tls -P 127.0.0.1:8080 -t tcp -p :18080 -C proxy.crt -K proxy.key`
|
||||||
|
|
||||||
|
假设已经存在一个kcp的http(s)代理(密码是:demo123):127.0.0.1:8080,现在我们把它转为同时支持http(s)和socks5的普通代理,转换后的本地端口为18080。
|
||||||
|
命令如下:
|
||||||
|
`./proxy sps -S http -T kcp -P 127.0.0.1:8080 -t tcp -p :18080 -B demo123`
|
||||||
|
|
||||||
|
#### **6.3 SOCKS5转HTTP(S)+SOCKS5**
|
||||||
|
假设已经存在一个普通的socks5代理:127.0.0.1:8080,现在我们把它转为同时支持http(s)和socks5的普通代理,转换后的本地端口为18080。
|
||||||
|
命令如下:
|
||||||
|
`./proxy sps -S socks -T tcp -P 127.0.0.1:8080 -t tcp -p :18080`
|
||||||
|
|
||||||
|
假设已经存在一个tls的socks5代理:127.0.0.1:8080,现在我们把它转为同时支持http(s)和socks5的普通代理,转换后的本地端口为18080,tls需要证书文件。
|
||||||
|
命令如下:
|
||||||
|
`./proxy sps -S socks -T tls -P 127.0.0.1:8080 -t tcp -p :18080 -C proxy.crt -K proxy.key`
|
||||||
|
|
||||||
|
假设已经存在一个kcp的socks5代理(密码是:demo123):127.0.0.1:8080,现在我们把它转为同时支持http(s)和socks5的普通代理,转换后的本地端口为18080。
|
||||||
|
命令如下:
|
||||||
|
`./proxy sps -S socks -T kcp -P 127.0.0.1:8080 -t tcp -p :18080 -B demo123`
|
||||||
|
|
||||||
|
#### **6.4 链式连接**
|
||||||
|
上面提过多个sps结点可以层级连接构建加密通道,假设有如下vps和家里的pc电脑。
|
||||||
|
vps01:2.2.2.2
|
||||||
|
vps02:3.3.3.3
|
||||||
|
现在我们想利用pc和vps01和vps02构建一个加密通道,本例子用tls加密也可以用kcp,在pc上访问本地18080端口就是访问vps02的本地8080端口。
|
||||||
|
首先在vps01(2.2.2.2)上我们运行一个只有本地可以访问的http(s)代理,执行:
|
||||||
|
`./proxy -t tcp -p 127.0.0.1:8080`
|
||||||
|
|
||||||
|
然后在vps01(2.2.2.2)上运行一个sps结点,执行:
|
||||||
|
`./proxy -S http -T tcp -P 127.0.0.1:8080 -t tls -p :8081 -C proxy.crt -K proxy.key`
|
||||||
|
|
||||||
|
然后在vps02(3.3.3.3)上运行一个sps结点,执行:
|
||||||
|
`./proxy -S http -T tls -P 2.2.2.2:8081 -t tls -p :8082 -C proxy.crt -K proxy.key`
|
||||||
|
|
||||||
|
然后在pc上运行一个sps结点,执行:
|
||||||
|
`./proxy -S http -T tls -P 3.3.3.3:8082 -t tcp -p :18080 -C proxy.crt -K proxy.key`
|
||||||
|
|
||||||
|
完成。
|
||||||
|
|
||||||
|
#### **6.5 查看帮助**
|
||||||
|
`./proxy help sps`
|
||||||
|
|
||||||
|
|
||||||
### TODO
|
### TODO
|
||||||
- http,socks代理多个上级负载均衡?
|
- http,socks代理多个上级负载均衡?
|
||||||
- http(s)代理增加pac支持?
|
- http(s)代理增加pac支持?
|
||||||
|
|||||||
12
config.go
12
config.go
@ -192,11 +192,15 @@ func initConfig() (err error) {
|
|||||||
spsArgs.Parent = sps.Flag("parent", "parent address, such as: \"23.32.32.19:28008\"").Default("").Short('P').String()
|
spsArgs.Parent = sps.Flag("parent", "parent address, such as: \"23.32.32.19:28008\"").Default("").Short('P').String()
|
||||||
spsArgs.CertFile = sps.Flag("cert", "cert file for tls").Short('C').Default("proxy.crt").String()
|
spsArgs.CertFile = sps.Flag("cert", "cert file for tls").Short('C').Default("proxy.crt").String()
|
||||||
spsArgs.KeyFile = sps.Flag("key", "key file for tls").Short('K').Default("proxy.key").String()
|
spsArgs.KeyFile = sps.Flag("key", "key file for tls").Short('K').Default("proxy.key").String()
|
||||||
spsArgs.Timeout = sps.Flag("timeout", "tcp timeout milliseconds when connect to real server or parent proxy").Short('e').Default("2000").Int()
|
spsArgs.Timeout = sps.Flag("timeout", "tcp timeout milliseconds when connect to real server or parent proxy").Short('i').Default("2000").Int()
|
||||||
spsArgs.ParentServiceType = sps.Flag("parent-service-type", "parent service type <http|socks>").Short('S').Enum("http", "socks")
|
spsArgs.ParentType = sps.Flag("parent-type", "parent protocol type <tls|tcp|kcp>").Short('T').Enum("tls", "tcp", "kcp")
|
||||||
spsArgs.ParentType = sps.Flag("parent-type", "parent protocol type <tls|tcp>").Short('T').Enum("tls", "tcp")
|
spsArgs.LocalType = sps.Flag("local-type", "local protocol type <tls|tcp|kcp>").Default("tcp").Short('t').Enum("tls", "tcp", "kcp")
|
||||||
spsArgs.LocalType = sps.Flag("local-type", "local protocol type <tls|tcp>").Default("tcp").Short('t').Enum("tls", "tcp")
|
|
||||||
spsArgs.Local = sps.Flag("local", "local ip:port to listen").Short('p').Default(":33080").String()
|
spsArgs.Local = sps.Flag("local", "local ip:port to listen").Short('p').Default(":33080").String()
|
||||||
|
spsArgs.KCPKey = sps.Flag("kcp-key", "key for kcp encrypt/decrypt data").Short('B').Default("encrypt").String()
|
||||||
|
spsArgs.KCPMethod = sps.Flag("kcp-method", "kcp encrypt/decrypt method").Short('M').Default("3des").String()
|
||||||
|
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.DNSTTL = sps.Flag("dns-ttl", "caching seconds of dns query result").Short('e').Default("300").Int()
|
||||||
|
|
||||||
//parse args
|
//parse args
|
||||||
serviceName := kingpin.MustParse(app.Parse(os.Args[1:]))
|
serviceName := kingpin.MustParse(app.Parse(os.Args[1:]))
|
||||||
|
|||||||
@ -197,7 +197,11 @@ type SPSArgs struct {
|
|||||||
ParentType *string
|
ParentType *string
|
||||||
LocalType *string
|
LocalType *string
|
||||||
Timeout *int
|
Timeout *int
|
||||||
|
KCPMethod *string
|
||||||
|
KCPKey *string
|
||||||
ParentServiceType *string
|
ParentServiceType *string
|
||||||
|
DNSAddress *string
|
||||||
|
DNSTTL *int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *SPSArgs) Protocol() string {
|
func (a *SPSArgs) Protocol() string {
|
||||||
@ -206,6 +210,8 @@ func (a *SPSArgs) Protocol() string {
|
|||||||
return TYPE_TLS
|
return TYPE_TLS
|
||||||
case TYPE_TCP:
|
case TYPE_TCP:
|
||||||
return TYPE_TCP
|
return TYPE_TCP
|
||||||
|
case TYPE_KCP:
|
||||||
|
return TYPE_KCP
|
||||||
}
|
}
|
||||||
return "unknown"
|
return "unknown"
|
||||||
}
|
}
|
||||||
|
|||||||
232
services/sps.go
232
services/sps.go
@ -1,6 +1,8 @@
|
|||||||
package services
|
package services
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
@ -8,11 +10,13 @@ import (
|
|||||||
"snail007/proxy/utils"
|
"snail007/proxy/utils"
|
||||||
"snail007/proxy/utils/socks"
|
"snail007/proxy/utils/socks"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
type SPS struct {
|
type SPS struct {
|
||||||
outPool utils.OutPool
|
outPool utils.OutPool
|
||||||
cfg SPSArgs
|
cfg SPSArgs
|
||||||
|
domainResolver utils.DomainResolver
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSPS() Service {
|
func NewSPS() Service {
|
||||||
@ -26,15 +30,33 @@ func (s *SPS) CheckArgs() {
|
|||||||
log.Fatalf("parent required for %s %s", s.cfg.Protocol(), *s.cfg.Local)
|
log.Fatalf("parent required for %s %s", s.cfg.Protocol(), *s.cfg.Local)
|
||||||
}
|
}
|
||||||
if *s.cfg.ParentType == "" {
|
if *s.cfg.ParentType == "" {
|
||||||
log.Fatalf("parent type unkown,use -T <tls|tcp>")
|
log.Fatalf("parent type unkown,use -T <tls|tcp|kcp>")
|
||||||
}
|
}
|
||||||
if *s.cfg.ParentType == TYPE_TLS || *s.cfg.LocalType == TYPE_TLS {
|
if *s.cfg.ParentType == TYPE_TLS || *s.cfg.LocalType == TYPE_TLS {
|
||||||
s.cfg.CertBytes, s.cfg.KeyBytes = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
|
s.cfg.CertBytes, s.cfg.KeyBytes = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func (s *SPS) InitService() {
|
func (s *SPS) InitService() {
|
||||||
|
s.InitOutConnPool()
|
||||||
}
|
}
|
||||||
|
func (s *SPS) InitOutConnPool() {
|
||||||
|
if *s.cfg.ParentType == TYPE_TLS || *s.cfg.ParentType == TYPE_TCP || *s.cfg.ParentType == TYPE_KCP {
|
||||||
|
//dur int, isTLS bool, certBytes, keyBytes []byte,
|
||||||
|
//parent string, timeout int, InitialCap int, MaxCap int
|
||||||
|
s.outPool = utils.NewOutPool(
|
||||||
|
0,
|
||||||
|
*s.cfg.ParentType,
|
||||||
|
*s.cfg.KCPMethod,
|
||||||
|
*s.cfg.KCPKey,
|
||||||
|
s.cfg.CertBytes, s.cfg.KeyBytes,
|
||||||
|
*s.cfg.Parent,
|
||||||
|
*s.cfg.Timeout,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (s *SPS) StopService() {
|
func (s *SPS) StopService() {
|
||||||
if s.outPool.Pool != nil {
|
if s.outPool.Pool != nil {
|
||||||
s.outPool.Pool.ReleaseAll()
|
s.outPool.Pool.ReleaseAll()
|
||||||
@ -49,11 +71,12 @@ func (s *SPS) Start(args interface{}) (err error) {
|
|||||||
host, port, _ := net.SplitHostPort(*s.cfg.Local)
|
host, port, _ := net.SplitHostPort(*s.cfg.Local)
|
||||||
p, _ := strconv.Atoi(port)
|
p, _ := strconv.Atoi(port)
|
||||||
sc := utils.NewServerChannel(host, p)
|
sc := utils.NewServerChannel(host, p)
|
||||||
|
|
||||||
if *s.cfg.LocalType == TYPE_TCP {
|
if *s.cfg.LocalType == TYPE_TCP {
|
||||||
err = sc.ListenTCP(s.callback)
|
err = sc.ListenTCP(s.callback)
|
||||||
} else if *s.cfg.LocalType == TYPE_TLS {
|
} else if *s.cfg.LocalType == TYPE_TLS {
|
||||||
err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, s.callback)
|
err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, s.callback)
|
||||||
|
} else if *s.cfg.LocalType == TYPE_KCP {
|
||||||
|
err = sc.ListenKCP(*s.cfg.KCPMethod, *s.cfg.KCPKey, s.callback)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
@ -73,6 +96,8 @@ func (s *SPS) callback(inConn net.Conn) {
|
|||||||
}()
|
}()
|
||||||
var err error
|
var err error
|
||||||
switch *s.cfg.ParentType {
|
switch *s.cfg.ParentType {
|
||||||
|
case TYPE_KCP:
|
||||||
|
fallthrough
|
||||||
case TYPE_TCP:
|
case TYPE_TCP:
|
||||||
fallthrough
|
fallthrough
|
||||||
case TYPE_TLS:
|
case TYPE_TLS:
|
||||||
@ -94,17 +119,204 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (err error) {
|
|||||||
utils.CloseConn(inConn)
|
utils.CloseConn(inConn)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fmt.Printf("%v", header[0])
|
address := ""
|
||||||
|
var forwardBytes []byte
|
||||||
|
//fmt.Printf("%v", header)
|
||||||
if header[0] == socks.VERSION_V5 {
|
if header[0] == socks.VERSION_V5 {
|
||||||
req, e := socks.NewMethodsRequest(*inConn, header)
|
//socks
|
||||||
|
methodReq, e := socks.NewMethodsRequest(*inConn, header)
|
||||||
if e != nil {
|
if e != nil {
|
||||||
log.Printf("ERR:%s", e)
|
log.Printf("new method request err:%s", e)
|
||||||
utils.CloseConn(inConn)
|
utils.CloseConn(inConn)
|
||||||
err = e.(error)
|
err = e.(error)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fmt.Printf("address:%v", req.Version())
|
if !methodReq.Select(socks.Method_NO_AUTH) {
|
||||||
|
methodReq.Reply(socks.Method_NONE_ACCEPTABLE)
|
||||||
|
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 {
|
||||||
|
//http
|
||||||
|
var request utils.HTTPRequest
|
||||||
|
request, err = utils.NewHTTPRequest(inConn, 1024, false, nil, header)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("new http request fail,ERR: %s", err)
|
||||||
|
utils.CloseConn(inConn)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(header) >= 7 && strings.ToLower(string(header[:7])) == "connect" {
|
||||||
|
//https
|
||||||
|
request.HTTPSReply()
|
||||||
|
//log.Printf("https reply: %s", request.Host)
|
||||||
|
} else {
|
||||||
|
forwardBytes = request.HeadBuf
|
||||||
|
}
|
||||||
|
address = request.Host
|
||||||
|
} else {
|
||||||
|
log.Printf("unknown request from: %s,%s", (*inConn).RemoteAddr(), string(header))
|
||||||
|
utils.CloseConn(inConn)
|
||||||
|
err = errors.New("unknown request")
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
//connect to parent
|
||||||
|
var outConn net.Conn
|
||||||
|
var _outConn interface{}
|
||||||
|
_outConn, err = s.outPool.Pool.Get()
|
||||||
|
if err == nil {
|
||||||
|
outConn = _outConn.(net.Conn)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("connect to %s , err:%s", *s.cfg.Parent, err)
|
||||||
|
utils.CloseConn(inConn)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
//ask parent for connect to target address
|
||||||
|
if *s.cfg.ParentServiceType == "http" {
|
||||||
|
//http parent
|
||||||
|
fmt.Fprintf(outConn, "CONNECT %s\r\n", address)
|
||||||
|
reply := make([]byte, 100)
|
||||||
|
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("reply: %s", string(reply[:n]))
|
||||||
|
} else {
|
||||||
|
log.Printf("connect %s", address)
|
||||||
|
//socks parent
|
||||||
|
//send auth type
|
||||||
|
_, err = outConn.Write([]byte{0x05, 0x01, 0x00})
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("write method 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("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.
|
||||||
|
if len(forwardBytes) > 0 {
|
||||||
|
outConn.Write(forwardBytes)
|
||||||
|
}
|
||||||
|
//bind
|
||||||
|
inAddr := (*inConn).RemoteAddr().String()
|
||||||
|
outAddr := outConn.RemoteAddr().String()
|
||||||
|
utils.IoBind((*inConn), outConn, func(err interface{}) {
|
||||||
|
log.Printf("conn %s - %s released", inAddr, outAddr)
|
||||||
|
})
|
||||||
|
log.Printf("conn %s - %s connected", inAddr, outAddr)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
func (s *SPS) buildRequest(address string) (buf []byte, err error) {
|
||||||
|
host, portStr, err := net.SplitHostPort(address)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
port, err := strconv.Atoi(portStr)
|
||||||
|
if err != nil {
|
||||||
|
err = errors.New("proxy: failed to parse port number: " + portStr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if port < 1 || port > 0xffff {
|
||||||
|
err = errors.New("proxy: port number out of range: " + portStr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
buf = buf[:0]
|
||||||
|
buf = append(buf, 0x05, 0x01, 0 /* reserved */)
|
||||||
|
|
||||||
|
if ip := net.ParseIP(host); ip != nil {
|
||||||
|
if ip4 := ip.To4(); ip4 != nil {
|
||||||
|
buf = append(buf, 0x01)
|
||||||
|
ip = ip4
|
||||||
|
} else {
|
||||||
|
buf = append(buf, 0x04)
|
||||||
|
}
|
||||||
|
buf = append(buf, ip...)
|
||||||
|
} else {
|
||||||
|
if len(host) > 255 {
|
||||||
|
err = errors.New("proxy: destination host name too long: " + host)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
buf = append(buf, 0x03)
|
||||||
|
buf = append(buf, byte(len(host)))
|
||||||
|
buf = append(buf, host...)
|
||||||
|
}
|
||||||
|
buf = append(buf, byte(port>>8), byte(port))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
func (s *SPS) Resolve(address string) string {
|
||||||
|
if *s.cfg.DNSAddress == "" {
|
||||||
|
return address
|
||||||
|
}
|
||||||
|
ip, err := s.domainResolver.Resolve(address)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("dns error %s , ERR:%s", address, err)
|
||||||
|
}
|
||||||
|
return ip
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user