mirror of
https://github.com/nadoo/glider.git
synced 2025-02-24 01:45:39 +08:00
socks5: support auth in server mode. #84
This commit is contained in:
parent
822693b05b
commit
2560f6727f
@ -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
3
go.mod
@ -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
6
go.sum
@ -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=
|
||||||
|
2
main.go
2
main.go
@ -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
|
||||||
|
@ -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")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
}
|
||||||
|
|
||||||
|
_, 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
|
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
|
||||||
|
Loading…
Reference in New Issue
Block a user