socks5: support auth in server mode. #84

This commit is contained in:
nadoo 2019-10-19 20:29:52 +08:00
parent 822693b05b
commit 2560f6727f
6 changed files with 89 additions and 28 deletions

View File

@ -44,6 +44,7 @@ Forward (local proxy client/upstream proxy server):
DNS Forwarding Server (udp2tcp): DNS Forwarding Server (udp2tcp):
- DNS Over Proxy
- Listen on UDP and forward dns requests to remote dns server in TCP via forwarders - Listen on UDP and forward dns requests to remote dns server in TCP via forwarders
- Specify different upstream dns server based on destinations(in rule file) - Specify different upstream dns server based on destinations(in rule file)
- Tunnel mode: forward to a fixed upstream dns server - Tunnel mode: forward to a fixed upstream dns server

3
go.mod
View File

@ -15,7 +15,8 @@ require (
github.com/xtaci/kcp-go v5.4.11+incompatible github.com/xtaci/kcp-go v5.4.11+incompatible
github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae // indirect github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae // indirect
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550
golang.org/x/net v0.0.0-20191011234655-491137f69257 // indirect golang.org/x/net v0.0.0-20191014212845-da9a3fd4c582 // indirect
golang.org/x/sys v0.0.0-20191018095205-727590c5006e // indirect
) )
// Replace dependency modules with local developing copy // Replace dependency modules with local developing copy

6
go.sum
View File

@ -37,11 +37,13 @@ golang.org/x/crypto v0.0.0-20191010185427-af544f31c8ac/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20191011234655-491137f69257 h1:ry8e2D+cwaV6hk7lb3aRTjjZo24shrbK0e11QEOkTIg= golang.org/x/net v0.0.0-20191014212845-da9a3fd4c582 h1:p9xBe/w/OzkeYVKm234g55gMdD1nSIooTir5kV11kfA=
golang.org/x/net v0.0.0-20191011234655-491137f69257/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191014212845-da9a3fd4c582/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191009170203-06d7bd2c5f4f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191009170203-06d7bd2c5f4f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191010194322-b09406accb47 h1:/XfQ9z7ib8eEJX2hdgFTZJ/ntt0swNk5oYBziWeTCvY= golang.org/x/sys v0.0.0-20191010194322-b09406accb47 h1:/XfQ9z7ib8eEJX2hdgFTZJ/ntt0swNk5oYBziWeTCvY=
golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191018095205-727590c5006e h1:ZtoklVMHQy6BFRHkbG6JzK+S6rX82//Yeok1vMlizfQ=
golang.org/x/sys v0.0.0-20191018095205-727590c5006e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=

View File

