Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com>
This commit is contained in:
@ -1,6 +1,6 @@
|
|||||||
proxy更新日志
|
proxy更新日志
|
||||||
v3.4
|
v3.4
|
||||||
1.
|
1.socks5代理新增了用户名密码验证支持.
|
||||||
|
|
||||||
v3.3
|
v3.3
|
||||||
1.修复了socks代理模式对证书文件的判断逻辑.
|
1.修复了socks代理模式对证书文件的判断逻辑.
|
||||||
|
|||||||
13
README.md
13
README.md
@ -31,6 +31,8 @@ Proxy是golang实现的高性能http,https,websocket,tcp,udp,socks5代理服务
|
|||||||
- [v3.0手册](https://github.com/snail007/goproxy/tree/v3.0)
|
- [v3.0手册](https://github.com/snail007/goproxy/tree/v3.0)
|
||||||
- [v2.x手册](https://github.com/snail007/goproxy/tree/v2.2)
|
- [v2.x手册](https://github.com/snail007/goproxy/tree/v2.2)
|
||||||
|
|
||||||
|
[TOC]
|
||||||
|
|
||||||
### Fast Start
|
### Fast Start
|
||||||
提示:所有操作需要root权限.
|
提示:所有操作需要root权限.
|
||||||
**0.如果你的VPS是linux64位的系统,那么只需要执行下面一句,就可以完成自动安装和配置.**
|
**0.如果你的VPS是linux64位的系统,那么只需要执行下面一句,就可以完成自动安装和配置.**
|
||||||
@ -420,11 +422,18 @@ server连接到bridge的时候,如果同时有多个client连接到同一个brid
|
|||||||
|
|
||||||
那么访问本地的28080端口就是通过VPS访问目标地址.
|
那么访问本地的28080端口就是通过VPS访问目标地址.
|
||||||
|
|
||||||
**5.7.查看帮助**
|
**5.7.认证**
|
||||||
|
对于socks5代理协议我们可以进行用户名密码认证,认证的用户名和密码可以在命令行指定
|
||||||
|
`./proxy socks -t tcp -p ":33080" -a "user1:pass1" -a "user2:pass2"`
|
||||||
|
多个用户,重复-a参数即可.
|
||||||
|
也可以放在文件中,格式是一行一个"用户名:密码",然后用-F指定.
|
||||||
|
`./proxy socks -t tcp -p ":33080" -F auth-file.txt`
|
||||||
|
如果没有-a或-F参数,就是关闭认证.
|
||||||
|
|
||||||
|
**5.8.查看帮助**
|
||||||
`./proxy help socks`
|
`./proxy help socks`
|
||||||
|
|
||||||
### TODO
|
### TODO
|
||||||
- SOCKS5增加用户名密码认证?
|
|
||||||
- http,socks代理多个上级负载均衡?
|
- http,socks代理多个上级负载均衡?
|
||||||
- 内网穿透server<->bridge心跳机制?
|
- 内网穿透server<->bridge心跳机制?
|
||||||
- 欢迎加群反馈...
|
- 欢迎加群反馈...
|
||||||
|
|||||||
@ -124,6 +124,8 @@ func initConfig() (err error) {
|
|||||||
socksArgs.Interval = socks.Flag("interval", "check domain if blocked every interval seconds").Default("10").Int()
|
socksArgs.Interval = socks.Flag("interval", "check domain if blocked every interval seconds").Default("10").Int()
|
||||||
socksArgs.Blocked = socks.Flag("blocked", "blocked domain file , one domain each line").Default("blocked").Short('b').String()
|
socksArgs.Blocked = socks.Flag("blocked", "blocked domain file , one domain each line").Default("blocked").Short('b').String()
|
||||||
socksArgs.Direct = socks.Flag("direct", "direct domain file , one domain each line").Default("direct").Short('d').String()
|
socksArgs.Direct = socks.Flag("direct", "direct domain file , one domain each line").Default("direct").Short('d').String()
|
||||||
|
socksArgs.AuthFile = socks.Flag("auth-file", "http basic auth file,\"username:password\" each line in file").Short('F').String()
|
||||||
|
socksArgs.Auth = socks.Flag("auth", "socks auth username and password, mutiple user repeat -a ,such as: -a user1:pass1 -a user2:pass2").Short('a').Strings()
|
||||||
//parse args
|
//parse args
|
||||||
serviceName := kingpin.MustParse(app.Parse(os.Args[1:]))
|
serviceName := kingpin.MustParse(app.Parse(os.Args[1:]))
|
||||||
flags := log.Ldate
|
flags := log.Ldate
|
||||||
|
|||||||
@ -118,6 +118,8 @@ type SocksArgs struct {
|
|||||||
Interval *int
|
Interval *int
|
||||||
Blocked *string
|
Blocked *string
|
||||||
Direct *string
|
Direct *string
|
||||||
|
AuthFile *string
|
||||||
|
Auth *[]string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *TCPArgs) Protocol() string {
|
func (a *TCPArgs) Protocol() string {
|
||||||
|
|||||||
@ -78,6 +78,7 @@ func (s *Socks) CheckArgs() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
func (s *Socks) InitService() {
|
func (s *Socks) InitService() {
|
||||||
|
s.InitBasicAuth()
|
||||||
s.checker = utils.NewChecker(*s.cfg.Timeout, int64(*s.cfg.Interval), *s.cfg.Blocked, *s.cfg.Direct)
|
s.checker = utils.NewChecker(*s.cfg.Timeout, int64(*s.cfg.Interval), *s.cfg.Blocked, *s.cfg.Direct)
|
||||||
if *s.cfg.ParentType == "ssh" {
|
if *s.cfg.ParentType == "ssh" {
|
||||||
err := s.ConnectSSH()
|
err := s.ConnectSSH()
|
||||||
@ -94,9 +95,6 @@ func (s *Socks) InitService() {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
if s.sshClient != nil {
|
if s.sshClient != nil {
|
||||||
s.sshClient.Close()
|
s.sshClient.Close()
|
||||||
if s.sshClient.Conn != nil {
|
|
||||||
s.sshClient.Conn.Close()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
log.Printf("ssh offline, retrying...")
|
log.Printf("ssh offline, retrying...")
|
||||||
s.ConnectSSH()
|
s.ConnectSSH()
|
||||||
@ -290,28 +288,72 @@ func (s *Socks) socksConnCallback(inConn net.Conn) {
|
|||||||
}
|
}
|
||||||
utils.CloseConn(&inConn)
|
utils.CloseConn(&inConn)
|
||||||
}()
|
}()
|
||||||
|
//协商开始
|
||||||
|
|
||||||
//method select request
|
//method select request
|
||||||
|
inConn.SetReadDeadline(time.Now().Add(time.Second * 3))
|
||||||
methodReq, err := socks.NewMethodsRequest(inConn)
|
methodReq, err := socks.NewMethodsRequest(inConn)
|
||||||
if err != nil || !methodReq.Select(socks.Method_NO_AUTH) {
|
inConn.SetReadDeadline(time.Time{})
|
||||||
|
if err != nil {
|
||||||
methodReq.Reply(socks.Method_NONE_ACCEPTABLE)
|
methodReq.Reply(socks.Method_NONE_ACCEPTABLE)
|
||||||
utils.CloseConn(&inConn)
|
utils.CloseConn(&inConn)
|
||||||
if err != nil {
|
log.Printf("new methods request fail,ERR: %s", err)
|
||||||
log.Printf("new methods request fail,ERR: %s", err)
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !s.IsBasicAuth() {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
// log.Printf("% x", methodReq.Bytes())
|
||||||
|
} else {
|
||||||
|
//auth
|
||||||
|
if !methodReq.Select(socks.Method_USER_PASS) {
|
||||||
|
methodReq.Reply(socks.Method_NONE_ACCEPTABLE)
|
||||||
|
utils.CloseConn(&inConn)
|
||||||
|
log.Printf("none method found : Method_USER_PASS")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
//method reply need auth
|
||||||
|
err = methodReq.Reply(socks.Method_USER_PASS)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("reply answer data fail,ERR: %s", err)
|
||||||
|
utils.CloseConn(&inConn)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
//read auth
|
||||||
|
buf := make([]byte, 500)
|
||||||
|
inConn.SetReadDeadline(time.Now().Add(time.Second * 3))
|
||||||
|
n, err := inConn.Read(buf)
|
||||||
|
inConn.SetReadDeadline(time.Time{})
|
||||||
|
if err != nil {
|
||||||
|
utils.CloseConn(&inConn)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r := buf[:n]
|
||||||
|
user := string(r[2 : r[1]+2])
|
||||||
|
pass := string(r[2+r[1]+1:])
|
||||||
|
//log.Printf("user:%s,pass:%s", user, pass)
|
||||||
|
//auth
|
||||||
|
if s.basicAuth.CheckUserPass(user, pass) {
|
||||||
|
inConn.Write([]byte{0x01, 0x00})
|
||||||
|
} else {
|
||||||
|
inConn.Write([]byte{0x01, 0x01})
|
||||||
|
utils.CloseConn(&inConn)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
// log.Printf("% x", methodReq.Bytes())
|
|
||||||
|
|
||||||
//request detail
|
//request detail
|
||||||
request, err := socks.NewRequest(inConn)
|
request, err := socks.NewRequest(inConn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -319,6 +361,7 @@ func (s *Socks) socksConnCallback(inConn net.Conn) {
|
|||||||
utils.CloseConn(&inConn)
|
utils.CloseConn(&inConn)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
//协商结束
|
||||||
|
|
||||||
switch request.CMD() {
|
switch request.CMD() {
|
||||||
case socks.CMD_BIND:
|
case socks.CMD_BIND:
|
||||||
@ -447,7 +490,7 @@ func (s *Socks) getOutConn(methodBytes, reqBytes []byte, host string) (outConn n
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
wait := make(chan bool, 1)
|
wait := make(chan bool, 1)
|
||||||
func() {
|
go func() {
|
||||||
defer func() {
|
defer func() {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
err = recover()
|
err = recover()
|
||||||
@ -458,8 +501,9 @@ func (s *Socks) getOutConn(methodBytes, reqBytes []byte, host string) (outConn n
|
|||||||
}()
|
}()
|
||||||
select {
|
select {
|
||||||
case <-wait:
|
case <-wait:
|
||||||
case <-time.After(time.Second * 5):
|
case <-time.After(time.Millisecond * time.Duration(*s.cfg.Timeout) * 2):
|
||||||
err = fmt.Errorf("ssh dial %s timeout", host)
|
err = fmt.Errorf("ssh dial %s timeout", host)
|
||||||
|
s.sshClient.Close()
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("connect ssh fail, ERR: %s, retrying...", err)
|
log.Printf("connect ssh fail, ERR: %s, retrying...", err)
|
||||||
@ -498,3 +542,23 @@ func (s *Socks) ConnectSSH() (err error) {
|
|||||||
<-s.lockChn
|
<-s.lockChn
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
func (s *Socks) InitBasicAuth() (err error) {
|
||||||
|
s.basicAuth = utils.NewBasicAuth()
|
||||||
|
if *s.cfg.AuthFile != "" {
|
||||||
|
var n = 0
|
||||||
|
n, err = s.basicAuth.AddFromFile(*s.cfg.AuthFile)
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("auth-file ERR:%s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Printf("auth data added from file %d , total:%d", n, s.basicAuth.Total())
|
||||||
|
}
|
||||||
|
if len(*s.cfg.Auth) > 0 {
|
||||||
|
n := s.basicAuth.Add(*s.cfg.Auth)
|
||||||
|
log.Printf("auth data added %d, total:%d", n, s.basicAuth.Total())
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
func (s *Socks) IsBasicAuth() bool {
|
||||||
|
return *s.cfg.AuthFile != "" || len(*s.cfg.Auth) > 0
|
||||||
|
}
|
||||||
|
|||||||
@ -213,7 +213,12 @@ func (ba *BasicAuth) Add(userpassArr []string) (n int) {
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
func (ba *BasicAuth) CheckUserPass(user, pass string) (ok bool) {
|
||||||
|
if p, _ok := ba.data.Get(user); _ok {
|
||||||
|
return p.(string) == pass
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
func (ba *BasicAuth) Check(userpass string) (ok bool) {
|
func (ba *BasicAuth) Check(userpass string) (ok bool) {
|
||||||
u := strings.Split(strings.Trim(userpass, " "), ":")
|
u := strings.Split(strings.Trim(userpass, " "), ":")
|
||||||
if len(u) == 2 {
|
if len(u) == 2 {
|
||||||
|
|||||||
Reference in New Issue
Block a user