mirror of https://github.com/ginuerzh/gost
11 changed files with 506 additions and 353 deletions
@ -0,0 +1,66 @@ |
|||
package main |
|||
|
|||
import ( |
|||
"bufio" |
|||
"context" |
|||
"crypto/tls" |
|||
"log" |
|||
"net/http" |
|||
"net/http/httputil" |
|||
"net/url" |
|||
|
|||
"github.com/ginuerzh/gost/gost" |
|||
) |
|||
|
|||
func init() { |
|||
log.SetFlags(log.LstdFlags | log.Lshortfile) |
|||
gost.Debug = true |
|||
} |
|||
|
|||
func main() { |
|||
chain := gost.NewChain( |
|||
gost.Node{ |
|||
Addr: "127.0.0.1:1080", |
|||
Client: gost.NewClient( |
|||
gost.HTTPConnector(url.UserPassword("admin", "123456")), |
|||
gost.TCPTransporter(), |
|||
), |
|||
}, |
|||
gost.Node{ |
|||
Addr: "172.24.222.54:8338", |
|||
Client: gost.NewClient( |
|||
gost.ShadowConnector(url.UserPassword("chacha20", "123456")), |
|||
gost.TCPTransporter(), |
|||
), |
|||
}, |
|||
gost.Node{ |
|||
Addr: "172.24.222.54:8080", |
|||
Client: gost.NewClient( |
|||
gost.SOCKS5Connector(url.UserPassword("cmdsh", "cmdsh123456")), |
|||
gost.TCPTransporter(), |
|||
), |
|||
}, |
|||
) |
|||
conn, err := chain.Dial(context.Background(), "baidu.com:443") |
|||
if err != nil { |
|||
log.Fatal(err) |
|||
} |
|||
conn = tls.Client(conn, &tls.Config{InsecureSkipVerify: true}) |
|||
req, err := http.NewRequest(http.MethodGet, "https://www.baidu.com", nil) |
|||
if err != nil { |
|||
log.Fatal(err) |
|||
} |
|||
if err := req.Write(conn); err != nil { |
|||
log.Fatal(err) |
|||
} |
|||
resp, err := http.ReadResponse(bufio.NewReader(conn), req) |
|||
if err != nil { |
|||
log.Fatal(err) |
|||
} |
|||
defer resp.Body.Close() |
|||
|
|||
rb, _ := httputil.DumpRequest(req, true) |
|||
log.Println(string(rb)) |
|||
rb, _ = httputil.DumpResponse(resp, true) |
|||
log.Println(string(rb)) |
|||
} |
|||
@ -1,167 +1,58 @@ |
|||
package gost |
|||
|
|||
import ( |
|||
"bufio" |
|||
"context" |
|||
"crypto/tls" |
|||
"encoding/base64" |
|||
"errors" |
|||
"fmt" |
|||
"net" |
|||
"net/http" |
|||
"net/http/httputil" |
|||
"net/url" |
|||
"strconv" |
|||
|
|||
"github.com/ginuerzh/gosocks4" |
|||
"github.com/ginuerzh/gosocks5" |
|||
"github.com/go-log/log" |
|||
ss "github.com/shadowsocks/shadowsocks-go/shadowsocks" |
|||
) |
|||
|
|||
type Client struct { |
|||
Protocol string |
|||
Transport *Transport |
|||
User *url.Userinfo |
|||
} |
|||
|
|||
func (c *Client) Dial(ctx context.Context, addr string) (net.Conn, error) { |
|||
return c.Transport.Dial(ctx, addr) |
|||
Connector Connector |
|||
Transporter Transporter |
|||
} |
|||
|
|||
func (c *Client) Connect(ctx context.Context, conn net.Conn, addr string) (net.Conn, error) { |
|||
protocol := c.Protocol |
|||
|
|||
switch protocol { |
|||
case "ss": // shadowsocks
|
|||
rawaddr, err := ss.RawAddr(addr) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
var method, password string |
|||
if c.User != nil { |
|||
method = c.User.Username() |
|||
password, _ = c.User.Password() |
|||
} |
|||
// DefaultClient is a standard HTTP proxy
|
|||
var DefaultClient = NewClient(HTTPConnector(nil), TCPTransporter()) |
|||
|
|||
cipher, err := ss.NewCipher(method, password) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
sc, err := ss.DialWithRawAddrConn(rawaddr, conn, cipher) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
conn = ShadowConn(sc) |
|||
|
|||
case "socks", "socks5": |
|||
host, port, err := net.SplitHostPort(addr) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
p, _ := strconv.Atoi(port) |
|||
req := gosocks5.NewRequest(gosocks5.CmdConnect, &gosocks5.Addr{ |
|||
Type: gosocks5.AddrDomain, |
|||
Host: host, |
|||
Port: uint16(p), |
|||
}) |
|||
if err := req.Write(conn); err != nil { |
|||
return nil, err |
|||
} |
|||
log.Log("[socks5]", req) |
|||
|
|||
reply, err := gosocks5.ReadReply(conn) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
log.Log("[socks5]", reply) |
|||
if reply.Rep != gosocks5.Succeeded { |
|||
return nil, errors.New("Service unavailable") |
|||
} |
|||
|
|||
case "socks4", "socks4a": |
|||
atype := gosocks4.AddrDomain |
|||
host, port, err := net.SplitHostPort(addr) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
p, _ := strconv.Atoi(port) |
|||
func NewClient(c Connector, tr Transporter) *Client { |
|||
return &Client{ |
|||
Connector: c, |
|||
Transporter: tr, |
|||
} |
|||
} |
|||
|
|||
if protocol == "socks4" { |
|||
taddr, err := net.ResolveTCPAddr("tcp4", addr) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
host = taddr.IP.String() |
|||
p = taddr.Port |
|||
atype = gosocks4.AddrIPv4 |
|||
} |
|||
req := gosocks4.NewRequest(gosocks4.CmdConnect, |
|||
&gosocks4.Addr{Type: atype, Host: host, Port: uint16(p)}, nil) |
|||
if err := req.Write(conn); err != nil { |
|||
return nil, err |
|||
} |
|||
log.Logf("[%s] %s", protocol, req) |
|||
// Dial connects to the target address
|
|||
func (c *Client) Dial(ctx context.Context, addr string) (net.Conn, error) { |
|||
return net.Dial(c.Transporter.Network(), addr) |
|||
} |
|||
|
|||
reply, err := gosocks4.ReadReply(conn) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
log.Logf("[%s] %s", protocol, reply) |
|||
func (c *Client) Handshake(ctx context.Context, conn net.Conn) (net.Conn, error) { |
|||
return c.Transporter.Handshake(ctx, conn) |
|||
} |
|||
|
|||
if reply.Code != gosocks4.Granted { |
|||
return nil, fmt.Errorf("%s: code=%d", protocol, reply.Code) |
|||
} |
|||
case "http": |
|||
fallthrough |
|||
default: |
|||
req := &http.Request{ |
|||
Method: http.MethodConnect, |
|||
URL: &url.URL{Host: addr}, |
|||
Host: addr, |
|||
ProtoMajor: 1, |
|||
ProtoMinor: 1, |
|||
Header: make(http.Header), |
|||
} |
|||
req.Header.Set("Proxy-Connection", "keep-alive") |
|||
if c.User != nil { |
|||
s := c.User.String() |
|||
if _, set := c.User.Password(); !set { |
|||
s += ":" |
|||
} |
|||
req.Header.Set("Proxy-Authorization", |
|||
"Basic "+base64.StdEncoding.EncodeToString([]byte(s))) |
|||
} |
|||
if err := req.Write(conn); err != nil { |
|||
return nil, err |
|||
} |
|||
func (c *Client) Connect(ctx context.Context, conn net.Conn, addr string) (net.Conn, error) { |
|||
return c.Connector.Connect(ctx, conn, addr) |
|||
} |
|||
|
|||
if Debug { |
|||
dump, _ := httputil.DumpRequest(req, false) |
|||
log.Log(string(dump)) |
|||
} |
|||
type Connector interface { |
|||
Connect(ctx context.Context, conn net.Conn, addr string) (net.Conn, error) |
|||
} |
|||
|
|||
resp, err := http.ReadResponse(bufio.NewReader(conn), req) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
type Transporter interface { |
|||
Network() string |
|||
Handshake(ctx context.Context, conn net.Conn) (net.Conn, error) |
|||
} |
|||
|
|||
if Debug { |
|||
dump, _ := httputil.DumpResponse(resp, false) |
|||
log.Log(string(dump)) |
|||
} |
|||
type tcpTransporter struct { |
|||
} |
|||
|
|||
if resp.StatusCode != http.StatusOK { |
|||
return nil, fmt.Errorf("%d %s", resp.StatusCode, resp.Status) |
|||
} |
|||
} |
|||
func TCPTransporter() Transporter { |
|||
return &tcpTransporter{} |
|||
} |
|||
|
|||
return conn, nil |
|||
func (tr *tcpTransporter) Network() string { |
|||
return "tcp" |
|||
} |
|||
|
|||
type Transport struct { |
|||
Dial func(ctx context.Context, addr string) (net.Conn, error) |
|||
TLSClientConfig *tls.Config |
|||
func (tr *tcpTransporter) Handshake(ctx context.Context, conn net.Conn) (net.Conn, error) { |
|||
return conn, nil |
|||
} |
|||
|
|||
@ -1,3 +1,11 @@ |
|||
package gost |
|||
|
|||
import ( |
|||
"github.com/go-log/log" |
|||
) |
|||
|
|||
var Debug bool |
|||
|
|||
func init() { |
|||
log.DefaultLogger = &logger{} |
|||
} |
|||
|
|||
@ -0,0 +1,68 @@ |
|||
package gost |
|||
|
|||
import ( |
|||
"bufio" |
|||
"context" |
|||
"encoding/base64" |
|||
"fmt" |
|||
"net" |
|||
"net/http" |
|||
"net/http/httputil" |
|||
"net/url" |
|||
|
|||
"github.com/go-log/log" |
|||
) |
|||
|
|||
type httpConnector struct { |
|||
User *url.Userinfo |
|||
} |
|||
|
|||
func HTTPConnector(user *url.Userinfo) Connector { |
|||
return &httpConnector{User: user} |
|||
} |
|||
|
|||
func (c *httpConnector) Connect(ctx context.Context, conn net.Conn, addr string) (net.Conn, error) { |
|||
req := &http.Request{ |
|||
Method: http.MethodConnect, |
|||
URL: &url.URL{Host: addr}, |
|||
Host: addr, |
|||
ProtoMajor: 1, |
|||
ProtoMinor: 1, |
|||
Header: make(http.Header), |
|||
} |
|||
req.Header.Set("Proxy-Connection", "keep-alive") |
|||
|
|||
if c.User != nil { |
|||
s := c.User.String() |
|||
if _, set := c.User.Password(); !set { |
|||
s += ":" |
|||
} |
|||
req.Header.Set("Proxy-Authorization", |
|||
"Basic "+base64.StdEncoding.EncodeToString([]byte(s))) |
|||
} |
|||
|
|||
if err := req.Write(conn); err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
if Debug { |
|||
dump, _ := httputil.DumpRequest(req, false) |
|||
log.Log(string(dump)) |
|||
} |
|||
|
|||
resp, err := http.ReadResponse(bufio.NewReader(conn), req) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
if Debug { |
|||
dump, _ := httputil.DumpResponse(resp, false) |
|||
log.Log(string(dump)) |
|||
} |
|||
|
|||
if resp.StatusCode != http.StatusOK { |
|||
return nil, fmt.Errorf("%s", resp.Status) |
|||
} |
|||
|
|||
return conn, nil |
|||
} |
|||
@ -0,0 +1,18 @@ |
|||
package gost |
|||
|
|||
import "log" |
|||
|
|||
func init() { |
|||
log.SetFlags(log.LstdFlags | log.Lshortfile) |
|||
} |
|||
|
|||
type logger struct { |
|||
} |
|||
|
|||
func (l *logger) Log(v ...interface{}) { |
|||
log.Println(v...) |
|||
} |
|||
|
|||
func (l *logger) Logf(format string, v ...interface{}) { |
|||
log.Printf(format, v...) |
|||
} |
|||
@ -1,6 +1,8 @@ |
|||
package gost |
|||
|
|||
type Node struct { |
|||
Addr string |
|||
Client *Client |
|||
Addr string |
|||
Protocol string |
|||
Transport string |
|||
Client *Client |
|||
} |
|||
|
|||
@ -0,0 +1,225 @@ |
|||
package gost |
|||
|
|||
import ( |
|||
"context" |
|||
"crypto/tls" |
|||
"errors" |
|||
"fmt" |
|||
"net" |
|||
"net/url" |
|||
"strconv" |
|||
|
|||
"github.com/ginuerzh/gosocks4" |
|||
"github.com/ginuerzh/gosocks5" |
|||
"github.com/go-log/log" |
|||
) |
|||
|
|||
const ( |
|||
MethodTLS uint8 = 0x80 // extended method for tls
|
|||
MethodTLSAuth uint8 = 0x82 // extended method for tls+auth
|
|||
) |
|||
|
|||
const ( |
|||
CmdUdpTun uint8 = 0xF3 // extended method for udp over tcp
|
|||
) |
|||
|
|||
type ClientSelector struct { |
|||
methods []uint8 |
|||
User *url.Userinfo |
|||
TLSConfig *tls.Config |
|||
} |
|||
|
|||
func (selector *ClientSelector) Methods() []uint8 { |
|||
return selector.methods |
|||
} |
|||
|
|||
func (selector *ClientSelector) AddMethod(methods ...uint8) { |
|||
selector.methods = append(selector.methods, methods...) |
|||
} |
|||
|
|||
func (selector *ClientSelector) Select(methods ...uint8) (method uint8) { |
|||
return |
|||
} |
|||
|
|||
func (selector *ClientSelector) OnSelected(method uint8, conn net.Conn) (net.Conn, error) { |
|||
switch method { |
|||
case MethodTLS: |
|||
conn = tls.Client(conn, selector.TLSConfig) |
|||
|
|||
case gosocks5.MethodUserPass, MethodTLSAuth: |
|||
if method == MethodTLSAuth { |
|||
conn = tls.Client(conn, selector.TLSConfig) |
|||
} |
|||
|
|||
var username, password string |
|||
if selector.User != nil { |
|||
username = selector.User.Username() |
|||
password, _ = selector.User.Password() |
|||
} |
|||
|
|||
req := gosocks5.NewUserPassRequest(gosocks5.UserPassVer, username, password) |
|||
if err := req.Write(conn); err != nil { |
|||
log.Log("[socks5]", err) |
|||
return nil, err |
|||
} |
|||
if Debug { |
|||
log.Log("[socks5]", req) |
|||
} |
|||
resp, err := gosocks5.ReadUserPassResponse(conn) |
|||
if err != nil { |
|||
log.Log("[socks5]", err) |
|||
return nil, err |
|||
} |
|||
if Debug { |
|||
log.Log("[socks5]", resp) |
|||
} |
|||
if resp.Status != gosocks5.Succeeded { |
|||
return nil, gosocks5.ErrAuthFailure |
|||
} |
|||
case gosocks5.MethodNoAcceptable: |
|||
return nil, gosocks5.ErrBadMethod |
|||
} |
|||
|
|||
return conn, nil |
|||
} |
|||
|
|||
type socks5Connector struct { |
|||
User *url.Userinfo |
|||
} |
|||
|
|||
func SOCKS5Connector(user *url.Userinfo) Connector { |
|||
return &socks5Connector{User: user} |
|||
} |
|||
|
|||
func (c *socks5Connector) Connect(ctx context.Context, conn net.Conn, addr string) (net.Conn, error) { |
|||
selector := &ClientSelector{ |
|||
TLSConfig: &tls.Config{InsecureSkipVerify: true}, |
|||
User: c.User, |
|||
} |
|||
selector.AddMethod( |
|||
gosocks5.MethodNoAuth, |
|||
gosocks5.MethodUserPass, |
|||
MethodTLS, |
|||
) |
|||
|
|||
cc := gosocks5.ClientConn(conn, selector) |
|||
if err := cc.Handleshake(); err != nil { |
|||
return nil, err |
|||
} |
|||
conn = cc |
|||
|
|||
host, port, err := net.SplitHostPort(addr) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
p, _ := strconv.Atoi(port) |
|||
req := gosocks5.NewRequest(gosocks5.CmdConnect, &gosocks5.Addr{ |
|||
Type: gosocks5.AddrDomain, |
|||
Host: host, |
|||
Port: uint16(p), |
|||
}) |
|||
if err := req.Write(conn); err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
if Debug { |
|||
log.Log("[socks5]", req) |
|||
} |
|||
|
|||
reply, err := gosocks5.ReadReply(conn) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
if Debug { |
|||
log.Log("[socks5]", reply) |
|||
} |
|||
|
|||
if reply.Rep != gosocks5.Succeeded { |
|||
return nil, errors.New("Service unavailable") |
|||
} |
|||
|
|||
return conn, nil |
|||
} |
|||
|
|||
type socks4Connector struct{} |
|||
|
|||
func SOCKS4Connector() Connector { |
|||
return &socks4Connector{} |
|||
} |
|||
|
|||
func (c *socks4Connector) Connect(ctx context.Context, conn net.Conn, addr string) (net.Conn, error) { |
|||
taddr, err := net.ResolveTCPAddr("tcp4", addr) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
req := gosocks4.NewRequest(gosocks4.CmdConnect, |
|||
&gosocks4.Addr{ |
|||
Type: gosocks4.AddrIPv4, |
|||
Host: taddr.IP.String(), |
|||
Port: uint16(taddr.Port), |
|||
}, nil, |
|||
) |
|||
if err := req.Write(conn); err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
if Debug { |
|||
log.Logf("[socks4] %s", req) |
|||
} |
|||
|
|||
reply, err := gosocks4.ReadReply(conn) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
if Debug { |
|||
log.Logf("[socks4] %s", reply) |
|||
} |
|||
|
|||
if reply.Code != gosocks4.Granted { |
|||
return nil, fmt.Errorf("[socks4] %d", reply.Code) |
|||
} |
|||
|
|||
return conn, nil |
|||
} |
|||
|
|||
type socks4aConnector struct{} |
|||
|
|||
func SOCKS4AConnector() Connector { |
|||
return &socks4aConnector{} |
|||
} |
|||
|
|||
func (c *socks4aConnector) Connect(ctx context.Context, conn net.Conn, addr string) (net.Conn, error) { |
|||
host, port, err := net.SplitHostPort(addr) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
p, _ := strconv.Atoi(port) |
|||
|
|||
req := gosocks4.NewRequest(gosocks4.CmdConnect, |
|||
&gosocks4.Addr{Type: gosocks4.AddrDomain, Host: host, Port: uint16(p)}, nil) |
|||
if err := req.Write(conn); err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
if Debug { |
|||
log.Logf("[socks4] %s", req) |
|||
} |
|||
|
|||
reply, err := gosocks4.ReadReply(conn) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
if Debug { |
|||
log.Logf("[socks4] %s", reply) |
|||
} |
|||
|
|||
if reply.Code != gosocks4.Granted { |
|||
return nil, fmt.Errorf("[socks4] %d", reply.Code) |
|||
} |
|||
|
|||
return conn, nil |
|||
} |
|||
@ -0,0 +1,23 @@ |
|||
package gost |
|||
|
|||
import ( |
|||
"context" |
|||
"crypto/tls" |
|||
"net" |
|||
) |
|||
|
|||
type tlsTransporter struct { |
|||
TLSClientConfig *tls.Config |
|||
} |
|||
|
|||
func TLSTransporter(cfg *tls.Config) Transporter { |
|||
return &tlsTransporter{TLSClientConfig: cfg} |
|||
} |
|||
|
|||
func (tr *tlsTransporter) Network() string { |
|||
return "tcp" |
|||
} |
|||
|
|||
func (tr *tlsTransporter) Handshake(ctx context.Context, conn net.Conn) (net.Conn, error) { |
|||
return tls.Client(conn, tr.TLSClientConfig), nil |
|||
} |
|||
@ -1,202 +0,0 @@ |
|||
package tcp |
|||
|
|||
import ( |
|||
"bufio" |
|||
"crypto/tls" |
|||
"encoding/base64" |
|||
"errors" |
|||
"fmt" |
|||
"net" |
|||
"net/http" |
|||
"net/http/httputil" |
|||
"net/url" |
|||
"strconv" |
|||
|
|||
"github.com/ginuerzh/gosocks4" |
|||
"github.com/ginuerzh/gosocks5" |
|||
"github.com/ginuerzh/gost" |
|||
"github.com/ginuerzh/gost/client" |
|||
"github.com/go-log/log" |
|||
ss "github.com/shadowsocks/shadowsocks-go/shadowsocks" |
|||
) |
|||
|
|||
type nodeClient struct { |
|||
options *client.Options |
|||
} |
|||
|
|||
func (c *nodeClient) Init(opts ...client.Option) { |
|||
for _, opt := range opts { |
|||
opt(c.options) |
|||
} |
|||
} |
|||
|
|||
func (c *nodeClient) Options() *Options { |
|||
return c.options |
|||
} |
|||
|
|||
func (c *nodeClient) Connect() (net.Conn, error) { |
|||
return net.Dial("tcp", c.options.Addr) |
|||
} |
|||
|
|||
func (c *nodeClient) Handshake(conn net.Conn) (net.Conn, error) { |
|||
return conn, nil |
|||
} |
|||
|
|||
func (c *nodeClient) Dial(conn net.Conn, addr string) (net.Conn, error) { |
|||
if c.options.Protocol == "socks5" { |
|||
selector := &gost.ClientSelector{ |
|||
TLSConfig: &tls.Config{ |
|||
InsecureSkipVerify: !c.options.SecureVerify, |
|||
ServerName: c.options.ServerName, |
|||
}, |
|||
} |
|||
selector.AddMethod( |
|||
gosocks5.MethodNoAuth, |
|||
gosocks5.MethodUserPass, |
|||
gost.MethodTLS, |
|||
) |
|||
users := c.options.Users |
|||
if len(users) > 0 { |
|||
selector.User = &users[0] |
|||
} |
|||
|
|||
cc := gosocks5.ClientConn(conn, selector) |
|||
if err := cc.Handleshake(); err != nil { |
|||
return nil, err |
|||
} |
|||
conn = cc |
|||
} |
|||
|
|||
return c.dial(conn, addr) |
|||
} |
|||
|
|||
func (c *nodeClient) dial(conn net.Conn, addr string) (net.Conn, error) { |
|||
protocol := c.options.Protocol |
|||
switch protocol { |
|||
case "ss": // shadowsocks
|
|||
rawaddr, err := ss.RawAddr(addr) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
var method, password string |
|||
users := c.options.Users |
|||
if len(users) > 0 { |
|||
method = users[0].Username() |
|||
password, _ = users[0].Password() |
|||
} |
|||
|
|||
cipher, err := ss.NewCipher(method, password) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
sc, err := ss.DialWithRawAddrConn(rawaddr, conn, cipher) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
conn = gost.ShadowConn(sc) |
|||
|
|||
case "socks", "socks5": |
|||
host, port, err := net.SplitHostPort(addr) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
p, _ := strconv.Atoi(port) |
|||
req := gosocks5.NewRequest(gosocks5.CmdConnect, &gosocks5.Addr{ |
|||
Type: gosocks5.AddrDomain, |
|||
Host: host, |
|||
Port: uint16(p), |
|||
}) |
|||
if err := req.Write(conn); err != nil { |
|||
return nil, err |
|||
} |
|||
log.Log("[socks5]", req) |
|||
|
|||
reply, err := gosocks5.ReadReply(conn) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
log.Log("[socks5]", reply) |
|||
if reply.Rep != gosocks5.Succeeded { |
|||
return nil, errors.New("Service unavailable") |
|||
} |
|||
|
|||
case "socks4", "socks4a": |
|||
atype := gosocks4.AddrDomain |
|||
host, port, err := net.SplitHostPort(addr) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
p, _ := strconv.Atoi(port) |
|||
|
|||
if protocol == "socks4" { |
|||
taddr, err := net.ResolveTCPAddr("tcp4", addr) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
host = taddr.IP.String() |
|||
p = taddr.Port |
|||
atype = gosocks4.AddrIPv4 |
|||
} |
|||
req := gosocks4.NewRequest(gosocks4.CmdConnect, |
|||
&gosocks4.Addr{Type: atype, Host: host, Port: uint16(p)}, nil) |
|||
if err := req.Write(conn); err != nil { |
|||
return nil, err |
|||
} |
|||
log.Logf("[%s] %s", protocol, req) |
|||
|
|||
reply, err := gosocks4.ReadReply(conn) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
log.Logf("[%s] %s", protocol, reply) |
|||
|
|||
if reply.Code != gosocks4.Granted { |
|||
return nil, fmt.Errorf("%s: code=%d", protocol, reply.Code) |
|||
} |
|||
case "http": |
|||
fallthrough |
|||
default: |
|||
req := &http.Request{ |
|||
Method: http.MethodConnect, |
|||
URL: &url.URL{Host: addr}, |
|||
Host: addr, |
|||
ProtoMajor: 1, |
|||
ProtoMinor: 1, |
|||
Header: make(http.Header), |
|||
} |
|||
req.Header.Set("Proxy-Connection", "keep-alive") |
|||
users := c.options.Users |
|||
if len(users) > 0 { |
|||
user := users[0] |
|||
s := user.String() |
|||
if _, set := user.Password(); !set { |
|||
s += ":" |
|||
} |
|||
req.Header.Set("Proxy-Authorization", |
|||
"Basic "+base64.StdEncoding.EncodeToString([]byte(s))) |
|||
} |
|||
if err := req.Write(conn); err != nil { |
|||
return nil, err |
|||
} |
|||
//if glog.V(LDEBUG) {
|
|||
dump, _ := httputil.DumpRequest(req, false) |
|||
log.Log(string(dump)) |
|||
//}
|
|||
|
|||
resp, err := http.ReadResponse(bufio.NewReader(conn), req) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
//if glog.V(LDEBUG) {
|
|||
dump, _ = httputil.DumpResponse(resp, false) |
|||
log.Log(string(dump)) |
|||
//}
|
|||
if resp.StatusCode != http.StatusOK { |
|||
return nil, fmt.Errorf("%d %s", resp.StatusCode, resp.Status) |
|||
} |
|||
} |
|||
|
|||
return conn, nil |
|||
} |
|||
Loading…
Reference in new issue