@ -29,7 +29,7 @@ import (
_ "github.com/nadoo/glider/proxy/ws" _ "github.com/nadoo/glider/proxy/ws"
) )
var version = "0.8.3" var version = "0.9.0"
func main() { func main() {
// read configs // read configs

View File

@ -1,6 +1,7 @@
// http proxy // https://developer.mozilla.org/en-US/docs/Web/HTTP/Messages
// NOTE: never keep-alive so the implementation can be much easier. // NOTE: never keep-alive so the implementation can be much easier.
// Package http implements a http proxy.
package http package http
import ( import (
@ -107,7 +108,7 @@ func (s *HTTP) Serve(c net.Conn) {
reqR := bufio.NewReader(c) reqR := bufio.NewReader(c)
reqTP := textproto.NewReader(reqR) reqTP := textproto.NewReader(reqR)
method, requestURI, proto, ok := parseFirstLine(reqTP) method, requestURI, proto, ok := parseStartLine(reqTP)
if !ok { if !ok {
return return
} }
@ -139,7 +140,7 @@ func (s *HTTP) Serve(c net.Conn) {
return return
} }
var tgt = u.Host tgt := u.Host
if !strings.Contains(u.Host, ":") { if !strings.Contains(u.Host, ":") {
tgt += ":80" tgt += ":80"
} }
@ -157,12 +158,12 @@ func (s *HTTP) Serve(c net.Conn) {
u.Scheme, u.Host = "", "" u.Scheme, u.Host = "", ""
uri := u.String() uri := u.String()
var reqBuf bytes.Buffer var buf bytes.Buffer
writeFirstLine(&reqBuf, method, uri, proto) writeStartLine(&buf, method, uri, proto)
writeHeaders(&reqBuf, reqHeader) writeHeaders(&buf, reqHeader)
// send request to remote server // send request to remote server
rc.Write(reqBuf.Bytes()) rc.Write(buf.Bytes())
// copy the left request bytes to remote server. eg. length specificed or chunked body // copy the left request bytes to remote server. eg. length specificed or chunked body
go func() { go func() {
@ -175,7 +176,7 @@ func (s *HTTP) Serve(c net.Conn) {
respR := bufio.NewReader(rc) respR := bufio.NewReader(rc)
respTP := textproto.NewReader(respR) respTP := textproto.NewReader(respR)
proto, code, status, ok := parseFirstLine(respTP) proto, code, status, ok := parseStartLine(respTP)
if !ok { if !ok {
return return
} }
@ -189,12 +190,12 @@ func (s *HTTP) Serve(c net.Conn) {
respHeader.Set("Proxy-Connection", "close") respHeader.Set("Proxy-Connection", "close")
respHeader.Set("Connection", "close") respHeader.Set("Connection", "close")
var respBuf bytes.Buffer buf.Reset()
writeFirstLine(&respBuf, proto, code, status) writeStartLine(&buf, proto, code, status)
writeHeaders(&respBuf, respHeader) writeHeaders(&buf, respHeader)
log.F("[http] %s <-> %s via %s", c.RemoteAddr(), tgt, p) log.F("[http] %s <-> %s via %s", c.RemoteAddr(), tgt, p)
c.Write(respBuf.Bytes()) c.Write(buf.Bytes())
io.Copy(c, respR) io.Copy(c, respR)
} }
@ -256,7 +257,7 @@ func (s *HTTP) Dial(network, addr string) (net.Conn, error) {
c := conn.NewConn(rc) c := conn.NewConn(rc)
tpr := textproto.NewReader(c.Reader()) tpr := textproto.NewReader(c.Reader())
_, code, _, ok := parseFirstLine(tpr) _, code, _, ok := parseStartLine(tpr)
if ok && code == "200" { if ok && code == "200" {
tpr.ReadMIMEHeader() tpr.ReadMIMEHeader()
return c, err return c, err
@ -276,8 +277,8 @@ func (s *HTTP) DialUDP(network, addr string) (pc net.PacketConn, writeTo net.Add
return nil, nil, errors.New("http client does not support udp") return nil, nil, errors.New("http client does not support udp")
} }
// parseFirstLine parses "GET /foo HTTP/1.1" OR "HTTP/1.1 200 OK" into its three parts. // parseStartLine parses "GET /foo HTTP/1.1" OR "HTTP/1.1 200 OK" into its three parts.
func parseFirstLine(tp *textproto.Reader) (r1, r2, r3 string, ok bool) { func parseStartLine(tp *textproto.Reader) (r1, r2, r3 string, ok bool) {
line, err := tp.ReadLine() line, err := tp.ReadLine()
if err != nil { if err != nil {
return return
@ -304,7 +305,7 @@ func cleanHeaders(header textproto.MIMEHeader) {
header.Del("Upgrade") header.Del("Upgrade")
} }
func writeFirstLine(buf *bytes.Buffer, s1, s2, s3 string) { func writeStartLine(buf *bytes.Buffer, s1, s2, s3 string) {
buf.WriteString(s1 + " " + s2 + " " + s3 + "\r\n") buf.WriteString(s1 + " " + s2 + " " + s3 + "\r\n")
} }

View File

@ -6,9 +6,6 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// socks5 server:
// https://github.com/shadowsocks/go-shadowsocks2/tree/master/socks
// Package socks5 implements a socks5 proxy. // Package socks5 implements a socks5 proxy.
package socks5 package socks5
@ -129,7 +126,7 @@ func (s *Socks5) Serve(c net.Conn) {
} }
} }
log.F("[socks5] failed to get target address: %v", err) log.F("[socks5] failed in handshake: %v", err)
return return
} }
@ -253,7 +250,7 @@ func (s *Socks5) DialUDP(network, addr string) (pc net.PacketConn, writeTo net.A
} }
// send VER, NMETHODS, METHODS // send VER, NMETHODS, METHODS
c.Write([]byte{5, 1, 0}) c.Write([]byte{Version, 1, 0})
buf := make([]byte, socks.MaxAddrLen) buf := make([]byte, socks.MaxAddrLen)
// read VER METHOD // read VER METHOD
@ -263,7 +260,7 @@ func (s *Socks5) DialUDP(network, addr string) (pc net.PacketConn, writeTo net.A
dstAddr := socks.ParseAddr(addr) dstAddr := socks.ParseAddr(addr)
// write VER CMD RSV ATYP DST.ADDR DST.PORT // write VER CMD RSV ATYP DST.ADDR DST.PORT
c.Write(append([]byte{5, socks.CmdUDPAssociate, 0}, dstAddr...)) c.Write(append([]byte{Version, socks.CmdUDPAssociate, 0}, dstAddr...))
// read VER REP RSV ATYP BND.ADDR BND.PORT // read VER REP RSV ATYP BND.ADDR BND.PORT
if _, err := io.ReadFull(c, buf[:3]); err != nil { if _, err := io.ReadFull(c, buf[:3]); err != nil {
@ -325,7 +322,7 @@ func (s *Socks5) connect(conn net.Conn, target string) error {
if _, err := io.ReadFull(conn, buf[:2]); err != nil { if _, err := io.ReadFull(conn, buf[:2]); err != nil {
return errors.New("proxy: failed to read greeting from SOCKS5 proxy at " + s.addr + ": " + err.Error()) return errors.New("proxy: failed to read greeting from SOCKS5 proxy at " + s.addr + ": " + err.Error())
} }
if buf[0] != 5 { if buf[0] != Version {
return errors.New("proxy: SOCKS5 proxy at " + s.addr + " has unexpected version " + strconv.Itoa(int(buf[0]))) return errors.New("proxy: SOCKS5 proxy at " + s.addr + " has unexpected version " + strconv.Itoa(int(buf[0])))
} }
if buf[1] == 0xff { if buf[1] == 0xff {
@ -432,14 +429,73 @@ func (s *Socks5) handshake(rw io.ReadWriter) (socks.Addr, error) {
if _, err := io.ReadFull(rw, buf[:2]); err != nil { if _, err := io.ReadFull(rw, buf[:2]); err != nil {
return nil, err return nil, err
} }
nmethods := buf[1] nmethods := buf[1]
if _, err := io.ReadFull(rw, buf[:nmethods]); err != nil { if _, err := io.ReadFull(rw, buf[:nmethods]); err != nil {
return nil, err return nil, err
} }
// write VER METHOD // write VER METHOD
if _, err := rw.Write([]byte{5, 0}); err != nil { if s.user != "" && s.password != "" {
_, err := rw.Write([]byte{Version, socks.AuthPassword})
if err != nil {
return nil, err return nil, err
} }
_, err = io.ReadFull(rw, buf[:2])
if err != nil {
return nil, err
}
// Get username
userLen := int(buf[1])
if userLen <= 0 {
rw.Write([]byte{1, 1})
return nil, errors.New("auth failed: wrong username length")
}
if _, err := io.ReadFull(rw, buf[:userLen]); err != nil {
return nil, errors.New("auth failed: cannot get username")
}
user := string(buf[:userLen])
// Get password
_, err = rw.Read(buf[:1])
if err != nil {
return nil, errors.New("auth failed: cannot get password len")
}
passLen := int(buf[0])
if passLen <= 0 {
rw.Write([]byte{1, 1})
return nil, errors.New("auth failed: wrong password length")
}
_, err = io.ReadFull(rw, buf[:passLen])
if err != nil {
return nil, errors.New("auth failed: cannot get password")
}
pass := string(buf[:passLen])
// Verify
if user != s.user || pass != s.password {
_, err = rw.Write([]byte{1, 1})
if err != nil {
return nil, err
}
return nil, errors.New("auth failed")
}
// Response auth state
_, err = rw.Write([]byte{1, 0})
if err != nil {
return nil, err
}
} else if _, err := rw.Write([]byte{Version, socks.AuthNone}); err != nil {
return nil, err
}
// read VER CMD RSV ATYP DST.ADDR DST.PORT // read VER CMD RSV ATYP DST.ADDR DST.PORT
if _, err := io.ReadFull(rw, buf[:3]); err != nil { if _, err := io.ReadFull(rw, buf[:3]); err != nil {
return nil, err return nil, err