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