@ -1,4 +1,9 @@
|
||||
proxy更新日志
|
||||
v5.2
|
||||
1.修复了HTTP(S)\SPS反向代理无法正常工作的问题.
|
||||
2.优化了智能判断,减少不必要的DNS解析.
|
||||
3.重构了SOCKS和SPS的UDP功能,基于UDP的游戏加速嗖嗖的.
|
||||
|
||||
v5.1
|
||||
1.优化了kcp默认mtu配置,调整为450.
|
||||
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)
|
||||
|
||||
[中文手册](/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
|
||||
- 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.
|
||||
- [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)
|
||||
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).
|
||||
|
||||
### 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)
|
||||
@ -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.
|
||||
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
|
||||
Proxy is licensed under GPLv3 license.
|
||||
### 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)
|
||||
|
||||
**[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
|
||||
- 链式代理,程序本身可以作为一级代理,如果设置了上级代理那么可以作为二级代理,乃至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`
|
||||
|
||||
### **5.SOCKS5代理**
|
||||
提示:SOCKS5代理,支持CONNECT,UDP协议,不支持BIND,支持用户名密码认证.
|
||||
提示:
|
||||
|
||||
SOCKS5代理,支持CONNECT,UDP协议,不支持BIND,支持用户名密码认证.
|
||||
|
||||
***如果你的VPS是阿里云,腾讯云这种VPS,就是ifconfig看不见你的公网IP,只能看见内网IP,***
|
||||
|
||||
***那么需要加上`-g VPS公网IP`参数,SOCKS5代理的UDP功能才能正常工作。***
|
||||
|
||||
#### **5.1.普通SOCKS5代理**
|
||||
`./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支持?
|
||||
- 欢迎加群反馈...
|
||||
|
||||
### 如何贡献代码(Pull Request)?
|
||||
首先需要clone本项目到自己的帐号下面,然后在dev分支上面修改代码,
|
||||
最后发Pull Request到goproxy项目的dev分支即可,为了高效贡献代码,
|
||||
pr的时候需要说明做了什么变更,原因是什么.
|
||||
|
||||
### 如何使用源码?
|
||||
建议go1.10.1.
|
||||
`go get github.com/snail007/goproxy`
|
||||
@ -1133,5 +1145,3 @@ QQ交流群:189618940
|
||||
如果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/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.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.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.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()
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
# Old Versions of Proxy
|
||||
|
||||
- [v5.1手册](https://github.com/snail007/goproxy/tree/v5.1)
|
||||
- [v5.0手册](https://github.com/snail007/goproxy/tree/v5.0)
|
||||
- [v4.9手册](https://github.com/snail007/goproxy/tree/v4.9)
|
||||
- [v4.8手册](https://github.com/snail007/goproxy/tree/v4.8)
|
||||
|
||||
@ -5,7 +5,7 @@ if [ -e /tmp/proxy ]; then
|
||||
fi
|
||||
mkdir /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
|
||||
tar zxvf proxy-linux-amd64.tar.gz
|
||||
|
||||
2
main.go
2
main.go
@ -9,7 +9,7 @@ import (
|
||||
"github.com/snail007/goproxy/services"
|
||||
)
|
||||
|
||||
const APP_VERSION = "5.1"
|
||||
const APP_VERSION = "5.2"
|
||||
|
||||
func main() {
|
||||
err := initConfig()
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
#!/bin/bash
|
||||
VER="5.1"
|
||||
VER="5.2"
|
||||
RELEASE="release-${VER}"
|
||||
rm -rf .cert
|
||||
mkdir .cert
|
||||
|
||||
@ -76,7 +76,7 @@ func (s *DNS) InitService() (err error) {
|
||||
nil,
|
||||
&net.Dialer{
|
||||
Timeout: 5 * time.Second,
|
||||
KeepAlive: 5 * time.Second,
|
||||
KeepAlive: 2 * time.Second,
|
||||
},
|
||||
)
|
||||
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.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.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.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()
|
||||
|
||||
@ -277,10 +277,11 @@ func (s *HTTP) callback(inConn net.Conn) {
|
||||
} else if *s.cfg.Always {
|
||||
useProxy = true
|
||||
} else {
|
||||
k := s.Resolve(address)
|
||||
s.checker.Add(address, k)
|
||||
//var n, m uint
|
||||
useProxy, _, _ = s.checker.IsBlocked(k)
|
||||
var isInMap bool
|
||||
useProxy, isInMap, _, _ = s.checker.IsBlocked(address)
|
||||
if !isInMap {
|
||||
s.checker.Add(address, s.Resolve(address))
|
||||
}
|
||||
//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,
|
||||
})
|
||||
}
|
||||
|
||||
outAddr := outConn.RemoteAddr().String()
|
||||
//outLocalAddr := outConn.LocalAddr().String()
|
||||
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 {
|
||||
//https或者http,上级是代理,proxy需要转发
|
||||
outConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
//直连目标或上级非代理,清理HTTP头部的代理头信息
|
||||
if !useProxy || *s.cfg.ParentType == "ssh" {
|
||||
//直连目标或上级非代理或非SNI,清理HTTP头部的代理头信息.
|
||||
if (!useProxy || *s.cfg.ParentType == "ssh") && !req.IsSNI {
|
||||
_, err = outConn.Write(utils.RemoveProxyHeaders(req.HeadBuf))
|
||||
} else {
|
||||
_, err = outConn.Write(req.HeadBuf)
|
||||
@ -524,6 +524,7 @@ func (s *HTTP) Resolve(address string) string {
|
||||
ip, err := s.domainResolver.Resolve(address)
|
||||
if err != nil {
|
||||
s.log.Printf("dns error %s , ERR:%s", address, err)
|
||||
return address
|
||||
}
|
||||
return ip
|
||||
}
|
||||
|
||||
@ -88,7 +88,7 @@ func (s *MuxBridge) StopService() {
|
||||
(*(*s.sc).Listener).Close()
|
||||
}
|
||||
for _, g := range s.clientControlConns.Items() {
|
||||
for _, session := range g.(utils.ConcurrentMap).Items() {
|
||||
for _, session := range g.(*utils.ConcurrentMap).Items() {
|
||||
(session.(*smux.Session)).Close()
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@ package socks
|
||||
import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
logger "log"
|
||||
"net"
|
||||
@ -13,7 +14,6 @@ import (
|
||||
"github.com/snail007/goproxy/services"
|
||||
"github.com/snail007/goproxy/services/kcpcfg"
|
||||
"github.com/snail007/goproxy/utils"
|
||||
"github.com/snail007/goproxy/utils/aes"
|
||||
"github.com/snail007/goproxy/utils/conncrypt"
|
||||
"github.com/snail007/goproxy/utils/socks"
|
||||
"golang.org/x/crypto/ssh"
|
||||
@ -48,8 +48,6 @@ type SocksArgs struct {
|
||||
AuthURLTimeout *int
|
||||
AuthURLRetry *int
|
||||
KCP kcpcfg.KCPConfigArgs
|
||||
UDPParent *string
|
||||
UDPLocal *string
|
||||
LocalIPS *[]string
|
||||
DNSAddress *string
|
||||
DNSTTL *int
|
||||
@ -70,6 +68,9 @@ type Socks struct {
|
||||
isStop bool
|
||||
userConns utils.ConcurrentMap
|
||||
log *logger.Logger
|
||||
udpRelatedPacketConns utils.ConcurrentMap
|
||||
udpLocalKey []byte
|
||||
udpParentKey []byte
|
||||
}
|
||||
|
||||
func NewSocks() services.Service {
|
||||
@ -80,6 +81,7 @@ func NewSocks() services.Service {
|
||||
lockChn: make(chan bool, 1),
|
||||
isStop: false,
|
||||
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>")
|
||||
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.SSHUser == "" {
|
||||
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
|
||||
}
|
||||
func (s *Socks) InitService() (err error) {
|
||||
@ -186,14 +180,6 @@ func (s *Socks) InitService() (err error) {
|
||||
}
|
||||
if *s.cfg.ParentType == "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
|
||||
}
|
||||
@ -220,6 +206,9 @@ func (s *Socks) StopService() {
|
||||
for _, c := range s.userConns.Items() {
|
||||
(*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) {
|
||||
s.log = log
|
||||
@ -234,9 +223,6 @@ func (s *Socks) Start(args interface{}, log *logger.Logger) (err error) {
|
||||
if *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)
|
||||
if *s.cfg.LocalType == "tcp" {
|
||||
err = sc.ListenTCP(s.socksConnCallback)
|
||||
@ -255,165 +241,7 @@ func (s *Socks) Start(args interface{}, log *logger.Logger) (err error) {
|
||||
func (s *Socks) Clean() {
|
||||
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) {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
@ -438,7 +266,9 @@ func (s *Socks) socksConnCallback(inConn net.Conn) {
|
||||
if err != nil {
|
||||
methodReq.Reply(socks.Method_NONE_ACCEPTABLE)
|
||||
utils.CloseConn(&inConn)
|
||||
if err != io.EOF {
|
||||
s.log.Printf("new methods request fail,ERR: %s", err)
|
||||
}
|
||||
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) {
|
||||
var outConn net.Conn
|
||||
var err interface{}
|
||||
@ -554,7 +375,7 @@ func (s *Socks) proxyTCP(inConn *net.Conn, methodReq socks.MethodsRequest, reque
|
||||
return
|
||||
}
|
||||
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 {
|
||||
if *s.cfg.Parent != "" {
|
||||
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) {
|
||||
useProxy = false
|
||||
} else {
|
||||
k := s.Resolve(request.Addr())
|
||||
s.checker.Add(request.Addr(), k)
|
||||
useProxy, _, _ = s.checker.IsBlocked(k)
|
||||
var isInMap bool
|
||||
useProxy, isInMap, _, _ = s.checker.IsBlocked(request.Addr())
|
||||
if !isInMap {
|
||||
s.checker.Add(request.Addr(), s.Resolve(request.Addr()))
|
||||
}
|
||||
}
|
||||
if useProxy {
|
||||
outConn, err = s.getOutConn(methodReq.Bytes(), request.Bytes(), request.Addr())
|
||||
outConn, err = s.getOutConn(methodReq.Bytes(), request.Bytes(), request.Addr(), true)
|
||||
} else {
|
||||
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)
|
||||
}
|
||||
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 {
|
||||
case "kcp":
|
||||
fallthrough
|
||||
@ -635,6 +458,9 @@ func (s *Socks) getOutConn(methodBytes, reqBytes []byte, host string) (outConn n
|
||||
Password: *s.cfg.ParentKey,
|
||||
})
|
||||
}
|
||||
if !handshake {
|
||||
return
|
||||
}
|
||||
var buf = make([]byte, 1024)
|
||||
//var n int
|
||||
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)
|
||||
if err != nil {
|
||||
s.log.Printf("dns error %s , ERR:%s", address, err)
|
||||
return address
|
||||
}
|
||||
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/utils"
|
||||
"github.com/snail007/goproxy/utils/conncrypt"
|
||||
"github.com/snail007/goproxy/utils/sni"
|
||||
"github.com/snail007/goproxy/utils/socks"
|
||||
)
|
||||
|
||||
@ -59,6 +60,9 @@ type SPS struct {
|
||||
serverChannels []*utils.ServerChannel
|
||||
userConns utils.ConcurrentMap
|
||||
log *logger.Logger
|
||||
udpRelatedPacketConns utils.ConcurrentMap
|
||||
udpLocalKey []byte
|
||||
udpParentKey []byte
|
||||
}
|
||||
|
||||
func NewSPS() services.Service {
|
||||
@ -68,6 +72,7 @@ func NewSPS() services.Service {
|
||||
basicAuth: utils.BasicAuth{},
|
||||
serverChannels: []*utils.ServerChannel{},
|
||||
userConns: utils.NewConcurrentMap(),
|
||||
udpRelatedPacketConns: utils.NewConcurrentMap(),
|
||||
}
|
||||
}
|
||||
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
|
||||
}
|
||||
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) {
|
||||
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)
|
||||
//important
|
||||
//action read will regist read event to system,
|
||||
@ -218,7 +230,7 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (err error) {
|
||||
bInConn.ReadByte()
|
||||
bInConn.UnreadByte()
|
||||
|
||||
n := 8
|
||||
n := 2048
|
||||
if n > bInConn.Buffered() {
|
||||
n = bInConn.Buffered()
|
||||
}
|
||||
@ -228,12 +240,12 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (err error) {
|
||||
(*inConn).Close()
|
||||
return
|
||||
}
|
||||
|
||||
isSNI, _ := sni.ServerNameFromBytes(h)
|
||||
*inConn = bInConn
|
||||
address := ""
|
||||
var auth socks.Auth
|
||||
var forwardBytes []byte
|
||||
//fmt.Printf("%v", header)
|
||||
//fmt.Printf("%v", h)
|
||||
if utils.IsSocks5(h) {
|
||||
if *s.cfg.DisableSocks5 {
|
||||
(*inConn).Close()
|
||||
@ -242,16 +254,20 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (err error) {
|
||||
//socks5 server
|
||||
var serverConn *socks.ServerConn
|
||||
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 {
|
||||
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 {
|
||||
return
|
||||
}
|
||||
address = serverConn.Target()
|
||||
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 {
|
||||
(*inConn).Close()
|
||||
return
|
||||
@ -495,6 +511,7 @@ func (s *SPS) Resolve(address string) string {
|
||||
ip, err := s.domainResolver.Resolve(address)
|
||||
if err != nil {
|
||||
s.log.Printf("dns error %s , ERR:%s", address, err)
|
||||
return address
|
||||
}
|
||||
return ip
|
||||
}
|
||||
|
||||
@ -73,7 +73,7 @@ func CreateSignCert(rootCa *x509.Certificate, rootKey *rsa.PrivateKey, domainOrI
|
||||
|
||||
buf := x509.MarshalPKCS1PrivateKey(priKey)
|
||||
keyPem := &pem.Block{
|
||||
Type: "PRIVATE KEY",
|
||||
Type: "RSA PRIVATE KEY",
|
||||
Bytes: buf,
|
||||
}
|
||||
keyBytes = pem.EncodeToMemory(keyPem)
|
||||
|
||||
@ -12,8 +12,8 @@ import (
|
||||
)
|
||||
|
||||
//Confg defaults
|
||||
const DefaultIterations = 2048
|
||||
const DefaultKeySize = 32 //256bits
|
||||
const DefaultIterations = 1024
|
||||
const DefaultKeySize = 24 //256bits
|
||||
var DefaultHashFunc = sha256.New
|
||||
var DefaultSalt = []byte(`
|
||||
(;QUHj.BQ?RXzYSO]ifkXp/G!kFmWyXyEV6Nt!d|@bo+N$L9+<d$|g6e26T}
|
||||
|
||||
@ -17,7 +17,6 @@ import (
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
|
||||
"github.com/snail007/goproxy/services/kcpcfg"
|
||||
|
||||
@ -209,98 +208,6 @@ func CloseConn(conn *net.Conn) {
|
||||
(*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) {
|
||||
|
||||
ifaces, err := net.Interfaces()
|
||||
|
||||
@ -33,7 +33,7 @@ type ClientConn struct {
|
||||
timeout time.Duration
|
||||
addr string
|
||||
network string
|
||||
udpAddr string
|
||||
UDPAddr string
|
||||
}
|
||||
|
||||
// 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]})
|
||||
//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)
|
||||
(*s.conn).SetDeadline(time.Time{})
|
||||
return nil
|
||||
}
|
||||
func (s *ClientConn) SendUDP(data []byte, addr string) (respData []byte, err error) {
|
||||
|
||||
c, err := net.DialTimeout("udp", s.udpAddr, s.timeout)
|
||||
c, err := net.DialTimeout("udp", s.UDPAddr, s.timeout)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@ -2,10 +2,11 @@ package socks
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/snail007/goproxy/utils"
|
||||
"net"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/snail007/goproxy/utils"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -60,20 +61,21 @@ type ServerConn struct {
|
||||
dstAddr string
|
||||
dstPort 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 {
|
||||
if udpAddress == "" {
|
||||
udpAddress = "0.0.0.0:16666"
|
||||
}
|
||||
func NewServerConn(conn *net.Conn, timeout time.Duration, auth *utils.BasicAuth, enableUDP bool, udpHost string, header []byte) *ServerConn {
|
||||
|
||||
s := &ServerConn{
|
||||
conn: conn,
|
||||
timeout: timeout,
|
||||
auth: auth,
|
||||
header: header,
|
||||
ver: VERSION_V5,
|
||||
udpAddress: udpAddress,
|
||||
enableUDP: enableUDP,
|
||||
udpIP: udpHost,
|
||||
}
|
||||
return s
|
||||
|
||||
@ -84,6 +86,12 @@ func (s *ServerConn) Close() {
|
||||
func (s *ServerConn) AuthData() Auth {
|
||||
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 {
|
||||
return s.method
|
||||
}
|
||||
@ -205,11 +213,29 @@ func (s *ServerConn) Handshake() (err error) {
|
||||
return
|
||||
}
|
||||
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 {
|
||||
err = fmt.Errorf("UDPReply REP_SUCCESS to %s fail,ERR: %s", remoteAddr, err)
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//fill socks info
|
||||
|
||||
@ -33,15 +33,11 @@ type Checker struct {
|
||||
log *logger.Logger
|
||||
}
|
||||
type CheckerItem struct {
|
||||
IsHTTPS bool
|
||||
Method string
|
||||
URL string
|
||||
Domain string
|
||||
Host string
|
||||
Data []byte
|
||||
Address string
|
||||
SuccessCount uint
|
||||
FailCount uint
|
||||
Key string
|
||||
Lasttime int64
|
||||
}
|
||||
|
||||
//NewChecker args:
|
||||
@ -101,17 +97,23 @@ func (c *Checker) start() {
|
||||
//log.Printf("check %s", item.Host)
|
||||
var conn net.Conn
|
||||
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 {
|
||||
conn.SetDeadline(time.Now().Add(time.Millisecond))
|
||||
conn.Close()
|
||||
}
|
||||
if now-item.Lasttime > 1800 {
|
||||
item.FailCount = 0
|
||||
item.SuccessCount = 0
|
||||
}
|
||||
if err != nil {
|
||||
item.FailCount = item.FailCount + 1
|
||||
} else {
|
||||
item.SuccessCount = item.SuccessCount + 1
|
||||
}
|
||||
c.data.Set(item.Host, item)
|
||||
item.Lasttime = now
|
||||
c.data.Set(item.Domain, item)
|
||||
}
|
||||
}(v.(CheckerItem))
|
||||
}
|
||||
@ -124,32 +126,37 @@ func (c *Checker) start() {
|
||||
}
|
||||
func (c *Checker) isNeedCheck(item CheckerItem) bool {
|
||||
var minCount uint = 5
|
||||
if (item.SuccessCount >= minCount && item.SuccessCount > item.FailCount) ||
|
||||
(item.FailCount >= minCount && item.SuccessCount > item.FailCount) ||
|
||||
c.domainIsInMap(item.Host, false) ||
|
||||
c.domainIsInMap(item.Host, true) {
|
||||
var now = time.Now().Unix()
|
||||
if (item.SuccessCount >= minCount && item.SuccessCount > item.FailCount && now-item.Lasttime < 1800) ||
|
||||
(item.FailCount >= minCount && item.SuccessCount > item.FailCount && now-item.Lasttime < 1800) ||
|
||||
c.domainIsInMap(item.Domain, false) ||
|
||||
c.domainIsInMap(item.Domain, true) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
func (c *Checker) IsBlocked(address string) (blocked bool, failN, successN uint) {
|
||||
if c.domainIsInMap(address, true) {
|
||||
//log.Printf("%s in blocked ? true", address)
|
||||
return true, 0, 0
|
||||
func (c *Checker) IsBlocked(domain string) (blocked, isInMap bool, failN, successN uint) {
|
||||
h, _, _ := net.SplitHostPort(domain)
|
||||
if h != "" {
|
||||
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)
|
||||
return false, 0, 0
|
||||
return false, true, 0, 0
|
||||
}
|
||||
|
||||
_item, ok := c.data.Get(address)
|
||||
_item, ok := c.data.Get(domain)
|
||||
if !ok {
|
||||
//log.Printf("%s not in map, blocked true", address)
|
||||
return true, 0, 0
|
||||
return true, false, 0, 0
|
||||
}
|
||||
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 {
|
||||
u, err := url.Parse("http://" + address)
|
||||
@ -174,16 +181,20 @@ func (c *Checker) domainIsInMap(address string, blockedMap bool) bool {
|
||||
}
|
||||
return false
|
||||
}
|
||||
func (c *Checker) Add(key, address string) {
|
||||
if c.domainIsInMap(key, false) || c.domainIsInMap(key, true) {
|
||||
func (c *Checker) Add(domain, address string) {
|
||||
h, _, _ := net.SplitHostPort(domain)
|
||||
if h != "" {
|
||||
domain = h
|
||||
}
|
||||
if c.domainIsInMap(domain, false) || c.domainIsInMap(domain, true) {
|
||||
return
|
||||
}
|
||||
var item CheckerItem
|
||||
item = CheckerItem{
|
||||
Host: address,
|
||||
Key: key,
|
||||
Domain: domain,
|
||||
Address: address,
|
||||
}
|
||||
c.data.SetIfAbsent(item.Host, item)
|
||||
c.data.SetIfAbsent(item.Domain, item)
|
||||
}
|
||||
|
||||
type BasicAuth struct {
|
||||
@ -329,6 +340,7 @@ type HTTPRequest struct {
|
||||
isBasicAuth bool
|
||||
basicAuth *BasicAuth
|
||||
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) {
|
||||
@ -360,6 +372,7 @@ func NewHTTPRequest(inConn *net.Conn, bufSize int, isBasicAuth bool, basicAuth *
|
||||
//sni success
|
||||
req.Method = "SNI"
|
||||
req.hostOrURL = "https://" + serverName + ":443"
|
||||
req.IsSNI = true
|
||||
} else {
|
||||
//sni fail , try http
|
||||
index := bytes.IndexByte(req.HeadBuf, '\n')
|
||||
|
||||
Reference in New Issue
Block a user