diff --git a/go.mod b/go.mod index a3c7bd75a48d4c3521ba84ca9c635c394e17317b..4d44b63ac4877447a3d32941931a9dcf07146387 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.22 toolchain go1.22.2 require ( - 0xacab.org/leap/obfsvpn v0.0.0-20240422180703-83037b24d5cc + 0xacab.org/leap/obfsvpn v1.0.1-0.20240625123757-59f234eea051 git.torproject.org/pluggable-transports/goptlib.git v1.3.0 git.torproject.org/pluggable-transports/snowflake.git v1.1.0 github.com/ProtonMail/go-autostart v0.0.0-20210130080809-00ed301c8e9a @@ -16,7 +16,7 @@ require ( github.com/pion/webrtc/v3 v3.2.24 github.com/sevlyar/go-daemon v0.1.6 github.com/smartystreets/goconvey v1.6.4 - github.com/xtaci/kcp-go/v5 v5.6.1 + github.com/xtaci/kcp-go/v5 v5.6.3 github.com/xtaci/smux v1.5.24 // Do not update obfs4 past e330d1b7024b, a backwards incompatible change was // made that will break negotiation!! riseup should move to the newest asap. @@ -56,7 +56,6 @@ require ( github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/jtolds/gls v4.20.0+incompatible // indirect - github.com/kalikaneko/socks5 v1.0.1 // indirect github.com/klauspost/compress v1.16.6 // indirect github.com/klauspost/cpuid/v2 v2.2.6 // indirect github.com/klauspost/reedsolomon v1.12.1 // indirect diff --git a/go.sum b/go.sum index 9a9a8a31c0c9b9b9c57f578f7a03c573373692a4..56ee93566c595d06fa0166df3a1e84205ae9875c 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ 0xacab.org/leap/bitmask-core v0.0.0-20240529192952-8ea2f4de269e h1:dg8K5g8gpWYh8GfJPJKlSF6twnjFa4Ui9FMEahAf3jw= 0xacab.org/leap/bitmask-core v0.0.0-20240529192952-8ea2f4de269e/go.mod h1:kuAy05ISfgrZJIPj2i7lXRxRlFF8gtRy3KvYYOgMYvI= -0xacab.org/leap/obfsvpn v0.0.0-20240422180703-83037b24d5cc h1:QyADySTHZtWA81k58D/eD5aLFG2n8QaeKjIB/aMI3OU= -0xacab.org/leap/obfsvpn v0.0.0-20240422180703-83037b24d5cc/go.mod h1:cOGeSmVkgxW5qYIOSvkBeFxwBnoOYsjuQWFYB5YYlm4= +0xacab.org/leap/obfsvpn v1.0.1-0.20240625123757-59f234eea051 h1:z9sIIud8NbKW5+Qp0k6BnogK3O8CPWCN3Rx5Jbzq7bQ= +0xacab.org/leap/obfsvpn v1.0.1-0.20240625123757-59f234eea051/go.mod h1:uesfK5XkHYSgHRpE9/Bb2yKkKTE6VFViyjbU/z4ST60= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= filippo.io/edwards25519 v1.0.0/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns= @@ -262,8 +262,6 @@ github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7 github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= -github.com/kalikaneko/socks5 v1.0.1 h1:j60X3e1sAmy/LK/WtHyU3xH6uMmwlRJyc9TE3AqYDpU= -github.com/kalikaneko/socks5 v1.0.1/go.mod h1:XAMwFixakJUP0wv6pEVp6v2wx3SwhQEdL8TGDYKFAGU= github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 h1:iQTw/8FWTuc7uiaSepXwyf3o52HaUYcV+Tu66S3F5GA= github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8= github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4= @@ -563,8 +561,9 @@ github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgk github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xtaci/kcp-go v5.4.20+incompatible h1:TN1uey3Raw0sTz0Fg8GkfM0uH3YwzhnZWQ1bABv5xAg= github.com/xtaci/kcp-go v5.4.20+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45a+AZwO7eyRCmEIbtvE= -github.com/xtaci/kcp-go/v5 v5.6.1 h1:Pwn0aoeNSPF9dTS7IgiPXn0HEtaIlVb6y5UKWPsx8bI= github.com/xtaci/kcp-go/v5 v5.6.1/go.mod h1:W3kVPyNYwZ06p79dNwFWQOVFrdcBpDBsdyvK8moQrYo= +github.com/xtaci/kcp-go/v5 v5.6.3 h1:yd59SKXdJ0PBxeMBy3apalxFCEmBLGgQmL6nP46tU0g= +github.com/xtaci/kcp-go/v5 v5.6.3/go.mod h1:uIuw2KEg3FcmEdS4PeXHaGty9Ui7NYb1WKIrSDwpMg4= github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae/go.mod h1:gXtu8J62kEgmN++bm9BVICuT/e8yiLI2KFobd/TRFsE= github.com/xtaci/lossyconn v0.0.0-20200209145036-adba10fffc37 h1:EWU6Pktpas0n8lLQwDsRyZfmkPeRbdgPtW609es+/9E= github.com/xtaci/lossyconn v0.0.0-20200209145036-adba10fffc37/go.mod h1:HpMP7DB2CyokmAh4lp0EQnnWhmycP/TvwBGzvuie+H0= diff --git a/pkg/vpn/openvpn.go b/pkg/vpn/openvpn.go index 1ece141f63693a61da65a65f7ad67bf8616608e0..416774f828cbd30a2b81352beff7852ccc4814d8 100644 --- a/pkg/vpn/openvpn.go +++ b/pkg/vpn/openvpn.go @@ -30,7 +30,8 @@ import ( "0xacab.org/leap/bitmask-vpn/pkg/config" "0xacab.org/leap/bitmask-vpn/pkg/vpn/bonafide" - obfsvpn "0xacab.org/leap/obfsvpn/client" + obfsvpnClient "0xacab.org/leap/obfsvpn/client" + "0xacab.org/leap/obfsvpn/obfsvpn" ) const ( @@ -68,11 +69,32 @@ func (b *Bitmask) CanStartVPN() bool { func (b *Bitmask) startTransportForPrivateBridge(ctx context.Context, gw bonafide.Gateway) (proxy string, err error) { proxyAddr := "127.0.0.1:8080" - kcpMode := false + kcpConfig := obfsvpn.KCPConfig{ + Enabled: false, + } if os.Getenv("LEAP_KCP") == "1" { - kcpMode = true + kcpConfig = *obfsvpn.DefaultKCPConfig() + } + + obfsvpnCfg := obfsvpnClient.Config{ + ProxyAddr: proxyAddr, + HoppingConfig: obfsvpnClient.HoppingConfig{ + Enabled: false, + }, + KCPConfig: kcpConfig, + Obfs4Cert: gw.Options["cert"], + RemoteIP: gw.IPAddress, + RemotePort: gw.Ports[0], } - b.obfsvpnProxy = obfsvpn.NewClient(ctx, kcpMode, proxyAddr, gw.Options["cert"]).(*obfsvpn.Client) + log.Info().Str("OBFS4 local proxy address:", obfsvpnCfg.ProxyAddr). + Str("OBFS4 Cert:", obfsvpnCfg.Obfs4Cert). + Bool("OBFS4+KCP:", kcpConfig.Enabled). + Str("OBFS4 Hostname", gw.Host). + Str("OBFS4 IP", gw.IPAddress). + Str("OBFS4 Port:", obfsvpnCfg.RemotePort). + Msg("OBFS4 bridge connection parameters") + ctx, cancelFunc := context.WithCancel(ctx) + b.obfsvpnProxy = obfsvpnClient.NewClient(ctx, cancelFunc, obfsvpnCfg) go func() { _, err = b.obfsvpnProxy.Start() if err != nil { @@ -126,21 +148,25 @@ func (b *Bitmask) startTransport(ctx context.Context, host string) (proxy string Str("ip", gw.IPAddress). Msg("Selected Gateway") - kcpMode := false + kcpConfig := obfsvpn.KCPConfig{ + Enabled: false, + } if os.Getenv("LEAP_KCP") == "1" { - kcpMode = true + kcpConfig = *obfsvpn.DefaultKCPConfig() } - log.Debug(). - Str("host", gw.Host). - Str("ip", gw.IPAddress). - Bool("kcp", kcpMode). - Str("cert", gw.Options["cert"]). - Str("proxyAddr", proxyAddr). - Str("transport", b.transport). - Msg("Using gateway") - - b.obfsvpnProxy = obfsvpn.NewClient(ctx, kcpMode, proxyAddr, gw.Options["cert"]).(*obfsvpn.Client) + obfsvpnCfg := obfsvpnClient.Config{ + ProxyAddr: proxyAddr, + HoppingConfig: obfsvpnClient.HoppingConfig{ + Enabled: false, + }, + KCPConfig: kcpConfig, + Obfs4Cert: gw.Options["cert"], + RemoteIP: gw.IPAddress, + RemotePort: gw.Ports[0], + } + ctx, cancelFunc := context.WithCancel(ctx) + b.obfsvpnProxy = obfsvpnClient.NewClient(ctx, cancelFunc, obfsvpnCfg) go func() { _, err = b.obfsvpnProxy.Start() if err != nil { @@ -154,6 +180,14 @@ func (b *Bitmask) startTransport(ctx context.Context, host string) (proxy string Str("host", gw.Host). Msg("Connected via obfs4") }() + log.Debug(). + Str("host", gw.Host). + Str("ip", gw.IPAddress). + Bool("kcp", kcpConfig.Enabled). + Str("cert", gw.Options["cert"]). + Str("proxyAddr", proxyAddr). + Str("transport", b.transport). + Msg("Using gateway") return proxyAddr, nil } @@ -278,8 +312,7 @@ func (b *Bitmask) startOpenVPN(ctx context.Context) error { } proxyArgs := strings.Split(proxy, ":") - arg = append(arg, "--socks-proxy", proxyArgs[0], proxyArgs[1]) - arg = append(arg, "--remote", gw.IPAddress, gw.Ports[0], "tcp4") + arg = append(arg, "--remote", proxyArgs[0], proxyArgs[1], "udp") arg = append(arg, "--route", gw.IPAddress, "255.255.255.255", "net_gateway") } else { diff --git a/vendor/0xacab.org/leap/obfsvpn/client/client.go b/vendor/0xacab.org/leap/obfsvpn/client/client.go index 193b88e328ffac08d3c500e2ea226bb47b379400..ad9745fb419ad640b38471c62c6f7cd97b043f34 100644 --- a/vendor/0xacab.org/leap/obfsvpn/client/client.go +++ b/vendor/0xacab.org/leap/obfsvpn/client/client.go @@ -1,18 +1,28 @@ -// Package client exposes a socks5 proxy that uses obfs4 to communicate with the server, -// with an optional kcp wire transport. +// Package client exposes a proxy that uses obfs4 to communicate with the server, +// with an optional KCP wire transport. package client import ( "context" + "encoding/json" "errors" "fmt" "log" + "math/rand" "net" "sync" + "time" "0xacab.org/leap/obfsvpn/obfsvpn" - "github.com/kalikaneko/socks5" - "github.com/xtaci/kcp-go" +) + +type clientState string + +const ( + starting clientState = "STARTING" + running clientState = "RUNNING" + stopping clientState = "STOPPING" + stopped clientState = "STOPPED" ) var ( @@ -21,113 +31,453 @@ var ( ErrBadConfig = errors.New("configuration error") ) -type Client struct { - ctx context.Context - kcp bool - SocksAddr string - obfs4Cert string - server *socks5.Server - EventLogger EventLogger - mux sync.Mutex -} - type EventLogger interface { Log(state string, message string) Error(message string) } -func NewClient(ctx context.Context, kcp bool, socksAddr, obfs4Cert string) ObfsClient { +const ( + dialGiveUpTime = 15 * time.Second +) + +type Obfs4Config struct { + Remote string + Cert string +} + +func (oc *Obfs4Config) String() string { + return oc.Remote +} + +type Config struct { + ProxyAddr string `json:"proxy_addr"` + HoppingConfig HoppingConfig `json:"hopping_config"` + KCPConfig obfsvpn.KCPConfig `json:"kcp_config"` + RemoteIP string `json:"remote_ip"` + RemotePort string `json:"remote_port"` + Obfs4Cert string `json:"obfs4_cert"` +} + +type HoppingConfig struct { + Enabled bool `json:"enabled"` + Remotes []string `json:"remotes"` + Obfs4Certs []string `json:"obfs4_certs"` + PortSeed int64 `json:"port_seed"` + PortCount uint `json:"port_count"` + MinHopSeconds uint `json:"min_hop_seconds"` + HopJitter uint `json:"hop_jitter"` +} + +type Client struct { + kcpConfig obfsvpn.KCPConfig + ProxyAddr string + newObfs4Conn chan net.Conn + obfs4Conns []net.Conn + obfs4Endpoints []*Obfs4Config + obfs4Dialer *obfsvpn.Dialer + obfs4Failures map[string]int32 + EventLogger EventLogger + state clientState + ctx context.Context + mux sync.Mutex + stop context.CancelFunc + openvpnConn *net.UDPConn + openvpnAddr *net.UDPAddr + openvpnAddrLock sync.RWMutex + outLock sync.Mutex + hopEnabled bool + minHopSeconds uint + hopJitter uint +} + +func NewClient(ctx context.Context, stop context.CancelFunc, config Config) *Client { + obfs4Endpoints := generateObfs4Config(config) return &Client{ - ctx: ctx, - kcp: kcp, - obfs4Cert: obfs4Cert, - SocksAddr: socksAddr, + ProxyAddr: config.ProxyAddr, + hopEnabled: config.HoppingConfig.Enabled, + ctx: ctx, + hopJitter: config.HoppingConfig.HopJitter, + kcpConfig: config.KCPConfig, + obfs4Failures: map[string]int32{}, + minHopSeconds: config.HoppingConfig.MinHopSeconds, + newObfs4Conn: make(chan net.Conn), + obfs4Endpoints: obfs4Endpoints, + stop: stop, + state: stopped, + } +} + +// NewFFIClient creates a new client +// This function is exposed to the JNI and since it's not allowed to pass objects that contain slices (other than byte slices) over the JNI +// we have to pass a json formatted string and convert it to a Config struct for further processing +func NewFFIClient(jsonConfig string) (*Client, error) { + config := Config{} + err := json.Unmarshal([]byte(jsonConfig), &config) + if err != nil { + return nil, err } + ctx, stop := context.WithCancel(context.Background()) + return NewClient(ctx, stop, config), nil +} + +func generateObfs4Config(config Config) []*Obfs4Config { + obfsEndpoints := []*Obfs4Config{} + + if config.HoppingConfig.Enabled { + for i, obfs4Remote := range config.HoppingConfig.Remotes { + // We want a non-crypto RNG so that we can share a seed + // #nosec G404 + r := rand.New(rand.NewSource(config.HoppingConfig.PortSeed)) + for pi := 0; pi < int(config.HoppingConfig.PortCount); pi++ { + portOffset := r.Intn(obfsvpn.PortHopRange) + addr := net.JoinHostPort(obfs4Remote, fmt.Sprint(portOffset+obfsvpn.MinHopPort)) + obfsEndpoints = append(obfsEndpoints, &Obfs4Config{ + Cert: config.HoppingConfig.Obfs4Certs[i], + Remote: addr, + }) + } + } + } else { + addr := net.JoinHostPort(config.RemoteIP, config.RemotePort) + obfsEndpoints = append(obfsEndpoints, &Obfs4Config{ + Cert: config.Obfs4Cert, + Remote: addr, + }) + } + + log.Printf("obfs4 endpoints: %+v", obfsEndpoints) + return obfsEndpoints } func (c *Client) Start() (bool, error) { + var err error + c.mux.Lock() defer func() { - c.log("STOPPED", "") + c.updateState(stopped) + + if err != nil { + c.mux.Unlock() + } }() if c.IsStarted() { c.error("Cannot start proxy server, already running") - return false, ErrAlreadyRunning + err = ErrAlreadyRunning + return false, err } - c.server = &socks5.Server{ - Addr: c.SocksAddr, - BindIP: "127.0.0.1", + if len(c.obfs4Endpoints) == 0 { + c.error("Cannot start proxy server, no valid endpoints") + err = ErrBadConfig + return false, err } - dialer, err := obfsvpn.NewDialerFromCert(c.obfs4Cert) + c.updateState(starting) + + obfs4Endpoint := c.obfs4Endpoints[0] + + c.obfs4Dialer, err = obfsvpn.NewDialerFromCert(obfs4Endpoint.Cert) if err != nil { - c.error("Error getting dialer: %v\n", err) - return false, err + return false, fmt.Errorf("could not dial obfs4 remote: %w", err) } - switch { - case c.kcp: - dialer.DialFunc = func(network, address string) (net.Conn, error) { - c.log("RUNNING", "client.Start(): dialing kcp://%s\n", address) - return kcp.Dial(address) - } + if c.kcpConfig.Enabled { + c.obfs4Dialer.DialFunc = obfsvpn.GetKCPDialer(c.kcpConfig, c.log) + } + + obfs4Conn, err := c.obfs4Dialer.Dial("tcp", obfs4Endpoint.Remote) + if err != nil { + c.error("Could not dial obfs4 remote: %v", err) + return false, fmt.Errorf("could not dial remote: %w", err) + } + + c.obfs4Conns = []net.Conn{obfs4Conn} + + c.updateState(running) + + proxyAddr, err := net.ResolveUDPAddr("udp", c.ProxyAddr) + if err != nil { + return false, fmt.Errorf("cannot resolve UDP addr: %w", err) } - c.server.Dial = dialer.Dial + c.openvpnConn, err = net.ListenUDP("udp", proxyAddr) + if err != nil { + return false, fmt.Errorf("error accepting udp connection: %w", err) + } + + if c.hopEnabled { + go c.hop() + } - c.log("RUNNING", "[+] Starting socks5 proxy at %s\n", c.SocksAddr) + go c.readUDPWriteTCP() - errCh := make(chan error) - go c.startSocksServer(errCh) + go c.readTCPWriteUDP() c.mux.Unlock() - select { - case <-c.ctx.Done(): - return true, nil - case err := <-errCh: - c.server = nil - return false, err + <-c.ctx.Done() + + return true, nil +} + +// updateState sets a new client state, logs it and sends an event to the clients +// EventLogger in case it is available. Always set the state with this function in +// order to ensure integrating clients receive an update state event via FFI. +func (c *Client) updateState(state clientState) { + c.state = state + c.log("Update state: %v", state) +} + +// pickRandomRemote returns a random remote from the internal array. +// An obvious improvement to this function is to check the number of failures in c.obfs4Failures and avoid +// a given remote if it failed more than a threshold. A consecuence is that +// we'll have to return an unrecoverable error from hop() if there are no +// more usable remotes. If we ever want to get fancy, an even better heuristic +// can be to avoid IPs that have more failures than the average. +func (c *Client) pickRandomEndpoint() *Obfs4Config { + // #nosec G404 + i := rand.Intn(len(c.obfs4Endpoints)) + endpoint := c.obfs4Endpoints[i] + // here we could check if the number of failures is ok-ish. we can also do moving averages etc. + return endpoint +} + +func (c *Client) hop() { + for { + select { + case <-c.ctx.Done(): + return + default: + } + + // #nosec G404 + sleepSeconds := rand.Intn(int(c.hopJitter)) + int(c.minHopSeconds) + c.log("Sleeping %d seconds...", sleepSeconds) + time.Sleep(time.Duration(sleepSeconds) * time.Second) + + obfs4Endpoint := c.pickRandomEndpoint() + + host, port, err := net.SplitHostPort(obfs4Endpoint.Remote) + if err != nil { + c.error("Could not split obfs4 remote: %v", err) + continue + } + remoteAddrs, err := net.DefaultResolver.LookupHost(c.ctx, host) + if err != nil { + c.error("Could not lookup obfs4 remote: %v", err) + continue + } + + if len(remoteAddrs) <= 0 { + c.error("Could not lookup obfs4 remote: %v", err) + continue + } + + newRemote := net.JoinHostPort(remoteAddrs[0], port) + + for _, obfs4Conn := range c.obfs4Conns { + if obfs4Conn.RemoteAddr().String() == newRemote { + c.log("Not hopping to address already in obfs4Conns list: %v", newRemote) + continue + } + } + + c.log("HOPPING to %+v", newRemote) + + obfs4Dialer, err := obfsvpn.NewDialerFromCert(obfs4Endpoint.Cert) + if err != nil { + c.error("Could not dial obfs4 remote: %v", err) + return + } + + if c.kcpConfig.Enabled { + c.obfs4Dialer.DialFunc = obfsvpn.GetKCPDialer(c.kcpConfig, c.log) + } + + ctx, cancel := context.WithTimeout(context.Background(), dialGiveUpTime) + defer cancel() + + c.log("Dialing new remote: %v", newRemote) + newObfs4Conn, err := obfs4Dialer.DialContext(ctx, "tcp", newRemote) + + if err != nil { + _, ok := c.obfs4Failures[newRemote] + if ok { + c.obfs4Failures[newRemote] += 1 + } else { + c.obfs4Failures[newRemote] = 1 + } + c.error("Could not dial obfs4 remote: %v (failures: %d)", err, c.obfs4Failures[newRemote]) + } + + if newObfs4Conn == nil { + c.error("Did not get obfs4: %v ", err) + } else { + c.outLock.Lock() + c.obfs4Conns = append([]net.Conn{newObfs4Conn}, c.obfs4Conns...) + c.outLock.Unlock() + + c.newObfs4Conn <- newObfs4Conn + c.log("Dialed new remote") + + // If we wait sleepSeconds here to clean up the previous connection, we can guarantee that the + // connection list will not grow unbounded + go func() { + time.Sleep(time.Duration(sleepSeconds) * time.Second) + + c.cleanupOldConn() + }() + } } } -func (c *Client) startSocksServer(ch chan error) { - if err := c.server.ListenAndServe(); err != nil { - c.error("error while listening: %v\n", err) - ch <- err +func (c *Client) cleanupOldConn() { + c.outLock.Lock() + defer c.outLock.Unlock() + + if len(c.obfs4Conns) > 1 { + c.log("Connections: %v", len(c.obfs4Conns)) + connToClose := c.obfs4Conns[len(c.obfs4Conns)-1] + if connToClose != nil { + c.log("Cleaning up old connection to %v", connToClose.RemoteAddr()) + + err := connToClose.Close() + if err != nil { + c.log("Error closing obfs4 connection to %v: %v", connToClose.RemoteAddr(), err) + } + } + + // Remove the connection from our tracking list + c.obfs4Conns = c.obfs4Conns[:len(c.obfs4Conns)-1] } } -func (c *Client) Stop() (bool, error) { - if !c.IsStarted() { - return false, ErrNotRunning +func (c *Client) readUDPWriteTCP() { + datagramBuffer := make([]byte, obfsvpn.MaxUDPLen) + for { + select { + case <-c.ctx.Done(): + return + default: + } + + tcpBuffer, newOpenvpnAddr, err := obfsvpn.ReadUDPFrameTCP(c.openvpnConn, datagramBuffer) + if err != nil { + c.error("Read err from %v: %v", c.openvpnConn.LocalAddr(), err) + continue + } + + if newOpenvpnAddr != c.openvpnAddr { + c.openvpnAddrLock.Lock() + c.openvpnAddr = newOpenvpnAddr + c.openvpnAddrLock.Unlock() + } + + func() { + // Always write to the first connection in our list because it will be most up to date + func() { + conn, err := c.getUsableConnection() + if err != nil { + c.log("Cannot get connection: %s", err) + return + } + _, err = conn.Write(tcpBuffer) + if err != nil { + c.log("Write err from %v to %v: %v", conn.LocalAddr(), conn.RemoteAddr(), err) + return + } + }() + }() + } +} + +func (c *Client) getUsableConnection() (net.Conn, error) { + c.outLock.Lock() + defer c.outLock.Unlock() + + if len(c.obfs4Conns) == 0 { + return nil, errors.New("no usable connection") + } else { + return c.obfs4Conns[0], nil + } +} + +func (c *Client) readTCPWriteUDP() { + for { + select { + case <-c.ctx.Done(): + return + default: + } + + fromTCP := make(chan []byte, 2048) + + handleObfs4Conn := func(conn net.Conn) { + datagramBuffer := make([]byte, obfsvpn.MaxUDPLen) + lengthBuffer := make([]byte, 2) + for { + udpBuffer, err := obfsvpn.ReadTCPFrameUDP(conn, datagramBuffer, lengthBuffer) + if err != nil { + c.error("Reading/framing error: %v", err) + return + } + + fromTCP <- udpBuffer + } + } + + go func() { + for { + newObfs4Conn := <-c.newObfs4Conn + + go handleObfs4Conn(newObfs4Conn) + } + }() + + go handleObfs4Conn(c.obfs4Conns[0]) + + for { + tcpBytes := <-fromTCP + + c.openvpnAddrLock.RLock() + _, err := c.openvpnConn.WriteToUDP(tcpBytes, c.openvpnAddr) + c.openvpnAddrLock.RUnlock() + if err != nil { + c.error("Write err from %v to %v: %v", c.openvpnConn.LocalAddr(), c.openvpnConn.RemoteAddr(), err) + return + } + } } +} +func (c *Client) Stop() (bool, error) { c.mux.Lock() defer c.mux.Unlock() - if err := c.server.Close(); err != nil { - c.error("error while stopping: %v\n", err) - return false, err + if !c.IsStarted() { + return false, ErrNotRunning } - c.server = nil + c.stop() + c.openvpnConn.Close() + + c.updateState(stopped) + return true, nil } -func (c *Client) log(state string, format string, a ...interface{}) { +func (c *Client) log(format string, a ...interface{}) { if c.EventLogger != nil { - c.EventLogger.Log(state, fmt.Sprintf(format, a...)) + c.EventLogger.Log(string(c.state), fmt.Sprintf(format, a...)) return } if format == "" { - log.Print(a...) + log.Println(a...) return } - log.Printf(format, a...) + log.Printf(format+"\n", a...) } func (c *Client) error(format string, a ...interface{}) { @@ -136,12 +486,12 @@ func (c *Client) error(format string, a ...interface{}) { return } if format == "" { - log.Print(a...) + log.Println(a...) return } - log.Printf(format, a...) + log.Printf(format+"\n", a...) } func (c *Client) IsStarted() bool { - return c.server != nil + return c.state != stopped } diff --git a/vendor/0xacab.org/leap/obfsvpn/client/hopclient.go b/vendor/0xacab.org/leap/obfsvpn/client/hopclient.go deleted file mode 100644 index 2f5fbee064d84fc8f7fe925258c82967aa24f364..0000000000000000000000000000000000000000 --- a/vendor/0xacab.org/leap/obfsvpn/client/hopclient.go +++ /dev/null @@ -1,444 +0,0 @@ -// Package client exposes a socks5 proxy that uses obfs4 to communicate with the server, -// with an optional KCP wire transport. -package client - -import ( - "context" - "encoding/json" - "errors" - "fmt" - "log" - "math/rand" - "net" - "sync" - "time" - - "0xacab.org/leap/obfsvpn/obfsvpn" - "github.com/xtaci/kcp-go" -) - -type clientState string - -const ( - starting clientState = "STARTING" - running clientState = "RUNNING" - stopping clientState = "STOPPING" - stopped clientState = "STOPPED" -) - -const ( - dialGiveUpTime = 15 * time.Second -) - -type Obfs4Config struct { - Remote string - Cert string -} - -func (oc *Obfs4Config) String() string { - return oc.Remote -} - -type HoppingConfig struct { - KCP bool `json:"kcp"` - ProxyAddr string `json:"proxy_addr"` - Remotes []string `json:"remotes"` - Certs []string `json:"certs"` - PortSeed int64 `json:"port_seed"` - PortCount uint `json:"port_count"` - MinHopSeconds uint `json:"min_hop_seconds"` - HopJitter uint `json:"hop_jitter"` -} - -type HopClient struct { - kcp bool - ProxyAddr string - newObfs4Conn chan net.Conn - obfs4Conns []net.Conn - obfs4Endpoints []*Obfs4Config - obfs4Dialer *obfsvpn.Dialer - obfs4Failures map[string]int32 - EventLogger EventLogger - state clientState - ctx context.Context - stop context.CancelFunc - openvpnConn *net.UDPConn - openvpnAddr *net.UDPAddr - openvpnAddrLock sync.RWMutex - outLock sync.Mutex - minHopSeconds uint - hopJitter uint -} - -func NewHopClient(ctx context.Context, stop context.CancelFunc, config HoppingConfig) ObfsClient { - obfs4Endpoints := generateObfs4Config(config.Remotes, config.PortSeed, config.PortCount, config.Certs) - return &HopClient{ - ProxyAddr: config.ProxyAddr, - - ctx: ctx, - hopJitter: config.HopJitter, - kcp: config.KCP, - obfs4Failures: map[string]int32{}, - minHopSeconds: config.MinHopSeconds, - newObfs4Conn: make(chan net.Conn), - obfs4Endpoints: obfs4Endpoints, - stop: stop, - state: stopped, - } -} - -// NewFFIHopClient creates a new Hopping PT client -// This function is exposed to the JNI and since it's not allowed to pass objects that contain slices (other than byte slices) over the JNI -// we have to pass a json formatted string and convert it to a HoppingConfig struct for further processing -func NewFFIHopClient(hoppingConfig string) (*HopClient, error) { - config := HoppingConfig{} - err := json.Unmarshal([]byte(hoppingConfig), &config) - if err != nil { - return nil, err - } - ctx, stop := context.WithCancel(context.Background()) - return NewHopClient(ctx, stop, config).(*HopClient), nil -} - -func generateObfs4Config(remoteIPs []string, portSeed int64, portCount uint, certs []string) []*Obfs4Config { - obfsEndpoints := []*Obfs4Config{} - - for i, obfs4Remote := range remoteIPs { - // We want a non-crypto RNG so that we can share a seed - // #nosec G404 - r := rand.New(rand.NewSource(portSeed)) - for pi := 0; pi < int(portCount); pi++ { - portOffset := r.Intn(obfsvpn.PortHopRange) - addr := net.JoinHostPort(obfs4Remote, fmt.Sprint(portOffset+obfsvpn.MinHopPort)) - obfsEndpoints = append(obfsEndpoints, &Obfs4Config{ - Cert: certs[i], - Remote: addr, - }) - } - } - - log.Printf("obfs4 endpoints: %+v", obfsEndpoints) - return obfsEndpoints -} - -func (c *HopClient) Start() (bool, error) { - defer func() { - c.state = stopped - c.log("Start function ended") - }() - - if c.IsStarted() { - c.error("Cannot start proxy server, already running") - return false, ErrAlreadyRunning - } - - if len(c.obfs4Endpoints) == 0 { - c.error("Cannot start proxy server, no valid endpoints") - return false, ErrBadConfig - } - - c.state = starting - - var err error - - obfs4Endpoint := c.obfs4Endpoints[0] - - c.obfs4Dialer, err = obfsvpn.NewDialerFromCert(obfs4Endpoint.Cert) - if err != nil { - return false, fmt.Errorf("could not dial obfs4 remote: %w", err) - } - - if c.kcp { - c.obfs4Dialer.DialFunc = func(network, address string) (net.Conn, error) { - c.log("Dialing kcp://%s", address) - return kcp.Dial(address) - } - } - - obfs4Conn, err := c.obfs4Dialer.Dial("tcp", obfs4Endpoint.Remote) - if err != nil { - c.error("Could not dial obfs4 remote: %v", err) - } - - c.obfs4Conns = []net.Conn{obfs4Conn} - - c.state = running - - proxyAddr, err := net.ResolveUDPAddr("udp", c.ProxyAddr) - if err != nil { - return false, fmt.Errorf("cannot resolve UDP addr: %w", err) - } - - c.openvpnConn, err = net.ListenUDP("udp", proxyAddr) - if err != nil { - return false, fmt.Errorf("error accepting udp connection: %w", err) - } - - go c.hop() - - go c.readUDPWriteTCP() - - go c.readTCPWriteUDP() - - <-c.ctx.Done() - - return true, nil -} - -// pickRandomRemote returns a random remote from the internal array. -// An obvious improvement to this function is to check the number of failures in c.obfs4Failures and avoid -// a given remote if it failed more than a threshold. A consecuence is that -// we'll have to return an unrecoverable error from hop() if there are no -// more usable remotes. If we ever want to get fancy, an even better heuristic -// can be to avoid IPs that have more failures than the average. -func (c *HopClient) pickRandomEndpoint() *Obfs4Config { - // #nosec G404 - i := rand.Intn(len(c.obfs4Endpoints)) - endpoint := c.obfs4Endpoints[i] - // here we could check if the number of failures is ok-ish. we can also do moving averages etc. - return endpoint -} - -func (c *HopClient) hop() { - for { - select { - case <-c.ctx.Done(): - return - default: - } - - // #nosec G404 - sleepSeconds := rand.Intn(int(c.hopJitter)) + int(c.minHopSeconds) - c.log("Sleeping %d seconds...", sleepSeconds) - time.Sleep(time.Duration(sleepSeconds) * time.Second) - - obfs4Endpoint := c.pickRandomEndpoint() - - host, port, err := net.SplitHostPort(obfs4Endpoint.Remote) - if err != nil { - c.error("Could not split obfs4 remote: %v", err) - continue - } - remoteAddrs, err := net.DefaultResolver.LookupHost(c.ctx, host) - if err != nil { - c.error("Could not lookup obfs4 remote: %v", err) - continue - } - - if len(remoteAddrs) <= 0 { - c.error("Could not lookup obfs4 remote: %v", err) - continue - } - - newRemote := net.JoinHostPort(remoteAddrs[0], port) - - c.log("HOPPING to %+v", newRemote) - - obfs4Dialer, err := obfsvpn.NewDialerFromCert(obfs4Endpoint.Cert) - if err != nil { - c.error("Could not dial obfs4 remote: %v", err) - return - } - - if c.kcp { - obfs4Dialer.DialFunc = func(network, address string) (net.Conn, error) { - c.log("Dialing kcp://%s", address) - return kcp.Dial(address) - } - } - - ctx, cancel := context.WithTimeout(context.Background(), dialGiveUpTime) - defer cancel() - - c.log("Dialing new remote: %v", newRemote) - newObfs4Conn, err := obfs4Dialer.DialContext(ctx, "tcp", newRemote) - - if err != nil { - _, ok := c.obfs4Failures[newRemote] - if ok { - c.obfs4Failures[newRemote] += 1 - } else { - c.obfs4Failures[newRemote] = 1 - } - c.error("Could not dial obfs4 remote: %v (failures: %d)", err, c.obfs4Failures[newRemote]) - } - - if newObfs4Conn == nil { - c.error("Did not get obfs4: %v ", err) - } else { - c.outLock.Lock() - c.obfs4Conns = append([]net.Conn{newObfs4Conn}, c.obfs4Conns...) - c.outLock.Unlock() - - c.newObfs4Conn <- newObfs4Conn - c.log("Dialed new remote") - - // If we wait sleepSeconds here to clean up the previous connection, we can guarantee that the - // connection list will not grow unbounded - go func() { - time.Sleep(time.Duration(sleepSeconds) * time.Second) - - c.cleanupOldConn() - }() - } - } -} - -func (c *HopClient) cleanupOldConn() { - c.outLock.Lock() - defer c.outLock.Unlock() - - if len(c.obfs4Conns) > 1 { - c.log("Connections: %v", len(c.obfs4Conns)) - connToClose := c.obfs4Conns[len(c.obfs4Conns)-1] - if connToClose != nil { - c.log("Cleaning up old connection to %v", connToClose.RemoteAddr()) - - err := connToClose.Close() - if err != nil { - c.log("Error closing obfs4 connection to %v: %v", connToClose.RemoteAddr(), err) - } - } - - // Remove the connection from our tracking list - c.obfs4Conns = c.obfs4Conns[:len(c.obfs4Conns)-1] - } -} - -func (c *HopClient) readUDPWriteTCP() { - datagramBuffer := make([]byte, obfsvpn.MaxUDPLen) - for { - select { - case <-c.ctx.Done(): - return - default: - } - - tcpBuffer, newOpenvpnAddr, err := obfsvpn.ReadUDPFrameTCP(c.openvpnConn, datagramBuffer) - if err != nil { - c.error("Read err from %v: %v", c.openvpnConn.LocalAddr(), err) - continue - } - - if newOpenvpnAddr != c.openvpnAddr { - c.openvpnAddrLock.Lock() - c.openvpnAddr = newOpenvpnAddr - c.openvpnAddrLock.Unlock() - } - - func() { - // Always write to the first connection in our list because it will be most up to date - func() { - conn, err := c.getUsableConnection() - if err != nil { - c.log("Cannot get connection: %s", err) - return - } - _, err = conn.Write(tcpBuffer) - if err != nil { - c.log("Write err from %v to %v: %v", conn.LocalAddr(), conn.RemoteAddr(), err) - return - } - }() - }() - } -} - -func (c *HopClient) getUsableConnection() (net.Conn, error) { - c.outLock.Lock() - defer c.outLock.Unlock() - - if len(c.obfs4Conns) == 0 { - return nil, errors.New("no usable connection") - } else { - return c.obfs4Conns[0], nil - } -} - -func (c *HopClient) readTCPWriteUDP() { - for { - select { - case <-c.ctx.Done(): - return - default: - } - - fromTCP := make(chan []byte, 2048) - - handleObfs4Conn := func(conn net.Conn) { - datagramBuffer := make([]byte, obfsvpn.MaxUDPLen) - lengthBuffer := make([]byte, 2) - for { - udpBuffer, err := obfsvpn.ReadTCPFrameUDP(conn, datagramBuffer, lengthBuffer) - if err != nil { - c.error("Reading/framing error: %v", err) - return - } - - fromTCP <- udpBuffer - } - } - - go func() { - for { - newObfs4Conn := <-c.newObfs4Conn - - go handleObfs4Conn(newObfs4Conn) - } - }() - - go handleObfs4Conn(c.obfs4Conns[0]) - - for { - tcpBytes := <-fromTCP - - c.openvpnAddrLock.RLock() - _, err := c.openvpnConn.WriteToUDP(tcpBytes, c.openvpnAddr) - c.openvpnAddrLock.RUnlock() - if err != nil { - c.error("Write err from %v to %v: %v", c.openvpnConn.LocalAddr(), c.openvpnConn.RemoteAddr(), err) - return - } - } - } -} - -func (c *HopClient) Stop() (bool, error) { - if !c.IsStarted() { - return false, ErrNotRunning - } - - c.stop() - - c.state = stopped - - return true, nil -} - -func (c *HopClient) log(format string, a ...interface{}) { - if c.EventLogger != nil { - c.EventLogger.Log(string(c.state), fmt.Sprintf(format, a...)) - return - } - if format == "" { - log.Println(a...) - return - } - log.Printf(format+"\n", a...) -} - -func (c *HopClient) error(format string, a ...interface{}) { - if c.EventLogger != nil { - c.EventLogger.Error(fmt.Sprintf(format, a...)) - return - } - if format == "" { - log.Println(a...) - return - } - log.Printf(format+"\n", a...) -} - -func (c *HopClient) IsStarted() bool { - return c.state != stopped -} diff --git a/vendor/0xacab.org/leap/obfsvpn/client/interfaces.go b/vendor/0xacab.org/leap/obfsvpn/client/interfaces.go deleted file mode 100644 index 06174b3675c4307dd304a332c1eae84e16cedc2d..0000000000000000000000000000000000000000 --- a/vendor/0xacab.org/leap/obfsvpn/client/interfaces.go +++ /dev/null @@ -1,7 +0,0 @@ -package client - -type ObfsClient interface { - Start() (bool, error) - Stop() (bool, error) - IsStarted() bool -} diff --git a/vendor/0xacab.org/leap/obfsvpn/obfsvpn/kcp.go b/vendor/0xacab.org/leap/obfsvpn/obfsvpn/kcp.go new file mode 100644 index 0000000000000000000000000000000000000000..05c92b7b829daf9396f9dcb83e172c011cd17254 --- /dev/null +++ b/vendor/0xacab.org/leap/obfsvpn/obfsvpn/kcp.go @@ -0,0 +1,56 @@ +package obfsvpn + +import ( + "net" + + "github.com/xtaci/kcp-go/v5" +) + +const ( + DefaultKCPSendWindowSize int = 65535 + DefaultKCPReceiveWindowSize int = 65535 + DefaultKCPReadBuffer int = 16 * 1024 * 1024 + DefaultKCPWriteBuffer int = 16 * 1024 * 1024 +) + +type KCPConfig struct { + Enabled bool + SendWindowSize int + ReceiveWindowSize int + ReadBuffer int + WriteBuffer int +} + +func DefaultKCPConfig() *KCPConfig { + return &KCPConfig{ + Enabled: true, + SendWindowSize: DefaultKCPSendWindowSize, + ReceiveWindowSize: DefaultKCPReceiveWindowSize, + ReadBuffer: DefaultKCPReadBuffer, + WriteBuffer: DefaultKCPWriteBuffer, + } +} + +func GetKCPDialer(kcpConfig KCPConfig, logger func(format string, a ...interface{})) func(network, address string) (net.Conn, error) { + return func(network, address string) (net.Conn, error) { + if logger != nil { + logger("Dialing kcp://%s", address) + } + kcpSession, err := kcp.DialWithOptions(address, nil, 10, 3) + if err != nil { + return nil, err + } + kcpSession.SetStreamMode(true) + kcpSession.SetWindowSize(kcpConfig.SendWindowSize, kcpConfig.ReceiveWindowSize) + if err := kcpSession.SetReadBuffer(kcpConfig.ReadBuffer); err != nil { + return nil, err + } + if err := kcpSession.SetWriteBuffer(kcpConfig.WriteBuffer); err != nil { + return nil, err + } + // https://github.com/skywind3000/kcp/blob/master/README.en.md#protocol-configuration + kcpSession.SetNoDelay(1, 10, 2, 1) + return kcpSession, nil + } + +} diff --git a/vendor/0xacab.org/leap/obfsvpn/obfsvpn/listener.go b/vendor/0xacab.org/leap/obfsvpn/obfsvpn/listener.go index 2826cb492cd117d4955204307c6436239c05cba5..2733430da34244912165e26e29e9fbdd7bb0629e 100644 --- a/vendor/0xacab.org/leap/obfsvpn/obfsvpn/listener.go +++ b/vendor/0xacab.org/leap/obfsvpn/obfsvpn/listener.go @@ -8,22 +8,19 @@ import ( "log" "net" - "github.com/xtaci/kcp-go" + "github.com/xtaci/kcp-go/v5" "gitlab.com/yawning/obfs4.git/common/ntor" "gitlab.com/yawning/obfs4.git/transports/base" "gitlab.com/yawning/obfs4.git/transports/obfs4" pt "gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/goptlib" ) -const ( - netKCP = "kcp" -) - // ListenConfig contains options for listening to an address. // If Seed is not set it defaults to a randomized value. // If StateDir is not set the current working directory is used. type ListenConfig struct { ListenConfig net.ListenConfig + KCPConfig KCPConfig NodeID *ntor.NodeID PrivateKey *ntor.PrivateKey @@ -34,7 +31,7 @@ type ListenConfig struct { // NewListenConfig returns a ListenConfig and any error during the initialization. // perhaps this is redundant, but using the same json format than ss for debug. -func NewListenConfig(nodeIDStr, privKeyStr, pubKeyStr, seedStr, stateDir string) (*ListenConfig, error) { +func NewListenConfig(nodeIDStr, privKeyStr, pubKeyStr, seedStr, stateDir string, kcpConfig KCPConfig) (*ListenConfig, error) { var err error var seed [ntor.KeySeedLength]byte var nodeID *ntor.NodeID @@ -62,6 +59,7 @@ func NewListenConfig(nodeIDStr, privKeyStr, pubKeyStr, seedStr, stateDir string) PublicKey: pubKeyStr, Seed: seed, StateDir: stateDir, + KCPConfig: kcpConfig, } return lc, nil } @@ -119,21 +117,26 @@ func NewServerState(stateDir string) error { // Listen listens on the local network address. // See func net.Dial for a description of the network and address parameters. -func (lc *ListenConfig) Listen(ctx context.Context, network, address string) (*Listener, error) { - var ln net.Listener - var err error - switch network { - case netKCP: +func (lc *ListenConfig) Listen(ctx context.Context, kcpConfig KCPConfig, address string) (*Listener, error) { + if kcpConfig.Enabled { log.Println("kcp listen on", address) - ln, err = kcp.Listen(address) + ln, err := kcp.ListenWithOptions(address, nil, 10, 3) if err != nil { return nil, err } - default: - ln, err = lc.ListenConfig.Listen(ctx, network, address) - if err != nil { + + if err := ln.SetReadBuffer(kcpConfig.ReadBuffer); err != nil { + return nil, err + } + if err := ln.SetWriteBuffer(kcpConfig.WriteBuffer); err != nil { return nil, err } + + return lc.Wrap(ctx, ln) + } + ln, err := lc.ListenConfig.Listen(ctx, "tcp", address) + if err != nil { + return nil, err } return lc.Wrap(ctx, ln) } @@ -141,8 +144,9 @@ func (lc *ListenConfig) Listen(ctx context.Context, network, address string) (*L // Listener is a network listener that accepts obfuscated connections and // performs the ntor handshake on them. type Listener struct { - sf base.ServerFactory - ln net.Listener + sf base.ServerFactory + ln net.Listener + kcpConfig KCPConfig } // Accept waits for and returns the next connection to the listener. @@ -151,6 +155,13 @@ func (l *Listener) Accept() (net.Conn, error) { if err != nil { return nil, err } + kcpSession, ok := conn.(*kcp.UDPSession) + if ok { + kcpSession.SetStreamMode(true) + kcpSession.SetWindowSize(l.kcpConfig.SendWindowSize, l.kcpConfig.ReceiveWindowSize) + // https://github.com/skywind3000/kcp/blob/master/README.en.md#protocol-configuration + kcpSession.SetNoDelay(1, 10, 2, 1) + } conn, err = l.sf.WrapConn(conn) return conn, err } diff --git a/vendor/github.com/kalikaneko/socks5/.gitignore b/vendor/github.com/kalikaneko/socks5/.gitignore deleted file mode 100644 index acc70b4da598e264064aa9d1c749a30958c57530..0000000000000000000000000000000000000000 --- a/vendor/github.com/kalikaneko/socks5/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -main/ -.vscode/ -.idea/ \ No newline at end of file diff --git a/vendor/github.com/kalikaneko/socks5/LICENSE b/vendor/github.com/kalikaneko/socks5/LICENSE deleted file mode 100644 index 0e797b440ada83038b625f368074c55367071685..0000000000000000000000000000000000000000 --- a/vendor/github.com/kalikaneko/socks5/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -MIT License - -Copyright (c) 2021 haochen233 -Copyright (c) 2022 kali kaneko - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/vendor/github.com/kalikaneko/socks5/README.md b/vendor/github.com/kalikaneko/socks5/README.md deleted file mode 100644 index dde63b86514aca0c819eb6823b46e0af994a6680..0000000000000000000000000000000000000000 --- a/vendor/github.com/kalikaneko/socks5/README.md +++ /dev/null @@ -1,316 +0,0 @@ -# socks5 - -This is a Golang implementation of the Socks5 protocol library. -To see in this [SOCKS Protocol Version 5](https://www.rfc-editor.org/rfc/rfc1928.html). -This library is also compatible with Socks4 and Socks4a. - -# Contents - -- [Features](#Features) -- [Install](#Installation) -- [Examples](#Examples) - - [Server example](#Server-example) - - [simple (no authentication)](#simple-no-authentication) - - [username/password authentication in memory](#username/password-authentication-in-memory) - - [custom transporter to transmit data between client and remote](#custom-transporter-to-transmit-data-between-client-and-remote) - - [Client example](#Client) - - [CONNECT usage](#CONNECT-usage) - - [UDP_ASSOCIATE usage](#UDP_ASSOCIATE-usage) - - [BIND usage](#BIND-usage) -- [FAQ](#FAQ) - -# Features - -- socks5: - - command: **CONNECT**, **UDP ASSOCIATE**, **BIND**. - - auth methods: - - **Username/Password** authentication. - - No Authentication Required. -- socks4: - - command: **CONNECT**, **BIND**. - - auth: (no support). -- sock4a: same as socks4. -- Custom client and server authenticator. -- Easy to read source code. -- Similar to the Golang standard library experience. - -# Installation - -``` sh -$ go get "github.com/haochen233/socks5"` -``` - -# Examples - -## Server example - -### simple (no authentication): - -```go -package main - -import ( - "log" - "github.com/haochen233/socks5" -) - -func main() { - // create socks server. - srv := &socks5.Server{ - // socks server listen address. - Addr: "127.0.0.1:1080", - // UDP assocaite and bind command listen ip. - // Don't need port, the port will automatically chosen. - BindIP: "127.0.0.1", - // if nil server will provide no authentication required method. - Authenticators: nil, - } - - // start listen - err := srv.ListenAndServe() - if err != nil { - log.Fatal(err) - } -} - - -``` - -### username/password authentication in memory: - -```go -package main - -import ( - "crypto/md5" - "log" - - "github.com/haochen233/socks5" -) - -func main() { - // create a username/password store in memory. - var userStorage socks5.UserPwdStore = socks5.NewMemeryStore(md5.New(), "secret") - // set a pair of username/password. - userStorage.Set("admin", "123456") - - srv := &socks5.Server{ - Addr: "127.0.0.1:1080", - BindIP: "127.0.0.1", - // enable username/password method and authenticator. - Authenticators: map[socks5.METHOD]socks5.Authenticator{ - socks5.USERNAME_PASSWORD: socks5.UserPwdAuth{UserPwdStore: userStorage}, - // There is already an authentication method. - // If want enable no authentication required method. - // you should enable it explicit. - socks5.NO_AUTHENTICATION_REQUIRED: socks5.NoAuth{}, - }, - } - - err := srv.ListenAndServe() - if err != nil { - log.Fatal(err) - } -} -``` - -### custom transporter to transmit data between client and remote. - -```go -package main - -import ( - "log" - "net" - - "github.com/haochen233/socks5" -) - -// simulate to impl socks5.Transporter interface. -// transport encrypted data. -type cryptTransport struct { -} - -func (c *cryptTransport) TransportTCP(client *net.TCPConn, remote *net.TCPConn) <-chan error { - //encrypt data and send to remote - //decrypt data and send to client - return nil -} - -func (c *cryptTransport) TransportUDP(server *socks5.UDPConn, request *socks5.Request) error { - panic("implement me") - return nil -} - -func main() { - server := &socks5.Server{ - Addr: "127.0.0.1:1080", - BindIP: "127.0.0.1", - // replace default Transporter interface - Transporter: &cryptTransport{}, - } - - err := server.ListenAndServe() - if err != nil { - log.Fatal(err) - } -} -``` - -## Client example - -### CONNECT usage: - -```go -package main - -import ( - "log" - - "github.com/haochen233/socks5" -) - -func main() { - // create socks client - clnt := socks5.Client{ - ProxyAddr: "127.0.0.1:1080", - // Authenticator supported by the client. - // It must not be nil. - Auth: map[socks5.METHOD]socks5.Authenticator{ - // If client want send NO_AUTHENTICATION_REQUIRED method to server, must - // add socks5.NoAuth authenticator explicitly - socks5.NO_AUTHENTICATION_REQUIRED: &socks5.NoAuth{}, - }, - } - - // client send CONNECT command and get a tcp connection. - // and use this connection transit data between you and www.google.com:80. - conn, err := clnt.Connect(socks5.Version5, "www.baidu.com:80") - if err != nil { - log.Fatal(err) - } - - // close connection. - conn.Close() -} - -``` - -### UDP_ASSOCIATE usage: - -```go -package main - -import ( - "fmt" - "log" - - "github.com/haochen233/socks5" -) - -func main() { - clnt := socks5.Client{ - ProxyAddr: "127.0.0.1:1080", - // client provide USERNAME_PASSWORD method and - // NO_AUTHENTICATION_REQUIRED. - Auth: map[socks5.METHOD]socks5.Authenticator{ - socks5.NO_AUTHENTICATION_REQUIRED: &socks5.NoAuth{}, - socks5.USERNAME_PASSWORD: &socks5.UserPasswd{Username: "admin", Password: "123456"}, - }, - } - - // client send UDP_ASSOCIATE command and get a udp connection. - // Empty local addr string a local address (127.0.0.1:port) is automatically chosen. - // you can specific a address to tell socks server which client address will - // send udp data. Such as clnt.UDPForward("127.0.0.1:9999"). - conn, err := clnt.UDPForward("") - if err != nil { - log.Fatal(err) - } - defer conn.Close() - - // send every datagram should add UDP request header. - someData := []byte("some data") - // dest addr where are you send to. - destAddr, _ := socks5.ParseAddress("127.0.0.1:9190") - // packing socks5 UDP data with dest addr. - pakcedData, err := socks5.PackUDPData(destAddr, someData) - // final send you data - conn.Write(pakcedData) - - // on the contrary. - // you should unpacked the packet, after received every packedData. - buf := make([]byte, 65507) - conn.Read(buf) - - // unpacking data. - destAddr, unpackedData, err := socks5.UnpackUDPData(buf) - // operate your udp data. - fmt.Println(unpackedData) -} -``` - -### BIND usage: - -```go -package main - -import ( - "encoding/binary" - "github.com/haochen233/socks5" - "log" -) - -func main() { - c := socks5.Client{ - ProxyAddr: "172.16.1.28:1080", - Auth: map[socks5.METHOD]socks5.Authenticator{ - socks5.USERNAME_PASSWORD: &socks5.UserPasswd{"admin", "123456"}, - socks5.NO_AUTHENTICATION_REQUIRED: &socks5.NoAuth{}, - }, - } - - // connect - conn1, err := c.Connect(5, "127.0.0.1:9000") - if err != nil { - log.Fatal(err) - } - - dest := "127.0.0.1:9001" - // bind - bindAddr, errors, conn2, err := c.Bind(4, dest) - if err != nil { - log.Fatal(err) - } - - // An example tell dest about socks server bind address - // via CONNECT proxy connection. - port := make([]byte, 2) - binary.BigEndian.PutUint16(port, bindAddr.Port) - conn1.Write(append(bindAddr.Addr, port...)) - - // wait the second reply. if nil the dest already - // established with socks server. - err = <-errors - if err != nil { - log.Fatal(err) - return - } - - // bind success - _, err = conn2.Write([]byte("hello")) - if err != nil { - return - log.Fatal(err) - } -} -``` - -# FAQ: -- Server default enable socks4. How to disable socks4 support? - when you initialize a socks5 server, you should spefic this flag to disable explicitly. - ```go - server := &socks5.Server{ - DisableSocks4: true, - } - ``` \ No newline at end of file diff --git a/vendor/github.com/kalikaneko/socks5/address.go b/vendor/github.com/kalikaneko/socks5/address.go deleted file mode 100644 index 37f8f3349e6169c16e217bc9d02f1770b5b34169..0000000000000000000000000000000000000000 --- a/vendor/github.com/kalikaneko/socks5/address.go +++ /dev/null @@ -1,263 +0,0 @@ -package socks5 - -import ( - "bytes" - "encoding/binary" - "errors" - "fmt" - "io" - "net" - "strconv" - "sync" -) - -// Address represents address in socks protocol. -type Address struct { - Addr net.IP - ATYPE - Port uint16 -} - -var bufPool = sync.Pool{New: func() interface{} { - buf := bytes.Buffer{} - return &buf -}} - -// Address return address -// Examples: -// 127.0.0.1:80 -// example.com:443 -// [fe80::1%lo0]:80 -func (a *Address) String() string { - if a.ATYPE == DOMAINNAME { - return net.JoinHostPort(string(a.Addr), strconv.Itoa(int(a.Port))) - } - return net.JoinHostPort(a.Addr.String(), strconv.Itoa(int(a.Port))) -} - -var errDomainMaxLengthLimit = errors.New("domain name out of max length") - -// Bytes return bytes slice of Address by ver param. -// If ver is socks4, the returned socks4 address format as follows: -// +----+----+----+----+----+----+....+----+....+----+ -// | DSTPORT | DSTIP | USERID |NULL| -// +----+----+----+----+----+----+----+----+....+----+ -// If ver is socks4 and address type is domain name, -// the returned socks4 address format as follows: -// +----+----+----+----+----+----+....+----+....+----+....+----+....+----+ -// | DSTPORT | DSTIP | USERID |NULL| HOSTNAME |NULL| -// +----+----+----+----+----+----+----+----+....+----+----+----+....+----+ -// If ver is socks5 -// the returned socks5 address format as follows: -// +------+----------+----------+ -// | ATYP | DST.ADDR | DST.PORT | -// +------+----------+----------+ -// | 1 | Variable | 2 | -// +------+----------+----------+ -// Socks4 call this method return bytes end with NULL, socks4 client use normally, -// Socks4 server should trim terminative NULL. -// Socks4 server should not call this method if server address type is DOMAINNAME -func (a *Address) Bytes(ver VER) ([]byte, error) { - buf := bufPool.Get().(*bytes.Buffer) - defer buf.Reset() - defer bufPool.Put(buf) - - // port - port := make([]byte, 2) - binary.BigEndian.PutUint16(port, a.Port) - - switch ver { - case Version4: - // socks4a - buf.Write(port) - if a.ATYPE == DOMAINNAME { - buf.Write(net.IPv4(0, 0, 0, 1).To4()) - // NULL - buf.WriteByte(NULL) - // hostname - buf.Write(a.Addr) - } else if a.ATYPE == IPV4_ADDRESS { - buf.Write(a.Addr) - } else { - return nil, fmt.Errorf("socks4 unsupported address type: %#x", a.ATYPE) - } - buf.WriteByte(NULL) - case Version5: - // address type - buf.WriteByte(a.ATYPE) - // domain name address type - if a.ATYPE == DOMAINNAME { - if len(a.Addr) > 255 { - return nil, errDomainMaxLengthLimit - } - buf.WriteByte(byte(len(a.Addr))) - buf.Write(a.Addr) - } else if a.ATYPE == IPV4_ADDRESS { - buf.Write(a.Addr.To4()) - } else if a.ATYPE == IPV6_ADDRESS { - buf.Write(a.Addr.To16()) - } - buf.Write(port) - } - - return buf.Bytes(), nil -} - -// readAddress read address info from follows: -// socks5 server's reply. -// socks5 client's request. -// socks5 server's udp reply header. -// socks5 client's udp request header. -// -// socks4 client's request. -// socks4a client's request -// exclude: socks4a server's reply, socks4 server's reply. Please use readSocks4ReplyAddress. -func readAddress(r io.Reader, ver VER) (*Address, REP, error) { - addr := &Address{} - - switch ver { - case Version4: - // DST.PORT - port, err := ReadNBytes(r, 2) - if err != nil { - return nil, Rejected, &OpError{Version5, "read", nil, "client dest port", err} - } - addr.Port = binary.BigEndian.Uint16(port) - // DST.IP - ip, err := ReadNBytes(r, 4) - if err != nil { - return nil, Rejected, &OpError{Version4, "read", nil, "\"process request dest ip\"", err} - } - addr.ATYPE = IPV4_ADDRESS - - //Discard later bytes until read EOF - //Please see socks4 request format at(http://ftp.icm.edu.pl/packages/socks/socks4/SOCKS4.protocol) - _, err = ReadUntilNULL(r) - if err != nil { - return nil, Rejected, &OpError{Version4, "read", nil, "\"process request useless header \"", err} - } - - //Socks4a extension - // +----+----+----+----+----+----+----+----+----+----++----++-----+-----++----+ - // | VN | CD | DSTPORT | DSTIP | USERID |NULL| HOSTNAME |NULL| - // +----+----+----+----+----+----+----+----+----+----++----++-----+-----++----+ - // 1 1 2 4 variable 1 variable 1 - //The client sets the first three bytes of DSTIP to NULL and - //the last byte to non-zero. The corresponding IP address is - //0.0.0.x, where x is non-zero - if ip[0] == 0 && ip[1] == 0 && ip[2] == 0 && - ip[3] != 0 { - ip, err = ReadUntilNULL(r) - if err != nil { - return nil, Rejected, &OpError{Version4, "read", nil, "\"process socks4a extension request\"", err} - } - addr.ATYPE = DOMAINNAME - } - addr.Addr = ip - return addr, Granted, nil - case Version5: - // ATYP - aType, err := ReadNBytes(r, 1) - if err != nil { - return nil, GENERAL_SOCKS_SERVER_FAILURE, &OpError{Version5, "read", nil, "dest address type", err} - } - addr.ATYPE = aType[0] - - var addrLen int - switch addr.ATYPE { - case IPV4_ADDRESS: - addrLen = 4 - case IPV6_ADDRESS: - addrLen = 16 - case DOMAINNAME: - fqdnLength, err := ReadNBytes(r, 1) - if err != nil { - return nil, GENERAL_SOCKS_SERVER_FAILURE, &OpError{Version5, "read", nil, "\"dest domain name length\"", err} - } - addrLen = int(fqdnLength[0]) - default: - return nil, ADDRESS_TYPE_NOT_SUPPORTED, &OpError{Version5, "", nil, "\"dest address\"", &AtypeError{aType[0]}} - } - - // DST.ADDR - ip, err := ReadNBytes(r, addrLen) - if err != nil { - return nil, GENERAL_SOCKS_SERVER_FAILURE, err - } - addr.Addr = ip - - // DST.PORT - port, err := ReadNBytes(r, 2) - if err != nil { - return nil, GENERAL_SOCKS_SERVER_FAILURE, &OpError{Version5, "read", nil, "client dest port", err} - } - addr.Port = binary.BigEndian.Uint16(port) - return addr, SUCCESSED, nil - default: - return nil, UNASSIGNED, &VersionError{ver} - } -} - -// readSocks4ReplyAddress read socks4 reply address. Why don't use readAddress, -// because socks4 reply not end with NULL, they're not compatible -func readSocks4ReplyAddress(r io.Reader, ver VER) (*Address, REP, error) { - addr := &Address{} - - // DST.PORT - port, err := ReadNBytes(r, 2) - if err != nil { - return nil, Rejected, &OpError{Version5, "read", nil, "client dest port", err} - } - addr.Port = binary.BigEndian.Uint16(port) - // DST.IP - ip, err := ReadNBytes(r, 4) - if err != nil { - return nil, Rejected, &OpError{Version4, "read", nil, "\"process request dest ip\"", err} - } - addr.Addr = ip - addr.ATYPE = IPV4_ADDRESS - - return addr, Granted, nil -} - -// UDPAddr return UDP Address. -func (a *Address) UDPAddr() (*net.UDPAddr, error) { - return net.ResolveUDPAddr("udp", a.String()) -} - -// TCPAddr return TCP Address. -func (a *Address) TCPAddr() (*net.TCPAddr, error) { - return net.ResolveTCPAddr("tcp", a.String()) -} - -// ParseAddress parse address to *Address -// Input Examples: -// 127.0.0.1:80 -// example.com:443 -// [fe80::1%lo0]:80 -func ParseAddress(addr string) (*Address, error) { - Address := new(Address) - - host, port, err := net.SplitHostPort(addr) - if err != nil { - return nil, err - } - - ip := net.ParseIP(host) - if ip == nil { - Address.ATYPE = DOMAINNAME - Address.Addr = []byte(host) - } else if ip.To4() != nil { - Address.ATYPE = IPV4_ADDRESS - Address.Addr = ip.To4() - } else if ip.To16() != nil { - Address.ATYPE = IPV6_ADDRESS - Address.Addr = ip.To16() - } - atoi, err := strconv.Atoi(port) - if err != nil { - return nil, err - } - Address.Port = uint16(atoi) - return Address, nil -} diff --git a/vendor/github.com/kalikaneko/socks5/auth.go b/vendor/github.com/kalikaneko/socks5/auth.go deleted file mode 100644 index d8f0e98b2f3c0e8dddc97837608e24450028e6e2..0000000000000000000000000000000000000000 --- a/vendor/github.com/kalikaneko/socks5/auth.go +++ /dev/null @@ -1,165 +0,0 @@ -package socks5 - -import ( - "bytes" - "fmt" - "hash" - "io" - "sync" -) - -// Authenticator provides socks5's authentication sub negotiation. -type Authenticator interface { - Authenticate(in io.Reader, out io.Writer) error -} - -// NoAuth NO_AUTHENTICATION_REQUIRED implementation. -type NoAuth struct { -} - -// Authenticate NO_AUTHENTICATION_REQUIRED Authentication for socks5 Server and Client. -func (n NoAuth) Authenticate(in io.Reader, out io.Writer) error { - return nil -} - -// UserPwdAuth provides socks5 Server Username/Password Authenticator. -type UserPwdAuth struct { - UserPwdStore -} - -// Authenticate provide socks5 Server Username/Password authentication. -func (u UserPwdAuth) Authenticate(in io.Reader, out io.Writer) error { - uname, passwd, err := u.ReadUserPwd(in) - if err != nil { - return err - } - - err = u.Validate(string(uname), string(passwd)) - if err != nil { - reply := []byte{1, 1} - _, err1 := out.Write(reply) - if err1 != nil { - return err - } - return err - } - - //authentication successful,then send reply to client - reply := []byte{1, 0} - _, err = out.Write(reply) - if err != nil { - return err - } - - return nil -} - -// ReadUserPwd read Username/Password request from client -// return username and password. -// Username/Password request format is as follows: -// +----+------+----------+------+----------+ -// |VER | ULEN | UNAME | PLEN | PASSWD | -// +----+------+----------+------+----------+ -// | 1 | 1 | 1 to 255 | 1 | 1 to 255 | -// +----+------+----------+------+----------+ -// For standard details, please see (https://www.rfc-editor.org/rfc/rfc1929.html) -func (u UserPwdAuth) ReadUserPwd(in io.Reader) ([]byte, []byte, error) { - - ulen, err := ReadNBytes(in, 2) - if err != nil { - return nil, nil, err - } - - uname, err := ReadNBytes(in, int(ulen[1])) - if err != nil { - return nil, nil, err - } - - plen, err := ReadNBytes(in, 1) - if err != nil { - return nil, nil, err - } - - passwd := make([]byte, plen[0]) - passwd, err = ReadNBytes(in, int(plen[0])) - if err != nil { - return nil, nil, err - } - - return uname, passwd, nil -} - -// UserPwdStore provide username and password storage. -type UserPwdStore interface { - Set(username string, password string) error - Del(username string) error - Validate(username string, password string) error -} - -// MemoryStore store username&password in memory. -// the password is encrypt with hash method. -type MemoryStore struct { - Users map[string][]byte - mu sync.Mutex - hash.Hash - algoSecret string -} - -// NewMemeryStore return a new MemoryStore -func NewMemeryStore(algo hash.Hash, secret string) *MemoryStore { - return &MemoryStore{ - Users: make(map[string][]byte), - Hash: algo, - algoSecret: secret, - } -} - -// Set the mapping of username and password. -func (m *MemoryStore) Set(username string, password string) error { - m.mu.Lock() - defer m.mu.Unlock() - build := bytes.NewBuffer(nil) - build.WriteString(password + m.algoSecret) - cryptPasswd := m.Hash.Sum(build.Bytes()) - m.Users[username] = cryptPasswd - return nil -} - -// UserNotExist the error type used in UserPwdStore.Del() method and -// UserPwdStore.Validate method. -type UserNotExist struct { - username string -} - -func (u UserNotExist) Error() string { - return fmt.Sprintf("user %s don't exist", u.username) -} - -// Del delete by username -func (m *MemoryStore) Del(username string) error { - m.mu.Lock() - defer m.mu.Unlock() - if _, ok := m.Users[username]; !ok { - return UserNotExist{username: username} - } - - delete(m.Users, username) - return nil -} - -// Validate validate username and password. -func (m *MemoryStore) Validate(username string, password string) error { - m.mu.Lock() - defer m.mu.Unlock() - if _, ok := m.Users[username]; !ok { - return UserNotExist{username: username} - } - - build := bytes.NewBuffer(nil) - build.WriteString(password + m.algoSecret) - cryptPasswd := m.Hash.Sum(build.Bytes()) - if !bytes.Equal(cryptPasswd, m.Users[username]) { - return fmt.Errorf("user %s has bad password", username) - } - return nil -} diff --git a/vendor/github.com/kalikaneko/socks5/client.go b/vendor/github.com/kalikaneko/socks5/client.go deleted file mode 100644 index a2f652b1b47593356af9343817ee5e70bfb325a5..0000000000000000000000000000000000000000 --- a/vendor/github.com/kalikaneko/socks5/client.go +++ /dev/null @@ -1,542 +0,0 @@ -package socks5 - -import ( - "errors" - "fmt" - "io" - "log" - "net" - "strconv" - "time" -) - -// Client defines parameters for running socks client. -type Client struct { - // ProxyAddr in the form "host:port". It not be empty. - ProxyAddr string - - // Timeout specifies a time limit for requests made by this - // Client. The timeout includes connection time, reading the response body. - // - // A Timeout of zero means no timeout. - // - // The Client cancels requests to the underlying Transport - // as if the Request's Context ended. - Timeout time.Duration - - // method mapping to the authenticator - Auth map[METHOD]Authenticator - - // ErrorLog specifics an options logger for errors accepting - // If nil, logging is done via log package's standard logger. - ErrorLog *log.Logger - - // DisableSocks4A client disable socks4a client, default enable socks4a extension. - DisableSocks4A bool -} - -// UserPasswd provide socks5 Client Username/Password Authenticator. -type UserPasswd struct { - Username string - Password string -} - -// Authenticate socks5 Client Username/Password Authentication. -func (c *UserPasswd) Authenticate(in io.Reader, out io.Writer) error { - //This begins with the client producing a Username/Password request: - // +----+------+----------+------+----------+ - // |VER | ULEN | UNAME | PLEN | PASSWD | - // +----+------+----------+------+----------+ - // | 1 | 1 | 1 to 255 | 1 | 1 to 255 | - // +----+------+----------+------+----------+ - _, err := out.Write(append(append(append([]byte{0x01, byte(len(c.Username))}, []byte(c.Username)...), byte(len(c.Password))), []byte(c.Password)...)) - if err != nil { - return err - } - //Get reply, the following response: - - // +----+--------+ - // |VER | STATUS | - // +----+--------+ - // | 1 | 1 | - // +----+--------+ - tmp, err := ReadNBytes(in, 2) - if err != nil { - return err - } - if tmp[0] != 0x01 { - return errors.New("not support method") - } - if tmp[1] != SUCCESSED { - return errors.New("user authentication failed") - } - return nil -} - -// handshake socks TCP connect,get a tcp connect and reply addr -func (clt *Client) handshake(request *Request) (conn *net.TCPConn, replyAddr *Address, err error) { - // get Socks server Address - proxyTCPAddr, err := net.ResolveTCPAddr("tcp", clt.ProxyAddr) - if err != nil { - return nil, nil, err - } - - // dial to Socks server. - proxyTCPConn, err := net.DialTCP("tcp", nil, proxyTCPAddr) - if err != nil { - return nil, nil, err - } - if clt.Timeout != 0 { - err = proxyTCPConn.SetDeadline(time.Now().Add(clt.Timeout)) - if err != nil { - return nil, nil, err - } - defer proxyTCPConn.SetDeadline(time.Time{}) - } - - // process handshake by version - if request.VER == Version5 { - replyAddr, err = clt.handShake5(request, proxyTCPConn) - } else if request.VER == Version4 { - if request.ATYPE == DOMAINNAME && clt.DisableSocks4A { - return nil, nil, errors.New("socks4a client had been disabled") - } - replyAddr, err = clt.handshake4(request, proxyTCPConn) - } - - // handshake wrong. - if err != nil { - proxyTCPConn.Close() - return nil, nil, err - } - - return proxyTCPConn, replyAddr, nil -} - -// handShake5 Socks 5 version of the connection handshake -func (clt *Client) handShake5(request *Request, proxyTCPConn net.Conn) (*Address, error) { - err := clt.authentication(proxyTCPConn) - if err != nil { - return nil, err - } - destAddrByte, err := request.Address.Bytes(Version5) - if err != nil { - return nil, err - } - // The SOCKS request is formed as follows: - // +----+-----+-------+------+----------+----------+ - // |VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT | - // +----+-----+-------+------+----------+----------+ - // | 1 | 1 | X'00' | 1 | Variable | 2 | - // +----+-----+-------+------+----------+----------+ - if _, err := proxyTCPConn.Write(append([]byte{request.VER, request.CMD, request.RSV}, destAddrByte...)); err != nil { - return nil, err - } - // reply formed as follows: - // +----+-----+-------+------+----------+----------+ - // |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT | - // +----+-----+-------+------+----------+----------+ - // | 1 | 1 | X'00' | 1 | Variable | 2 | - // +----+-----+-------+------+----------+----------+ - reply := &Reply{} - tmp, err := ReadNBytes(proxyTCPConn, 3) - if err != nil { - return nil, fmt.Errorf("failed to get reply version and command and reserved, %v", err) - } - reply.VER, reply.REP, reply.RSV = tmp[0], tmp[1], tmp[2] - if reply.VER != Version5 { - return nil, fmt.Errorf("unrecognized SOCKS version[%d]", reply.VER) - } - // read address - serverBoundAddr, _, err := readAddress(proxyTCPConn, request.VER) - if err != nil { - return nil, fmt.Errorf("failed to get reply address, %v", err) - } - reply.Address = serverBoundAddr - if reply.REP != SUCCESSED { - return nil, fmt.Errorf("server refuse client request, %s", rep2Str[reply.REP]) - } - return reply.Address, nil -} - -// authentication -func (clt *Client) authentication(proxyConn net.Conn) error { - var methods []byte - for method := range clt.Auth { - methods = append(methods, method) - } - // The client connects to the server, and sends a version identifier/method selection message: - // +----+----------+----------+ - // |VER | NMETHODS | METHODS | - // +----+----------+----------+ - // | 1 | 1 | 1 to 255 | - // +----+----------+----------+ - _, err := proxyConn.Write(append([]byte{Version5, byte(len(methods))}, methods...)) - if err != nil { - return nil - } - //Get reply, a METHOD selection message: - // +----+--------+ - // |VER | METHOD | - // +----+--------+ - // | 1 | 1 | - // +----+--------+ - reply, err := ReadNBytes(proxyConn, 2) - if err != nil { - return err - } - if reply[0] != Version5 { - return &VersionError{reply[0]} - } - - // Is client has this method? - if _, ok := clt.Auth[reply[1]]; !ok { - return &MethodError{reply[1]} - } - - // process authentication sub negotiation - err = clt.Auth[reply[1]].Authenticate(proxyConn, proxyConn) - if err != nil { - return err - } - - return nil -} - -// handShake4 Socks 4 version of the connection handshake -func (clt *Client) handshake4(request *Request, proxyConn net.Conn) (*Address, error) { - destAddrByte, err := request.Address.Bytes(Version4) - if err != nil { - return nil, err - } - // The client connects to the SOCKS server and sends a CONNECT request when it wants to establish a connection to an application server. - // The client includes in the request packet the IP address and the port number of the destination host, and userid, in the following format. - // +----+----+----+----+----+----+----+----+----+----+....+----+ - // | VN | CD | DSTPORT | DSTIP | USERID |NULL| - // +----+----+----+----+----+----+----+----+----+----+....+----+ - // 1 1 2 4 variable 1 - if _, err := proxyConn.Write(append([]byte{request.VER, request.CMD}, destAddrByte...)); err != nil { - return nil, err - } - // A reply packet is sent to the client when this connection is established,or when the request is rejected or the operation fails. - // +----+----+----+----+----+----+----+----+ - // | VN | CD | DSTPORT | DSTIP | - // +----+----+----+----+----+----+----+----+ - // 1 1 2 4 - tmp, err := ReadNBytes(proxyConn, 2) - if err != nil { - return nil, fmt.Errorf("failed to get reply version and command, %v", err) - } - if tmp[0] != 0 { - return nil, fmt.Errorf("response VN wrong[%d]", tmp[0]) - } - if tmp[1] != Granted { - return nil, errors.New("server refuse client request") - } - // Read address - replyAddr, _, err := readSocks4ReplyAddress(proxyConn, request.VER) - if err != nil { - return nil, fmt.Errorf("failed to get reply address, %v", err) - } - return replyAddr, nil -} - -// Connect send CONNECT Request. Returned a connected proxy connection. -func (clt *Client) Connect(ver VER, dest string) (*net.TCPConn, error) { - if ver != Version4 && ver != Version5 { - return nil, &VersionError{ver} - } - - destAddr, err := ParseAddress(dest) - if err != nil { - return nil, err - } - req := &Request{ - VER: ver, - CMD: CONNECT, - RSV: 0, - Address: destAddr, - } - - conn, _, err := clt.handshake(req) - if err != nil { - return nil, err - } - return conn, nil -} - -// UDPForward send UDP_ASSOCIATE Request. -// The laddr Param specific Client address to send udp datagram. -// If laddr is empty string, a local address (127.0.0.1:port) is automatically chosen. -// If port is occupied will return error. -func (clt *Client) UDPForward(laddr string) (*UDPConn, error) { - if laddr == "" { - laddr = "127.0.0.1:0" - } - - // split laddr to host/port - host, portStr, err := net.SplitHostPort(laddr) - p, err := strconv.Atoi(portStr) - if err != nil { - return nil, err - } - port := uint16(p) - - // zero port, will automatically chosen. - if port == 0 { - err, port = GetRandomPort("udp") - if err != nil { - return nil, errors.New("automatically chosen port fail") - } - laddr = net.JoinHostPort(host, strconv.Itoa(int(port))) - } - - // get addr - addr, err := ParseAddress(laddr) - if err != nil { - return nil, err - } - - req := &Request{ - VER: Version5, - CMD: UDP_ASSOCIATE, - RSV: 0, - Address: addr, - } - - // Handshake base on TCP connection - proxyTCPConn, UDPRelayAddr, err := clt.handshake(req) - if err != nil { - return nil, err - } - - // Get local UDP addr - localUDPAddr, err := addr.UDPAddr() - if err != nil { - return nil, err - } - - // Get udp relay server bind addr. - serverListenUDPAddr, err := UDPRelayAddr.UDPAddr() - if err != nil { - return nil, err - } - - // Dial UDP relay Server - err = IsFreePort("udp", port) - if err != nil { - proxyTCPConn.Close() - return nil, fmt.Errorf("port %d is occupied", port) - } - proxyUDPConn, err := net.DialUDP("udp", localUDPAddr, serverListenUDPAddr) - if err != nil { - proxyTCPConn.Close() - return nil, err - } - return NewUDPConn(proxyUDPConn, proxyTCPConn), nil -} - -// Bind send BIND Request. return 4 params: -// 1. Server bind address. -// 2. a readable chan to recv second reply from socks server. -// 3. A connection that is not immediately available, until read a nil from err chan. -// 4. An error, indicate the first reply result. If nil, successes. -func (clt *Client) Bind(ver VER, destAddr string) (*Address, <-chan error, net.Conn, error) { - dest, err := ParseAddress(destAddr) - if err != nil { - return nil, nil, nil, err - } - - request := &Request{ - Address: dest, - CMD: BIND, - VER: ver, - } - proxyConn, err := net.Dial("tcp", clt.ProxyAddr) - if err != nil { - clt.logf()(err.Error()) - return nil, nil, nil, err - } - if clt.Timeout != 0 { - err = proxyConn.SetDeadline(time.Now().Add(clt.Timeout)) - if err != nil { - clt.logf()(err.Error()) - return nil, nil, nil, err - } - defer proxyConn.SetDeadline(time.Time{}) - } - switch request.VER { - case Version4: - serverBindAddr, secondReply, err := clt.bind4(request, proxyConn) - if err != nil { - proxyConn.Close() - clt.logf()(err.Error()) - return nil, nil, nil, err - } - return serverBindAddr, secondReply, proxyConn, nil - case Version5: - serverBindAddr, secondReply, err := clt.bind5(request, proxyConn) - if err != nil { - proxyConn.Close() - clt.logf()(err.Error()) - return nil, nil, nil, err - } - return serverBindAddr, secondReply, proxyConn, nil - default: - proxyConn.Close() - return nil, nil, nil, &VersionError{request.VER} - } -} - -// bind5 socks5 bind -func (clt *Client) bind5(request *Request, proxyBindConn net.Conn) (*Address, <-chan error, error) { - err := clt.authentication(proxyBindConn) - if err != nil { - return nil, nil, err - } - destAddrByte, err := request.Address.Bytes(Version5) - if err != nil { - return nil, nil, err - } - // The SOCKS request is formed as follows: - // +----+-----+-------+------+----------+----------+ - // // |VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT | - // // +----+-----+-------+------+----------+----------+ - // // | 1 | 1 | X'00' | 1 | Variable | 2 | - // +----+-----+-------+------+----------+----------+ - if _, err := proxyBindConn.Write(append([]byte{request.VER, request.CMD, request.RSV}, destAddrByte...)); err != nil { - return nil, nil, err - } - // reply formed as follows: - // +----+-----+-------+------+----------+----------+ - // |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT | - // +----+-----+-------+------+----------+----------+ - // | 1 | 1 | X'00' | 1 | Variable | 2 | - // +----+-----+-------+------+----------+----------+ - reply := &Reply{} - tmp, err := ReadNBytes(proxyBindConn, 3) - if err != nil { - return nil, nil, fmt.Errorf("failed to get reply version and command and reserved, %v", err) - } - reply.VER, reply.REP, reply.RSV = tmp[0], tmp[1], tmp[2] - if reply.VER != Version5 { - return nil, nil, fmt.Errorf("unrecognized SOCKS version[%d]", reply.VER) - } - // read address - serverBoundAddr, _, err := readAddress(proxyBindConn, request.VER) - if err != nil { - return nil, nil, fmt.Errorf("failed to get reply address, %v", err) - } - reply.Address = serverBoundAddr - if reply.REP != SUCCESSED { - return nil, nil, fmt.Errorf("server refuse client request, %s,when first time reply", rep2Str[reply.REP]) - } - errorChan := make(chan error) - go func() { - reply2 := &Reply{} - // The second time reply formed as follows: - // +----+-----+-------+------+----------+----------+ - // |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT | - // +----+-----+-------+------+----------+----------+ - // | 1 | 1 | X'00' | 1 | Variable | 2 | - // +----+-----+-------+------+----------+----------+ - tmp, err := ReadNBytes(proxyBindConn, 3) - if err != nil { - errorChan <- fmt.Errorf("failed to get reply version and command and reserved, %v", err) - proxyBindConn.Close() - } - reply2.VER, reply2.REP, reply2.RSV = tmp[0], tmp[1], tmp[2] - if reply2.VER != Version5 { - errorChan <- fmt.Errorf("unrecognized SOCKS version[%d]", reply.VER) - proxyBindConn.Close() - } - // read address - serverBoundAddr, _, err := readAddress(proxyBindConn, request.VER) - if err != nil { - errorChan <- fmt.Errorf("failed to get reply address, %v", err) - proxyBindConn.Close() - } - reply2.Address = serverBoundAddr - if reply2.REP != SUCCESSED { - errorChan <- errors.New("server refuse client request,when second time reply") - proxyBindConn.Close() - } - errorChan <- nil - }() - return serverBoundAddr, errorChan, nil -} - -// bind4 socks4 bind -func (clt *Client) bind4(request *Request, proxyBindConn net.Conn) (*Address, <-chan error, error) { - destAddrByte, err := request.Address.Bytes(Version4) - if err != nil { - return nil, nil, err - } - // The client connects to the SOCKS server and sends a CONNECT request when it wants to establish a connection to an application server. - // The client includes in the request packet the IP address and the port number of the destination host, and userid, in the following format. - // +----+----+----+----+----+----+----+----+----+----+....+----+ - // | VN | CD | DSTPORT | DSTIP | USERID |NULL| - // +----+----+----+----+----+----+----+----+----+----+....+----+ - // 1 1 2 4 variable 1 - if _, err := proxyBindConn.Write(append([]byte{request.VER, request.CMD}, destAddrByte...)); err != nil { - return nil, nil, err - } - // A reply packet is sent to the client when this connection is established,or when the request is rejected or the operation fails. - // +----+----+----+----+----+----+----+----+ - // | VN | CD | DSTPORT | DSTIP | - // +----+----+----+----+----+----+----+----+ - // 1 1 2 4 - tmp, err := ReadNBytes(proxyBindConn, 2) - if err != nil { - return nil, nil, fmt.Errorf("failed to get reply version and command, %v", err) - } - if tmp[0] != 0 { - return nil, nil, fmt.Errorf("response VN wrong[%d]", tmp[0]) - } - // Read address - serverBoundAddr, _, err := readSocks4ReplyAddress(proxyBindConn, request.VER) - if err != nil { - return nil, nil, fmt.Errorf("failed to get reply address, %v", err) - } - if tmp[1] != Granted { - return nil, nil, errors.New("server refuse client request,when first time reply") - } - errorChan := make(chan error) - go func() { - // A reply packet is sent to the client,or when the request is rejected or the operation fails. - // +----+----+----+----+----+----+----+----+ - // | VN | CD | DSTPORT | DSTIP | - // +----+----+----+----+----+----+----+----+ - // 1 1 2 4 - tmp, err := ReadNBytes(proxyBindConn, 2) - if err != nil { - errorChan <- fmt.Errorf("failed to get reply version and command, %v", err) - proxyBindConn.Close() - } - if tmp[0] != 0 { - errorChan <- fmt.Errorf("response VN wrong[%d]", tmp[0]) - proxyBindConn.Close() - } - // read address - _, _, err = readSocks4ReplyAddress(proxyBindConn, request.VER) - if err != nil { - errorChan <- fmt.Errorf("failed to get reply address, %v", err) - proxyBindConn.Close() - } - - if tmp[1] != Granted { - errorChan <- errors.New("server refuse client request,when second time reply") - proxyBindConn.Close() - } - errorChan <- nil - }() - return serverBoundAddr, errorChan, nil -} - -// logf Logging is done using the client's errorlog -func (clt *Client) logf() func(format string, args ...interface{}) { - if clt.ErrorLog == nil { - return log.Printf - } - return clt.ErrorLog.Printf -} diff --git a/vendor/github.com/kalikaneko/socks5/common.go b/vendor/github.com/kalikaneko/socks5/common.go deleted file mode 100644 index ea64b2f5a4251900abf12e13f4ff8edfd20fe6f6..0000000000000000000000000000000000000000 --- a/vendor/github.com/kalikaneko/socks5/common.go +++ /dev/null @@ -1,47 +0,0 @@ -package socks5 - -import ( - "bytes" - "errors" - "io" -) - -var errUnexpectMinusLength = errors.New("arg number should not be minus") - -// ReadNBytes wrap io.ReadFull. read n bytes. -// The error is EOF only if no bytes were read. -// If an EOF happens after reading some but not all the bytes, -// ReadFull returns ErrUnexpectedEOF. -func ReadNBytes(reader io.Reader, n int) ([]byte, error) { - if n < 0 { - return nil, errUnexpectMinusLength - } - data := make([]byte, n) - _, err := io.ReadFull(reader, data) - if err != nil { - return nil, err - } - - return data, nil -} - -// ReadUntilNULL Read all not Null byte. -// Until read first Null byte(all zero bits) -func ReadUntilNULL(reader io.Reader) ([]byte, error) { - data := &bytes.Buffer{} - b := make([]byte, 1) - for { - _, err := reader.Read(b) - if err != nil { - if err == io.EOF { - return nil, nil - } - return nil, err - } - - if b[0] == NULL { - return data.Bytes(), nil - } - data.WriteByte(b[0]) - } -} diff --git a/vendor/github.com/kalikaneko/socks5/conn.go b/vendor/github.com/kalikaneko/socks5/conn.go deleted file mode 100644 index a94aee2179db4889ff437bb6c48f4f2e4f5f85fd..0000000000000000000000000000000000000000 --- a/vendor/github.com/kalikaneko/socks5/conn.go +++ /dev/null @@ -1,116 +0,0 @@ -package socks5 - -import ( - "io" - "net" - "sync" - "time" -) - -// UDPConn be associated with TCP connections. -// The UDP connection will close immediately, When TCP connection closed, -// UDPConn only use in UDP_ASSOCIATE command. -type UDPConn struct { - mu sync.Mutex - udp *net.UDPConn - tcp *net.TCPConn - closeChan chan struct{} -} - -// NewUDPConn get a *UDPConn through provide a tcp and udp connection. -// the tcp connection is used for socks UDP_ASSOCIATE handshake. -// the udp connection is used for socks udp forwarding. -// -// After UDP_ASSOCIATE handshake, the tcp transit nothing. Its only -// function is udp relay connection still running. -// -// If one of them shuts off, it will close them all. -func NewUDPConn(udp *net.UDPConn, tcp *net.TCPConn) *UDPConn { - if udp == nil || tcp == nil { - return nil - } - - u := &UDPConn{ - udp: udp, - tcp: tcp, - closeChan: make(chan struct{}), - } - - go func() { - // guard tcp connection, if it closed should close tcp relay too. - io.Copy(io.Discard, tcp) - u.Close() - }() - - return u -} - -func (u *UDPConn) LocalAddr() net.Addr { - return u.udp.LocalAddr() -} - -func (u *UDPConn) RemoteAddr() net.Addr { - return u.udp.RemoteAddr() -} - -func (u *UDPConn) SetDeadline(t time.Time) error { - return u.udp.SetDeadline(t) -} - -func (u *UDPConn) SetReadDeadline(t time.Time) error { - return u.udp.SetReadDeadline(t) -} - -func (u *UDPConn) SetWriteDeadline(t time.Time) error { - return u.udp.SetWriteDeadline(t) -} - -func (u *UDPConn) Read(b []byte) (n int, err error) { - return u.udp.Read(b) -} - -func (u *UDPConn) WriteToUDP(b []byte, addr *net.UDPAddr) (int, error) { - return u.udp.WriteToUDP(b, addr) -} - -func (u *UDPConn) ReadFromUDP(b []byte) (int, *net.UDPAddr, error) { - return u.udp.ReadFromUDP(b) -} - -func (u *UDPConn) Write(b []byte) (n int, err error) { - return u.udp.Write(b) -} - -func (u *UDPConn) Close() error { - var err error - u.mu.Lock() - defer u.mu.Unlock() - - ch := u.getCloseChanLocked() - select { - case <-ch: - return nil - default: - if err2 := u.udp.Close(); err2 != nil { - err = err2 - } - if err2 := u.tcp.Close(); err2 != nil { - err = err2 - } - close(u.closeChan) - } - return err -} - -func (u *UDPConn) CloseCh() <-chan struct{} { - u.mu.Lock() - defer u.mu.Unlock() - return u.getCloseChanLocked() -} - -func (u *UDPConn) getCloseChanLocked() <-chan struct{} { - if u.closeChan == nil { - u.closeChan = make(chan struct{}) - } - return u.closeChan -} diff --git a/vendor/github.com/kalikaneko/socks5/port.go b/vendor/github.com/kalikaneko/socks5/port.go deleted file mode 100644 index 5e1a85241ff2dad125aa4770dadd747d0e8ffb57..0000000000000000000000000000000000000000 --- a/vendor/github.com/kalikaneko/socks5/port.go +++ /dev/null @@ -1,101 +0,0 @@ -package socks5 - -import ( - "errors" - "net" - "strconv" - "strings" -) - -// GetRandomPort return a random port by specific network. -// The network must be "tcp", "udp". -func GetRandomPort(network string) (err error, port uint16) { - network = strings.ToLower(network) - addr := "0.0.0.0:0" - - switch network { - case "tcp", "tcp4", "tcp6": - tcpAddr, err := net.ResolveTCPAddr(network, addr) - if err != nil { - return err, 0 - } - ln, err := net.ListenTCP(network, tcpAddr) - if err != nil { - return err, 0 - } - - _, portStr, err := net.SplitHostPort(ln.Addr().String()) - p, err := strconv.Atoi(portStr) - port = uint16(p) - - err = ln.Close() - if err != nil { - return err, 0 - } - return err, port - case "udp", "udp4", "udp6": - udpAddr, err := net.ResolveUDPAddr(network, addr) - if err != nil { - return err, 0 - } - ln, err := net.ListenUDP(network, udpAddr) - if err != nil { - return err, 0 - } - - _, portStr, err := net.SplitHostPort(ln.LocalAddr().String()) - p, err := strconv.Atoi(portStr) - port = uint16(p) - - err = ln.Close() - if err != nil { - return err, 0 - } - return err, port - default: - return errors.New("unknown network type " + network), 0 - } -} - -// IsFreePort indicates the port is available. -// The network must be "tcp", "udp". -func IsFreePort(network string, port uint16) error { - network = strings.ToLower(network) - portStr := strconv.Itoa(int(port)) - addr := "0.0.0.0:" + portStr - - switch network { - case "tcp": - tcpAddr, err := net.ResolveTCPAddr(network, addr) - if err != nil { - return err - } - ln, err := net.ListenTCP(network, tcpAddr) - if err != nil { - return err - } - - ln.Close() - if err != nil { - return err - } - return nil - case "udp": - udpAddr, err := net.ResolveUDPAddr(network, addr) - if err != nil { - return err - } - ln, err := net.ListenUDP(network, udpAddr) - if err != nil { - return err - } - - ln.Close() - if err != nil { - return err - } - return nil - default: - return errors.New("unknown network type " + network) - } -} diff --git a/vendor/github.com/kalikaneko/socks5/protocol.go b/vendor/github.com/kalikaneko/socks5/protocol.go deleted file mode 100644 index d0194eaf4bf61a535a7b33131bf6c55b535bb313..0000000000000000000000000000000000000000 --- a/vendor/github.com/kalikaneko/socks5/protocol.go +++ /dev/null @@ -1,155 +0,0 @@ -package socks5 - -import "fmt" - -type VersionError struct { - VER -} - -func (v *VersionError) Error() string { - return fmt.Sprintf("error socks protocol version: %d", v.VER) -} - -// VER indicates protocol version -type VER = uint8 - -const ( - Version4 = 0x04 - Version5 = 0x05 -) - -type MethodError struct { - METHOD -} - -func (m *MethodError) Error() string { - if _, ok := method2Str[m.METHOD]; ok { - return fmt.Sprintf("don't support this method %s", method2Str[m.METHOD]) - } else { - return fmt.Sprintf("unknown mehotd %#x", m.METHOD) - } -} - -// METHOD Defined authentication methods -type METHOD = uint8 - -const ( - NO_AUTHENTICATION_REQUIRED METHOD = 0x00 - GSSAPI METHOD = 0x01 - USERNAME_PASSWORD METHOD = 0x02 - IANA_ASSIGNED METHOD = 0x03 - NO_ACCEPTABLE_METHODS METHOD = 0xff -) - -var method2Str = map[METHOD]string{ - NO_AUTHENTICATION_REQUIRED: "NO_AUTHENTICATION_REQUIRED", - GSSAPI: "GSSAPI", - USERNAME_PASSWORD: "USERNAME_PASSWORD", - IANA_ASSIGNED: "IANA_ASSIGNED", - NO_ACCEPTABLE_METHODS: "NO_ACCEPTABLE_METHODS", -} - -// CMDError cmd error type -type CMDError struct { - CMD -} - -func (c *CMDError) Error() string { - if _, ok := cmd2Str[c.CMD]; !ok { - return fmt.Sprintf("unknown command:%#x", c.CMD) - } - return fmt.Sprintf("don't support this command:%s", cmd2Str[c.CMD]) -} - -// CMD is one of a field in Socks5 Request -type CMD = uint8 - -const ( - CONNECT CMD = 0x01 - BIND CMD = 0x02 - UDP_ASSOCIATE CMD = 0x03 -) - -var cmd2Str = map[CMD]string{ - CONNECT: "CONNECT", - BIND: "BIND", - UDP_ASSOCIATE: "UDP_ASSOCIATE", - Rejected: "Rejected", - Granted: "Granted", -} - -type REPError struct { - REP -} - -func (r *REPError) Error() string { - if _, ok := cmd2Str[r.REP]; !ok { - return fmt.Sprintf("unknown rep:%#x", r.REP) - } - return fmt.Sprintf("don't support this rep:%s", rep2Str[r.REP]) -} - -// REP is one of a filed in Socks5 Reply -type REP = uint8 - -//socks5 reply -const ( - SUCCESSED REP = 0x00 - GENERAL_SOCKS_SERVER_FAILURE REP = 0x01 - CONNECTION_NOT_ALLOW_BY_RULESET REP = 0x02 - NETWORK_UNREACHABLE REP = 0x03 - HOST_UNREACHABLE REP = 0x04 - CONNECTION_REFUSED REP = 0x05 - TTL_EXPIRED REP = 0x06 - COMMAND_NOT_SUPPORTED REP = 0x07 - ADDRESS_TYPE_NOT_SUPPORTED REP = 0x08 - UNASSIGNED REP = 0x09 -) - -var rep2Str = map[REP]string{ - SUCCESSED: "successes", - GENERAL_SOCKS_SERVER_FAILURE: "general_socks_server_failure", - CONNECTION_NOT_ALLOW_BY_RULESET: "connection_not_allow_by_ruleset", - NETWORK_UNREACHABLE: "network_unreachable", - HOST_UNREACHABLE: "host_unreachable", - CONNECTION_REFUSED: "connection_refused", - TTL_EXPIRED: "ttl_expired", - COMMAND_NOT_SUPPORTED: "command_not_supported", - ADDRESS_TYPE_NOT_SUPPORTED: "address_type_not_supported", - UNASSIGNED: "unassigned", - Granted: "granted", - Rejected: "rejected", -} - -//socks4 reply -const ( - // Granted means server allow client request - Granted = 90 - // Rejected means server refuse client request - Rejected = 91 -) - -type AtypeError struct { - ATYPE -} - -func (a *AtypeError) Error() string { - return fmt.Sprintf("unknown address type:%#x", a.ATYPE) -} - -// ATYPE indicates address type in Request and Reply struct -type ATYPE = uint8 - -const ( - IPV4_ADDRESS ATYPE = 0x01 - DOMAINNAME ATYPE = 0x03 - IPV6_ADDRESS ATYPE = 0x04 -) - -var atype2Str = map[ATYPE]string{ - IPV4_ADDRESS: "IPV4_ADDRESS", - DOMAINNAME: "DOMAINNAME", - IPV6_ADDRESS: "IPV6_ADDRESS", -} - -const NULL byte = 0 diff --git a/vendor/github.com/kalikaneko/socks5/reply.go b/vendor/github.com/kalikaneko/socks5/reply.go deleted file mode 100644 index 4cf3b043dcdb7cc6687e32902074608c00c74d8b..0000000000000000000000000000000000000000 --- a/vendor/github.com/kalikaneko/socks5/reply.go +++ /dev/null @@ -1,14 +0,0 @@ -package socks5 - -// Reply a reply formed as follows: -// +----+-----+-------+------+----------+----------+ -// |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT | -// +----+-----+-------+------+----------+----------+ -// | 1 | 1 | X'00' | 1 | Variable | 2 | -// +----+-----+-------+------+----------+----------+ -type Reply struct { - VER - REP - RSV uint8 - *Address -} diff --git a/vendor/github.com/kalikaneko/socks5/request.go b/vendor/github.com/kalikaneko/socks5/request.go deleted file mode 100644 index ecfea0391c77d42bd9573d5e07193b48026ba4f5..0000000000000000000000000000000000000000 --- a/vendor/github.com/kalikaneko/socks5/request.go +++ /dev/null @@ -1,70 +0,0 @@ -package socks5 - -import ( - "bytes" - "errors" -) - -// Request The SOCKS request is formed as follows: -// +----+-----+-------+------+----------+----------+ -// |VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT | -// +----+-----+-------+------+----------+----------+ -// | 1 | 1 | X'00' | 1 | Variable | 2 | -// +----+-----+-------+------+----------+----------+ -type Request struct { - VER - CMD - RSV uint8 - *Address -} - -// UDPHeader Each UDP datagram carries a UDP request -// header with it: -// +----+------+------+----------+----------+----------+ -// |RSV | FRAG | ATYP | DST.ADDR | DST.PORT | DATA | -// +----+------+------+----------+----------+----------+ -// | 2 | 1 | 1 | Variable | 2 | Variable | -// +----+------+------+----------+----------+----------+ -type UDPHeader struct { - RSV uint16 - FRAG uint8 - *Address - Data []byte -} - -var errEmptyPayload = errors.New("empty payload") - -// PackUDPData add UDP request header before payload. -func PackUDPData(addr *Address, payload []byte) ([]byte, error) { - if len(payload) == 0 { - return nil, errEmptyPayload - } - if addr == nil { - return nil, errors.New("addr is nil") - } - // RSV, FRAG - data := []byte{0x00, 0x00, 0x00} - dest, err := addr.Bytes(Version5) - if err != nil { - return nil, err - } - // ATYP, DEST.IP, DEST.PORT - data = append(data, dest...) - // DATA - data = append(data, payload...) - return data, nil -} - -// UnpackUDPData split UDP header and payload. -func UnpackUDPData(data []byte) (addr *Address, payload []byte, err error) { - // trim RSV, FRAG - data = data[3:] - buf := bytes.NewBuffer(data) - addr, _, err = readAddress(buf, Version5) - if err != nil { - return nil, nil, err - } - - payload = buf.Bytes() - return -} diff --git a/vendor/github.com/kalikaneko/socks5/server.go b/vendor/github.com/kalikaneko/socks5/server.go deleted file mode 100644 index 33059e2acf7679c69659babbf4ef7eb20a9ffbec..0000000000000000000000000000000000000000 --- a/vendor/github.com/kalikaneko/socks5/server.go +++ /dev/null @@ -1,653 +0,0 @@ -package socks5 - -import ( - "errors" - "io" - "log" - "net" - "strconv" - "sync" - "sync/atomic" - "time" -) - -// Server defines parameters for running socks server. -// The zero value for Server is a valid configuration(tcp listen on :1080). -type Server struct { - // Addr optionally specifies the TCP address for the server to listen on, - // in the form "host:port". If empty, ":1080" (port 1080) is used. - Addr string - - // BindIP specific UDP relay server IP and bind listen IP. - // It shouldn't be ipv4zero like "0,0,0,0" or ipv6zero like [:] - // If empty, localhost used. - BindIP string - - // ReadTimeout is the maximum duration for reading from socks client. - // it's only effective to socks server handshake process. - // - // If zero, there is no timeout. - ReadTimeout time.Duration - - // WriteTimeout is the maximum duration for writing to socks client. - // it's only effective to socks server handshake process. - // - // If zero, there is no timeout. - WriteTimeout time.Duration - - // method mapping to the authenticator - // if nil server provide NO_AUTHENTICATION_REQUIRED method by default - Authenticators map[METHOD]Authenticator - - // The server select method to use policy - //MethodSelector - - Dial DialFunc - - // Server transmit data between client and dest server. - // if nil, DefaultTransport is used. - Transporter - - // ErrorLog specifics an options logger for errors accepting - // connections, unexpected socks protocol handshake process, - // and server to remote connection errors. - // If nil, logging is done via log package's standard logger. - ErrorLog *log.Logger - - // DisableSocks4, disable socks4 server, default enable socks4 compatible. - DisableSocks4 bool - - // 1 indicate server is shutting down. - // 0 indicate server is running. - // Atomic operation must be guaranteed. - isShutdown int32 - - mu sync.Mutex - listeners map[*net.Listener]struct{} - activeConn map[net.Conn]struct{} - doneCh chan struct{} -} - -type DialFunc func(string, string) (net.Conn, error) - -func (srv *Server) getDoneChan() <-chan struct{} { - srv.mu.Lock() - defer srv.mu.Unlock() - return srv.getDoneChanLocked() -} - -func (srv *Server) getDoneChanLocked() chan struct{} { - if srv.doneCh == nil { - srv.doneCh = make(chan struct{}) - } - return srv.doneCh -} - -func (srv *Server) closeDoneChanLocked() { - ch := srv.getDoneChanLocked() - select { - case <-ch: - default: - close(srv.doneCh) - } -} - -func (srv *Server) Close() error { - atomic.StoreInt32(&srv.isShutdown, 1) - srv.mu.Lock() - defer srv.mu.Unlock() - // close all listeners. - err := srv.closeListenerLocked() - if err != nil { - return err - } - // close doneCh to broadcast close message. - srv.closeDoneChanLocked() - // Close all open connections. - for conn, _ := range srv.activeConn { - conn.Close() - } - return nil -} - -func (srv *Server) inShuttingDown() bool { - return atomic.LoadInt32(&srv.isShutdown) != 0 -} - -func (srv *Server) closeListenerLocked() error { - var err error - for ln := range srv.listeners { - if cerr := (*ln).Close(); cerr != nil { - err = cerr - } - } - return err -} - -// trackListener adds or removes a net.Listener to the set of tracked -// listeners. -// -// We store a pointer to interface in the map set, in case the -// net.Listener is not comparable. This is safe because we only call -// trackListener via Serve and can track+defer untrack the same -// pointer to local variable there. We never need to compare a -// Listener from another caller. -// -// It reports whether the server is still up (not Shutdown or Closed). -func (srv *Server) trackListener(l *net.Listener, add bool) bool { - srv.mu.Lock() - defer srv.mu.Unlock() - if srv.listeners == nil { - srv.listeners = make(map[*net.Listener]struct{}) - } - - if add { - if srv.inShuttingDown() { - return false - } - srv.listeners[l] = struct{}{} - } else { - delete(srv.listeners, l) - } - return true -} - -func (srv *Server) trackConn(c net.Conn, add bool) { - srv.mu.Lock() - defer srv.mu.Unlock() - if srv.activeConn == nil { - srv.activeConn = make(map[net.Conn]struct{}) - } - if add { - srv.activeConn[c] = struct{}{} - } else { - delete(srv.activeConn, c) - } -} - -// ListenAndServe listens on the TCP network address srv.Addr and then -// calls serve to handle requests on incoming connections. -// -// If srv.Addr is blank, ":1080" is used. -func (srv *Server) ListenAndServe() error { - if srv.inShuttingDown() { - return ErrServerClosed - } - - addr := srv.Addr - if addr == "" { - addr = "0.0.0.0:1080" - } - - if srv.BindIP == "" { - srv.BindIP = "localhost" - } else if srv.BindIP == net.IPv4zero.String() || srv.BindIP == net.IPv6zero.String() { - return errors.New("socks: server bindIP shouldn't be zero") - } - - ln, err := net.Listen("tcp", addr) - if err != nil { - return err - } - return srv.Serve(ln) -} - -// ErrServerClosed is returned by the Server's Serve, ListenAndServe methods after a call to Shutdown or Close. -var ErrServerClosed = errors.New("socks: Server closed") - -// Serve accepts incoming connections on the Listener l, creating a -// new service goroutine for each. The service goroutine select client -// list methods and reply client. Then process authentication and reply -// to them. At then end of handshake, read socks request from client and -// establish a connection to the target. -func (srv *Server) Serve(l net.Listener) error { - srv.trackListener(&l, true) - defer srv.trackListener(&l, false) - - var tempDelay time.Duration - - for { - client, err := l.Accept() - if err != nil { - select { - case <-srv.getDoneChan(): - return ErrServerClosed - default: - } - if ne, ok := err.(net.Error); ok && ne.Temporary() { - if tempDelay == 0 { - tempDelay = 5 * time.Millisecond - } else { - tempDelay *= 2 - } - if max := time.Second; tempDelay > max { - tempDelay = max - } - srv.logf()("socks: Accept error: %v, retrying in %v", err, tempDelay) - time.Sleep(tempDelay) - continue - } - return err - } - go srv.serveconn(client) - } -} - -func (srv *Server) serveconn(client net.Conn) { - if srv.ReadTimeout != 0 { - client.SetReadDeadline(time.Now().Add(srv.ReadTimeout)) - } - if srv.WriteTimeout != 0 { - client.SetWriteDeadline(time.Now().Add(srv.WriteTimeout)) - } - - // handshake - request, err := srv.handShake(client) - if err != nil { - srv.logf()(err.Error()) - client.Close() - return - } - - // establish connection to remote - remote, err := srv.establish(client, request) - if err != nil { - srv.logf()(err.Error()) - client.Close() - return - } - - // establish over, reset deadline. - client.SetReadDeadline(time.Time{}) - client.SetWriteDeadline(time.Time{}) - - // transport data - switch request.CMD { - case CONNECT, BIND: - srv.trackConn(client, true) - defer srv.trackConn(client, false) - srv.trackConn(remote, true) - defer srv.trackConn(remote, false) - - errCh := srv.transport().TransportTCP(client, remote) - for err := range errCh { - if err != nil { - srv.logf()(err.Error()) - } - } - case UDP_ASSOCIATE: - relay := NewUDPConn(remote.(*net.UDPConn), client.(*net.TCPConn)) - srv.trackConn(relay, true) - defer srv.trackConn(relay, false) - - err = srv.transport().TransportUDP(relay, request) - if err != nil { - srv.logf()(err.Error()) - } - } -} - -func (srv *Server) transport() Transporter { - if srv.Transporter == nil { - return DefaultTransporter - } - return srv.Transporter -} - -func (srv *Server) dialFn() DialFunc { - if srv.Dial == nil { - return net.Dial - } - return srv.Dial -} - -var errDisableSocks4 = errors.New("socks4 server has been disabled") - -// handShake socks protocol handshake process -func (srv *Server) handShake(client net.Conn) (*Request, error) { - //validate socks version message - _, err := checkVersion(client) - - if err != nil { - return nil, &OpError{Version5, "read", client.RemoteAddr(), "\"check version\"", err} - } - - //socks5 protocol authentication - err = srv.authentication(client) - if err != nil { - return nil, err - } - - //handle socks5 request - return srv.readSocks5Request(client) -} - -// authentication socks5 authentication process -func (srv *Server) authentication(client net.Conn) error { - //get nMethods - nMethods, err := ReadNBytes(client, 1) - if err != nil { - return err - } - - //Get methods - methods, err := ReadNBytes(client, int(nMethods[0])) - if err != nil { - return err - } - - return srv.MethodSelect(methods, client) -} - -// readSocks5Request read socks5 protocol client request. -func (srv *Server) readSocks5Request(client net.Conn) (*Request, error) { - reply := &Reply{ - VER: Version5, - Address: &Address{net.IPv4zero, IPV4_ADDRESS, 0}, - } - req := &Request{} - //VER, CMD, RSV - cmd, err := ReadNBytes(client, 3) - if err != nil { - return nil, &OpError{req.VER, "read", client.RemoteAddr(), "\"process request ver,cmd,rsv\"", err} - } - req.VER = cmd[0] - req.CMD = cmd[1] - req.RSV = cmd[2] - // ATYPE, DST.IP, DST.PORT - addr, rep, err := readAddress(client, req.VER) - if err != nil { - reply.REP = rep - err := srv.sendReply(client, reply) - if err != nil { - return nil, &OpError{req.VER, "write", client.RemoteAddr(), "\"process request address\"", err} - } - } - req.Address = addr - - return req, nil -} - -// IsAllowNoAuthRequired return true if server enable NO_AUTHENTICATION_REQUIRED. -// Or the server doesn't has no Authenticator return true. Otherwise return false. -func (srv *Server) IsAllowNoAuthRequired() bool { - if len(srv.Authenticators) == 0 { - return true - } - for method := range srv.Authenticators { - if method == NO_AUTHENTICATION_REQUIRED { - return true - } - } - return false -} - -// establish tcp connection to remote host if command is CONNECT or -// start listen on udp socket when command is UDP_ASSOCIATE. Listen -// and accept host connection when command is BIND. Finally, send -// corresponding reply to client. -func (srv *Server) establish(client net.Conn, req *Request) (dest net.Conn, err error) { - reply := &Reply{ - VER: req.VER, - Address: &Address{net.IPv4zero, IPV4_ADDRESS, 0}, - } - if req.VER != Version5 { - // unknown version - return nil, &VersionError{req.VER} - } - - switch req.CMD { - case CONNECT: - // dial dest host. - dest, err = srv.dialFn()("tcp", req.Address.String()) - if err != nil { - reply.REP = HOST_UNREACHABLE - err2 := srv.sendReply(client, reply) - if err2 != nil { - return nil, &OpError{req.VER, "write", client.RemoteAddr(), "\"process request\"", err2} - - } - return nil, err - } - - // parse remote host address. - remoteAddr, err := ParseAddress(dest.RemoteAddr().String()) - if err != nil { - reply.REP = GENERAL_SOCKS_SERVER_FAILURE - err2 := srv.sendReply(client, reply) - if err2 != nil { - return nil, &OpError{req.VER, "write", client.RemoteAddr(), "\"process request\"", err2} - } - return nil, err - } - reply.Address = remoteAddr - - // success - reply.REP = SUCCESSED - err = srv.sendReply(client, reply) - if err != nil { - return nil, &OpError{req.VER, "write", client.RemoteAddr(), "\"process request\"", err} - } - case UDP_ASSOCIATE: - addr, err := net.ResolveUDPAddr("udp", net.JoinHostPort(srv.BindIP, "0")) - if err != nil { - return nil, err - } - - // start udp listening on random port. - dest, err = net.ListenUDP("udp", addr) - if err != nil { - reply.REP = GENERAL_SOCKS_SERVER_FAILURE - err2 := srv.sendReply(client, reply) - if err2 != nil { - return nil, &OpError{req.VER, "write", client.RemoteAddr(), "\"process request\"", err2} - } - return nil, err - } - - // success - reply.REP = SUCCESSED - relayAddr, err := ParseAddress(dest.LocalAddr().String()) - if err != nil { - return nil, err - } - reply.Address = relayAddr - err = srv.sendReply(client, reply) - if err != nil { - return nil, &OpError{req.VER, "write", client.RemoteAddr(), "\"process request\"", err} - } - case BIND: - bindAddr, err := net.ResolveTCPAddr("tcp", net.JoinHostPort(srv.BindIP, "0")) - if err != nil { - return nil, err - } - - // start tcp listening on random port. - bindServer, err := net.ListenTCP("tcp", bindAddr) - if err != nil { - reply.REP = GENERAL_SOCKS_SERVER_FAILURE - err2 := srv.sendReply(client, reply) - if err2 != nil { - return nil, &OpError{req.VER, "write", client.RemoteAddr(), "\"process request\"", err2} - } - return nil, err - } - defer bindServer.Close() - reply.REP = SUCCESSED - reply.Address, err = ParseAddress(bindServer.Addr().String()) - if err != nil { - return nil, err - } - - // send first reply to client. - err = srv.sendReply(client, reply) - if err != nil { - return nil, &OpError{req.VER, "write", client.RemoteAddr(), "\"process request\"", err} - } - dest, err = bindServer.Accept() - if err != nil { - reply.REP = GENERAL_SOCKS_SERVER_FAILURE - err2 := srv.sendReply(client, reply) - if err2 != nil { - return nil, &OpError{req.VER, "write", client.RemoteAddr(), "\"process request\"", err2} - } - return nil, err - } - - // send second reply to client. - if req.Address.String() == dest.RemoteAddr().String() { - reply.Address, err = ParseAddress(dest.RemoteAddr().String()) - if err != nil { - return nil, err - } - err = srv.sendReply(client, reply) - if err != nil { - return nil, &OpError{req.VER, "write", client.RemoteAddr(), "\"process request\"", err} - } - } else { - reply.REP = GENERAL_SOCKS_SERVER_FAILURE - err = srv.sendReply(client, reply) - if err != nil { - return nil, &OpError{req.VER, "write", client.RemoteAddr(), "\"process request\"", err} - } - } - default: - reply.REP = COMMAND_NOT_SUPPORTED - err = srv.sendReply(client, reply) - if err != nil { - return nil, &OpError{req.VER, "write", client.RemoteAddr(), "\"process request\"", err} - } - - return nil, &OpError{Version5, "", client.RemoteAddr(), "\"process request\"", &CMDError{req.CMD}} - } - return -} - -// sendReply The server send socks protocol reply to client -func (srv *Server) sendReply(out io.Writer, r *Reply) error { - var reply []byte - var err error - - if r.VER == Version4 { - if r.Address.ATYPE != IPV4_ADDRESS { - return errErrorATPE - } - addr, err := r.Address.Bytes(r.VER) - if err != nil { - return err - } - reply = append(reply, 0, r.REP) - // Remove NULL at the end. Please see Address.Bytes() Method. - reply = append(reply, addr[:len(addr)-1]...) - } else if r.VER == Version5 { - addr, err := r.Address.Bytes(r.VER) - if err != nil { - return err - } - reply = append(reply, r.VER, r.REP, r.RSV) - reply = append(reply, addr...) - } else { - return &VersionError{r.VER} - } - - _, err = out.Write(reply) - return err -} - -// MethodSelect select authentication method and reply to client. -func (srv *Server) MethodSelect(methods []CMD, client net.Conn) error { - // Select method to authenticate, then send selected method to client. - for _, method := range methods { - //Preferred to use NO_AUTHENTICATION_REQUIRED method - if method == NO_AUTHENTICATION_REQUIRED && srv.IsAllowNoAuthRequired() { - reply := []byte{Version5, NO_AUTHENTICATION_REQUIRED} - _, err := client.Write(reply) - if err != nil { - return &OpError{Version5, "write", client.RemoteAddr(), "authentication", err} - } - return nil - } - for m := range srv.Authenticators { - //Select the first matched method to authenticate - if m == method { - reply := []byte{Version5, method} - _, err := client.Write(reply) - if err != nil { - return &OpError{Version5, "write", client.RemoteAddr(), "authentication", err} - } - - err = srv.Authenticators[m].Authenticate(client, client) - if err != nil { - return &OpError{Version5, "", client.RemoteAddr(), "authentication", err} - } - return nil - } - } - } - - // There are no Methods can use - reply := []byte{Version5, NO_ACCEPTABLE_METHODS} - _, err := client.Write(reply) - if err != nil { - return &OpError{Version5, "write", client.RemoteAddr(), "authentication", err} - } - return &OpError{Version5, "", client.RemoteAddr(), "authentication", &MethodError{methods[0]}} -} - -func (srv *Server) logf() func(format string, args ...interface{}) { - if srv.ErrorLog == nil { - return log.Printf - } - return srv.ErrorLog.Printf -} - -// checkVersion check version is 4 or 5. -func checkVersion(in io.Reader) (VER, error) { - version, err := ReadNBytes(in, 1) - if err != nil { - return 0, err - } - - if (version[0] != Version5) && (version[0] != Version4) { - return 0, &VersionError{version[0]} - } - return version[0], nil -} - -// OpError is the error type usually returned by functions in the socks5 -// package. It describes the socks version, operation, client address, -// and address of an error. -type OpError struct { - // VER describe the socks server version on process. - VER - - // Op is the operation which caused the error, such as - // "read", "write". - Op string - - // Addr define client's address which caused the error. - Addr net.Addr - - // Step is the client's current connection stage, such as - // "check version", "authentication", "process request", - Step string - - // Err is the error that occurred during the operation. - // The Error method panics if the error is nil. - Err error -} - -func (o *OpError) Error() string { - str := "socks" + strconv.Itoa(int(o.VER)) - str += " " + o.Op - if o.Addr == nil { - str += " " - } else { - str += " " + o.Addr.String() - } - str += " " + o.Step - str += ":" + o.Err.Error() - return str -} - -var errErrorATPE = errors.New("socks4 server bind address type should be ipv4") diff --git a/vendor/github.com/kalikaneko/socks5/transport.go b/vendor/github.com/kalikaneko/socks5/transport.go deleted file mode 100644 index fc7a739ceb87e8a61f727677b46853eb94d56011..0000000000000000000000000000000000000000 --- a/vendor/github.com/kalikaneko/socks5/transport.go +++ /dev/null @@ -1,122 +0,0 @@ -package socks5 - -import ( - "io" - "net" - "strings" - "sync" -) - -// Transporter transmit data between client and dest server. -type Transporter interface { - TransportTCP(client net.Conn, remote net.Conn) <-chan error - TransportUDP(server *UDPConn, request *Request) error -} - -type transport struct { -} - -const maxLenOfDatagram = 65507 - -var transportPool = &sync.Pool{ - New: func() interface{} { - return make([]byte, maxLenOfDatagram) - }, -} - -// TransportTCP use io.CopyBuffer transmit data. -func (t *transport) TransportTCP(client net.Conn, remote net.Conn) <-chan error { - errCh := make(chan error) - var wg = sync.WaitGroup{} - - f := func(dst net.Conn, src net.Conn) { - defer wg.Done() - buf := transportPool.Get().([]byte) - defer transportPool.Put(buf) - _, err := io.CopyBuffer(dst, src, buf) - errCh <- err - } - - wg.Add(2) - go func() { - wg.Wait() - defer client.Close() - defer remote.Close() - close(errCh) - }() - - go f(remote, client) - go f(client, remote) - - return errCh -} - -// TransportUDP forwarding UDP packet between client and dest. -func (t *transport) TransportUDP(server *UDPConn, request *Request) error { - // Client udp address, limit access to the association. - clientAddr, err := request.Address.UDPAddr() - if err != nil { - return err - } - - // Record dest address, limit access to the association. - forwardAddr := make(map[string]struct{}) - buf := transportPool.Get().([]byte) - defer transportPool.Put(buf) - - defer server.Close() - for { - select { - default: - // Receive data from remote. - n, addr, err := server.ReadFromUDP(buf) - if err != nil { - return err - } - - // Should unpack data when data from client. - if strings.EqualFold(clientAddr.String(), addr.String()) { - destAddr, payload, err := UnpackUDPData(buf[:n]) - if err != nil { - return err - } - - destUDPAddr, err := destAddr.UDPAddr() - if err != nil { - return err - } - forwardAddr[destUDPAddr.String()] = struct{}{} - - // send payload to dest address - _, err = server.WriteToUDP(payload, destUDPAddr) - if err != nil { - return err - } - } - - // Should pack data when data from dest host - if _, ok := forwardAddr[addr.String()]; ok { - address, err := ParseAddress(addr.String()) - if err != nil { - return err - } - - // packed Data - packedData, err := PackUDPData(address, buf[:n]) - if err != nil { - return err - } - - // send payload to client - _, err = server.WriteToUDP(packedData, clientAddr) - if err != nil { - return err - } - } - case <-server.CloseCh(): - return nil - } - } -} - -var DefaultTransporter Transporter = &transport{} diff --git a/vendor/github.com/xtaci/kcp-go/v5/.travis.yml b/vendor/github.com/xtaci/kcp-go/v5/.travis.yml index 0e7c4ac1058ddf8d2d0460dbf6da9fb26b940ffe..6754ef6777db874e391a56d44132469fb66f7c96 100644 --- a/vendor/github.com/xtaci/kcp-go/v5/.travis.yml +++ b/vendor/github.com/xtaci/kcp-go/v5/.travis.yml @@ -1,4 +1,8 @@ +arch: + - amd64 + - ppc64le language: go + go: - 1.11.x - 1.12.x diff --git a/vendor/github.com/xtaci/kcp-go/v5/README.md b/vendor/github.com/xtaci/kcp-go/v5/README.md index d2273f890a6baaef31662ec1526520d0245e52ab..f68406d93da3552605033ebf39af4f0b07f3cbfa 100644 --- a/vendor/github.com/xtaci/kcp-go/v5/README.md +++ b/vendor/github.com/xtaci/kcp-go/v5/README.md @@ -277,9 +277,3 @@ A: Yes, for the safety of protocol, even if the upper layer has encrypted. 1. https://github.com/xtaci/libkcp -- FEC enhanced KCP session library for iOS/Android in C++ 1. https://github.com/skywind3000/kcp -- A Fast and Reliable ARQ Protocol 1. https://github.com/klauspost/reedsolomon -- Reed-Solomon Erasure Coding in Go - -## Consulting - -WeChat(付费技术咨询) - -<img src="wechat_donate.jpg" alt="kcptun" height="120px" /> diff --git a/vendor/github.com/xtaci/kcp-go/v5/donate.png b/vendor/github.com/xtaci/kcp-go/v5/donate.png deleted file mode 100644 index 0f353d96e902936aed15a7312a6e8b4b332fe960..0000000000000000000000000000000000000000 Binary files a/vendor/github.com/xtaci/kcp-go/v5/donate.png and /dev/null differ diff --git a/vendor/github.com/xtaci/kcp-go/v5/fec.go b/vendor/github.com/xtaci/kcp-go/v5/fec.go index 0a203ee3e624144bdf2ffdee74d03b5cd261d206..88f5a9c4b4fce6f94df5bdec761fa8bfc396c2a5 100644 --- a/vendor/github.com/xtaci/kcp-go/v5/fec.go +++ b/vendor/github.com/xtaci/kcp-go/v5/fec.go @@ -41,9 +41,6 @@ type fecDecoder struct { decodeCache [][]byte flagCache []bool - // zeros - zeros []byte - // RS decoder codec reedsolomon.Encoder @@ -68,7 +65,6 @@ func newFECDecoder(dataShards, parityShards int) *fecDecoder { dec.codec = codec dec.decodeCache = make([][]byte, dec.shardSize) dec.flagCache = make([]bool, dec.shardSize) - dec.zeros = make([]byte, mtuLimit) return dec } @@ -199,7 +195,7 @@ func (dec *fecDecoder) decode(in fecPacket) (recovered [][]byte) { if shards[k] != nil { dlen := len(shards[k]) shards[k] = shards[k][:maxlen] - copy(shards[k][dlen:], dec.zeros) + clear(shards[k][dlen:]) } else if k < dec.dataShards { shards[k] = xmitBuf.Get().([]byte)[:0] } @@ -279,9 +275,6 @@ type ( shardCache [][]byte encodeCache [][]byte - // zeros - zeros []byte - // RS encoder codec reedsolomon.Encoder } @@ -311,7 +304,6 @@ func newFECEncoder(dataShards, parityShards, offset int) *fecEncoder { for k := range enc.shardCache { enc.shardCache[k] = make([]byte, mtuLimit) } - enc.zeros = make([]byte, mtuLimit) return enc } @@ -341,7 +333,7 @@ func (enc *fecEncoder) encode(b []byte) (ps [][]byte) { for i := 0; i < enc.dataShards; i++ { shard := enc.shardCache[i] slen := len(shard) - copy(shard[slen:enc.maxSize], enc.zeros) + clear(shard[slen:enc.maxSize]) } // construct equal-sized slice with stripped header diff --git a/vendor/github.com/xtaci/kcp-go/v5/sess.go b/vendor/github.com/xtaci/kcp-go/v5/sess.go index 2dedd74520919033994838ddcb2cd7485ceb35d2..35e7b8043f08184212485f4b9a5e15a4491b16c2 100644 --- a/vendor/github.com/xtaci/kcp-go/v5/sess.go +++ b/vendor/github.com/xtaci/kcp-go/v5/sess.go @@ -195,6 +195,16 @@ func newUDPSession(conv uint32, dataShards, parityShards int, l *Listener, conn // Read implements net.Conn func (s *UDPSession) Read(b []byte) (n int, err error) { + var timeout *time.Timer + // deadline for current reading operation + var c <-chan time.Time + if !s.rd.IsZero() { + delay := time.Until(s.rd) + timeout = time.NewTimer(delay) + c = timeout.C + defer timeout.Stop() + } + for { s.mu.Lock() if len(s.bufptr) > 0 { // copy from buffer into b @@ -228,27 +238,11 @@ func (s *UDPSession) Read(b []byte) (n int, err error) { return n, nil } - // deadline for current reading operation - var timeout *time.Timer - var c <-chan time.Time - if !s.rd.IsZero() { - if time.Now().After(s.rd) { - s.mu.Unlock() - return 0, errors.WithStack(errTimeout) - } - - delay := time.Until(s.rd) - timeout = time.NewTimer(delay) - c = timeout.C - } s.mu.Unlock() // wait for read event or timeout or error select { case <-s.chReadEvent: - if timeout != nil { - timeout.Stop() - } case <-c: return 0, errors.WithStack(errTimeout) case <-s.chSocketReadError: @@ -264,6 +258,15 @@ func (s *UDPSession) Write(b []byte) (n int, err error) { return s.WriteBuffers( // WriteBuffers write a vector of byte slices to the underlying connection func (s *UDPSession) WriteBuffers(v [][]byte) (n int, err error) { + var timeout *time.Timer + var c <-chan time.Time + if !s.wd.IsZero() { + delay := time.Until(s.wd) + timeout = time.NewTimer(delay) + c = timeout.C + defer timeout.Stop() + } + for { select { case <-s.chSocketWriteError: @@ -301,24 +304,10 @@ func (s *UDPSession) WriteBuffers(v [][]byte) (n int, err error) { return n, nil } - var timeout *time.Timer - var c <-chan time.Time - if !s.wd.IsZero() { - if time.Now().After(s.wd) { - s.mu.Unlock() - return 0, errors.WithStack(errTimeout) - } - delay := time.Until(s.wd) - timeout = time.NewTimer(delay) - c = timeout.C - } s.mu.Unlock() select { case <-s.chWriteEvent: - if timeout != nil { - timeout.Stop() - } case <-c: return 0, errors.WithStack(errTimeout) case <-s.chSocketWriteError: diff --git a/vendor/github.com/xtaci/kcp-go/v5/wechat_donate.jpg b/vendor/github.com/xtaci/kcp-go/v5/wechat_donate.jpg deleted file mode 100644 index ad72505ce56882faf47353fbc27c54826df29526..0000000000000000000000000000000000000000 Binary files a/vendor/github.com/xtaci/kcp-go/v5/wechat_donate.jpg and /dev/null differ diff --git a/vendor/modules.txt b/vendor/modules.txt index ffa7d6a2ef0b26edf14bd2a3d31224899170b75d..807ebea46f356f3c0bb2cfc854953e40c41597f3 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -7,8 +7,8 @@ 0xacab.org/leap/bitmask-core/pkg/introducer 0xacab.org/leap/bitmask-core/pkg/models 0xacab.org/leap/bitmask-core/pkg/storage -# 0xacab.org/leap/obfsvpn v0.0.0-20240422180703-83037b24d5cc -## explicit; go 1.20 +# 0xacab.org/leap/obfsvpn v1.0.1-0.20240625123757-59f234eea051 +## explicit; go 1.22 0xacab.org/leap/obfsvpn/client 0xacab.org/leap/obfsvpn/obfsvpn # filippo.io/edwards25519 v1.1.0 @@ -126,9 +126,6 @@ github.com/josharian/intern # github.com/jtolds/gls v4.20.0+incompatible ## explicit github.com/jtolds/gls -# github.com/kalikaneko/socks5 v1.0.1 -## explicit; go 1.16 -github.com/kalikaneko/socks5 # github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 ## explicit github.com/kardianos/osext @@ -328,8 +325,8 @@ github.com/tjfoc/gmsm/sm4 # github.com/xtaci/kcp-go v5.4.20+incompatible ## explicit github.com/xtaci/kcp-go -# github.com/xtaci/kcp-go/v5 v5.6.1 -## explicit; go 1.13 +# github.com/xtaci/kcp-go/v5 v5.6.3 +## explicit; go 1.21 github.com/xtaci/kcp-go/v5 # github.com/xtaci/smux v1.5.24 ## explicit; go 1.13