mirror of
https://github.com/wweir/sower.git
synced 2024-04-21 12:42:15 +00:00
support use socks5 as upstream proxy
This commit is contained in:
+3
-3
@@ -26,9 +26,9 @@ var (
|
||||
|
||||
conf = struct {
|
||||
Remote struct {
|
||||
Type string `default:"sower" required:"true" usage:"remote proxy protocol, sower/trojan"`
|
||||
Addr string `required:"true" usage:"remote proxy address, eg: proxy.com"`
|
||||
Password string `required:"true" usage:"remote proxy password"`
|
||||
Type string `default:"sower" required:"true" usage:"remote proxy protocol, optional: sower/trojan/socks5"`
|
||||
Addr string `required:"true" usage:"remote proxy address, eg: proxy.com/127.0.0.1:7890"`
|
||||
Password string `usage:"remote proxy password"`
|
||||
}
|
||||
|
||||
DNS struct {
|
||||
|
||||
+47
-10
@@ -12,22 +12,37 @@ import (
|
||||
"github.com/wweir/sower/pkg/teeconn"
|
||||
"github.com/wweir/sower/router"
|
||||
"github.com/wweir/sower/transport"
|
||||
"github.com/wweir/sower/transport/socks5"
|
||||
"github.com/wweir/sower/transport/sower"
|
||||
"github.com/wweir/sower/transport/trojan"
|
||||
"github.com/wweir/sower/util"
|
||||
)
|
||||
|
||||
func GenProxyDial(proxyType, proxyHost, proxyPassword string) router.ProxyDialFn {
|
||||
var (
|
||||
proxyAddr = net.JoinHostPort(proxyHost, "443")
|
||||
tlsCfg = &tls.Config{}
|
||||
proxy transport.Transport
|
||||
)
|
||||
var proxy transport.Transport
|
||||
var dialFn func() (net.Conn, error)
|
||||
|
||||
switch conf.Remote.Type {
|
||||
case "sower":
|
||||
proxy = sower.New(conf.Remote.Password)
|
||||
tlsCfg := &tls.Config{}
|
||||
dialFn = func() (net.Conn, error) {
|
||||
return tls.Dial("tcp", net.JoinHostPort(proxyHost, "443"), tlsCfg)
|
||||
}
|
||||
|
||||
case "trojan":
|
||||
proxy = trojan.New(conf.Remote.Password)
|
||||
tlsCfg := &tls.Config{}
|
||||
dialFn = func() (net.Conn, error) {
|
||||
return tls.Dial("tcp", net.JoinHostPort(proxyHost, "443"), tlsCfg)
|
||||
}
|
||||
|
||||
case "socks5":
|
||||
proxy = socks5.New()
|
||||
dialFn = func() (net.Conn, error) {
|
||||
return net.Dial("tcp", proxyHost)
|
||||
}
|
||||
|
||||
default:
|
||||
log.Fatal().
|
||||
Str("type", conf.Remote.Type).
|
||||
@@ -39,16 +54,17 @@ func GenProxyDial(proxyType, proxyHost, proxyPassword string) router.ProxyDialFn
|
||||
return nil, errors.Errorf("invalid addr(%s:%d)", host, port)
|
||||
}
|
||||
|
||||
c, err := tls.Dial("tcp", proxyAddr, tlsCfg)
|
||||
conn, err := dialFn()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := proxy.Wrap(c, host, port); err != nil {
|
||||
if err := proxy.Wrap(conn, host, port); err != nil {
|
||||
conn.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return c, nil
|
||||
return conn, nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,7 +98,7 @@ func ServeHTTP(ln net.Listener, r *router.Router) {
|
||||
|
||||
teeconn.Stop().Reread()
|
||||
util.Relay(teeconn, rc)
|
||||
log.Info().
|
||||
log.Debug().
|
||||
Str("host", req.Host).
|
||||
Dur("spend", time.Since(start)).
|
||||
Msg("serve http")
|
||||
@@ -119,8 +135,29 @@ func ServeHTTPS(ln net.Listener, r *router.Router) {
|
||||
|
||||
teeconn.Stop().Reread()
|
||||
util.Relay(teeconn, rc)
|
||||
log.Info().
|
||||
log.Debug().
|
||||
Str("host", domain).
|
||||
Dur("spend", time.Since(start)).
|
||||
Msg("serve http")
|
||||
}
|
||||
|
||||
func ServeSocks5(ln net.Listener, r *router.Router) {
|
||||
conn, err := ln.Accept()
|
||||
if err != nil {
|
||||
log.Fatal().Err(err).
|
||||
Msg("serve socks5")
|
||||
}
|
||||
go ServeSocks5(ln, r)
|
||||
defer conn.Close()
|
||||
|
||||
addr, err := socks5.New().Unwrap(conn)
|
||||
if err != nil {
|
||||
log.Warn().Err(err).
|
||||
Str("addr", addr.String()).
|
||||
Msg("parse socks5 target")
|
||||
return
|
||||
}
|
||||
|
||||
host, port := addr.(*socks5.AddrHead).Addr()
|
||||
r.RouteHandle(conn, host, port)
|
||||
}
|
||||
|
||||
+2
-2
@@ -109,7 +109,7 @@ func serve443(ln net.Listener, fakeSite string, sower *sower.Sower, trojan *troj
|
||||
defer teeconn.Close()
|
||||
|
||||
teeconn.Reread()
|
||||
if addr := sower.Unwrap(teeconn); addr != nil {
|
||||
if addr, err := sower.Unwrap(teeconn); err == nil {
|
||||
teeconn.Stop()
|
||||
|
||||
dur, err := util.RelayTo(teeconn, addr.String())
|
||||
@@ -121,7 +121,7 @@ func serve443(ln net.Listener, fakeSite string, sower *sower.Sower, trojan *troj
|
||||
}
|
||||
|
||||
teeconn.Reread()
|
||||
if addr := trojan.Unwrap(teeconn); addr != nil {
|
||||
if addr, err := trojan.Unwrap(teeconn); err == nil {
|
||||
teeconn.Stop()
|
||||
|
||||
dur, err := util.RelayTo(teeconn, addr.String())
|
||||
|
||||
@@ -4,7 +4,6 @@ go 1.16
|
||||
|
||||
require (
|
||||
github.com/cristalhq/aconfig v0.16.2
|
||||
github.com/cristalhq/aconfig/aconfigdotenv v0.16.1
|
||||
github.com/cristalhq/aconfig/aconfighcl v0.16.1
|
||||
github.com/cristalhq/aconfig/aconfigtoml v0.16.1
|
||||
github.com/cristalhq/aconfig/aconfigyaml v0.16.1
|
||||
|
||||
@@ -4,8 +4,6 @@ github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSV
|
||||
github.com/cristalhq/aconfig v0.16.1/go.mod h1:NXaRp+1e6bkO4dJn+wZ71xyaihMDYPtCSvEhMTm/H3E=
|
||||
github.com/cristalhq/aconfig v0.16.2 h1:cN+y3rtHyK9ar7NRiY4E+USs07P2qnZnGeZfNzXoV2g=
|
||||
github.com/cristalhq/aconfig v0.16.2/go.mod h1:NXaRp+1e6bkO4dJn+wZ71xyaihMDYPtCSvEhMTm/H3E=
|
||||
github.com/cristalhq/aconfig/aconfigdotenv v0.16.1 h1:nsybrhIghZ2y0hQAijDlqih7KYgs03UujQ+GcyButLc=
|
||||
github.com/cristalhq/aconfig/aconfigdotenv v0.16.1/go.mod h1:VQMzt9eS0Zlxwsuf/zkJuk1oZLm72cjpAkEkMrpbOm0=
|
||||
github.com/cristalhq/aconfig/aconfighcl v0.16.1 h1:RiziovFKOwB6+H1LCD7DXxrFgoKDEJxxYLSsAOsj+vQ=
|
||||
github.com/cristalhq/aconfig/aconfighcl v0.16.1/go.mod h1:YvZyVGtty/7yIdyOPPl68u7ENaUMq6ybZAph+n3g4II=
|
||||
github.com/cristalhq/aconfig/aconfigtoml v0.16.1 h1:q9DJfJqdLvZj7vL3bOIR6QM0ySpA0i6X8CZ8FNob6nc=
|
||||
@@ -18,8 +16,6 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
|
||||
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
|
||||
github.com/krolaw/dhcp4 v0.0.0-20190909130307-a50d88189771 h1:t2c2B9g1ZVhMYduqmANSEGVD3/1WlsrEYNPtVoFlENk=
|
||||
github.com/krolaw/dhcp4 v0.0.0-20190909130307-a50d88189771/go.mod h1:0AqAH3ZogsCrvrtUpvc6EtVKbc3w6xwZhkvGLuqyi3o=
|
||||
github.com/libp2p/go-reuseport v0.0.2 h1:XSG94b1FJfGA01BUrT82imejHQyTxO4jEWqheyCXYvU=
|
||||
|
||||
+4
-4
@@ -24,11 +24,11 @@ type Router struct {
|
||||
accessCache *mem.Cache
|
||||
|
||||
dns struct {
|
||||
dns.Client
|
||||
fallbackDNS string
|
||||
serveIP net.IP
|
||||
dns.Client
|
||||
connCh chan *dns.Conn
|
||||
cache *mem.Cache
|
||||
connCh chan *dns.Conn
|
||||
cache *mem.Cache
|
||||
}
|
||||
|
||||
country struct {
|
||||
@@ -102,7 +102,7 @@ func (r *Router) RouteHandle(conn net.Conn, domain string, port uint16) (err err
|
||||
Str("domain", domain).
|
||||
Uint16("port", port).
|
||||
Dur("spend", time.Since(start)).
|
||||
Msg("RouteHandle")
|
||||
Msg("serve socks5")
|
||||
}()
|
||||
|
||||
addr := net.JoinHostPort(domain, strconv.FormatUint(uint64(port), 10))
|
||||
|
||||
@@ -1,84 +1,21 @@
|
||||
package main
|
||||
package socks5
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"io"
|
||||
"net"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/wweir/sower/router"
|
||||
)
|
||||
|
||||
func ServeSocks5(ln net.Listener, r *router.Router) {
|
||||
conn, err := ln.Accept()
|
||||
if err != nil {
|
||||
log.Fatal().Err(err).
|
||||
Msg("serve socks5")
|
||||
}
|
||||
go ServeSocks5(ln, r)
|
||||
defer conn.Close()
|
||||
|
||||
{
|
||||
auth := new(socks5AuthReq)
|
||||
if err := auth.Fulfill(conn); err != nil {
|
||||
log.Error().Err(err).
|
||||
Interface("request", auth).
|
||||
Msg("socks5 auth")
|
||||
return
|
||||
}
|
||||
|
||||
if err := binary.Write(conn, binary.BigEndian, socks5AuthResp); err != nil {
|
||||
log.Error().Err(err).
|
||||
Msg("socks5 auth")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
var addr addrType
|
||||
{
|
||||
head := new(socks5HeadReq)
|
||||
if err := binary.Read(conn, binary.BigEndian, head); err != nil || !head.IsValid() {
|
||||
return
|
||||
}
|
||||
switch head.ATYP {
|
||||
case 0x01: // IPv4
|
||||
addr = &addrTypeIPv4{}
|
||||
case 0x03: // domain name
|
||||
addr = &addrTypeDomain{}
|
||||
case 0x04: // IPv6
|
||||
addr = &addrTypeIPv6{}
|
||||
default:
|
||||
log.Error().Err(err).
|
||||
Interface("head", head).
|
||||
Msg("socks5 connect")
|
||||
return
|
||||
}
|
||||
|
||||
if err := addr.Fulfill(conn); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err := binary.Write(conn, binary.BigEndian, socks5HeadResp); err != nil {
|
||||
log.Error().Err(err).
|
||||
Msg("socks5 head")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
host, port := addr.Addr()
|
||||
r.RouteHandle(conn, host, port)
|
||||
}
|
||||
|
||||
/******************* https://tools.ietf.org/html/rfc1928 *******************/
|
||||
// https://tools.ietf.org/html/rfc1928
|
||||
|
||||
// 1. client send auth request
|
||||
type socks5AuthReq struct {
|
||||
type authReq struct {
|
||||
VER byte
|
||||
NMETHODS uint8
|
||||
METHODS []byte
|
||||
}
|
||||
|
||||
func (req *socks5AuthReq) Fulfill(r io.Reader) error {
|
||||
func (req *authReq) Fulfill(r io.Reader) error {
|
||||
buf := make([]byte, 2)
|
||||
if n, err := r.Read(buf); err != nil || n != 2 {
|
||||
return err
|
||||
@@ -95,39 +32,37 @@ func (req *socks5AuthReq) Fulfill(r io.Reader) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *socks5AuthReq) IsValid() bool {
|
||||
func (r *authReq) IsValid() bool {
|
||||
return r.VER == 5 && r.METHODS[0] == 0
|
||||
}
|
||||
|
||||
// 2. server response auth request
|
||||
var socks5AuthResp = struct {
|
||||
type authResp struct {
|
||||
VER byte
|
||||
METHOD byte
|
||||
}{VER: 5, METHOD: 0}
|
||||
}
|
||||
|
||||
// 3. client request with target address
|
||||
type socks5HeadReq struct {
|
||||
type reqHead struct {
|
||||
VER byte
|
||||
CMD byte
|
||||
RSV byte
|
||||
ATYP byte
|
||||
}
|
||||
|
||||
func (r *socks5HeadReq) IsValid() bool {
|
||||
func (r *reqHead) IsValid() bool {
|
||||
return r.VER == 5 && r.CMD == 1
|
||||
}
|
||||
|
||||
// 4. server response with the address that assigned to connect to target address
|
||||
var socks5HeadResp = struct {
|
||||
VER byte
|
||||
REP byte
|
||||
RSV byte
|
||||
ATYP byte
|
||||
BIND struct {
|
||||
ADDR [4]byte
|
||||
PORT uint16
|
||||
}
|
||||
}{VER: 5, REP: 0, RSV: 0, ATYP: 1}
|
||||
type respHead struct {
|
||||
VER byte
|
||||
REP byte
|
||||
RSV byte
|
||||
ATYP byte
|
||||
BND_ADDR [net.IPv4len]byte
|
||||
BND_PORT uint16
|
||||
}
|
||||
|
||||
type addrType interface {
|
||||
Fulfill(r io.Reader) error
|
||||
@@ -150,18 +85,6 @@ func (a *addrTypeIPv4) Addr() (string, uint16) {
|
||||
return net.IP(a.DST_ADDR[:]).String(), a.DST_PORT
|
||||
}
|
||||
|
||||
type addrTypeIPv6 struct {
|
||||
DST_ADDR [16]byte
|
||||
DST_PORT uint16
|
||||
}
|
||||
|
||||
func (a *addrTypeIPv6) Fulfill(r io.Reader) error {
|
||||
return binary.Read(r, binary.BigEndian, &a)
|
||||
}
|
||||
func (a *addrTypeIPv6) Addr() (string, uint16) {
|
||||
return net.IP(a.DST_ADDR[:]).String(), a.DST_PORT
|
||||
}
|
||||
|
||||
type addrTypeDomain struct {
|
||||
DST_ADDR_LEN uint8
|
||||
DST_ADDR []byte
|
||||
@@ -188,3 +111,15 @@ func (a *addrTypeDomain) Fulfill(r io.Reader) error {
|
||||
func (a *addrTypeDomain) Addr() (string, uint16) {
|
||||
return string(a.DST_ADDR[:]), a.DST_PORT
|
||||
}
|
||||
|
||||
type addrTypeIPv6 struct {
|
||||
DST_ADDR [16]byte
|
||||
DST_PORT uint16
|
||||
}
|
||||
|
||||
func (a *addrTypeIPv6) Fulfill(r io.Reader) error {
|
||||
return binary.Read(r, binary.BigEndian, &a)
|
||||
}
|
||||
func (a *addrTypeIPv6) Addr() (string, uint16) {
|
||||
return net.IP(a.DST_ADDR[:]).String(), a.DST_PORT
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
package socks5
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"net"
|
||||
"strconv"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type AddrHead struct {
|
||||
addrType
|
||||
}
|
||||
|
||||
func (h *AddrHead) Network() string { return "tcp" }
|
||||
func (h *AddrHead) String() string {
|
||||
host, port := h.Addr()
|
||||
return net.JoinHostPort(host, strconv.Itoa(int(port)))
|
||||
}
|
||||
|
||||
// Socks5 is a SOCKS5 proxy. It implements the teeconn.Conn interface.
|
||||
// It is used to be a second relay of other proxy tools.
|
||||
// user -> sower -socks5-> third-party proxy -> target
|
||||
type Socks5 struct {
|
||||
}
|
||||
|
||||
func New() *Socks5 {
|
||||
return &Socks5{}
|
||||
}
|
||||
|
||||
var noAuthResp = authResp{VER: 5, METHOD: 0}
|
||||
var succHeadResp = respHead{VER: 5, REP: 0, RSV: 0, ATYP: 1}
|
||||
|
||||
func (s *Socks5) Unwrap(conn net.Conn) (net.Addr, error) {
|
||||
{
|
||||
auth := new(authReq)
|
||||
if err := auth.Fulfill(conn); err != nil && !auth.IsValid() {
|
||||
return nil, errors.Wrap(err, "read auth")
|
||||
}
|
||||
|
||||
if err := binary.Write(conn, binary.BigEndian, noAuthResp); err != nil {
|
||||
return nil, errors.Wrap(err, "write auth")
|
||||
}
|
||||
}
|
||||
|
||||
var addr addrType
|
||||
{
|
||||
head := new(reqHead)
|
||||
if err := binary.Read(conn, binary.BigEndian, head); err != nil || !head.IsValid() {
|
||||
return nil, errors.Wrap(err, "read head")
|
||||
}
|
||||
switch head.ATYP {
|
||||
case 0x01: // IPv4
|
||||
addr = &addrTypeIPv4{}
|
||||
case 0x03: // domain name
|
||||
addr = &addrTypeDomain{}
|
||||
case 0x04: // IPv6
|
||||
addr = &addrTypeIPv6{}
|
||||
default:
|
||||
return nil, errors.New("invalid ATYP")
|
||||
}
|
||||
|
||||
if err := addr.Fulfill(conn); err != nil {
|
||||
return nil, errors.Wrap(err, "read target")
|
||||
}
|
||||
|
||||
if err := binary.Write(conn, binary.BigEndian, succHeadResp); err != nil {
|
||||
return nil, errors.Wrap(err, "write head")
|
||||
}
|
||||
}
|
||||
|
||||
return &AddrHead{
|
||||
addrType: addr,
|
||||
}, nil
|
||||
}
|
||||
|
||||
var noAuthReq = struct {
|
||||
VER byte
|
||||
NMETHODS uint8
|
||||
METHODS byte
|
||||
}{5, 1, 0}
|
||||
var domainHead = reqHead{VER: 5, CMD: 1, RSV: 0, ATYP: 0x03}
|
||||
|
||||
func (s *Socks5) Wrap(conn net.Conn, tgtHost string, tgtPort uint16) error {
|
||||
{
|
||||
if err := binary.Write(conn, binary.BigEndian, &noAuthReq); err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
resp := &authResp{}
|
||||
if err := binary.Read(conn, binary.BigEndian, resp); err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
buf := bytes.NewBuffer(make([]byte, 0, binary.Size(domainHead)+1+len(tgtHost)+2))
|
||||
_ = binary.Write(buf, binary.BigEndian, domainHead)
|
||||
buf.WriteByte(uint8(len(tgtHost)))
|
||||
buf.WriteString(tgtHost)
|
||||
buf.Write([]byte{byte(tgtPort >> 8), byte(tgtPort)})
|
||||
|
||||
if _, err := conn.Write(buf.Bytes()); err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
head := respHead{}
|
||||
if err := binary.Read(conn, binary.BigEndian, &head); err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
"net"
|
||||
"strconv"
|
||||
|
||||
"github.com/wweir/sower/pkg/teeconn"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// https://en.wikipedia.org/wiki/Domain_Name_System
|
||||
@@ -41,10 +41,10 @@ func New(password string) *Sower {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Sower) Unwrap(conn *teeconn.Conn) net.Addr {
|
||||
func (s *Sower) Unwrap(conn net.Conn) (net.Addr, error) {
|
||||
buf := make([]byte, headSize)
|
||||
if n, err := conn.Read(buf); err != nil || n != headSize {
|
||||
return nil
|
||||
return nil, errors.Wrap(err, "read head")
|
||||
}
|
||||
|
||||
h := &Head{}
|
||||
@@ -52,14 +52,14 @@ func (s *Sower) Unwrap(conn *teeconn.Conn) net.Addr {
|
||||
switch h.Cmd {
|
||||
case 0x80:
|
||||
default:
|
||||
return nil
|
||||
return nil, errors.Errorf("invalid command: %d", h.Cmd)
|
||||
}
|
||||
|
||||
if h.Checksum != sumChecksum(h.TgtAddr, s.password) {
|
||||
return nil
|
||||
return nil, errors.New("auth fail")
|
||||
}
|
||||
|
||||
return h
|
||||
return h, nil
|
||||
}
|
||||
|
||||
func (s *Sower) Wrap(conn net.Conn, tgtHost string, tgtPort uint16) error {
|
||||
|
||||
@@ -2,11 +2,9 @@ package transport
|
||||
|
||||
import (
|
||||
"net"
|
||||
|
||||
"github.com/wweir/sower/pkg/teeconn"
|
||||
)
|
||||
|
||||
type Transport interface {
|
||||
Unwrap(conn *teeconn.Conn) net.Addr
|
||||
Unwrap(conn net.Conn) (net.Addr, error)
|
||||
Wrap(conn net.Conn, tgtHost string, tgtPort uint16) error
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ func init() {
|
||||
log.Logger = log.Logger.With().Caller().Logger()
|
||||
}
|
||||
|
||||
func testPipe(tran Transport) net.Addr {
|
||||
func testPipe(tran Transport) (net.Addr, error) {
|
||||
r, w := net.Pipe()
|
||||
defer r.Close()
|
||||
|
||||
@@ -28,11 +28,11 @@ func testPipe(tran Transport) net.Addr {
|
||||
}
|
||||
|
||||
func Test_Transports(t *testing.T) {
|
||||
if addr := testPipe(newSower()); addr == nil || strings.TrimSpace(addr.String()) != "sower:443" {
|
||||
if addr, err := testPipe(newSower()); err != nil || strings.TrimSpace(addr.String()) != "sower:443" {
|
||||
t.Errorf("test sower, unexpected address: %s", addr)
|
||||
}
|
||||
|
||||
if addr := testPipe(newTrojan()); addr == nil || strings.TrimSpace(addr.String()) != "sower:443" {
|
||||
if addr, err := testPipe(newTrojan()); err != nil || strings.TrimSpace(addr.String()) != "sower:443" {
|
||||
t.Errorf("test trojan, unexpected address: %s", addr)
|
||||
}
|
||||
}
|
||||
|
||||
+11
-18
@@ -10,7 +10,6 @@ import (
|
||||
"strconv"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/wweir/sower/pkg/teeconn"
|
||||
)
|
||||
|
||||
// +-----------------------+---------+----------------+---------+----------+
|
||||
@@ -110,47 +109,41 @@ func New(password string) *Trojan {
|
||||
return t
|
||||
}
|
||||
|
||||
func (t *Trojan) Unwrap(conn *teeconn.Conn) net.Addr {
|
||||
func (t *Trojan) Unwrap(conn net.Conn) (net.Addr, error) {
|
||||
buf := make([]byte, headLen)
|
||||
// do not use io.ReadFull to avoid hang
|
||||
if n, err := conn.Read(buf); err != nil || n != headLen {
|
||||
return nil
|
||||
return nil, errors.Wrap(err, "read head")
|
||||
}
|
||||
|
||||
head := &staticHead{}
|
||||
if err := binary.Read(bytes.NewBuffer(buf), binary.BigEndian, head); err != nil {
|
||||
return nil
|
||||
return nil, errors.Wrap(err, "read head")
|
||||
}
|
||||
|
||||
if !bytes.Equal(head.Passwd[:], []byte(t.headPasswd)) {
|
||||
return nil
|
||||
return nil, errors.New("auth fail")
|
||||
}
|
||||
|
||||
head.CMD, head.ATYP = buf[58], buf[59]
|
||||
switch head.ATYP {
|
||||
case 0x01: //ipv4
|
||||
addr := &ipv4Addr{}
|
||||
if err := binary.Read(conn, binary.BigEndian, addr); err != nil {
|
||||
return nil
|
||||
}
|
||||
return addr
|
||||
err := binary.Read(conn, binary.BigEndian, addr)
|
||||
return addr, errors.Wrap(err, "read addr")
|
||||
|
||||
case 0x04: //ipv6
|
||||
addr := &ipv6Addr{}
|
||||
if err := binary.Read(conn, binary.BigEndian, addr); err != nil {
|
||||
return nil
|
||||
}
|
||||
return addr
|
||||
err := binary.Read(conn, binary.BigEndian, addr)
|
||||
return addr, errors.Wrap(err, "read addr")
|
||||
|
||||
case 0x03: // domain
|
||||
addr := &domain{}
|
||||
if err := addr.Fulfill(conn); err != nil {
|
||||
return nil
|
||||
}
|
||||
return addr
|
||||
err := addr.Fulfill(conn)
|
||||
return addr, errors.Wrap(err, "read addr")
|
||||
|
||||
default:
|
||||
return nil
|
||||
return nil, errors.New("invalid ATYP")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user