From f96ebab99f21004c0f4d2e723ce2be23a8e326f7 Mon Sep 17 00:00:00 2001
From: Dreamacro <8615343+Dreamacro@users.noreply.github.com>
Date: Thu, 13 May 2021 22:18:49 +0800
Subject: [PATCH 01/96] Chore: split component to transport
---
adapters/inbound/packet.go | 2 +-
adapters/inbound/socket.go | 2 +-
adapters/inbound/util.go | 2 +-
adapters/outbound/shadowsocks.go | 6 +++---
adapters/outbound/shadowsocksr.go | 4 ++--
adapters/outbound/snell.go | 4 ++--
adapters/outbound/socks5.go | 2 +-
adapters/outbound/trojan.go | 4 ++--
adapters/outbound/util.go | 2 +-
adapters/outbound/vmess.go | 4 ++--
proxy/mixed/mixed.go | 3 +--
proxy/redir/tcp_darwin.go | 2 +-
proxy/redir/tproxy.go | 2 +-
proxy/redir/udp.go | 2 +-
proxy/socks/tcp.go | 2 +-
proxy/socks/udp.go | 2 +-
proxy/socks/utils.go | 2 +-
{component => transport}/gun/gun.go | 0
{component => transport}/simple-obfs/http.go | 0
{component => transport}/simple-obfs/tls.go | 0
{component => transport}/snell/cipher.go | 0
{component => transport}/snell/pool.go | 0
{component => transport}/snell/snell.go | 0
{component => transport}/socks5/socks5.go | 0
{component => transport}/ssr/obfs/base.go | 0
{component => transport}/ssr/obfs/http_post.go | 0
{component => transport}/ssr/obfs/http_simple.go | 2 +-
{component => transport}/ssr/obfs/obfs.go | 0
{component => transport}/ssr/obfs/plain.go | 0
{component => transport}/ssr/obfs/random_head.go | 0
{component => transport}/ssr/obfs/tls1.2_ticket_auth.go | 2 +-
{component => transport}/ssr/protocol/auth_aes128_md5.go | 2 +-
{component => transport}/ssr/protocol/auth_aes128_sha1.go | 2 +-
{component => transport}/ssr/protocol/auth_chain_a.go | 2 +-
{component => transport}/ssr/protocol/auth_chain_b.go | 2 +-
{component => transport}/ssr/protocol/auth_sha1_v4.go | 2 +-
{component => transport}/ssr/protocol/base.go | 0
{component => transport}/ssr/protocol/origin.go | 0
{component => transport}/ssr/protocol/packet.go | 2 +-
{component => transport}/ssr/protocol/protocol.go | 0
{component => transport}/ssr/protocol/stream.go | 2 +-
{component => transport}/ssr/tools/bufPool.go | 0
{component => transport}/ssr/tools/crypto.go | 0
{component => transport}/ssr/tools/random.go | 0
{component => transport}/trojan/trojan.go | 2 +-
{component => transport}/v2ray-plugin/mux.go | 0
{component => transport}/v2ray-plugin/websocket.go | 2 +-
{component => transport}/vmess/aead.go | 0
{component => transport}/vmess/chunk.go | 0
{component => transport}/vmess/conn.go | 0
{component => transport}/vmess/h2.go | 0
{component => transport}/vmess/header.go | 0
{component => transport}/vmess/http.go | 0
{component => transport}/vmess/tls.go | 0
{component => transport}/vmess/user.go | 0
{component => transport}/vmess/vmess.go | 0
{component => transport}/vmess/websocket.go | 0
57 files changed, 34 insertions(+), 35 deletions(-)
rename {component => transport}/gun/gun.go (100%)
rename {component => transport}/simple-obfs/http.go (100%)
rename {component => transport}/simple-obfs/tls.go (100%)
rename {component => transport}/snell/cipher.go (100%)
rename {component => transport}/snell/pool.go (100%)
rename {component => transport}/snell/snell.go (100%)
rename {component => transport}/socks5/socks5.go (100%)
rename {component => transport}/ssr/obfs/base.go (100%)
rename {component => transport}/ssr/obfs/http_post.go (100%)
rename {component => transport}/ssr/obfs/http_simple.go (99%)
rename {component => transport}/ssr/obfs/obfs.go (100%)
rename {component => transport}/ssr/obfs/plain.go (100%)
rename {component => transport}/ssr/obfs/random_head.go (100%)
rename {component => transport}/ssr/obfs/tls1.2_ticket_auth.go (99%)
rename {component => transport}/ssr/protocol/auth_aes128_md5.go (87%)
rename {component => transport}/ssr/protocol/auth_aes128_sha1.go (99%)
rename {component => transport}/ssr/protocol/auth_chain_a.go (99%)
rename {component => transport}/ssr/protocol/auth_chain_b.go (97%)
rename {component => transport}/ssr/protocol/auth_sha1_v4.go (98%)
rename {component => transport}/ssr/protocol/base.go (100%)
rename {component => transport}/ssr/protocol/origin.go (100%)
rename {component => transport}/ssr/protocol/packet.go (93%)
rename {component => transport}/ssr/protocol/protocol.go (100%)
rename {component => transport}/ssr/protocol/stream.go (94%)
rename {component => transport}/ssr/tools/bufPool.go (100%)
rename {component => transport}/ssr/tools/crypto.go (100%)
rename {component => transport}/ssr/tools/random.go (100%)
rename {component => transport}/trojan/trojan.go (98%)
rename {component => transport}/v2ray-plugin/mux.go (100%)
rename {component => transport}/v2ray-plugin/websocket.go (95%)
rename {component => transport}/vmess/aead.go (100%)
rename {component => transport}/vmess/chunk.go (100%)
rename {component => transport}/vmess/conn.go (100%)
rename {component => transport}/vmess/h2.go (100%)
rename {component => transport}/vmess/header.go (100%)
rename {component => transport}/vmess/http.go (100%)
rename {component => transport}/vmess/tls.go (100%)
rename {component => transport}/vmess/user.go (100%)
rename {component => transport}/vmess/vmess.go (100%)
rename {component => transport}/vmess/websocket.go (100%)
diff --git a/adapters/inbound/packet.go b/adapters/inbound/packet.go
index 001a579b8..80b136cd6 100644
--- a/adapters/inbound/packet.go
+++ b/adapters/inbound/packet.go
@@ -1,8 +1,8 @@
package inbound
import (
- "github.com/Dreamacro/clash/component/socks5"
C "github.com/Dreamacro/clash/constant"
+ "github.com/Dreamacro/clash/transport/socks5"
)
// PacketAdapter is a UDP Packet adapter for socks/redir/tun
diff --git a/adapters/inbound/socket.go b/adapters/inbound/socket.go
index be772b7bc..be717017e 100644
--- a/adapters/inbound/socket.go
+++ b/adapters/inbound/socket.go
@@ -3,9 +3,9 @@ package inbound
import (
"net"
- "github.com/Dreamacro/clash/component/socks5"
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/context"
+ "github.com/Dreamacro/clash/transport/socks5"
)
// NewSocket receive TCP inbound and return ConnContext
diff --git a/adapters/inbound/util.go b/adapters/inbound/util.go
index 6241ac803..07577ec0e 100644
--- a/adapters/inbound/util.go
+++ b/adapters/inbound/util.go
@@ -6,8 +6,8 @@ import (
"strconv"
"strings"
- "github.com/Dreamacro/clash/component/socks5"
C "github.com/Dreamacro/clash/constant"
+ "github.com/Dreamacro/clash/transport/socks5"
)
func parseSocksAddr(target socks5.Addr) *C.Metadata {
diff --git a/adapters/outbound/shadowsocks.go b/adapters/outbound/shadowsocks.go
index edcd60abe..6dcfc2c08 100644
--- a/adapters/outbound/shadowsocks.go
+++ b/adapters/outbound/shadowsocks.go
@@ -10,10 +10,10 @@ import (
"github.com/Dreamacro/clash/common/structure"
"github.com/Dreamacro/clash/component/dialer"
- obfs "github.com/Dreamacro/clash/component/simple-obfs"
- "github.com/Dreamacro/clash/component/socks5"
- v2rayObfs "github.com/Dreamacro/clash/component/v2ray-plugin"
C "github.com/Dreamacro/clash/constant"
+ obfs "github.com/Dreamacro/clash/transport/simple-obfs"
+ "github.com/Dreamacro/clash/transport/socks5"
+ v2rayObfs "github.com/Dreamacro/clash/transport/v2ray-plugin"
"github.com/Dreamacro/go-shadowsocks2/core"
)
diff --git a/adapters/outbound/shadowsocksr.go b/adapters/outbound/shadowsocksr.go
index 6636d5ff9..635135fcd 100644
--- a/adapters/outbound/shadowsocksr.go
+++ b/adapters/outbound/shadowsocksr.go
@@ -8,9 +8,9 @@ import (
"strconv"
"github.com/Dreamacro/clash/component/dialer"
- "github.com/Dreamacro/clash/component/ssr/obfs"
- "github.com/Dreamacro/clash/component/ssr/protocol"
C "github.com/Dreamacro/clash/constant"
+ "github.com/Dreamacro/clash/transport/ssr/obfs"
+ "github.com/Dreamacro/clash/transport/ssr/protocol"
"github.com/Dreamacro/go-shadowsocks2/core"
"github.com/Dreamacro/go-shadowsocks2/shadowaead"
diff --git a/adapters/outbound/snell.go b/adapters/outbound/snell.go
index 0b65b272b..2dc16a511 100644
--- a/adapters/outbound/snell.go
+++ b/adapters/outbound/snell.go
@@ -8,9 +8,9 @@ import (
"github.com/Dreamacro/clash/common/structure"
"github.com/Dreamacro/clash/component/dialer"
- obfs "github.com/Dreamacro/clash/component/simple-obfs"
- "github.com/Dreamacro/clash/component/snell"
C "github.com/Dreamacro/clash/constant"
+ obfs "github.com/Dreamacro/clash/transport/simple-obfs"
+ "github.com/Dreamacro/clash/transport/snell"
)
type Snell struct {
diff --git a/adapters/outbound/socks5.go b/adapters/outbound/socks5.go
index 377d7d173..466797de8 100644
--- a/adapters/outbound/socks5.go
+++ b/adapters/outbound/socks5.go
@@ -11,8 +11,8 @@ import (
"strconv"
"github.com/Dreamacro/clash/component/dialer"
- "github.com/Dreamacro/clash/component/socks5"
C "github.com/Dreamacro/clash/constant"
+ "github.com/Dreamacro/clash/transport/socks5"
)
type Socks5 struct {
diff --git a/adapters/outbound/trojan.go b/adapters/outbound/trojan.go
index cfd734499..929f44147 100644
--- a/adapters/outbound/trojan.go
+++ b/adapters/outbound/trojan.go
@@ -9,9 +9,9 @@ import (
"strconv"
"github.com/Dreamacro/clash/component/dialer"
- "github.com/Dreamacro/clash/component/gun"
- "github.com/Dreamacro/clash/component/trojan"
C "github.com/Dreamacro/clash/constant"
+ "github.com/Dreamacro/clash/transport/gun"
+ "github.com/Dreamacro/clash/transport/trojan"
"golang.org/x/net/http2"
)
diff --git a/adapters/outbound/util.go b/adapters/outbound/util.go
index 932f741cc..cd60d3732 100644
--- a/adapters/outbound/util.go
+++ b/adapters/outbound/util.go
@@ -11,8 +11,8 @@ import (
"time"
"github.com/Dreamacro/clash/component/resolver"
- "github.com/Dreamacro/clash/component/socks5"
C "github.com/Dreamacro/clash/constant"
+ "github.com/Dreamacro/clash/transport/socks5"
)
const (
diff --git a/adapters/outbound/vmess.go b/adapters/outbound/vmess.go
index 528db7f5c..246450aca 100644
--- a/adapters/outbound/vmess.go
+++ b/adapters/outbound/vmess.go
@@ -11,10 +11,10 @@ import (
"strings"
"github.com/Dreamacro/clash/component/dialer"
- "github.com/Dreamacro/clash/component/gun"
"github.com/Dreamacro/clash/component/resolver"
- "github.com/Dreamacro/clash/component/vmess"
C "github.com/Dreamacro/clash/constant"
+ "github.com/Dreamacro/clash/transport/gun"
+ "github.com/Dreamacro/clash/transport/vmess"
"golang.org/x/net/http2"
)
diff --git a/proxy/mixed/mixed.go b/proxy/mixed/mixed.go
index 3328724e1..b89748eea 100644
--- a/proxy/mixed/mixed.go
+++ b/proxy/mixed/mixed.go
@@ -5,11 +5,10 @@ import (
"time"
"github.com/Dreamacro/clash/common/cache"
- "github.com/Dreamacro/clash/component/socks5"
"github.com/Dreamacro/clash/log"
-
"github.com/Dreamacro/clash/proxy/http"
"github.com/Dreamacro/clash/proxy/socks"
+ "github.com/Dreamacro/clash/transport/socks5"
)
type MixedListener struct {
diff --git a/proxy/redir/tcp_darwin.go b/proxy/redir/tcp_darwin.go
index 4e9ade1e5..5a2f331c3 100644
--- a/proxy/redir/tcp_darwin.go
+++ b/proxy/redir/tcp_darwin.go
@@ -5,7 +5,7 @@ import (
"syscall"
"unsafe"
- "github.com/Dreamacro/clash/component/socks5"
+ "github.com/Dreamacro/clash/transport/socks5"
)
func parserPacket(c net.Conn) (socks5.Addr, error) {
diff --git a/proxy/redir/tproxy.go b/proxy/redir/tproxy.go
index e2846e4f0..576c4d37f 100644
--- a/proxy/redir/tproxy.go
+++ b/proxy/redir/tproxy.go
@@ -4,9 +4,9 @@ import (
"net"
"github.com/Dreamacro/clash/adapters/inbound"
- "github.com/Dreamacro/clash/component/socks5"
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/log"
+ "github.com/Dreamacro/clash/transport/socks5"
"github.com/Dreamacro/clash/tunnel"
)
diff --git a/proxy/redir/udp.go b/proxy/redir/udp.go
index 45a726e07..57bd3ff35 100644
--- a/proxy/redir/udp.go
+++ b/proxy/redir/udp.go
@@ -5,8 +5,8 @@ import (
adapters "github.com/Dreamacro/clash/adapters/inbound"
"github.com/Dreamacro/clash/common/pool"
- "github.com/Dreamacro/clash/component/socks5"
C "github.com/Dreamacro/clash/constant"
+ "github.com/Dreamacro/clash/transport/socks5"
"github.com/Dreamacro/clash/tunnel"
)
diff --git a/proxy/socks/tcp.go b/proxy/socks/tcp.go
index 0f6c4fb4f..116ea3f6b 100644
--- a/proxy/socks/tcp.go
+++ b/proxy/socks/tcp.go
@@ -6,10 +6,10 @@ import (
"net"
adapters "github.com/Dreamacro/clash/adapters/inbound"
- "github.com/Dreamacro/clash/component/socks5"
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/log"
authStore "github.com/Dreamacro/clash/proxy/auth"
+ "github.com/Dreamacro/clash/transport/socks5"
"github.com/Dreamacro/clash/tunnel"
)
diff --git a/proxy/socks/udp.go b/proxy/socks/udp.go
index 38bc11313..a365353b8 100644
--- a/proxy/socks/udp.go
+++ b/proxy/socks/udp.go
@@ -6,9 +6,9 @@ import (
adapters "github.com/Dreamacro/clash/adapters/inbound"
"github.com/Dreamacro/clash/common/pool"
"github.com/Dreamacro/clash/common/sockopt"
- "github.com/Dreamacro/clash/component/socks5"
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/log"
+ "github.com/Dreamacro/clash/transport/socks5"
"github.com/Dreamacro/clash/tunnel"
)
diff --git a/proxy/socks/utils.go b/proxy/socks/utils.go
index 797e0a220..28dfef723 100644
--- a/proxy/socks/utils.go
+++ b/proxy/socks/utils.go
@@ -4,7 +4,7 @@ import (
"net"
"github.com/Dreamacro/clash/common/pool"
- "github.com/Dreamacro/clash/component/socks5"
+ "github.com/Dreamacro/clash/transport/socks5"
)
type packet struct {
diff --git a/component/gun/gun.go b/transport/gun/gun.go
similarity index 100%
rename from component/gun/gun.go
rename to transport/gun/gun.go
diff --git a/component/simple-obfs/http.go b/transport/simple-obfs/http.go
similarity index 100%
rename from component/simple-obfs/http.go
rename to transport/simple-obfs/http.go
diff --git a/component/simple-obfs/tls.go b/transport/simple-obfs/tls.go
similarity index 100%
rename from component/simple-obfs/tls.go
rename to transport/simple-obfs/tls.go
diff --git a/component/snell/cipher.go b/transport/snell/cipher.go
similarity index 100%
rename from component/snell/cipher.go
rename to transport/snell/cipher.go
diff --git a/component/snell/pool.go b/transport/snell/pool.go
similarity index 100%
rename from component/snell/pool.go
rename to transport/snell/pool.go
diff --git a/component/snell/snell.go b/transport/snell/snell.go
similarity index 100%
rename from component/snell/snell.go
rename to transport/snell/snell.go
diff --git a/component/socks5/socks5.go b/transport/socks5/socks5.go
similarity index 100%
rename from component/socks5/socks5.go
rename to transport/socks5/socks5.go
diff --git a/component/ssr/obfs/base.go b/transport/ssr/obfs/base.go
similarity index 100%
rename from component/ssr/obfs/base.go
rename to transport/ssr/obfs/base.go
diff --git a/component/ssr/obfs/http_post.go b/transport/ssr/obfs/http_post.go
similarity index 100%
rename from component/ssr/obfs/http_post.go
rename to transport/ssr/obfs/http_post.go
diff --git a/component/ssr/obfs/http_simple.go b/transport/ssr/obfs/http_simple.go
similarity index 99%
rename from component/ssr/obfs/http_simple.go
rename to transport/ssr/obfs/http_simple.go
index 86dea9475..26fb31247 100644
--- a/component/ssr/obfs/http_simple.go
+++ b/transport/ssr/obfs/http_simple.go
@@ -10,7 +10,7 @@ import (
"strings"
"github.com/Dreamacro/clash/common/pool"
- "github.com/Dreamacro/clash/component/ssr/tools"
+ "github.com/Dreamacro/clash/transport/ssr/tools"
)
func init() {
diff --git a/component/ssr/obfs/obfs.go b/transport/ssr/obfs/obfs.go
similarity index 100%
rename from component/ssr/obfs/obfs.go
rename to transport/ssr/obfs/obfs.go
diff --git a/component/ssr/obfs/plain.go b/transport/ssr/obfs/plain.go
similarity index 100%
rename from component/ssr/obfs/plain.go
rename to transport/ssr/obfs/plain.go
diff --git a/component/ssr/obfs/random_head.go b/transport/ssr/obfs/random_head.go
similarity index 100%
rename from component/ssr/obfs/random_head.go
rename to transport/ssr/obfs/random_head.go
diff --git a/component/ssr/obfs/tls1.2_ticket_auth.go b/transport/ssr/obfs/tls1.2_ticket_auth.go
similarity index 99%
rename from component/ssr/obfs/tls1.2_ticket_auth.go
rename to transport/ssr/obfs/tls1.2_ticket_auth.go
index f3c5b456d..d9141121c 100644
--- a/component/ssr/obfs/tls1.2_ticket_auth.go
+++ b/transport/ssr/obfs/tls1.2_ticket_auth.go
@@ -10,7 +10,7 @@ import (
"time"
"github.com/Dreamacro/clash/common/pool"
- "github.com/Dreamacro/clash/component/ssr/tools"
+ "github.com/Dreamacro/clash/transport/ssr/tools"
)
func init() {
diff --git a/component/ssr/protocol/auth_aes128_md5.go b/transport/ssr/protocol/auth_aes128_md5.go
similarity index 87%
rename from component/ssr/protocol/auth_aes128_md5.go
rename to transport/ssr/protocol/auth_aes128_md5.go
index 08e350c46..d3bc94172 100644
--- a/component/ssr/protocol/auth_aes128_md5.go
+++ b/transport/ssr/protocol/auth_aes128_md5.go
@@ -1,6 +1,6 @@
package protocol
-import "github.com/Dreamacro/clash/component/ssr/tools"
+import "github.com/Dreamacro/clash/transport/ssr/tools"
func init() {
register("auth_aes128_md5", newAuthAES128MD5, 9)
diff --git a/component/ssr/protocol/auth_aes128_sha1.go b/transport/ssr/protocol/auth_aes128_sha1.go
similarity index 99%
rename from component/ssr/protocol/auth_aes128_sha1.go
rename to transport/ssr/protocol/auth_aes128_sha1.go
index 503834562..65bcd7416 100644
--- a/component/ssr/protocol/auth_aes128_sha1.go
+++ b/transport/ssr/protocol/auth_aes128_sha1.go
@@ -10,8 +10,8 @@ import (
"strings"
"github.com/Dreamacro/clash/common/pool"
- "github.com/Dreamacro/clash/component/ssr/tools"
"github.com/Dreamacro/clash/log"
+ "github.com/Dreamacro/clash/transport/ssr/tools"
)
type hmacMethod func(key, data []byte) []byte
diff --git a/component/ssr/protocol/auth_chain_a.go b/transport/ssr/protocol/auth_chain_a.go
similarity index 99%
rename from component/ssr/protocol/auth_chain_a.go
rename to transport/ssr/protocol/auth_chain_a.go
index db51e1048..4ce55c1a6 100644
--- a/component/ssr/protocol/auth_chain_a.go
+++ b/transport/ssr/protocol/auth_chain_a.go
@@ -12,8 +12,8 @@ import (
"strings"
"github.com/Dreamacro/clash/common/pool"
- "github.com/Dreamacro/clash/component/ssr/tools"
"github.com/Dreamacro/clash/log"
+ "github.com/Dreamacro/clash/transport/ssr/tools"
"github.com/Dreamacro/go-shadowsocks2/core"
)
diff --git a/component/ssr/protocol/auth_chain_b.go b/transport/ssr/protocol/auth_chain_b.go
similarity index 97%
rename from component/ssr/protocol/auth_chain_b.go
rename to transport/ssr/protocol/auth_chain_b.go
index 2f3f8f17a..857b2a3aa 100644
--- a/component/ssr/protocol/auth_chain_b.go
+++ b/transport/ssr/protocol/auth_chain_b.go
@@ -4,7 +4,7 @@ import (
"net"
"sort"
- "github.com/Dreamacro/clash/component/ssr/tools"
+ "github.com/Dreamacro/clash/transport/ssr/tools"
)
func init() {
diff --git a/component/ssr/protocol/auth_sha1_v4.go b/transport/ssr/protocol/auth_sha1_v4.go
similarity index 98%
rename from component/ssr/protocol/auth_sha1_v4.go
rename to transport/ssr/protocol/auth_sha1_v4.go
index 0f24c360c..30392c9e7 100644
--- a/component/ssr/protocol/auth_sha1_v4.go
+++ b/transport/ssr/protocol/auth_sha1_v4.go
@@ -9,7 +9,7 @@ import (
"net"
"github.com/Dreamacro/clash/common/pool"
- "github.com/Dreamacro/clash/component/ssr/tools"
+ "github.com/Dreamacro/clash/transport/ssr/tools"
)
func init() {
diff --git a/component/ssr/protocol/base.go b/transport/ssr/protocol/base.go
similarity index 100%
rename from component/ssr/protocol/base.go
rename to transport/ssr/protocol/base.go
diff --git a/component/ssr/protocol/origin.go b/transport/ssr/protocol/origin.go
similarity index 100%
rename from component/ssr/protocol/origin.go
rename to transport/ssr/protocol/origin.go
diff --git a/component/ssr/protocol/packet.go b/transport/ssr/protocol/packet.go
similarity index 93%
rename from component/ssr/protocol/packet.go
rename to transport/ssr/protocol/packet.go
index 1577c7885..621dc8c8f 100644
--- a/component/ssr/protocol/packet.go
+++ b/transport/ssr/protocol/packet.go
@@ -4,7 +4,7 @@ import (
"bytes"
"net"
- "github.com/Dreamacro/clash/component/ssr/tools"
+ "github.com/Dreamacro/clash/transport/ssr/tools"
)
type PacketConn struct {
diff --git a/component/ssr/protocol/protocol.go b/transport/ssr/protocol/protocol.go
similarity index 100%
rename from component/ssr/protocol/protocol.go
rename to transport/ssr/protocol/protocol.go
diff --git a/component/ssr/protocol/stream.go b/transport/ssr/protocol/stream.go
similarity index 94%
rename from component/ssr/protocol/stream.go
rename to transport/ssr/protocol/stream.go
index 53f53ead4..25d46f74a 100644
--- a/component/ssr/protocol/stream.go
+++ b/transport/ssr/protocol/stream.go
@@ -5,7 +5,7 @@ import (
"net"
"github.com/Dreamacro/clash/common/pool"
- "github.com/Dreamacro/clash/component/ssr/tools"
+ "github.com/Dreamacro/clash/transport/ssr/tools"
)
type Conn struct {
diff --git a/component/ssr/tools/bufPool.go b/transport/ssr/tools/bufPool.go
similarity index 100%
rename from component/ssr/tools/bufPool.go
rename to transport/ssr/tools/bufPool.go
diff --git a/component/ssr/tools/crypto.go b/transport/ssr/tools/crypto.go
similarity index 100%
rename from component/ssr/tools/crypto.go
rename to transport/ssr/tools/crypto.go
diff --git a/component/ssr/tools/random.go b/transport/ssr/tools/random.go
similarity index 100%
rename from component/ssr/tools/random.go
rename to transport/ssr/tools/random.go
diff --git a/component/trojan/trojan.go b/transport/trojan/trojan.go
similarity index 98%
rename from component/trojan/trojan.go
rename to transport/trojan/trojan.go
index ef440d62b..88cc95fb1 100644
--- a/component/trojan/trojan.go
+++ b/transport/trojan/trojan.go
@@ -11,7 +11,7 @@ import (
"net"
"sync"
- "github.com/Dreamacro/clash/component/socks5"
+ "github.com/Dreamacro/clash/transport/socks5"
)
const (
diff --git a/component/v2ray-plugin/mux.go b/transport/v2ray-plugin/mux.go
similarity index 100%
rename from component/v2ray-plugin/mux.go
rename to transport/v2ray-plugin/mux.go
diff --git a/component/v2ray-plugin/websocket.go b/transport/v2ray-plugin/websocket.go
similarity index 95%
rename from component/v2ray-plugin/websocket.go
rename to transport/v2ray-plugin/websocket.go
index fbd1f3e32..9feaf2c2f 100644
--- a/component/v2ray-plugin/websocket.go
+++ b/transport/v2ray-plugin/websocket.go
@@ -5,7 +5,7 @@ import (
"net"
"net/http"
- "github.com/Dreamacro/clash/component/vmess"
+ "github.com/Dreamacro/clash/transport/vmess"
)
// Option is options of websocket obfs
diff --git a/component/vmess/aead.go b/transport/vmess/aead.go
similarity index 100%
rename from component/vmess/aead.go
rename to transport/vmess/aead.go
diff --git a/component/vmess/chunk.go b/transport/vmess/chunk.go
similarity index 100%
rename from component/vmess/chunk.go
rename to transport/vmess/chunk.go
diff --git a/component/vmess/conn.go b/transport/vmess/conn.go
similarity index 100%
rename from component/vmess/conn.go
rename to transport/vmess/conn.go
diff --git a/component/vmess/h2.go b/transport/vmess/h2.go
similarity index 100%
rename from component/vmess/h2.go
rename to transport/vmess/h2.go
diff --git a/component/vmess/header.go b/transport/vmess/header.go
similarity index 100%
rename from component/vmess/header.go
rename to transport/vmess/header.go
diff --git a/component/vmess/http.go b/transport/vmess/http.go
similarity index 100%
rename from component/vmess/http.go
rename to transport/vmess/http.go
diff --git a/component/vmess/tls.go b/transport/vmess/tls.go
similarity index 100%
rename from component/vmess/tls.go
rename to transport/vmess/tls.go
diff --git a/component/vmess/user.go b/transport/vmess/user.go
similarity index 100%
rename from component/vmess/user.go
rename to transport/vmess/user.go
diff --git a/component/vmess/vmess.go b/transport/vmess/vmess.go
similarity index 100%
rename from component/vmess/vmess.go
rename to transport/vmess/vmess.go
diff --git a/component/vmess/websocket.go b/transport/vmess/websocket.go
similarity index 100%
rename from component/vmess/websocket.go
rename to transport/vmess/websocket.go
From 4e5898197aed4e944f8ad9d2139c24ffd0ad6a95 Mon Sep 17 00:00:00 2001
From: Dreamacro <8615343+Dreamacro@users.noreply.github.com>
Date: Thu, 13 May 2021 22:39:33 +0800
Subject: [PATCH 02/96] Fix: build broken
---
proxy/redir/tcp_freebsd.go | 2 +-
proxy/redir/tcp_linux.go | 2 +-
proxy/redir/tcp_other.go | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/proxy/redir/tcp_freebsd.go b/proxy/redir/tcp_freebsd.go
index f9cdf5a6a..12c4ba6ae 100644
--- a/proxy/redir/tcp_freebsd.go
+++ b/proxy/redir/tcp_freebsd.go
@@ -6,7 +6,7 @@ import (
"syscall"
"unsafe"
- "github.com/Dreamacro/clash/component/socks5"
+ "github.com/Dreamacro/clash/transport/socks5"
)
const (
diff --git a/proxy/redir/tcp_linux.go b/proxy/redir/tcp_linux.go
index ac3a455c3..e802319cd 100644
--- a/proxy/redir/tcp_linux.go
+++ b/proxy/redir/tcp_linux.go
@@ -6,7 +6,7 @@ import (
"syscall"
"unsafe"
- "github.com/Dreamacro/clash/component/socks5"
+ "github.com/Dreamacro/clash/transport/socks5"
)
const (
diff --git a/proxy/redir/tcp_other.go b/proxy/redir/tcp_other.go
index 21743ec08..50968e9ab 100644
--- a/proxy/redir/tcp_other.go
+++ b/proxy/redir/tcp_other.go
@@ -6,7 +6,7 @@ import (
"errors"
"net"
- "github.com/Dreamacro/clash/component/socks5"
+ "github.com/Dreamacro/clash/transport/socks5"
)
func parserPacket(conn net.Conn) (socks5.Addr, error) {
From 06fdd3abe0ab610a57ce88c448e59003d3c13368 Mon Sep 17 00:00:00 2001
From: Dreamacro <8615343+Dreamacro@users.noreply.github.com>
Date: Sun, 16 May 2021 20:05:41 +0800
Subject: [PATCH 03/96] Fix: vmess http should use Host header on request
---
transport/vmess/http.go | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/transport/vmess/http.go b/transport/vmess/http.go
index 5c1a5bd1c..1c09e215a 100644
--- a/transport/vmess/http.go
+++ b/transport/vmess/http.go
@@ -52,7 +52,12 @@ func (hc *httpConn) Write(b []byte) (int, error) {
}
path := hc.cfg.Path[rand.Intn(len(hc.cfg.Path))]
- u := fmt.Sprintf("http://%s%s", hc.cfg.Host, path)
+ host := hc.cfg.Host
+ if header := hc.cfg.Headers["Host"]; len(header) != 0 {
+ host = header[rand.Intn(len(header))]
+ }
+
+ u := fmt.Sprintf("http://%s%s", host, path)
req, _ := http.NewRequest("GET", u, bytes.NewBuffer(b))
for key, list := range hc.cfg.Headers {
req.Header.Set(key, list[rand.Intn(len(list))])
From d5e52bed433c73369e4571cd42b469ddae4afb56 Mon Sep 17 00:00:00 2001
From: Dreamacro <8615343+Dreamacro@users.noreply.github.com>
Date: Mon, 17 May 2021 20:33:00 +0800
Subject: [PATCH 04/96] Feature: add protocol test
---
test/README.md | 49 +++
test/clash_test.go | 635 ++++++++++++++++++++++++++++++++
test/config/example.org-key.pem | 28 ++
test/config/example.org.pem | 25 ++
test/config/snell-http.conf | 4 +
test/config/snell-tls.conf | 4 +
test/config/snell.conf | 3 +
test/config/trojan-grpc.json | 40 ++
test/config/trojan.json | 40 ++
test/config/vmess-aead.json | 28 ++
test/config/vmess-grpc.json | 40 ++
test/config/vmess-http.json | 55 +++
test/config/vmess-http2.json | 43 +++
test/config/vmess-tls.json | 37 ++
test/config/vmess-ws-tls.json | 34 ++
test/config/vmess-ws.json | 26 ++
test/config/vmess.json | 28 ++
test/dns_test.go | 103 ++++++
test/docker_test.go | 45 +++
test/go.mod | 26 ++
test/go.sum | 202 ++++++++++
test/snell_test.go | 121 ++++++
test/ss_test.go | 172 +++++++++
test/trojan_test.go | 94 +++++
test/util_test.go | 70 ++++
test/vmess_test.go | 347 +++++++++++++++++
26 files changed, 2299 insertions(+)
create mode 100644 test/README.md
create mode 100644 test/clash_test.go
create mode 100644 test/config/example.org-key.pem
create mode 100644 test/config/example.org.pem
create mode 100644 test/config/snell-http.conf
create mode 100644 test/config/snell-tls.conf
create mode 100644 test/config/snell.conf
create mode 100644 test/config/trojan-grpc.json
create mode 100644 test/config/trojan.json
create mode 100644 test/config/vmess-aead.json
create mode 100644 test/config/vmess-grpc.json
create mode 100644 test/config/vmess-http.json
create mode 100644 test/config/vmess-http2.json
create mode 100644 test/config/vmess-tls.json
create mode 100644 test/config/vmess-ws-tls.json
create mode 100644 test/config/vmess-ws.json
create mode 100644 test/config/vmess.json
create mode 100644 test/dns_test.go
create mode 100644 test/docker_test.go
create mode 100644 test/go.mod
create mode 100644 test/go.sum
create mode 100644 test/snell_test.go
create mode 100644 test/ss_test.go
create mode 100644 test/trojan_test.go
create mode 100644 test/util_test.go
create mode 100644 test/vmess_test.go
diff --git a/test/README.md b/test/README.md
new file mode 100644
index 000000000..dec9999c2
--- /dev/null
+++ b/test/README.md
@@ -0,0 +1,49 @@
+## Clash testing suit
+
+### Protocol testing suit
+
+* TCP pingpong test
+* UDP pingpong test
+* TCP large data test
+* UDP large data test
+
+### Protocols
+
+- [x] Shadowsocks
+ - [x] Normal
+ - [x] ObfsHTTP
+ - [x] ObfsTLS
+ - [x] ObfsV2rayPlugin
+- [x] Vmess
+ - [x] Normal
+ - [x] AEAD
+ - [x] HTTP
+ - [x] HTTP2
+ - [x] TLS
+ - [x] Websocket
+ - [x] Websocket TLS
+ - [x] gRPC
+- [x] Trojan
+ - [x] Normal
+ - [x] gRPC
+- [x] Snell
+ - [x] Normal
+ - [x] ObfsHTTP
+ - [x] ObfsTLS
+
+### Features
+
+- [ ] DNS
+ - [x] DNS Server
+ - [x] FakeIP
+ - [x] Host
+
+### Command
+
+Prerequisite
+
+* docker (support Linux and macOS)
+
+```
+$ go test -p 1 -v
+```
diff --git a/test/clash_test.go b/test/clash_test.go
new file mode 100644
index 000000000..e835b0fec
--- /dev/null
+++ b/test/clash_test.go
@@ -0,0 +1,635 @@
+package main
+
+import (
+ "context"
+ "crypto/md5"
+ "crypto/rand"
+ "errors"
+ "fmt"
+ "io"
+ "net"
+ "os"
+ "path/filepath"
+ "runtime"
+ "sync"
+ "testing"
+ "time"
+
+ C "github.com/Dreamacro/clash/constant"
+ "github.com/Dreamacro/clash/hub/executor"
+ "github.com/Dreamacro/clash/transport/socks5"
+
+ "github.com/docker/docker/api/types"
+ "github.com/docker/docker/client"
+ "github.com/docker/go-connections/nat"
+ "github.com/stretchr/testify/assert"
+)
+
+const (
+ ImageShadowsocks = "mritd/shadowsocks:latest"
+ ImageVmess = "v2fly/v2fly-core:latest"
+ ImageTrojan = "trojangfw/trojan:latest"
+ ImageSnell = "icpz/snell-server:latest"
+ ImageXray = "teddysun/xray:latest"
+)
+
+var (
+ waitTime = time.Second
+ localIP = net.ParseIP("127.0.0.1")
+
+ defaultExposedPorts = nat.PortSet{
+ "10002/tcp": struct{}{},
+ "10002/udp": struct{}{},
+ }
+ defaultPortBindings = nat.PortMap{
+ "10002/tcp": []nat.PortBinding{
+ {HostPort: "10002", HostIP: "0.0.0.0"},
+ },
+ "10002/udp": []nat.PortBinding{
+ {HostPort: "10002", HostIP: "0.0.0.0"},
+ },
+ }
+)
+
+func init() {
+ if runtime.GOOS == "darwin" {
+ isDarwin = true
+ }
+
+ currentDir, err := os.Getwd()
+ if err != nil {
+ panic(err)
+ }
+ homeDir := filepath.Join(currentDir, "config")
+ C.SetHomeDir(homeDir)
+
+ if isDarwin {
+ localIP, err = defaultRouteIP()
+ if err != nil {
+ panic(err)
+ }
+ }
+
+ c, err := client.NewClientWithOpts(client.FromEnv)
+ if err != nil {
+ panic(err)
+ }
+ defer c.Close()
+
+ list, err := c.ImageList(context.Background(), types.ImageListOptions{All: true})
+ if err != nil {
+ panic(err)
+ }
+
+ imageExist := func(image string) bool {
+ for _, item := range list {
+ for _, tag := range item.RepoTags {
+ if image == tag {
+ return true
+ }
+ }
+ }
+ return false
+ }
+
+ images := []string{
+ ImageShadowsocks,
+ ImageVmess,
+ ImageTrojan,
+ ImageSnell,
+ ImageXray,
+ }
+
+ for _, image := range images {
+ if imageExist(image) {
+ continue
+ }
+
+ imageStream, err := c.ImagePull(context.Background(), image, types.ImagePullOptions{})
+ if err != nil {
+ panic(err)
+ }
+
+ io.Copy(io.Discard, imageStream)
+ }
+}
+
+var clean = `
+port: 0
+socks-port: 0
+mixed-port: 0
+redir-port: 0
+tproxy-port: 0
+dns:
+ enable: false
+`
+
+func cleanup() {
+ parseAndApply(clean)
+}
+
+func parseAndApply(cfgStr string) error {
+ cfg, err := executor.ParseWithBytes([]byte(cfgStr))
+ if err != nil {
+ return err
+ }
+
+ executor.ApplyConfig(cfg, true)
+ return nil
+}
+
+func newPingPongPair() (chan []byte, chan []byte, func(t *testing.T) error) {
+ pingCh := make(chan []byte)
+ pongCh := make(chan []byte)
+ test := func(t *testing.T) error {
+ defer close(pingCh)
+ defer close(pongCh)
+ pingOpen := false
+ pongOpen := false
+ var recv []byte
+
+ for {
+ if pingOpen && pongOpen {
+ break
+ }
+
+ select {
+ case recv, pingOpen = <-pingCh:
+ assert.True(t, pingOpen)
+ assert.Equal(t, []byte("ping"), recv)
+ case recv, pongOpen = <-pongCh:
+ assert.True(t, pongOpen)
+ assert.Equal(t, []byte("pong"), recv)
+ case <-time.After(10 * time.Second):
+ return errors.New("timeout")
+ }
+ }
+ return nil
+ }
+
+ return pingCh, pongCh, test
+}
+
+func newLargeDataPair() (chan hashPair, chan hashPair, func(t *testing.T) error) {
+ pingCh := make(chan hashPair)
+ pongCh := make(chan hashPair)
+ test := func(t *testing.T) error {
+ defer close(pingCh)
+ defer close(pongCh)
+ pingOpen := false
+ pongOpen := false
+ var serverPair hashPair
+ var clientPair hashPair
+
+ for {
+ if pingOpen && pongOpen {
+ break
+ }
+
+ select {
+ case serverPair, pingOpen = <-pingCh:
+ assert.True(t, pingOpen)
+ case clientPair, pongOpen = <-pongCh:
+ assert.True(t, pongOpen)
+ case <-time.After(10 * time.Second):
+ return errors.New("timeout")
+ }
+ }
+
+ assert.Equal(t, serverPair.recvHash, clientPair.sendHash)
+ assert.Equal(t, serverPair.sendHash, clientPair.recvHash)
+
+ return nil
+ }
+
+ return pingCh, pongCh, test
+}
+
+func testPingPongWithSocksPort(t *testing.T, port int) {
+ pingCh, pongCh, test := newPingPongPair()
+ go func() {
+ l, err := net.Listen("tcp", ":10001")
+ if err != nil {
+ assert.FailNow(t, err.Error())
+ }
+
+ c, err := l.Accept()
+ if err != nil {
+ assert.FailNow(t, err.Error())
+ }
+
+ buf := make([]byte, 4)
+ if _, err := io.ReadFull(c, buf); err != nil {
+ assert.FailNow(t, err.Error())
+ }
+
+ pingCh <- buf
+ if _, err := c.Write([]byte("pong")); err != nil {
+ assert.FailNow(t, err.Error())
+ }
+ l.Close()
+ }()
+
+ go func() {
+ c, err := net.Dial("tcp", fmt.Sprintf("127.0.0.1:%d", port))
+ if err != nil {
+ assert.FailNow(t, err.Error())
+ }
+
+ if _, err := socks5.ClientHandshake(c, socks5.ParseAddr("127.0.0.1:10001"), socks5.CmdConnect, nil); err != nil {
+ assert.FailNow(t, err.Error())
+ }
+
+ if _, err := c.Write([]byte("ping")); err != nil {
+ assert.FailNow(t, err.Error())
+ }
+
+ buf := make([]byte, 4)
+ if _, err := io.ReadFull(c, buf); err != nil {
+ assert.FailNow(t, err.Error())
+ }
+
+ pongCh <- buf
+ c.Close()
+ }()
+
+ test(t)
+}
+
+func testPingPongWithConn(t *testing.T, c net.Conn) error {
+ l, err := net.Listen("tcp", ":10001")
+ if err != nil {
+ return err
+ }
+ defer l.Close()
+
+ pingCh, pongCh, test := newPingPongPair()
+ go func() {
+ c, err := l.Accept()
+ if err != nil {
+ return
+ }
+
+ buf := make([]byte, 4)
+ if _, err := io.ReadFull(c, buf); err != nil {
+ return
+ }
+
+ pingCh <- buf
+ if _, err := c.Write([]byte("pong")); err != nil {
+ return
+ }
+ }()
+
+ go func() {
+ if _, err := c.Write([]byte("ping")); err != nil {
+ return
+ }
+
+ buf := make([]byte, 4)
+ if _, err := io.ReadFull(c, buf); err != nil {
+ return
+ }
+
+ pongCh <- buf
+ }()
+
+ return test(t)
+}
+
+func testPingPongWithPacketConn(t *testing.T, pc net.PacketConn) error {
+ l, err := net.ListenPacket("udp", ":10001")
+ if err != nil {
+ return err
+ }
+ defer l.Close()
+
+ rAddr := &net.UDPAddr{IP: localIP, Port: 10001}
+
+ pingCh, pongCh, test := newPingPongPair()
+ go func() {
+ buf := make([]byte, 1024)
+ n, rAddr, err := l.ReadFrom(buf)
+ if err != nil {
+ return
+ }
+
+ pingCh <- buf[:n]
+ if _, err := l.WriteTo([]byte("pong"), rAddr); err != nil {
+ return
+ }
+ }()
+
+ go func() {
+ if _, err := pc.WriteTo([]byte("ping"), rAddr); err != nil {
+ return
+ }
+
+ buf := make([]byte, 1024)
+ n, _, err := pc.ReadFrom(buf)
+ if err != nil {
+ return
+ }
+
+ pongCh <- buf[:n]
+ }()
+
+ return test(t)
+}
+
+type hashPair struct {
+ sendHash map[int][]byte
+ recvHash map[int][]byte
+}
+
+func testLargeDataWithConn(t *testing.T, c net.Conn) error {
+ l, err := net.Listen("tcp", ":10001")
+ if err != nil {
+ return err
+ }
+ defer l.Close()
+
+ times := 100
+ chunkSize := int64(64 * 1024)
+
+ pingCh, pongCh, test := newLargeDataPair()
+ writeRandData := func(conn net.Conn) (map[int][]byte, error) {
+ buf := make([]byte, chunkSize)
+ hashMap := map[int][]byte{}
+ for i := 0; i < times; i++ {
+ if _, err := rand.Read(buf[1:]); err != nil {
+ return nil, err
+ }
+ buf[0] = byte(i)
+
+ hash := md5.Sum(buf)
+ hashMap[i] = hash[:]
+
+ if _, err := conn.Write(buf); err != nil {
+ return nil, err
+ }
+ }
+
+ return hashMap, nil
+ }
+
+ go func() {
+ c, err := l.Accept()
+ if err != nil {
+ return
+ }
+
+ hashMap := map[int][]byte{}
+ buf := make([]byte, chunkSize)
+
+ for i := 0; i < times; i++ {
+ _, err := io.ReadFull(c, buf)
+ if err != nil {
+ t.Log(err.Error())
+ return
+ }
+
+ hash := md5.Sum(buf)
+ hashMap[int(buf[0])] = hash[:]
+ }
+
+ sendHash, err := writeRandData(c)
+ if err != nil {
+ t.Log(err.Error())
+ return
+ }
+
+ pingCh <- hashPair{
+ sendHash: sendHash,
+ recvHash: hashMap,
+ }
+ }()
+
+ go func() {
+ sendHash, err := writeRandData(c)
+ if err != nil {
+ t.Log(err.Error())
+ return
+ }
+
+ hashMap := map[int][]byte{}
+ buf := make([]byte, chunkSize)
+
+ for i := 0; i < times; i++ {
+ _, err := io.ReadFull(c, buf)
+ if err != nil {
+ t.Log(err.Error())
+ return
+ }
+
+ hash := md5.Sum(buf)
+ hashMap[int(buf[0])] = hash[:]
+ }
+
+ pongCh <- hashPair{
+ sendHash: sendHash,
+ recvHash: hashMap,
+ }
+ }()
+
+ return test(t)
+}
+
+func testLargeDataWithPacketConn(t *testing.T, pc net.PacketConn) error {
+ l, err := net.ListenPacket("udp", ":10001")
+ if err != nil {
+ return err
+ }
+ defer l.Close()
+
+ rAddr := &net.UDPAddr{IP: localIP, Port: 10001}
+
+ times := 50
+ chunkSize := int64(1024)
+
+ pingCh, pongCh, test := newLargeDataPair()
+ writeRandData := func(pc net.PacketConn, addr net.Addr) (map[int][]byte, error) {
+ hashMap := map[int][]byte{}
+ mux := sync.Mutex{}
+ for i := 0; i < times; i++ {
+ go func(idx int) {
+ buf := make([]byte, chunkSize)
+ if _, err := rand.Read(buf[1:]); err != nil {
+ t.Log(err.Error())
+ return
+ }
+ buf[0] = byte(idx)
+
+ hash := md5.Sum(buf)
+ mux.Lock()
+ hashMap[idx] = hash[:]
+ mux.Unlock()
+
+ if _, err := pc.WriteTo(buf, addr); err != nil {
+ t.Log(err.Error())
+ return
+ }
+ }(i)
+ }
+
+ return hashMap, nil
+ }
+
+ go func() {
+ var rAddr net.Addr
+ hashMap := map[int][]byte{}
+ buf := make([]byte, 64*1024)
+
+ for i := 0; i < times; i++ {
+ _, rAddr, err = l.ReadFrom(buf)
+ if err != nil {
+ t.Log(err.Error())
+ return
+ }
+
+ hash := md5.Sum(buf[:chunkSize])
+ hashMap[int(buf[0])] = hash[:]
+ }
+
+ sendHash, err := writeRandData(l, rAddr)
+ if err != nil {
+ t.Log(err.Error())
+ return
+ }
+
+ pingCh <- hashPair{
+ sendHash: sendHash,
+ recvHash: hashMap,
+ }
+ }()
+
+ go func() {
+ sendHash, err := writeRandData(pc, rAddr)
+ if err != nil {
+ t.Log(err.Error())
+ return
+ }
+
+ hashMap := map[int][]byte{}
+ buf := make([]byte, 64*1024)
+
+ for i := 0; i < times; i++ {
+ _, _, err := pc.ReadFrom(buf)
+ if err != nil {
+ t.Log(err.Error())
+ return
+ }
+
+ hash := md5.Sum(buf[:chunkSize])
+ hashMap[int(buf[0])] = hash[:]
+ }
+
+ pongCh <- hashPair{
+ sendHash: sendHash,
+ recvHash: hashMap,
+ }
+ }()
+
+ return test(t)
+}
+
+func testPacketConnTimeout(t *testing.T, pc net.PacketConn) error {
+ err := pc.SetReadDeadline(time.Now().Add(time.Millisecond * 300))
+ assert.NoError(t, err)
+
+ errCh := make(chan error, 1)
+ go func() {
+ buf := make([]byte, 1024)
+ _, _, err := pc.ReadFrom(buf)
+ errCh <- err
+ }()
+
+ select {
+ case <-errCh:
+ return nil
+ case <-time.After(time.Second * 10):
+ return errors.New("timeout")
+ }
+}
+
+func testSuit(t *testing.T, proxy C.ProxyAdapter) {
+ conn, err := proxy.DialContext(context.Background(), &C.Metadata{
+ Host: localIP.String(),
+ DstPort: "10001",
+ AddrType: socks5.AtypDomainName,
+ })
+ if err != nil {
+ assert.FailNow(t, err.Error())
+ }
+ defer conn.Close()
+ assert.NoError(t, testPingPongWithConn(t, conn))
+
+ conn, err = proxy.DialContext(context.Background(), &C.Metadata{
+ Host: localIP.String(),
+ DstPort: "10001",
+ AddrType: socks5.AtypDomainName,
+ })
+ if err != nil {
+ assert.FailNow(t, err.Error())
+ }
+ defer conn.Close()
+ assert.NoError(t, testLargeDataWithConn(t, conn))
+
+ if !proxy.SupportUDP() {
+ return
+ }
+
+ pc, err := proxy.DialUDP(&C.Metadata{
+ NetWork: C.UDP,
+ DstIP: localIP,
+ DstPort: "10001",
+ AddrType: socks5.AtypIPv4,
+ })
+ if err != nil {
+ assert.FailNow(t, err.Error())
+ }
+ defer pc.Close()
+
+ assert.NoError(t, testPingPongWithPacketConn(t, pc))
+
+ pc, err = proxy.DialUDP(&C.Metadata{
+ NetWork: C.UDP,
+ DstIP: localIP,
+ DstPort: "10001",
+ AddrType: socks5.AtypIPv4,
+ })
+ if err != nil {
+ assert.FailNow(t, err.Error())
+ }
+ defer pc.Close()
+
+ assert.NoError(t, testLargeDataWithPacketConn(t, pc))
+
+ pc, err = proxy.DialUDP(&C.Metadata{
+ NetWork: C.UDP,
+ DstIP: localIP,
+ DstPort: "10001",
+ AddrType: socks5.AtypIPv4,
+ })
+ if err != nil {
+ assert.FailNow(t, err.Error())
+ }
+ defer pc.Close()
+
+ assert.NoError(t, testPacketConnTimeout(t, pc))
+}
+
+func TestClash_Basic(t *testing.T) {
+ basic := `
+mixed-port: 10000
+log-level: silent
+`
+
+ if err := parseAndApply(basic); err != nil {
+ assert.FailNow(t, err.Error())
+ }
+ defer cleanup()
+
+ time.Sleep(waitTime)
+ testPingPongWithSocksPort(t, 10000)
+}
diff --git a/test/config/example.org-key.pem b/test/config/example.org-key.pem
new file mode 100644
index 000000000..dbe9a3db3
--- /dev/null
+++ b/test/config/example.org-key.pem
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDQ+c++LkDTdaw5
+5spCu9MWMcvVdrYBZZ5qZy7DskphSUSQp25cIu34GJXVPNxtbWx1CQCmdLlwqXvo
+PfUt5/pz9qsfhdAbzFduZQgGd7GTQOTJBDrAhm2+iVsQyGHHhF68muN+SgT+AtRE
+sJyZoHNYtjjWEIHQ++FHEDqwUVnj6Ut99LHlyfCjOZ5+WyBiKCjyMNots/gDep7R
+i4X2kMTqNMIIqPUcAaP5EQk41bJbFhKe915qN9b1dRISKFKmiWeOsxgTB/O/EaL5
+LsBYwZ/BiIMDk30aZvzRJeloasIR3z4hrKQqBfB0lfeIdiPpJIs5rXJQEiWH89ge
+gplsLbfrAgMBAAECggEBAKpMGaZzDPMF/v8Ee6lcZM2+cMyZPALxa+JsCakCvyh+
+y7hSKVY+RM0cQ+YM/djTBkJtvrDniEMuasI803PAitI7nwJGSuyMXmehP6P9oKFO
+jeLeZn6ETiSqzKJlmYE89vMeCevdqCnT5mW/wy5Smg0eGj0gIJpM2S3PJPSQpv9Z
+ots0JXkwooJcpGWzlwPkjSouY2gDbE4Coi+jmYLNjA1k5RbggcutnUCZZkJ6yMNv
+H52VjnkffpAFHRouK/YgF+5nbMyyw5YTLOyTWBq7qfBMsXynkWLU73GC/xDZa3yG
+o/Ph2knXCjgLmCRessTOObdOXedjnGWIjiqF8fVboDECgYEA6x5CteYiwthDBULZ
+CG5nE9VKkRHJYdArm+VjmGbzK51tKli112avmU4r3ol907+mEa4tWLkPqdZrrL49
+aHltuHizZJixJcw0rcI302ot/Ov0gkF9V55gnAQS/Kemvx9FHWm5NHdYvbObzj33
+bYRLJBtJWzYg9M8Bw9ZrUnegc/MCgYEA44kq5OSYCbyu3eaX8XHTtFhuQHNFjwl7
+Xk/Oel6PVZzmt+oOlDHnOfGSB/KpR3YXxFRngiiPZzbrOwFyPGe7HIfg03HAXiJh
+ivEfrPHbQqQUI/4b44GpDy6bhNtz777ivFGYEt21vpwd89rFiye+RkqF8eL/evxO
+pUayDZYvwikCgYEA07wFoZ/lkAiHmpZPsxsRcrfzFd+pto9splEWtumHdbCo3ajT
+4W5VFr9iHF8/VFDT8jokFjFaXL1/bCpKTOqFl8oC68XiSkKy8gPkmFyXm5y2LhNi
+GGTFZdr5alRkgttbN5i9M/WCkhvMZRhC2Xp43MRB9IUzeqNtWHqhXbvjYGcCgYEA
+vTMOztviLJ6PjYa0K5lp31l0+/SeD21j/y0/VPOSHi9kjeN7EfFZAw6DTkaSShDB
+fIhutYVCkSHSgfMW6XGb3gKCiW/Z9KyEDYOowicuGgDTmoYu7IOhbzVjLhtJET7Z
+zJvQZ0eiW4f3RBFTF/4JMuu+6z7FD6ADSV06qx+KQNkCgYBw26iQxmT5e/4kVv8X
+DzBJ1HuliKBnnzZA1YRjB4H8F6Yrq+9qur1Lurez4YlbkGV8yPFt+Iu82ViUWL28
+9T7Jgp3TOpf8qOqsWFv8HldpEZbE0Tcib4x6s+zOg/aw0ac/xOPY1sCVFB81VODP
+XCar+uxMBXI1zbXqd9QdEwy4Ig==
+-----END PRIVATE KEY-----
diff --git a/test/config/example.org.pem b/test/config/example.org.pem
new file mode 100644
index 000000000..9b99259a3
--- /dev/null
+++ b/test/config/example.org.pem
@@ -0,0 +1,25 @@
+-----BEGIN CERTIFICATE-----
+MIIESzCCArOgAwIBAgIQIi5xRZvFZaSweWU9Y5mExjANBgkqhkiG9w0BAQsFADCB
+hzEeMBwGA1UEChMVbWtjZXJ0IGRldmVsb3BtZW50IENBMS4wLAYDVQQLDCVkcmVh
+bWFjcm9ARHJlYW1hY3JvLmxvY2FsIChEcmVhbWFjcm8pMTUwMwYDVQQDDCxta2Nl
+cnQgZHJlYW1hY3JvQERyZWFtYWNyby5sb2NhbCAoRHJlYW1hY3JvKTAeFw0yMTAz
+MTcxNDQwMzZaFw0yMzA2MTcxNDQwMzZaMFkxJzAlBgNVBAoTHm1rY2VydCBkZXZl
+bG9wbWVudCBjZXJ0aWZpY2F0ZTEuMCwGA1UECwwlZHJlYW1hY3JvQERyZWFtYWNy
+by5sb2NhbCAoRHJlYW1hY3JvKTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
+ggEBAND5z74uQNN1rDnmykK70xYxy9V2tgFlnmpnLsOySmFJRJCnblwi7fgYldU8
+3G1tbHUJAKZ0uXCpe+g99S3n+nP2qx+F0BvMV25lCAZ3sZNA5MkEOsCGbb6JWxDI
+YceEXrya435KBP4C1ESwnJmgc1i2ONYQgdD74UcQOrBRWePpS330seXJ8KM5nn5b
+IGIoKPIw2i2z+AN6ntGLhfaQxOo0wgio9RwBo/kRCTjVslsWEp73Xmo31vV1EhIo
+UqaJZ46zGBMH878RovkuwFjBn8GIgwOTfRpm/NEl6WhqwhHfPiGspCoF8HSV94h2
+I+kkizmtclASJYfz2B6CmWwtt+sCAwEAAaNgMF4wDgYDVR0PAQH/BAQDAgWgMBMG
+A1UdJQQMMAoGCCsGAQUFBwMBMB8GA1UdIwQYMBaAFO800LQ6Pa85RH4EbMmFH6ln
+F150MBYGA1UdEQQPMA2CC2V4YW1wbGUub3JnMA0GCSqGSIb3DQEBCwUAA4IBgQAP
+TsF53h7bvJcUXT3Y9yZ2vnW6xr9r92tNnM1Gfo3D2Yyn9oLf2YrfJng6WZ04Fhqa
+Wh0HOvE0n6yPNpm/Q7mh64DrgolZ8Ce5H4RTJDAabHU9XhEzfGSVtzRSFsz+szu1
+Y30IV+08DxxqMmNPspYdpAET2Lwyk2WhnARGiGw11CRkQCEkVEe6d702vS9UGBUz
+Du6lmCYCm0SbFrZ0CGgmHSHoTcCtf3EjVam7dPg3yWiPbWjvhXxgip6hz9sCqkhG
+WA5f+fPgSZ1I9U4i+uYnqjfrzwgC08RwUYordm15F6gPvXw+KVwDO8yUYQoEH0b6
+AFJtbzoAXDysvBC6kWYFFOr62EaisaEkELTS/NrPD9ux1eKbxcxHCwEtVjgC0CL6
+gAxEAQ+9maJMbrAFhsOBbGGFC+mMCGg4eEyx6+iMB0oQe0W7QFeRUAFi7Ptc/ocS
+tZ9lbrfX1/wrcTTWIYWE+xH6oeb4fhs29kxjHcf2l+tQzmpl0aP3Z/bMW4BSB+w=
+-----END CERTIFICATE-----
diff --git a/test/config/snell-http.conf b/test/config/snell-http.conf
new file mode 100644
index 000000000..f5130dc10
--- /dev/null
+++ b/test/config/snell-http.conf
@@ -0,0 +1,4 @@
+[snell-server]
+listen = 0.0.0.0:10002
+psk = password
+obfs = http
diff --git a/test/config/snell-tls.conf b/test/config/snell-tls.conf
new file mode 100644
index 000000000..bf8b51396
--- /dev/null
+++ b/test/config/snell-tls.conf
@@ -0,0 +1,4 @@
+[snell-server]
+listen = 0.0.0.0:10002
+psk = password
+obfs = tls
diff --git a/test/config/snell.conf b/test/config/snell.conf
new file mode 100644
index 000000000..40266391b
--- /dev/null
+++ b/test/config/snell.conf
@@ -0,0 +1,3 @@
+[snell-server]
+listen = 0.0.0.0:10002
+psk = password
diff --git a/test/config/trojan-grpc.json b/test/config/trojan-grpc.json
new file mode 100644
index 000000000..eb0dcc990
--- /dev/null
+++ b/test/config/trojan-grpc.json
@@ -0,0 +1,40 @@
+{
+ "inbounds": [
+ {
+ "port": 10002,
+ "listen": "0.0.0.0",
+ "protocol": "trojan",
+ "settings": {
+ "clients": [
+ {
+ "password": "example",
+ "email": "grpc@example.com"
+ }
+ ]
+ },
+ "streamSettings": {
+ "network": "grpc",
+ "security": "tls",
+ "tlsSettings": {
+ "certificates": [
+ {
+ "certificateFile": "/etc/ssl/v2ray/fullchain.pem",
+ "keyFile": "/etc/ssl/v2ray/privkey.pem"
+ }
+ ]
+ },
+ "grpcSettings": {
+ "serviceName": "example"
+ }
+ }
+ }
+ ],
+ "outbounds": [
+ {
+ "protocol": "freedom"
+ }
+ ],
+ "log": {
+ "loglevel": "debug"
+ }
+}
\ No newline at end of file
diff --git a/test/config/trojan.json b/test/config/trojan.json
new file mode 100644
index 000000000..18e33a980
--- /dev/null
+++ b/test/config/trojan.json
@@ -0,0 +1,40 @@
+{
+ "run_type": "server",
+ "local_addr": "0.0.0.0",
+ "local_port": 10002,
+ "password": [
+ "password"
+ ],
+ "log_level": 1,
+ "ssl": {
+ "cert": "/path/to/certificate.crt",
+ "key": "/path/to/private.key",
+ "key_password": "",
+ "cipher": "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384",
+ "cipher_tls13": "TLS_AES_128_GCM_SHA256:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_256_GCM_SHA384",
+ "prefer_server_cipher": true,
+ "alpn": [
+ "http/1.1"
+ ],
+ "alpn_port_override": {
+ "h2": 81
+ },
+ "reuse_session": true,
+ "session_ticket": false,
+ "session_timeout": 600,
+ "plain_http_response": "",
+ "curves": "",
+ "dhparam": ""
+ },
+ "tcp": {
+ "prefer_ipv4": false,
+ "no_delay": true,
+ "keep_alive": true,
+ "reuse_port": false,
+ "fast_open": false,
+ "fast_open_qlen": 20
+ },
+ "mysql": {
+ "enabled": false
+ }
+}
\ No newline at end of file
diff --git a/test/config/vmess-aead.json b/test/config/vmess-aead.json
new file mode 100644
index 000000000..27bc4757f
--- /dev/null
+++ b/test/config/vmess-aead.json
@@ -0,0 +1,28 @@
+{
+ "inbounds": [
+ {
+ "port": 10002,
+ "listen": "0.0.0.0",
+ "protocol": "vmess",
+ "settings": {
+ "clients": [
+ {
+ "id": "b831381d-6324-4d53-ad4f-8cda48b30811",
+ "alterId": 0
+ }
+ ]
+ },
+ "streamSettings": {
+ "network": "tcp"
+ }
+ }
+ ],
+ "outbounds": [
+ {
+ "protocol": "freedom"
+ }
+ ],
+ "log": {
+ "loglevel": "debug"
+ }
+}
\ No newline at end of file
diff --git a/test/config/vmess-grpc.json b/test/config/vmess-grpc.json
new file mode 100644
index 000000000..1b3a8e9a7
--- /dev/null
+++ b/test/config/vmess-grpc.json
@@ -0,0 +1,40 @@
+{
+ "inbounds": [
+ {
+ "port": 10002,
+ "listen": "0.0.0.0",
+ "protocol": "vmess",
+ "settings": {
+ "clients": [
+ {
+ "id": "b831381d-6324-4d53-ad4f-8cda48b30811",
+ "alterId": 32
+ }
+ ]
+ },
+ "streamSettings": {
+ "network": "grpc",
+ "security": "tls",
+ "tlsSettings": {
+ "certificates": [
+ {
+ "certificateFile": "/etc/ssl/v2ray/fullchain.pem",
+ "keyFile": "/etc/ssl/v2ray/privkey.pem"
+ }
+ ]
+ },
+ "grpcSettings": {
+ "serviceName": "example"
+ }
+ }
+ }
+ ],
+ "outbounds": [
+ {
+ "protocol": "freedom"
+ }
+ ],
+ "log": {
+ "loglevel": "debug"
+ }
+}
\ No newline at end of file
diff --git a/test/config/vmess-http.json b/test/config/vmess-http.json
new file mode 100644
index 000000000..aa6c6c8ed
--- /dev/null
+++ b/test/config/vmess-http.json
@@ -0,0 +1,55 @@
+{
+ "inbounds": [
+ {
+ "port": 10002,
+ "listen": "0.0.0.0",
+ "protocol": "vmess",
+ "settings": {
+ "clients": [
+ {
+ "id": "b831381d-6324-4d53-ad4f-8cda48b30811",
+ "alterId": 32
+ }
+ ]
+ },
+ "streamSettings": {
+ "network": "tcp",
+ "tcpSettings": {
+ "header": {
+ "type": "http",
+ "response": {
+ "version": "1.1",
+ "status": "200",
+ "reason": "OK",
+ "headers": {
+ "Content-Type": [
+ "application/octet-stream",
+ "video/mpeg",
+ "application/x-msdownload",
+ "text/html",
+ "application/x-shockwave-flash"
+ ],
+ "Transfer-Encoding": [
+ "chunked"
+ ],
+ "Connection": [
+ "keep-alive"
+ ],
+ "Pragma": "no-cache"
+ }
+ }
+ }
+ },
+ "security": "none"
+ }
+ }
+ ],
+ "outbounds": [
+ {
+ "protocol": "freedom"
+ }
+ ],
+ "log": {
+ "loglevel": "debug"
+ }
+}
\ No newline at end of file
diff --git a/test/config/vmess-http2.json b/test/config/vmess-http2.json
new file mode 100644
index 000000000..488737311
--- /dev/null
+++ b/test/config/vmess-http2.json
@@ -0,0 +1,43 @@
+{
+ "inbounds": [
+ {
+ "port": 10002,
+ "listen": "0.0.0.0",
+ "protocol": "vmess",
+ "settings": {
+ "clients": [
+ {
+ "id": "b831381d-6324-4d53-ad4f-8cda48b30811",
+ "alterId": 32
+ }
+ ]
+ },
+ "streamSettings": {
+ "network": "http",
+ "security": "tls",
+ "tlsSettings": {
+ "certificates": [
+ {
+ "certificateFile": "/etc/ssl/v2ray/fullchain.pem",
+ "keyFile": "/etc/ssl/v2ray/privkey.pem"
+ }
+ ]
+ },
+ "httpSettings": {
+ "host": [
+ "example.org"
+ ],
+ "path": "/test"
+ }
+ }
+ }
+ ],
+ "outbounds": [
+ {
+ "protocol": "freedom"
+ }
+ ],
+ "log": {
+ "loglevel": "debug"
+ }
+}
\ No newline at end of file
diff --git a/test/config/vmess-tls.json b/test/config/vmess-tls.json
new file mode 100644
index 000000000..ae2fa489b
--- /dev/null
+++ b/test/config/vmess-tls.json
@@ -0,0 +1,37 @@
+{
+ "inbounds": [
+ {
+ "port": 10002,
+ "listen": "0.0.0.0",
+ "protocol": "vmess",
+ "settings": {
+ "clients": [
+ {
+ "id": "b831381d-6324-4d53-ad4f-8cda48b30811",
+ "alterId": 32
+ }
+ ]
+ },
+ "streamSettings": {
+ "network": "tcp",
+ "security": "tls",
+ "tlsSettings": {
+ "certificates": [
+ {
+ "certificateFile": "/etc/ssl/v2ray/fullchain.pem",
+ "keyFile": "/etc/ssl/v2ray/privkey.pem"
+ }
+ ]
+ }
+ }
+ }
+ ],
+ "outbounds": [
+ {
+ "protocol": "freedom"
+ }
+ ],
+ "log": {
+ "loglevel": "debug"
+ }
+}
\ No newline at end of file
diff --git a/test/config/vmess-ws-tls.json b/test/config/vmess-ws-tls.json
new file mode 100644
index 000000000..dda1e0c96
--- /dev/null
+++ b/test/config/vmess-ws-tls.json
@@ -0,0 +1,34 @@
+{
+ "inbounds": [
+ {
+ "port": 10002,
+ "listen": "0.0.0.0",
+ "protocol": "vmess",
+ "settings": {
+ "clients": [
+ {
+ "id": "b831381d-6324-4d53-ad4f-8cda48b30811",
+ "alterId": 32
+ }
+ ]
+ },
+ "streamSettings": {
+ "network": "ws",
+ "security": "tls",
+ "tlsSettings": {
+ "certificates": [
+ {
+ "certificateFile": "/etc/ssl/v2ray/fullchain.pem",
+ "keyFile": "/etc/ssl/v2ray/privkey.pem"
+ }
+ ]
+ }
+ }
+ }
+ ],
+ "outbounds": [
+ {
+ "protocol": "freedom"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/test/config/vmess-ws.json b/test/config/vmess-ws.json
new file mode 100644
index 000000000..94ace4e32
--- /dev/null
+++ b/test/config/vmess-ws.json
@@ -0,0 +1,26 @@
+{
+ "inbounds": [
+ {
+ "port": 10002,
+ "listen": "0.0.0.0",
+ "protocol": "vmess",
+ "settings": {
+ "clients": [
+ {
+ "id": "b831381d-6324-4d53-ad4f-8cda48b30811",
+ "alterId": 32
+ }
+ ]
+ },
+ "streamSettings": {
+ "network": "ws",
+ "security": "none"
+ }
+ }
+ ],
+ "outbounds": [
+ {
+ "protocol": "freedom"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/test/config/vmess.json b/test/config/vmess.json
new file mode 100644
index 000000000..bcf53cd8c
--- /dev/null
+++ b/test/config/vmess.json
@@ -0,0 +1,28 @@
+{
+ "inbounds": [
+ {
+ "port": 10002,
+ "listen": "0.0.0.0",
+ "protocol": "vmess",
+ "settings": {
+ "clients": [
+ {
+ "id": "b831381d-6324-4d53-ad4f-8cda48b30811",
+ "alterId": 32
+ }
+ ]
+ },
+ "streamSettings": {
+ "network": "tcp"
+ }
+ }
+ ],
+ "outbounds": [
+ {
+ "protocol": "freedom"
+ }
+ ],
+ "log": {
+ "loglevel": "debug"
+ }
+}
\ No newline at end of file
diff --git a/test/dns_test.go b/test/dns_test.go
new file mode 100644
index 000000000..dd07bda84
--- /dev/null
+++ b/test/dns_test.go
@@ -0,0 +1,103 @@
+package main
+
+import (
+ "testing"
+ "time"
+
+ "github.com/miekg/dns"
+ "github.com/stretchr/testify/assert"
+)
+
+func exchange(address, domain string, tp uint16) ([]dns.RR, error) {
+ client := dns.Client{}
+ query := &dns.Msg{}
+ query.SetQuestion(dns.Fqdn(domain), tp)
+
+ r, _, err := client.Exchange(query, address)
+ if err != nil {
+ return nil, err
+ }
+ return r.Answer, nil
+}
+
+func TestClash_DNS(t *testing.T) {
+ basic := `
+log-level: silent
+dns:
+ enable: true
+ listen: 0.0.0.0:8553
+ nameserver:
+ - 119.29.29.29
+`
+
+ if err := parseAndApply(basic); err != nil {
+ assert.FailNow(t, err.Error())
+ }
+ defer cleanup()
+
+ time.Sleep(waitTime)
+
+ rr, err := exchange("127.0.0.1:8553", "1.1.1.1.nip.io", dns.TypeA)
+ assert.NoError(t, err)
+ if !assert.NotEmpty(t, rr) {
+ assert.FailNow(t, "record empty")
+ }
+
+ record := rr[0].(*dns.A)
+ assert.Equal(t, record.A.String(), "1.1.1.1")
+
+ rr, err = exchange("127.0.0.1:8553", "2606-4700-4700--1111.sslip.io", dns.TypeAAAA)
+ assert.NoError(t, err)
+ assert.Empty(t, rr)
+}
+
+func TestClash_DNSHostAndFakeIP(t *testing.T) {
+ basic := `
+log-level: silent
+hosts:
+ foo.clash.dev: 1.1.1.1
+dns:
+ enable: true
+ listen: 0.0.0.0:8553
+ ipv6: true
+ enhanced-mode: fake-ip
+ fake-ip-range: 198.18.0.1/16
+ fake-ip-filter:
+ - .sslip.io
+ nameserver:
+ - 119.29.29.29
+`
+
+ if err := parseAndApply(basic); err != nil {
+ assert.FailNow(t, err.Error())
+ }
+ defer cleanup()
+
+ time.Sleep(waitTime)
+
+ type domainPair struct {
+ domain string
+ ip string
+ }
+
+ list := []domainPair{
+ {"foo.org", "198.18.0.2"},
+ {"bar.org", "198.18.0.3"},
+ {"foo.org", "198.18.0.2"},
+ {"foo.clash.dev", "1.1.1.1"},
+ }
+
+ for _, pair := range list {
+ rr, err := exchange("127.0.0.1:8553", pair.domain, dns.TypeA)
+ assert.NoError(t, err)
+ assert.NotEmpty(t, rr)
+
+ record := rr[0].(*dns.A)
+ assert.Equal(t, record.A.String(), pair.ip)
+ }
+
+ rr, err := exchange("127.0.0.1:8553", "2606-4700-4700--1111.sslip.io", dns.TypeAAAA)
+ assert.NoError(t, err)
+ assert.NotEmpty(t, rr)
+ assert.Equal(t, rr[0].(*dns.AAAA).AAAA.String(), "2606:4700:4700::1111")
+}
diff --git a/test/docker_test.go b/test/docker_test.go
new file mode 100644
index 000000000..ce4c2de47
--- /dev/null
+++ b/test/docker_test.go
@@ -0,0 +1,45 @@
+package main
+
+import (
+ "context"
+
+ "github.com/docker/docker/api/types"
+ "github.com/docker/docker/api/types/container"
+ "github.com/docker/docker/client"
+)
+
+var isDarwin = false
+
+func startContainer(cfg *container.Config, hostCfg *container.HostConfig, name string) (string, error) {
+ c, err := client.NewClientWithOpts(client.FromEnv)
+ if err != nil {
+ return "", err
+ }
+ defer c.Close()
+
+ if !isDarwin {
+ hostCfg.NetworkMode = "host"
+ }
+
+ container, err := c.ContainerCreate(context.Background(), cfg, hostCfg, nil, nil, name)
+ if err != nil {
+ return "", err
+ }
+
+ if err = c.ContainerStart(context.Background(), container.ID, types.ContainerStartOptions{}); err != nil {
+ return "", err
+ }
+
+ return container.ID, nil
+}
+
+func cleanContainer(id string) error {
+ c, err := client.NewClientWithOpts(client.FromEnv)
+ if err != nil {
+ return err
+ }
+ defer c.Close()
+
+ removeOpts := types.ContainerRemoveOptions{Force: true}
+ return c.ContainerRemove(context.Background(), id, removeOpts)
+}
diff --git a/test/go.mod b/test/go.mod
new file mode 100644
index 000000000..1a5cb6763
--- /dev/null
+++ b/test/go.mod
@@ -0,0 +1,26 @@
+module clash-test
+
+go 1.16
+
+require (
+ github.com/Dreamacro/clash v1.6.1-0.20210516120541-06fdd3abe0ab
+ github.com/Microsoft/go-winio v0.4.16 // indirect
+ github.com/containerd/containerd v1.4.4 // indirect
+ github.com/docker/distribution v2.7.1+incompatible // indirect
+ github.com/docker/docker v20.10.6+incompatible
+ github.com/docker/go-connections v0.4.0
+ github.com/docker/go-units v0.4.0 // indirect
+ github.com/gogo/protobuf v1.3.2 // indirect
+ github.com/google/go-cmp v0.5.5 // indirect
+ github.com/gorilla/mux v1.8.0 // indirect
+ github.com/miekg/dns v1.1.42
+ github.com/moby/term v0.0.0-20201216013528-df9cb8a40635 // indirect
+ github.com/morikuni/aec v1.0.0 // indirect
+ github.com/opencontainers/go-digest v1.0.0 // indirect
+ github.com/opencontainers/image-spec v1.0.1 // indirect
+ github.com/stretchr/testify v1.7.0
+ golang.org/x/net v0.0.0-20210510120150-4163338589ed
+ golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba // indirect
+ google.golang.org/grpc v1.36.0 // indirect
+ gotest.tools/v3 v3.0.3 // indirect
+)
diff --git a/test/go.sum b/test/go.sum
new file mode 100644
index 000000000..2a641fb70
--- /dev/null
+++ b/test/go.sum
@@ -0,0 +1,202 @@
+cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8=
+github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
+github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/Dreamacro/clash v1.6.1-0.20210516120541-06fdd3abe0ab h1:hfjxpY+73Xo6k+JHMkLlaOR3Tw5hG/YZxmDFyV9Y6sY=
+github.com/Dreamacro/clash v1.6.1-0.20210516120541-06fdd3abe0ab/go.mod h1:Pz9GwWR244jrMSInQ0KUL02jMCe5xIJ+pkgzuNIy2Iw=
+github.com/Dreamacro/go-shadowsocks2 v0.1.7 h1:8CtbE1HoPPMfrQZGXmlluq6dO2lL31W6WRRE8fabc4Q=
+github.com/Dreamacro/go-shadowsocks2 v0.1.7/go.mod h1:8p5G4cAj5ZlXwUR+Ww63gfSikr8kvw8uw3TDwLAJpUc=
+github.com/Microsoft/go-winio v0.4.16 h1:FtSW/jqD+l4ba5iPBj9CODVtgfYAD8w2wS923g/cFDk=
+github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0=
+github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
+github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
+github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
+github.com/containerd/containerd v1.4.4 h1:rtRG4N6Ct7GNssATwgpvMGfnjnwfjnu/Zs9W3Ikzq+M=
+github.com/containerd/containerd v1.4.4/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
+github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug=
+github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
+github.com/docker/docker v20.10.6+incompatible h1:oXI3Vas8TI8Eu/EjH4srKHJBVqraSzJybhxY7Om9faQ=
+github.com/docker/docker v20.10.6+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
+github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
+github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
+github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw=
+github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
+github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
+github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
+github.com/go-chi/chi/v5 v5.0.3/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
+github.com/go-chi/cors v1.2.0/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58=
+github.com/go-chi/render v1.0.1/go.mod h1:pq4Rr7HbnsdaeHagklXub+p6Wd16Af5l9koip1OvJns=
+github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw=
+github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
+github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
+github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
+github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
+github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
+github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
+github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
+github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
+github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
+github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
+github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
+github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
+github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
+github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
+github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
+github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
+github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
+github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
+github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
+github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
+github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/miekg/dns v1.1.42 h1:gWGe42RGaIqXQZ+r3WUGEKBEtvPHY2SXo4dqixDNxuY=
+github.com/miekg/dns v1.1.42/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4=
+github.com/moby/term v0.0.0-20201216013528-df9cb8a40635 h1:rzf0wL0CHVc8CEsgyygG0Mn9CNCCPZqOPaz8RiiHYQk=
+github.com/moby/term v0.0.0-20201216013528-df9cb8a40635/go.mod h1:FBS0z0QWA44HXygs7VXDUOGoN/1TV3RuWkLO04am3wc=
+github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
+github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
+github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
+github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
+github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI=
+github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
+github.com/oschwald/geoip2-golang v1.5.0 h1:igg2yQIrrcRccB1ytFXqBfOHCjXWIoMv85lVJ1ONZzw=
+github.com/oschwald/geoip2-golang v1.5.0/go.mod h1:xdvYt5xQzB8ORWFqPnqMwZpCpgNagttWdoZLlJQzg7s=
+github.com/oschwald/maxminddb-golang v1.8.0 h1:Uh/DSnGoxsyp/KYbY1AuP0tYEwfs0sCph9p/UMXK/Hk=
+github.com/oschwald/maxminddb-golang v1.8.0/go.mod h1:RXZtst0N6+FY/3qCNmZMBApR19cdQj43/NM9VkrNAis=
+github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
+github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
+github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
+github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
+github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
+github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
+github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
+go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20210317152858-513c2a44f670/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
+golang.org/x/crypto v0.0.0-20210506145944-38f3c27a63bf h1:B2n+Zi5QeYRDAEodEu72OS36gmTWjgpXr2+cWcBW90o=
+golang.org/x/crypto v0.0.0-20210506145944-38f3c27a63bf/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
+golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
+golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20210508051633-16afe75a6701/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20210510120150-4163338589ed h1:p9UgmWI9wKpfYmgaV/IZKGdXc5qEK45tDwwwDyjS26I=
+golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
+golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191224085550-c709ea063b76/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210507161434-a76c4d0a0096 h1:5PbJGn5Sp3GEUjJ61aYbUP6RIo3Z3r2E4Tv9y2z8UHo=
+golang.org/x/sys v0.0.0-20210507161434-a76c4d0a0096/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
+golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba h1:O8mE0/t419eoIwhTFpKVkHiTs/Igowgfkj25AcZrtiE=
+golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
+golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
+google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY=
+google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
+google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
+google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
+google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
+google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.36.0 h1:o1bcQ6imQMIOpdrO3SWf2z5RV72WbDwdXuK0MDlc8As=
+google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
+google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
+google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
+google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
+google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
+google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
+google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
+google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
+gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
+gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0=
+gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8=
+honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
diff --git a/test/snell_test.go b/test/snell_test.go
new file mode 100644
index 000000000..0d9e059a0
--- /dev/null
+++ b/test/snell_test.go
@@ -0,0 +1,121 @@
+package main
+
+import (
+ "fmt"
+ "testing"
+ "time"
+
+ "github.com/Dreamacro/clash/adapters/outbound"
+ C "github.com/Dreamacro/clash/constant"
+
+ "github.com/docker/docker/api/types/container"
+ "github.com/stretchr/testify/assert"
+)
+
+func TestClash_SnellObfsHTTP(t *testing.T) {
+ cfg := &container.Config{
+ Image: ImageSnell,
+ ExposedPorts: defaultExposedPorts,
+ Cmd: []string{"-c", "/config.conf"},
+ }
+ hostCfg := &container.HostConfig{
+ PortBindings: defaultPortBindings,
+ Binds: []string{fmt.Sprintf("%s:/config.conf", C.Path.Resolve("snell-http.conf"))},
+ }
+
+ id, err := startContainer(cfg, hostCfg, "snell-http")
+ if err != nil {
+ assert.FailNow(t, err.Error())
+ }
+
+ t.Cleanup(func() {
+ cleanContainer(id)
+ })
+
+ proxy, err := outbound.NewSnell(outbound.SnellOption{
+ Name: "snell",
+ Server: localIP.String(),
+ Port: 10002,
+ Psk: "password",
+ ObfsOpts: map[string]interface{}{
+ "mode": "http",
+ },
+ })
+ if err != nil {
+ assert.FailNow(t, err.Error())
+ }
+
+ time.Sleep(waitTime)
+ testSuit(t, proxy)
+}
+
+func TestClash_SnellObfsTLS(t *testing.T) {
+ cfg := &container.Config{
+ Image: ImageSnell,
+ ExposedPorts: defaultExposedPorts,
+ Cmd: []string{"-c", "/config.conf"},
+ }
+ hostCfg := &container.HostConfig{
+ PortBindings: defaultPortBindings,
+ Binds: []string{fmt.Sprintf("%s:/config.conf", C.Path.Resolve("snell-tls.conf"))},
+ }
+
+ id, err := startContainer(cfg, hostCfg, "snell-tls")
+ if err != nil {
+ assert.FailNow(t, err.Error())
+ }
+
+ t.Cleanup(func() {
+ cleanContainer(id)
+ })
+
+ proxy, err := outbound.NewSnell(outbound.SnellOption{
+ Name: "snell",
+ Server: localIP.String(),
+ Port: 10002,
+ Psk: "password",
+ ObfsOpts: map[string]interface{}{
+ "mode": "tls",
+ },
+ })
+ if err != nil {
+ assert.FailNow(t, err.Error())
+ }
+
+ time.Sleep(waitTime)
+ testSuit(t, proxy)
+}
+
+func TestClash_Snell(t *testing.T) {
+ cfg := &container.Config{
+ Image: ImageSnell,
+ ExposedPorts: defaultExposedPorts,
+ Cmd: []string{"-c", "/config.conf"},
+ }
+ hostCfg := &container.HostConfig{
+ PortBindings: defaultPortBindings,
+ Binds: []string{fmt.Sprintf("%s:/config.conf", C.Path.Resolve("snell.conf"))},
+ }
+
+ id, err := startContainer(cfg, hostCfg, "snell")
+ if err != nil {
+ assert.FailNow(t, err.Error())
+ }
+
+ t.Cleanup(func() {
+ cleanContainer(id)
+ })
+
+ proxy, err := outbound.NewSnell(outbound.SnellOption{
+ Name: "snell",
+ Server: localIP.String(),
+ Port: 10002,
+ Psk: "password",
+ })
+ if err != nil {
+ assert.FailNow(t, err.Error())
+ }
+
+ time.Sleep(waitTime)
+ testSuit(t, proxy)
+}
diff --git a/test/ss_test.go b/test/ss_test.go
new file mode 100644
index 000000000..6876d3fb5
--- /dev/null
+++ b/test/ss_test.go
@@ -0,0 +1,172 @@
+package main
+
+import (
+ "testing"
+ "time"
+
+ "github.com/Dreamacro/clash/adapters/outbound"
+
+ "github.com/docker/docker/api/types/container"
+ "github.com/stretchr/testify/assert"
+)
+
+func TestClash_Shadowsocks(t *testing.T) {
+ cfg := &container.Config{
+ Image: ImageShadowsocks,
+ Env: []string{"SS_MODULE=ss-server", "SS_CONFIG=-s 0.0.0.0 -u -v -p 10002 -m chacha20-ietf-poly1305 -k FzcLbKs2dY9mhL"},
+ ExposedPorts: defaultExposedPorts,
+ }
+ hostCfg := &container.HostConfig{
+ PortBindings: defaultPortBindings,
+ }
+
+ id, err := startContainer(cfg, hostCfg, "ss")
+ if err != nil {
+ assert.FailNow(t, err.Error())
+ }
+
+ t.Cleanup(func() {
+ cleanContainer(id)
+ })
+
+ proxy, err := outbound.NewShadowSocks(outbound.ShadowSocksOption{
+ Name: "ss",
+ Server: localIP.String(),
+ Port: 10002,
+ Password: "FzcLbKs2dY9mhL",
+ Cipher: "chacha20-ietf-poly1305",
+ UDP: true,
+ })
+ if err != nil {
+ assert.FailNow(t, err.Error())
+ }
+
+ time.Sleep(waitTime)
+ testSuit(t, proxy)
+}
+
+func TestClash_ShadowsocksObfsHTTP(t *testing.T) {
+ cfg := &container.Config{
+ Image: ImageShadowsocks,
+ Env: []string{
+ "SS_MODULE=ss-server",
+ "SS_CONFIG=-s 0.0.0.0 -u -p 10002 -m chacha20-ietf-poly1305 -k FzcLbKs2dY9mhL --plugin obfs-server --plugin-opts obfs=http",
+ },
+ ExposedPorts: defaultExposedPorts,
+ }
+ hostCfg := &container.HostConfig{
+ PortBindings: defaultPortBindings,
+ }
+
+ id, err := startContainer(cfg, hostCfg, "ss-obfs-http")
+ if err != nil {
+ assert.FailNow(t, err.Error())
+ }
+
+ t.Cleanup(func() {
+ cleanContainer(id)
+ })
+
+ proxy, err := outbound.NewShadowSocks(outbound.ShadowSocksOption{
+ Name: "ss",
+ Server: localIP.String(),
+ Port: 10002,
+ Password: "FzcLbKs2dY9mhL",
+ Cipher: "chacha20-ietf-poly1305",
+ UDP: true,
+ Plugin: "obfs",
+ PluginOpts: map[string]interface{}{
+ "mode": "http",
+ },
+ })
+ if err != nil {
+ assert.FailNow(t, err.Error())
+ }
+
+ time.Sleep(waitTime)
+ testSuit(t, proxy)
+}
+
+func TestClash_ShadowsocksObfsTLS(t *testing.T) {
+ cfg := &container.Config{
+ Image: ImageShadowsocks,
+ Env: []string{
+ "SS_MODULE=ss-server",
+ "SS_CONFIG=-s 0.0.0.0 -u -p 10002 -m chacha20-ietf-poly1305 -k FzcLbKs2dY9mhL --plugin obfs-server --plugin-opts obfs=tls",
+ },
+ ExposedPorts: defaultExposedPorts,
+ }
+ hostCfg := &container.HostConfig{
+ PortBindings: defaultPortBindings,
+ }
+
+ id, err := startContainer(cfg, hostCfg, "ss-obfs-tls")
+ if err != nil {
+ assert.FailNow(t, err.Error())
+ }
+
+ t.Cleanup(func() {
+ cleanContainer(id)
+ })
+
+ proxy, err := outbound.NewShadowSocks(outbound.ShadowSocksOption{
+ Name: "ss",
+ Server: localIP.String(),
+ Port: 10002,
+ Password: "FzcLbKs2dY9mhL",
+ Cipher: "chacha20-ietf-poly1305",
+ UDP: true,
+ Plugin: "obfs",
+ PluginOpts: map[string]interface{}{
+ "mode": "tls",
+ },
+ })
+ if err != nil {
+ assert.FailNow(t, err.Error())
+ }
+
+ time.Sleep(waitTime)
+ testSuit(t, proxy)
+}
+
+func TestClash_ShadowsocksV2RayPlugin(t *testing.T) {
+ cfg := &container.Config{
+ Image: ImageShadowsocks,
+ Env: []string{
+ "SS_MODULE=ss-server",
+ "SS_CONFIG=-s 0.0.0.0 -u -p 10002 -m chacha20-ietf-poly1305 -k FzcLbKs2dY9mhL --plugin v2ray-plugin --plugin-opts=server",
+ },
+ ExposedPorts: defaultExposedPorts,
+ }
+ hostCfg := &container.HostConfig{
+ PortBindings: defaultPortBindings,
+ }
+
+ id, err := startContainer(cfg, hostCfg, "ss-v2ray-plugin")
+ if err != nil {
+ assert.FailNow(t, err.Error())
+ }
+
+ t.Cleanup(func() {
+ cleanContainer(id)
+ })
+
+ proxy, err := outbound.NewShadowSocks(outbound.ShadowSocksOption{
+ Name: "ss",
+ Server: localIP.String(),
+ Port: 10002,
+ Password: "FzcLbKs2dY9mhL",
+ Cipher: "chacha20-ietf-poly1305",
+ UDP: true,
+ Plugin: "v2ray-plugin",
+ PluginOpts: map[string]interface{}{
+ "mode": "websocket",
+ },
+ })
+ if err != nil {
+ assert.FailNow(t, err.Error())
+ }
+
+ time.Sleep(waitTime)
+ testSuit(t, proxy)
+}
diff --git a/test/trojan_test.go b/test/trojan_test.go
new file mode 100644
index 000000000..c20f12792
--- /dev/null
+++ b/test/trojan_test.go
@@ -0,0 +1,94 @@
+package main
+
+import (
+ "fmt"
+ "testing"
+ "time"
+
+ "github.com/Dreamacro/clash/adapters/outbound"
+ C "github.com/Dreamacro/clash/constant"
+
+ "github.com/docker/docker/api/types/container"
+ "github.com/stretchr/testify/assert"
+)
+
+func TestClash_Trojan(t *testing.T) {
+ cfg := &container.Config{
+ Image: ImageTrojan,
+ ExposedPorts: defaultExposedPorts,
+ }
+ hostCfg := &container.HostConfig{
+ PortBindings: defaultPortBindings,
+ Binds: []string{
+ fmt.Sprintf("%s:/config/config.json", C.Path.Resolve("trojan.json")),
+ fmt.Sprintf("%s:/path/to/certificate.crt", C.Path.Resolve("example.org.pem")),
+ fmt.Sprintf("%s:/path/to/private.key", C.Path.Resolve("example.org-key.pem")),
+ },
+ }
+
+ id, err := startContainer(cfg, hostCfg, "trojan")
+ if err != nil {
+ assert.FailNow(t, err.Error())
+ }
+
+ t.Cleanup(func() {
+ cleanContainer(id)
+ })
+
+ proxy, err := outbound.NewTrojan(outbound.TrojanOption{
+ Name: "trojan",
+ Server: localIP.String(),
+ Port: 10002,
+ Password: "password",
+ SNI: "example.org",
+ SkipCertVerify: true,
+ UDP: true,
+ })
+ if err != nil {
+ assert.FailNow(t, err.Error())
+ }
+
+ time.Sleep(waitTime)
+ testSuit(t, proxy)
+}
+
+func TestClash_TrojanGrpc(t *testing.T) {
+ cfg := &container.Config{
+ Image: ImageXray,
+ ExposedPorts: defaultExposedPorts,
+ }
+ hostCfg := &container.HostConfig{
+ PortBindings: defaultPortBindings,
+ Binds: []string{
+ fmt.Sprintf("%s:/etc/xray/config.json", C.Path.Resolve("trojan-grpc.json")),
+ fmt.Sprintf("%s:/etc/ssl/v2ray/fullchain.pem", C.Path.Resolve("example.org.pem")),
+ fmt.Sprintf("%s:/etc/ssl/v2ray/privkey.pem", C.Path.Resolve("example.org-key.pem")),
+ },
+ }
+
+ id, err := startContainer(cfg, hostCfg, "trojan-grpc")
+ if err != nil {
+ assert.FailNow(t, err.Error())
+ }
+ defer cleanContainer(id)
+
+ proxy, err := outbound.NewTrojan(outbound.TrojanOption{
+ Name: "trojan",
+ Server: localIP.String(),
+ Port: 10002,
+ Password: "example",
+ SNI: "example.org",
+ SkipCertVerify: true,
+ UDP: true,
+ Network: "grpc",
+ GrpcOpts: outbound.GrpcOptions{
+ GrpcServiceName: "example",
+ },
+ })
+ if err != nil {
+ assert.FailNow(t, err.Error())
+ }
+
+ time.Sleep(waitTime)
+ testSuit(t, proxy)
+}
diff --git a/test/util_test.go b/test/util_test.go
new file mode 100644
index 000000000..ab9b8b2bf
--- /dev/null
+++ b/test/util_test.go
@@ -0,0 +1,70 @@
+package main
+
+import (
+ "errors"
+ "fmt"
+ "net"
+ "syscall"
+
+ "golang.org/x/net/route"
+)
+
+func defaultRouteIP() (net.IP, error) {
+ idx, err := defaultRouteInterfaceIndex()
+ if err != nil {
+ return nil, err
+ }
+ iface, err := net.InterfaceByIndex(idx)
+ if err != nil {
+ return nil, err
+ }
+ addrs, err := iface.Addrs()
+ if err != nil {
+ return nil, err
+ }
+ for _, addr := range addrs {
+ ip := addr.(*net.IPNet).IP
+ if ip.To4() != nil {
+ return ip, nil
+ }
+ }
+
+ return nil, errors.New("no ipv4 addr")
+}
+
+func defaultRouteInterfaceIndex() (int, error) {
+ rib, err := route.FetchRIB(syscall.AF_UNSPEC, syscall.NET_RT_DUMP2, 0)
+ if err != nil {
+ return 0, fmt.Errorf("route.FetchRIB: %w", err)
+ }
+ msgs, err := route.ParseRIB(syscall.NET_RT_IFLIST2, rib)
+ if err != nil {
+ return 0, fmt.Errorf("route.ParseRIB: %w", err)
+ }
+ for _, message := range msgs {
+ routeMessage := message.(*route.RouteMessage)
+ if routeMessage.Flags&(syscall.RTF_UP|syscall.RTF_GATEWAY|syscall.RTF_STATIC) == 0 {
+ continue
+ }
+
+ addresses := routeMessage.Addrs
+
+ destination, ok := addresses[0].(*route.Inet4Addr)
+ if !ok {
+ continue
+ }
+
+ if destination.IP != [4]byte{0, 0, 0, 0} {
+ continue
+ }
+
+ switch addresses[1].(type) {
+ case *route.Inet4Addr:
+ return routeMessage.Index, nil
+ default:
+ continue
+ }
+ }
+
+ return 0, fmt.Errorf("ambiguous gateway interfaces found")
+}
diff --git a/test/vmess_test.go b/test/vmess_test.go
new file mode 100644
index 000000000..cf539bf89
--- /dev/null
+++ b/test/vmess_test.go
@@ -0,0 +1,347 @@
+package main
+
+import (
+ "fmt"
+ "testing"
+ "time"
+
+ "github.com/Dreamacro/clash/adapters/outbound"
+ C "github.com/Dreamacro/clash/constant"
+
+ "github.com/docker/docker/api/types/container"
+ "github.com/stretchr/testify/assert"
+)
+
+func TestClash_Vmess(t *testing.T) {
+ configPath := C.Path.Resolve("vmess.json")
+
+ cfg := &container.Config{
+ Image: ImageVmess,
+ ExposedPorts: defaultExposedPorts,
+ }
+ hostCfg := &container.HostConfig{
+ PortBindings: defaultPortBindings,
+ Binds: []string{fmt.Sprintf("%s:/etc/v2ray/config.json", configPath)},
+ }
+
+ id, err := startContainer(cfg, hostCfg, "vmess")
+ if err != nil {
+ assert.FailNow(t, err.Error())
+ }
+
+ t.Cleanup(func() {
+ cleanContainer(id)
+ })
+
+ proxy, err := outbound.NewVmess(outbound.VmessOption{
+ Name: "vmess",
+ Server: localIP.String(),
+ Port: 10002,
+ UUID: "b831381d-6324-4d53-ad4f-8cda48b30811",
+ Cipher: "auto",
+ AlterID: 32,
+ UDP: true,
+ })
+ if err != nil {
+ assert.FailNow(t, err.Error())
+ }
+
+ time.Sleep(waitTime)
+ testSuit(t, proxy)
+}
+
+func TestClash_VmessAEAD(t *testing.T) {
+ configPath := C.Path.Resolve("vmess-aead.json")
+
+ cfg := &container.Config{
+ Image: ImageVmess,
+ ExposedPorts: defaultExposedPorts,
+ }
+ hostCfg := &container.HostConfig{
+ PortBindings: defaultPortBindings,
+ Binds: []string{fmt.Sprintf("%s:/etc/v2ray/config.json", configPath)},
+ }
+
+ id, err := startContainer(cfg, hostCfg, "vmess-aead")
+ if err != nil {
+ assert.FailNow(t, err.Error())
+ }
+
+ t.Cleanup(func() {
+ cleanContainer(id)
+ })
+
+ proxy, err := outbound.NewVmess(outbound.VmessOption{
+ Name: "vmess",
+ Server: localIP.String(),
+ Port: 10002,
+ UUID: "b831381d-6324-4d53-ad4f-8cda48b30811",
+ Cipher: "auto",
+ AlterID: 0,
+ UDP: true,
+ })
+ if err != nil {
+ assert.FailNow(t, err.Error())
+ }
+
+ time.Sleep(waitTime)
+ testSuit(t, proxy)
+}
+
+func TestClash_VmessTLS(t *testing.T) {
+ cfg := &container.Config{
+ Image: ImageVmess,
+ ExposedPorts: defaultExposedPorts,
+ }
+ hostCfg := &container.HostConfig{
+ PortBindings: defaultPortBindings,
+ Binds: []string{
+ fmt.Sprintf("%s:/etc/v2ray/config.json", C.Path.Resolve("vmess-tls.json")),
+ fmt.Sprintf("%s:/etc/ssl/v2ray/fullchain.pem", C.Path.Resolve("example.org.pem")),
+ fmt.Sprintf("%s:/etc/ssl/v2ray/privkey.pem", C.Path.Resolve("example.org-key.pem")),
+ },
+ }
+
+ id, err := startContainer(cfg, hostCfg, "vmess-tls")
+ if err != nil {
+ assert.FailNow(t, err.Error())
+ }
+ defer cleanContainer(id)
+
+ proxy, err := outbound.NewVmess(outbound.VmessOption{
+ Name: "vmess",
+ Server: localIP.String(),
+ Port: 10002,
+ UUID: "b831381d-6324-4d53-ad4f-8cda48b30811",
+ Cipher: "auto",
+ AlterID: 32,
+ TLS: true,
+ SkipCertVerify: true,
+ ServerName: "example.org",
+ UDP: true,
+ })
+ if err != nil {
+ assert.FailNow(t, err.Error())
+ }
+
+ time.Sleep(waitTime)
+ testSuit(t, proxy)
+}
+
+func TestClash_VmessHTTP2(t *testing.T) {
+ cfg := &container.Config{
+ Image: ImageVmess,
+ ExposedPorts: defaultExposedPorts,
+ }
+ hostCfg := &container.HostConfig{
+ PortBindings: defaultPortBindings,
+ Binds: []string{
+ fmt.Sprintf("%s:/etc/v2ray/config.json", C.Path.Resolve("vmess-http2.json")),
+ fmt.Sprintf("%s:/etc/ssl/v2ray/fullchain.pem", C.Path.Resolve("example.org.pem")),
+ fmt.Sprintf("%s:/etc/ssl/v2ray/privkey.pem", C.Path.Resolve("example.org-key.pem")),
+ },
+ }
+
+ id, err := startContainer(cfg, hostCfg, "vmess-http2")
+ if err != nil {
+ assert.FailNow(t, err.Error())
+ }
+ defer cleanContainer(id)
+
+ proxy, err := outbound.NewVmess(outbound.VmessOption{
+ Name: "vmess",
+ Server: localIP.String(),
+ Port: 10002,
+ UUID: "b831381d-6324-4d53-ad4f-8cda48b30811",
+ Cipher: "auto",
+ AlterID: 32,
+ Network: "h2",
+ TLS: true,
+ SkipCertVerify: true,
+ ServerName: "example.org",
+ UDP: true,
+ HTTP2Opts: outbound.HTTP2Options{
+ Host: []string{"example.org"},
+ Path: "/test",
+ },
+ })
+ if err != nil {
+ assert.FailNow(t, err.Error())
+ }
+
+ time.Sleep(waitTime)
+ testSuit(t, proxy)
+}
+
+func TestClash_VmessHTTP(t *testing.T) {
+ cfg := &container.Config{
+ Image: ImageVmess,
+ ExposedPorts: defaultExposedPorts,
+ }
+ hostCfg := &container.HostConfig{
+ PortBindings: defaultPortBindings,
+ Binds: []string{
+ fmt.Sprintf("%s:/etc/v2ray/config.json", C.Path.Resolve("vmess-http.json")),
+ },
+ }
+
+ id, err := startContainer(cfg, hostCfg, "vmess-http")
+ if err != nil {
+ assert.FailNow(t, err.Error())
+ }
+ defer cleanContainer(id)
+
+ proxy, err := outbound.NewVmess(outbound.VmessOption{
+ Name: "vmess",
+ Server: localIP.String(),
+ Port: 10002,
+ UUID: "b831381d-6324-4d53-ad4f-8cda48b30811",
+ Cipher: "auto",
+ AlterID: 32,
+ Network: "http",
+ UDP: true,
+ HTTPOpts: outbound.HTTPOptions{
+ Method: "GET",
+ Path: []string{"/"},
+ Headers: map[string][]string{
+ "Host": {"www.amazon.com"},
+ "User-Agent": {
+ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.105 Safari/537.36 Edg/84.0.522.49",
+ },
+ "Accept-Encoding": {
+ "gzip, deflate",
+ },
+ "Connection": {
+ "keep-alive",
+ },
+ "Pragma": {"no-cache"},
+ },
+ },
+ })
+ if err != nil {
+ assert.FailNow(t, err.Error())
+ }
+
+ time.Sleep(waitTime)
+ testSuit(t, proxy)
+}
+
+func TestClash_VmessWebsocket(t *testing.T) {
+ cfg := &container.Config{
+ Image: ImageVmess,
+ ExposedPorts: defaultExposedPorts,
+ }
+ hostCfg := &container.HostConfig{
+ PortBindings: defaultPortBindings,
+ Binds: []string{
+ fmt.Sprintf("%s:/etc/v2ray/config.json", C.Path.Resolve("vmess-ws.json")),
+ },
+ }
+
+ id, err := startContainer(cfg, hostCfg, "vmess-ws")
+ if err != nil {
+ assert.FailNow(t, err.Error())
+ }
+ defer cleanContainer(id)
+
+ proxy, err := outbound.NewVmess(outbound.VmessOption{
+ Name: "vmess",
+ Server: localIP.String(),
+ Port: 10002,
+ UUID: "b831381d-6324-4d53-ad4f-8cda48b30811",
+ Cipher: "auto",
+ AlterID: 32,
+ Network: "ws",
+ UDP: true,
+ })
+ if err != nil {
+ assert.FailNow(t, err.Error())
+ }
+
+ time.Sleep(waitTime)
+ testSuit(t, proxy)
+}
+
+func TestClash_VmessWebsocketTLS(t *testing.T) {
+ cfg := &container.Config{
+ Image: ImageVmess,
+ ExposedPorts: defaultExposedPorts,
+ }
+ hostCfg := &container.HostConfig{
+ PortBindings: defaultPortBindings,
+ Binds: []string{
+ fmt.Sprintf("%s:/etc/v2ray/config.json", C.Path.Resolve("vmess-ws-tls.json")),
+ fmt.Sprintf("%s:/etc/ssl/v2ray/fullchain.pem", C.Path.Resolve("example.org.pem")),
+ fmt.Sprintf("%s:/etc/ssl/v2ray/privkey.pem", C.Path.Resolve("example.org-key.pem")),
+ },
+ }
+
+ id, err := startContainer(cfg, hostCfg, "vmess-ws")
+ if err != nil {
+ assert.FailNow(t, err.Error())
+ }
+ defer cleanContainer(id)
+
+ proxy, err := outbound.NewVmess(outbound.VmessOption{
+ Name: "vmess",
+ Server: localIP.String(),
+ Port: 10002,
+ UUID: "b831381d-6324-4d53-ad4f-8cda48b30811",
+ Cipher: "auto",
+ AlterID: 32,
+ Network: "ws",
+ TLS: true,
+ SkipCertVerify: true,
+ UDP: true,
+ })
+ if err != nil {
+ assert.FailNow(t, err.Error())
+ }
+
+ time.Sleep(waitTime)
+ testSuit(t, proxy)
+}
+
+func TestClash_VmessGrpc(t *testing.T) {
+ cfg := &container.Config{
+ Image: ImageXray,
+ ExposedPorts: defaultExposedPorts,
+ }
+ hostCfg := &container.HostConfig{
+ PortBindings: defaultPortBindings,
+ Binds: []string{
+ fmt.Sprintf("%s:/etc/xray/config.json", C.Path.Resolve("vmess-grpc.json")),
+ fmt.Sprintf("%s:/etc/ssl/v2ray/fullchain.pem", C.Path.Resolve("example.org.pem")),
+ fmt.Sprintf("%s:/etc/ssl/v2ray/privkey.pem", C.Path.Resolve("example.org-key.pem")),
+ },
+ }
+
+ id, err := startContainer(cfg, hostCfg, "vmess-grpc")
+ if err != nil {
+ assert.FailNow(t, err.Error())
+ }
+ defer cleanContainer(id)
+
+ proxy, err := outbound.NewVmess(outbound.VmessOption{
+ Name: "vmess",
+ Server: localIP.String(),
+ Port: 10002,
+ UUID: "b831381d-6324-4d53-ad4f-8cda48b30811",
+ Cipher: "auto",
+ AlterID: 32,
+ Network: "grpc",
+ TLS: true,
+ SkipCertVerify: true,
+ UDP: true,
+ ServerName: "example.org",
+ GrpcOpts: outbound.GrpcOptions{
+ GrpcServiceName: "example",
+ },
+ })
+ if err != nil {
+ assert.FailNow(t, err.Error())
+ }
+
+ time.Sleep(waitTime)
+ testSuit(t, proxy)
+}
From 0778591524e180cc935176e772ede8d8a86c0f85 Mon Sep 17 00:00:00 2001
From: Rusty Pen
Date: Wed, 19 May 2021 11:17:35 +0800
Subject: [PATCH 05/96] Feature: dns resolve domain through nameserver-policy
(#1406)
---
component/trie/domain.go | 6 +++---
config/config.go | 23 +++++++++++++++++++++++
dns/resolver.go | 35 +++++++++++++++++++++++++++++++++++
hub/executor/executor.go | 1 +
4 files changed, 62 insertions(+), 3 deletions(-)
diff --git a/component/trie/domain.go b/component/trie/domain.go
index c063686e0..b4de4a707 100644
--- a/component/trie/domain.go
+++ b/component/trie/domain.go
@@ -23,7 +23,7 @@ type DomainTrie struct {
root *Node
}
-func validAndSplitDomain(domain string) ([]string, bool) {
+func ValidAndSplitDomain(domain string) ([]string, bool) {
if domain != "" && domain[len(domain)-1] == '.' {
return nil, false
}
@@ -54,7 +54,7 @@ func validAndSplitDomain(domain string) ([]string, bool) {
// 4. .example.com
// 5. +.example.com
func (t *DomainTrie) Insert(domain string, data interface{}) error {
- parts, valid := validAndSplitDomain(domain)
+ parts, valid := ValidAndSplitDomain(domain)
if !valid {
return ErrInvalidDomain
}
@@ -91,7 +91,7 @@ func (t *DomainTrie) insert(parts []string, data interface{}) {
// 2. wildcard domain
// 2. dot wildcard domain
func (t *DomainTrie) Search(domain string) *Node {
- parts, valid := validAndSplitDomain(domain)
+ parts, valid := ValidAndSplitDomain(domain)
if !valid || parts[0] == "" {
return nil
}
diff --git a/config/config.go b/config/config.go
index 51faac918..903316492 100644
--- a/config/config.go
+++ b/config/config.go
@@ -64,6 +64,7 @@ type DNS struct {
DefaultNameserver []dns.NameServer `yaml:"default-nameserver"`
FakeIPRange *fakeip.Pool
Hosts *trie.DomainTrie
+ NameServerPolicy map[string]dns.NameServer
}
// FallbackFilter config
@@ -106,6 +107,7 @@ type RawDNS struct {
FakeIPRange string `yaml:"fake-ip-range"`
FakeIPFilter []string `yaml:"fake-ip-filter"`
DefaultNameserver []string `yaml:"default-nameserver"`
+ NameServerPolicy map[string]string `yaml:"nameserver-policy"`
}
type RawFallbackFilter struct {
@@ -500,6 +502,23 @@ func parseNameServer(servers []string) ([]dns.NameServer, error) {
return nameservers, nil
}
+func parseNameServerPolicy(nsPolicy map[string]string) (map[string]dns.NameServer, error) {
+ policy := map[string]dns.NameServer{}
+
+ for domain, server := range nsPolicy {
+ nameservers, err := parseNameServer([]string{server})
+ if err != nil {
+ return nil, err
+ }
+ if _, valid := trie.ValidAndSplitDomain(domain); !valid {
+ return nil, fmt.Errorf("DNS ResoverRule invalid domain: %s", domain)
+ }
+ policy[domain] = nameservers[0]
+ }
+
+ return policy, nil
+}
+
func parseFallbackIPCIDR(ips []string) ([]*net.IPNet, error) {
ipNets := []*net.IPNet{}
@@ -537,6 +556,10 @@ func parseDNS(cfg RawDNS, hosts *trie.DomainTrie) (*DNS, error) {
return nil, err
}
+ if dnsCfg.NameServerPolicy, err = parseNameServerPolicy(cfg.NameServerPolicy); err != nil {
+ return nil, err
+ }
+
if len(cfg.DefaultNameserver) == 0 {
return nil, errors.New("default nameserver should have at least one nameserver")
}
diff --git a/dns/resolver.go b/dns/resolver.go
index 0db6855dd..f57fec525 100644
--- a/dns/resolver.go
+++ b/dns/resolver.go
@@ -43,6 +43,7 @@ type Resolver struct {
fallbackIPFilters []fallbackIPFilter
group singleflight.Group
lruCache *cache.LruCache
+ policy *trie.DomainTrie
}
// ResolveIP request with TypeA and TypeAAAA, priority return TypeA
@@ -131,6 +132,9 @@ func (r *Resolver) exchangeWithoutCache(m *D.Msg) (msg *D.Msg, err error) {
return r.ipExchange(m)
}
+ if matched := r.matchPolicy(m); len(matched) != 0 {
+ return r.batchExchange(matched, m)
+ }
return r.batchExchange(r.main, m)
})
@@ -172,6 +176,24 @@ func (r *Resolver) batchExchange(clients []dnsClient, m *D.Msg) (msg *D.Msg, err
return
}
+func (r *Resolver) matchPolicy(m *D.Msg) []dnsClient {
+ if r.policy == nil {
+ return nil
+ }
+
+ domain := r.msgToDomain(m)
+ if domain == "" {
+ return nil
+ }
+
+ record := r.policy.Search(domain)
+ if record == nil {
+ return nil
+ }
+
+ return record.Data.([]dnsClient)
+}
+
func (r *Resolver) shouldOnlyQueryFallback(m *D.Msg) bool {
if r.fallback == nil || len(r.fallbackDomainFilters) == 0 {
return false
@@ -194,6 +216,11 @@ func (r *Resolver) shouldOnlyQueryFallback(m *D.Msg) bool {
func (r *Resolver) ipExchange(m *D.Msg) (msg *D.Msg, err error) {
+ if matched := r.matchPolicy(m); len(matched) != 0 {
+ res := <-r.asyncExchange(matched, m)
+ return res.Msg, res.Error
+ }
+
onlyFallback := r.shouldOnlyQueryFallback(m)
if onlyFallback {
@@ -293,6 +320,7 @@ type Config struct {
FallbackFilter FallbackFilter
Pool *fakeip.Pool
Hosts *trie.DomainTrie
+ Policy map[string]NameServer
}
func NewResolver(config Config) *Resolver {
@@ -312,6 +340,13 @@ func NewResolver(config Config) *Resolver {
r.fallback = transform(config.Fallback, defaultResolver)
}
+ if len(config.Policy) != 0 {
+ r.policy = trie.New()
+ for domain, nameserver := range config.Policy {
+ r.policy.Insert(domain, transform([]NameServer{nameserver}, defaultResolver))
+ }
+ }
+
fallbackIPFilters := []fallbackIPFilter{}
if config.FallbackFilter.GeoIP {
fallbackIPFilters = append(fallbackIPFilters, &geoipFilter{})
diff --git a/hub/executor/executor.go b/hub/executor/executor.go
index bea2a1abd..caf75aff9 100644
--- a/hub/executor/executor.go
+++ b/hub/executor/executor.go
@@ -128,6 +128,7 @@ func updateDNS(c *config.DNS) {
Domain: c.FallbackFilter.Domain,
},
Default: c.DefaultNameserver,
+ Policy: c.NameServerPolicy,
}
r := dns.NewResolver(cfg)
From 045edc188cd3f90e9aa95c0c6f02f89848cb4967 Mon Sep 17 00:00:00 2001
From: Dreamacro <8615343+Dreamacro@users.noreply.github.com>
Date: Thu, 10 Jun 2021 14:05:56 +0800
Subject: [PATCH 06/96] Style: code style
---
.../outbound/base.go => adapter/adapter.go | 126 +++++-------------
{adapters => adapter}/inbound/http.go | 0
{adapters => adapter}/inbound/https.go | 0
{adapters => adapter}/inbound/packet.go | 0
{adapters => adapter}/inbound/socket.go | 0
{adapters => adapter}/inbound/util.go | 0
adapter/outbound/base.go | 100 ++++++++++++++
{adapters => adapter}/outbound/direct.go | 0
{adapters => adapter}/outbound/http.go | 0
{adapters => adapter}/outbound/reject.go | 0
{adapters => adapter}/outbound/shadowsocks.go | 8 --
.../outbound/shadowsocksr.go | 8 --
{adapters => adapter}/outbound/snell.go | 0
{adapters => adapter}/outbound/socks5.go | 2 +-
{adapters => adapter}/outbound/trojan.go | 9 +-
{adapters => adapter}/outbound/util.go | 34 -----
{adapters => adapter}/outbound/vmess.go | 2 +-
{adapters => adapter}/outboundgroup/common.go | 2 +-
.../outboundgroup/fallback.go | 4 +-
.../outboundgroup/loadbalance.go | 4 +-
{adapters => adapter}/outboundgroup/parser.go | 2 +-
{adapters => adapter}/outboundgroup/relay.go | 4 +-
.../outboundgroup/selector.go | 4 +-
.../outboundgroup/urltest.go | 4 +-
{adapters => adapter}/outboundgroup/util.go | 0
{adapters/outbound => adapter}/parser.go | 33 ++---
{adapters => adapter}/provider/fetcher.go | 0
{adapters => adapter}/provider/healthcheck.go | 0
{adapters => adapter}/provider/parser.go | 0
{adapters => adapter}/provider/provider.go | 4 +-
{adapters => adapter}/provider/vehicle.go | 0
config/config.go | 19 +--
config/utils.go | 2 +-
constant/adapters.go | 4 +
hub/executor/executor.go | 8 +-
hub/route/provider.go | 2 +-
hub/route/proxies.go | 6 +-
proxy/http/server.go | 6 +-
proxy/redir/tcp.go | 2 +-
proxy/redir/tproxy.go | 2 +-
proxy/redir/udp.go | 4 +-
proxy/socks/tcp.go | 4 +-
proxy/socks/udp.go | 4 +-
{rules => rule}/base.go | 0
{rules => rule}/domain.go | 0
{rules => rule}/domain_keyword.go | 0
{rules => rule}/domain_suffix.go | 0
{rules => rule}/final.go | 0
{rules => rule}/geoip.go | 0
{rules => rule}/ipcidr.go | 0
{rules => rule}/parser.go | 0
{rules => rule}/port.go | 0
{rules => rule}/process.go | 0
test/snell_test.go | 2 +-
test/ss_test.go | 2 +-
test/trojan_test.go | 2 +-
test/vmess_test.go | 2 +-
tunnel/connection.go | 2 +-
tunnel/tunnel.go | 4 +-
59 files changed, 207 insertions(+), 220 deletions(-)
rename adapters/outbound/base.go => adapter/adapter.go (61%)
rename {adapters => adapter}/inbound/http.go (100%)
rename {adapters => adapter}/inbound/https.go (100%)
rename {adapters => adapter}/inbound/packet.go (100%)
rename {adapters => adapter}/inbound/socket.go (100%)
rename {adapters => adapter}/inbound/util.go (100%)
create mode 100644 adapter/outbound/base.go
rename {adapters => adapter}/outbound/direct.go (100%)
rename {adapters => adapter}/outbound/http.go (100%)
rename {adapters => adapter}/outbound/reject.go (100%)
rename {adapters => adapter}/outbound/shadowsocks.go (96%)
rename {adapters => adapter}/outbound/shadowsocksr.go (95%)
rename {adapters => adapter}/outbound/snell.go (100%)
rename {adapters => adapter}/outbound/socks5.go (98%)
rename {adapters => adapter}/outbound/trojan.go (95%)
rename {adapters => adapter}/outbound/util.go (76%)
rename {adapters => adapter}/outbound/vmess.go (99%)
rename {adapters => adapter}/outboundgroup/common.go (90%)
rename {adapters => adapter}/outboundgroup/fallback.go (95%)
rename {adapters => adapter}/outboundgroup/loadbalance.go (97%)
rename {adapters => adapter}/outboundgroup/parser.go (98%)
rename {adapters => adapter}/outboundgroup/relay.go (95%)
rename {adapters => adapter}/outboundgroup/selector.go (96%)
rename {adapters => adapter}/outboundgroup/urltest.go (97%)
rename {adapters => adapter}/outboundgroup/util.go (100%)
rename {adapters/outbound => adapter}/parser.go (63%)
rename {adapters => adapter}/provider/fetcher.go (100%)
rename {adapters => adapter}/provider/healthcheck.go (100%)
rename {adapters => adapter}/provider/parser.go (100%)
rename {adapters => adapter}/provider/provider.go (98%)
rename {adapters => adapter}/provider/vehicle.go (100%)
rename {rules => rule}/base.go (100%)
rename {rules => rule}/domain.go (100%)
rename {rules => rule}/domain_keyword.go (100%)
rename {rules => rule}/domain_suffix.go (100%)
rename {rules => rule}/final.go (100%)
rename {rules => rule}/geoip.go (100%)
rename {rules => rule}/ipcidr.go (100%)
rename {rules => rule}/parser.go (100%)
rename {rules => rule}/port.go (100%)
rename {rules => rule}/process.go (100%)
diff --git a/adapters/outbound/base.go b/adapter/adapter.go
similarity index 61%
rename from adapters/outbound/base.go
rename to adapter/adapter.go
index 6e16bbaed..f3503f04c 100644
--- a/adapters/outbound/base.go
+++ b/adapter/adapter.go
@@ -1,11 +1,12 @@
-package outbound
+package adapter
import (
"context"
"encoding/json"
- "errors"
+ "fmt"
"net"
"net/http"
+ "net/url"
"time"
"github.com/Dreamacro/clash/common/queue"
@@ -14,97 +15,6 @@ import (
"go.uber.org/atomic"
)
-type Base struct {
- name string
- addr string
- tp C.AdapterType
- udp bool
-}
-
-// Name implements C.ProxyAdapter
-func (b *Base) Name() string {
- return b.name
-}
-
-// Type implements C.ProxyAdapter
-func (b *Base) Type() C.AdapterType {
- return b.tp
-}
-
-// StreamConn implements C.ProxyAdapter
-func (b *Base) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {
- return c, errors.New("no support")
-}
-
-// DialUDP implements C.ProxyAdapter
-func (b *Base) DialUDP(metadata *C.Metadata) (C.PacketConn, error) {
- return nil, errors.New("no support")
-}
-
-// SupportUDP implements C.ProxyAdapter
-func (b *Base) SupportUDP() bool {
- return b.udp
-}
-
-// MarshalJSON implements C.ProxyAdapter
-func (b *Base) MarshalJSON() ([]byte, error) {
- return json.Marshal(map[string]string{
- "type": b.Type().String(),
- })
-}
-
-// Addr implements C.ProxyAdapter
-func (b *Base) Addr() string {
- return b.addr
-}
-
-// Unwrap implements C.ProxyAdapter
-func (b *Base) Unwrap(metadata *C.Metadata) C.Proxy {
- return nil
-}
-
-func NewBase(name string, addr string, tp C.AdapterType, udp bool) *Base {
- return &Base{name, addr, tp, udp}
-}
-
-type conn struct {
- net.Conn
- chain C.Chain
-}
-
-// Chains implements C.Connection
-func (c *conn) Chains() C.Chain {
- return c.chain
-}
-
-// AppendToChains implements C.Connection
-func (c *conn) AppendToChains(a C.ProxyAdapter) {
- c.chain = append(c.chain, a.Name())
-}
-
-func NewConn(c net.Conn, a C.ProxyAdapter) C.Conn {
- return &conn{c, []string{a.Name()}}
-}
-
-type packetConn struct {
- net.PacketConn
- chain C.Chain
-}
-
-// Chains implements C.Connection
-func (c *packetConn) Chains() C.Chain {
- return c.chain
-}
-
-// AppendToChains implements C.Connection
-func (c *packetConn) AppendToChains(a C.ProxyAdapter) {
- c.chain = append(c.chain, a.Name())
-}
-
-func newPacketConn(pc net.PacketConn, a C.ProxyAdapter) C.PacketConn {
- return &packetConn{pc, []string{a.Name()}}
-}
-
type Proxy struct {
C.ProxyAdapter
history *queue.Queue
@@ -118,7 +28,7 @@ func (p *Proxy) Alive() bool {
// Dial implements C.Proxy
func (p *Proxy) Dial(metadata *C.Metadata) (C.Conn, error) {
- ctx, cancel := context.WithTimeout(context.Background(), tcpTimeout)
+ ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTCPTimeout)
defer cancel()
return p.DialContext(ctx, metadata)
}
@@ -237,3 +147,31 @@ func (p *Proxy) URLTest(ctx context.Context, url string) (t uint16, err error) {
func NewProxy(adapter C.ProxyAdapter) *Proxy {
return &Proxy{adapter, queue.New(10), atomic.NewBool(true)}
}
+
+func urlToMetadata(rawURL string) (addr C.Metadata, err error) {
+ u, err := url.Parse(rawURL)
+ if err != nil {
+ return
+ }
+
+ port := u.Port()
+ if port == "" {
+ switch u.Scheme {
+ case "https":
+ port = "443"
+ case "http":
+ port = "80"
+ default:
+ err = fmt.Errorf("%s scheme not Support", rawURL)
+ return
+ }
+ }
+
+ addr = C.Metadata{
+ AddrType: C.AtypDomainName,
+ Host: u.Hostname(),
+ DstIP: nil,
+ DstPort: port,
+ }
+ return
+}
diff --git a/adapters/inbound/http.go b/adapter/inbound/http.go
similarity index 100%
rename from adapters/inbound/http.go
rename to adapter/inbound/http.go
diff --git a/adapters/inbound/https.go b/adapter/inbound/https.go
similarity index 100%
rename from adapters/inbound/https.go
rename to adapter/inbound/https.go
diff --git a/adapters/inbound/packet.go b/adapter/inbound/packet.go
similarity index 100%
rename from adapters/inbound/packet.go
rename to adapter/inbound/packet.go
diff --git a/adapters/inbound/socket.go b/adapter/inbound/socket.go
similarity index 100%
rename from adapters/inbound/socket.go
rename to adapter/inbound/socket.go
diff --git a/adapters/inbound/util.go b/adapter/inbound/util.go
similarity index 100%
rename from adapters/inbound/util.go
rename to adapter/inbound/util.go
diff --git a/adapter/outbound/base.go b/adapter/outbound/base.go
new file mode 100644
index 000000000..a001d799e
--- /dev/null
+++ b/adapter/outbound/base.go
@@ -0,0 +1,100 @@
+package outbound
+
+import (
+ "encoding/json"
+ "errors"
+ "net"
+
+ C "github.com/Dreamacro/clash/constant"
+)
+
+type Base struct {
+ name string
+ addr string
+ tp C.AdapterType
+ udp bool
+}
+
+// Name implements C.ProxyAdapter
+func (b *Base) Name() string {
+ return b.name
+}
+
+// Type implements C.ProxyAdapter
+func (b *Base) Type() C.AdapterType {
+ return b.tp
+}
+
+// StreamConn implements C.ProxyAdapter
+func (b *Base) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {
+ return c, errors.New("no support")
+}
+
+// DialUDP implements C.ProxyAdapter
+func (b *Base) DialUDP(metadata *C.Metadata) (C.PacketConn, error) {
+ return nil, errors.New("no support")
+}
+
+// SupportUDP implements C.ProxyAdapter
+func (b *Base) SupportUDP() bool {
+ return b.udp
+}
+
+// MarshalJSON implements C.ProxyAdapter
+func (b *Base) MarshalJSON() ([]byte, error) {
+ return json.Marshal(map[string]string{
+ "type": b.Type().String(),
+ })
+}
+
+// Addr implements C.ProxyAdapter
+func (b *Base) Addr() string {
+ return b.addr
+}
+
+// Unwrap implements C.ProxyAdapter
+func (b *Base) Unwrap(metadata *C.Metadata) C.Proxy {
+ return nil
+}
+
+func NewBase(name string, addr string, tp C.AdapterType, udp bool) *Base {
+ return &Base{name, addr, tp, udp}
+}
+
+type conn struct {
+ net.Conn
+ chain C.Chain
+}
+
+// Chains implements C.Connection
+func (c *conn) Chains() C.Chain {
+ return c.chain
+}
+
+// AppendToChains implements C.Connection
+func (c *conn) AppendToChains(a C.ProxyAdapter) {
+ c.chain = append(c.chain, a.Name())
+}
+
+func NewConn(c net.Conn, a C.ProxyAdapter) C.Conn {
+ return &conn{c, []string{a.Name()}}
+}
+
+type packetConn struct {
+ net.PacketConn
+ chain C.Chain
+}
+
+// Chains implements C.Connection
+func (c *packetConn) Chains() C.Chain {
+ return c.chain
+}
+
+// AppendToChains implements C.Connection
+func (c *packetConn) AppendToChains(a C.ProxyAdapter) {
+ c.chain = append(c.chain, a.Name())
+}
+
+func newPacketConn(pc net.PacketConn, a C.ProxyAdapter) C.PacketConn {
+ return &packetConn{pc, []string{a.Name()}}
+}
diff --git a/adapters/outbound/direct.go b/adapter/outbound/direct.go
similarity index 100%
rename from adapters/outbound/direct.go
rename to adapter/outbound/direct.go
diff --git a/adapters/outbound/http.go b/adapter/outbound/http.go
similarity index 100%
rename from adapters/outbound/http.go
rename to adapter/outbound/http.go
diff --git a/adapters/outbound/reject.go b/adapter/outbound/reject.go
similarity index 100%
rename from adapters/outbound/reject.go
rename to adapter/outbound/reject.go
diff --git a/adapters/outbound/shadowsocks.go b/adapter/outbound/shadowsocks.go
similarity index 96%
rename from adapters/outbound/shadowsocks.go
rename to adapter/outbound/shadowsocks.go
index 6dcfc2c08..0fb3ab9a8 100644
--- a/adapters/outbound/shadowsocks.go
+++ b/adapter/outbound/shadowsocks.go
@@ -2,7 +2,6 @@ package outbound
import (
"context"
- "encoding/json"
"errors"
"fmt"
"net"
@@ -105,13 +104,6 @@ func (ss *ShadowSocks) DialUDP(metadata *C.Metadata) (C.PacketConn, error) {
return newPacketConn(&ssPacketConn{PacketConn: pc, rAddr: addr}, ss), nil
}
-// MarshalJSON implements C.ProxyAdapter
-func (ss *ShadowSocks) MarshalJSON() ([]byte, error) {
- return json.Marshal(map[string]string{
- "type": ss.Type().String(),
- })
-}
-
func NewShadowSocks(option ShadowSocksOption) (*ShadowSocks, error) {
addr := net.JoinHostPort(option.Server, strconv.Itoa(option.Port))
cipher := option.Cipher
diff --git a/adapters/outbound/shadowsocksr.go b/adapter/outbound/shadowsocksr.go
similarity index 95%
rename from adapters/outbound/shadowsocksr.go
rename to adapter/outbound/shadowsocksr.go
index 635135fcd..b44f46e56 100644
--- a/adapters/outbound/shadowsocksr.go
+++ b/adapter/outbound/shadowsocksr.go
@@ -2,7 +2,6 @@ package outbound
import (
"context"
- "encoding/json"
"fmt"
"net"
"strconv"
@@ -91,13 +90,6 @@ func (ssr *ShadowSocksR) DialUDP(metadata *C.Metadata) (C.PacketConn, error) {
return newPacketConn(&ssPacketConn{PacketConn: pc, rAddr: addr}, ssr), nil
}
-// MarshalJSON implements C.ProxyAdapter
-func (ssr *ShadowSocksR) MarshalJSON() ([]byte, error) {
- return json.Marshal(map[string]string{
- "type": ssr.Type().String(),
- })
-}
-
func NewShadowSocksR(option ShadowSocksROption) (*ShadowSocksR, error) {
addr := net.JoinHostPort(option.Server, strconv.Itoa(option.Port))
cipher := option.Cipher
diff --git a/adapters/outbound/snell.go b/adapter/outbound/snell.go
similarity index 100%
rename from adapters/outbound/snell.go
rename to adapter/outbound/snell.go
diff --git a/adapters/outbound/socks5.go b/adapter/outbound/socks5.go
similarity index 98%
rename from adapters/outbound/socks5.go
rename to adapter/outbound/socks5.go
index 466797de8..26c7c06ad 100644
--- a/adapters/outbound/socks5.go
+++ b/adapter/outbound/socks5.go
@@ -79,7 +79,7 @@ func (ss *Socks5) DialContext(ctx context.Context, metadata *C.Metadata) (_ C.Co
// DialUDP implements C.ProxyAdapter
func (ss *Socks5) DialUDP(metadata *C.Metadata) (_ C.PacketConn, err error) {
- ctx, cancel := context.WithTimeout(context.Background(), tcpTimeout)
+ ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTCPTimeout)
defer cancel()
c, err := dialer.DialContext(ctx, "tcp", ss.addr)
if err != nil {
diff --git a/adapters/outbound/trojan.go b/adapter/outbound/trojan.go
similarity index 95%
rename from adapters/outbound/trojan.go
rename to adapter/outbound/trojan.go
index 929f44147..5d8527353 100644
--- a/adapters/outbound/trojan.go
+++ b/adapter/outbound/trojan.go
@@ -3,7 +3,6 @@ package outbound
import (
"context"
"crypto/tls"
- "encoding/json"
"fmt"
"net"
"strconv"
@@ -101,7 +100,7 @@ func (t *Trojan) DialUDP(metadata *C.Metadata) (_ C.PacketConn, err error) {
}
defer safeConnClose(c, err)
} else {
- ctx, cancel := context.WithTimeout(context.Background(), tcpTimeout)
+ ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTCPTimeout)
defer cancel()
c, err = dialer.DialContext(ctx, "tcp", t.addr)
if err != nil {
@@ -124,12 +123,6 @@ func (t *Trojan) DialUDP(metadata *C.Metadata) (_ C.PacketConn, err error) {
return newPacketConn(pc, t), err
}
-func (t *Trojan) MarshalJSON() ([]byte, error) {
- return json.Marshal(map[string]string{
- "type": t.Type().String(),
- })
-}
-
func NewTrojan(option TrojanOption) (*Trojan, error) {
addr := net.JoinHostPort(option.Server, strconv.Itoa(option.Port))
diff --git a/adapters/outbound/util.go b/adapter/outbound/util.go
similarity index 76%
rename from adapters/outbound/util.go
rename to adapter/outbound/util.go
index cd60d3732..4b81eb5d6 100644
--- a/adapters/outbound/util.go
+++ b/adapter/outbound/util.go
@@ -3,9 +3,7 @@ package outbound
import (
"bytes"
"crypto/tls"
- "fmt"
"net"
- "net/url"
"strconv"
"sync"
"time"
@@ -15,43 +13,11 @@ import (
"github.com/Dreamacro/clash/transport/socks5"
)
-const (
- tcpTimeout = 5 * time.Second
-)
-
var (
globalClientSessionCache tls.ClientSessionCache
once sync.Once
)
-func urlToMetadata(rawURL string) (addr C.Metadata, err error) {
- u, err := url.Parse(rawURL)
- if err != nil {
- return
- }
-
- port := u.Port()
- if port == "" {
- switch u.Scheme {
- case "https":
- port = "443"
- case "http":
- port = "80"
- default:
- err = fmt.Errorf("%s scheme not Support", rawURL)
- return
- }
- }
-
- addr = C.Metadata{
- AddrType: C.AtypDomainName,
- Host: u.Hostname(),
- DstIP: nil,
- DstPort: port,
- }
- return
-}
-
func tcpKeepAlive(c net.Conn) {
if tcp, ok := c.(*net.TCPConn); ok {
tcp.SetKeepAlive(true)
diff --git a/adapters/outbound/vmess.go b/adapter/outbound/vmess.go
similarity index 99%
rename from adapters/outbound/vmess.go
rename to adapter/outbound/vmess.go
index 246450aca..672f767ba 100644
--- a/adapters/outbound/vmess.go
+++ b/adapter/outbound/vmess.go
@@ -222,7 +222,7 @@ func (v *Vmess) DialUDP(metadata *C.Metadata) (_ C.PacketConn, err error) {
c, err = v.client.StreamConn(c, parseVmessAddr(metadata))
} else {
- ctx, cancel := context.WithTimeout(context.Background(), tcpTimeout)
+ ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTCPTimeout)
defer cancel()
c, err = dialer.DialContext(ctx, "tcp", v.addr)
if err != nil {
diff --git a/adapters/outboundgroup/common.go b/adapter/outboundgroup/common.go
similarity index 90%
rename from adapters/outboundgroup/common.go
rename to adapter/outboundgroup/common.go
index c5c719f29..31b8cb6bb 100644
--- a/adapters/outboundgroup/common.go
+++ b/adapter/outboundgroup/common.go
@@ -3,7 +3,7 @@ package outboundgroup
import (
"time"
- "github.com/Dreamacro/clash/adapters/provider"
+ "github.com/Dreamacro/clash/adapter/provider"
C "github.com/Dreamacro/clash/constant"
)
diff --git a/adapters/outboundgroup/fallback.go b/adapter/outboundgroup/fallback.go
similarity index 95%
rename from adapters/outboundgroup/fallback.go
rename to adapter/outboundgroup/fallback.go
index b3dbe0cb7..8b38f09ca 100644
--- a/adapters/outboundgroup/fallback.go
+++ b/adapter/outboundgroup/fallback.go
@@ -4,8 +4,8 @@ import (
"context"
"encoding/json"
- "github.com/Dreamacro/clash/adapters/outbound"
- "github.com/Dreamacro/clash/adapters/provider"
+ "github.com/Dreamacro/clash/adapter/outbound"
+ "github.com/Dreamacro/clash/adapter/provider"
"github.com/Dreamacro/clash/common/singledo"
C "github.com/Dreamacro/clash/constant"
)
diff --git a/adapters/outboundgroup/loadbalance.go b/adapter/outboundgroup/loadbalance.go
similarity index 97%
rename from adapters/outboundgroup/loadbalance.go
rename to adapter/outboundgroup/loadbalance.go
index b44fade17..7856a07d6 100644
--- a/adapters/outboundgroup/loadbalance.go
+++ b/adapter/outboundgroup/loadbalance.go
@@ -7,8 +7,8 @@ import (
"fmt"
"net"
- "github.com/Dreamacro/clash/adapters/outbound"
- "github.com/Dreamacro/clash/adapters/provider"
+ "github.com/Dreamacro/clash/adapter/outbound"
+ "github.com/Dreamacro/clash/adapter/provider"
"github.com/Dreamacro/clash/common/murmur3"
"github.com/Dreamacro/clash/common/singledo"
C "github.com/Dreamacro/clash/constant"
diff --git a/adapters/outboundgroup/parser.go b/adapter/outboundgroup/parser.go
similarity index 98%
rename from adapters/outboundgroup/parser.go
rename to adapter/outboundgroup/parser.go
index 82ceaa798..d11040a5f 100644
--- a/adapters/outboundgroup/parser.go
+++ b/adapter/outboundgroup/parser.go
@@ -4,7 +4,7 @@ import (
"errors"
"fmt"
- "github.com/Dreamacro/clash/adapters/provider"
+ "github.com/Dreamacro/clash/adapter/provider"
"github.com/Dreamacro/clash/common/structure"
C "github.com/Dreamacro/clash/constant"
)
diff --git a/adapters/outboundgroup/relay.go b/adapter/outboundgroup/relay.go
similarity index 95%
rename from adapters/outboundgroup/relay.go
rename to adapter/outboundgroup/relay.go
index 6583d3903..e4a897b8a 100644
--- a/adapters/outboundgroup/relay.go
+++ b/adapter/outboundgroup/relay.go
@@ -6,8 +6,8 @@ import (
"errors"
"fmt"
- "github.com/Dreamacro/clash/adapters/outbound"
- "github.com/Dreamacro/clash/adapters/provider"
+ "github.com/Dreamacro/clash/adapter/outbound"
+ "github.com/Dreamacro/clash/adapter/provider"
"github.com/Dreamacro/clash/common/singledo"
"github.com/Dreamacro/clash/component/dialer"
C "github.com/Dreamacro/clash/constant"
diff --git a/adapters/outboundgroup/selector.go b/adapter/outboundgroup/selector.go
similarity index 96%
rename from adapters/outboundgroup/selector.go
rename to adapter/outboundgroup/selector.go
index 67afaaabe..c28b6f8cf 100644
--- a/adapters/outboundgroup/selector.go
+++ b/adapter/outboundgroup/selector.go
@@ -5,8 +5,8 @@ import (
"encoding/json"
"errors"
- "github.com/Dreamacro/clash/adapters/outbound"
- "github.com/Dreamacro/clash/adapters/provider"
+ "github.com/Dreamacro/clash/adapter/outbound"
+ "github.com/Dreamacro/clash/adapter/provider"
"github.com/Dreamacro/clash/common/singledo"
C "github.com/Dreamacro/clash/constant"
)
diff --git a/adapters/outboundgroup/urltest.go b/adapter/outboundgroup/urltest.go
similarity index 97%
rename from adapters/outboundgroup/urltest.go
rename to adapter/outboundgroup/urltest.go
index 52c5fef91..0f59d4be5 100644
--- a/adapters/outboundgroup/urltest.go
+++ b/adapter/outboundgroup/urltest.go
@@ -5,8 +5,8 @@ import (
"encoding/json"
"time"
- "github.com/Dreamacro/clash/adapters/outbound"
- "github.com/Dreamacro/clash/adapters/provider"
+ "github.com/Dreamacro/clash/adapter/outbound"
+ "github.com/Dreamacro/clash/adapter/provider"
"github.com/Dreamacro/clash/common/singledo"
C "github.com/Dreamacro/clash/constant"
)
diff --git a/adapters/outboundgroup/util.go b/adapter/outboundgroup/util.go
similarity index 100%
rename from adapters/outboundgroup/util.go
rename to adapter/outboundgroup/util.go
diff --git a/adapters/outbound/parser.go b/adapter/parser.go
similarity index 63%
rename from adapters/outbound/parser.go
rename to adapter/parser.go
index f0f894da3..62d152259 100644
--- a/adapters/outbound/parser.go
+++ b/adapter/parser.go
@@ -1,8 +1,9 @@
-package outbound
+package adapter
import (
"fmt"
+ "github.com/Dreamacro/clash/adapter/outbound"
"github.com/Dreamacro/clash/common/structure"
C "github.com/Dreamacro/clash/constant"
)
@@ -20,36 +21,36 @@ func ParseProxy(mapping map[string]interface{}) (C.Proxy, error) {
)
switch proxyType {
case "ss":
- ssOption := &ShadowSocksOption{}
+ ssOption := &outbound.ShadowSocksOption{}
err = decoder.Decode(mapping, ssOption)
if err != nil {
break
}
- proxy, err = NewShadowSocks(*ssOption)
+ proxy, err = outbound.NewShadowSocks(*ssOption)
case "ssr":
- ssrOption := &ShadowSocksROption{}
+ ssrOption := &outbound.ShadowSocksROption{}
err = decoder.Decode(mapping, ssrOption)
if err != nil {
break
}
- proxy, err = NewShadowSocksR(*ssrOption)
+ proxy, err = outbound.NewShadowSocksR(*ssrOption)
case "socks5":
- socksOption := &Socks5Option{}
+ socksOption := &outbound.Socks5Option{}
err = decoder.Decode(mapping, socksOption)
if err != nil {
break
}
- proxy = NewSocks5(*socksOption)
+ proxy = outbound.NewSocks5(*socksOption)
case "http":
- httpOption := &HttpOption{}
+ httpOption := &outbound.HttpOption{}
err = decoder.Decode(mapping, httpOption)
if err != nil {
break
}
- proxy = NewHttp(*httpOption)
+ proxy = outbound.NewHttp(*httpOption)
case "vmess":
- vmessOption := &VmessOption{
- HTTPOpts: HTTPOptions{
+ vmessOption := &outbound.VmessOption{
+ HTTPOpts: outbound.HTTPOptions{
Method: "GET",
Path: []string{"/"},
},
@@ -58,21 +59,21 @@ func ParseProxy(mapping map[string]interface{}) (C.Proxy, error) {
if err != nil {
break
}
- proxy, err = NewVmess(*vmessOption)
+ proxy, err = outbound.NewVmess(*vmessOption)
case "snell":
- snellOption := &SnellOption{}
+ snellOption := &outbound.SnellOption{}
err = decoder.Decode(mapping, snellOption)
if err != nil {
break
}
- proxy, err = NewSnell(*snellOption)
+ proxy, err = outbound.NewSnell(*snellOption)
case "trojan":
- trojanOption := &TrojanOption{}
+ trojanOption := &outbound.TrojanOption{}
err = decoder.Decode(mapping, trojanOption)
if err != nil {
break
}
- proxy, err = NewTrojan(*trojanOption)
+ proxy, err = outbound.NewTrojan(*trojanOption)
default:
return nil, fmt.Errorf("unsupport proxy type: %s", proxyType)
}
diff --git a/adapters/provider/fetcher.go b/adapter/provider/fetcher.go
similarity index 100%
rename from adapters/provider/fetcher.go
rename to adapter/provider/fetcher.go
diff --git a/adapters/provider/healthcheck.go b/adapter/provider/healthcheck.go
similarity index 100%
rename from adapters/provider/healthcheck.go
rename to adapter/provider/healthcheck.go
diff --git a/adapters/provider/parser.go b/adapter/provider/parser.go
similarity index 100%
rename from adapters/provider/parser.go
rename to adapter/provider/parser.go
diff --git a/adapters/provider/provider.go b/adapter/provider/provider.go
similarity index 98%
rename from adapters/provider/provider.go
rename to adapter/provider/provider.go
index 756a89d12..f87fe2a12 100644
--- a/adapters/provider/provider.go
+++ b/adapter/provider/provider.go
@@ -7,7 +7,7 @@ import (
"runtime"
"time"
- "github.com/Dreamacro/clash/adapters/outbound"
+ "github.com/Dreamacro/clash/adapter"
C "github.com/Dreamacro/clash/constant"
"gopkg.in/yaml.v2"
@@ -133,7 +133,7 @@ func proxiesParse(buf []byte) (interface{}, error) {
proxies := []C.Proxy{}
for idx, mapping := range schema.Proxies {
- proxy, err := outbound.ParseProxy(mapping)
+ proxy, err := adapter.ParseProxy(mapping)
if err != nil {
return nil, fmt.Errorf("proxy %d error: %w", idx, err)
}
diff --git a/adapters/provider/vehicle.go b/adapter/provider/vehicle.go
similarity index 100%
rename from adapters/provider/vehicle.go
rename to adapter/provider/vehicle.go
diff --git a/config/config.go b/config/config.go
index 903316492..a256d2820 100644
--- a/config/config.go
+++ b/config/config.go
@@ -8,16 +8,17 @@ import (
"os"
"strings"
- "github.com/Dreamacro/clash/adapters/outbound"
- "github.com/Dreamacro/clash/adapters/outboundgroup"
- "github.com/Dreamacro/clash/adapters/provider"
+ "github.com/Dreamacro/clash/adapter"
+ "github.com/Dreamacro/clash/adapter/outbound"
+ "github.com/Dreamacro/clash/adapter/outboundgroup"
+ "github.com/Dreamacro/clash/adapter/provider"
"github.com/Dreamacro/clash/component/auth"
"github.com/Dreamacro/clash/component/fakeip"
"github.com/Dreamacro/clash/component/trie"
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/dns"
"github.com/Dreamacro/clash/log"
- R "github.com/Dreamacro/clash/rules"
+ R "github.com/Dreamacro/clash/rule"
T "github.com/Dreamacro/clash/tunnel"
yaml "gopkg.in/yaml.v2"
@@ -274,13 +275,13 @@ func parseProxies(cfg *RawConfig) (proxies map[string]C.Proxy, providersMap map[
groupsConfig := cfg.ProxyGroup
providersConfig := cfg.ProxyProvider
- proxies["DIRECT"] = outbound.NewProxy(outbound.NewDirect())
- proxies["REJECT"] = outbound.NewProxy(outbound.NewReject())
+ proxies["DIRECT"] = adapter.NewProxy(outbound.NewDirect())
+ proxies["REJECT"] = adapter.NewProxy(outbound.NewReject())
proxyList = append(proxyList, "DIRECT", "REJECT")
// parse proxy
for idx, mapping := range proxiesConfig {
- proxy, err := outbound.ParseProxy(mapping)
+ proxy, err := adapter.ParseProxy(mapping)
if err != nil {
return nil, nil, fmt.Errorf("proxy %d: %w", idx, err)
}
@@ -339,7 +340,7 @@ func parseProxies(cfg *RawConfig) (proxies map[string]C.Proxy, providersMap map[
return nil, nil, fmt.Errorf("proxy group %s: the duplicate name", groupName)
}
- proxies[groupName] = outbound.NewProxy(group)
+ proxies[groupName] = adapter.NewProxy(group)
}
// initial compatible provider
@@ -368,7 +369,7 @@ func parseProxies(cfg *RawConfig) (proxies map[string]C.Proxy, providersMap map[
},
[]provider.ProxyProvider{pd},
)
- proxies["GLOBAL"] = outbound.NewProxy(global)
+ proxies["GLOBAL"] = adapter.NewProxy(global)
return proxies, providersMap, nil
}
diff --git a/config/utils.go b/config/utils.go
index b3d198f7f..387591d0b 100644
--- a/config/utils.go
+++ b/config/utils.go
@@ -4,7 +4,7 @@ import (
"fmt"
"strings"
- "github.com/Dreamacro/clash/adapters/outboundgroup"
+ "github.com/Dreamacro/clash/adapter/outboundgroup"
"github.com/Dreamacro/clash/common/structure"
)
diff --git a/constant/adapters.go b/constant/adapters.go
index 333243d8a..733d86b91 100644
--- a/constant/adapters.go
+++ b/constant/adapters.go
@@ -27,6 +27,10 @@ const (
LoadBalance
)
+const (
+ DefaultTCPTimeout = 5 * time.Second
+)
+
type Connection interface {
Chains() Chain
AppendToChains(adapter ProxyAdapter)
diff --git a/hub/executor/executor.go b/hub/executor/executor.go
index caf75aff9..5d803106a 100644
--- a/hub/executor/executor.go
+++ b/hub/executor/executor.go
@@ -6,9 +6,9 @@ import (
"os"
"sync"
- "github.com/Dreamacro/clash/adapters/outbound"
- "github.com/Dreamacro/clash/adapters/outboundgroup"
- "github.com/Dreamacro/clash/adapters/provider"
+ "github.com/Dreamacro/clash/adapter"
+ "github.com/Dreamacro/clash/adapter/outboundgroup"
+ "github.com/Dreamacro/clash/adapter/provider"
"github.com/Dreamacro/clash/component/auth"
"github.com/Dreamacro/clash/component/dialer"
"github.com/Dreamacro/clash/component/profile"
@@ -232,7 +232,7 @@ func patchSelectGroup(proxies map[string]C.Proxy) {
}
for name, proxy := range proxies {
- outbound, ok := proxy.(*outbound.Proxy)
+ outbound, ok := proxy.(*adapter.Proxy)
if !ok {
continue
}
diff --git a/hub/route/provider.go b/hub/route/provider.go
index 902f13aff..f373d5114 100644
--- a/hub/route/provider.go
+++ b/hub/route/provider.go
@@ -4,7 +4,7 @@ import (
"context"
"net/http"
- "github.com/Dreamacro/clash/adapters/provider"
+ "github.com/Dreamacro/clash/adapter/provider"
"github.com/Dreamacro/clash/tunnel"
"github.com/go-chi/chi/v5"
diff --git a/hub/route/proxies.go b/hub/route/proxies.go
index e541223dd..bba9e2a80 100644
--- a/hub/route/proxies.go
+++ b/hub/route/proxies.go
@@ -7,8 +7,8 @@ import (
"strconv"
"time"
- "github.com/Dreamacro/clash/adapters/outbound"
- "github.com/Dreamacro/clash/adapters/outboundgroup"
+ "github.com/Dreamacro/clash/adapter"
+ "github.com/Dreamacro/clash/adapter/outboundgroup"
"github.com/Dreamacro/clash/component/profile/cachefile"
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/tunnel"
@@ -78,7 +78,7 @@ func updateProxy(w http.ResponseWriter, r *http.Request) {
return
}
- proxy := r.Context().Value(CtxKeyProxy).(*outbound.Proxy)
+ proxy := r.Context().Value(CtxKeyProxy).(*adapter.Proxy)
selector, ok := proxy.ProxyAdapter.(*outboundgroup.Selector)
if !ok {
render.Status(r, http.StatusBadRequest)
diff --git a/proxy/http/server.go b/proxy/http/server.go
index 75f4fc368..69117dbb8 100644
--- a/proxy/http/server.go
+++ b/proxy/http/server.go
@@ -8,7 +8,7 @@ import (
"strings"
"time"
- adapters "github.com/Dreamacro/clash/adapters/inbound"
+ "github.com/Dreamacro/clash/adapter/inbound"
"github.com/Dreamacro/clash/common/cache"
"github.com/Dreamacro/clash/component/auth"
"github.com/Dreamacro/clash/log"
@@ -106,9 +106,9 @@ keepAlive:
conn.Close()
return
}
- tunnel.Add(adapters.NewHTTPS(request, conn))
+ tunnel.Add(inbound.NewHTTPS(request, conn))
return
}
- tunnel.Add(adapters.NewHTTP(request, conn))
+ tunnel.Add(inbound.NewHTTP(request, conn))
}
diff --git a/proxy/redir/tcp.go b/proxy/redir/tcp.go
index e53d000d6..ef6718ec9 100644
--- a/proxy/redir/tcp.go
+++ b/proxy/redir/tcp.go
@@ -3,7 +3,7 @@ package redir
import (
"net"
- "github.com/Dreamacro/clash/adapters/inbound"
+ "github.com/Dreamacro/clash/adapter/inbound"
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/log"
"github.com/Dreamacro/clash/tunnel"
diff --git a/proxy/redir/tproxy.go b/proxy/redir/tproxy.go
index 576c4d37f..44682362f 100644
--- a/proxy/redir/tproxy.go
+++ b/proxy/redir/tproxy.go
@@ -3,7 +3,7 @@ package redir
import (
"net"
- "github.com/Dreamacro/clash/adapters/inbound"
+ "github.com/Dreamacro/clash/adapter/inbound"
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/log"
"github.com/Dreamacro/clash/transport/socks5"
diff --git a/proxy/redir/udp.go b/proxy/redir/udp.go
index 57bd3ff35..e43af878b 100644
--- a/proxy/redir/udp.go
+++ b/proxy/redir/udp.go
@@ -3,7 +3,7 @@ package redir
import (
"net"
- adapters "github.com/Dreamacro/clash/adapters/inbound"
+ "github.com/Dreamacro/clash/adapter/inbound"
"github.com/Dreamacro/clash/common/pool"
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/transport/socks5"
@@ -75,5 +75,5 @@ func handleRedirUDP(pc net.PacketConn, buf []byte, lAddr *net.UDPAddr, rAddr *ne
lAddr: lAddr,
buf: buf,
}
- tunnel.AddPacket(adapters.NewPacket(target, pkt, C.TPROXY))
+ tunnel.AddPacket(inbound.NewPacket(target, pkt, C.TPROXY))
}
diff --git a/proxy/socks/tcp.go b/proxy/socks/tcp.go
index 116ea3f6b..a58d63d18 100644
--- a/proxy/socks/tcp.go
+++ b/proxy/socks/tcp.go
@@ -5,7 +5,7 @@ import (
"io/ioutil"
"net"
- adapters "github.com/Dreamacro/clash/adapters/inbound"
+ "github.com/Dreamacro/clash/adapter/inbound"
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/log"
authStore "github.com/Dreamacro/clash/proxy/auth"
@@ -66,5 +66,5 @@ func HandleSocks(conn net.Conn) {
io.Copy(ioutil.Discard, conn)
return
}
- tunnel.Add(adapters.NewSocket(target, conn, C.SOCKS))
+ tunnel.Add(inbound.NewSocket(target, conn, C.SOCKS))
}
diff --git a/proxy/socks/udp.go b/proxy/socks/udp.go
index a365353b8..b41e6f18e 100644
--- a/proxy/socks/udp.go
+++ b/proxy/socks/udp.go
@@ -3,7 +3,7 @@ package socks
import (
"net"
- adapters "github.com/Dreamacro/clash/adapters/inbound"
+ "github.com/Dreamacro/clash/adapter/inbound"
"github.com/Dreamacro/clash/common/pool"
"github.com/Dreamacro/clash/common/sockopt"
C "github.com/Dreamacro/clash/constant"
@@ -70,5 +70,5 @@ func handleSocksUDP(pc net.PacketConn, buf []byte, addr net.Addr) {
payload: payload,
bufRef: buf,
}
- tunnel.AddPacket(adapters.NewPacket(target, packet, C.SOCKS))
+ tunnel.AddPacket(inbound.NewPacket(target, packet, C.SOCKS))
}
diff --git a/rules/base.go b/rule/base.go
similarity index 100%
rename from rules/base.go
rename to rule/base.go
diff --git a/rules/domain.go b/rule/domain.go
similarity index 100%
rename from rules/domain.go
rename to rule/domain.go
diff --git a/rules/domain_keyword.go b/rule/domain_keyword.go
similarity index 100%
rename from rules/domain_keyword.go
rename to rule/domain_keyword.go
diff --git a/rules/domain_suffix.go b/rule/domain_suffix.go
similarity index 100%
rename from rules/domain_suffix.go
rename to rule/domain_suffix.go
diff --git a/rules/final.go b/rule/final.go
similarity index 100%
rename from rules/final.go
rename to rule/final.go
diff --git a/rules/geoip.go b/rule/geoip.go
similarity index 100%
rename from rules/geoip.go
rename to rule/geoip.go
diff --git a/rules/ipcidr.go b/rule/ipcidr.go
similarity index 100%
rename from rules/ipcidr.go
rename to rule/ipcidr.go
diff --git a/rules/parser.go b/rule/parser.go
similarity index 100%
rename from rules/parser.go
rename to rule/parser.go
diff --git a/rules/port.go b/rule/port.go
similarity index 100%
rename from rules/port.go
rename to rule/port.go
diff --git a/rules/process.go b/rule/process.go
similarity index 100%
rename from rules/process.go
rename to rule/process.go
diff --git a/test/snell_test.go b/test/snell_test.go
index 0d9e059a0..bc8b47aa7 100644
--- a/test/snell_test.go
+++ b/test/snell_test.go
@@ -5,7 +5,7 @@ import (
"testing"
"time"
- "github.com/Dreamacro/clash/adapters/outbound"
+ "github.com/Dreamacro/clash/adapter/outbound"
C "github.com/Dreamacro/clash/constant"
"github.com/docker/docker/api/types/container"
diff --git a/test/ss_test.go b/test/ss_test.go
index 6876d3fb5..ea33445c5 100644
--- a/test/ss_test.go
+++ b/test/ss_test.go
@@ -4,7 +4,7 @@ import (
"testing"
"time"
- "github.com/Dreamacro/clash/adapters/outbound"
+ "github.com/Dreamacro/clash/adapter/outbound"
"github.com/docker/docker/api/types/container"
"github.com/stretchr/testify/assert"
diff --git a/test/trojan_test.go b/test/trojan_test.go
index c20f12792..236b5af1e 100644
--- a/test/trojan_test.go
+++ b/test/trojan_test.go
@@ -5,7 +5,7 @@ import (
"testing"
"time"
- "github.com/Dreamacro/clash/adapters/outbound"
+ "github.com/Dreamacro/clash/adapter/outbound"
C "github.com/Dreamacro/clash/constant"
"github.com/docker/docker/api/types/container"
diff --git a/test/vmess_test.go b/test/vmess_test.go
index cf539bf89..92cb300e2 100644
--- a/test/vmess_test.go
+++ b/test/vmess_test.go
@@ -5,7 +5,7 @@ import (
"testing"
"time"
- "github.com/Dreamacro/clash/adapters/outbound"
+ "github.com/Dreamacro/clash/adapter/outbound"
C "github.com/Dreamacro/clash/constant"
"github.com/docker/docker/api/types/container"
diff --git a/tunnel/connection.go b/tunnel/connection.go
index 24314fb6c..2cc5964c3 100644
--- a/tunnel/connection.go
+++ b/tunnel/connection.go
@@ -9,7 +9,7 @@ import (
"strings"
"time"
- "github.com/Dreamacro/clash/adapters/inbound"
+ "github.com/Dreamacro/clash/adapter/inbound"
N "github.com/Dreamacro/clash/common/net"
"github.com/Dreamacro/clash/common/pool"
"github.com/Dreamacro/clash/component/resolver"
diff --git a/tunnel/tunnel.go b/tunnel/tunnel.go
index 77c24d889..18551ae87 100644
--- a/tunnel/tunnel.go
+++ b/tunnel/tunnel.go
@@ -7,8 +7,8 @@ import (
"sync"
"time"
- "github.com/Dreamacro/clash/adapters/inbound"
- "github.com/Dreamacro/clash/adapters/provider"
+ "github.com/Dreamacro/clash/adapter/inbound"
+ "github.com/Dreamacro/clash/adapter/provider"
"github.com/Dreamacro/clash/component/nat"
"github.com/Dreamacro/clash/component/resolver"
C "github.com/Dreamacro/clash/constant"
From bcfc15e3980aa227a7dbdf21f4e299df76c57df2 Mon Sep 17 00:00:00 2001
From: Fndroid
Date: Thu, 10 Jun 2021 15:08:33 +0800
Subject: [PATCH 07/96] chore: expose udp field to proxies API (#1441)
---
adapter/adapter.go | 1 +
1 file changed, 1 insertion(+)
diff --git a/adapter/adapter.go b/adapter/adapter.go
index f3503f04c..787a45b13 100644
--- a/adapter/adapter.go
+++ b/adapter/adapter.go
@@ -82,6 +82,7 @@ func (p *Proxy) MarshalJSON() ([]byte, error) {
json.Unmarshal(inner, &mapping)
mapping["history"] = p.DelayHistory()
mapping["name"] = p.Name()
+ mapping["udp"] = p.SupportUDP()
return json.Marshal(mapping)
}
From 6091fcdfece557284ef519816111e86537d56775 Mon Sep 17 00:00:00 2001
From: Dreamacro <8615343+Dreamacro@users.noreply.github.com>
Date: Sun, 13 Jun 2021 17:23:10 +0800
Subject: [PATCH 08/96] Style: code style
---
hub/executor/executor.go | 17 ++---
hub/route/configs.go | 16 +++--
{proxy => listener}/auth/auth.go | 0
{proxy => listener}/http/server.go | 25 ++++----
{proxy => listener}/listener.go | 62 +++++++++++--------
{proxy => listener}/mixed/conn.go | 0
{proxy => listener}/mixed/mixed.go | 26 ++++----
{proxy => listener}/redir/tcp.go | 19 +++---
{proxy => listener}/redir/tcp_darwin.go | 0
{proxy => listener}/redir/tcp_freebsd.go | 0
{proxy => listener}/redir/tcp_linux.go | 0
{proxy => listener}/redir/tcp_linux_386.go | 0
{proxy => listener}/redir/tcp_linux_other.go | 0
{proxy => listener}/redir/tcp_other.go | 0
{proxy => listener}/socks/tcp.go | 21 +++----
{proxy => listener}/socks/udp.go | 23 +++----
{proxy => listener}/socks/utils.go | 0
.../utils.go => listener/tproxy/packet.go | 2 +-
.../tproxy/setsockopt_linux.go | 2 +-
.../tproxy/setsockopt_other.go | 2 +-
{proxy/redir => listener/tproxy}/tproxy.go | 21 +++----
{proxy/redir => listener/tproxy}/udp.go | 22 ++++---
.../tproxy/udp_linux.go | 30 ++++++++-
.../tproxy/udp_other.go | 6 +-
proxy/redir/udp_linux.go | 36 -----------
proxy/redir/udp_other.go | 12 ----
tunnel/tunnel.go | 15 ++---
27 files changed, 171 insertions(+), 186 deletions(-)
rename {proxy => listener}/auth/auth.go (100%)
rename {proxy => listener}/http/server.go (79%)
rename {proxy => listener}/listener.go (71%)
rename {proxy => listener}/mixed/conn.go (100%)
rename {proxy => listener}/mixed/mixed.go (52%)
rename {proxy => listener}/redir/tcp.go (56%)
rename {proxy => listener}/redir/tcp_darwin.go (100%)
rename {proxy => listener}/redir/tcp_freebsd.go (100%)
rename {proxy => listener}/redir/tcp_linux.go (100%)
rename {proxy => listener}/redir/tcp_linux_386.go (100%)
rename {proxy => listener}/redir/tcp_linux_other.go (100%)
rename {proxy => listener}/redir/tcp_other.go (100%)
rename {proxy => listener}/socks/tcp.go (63%)
rename {proxy => listener}/socks/udp.go (66%)
rename {proxy => listener}/socks/utils.go (100%)
rename proxy/redir/utils.go => listener/tproxy/packet.go (97%)
rename proxy/redir/tproxy_linux.go => listener/tproxy/setsockopt_linux.go (98%)
rename proxy/redir/tproxy_other.go => listener/tproxy/setsockopt_other.go (91%)
rename {proxy/redir => listener/tproxy}/tproxy.go (62%)
rename {proxy/redir => listener/tproxy}/udp.go (66%)
rename proxy/redir/utils_linux.go => listener/tproxy/udp_linux.go (71%)
rename proxy/redir/utils_other.go => listener/tproxy/udp_other.go (58%)
delete mode 100644 proxy/redir/udp_linux.go
delete mode 100644 proxy/redir/udp_other.go
diff --git a/hub/executor/executor.go b/hub/executor/executor.go
index 5d803106a..81920221d 100644
--- a/hub/executor/executor.go
+++ b/hub/executor/executor.go
@@ -18,9 +18,9 @@ import (
"github.com/Dreamacro/clash/config"
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/dns"
+ P "github.com/Dreamacro/clash/listener"
+ authStore "github.com/Dreamacro/clash/listener/auth"
"github.com/Dreamacro/clash/log"
- P "github.com/Dreamacro/clash/proxy"
- authStore "github.com/Dreamacro/clash/proxy/auth"
"github.com/Dreamacro/clash/tunnel"
)
@@ -187,23 +187,26 @@ func updateGeneral(general *config.General, force bool) {
bindAddress := general.BindAddress
P.SetBindAddress(bindAddress)
- if err := P.ReCreateHTTP(general.Port); err != nil {
+ tcpIn := tunnel.TCPIn()
+ udpIn := tunnel.UDPIn()
+
+ if err := P.ReCreateHTTP(general.Port, tcpIn); err != nil {
log.Errorln("Start HTTP server error: %s", err.Error())
}
- if err := P.ReCreateSocks(general.SocksPort); err != nil {
+ if err := P.ReCreateSocks(general.SocksPort, tcpIn, udpIn); err != nil {
log.Errorln("Start SOCKS5 server error: %s", err.Error())
}
- if err := P.ReCreateRedir(general.RedirPort); err != nil {
+ if err := P.ReCreateRedir(general.RedirPort, tcpIn, udpIn); err != nil {
log.Errorln("Start Redir server error: %s", err.Error())
}
- if err := P.ReCreateTProxy(general.TProxyPort); err != nil {
+ if err := P.ReCreateTProxy(general.TProxyPort, tcpIn, udpIn); err != nil {
log.Errorln("Start TProxy server error: %s", err.Error())
}
- if err := P.ReCreateMixed(general.MixedPort); err != nil {
+ if err := P.ReCreateMixed(general.MixedPort, tcpIn, udpIn); err != nil {
log.Errorln("Start Mixed(http and socks5) server error: %s", err.Error())
}
}
diff --git a/hub/route/configs.go b/hub/route/configs.go
index 84dd10a6b..315180f77 100644
--- a/hub/route/configs.go
+++ b/hub/route/configs.go
@@ -7,8 +7,8 @@ import (
"github.com/Dreamacro/clash/component/resolver"
"github.com/Dreamacro/clash/config"
"github.com/Dreamacro/clash/hub/executor"
+ P "github.com/Dreamacro/clash/listener"
"github.com/Dreamacro/clash/log"
- P "github.com/Dreamacro/clash/proxy"
"github.com/Dreamacro/clash/tunnel"
"github.com/go-chi/chi/v5"
@@ -66,11 +66,15 @@ func patchConfigs(w http.ResponseWriter, r *http.Request) {
}
ports := P.GetPorts()
- P.ReCreateHTTP(pointerOrDefault(general.Port, ports.Port))
- P.ReCreateSocks(pointerOrDefault(general.SocksPort, ports.SocksPort))
- P.ReCreateRedir(pointerOrDefault(general.RedirPort, ports.RedirPort))
- P.ReCreateTProxy(pointerOrDefault(general.TProxyPort, ports.TProxyPort))
- P.ReCreateMixed(pointerOrDefault(general.MixedPort, ports.MixedPort))
+
+ tcpIn := tunnel.TCPIn()
+ udpIn := tunnel.UDPIn()
+
+ P.ReCreateHTTP(pointerOrDefault(general.Port, ports.Port), tcpIn)
+ P.ReCreateSocks(pointerOrDefault(general.SocksPort, ports.SocksPort), tcpIn, udpIn)
+ P.ReCreateRedir(pointerOrDefault(general.RedirPort, ports.RedirPort), tcpIn, udpIn)
+ P.ReCreateTProxy(pointerOrDefault(general.TProxyPort, ports.TProxyPort), tcpIn, udpIn)
+ P.ReCreateMixed(pointerOrDefault(general.MixedPort, ports.MixedPort), tcpIn, udpIn)
if general.Mode != nil {
tunnel.SetMode(*general.Mode)
diff --git a/proxy/auth/auth.go b/listener/auth/auth.go
similarity index 100%
rename from proxy/auth/auth.go
rename to listener/auth/auth.go
diff --git a/proxy/http/server.go b/listener/http/server.go
similarity index 79%
rename from proxy/http/server.go
rename to listener/http/server.go
index 69117dbb8..e52b84a96 100644
--- a/proxy/http/server.go
+++ b/listener/http/server.go
@@ -11,28 +11,25 @@ import (
"github.com/Dreamacro/clash/adapter/inbound"
"github.com/Dreamacro/clash/common/cache"
"github.com/Dreamacro/clash/component/auth"
+ C "github.com/Dreamacro/clash/constant"
+ authStore "github.com/Dreamacro/clash/listener/auth"
"github.com/Dreamacro/clash/log"
- authStore "github.com/Dreamacro/clash/proxy/auth"
- "github.com/Dreamacro/clash/tunnel"
)
-type HTTPListener struct {
+type Listener struct {
net.Listener
address string
closed bool
cache *cache.Cache
}
-func NewHTTPProxy(addr string) (*HTTPListener, error) {
+func New(addr string, in chan<- C.ConnContext) (*Listener, error) {
l, err := net.Listen("tcp", addr)
if err != nil {
return nil, err
}
- hl := &HTTPListener{l, addr, false, cache.New(30 * time.Second)}
-
+ hl := &Listener{l, addr, false, cache.New(30 * time.Second)}
go func() {
- log.Infoln("HTTP proxy listening at: %s", addr)
-
for {
c, err := hl.Accept()
if err != nil {
@@ -41,19 +38,19 @@ func NewHTTPProxy(addr string) (*HTTPListener, error) {
}
continue
}
- go HandleConn(c, hl.cache)
+ go HandleConn(c, in, hl.cache)
}
}()
return hl, nil
}
-func (l *HTTPListener) Close() {
+func (l *Listener) Close() {
l.closed = true
l.Listener.Close()
}
-func (l *HTTPListener) Address() string {
+func (l *Listener) Address() string {
return l.address
}
@@ -70,7 +67,7 @@ func canActivate(loginStr string, authenticator auth.Authenticator, cache *cache
return
}
-func HandleConn(conn net.Conn, cache *cache.Cache) {
+func HandleConn(conn net.Conn, in chan<- C.ConnContext, cache *cache.Cache) {
br := bufio.NewReader(conn)
keepAlive:
@@ -106,9 +103,9 @@ keepAlive:
conn.Close()
return
}
- tunnel.Add(inbound.NewHTTPS(request, conn))
+ in <- inbound.NewHTTPS(request, conn)
return
}
- tunnel.Add(inbound.NewHTTP(request, conn))
+ in <- inbound.NewHTTP(request, conn)
}
diff --git a/proxy/listener.go b/listener/listener.go
similarity index 71%
rename from proxy/listener.go
rename to listener/listener.go
index ec9b69f9d..cf0390e7e 100644
--- a/proxy/listener.go
+++ b/listener/listener.go
@@ -6,26 +6,29 @@ import (
"strconv"
"sync"
+ "github.com/Dreamacro/clash/adapter/inbound"
+ C "github.com/Dreamacro/clash/constant"
+ "github.com/Dreamacro/clash/listener/http"
+ "github.com/Dreamacro/clash/listener/mixed"
+ "github.com/Dreamacro/clash/listener/redir"
+ "github.com/Dreamacro/clash/listener/socks"
+ "github.com/Dreamacro/clash/listener/tproxy"
"github.com/Dreamacro/clash/log"
- "github.com/Dreamacro/clash/proxy/http"
- "github.com/Dreamacro/clash/proxy/mixed"
- "github.com/Dreamacro/clash/proxy/redir"
- "github.com/Dreamacro/clash/proxy/socks"
)
var (
allowLan = false
bindAddress = "*"
- socksListener *socks.SockListener
- socksUDPListener *socks.SockUDPListener
- httpListener *http.HTTPListener
- redirListener *redir.RedirListener
- redirUDPListener *redir.RedirUDPListener
- tproxyListener *redir.TProxyListener
- tproxyUDPListener *redir.RedirUDPListener
- mixedListener *mixed.MixedListener
- mixedUDPLister *socks.SockUDPListener
+ socksListener *socks.Listener
+ socksUDPListener *socks.UDPListener
+ httpListener *http.Listener
+ redirListener *redir.Listener
+ redirUDPListener *tproxy.UDPListener
+ tproxyListener *tproxy.Listener
+ tproxyUDPListener *tproxy.UDPListener
+ mixedListener *mixed.Listener
+ mixedUDPLister *socks.UDPListener
// lock for recreate function
socksMux sync.Mutex
@@ -59,7 +62,7 @@ func SetBindAddress(host string) {
bindAddress = host
}
-func ReCreateHTTP(port int) error {
+func ReCreateHTTP(port int, tcpIn chan<- C.ConnContext) error {
httpMux.Lock()
defer httpMux.Unlock()
@@ -78,15 +81,16 @@ func ReCreateHTTP(port int) error {
}
var err error
- httpListener, err = http.NewHTTPProxy(addr)
+ httpListener, err = http.New(addr, tcpIn)
if err != nil {
return err
}
+ log.Infoln("HTTP proxy listening at: %s", httpListener.Address())
return nil
}
-func ReCreateSocks(port int) error {
+func ReCreateSocks(port int, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.PacketAdapter) error {
socksMux.Lock()
defer socksMux.Unlock()
@@ -121,12 +125,12 @@ func ReCreateSocks(port int) error {
return nil
}
- tcpListener, err := socks.NewSocksProxy(addr)
+ tcpListener, err := socks.New(addr, tcpIn)
if err != nil {
return err
}
- udpListener, err := socks.NewSocksUDPProxy(addr)
+ udpListener, err := socks.NewUDP(addr, udpIn)
if err != nil {
tcpListener.Close()
return err
@@ -135,10 +139,11 @@ func ReCreateSocks(port int) error {
socksListener = tcpListener
socksUDPListener = udpListener
+ log.Infoln("SOCKS5 proxy listening at: %s", socksListener.Address())
return nil
}
-func ReCreateRedir(port int) error {
+func ReCreateRedir(port int, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.PacketAdapter) error {
redirMux.Lock()
defer redirMux.Unlock()
@@ -165,20 +170,21 @@ func ReCreateRedir(port int) error {
}
var err error
- redirListener, err = redir.NewRedirProxy(addr)
+ redirListener, err = redir.New(addr, tcpIn)
if err != nil {
return err
}
- redirUDPListener, err = redir.NewRedirUDPProxy(addr)
+ redirUDPListener, err = tproxy.NewUDP(addr, udpIn)
if err != nil {
log.Warnln("Failed to start Redir UDP Listener: %s", err)
}
+ log.Infoln("Redirect proxy listening at: %s", redirListener.Address())
return nil
}
-func ReCreateTProxy(port int) error {
+func ReCreateTProxy(port int, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.PacketAdapter) error {
tproxyMux.Lock()
defer tproxyMux.Unlock()
@@ -205,20 +211,21 @@ func ReCreateTProxy(port int) error {
}
var err error
- tproxyListener, err = redir.NewTProxy(addr)
+ tproxyListener, err = tproxy.New(addr, tcpIn)
if err != nil {
return err
}
- tproxyUDPListener, err = redir.NewRedirUDPProxy(addr)
+ tproxyUDPListener, err = tproxy.NewUDP(addr, udpIn)
if err != nil {
log.Warnln("Failed to start TProxy UDP Listener: %s", err)
}
+ log.Infoln("TProxy server listening at: %s", tproxyListener.Address())
return nil
}
-func ReCreateMixed(port int) error {
+func ReCreateMixed(port int, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.PacketAdapter) error {
mixedMux.Lock()
defer mixedMux.Unlock()
@@ -253,17 +260,18 @@ func ReCreateMixed(port int) error {
}
var err error
- mixedListener, err = mixed.NewMixedProxy(addr)
+ mixedListener, err = mixed.New(addr, tcpIn)
if err != nil {
return err
}
- mixedUDPLister, err = socks.NewSocksUDPProxy(addr)
+ mixedUDPLister, err = socks.NewUDP(addr, udpIn)
if err != nil {
mixedListener.Close()
return err
}
+ log.Infoln("Mixed(http+socks5) proxy listening at: %s", mixedListener.Address())
return nil
}
diff --git a/proxy/mixed/conn.go b/listener/mixed/conn.go
similarity index 100%
rename from proxy/mixed/conn.go
rename to listener/mixed/conn.go
diff --git a/proxy/mixed/mixed.go b/listener/mixed/mixed.go
similarity index 52%
rename from proxy/mixed/mixed.go
rename to listener/mixed/mixed.go
index b89748eea..b930d0682 100644
--- a/proxy/mixed/mixed.go
+++ b/listener/mixed/mixed.go
@@ -5,29 +5,27 @@ import (
"time"
"github.com/Dreamacro/clash/common/cache"
- "github.com/Dreamacro/clash/log"
- "github.com/Dreamacro/clash/proxy/http"
- "github.com/Dreamacro/clash/proxy/socks"
+ C "github.com/Dreamacro/clash/constant"
+ "github.com/Dreamacro/clash/listener/http"
+ "github.com/Dreamacro/clash/listener/socks"
"github.com/Dreamacro/clash/transport/socks5"
)
-type MixedListener struct {
+type Listener struct {
net.Listener
address string
closed bool
cache *cache.Cache
}
-func NewMixedProxy(addr string) (*MixedListener, error) {
+func New(addr string, in chan<- C.ConnContext) (*Listener, error) {
l, err := net.Listen("tcp", addr)
if err != nil {
return nil, err
}
- ml := &MixedListener{l, addr, false, cache.New(30 * time.Second)}
+ ml := &Listener{l, addr, false, cache.New(30 * time.Second)}
go func() {
- log.Infoln("Mixed(http+socks5) proxy listening at: %s", addr)
-
for {
c, err := ml.Accept()
if err != nil {
@@ -36,23 +34,23 @@ func NewMixedProxy(addr string) (*MixedListener, error) {
}
continue
}
- go handleConn(c, ml.cache)
+ go handleConn(c, in, ml.cache)
}
}()
return ml, nil
}
-func (l *MixedListener) Close() {
+func (l *Listener) Close() {
l.closed = true
l.Listener.Close()
}
-func (l *MixedListener) Address() string {
+func (l *Listener) Address() string {
return l.address
}
-func handleConn(conn net.Conn, cache *cache.Cache) {
+func handleConn(conn net.Conn, in chan<- C.ConnContext, cache *cache.Cache) {
bufConn := NewBufferedConn(conn)
head, err := bufConn.Peek(1)
if err != nil {
@@ -60,9 +58,9 @@ func handleConn(conn net.Conn, cache *cache.Cache) {
}
if head[0] == socks5.Version {
- socks.HandleSocks(bufConn)
+ socks.HandleSocks(bufConn, in)
return
}
- http.HandleConn(bufConn, cache)
+ http.HandleConn(bufConn, in, cache)
}
diff --git a/proxy/redir/tcp.go b/listener/redir/tcp.go
similarity index 56%
rename from proxy/redir/tcp.go
rename to listener/redir/tcp.go
index ef6718ec9..a54bfff87 100644
--- a/proxy/redir/tcp.go
+++ b/listener/redir/tcp.go
@@ -5,25 +5,22 @@ import (
"github.com/Dreamacro/clash/adapter/inbound"
C "github.com/Dreamacro/clash/constant"
- "github.com/Dreamacro/clash/log"
- "github.com/Dreamacro/clash/tunnel"
)
-type RedirListener struct {
+type Listener struct {
net.Listener
address string
closed bool
}
-func NewRedirProxy(addr string) (*RedirListener, error) {
+func New(addr string, in chan<- C.ConnContext) (*Listener, error) {
l, err := net.Listen("tcp", addr)
if err != nil {
return nil, err
}
- rl := &RedirListener{l, addr, false}
+ rl := &Listener{l, addr, false}
go func() {
- log.Infoln("Redir proxy listening at: %s", addr)
for {
c, err := l.Accept()
if err != nil {
@@ -32,28 +29,28 @@ func NewRedirProxy(addr string) (*RedirListener, error) {
}
continue
}
- go handleRedir(c)
+ go handleRedir(c, in)
}
}()
return rl, nil
}
-func (l *RedirListener) Close() {
+func (l *Listener) Close() {
l.closed = true
l.Listener.Close()
}
-func (l *RedirListener) Address() string {
+func (l *Listener) Address() string {
return l.address
}
-func handleRedir(conn net.Conn) {
+func handleRedir(conn net.Conn, in chan<- C.ConnContext) {
target, err := parserPacket(conn)
if err != nil {
conn.Close()
return
}
conn.(*net.TCPConn).SetKeepAlive(true)
- tunnel.Add(inbound.NewSocket(target, conn, C.REDIR))
+ in <- inbound.NewSocket(target, conn, C.REDIR)
}
diff --git a/proxy/redir/tcp_darwin.go b/listener/redir/tcp_darwin.go
similarity index 100%
rename from proxy/redir/tcp_darwin.go
rename to listener/redir/tcp_darwin.go
diff --git a/proxy/redir/tcp_freebsd.go b/listener/redir/tcp_freebsd.go
similarity index 100%
rename from proxy/redir/tcp_freebsd.go
rename to listener/redir/tcp_freebsd.go
diff --git a/proxy/redir/tcp_linux.go b/listener/redir/tcp_linux.go
similarity index 100%
rename from proxy/redir/tcp_linux.go
rename to listener/redir/tcp_linux.go
diff --git a/proxy/redir/tcp_linux_386.go b/listener/redir/tcp_linux_386.go
similarity index 100%
rename from proxy/redir/tcp_linux_386.go
rename to listener/redir/tcp_linux_386.go
diff --git a/proxy/redir/tcp_linux_other.go b/listener/redir/tcp_linux_other.go
similarity index 100%
rename from proxy/redir/tcp_linux_other.go
rename to listener/redir/tcp_linux_other.go
diff --git a/proxy/redir/tcp_other.go b/listener/redir/tcp_other.go
similarity index 100%
rename from proxy/redir/tcp_other.go
rename to listener/redir/tcp_other.go
diff --git a/proxy/socks/tcp.go b/listener/socks/tcp.go
similarity index 63%
rename from proxy/socks/tcp.go
rename to listener/socks/tcp.go
index a58d63d18..eca36f0fb 100644
--- a/proxy/socks/tcp.go
+++ b/listener/socks/tcp.go
@@ -7,27 +7,24 @@ import (
"github.com/Dreamacro/clash/adapter/inbound"
C "github.com/Dreamacro/clash/constant"
- "github.com/Dreamacro/clash/log"
- authStore "github.com/Dreamacro/clash/proxy/auth"
+ authStore "github.com/Dreamacro/clash/listener/auth"
"github.com/Dreamacro/clash/transport/socks5"
- "github.com/Dreamacro/clash/tunnel"
)
-type SockListener struct {
+type Listener struct {
net.Listener
address string
closed bool
}
-func NewSocksProxy(addr string) (*SockListener, error) {
+func New(addr string, in chan<- C.ConnContext) (*Listener, error) {
l, err := net.Listen("tcp", addr)
if err != nil {
return nil, err
}
- sl := &SockListener{l, addr, false}
+ sl := &Listener{l, addr, false}
go func() {
- log.Infoln("SOCKS proxy listening at: %s", addr)
for {
c, err := l.Accept()
if err != nil {
@@ -36,23 +33,23 @@ func NewSocksProxy(addr string) (*SockListener, error) {
}
continue
}
- go HandleSocks(c)
+ go HandleSocks(c, in)
}
}()
return sl, nil
}
-func (l *SockListener) Close() {
+func (l *Listener) Close() {
l.closed = true
l.Listener.Close()
}
-func (l *SockListener) Address() string {
+func (l *Listener) Address() string {
return l.address
}
-func HandleSocks(conn net.Conn) {
+func HandleSocks(conn net.Conn, in chan<- C.ConnContext) {
target, command, err := socks5.ServerHandshake(conn, authStore.Authenticator())
if err != nil {
conn.Close()
@@ -66,5 +63,5 @@ func HandleSocks(conn net.Conn) {
io.Copy(ioutil.Discard, conn)
return
}
- tunnel.Add(inbound.NewSocket(target, conn, C.SOCKS))
+ in <- inbound.NewSocket(target, conn, C.SOCKS)
}
diff --git a/proxy/socks/udp.go b/listener/socks/udp.go
similarity index 66%
rename from proxy/socks/udp.go
rename to listener/socks/udp.go
index b41e6f18e..7ddeed202 100644
--- a/proxy/socks/udp.go
+++ b/listener/socks/udp.go
@@ -9,27 +9,25 @@ import (
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/log"
"github.com/Dreamacro/clash/transport/socks5"
- "github.com/Dreamacro/clash/tunnel"
)
-type SockUDPListener struct {
+type UDPListener struct {
net.PacketConn
address string
closed bool
}
-func NewSocksUDPProxy(addr string) (*SockUDPListener, error) {
+func NewUDP(addr string, in chan<- *inbound.PacketAdapter) (*UDPListener, error) {
l, err := net.ListenPacket("udp", addr)
if err != nil {
return nil, err
}
- err = sockopt.UDPReuseaddr(l.(*net.UDPConn))
- if err != nil {
+ if err := sockopt.UDPReuseaddr(l.(*net.UDPConn)); err != nil {
log.Warnln("Failed to Reuse UDP Address: %s", err)
}
- sl := &SockUDPListener{l, addr, false}
+ sl := &UDPListener{l, addr, false}
go func() {
for {
buf := pool.Get(pool.RelayBufferSize)
@@ -41,23 +39,23 @@ func NewSocksUDPProxy(addr string) (*SockUDPListener, error) {
}
continue
}
- handleSocksUDP(l, buf[:n], remoteAddr)
+ handleSocksUDP(l, in, buf[:n], remoteAddr)
}
}()
return sl, nil
}
-func (l *SockUDPListener) Close() error {
+func (l *UDPListener) Close() error {
l.closed = true
return l.PacketConn.Close()
}
-func (l *SockUDPListener) Address() string {
+func (l *UDPListener) Address() string {
return l.address
}
-func handleSocksUDP(pc net.PacketConn, buf []byte, addr net.Addr) {
+func handleSocksUDP(pc net.PacketConn, in chan<- *inbound.PacketAdapter, buf []byte, addr net.Addr) {
target, payload, err := socks5.DecodeUDPPacket(buf)
if err != nil {
// Unresolved UDP packet, return buffer to the pool
@@ -70,5 +68,8 @@ func handleSocksUDP(pc net.PacketConn, buf []byte, addr net.Addr) {
payload: payload,
bufRef: buf,
}
- tunnel.AddPacket(inbound.NewPacket(target, packet, C.SOCKS))
+ select {
+ case in <- inbound.NewPacket(target, packet, C.TPROXY):
+ default:
+ }
}
diff --git a/proxy/socks/utils.go b/listener/socks/utils.go
similarity index 100%
rename from proxy/socks/utils.go
rename to listener/socks/utils.go
diff --git a/proxy/redir/utils.go b/listener/tproxy/packet.go
similarity index 97%
rename from proxy/redir/utils.go
rename to listener/tproxy/packet.go
index 58e30b0ce..8aa3e9bf4 100644
--- a/proxy/redir/utils.go
+++ b/listener/tproxy/packet.go
@@ -1,4 +1,4 @@
-package redir
+package tproxy
import (
"net"
diff --git a/proxy/redir/tproxy_linux.go b/listener/tproxy/setsockopt_linux.go
similarity index 98%
rename from proxy/redir/tproxy_linux.go
rename to listener/tproxy/setsockopt_linux.go
index 22f8b46b2..a70223f7f 100644
--- a/proxy/redir/tproxy_linux.go
+++ b/listener/tproxy/setsockopt_linux.go
@@ -1,6 +1,6 @@
// +build linux
-package redir
+package tproxy
import (
"net"
diff --git a/proxy/redir/tproxy_other.go b/listener/tproxy/setsockopt_other.go
similarity index 91%
rename from proxy/redir/tproxy_other.go
rename to listener/tproxy/setsockopt_other.go
index c20ea7d72..059477284 100644
--- a/proxy/redir/tproxy_other.go
+++ b/listener/tproxy/setsockopt_other.go
@@ -1,6 +1,6 @@
// +build !linux
-package redir
+package tproxy
import (
"errors"
diff --git a/proxy/redir/tproxy.go b/listener/tproxy/tproxy.go
similarity index 62%
rename from proxy/redir/tproxy.go
rename to listener/tproxy/tproxy.go
index 44682362f..a787b3595 100644
--- a/proxy/redir/tproxy.go
+++ b/listener/tproxy/tproxy.go
@@ -1,22 +1,20 @@
-package redir
+package tproxy
import (
"net"
"github.com/Dreamacro/clash/adapter/inbound"
C "github.com/Dreamacro/clash/constant"
- "github.com/Dreamacro/clash/log"
"github.com/Dreamacro/clash/transport/socks5"
- "github.com/Dreamacro/clash/tunnel"
)
-type TProxyListener struct {
+type Listener struct {
net.Listener
address string
closed bool
}
-func NewTProxy(addr string) (*TProxyListener, error) {
+func New(addr string, in chan<- C.ConnContext) (*Listener, error) {
l, err := net.Listen("tcp", addr)
if err != nil {
return nil, err
@@ -33,13 +31,12 @@ func NewTProxy(addr string) (*TProxyListener, error) {
return nil, err
}
- rl := &TProxyListener{
+ rl := &Listener{
Listener: l,
address: addr,
}
go func() {
- log.Infoln("TProxy server listening at: %s", addr)
for {
c, err := l.Accept()
if err != nil {
@@ -48,24 +45,24 @@ func NewTProxy(addr string) (*TProxyListener, error) {
}
continue
}
- go rl.handleTProxy(c)
+ go rl.handleTProxy(c, in)
}
}()
return rl, nil
}
-func (l *TProxyListener) Close() {
+func (l *Listener) Close() {
l.closed = true
l.Listener.Close()
}
-func (l *TProxyListener) Address() string {
+func (l *Listener) Address() string {
return l.address
}
-func (l *TProxyListener) handleTProxy(conn net.Conn) {
+func (l *Listener) handleTProxy(conn net.Conn, in chan<- C.ConnContext) {
target := socks5.ParseAddrToSocksAddr(conn.LocalAddr())
conn.(*net.TCPConn).SetKeepAlive(true)
- tunnel.Add(inbound.NewSocket(target, conn, C.TPROXY))
+ in <- inbound.NewSocket(target, conn, C.TPROXY)
}
diff --git a/proxy/redir/udp.go b/listener/tproxy/udp.go
similarity index 66%
rename from proxy/redir/udp.go
rename to listener/tproxy/udp.go
index e43af878b..881250164 100644
--- a/proxy/redir/udp.go
+++ b/listener/tproxy/udp.go
@@ -1,4 +1,4 @@
-package redir
+package tproxy
import (
"net"
@@ -7,22 +7,21 @@ import (
"github.com/Dreamacro/clash/common/pool"
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/transport/socks5"
- "github.com/Dreamacro/clash/tunnel"
)
-type RedirUDPListener struct {
+type UDPListener struct {
net.PacketConn
address string
closed bool
}
-func NewRedirUDPProxy(addr string) (*RedirUDPListener, error) {
+func NewUDP(addr string, in chan<- *inbound.PacketAdapter) (*UDPListener, error) {
l, err := net.ListenPacket("udp", addr)
if err != nil {
return nil, err
}
- rl := &RedirUDPListener{l, addr, false}
+ rl := &UDPListener{l, addr, false}
c := l.(*net.UDPConn)
@@ -53,27 +52,30 @@ func NewRedirUDPProxy(addr string) (*RedirUDPListener, error) {
if err != nil {
continue
}
- handleRedirUDP(l, buf[:n], lAddr, rAddr)
+ handlePacketConn(l, in, buf[:n], lAddr, rAddr)
}
}()
return rl, nil
}
-func (l *RedirUDPListener) Close() error {
+func (l *UDPListener) Close() error {
l.closed = true
return l.PacketConn.Close()
}
-func (l *RedirUDPListener) Address() string {
+func (l *UDPListener) Address() string {
return l.address
}
-func handleRedirUDP(pc net.PacketConn, buf []byte, lAddr *net.UDPAddr, rAddr *net.UDPAddr) {
+func handlePacketConn(pc net.PacketConn, in chan<- *inbound.PacketAdapter, buf []byte, lAddr *net.UDPAddr, rAddr *net.UDPAddr) {
target := socks5.ParseAddrToSocksAddr(rAddr)
pkt := &packet{
lAddr: lAddr,
buf: buf,
}
- tunnel.AddPacket(inbound.NewPacket(target, pkt, C.TPROXY))
+ select {
+ case in <- inbound.NewPacket(target, pkt, C.TPROXY):
+ default:
+ }
}
diff --git a/proxy/redir/utils_linux.go b/listener/tproxy/udp_linux.go
similarity index 71%
rename from proxy/redir/utils_linux.go
rename to listener/tproxy/udp_linux.go
index 888601a48..40c177e7e 100644
--- a/proxy/redir/utils_linux.go
+++ b/listener/tproxy/udp_linux.go
@@ -1,8 +1,10 @@
// +build linux
-package redir
+package tproxy
import (
+ "encoding/binary"
+ "errors"
"fmt"
"net"
"os"
@@ -10,6 +12,11 @@ import (
"syscall"
)
+const (
+ IPV6_TRANSPARENT = 0x4b
+ IPV6_RECVORIGDSTADDR = 0x4a
+)
+
// dialUDP acts like net.DialUDP for transparent proxy.
// It binds to a non-local address(`lAddr`).
func dialUDP(network string, lAddr *net.UDPAddr, rAddr *net.UDPAddr) (*net.UDPConn, error) {
@@ -94,3 +101,24 @@ func udpAddrFamily(net string, lAddr, rAddr *net.UDPAddr) int {
}
return syscall.AF_INET6
}
+
+func getOrigDst(oob []byte, oobn int) (*net.UDPAddr, error) {
+ msgs, err := syscall.ParseSocketControlMessage(oob[:oobn])
+ if err != nil {
+ return nil, err
+ }
+
+ for _, msg := range msgs {
+ if msg.Header.Level == syscall.SOL_IP && msg.Header.Type == syscall.IP_RECVORIGDSTADDR {
+ ip := net.IP(msg.Data[4:8])
+ port := binary.BigEndian.Uint16(msg.Data[2:4])
+ return &net.UDPAddr{IP: ip, Port: int(port)}, nil
+ } else if msg.Header.Level == syscall.SOL_IPV6 && msg.Header.Type == IPV6_RECVORIGDSTADDR {
+ ip := net.IP(msg.Data[8:24])
+ port := binary.BigEndian.Uint16(msg.Data[2:4])
+ return &net.UDPAddr{IP: ip, Port: int(port)}, nil
+ }
+ }
+
+ return nil, errors.New("cannot find origDst")
+}
diff --git a/proxy/redir/utils_other.go b/listener/tproxy/udp_other.go
similarity index 58%
rename from proxy/redir/utils_other.go
rename to listener/tproxy/udp_other.go
index faec71e27..a4531b5d0 100644
--- a/proxy/redir/utils_other.go
+++ b/listener/tproxy/udp_other.go
@@ -1,12 +1,16 @@
// +build !linux
-package redir
+package tproxy
import (
"errors"
"net"
)
+func getOrigDst(oob []byte, oobn int) (*net.UDPAddr, error) {
+ return nil, errors.New("UDP redir not supported on current platform")
+}
+
func dialUDP(network string, lAddr *net.UDPAddr, rAddr *net.UDPAddr) (*net.UDPConn, error) {
return nil, errors.New("UDP redir not supported on current platform")
}
diff --git a/proxy/redir/udp_linux.go b/proxy/redir/udp_linux.go
deleted file mode 100644
index e5a53e4da..000000000
--- a/proxy/redir/udp_linux.go
+++ /dev/null
@@ -1,36 +0,0 @@
-// +build linux
-
-package redir
-
-import (
- "encoding/binary"
- "errors"
- "net"
- "syscall"
-)
-
-const (
- IPV6_TRANSPARENT = 0x4b
- IPV6_RECVORIGDSTADDR = 0x4a
-)
-
-func getOrigDst(oob []byte, oobn int) (*net.UDPAddr, error) {
- msgs, err := syscall.ParseSocketControlMessage(oob[:oobn])
- if err != nil {
- return nil, err
- }
-
- for _, msg := range msgs {
- if msg.Header.Level == syscall.SOL_IP && msg.Header.Type == syscall.IP_RECVORIGDSTADDR {
- ip := net.IP(msg.Data[4:8])
- port := binary.BigEndian.Uint16(msg.Data[2:4])
- return &net.UDPAddr{IP: ip, Port: int(port)}, nil
- } else if msg.Header.Level == syscall.SOL_IPV6 && msg.Header.Type == IPV6_RECVORIGDSTADDR {
- ip := net.IP(msg.Data[8:24])
- port := binary.BigEndian.Uint16(msg.Data[2:4])
- return &net.UDPAddr{IP: ip, Port: int(port)}, nil
- }
- }
-
- return nil, errors.New("cannot find origDst")
-}
diff --git a/proxy/redir/udp_other.go b/proxy/redir/udp_other.go
deleted file mode 100644
index e50ec5b97..000000000
--- a/proxy/redir/udp_other.go
+++ /dev/null
@@ -1,12 +0,0 @@
-// +build !linux
-
-package redir
-
-import (
- "errors"
- "net"
-)
-
-func getOrigDst(oob []byte, oobn int) (*net.UDPAddr, error) {
- return nil, errors.New("UDP redir not supported on current platform")
-}
diff --git a/tunnel/tunnel.go b/tunnel/tunnel.go
index 18551ae87..a9ffb61fc 100644
--- a/tunnel/tunnel.go
+++ b/tunnel/tunnel.go
@@ -37,17 +37,14 @@ func init() {
go process()
}
-// Add request to queue
-func Add(ctx C.ConnContext) {
- tcpQueue <- ctx
+// TCPIn return fan-in queue
+func TCPIn() chan<- C.ConnContext {
+ return tcpQueue
}
-// AddPacket add udp Packet to queue
-func AddPacket(packet *inbound.PacketAdapter) {
- select {
- case udpQueue <- packet:
- default:
- }
+// UDPIn return fan-in udp queue
+func UDPIn() chan<- *inbound.PacketAdapter {
+ return udpQueue
}
// Rules return all rules
From f231a63e9322198deb8e4e65afd3572344f62d31 Mon Sep 17 00:00:00 2001
From: Dreamacro <8615343+Dreamacro@users.noreply.github.com>
Date: Sun, 13 Jun 2021 23:05:22 +0800
Subject: [PATCH 09/96] Chore: Listener should not expose original net.Listener
---
listener/http/server.go | 12 ++++++------
listener/mixed/mixed.go | 12 ++++++------
listener/redir/tcp.go | 8 ++++----
listener/socks/tcp.go | 8 ++++----
listener/socks/udp.go | 8 ++++----
listener/tproxy/tproxy.go | 10 +++++-----
listener/tproxy/udp.go | 8 ++++----
7 files changed, 33 insertions(+), 33 deletions(-)
diff --git a/listener/http/server.go b/listener/http/server.go
index e52b84a96..a77e01daa 100644
--- a/listener/http/server.go
+++ b/listener/http/server.go
@@ -17,10 +17,10 @@ import (
)
type Listener struct {
- net.Listener
- address string
- closed bool
- cache *cache.Cache
+ listener net.Listener
+ address string
+ closed bool
+ cache *cache.Cache
}
func New(addr string, in chan<- C.ConnContext) (*Listener, error) {
@@ -31,7 +31,7 @@ func New(addr string, in chan<- C.ConnContext) (*Listener, error) {
hl := &Listener{l, addr, false, cache.New(30 * time.Second)}
go func() {
for {
- c, err := hl.Accept()
+ c, err := hl.listener.Accept()
if err != nil {
if hl.closed {
break
@@ -47,7 +47,7 @@ func New(addr string, in chan<- C.ConnContext) (*Listener, error) {
func (l *Listener) Close() {
l.closed = true
- l.Listener.Close()
+ l.listener.Close()
}
func (l *Listener) Address() string {
diff --git a/listener/mixed/mixed.go b/listener/mixed/mixed.go
index b930d0682..3c4b49a84 100644
--- a/listener/mixed/mixed.go
+++ b/listener/mixed/mixed.go
@@ -12,10 +12,10 @@ import (
)
type Listener struct {
- net.Listener
- address string
- closed bool
- cache *cache.Cache
+ listener net.Listener
+ address string
+ closed bool
+ cache *cache.Cache
}
func New(addr string, in chan<- C.ConnContext) (*Listener, error) {
@@ -27,7 +27,7 @@ func New(addr string, in chan<- C.ConnContext) (*Listener, error) {
ml := &Listener{l, addr, false, cache.New(30 * time.Second)}
go func() {
for {
- c, err := ml.Accept()
+ c, err := ml.listener.Accept()
if err != nil {
if ml.closed {
break
@@ -43,7 +43,7 @@ func New(addr string, in chan<- C.ConnContext) (*Listener, error) {
func (l *Listener) Close() {
l.closed = true
- l.Listener.Close()
+ l.listener.Close()
}
func (l *Listener) Address() string {
diff --git a/listener/redir/tcp.go b/listener/redir/tcp.go
index a54bfff87..372688409 100644
--- a/listener/redir/tcp.go
+++ b/listener/redir/tcp.go
@@ -8,9 +8,9 @@ import (
)
type Listener struct {
- net.Listener
- address string
- closed bool
+ listener net.Listener
+ address string
+ closed bool
}
func New(addr string, in chan<- C.ConnContext) (*Listener, error) {
@@ -38,7 +38,7 @@ func New(addr string, in chan<- C.ConnContext) (*Listener, error) {
func (l *Listener) Close() {
l.closed = true
- l.Listener.Close()
+ l.listener.Close()
}
func (l *Listener) Address() string {
diff --git a/listener/socks/tcp.go b/listener/socks/tcp.go
index eca36f0fb..8e12ac71d 100644
--- a/listener/socks/tcp.go
+++ b/listener/socks/tcp.go
@@ -12,9 +12,9 @@ import (
)
type Listener struct {
- net.Listener
- address string
- closed bool
+ listener net.Listener
+ address string
+ closed bool
}
func New(addr string, in chan<- C.ConnContext) (*Listener, error) {
@@ -42,7 +42,7 @@ func New(addr string, in chan<- C.ConnContext) (*Listener, error) {
func (l *Listener) Close() {
l.closed = true
- l.Listener.Close()
+ l.listener.Close()
}
func (l *Listener) Address() string {
diff --git a/listener/socks/udp.go b/listener/socks/udp.go
index 7ddeed202..b98ae897a 100644
--- a/listener/socks/udp.go
+++ b/listener/socks/udp.go
@@ -12,9 +12,9 @@ import (
)
type UDPListener struct {
- net.PacketConn
- address string
- closed bool
+ packetConn net.PacketConn
+ address string
+ closed bool
}
func NewUDP(addr string, in chan<- *inbound.PacketAdapter) (*UDPListener, error) {
@@ -48,7 +48,7 @@ func NewUDP(addr string, in chan<- *inbound.PacketAdapter) (*UDPListener, error)
func (l *UDPListener) Close() error {
l.closed = true
- return l.PacketConn.Close()
+ return l.packetConn.Close()
}
func (l *UDPListener) Address() string {
diff --git a/listener/tproxy/tproxy.go b/listener/tproxy/tproxy.go
index a787b3595..142336fe8 100644
--- a/listener/tproxy/tproxy.go
+++ b/listener/tproxy/tproxy.go
@@ -9,9 +9,9 @@ import (
)
type Listener struct {
- net.Listener
- address string
- closed bool
+ listener net.Listener
+ address string
+ closed bool
}
func New(addr string, in chan<- C.ConnContext) (*Listener, error) {
@@ -32,7 +32,7 @@ func New(addr string, in chan<- C.ConnContext) (*Listener, error) {
}
rl := &Listener{
- Listener: l,
+ listener: l,
address: addr,
}
@@ -54,7 +54,7 @@ func New(addr string, in chan<- C.ConnContext) (*Listener, error) {
func (l *Listener) Close() {
l.closed = true
- l.Listener.Close()
+ l.listener.Close()
}
func (l *Listener) Address() string {
diff --git a/listener/tproxy/udp.go b/listener/tproxy/udp.go
index 881250164..20c2e0836 100644
--- a/listener/tproxy/udp.go
+++ b/listener/tproxy/udp.go
@@ -10,9 +10,9 @@ import (
)
type UDPListener struct {
- net.PacketConn
- address string
- closed bool
+ packetConn net.PacketConn
+ address string
+ closed bool
}
func NewUDP(addr string, in chan<- *inbound.PacketAdapter) (*UDPListener, error) {
@@ -61,7 +61,7 @@ func NewUDP(addr string, in chan<- *inbound.PacketAdapter) (*UDPListener, error)
func (l *UDPListener) Close() error {
l.closed = true
- return l.PacketConn.Close()
+ return l.packetConn.Close()
}
func (l *UDPListener) Address() string {
From 70d53fd45aa33e0dfbbf4c885f80181896624151 Mon Sep 17 00:00:00 2001
From: Dreamacro <8615343+Dreamacro@users.noreply.github.com>
Date: Sun, 13 Jun 2021 23:11:49 +0800
Subject: [PATCH 10/96] Chore: update development wiki to README.md
---
README.md | 3 +++
1 file changed, 3 insertions(+)
diff --git a/README.md b/README.md
index f2dbf7228..b948b49d0 100644
--- a/README.md
+++ b/README.md
@@ -40,6 +40,9 @@ Documentations are now moved to [GitHub Wiki](https://github.com/Dreamacro/clash
## Premium Release
[Release](https://github.com/Dreamacro/clash/releases/tag/premium)
+## Development
+If you want to build an application that uses clash as a library, check out the the [GitHub Wiki](https://github.com/Dreamacro/clash/wiki/use-clash-as-a-library)
+
## Credits
* [riobard/go-shadowsocks2](https://github.com/riobard/go-shadowsocks2)
From b6ff08074c858bb78d6fd670b9ce137c41dd25e9 Mon Sep 17 00:00:00 2001
From: Kr328
Date: Tue, 15 Jun 2021 17:13:40 +0800
Subject: [PATCH 11/96] Refactor: plain http proxy (#1443)
---
adapter/inbound/http.go | 52 +------
.../mixed/conn.go => common/net/bufconn.go | 2 +-
context/http.go | 47 -------
listener/http/client.go | 39 ++++++
listener/http/hack.go | 10 ++
listener/http/proxy.go | 132 ++++++++++++++++++
listener/http/server.go | 84 +++--------
listener/http/utils.go | 74 ++++++++++
listener/mixed/mixed.go | 3 +-
tunnel/connection.go | 104 --------------
tunnel/tunnel.go | 7 +-
11 files changed, 281 insertions(+), 273 deletions(-)
rename listener/mixed/conn.go => common/net/bufconn.go (98%)
delete mode 100644 context/http.go
create mode 100644 listener/http/client.go
create mode 100644 listener/http/hack.go
create mode 100644 listener/http/proxy.go
create mode 100644 listener/http/utils.go
diff --git a/adapter/inbound/http.go b/adapter/inbound/http.go
index b01c62bfb..94b9fc21f 100644
--- a/adapter/inbound/http.go
+++ b/adapter/inbound/http.go
@@ -2,60 +2,20 @@ package inbound
import (
"net"
- "net/http"
- "strings"
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/context"
+ "github.com/Dreamacro/clash/transport/socks5"
)
// NewHTTP receive normal http request and return HTTPContext
-func NewHTTP(request *http.Request, conn net.Conn) *context.HTTPContext {
- metadata := parseHTTPAddr(request)
+func NewHTTP(target string, source net.Addr, conn net.Conn) *context.ConnContext {
+ metadata := parseSocksAddr(socks5.ParseAddr(target))
+ metadata.NetWork = C.TCP
metadata.Type = C.HTTP
- if ip, port, err := parseAddr(conn.RemoteAddr().String()); err == nil {
+ if ip, port, err := parseAddr(source.String()); err == nil {
metadata.SrcIP = ip
metadata.SrcPort = port
}
- return context.NewHTTPContext(conn, request, metadata)
-}
-
-// RemoveHopByHopHeaders remove hop-by-hop header
-func RemoveHopByHopHeaders(header http.Header) {
- // Strip hop-by-hop header based on RFC:
- // http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.5.1
- // https://www.mnot.net/blog/2011/07/11/what_proxies_must_do
-
- header.Del("Proxy-Connection")
- header.Del("Proxy-Authenticate")
- header.Del("Proxy-Authorization")
- header.Del("TE")
- header.Del("Trailers")
- header.Del("Transfer-Encoding")
- header.Del("Upgrade")
-
- connections := header.Get("Connection")
- header.Del("Connection")
- if len(connections) == 0 {
- return
- }
- for _, h := range strings.Split(connections, ",") {
- header.Del(strings.TrimSpace(h))
- }
-}
-
-// RemoveExtraHTTPHostPort remove extra host port (example.com:80 --> example.com)
-// It resolves the behavior of some HTTP servers that do not handle host:80 (e.g. baidu.com)
-func RemoveExtraHTTPHostPort(req *http.Request) {
- host := req.Host
- if host == "" {
- host = req.URL.Host
- }
-
- if pHost, port, err := net.SplitHostPort(host); err == nil && port == "80" {
- host = pHost
- }
-
- req.Host = host
- req.URL.Host = host
+ return context.NewConnContext(conn, metadata)
}
diff --git a/listener/mixed/conn.go b/common/net/bufconn.go
similarity index 98%
rename from listener/mixed/conn.go
rename to common/net/bufconn.go
index f009a0060..cb7433d2e 100644
--- a/listener/mixed/conn.go
+++ b/common/net/bufconn.go
@@ -1,4 +1,4 @@
-package mixed
+package net
import (
"bufio"
diff --git a/context/http.go b/context/http.go
deleted file mode 100644
index 292f7d970..000000000
--- a/context/http.go
+++ /dev/null
@@ -1,47 +0,0 @@
-package context
-
-import (
- "net"
- "net/http"
-
- C "github.com/Dreamacro/clash/constant"
-
- "github.com/gofrs/uuid"
-)
-
-type HTTPContext struct {
- id uuid.UUID
- metadata *C.Metadata
- conn net.Conn
- req *http.Request
-}
-
-func NewHTTPContext(conn net.Conn, req *http.Request, metadata *C.Metadata) *HTTPContext {
- id, _ := uuid.NewV4()
- return &HTTPContext{
- id: id,
- metadata: metadata,
- conn: conn,
- req: req,
- }
-}
-
-// ID implement C.ConnContext ID
-func (hc *HTTPContext) ID() uuid.UUID {
- return hc.id
-}
-
-// Metadata implement C.ConnContext Metadata
-func (hc *HTTPContext) Metadata() *C.Metadata {
- return hc.metadata
-}
-
-// Conn implement C.ConnContext Conn
-func (hc *HTTPContext) Conn() net.Conn {
- return hc.conn
-}
-
-// Request return the http request struct
-func (hc *HTTPContext) Request() *http.Request {
- return hc.req
-}
diff --git a/listener/http/client.go b/listener/http/client.go
new file mode 100644
index 000000000..3b5fd3842
--- /dev/null
+++ b/listener/http/client.go
@@ -0,0 +1,39 @@
+package http
+
+import (
+ "context"
+ "errors"
+ "net"
+ "net/http"
+ "time"
+
+ "github.com/Dreamacro/clash/adapter/inbound"
+ C "github.com/Dreamacro/clash/constant"
+)
+
+func newClient(source net.Addr, in chan<- C.ConnContext) *http.Client {
+ return &http.Client{
+ Transport: &http.Transport{
+ // from http.DefaultTransport
+ MaxIdleConns: 100,
+ IdleConnTimeout: 90 * time.Second,
+ TLSHandshakeTimeout: 10 * time.Second,
+ ResponseHeaderTimeout: 10 * time.Second,
+ ExpectContinueTimeout: 1 * time.Second,
+ DialContext: func(context context.Context, network, address string) (net.Conn, error) {
+ if network != "tcp" && network != "tcp4" && network != "tcp6" {
+ return nil, errors.New("unsupported network " + network)
+ }
+
+ left, right := net.Pipe()
+
+ in <- inbound.NewHTTP(address, source, right)
+
+ return left, nil
+ },
+ },
+ CheckRedirect: func(req *http.Request, via []*http.Request) error {
+ return http.ErrUseLastResponse
+ },
+ }
+}
diff --git a/listener/http/hack.go b/listener/http/hack.go
new file mode 100644
index 000000000..14a725383
--- /dev/null
+++ b/listener/http/hack.go
@@ -0,0 +1,10 @@
+package http
+
+import (
+ "bufio"
+ "net/http"
+ _ "unsafe"
+)
+
+//go:linkname ReadRequest net/http.readRequest
+func ReadRequest(b *bufio.Reader, deleteHostHeader bool) (req *http.Request, err error)
diff --git a/listener/http/proxy.go b/listener/http/proxy.go
new file mode 100644
index 000000000..12508ba3d
--- /dev/null
+++ b/listener/http/proxy.go
@@ -0,0 +1,132 @@
+package http
+
+import (
+ "net"
+ "net/http"
+ "strings"
+ "time"
+
+ "github.com/Dreamacro/clash/adapter/inbound"
+ "github.com/Dreamacro/clash/common/cache"
+ N "github.com/Dreamacro/clash/common/net"
+ C "github.com/Dreamacro/clash/constant"
+ authStore "github.com/Dreamacro/clash/listener/auth"
+ "github.com/Dreamacro/clash/log"
+)
+
+func HandleConn(c net.Conn, in chan<- C.ConnContext, cache *cache.Cache) {
+ client := newClient(c.RemoteAddr(), in)
+ defer client.CloseIdleConnections()
+
+ conn := N.NewBufferedConn(c)
+
+ keepAlive := true
+ trusted := cache == nil // disable authenticate if cache is nil
+
+ for keepAlive {
+ request, err := ReadRequest(conn.Reader(), false)
+ if err != nil {
+ break
+ }
+
+ request.RemoteAddr = conn.RemoteAddr().String()
+
+ keepAlive = strings.TrimSpace(strings.ToLower(request.Header.Get("Proxy-Connection"))) == "keep-alive"
+
+ var resp *http.Response
+
+ if !trusted {
+ resp = authenticate(request, cache)
+
+ trusted = resp == nil
+ }
+
+ if trusted {
+ if request.Method == http.MethodConnect {
+ resp = responseWith(200)
+ resp.Status = "Connection established"
+
+ if resp.Write(conn) != nil {
+ break // close connection
+ }
+
+ in <- inbound.NewHTTPS(request, conn)
+
+ return // hijack connection
+ }
+
+ host := request.Header.Get("Host")
+ if host != "" {
+ request.Host = host
+ }
+
+ request.RequestURI = ""
+
+ RemoveHopByHopHeaders(request.Header)
+ RemoveExtraHTTPHostPort(request)
+
+ if request.URL.Scheme == "" || request.URL.Host == "" {
+ resp = responseWith(http.StatusBadRequest)
+ } else {
+ resp, err = client.Do(request)
+ if err != nil {
+ resp = responseWith(http.StatusBadGateway)
+ }
+ }
+ }
+
+ RemoveHopByHopHeaders(resp.Header)
+
+ if keepAlive {
+ resp.Header.Set("Proxy-Connection", "keep-alive")
+ resp.Header.Set("Connection", "keep-alive")
+ resp.Header.Set("Keep-Alive", "timeout=4")
+ }
+
+ resp.Close = !keepAlive
+
+ err = resp.Write(conn)
+ if err != nil {
+ break // close connection
+ }
+ }
+
+ conn.Close()
+}
+
+func authenticate(request *http.Request, cache *cache.Cache) *http.Response {
+ authenticator := authStore.Authenticator()
+ if authenticator != nil {
+ credential := ParseBasicProxyAuthorization(request)
+ if credential == "" {
+ resp := responseWith(http.StatusProxyAuthRequired)
+ resp.Header.Set("Proxy-Authenticate", "Basic")
+ return resp
+ }
+
+ var authed interface{}
+ if authed = cache.Get(credential); authed == nil {
+ user, pass, err := DecodeBasicProxyAuthorization(credential)
+ authed = err == nil && authenticator.Verify(user, pass)
+ cache.Put(credential, authed, time.Minute)
+ }
+ if !authed.(bool) {
+ log.Infoln("Auth failed from %s", request.RemoteAddr)
+
+ return responseWith(http.StatusForbidden)
+ }
+ }
+
+ return nil
+}
+
+func responseWith(statusCode int) *http.Response {
+ return &http.Response{
+ StatusCode: statusCode,
+ Status: http.StatusText(statusCode),
+ Proto: "HTTP/1.1",
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ Header: http.Header{},
+ }
+}
diff --git a/listener/http/server.go b/listener/http/server.go
index a77e01daa..ed8383710 100644
--- a/listener/http/server.go
+++ b/listener/http/server.go
@@ -1,44 +1,48 @@
package http
import (
- "bufio"
- "encoding/base64"
"net"
- "net/http"
- "strings"
"time"
- "github.com/Dreamacro/clash/adapter/inbound"
"github.com/Dreamacro/clash/common/cache"
- "github.com/Dreamacro/clash/component/auth"
C "github.com/Dreamacro/clash/constant"
- authStore "github.com/Dreamacro/clash/listener/auth"
- "github.com/Dreamacro/clash/log"
)
type Listener struct {
listener net.Listener
address string
closed bool
- cache *cache.Cache
}
func New(addr string, in chan<- C.ConnContext) (*Listener, error) {
+ return NewWithAuthenticate(addr, in, true)
+}
+
+func NewWithAuthenticate(addr string, in chan<- C.ConnContext, authenticate bool) (*Listener, error) {
l, err := net.Listen("tcp", addr)
if err != nil {
return nil, err
}
- hl := &Listener{l, addr, false, cache.New(30 * time.Second)}
+
+ var c *cache.Cache
+ if authenticate {
+ c = cache.New(time.Second * 30)
+ }
+
+ hl := &Listener{
+ listener: l,
+ address: addr,
+ }
go func() {
for {
- c, err := hl.listener.Accept()
+ conn, err := hl.listener.Accept()
if err != nil {
if hl.closed {
break
}
continue
}
- go HandleConn(c, in, hl.cache)
+ go HandleConn(conn, in, c)
}
}()
@@ -53,59 +57,3 @@ func (l *Listener) Close() {
func (l *Listener) Address() string {
return l.address
}
-
-func canActivate(loginStr string, authenticator auth.Authenticator, cache *cache.Cache) (ret bool) {
- if result := cache.Get(loginStr); result != nil {
- ret = result.(bool)
- return
- }
- loginData, err := base64.StdEncoding.DecodeString(loginStr)
- login := strings.Split(string(loginData), ":")
- ret = err == nil && len(login) == 2 && authenticator.Verify(login[0], login[1])
-
- cache.Put(loginStr, ret, time.Minute)
- return
-}
-
-func HandleConn(conn net.Conn, in chan<- C.ConnContext, cache *cache.Cache) {
- br := bufio.NewReader(conn)
-
-keepAlive:
- request, err := http.ReadRequest(br)
- if err != nil || request.URL.Host == "" {
- conn.Close()
- return
- }
-
- keepAlive := strings.TrimSpace(strings.ToLower(request.Header.Get("Proxy-Connection"))) == "keep-alive"
- authenticator := authStore.Authenticator()
- if authenticator != nil {
- if authStrings := strings.Split(request.Header.Get("Proxy-Authorization"), " "); len(authStrings) != 2 {
- conn.Write([]byte("HTTP/1.1 407 Proxy Authentication Required\r\nProxy-Authenticate: Basic\r\n\r\n"))
- if keepAlive {
- goto keepAlive
- }
- return
- } else if !canActivate(authStrings[1], authenticator, cache) {
- conn.Write([]byte("HTTP/1.1 403 Forbidden\r\n\r\n"))
- log.Infoln("Auth failed from %s", conn.RemoteAddr().String())
- if keepAlive {
- goto keepAlive
- }
- conn.Close()
- return
- }
- }
-
- if request.Method == http.MethodConnect {
- _, err := conn.Write([]byte("HTTP/1.1 200 Connection established\r\n\r\n"))
- if err != nil {
- conn.Close()
- return
- }
- in <- inbound.NewHTTPS(request, conn)
- return
- }
-
- in <- inbound.NewHTTP(request, conn)
-}
diff --git a/listener/http/utils.go b/listener/http/utils.go
new file mode 100644
index 000000000..f3d7840c6
--- /dev/null
+++ b/listener/http/utils.go
@@ -0,0 +1,74 @@
+package http
+
+import (
+ "encoding/base64"
+ "errors"
+ "net"
+ "net/http"
+ "strings"
+)
+
+// RemoveHopByHopHeaders remove hop-by-hop header
+func RemoveHopByHopHeaders(header http.Header) {
+ // Strip hop-by-hop header based on RFC:
+ // http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.5.1
+ // https://www.mnot.net/blog/2011/07/11/what_proxies_must_do
+
+ header.Del("Proxy-Connection")
+ header.Del("Proxy-Authenticate")
+ header.Del("Proxy-Authorization")
+ header.Del("TE")
+ header.Del("Trailers")
+ header.Del("Transfer-Encoding")
+ header.Del("Upgrade")
+
+ connections := header.Get("Connection")
+ header.Del("Connection")
+ if len(connections) == 0 {
+ return
+ }
+ for _, h := range strings.Split(connections, ",") {
+ header.Del(strings.TrimSpace(h))
+ }
+}
+
+// RemoveExtraHTTPHostPort remove extra host port (example.com:80 --> example.com)
+// It resolves the behavior of some HTTP servers that do not handle host:80 (e.g. baidu.com)
+func RemoveExtraHTTPHostPort(req *http.Request) {
+ host := req.Host
+ if host == "" {
+ host = req.URL.Host
+ }
+
+ if pHost, port, err := net.SplitHostPort(host); err == nil && port == "80" {
+ host = pHost
+ }
+
+ req.Host = host
+ req.URL.Host = host
+}
+
+// ParseBasicProxyAuthorization parse header Proxy-Authorization and return base64-encoded credential
+func ParseBasicProxyAuthorization(request *http.Request) string {
+ value := request.Header.Get("Proxy-Authorization")
+ if !strings.HasPrefix(value, "Basic ") {
+ return ""
+ }
+
+ return value[6:] // value[len("Basic "):]
+}
+
+// DecodeBasicProxyAuthorization decode base64-encoded credential
+func DecodeBasicProxyAuthorization(credential string) (string, string, error) {
+ plain, err := base64.StdEncoding.DecodeString(credential)
+ if err != nil {
+ return "", "", err
+ }
+
+ login := strings.Split(string(plain), ":")
+ if len(login) != 2 {
+ return "", "", errors.New("invalid login")
+ }
+
+ return login[0], login[1], nil
+}
diff --git a/listener/mixed/mixed.go b/listener/mixed/mixed.go
index 3c4b49a84..07ad03b62 100644
--- a/listener/mixed/mixed.go
+++ b/listener/mixed/mixed.go
@@ -5,6 +5,7 @@ import (
"time"
"github.com/Dreamacro/clash/common/cache"
+ N "github.com/Dreamacro/clash/common/net"
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/listener/http"
"github.com/Dreamacro/clash/listener/socks"
@@ -51,7 +52,7 @@ func (l *Listener) Address() string {
}
func handleConn(conn net.Conn, in chan<- C.ConnContext, cache *cache.Cache) {
- bufConn := NewBufferedConn(conn)
+ bufConn := N.NewBufferedConn(conn)
head, err := bufConn.Peek(1)
if err != nil {
return
diff --git a/tunnel/connection.go b/tunnel/connection.go
index 2cc5964c3..8c3b4cb61 100644
--- a/tunnel/connection.go
+++ b/tunnel/connection.go
@@ -1,93 +1,17 @@
package tunnel
import (
- "bufio"
"errors"
"io"
"net"
- "net/http"
- "strings"
"time"
- "github.com/Dreamacro/clash/adapter/inbound"
N "github.com/Dreamacro/clash/common/net"
"github.com/Dreamacro/clash/common/pool"
"github.com/Dreamacro/clash/component/resolver"
C "github.com/Dreamacro/clash/constant"
- "github.com/Dreamacro/clash/context"
)
-func handleHTTP(ctx *context.HTTPContext, outbound net.Conn) {
- req := ctx.Request()
- conn := ctx.Conn()
-
- // make outbound close after inbound error or close
- conn = &connLinker{conn, outbound}
-
- inboundReader := bufio.NewReader(conn)
- outboundReader := bufio.NewReader(outbound)
-
- inbound.RemoveExtraHTTPHostPort(req)
- host := req.Host
- for {
- keepAlive := strings.TrimSpace(strings.ToLower(req.Header.Get("Proxy-Connection"))) == "keep-alive"
-
- req.RequestURI = ""
- inbound.RemoveHopByHopHeaders(req.Header)
- err := req.Write(outbound)
- if err != nil {
- break
- }
-
- handleResponse:
- // resp will be closed after we call resp.Write()
- // see https://golang.org/pkg/net/http/#Response.Write
- resp, err := http.ReadResponse(outboundReader, req)
- if err != nil {
- break
- }
- inbound.RemoveHopByHopHeaders(resp.Header)
-
- if resp.StatusCode == http.StatusContinue {
- err = resp.Write(conn)
- if err != nil {
- break
- }
- goto handleResponse
- }
-
- // close conn when header `Connection` is `close`
- if resp.Header.Get("Connection") == "close" {
- keepAlive = false
- }
-
- if keepAlive {
- resp.Header.Set("Proxy-Connection", "keep-alive")
- resp.Header.Set("Connection", "keep-alive")
- resp.Header.Set("Keep-Alive", "timeout=4")
- resp.Close = false
- } else {
- resp.Close = true
- }
- err = resp.Write(conn)
- if err != nil || resp.Close {
- break
- }
-
- req, err = http.ReadRequest(inboundReader)
- if err != nil {
- break
- }
-
- inbound.RemoveExtraHTTPHostPort(req)
- // Sometimes firefox just open a socket to process multiple domains in HTTP
- // The temporary solution is close connection when encountering different HOST
- if req.Host != host {
- break
- }
- }
-}
-
func handleUDPToRemote(packet C.UDPPacket, pc C.PacketConn, metadata *C.Metadata) error {
defer packet.Drop()
@@ -162,31 +86,3 @@ func relay(leftConn, rightConn net.Conn) {
rightConn.SetReadDeadline(time.Now())
<-ch
}
-
-// connLinker make the two net.Conn correlated, for temporary resolution of leaks.
-// There is no better way to do this for now.
-type connLinker struct {
- net.Conn
- linker net.Conn
-}
-
-func (conn *connLinker) Read(b []byte) (n int, err error) {
- n, err = conn.Conn.Read(b)
- if err != nil {
- conn.linker.Close()
- }
- return n, err
-}
-
-func (conn *connLinker) Write(b []byte) (n int, err error) {
- n, err = conn.Conn.Write(b)
- if err != nil {
- conn.linker.Close()
- }
- return n, err
-}
-
-func (conn *connLinker) Close() error {
- conn.linker.Close()
- return conn.Conn.Close()
-}
diff --git a/tunnel/tunnel.go b/tunnel/tunnel.go
index a9ffb61fc..a40b697df 100644
--- a/tunnel/tunnel.go
+++ b/tunnel/tunnel.go
@@ -289,12 +289,7 @@ func handleTCPConn(ctx C.ConnContext) {
log.Infoln("[TCP] %s --> %v doesn't match any rule using DIRECT", metadata.SourceAddress(), metadata.String())
}
- switch c := ctx.(type) {
- case *context.HTTPContext:
- handleHTTP(c, remoteConn)
- default:
- handleSocket(ctx, remoteConn)
- }
+ handleSocket(ctx, remoteConn)
}
func shouldResolveIP(rule C.Rule, metadata *C.Metadata) bool {
From c35cb24bdacf66cd65af508f48323a647882ef08 Mon Sep 17 00:00:00 2001
From: Dreamacro <8615343+Dreamacro@users.noreply.github.com>
Date: Tue, 15 Jun 2021 21:03:47 +0800
Subject: [PATCH 12/96] Chore: use unix.ByteSliceToString transform cstring
---
component/process/process_darwin.go | 9 +++------
1 file changed, 3 insertions(+), 6 deletions(-)
diff --git a/component/process/process_darwin.go b/component/process/process_darwin.go
index 5157b2099..7e4baf74c 100644
--- a/component/process/process_darwin.go
+++ b/component/process/process_darwin.go
@@ -1,12 +1,13 @@
package process
import (
- "bytes"
"encoding/binary"
"net"
"path/filepath"
"syscall"
"unsafe"
+
+ "golang.org/x/sys/unix"
)
const (
@@ -94,12 +95,8 @@ func getExecPathFromPID(pid uint32) (string, error) {
if errno != 0 {
return "", errno
}
- firstZero := bytes.IndexByte(buf, 0)
- if firstZero <= 0 {
- return "", nil
- }
- return filepath.Base(string(buf[:firstZero])), nil
+ return filepath.Base(unix.ByteSliceToString(buf)), nil
}
func readNativeUint32(b []byte) uint32 {
From 244cb370a438cdf663370bc6bfb0ad784a219b4b Mon Sep 17 00:00:00 2001
From: ayanamist
Date: Mon, 21 Jun 2021 17:33:34 +0800
Subject: [PATCH 13/96] Change: config reload API use default path when both
path and payload don't exist (#1447)
---
hub/route/configs.go | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/hub/route/configs.go b/hub/route/configs.go
index 315180f77..48cb95eda 100644
--- a/hub/route/configs.go
+++ b/hub/route/configs.go
@@ -6,6 +6,7 @@ import (
"github.com/Dreamacro/clash/component/resolver"
"github.com/Dreamacro/clash/config"
+ "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/hub/executor"
P "github.com/Dreamacro/clash/listener"
"github.com/Dreamacro/clash/log"
@@ -116,6 +117,9 @@ func updateConfigs(w http.ResponseWriter, r *http.Request) {
return
}
} else {
+ if req.Path == "" {
+ req.Path = constant.Path.Config()
+ }
if !filepath.IsAbs(req.Path) {
render.Status(r, http.StatusBadRequest)
render.JSON(w, r, newError("path is not a absolute path"))
From 3ca5d17c40d3cc682e71f295f0761445cf7a4793 Mon Sep 17 00:00:00 2001
From: Indust
Date: Thu, 24 Jun 2021 13:38:44 +0800
Subject: [PATCH 14/96] Fix: enable DNS server message compression (#1451)
---
dns/server.go | 1 +
1 file changed, 1 insertion(+)
diff --git a/dns/server.go b/dns/server.go
index 84ff0bac4..7abdd4d0f 100644
--- a/dns/server.go
+++ b/dns/server.go
@@ -30,6 +30,7 @@ func (s *Server) ServeDNS(w D.ResponseWriter, r *D.Msg) {
D.HandleFailed(w, r)
return
}
+ msg.Compress = true
w.WriteMsg(msg)
}
From 995aa7a8fc641fa00b44ad290ac59c3e4c2a565f Mon Sep 17 00:00:00 2001
From: Dreamacro <8615343+Dreamacro@users.noreply.github.com>
Date: Sat, 3 Jul 2021 20:34:44 +0800
Subject: [PATCH 15/96] Fix: remove ClientSessionCache and add NextProtos for
vmess to fix #1468
---
adapter/outbound/http.go | 1 -
adapter/outbound/shadowsocks.go | 1 -
adapter/outbound/socks5.go | 1 -
adapter/outbound/trojan.go | 10 ++++------
adapter/outbound/util.go | 14 --------------
adapter/outbound/vmess.go | 4 ----
dns/doh.go | 2 --
dns/resolver.go | 5 -----
dns/util.go | 1 -
transport/trojan/trojan.go | 10 ++++------
transport/v2ray-plugin/websocket.go | 3 ---
transport/vmess/tls.go | 2 --
transport/vmess/websocket.go | 3 +--
13 files changed, 9 insertions(+), 48 deletions(-)
diff --git a/adapter/outbound/http.go b/adapter/outbound/http.go
index 43ca12042..b4dffdf78 100644
--- a/adapter/outbound/http.go
+++ b/adapter/outbound/http.go
@@ -125,7 +125,6 @@ func NewHttp(option HttpOption) *Http {
}
tlsConfig = &tls.Config{
InsecureSkipVerify: option.SkipCertVerify,
- ClientSessionCache: getClientSessionCache(),
ServerName: sni,
}
}
diff --git a/adapter/outbound/shadowsocks.go b/adapter/outbound/shadowsocks.go
index 0fb3ab9a8..39d1e36d0 100644
--- a/adapter/outbound/shadowsocks.go
+++ b/adapter/outbound/shadowsocks.go
@@ -149,7 +149,6 @@ func NewShadowSocks(option ShadowSocksOption) (*ShadowSocks, error) {
if opts.TLS {
v2rayOption.TLS = true
v2rayOption.SkipCertVerify = opts.SkipCertVerify
- v2rayOption.SessionCache = getClientSessionCache()
}
}
diff --git a/adapter/outbound/socks5.go b/adapter/outbound/socks5.go
index 26c7c06ad..8106e0e2e 100644
--- a/adapter/outbound/socks5.go
+++ b/adapter/outbound/socks5.go
@@ -145,7 +145,6 @@ func NewSocks5(option Socks5Option) *Socks5 {
if option.TLS {
tlsConfig = &tls.Config{
InsecureSkipVerify: option.SkipCertVerify,
- ClientSessionCache: getClientSessionCache(),
ServerName: option.Server,
}
}
diff --git a/adapter/outbound/trojan.go b/adapter/outbound/trojan.go
index 5d8527353..afed410fb 100644
--- a/adapter/outbound/trojan.go
+++ b/adapter/outbound/trojan.go
@@ -127,11 +127,10 @@ func NewTrojan(option TrojanOption) (*Trojan, error) {
addr := net.JoinHostPort(option.Server, strconv.Itoa(option.Port))
tOption := &trojan.Option{
- Password: option.Password,
- ALPN: option.ALPN,
- ServerName: option.Server,
- SkipCertVerify: option.SkipCertVerify,
- ClientSessionCache: getClientSessionCache(),
+ Password: option.Password,
+ ALPN: option.ALPN,
+ ServerName: option.Server,
+ SkipCertVerify: option.SkipCertVerify,
}
if option.SNI != "" {
@@ -163,7 +162,6 @@ func NewTrojan(option TrojanOption) (*Trojan, error) {
MinVersion: tls.VersionTLS12,
InsecureSkipVerify: tOption.SkipCertVerify,
ServerName: tOption.ServerName,
- ClientSessionCache: getClientSessionCache(),
}
t.transport = gun.NewHTTP2Client(dialFn, tlsConfig)
diff --git a/adapter/outbound/util.go b/adapter/outbound/util.go
index 4b81eb5d6..0e1d4c8e5 100644
--- a/adapter/outbound/util.go
+++ b/adapter/outbound/util.go
@@ -2,10 +2,8 @@ package outbound
import (
"bytes"
- "crypto/tls"
"net"
"strconv"
- "sync"
"time"
"github.com/Dreamacro/clash/component/resolver"
@@ -13,11 +11,6 @@ import (
"github.com/Dreamacro/clash/transport/socks5"
)
-var (
- globalClientSessionCache tls.ClientSessionCache
- once sync.Once
-)
-
func tcpKeepAlive(c net.Conn) {
if tcp, ok := c.(*net.TCPConn); ok {
tcp.SetKeepAlive(true)
@@ -25,13 +18,6 @@ func tcpKeepAlive(c net.Conn) {
}
}
-func getClientSessionCache() tls.ClientSessionCache {
- once.Do(func() {
- globalClientSessionCache = tls.NewLRUClientSessionCache(128)
- })
- return globalClientSessionCache
-}
-
func serializesSocksAddr(metadata *C.Metadata) []byte {
var buf [][]byte
aType := uint8(metadata.AddrType)
diff --git a/adapter/outbound/vmess.go b/adapter/outbound/vmess.go
index 672f767ba..5ee4abbc3 100644
--- a/adapter/outbound/vmess.go
+++ b/adapter/outbound/vmess.go
@@ -86,7 +86,6 @@ func (v *Vmess) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {
if v.option.TLS {
wsOpts.TLS = true
- wsOpts.SessionCache = getClientSessionCache()
wsOpts.SkipCertVerify = v.option.SkipCertVerify
wsOpts.ServerName = v.option.ServerName
}
@@ -98,7 +97,6 @@ func (v *Vmess) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {
tlsOpts := &vmess.TLSConfig{
Host: host,
SkipCertVerify: v.option.SkipCertVerify,
- SessionCache: getClientSessionCache(),
}
if v.option.ServerName != "" {
@@ -125,7 +123,6 @@ func (v *Vmess) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {
tlsOpts := vmess.TLSConfig{
Host: host,
SkipCertVerify: v.option.SkipCertVerify,
- SessionCache: getClientSessionCache(),
NextProtos: []string{"h2"},
}
@@ -153,7 +150,6 @@ func (v *Vmess) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {
tlsOpts := &vmess.TLSConfig{
Host: host,
SkipCertVerify: v.option.SkipCertVerify,
- SessionCache: getClientSessionCache(),
}
if v.option.ServerName != "" {
diff --git a/dns/doh.go b/dns/doh.go
index 247e0704d..34375017d 100644
--- a/dns/doh.go
+++ b/dns/doh.go
@@ -3,7 +3,6 @@ package dns
import (
"bytes"
"context"
- "crypto/tls"
"io/ioutil"
"net"
"net/http"
@@ -76,7 +75,6 @@ func newDoHClient(url string, r *Resolver) *dohClient {
return &dohClient{
url: url,
transport: &http.Transport{
- TLSClientConfig: &tls.Config{ClientSessionCache: globalSessionCache},
ForceAttemptHTTP2: true,
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
host, port, err := net.SplitHostPort(addr)
diff --git a/dns/resolver.go b/dns/resolver.go
index f57fec525..1ca0293ea 100644
--- a/dns/resolver.go
+++ b/dns/resolver.go
@@ -2,7 +2,6 @@ package dns
import (
"context"
- "crypto/tls"
"errors"
"fmt"
"math/rand"
@@ -20,10 +19,6 @@ import (
"golang.org/x/sync/singleflight"
)
-var (
- globalSessionCache = tls.NewLRUClientSessionCache(64)
-)
-
type dnsClient interface {
Exchange(m *D.Msg) (msg *D.Msg, err error)
ExchangeContext(ctx context.Context, m *D.Msg) (msg *D.Msg, err error)
diff --git a/dns/util.go b/dns/util.go
index c2bb11d86..e56aaeb5a 100644
--- a/dns/util.go
+++ b/dns/util.go
@@ -127,7 +127,6 @@ func transform(servers []NameServer, resolver *Resolver) []dnsClient {
Client: &D.Client{
Net: s.Net,
TLSConfig: &tls.Config{
- ClientSessionCache: globalSessionCache,
// alpn identifier, see https://tools.ietf.org/html/draft-hoffman-dprive-dns-tls-alpn-00#page-6
NextProtos: []string{"dns"},
ServerName: host,
diff --git a/transport/trojan/trojan.go b/transport/trojan/trojan.go
index 88cc95fb1..d62e3f80d 100644
--- a/transport/trojan/trojan.go
+++ b/transport/trojan/trojan.go
@@ -34,11 +34,10 @@ var (
)
type Option struct {
- Password string
- ALPN []string
- ServerName string
- SkipCertVerify bool
- ClientSessionCache tls.ClientSessionCache
+ Password string
+ ALPN []string
+ ServerName string
+ SkipCertVerify bool
}
type Trojan struct {
@@ -57,7 +56,6 @@ func (t *Trojan) StreamConn(conn net.Conn) (net.Conn, error) {
MinVersion: tls.VersionTLS12,
InsecureSkipVerify: t.option.SkipCertVerify,
ServerName: t.option.ServerName,
- ClientSessionCache: t.option.ClientSessionCache,
}
tlsConn := tls.Client(conn, tlsConfig)
diff --git a/transport/v2ray-plugin/websocket.go b/transport/v2ray-plugin/websocket.go
index 9feaf2c2f..317c172fc 100644
--- a/transport/v2ray-plugin/websocket.go
+++ b/transport/v2ray-plugin/websocket.go
@@ -1,7 +1,6 @@
package obfs
import (
- "crypto/tls"
"net"
"net/http"
@@ -16,7 +15,6 @@ type Option struct {
Headers map[string]string
TLS bool
SkipCertVerify bool
- SessionCache tls.ClientSessionCache
Mux bool
}
@@ -34,7 +32,6 @@ func NewV2rayObfs(conn net.Conn, option *Option) (net.Conn, error) {
TLS: option.TLS,
Headers: header,
SkipCertVerify: option.SkipCertVerify,
- SessionCache: option.SessionCache,
}
var err error
diff --git a/transport/vmess/tls.go b/transport/vmess/tls.go
index b003a7533..234c31477 100644
--- a/transport/vmess/tls.go
+++ b/transport/vmess/tls.go
@@ -8,7 +8,6 @@ import (
type TLSConfig struct {
Host string
SkipCertVerify bool
- SessionCache tls.ClientSessionCache
NextProtos []string
}
@@ -16,7 +15,6 @@ func StreamTLSConn(conn net.Conn, cfg *TLSConfig) (net.Conn, error) {
tlsConfig := &tls.Config{
ServerName: cfg.Host,
InsecureSkipVerify: cfg.SkipCertVerify,
- ClientSessionCache: cfg.SessionCache,
NextProtos: cfg.NextProtos,
}
diff --git a/transport/vmess/websocket.go b/transport/vmess/websocket.go
index 980add13e..6ed353e76 100644
--- a/transport/vmess/websocket.go
+++ b/transport/vmess/websocket.go
@@ -32,7 +32,6 @@ type WebsocketConfig struct {
TLS bool
SkipCertVerify bool
ServerName string
- SessionCache tls.ClientSessionCache
}
// Read implements net.Conn.Read()
@@ -130,7 +129,7 @@ func StreamWebsocketConn(conn net.Conn, c *WebsocketConfig) (net.Conn, error) {
dialer.TLSClientConfig = &tls.Config{
ServerName: c.Host,
InsecureSkipVerify: c.SkipCertVerify,
- ClientSessionCache: c.SessionCache,
+ NextProtos: []string{"http/1.1"},
}
if c.ServerName != "" {
From dff1e8f1ce0c6ed9d8a070c513a6b3478f701e2b Mon Sep 17 00:00:00 2001
From: Dreamacro <8615343+Dreamacro@users.noreply.github.com>
Date: Sat, 3 Jul 2021 21:01:41 +0800
Subject: [PATCH 16/96] Chore: update dependencies
---
go.mod | 10 +++++-----
go.sum | 21 +++++++++++----------
2 files changed, 16 insertions(+), 15 deletions(-)
diff --git a/go.mod b/go.mod
index 17056c628..28e4d44ba 100644
--- a/go.mod
+++ b/go.mod
@@ -9,14 +9,14 @@ require (
github.com/go-chi/render v1.0.1
github.com/gofrs/uuid v4.0.0+incompatible
github.com/gorilla/websocket v1.4.2
- github.com/miekg/dns v1.1.42
+ github.com/miekg/dns v1.1.43
github.com/oschwald/geoip2-golang v1.5.0
github.com/sirupsen/logrus v1.8.1
github.com/stretchr/testify v1.7.0
- go.uber.org/atomic v1.7.0
- golang.org/x/crypto v0.0.0-20210506145944-38f3c27a63bf
- golang.org/x/net v0.0.0-20210508051633-16afe75a6701
+ go.uber.org/atomic v1.8.0
+ golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e
+ golang.org/x/net v0.0.0-20210614182718-04defd469f4e
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
- golang.org/x/sys v0.0.0-20210507161434-a76c4d0a0096
+ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c
gopkg.in/yaml.v2 v2.4.0
)
diff --git a/go.sum b/go.sum
index 58dcc672b..fa37dc3be 100644
--- a/go.sum
+++ b/go.sum
@@ -13,8 +13,8 @@ github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPh
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
-github.com/miekg/dns v1.1.42 h1:gWGe42RGaIqXQZ+r3WUGEKBEtvPHY2SXo4dqixDNxuY=
-github.com/miekg/dns v1.1.42/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4=
+github.com/miekg/dns v1.1.43 h1:JKfpVSCB84vrAmHzyrsxB5NAr5kLoMXZArPSw7Qlgyg=
+github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4=
github.com/oschwald/geoip2-golang v1.5.0 h1:igg2yQIrrcRccB1ytFXqBfOHCjXWIoMv85lVJ1ONZzw=
github.com/oschwald/geoip2-golang v1.5.0/go.mod h1:xdvYt5xQzB8ORWFqPnqMwZpCpgNagttWdoZLlJQzg7s=
github.com/oschwald/maxminddb-golang v1.8.0 h1:Uh/DSnGoxsyp/KYbY1AuP0tYEwfs0sCph9p/UMXK/Hk=
@@ -29,14 +29,14 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
-go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
+go.uber.org/atomic v1.8.0 h1:CUhrE4N1rqSE6FM9ecihEjRkLQu8cDfgDyoOs83mEY4=
+go.uber.org/atomic v1.8.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
golang.org/x/crypto v0.0.0-20210317152858-513c2a44f670/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
-golang.org/x/crypto v0.0.0-20210506145944-38f3c27a63bf h1:B2n+Zi5QeYRDAEodEu72OS36gmTWjgpXr2+cWcBW90o=
-golang.org/x/crypto v0.0.0-20210506145944-38f3c27a63bf/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
+golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e h1:gsTQYXdTw2Gq7RBsWvlQ91b+aEQ6bXFUngBGuR8sPpI=
+golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
-golang.org/x/net v0.0.0-20210508051633-16afe75a6701 h1:lQVgcB3+FoAXOb20Dp6zTzAIrpj1k/yOOBN7s+Zv1rA=
-golang.org/x/net v0.0.0-20210508051633-16afe75a6701/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20210614182718-04defd469f4e h1:XpT3nA5TvE525Ne3hInMh6+GETgn27Zfm9dxsThnX2Q=
+golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -44,8 +44,9 @@ golang.org/x/sys v0.0.0-20191224085550-c709ea063b76/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210507161434-a76c4d0a0096 h1:5PbJGn5Sp3GEUjJ61aYbUP6RIo3Z3r2E4Tv9y2z8UHo=
-golang.org/x/sys v0.0.0-20210507161434-a76c4d0a0096/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I=
+golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
From d755383e394e8754cebd6f7cb2dbf205b9a3c686 Mon Sep 17 00:00:00 2001
From: Dreamacro <8615343+Dreamacro@users.noreply.github.com>
Date: Sun, 4 Jul 2021 20:32:59 +0800
Subject: [PATCH 17/96] Chore: move provider interface to constant
---
adapter/outboundgroup/common.go | 2 +-
adapter/outboundgroup/fallback.go | 2 +-
adapter/outboundgroup/loadbalance.go | 2 +-
adapter/outboundgroup/parser.go | 11 +--
adapter/outboundgroup/relay.go | 2 +-
adapter/outboundgroup/selector.go | 2 +-
adapter/outboundgroup/urltest.go | 2 +-
adapter/provider/fetcher.go | 11 +--
adapter/provider/parser.go | 5 +-
adapter/provider/provider.go | 54 ++------------
adapter/provider/vehicle.go | 38 ++--------
config/config.go | 11 +--
constant/provider/interface.go | 105 +++++++++++++++++++++++++++
hub/executor/executor.go | 2 +-
hub/route/provider.go | 2 +-
tunnel/tunnel.go | 2 +-
16 files changed, 148 insertions(+), 105 deletions(-)
create mode 100644 constant/provider/interface.go
diff --git a/adapter/outboundgroup/common.go b/adapter/outboundgroup/common.go
index 31b8cb6bb..758c7801a 100644
--- a/adapter/outboundgroup/common.go
+++ b/adapter/outboundgroup/common.go
@@ -3,8 +3,8 @@ package outboundgroup
import (
"time"
- "github.com/Dreamacro/clash/adapter/provider"
C "github.com/Dreamacro/clash/constant"
+ "github.com/Dreamacro/clash/constant/provider"
)
const (
diff --git a/adapter/outboundgroup/fallback.go b/adapter/outboundgroup/fallback.go
index 8b38f09ca..da01d4de1 100644
--- a/adapter/outboundgroup/fallback.go
+++ b/adapter/outboundgroup/fallback.go
@@ -5,9 +5,9 @@ import (
"encoding/json"
"github.com/Dreamacro/clash/adapter/outbound"
- "github.com/Dreamacro/clash/adapter/provider"
"github.com/Dreamacro/clash/common/singledo"
C "github.com/Dreamacro/clash/constant"
+ "github.com/Dreamacro/clash/constant/provider"
)
type Fallback struct {
diff --git a/adapter/outboundgroup/loadbalance.go b/adapter/outboundgroup/loadbalance.go
index 7856a07d6..e529b53be 100644
--- a/adapter/outboundgroup/loadbalance.go
+++ b/adapter/outboundgroup/loadbalance.go
@@ -8,10 +8,10 @@ import (
"net"
"github.com/Dreamacro/clash/adapter/outbound"
- "github.com/Dreamacro/clash/adapter/provider"
"github.com/Dreamacro/clash/common/murmur3"
"github.com/Dreamacro/clash/common/singledo"
C "github.com/Dreamacro/clash/constant"
+ "github.com/Dreamacro/clash/constant/provider"
"golang.org/x/net/publicsuffix"
)
diff --git a/adapter/outboundgroup/parser.go b/adapter/outboundgroup/parser.go
index d11040a5f..cf97579f9 100644
--- a/adapter/outboundgroup/parser.go
+++ b/adapter/outboundgroup/parser.go
@@ -7,6 +7,7 @@ import (
"github.com/Dreamacro/clash/adapter/provider"
"github.com/Dreamacro/clash/common/structure"
C "github.com/Dreamacro/clash/constant"
+ types "github.com/Dreamacro/clash/constant/provider"
)
var (
@@ -28,7 +29,7 @@ type GroupCommonOption struct {
DisableUDP bool `group:"disable-udp,omitempty"`
}
-func ParseProxyGroup(config map[string]interface{}, proxyMap map[string]C.Proxy, providersMap map[string]provider.ProxyProvider) (C.ProxyAdapter, error) {
+func ParseProxyGroup(config map[string]interface{}, proxyMap map[string]C.Proxy, providersMap map[string]types.ProxyProvider) (C.ProxyAdapter, error) {
decoder := structure.NewDecoder(structure.Option{TagName: "group", WeaklyTypedInput: true})
groupOption := &GroupCommonOption{
@@ -44,7 +45,7 @@ func ParseProxyGroup(config map[string]interface{}, proxyMap map[string]C.Proxy,
groupName := groupOption.Name
- providers := []provider.ProxyProvider{}
+ providers := []types.ProxyProvider{}
if len(groupOption.Proxies) == 0 && len(groupOption.Use) == 0 {
return nil, errMissProxy
@@ -138,15 +139,15 @@ func getProxies(mapping map[string]C.Proxy, list []string) ([]C.Proxy, error) {
return ps, nil
}
-func getProviders(mapping map[string]provider.ProxyProvider, list []string) ([]provider.ProxyProvider, error) {
- var ps []provider.ProxyProvider
+func getProviders(mapping map[string]types.ProxyProvider, list []string) ([]types.ProxyProvider, error) {
+ var ps []types.ProxyProvider
for _, name := range list {
p, ok := mapping[name]
if !ok {
return nil, fmt.Errorf("'%s' not found", name)
}
- if p.VehicleType() == provider.Compatible {
+ if p.VehicleType() == types.Compatible {
return nil, fmt.Errorf("proxy group %s can't contains in `use`", name)
}
ps = append(ps, p)
diff --git a/adapter/outboundgroup/relay.go b/adapter/outboundgroup/relay.go
index e4a897b8a..8d8128bac 100644
--- a/adapter/outboundgroup/relay.go
+++ b/adapter/outboundgroup/relay.go
@@ -7,10 +7,10 @@ import (
"fmt"
"github.com/Dreamacro/clash/adapter/outbound"
- "github.com/Dreamacro/clash/adapter/provider"
"github.com/Dreamacro/clash/common/singledo"
"github.com/Dreamacro/clash/component/dialer"
C "github.com/Dreamacro/clash/constant"
+ "github.com/Dreamacro/clash/constant/provider"
)
type Relay struct {
diff --git a/adapter/outboundgroup/selector.go b/adapter/outboundgroup/selector.go
index c28b6f8cf..124539278 100644
--- a/adapter/outboundgroup/selector.go
+++ b/adapter/outboundgroup/selector.go
@@ -6,9 +6,9 @@ import (
"errors"
"github.com/Dreamacro/clash/adapter/outbound"
- "github.com/Dreamacro/clash/adapter/provider"
"github.com/Dreamacro/clash/common/singledo"
C "github.com/Dreamacro/clash/constant"
+ "github.com/Dreamacro/clash/constant/provider"
)
type Selector struct {
diff --git a/adapter/outboundgroup/urltest.go b/adapter/outboundgroup/urltest.go
index 0f59d4be5..2a11cd23b 100644
--- a/adapter/outboundgroup/urltest.go
+++ b/adapter/outboundgroup/urltest.go
@@ -6,9 +6,9 @@ import (
"time"
"github.com/Dreamacro/clash/adapter/outbound"
- "github.com/Dreamacro/clash/adapter/provider"
"github.com/Dreamacro/clash/common/singledo"
C "github.com/Dreamacro/clash/constant"
+ "github.com/Dreamacro/clash/constant/provider"
)
type urlTestOption func(*URLTest)
diff --git a/adapter/provider/fetcher.go b/adapter/provider/fetcher.go
index 5ef3f25ca..777e3aa54 100644
--- a/adapter/provider/fetcher.go
+++ b/adapter/provider/fetcher.go
@@ -8,6 +8,7 @@ import (
"path/filepath"
"time"
+ types "github.com/Dreamacro/clash/constant/provider"
"github.com/Dreamacro/clash/log"
)
@@ -20,7 +21,7 @@ type parser = func([]byte) (interface{}, error)
type fetcher struct {
name string
- vehicle Vehicle
+ vehicle types.Vehicle
updatedAt *time.Time
ticker *time.Ticker
done chan struct{}
@@ -33,7 +34,7 @@ func (f *fetcher) Name() string {
return f.name
}
-func (f *fetcher) VehicleType() VehicleType {
+func (f *fetcher) VehicleType() types.VehicleType {
return f.vehicle.Type()
}
@@ -76,7 +77,7 @@ func (f *fetcher) Initial() (interface{}, error) {
isLocal = false
}
- if f.vehicle.Type() != File && !isLocal {
+ if f.vehicle.Type() != types.File && !isLocal {
if err := safeWrite(f.vehicle.Path(), buf); err != nil {
return nil, err
}
@@ -110,7 +111,7 @@ func (f *fetcher) Update() (interface{}, bool, error) {
return nil, false, err
}
- if f.vehicle.Type() != File {
+ if f.vehicle.Type() != types.File {
if err := safeWrite(f.vehicle.Path(), buf); err != nil {
return nil, false, err
}
@@ -167,7 +168,7 @@ func safeWrite(path string, buf []byte) error {
return ioutil.WriteFile(path, buf, fileMode)
}
-func newFetcher(name string, interval time.Duration, vehicle Vehicle, parser parser, onUpdate func(interface{})) *fetcher {
+func newFetcher(name string, interval time.Duration, vehicle types.Vehicle, parser parser, onUpdate func(interface{})) *fetcher {
var ticker *time.Ticker
if interval != 0 {
ticker = time.NewTicker(interval)
diff --git a/adapter/provider/parser.go b/adapter/provider/parser.go
index aa5d7ae29..f326d4ccb 100644
--- a/adapter/provider/parser.go
+++ b/adapter/provider/parser.go
@@ -7,6 +7,7 @@ import (
"github.com/Dreamacro/clash/common/structure"
C "github.com/Dreamacro/clash/constant"
+ types "github.com/Dreamacro/clash/constant/provider"
)
var (
@@ -28,7 +29,7 @@ type proxyProviderSchema struct {
HealthCheck healthCheckSchema `provider:"health-check,omitempty"`
}
-func ParseProxyProvider(name string, mapping map[string]interface{}) (ProxyProvider, error) {
+func ParseProxyProvider(name string, mapping map[string]interface{}) (types.ProxyProvider, error) {
decoder := structure.NewDecoder(structure.Option{TagName: "provider", WeaklyTypedInput: true})
schema := &proxyProviderSchema{
@@ -48,7 +49,7 @@ func ParseProxyProvider(name string, mapping map[string]interface{}) (ProxyProvi
path := C.Path.Resolve(schema.Path)
- var vehicle Vehicle
+ var vehicle types.Vehicle
switch schema.Type {
case "file":
vehicle = NewFileVehicle(path)
diff --git a/adapter/provider/provider.go b/adapter/provider/provider.go
index f87fe2a12..b6e1ac754 100644
--- a/adapter/provider/provider.go
+++ b/adapter/provider/provider.go
@@ -9,6 +9,7 @@ import (
"github.com/Dreamacro/clash/adapter"
C "github.com/Dreamacro/clash/constant"
+ types "github.com/Dreamacro/clash/constant/provider"
"gopkg.in/yaml.v2"
)
@@ -17,45 +18,6 @@ const (
ReservedName = "default"
)
-// Provider Type
-const (
- Proxy ProviderType = iota
- Rule
-)
-
-// ProviderType defined
-type ProviderType int
-
-func (pt ProviderType) String() string {
- switch pt {
- case Proxy:
- return "Proxy"
- case Rule:
- return "Rule"
- default:
- return "Unknown"
- }
-}
-
-// Provider interface
-type Provider interface {
- Name() string
- VehicleType() VehicleType
- Type() ProviderType
- Initial() error
- Update() error
-}
-
-// ProxyProvider interface
-type ProxyProvider interface {
- Provider
- Proxies() []C.Proxy
- // ProxiesWithTouch is used to inform the provider that the proxy is actually being used while getting the list of proxies.
- // Commonly used in Dial and DialUDP
- ProxiesWithTouch() []C.Proxy
- HealthCheck()
-}
-
type ProxySchema struct {
Proxies []map[string]interface{} `yaml:"proxies"`
}
@@ -107,8 +69,8 @@ func (pp *proxySetProvider) Initial() error {
return nil
}
-func (pp *proxySetProvider) Type() ProviderType {
- return Proxy
+func (pp *proxySetProvider) Type() types.ProviderType {
+ return types.Proxy
}
func (pp *proxySetProvider) Proxies() []C.Proxy {
@@ -160,7 +122,7 @@ func stopProxyProvider(pd *ProxySetProvider) {
pd.fetcher.Destroy()
}
-func NewProxySetProvider(name string, interval time.Duration, vehicle Vehicle, hc *HealthCheck) *ProxySetProvider {
+func NewProxySetProvider(name string, interval time.Duration, vehicle types.Vehicle, hc *HealthCheck) *ProxySetProvider {
if hc.auto() {
go hc.process()
}
@@ -219,12 +181,12 @@ func (cp *compatibleProvider) Initial() error {
return nil
}
-func (cp *compatibleProvider) VehicleType() VehicleType {
- return Compatible
+func (cp *compatibleProvider) VehicleType() types.VehicleType {
+ return types.Compatible
}
-func (cp *compatibleProvider) Type() ProviderType {
- return Proxy
+func (cp *compatibleProvider) Type() types.ProviderType {
+ return types.Proxy
}
func (cp *compatibleProvider) Proxies() []C.Proxy {
diff --git a/adapter/provider/vehicle.go b/adapter/provider/vehicle.go
index 13d898fc8..ea6a835a2 100644
--- a/adapter/provider/vehicle.go
+++ b/adapter/provider/vehicle.go
@@ -8,43 +8,15 @@ import (
"time"
"github.com/Dreamacro/clash/component/dialer"
+ types "github.com/Dreamacro/clash/constant/provider"
)
-// Vehicle Type
-const (
- File VehicleType = iota
- HTTP
- Compatible
-)
-
-// VehicleType defined
-type VehicleType int
-
-func (v VehicleType) String() string {
- switch v {
- case File:
- return "File"
- case HTTP:
- return "HTTP"
- case Compatible:
- return "Compatible"
- default:
- return "Unknown"
- }
-}
-
-type Vehicle interface {
- Read() ([]byte, error)
- Path() string
- Type() VehicleType
-}
-
type FileVehicle struct {
path string
}
-func (f *FileVehicle) Type() VehicleType {
- return File
+func (f *FileVehicle) Type() types.VehicleType {
+ return types.File
}
func (f *FileVehicle) Path() string {
@@ -64,8 +36,8 @@ type HTTPVehicle struct {
path string
}
-func (h *HTTPVehicle) Type() VehicleType {
- return HTTP
+func (h *HTTPVehicle) Type() types.VehicleType {
+ return types.HTTP
}
func (h *HTTPVehicle) Path() string {
diff --git a/config/config.go b/config/config.go
index a256d2820..a9628192b 100644
--- a/config/config.go
+++ b/config/config.go
@@ -16,6 +16,7 @@ import (
"github.com/Dreamacro/clash/component/fakeip"
"github.com/Dreamacro/clash/component/trie"
C "github.com/Dreamacro/clash/constant"
+ providerTypes "github.com/Dreamacro/clash/constant/provider"
"github.com/Dreamacro/clash/dns"
"github.com/Dreamacro/clash/log"
R "github.com/Dreamacro/clash/rule"
@@ -93,7 +94,7 @@ type Config struct {
Rules []C.Rule
Users []auth.AuthUser
Proxies map[string]C.Proxy
- Providers map[string]provider.ProxyProvider
+ Providers map[string]providerTypes.ProxyProvider
}
type RawDNS struct {
@@ -267,9 +268,9 @@ func parseGeneral(cfg *RawConfig) (*General, error) {
}, nil
}
-func parseProxies(cfg *RawConfig) (proxies map[string]C.Proxy, providersMap map[string]provider.ProxyProvider, err error) {
+func parseProxies(cfg *RawConfig) (proxies map[string]C.Proxy, providersMap map[string]providerTypes.ProxyProvider, err error) {
proxies = make(map[string]C.Proxy)
- providersMap = make(map[string]provider.ProxyProvider)
+ providersMap = make(map[string]providerTypes.ProxyProvider)
proxyList := []string{}
proxiesConfig := cfg.Proxy
groupsConfig := cfg.ProxyGroup
@@ -345,7 +346,7 @@ func parseProxies(cfg *RawConfig) (proxies map[string]C.Proxy, providersMap map[
// initial compatible provider
for _, pd := range providersMap {
- if pd.VehicleType() != provider.Compatible {
+ if pd.VehicleType() != providerTypes.Compatible {
continue
}
@@ -367,7 +368,7 @@ func parseProxies(cfg *RawConfig) (proxies map[string]C.Proxy, providersMap map[
&outboundgroup.GroupCommonOption{
Name: "GLOBAL",
},
- []provider.ProxyProvider{pd},
+ []providerTypes.ProxyProvider{pd},
)
proxies["GLOBAL"] = adapter.NewProxy(global)
return proxies, providersMap, nil
diff --git a/constant/provider/interface.go b/constant/provider/interface.go
new file mode 100644
index 000000000..d3483cdcd
--- /dev/null
+++ b/constant/provider/interface.go
@@ -0,0 +1,105 @@
+package provider
+
+import (
+ "github.com/Dreamacro/clash/constant"
+)
+
+// Vehicle Type
+const (
+ File VehicleType = iota
+ HTTP
+ Compatible
+)
+
+// VehicleType defined
+type VehicleType int
+
+func (v VehicleType) String() string {
+ switch v {
+ case File:
+ return "File"
+ case HTTP:
+ return "HTTP"
+ case Compatible:
+ return "Compatible"
+ default:
+ return "Unknown"
+ }
+}
+
+type Vehicle interface {
+ Read() ([]byte, error)
+ Path() string
+ Type() VehicleType
+}
+
+// Provider Type
+const (
+ Proxy ProviderType = iota
+ Rule
+)
+
+// ProviderType defined
+type ProviderType int
+
+func (pt ProviderType) String() string {
+ switch pt {
+ case Proxy:
+ return "Proxy"
+ case Rule:
+ return "Rule"
+ default:
+ return "Unknown"
+ }
+}
+
+// Provider interface
+type Provider interface {
+ Name() string
+ VehicleType() VehicleType
+ Type() ProviderType
+ Initial() error
+ Update() error
+}
+
+// ProxyProvider interface
+type ProxyProvider interface {
+ Provider
+ Proxies() []constant.Proxy
+ // ProxiesWithTouch is used to inform the provider that the proxy is actually being used while getting the list of proxies.
+ // Commonly used in Dial and DialUDP
+ ProxiesWithTouch() []constant.Proxy
+ HealthCheck()
+}
+
+// Rule Type
+const (
+ Domain RuleType = iota
+ IPCIDR
+ Classical
+)
+
+// RuleType defined
+type RuleType int
+
+func (rt RuleType) String() string {
+ switch rt {
+ case Domain:
+ return "Domain"
+ case IPCIDR:
+ return "IPCIDR"
+ case Classical:
+ return "Classical"
+ default:
+ return "Unknown"
+ }
+}
+
+// RuleProvider interface
+type RuleProvider interface {
+ Provider
+ Behavior() RuleType
+ Match(*constant.Metadata) bool
+ ShouldResolveIP() bool
+ AsRule(adaptor string) constant.Rule
+}
diff --git a/hub/executor/executor.go b/hub/executor/executor.go
index 81920221d..321efe250 100644
--- a/hub/executor/executor.go
+++ b/hub/executor/executor.go
@@ -8,7 +8,6 @@ import (
"github.com/Dreamacro/clash/adapter"
"github.com/Dreamacro/clash/adapter/outboundgroup"
- "github.com/Dreamacro/clash/adapter/provider"
"github.com/Dreamacro/clash/component/auth"
"github.com/Dreamacro/clash/component/dialer"
"github.com/Dreamacro/clash/component/profile"
@@ -17,6 +16,7 @@ import (
"github.com/Dreamacro/clash/component/trie"
"github.com/Dreamacro/clash/config"
C "github.com/Dreamacro/clash/constant"
+ "github.com/Dreamacro/clash/constant/provider"
"github.com/Dreamacro/clash/dns"
P "github.com/Dreamacro/clash/listener"
authStore "github.com/Dreamacro/clash/listener/auth"
diff --git a/hub/route/provider.go b/hub/route/provider.go
index f373d5114..0b599445a 100644
--- a/hub/route/provider.go
+++ b/hub/route/provider.go
@@ -4,7 +4,7 @@ import (
"context"
"net/http"
- "github.com/Dreamacro/clash/adapter/provider"
+ "github.com/Dreamacro/clash/constant/provider"
"github.com/Dreamacro/clash/tunnel"
"github.com/go-chi/chi/v5"
diff --git a/tunnel/tunnel.go b/tunnel/tunnel.go
index a40b697df..0ec36d3f1 100644
--- a/tunnel/tunnel.go
+++ b/tunnel/tunnel.go
@@ -8,10 +8,10 @@ import (
"time"
"github.com/Dreamacro/clash/adapter/inbound"
- "github.com/Dreamacro/clash/adapter/provider"
"github.com/Dreamacro/clash/component/nat"
"github.com/Dreamacro/clash/component/resolver"
C "github.com/Dreamacro/clash/constant"
+ "github.com/Dreamacro/clash/constant/provider"
"github.com/Dreamacro/clash/context"
"github.com/Dreamacro/clash/log"
"github.com/Dreamacro/clash/tunnel/statistic"
From b4292d09721e3cc20745903e9dc3bece1a5a1221 Mon Sep 17 00:00:00 2001
From: Dreamacro <8615343+Dreamacro@users.noreply.github.com>
Date: Tue, 6 Jul 2021 00:33:13 +0800
Subject: [PATCH 18/96] Fix: staticcheck error
---
adapter/provider/provider.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/adapter/provider/provider.go b/adapter/provider/provider.go
index b6e1ac754..32baaedd9 100644
--- a/adapter/provider/provider.go
+++ b/adapter/provider/provider.go
@@ -204,7 +204,7 @@ func stopCompatibleProvider(pd *CompatibleProvider) {
func NewCompatibleProvider(name string, proxies []C.Proxy, hc *HealthCheck) (*CompatibleProvider, error) {
if len(proxies) == 0 {
- return nil, errors.New("Provider need one proxy at least")
+ return nil, errors.New("provider need one proxy at least")
}
if hc.auto() {
From 250a9f4f847cad95f1960d280603d4bf07991d47 Mon Sep 17 00:00:00 2001
From: Dreamacro <8615343+Dreamacro@users.noreply.github.com>
Date: Sat, 10 Jul 2021 17:01:40 +0800
Subject: [PATCH 19/96] Fix: reorder apply config to ensure update proxies and
rules
---
hub/executor/executor.go | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/hub/executor/executor.go b/hub/executor/executor.go
index 321efe250..4438a5761 100644
--- a/hub/executor/executor.go
+++ b/hub/executor/executor.go
@@ -70,13 +70,13 @@ func ApplyConfig(cfg *config.Config, force bool) {
defer mux.Unlock()
updateUsers(cfg.Users)
- updateGeneral(cfg.General, force)
updateProxies(cfg.Proxies, cfg.Providers)
updateRules(cfg.Rules)
- updateDNS(cfg.DNS)
updateHosts(cfg.Hosts)
- updateExperimental(cfg)
updateProfile(cfg)
+ updateGeneral(cfg.General, force)
+ updateDNS(cfg.DNS)
+ updateExperimental(cfg)
}
func GetGeneral() *config.General {
From 46f4f8444260bc0b93f1d83c88ba92ef39cb9a9c Mon Sep 17 00:00:00 2001
From: Dreamacro <8615343+Dreamacro@users.noreply.github.com>
Date: Sun, 11 Jul 2021 19:42:54 +0800
Subject: [PATCH 20/96] Chore: use iife replace init in some cases
---
common/pool/alloc.go | 6 +-----
component/process/process_linux.go | 12 +++++-------
constant/path.go | 16 +++++++---------
3 files changed, 13 insertions(+), 21 deletions(-)
diff --git a/common/pool/alloc.go b/common/pool/alloc.go
index bf177da88..6ae53c1db 100644
--- a/common/pool/alloc.go
+++ b/common/pool/alloc.go
@@ -8,11 +8,7 @@ import (
"sync"
)
-var defaultAllocator *Allocator
-
-func init() {
- defaultAllocator = NewAllocator()
-}
+var defaultAllocator = NewAllocator()
// Allocator for incoming frames, optimized to prevent overwriting after zeroing
type Allocator struct {
diff --git a/component/process/process_linux.go b/component/process/process_linux.go
index 1f651cd48..fabe969c8 100644
--- a/component/process/process_linux.go
+++ b/component/process/process_linux.go
@@ -16,14 +16,14 @@ import (
)
// from https://github.com/vishvananda/netlink/blob/bca67dfc8220b44ef582c9da4e9172bf1c9ec973/nl/nl_linux.go#L52-L62
-func init() {
+var nativeEndian = func() binary.ByteOrder {
var x uint32 = 0x01020304
if *(*byte)(unsafe.Pointer(&x)) == 0x01 {
- nativeEndian = binary.BigEndian
- } else {
- nativeEndian = binary.LittleEndian
+ return binary.BigEndian
}
-}
+
+ return binary.LittleEndian
+}()
type SocketResolver func(network string, ip net.IP, srcPort int) (inode, uid int, err error)
type ProcessNameResolver func(inode, uid int) (name string, err error)
@@ -40,8 +40,6 @@ const (
pathProc = "/proc"
)
-var nativeEndian binary.ByteOrder = binary.LittleEndian
-
func findProcessName(network string, ip net.IP, srcPort int) (string, error) {
inode, uid, err := DefaultSocketResolver(network, ip, srcPort)
if err != nil {
diff --git a/constant/path.go b/constant/path.go
index 021721ec4..ba0e8c23b 100644
--- a/constant/path.go
+++ b/constant/path.go
@@ -9,21 +9,19 @@ import (
const Name = "clash"
// Path is used to get the configuration path
-var Path *path
-
-type path struct {
- homeDir string
- configFile string
-}
-
-func init() {
+var Path = func() *path {
homeDir, err := os.UserHomeDir()
if err != nil {
homeDir, _ = os.Getwd()
}
homeDir = P.Join(homeDir, ".config", Name)
- Path = &path{homeDir: homeDir, configFile: "config.yaml"}
+ return &path{homeDir: homeDir, configFile: "config.yaml"}
+}()
+
+type path struct {
+ homeDir string
+ configFile string
}
// SetHomeDir is used to set the configuration path
From a461c2306ab97d7814b196d057e91ed9dce71284 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?x=E1=B4=8A=E1=B4=80s=E1=B4=8F=C9=B4=CA=9F=CA=8F=E1=B4=9C?=
Date: Sun, 18 Jul 2021 16:09:09 +0800
Subject: [PATCH 21/96] Feature: SOCKS4/SOCKS4A Inbound Compatible Support
(#1491)
---
hub/executor/executor.go | 4 +-
listener/listener.go | 4 +-
listener/mixed/mixed.go | 13 ++-
listener/socks/tcp.go | 36 ++++++-
transport/socks4/socks4.go | 195 +++++++++++++++++++++++++++++++++++++
5 files changed, 241 insertions(+), 11 deletions(-)
create mode 100644 transport/socks4/socks4.go
diff --git a/hub/executor/executor.go b/hub/executor/executor.go
index 4438a5761..b3772211f 100644
--- a/hub/executor/executor.go
+++ b/hub/executor/executor.go
@@ -195,7 +195,7 @@ func updateGeneral(general *config.General, force bool) {
}
if err := P.ReCreateSocks(general.SocksPort, tcpIn, udpIn); err != nil {
- log.Errorln("Start SOCKS5 server error: %s", err.Error())
+ log.Errorln("Start SOCKS server error: %s", err.Error())
}
if err := P.ReCreateRedir(general.RedirPort, tcpIn, udpIn); err != nil {
@@ -207,7 +207,7 @@ func updateGeneral(general *config.General, force bool) {
}
if err := P.ReCreateMixed(general.MixedPort, tcpIn, udpIn); err != nil {
- log.Errorln("Start Mixed(http and socks5) server error: %s", err.Error())
+ log.Errorln("Start Mixed(http and socks) server error: %s", err.Error())
}
}
diff --git a/listener/listener.go b/listener/listener.go
index cf0390e7e..5d0e8d7bf 100644
--- a/listener/listener.go
+++ b/listener/listener.go
@@ -139,7 +139,7 @@ func ReCreateSocks(port int, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.P
socksListener = tcpListener
socksUDPListener = udpListener
- log.Infoln("SOCKS5 proxy listening at: %s", socksListener.Address())
+ log.Infoln("SOCKS proxy listening at: %s", socksListener.Address())
return nil
}
@@ -271,7 +271,7 @@ func ReCreateMixed(port int, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.P
return err
}
- log.Infoln("Mixed(http+socks5) proxy listening at: %s", mixedListener.Address())
+ log.Infoln("Mixed(http+socks) proxy listening at: %s", mixedListener.Address())
return nil
}
diff --git a/listener/mixed/mixed.go b/listener/mixed/mixed.go
index 07ad03b62..7d89e3c8d 100644
--- a/listener/mixed/mixed.go
+++ b/listener/mixed/mixed.go
@@ -9,6 +9,7 @@ import (
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/listener/http"
"github.com/Dreamacro/clash/listener/socks"
+ "github.com/Dreamacro/clash/transport/socks4"
"github.com/Dreamacro/clash/transport/socks5"
)
@@ -58,10 +59,12 @@ func handleConn(conn net.Conn, in chan<- C.ConnContext, cache *cache.Cache) {
return
}
- if head[0] == socks5.Version {
- socks.HandleSocks(bufConn, in)
- return
+ switch head[0] {
+ case socks4.Version:
+ socks.HandleSocks4(bufConn, in)
+ case socks5.Version:
+ socks.HandleSocks5(bufConn, in)
+ default:
+ http.HandleConn(bufConn, in, cache)
}
-
- http.HandleConn(bufConn, in, cache)
}
diff --git a/listener/socks/tcp.go b/listener/socks/tcp.go
index 8e12ac71d..60da0e264 100644
--- a/listener/socks/tcp.go
+++ b/listener/socks/tcp.go
@@ -6,8 +6,10 @@ import (
"net"
"github.com/Dreamacro/clash/adapter/inbound"
+ N "github.com/Dreamacro/clash/common/net"
C "github.com/Dreamacro/clash/constant"
authStore "github.com/Dreamacro/clash/listener/auth"
+ "github.com/Dreamacro/clash/transport/socks4"
"github.com/Dreamacro/clash/transport/socks5"
)
@@ -33,7 +35,7 @@ func New(addr string, in chan<- C.ConnContext) (*Listener, error) {
}
continue
}
- go HandleSocks(c, in)
+ go handleSocks(c, in)
}
}()
@@ -49,7 +51,37 @@ func (l *Listener) Address() string {
return l.address
}
-func HandleSocks(conn net.Conn, in chan<- C.ConnContext) {
+func handleSocks(conn net.Conn, in chan<- C.ConnContext) {
+ bufConn := N.NewBufferedConn(conn)
+ head, err := bufConn.Peek(1)
+ if err != nil {
+ conn.Close()
+ return
+ }
+
+ switch head[0] {
+ case socks4.Version:
+ HandleSocks4(bufConn, in)
+ case socks5.Version:
+ HandleSocks5(bufConn, in)
+ default:
+ conn.Close()
+ }
+}
+
+func HandleSocks4(conn net.Conn, in chan<- C.ConnContext) {
+ addr, _, err := socks4.ServerHandshake(conn, authStore.Authenticator())
+ if err != nil {
+ conn.Close()
+ return
+ }
+ if c, ok := conn.(*net.TCPConn); ok {
+ c.SetKeepAlive(true)
+ }
+ in <- inbound.NewSocket(socks5.ParseAddr(addr), conn, C.SOCKS)
+}
+
+func HandleSocks5(conn net.Conn, in chan<- C.ConnContext) {
target, command, err := socks5.ServerHandshake(conn, authStore.Authenticator())
if err != nil {
conn.Close()
diff --git a/transport/socks4/socks4.go b/transport/socks4/socks4.go
new file mode 100644
index 000000000..c6b2f2db5
--- /dev/null
+++ b/transport/socks4/socks4.go
@@ -0,0 +1,195 @@
+package socks4
+
+import (
+ "bytes"
+ "encoding/binary"
+ "errors"
+ "io"
+ "net"
+ "strconv"
+
+ "github.com/Dreamacro/clash/component/auth"
+)
+
+const Version = 0x04
+
+type Command = uint8
+
+const (
+ CmdConnect Command = 0x01
+ CmdBind Command = 0x02
+)
+
+type Code = uint8
+
+const (
+ RequestGranted Code = 90
+ RequestRejected Code = 91
+ RequestIdentdFailed Code = 92
+ RequestIdentdMismatched Code = 93
+)
+
+var (
+ errVersionMismatched = errors.New("version code mismatched")
+ errCommandNotSupported = errors.New("command not supported")
+ errIPv6NotSupported = errors.New("IPv6 not supported")
+
+ ErrRequestRejected = errors.New("request rejected or failed")
+ ErrRequestIdentdFailed = errors.New("request rejected because SOCKS server cannot connect to identd on the client")
+ ErrRequestIdentdMismatched = errors.New("request rejected because the client program and identd report different user-ids")
+ ErrRequestUnknownCode = errors.New("request failed with unknown code")
+)
+
+func ServerHandshake(rw io.ReadWriter, authenticator auth.Authenticator) (addr string, command Command, err error) {
+ var req [8]byte
+ if _, err = io.ReadFull(rw, req[:]); err != nil {
+ return
+ }
+
+ if req[0] != Version {
+ err = errVersionMismatched
+ return
+ }
+
+ if command = req[1]; command != CmdConnect {
+ err = errCommandNotSupported
+ return
+ }
+
+ var (
+ dstIP = req[4:8] // [4]byte
+ dstPort = req[2:4] // [2]byte
+ )
+
+ var (
+ host string
+ port string
+ code uint8
+ userID []byte
+ )
+ if userID, err = readUntilNull(rw); err != nil {
+ return
+ }
+
+ if isReservedIP(dstIP) {
+ var target []byte
+ if target, err = readUntilNull(rw); err != nil {
+ return
+ }
+ host = string(target)
+ }
+
+ port = strconv.Itoa(int(binary.BigEndian.Uint16(dstPort)))
+ if host != "" {
+ addr = net.JoinHostPort(host, port)
+ } else {
+ addr = net.JoinHostPort(net.IP(dstIP).String(), port)
+ }
+
+ // SOCKS4 only support USERID auth.
+ if authenticator == nil || authenticator.Verify(string(userID), "") {
+ code = RequestGranted
+ } else {
+ code = RequestIdentdMismatched
+ }
+
+ var reply [8]byte
+ reply[0] = 0x00 // reply code
+ reply[1] = code // result code
+ copy(reply[4:8], dstIP)
+ copy(reply[2:4], dstPort)
+
+ _, err = rw.Write(reply[:])
+ return
+}
+
+func ClientHandshake(rw io.ReadWriter, addr string, command Command, userID string) (err error) {
+ host, portStr, err := net.SplitHostPort(addr)
+ if err != nil {
+ return err
+ }
+
+ port, err := strconv.ParseUint(portStr, 10, 16)
+ if err != nil {
+ return err
+ }
+
+ ip := net.ParseIP(host)
+ if ip == nil /* HOST */ {
+ ip = net.IPv4(0, 0, 0, 1).To4()
+ } else if ip.To4() == nil /* IPv6 */ {
+ return errIPv6NotSupported
+ }
+
+ dstIP := ip.To4()
+
+ req := &bytes.Buffer{}
+ req.WriteByte(Version)
+ req.WriteByte(command)
+ binary.Write(req, binary.BigEndian, uint16(port))
+ req.Write(dstIP)
+ req.WriteString(userID)
+ req.WriteByte(0) /* NULL */
+
+ if isReservedIP(dstIP) /* SOCKS4A */ {
+ req.WriteString(host)
+ req.WriteByte(0) /* NULL */
+ }
+
+ if _, err = rw.Write(req.Bytes()); err != nil {
+ return err
+ }
+
+ var resp [8]byte
+ if _, err = io.ReadFull(rw, resp[:]); err != nil {
+ return err
+ }
+
+ if resp[0] != 0x00 {
+ return errVersionMismatched
+ }
+
+ switch resp[1] {
+ case RequestGranted:
+ return nil
+ case RequestRejected:
+ return ErrRequestRejected
+ case RequestIdentdFailed:
+ return ErrRequestIdentdFailed
+ case RequestIdentdMismatched:
+ return ErrRequestIdentdMismatched
+ default:
+ return ErrRequestUnknownCode
+ }
+}
+
+// For version 4A, if the client cannot resolve the destination host's
+// domain name to find its IP address, it should set the first three bytes
+// of DSTIP to NULL and the last byte to a non-zero value. (This corresponds
+// to IP address 0.0.0.x, with x nonzero. As decreed by IANA -- The
+// Internet Assigned Numbers Authority -- such an address is inadmissible
+// as a destination IP address and thus should never occur if the client
+// can resolve the domain name.)
+func isReservedIP(ip net.IP) bool {
+ subnet := net.IPNet{
+ IP: net.IPv4zero,
+ Mask: net.IPv4Mask(0xff, 0xff, 0xff, 0x00),
+ }
+
+ return !ip.IsUnspecified() && subnet.Contains(ip)
+}
+
+func readUntilNull(r io.Reader) ([]byte, error) {
+ var buf = &bytes.Buffer{}
+ var data [1]byte
+
+ for {
+ if _, err := r.Read(data[:]); err != nil {
+ return nil, err
+ }
+ if data[0] == 0 {
+ return buf.Bytes(), nil
+ }
+ buf.WriteByte(data[0])
+ }
+}
From 91ed0118f628dd378fb3c74a23f3e46f838012ae Mon Sep 17 00:00:00 2001
From: Dreamacro <8615343+Dreamacro@users.noreply.github.com>
Date: Sun, 18 Jul 2021 17:23:22 +0800
Subject: [PATCH 22/96] Test: add basic protocol benchmark
---
test/clash_test.go | 35 +
test/go.mod | 25 +-
test/go.sum | 844 ++++++++++++++++++++-
test/snell_test.go | 37 +
test/ss_test.go | 35 +
test/trojan_test.go | 40 +
test/{util_test.go => util_darwin_test.go} | 0
test/util_other_test.go | 12 +
test/vmess_test.go | 38 +
9 files changed, 1020 insertions(+), 46 deletions(-)
rename test/{util_test.go => util_darwin_test.go} (100%)
create mode 100644 test/util_other_test.go
diff --git a/test/clash_test.go b/test/clash_test.go
index e835b0fec..97f6648b1 100644
--- a/test/clash_test.go
+++ b/test/clash_test.go
@@ -619,6 +619,41 @@ func testSuit(t *testing.T, proxy C.ProxyAdapter) {
assert.NoError(t, testPacketConnTimeout(t, pc))
}
+func benchmarkProxy(b *testing.B, proxy C.ProxyAdapter) {
+ l, err := net.Listen("tcp", ":10001")
+ if err != nil {
+ assert.FailNow(b, err.Error())
+ }
+
+ go func() {
+ c, err := l.Accept()
+ if err != nil {
+ assert.FailNow(b, err.Error())
+ }
+
+ io.Copy(io.Discard, c)
+ c.Close()
+ }()
+
+ chunk := make([]byte, 1024)
+ conn, err := proxy.DialContext(context.Background(), &C.Metadata{
+ Host: localIP.String(),
+ DstPort: "10001",
+ AddrType: socks5.AtypDomainName,
+ })
+ if err != nil {
+ assert.FailNow(b, err.Error())
+ }
+
+ b.SetBytes(1024)
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ if _, err := conn.Write(chunk); err != nil {
+ assert.FailNow(b, err.Error())
+ }
+ }
+}
+
func TestClash_Basic(t *testing.T) {
basic := `
mixed-port: 10000
diff --git a/test/go.mod b/test/go.mod
index 1a5cb6763..88db62292 100644
--- a/test/go.mod
+++ b/test/go.mod
@@ -3,24 +3,17 @@ module clash-test
go 1.16
require (
- github.com/Dreamacro/clash v1.6.1-0.20210516120541-06fdd3abe0ab
- github.com/Microsoft/go-winio v0.4.16 // indirect
- github.com/containerd/containerd v1.4.4 // indirect
- github.com/docker/distribution v2.7.1+incompatible // indirect
- github.com/docker/docker v20.10.6+incompatible
+ github.com/Dreamacro/clash v1.6.5
+ github.com/Microsoft/go-winio v0.5.0 // indirect
+ github.com/containerd/containerd v1.5.3 // indirect
+ github.com/docker/docker v20.10.7+incompatible
github.com/docker/go-connections v0.4.0
- github.com/docker/go-units v0.4.0 // indirect
- github.com/gogo/protobuf v1.3.2 // indirect
- github.com/google/go-cmp v0.5.5 // indirect
github.com/gorilla/mux v1.8.0 // indirect
- github.com/miekg/dns v1.1.42
- github.com/moby/term v0.0.0-20201216013528-df9cb8a40635 // indirect
+ github.com/miekg/dns v1.1.43
+ github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 // indirect
github.com/morikuni/aec v1.0.0 // indirect
- github.com/opencontainers/go-digest v1.0.0 // indirect
- github.com/opencontainers/image-spec v1.0.1 // indirect
github.com/stretchr/testify v1.7.0
- golang.org/x/net v0.0.0-20210510120150-4163338589ed
- golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba // indirect
- google.golang.org/grpc v1.36.0 // indirect
- gotest.tools/v3 v3.0.3 // indirect
+ golang.org/x/net v0.0.0-20210614182718-04defd469f4e
+ golang.org/x/time v0.0.0-20210611083556-38a9dc6acbc6 // indirect
+ google.golang.org/grpc v1.39.0 // indirect
)
diff --git a/test/go.sum b/test/go.sum
index 2a641fb70..0b460241b 100644
--- a/test/go.sum
+++ b/test/go.sum
@@ -1,164 +1,837 @@
+bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8=
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
-github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8=
+cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
+cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
+cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
+cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
+cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
+cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
+cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
+cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
+cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
+cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
+cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
+cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
+cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
+cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
+cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
+cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
+cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
+cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
+cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
+cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
+dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
+github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
+github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8=
+github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
+github.com/Azure/go-autorest v10.8.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
+github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
+github.com/Azure/go-autorest/autorest v0.11.1/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw=
+github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg=
+github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A=
+github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74=
+github.com/Azure/go-autorest/autorest/mocks v0.4.0/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k=
+github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k=
+github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8=
+github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
-github.com/Dreamacro/clash v1.6.1-0.20210516120541-06fdd3abe0ab h1:hfjxpY+73Xo6k+JHMkLlaOR3Tw5hG/YZxmDFyV9Y6sY=
-github.com/Dreamacro/clash v1.6.1-0.20210516120541-06fdd3abe0ab/go.mod h1:Pz9GwWR244jrMSInQ0KUL02jMCe5xIJ+pkgzuNIy2Iw=
+github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
+github.com/Dreamacro/clash v1.6.5 h1:bO8MJpfDOqZsgiK32x2xe9fjniujqVabQOWEYAg5Rac=
+github.com/Dreamacro/clash v1.6.5/go.mod h1:AqwqYq0ibcW8j14Re3/uY0bido9PzAuME7Dj+7zst/o=
github.com/Dreamacro/go-shadowsocks2 v0.1.7 h1:8CtbE1HoPPMfrQZGXmlluq6dO2lL31W6WRRE8fabc4Q=
github.com/Dreamacro/go-shadowsocks2 v0.1.7/go.mod h1:8p5G4cAj5ZlXwUR+Ww63gfSikr8kvw8uw3TDwLAJpUc=
-github.com/Microsoft/go-winio v0.4.16 h1:FtSW/jqD+l4ba5iPBj9CODVtgfYAD8w2wS923g/cFDk=
+github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
+github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
+github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw=
+github.com/Microsoft/go-winio v0.4.16-0.20201130162521-d1ffc52c7331/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0=
github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0=
+github.com/Microsoft/go-winio v0.4.17-0.20210211115548-6eac466e5fa3/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
+github.com/Microsoft/go-winio v0.4.17-0.20210324224401-5516f17a5958/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
+github.com/Microsoft/go-winio v0.4.17/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
+github.com/Microsoft/go-winio v0.5.0 h1:Elr9Wn+sGKPlkaBvwu4mTrxtmOp3F3yV9qhaHbXGjwU=
+github.com/Microsoft/go-winio v0.5.0/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
+github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg=
+github.com/Microsoft/hcsshim v0.8.7-0.20190325164909-8abdbb8205e4/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg=
+github.com/Microsoft/hcsshim v0.8.7/go.mod h1:OHd7sQqRFrYd3RmSgbgji+ctCwkbq2wbEYNSzOYtcBQ=
+github.com/Microsoft/hcsshim v0.8.9/go.mod h1:5692vkUqntj1idxauYlpoINNKeqCiG6Sg38RRsjT5y8=
+github.com/Microsoft/hcsshim v0.8.14/go.mod h1:NtVKoYxQuTLx6gEq0L96c9Ju4JbRJ4nY2ow3VK6a9Lg=
+github.com/Microsoft/hcsshim v0.8.15/go.mod h1:x38A4YbHbdxJtc0sF6oIz+RG0npwSCAvn69iY6URG00=
+github.com/Microsoft/hcsshim v0.8.16/go.mod h1:o5/SZqmR7x9JNKsW3pu+nqHm0MF8vbA+VxGOoXdC600=
+github.com/Microsoft/hcsshim v0.8.18/go.mod h1:+w2gRZ5ReXQhFOrvSQeNfhrYB/dg3oDwTOcER2fw4I4=
+github.com/Microsoft/hcsshim/test v0.0.0-20201218223536-d3e5debf77da/go.mod h1:5hlzMzRKMLyo42nCZ9oml8AdTlq/0cvIaBv6tK1RehU=
+github.com/Microsoft/hcsshim/test v0.0.0-20210227013316-43a75bb4edd3/go.mod h1:mw7qgWloBUl75W/gVH3cQszUg1+gUITj7D6NY7ywVnY=
+github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
+github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
+github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
+github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
+github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ=
+github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
+github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
+github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
+github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
+github.com/alexflint/go-filemutex v0.0.0-20171022225611-72bdc8eae2ae/go.mod h1:CgnQgUtFrFz9mxFNtED3jI5tLDjKlOM+oUF/sTk6ps0=
+github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
+github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
+github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
+github.com/aws/aws-sdk-go v1.15.11/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0=
+github.com/beorn7/perks v0.0.0-20160804104726-4c0e84591b9a/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
+github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
+github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
+github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
+github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
+github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA=
+github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
+github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
+github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
+github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk=
+github.com/buger/jsonparser v0.0.0-20180808090653-f4dd9f5a6b44/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
+github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8=
+github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50=
+github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
+github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
+github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/checkpoint-restore/go-criu/v4 v4.1.0/go.mod h1:xUQBLp4RLc5zJtWY++yjOoMoB5lihDt7fai+75m+rGw=
+github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
+github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
+github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
+github.com/cilium/ebpf v0.0.0-20200110133405-4032b1d8aae3/go.mod h1:MA5e5Lr8slmEg9bt0VpxxWqJlO4iwu3FBdHUzV7wQVg=
+github.com/cilium/ebpf v0.0.0-20200702112145-1c8d4c9ef775/go.mod h1:7cR51M8ViRLIdUjrmSXlK9pkrsDlLHbO8jiB8X8JnOc=
+github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs=
+github.com/cilium/ebpf v0.4.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
+github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
-github.com/containerd/containerd v1.4.4 h1:rtRG4N6Ct7GNssATwgpvMGfnjnwfjnu/Zs9W3Ikzq+M=
-github.com/containerd/containerd v1.4.4/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
+github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
+github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
+github.com/containerd/aufs v0.0.0-20200908144142-dab0cbea06f4/go.mod h1:nukgQABAEopAHvB6j7cnP5zJ+/3aVcE7hCYqvIwAHyE=
+github.com/containerd/aufs v0.0.0-20201003224125-76a6863f2989/go.mod h1:AkGGQs9NM2vtYHaUen+NljV0/baGCAPELGm2q9ZXpWU=
+github.com/containerd/aufs v0.0.0-20210316121734-20793ff83c97/go.mod h1:kL5kd6KM5TzQjR79jljyi4olc1Vrx6XBlcyj3gNv2PU=
+github.com/containerd/aufs v1.0.0/go.mod h1:kL5kd6KM5TzQjR79jljyi4olc1Vrx6XBlcyj3gNv2PU=
+github.com/containerd/btrfs v0.0.0-20201111183144-404b9149801e/go.mod h1:jg2QkJcsabfHugurUvvPhS3E08Oxiuh5W/g1ybB4e0E=
+github.com/containerd/btrfs v0.0.0-20210316141732-918d888fb676/go.mod h1:zMcX3qkXTAi9GI50+0HOeuV8LU2ryCE/V2vG/ZBiTss=
+github.com/containerd/btrfs v1.0.0/go.mod h1:zMcX3qkXTAi9GI50+0HOeuV8LU2ryCE/V2vG/ZBiTss=
+github.com/containerd/cgroups v0.0.0-20190717030353-c4b9ac5c7601/go.mod h1:X9rLEHIqSf/wfK8NsPqxJmeZgW4pcfzdXITDrUSJ6uI=
+github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko=
+github.com/containerd/cgroups v0.0.0-20200531161412-0dbf7f05ba59/go.mod h1:pA0z1pT8KYB3TCXK/ocprsh7MAkoW8bZVzPdih9snmM=
+github.com/containerd/cgroups v0.0.0-20200710171044-318312a37340/go.mod h1:s5q4SojHctfxANBDvMeIaIovkq29IP48TKAxnhYRxvo=
+github.com/containerd/cgroups v0.0.0-20200824123100-0b889c03f102/go.mod h1:s5q4SojHctfxANBDvMeIaIovkq29IP48TKAxnhYRxvo=
+github.com/containerd/cgroups v0.0.0-20210114181951-8a68de567b68/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE=
+github.com/containerd/cgroups v1.0.1/go.mod h1:0SJrPIenamHDcZhEcJMNBB85rHcUsw4f25ZfBiPYRkU=
+github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw=
+github.com/containerd/console v0.0.0-20181022165439-0650fd9eeb50/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw=
+github.com/containerd/console v0.0.0-20191206165004-02ecf6a7291e/go.mod h1:8Pf4gM6VEbTNRIT26AyyU7hxdQU3MvAvxVI0sc00XBE=
+github.com/containerd/console v1.0.1/go.mod h1:XUsP6YE/mKtz6bxc+I8UiKKTP04qjQL4qcS3XoQ5xkw=
+github.com/containerd/console v1.0.2/go.mod h1:ytZPjGgY2oeTkAONYafi2kSj0aYggsf8acV1PGKCbzQ=
+github.com/containerd/containerd v1.2.10/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
+github.com/containerd/containerd v1.3.0-beta.2.0.20190828155532-0293cbd26c69/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
+github.com/containerd/containerd v1.3.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
+github.com/containerd/containerd v1.3.1-0.20191213020239-082f7e3aed57/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
+github.com/containerd/containerd v1.3.2/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
+github.com/containerd/containerd v1.4.0-beta.2.0.20200729163537-40b22ef07410/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
+github.com/containerd/containerd v1.4.1/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
+github.com/containerd/containerd v1.4.3/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
+github.com/containerd/containerd v1.5.0-beta.1/go.mod h1:5HfvG1V2FsKesEGQ17k5/T7V960Tmcumvqn8Mc+pCYQ=
+github.com/containerd/containerd v1.5.0-beta.3/go.mod h1:/wr9AVtEM7x9c+n0+stptlo/uBBoBORwEx6ardVcmKU=
+github.com/containerd/containerd v1.5.0-beta.4/go.mod h1:GmdgZd2zA2GYIBZ0w09ZvgqEq8EfBp/m3lcVZIvPHhI=
+github.com/containerd/containerd v1.5.0-rc.0/go.mod h1:V/IXoMqNGgBlabz3tHD2TWDoTJseu1FGOKuoA4nNb2s=
+github.com/containerd/containerd v1.5.1/go.mod h1:0DOxVqwDy2iZvrZp2JUx/E+hS0UNTVn7dJnIOwtYR4g=
+github.com/containerd/containerd v1.5.3 h1:mfKOepNDIJ3EiBTEyHFpEqB6YSOSkGcjPDIu7cD+YzY=
+github.com/containerd/containerd v1.5.3/go.mod h1:sx18RgvW6ABJ4iYUw7Q5x7bgFOAB9B6G7+yO0XBc4zw=
+github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
+github.com/containerd/continuity v0.0.0-20190815185530-f2a389ac0a02/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
+github.com/containerd/continuity v0.0.0-20191127005431-f65d91d395eb/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
+github.com/containerd/continuity v0.0.0-20200710164510-efbc4488d8fe/go.mod h1:cECdGN1O8G9bgKTlLhuPJimka6Xb/Gg7vYzCTNVxhvo=
+github.com/containerd/continuity v0.0.0-20201208142359-180525291bb7/go.mod h1:kR3BEg7bDFaEddKm54WSmrol1fKWDU1nKYkgrcgZT7Y=
+github.com/containerd/continuity v0.0.0-20210208174643-50096c924a4e/go.mod h1:EXlVlkqNba9rJe3j7w3Xa924itAMLgZH4UD/Q4PExuQ=
+github.com/containerd/continuity v0.1.0/go.mod h1:ICJu0PwR54nI0yPEnJ6jcS+J7CZAUXrLh8lPo2knzsM=
+github.com/containerd/fifo v0.0.0-20180307165137-3d5202aec260/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI=
+github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI=
+github.com/containerd/fifo v0.0.0-20200410184934-f15a3290365b/go.mod h1:jPQ2IAeZRCYxpS/Cm1495vGFww6ecHmMk1YJH2Q5ln0=
+github.com/containerd/fifo v0.0.0-20201026212402-0724c46b320c/go.mod h1:jPQ2IAeZRCYxpS/Cm1495vGFww6ecHmMk1YJH2Q5ln0=
+github.com/containerd/fifo v0.0.0-20210316144830-115abcc95a1d/go.mod h1:ocF/ME1SX5b1AOlWi9r677YJmCPSwwWnQ9O123vzpE4=
+github.com/containerd/fifo v1.0.0/go.mod h1:ocF/ME1SX5b1AOlWi9r677YJmCPSwwWnQ9O123vzpE4=
+github.com/containerd/go-cni v1.0.1/go.mod h1:+vUpYxKvAF72G9i1WoDOiPGRtQpqsNW/ZHtSlv++smU=
+github.com/containerd/go-cni v1.0.2/go.mod h1:nrNABBHzu0ZwCug9Ije8hL2xBCYh/pjfMb1aZGrrohk=
+github.com/containerd/go-runc v0.0.0-20180907222934-5a6d9f37cfa3/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0=
+github.com/containerd/go-runc v0.0.0-20190911050354-e029b79d8cda/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0=
+github.com/containerd/go-runc v0.0.0-20200220073739-7016d3ce2328/go.mod h1:PpyHrqVs8FTi9vpyHwPwiNEGaACDxT/N/pLcvMSRA9g=
+github.com/containerd/go-runc v0.0.0-20201020171139-16b287bc67d0/go.mod h1:cNU0ZbCgCQVZK4lgG3P+9tn9/PaJNmoDXPpoJhDR+Ok=
+github.com/containerd/go-runc v1.0.0/go.mod h1:cNU0ZbCgCQVZK4lgG3P+9tn9/PaJNmoDXPpoJhDR+Ok=
+github.com/containerd/imgcrypt v1.0.1/go.mod h1:mdd8cEPW7TPgNG4FpuP3sGBiQ7Yi/zak9TYCG3juvb0=
+github.com/containerd/imgcrypt v1.0.4-0.20210301171431-0ae5c75f59ba/go.mod h1:6TNsg0ctmizkrOgXRNQjAPFWpMYRWuiB6dSF4Pfa5SA=
+github.com/containerd/imgcrypt v1.1.1-0.20210312161619-7ed62a527887/go.mod h1:5AZJNI6sLHJljKuI9IHnw1pWqo/F0nGDOuR9zgTs7ow=
+github.com/containerd/imgcrypt v1.1.1/go.mod h1:xpLnwiQmEUJPvQoAapeb2SNCxz7Xr6PJrXQb0Dpc4ms=
+github.com/containerd/nri v0.0.0-20201007170849-eb1350a75164/go.mod h1:+2wGSDGFYfE5+So4M5syatU0N0f0LbWpuqyMi4/BE8c=
+github.com/containerd/nri v0.0.0-20210316161719-dbaa18c31c14/go.mod h1:lmxnXF6oMkbqs39FiCt1s0R2HSMhcLel9vNL3m4AaeY=
+github.com/containerd/nri v0.1.0/go.mod h1:lmxnXF6oMkbqs39FiCt1s0R2HSMhcLel9vNL3m4AaeY=
+github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o=
+github.com/containerd/ttrpc v0.0.0-20190828172938-92c8520ef9f8/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o=
+github.com/containerd/ttrpc v0.0.0-20191028202541-4f1b8fe65a5c/go.mod h1:LPm1u0xBw8r8NOKoOdNMeVHSawSsltak+Ihv+etqsE8=
+github.com/containerd/ttrpc v1.0.1/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y=
+github.com/containerd/ttrpc v1.0.2/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y=
+github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc=
+github.com/containerd/typeurl v0.0.0-20190911142611-5eb25027c9fd/go.mod h1:GeKYzf2pQcqv7tJ0AoCuuhtnqhva5LNU3U+OyKxxJpk=
+github.com/containerd/typeurl v1.0.1/go.mod h1:TB1hUtrpaiO88KEK56ijojHS1+NeF0izUACaJW2mdXg=
+github.com/containerd/typeurl v1.0.2/go.mod h1:9trJWW2sRlGub4wZJRTW83VtbOLS6hwcDZXTn6oPz9s=
+github.com/containerd/zfs v0.0.0-20200918131355-0a33824f23a2/go.mod h1:8IgZOBdv8fAgXddBT4dBXJPtxyRsejFIpXoklgxgEjw=
+github.com/containerd/zfs v0.0.0-20210301145711-11e8f1707f62/go.mod h1:A9zfAbMlQwE+/is6hi0Xw8ktpL+6glmqZYtevJgaB8Y=
+github.com/containerd/zfs v0.0.0-20210315114300-dde8f0fda960/go.mod h1:m+m51S1DvAP6r3FcmYCp54bQ34pyOwTieQDNRIRHsFY=
+github.com/containerd/zfs v0.0.0-20210324211415-d5c4544f0433/go.mod h1:m+m51S1DvAP6r3FcmYCp54bQ34pyOwTieQDNRIRHsFY=
+github.com/containerd/zfs v1.0.0/go.mod h1:m+m51S1DvAP6r3FcmYCp54bQ34pyOwTieQDNRIRHsFY=
+github.com/containernetworking/cni v0.7.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY=
+github.com/containernetworking/cni v0.8.0/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY=
+github.com/containernetworking/cni v0.8.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY=
+github.com/containernetworking/plugins v0.8.6/go.mod h1:qnw5mN19D8fIwkqW7oHHYDHVlzhJpcY6TQxn/fUyDDM=
+github.com/containernetworking/plugins v0.9.1/go.mod h1:xP/idU2ldlzN6m4p5LmGiwRDjeJr6FLK6vuiUwoH7P8=
+github.com/containers/ocicrypt v1.0.1/go.mod h1:MeJDzk1RJHv89LjsH0Sp5KTY3ZYkjXO/C+bKAeWFIrc=
+github.com/containers/ocicrypt v1.1.0/go.mod h1:b8AOe0YR67uU8OqfVNcznfFpAzu3rdgUV4GP9qXPfu4=
+github.com/containers/ocicrypt v1.1.1/go.mod h1:Dm55fwWm1YZAjYRaJ94z2mfZikIyIN4B0oB3dj3jFxY=
+github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
+github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
+github.com/coreos/go-iptables v0.4.5/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU=
+github.com/coreos/go-iptables v0.5.0/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU=
+github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc=
+github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
+github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
+github.com/coreos/go-systemd v0.0.0-20161114122254-48702e0da86b/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
+github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
+github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
+github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk=
+github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk=
+github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
+github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
+github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
+github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
+github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
+github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4=
+github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c/go.mod h1:Ct2BUK8SB0YC1SMSibvLzxjeJLnrYEVLULFNiHY9YfQ=
+github.com/d2g/dhcp4client v1.0.0/go.mod h1:j0hNfjhrt2SxUOw55nL0ATM/z4Yt3t2Kd1mW34z5W5s=
+github.com/d2g/dhcp4server v0.0.0-20181031114812-7d4a0a7f59a5/go.mod h1:Eo87+Kg/IX2hfWJfwxMzLyuSZyxSoAug2nGa1G2QAi8=
+github.com/d2g/hardwareaddr v0.0.0-20190221164911-e7d9fbe030e4/go.mod h1:bMl4RjIciD2oAxI7DmWRx6gbeqrkoLqv3MV0vzNad+I=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0=
+github.com/dgrijalva/jwt-go v0.0.0-20170104182250-a601269ab70c/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
+github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
+github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
+github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
+github.com/docker/distribution v0.0.0-20190905152932-14b96e55d84c/go.mod h1:0+TTO4EOBfRPhZXAeF1Vu+W3hHZ8eLp8PgKVZlcvtFY=
+github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug=
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
-github.com/docker/docker v20.10.6+incompatible h1:oXI3Vas8TI8Eu/EjH4srKHJBVqraSzJybhxY7Om9faQ=
-github.com/docker/docker v20.10.6+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
+github.com/docker/docker v20.10.7+incompatible h1:Z6O9Nhsjv+ayUEeI1IojKbYcsGdgYSNqxe1s2MYzUhQ=
+github.com/docker/docker v20.10.7+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
+github.com/docker/go-events v0.0.0-20170721190031-9461782956ad/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA=
+github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA=
+github.com/docker/go-metrics v0.0.0-20180209012529-399ea8c73916/go.mod h1:/u0gXw0Gay3ceNrsHubL3BtdOL2fHf93USgMTe0W5dI=
+github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw=
github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw=
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
+github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE=
+github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
+github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
+github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
+github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
+github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
+github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
+github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
+github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
+github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
+github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
+github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
+github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k=
+github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
+github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
+github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXtdwXqoenmZCw6S+25EAm2MkxbG0deNDu4cbSA=
+github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY=
+github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
+github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-chi/chi/v5 v5.0.3/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
github.com/go-chi/cors v1.2.0/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58=
github.com/go-chi/render v1.0.1/go.mod h1:pq4Rr7HbnsdaeHagklXub+p6Wd16Af5l9koip1OvJns=
+github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
+github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
+github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
+github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
+github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
+github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
+github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
+github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
+github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
+github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
+github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg=
+github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
+github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc=
+github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8=
+github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo=
+github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
+github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
+github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
+github.com/godbus/dbus v0.0.0-20151105175453-c7fdd8b5cd55/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw=
+github.com/godbus/dbus v0.0.0-20180201030542-885f9cc04c9c/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw=
+github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4=
+github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw=
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
+github.com/gogo/googleapis v1.2.0/go.mod h1:Njal3psf3qN6dwBtQfUmBZh2ybovJ0tlu3o/AC7HYjU=
+github.com/gogo/googleapis v1.4.0/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c=
+github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
+github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
+github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
+github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
+github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
+github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
+github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
+github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
+github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
+github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
-github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
+github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM=
+github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
+github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
-github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M=
+github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
+github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
+github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
+github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
+github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
+github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
+github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg=
+github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
+github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=
+github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
+github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
+github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
+github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
+github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
+github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
+github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
+github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
+github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
+github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
+github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
+github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
+github.com/hashicorp/go-multierror v0.0.0-20161216184304-ed905158d874/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I=
+github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
+github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
+github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
+github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
+github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
+github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
+github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
+github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
+github.com/imdario/mergo v0.3.10/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
+github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
+github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
+github.com/j-keck/arping v0.0.0-20160618110441-2cf9dc699c56/go.mod h1:ymszkNOg6tORTn+6F6j+Jc8TOr5osrynvN6ivFWZ2GA=
+github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
+github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
+github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
+github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
+github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
+github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
+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/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
+github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
+github.com/klauspost/compress v1.11.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
+github.com/klauspost/compress v1.11.13/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
-github.com/miekg/dns v1.1.42 h1:gWGe42RGaIqXQZ+r3WUGEKBEtvPHY2SXo4dqixDNxuY=
-github.com/miekg/dns v1.1.42/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4=
-github.com/moby/term v0.0.0-20201216013528-df9cb8a40635 h1:rzf0wL0CHVc8CEsgyygG0Mn9CNCCPZqOPaz8RiiHYQk=
-github.com/moby/term v0.0.0-20201216013528-df9cb8a40635/go.mod h1:FBS0z0QWA44HXygs7VXDUOGoN/1TV3RuWkLO04am3wc=
+github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
+github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
+github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
+github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
+github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA=
+github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
+github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
+github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
+github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
+github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho=
+github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
+github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
+github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
+github.com/mattn/go-shellwords v1.0.3/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
+github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
+github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
+github.com/miekg/dns v1.1.43 h1:JKfpVSCB84vrAmHzyrsxB5NAr5kLoMXZArPSw7Qlgyg=
+github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4=
+github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
+github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4=
+github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
+github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A=
+github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc=
+github.com/moby/sys/mountinfo v0.4.0/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A=
+github.com/moby/sys/mountinfo v0.4.1/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A=
+github.com/moby/sys/symlink v0.1.0/go.mod h1:GGDODQmbFOjFsXvfLVn3+ZRxkch54RkSiGqsZeMYowQ=
+github.com/moby/term v0.0.0-20200312100748-672ec06f55cd/go.mod h1:DdlQx2hp0Ss5/fLikoLlEeIYiATotOjgB//nb973jeo=
+github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 h1:dcztxKSvZ4Id8iPpHERQBbIJfabdt4wUm5qy3wOL2Zc=
+github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw=
+github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
+github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ=
+github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
+github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
+github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
+github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
+github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM=
+github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
+github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
+github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
+github.com/onsi/ginkgo v0.0.0-20151202141238-7f8ab55aaf3b/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
+github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
+github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
+github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
+github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
+github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc=
+github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
+github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
+github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
+github.com/opencontainers/go-digest v1.0.0-rc1.0.20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
+github.com/opencontainers/image-spec v1.0.0/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI=
github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
+github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
+github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
+github.com/opencontainers/runc v1.0.0-rc8.0.20190926000215-3e425f80a8c9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
+github.com/opencontainers/runc v1.0.0-rc9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
+github.com/opencontainers/runc v1.0.0-rc93/go.mod h1:3NOsor4w32B2tC0Zbl8Knk4Wg84SM2ImC1fxBuqJ/H0=
+github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
+github.com/opencontainers/runtime-spec v1.0.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
+github.com/opencontainers/runtime-spec v1.0.2-0.20190207185410-29686dbc5559/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
+github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
+github.com/opencontainers/runtime-spec v1.0.3-0.20200929063507-e6143ca7d51d/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
+github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs=
+github.com/opencontainers/selinux v1.6.0/go.mod h1:VVGKuOLlE7v4PJyT6h7mNWvq1rzqiriPsEqVhc+svHE=
+github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3ogry1nUQF8Evvo=
github.com/oschwald/geoip2-golang v1.5.0 h1:igg2yQIrrcRccB1ytFXqBfOHCjXWIoMv85lVJ1ONZzw=
github.com/oschwald/geoip2-golang v1.5.0/go.mod h1:xdvYt5xQzB8ORWFqPnqMwZpCpgNagttWdoZLlJQzg7s=
github.com/oschwald/maxminddb-golang v1.8.0 h1:Uh/DSnGoxsyp/KYbY1AuP0tYEwfs0sCph9p/UMXK/Hk=
github.com/oschwald/maxminddb-golang v1.8.0/go.mod h1:RXZtst0N6+FY/3qCNmZMBApR19cdQj43/NM9VkrNAis=
+github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
+github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc=
+github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
+github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA=
+github.com/prometheus/client_golang v0.0.0-20180209125602-c332b6f63c06/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
+github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
+github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
+github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
+github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g=
+github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
+github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
+github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
+github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/common v0.0.0-20180110214958-89604d197083/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
+github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
+github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
+github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
+github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc=
+github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
+github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
+github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
+github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
+github.com/prometheus/procfs v0.0.0-20190522114515-bc1a522cf7b1/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
+github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
+github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
+github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
+github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
+github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
+github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
+github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
+github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
+github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
+github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
+github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
+github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
+github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4=
+github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
+github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo=
+github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
+github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
+github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
+github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
+github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
+github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
+github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
+github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
+github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
+github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
+github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
+github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
+github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
+github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
+github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
+github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
+github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
+github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
+github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
+github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
+github.com/stefanberger/go-pkcs11uri v0.0.0-20201008174630-78d3cae3a980/go.mod h1:AO3tvPzVZ/ayst6UlUKUv6rcPQInYe3IknH3jYhAKu8=
+github.com/stretchr/objx v0.0.0-20180129172003-8a3f7159479f/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
+github.com/stretchr/testify v0.0.0-20180303142811-b89eecf5ca5d/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
+github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
+github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
+github.com/tchap/go-patricia v2.2.6+incompatible/go.mod h1:bmLyhP68RS6kStMGxByiQ23RP/odRBOTVjwp2cDyi6I=
+github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
+github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
+github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
+github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
+github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
+github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
+github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
+github.com/vishvananda/netlink v0.0.0-20181108222139-023a6dafdcdf/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk=
+github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE=
+github.com/vishvananda/netlink v1.1.1-0.20201029203352-d40f9887b852/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho=
+github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI=
+github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU=
+github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
+github.com/willf/bitset v1.1.11-0.20200630133818-d5bec3311243/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
+github.com/willf/bitset v1.1.11/go.mod h1:83CECat5yLh5zVOf4P1ErAgKA5UDvKtgyUABdr3+MjI=
+github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
+github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
+github.com/xeipuuv/gojsonschema v0.0.0-20180618132009-1d523034197f/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs=
+github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
+github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
-go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
-go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
+github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs=
+github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA=
+github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg=
+go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
+go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
+go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
+go.etcd.io/etcd v0.5.0-alpha.5.0.20200910180754-dd1b699fc489/go.mod h1:yVHk9ub3CSBatqGNg7GRmsnfLWtoW60w4eDYfh7vHDg=
+go.mozilla.org/pkcs7 v0.0.0-20200128120323-432b2356ecb1/go.mod h1:SNgMg+EgDFwmvSmLRTNKC5fegJjB7v23qTQ0XLGUNHk=
+go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
+go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
+go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
+go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
+go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
+go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
+go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
+go.uber.org/atomic v1.8.0 h1:CUhrE4N1rqSE6FM9ecihEjRkLQu8cDfgDyoOs83mEY4=
+go.uber.org/atomic v1.8.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
+go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
+go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
+golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20181009213950-7c1a557ab941/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210317152858-513c2a44f670/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
-golang.org/x/crypto v0.0.0-20210506145944-38f3c27a63bf h1:B2n+Zi5QeYRDAEodEu72OS36gmTWjgpXr2+cWcBW90o=
-golang.org/x/crypto v0.0.0-20210506145944-38f3c27a63bf/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
+golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
+golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e h1:gsTQYXdTw2Gq7RBsWvlQ91b+aEQ6bXFUngBGuR8sPpI=
+golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
+golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
+golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
+golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
+golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
+golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
+golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
+golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
+golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
+golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
+golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
+golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
+golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
+golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
+golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
+golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
+golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
+golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
+golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
+golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
+golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
-golang.org/x/net v0.0.0-20210508051633-16afe75a6701/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.0.0-20210510120150-4163338589ed h1:p9UgmWI9wKpfYmgaV/IZKGdXc5qEK45tDwwwDyjS26I=
-golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20210614182718-04defd469f4e h1:XpT3nA5TvE525Ne3hInMh6+GETgn27Zfm9dxsThnX2Q=
+golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190514135907-3a4b5fb9f71f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190522044717-8097e1b27ff5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190812073006-9eafafc0a87e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191210023423-ac6580df4449/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191224085550-c709ea063b76/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200120151820-655fe14d7479/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200817155316-9781c653f443/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200916030750-2334cc1a136f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200922070232-aee5d888a860/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201117170446-d9b008d0a637/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201202213521-69691e467435/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210507161434-a76c4d0a0096 h1:5PbJGn5Sp3GEUjJ61aYbUP6RIo3Z3r2E4Tv9y2z8UHo=
-golang.org/x/sys v0.0.0-20210507161434-a76c4d0a0096/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I=
+golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba h1:O8mE0/t419eoIwhTFpKVkHiTs/Igowgfkj25AcZrtiE=
-golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20210611083556-38a9dc6acbc6 h1:Vv0JUPWTyeqUq42B2WJ1FeIDjjvGKoA2Ss+Ts0lAVbs=
+golang.org/x/time v0.0.0-20210611083556-38a9dc6acbc6/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -166,18 +839,65 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8T
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+google.golang.org/api v0.0.0-20160322025152-9bf6e6e569ff/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
+google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
+google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
+google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
+google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
+google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
+google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
+google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
+google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
+google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
+google.golang.org/cloud v0.0.0-20151119220103-975617b05ea8/go.mod h1:0H1ncTHf11KCFhTc/+EFRbzSCOZx+VUbRMk55Yv5MYk=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190522204451-c2c4e71fbf69/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s=
+google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
-google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY=
+google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
+google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200117163144-32f20d992d24/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
+google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
+google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a h1:pOwg4OoaRYScjmR4LlLgdtnyoHYTSAVhhqe5uPdpII8=
+google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
+google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
+google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
+google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
+google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
+google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
+google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
-google.golang.org/grpc v1.36.0 h1:o1bcQ6imQMIOpdrO3SWf2z5RV72WbDwdXuK0MDlc8As=
+google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
+google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
+google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
+google.golang.org/grpc v1.39.0 h1:Klz8I9kdtkIN6EpHHUOMLCYhTn/2WAe5a0s1hcBkdTI=
+google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
@@ -186,17 +906,81 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
-gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
+gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
+gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20141024133853-64131543e789/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
+gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
+gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
+gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
+gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo=
+gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
+gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
+gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
+gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
+gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
+gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
+gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
+gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
+gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0=
gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
+honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
+k8s.io/api v0.20.1/go.mod h1:KqwcCVogGxQY3nBlRpwt+wpAMF/KjaCc7RpywacvqUo=
+k8s.io/api v0.20.4/go.mod h1:++lNL1AJMkDymriNniQsWRkMDzRaX2Y/POTUi8yvqYQ=
+k8s.io/api v0.20.6/go.mod h1:X9e8Qag6JV/bL5G6bU8sdVRltWKmdHsFUGS3eVndqE8=
+k8s.io/apimachinery v0.20.1/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU=
+k8s.io/apimachinery v0.20.4/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU=
+k8s.io/apimachinery v0.20.6/go.mod h1:ejZXtW1Ra6V1O5H8xPBGz+T3+4gfkTCeExAHKU57MAc=
+k8s.io/apiserver v0.20.1/go.mod h1:ro5QHeQkgMS7ZGpvf4tSMx6bBOgPfE+f52KwvXfScaU=
+k8s.io/apiserver v0.20.4/go.mod h1:Mc80thBKOyy7tbvFtB4kJv1kbdD0eIH8k8vianJcbFM=
+k8s.io/apiserver v0.20.6/go.mod h1:QIJXNt6i6JB+0YQRNcS0hdRHJlMhflFmsBDeSgT1r8Q=
+k8s.io/client-go v0.20.1/go.mod h1:/zcHdt1TeWSd5HoUe6elJmHSQ6uLLgp4bIJHVEuy+/Y=
+k8s.io/client-go v0.20.4/go.mod h1:LiMv25ND1gLUdBeYxBIwKpkSC5IsozMMmOOeSJboP+k=
+k8s.io/client-go v0.20.6/go.mod h1:nNQMnOvEUEsOzRRFIIkdmYOjAZrC8bgq0ExboWSU1I0=
+k8s.io/component-base v0.20.1/go.mod h1:guxkoJnNoh8LNrbtiQOlyp2Y2XFCZQmrcg2n/DeYNLk=
+k8s.io/component-base v0.20.4/go.mod h1:t4p9EdiagbVCJKrQ1RsA5/V4rFQNDfRlevJajlGwgjI=
+k8s.io/component-base v0.20.6/go.mod h1:6f1MPBAeI+mvuts3sIdtpjljHWBQ2cIy38oBIWMYnrM=
+k8s.io/cri-api v0.17.3/go.mod h1:X1sbHmuXhwaHs9xxYffLqJogVsnI+f6cPRcgPel7ywM=
+k8s.io/cri-api v0.20.1/go.mod h1:2JRbKt+BFLTjtrILYVqQK5jqhI+XNdF6UiGMgczeBCI=
+k8s.io/cri-api v0.20.4/go.mod h1:2JRbKt+BFLTjtrILYVqQK5jqhI+XNdF6UiGMgczeBCI=
+k8s.io/cri-api v0.20.6/go.mod h1:ew44AjNXwyn1s0U4xCKGodU7J1HzBeZ1MpGrpa5r8Yc=
+k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
+k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
+k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
+k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM=
+k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk=
+k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
+rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
+rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
+rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
+sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.14/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg=
+sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.15/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg=
+sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
+sigs.k8s.io/structured-merge-diff/v4 v4.0.3/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
+sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
+sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
diff --git a/test/snell_test.go b/test/snell_test.go
index bc8b47aa7..f9cd610c0 100644
--- a/test/snell_test.go
+++ b/test/snell_test.go
@@ -119,3 +119,40 @@ func TestClash_Snell(t *testing.T) {
time.Sleep(waitTime)
testSuit(t, proxy)
}
+
+func Benchmark_Snell(b *testing.B) {
+ cfg := &container.Config{
+ Image: ImageSnell,
+ ExposedPorts: defaultExposedPorts,
+ Cmd: []string{"-c", "/config.conf"},
+ }
+ hostCfg := &container.HostConfig{
+ PortBindings: defaultPortBindings,
+ Binds: []string{fmt.Sprintf("%s:/config.conf", C.Path.Resolve("snell-http.conf"))},
+ }
+
+ id, err := startContainer(cfg, hostCfg, "snell-http")
+ if err != nil {
+ assert.FailNow(b, err.Error())
+ }
+
+ b.Cleanup(func() {
+ cleanContainer(id)
+ })
+
+ proxy, err := outbound.NewSnell(outbound.SnellOption{
+ Name: "snell",
+ Server: localIP.String(),
+ Port: 10002,
+ Psk: "password",
+ ObfsOpts: map[string]interface{}{
+ "mode": "http",
+ },
+ })
+ if err != nil {
+ assert.FailNow(b, err.Error())
+ }
+
+ time.Sleep(waitTime)
+ benchmarkProxy(b, proxy)
+}
diff --git a/test/ss_test.go b/test/ss_test.go
index ea33445c5..caac90337 100644
--- a/test/ss_test.go
+++ b/test/ss_test.go
@@ -170,3 +170,38 @@ func TestClash_ShadowsocksV2RayPlugin(t *testing.T) {
time.Sleep(waitTime)
testSuit(t, proxy)
}
+
+func Benchmark_Shadowsocks(b *testing.B) {
+ cfg := &container.Config{
+ Image: ImageShadowsocks,
+ Env: []string{"SS_MODULE=ss-server", "SS_CONFIG=-s 0.0.0.0 -u -v -p 10002 -m chacha20-ietf-poly1305 -k FzcLbKs2dY9mhL"},
+ ExposedPorts: defaultExposedPorts,
+ }
+ hostCfg := &container.HostConfig{
+ PortBindings: defaultPortBindings,
+ }
+
+ id, err := startContainer(cfg, hostCfg, "ss")
+ if err != nil {
+ assert.FailNow(b, err.Error())
+ }
+
+ b.Cleanup(func() {
+ cleanContainer(id)
+ })
+
+ proxy, err := outbound.NewShadowSocks(outbound.ShadowSocksOption{
+ Name: "ss",
+ Server: localIP.String(),
+ Port: 10002,
+ Password: "FzcLbKs2dY9mhL",
+ Cipher: "chacha20-ietf-poly1305",
+ UDP: true,
+ })
+ if err != nil {
+ assert.FailNow(b, err.Error())
+ }
+
+ time.Sleep(waitTime)
+ benchmarkProxy(b, proxy)
+}
diff --git a/test/trojan_test.go b/test/trojan_test.go
index 236b5af1e..a57dab99f 100644
--- a/test/trojan_test.go
+++ b/test/trojan_test.go
@@ -92,3 +92,43 @@ func TestClash_TrojanGrpc(t *testing.T) {
time.Sleep(waitTime)
testSuit(t, proxy)
}
+
+func Benchmark_Trojan(b *testing.B) {
+ cfg := &container.Config{
+ Image: ImageTrojan,
+ ExposedPorts: defaultExposedPorts,
+ }
+ hostCfg := &container.HostConfig{
+ PortBindings: defaultPortBindings,
+ Binds: []string{
+ fmt.Sprintf("%s:/config/config.json", C.Path.Resolve("trojan.json")),
+ fmt.Sprintf("%s:/path/to/certificate.crt", C.Path.Resolve("example.org.pem")),
+ fmt.Sprintf("%s:/path/to/private.key", C.Path.Resolve("example.org-key.pem")),
+ },
+ }
+
+ id, err := startContainer(cfg, hostCfg, "trojan")
+ if err != nil {
+ assert.FailNow(b, err.Error())
+ }
+
+ b.Cleanup(func() {
+ cleanContainer(id)
+ })
+
+ proxy, err := outbound.NewTrojan(outbound.TrojanOption{
+ Name: "trojan",
+ Server: localIP.String(),
+ Port: 10002,
+ Password: "password",
+ SNI: "example.org",
+ SkipCertVerify: true,
+ UDP: true,
+ })
+ if err != nil {
+ assert.FailNow(b, err.Error())
+ }
+
+ time.Sleep(waitTime)
+ benchmarkProxy(b, proxy)
+}
diff --git a/test/util_test.go b/test/util_darwin_test.go
similarity index 100%
rename from test/util_test.go
rename to test/util_darwin_test.go
diff --git a/test/util_other_test.go b/test/util_other_test.go
new file mode 100644
index 000000000..e325bd8ba
--- /dev/null
+++ b/test/util_other_test.go
@@ -0,0 +1,12 @@
+// +build !darwin
+
+package main
+
+import (
+ "errors"
+ "net"
+)
+
+func defaultRouteIP() (net.IP, error) {
+ return nil, errors.New("not supported")
+}
diff --git a/test/vmess_test.go b/test/vmess_test.go
index 92cb300e2..bdc5ad9e0 100644
--- a/test/vmess_test.go
+++ b/test/vmess_test.go
@@ -345,3 +345,41 @@ func TestClash_VmessGrpc(t *testing.T) {
time.Sleep(waitTime)
testSuit(t, proxy)
}
+
+func Benchmark_Vmess(b *testing.B) {
+ configPath := C.Path.Resolve("vmess.json")
+
+ cfg := &container.Config{
+ Image: ImageVmess,
+ ExposedPorts: defaultExposedPorts,
+ }
+ hostCfg := &container.HostConfig{
+ PortBindings: defaultPortBindings,
+ Binds: []string{fmt.Sprintf("%s:/etc/v2ray/config.json", configPath)},
+ }
+
+ id, err := startContainer(cfg, hostCfg, "vmess")
+ if err != nil {
+ assert.FailNow(b, err.Error())
+ }
+
+ b.Cleanup(func() {
+ cleanContainer(id)
+ })
+
+ proxy, err := outbound.NewVmess(outbound.VmessOption{
+ Name: "vmess",
+ Server: localIP.String(),
+ Port: 10002,
+ UUID: "b831381d-6324-4d53-ad4f-8cda48b30811",
+ Cipher: "auto",
+ AlterID: 32,
+ UDP: true,
+ })
+ if err != nil {
+ assert.FailNow(b, err.Error())
+ }
+
+ time.Sleep(waitTime)
+ benchmarkProxy(b, proxy)
+}
From 44872300e94698428e7e4bacf8255b09042cb40a Mon Sep 17 00:00:00 2001
From: Dreamacro <8615343+Dreamacro@users.noreply.github.com>
Date: Sun, 18 Jul 2021 17:37:23 +0800
Subject: [PATCH 23/96] Test: ss use aes-256-gcm and vmess-aead for benchmark
---
test/ss_test.go | 4 ++--
test/vmess_test.go | 6 +++---
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/test/ss_test.go b/test/ss_test.go
index caac90337..7cba7efd9 100644
--- a/test/ss_test.go
+++ b/test/ss_test.go
@@ -174,7 +174,7 @@ func TestClash_ShadowsocksV2RayPlugin(t *testing.T) {
func Benchmark_Shadowsocks(b *testing.B) {
cfg := &container.Config{
Image: ImageShadowsocks,
- Env: []string{"SS_MODULE=ss-server", "SS_CONFIG=-s 0.0.0.0 -u -v -p 10002 -m chacha20-ietf-poly1305 -k FzcLbKs2dY9mhL"},
+ Env: []string{"SS_MODULE=ss-server", "SS_CONFIG=-s 0.0.0.0 -u -v -p 10002 -m aes-256-gcm -k FzcLbKs2dY9mhL"},
ExposedPorts: defaultExposedPorts,
}
hostCfg := &container.HostConfig{
@@ -195,7 +195,7 @@ func Benchmark_Shadowsocks(b *testing.B) {
Server: localIP.String(),
Port: 10002,
Password: "FzcLbKs2dY9mhL",
- Cipher: "chacha20-ietf-poly1305",
+ Cipher: "aes-256-gcm",
UDP: true,
})
if err != nil {
diff --git a/test/vmess_test.go b/test/vmess_test.go
index bdc5ad9e0..de3b2ba6a 100644
--- a/test/vmess_test.go
+++ b/test/vmess_test.go
@@ -347,7 +347,7 @@ func TestClash_VmessGrpc(t *testing.T) {
}
func Benchmark_Vmess(b *testing.B) {
- configPath := C.Path.Resolve("vmess.json")
+ configPath := C.Path.Resolve("vmess-aead.json")
cfg := &container.Config{
Image: ImageVmess,
@@ -358,7 +358,7 @@ func Benchmark_Vmess(b *testing.B) {
Binds: []string{fmt.Sprintf("%s:/etc/v2ray/config.json", configPath)},
}
- id, err := startContainer(cfg, hostCfg, "vmess")
+ id, err := startContainer(cfg, hostCfg, "vmess-aead")
if err != nil {
assert.FailNow(b, err.Error())
}
@@ -373,7 +373,7 @@ func Benchmark_Vmess(b *testing.B) {
Port: 10002,
UUID: "b831381d-6324-4d53-ad4f-8cda48b30811",
Cipher: "auto",
- AlterID: 32,
+ AlterID: 0,
UDP: true,
})
if err != nil {
From c2f3111922fcc5de65273d4fbe2493de6000cb17 Mon Sep 17 00:00:00 2001
From: Dreamacro <8615343+Dreamacro@users.noreply.github.com>
Date: Sun, 18 Jul 2021 19:26:51 +0800
Subject: [PATCH 24/96] Test: add direct benchmark
---
test/clash_test.go | 8 +++++++-
test/docker_test.go | 4 ++--
2 files changed, 9 insertions(+), 3 deletions(-)
diff --git a/test/clash_test.go b/test/clash_test.go
index 97f6648b1..7d373bbd5 100644
--- a/test/clash_test.go
+++ b/test/clash_test.go
@@ -15,6 +15,7 @@ import (
"testing"
"time"
+ "github.com/Dreamacro/clash/adapter/outbound"
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/hub/executor"
"github.com/Dreamacro/clash/transport/socks5"
@@ -70,7 +71,7 @@ func init() {
}
}
- c, err := client.NewClientWithOpts(client.FromEnv)
+ c, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
if err != nil {
panic(err)
}
@@ -668,3 +669,8 @@ log-level: silent
time.Sleep(waitTime)
testPingPongWithSocksPort(t, 10000)
}
+
+func Benchmark_Direct(b *testing.B) {
+ proxy := outbound.NewDirect()
+ benchmarkProxy(b, proxy)
+}
diff --git a/test/docker_test.go b/test/docker_test.go
index ce4c2de47..12c427b18 100644
--- a/test/docker_test.go
+++ b/test/docker_test.go
@@ -11,7 +11,7 @@ import (
var isDarwin = false
func startContainer(cfg *container.Config, hostCfg *container.HostConfig, name string) (string, error) {
- c, err := client.NewClientWithOpts(client.FromEnv)
+ c, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
if err != nil {
return "", err
}
@@ -34,7 +34,7 @@ func startContainer(cfg *container.Config, hostCfg *container.HostConfig, name s
}
func cleanContainer(id string) error {
- c, err := client.NewClientWithOpts(client.FromEnv)
+ c, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
if err != nil {
return err
}
From 247dd84970f00f2e1f43fac3b73cb710ff4f5a5d Mon Sep 17 00:00:00 2001
From: ayanamist
Date: Mon, 19 Jul 2021 14:07:51 +0800
Subject: [PATCH 25/96] Chore: logging real listen port (#1492)
---
hub/route/server.go | 12 +++++++++---
listener/http/server.go | 4 +---
listener/mixed/mixed.go | 8 +++++---
listener/redir/tcp.go | 7 ++++---
listener/socks/tcp.go | 7 ++++---
listener/socks/udp.go | 7 ++++---
listener/tproxy/tproxy.go | 4 +---
listener/tproxy/udp.go | 7 ++++---
8 files changed, 32 insertions(+), 24 deletions(-)
diff --git a/hub/route/server.go b/hub/route/server.go
index 98dc3588d..e01696bed 100644
--- a/hub/route/server.go
+++ b/hub/route/server.go
@@ -3,6 +3,7 @@ package route
import (
"bytes"
"encoding/json"
+ "net"
"net/http"
"strings"
"time"
@@ -81,10 +82,15 @@ func Start(addr string, secret string) {
})
}
- log.Infoln("RESTful API listening at: %s", addr)
- err := http.ListenAndServe(addr, r)
+ l, err := net.Listen("tcp", addr)
if err != nil {
- log.Errorln("External controller error: %s", err.Error())
+ log.Errorln("External controller listen error: %s", err)
+ return
+ }
+ serverAddr = l.Addr().String()
+ log.Infoln("RESTful API listening at: %s", serverAddr)
+ if err = http.Serve(l, r); err != nil {
+ log.Errorln("External controller serve error: %s", err)
}
}
diff --git a/listener/http/server.go b/listener/http/server.go
index ed8383710..6c5a7f6a4 100644
--- a/listener/http/server.go
+++ b/listener/http/server.go
@@ -10,7 +10,6 @@ import (
type Listener struct {
listener net.Listener
- address string
closed bool
}
@@ -31,7 +30,6 @@ func NewWithAuthenticate(addr string, in chan<- C.ConnContext, authenticate bool
hl := &Listener{
listener: l,
- address: addr,
}
go func() {
for {
@@ -55,5 +53,5 @@ func (l *Listener) Close() {
}
func (l *Listener) Address() string {
- return l.address
+ return l.listener.Addr().String()
}
diff --git a/listener/mixed/mixed.go b/listener/mixed/mixed.go
index 7d89e3c8d..97be69f0b 100644
--- a/listener/mixed/mixed.go
+++ b/listener/mixed/mixed.go
@@ -15,7 +15,6 @@ import (
type Listener struct {
listener net.Listener
- address string
closed bool
cache *cache.Cache
}
@@ -26,7 +25,10 @@ func New(addr string, in chan<- C.ConnContext) (*Listener, error) {
return nil, err
}
- ml := &Listener{l, addr, false, cache.New(30 * time.Second)}
+ ml := &Listener{
+ listener: l,
+ cache: cache.New(30 * time.Second),
+ }
go func() {
for {
c, err := ml.listener.Accept()
@@ -49,7 +51,7 @@ func (l *Listener) Close() {
}
func (l *Listener) Address() string {
- return l.address
+ return l.listener.Addr().String()
}
func handleConn(conn net.Conn, in chan<- C.ConnContext, cache *cache.Cache) {
diff --git a/listener/redir/tcp.go b/listener/redir/tcp.go
index 372688409..f7160eb01 100644
--- a/listener/redir/tcp.go
+++ b/listener/redir/tcp.go
@@ -9,7 +9,6 @@ import (
type Listener struct {
listener net.Listener
- address string
closed bool
}
@@ -18,7 +17,9 @@ func New(addr string, in chan<- C.ConnContext) (*Listener, error) {
if err != nil {
return nil, err
}
- rl := &Listener{l, addr, false}
+ rl := &Listener{
+ listener: l,
+ }
go func() {
for {
@@ -42,7 +43,7 @@ func (l *Listener) Close() {
}
func (l *Listener) Address() string {
- return l.address
+ return l.listener.Addr().String()
}
func handleRedir(conn net.Conn, in chan<- C.ConnContext) {
diff --git a/listener/socks/tcp.go b/listener/socks/tcp.go
index 60da0e264..587af2213 100644
--- a/listener/socks/tcp.go
+++ b/listener/socks/tcp.go
@@ -15,7 +15,6 @@ import (
type Listener struct {
listener net.Listener
- address string
closed bool
}
@@ -25,7 +24,9 @@ func New(addr string, in chan<- C.ConnContext) (*Listener, error) {
return nil, err
}
- sl := &Listener{l, addr, false}
+ sl := &Listener{
+ listener: l,
+ }
go func() {
for {
c, err := l.Accept()
@@ -48,7 +49,7 @@ func (l *Listener) Close() {
}
func (l *Listener) Address() string {
- return l.address
+ return l.listener.Addr().String()
}
func handleSocks(conn net.Conn, in chan<- C.ConnContext) {
diff --git a/listener/socks/udp.go b/listener/socks/udp.go
index b98ae897a..5de0a0bf3 100644
--- a/listener/socks/udp.go
+++ b/listener/socks/udp.go
@@ -13,7 +13,6 @@ import (
type UDPListener struct {
packetConn net.PacketConn
- address string
closed bool
}
@@ -27,7 +26,9 @@ func NewUDP(addr string, in chan<- *inbound.PacketAdapter) (*UDPListener, error)
log.Warnln("Failed to Reuse UDP Address: %s", err)
}
- sl := &UDPListener{l, addr, false}
+ sl := &UDPListener{
+ packetConn: l,
+ }
go func() {
for {
buf := pool.Get(pool.RelayBufferSize)
@@ -52,7 +53,7 @@ func (l *UDPListener) Close() error {
}
func (l *UDPListener) Address() string {
- return l.address
+ return l.packetConn.LocalAddr().String()
}
func handleSocksUDP(pc net.PacketConn, in chan<- *inbound.PacketAdapter, buf []byte, addr net.Addr) {
diff --git a/listener/tproxy/tproxy.go b/listener/tproxy/tproxy.go
index 142336fe8..87f2d7d67 100644
--- a/listener/tproxy/tproxy.go
+++ b/listener/tproxy/tproxy.go
@@ -10,7 +10,6 @@ import (
type Listener struct {
listener net.Listener
- address string
closed bool
}
@@ -33,7 +32,6 @@ func New(addr string, in chan<- C.ConnContext) (*Listener, error) {
rl := &Listener{
listener: l,
- address: addr,
}
go func() {
@@ -58,7 +56,7 @@ func (l *Listener) Close() {
}
func (l *Listener) Address() string {
- return l.address
+ return l.listener.Addr().String()
}
func (l *Listener) handleTProxy(conn net.Conn, in chan<- C.ConnContext) {
diff --git a/listener/tproxy/udp.go b/listener/tproxy/udp.go
index 20c2e0836..6f9de6f54 100644
--- a/listener/tproxy/udp.go
+++ b/listener/tproxy/udp.go
@@ -11,7 +11,6 @@ import (
type UDPListener struct {
packetConn net.PacketConn
- address string
closed bool
}
@@ -21,7 +20,9 @@ func NewUDP(addr string, in chan<- *inbound.PacketAdapter) (*UDPListener, error)
return nil, err
}
- rl := &UDPListener{l, addr, false}
+ rl := &UDPListener{
+ packetConn: l,
+ }
c := l.(*net.UDPConn)
@@ -65,7 +66,7 @@ func (l *UDPListener) Close() error {
}
func (l *UDPListener) Address() string {
- return l.address
+ return l.packetConn.LocalAddr().String()
}
func handlePacketConn(pc net.PacketConn, in chan<- *inbound.PacketAdapter, buf []byte, lAddr *net.UDPAddr, rAddr *net.UDPAddr) {
From 53e17a916bb08a042b610b256bf640327895bfa9 Mon Sep 17 00:00:00 2001
From: ayanamist
Date: Mon, 19 Jul 2021 15:31:38 +0800
Subject: [PATCH 26/96] Chore: logging remote port on request (#1494)
---
adapter/outbound/direct.go | 4 +---
tunnel/tunnel.go | 24 ++++++++++++------------
2 files changed, 13 insertions(+), 15 deletions(-)
diff --git a/adapter/outbound/direct.go b/adapter/outbound/direct.go
index 5b4a710fd..83ea22eb8 100644
--- a/adapter/outbound/direct.go
+++ b/adapter/outbound/direct.go
@@ -14,9 +14,7 @@ type Direct struct {
// DialContext implements C.ProxyAdapter
func (d *Direct) DialContext(ctx context.Context, metadata *C.Metadata) (C.Conn, error) {
- address := net.JoinHostPort(metadata.String(), metadata.DstPort)
-
- c, err := dialer.DialContext(ctx, "tcp", address)
+ c, err := dialer.DialContext(ctx, "tcp", metadata.RemoteAddress())
if err != nil {
return nil, err
}
diff --git a/tunnel/tunnel.go b/tunnel/tunnel.go
index 0ec36d3f1..2a35f0960 100644
--- a/tunnel/tunnel.go
+++ b/tunnel/tunnel.go
@@ -219,9 +219,9 @@ func handleUDPConn(packet *inbound.PacketAdapter) {
rawPc, err := proxy.DialUDP(metadata)
if err != nil {
if rule == nil {
- log.Warnln("[UDP] dial %s to %s error: %s", proxy.Name(), metadata.String(), err.Error())
+ log.Warnln("[UDP] dial %s to %s error: %s", proxy.Name(), metadata.RemoteAddress(), err.Error())
} else {
- log.Warnln("[UDP] dial %s (match %s/%s) to %s error: %s", proxy.Name(), rule.RuleType().String(), rule.Payload(), metadata.String(), err.Error())
+ log.Warnln("[UDP] dial %s (match %s/%s) to %s error: %s", proxy.Name(), rule.RuleType().String(), rule.Payload(), metadata.RemoteAddress(), err.Error())
}
return
}
@@ -230,13 +230,13 @@ func handleUDPConn(packet *inbound.PacketAdapter) {
switch true {
case rule != nil:
- log.Infoln("[UDP] %s --> %v match %s(%s) using %s", metadata.SourceAddress(), metadata.String(), rule.RuleType().String(), rule.Payload(), rawPc.Chains().String())
+ log.Infoln("[UDP] %s --> %s match %s(%s) using %s", metadata.SourceAddress(), metadata.RemoteAddress(), rule.RuleType().String(), rule.Payload(), rawPc.Chains().String())
case mode == Global:
- log.Infoln("[UDP] %s --> %v using GLOBAL", metadata.SourceAddress(), metadata.String())
+ log.Infoln("[UDP] %s --> %s using GLOBAL", metadata.SourceAddress(), metadata.RemoteAddress())
case mode == Direct:
- log.Infoln("[UDP] %s --> %v using DIRECT", metadata.SourceAddress(), metadata.String())
+ log.Infoln("[UDP] %s --> %s using DIRECT", metadata.SourceAddress(), metadata.RemoteAddress())
default:
- log.Infoln("[UDP] %s --> %v doesn't match any rule using DIRECT", metadata.SourceAddress(), metadata.String())
+ log.Infoln("[UDP] %s --> %s doesn't match any rule using DIRECT", metadata.SourceAddress(), metadata.RemoteAddress())
}
go handleUDPToLocal(packet.UDPPacket, pc, key, fAddr)
@@ -269,9 +269,9 @@ func handleTCPConn(ctx C.ConnContext) {
remoteConn, err := proxy.Dial(metadata)
if err != nil {
if rule == nil {
- log.Warnln("[TCP] dial %s to %s error: %s", proxy.Name(), metadata.String(), err.Error())
+ log.Warnln("[TCP] dial %s to %s error: %s", proxy.Name(), metadata.RemoteAddress(), err.Error())
} else {
- log.Warnln("[TCP] dial %s (match %s/%s) to %s error: %s", proxy.Name(), rule.RuleType().String(), rule.Payload(), metadata.String(), err.Error())
+ log.Warnln("[TCP] dial %s (match %s/%s) to %s error: %s", proxy.Name(), rule.RuleType().String(), rule.Payload(), metadata.RemoteAddress(), err.Error())
}
return
}
@@ -280,13 +280,13 @@ func handleTCPConn(ctx C.ConnContext) {
switch true {
case rule != nil:
- log.Infoln("[TCP] %s --> %v match %s(%s) using %s", metadata.SourceAddress(), metadata.String(), rule.RuleType().String(), rule.Payload(), remoteConn.Chains().String())
+ log.Infoln("[TCP] %s --> %s match %s(%s) using %s", metadata.SourceAddress(), metadata.RemoteAddress(), rule.RuleType().String(), rule.Payload(), remoteConn.Chains().String())
case mode == Global:
- log.Infoln("[TCP] %s --> %v using GLOBAL", metadata.SourceAddress(), metadata.String())
+ log.Infoln("[TCP] %s --> %s using GLOBAL", metadata.SourceAddress(), metadata.RemoteAddress())
case mode == Direct:
- log.Infoln("[TCP] %s --> %v using DIRECT", metadata.SourceAddress(), metadata.String())
+ log.Infoln("[TCP] %s --> %s using DIRECT", metadata.SourceAddress(), metadata.RemoteAddress())
default:
- log.Infoln("[TCP] %s --> %v doesn't match any rule using DIRECT", metadata.SourceAddress(), metadata.String())
+ log.Infoln("[TCP] %s --> %s doesn't match any rule using DIRECT", metadata.SourceAddress(), metadata.RemoteAddress())
}
handleSocket(ctx, remoteConn)
From 8d37220566c2c312658b903a7baff64ca0878d0a Mon Sep 17 00:00:00 2001
From: Dreamacro <8615343+Dreamacro@users.noreply.github.com>
Date: Wed, 21 Jul 2021 17:01:02 +0800
Subject: [PATCH 27/96] Fix: limit concurrency number of provider health check
---
adapter/adapter.go | 2 +
adapter/provider/healthcheck.go | 19 +++---
common/batch/batch.go | 111 ++++++++++++++++++++++++++++++++
common/batch/batch_test.go | 82 +++++++++++++++++++++++
4 files changed, 203 insertions(+), 11 deletions(-)
create mode 100644 common/batch/batch.go
create mode 100644 common/batch/batch_test.go
diff --git a/adapter/adapter.go b/adapter/adapter.go
index 787a45b13..526866a5c 100644
--- a/adapter/adapter.go
+++ b/adapter/adapter.go
@@ -136,6 +136,8 @@ func (p *Proxy) URLTest(ctx context.Context, url string) (t uint16, err error) {
return http.ErrUseLastResponse
},
}
+ defer client.CloseIdleConnections()
+
resp, err := client.Do(req)
if err != nil {
return
diff --git a/adapter/provider/healthcheck.go b/adapter/provider/healthcheck.go
index 98f934e42..636873d94 100644
--- a/adapter/provider/healthcheck.go
+++ b/adapter/provider/healthcheck.go
@@ -2,9 +2,9 @@ package provider
import (
"context"
- "sync"
"time"
+ "github.com/Dreamacro/clash/common/batch"
C "github.com/Dreamacro/clash/constant"
"go.uber.org/atomic"
@@ -60,19 +60,16 @@ func (hc *HealthCheck) touch() {
func (hc *HealthCheck) check() {
ctx, cancel := context.WithTimeout(context.Background(), defaultURLTestTimeout)
- wg := &sync.WaitGroup{}
+ defer cancel()
+ b, ctx := batch.WithContext(ctx, batch.WithConcurrencyNum(10))
for _, proxy := range hc.proxies {
- wg.Add(1)
-
- go func(p C.Proxy) {
- p.URLTest(ctx, hc.url)
- wg.Done()
- }(proxy)
+ p := proxy
+ b.Go(p.Name(), func() (interface{}, error) {
+ return p.URLTest(ctx, hc.url)
+ })
}
-
- wg.Wait()
- cancel()
+ b.Wait()
}
func (hc *HealthCheck) close() {
diff --git a/common/batch/batch.go b/common/batch/batch.go
new file mode 100644
index 000000000..7fbca4217
--- /dev/null
+++ b/common/batch/batch.go
@@ -0,0 +1,111 @@
+package batch
+
+import (
+ "context"
+ "sync"
+)
+
+type Option = func(b *Batch)
+
+type Result struct {
+ Value interface{}
+ Err error
+}
+
+type Error struct {
+ Key string
+ Err error
+}
+
+func WithConcurrencyNum(n int) Option {
+ return func(b *Batch) {
+ q := make(chan struct{}, n)
+ for i := 0; i < n; i++ {
+ q <- struct{}{}
+ }
+ b.queue = q
+ }
+}
+
+// Batch similar to errgroup, but can control the maximum number of concurrent
+type Batch struct {
+ result map[string]Result
+ queue chan struct{}
+ wg sync.WaitGroup
+ mux sync.Mutex
+ err *Error
+ once sync.Once
+ cancel func()
+}
+
+func (b *Batch) Go(key string, fn func() (interface{}, error)) {
+ b.wg.Add(1)
+ go func() {
+ defer b.wg.Done()
+ if b.queue != nil {
+ <-b.queue
+ defer func() {
+ b.queue <- struct{}{}
+ }()
+ }
+
+ value, err := fn()
+ if err != nil {
+ b.once.Do(func() {
+ b.err = &Error{key, err}
+ if b.cancel != nil {
+ b.cancel()
+ }
+ })
+ }
+
+ ret := Result{value, err}
+ b.mux.Lock()
+ defer b.mux.Unlock()
+ b.result[key] = ret
+ }()
+}
+
+func (b *Batch) Wait() *Error {
+ b.wg.Wait()
+ if b.cancel != nil {
+ b.cancel()
+ }
+ return b.err
+}
+
+func (b *Batch) WaitAndGetResult() (map[string]Result, *Error) {
+ err := b.Wait()
+ return b.Result(), err
+}
+
+func (b *Batch) Result() map[string]Result {
+ b.mux.Lock()
+ defer b.mux.Unlock()
+ copy := map[string]Result{}
+ for k, v := range b.result {
+ copy[k] = v
+ }
+ return copy
+}
+
+func New(opts ...Option) *Batch {
+ b := &Batch{
+ result: map[string]Result{},
+ }
+
+ for _, o := range opts {
+ o(b)
+ }
+
+ return b
+}
+
+func WithContext(ctx context.Context, opts ...Option) (*Batch, context.Context) {
+ ctx, cancel := context.WithCancel(ctx)
+
+ b := New(opts...)
+ b.cancel = cancel
+
+ return b, ctx
+}
diff --git a/common/batch/batch_test.go b/common/batch/batch_test.go
new file mode 100644
index 000000000..4fcdbe81c
--- /dev/null
+++ b/common/batch/batch_test.go
@@ -0,0 +1,82 @@
+package batch
+
+import (
+ "context"
+ "errors"
+ "strconv"
+ "testing"
+ "time"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestBatch(t *testing.T) {
+ b := New()
+
+ now := time.Now()
+ b.Go("foo", func() (interface{}, error) {
+ time.Sleep(time.Millisecond * 100)
+ return "foo", nil
+ })
+ b.Go("bar", func() (interface{}, error) {
+ time.Sleep(time.Millisecond * 150)
+ return "bar", nil
+ })
+ result, err := b.WaitAndGetResult()
+
+ assert.Nil(t, err)
+
+ duration := time.Since(now)
+ assert.Less(t, duration, time.Millisecond*200)
+ assert.Equal(t, 2, len(result))
+
+ for k, v := range result {
+ assert.NoError(t, v.Err)
+ assert.Equal(t, k, v.Value.(string))
+ }
+}
+
+func TestBatchWithConcurrencyNum(t *testing.T) {
+ b := New(
+ WithConcurrencyNum(3),
+ )
+
+ now := time.Now()
+ for i := 0; i < 7; i++ {
+ idx := i
+ b.Go(strconv.Itoa(idx), func() (interface{}, error) {
+ time.Sleep(time.Millisecond * 100)
+ return strconv.Itoa(idx), nil
+ })
+ }
+ result, _ := b.WaitAndGetResult()
+ duration := time.Since(now)
+ assert.Greater(t, duration, time.Millisecond*260)
+ assert.Equal(t, 7, len(result))
+
+ for k, v := range result {
+ assert.NoError(t, v.Err)
+ assert.Equal(t, k, v.Value.(string))
+ }
+}
+
+func TestBatchContext(t *testing.T) {
+ b, ctx := WithContext(context.Background())
+
+ b.Go("error", func() (interface{}, error) {
+ time.Sleep(time.Millisecond * 100)
+ return nil, errors.New("test error")
+ })
+
+ b.Go("ctx", func() (interface{}, error) {
+ <-ctx.Done()
+ return nil, ctx.Err()
+ })
+
+ result, err := b.WaitAndGetResult()
+
+ assert.NotNil(t, err)
+ assert.Equal(t, "error", err.Key)
+
+ assert.Equal(t, ctx.Err(), result["ctx"].Err)
+}
From aa9f8a39a3a620f9a4ec0a241308414695735b31 Mon Sep 17 00:00:00 2001
From: Dreamacro <8615343+Dreamacro@users.noreply.github.com>
Date: Wed, 21 Jul 2021 23:08:52 +0800
Subject: [PATCH 28/96] Fix: socks inbound packet typo
---
listener/socks/udp.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/listener/socks/udp.go b/listener/socks/udp.go
index 5de0a0bf3..ca75b2c8a 100644
--- a/listener/socks/udp.go
+++ b/listener/socks/udp.go
@@ -70,7 +70,7 @@ func handleSocksUDP(pc net.PacketConn, in chan<- *inbound.PacketAdapter, buf []b
bufRef: buf,
}
select {
- case in <- inbound.NewPacket(target, packet, C.TPROXY):
+ case in <- inbound.NewPacket(target, packet, C.SOCKS):
default:
}
}
From 507ba1606564cf061242be1d450c14277331c2be Mon Sep 17 00:00:00 2001
From: Dreamacro <8615343+Dreamacro@users.noreply.github.com>
Date: Wed, 21 Jul 2021 23:53:31 +0800
Subject: [PATCH 29/96] Fix: incorrect use batch
---
adapter/provider/healthcheck.go | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/adapter/provider/healthcheck.go b/adapter/provider/healthcheck.go
index 636873d94..4d2711a51 100644
--- a/adapter/provider/healthcheck.go
+++ b/adapter/provider/healthcheck.go
@@ -59,14 +59,14 @@ func (hc *HealthCheck) touch() {
}
func (hc *HealthCheck) check() {
- ctx, cancel := context.WithTimeout(context.Background(), defaultURLTestTimeout)
- defer cancel()
-
- b, ctx := batch.WithContext(ctx, batch.WithConcurrencyNum(10))
+ b := batch.New(batch.WithConcurrencyNum(10))
for _, proxy := range hc.proxies {
p := proxy
b.Go(p.Name(), func() (interface{}, error) {
- return p.URLTest(ctx, hc.url)
+ ctx, cancel := context.WithTimeout(context.Background(), defaultURLTestTimeout)
+ defer cancel()
+ p.URLTest(ctx, hc.url)
+ return nil, nil
})
}
b.Wait()
From b3a293ab078eb192001871be6fcb49e9749f20a7 Mon Sep 17 00:00:00 2001
From: Dreamacro <8615343+Dreamacro@users.noreply.github.com>
Date: Thu, 22 Jul 2021 00:01:11 +0800
Subject: [PATCH 30/96] Chore: benchmark explanation
---
test/README.md | 10 ++++++++++
test/clash_test.go | 5 +++--
2 files changed, 13 insertions(+), 2 deletions(-)
diff --git a/test/README.md b/test/README.md
index dec9999c2..823fc5446 100644
--- a/test/README.md
+++ b/test/README.md
@@ -47,3 +47,13 @@ Prerequisite
```
$ go test -p 1 -v
```
+
+benchmark (Linux)
+
+> Cannot represent the throughput of the protocol on your machine
+> but you can compare the corresponding throughput of the protocol on clash
+> (change chunkSize to measure the maximum throughput of clash on your machine)
+
+```
+$ go test -benchmem -run=^$ -bench .
+```
diff --git a/test/clash_test.go b/test/clash_test.go
index 7d373bbd5..366cc260b 100644
--- a/test/clash_test.go
+++ b/test/clash_test.go
@@ -636,7 +636,8 @@ func benchmarkProxy(b *testing.B, proxy C.ProxyAdapter) {
c.Close()
}()
- chunk := make([]byte, 1024)
+ chunkSize := int64(16 * 1024)
+ chunk := make([]byte, chunkSize)
conn, err := proxy.DialContext(context.Background(), &C.Metadata{
Host: localIP.String(),
DstPort: "10001",
@@ -646,7 +647,7 @@ func benchmarkProxy(b *testing.B, proxy C.ProxyAdapter) {
assert.FailNow(b, err.Error())
}
- b.SetBytes(1024)
+ b.SetBytes(chunkSize)
b.ResetTimer()
for i := 0; i < b.N; i++ {
if _, err := conn.Write(chunk); err != nil {
From 4578b2c82635ac76df26a8ab0bbf0fba4c24a851 Mon Sep 17 00:00:00 2001
From: duama <30264485+duament@users.noreply.github.com>
Date: Thu, 22 Jul 2021 18:06:03 +0800
Subject: [PATCH 31/96] Fix: remove Content-Length from CONNECT response
(#1502)
---
listener/http/proxy.go | 1 +
1 file changed, 1 insertion(+)
diff --git a/listener/http/proxy.go b/listener/http/proxy.go
index 12508ba3d..9ac95cb49 100644
--- a/listener/http/proxy.go
+++ b/listener/http/proxy.go
@@ -45,6 +45,7 @@ func HandleConn(c net.Conn, in chan<- C.ConnContext, cache *cache.Cache) {
if request.Method == http.MethodConnect {
resp = responseWith(200)
resp.Status = "Connection established"
+ resp.ContentLength = -1
if resp.Write(conn) != nil {
break // close connection
From 09697b7679e0d934d51ef1ee55192e236c2c02f1 Mon Sep 17 00:00:00 2001
From: Dreamacro <8615343+Dreamacro@users.noreply.github.com>
Date: Fri, 23 Jul 2021 00:30:23 +0800
Subject: [PATCH 32/96] Chore: adjust batch
---
adapter/provider/healthcheck.go | 2 +-
common/batch/batch.go | 12 +++---------
common/batch/batch_test.go | 7 ++++---
3 files changed, 8 insertions(+), 13 deletions(-)
diff --git a/adapter/provider/healthcheck.go b/adapter/provider/healthcheck.go
index 4d2711a51..f41a4788d 100644
--- a/adapter/provider/healthcheck.go
+++ b/adapter/provider/healthcheck.go
@@ -59,7 +59,7 @@ func (hc *HealthCheck) touch() {
}
func (hc *HealthCheck) check() {
- b := batch.New(batch.WithConcurrencyNum(10))
+ b, _ := batch.New(context.Background(), batch.WithConcurrencyNum(10))
for _, proxy := range hc.proxies {
p := proxy
b.Go(p.Name(), func() (interface{}, error) {
diff --git a/common/batch/batch.go b/common/batch/batch.go
index 7fbca4217..ce20ed612 100644
--- a/common/batch/batch.go
+++ b/common/batch/batch.go
@@ -89,7 +89,9 @@ func (b *Batch) Result() map[string]Result {
return copy
}
-func New(opts ...Option) *Batch {
+func New(ctx context.Context, opts ...Option) (*Batch, context.Context) {
+ ctx, cancel := context.WithCancel(ctx)
+
b := &Batch{
result: map[string]Result{},
}
@@ -98,14 +100,6 @@ func New(opts ...Option) *Batch {
o(b)
}
- return b
-}
-
-func WithContext(ctx context.Context, opts ...Option) (*Batch, context.Context) {
- ctx, cancel := context.WithCancel(ctx)
-
- b := New(opts...)
b.cancel = cancel
-
return b, ctx
}
diff --git a/common/batch/batch_test.go b/common/batch/batch_test.go
index 4fcdbe81c..9465dbad9 100644
--- a/common/batch/batch_test.go
+++ b/common/batch/batch_test.go
@@ -11,7 +11,7 @@ import (
)
func TestBatch(t *testing.T) {
- b := New()
+ b, _ := New(context.Background())
now := time.Now()
b.Go("foo", func() (interface{}, error) {
@@ -37,7 +37,8 @@ func TestBatch(t *testing.T) {
}
func TestBatchWithConcurrencyNum(t *testing.T) {
- b := New(
+ b, _ := New(
+ context.Background(),
WithConcurrencyNum(3),
)
@@ -61,7 +62,7 @@ func TestBatchWithConcurrencyNum(t *testing.T) {
}
func TestBatchContext(t *testing.T) {
- b, ctx := WithContext(context.Background())
+ b, ctx := New(context.Background())
b.Go("error", func() (interface{}, error) {
time.Sleep(time.Millisecond * 100)
From 37059969740315cd342967fe1bb29b07592a75e4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?x=E1=B4=8A=E1=B4=80s=E1=B4=8F=C9=B4=CA=9F=CA=8F=E1=B4=9C?=
Date: Tue, 27 Jul 2021 13:58:29 +0800
Subject: [PATCH 33/96] Chore: split SOCKS version inbound metadata type
(#1513)
---
constant/metadata.go | 7 +++++--
listener/socks/tcp.go | 4 ++--
listener/socks/udp.go | 2 +-
3 files changed, 8 insertions(+), 5 deletions(-)
diff --git a/constant/metadata.go b/constant/metadata.go
index 93ef406d2..9fff773b3 100644
--- a/constant/metadata.go
+++ b/constant/metadata.go
@@ -17,7 +17,8 @@ const (
HTTP Type = iota
HTTPCONNECT
- SOCKS
+ SOCKS4
+ SOCKS5
REDIR
TPROXY
)
@@ -43,7 +44,9 @@ func (t Type) String() string {
return "HTTP"
case HTTPCONNECT:
return "HTTP Connect"
- case SOCKS:
+ case SOCKS4:
+ return "Socks4"
+ case SOCKS5:
return "Socks5"
case REDIR:
return "Redir"
diff --git a/listener/socks/tcp.go b/listener/socks/tcp.go
index 587af2213..20e48f85c 100644
--- a/listener/socks/tcp.go
+++ b/listener/socks/tcp.go
@@ -79,7 +79,7 @@ func HandleSocks4(conn net.Conn, in chan<- C.ConnContext) {
if c, ok := conn.(*net.TCPConn); ok {
c.SetKeepAlive(true)
}
- in <- inbound.NewSocket(socks5.ParseAddr(addr), conn, C.SOCKS)
+ in <- inbound.NewSocket(socks5.ParseAddr(addr), conn, C.SOCKS4)
}
func HandleSocks5(conn net.Conn, in chan<- C.ConnContext) {
@@ -96,5 +96,5 @@ func HandleSocks5(conn net.Conn, in chan<- C.ConnContext) {
io.Copy(ioutil.Discard, conn)
return
}
- in <- inbound.NewSocket(target, conn, C.SOCKS)
+ in <- inbound.NewSocket(target, conn, C.SOCKS5)
}
diff --git a/listener/socks/udp.go b/listener/socks/udp.go
index ca75b2c8a..f822d76af 100644
--- a/listener/socks/udp.go
+++ b/listener/socks/udp.go
@@ -70,7 +70,7 @@ func handleSocksUDP(pc net.PacketConn, in chan<- *inbound.PacketAdapter, buf []b
bufRef: buf,
}
select {
- case in <- inbound.NewPacket(target, packet, C.SOCKS):
+ case in <- inbound.NewPacket(target, packet, C.SOCKS5):
default:
}
}
From 1bfebd0d037b7d7fc877351cba46cd8a8f4ad65b Mon Sep 17 00:00:00 2001
From: Dreamacro <8615343+Dreamacro@users.noreply.github.com>
Date: Sun, 1 Aug 2021 00:35:37 +0800
Subject: [PATCH 34/96] Fix: listener patch diff
---
constant/listener.go | 7 +++++++
listener/http/server.go | 27 ++++++++++++++++++---------
listener/listener.go | 36 ++++++++++++++++++------------------
listener/mixed/mixed.go | 29 +++++++++++++++++++----------
listener/redir/tcp.go | 27 ++++++++++++++++++---------
listener/socks/tcp.go | 27 ++++++++++++++++++---------
listener/socks/udp.go | 27 ++++++++++++++++++---------
listener/tproxy/tproxy.go | 39 ++++++++++++++++++++++++---------------
listener/tproxy/udp.go | 27 ++++++++++++++++++---------
9 files changed, 158 insertions(+), 88 deletions(-)
create mode 100644 constant/listener.go
diff --git a/constant/listener.go b/constant/listener.go
new file mode 100644
index 000000000..07782a9e0
--- /dev/null
+++ b/constant/listener.go
@@ -0,0 +1,7 @@
+package constant
+
+type Listener interface {
+ RawAddress() string
+ Address() string
+ Close() error
+}
diff --git a/listener/http/server.go b/listener/http/server.go
index 6c5a7f6a4..bfdd9f1b6 100644
--- a/listener/http/server.go
+++ b/listener/http/server.go
@@ -10,9 +10,26 @@ import (
type Listener struct {
listener net.Listener
+ addr string
closed bool
}
+// RawAddress implements C.Listener
+func (l *Listener) RawAddress() string {
+ return l.addr
+}
+
+// Address implements C.Listener
+func (l *Listener) Address() string {
+ return l.listener.Addr().String()
+}
+
+// Close implements C.Listener
+func (l *Listener) Close() error {
+ l.closed = true
+ return l.listener.Close()
+}
+
func New(addr string, in chan<- C.ConnContext) (*Listener, error) {
return NewWithAuthenticate(addr, in, true)
}
@@ -30,6 +47,7 @@ func NewWithAuthenticate(addr string, in chan<- C.ConnContext, authenticate bool
hl := &Listener{
listener: l,
+ addr: addr,
}
go func() {
for {
@@ -46,12 +64,3 @@ func NewWithAuthenticate(addr string, in chan<- C.ConnContext, authenticate bool
return hl, nil
}
-
-func (l *Listener) Close() {
- l.closed = true
- l.listener.Close()
-}
-
-func (l *Listener) Address() string {
- return l.listener.Addr().String()
-}
diff --git a/listener/listener.go b/listener/listener.go
index 5d0e8d7bf..f9fffdf45 100644
--- a/listener/listener.go
+++ b/listener/listener.go
@@ -20,15 +20,15 @@ var (
allowLan = false
bindAddress = "*"
- socksListener *socks.Listener
- socksUDPListener *socks.UDPListener
- httpListener *http.Listener
- redirListener *redir.Listener
- redirUDPListener *tproxy.UDPListener
- tproxyListener *tproxy.Listener
- tproxyUDPListener *tproxy.UDPListener
- mixedListener *mixed.Listener
- mixedUDPLister *socks.UDPListener
+ socksListener C.Listener
+ socksUDPListener C.Listener
+ httpListener C.Listener
+ redirListener C.Listener
+ redirUDPListener C.Listener
+ tproxyListener C.Listener
+ tproxyUDPListener C.Listener
+ mixedListener C.Listener
+ mixedUDPLister C.Listener
// lock for recreate function
socksMux sync.Mutex
@@ -69,7 +69,7 @@ func ReCreateHTTP(port int, tcpIn chan<- C.ConnContext) error {
addr := genAddr(bindAddress, port, allowLan)
if httpListener != nil {
- if httpListener.Address() == addr {
+ if httpListener.RawAddress() == addr {
return nil
}
httpListener.Close()
@@ -100,7 +100,7 @@ func ReCreateSocks(port int, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.P
shouldUDPIgnore := false
if socksListener != nil {
- if socksListener.Address() != addr {
+ if socksListener.RawAddress() != addr {
socksListener.Close()
socksListener = nil
} else {
@@ -109,7 +109,7 @@ func ReCreateSocks(port int, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.P
}
if socksUDPListener != nil {
- if socksUDPListener.Address() != addr {
+ if socksUDPListener.RawAddress() != addr {
socksUDPListener.Close()
socksUDPListener = nil
} else {
@@ -150,7 +150,7 @@ func ReCreateRedir(port int, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.P
addr := genAddr(bindAddress, port, allowLan)
if redirListener != nil {
- if redirListener.Address() == addr {
+ if redirListener.RawAddress() == addr {
return nil
}
redirListener.Close()
@@ -158,7 +158,7 @@ func ReCreateRedir(port int, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.P
}
if redirUDPListener != nil {
- if redirUDPListener.Address() == addr {
+ if redirUDPListener.RawAddress() == addr {
return nil
}
redirUDPListener.Close()
@@ -191,7 +191,7 @@ func ReCreateTProxy(port int, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.
addr := genAddr(bindAddress, port, allowLan)
if tproxyListener != nil {
- if tproxyListener.Address() == addr {
+ if tproxyListener.RawAddress() == addr {
return nil
}
tproxyListener.Close()
@@ -199,7 +199,7 @@ func ReCreateTProxy(port int, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.
}
if tproxyUDPListener != nil {
- if tproxyUDPListener.Address() == addr {
+ if tproxyUDPListener.RawAddress() == addr {
return nil
}
tproxyUDPListener.Close()
@@ -235,7 +235,7 @@ func ReCreateMixed(port int, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.P
shouldUDPIgnore := false
if mixedListener != nil {
- if mixedListener.Address() != addr {
+ if mixedListener.RawAddress() != addr {
mixedListener.Close()
mixedListener = nil
} else {
@@ -243,7 +243,7 @@ func ReCreateMixed(port int, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.P
}
}
if mixedUDPLister != nil {
- if mixedUDPLister.Address() != addr {
+ if mixedUDPLister.RawAddress() != addr {
mixedUDPLister.Close()
mixedUDPLister = nil
} else {
diff --git a/listener/mixed/mixed.go b/listener/mixed/mixed.go
index 97be69f0b..8fd4f990e 100644
--- a/listener/mixed/mixed.go
+++ b/listener/mixed/mixed.go
@@ -15,8 +15,25 @@ import (
type Listener struct {
listener net.Listener
- closed bool
+ addr string
cache *cache.Cache
+ closed bool
+}
+
+// RawAddress implements C.Listener
+func (l *Listener) RawAddress() string {
+ return l.addr
+}
+
+// Address implements C.Listener
+func (l *Listener) Address() string {
+ return l.listener.Addr().String()
+}
+
+// Close implements C.Listener
+func (l *Listener) Close() error {
+ l.closed = true
+ return l.listener.Close()
}
func New(addr string, in chan<- C.ConnContext) (*Listener, error) {
@@ -27,6 +44,7 @@ func New(addr string, in chan<- C.ConnContext) (*Listener, error) {
ml := &Listener{
listener: l,
+ addr: addr,
cache: cache.New(30 * time.Second),
}
go func() {
@@ -45,15 +63,6 @@ func New(addr string, in chan<- C.ConnContext) (*Listener, error) {
return ml, nil
}
-func (l *Listener) Close() {
- l.closed = true
- l.listener.Close()
-}
-
-func (l *Listener) Address() string {
- return l.listener.Addr().String()
-}
-
func handleConn(conn net.Conn, in chan<- C.ConnContext, cache *cache.Cache) {
bufConn := N.NewBufferedConn(conn)
head, err := bufConn.Peek(1)
diff --git a/listener/redir/tcp.go b/listener/redir/tcp.go
index f7160eb01..15c98a8f3 100644
--- a/listener/redir/tcp.go
+++ b/listener/redir/tcp.go
@@ -9,9 +9,26 @@ import (
type Listener struct {
listener net.Listener
+ addr string
closed bool
}
+// RawAddress implements C.Listener
+func (l *Listener) RawAddress() string {
+ return l.addr
+}
+
+// Address implements C.Listener
+func (l *Listener) Address() string {
+ return l.listener.Addr().String()
+}
+
+// Close implements C.Listener
+func (l *Listener) Close() error {
+ l.closed = true
+ return l.listener.Close()
+}
+
func New(addr string, in chan<- C.ConnContext) (*Listener, error) {
l, err := net.Listen("tcp", addr)
if err != nil {
@@ -19,6 +36,7 @@ func New(addr string, in chan<- C.ConnContext) (*Listener, error) {
}
rl := &Listener{
listener: l,
+ addr: addr,
}
go func() {
@@ -37,15 +55,6 @@ func New(addr string, in chan<- C.ConnContext) (*Listener, error) {
return rl, nil
}
-func (l *Listener) Close() {
- l.closed = true
- l.listener.Close()
-}
-
-func (l *Listener) Address() string {
- return l.listener.Addr().String()
-}
-
func handleRedir(conn net.Conn, in chan<- C.ConnContext) {
target, err := parserPacket(conn)
if err != nil {
diff --git a/listener/socks/tcp.go b/listener/socks/tcp.go
index 20e48f85c..49d0a1e31 100644
--- a/listener/socks/tcp.go
+++ b/listener/socks/tcp.go
@@ -15,9 +15,26 @@ import (
type Listener struct {
listener net.Listener
+ addr string
closed bool
}
+// RawAddress implements C.Listener
+func (l *Listener) RawAddress() string {
+ return l.addr
+}
+
+// Address implements C.Listener
+func (l *Listener) Address() string {
+ return l.listener.Addr().String()
+}
+
+// Close implements C.Listener
+func (l *Listener) Close() error {
+ l.closed = true
+ return l.listener.Close()
+}
+
func New(addr string, in chan<- C.ConnContext) (*Listener, error) {
l, err := net.Listen("tcp", addr)
if err != nil {
@@ -26,6 +43,7 @@ func New(addr string, in chan<- C.ConnContext) (*Listener, error) {
sl := &Listener{
listener: l,
+ addr: addr,
}
go func() {
for {
@@ -43,15 +61,6 @@ func New(addr string, in chan<- C.ConnContext) (*Listener, error) {
return sl, nil
}
-func (l *Listener) Close() {
- l.closed = true
- l.listener.Close()
-}
-
-func (l *Listener) Address() string {
- return l.listener.Addr().String()
-}
-
func handleSocks(conn net.Conn, in chan<- C.ConnContext) {
bufConn := N.NewBufferedConn(conn)
head, err := bufConn.Peek(1)
diff --git a/listener/socks/udp.go b/listener/socks/udp.go
index f822d76af..a2d215083 100644
--- a/listener/socks/udp.go
+++ b/listener/socks/udp.go
@@ -13,9 +13,26 @@ import (
type UDPListener struct {
packetConn net.PacketConn
+ addr string
closed bool
}
+// RawAddress implements C.Listener
+func (l *UDPListener) RawAddress() string {
+ return l.addr
+}
+
+// Address implements C.Listener
+func (l *UDPListener) Address() string {
+ return l.packetConn.LocalAddr().String()
+}
+
+// Close implements C.Listener
+func (l *UDPListener) Close() error {
+ l.closed = true
+ return l.packetConn.Close()
+}
+
func NewUDP(addr string, in chan<- *inbound.PacketAdapter) (*UDPListener, error) {
l, err := net.ListenPacket("udp", addr)
if err != nil {
@@ -28,6 +45,7 @@ func NewUDP(addr string, in chan<- *inbound.PacketAdapter) (*UDPListener, error)
sl := &UDPListener{
packetConn: l,
+ addr: addr,
}
go func() {
for {
@@ -47,15 +65,6 @@ func NewUDP(addr string, in chan<- *inbound.PacketAdapter) (*UDPListener, error)
return sl, nil
}
-func (l *UDPListener) Close() error {
- l.closed = true
- return l.packetConn.Close()
-}
-
-func (l *UDPListener) Address() string {
- return l.packetConn.LocalAddr().String()
-}
-
func handleSocksUDP(pc net.PacketConn, in chan<- *inbound.PacketAdapter, buf []byte, addr net.Addr) {
target, payload, err := socks5.DecodeUDPPacket(buf)
if err != nil {
diff --git a/listener/tproxy/tproxy.go b/listener/tproxy/tproxy.go
index 87f2d7d67..1a09f3663 100644
--- a/listener/tproxy/tproxy.go
+++ b/listener/tproxy/tproxy.go
@@ -10,9 +10,32 @@ import (
type Listener struct {
listener net.Listener
+ addr string
closed bool
}
+// RawAddress implements C.Listener
+func (l *Listener) RawAddress() string {
+ return l.addr
+}
+
+// Address implements C.Listener
+func (l *Listener) Address() string {
+ return l.listener.Addr().String()
+}
+
+// Close implements C.Listener
+func (l *Listener) Close() error {
+ l.closed = true
+ return l.listener.Close()
+}
+
+func (l *Listener) handleTProxy(conn net.Conn, in chan<- C.ConnContext) {
+ target := socks5.ParseAddrToSocksAddr(conn.LocalAddr())
+ conn.(*net.TCPConn).SetKeepAlive(true)
+ in <- inbound.NewSocket(target, conn, C.TPROXY)
+}
+
func New(addr string, in chan<- C.ConnContext) (*Listener, error) {
l, err := net.Listen("tcp", addr)
if err != nil {
@@ -32,6 +55,7 @@ func New(addr string, in chan<- C.ConnContext) (*Listener, error) {
rl := &Listener{
listener: l,
+ addr: addr,
}
go func() {
@@ -49,18 +73,3 @@ func New(addr string, in chan<- C.ConnContext) (*Listener, error) {
return rl, nil
}
-
-func (l *Listener) Close() {
- l.closed = true
- l.listener.Close()
-}
-
-func (l *Listener) Address() string {
- return l.listener.Addr().String()
-}
-
-func (l *Listener) handleTProxy(conn net.Conn, in chan<- C.ConnContext) {
- target := socks5.ParseAddrToSocksAddr(conn.LocalAddr())
- conn.(*net.TCPConn).SetKeepAlive(true)
- in <- inbound.NewSocket(target, conn, C.TPROXY)
-}
diff --git a/listener/tproxy/udp.go b/listener/tproxy/udp.go
index 6f9de6f54..f3d8dbb3c 100644
--- a/listener/tproxy/udp.go
+++ b/listener/tproxy/udp.go
@@ -11,9 +11,26 @@ import (
type UDPListener struct {
packetConn net.PacketConn
+ addr string
closed bool
}
+// RawAddress implements C.Listener
+func (l *UDPListener) RawAddress() string {
+ return l.addr
+}
+
+// Address implements C.Listener
+func (l *UDPListener) Address() string {
+ return l.packetConn.LocalAddr().String()
+}
+
+// Close implements C.Listener
+func (l *UDPListener) Close() error {
+ l.closed = true
+ return l.packetConn.Close()
+}
+
func NewUDP(addr string, in chan<- *inbound.PacketAdapter) (*UDPListener, error) {
l, err := net.ListenPacket("udp", addr)
if err != nil {
@@ -22,6 +39,7 @@ func NewUDP(addr string, in chan<- *inbound.PacketAdapter) (*UDPListener, error)
rl := &UDPListener{
packetConn: l,
+ addr: addr,
}
c := l.(*net.UDPConn)
@@ -60,15 +78,6 @@ func NewUDP(addr string, in chan<- *inbound.PacketAdapter) (*UDPListener, error)
return rl, nil
}
-func (l *UDPListener) Close() error {
- l.closed = true
- return l.packetConn.Close()
-}
-
-func (l *UDPListener) Address() string {
- return l.packetConn.LocalAddr().String()
-}
-
func handlePacketConn(pc net.PacketConn, in chan<- *inbound.PacketAdapter, buf []byte, lAddr *net.UDPAddr, rAddr *net.UDPAddr) {
target := socks5.ParseAddrToSocksAddr(rAddr)
pkt := &packet{
From 588645a2c3eda1afcde9e93fc2d01b7c7357338a Mon Sep 17 00:00:00 2001
From: Dreamacro <8615343+Dreamacro@users.noreply.github.com>
Date: Wed, 4 Aug 2021 23:52:50 +0800
Subject: [PATCH 35/96] Fix: interface nil check panic from previous commit
---
listener/listener.go | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/listener/listener.go b/listener/listener.go
index f9fffdf45..d20af99db 100644
--- a/listener/listener.go
+++ b/listener/listener.go
@@ -20,15 +20,15 @@ var (
allowLan = false
bindAddress = "*"
- socksListener C.Listener
- socksUDPListener C.Listener
- httpListener C.Listener
- redirListener C.Listener
- redirUDPListener C.Listener
- tproxyListener C.Listener
- tproxyUDPListener C.Listener
- mixedListener C.Listener
- mixedUDPLister C.Listener
+ socksListener *socks.Listener
+ socksUDPListener *socks.UDPListener
+ httpListener *http.Listener
+ redirListener *redir.Listener
+ redirUDPListener *tproxy.UDPListener
+ tproxyListener *tproxy.Listener
+ tproxyUDPListener *tproxy.UDPListener
+ mixedListener *mixed.Listener
+ mixedUDPLister *socks.UDPListener
// lock for recreate function
socksMux sync.Mutex
From 9b0bbb90ff2741cc7b2e3a54ad47a8c403acf70c Mon Sep 17 00:00:00 2001
From: Dreamacro <8615343+Dreamacro@users.noreply.github.com>
Date: Sat, 7 Aug 2021 22:27:23 +0800
Subject: [PATCH 36/96] Chore: upgrade github actions
---
.github/workflows/docker.yml | 2 +-
.github/workflows/go.yml | 2 --
.github/workflows/stale.yml | 3 +--
3 files changed, 2 insertions(+), 5 deletions(-)
diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml
index 002a9cb35..35083e518 100644
--- a/.github/workflows/docker.yml
+++ b/.github/workflows/docker.yml
@@ -52,7 +52,7 @@ jobs:
- name: Get all docker tags
if: startsWith(github.ref, 'refs/tags/')
- uses: actions/github-script@v3
+ uses: actions/github-script@v4
id: tags
with:
script: |
diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml
index a52be1e9a..343e31ba1 100644
--- a/.github/workflows/go.yml
+++ b/.github/workflows/go.yml
@@ -39,8 +39,6 @@ jobs:
- name: Upload Release
uses: softprops/action-gh-release@v1
if: startsWith(github.ref, 'refs/tags/')
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
files: bin/*
draft: true
diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml
index 7581fc403..68f986ffc 100644
--- a/.github/workflows/stale.yml
+++ b/.github/workflows/stale.yml
@@ -11,9 +11,8 @@ jobs:
runs-on: ubuntu-latest
steps:
- - uses: actions/stale@v3
+ - uses: actions/stale@v4
with:
- repo-token: ${{ secrets.GITHUB_TOKEN }}
stale-issue-message: 'This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 5 days'
days-before-stale: 60
days-before-close: 5
From 2663cb2e6e69700527565683216f6d99ce60aeae Mon Sep 17 00:00:00 2001
From: Dreamacro <8615343+Dreamacro@users.noreply.github.com>
Date: Fri, 13 Aug 2021 22:35:07 +0800
Subject: [PATCH 37/96] Chore: update github issue template
---
.github/ISSUE_TEMPLATE/bug_report.md | 100 ---------------------
.github/ISSUE_TEMPLATE/bug_report.yml | 77 ++++++++++++++++
.github/ISSUE_TEMPLATE/config.yml | 6 ++
.github/ISSUE_TEMPLATE/feature_request.md | 78 ----------------
.github/ISSUE_TEMPLATE/feature_request.yml | 36 ++++++++
5 files changed, 119 insertions(+), 178 deletions(-)
delete mode 100644 .github/ISSUE_TEMPLATE/bug_report.md
create mode 100644 .github/ISSUE_TEMPLATE/bug_report.yml
create mode 100644 .github/ISSUE_TEMPLATE/config.yml
delete mode 100644 .github/ISSUE_TEMPLATE/feature_request.md
create mode 100644 .github/ISSUE_TEMPLATE/feature_request.yml
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
deleted file mode 100644
index 2e5b75545..000000000
--- a/.github/ISSUE_TEMPLATE/bug_report.md
+++ /dev/null
@@ -1,100 +0,0 @@
----
-name: Bug report
-about: Create a report to help us improve
-title: "[Bug]"
-labels: ''
-assignees: ''
-
----
-
-
-
-------------------------------------------------------------------
-
-
-
-### Clash config
-
-
- config.yaml
-
-```yaml
-……
-```
-
-
-
-### Clash log
-
-```
-……
-```
-
-### 环境 Environment
-
-* 操作系统 (the OS that the Clash core is running on)
-……
-* 网路环境或拓扑 (network conditions/topology)
-……
-* iptables,如果适用 (if applicable)
-……
-* ISP 有没有进行 DNS 污染 (is your ISP performing DNS pollution?)
-……
-* 其他 (any other information that would be useful)
-……
-
-### 说明 Description
-
-
-
-### 重现问题的具体布骤 Steps to Reproduce
-
-1. [First Step]
-2. [Second Step]
-3. ……
-
-**我预期会发生……?**
-
-
-**实际上发生了什么?**
-
-
-### 可能的解决方案 Possible Solution
-
-
-
-
-### 更多信息 More Information
diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml
new file mode 100644
index 000000000..0876a7a7e
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.yml
@@ -0,0 +1,77 @@
+name: Bug report
+description: Create a report to help us improve
+title: '[Bug] '
+body:
+ - type: checkboxes
+ id: ensure
+ attributes:
+ label: Verify steps
+ description: "
+在提交之前,请确认
+Please verify that you've followed these steps
+"
+ options:
+ - label: "
+如果你可以自己 debug 并解决的话,提交 PR 吧
+Is this something you can **debug and fix**? Send a pull request! Bug fixes and documentation fixes are welcome.
+"
+ required: true
+ - label: "
+我已经在 [Issue Tracker](……/) 中找过我要提出的问题
+I have searched on the [issue tracker](……/) for a related issue.
+"
+ required: true
+ - label: "
+我已经使用 dev 分支版本测试过,问题依旧存在
+I have tested using the dev branch, and the issue still exists.
+"
+ required: true
+ - label: "
+我已经仔细看过 [Documentation](https://github.com/Dreamacro/clash/wiki/) 并无法自行解决问题
+I have read the [documentation](https://github.com/Dreamacro/clash/wiki/) and was unable to solve the issue.
+"
+ required: true
+ - label: "
+这是 Clash 核心的问题,并非我所使用的 Clash 衍生版本(如 OpenClash、KoolClash 等)的特定问题
+This is an issue of the Clash core *per se*, not to the derivatives of Clash, like OpenClash or KoolClash.
+"
+ required: true
+ - type: textarea
+ attributes:
+ render: yaml
+ label: "Clash version"
+ validations:
+ required: true
+ - type: dropdown
+ id: os
+ attributes:
+ label: What OS are you seeing the problem on?
+ multiple: true
+ options:
+ - macOS
+ - Windows
+ - Linux
+ - OpenBSD/FreeBSD
+ - type: textarea
+ attributes:
+ render: yaml
+ label: "Clash config"
+ description: "
+在下方附上 Clash core 脱敏后配置文件的内容
+Paste the Clash core configuration below.
+"
+ validations:
+ required: true
+ - type: textarea
+ attributes:
+ render: yaml
+ label: "Clash log"
+ description: "
+在下方附上 Clash Core 的日志,log level 使用 DEBUG
+Paste the Clash core log below with the log level set to `DEBUG`.
+"
+ - type: textarea
+ attributes:
+ label: "Description"
+ validations:
+ required: true
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
new file mode 100644
index 000000000..7404fe27c
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -0,0 +1,6 @@
+blank_issues_enabled: false
+
+contact_links:
+ - name: Get help in GitHub Discussions
+ url: https://github.com/Dreamacro/clash/discussions
+ about: Have a question? Not sure if your issue affects everyone reproducibly? The quickest way to get help is on Clash's GitHub Discussions!
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
deleted file mode 100644
index d5ddc956a..000000000
--- a/.github/ISSUE_TEMPLATE/feature_request.md
+++ /dev/null
@@ -1,78 +0,0 @@
----
-name: Feature request
-about: Suggest an idea for this project
-title: "[Feature]"
-labels: ''
-assignees: ''
-
----
-
-
-感谢你向 Clash Core 提交 Feature Request!
-在提交之前,请确认:
-
-- [ ] 我已经在 [Issue Tracker](……/) 中找过我要提出的请求
-
-请注意,如果你并没有遵照这个 issue template 填写内容,我们将直接关闭这个 issue。
-
-
-
-我都确认过了,我要继续提交。
-
-------------------------------------------------------------------
-
-请附上任何可以帮助我们解决这个问题的信息,如果我们收到的信息不足,我们将对这个 issue 加上 *Needs more information* 标记并在收到更多资讯之前关闭 issue。
-
-
-### Clash core config
-
-```
-……
-```
-
-### Clash log
-
-```
-……
-```
-
-### 环境 Environment
-
-* Clash Core 的操作系统 (the OS that the Clash core is running on)
-……
-* 使用者的操作系统 (the OS running on the client)
-……
-* 网路环境或拓扑 (network conditions/topology)
-……
-* iptables,如果适用 (if applicable)
-……
-* ISP 有没有进行 DNS 污染 (is your ISP performing DNS pollution?)
-……
-* 其他
-……
-
-### 说明 Description
-
-
-
-### 可能的解决方案 Possible Solution
-
-
-
-
-### 更多信息 More Information
diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml
new file mode 100644
index 000000000..b00d5b9a9
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature_request.yml
@@ -0,0 +1,36 @@
+name: Feature request
+description: Suggest an idea for this project
+title: "[Feature] "
+body:
+ - type: checkboxes
+ id: ensure
+ attributes:
+ label: Verify steps
+ description: "
+在提交之前,请确认
+Please verify that you've followed these steps
+"
+ options:
+ - label: "
+我已经在 [Issue Tracker](……/) 中找过我要提出的请求
+I have searched on the [issue tracker](……/) for a related feature request.
+"
+ required: true
+ - label: "
+我已经仔细看过 [Documentation](https://github.com/Dreamacro/clash/wiki/) 并无法自行解决问题
+I have read the [documentation](https://github.com/Dreamacro/clash/wiki/) and was unable to solve the issue.
+"
+ required: true
+ - type: textarea
+ attributes:
+ label: "Description"
+ description: 请详细、清晰地表达你要提出的论述,例如这个问题如何影响到你?你想实现什么功能?目前 Clash Core 的行为是什麽?
+ validations:
+ required: true
+ - type: textarea
+ attributes:
+ label: "Possible Solution"
+ description: "
+此项非必须,但是如果你有想法的话欢迎提出。
+Not obligatory, but suggest a fix/reason for the bug, or ideas how to implement the addition or change
+"
From 1be09f57515f6aefd0f26633ee15ffe3e2c320cb Mon Sep 17 00:00:00 2001
From: Dreamacro <8615343+Dreamacro@users.noreply.github.com>
Date: Fri, 13 Aug 2021 22:44:22 +0800
Subject: [PATCH 38/96] Chore: fix issue template render type
---
.github/ISSUE_TEMPLATE/bug_report.yml | 13 ++++++-------
.github/ISSUE_TEMPLATE/feature_request.yml | 4 ++--
2 files changed, 8 insertions(+), 9 deletions(-)
diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml
index 0876a7a7e..b56b98651 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.yml
+++ b/.github/ISSUE_TEMPLATE/bug_report.yml
@@ -1,6 +1,6 @@
name: Bug report
description: Create a report to help us improve
-title: '[Bug] '
+title: "[Bug] "
body:
- type: checkboxes
id: ensure
@@ -36,10 +36,9 @@ I have read the [documentation](https://github.com/Dreamacro/clash/wiki/) and wa
This is an issue of the Clash core *per se*, not to the derivatives of Clash, like OpenClash or KoolClash.
"
required: true
- - type: textarea
+ - type: input
attributes:
- render: yaml
- label: "Clash version"
+ label: Clash version
validations:
required: true
- type: dropdown
@@ -64,14 +63,14 @@ Paste the Clash core configuration below.
required: true
- type: textarea
attributes:
- render: yaml
- label: "Clash log"
+ render: shell
+ label: Clash log
description: "
在下方附上 Clash Core 的日志,log level 使用 DEBUG
Paste the Clash core log below with the log level set to `DEBUG`.
"
- type: textarea
attributes:
- label: "Description"
+ label: Description
validations:
required: true
diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml
index b00d5b9a9..34668d1ab 100644
--- a/.github/ISSUE_TEMPLATE/feature_request.yml
+++ b/.github/ISSUE_TEMPLATE/feature_request.yml
@@ -23,13 +23,13 @@ I have read the [documentation](https://github.com/Dreamacro/clash/wiki/) and wa
required: true
- type: textarea
attributes:
- label: "Description"
+ label: Description
description: 请详细、清晰地表达你要提出的论述,例如这个问题如何影响到你?你想实现什么功能?目前 Clash Core 的行为是什麽?
validations:
required: true
- type: textarea
attributes:
- label: "Possible Solution"
+ label: Possible Solution
description: "
此项非必须,但是如果你有想法的话欢迎提出。
Not obligatory, but suggest a fix/reason for the bug, or ideas how to implement the addition or change
From 571d2a00755287afad5b0a93b36f1d75a3d55895 Mon Sep 17 00:00:00 2001
From: Dreamacro <8615343+Dreamacro@users.noreply.github.com>
Date: Wed, 18 Aug 2021 13:26:23 +0800
Subject: [PATCH 39/96] Migration: go 1.17
---
.github/workflows/go.yml | 2 +-
Makefile | 6 +++++-
common/sockopt/reuseaddr_other.go | 1 +
component/dialer/bind_others.go | 1 +
component/process/process_other.go | 5 ++++-
dns/filters.go | 2 +-
go.mod | 18 +++++++++++++-----
go.sum | 16 ++++++++--------
listener/redir/tcp_linux_other.go | 1 +
listener/redir/tcp_other.go | 1 +
listener/tproxy/setsockopt_linux.go | 1 +
listener/tproxy/setsockopt_other.go | 1 +
listener/tproxy/udp_linux.go | 1 +
listener/tproxy/udp_other.go | 1 +
rule/geoip.go | 4 ++++
15 files changed, 44 insertions(+), 17 deletions(-)
diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml
index 343e31ba1..d8a514eae 100644
--- a/.github/workflows/go.yml
+++ b/.github/workflows/go.yml
@@ -9,7 +9,7 @@ jobs:
- name: Setup Go
uses: actions/setup-go@v2
with:
- go-version: 1.16
+ go-version: 1.17
- name: Check out code into the Go module directory
uses: actions/checkout@v2
diff --git a/Makefile b/Makefile
index 686514460..97328bc23 100644
--- a/Makefile
+++ b/Makefile
@@ -28,6 +28,7 @@ PLATFORM_LIST = \
WINDOWS_ARCH_LIST = \
windows-386 \
windows-amd64 \
+ windows-arm64 \
windows-arm32v7
all: linux-amd64 darwin-amd64 windows-amd64 # Most used
@@ -91,7 +92,10 @@ windows-386:
windows-amd64:
GOARCH=amd64 GOOS=windows $(GOBUILD) -o $(BINDIR)/$(NAME)-$@.exe
-
+
+windows-arm64:
+ GOARCH=arm64 GOOS=windows $(GOBUILD) -o $(BINDIR)/$(NAME)-$@.exe
+
windows-arm32v7:
GOARCH=arm GOOS=windows GOARM=7 $(GOBUILD) -o $(BINDIR)/$(NAME)-$@.exe
diff --git a/common/sockopt/reuseaddr_other.go b/common/sockopt/reuseaddr_other.go
index 2b1369508..c07083de0 100644
--- a/common/sockopt/reuseaddr_other.go
+++ b/common/sockopt/reuseaddr_other.go
@@ -1,3 +1,4 @@
+//go:build !linux
// +build !linux
package sockopt
diff --git a/component/dialer/bind_others.go b/component/dialer/bind_others.go
index be30bae84..e09b5ff84 100644
--- a/component/dialer/bind_others.go
+++ b/component/dialer/bind_others.go
@@ -1,3 +1,4 @@
+//go:build !linux && !darwin
// +build !linux,!darwin
package dialer
diff --git a/component/process/process_other.go b/component/process/process_other.go
index 1e0bd4478..f8a6ebbb4 100644
--- a/component/process/process_other.go
+++ b/component/process/process_other.go
@@ -1,4 +1,7 @@
-// +build !darwin,!linux,!windows
+//go:build !darwin && !linux && !windows && (!freebsd || !amd64)
+// +build !darwin
+// +build !linux
+// +build !windows
// +build !freebsd !amd64
package process
diff --git a/dns/filters.go b/dns/filters.go
index 583883fab..a6bc6c544 100644
--- a/dns/filters.go
+++ b/dns/filters.go
@@ -15,7 +15,7 @@ type geoipFilter struct{}
func (gf *geoipFilter) Match(ip net.IP) bool {
record, _ := mmdb.Instance().Country(ip)
- return record.Country.IsoCode != "CN" && record.Country.IsoCode != ""
+ return record.Country.IsoCode != "CN" && !ip.IsPrivate()
}
type ipnetFilter struct {
diff --git a/go.mod b/go.mod
index 28e4d44ba..34915dd7a 100644
--- a/go.mod
+++ b/go.mod
@@ -1,6 +1,6 @@
module github.com/Dreamacro/clash
-go 1.16
+go 1.17
require (
github.com/Dreamacro/go-shadowsocks2 v0.1.7
@@ -13,10 +13,18 @@ require (
github.com/oschwald/geoip2-golang v1.5.0
github.com/sirupsen/logrus v1.8.1
github.com/stretchr/testify v1.7.0
- go.uber.org/atomic v1.8.0
- golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e
- golang.org/x/net v0.0.0-20210614182718-04defd469f4e
+ go.uber.org/atomic v1.9.0
+ golang.org/x/crypto v0.0.0-20210817164053-32db794688a5
+ golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
- golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c
+ golang.org/x/sys v0.0.0-20210817190340-bfb29a6856f2
gopkg.in/yaml.v2 v2.4.0
)
+
+require (
+ github.com/davecgh/go-spew v1.1.1 // indirect
+ github.com/oschwald/maxminddb-golang v1.8.0 // indirect
+ github.com/pmezard/go-difflib v1.0.0 // indirect
+ golang.org/x/text v0.3.6 // indirect
+ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
+)
diff --git a/go.sum b/go.sum
index fa37dc3be..2c433ac0a 100644
--- a/go.sum
+++ b/go.sum
@@ -29,14 +29,14 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-go.uber.org/atomic v1.8.0 h1:CUhrE4N1rqSE6FM9ecihEjRkLQu8cDfgDyoOs83mEY4=
-go.uber.org/atomic v1.8.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
+go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
+go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
golang.org/x/crypto v0.0.0-20210317152858-513c2a44f670/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
-golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e h1:gsTQYXdTw2Gq7RBsWvlQ91b+aEQ6bXFUngBGuR8sPpI=
-golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 h1:HWj/xjIHfjYU5nVXpTM0s39J9CbLn7Cc5a7IC5rwsMQ=
+golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
-golang.org/x/net v0.0.0-20210614182718-04defd469f4e h1:XpT3nA5TvE525Ne3hInMh6+GETgn27Zfm9dxsThnX2Q=
-golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d h1:LO7XpTYMwTqxjLcGWPijK3vRXg1aWdlNOVOHRq45d7c=
+golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -45,8 +45,8 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I=
-golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210817190340-bfb29a6856f2 h1:c8PlLMqBbOHoqtjteWm5/kbe6rNY2pbRfbIMVnepueo=
+golang.org/x/sys v0.0.0-20210817190340-bfb29a6856f2/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
diff --git a/listener/redir/tcp_linux_other.go b/listener/redir/tcp_linux_other.go
index 95472823c..3299843d0 100644
--- a/listener/redir/tcp_linux_other.go
+++ b/listener/redir/tcp_linux_other.go
@@ -1,3 +1,4 @@
+//go:build linux && !386
// +build linux,!386
package redir
diff --git a/listener/redir/tcp_other.go b/listener/redir/tcp_other.go
index 50968e9ab..592e9584f 100644
--- a/listener/redir/tcp_other.go
+++ b/listener/redir/tcp_other.go
@@ -1,3 +1,4 @@
+//go:build !darwin && !linux && !freebsd
// +build !darwin,!linux,!freebsd
package redir
diff --git a/listener/tproxy/setsockopt_linux.go b/listener/tproxy/setsockopt_linux.go
index a70223f7f..1e92db128 100644
--- a/listener/tproxy/setsockopt_linux.go
+++ b/listener/tproxy/setsockopt_linux.go
@@ -1,3 +1,4 @@
+//go:build linux
// +build linux
package tproxy
diff --git a/listener/tproxy/setsockopt_other.go b/listener/tproxy/setsockopt_other.go
index 059477284..24fb7c7b4 100644
--- a/listener/tproxy/setsockopt_other.go
+++ b/listener/tproxy/setsockopt_other.go
@@ -1,3 +1,4 @@
+//go:build !linux
// +build !linux
package tproxy
diff --git a/listener/tproxy/udp_linux.go b/listener/tproxy/udp_linux.go
index 40c177e7e..f68ce8f1f 100644
--- a/listener/tproxy/udp_linux.go
+++ b/listener/tproxy/udp_linux.go
@@ -1,3 +1,4 @@
+//go:build linux
// +build linux
package tproxy
diff --git a/listener/tproxy/udp_other.go b/listener/tproxy/udp_other.go
index a4531b5d0..f899fc3d2 100644
--- a/listener/tproxy/udp_other.go
+++ b/listener/tproxy/udp_other.go
@@ -1,3 +1,4 @@
+//go:build !linux
// +build !linux
package tproxy
diff --git a/rule/geoip.go b/rule/geoip.go
index be4b5029f..0b94c4c28 100644
--- a/rule/geoip.go
+++ b/rule/geoip.go
@@ -20,6 +20,10 @@ func (g *GEOIP) Match(metadata *C.Metadata) bool {
if ip == nil {
return false
}
+
+ if g.country == "LAN" {
+ return ip.IsPrivate()
+ }
record, _ := mmdb.Instance().Country(ip)
return record.Country.IsoCode == g.country
}
From 426ca361186950940c62af4b27f284c2ac3d6857 Mon Sep 17 00:00:00 2001
From: Dreamacro <8615343+Dreamacro@users.noreply.github.com>
Date: Wed, 18 Aug 2021 13:31:34 +0800
Subject: [PATCH 40/96] Chore: upgrade test package
---
test/go.mod | 33 ++++++++++++++++++++++++++++++---
test/go.sum | 7 ++++---
2 files changed, 34 insertions(+), 6 deletions(-)
diff --git a/test/go.mod b/test/go.mod
index 88db62292..8ee679f4d 100644
--- a/test/go.mod
+++ b/test/go.mod
@@ -1,19 +1,46 @@
module clash-test
-go 1.16
+go 1.17
require (
github.com/Dreamacro/clash v1.6.5
github.com/Microsoft/go-winio v0.5.0 // indirect
github.com/containerd/containerd v1.5.3 // indirect
- github.com/docker/docker v20.10.7+incompatible
+ github.com/docker/docker v20.10.8+incompatible
github.com/docker/go-connections v0.4.0
github.com/gorilla/mux v1.8.0 // indirect
github.com/miekg/dns v1.1.43
github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 // indirect
github.com/morikuni/aec v1.0.0 // indirect
github.com/stretchr/testify v1.7.0
- golang.org/x/net v0.0.0-20210614182718-04defd469f4e
+ golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d
golang.org/x/time v0.0.0-20210611083556-38a9dc6acbc6 // indirect
google.golang.org/grpc v1.39.0 // indirect
)
+
+require (
+ github.com/Dreamacro/go-shadowsocks2 v0.1.7 // indirect
+ github.com/davecgh/go-spew v1.1.1 // indirect
+ github.com/docker/distribution v2.7.1+incompatible // indirect
+ github.com/docker/go-units v0.4.0 // indirect
+ github.com/gofrs/uuid v4.0.0+incompatible // indirect
+ github.com/gogo/protobuf v1.3.2 // indirect
+ github.com/golang/protobuf v1.4.3 // indirect
+ github.com/gorilla/websocket v1.4.2 // indirect
+ github.com/opencontainers/go-digest v1.0.0 // indirect
+ github.com/opencontainers/image-spec v1.0.1 // indirect
+ github.com/oschwald/geoip2-golang v1.5.0 // indirect
+ github.com/oschwald/maxminddb-golang v1.8.0 // indirect
+ github.com/pkg/errors v0.9.1 // indirect
+ github.com/pmezard/go-difflib v1.0.0 // indirect
+ github.com/sirupsen/logrus v1.8.1 // indirect
+ go.uber.org/atomic v1.8.0 // indirect
+ golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e // indirect
+ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
+ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c // indirect
+ golang.org/x/text v0.3.6 // indirect
+ google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a // indirect
+ google.golang.org/protobuf v1.25.0 // indirect
+ gopkg.in/yaml.v2 v2.4.0 // indirect
+ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
+)
diff --git a/test/go.sum b/test/go.sum
index 0b460241b..e97659260 100644
--- a/test/go.sum
+++ b/test/go.sum
@@ -224,8 +224,8 @@ github.com/docker/distribution v0.0.0-20190905152932-14b96e55d84c/go.mod h1:0+TT
github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug=
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
-github.com/docker/docker v20.10.7+incompatible h1:Z6O9Nhsjv+ayUEeI1IojKbYcsGdgYSNqxe1s2MYzUhQ=
-github.com/docker/docker v20.10.7+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
+github.com/docker/docker v20.10.8+incompatible h1:RVqD337BgQicVCzYrrlhLDWhq6OAD2PJDUg2LsEUvKM=
+github.com/docker/docker v20.10.8+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
github.com/docker/go-events v0.0.0-20170721190031-9461782956ad/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA=
@@ -697,8 +697,9 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
-golang.org/x/net v0.0.0-20210614182718-04defd469f4e h1:XpT3nA5TvE525Ne3hInMh6+GETgn27Zfm9dxsThnX2Q=
golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d h1:LO7XpTYMwTqxjLcGWPijK3vRXg1aWdlNOVOHRq45d7c=
+golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
From 47044ec0d81dc0dc92a2dafc834f2b658177dee8 Mon Sep 17 00:00:00 2001
From: Dreamacro <8615343+Dreamacro@users.noreply.github.com>
Date: Wed, 18 Aug 2021 20:20:00 +0800
Subject: [PATCH 41/96] Fix: dependabot alerts
---
test/go.mod | 18 +++++++++---------
test/go.sum | 31 ++++++++++++++++++++++---------
2 files changed, 31 insertions(+), 18 deletions(-)
diff --git a/test/go.mod b/test/go.mod
index 8ee679f4d..f096b468d 100644
--- a/test/go.mod
+++ b/test/go.mod
@@ -4,29 +4,27 @@ go 1.17
require (
github.com/Dreamacro/clash v1.6.5
- github.com/Microsoft/go-winio v0.5.0 // indirect
- github.com/containerd/containerd v1.5.3 // indirect
github.com/docker/docker v20.10.8+incompatible
github.com/docker/go-connections v0.4.0
- github.com/gorilla/mux v1.8.0 // indirect
github.com/miekg/dns v1.1.43
- github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 // indirect
- github.com/morikuni/aec v1.0.0 // indirect
github.com/stretchr/testify v1.7.0
golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d
- golang.org/x/time v0.0.0-20210611083556-38a9dc6acbc6 // indirect
- google.golang.org/grpc v1.39.0 // indirect
)
require (
github.com/Dreamacro/go-shadowsocks2 v0.1.7 // indirect
+ github.com/Microsoft/go-winio v0.5.0 // indirect
+ github.com/containerd/containerd v1.5.5 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/docker/distribution v2.7.1+incompatible // indirect
github.com/docker/go-units v0.4.0 // indirect
github.com/gofrs/uuid v4.0.0+incompatible // indirect
github.com/gogo/protobuf v1.3.2 // indirect
- github.com/golang/protobuf v1.4.3 // indirect
+ github.com/golang/protobuf v1.5.0 // indirect
+ github.com/gorilla/mux v1.8.0 // indirect
github.com/gorilla/websocket v1.4.2 // indirect
+ github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 // indirect
+ github.com/morikuni/aec v1.0.0 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.0.1 // indirect
github.com/oschwald/geoip2-golang v1.5.0 // indirect
@@ -39,8 +37,10 @@ require (
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c // indirect
golang.org/x/text v0.3.6 // indirect
+ golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect
google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a // indirect
- google.golang.org/protobuf v1.25.0 // indirect
+ google.golang.org/grpc v1.40.0 // indirect
+ google.golang.org/protobuf v1.26.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
)
diff --git a/test/go.sum b/test/go.sum
index e97659260..e6b3582ea 100644
--- a/test/go.sum
+++ b/test/go.sum
@@ -82,6 +82,7 @@ github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+Ce
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA=
+github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA=
github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
@@ -94,6 +95,7 @@ github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/checkpoint-restore/go-criu/v4 v4.1.0/go.mod h1:xUQBLp4RLc5zJtWY++yjOoMoB5lihDt7fai+75m+rGw=
+github.com/checkpoint-restore/go-criu/v5 v5.0.0/go.mod h1:cfwC0EG7HMUenopBsUf9d89JlCLQIfgVcNsNN0t6T2M=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
@@ -101,6 +103,7 @@ github.com/cilium/ebpf v0.0.0-20200110133405-4032b1d8aae3/go.mod h1:MA5e5Lr8slmE
github.com/cilium/ebpf v0.0.0-20200702112145-1c8d4c9ef775/go.mod h1:7cR51M8ViRLIdUjrmSXlK9pkrsDlLHbO8jiB8X8JnOc=
github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs=
github.com/cilium/ebpf v0.4.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs=
+github.com/cilium/ebpf v0.6.2/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
@@ -138,8 +141,8 @@ github.com/containerd/containerd v1.5.0-beta.3/go.mod h1:/wr9AVtEM7x9c+n0+stptlo
github.com/containerd/containerd v1.5.0-beta.4/go.mod h1:GmdgZd2zA2GYIBZ0w09ZvgqEq8EfBp/m3lcVZIvPHhI=
github.com/containerd/containerd v1.5.0-rc.0/go.mod h1:V/IXoMqNGgBlabz3tHD2TWDoTJseu1FGOKuoA4nNb2s=
github.com/containerd/containerd v1.5.1/go.mod h1:0DOxVqwDy2iZvrZp2JUx/E+hS0UNTVn7dJnIOwtYR4g=
-github.com/containerd/containerd v1.5.3 h1:mfKOepNDIJ3EiBTEyHFpEqB6YSOSkGcjPDIu7cD+YzY=
-github.com/containerd/containerd v1.5.3/go.mod h1:sx18RgvW6ABJ4iYUw7Q5x7bgFOAB9B6G7+yO0XBc4zw=
+github.com/containerd/containerd v1.5.5 h1:q1gxsZsGZ8ddVe98yO6pR21b5xQSMiR61lD0W96pgQo=
+github.com/containerd/containerd v1.5.5/go.mod h1:oSTh0QpT1w6jYcGmbiSbxv9OSQYaa88mPyWIuU79zyo=
github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
github.com/containerd/continuity v0.0.0-20190815185530-f2a389ac0a02/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
github.com/containerd/continuity v0.0.0-20191127005431-f65d91d395eb/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
@@ -201,6 +204,7 @@ github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk=
github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk=
+github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
@@ -283,6 +287,7 @@ github.com/godbus/dbus v0.0.0-20151105175453-c7fdd8b5cd55/go.mod h1:/YcGZj5zSblf
github.com/godbus/dbus v0.0.0-20180201030542-885f9cc04c9c/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw=
github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4=
github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
+github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw=
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gogo/googleapis v1.2.0/go.mod h1:Njal3psf3qN6dwBtQfUmBZh2ybovJ0tlu3o/AC7HYjU=
@@ -318,8 +323,9 @@ github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:W
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
-github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
+github.com/golang/protobuf v1.5.0 h1:LUVKkCeviFUMKqHa4tXIIij/lbhnMbP7Fn5wKdKkRh4=
+github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
@@ -329,8 +335,9 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
+github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
@@ -472,14 +479,17 @@ github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59P
github.com/opencontainers/runc v1.0.0-rc8.0.20190926000215-3e425f80a8c9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
github.com/opencontainers/runc v1.0.0-rc9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
github.com/opencontainers/runc v1.0.0-rc93/go.mod h1:3NOsor4w32B2tC0Zbl8Knk4Wg84SM2ImC1fxBuqJ/H0=
+github.com/opencontainers/runc v1.0.1/go.mod h1:aTaHFFwQXuA71CiyxOdFFIorAoemI04suvGRQFzWTD0=
github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opencontainers/runtime-spec v1.0.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opencontainers/runtime-spec v1.0.2-0.20190207185410-29686dbc5559/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opencontainers/runtime-spec v1.0.3-0.20200929063507-e6143ca7d51d/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
+github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs=
github.com/opencontainers/selinux v1.6.0/go.mod h1:VVGKuOLlE7v4PJyT6h7mNWvq1rzqiriPsEqVhc+svHE=
github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3ogry1nUQF8Evvo=
+github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xAPP8dBsCoU0KuF8=
github.com/oschwald/geoip2-golang v1.5.0 h1:igg2yQIrrcRccB1ytFXqBfOHCjXWIoMv85lVJ1ONZzw=
github.com/oschwald/geoip2-golang v1.5.0/go.mod h1:xdvYt5xQzB8ORWFqPnqMwZpCpgNagttWdoZLlJQzg7s=
github.com/oschwald/maxminddb-golang v1.8.0 h1:Uh/DSnGoxsyp/KYbY1AuP0tYEwfs0sCph9p/UMXK/Hk=
@@ -778,6 +788,7 @@ golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I=
@@ -796,8 +807,8 @@ golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxb
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/time v0.0.0-20210611083556-38a9dc6acbc6 h1:Vv0JUPWTyeqUq42B2WJ1FeIDjjvGKoA2Ss+Ts0lAVbs=
-golang.org/x/time v0.0.0-20210611083556-38a9dc6acbc6/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2MaV/MapERkDIy+mwPyjs=
+golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@@ -897,8 +908,8 @@ google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
-google.golang.org/grpc v1.39.0 h1:Klz8I9kdtkIN6EpHHUOMLCYhTn/2WAe5a0s1hcBkdTI=
-google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
+google.golang.org/grpc v1.40.0 h1:AGJ0Ih4mHjSeibYkFGh1dD9KJ/eOtZ93I6hoHhukQ5Q=
+google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
@@ -908,8 +919,10 @@ google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
-google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
+google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
+google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
+google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
From 847f41952e97996bc5f4358a2df2ec8a1e4a8739 Mon Sep 17 00:00:00 2001
From: Dreamacro <8615343+Dreamacro@users.noreply.github.com>
Date: Thu, 19 Aug 2021 22:11:56 +0800
Subject: [PATCH 42/96] Fix: grpc transport path should not escape
---
test/config/vmess-grpc.json | 2 +-
test/vmess_test.go | 2 +-
transport/gun/gun.go | 2 ++
3 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/test/config/vmess-grpc.json b/test/config/vmess-grpc.json
index 1b3a8e9a7..22e117634 100644
--- a/test/config/vmess-grpc.json
+++ b/test/config/vmess-grpc.json
@@ -24,7 +24,7 @@
]
},
"grpcSettings": {
- "serviceName": "example"
+ "serviceName": "example!"
}
}
}
diff --git a/test/vmess_test.go b/test/vmess_test.go
index de3b2ba6a..7791abee8 100644
--- a/test/vmess_test.go
+++ b/test/vmess_test.go
@@ -335,7 +335,7 @@ func TestClash_VmessGrpc(t *testing.T) {
UDP: true,
ServerName: "example.org",
GrpcOpts: outbound.GrpcOptions{
- GrpcServiceName: "example",
+ GrpcServiceName: "example!",
},
})
if err != nil {
diff --git a/transport/gun/gun.go b/transport/gun/gun.go
index f19006adf..3f97121f8 100644
--- a/transport/gun/gun.go
+++ b/transport/gun/gun.go
@@ -211,6 +211,8 @@ func StreamGunWithTransport(transport *http2.Transport, cfg *Config) (net.Conn,
Scheme: "https",
Host: cfg.Host,
Path: fmt.Sprintf("/%s/Tun", serviceName),
+ // for unescape path
+ Opaque: fmt.Sprintf("//%s/%s/Tun", cfg.Host, serviceName),
},
Proto: "HTTP/2",
ProtoMajor: 2,
From c6d375eda257d6617d57ed9b7eb8c5e72f88981c Mon Sep 17 00:00:00 2001
From: Digital Pencil
Date: Fri, 20 Aug 2021 23:38:47 +0800
Subject: [PATCH 43/96] Fix: HTTP proxy internal linkage signature (#1555)
---
listener/http/hack.go | 2 +-
listener/http/proxy.go | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/listener/http/hack.go b/listener/http/hack.go
index 14a725383..c33eb6f1b 100644
--- a/listener/http/hack.go
+++ b/listener/http/hack.go
@@ -7,4 +7,4 @@ import (
)
//go:linkname ReadRequest net/http.readRequest
-func ReadRequest(b *bufio.Reader, deleteHostHeader bool) (req *http.Request, err error)
+func ReadRequest(b *bufio.Reader) (req *http.Request, err error)
diff --git a/listener/http/proxy.go b/listener/http/proxy.go
index 9ac95cb49..449658cac 100644
--- a/listener/http/proxy.go
+++ b/listener/http/proxy.go
@@ -24,7 +24,7 @@ func HandleConn(c net.Conn, in chan<- C.ConnContext, cache *cache.Cache) {
trusted := cache == nil // disable authenticate if cache is nil
for keepAlive {
- request, err := ReadRequest(conn.Reader(), false)
+ request, err := ReadRequest(conn.Reader())
if err != nil {
break
}
From 0267b2efad9a6b0f447efde20589e124ad369a15 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E7=A7=8B=E3=81=AE=E3=81=8B=E3=81=88=E3=81=A7?=
Date: Sun, 22 Aug 2021 00:25:29 +0800
Subject: [PATCH 44/96] Feature: add vmess WebSocket early data (#1505)
Co-authored-by: ShinyGwyn <79344143+ShinyGwyn@users.noreply.github.com>
---
adapter/outbound/vmess.go | 29 +++++--
transport/vmess/conn.go | 9 +-
transport/vmess/websocket.go | 161 +++++++++++++++++++++++++++++++++--
3 files changed, 181 insertions(+), 18 deletions(-)
diff --git a/adapter/outbound/vmess.go b/adapter/outbound/vmess.go
index 5ee4abbc3..445b1ef47 100644
--- a/adapter/outbound/vmess.go
+++ b/adapter/outbound/vmess.go
@@ -43,6 +43,7 @@ type VmessOption struct {
HTTPOpts HTTPOptions `proxy:"http-opts,omitempty"`
HTTP2Opts HTTP2Options `proxy:"h2-opts,omitempty"`
GrpcOpts GrpcOptions `proxy:"grpc-opts,omitempty"`
+ WSOpts WSOptions `proxy:"ws-opts,omitempty"`
WSPath string `proxy:"ws-path,omitempty"`
WSHeaders map[string]string `proxy:"ws-headers,omitempty"`
SkipCertVerify bool `proxy:"skip-cert-verify,omitempty"`
@@ -64,19 +65,35 @@ type GrpcOptions struct {
GrpcServiceName string `proxy:"grpc-service-name,omitempty"`
}
+type WSOptions struct {
+ Path string `proxy:"path,omitempty"`
+ Headers map[string]string `proxy:"headers,omitempty"`
+ MaxEarlyData int `proxy:"max-early-data,omitempty"`
+ EarlyDataHeaderName string `proxy:"early-data-header-name,omitempty"`
+}
+
// StreamConn implements C.ProxyAdapter
func (v *Vmess) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {
var err error
switch v.option.Network {
case "ws":
- host, port, _ := net.SplitHostPort(v.addr)
- wsOpts := &vmess.WebsocketConfig{
- Host: host,
- Port: port,
- Path: v.option.WSPath,
+ if v.option.WSOpts.Path == "" {
+ v.option.WSOpts.Path = v.option.WSPath
+ }
+ if len(v.option.WSOpts.Headers) == 0 {
+ v.option.WSOpts.Headers = v.option.WSHeaders
}
- if len(v.option.WSHeaders) != 0 {
+ host, port, _ := net.SplitHostPort(v.addr)
+ wsOpts := &vmess.WebsocketConfig{
+ Host: host,
+ Port: port,
+ Path: v.option.WSOpts.Path,
+ MaxEarlyData: v.option.WSOpts.MaxEarlyData,
+ EarlyDataHeaderName: v.option.WSOpts.EarlyDataHeaderName,
+ }
+
+ if len(v.option.WSOpts.Headers) != 0 {
header := http.Header{}
for key, value := range v.option.WSHeaders {
header.Add(key, value)
diff --git a/transport/vmess/conn.go b/transport/vmess/conn.go
index e6e57be61..cc3155ee4 100644
--- a/transport/vmess/conn.go
+++ b/transport/vmess/conn.go
@@ -59,12 +59,12 @@ func (vc *Conn) Read(b []byte) (int, error) {
func (vc *Conn) sendRequest() error {
timestamp := time.Now()
+ mbuf := &bytes.Buffer{}
+
if !vc.isAead {
h := hmac.New(md5.New, vc.id.UUID.Bytes())
binary.Write(h, binary.BigEndian, uint64(timestamp.Unix()))
- if _, err := vc.Conn.Write(h.Sum(nil)); err != nil {
- return err
- }
+ mbuf.Write(h.Sum(nil))
}
buf := &bytes.Buffer{}
@@ -110,7 +110,8 @@ func (vc *Conn) sendRequest() error {
stream := cipher.NewCFBEncrypter(block, hashTimestamp(timestamp))
stream.XORKeyStream(buf.Bytes(), buf.Bytes())
- _, err = vc.Conn.Write(buf.Bytes())
+ mbuf.Write(buf.Bytes())
+ _, err = vc.Conn.Write(mbuf.Bytes())
return err
}
diff --git a/transport/vmess/websocket.go b/transport/vmess/websocket.go
index 6ed353e76..956b6d957 100644
--- a/transport/vmess/websocket.go
+++ b/transport/vmess/websocket.go
@@ -1,7 +1,11 @@
package vmess
import (
+ "bytes"
+ "context"
"crypto/tls"
+ "encoding/base64"
+ "errors"
"fmt"
"io"
"net"
@@ -23,15 +27,26 @@ type websocketConn struct {
rMux sync.Mutex
wMux sync.Mutex
}
+type websocketWithEarlyDataConn struct {
+ net.Conn
+ underlay net.Conn
+ closed bool
+ dialed chan bool
+ cancel context.CancelFunc
+ ctx context.Context
+ config *WebsocketConfig
+}
type WebsocketConfig struct {
- Host string
- Port string
- Path string
- Headers http.Header
- TLS bool
- SkipCertVerify bool
- ServerName string
+ Host string
+ Port string
+ Path string
+ Headers http.Header
+ TLS bool
+ SkipCertVerify bool
+ ServerName string
+ MaxEarlyData int
+ EarlyDataHeaderName string
}
// Read implements net.Conn.Read()
@@ -113,7 +128,121 @@ func (wsc *websocketConn) SetWriteDeadline(t time.Time) error {
return wsc.conn.SetWriteDeadline(t)
}
-func StreamWebsocketConn(conn net.Conn, c *WebsocketConfig) (net.Conn, error) {
+func (wsedc *websocketWithEarlyDataConn) Dial(earlyData []byte) error {
+ earlyDataBuf := bytes.NewBuffer(nil)
+ base64EarlyDataEncoder := base64.NewEncoder(base64.RawURLEncoding, earlyDataBuf)
+
+ earlydata := bytes.NewReader(earlyData)
+ limitedEarlyDatareader := io.LimitReader(earlydata, int64(wsedc.config.MaxEarlyData))
+ n, encerr := io.Copy(base64EarlyDataEncoder, limitedEarlyDatareader)
+ if encerr != nil {
+ return errors.New("failed to encode early data: " + encerr.Error())
+ }
+
+ if errc := base64EarlyDataEncoder.Close(); errc != nil {
+ return errors.New("failed to encode early data tail: " + errc.Error())
+ }
+
+ var err error
+ if wsedc.Conn, err = streamWebsocketConn(wsedc.underlay, wsedc.config, earlyDataBuf); err != nil {
+ wsedc.Close()
+ return errors.New("failed to dial WebSocket: " + err.Error())
+ }
+
+ wsedc.dialed <- true
+
+ if n != int64(len(earlyData)) {
+ _, err = wsedc.Conn.Write(earlyData[n:])
+ }
+
+ return err
+}
+
+func (wsedc *websocketWithEarlyDataConn) Write(b []byte) (int, error) {
+ if wsedc.closed {
+ return 0, io.ErrClosedPipe
+ }
+ if wsedc.Conn == nil {
+ if err := wsedc.Dial(b); err != nil {
+ return 0, err
+ }
+ return len(b), nil
+ }
+
+ return wsedc.Conn.Write(b)
+}
+
+func (wsedc *websocketWithEarlyDataConn) Read(b []byte) (int, error) {
+ if wsedc.closed {
+ return 0, io.ErrClosedPipe
+ }
+ if wsedc.Conn == nil {
+ select {
+ case <-wsedc.ctx.Done():
+ return 0, io.ErrUnexpectedEOF
+ case <-wsedc.dialed:
+ }
+ }
+ return wsedc.Conn.Read(b)
+}
+
+func (wsedc *websocketWithEarlyDataConn) Close() error {
+ wsedc.closed = true
+ wsedc.cancel()
+ if wsedc.Conn == nil {
+ return nil
+ }
+ return wsedc.Conn.Close()
+}
+
+func (wsedc *websocketWithEarlyDataConn) LocalAddr() net.Addr {
+ if wsedc.Conn == nil {
+ return wsedc.underlay.LocalAddr()
+ }
+ return wsedc.Conn.LocalAddr()
+}
+
+func (wsedc *websocketWithEarlyDataConn) RemoteAddr() net.Addr {
+ if wsedc.Conn == nil {
+ return wsedc.underlay.RemoteAddr()
+ }
+ return wsedc.Conn.RemoteAddr()
+}
+
+func (wsedc *websocketWithEarlyDataConn) SetDeadline(t time.Time) error {
+ if err := wsedc.SetReadDeadline(t); err != nil {
+ return err
+ }
+ return wsedc.SetWriteDeadline(t)
+}
+
+func (wsedc *websocketWithEarlyDataConn) SetReadDeadline(t time.Time) error {
+ if wsedc.Conn == nil {
+ return nil
+ }
+ return wsedc.Conn.SetReadDeadline(t)
+}
+
+func (wsedc *websocketWithEarlyDataConn) SetWriteDeadline(t time.Time) error {
+ if wsedc.Conn == nil {
+ return nil
+ }
+ return wsedc.Conn.SetWriteDeadline(t)
+}
+
+func streamWebsocketWithEarlyDataConn(conn net.Conn, c *WebsocketConfig) (net.Conn, error) {
+ ctx, cancel := context.WithCancel(context.Background())
+ conn = &websocketWithEarlyDataConn{
+ dialed: make(chan bool, 1),
+ cancel: cancel,
+ ctx: ctx,
+ underlay: conn,
+ config: c,
+ }
+ return conn, nil
+}
+
+func streamWebsocketConn(conn net.Conn, c *WebsocketConfig, earlyData *bytes.Buffer) (net.Conn, error) {
dialer := &websocket.Dialer{
NetDial: func(network, addr string) (net.Conn, error) {
return conn, nil
@@ -152,6 +281,14 @@ func StreamWebsocketConn(conn net.Conn, c *WebsocketConfig) (net.Conn, error) {
}
}
+ if earlyData != nil {
+ if c.EarlyDataHeaderName == "" {
+ uri.Path += earlyData.String()
+ } else {
+ headers.Set(c.EarlyDataHeaderName, earlyData.String())
+ }
+ }
+
wsConn, resp, err := dialer.Dial(uri.String(), headers)
if err != nil {
reason := err.Error()
@@ -166,3 +303,11 @@ func StreamWebsocketConn(conn net.Conn, c *WebsocketConfig) (net.Conn, error) {
remoteAddr: conn.RemoteAddr(),
}, nil
}
+
+func StreamWebsocketConn(conn net.Conn, c *WebsocketConfig) (net.Conn, error) {
+ if c.MaxEarlyData > 0 {
+ return streamWebsocketWithEarlyDataConn(conn, c)
+ }
+
+ return streamWebsocketConn(conn, c, nil)
+}
From 410772e81c1c2f212616d367bd0e25e2ec1508a8 Mon Sep 17 00:00:00 2001
From: Dreamacro <8615343+Dreamacro@users.noreply.github.com>
Date: Sun, 22 Aug 2021 01:17:29 +0800
Subject: [PATCH 45/96] Test: add vmess ws 0-rtt test
---
test/config/vmess-ws-0rtt.json | 30 +++++++++++++++++++++++++
test/go.mod | 8 +++----
test/go.sum | 17 +++++++-------
test/vmess_test.go | 41 ++++++++++++++++++++++++++++++++++
4 files changed, 83 insertions(+), 13 deletions(-)
create mode 100644 test/config/vmess-ws-0rtt.json
diff --git a/test/config/vmess-ws-0rtt.json b/test/config/vmess-ws-0rtt.json
new file mode 100644
index 000000000..7e2876d0c
--- /dev/null
+++ b/test/config/vmess-ws-0rtt.json
@@ -0,0 +1,30 @@
+{
+ "inbounds": [
+ {
+ "port": 10002,
+ "listen": "0.0.0.0",
+ "protocol": "vmess",
+ "settings": {
+ "clients": [
+ {
+ "id": "b831381d-6324-4d53-ad4f-8cda48b30811",
+ "alterId": 32
+ }
+ ]
+ },
+ "streamSettings": {
+ "network": "ws",
+ "security": "none",
+ "wsSettings": {
+ "maxEarlyData": 128,
+ "earlyDataHeaderName": "Sec-WebSocket-Protocol"
+ }
+ }
+ }
+ ],
+ "outbounds": [
+ {
+ "protocol": "freedom"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/test/go.mod b/test/go.mod
index f096b468d..5d86eda93 100644
--- a/test/go.mod
+++ b/test/go.mod
@@ -3,7 +3,7 @@ module clash-test
go 1.17
require (
- github.com/Dreamacro/clash v1.6.5
+ github.com/Dreamacro/clash v1.6.6-0.20210821162529-0267b2efad9a
github.com/docker/docker v20.10.8+incompatible
github.com/docker/go-connections v0.4.0
github.com/miekg/dns v1.1.43
@@ -32,10 +32,10 @@ require (
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/sirupsen/logrus v1.8.1 // indirect
- go.uber.org/atomic v1.8.0 // indirect
- golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e // indirect
+ go.uber.org/atomic v1.9.0 // indirect
+ golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 // indirect
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
- golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c // indirect
+ golang.org/x/sys v0.0.0-20210817190340-bfb29a6856f2 // indirect
golang.org/x/text v0.3.6 // indirect
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect
google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a // indirect
diff --git a/test/go.sum b/test/go.sum
index e6b3582ea..e83047937 100644
--- a/test/go.sum
+++ b/test/go.sum
@@ -38,8 +38,8 @@ github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZ
github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
-github.com/Dreamacro/clash v1.6.5 h1:bO8MJpfDOqZsgiK32x2xe9fjniujqVabQOWEYAg5Rac=
-github.com/Dreamacro/clash v1.6.5/go.mod h1:AqwqYq0ibcW8j14Re3/uY0bido9PzAuME7Dj+7zst/o=
+github.com/Dreamacro/clash v1.6.6-0.20210821162529-0267b2efad9a h1:Y+EWU18ZaK9ZxcZGv2O3nUzGk3XYLZe2r5i8FMku7wA=
+github.com/Dreamacro/clash v1.6.6-0.20210821162529-0267b2efad9a/go.mod h1:eN07P85tFwbnkHnEQPYlFsyTc8spXBNa4fOFUea6F58=
github.com/Dreamacro/go-shadowsocks2 v0.1.7 h1:8CtbE1HoPPMfrQZGXmlluq6dO2lL31W6WRRE8fabc4Q=
github.com/Dreamacro/go-shadowsocks2 v0.1.7/go.mod h1:8p5G4cAj5ZlXwUR+Ww63gfSikr8kvw8uw3TDwLAJpUc=
github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
@@ -622,8 +622,8 @@ go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
-go.uber.org/atomic v1.8.0 h1:CUhrE4N1rqSE6FM9ecihEjRkLQu8cDfgDyoOs83mEY4=
-go.uber.org/atomic v1.8.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
+go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
+go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
@@ -640,8 +640,8 @@ golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210317152858-513c2a44f670/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
-golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e h1:gsTQYXdTw2Gq7RBsWvlQ91b+aEQ6bXFUngBGuR8sPpI=
-golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 h1:HWj/xjIHfjYU5nVXpTM0s39J9CbLn7Cc5a7IC5rwsMQ=
+golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -707,7 +707,6 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
-golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d h1:LO7XpTYMwTqxjLcGWPijK3vRXg1aWdlNOVOHRq45d7c=
golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@@ -791,8 +790,8 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I=
-golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210817190340-bfb29a6856f2 h1:c8PlLMqBbOHoqtjteWm5/kbe6rNY2pbRfbIMVnepueo=
+golang.org/x/sys v0.0.0-20210817190340-bfb29a6856f2/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
diff --git a/test/vmess_test.go b/test/vmess_test.go
index 7791abee8..6070354af 100644
--- a/test/vmess_test.go
+++ b/test/vmess_test.go
@@ -346,6 +346,47 @@ func TestClash_VmessGrpc(t *testing.T) {
testSuit(t, proxy)
}
+func TestClash_VmessWebsocket0RTT(t *testing.T) {
+ cfg := &container.Config{
+ Image: ImageXray,
+ ExposedPorts: defaultExposedPorts,
+ }
+ hostCfg := &container.HostConfig{
+ PortBindings: defaultPortBindings,
+ Binds: []string{
+ fmt.Sprintf("%s:/etc/xray/config.json", C.Path.Resolve("vmess-ws-0rtt.json")),
+ },
+ }
+
+ id, err := startContainer(cfg, hostCfg, "vmess-ws-0rtt")
+ if err != nil {
+ assert.FailNow(t, err.Error())
+ }
+ defer cleanContainer(id)
+
+ proxy, err := outbound.NewVmess(outbound.VmessOption{
+ Name: "vmess",
+ Server: localIP.String(),
+ Port: 10002,
+ UUID: "b831381d-6324-4d53-ad4f-8cda48b30811",
+ Cipher: "auto",
+ AlterID: 32,
+ Network: "ws",
+ UDP: true,
+ ServerName: "example.org",
+ WSOpts: outbound.WSOptions{
+ MaxEarlyData: 2048,
+ EarlyDataHeaderName: "Sec-WebSocket-Protocol",
+ },
+ })
+ if err != nil {
+ assert.FailNow(t, err.Error())
+ }
+
+ time.Sleep(waitTime)
+ testSuit(t, proxy)
+}
+
func Benchmark_Vmess(b *testing.B) {
configPath := C.Path.Resolve("vmess-aead.json")
From 4522cdc55170b85d5ed185244e01492296ef5d4f Mon Sep 17 00:00:00 2001
From: wwqgtxx
Date: Sun, 22 Aug 2021 16:03:46 +0800
Subject: [PATCH 46/96] Feature: support xray's ws-0rtt path (#1558)
---
transport/vmess/websocket.go | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/transport/vmess/websocket.go b/transport/vmess/websocket.go
index 956b6d957..7d7a75bb5 100644
--- a/transport/vmess/websocket.go
+++ b/transport/vmess/websocket.go
@@ -11,6 +11,7 @@ import (
"net"
"net/http"
"net/url"
+ "strconv"
"strings"
"sync"
"time"
@@ -305,6 +306,18 @@ func streamWebsocketConn(conn net.Conn, c *WebsocketConfig, earlyData *bytes.Buf
}
func StreamWebsocketConn(conn net.Conn, c *WebsocketConfig) (net.Conn, error) {
+ if u, err := url.Parse(c.Path); err == nil {
+ if q := u.Query(); q.Get("ed") != "" {
+ if ed, err := strconv.Atoi(q.Get("ed")); err == nil {
+ c.MaxEarlyData = ed
+ c.EarlyDataHeaderName = "Sec-WebSocket-Protocol"
+ q.Del("ed")
+ u.RawQuery = q.Encode()
+ c.Path = u.String()
+ }
+ }
+ }
+
if c.MaxEarlyData > 0 {
return streamWebsocketWithEarlyDataConn(conn, c)
}
From 121bc910f6e5a5faa38c0e3f87e4eea1f0bd8f1b Mon Sep 17 00:00:00 2001
From: Dreamacro <8615343+Dreamacro@users.noreply.github.com>
Date: Sun, 22 Aug 2021 16:16:45 +0800
Subject: [PATCH 47/96] Chore: adjust vmess 0rtt code and split xray test
---
test/vmess_test.go | 44 ++++++++++++++++++++++++++++++++++--
transport/vmess/websocket.go | 19 +++++++---------
2 files changed, 50 insertions(+), 13 deletions(-)
diff --git a/test/vmess_test.go b/test/vmess_test.go
index 6070354af..b696fcea7 100644
--- a/test/vmess_test.go
+++ b/test/vmess_test.go
@@ -348,13 +348,13 @@ func TestClash_VmessGrpc(t *testing.T) {
func TestClash_VmessWebsocket0RTT(t *testing.T) {
cfg := &container.Config{
- Image: ImageXray,
+ Image: ImageVmess,
ExposedPorts: defaultExposedPorts,
}
hostCfg := &container.HostConfig{
PortBindings: defaultPortBindings,
Binds: []string{
- fmt.Sprintf("%s:/etc/xray/config.json", C.Path.Resolve("vmess-ws-0rtt.json")),
+ fmt.Sprintf("%s:/etc/v2ray/config.json", C.Path.Resolve("vmess-ws-0rtt.json")),
},
}
@@ -387,6 +387,46 @@ func TestClash_VmessWebsocket0RTT(t *testing.T) {
testSuit(t, proxy)
}
+func TestClash_VmessWebsocketXray0RTT(t *testing.T) {
+ cfg := &container.Config{
+ Image: ImageXray,
+ ExposedPorts: defaultExposedPorts,
+ }
+ hostCfg := &container.HostConfig{
+ PortBindings: defaultPortBindings,
+ Binds: []string{
+ fmt.Sprintf("%s:/etc/xray/config.json", C.Path.Resolve("vmess-ws-0rtt.json")),
+ },
+ }
+
+ id, err := startContainer(cfg, hostCfg, "vmess-xray-ws-0rtt")
+ if err != nil {
+ assert.FailNow(t, err.Error())
+ }
+ defer cleanContainer(id)
+
+ proxy, err := outbound.NewVmess(outbound.VmessOption{
+ Name: "vmess",
+ Server: localIP.String(),
+ Port: 10002,
+ UUID: "b831381d-6324-4d53-ad4f-8cda48b30811",
+ Cipher: "auto",
+ AlterID: 32,
+ Network: "ws",
+ UDP: true,
+ ServerName: "example.org",
+ WSOpts: outbound.WSOptions{
+ Path: "/?ed=2048",
+ },
+ })
+ if err != nil {
+ assert.FailNow(t, err.Error())
+ }
+
+ time.Sleep(waitTime)
+ testSuit(t, proxy)
+}
+
func Benchmark_Vmess(b *testing.B) {
configPath := C.Path.Resolve("vmess-aead.json")
diff --git a/transport/vmess/websocket.go b/transport/vmess/websocket.go
index 7d7a75bb5..f00e4c4bf 100644
--- a/transport/vmess/websocket.go
+++ b/transport/vmess/websocket.go
@@ -130,14 +130,12 @@ func (wsc *websocketConn) SetWriteDeadline(t time.Time) error {
}
func (wsedc *websocketWithEarlyDataConn) Dial(earlyData []byte) error {
- earlyDataBuf := bytes.NewBuffer(nil)
- base64EarlyDataEncoder := base64.NewEncoder(base64.RawURLEncoding, earlyDataBuf)
+ base64DataBuf := &bytes.Buffer{}
+ base64EarlyDataEncoder := base64.NewEncoder(base64.RawURLEncoding, base64DataBuf)
- earlydata := bytes.NewReader(earlyData)
- limitedEarlyDatareader := io.LimitReader(earlydata, int64(wsedc.config.MaxEarlyData))
- n, encerr := io.Copy(base64EarlyDataEncoder, limitedEarlyDatareader)
- if encerr != nil {
- return errors.New("failed to encode early data: " + encerr.Error())
+ earlyDataBuf := bytes.NewBuffer(earlyData)
+ if _, err := base64EarlyDataEncoder.Write(earlyDataBuf.Next(wsedc.config.MaxEarlyData)); err != nil {
+ return errors.New("failed to encode early data: " + err.Error())
}
if errc := base64EarlyDataEncoder.Close(); errc != nil {
@@ -145,15 +143,14 @@ func (wsedc *websocketWithEarlyDataConn) Dial(earlyData []byte) error {
}
var err error
- if wsedc.Conn, err = streamWebsocketConn(wsedc.underlay, wsedc.config, earlyDataBuf); err != nil {
+ if wsedc.Conn, err = streamWebsocketConn(wsedc.underlay, wsedc.config, base64DataBuf); err != nil {
wsedc.Close()
return errors.New("failed to dial WebSocket: " + err.Error())
}
wsedc.dialed <- true
-
- if n != int64(len(earlyData)) {
- _, err = wsedc.Conn.Write(earlyData[n:])
+ if earlyDataBuf.Len() != 0 {
+ _, err = wsedc.Conn.Write(earlyDataBuf.Bytes())
}
return err
From e0d3f926b752a0f22a8c7b77f6b349819051939c Mon Sep 17 00:00:00 2001
From: Dreamacro <8615343+Dreamacro@users.noreply.github.com>
Date: Wed, 25 Aug 2021 15:15:13 +0800
Subject: [PATCH 48/96] Feature: add geoip-code option
---
config/config.go | 20 ++++++++++++--------
dns/filters.go | 6 ++++--
dns/resolver.go | 11 +++++++----
hub/executor/executor.go | 7 ++++---
4 files changed, 27 insertions(+), 17 deletions(-)
diff --git a/config/config.go b/config/config.go
index a9628192b..dc559ecf5 100644
--- a/config/config.go
+++ b/config/config.go
@@ -71,9 +71,10 @@ type DNS struct {
// FallbackFilter config
type FallbackFilter struct {
- GeoIP bool `yaml:"geoip"`
- IPCIDR []*net.IPNet `yaml:"ipcidr"`
- Domain []string `yaml:"domain"`
+ GeoIP bool `yaml:"geoip"`
+ GeoIPCode string `yaml:"geoip-code"`
+ IPCIDR []*net.IPNet `yaml:"ipcidr"`
+ Domain []string `yaml:"domain"`
}
// Profile config
@@ -113,9 +114,10 @@ type RawDNS struct {
}
type RawFallbackFilter struct {
- GeoIP bool `yaml:"geoip"`
- IPCIDR []string `yaml:"ipcidr"`
- Domain []string `yaml:"domain"`
+ GeoIP bool `yaml:"geoip"`
+ GeoIPCode string `yaml:"geoip-code"`
+ IPCIDR []string `yaml:"ipcidr"`
+ Domain []string `yaml:"domain"`
}
type RawConfig struct {
@@ -172,8 +174,9 @@ func UnmarshalRawConfig(buf []byte) (*RawConfig, error) {
UseHosts: true,
FakeIPRange: "198.18.0.1/16",
FallbackFilter: RawFallbackFilter{
- GeoIP: true,
- IPCIDR: []string{},
+ GeoIP: true,
+ GeoIPCode: "CN",
+ IPCIDR: []string{},
},
DefaultNameserver: []string{
"114.114.114.114",
@@ -600,6 +603,7 @@ func parseDNS(cfg RawDNS, hosts *trie.DomainTrie) (*DNS, error) {
}
dnsCfg.FallbackFilter.GeoIP = cfg.FallbackFilter.GeoIP
+ dnsCfg.FallbackFilter.GeoIPCode = cfg.FallbackFilter.GeoIPCode
if fallbackip, err := parseFallbackIPCIDR(cfg.FallbackFilter.IPCIDR); err == nil {
dnsCfg.FallbackFilter.IPCIDR = fallbackip
}
diff --git a/dns/filters.go b/dns/filters.go
index a6bc6c544..c9cece05c 100644
--- a/dns/filters.go
+++ b/dns/filters.go
@@ -11,11 +11,13 @@ type fallbackIPFilter interface {
Match(net.IP) bool
}
-type geoipFilter struct{}
+type geoipFilter struct {
+ code string
+}
func (gf *geoipFilter) Match(ip net.IP) bool {
record, _ := mmdb.Instance().Country(ip)
- return record.Country.IsoCode != "CN" && !ip.IsPrivate()
+ return record.Country.IsoCode != gf.code && !ip.IsPrivate()
}
type ipnetFilter struct {
diff --git a/dns/resolver.go b/dns/resolver.go
index 1ca0293ea..56b5e3268 100644
--- a/dns/resolver.go
+++ b/dns/resolver.go
@@ -302,9 +302,10 @@ type NameServer struct {
}
type FallbackFilter struct {
- GeoIP bool
- IPCIDR []*net.IPNet
- Domain []string
+ GeoIP bool
+ GeoIPCode string
+ IPCIDR []*net.IPNet
+ Domain []string
}
type Config struct {
@@ -344,7 +345,9 @@ func NewResolver(config Config) *Resolver {
fallbackIPFilters := []fallbackIPFilter{}
if config.FallbackFilter.GeoIP {
- fallbackIPFilters = append(fallbackIPFilters, &geoipFilter{})
+ fallbackIPFilters = append(fallbackIPFilters, &geoipFilter{
+ code: config.FallbackFilter.GeoIPCode,
+ })
}
for _, ipnet := range config.FallbackFilter.IPCIDR {
fallbackIPFilters = append(fallbackIPFilters, &ipnetFilter{ipnet: ipnet})
diff --git a/hub/executor/executor.go b/hub/executor/executor.go
index b3772211f..121e1d01d 100644
--- a/hub/executor/executor.go
+++ b/hub/executor/executor.go
@@ -123,9 +123,10 @@ func updateDNS(c *config.DNS) {
Pool: c.FakeIPRange,
Hosts: c.Hosts,
FallbackFilter: dns.FallbackFilter{
- GeoIP: c.FallbackFilter.GeoIP,
- IPCIDR: c.FallbackFilter.IPCIDR,
- Domain: c.FallbackFilter.Domain,
+ GeoIP: c.FallbackFilter.GeoIP,
+ GeoIPCode: c.FallbackFilter.GeoIPCode,
+ IPCIDR: c.FallbackFilter.IPCIDR,
+ Domain: c.FallbackFilter.Domain,
},
Default: c.DefaultNameserver,
Policy: c.NameServerPolicy,
From a20b9a3960658fb2844e5c52200705f1fc5cb90e Mon Sep 17 00:00:00 2001
From: Loyalsoldier <10487845+Loyalsoldier@users.noreply.github.com>
Date: Sun, 29 Aug 2021 22:19:22 +0800
Subject: [PATCH 49/96] Chore: make geoip match case-insensitive (#1574)
---
dns/filters.go | 3 ++-
rule/geoip.go | 6 ++++--
2 files changed, 6 insertions(+), 3 deletions(-)
diff --git a/dns/filters.go b/dns/filters.go
index c9cece05c..bacd7727f 100644
--- a/dns/filters.go
+++ b/dns/filters.go
@@ -2,6 +2,7 @@ package dns
import (
"net"
+ "strings"
"github.com/Dreamacro/clash/component/mmdb"
"github.com/Dreamacro/clash/component/trie"
@@ -17,7 +18,7 @@ type geoipFilter struct {
func (gf *geoipFilter) Match(ip net.IP) bool {
record, _ := mmdb.Instance().Country(ip)
- return record.Country.IsoCode != gf.code && !ip.IsPrivate()
+ return !strings.EqualFold(record.Country.IsoCode, gf.code) && !ip.IsPrivate()
}
type ipnetFilter struct {
diff --git a/rule/geoip.go b/rule/geoip.go
index 0b94c4c28..3b6fbe6b8 100644
--- a/rule/geoip.go
+++ b/rule/geoip.go
@@ -1,6 +1,8 @@
package rules
import (
+ "strings"
+
"github.com/Dreamacro/clash/component/mmdb"
C "github.com/Dreamacro/clash/constant"
)
@@ -21,11 +23,11 @@ func (g *GEOIP) Match(metadata *C.Metadata) bool {
return false
}
- if g.country == "LAN" {
+ if strings.EqualFold(g.country, "LAN") {
return ip.IsPrivate()
}
record, _ := mmdb.Instance().Country(ip)
- return record.Country.IsoCode == g.country
+ return strings.EqualFold(record.Country.IsoCode, g.country)
}
func (g *GEOIP) Adapter() string {
From 7d20097465fc0e8d91b8a3f2434b471fcc144e3d Mon Sep 17 00:00:00 2001
From: Dreamacro <8615343+Dreamacro@users.noreply.github.com>
Date: Mon, 30 Aug 2021 00:15:57 +0800
Subject: [PATCH 50/96] Fix: ssr auth aes128 udp hmac verify
---
transport/ssr/protocol/auth_aes128_sha1.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/transport/ssr/protocol/auth_aes128_sha1.go b/transport/ssr/protocol/auth_aes128_sha1.go
index 65bcd7416..fab9d0081 100644
--- a/transport/ssr/protocol/auth_aes128_sha1.go
+++ b/transport/ssr/protocol/auth_aes128_sha1.go
@@ -152,7 +152,7 @@ func (a *authAES128) Encode(buf *bytes.Buffer, b []byte) error {
}
func (a *authAES128) DecodePacket(b []byte) ([]byte, error) {
- if !bytes.Equal(a.hmac(a.Key, b[:len(b)-4])[:4], b[len(b)-4:]) {
+ if !bytes.Equal(a.hmac(a.userKey, b[:len(b)-4])[:4], b[len(b)-4:]) {
return nil, errAuthAES128ChksumError
}
return b[:len(b)-4], nil
From 661c417fceae6fd5f6c9f21a32bbacd6ff528c46 Mon Sep 17 00:00:00 2001
From: Dreamacro <8615343+Dreamacro@users.noreply.github.com>
Date: Sat, 4 Sep 2021 22:31:08 +0800
Subject: [PATCH 51/96] Test: use shadowsocks-rust for ss benchmark
---
test/clash_test.go | 11 ++++++-----
test/ss_test.go | 10 ++++++----
2 files changed, 12 insertions(+), 9 deletions(-)
diff --git a/test/clash_test.go b/test/clash_test.go
index 366cc260b..b31922832 100644
--- a/test/clash_test.go
+++ b/test/clash_test.go
@@ -27,11 +27,12 @@ import (
)
const (
- ImageShadowsocks = "mritd/shadowsocks:latest"
- ImageVmess = "v2fly/v2fly-core:latest"
- ImageTrojan = "trojangfw/trojan:latest"
- ImageSnell = "icpz/snell-server:latest"
- ImageXray = "teddysun/xray:latest"
+ ImageShadowsocks = "mritd/shadowsocks:latest"
+ ImageShadowsocksRust = "ghcr.io/shadowsocks/ssserver-rust:latest"
+ ImageVmess = "v2fly/v2fly-core:latest"
+ ImageTrojan = "trojangfw/trojan:latest"
+ ImageSnell = "icpz/snell-server:latest"
+ ImageXray = "teddysun/xray:latest"
)
var (
diff --git a/test/ss_test.go b/test/ss_test.go
index 7cba7efd9..446bae938 100644
--- a/test/ss_test.go
+++ b/test/ss_test.go
@@ -12,8 +12,9 @@ import (
func TestClash_Shadowsocks(t *testing.T) {
cfg := &container.Config{
- Image: ImageShadowsocks,
- Env: []string{"SS_MODULE=ss-server", "SS_CONFIG=-s 0.0.0.0 -u -v -p 10002 -m chacha20-ietf-poly1305 -k FzcLbKs2dY9mhL"},
+ Image: ImageShadowsocksRust,
+ Entrypoint: []string{"ssserver"},
+ Cmd: []string{"-s", "0.0.0.0:10002", "-m", "chacha20-ietf-poly1305", "-k", "FzcLbKs2dY9mhL", "-U"},
ExposedPorts: defaultExposedPorts,
}
hostCfg := &container.HostConfig{
@@ -173,8 +174,9 @@ func TestClash_ShadowsocksV2RayPlugin(t *testing.T) {
func Benchmark_Shadowsocks(b *testing.B) {
cfg := &container.Config{
- Image: ImageShadowsocks,
- Env: []string{"SS_MODULE=ss-server", "SS_CONFIG=-s 0.0.0.0 -u -v -p 10002 -m aes-256-gcm -k FzcLbKs2dY9mhL"},
+ Image: ImageShadowsocksRust,
+ Entrypoint: []string{"ssserver"},
+ Cmd: []string{"-s", "0.0.0.0:10002", "-m", "aes-256-gcm", "-k", "FzcLbKs2dY9mhL", "-U"},
ExposedPorts: defaultExposedPorts,
}
hostCfg := &container.HostConfig{
From ff56e5c5de10c70dfd8b9c674ed2e322a902baeb Mon Sep 17 00:00:00 2001
From: Dreamacro <8615343+Dreamacro@users.noreply.github.com>
Date: Sat, 4 Sep 2021 22:44:18 +0800
Subject: [PATCH 52/96] Test: fix direct listen fail
---
test/clash_test.go | 13 +++++++------
test/util.go | 37 +++++++++++++++++++++++++++++++++++++
test/util_other_test.go | 1 +
3 files changed, 45 insertions(+), 6 deletions(-)
create mode 100644 test/util.go
diff --git a/test/clash_test.go b/test/clash_test.go
index b31922832..e6cb14a15 100644
--- a/test/clash_test.go
+++ b/test/clash_test.go
@@ -210,7 +210,7 @@ func newLargeDataPair() (chan hashPair, chan hashPair, func(t *testing.T) error)
func testPingPongWithSocksPort(t *testing.T, port int) {
pingCh, pongCh, test := newPingPongPair()
go func() {
- l, err := net.Listen("tcp", ":10001")
+ l, err := Listen("tcp", ":10001")
if err != nil {
assert.FailNow(t, err.Error())
}
@@ -259,7 +259,7 @@ func testPingPongWithSocksPort(t *testing.T, port int) {
}
func testPingPongWithConn(t *testing.T, c net.Conn) error {
- l, err := net.Listen("tcp", ":10001")
+ l, err := Listen("tcp", ":10001")
if err != nil {
return err
}
@@ -300,7 +300,7 @@ func testPingPongWithConn(t *testing.T, c net.Conn) error {
}
func testPingPongWithPacketConn(t *testing.T, pc net.PacketConn) error {
- l, err := net.ListenPacket("udp", ":10001")
+ l, err := ListenPacket("udp", ":10001")
if err != nil {
return err
}
@@ -345,7 +345,7 @@ type hashPair struct {
}
func testLargeDataWithConn(t *testing.T, c net.Conn) error {
- l, err := net.Listen("tcp", ":10001")
+ l, err := Listen("tcp", ":10001")
if err != nil {
return err
}
@@ -438,7 +438,7 @@ func testLargeDataWithConn(t *testing.T, c net.Conn) error {
}
func testLargeDataWithPacketConn(t *testing.T, pc net.PacketConn) error {
- l, err := net.ListenPacket("udp", ":10001")
+ l, err := ListenPacket("udp", ":10001")
if err != nil {
return err
}
@@ -622,7 +622,7 @@ func testSuit(t *testing.T, proxy C.ProxyAdapter) {
}
func benchmarkProxy(b *testing.B, proxy C.ProxyAdapter) {
- l, err := net.Listen("tcp", ":10001")
+ l, err := Listen("tcp", ":10001")
if err != nil {
assert.FailNow(b, err.Error())
}
@@ -639,6 +639,7 @@ func benchmarkProxy(b *testing.B, proxy C.ProxyAdapter) {
chunkSize := int64(16 * 1024)
chunk := make([]byte, chunkSize)
+ rand.Read(chunk)
conn, err := proxy.DialContext(context.Background(), &C.Metadata{
Host: localIP.String(),
DstPort: "10001",
diff --git a/test/util.go b/test/util.go
new file mode 100644
index 000000000..f3325aeb6
--- /dev/null
+++ b/test/util.go
@@ -0,0 +1,37 @@
+package main
+
+import (
+ "context"
+ "net"
+ "time"
+)
+
+func Listen(network, address string) (net.Listener, error) {
+ lc := net.ListenConfig{}
+
+ var lastErr error
+ for i := 0; i < 5; i++ {
+ l, err := lc.Listen(context.Background(), network, address)
+ if err == nil {
+ return l, nil
+ }
+
+ lastErr = err
+ time.Sleep(time.Millisecond * 200)
+ }
+ return nil, lastErr
+}
+
+func ListenPacket(network, address string) (net.PacketConn, error) {
+ var lastErr error
+ for i := 0; i < 5; i++ {
+ l, err := net.ListenPacket(network, address)
+ if err == nil {
+ return l, nil
+ }
+
+ lastErr = err
+ time.Sleep(time.Millisecond * 200)
+ }
+ return nil, lastErr
+}
diff --git a/test/util_other_test.go b/test/util_other_test.go
index e325bd8ba..13ba87f33 100644
--- a/test/util_other_test.go
+++ b/test/util_other_test.go
@@ -1,3 +1,4 @@
+//go:build !darwin
// +build !darwin
package main
From c7b718f6512d612e1f342da3c3b7876e6d301a82 Mon Sep 17 00:00:00 2001
From: Dreamacro <8615343+Dreamacro@users.noreply.github.com>
Date: Sun, 5 Sep 2021 14:25:55 +0800
Subject: [PATCH 53/96] Test: release resources correctly
---
test/clash_test.go | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/test/clash_test.go b/test/clash_test.go
index e6cb14a15..4011b04a4 100644
--- a/test/clash_test.go
+++ b/test/clash_test.go
@@ -214,6 +214,7 @@ func testPingPongWithSocksPort(t *testing.T, port int) {
if err != nil {
assert.FailNow(t, err.Error())
}
+ defer l.Close()
c, err := l.Accept()
if err != nil {
@@ -229,7 +230,6 @@ func testPingPongWithSocksPort(t *testing.T, port int) {
if _, err := c.Write([]byte("pong")); err != nil {
assert.FailNow(t, err.Error())
}
- l.Close()
}()
go func() {
@@ -237,6 +237,7 @@ func testPingPongWithSocksPort(t *testing.T, port int) {
if err != nil {
assert.FailNow(t, err.Error())
}
+ defer c.Close()
if _, err := socks5.ClientHandshake(c, socks5.ParseAddr("127.0.0.1:10001"), socks5.CmdConnect, nil); err != nil {
assert.FailNow(t, err.Error())
@@ -252,7 +253,6 @@ func testPingPongWithSocksPort(t *testing.T, port int) {
}
pongCh <- buf
- c.Close()
}()
test(t)
@@ -380,6 +380,7 @@ func testLargeDataWithConn(t *testing.T, c net.Conn) error {
if err != nil {
return
}
+ defer c.Close()
hashMap := map[int][]byte{}
buf := make([]byte, chunkSize)
@@ -626,15 +627,16 @@ func benchmarkProxy(b *testing.B, proxy C.ProxyAdapter) {
if err != nil {
assert.FailNow(b, err.Error())
}
+ defer l.Close()
go func() {
c, err := l.Accept()
if err != nil {
assert.FailNow(b, err.Error())
}
+ defer c.Close()
io.Copy(io.Discard, c)
- c.Close()
}()
chunkSize := int64(16 * 1024)
From 8ef5cdb8be15e1a5f1c084ea81f83cf166772509 Mon Sep 17 00:00:00 2001
From: Dreamacro <8615343+Dreamacro@users.noreply.github.com>
Date: Sun, 5 Sep 2021 14:38:07 +0800
Subject: [PATCH 54/96] Test: use local clash pkg
---
test/go.mod | 4 +++-
test/go.sum | 2 --
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/test/go.mod b/test/go.mod
index 5d86eda93..97d3a79c6 100644
--- a/test/go.mod
+++ b/test/go.mod
@@ -3,7 +3,7 @@ module clash-test
go 1.17
require (
- github.com/Dreamacro/clash v1.6.6-0.20210821162529-0267b2efad9a
+ github.com/Dreamacro/clash v1.6.6-0.20210905062555-c7b718f6512d
github.com/docker/docker v20.10.8+incompatible
github.com/docker/go-connections v0.4.0
github.com/miekg/dns v1.1.43
@@ -11,6 +11,8 @@ require (
golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d
)
+replace github.com/Dreamacro/clash => ../
+
require (
github.com/Dreamacro/go-shadowsocks2 v0.1.7 // indirect
github.com/Microsoft/go-winio v0.5.0 // indirect
diff --git a/test/go.sum b/test/go.sum
index e83047937..c2b68eafd 100644
--- a/test/go.sum
+++ b/test/go.sum
@@ -38,8 +38,6 @@ github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZ
github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
-github.com/Dreamacro/clash v1.6.6-0.20210821162529-0267b2efad9a h1:Y+EWU18ZaK9ZxcZGv2O3nUzGk3XYLZe2r5i8FMku7wA=
-github.com/Dreamacro/clash v1.6.6-0.20210821162529-0267b2efad9a/go.mod h1:eN07P85tFwbnkHnEQPYlFsyTc8spXBNa4fOFUea6F58=
github.com/Dreamacro/go-shadowsocks2 v0.1.7 h1:8CtbE1HoPPMfrQZGXmlluq6dO2lL31W6WRRE8fabc4Q=
github.com/Dreamacro/go-shadowsocks2 v0.1.7/go.mod h1:8p5G4cAj5ZlXwUR+Ww63gfSikr8kvw8uw3TDwLAJpUc=
github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
From a2d59d6ef540e9e6831e988e6c43e2a3efc6e9ea Mon Sep 17 00:00:00 2001
From: Excited Codes <61885669+ExcitedCodes@users.noreply.github.com>
Date: Mon, 6 Sep 2021 21:39:28 +0800
Subject: [PATCH 55/96] Feature: skip DIRECT proxies in relay (#1583)
---
adapter/outboundgroup/relay.go | 17 +++++++++++++----
1 file changed, 13 insertions(+), 4 deletions(-)
diff --git a/adapter/outboundgroup/relay.go b/adapter/outboundgroup/relay.go
index 8d8128bac..78410a449 100644
--- a/adapter/outboundgroup/relay.go
+++ b/adapter/outboundgroup/relay.go
@@ -3,7 +3,6 @@ package outboundgroup
import (
"context"
"encoding/json"
- "errors"
"fmt"
"github.com/Dreamacro/clash/adapter/outbound"
@@ -21,10 +20,20 @@ type Relay struct {
// DialContext implements C.ProxyAdapter
func (r *Relay) DialContext(ctx context.Context, metadata *C.Metadata) (C.Conn, error) {
- proxies := r.proxies(metadata, true)
- if len(proxies) == 0 {
- return nil, errors.New("proxy does not exist")
+ var proxies []C.Proxy
+ for _, proxy := range r.proxies(metadata, true) {
+ if proxy.Type() != C.Direct {
+ proxies = append(proxies, proxy)
+ }
}
+
+ switch len(proxies) {
+ case 0:
+ return outbound.NewDirect().DialContext(ctx, metadata)
+ case 1:
+ return proxies[0].DialContext(ctx, metadata)
+ }
+
first := proxies[0]
last := proxies[len(proxies)-1]
From a5b950a779871ae7045653a242bc7b3906011cdd Mon Sep 17 00:00:00 2001
From: Kr328
Date: Mon, 6 Sep 2021 23:07:34 +0800
Subject: [PATCH 56/96] Feature: add dhcp type dns client (#1509)
---
adapter/outbound/direct.go | 2 +-
adapter/outbound/shadowsocks.go | 2 +-
adapter/outbound/shadowsocksr.go | 2 +-
adapter/outbound/socks5.go | 2 +-
adapter/provider/vehicle.go | 5 +-
component/dhcp/conn.go | 18 ++++
component/dhcp/dhcp.go | 94 +++++++++++++++++++
component/dialer/bind.go | 118 ------------------------
component/dialer/bind_darwin.go | 40 +++++----
component/dialer/bind_linux.go | 26 ++++--
component/dialer/bind_others.go | 89 ++++++++++++++++--
component/dialer/dialer.go | 97 ++++++++++----------
component/dialer/hook.go | 43 ---------
component/dialer/options.go | 31 +++++++
component/dialer/reuse_others.go | 10 +++
component/dialer/reuse_unix.go | 28 ++++++
component/dialer/reuse_windows.go | 24 +++++
component/iface/iface.go | 113 +++++++++++++++++++++++
config/config.go | 3 +
dns/client.go | 33 ++++---
dns/dhcp.go | 144 ++++++++++++++++++++++++++++++
dns/resolver.go | 35 ++++----
dns/util.go | 6 +-
go.mod | 8 +-
go.sum | 65 ++++++++++++--
hub/executor/executor.go | 9 +-
26 files changed, 759 insertions(+), 288 deletions(-)
create mode 100644 component/dhcp/conn.go
create mode 100644 component/dhcp/dhcp.go
delete mode 100644 component/dialer/bind.go
delete mode 100644 component/dialer/hook.go
create mode 100644 component/dialer/options.go
create mode 100644 component/dialer/reuse_others.go
create mode 100644 component/dialer/reuse_unix.go
create mode 100644 component/dialer/reuse_windows.go
create mode 100644 component/iface/iface.go
create mode 100644 dns/dhcp.go
diff --git a/adapter/outbound/direct.go b/adapter/outbound/direct.go
index 83ea22eb8..4b53e306c 100644
--- a/adapter/outbound/direct.go
+++ b/adapter/outbound/direct.go
@@ -24,7 +24,7 @@ func (d *Direct) DialContext(ctx context.Context, metadata *C.Metadata) (C.Conn,
// DialUDP implements C.ProxyAdapter
func (d *Direct) DialUDP(metadata *C.Metadata) (C.PacketConn, error) {
- pc, err := dialer.ListenPacket("udp", "")
+ pc, err := dialer.ListenPacket(context.Background(), "udp", "")
if err != nil {
return nil, err
}
diff --git a/adapter/outbound/shadowsocks.go b/adapter/outbound/shadowsocks.go
index 39d1e36d0..64b431a9b 100644
--- a/adapter/outbound/shadowsocks.go
+++ b/adapter/outbound/shadowsocks.go
@@ -89,7 +89,7 @@ func (ss *ShadowSocks) DialContext(ctx context.Context, metadata *C.Metadata) (_
// DialUDP implements C.ProxyAdapter
func (ss *ShadowSocks) DialUDP(metadata *C.Metadata) (C.PacketConn, error) {
- pc, err := dialer.ListenPacket("udp", "")
+ pc, err := dialer.ListenPacket(context.Background(), "udp", "")
if err != nil {
return nil, err
}
diff --git a/adapter/outbound/shadowsocksr.go b/adapter/outbound/shadowsocksr.go
index b44f46e56..9ba8bc229 100644
--- a/adapter/outbound/shadowsocksr.go
+++ b/adapter/outbound/shadowsocksr.go
@@ -74,7 +74,7 @@ func (ssr *ShadowSocksR) DialContext(ctx context.Context, metadata *C.Metadata)
// DialUDP implements C.ProxyAdapter
func (ssr *ShadowSocksR) DialUDP(metadata *C.Metadata) (C.PacketConn, error) {
- pc, err := dialer.ListenPacket("udp", "")
+ pc, err := dialer.ListenPacket(context.Background(), "udp", "")
if err != nil {
return nil, err
}
diff --git a/adapter/outbound/socks5.go b/adapter/outbound/socks5.go
index 8106e0e2e..1402c6186 100644
--- a/adapter/outbound/socks5.go
+++ b/adapter/outbound/socks5.go
@@ -110,7 +110,7 @@ func (ss *Socks5) DialUDP(metadata *C.Metadata) (_ C.PacketConn, err error) {
return
}
- pc, err := dialer.ListenPacket("udp", "")
+ pc, err := dialer.ListenPacket(context.Background(), "udp", "")
if err != nil {
return
}
diff --git a/adapter/provider/vehicle.go b/adapter/provider/vehicle.go
index ea6a835a2..f556e69c4 100644
--- a/adapter/provider/vehicle.go
+++ b/adapter/provider/vehicle.go
@@ -3,6 +3,7 @@ package provider
import (
"context"
"io/ioutil"
+ "net"
"net/http"
"net/url"
"time"
@@ -71,7 +72,9 @@ func (h *HTTPVehicle) Read() ([]byte, error) {
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
- DialContext: dialer.DialContext,
+ DialContext: func(ctx context.Context, network, address string) (net.Conn, error) {
+ return dialer.DialContext(ctx, network, address)
+ },
}
client := http.Client{Transport: transport}
diff --git a/component/dhcp/conn.go b/component/dhcp/conn.go
new file mode 100644
index 000000000..90a9e25b5
--- /dev/null
+++ b/component/dhcp/conn.go
@@ -0,0 +1,18 @@
+package dhcp
+
+import (
+ "context"
+ "net"
+ "runtime"
+
+ "github.com/Dreamacro/clash/component/dialer"
+)
+
+func ListenDHCPClient(ctx context.Context, ifaceName string) (net.PacketConn, error) {
+ listenAddr := "0.0.0.0:68"
+ if runtime.GOOS == "linux" || runtime.GOOS == "android" {
+ listenAddr = "255.255.255.255:68"
+ }
+
+ return dialer.ListenPacket(ctx, "udp4", listenAddr, dialer.WithInterface(ifaceName), dialer.WithAddrReuse(true))
+}
diff --git a/component/dhcp/dhcp.go b/component/dhcp/dhcp.go
new file mode 100644
index 000000000..b2ca6928f
--- /dev/null
+++ b/component/dhcp/dhcp.go
@@ -0,0 +1,94 @@
+package dhcp
+
+import (
+ "context"
+ "errors"
+ "math/rand"
+ "net"
+
+ "github.com/insomniacslk/dhcp/dhcpv4"
+)
+
+var (
+ ErrNotResponding = errors.New("DHCP not responding")
+ ErrNotFound = errors.New("DNS option not found")
+)
+
+func ResolveDNSFromDHCP(context context.Context, ifaceName string) ([]net.IP, error) {
+ conn, err := ListenDHCPClient(context, ifaceName)
+ if err != nil {
+ return nil, err
+ }
+ defer conn.Close()
+
+ result := make(chan []net.IP, 1)
+
+ discovery, err := dhcpv4.NewDiscovery(randomHardware(), dhcpv4.WithBroadcast(true), dhcpv4.WithRequestedOptions(dhcpv4.OptionDomainNameServer))
+ if err != nil {
+ return nil, err
+ }
+
+ go receiveOffer(conn, discovery.TransactionID, result)
+
+ _, err = conn.WriteTo(discovery.ToBytes(), &net.UDPAddr{IP: net.IPv4bcast, Port: 67})
+ if err != nil {
+ return nil, err
+ }
+
+ select {
+ case r, ok := <-result:
+ if !ok {
+ return nil, ErrNotFound
+ }
+ return r, nil
+ case <-context.Done():
+ return nil, ErrNotResponding
+ }
+}
+
+func receiveOffer(conn net.PacketConn, id dhcpv4.TransactionID, result chan<- []net.IP) {
+ defer close(result)
+
+ buf := make([]byte, dhcpv4.MaxMessageSize)
+
+ for {
+ n, _, err := conn.ReadFrom(buf)
+ if err != nil {
+ return
+ }
+
+ pkt, err := dhcpv4.FromBytes(buf[:n])
+ if err != nil {
+ continue
+ }
+
+ if pkt.MessageType() != dhcpv4.MessageTypeOffer {
+ continue
+ }
+
+ if pkt.TransactionID != id {
+ continue
+ }
+
+ dns := pkt.DNS()
+ if len(dns) == 0 {
+ return
+ }
+
+ result <- dns
+
+ return
+ }
+}
+
+func randomHardware() net.HardwareAddr {
+ addr := make(net.HardwareAddr, 6)
+
+ addr[0] = 0xff
+
+ for i := 1; i < len(addr); i++ {
+ addr[i] = byte(rand.Intn(254) + 1)
+ }
+
+ return addr
+}
diff --git a/component/dialer/bind.go b/component/dialer/bind.go
deleted file mode 100644
index 0ad520683..000000000
--- a/component/dialer/bind.go
+++ /dev/null
@@ -1,118 +0,0 @@
-package dialer
-
-import (
- "errors"
- "net"
- "time"
-
- "github.com/Dreamacro/clash/common/singledo"
-)
-
-// In some OS, such as Windows, it takes a little longer to get interface information
-var ifaceSingle = singledo.NewSingle(time.Second * 20)
-
-var (
- errPlatformNotSupport = errors.New("unsupport platform")
-)
-
-func lookupTCPAddr(ip net.IP, addrs []net.Addr) (*net.TCPAddr, error) {
- ipv4 := ip.To4() != nil
-
- for _, elm := range addrs {
- addr, ok := elm.(*net.IPNet)
- if !ok {
- continue
- }
-
- addrV4 := addr.IP.To4() != nil
-
- if addrV4 && ipv4 {
- return &net.TCPAddr{IP: addr.IP, Port: 0}, nil
- } else if !addrV4 && !ipv4 {
- return &net.TCPAddr{IP: addr.IP, Port: 0}, nil
- }
- }
-
- return nil, ErrAddrNotFound
-}
-
-func lookupUDPAddr(ip net.IP, addrs []net.Addr) (*net.UDPAddr, error) {
- ipv4 := ip.To4() != nil
-
- for _, elm := range addrs {
- addr, ok := elm.(*net.IPNet)
- if !ok {
- continue
- }
-
- addrV4 := addr.IP.To4() != nil
-
- if addrV4 && ipv4 {
- return &net.UDPAddr{IP: addr.IP, Port: 0}, nil
- } else if !addrV4 && !ipv4 {
- return &net.UDPAddr{IP: addr.IP, Port: 0}, nil
- }
- }
-
- return nil, ErrAddrNotFound
-}
-
-func fallbackBindToDialer(dialer *net.Dialer, network string, ip net.IP, name string) error {
- if !ip.IsGlobalUnicast() {
- return nil
- }
-
- iface, err, _ := ifaceSingle.Do(func() (interface{}, error) {
- return net.InterfaceByName(name)
- })
- if err != nil {
- return err
- }
-
- addrs, err := iface.(*net.Interface).Addrs()
- if err != nil {
- return err
- }
-
- switch network {
- case "tcp", "tcp4", "tcp6":
- if addr, err := lookupTCPAddr(ip, addrs); err == nil {
- dialer.LocalAddr = addr
- } else {
- return err
- }
- case "udp", "udp4", "udp6":
- if addr, err := lookupUDPAddr(ip, addrs); err == nil {
- dialer.LocalAddr = addr
- } else {
- return err
- }
- }
-
- return nil
-}
-
-func fallbackBindToListenConfig(name string) (string, error) {
- iface, err, _ := ifaceSingle.Do(func() (interface{}, error) {
- return net.InterfaceByName(name)
- })
- if err != nil {
- return "", err
- }
-
- addrs, err := iface.(*net.Interface).Addrs()
- if err != nil {
- return "", err
- }
-
- for _, elm := range addrs {
- addr, ok := elm.(*net.IPNet)
- if !ok || addr.IP.To4() == nil {
- continue
- }
-
- return net.JoinHostPort(addr.IP.String(), "0"), nil
- }
-
- return "", ErrAddrNotFound
-}
diff --git a/component/dialer/bind_darwin.go b/component/dialer/bind_darwin.go
index 0ce505412..b3ae9d815 100644
--- a/component/dialer/bind_darwin.go
+++ b/component/dialer/bind_darwin.go
@@ -3,51 +3,57 @@ package dialer
import (
"net"
"syscall"
+
+ "golang.org/x/sys/unix"
+
+ "github.com/Dreamacro/clash/component/iface"
)
type controlFn = func(network, address string, c syscall.RawConn) error
-func bindControl(ifaceIdx int) controlFn {
- return func(network, address string, c syscall.RawConn) error {
+func bindControl(ifaceIdx int, chain controlFn) controlFn {
+ return func(network, address string, c syscall.RawConn) (err error) {
+ defer func() {
+ if err == nil && chain != nil {
+ err = chain(network, address, c)
+ }
+ }()
+
ipStr, _, err := net.SplitHostPort(address)
if err == nil {
ip := net.ParseIP(ipStr)
if ip != nil && !ip.IsGlobalUnicast() {
- return nil
+ return
}
}
return c.Control(func(fd uintptr) {
switch network {
case "tcp4", "udp4":
- syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IP, syscall.IP_BOUND_IF, ifaceIdx)
+ unix.SetsockoptInt(int(fd), unix.IPPROTO_IP, unix.IP_BOUND_IF, ifaceIdx)
case "tcp6", "udp6":
- syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IPV6, syscall.IPV6_BOUND_IF, ifaceIdx)
+ unix.SetsockoptInt(int(fd), unix.IPPROTO_IPV6, unix.IPV6_BOUND_IF, ifaceIdx)
}
})
}
}
-func bindIfaceToDialer(dialer *net.Dialer, ifaceName string) error {
- iface, err, _ := ifaceSingle.Do(func() (interface{}, error) {
- return net.InterfaceByName(ifaceName)
- })
+func bindIfaceToDialer(ifaceName string, dialer *net.Dialer, _ string, _ net.IP) error {
+ ifaceObj, err := iface.ResolveInterface(ifaceName)
if err != nil {
return err
}
- dialer.Control = bindControl(iface.(*net.Interface).Index)
+ dialer.Control = bindControl(ifaceObj.Index, dialer.Control)
return nil
}
-func bindIfaceToListenConfig(lc *net.ListenConfig, ifaceName string) error {
- iface, err, _ := ifaceSingle.Do(func() (interface{}, error) {
- return net.InterfaceByName(ifaceName)
- })
+func bindIfaceToListenConfig(ifaceName string, lc *net.ListenConfig, _, address string) (string, error) {
+ ifaceObj, err := iface.ResolveInterface(ifaceName)
if err != nil {
- return err
+ return "", err
}
- lc.Control = bindControl(iface.(*net.Interface).Index)
- return nil
+ lc.Control = bindControl(ifaceObj.Index, lc.Control)
+ return address, nil
}
diff --git a/component/dialer/bind_linux.go b/component/dialer/bind_linux.go
index 7e9d308dd..ae772a71e 100644
--- a/component/dialer/bind_linux.go
+++ b/component/dialer/bind_linux.go
@@ -3,34 +3,42 @@ package dialer
import (
"net"
"syscall"
+
+ "golang.org/x/sys/unix"
)
type controlFn = func(network, address string, c syscall.RawConn) error
-func bindControl(ifaceName string) controlFn {
- return func(network, address string, c syscall.RawConn) error {
+func bindControl(ifaceName string, chain controlFn) controlFn {
+ return func(network, address string, c syscall.RawConn) (err error) {
+ defer func() {
+ if err == nil && chain != nil {
+ err = chain(network, address, c)
+ }
+ }()
+
ipStr, _, err := net.SplitHostPort(address)
if err == nil {
ip := net.ParseIP(ipStr)
if ip != nil && !ip.IsGlobalUnicast() {
- return nil
+ return
}
}
return c.Control(func(fd uintptr) {
- syscall.BindToDevice(int(fd), ifaceName)
+ unix.BindToDevice(int(fd), ifaceName)
})
}
}
-func bindIfaceToDialer(dialer *net.Dialer, ifaceName string) error {
- dialer.Control = bindControl(ifaceName)
+func bindIfaceToDialer(ifaceName string, dialer *net.Dialer, _ string, _ net.IP) error {
+ dialer.Control = bindControl(ifaceName, dialer.Control)
return nil
}
-func bindIfaceToListenConfig(lc *net.ListenConfig, ifaceName string) error {
- lc.Control = bindControl(ifaceName)
+func bindIfaceToListenConfig(ifaceName string, lc *net.ListenConfig, _, address string) (string, error) {
+ lc.Control = bindControl(ifaceName, lc.Control)
- return nil
+ return address, nil
}
diff --git a/component/dialer/bind_others.go b/component/dialer/bind_others.go
index e09b5ff84..7f1923aa2 100644
--- a/component/dialer/bind_others.go
+++ b/component/dialer/bind_others.go
@@ -3,12 +3,91 @@
package dialer
-import "net"
+import (
+ "net"
+ "strconv"
+ "strings"
-func bindIfaceToDialer(dialer *net.Dialer, ifaceName string) error {
- return errPlatformNotSupport
+ "github.com/Dreamacro/clash/component/iface"
+)
+
+func lookupLocalAddr(ifaceName string, network string, destination net.IP, port int) (net.Addr, error) {
+ ifaceObj, err := iface.ResolveInterface(ifaceName)
+ if err != nil {
+ return nil, err
+ }
+
+ var addr *net.IPNet
+ switch network {
+ case "udp4", "tcp4":
+ addr, err = ifaceObj.PickIPv4Addr(destination)
+ case "tcp6", "udp6":
+ addr, err = ifaceObj.PickIPv6Addr(destination)
+ default:
+ if destination != nil {
+ if destination.To4() != nil {
+ addr, err = ifaceObj.PickIPv4Addr(destination)
+ } else {
+ addr, err = ifaceObj.PickIPv6Addr(destination)
+ }
+ } else {
+ addr, err = ifaceObj.PickIPv4Addr(destination)
+ }
+ }
+ if err != nil {
+ return nil, err
+ }
+
+ if strings.HasPrefix(network, "tcp") {
+ return &net.TCPAddr{
+ IP: addr.IP,
+ Port: port,
+ }, nil
+ } else if strings.HasPrefix(network, "udp") {
+ return &net.UDPAddr{
+ IP: addr.IP,
+ Port: port,
+ }, nil
+ }
+
+ return nil, iface.ErrAddrNotFound
}
-func bindIfaceToListenConfig(lc *net.ListenConfig, ifaceName string) error {
- return errPlatformNotSupport
+func bindIfaceToDialer(ifaceName string, dialer *net.Dialer, network string, destination net.IP) error {
+ if !destination.IsGlobalUnicast() {
+ return nil
+ }
+
+ local := 0
+ if dialer.LocalAddr != nil {
+ _, port, err := net.SplitHostPort(dialer.LocalAddr.String())
+ if err == nil {
+ local, _ = strconv.Atoi(port)
+ }
+ }
+
+ addr, err := lookupLocalAddr(ifaceName, network, destination, local)
+ if err != nil {
+ return err
+ }
+
+ dialer.LocalAddr = addr
+
+ return nil
+}
+
+func bindIfaceToListenConfig(ifaceName string, _ *net.ListenConfig, network, address string) (string, error) {
+ _, port, err := net.SplitHostPort(address)
+ if err != nil {
+ port = "0"
+ }
+
+ local, _ := strconv.Atoi(port)
+
+ addr, err := lookupLocalAddr(ifaceName, network, nil, local)
+ if err != nil {
+ return "", err
+ }
+
+ return addr.String(), nil
}
diff --git a/component/dialer/dialer.go b/component/dialer/dialer.go
index be26681a7..75bbb8687 100644
--- a/component/dialer/dialer.go
+++ b/component/dialer/dialer.go
@@ -8,22 +8,7 @@ import (
"github.com/Dreamacro/clash/component/resolver"
)
-func Dialer() (*net.Dialer, error) {
- dialer := &net.Dialer{}
- if DialerHook != nil {
- if err := DialerHook(dialer); err != nil {
- return nil, err
- }
- }
-
- return dialer, nil
-}
-
-func Dial(network, address string) (net.Conn, error) {
- return DialContext(context.Background(), network, address)
-}
-
-func DialContext(ctx context.Context, network, address string) (net.Conn, error) {
+func DialContext(ctx context.Context, network, address string, options ...Option) (net.Conn, error) {
switch network {
case "tcp4", "tcp6", "udp4", "udp6":
host, port, err := net.SplitHostPort(address)
@@ -31,11 +16,6 @@ func DialContext(ctx context.Context, network, address string) (net.Conn, error)
return nil, err
}
- dialer, err := Dialer()
- if err != nil {
- return nil, err
- }
-
var ip net.IP
switch network {
case "tcp4", "udp4":
@@ -43,38 +23,70 @@ func DialContext(ctx context.Context, network, address string) (net.Conn, error)
default:
ip, err = resolver.ResolveIPv6(host)
}
-
if err != nil {
return nil, err
}
- if DialHook != nil {
- if err := DialHook(dialer, network, ip); err != nil {
- return nil, err
- }
- }
- return dialer.DialContext(ctx, network, net.JoinHostPort(ip.String(), port))
+ return dialContext(ctx, network, ip, port, options)
case "tcp", "udp":
- return dualStackDialContext(ctx, network, address)
+ return dualStackDialContext(ctx, network, address, options)
default:
return nil, errors.New("network invalid")
}
}
-func ListenPacket(network, address string) (net.PacketConn, error) {
- cfg := &net.ListenConfig{}
- if ListenPacketHook != nil {
- var err error
- address, err = ListenPacketHook(cfg, address)
+func ListenPacket(ctx context.Context, network, address string, options ...Option) (net.PacketConn, error) {
+ cfg := &config{}
+
+ if !cfg.skipDefault {
+ for _, o := range DefaultOptions {
+ o(cfg)
+ }
+ }
+
+ for _, o := range options {
+ o(cfg)
+ }
+
+ lc := &net.ListenConfig{}
+ if cfg.interfaceName != "" {
+ addr, err := bindIfaceToListenConfig(cfg.interfaceName, lc, network, address)
if err != nil {
return nil, err
}
+ address = addr
+ }
+ if cfg.addrReuse {
+ addrReuseToListenConfig(lc)
+ }
+
+ return lc.ListenPacket(ctx, network, address)
+}
+
+func dialContext(ctx context.Context, network string, destination net.IP, port string, options []Option) (net.Conn, error) {
+ opt := &config{}
+
+ if !opt.skipDefault {
+ for _, o := range DefaultOptions {
+ o(opt)
+ }
+ }
+
+ for _, o := range options {
+ o(opt)
+ }
+
+ dialer := &net.Dialer{}
+ if opt.interfaceName != "" {
+ if err := bindIfaceToDialer(opt.interfaceName, dialer, network, destination); err != nil {
+ return nil, err
+ }
}
- return cfg.ListenPacket(context.Background(), network, address)
+ return dialer.DialContext(ctx, network, net.JoinHostPort(destination.String(), port))
}
-func dualStackDialContext(ctx context.Context, network, address string) (net.Conn, error) {
+func dualStackDialContext(ctx context.Context, network, address string, options []Option) (net.Conn, error) {
host, port, err := net.SplitHostPort(address)
if err != nil {
return nil, err
@@ -105,12 +117,6 @@ func dualStackDialContext(ctx context.Context, network, address string) (net.Con
}
}()
- dialer, err := Dialer()
- if err != nil {
- result.error = err
- return
- }
-
var ip net.IP
if ipv6 {
ip, result.error = resolver.ResolveIPv6(host)
@@ -122,12 +128,7 @@ func dualStackDialContext(ctx context.Context, network, address string) (net.Con
}
result.resolved = true
- if DialHook != nil {
- if result.error = DialHook(dialer, network, ip); result.error != nil {
- return
- }
- }
- result.Conn, result.error = dialer.DialContext(ctx, network, net.JoinHostPort(ip.String(), port))
+ result.Conn, result.error = dialContext(ctx, network, ip, port, options)
}
go startRacer(ctx, network+"4", host, false)
diff --git a/component/dialer/hook.go b/component/dialer/hook.go
deleted file mode 100644
index 356e4b25f..000000000
--- a/component/dialer/hook.go
+++ /dev/null
@@ -1,43 +0,0 @@
-package dialer
-
-import (
- "errors"
- "net"
-)
-
-type DialerHookFunc = func(dialer *net.Dialer) error
-type DialHookFunc = func(dialer *net.Dialer, network string, ip net.IP) error
-type ListenPacketHookFunc = func(lc *net.ListenConfig, address string) (string, error)
-
-var (
- DialerHook DialerHookFunc
- DialHook DialHookFunc
- ListenPacketHook ListenPacketHookFunc
-)
-
-var (
- ErrAddrNotFound = errors.New("addr not found")
- ErrNetworkNotSupport = errors.New("network not support")
-)
-
-func ListenPacketWithInterface(name string) ListenPacketHookFunc {
- return func(lc *net.ListenConfig, address string) (string, error) {
- err := bindIfaceToListenConfig(lc, name)
- if err == errPlatformNotSupport {
- address, err = fallbackBindToListenConfig(name)
- }
-
- return address, err
- }
-}
-
-func DialerWithInterface(name string) DialHookFunc {
- return func(dialer *net.Dialer, network string, ip net.IP) error {
- err := bindIfaceToDialer(dialer, name)
- if err == errPlatformNotSupport {
- err = fallbackBindToDialer(dialer, network, ip, name)
- }
-
- return err
- }
-}
diff --git a/component/dialer/options.go b/component/dialer/options.go
new file mode 100644
index 000000000..4b5d64c0e
--- /dev/null
+++ b/component/dialer/options.go
@@ -0,0 +1,31 @@
+package dialer
+
+var (
+ DefaultOptions []Option
+)
+
+type config struct {
+ skipDefault bool
+ interfaceName string
+ addrReuse bool
+}
+
+type Option func(opt *config)
+
+func WithInterface(name string) Option {
+ return func(opt *config) {
+ opt.interfaceName = name
+ }
+}
+
+func WithAddrReuse(reuse bool) Option {
+ return func(opt *config) {
+ opt.addrReuse = reuse
+ }
+}
+
+func WithSkipDefault(skip bool) Option {
+ return func(opt *config) {
+ opt.skipDefault = skip
+ }
+}
diff --git a/component/dialer/reuse_others.go b/component/dialer/reuse_others.go
new file mode 100644
index 000000000..b76213a7f
--- /dev/null
+++ b/component/dialer/reuse_others.go
@@ -0,0 +1,10 @@
+//go:build !darwin && !dragonfly && !freebsd && !linux && !netbsd && !openbsd && !solaris && !windows
+// +build !darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd,!solaris,!windows
+
+package dialer
+
+import (
+ "net"
+)
+
+func addrReuseToListenConfig(*net.ListenConfig) {}
diff --git a/component/dialer/reuse_unix.go b/component/dialer/reuse_unix.go
new file mode 100644
index 000000000..d5f43d8fe
--- /dev/null
+++ b/component/dialer/reuse_unix.go
@@ -0,0 +1,28 @@
+//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+
+package dialer
+
+import (
+ "net"
+ "syscall"
+
+ "golang.org/x/sys/unix"
+)
+
+func addrReuseToListenConfig(lc *net.ListenConfig) {
+ chain := lc.Control
+
+ lc.Control = func(network, address string, c syscall.RawConn) (err error) {
+ defer func() {
+ if err == nil && chain != nil {
+ err = chain(network, address, c)
+ }
+ }()
+
+ return c.Control(func(fd uintptr) {
+ unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_REUSEADDR, 1)
+ unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_REUSEPORT, 1)
+ })
+ }
+}
diff --git a/component/dialer/reuse_windows.go b/component/dialer/reuse_windows.go
new file mode 100644
index 000000000..77fcf7ab2
--- /dev/null
+++ b/component/dialer/reuse_windows.go
@@ -0,0 +1,24 @@
+package dialer
+
+import (
+ "net"
+ "syscall"
+
+ "golang.org/x/sys/windows"
+)
+
+func addrReuseToListenConfig(lc *net.ListenConfig) {
+ chain := lc.Control
+
+ lc.Control = func(network, address string, c syscall.RawConn) (err error) {
+ defer func() {
+ if err == nil && chain != nil {
+ err = chain(network, address, c)
+ }
+ }()
+
+ return c.Control(func(fd uintptr) {
+ windows.SetsockoptInt(windows.Handle(fd), windows.SOL_SOCKET, windows.SO_REUSEADDR, 1)
+ })
+ }
+}
diff --git a/component/iface/iface.go b/component/iface/iface.go
new file mode 100644
index 000000000..30c6a6bcb
--- /dev/null
+++ b/component/iface/iface.go
@@ -0,0 +1,113 @@
+package iface
+
+import (
+ "errors"
+ "net"
+ "time"
+
+ "github.com/Dreamacro/clash/common/singledo"
+)
+
+type Interface struct {
+ Index int
+ Name string
+ Addrs []*net.IPNet
+ HardwareAddr net.HardwareAddr
+}
+
+var ErrIfaceNotFound = errors.New("interface not found")
+var ErrAddrNotFound = errors.New("addr not found")
+
+var interfaces = singledo.NewSingle(time.Second * 20)
+
+func ResolveInterface(name string) (*Interface, error) {
+ value, err, _ := interfaces.Do(func() (interface{}, error) {
+ ifaces, err := net.Interfaces()
+ if err != nil {
+ return nil, err
+ }
+
+ r := map[string]*Interface{}
+
+ for _, iface := range ifaces {
+ addrs, err := iface.Addrs()
+ if err != nil {
+ continue
+ }
+
+ ipNets := make([]*net.IPNet, 0, len(addrs))
+ for _, addr := range addrs {
+ ipNet := addr.(*net.IPNet)
+ if v4 := ipNet.IP.To4(); v4 != nil {
+ ipNet.IP = v4
+ }
+
+ ipNets = append(ipNets, ipNet)
+ }
+
+ r[iface.Name] = &Interface{
+ Index: iface.Index,
+ Name: iface.Name,
+ Addrs: ipNets,
+ HardwareAddr: iface.HardwareAddr,
+ }
+ }
+
+ return r, nil
+ })
+ if err != nil {
+ return nil, err
+ }
+
+ ifaces := value.(map[string]*Interface)
+ iface, ok := ifaces[name]
+ if !ok {
+ return nil, ErrIfaceNotFound
+ }
+
+ return iface, nil
+}
+
+func FlushCache() {
+ interfaces.Reset()
+}
+
+func (iface *Interface) PickIPv4Addr(destination net.IP) (*net.IPNet, error) {
+ return iface.pickIPAddr(destination, func(addr *net.IPNet) bool {
+ return addr.IP.To4() != nil
+ })
+}
+
+func (iface *Interface) PickIPv6Addr(destination net.IP) (*net.IPNet, error) {
+ return iface.pickIPAddr(destination, func(addr *net.IPNet) bool {
+ return addr.IP.To4() == nil
+ })
+}
+
+func (iface *Interface) pickIPAddr(destination net.IP, accept func(addr *net.IPNet) bool) (*net.IPNet, error) {
+ var fallback *net.IPNet
+
+ for _, addr := range iface.Addrs {
+ if !accept(addr) {
+ continue
+ }
+
+ if fallback == nil && !addr.IP.IsLinkLocalUnicast() {
+ fallback = addr
+
+ if destination == nil {
+ break
+ }
+ }
+
+ if destination != nil && addr.Contains(destination) {
+ return addr, nil
+ }
+ }
+
+ if fallback == nil {
+ return nil, ErrAddrNotFound
+ }
+
+ return fallback, nil
+}
diff --git a/config/config.go b/config/config.go
index dc559ecf5..824175129 100644
--- a/config/config.go
+++ b/config/config.go
@@ -488,6 +488,9 @@ func parseNameServer(servers []string) ([]dns.NameServer, error) {
clearURL := url.URL{Scheme: "https", Host: u.Host, Path: u.Path}
addr = clearURL.String()
dnsNetType = "https" // DNS over HTTPS
+ case "dhcp":
+ addr = u.Host
+ dnsNetType = "dhcp" // UDP from DHCP
default:
return nil, fmt.Errorf("DNS NameServer[%d] unsupport scheme: %s", idx, u.Scheme)
}
diff --git a/dns/client.go b/dns/client.go
index 405b3a989..d386ed4c3 100644
--- a/dns/client.go
+++ b/dns/client.go
@@ -2,6 +2,7 @@ package dns
import (
"context"
+ "crypto/tls"
"fmt"
"net"
"strings"
@@ -34,22 +35,16 @@ func (c *client) ExchangeContext(ctx context.Context, m *D.Msg) (msg *D.Msg, err
}
}
- d, err := dialer.Dialer()
+ network := "udp"
+ if strings.HasPrefix(c.Client.Net, "tcp") {
+ network = "tcp"
+ }
+
+ conn, err := dialer.DialContext(ctx, network, net.JoinHostPort(ip.String(), c.port))
if err != nil {
return nil, err
}
-
- if ip != nil && ip.IsGlobalUnicast() && dialer.DialHook != nil {
- network := "udp"
- if strings.HasPrefix(c.Client.Net, "tcp") {
- network = "tcp"
- }
- if err := dialer.DialHook(d, network, ip); err != nil {
- return nil, err
- }
- }
-
- c.Client.Dialer = d
+ defer conn.Close()
// miekg/dns ExchangeContext doesn't respond to context cancel.
// this is a workaround
@@ -59,7 +54,17 @@ func (c *client) ExchangeContext(ctx context.Context, m *D.Msg) (msg *D.Msg, err
}
ch := make(chan result, 1)
go func() {
- msg, _, err := c.Client.Exchange(m, net.JoinHostPort(ip.String(), c.port))
+ if strings.HasSuffix(c.Client.Net, "tls") {
+ conn = tls.Client(conn, c.Client.TLSConfig)
+ }
+
+ msg, _, err = c.Client.ExchangeWithConn(m, &D.Conn{
+ Conn: conn,
+ UDPSize: c.Client.UDPSize,
+ TsigSecret: c.Client.TsigSecret,
+ TsigProvider: c.Client.TsigProvider,
+ })
+
ch <- result{msg, err}
}()
diff --git a/dns/dhcp.go b/dns/dhcp.go
new file mode 100644
index 000000000..94f8a36ce
--- /dev/null
+++ b/dns/dhcp.go
@@ -0,0 +1,144 @@
+package dns
+
+import (
+ "bytes"
+ "context"
+ "net"
+ "sync"
+ "time"
+
+ "github.com/Dreamacro/clash/component/dhcp"
+ "github.com/Dreamacro/clash/component/iface"
+ "github.com/Dreamacro/clash/component/resolver"
+
+ D "github.com/miekg/dns"
+)
+
+const (
+ IfaceTTL = time.Second * 20
+ DHCPTTL = time.Hour
+ DHCPTimeout = time.Minute
+)
+
+type dhcpClient struct {
+ ifaceName string
+
+ lock sync.Mutex
+ ifaceInvalidate time.Time
+ dnsInvalidate time.Time
+
+ ifaceAddr *net.IPNet
+ done chan struct{}
+ resolver *Resolver
+ err error
+}
+
+func (d *dhcpClient) Exchange(m *D.Msg) (msg *D.Msg, err error) {
+ ctx, cancel := context.WithTimeout(context.Background(), resolver.DefaultDNSTimeout)
+ defer cancel()
+
+ return d.ExchangeContext(ctx, m)
+}
+
+func (d *dhcpClient) ExchangeContext(ctx context.Context, m *D.Msg) (msg *D.Msg, err error) {
+ res, err := d.resolve(ctx)
+ if err != nil {
+ return nil, err
+ }
+
+ return res.ExchangeContext(ctx, m)
+}
+
+func (d *dhcpClient) resolve(ctx context.Context) (*Resolver, error) {
+ d.lock.Lock()
+
+ invalidated, err := d.invalidate()
+ if err != nil {
+ d.err = err
+ } else if invalidated {
+ done := make(chan struct{})
+
+ d.done = done
+
+ go func() {
+ ctx, cancel := context.WithTimeout(context.Background(), DHCPTimeout)
+ defer cancel()
+
+ var res *Resolver
+ dns, err := dhcp.ResolveDNSFromDHCP(ctx, d.ifaceName)
+ if err == nil {
+ nameserver := make([]NameServer, 0, len(dns))
+ for _, d := range dns {
+ nameserver = append(nameserver, NameServer{Addr: net.JoinHostPort(d.String(), "53")})
+ }
+
+ res = NewResolver(Config{
+ Main: nameserver,
+ })
+ }
+
+ d.lock.Lock()
+ defer d.lock.Unlock()
+
+ close(done)
+
+ d.done = nil
+ d.resolver = res
+ d.err = err
+ }()
+ }
+
+ d.lock.Unlock()
+
+ for {
+ d.lock.Lock()
+
+ res, err, done := d.resolver, d.err, d.done
+
+ d.lock.Unlock()
+
+ // initializing
+ if res == nil && err == nil {
+ select {
+ case <-done:
+ continue
+ case <-ctx.Done():
+ return nil, ctx.Err()
+ }
+ }
+
+ // dirty return
+ return res, err
+ }
+}
+
+func (d *dhcpClient) invalidate() (bool, error) {
+ if time.Now().Before(d.ifaceInvalidate) {
+ return false, nil
+ }
+
+ d.ifaceInvalidate = time.Now().Add(IfaceTTL)
+
+ ifaceObj, err := iface.ResolveInterface(d.ifaceName)
+ if err != nil {
+ return false, err
+ }
+
+ addr, err := ifaceObj.PickIPv4Addr(nil)
+ if err != nil {
+ return false, err
+ }
+
+ if time.Now().Before(d.dnsInvalidate) && d.ifaceAddr.IP.Equal(addr.IP) && bytes.Equal(d.ifaceAddr.Mask, addr.Mask) {
+ return false, nil
+ }
+
+ d.dnsInvalidate = time.Now().Add(DHCPTTL)
+ d.ifaceAddr = addr
+
+ return d.done == nil, nil
+}
+
+func newDHCPClient(ifaceName string) *dhcpClient {
+ return &dhcpClient{ifaceName: ifaceName}
+}
diff --git a/dns/resolver.go b/dns/resolver.go
index 56b5e3268..914f1418e 100644
--- a/dns/resolver.go
+++ b/dns/resolver.go
@@ -87,6 +87,11 @@ func (r *Resolver) shouldIPFallback(ip net.IP) bool {
// Exchange a batch of dns request, and it use cache
func (r *Resolver) Exchange(m *D.Msg) (msg *D.Msg, err error) {
+ return r.ExchangeContext(context.Background(), m)
+}
+
+// ExchangeContext a batch of dns request with context.Context, and it use cache
+func (r *Resolver) ExchangeContext(ctx context.Context, m *D.Msg) (msg *D.Msg, err error) {
if len(m.Question) == 0 {
return nil, errors.New("should have one question at least")
}
@@ -98,17 +103,17 @@ func (r *Resolver) Exchange(m *D.Msg) (msg *D.Msg, err error) {
msg = cache.(*D.Msg).Copy()
if expireTime.Before(now) {
setMsgTTL(msg, uint32(1)) // Continue fetch
- go r.exchangeWithoutCache(m)
+ go r.exchangeWithoutCache(ctx, m)
} else {
setMsgTTL(msg, uint32(time.Until(expireTime).Seconds()))
}
return
}
- return r.exchangeWithoutCache(m)
+ return r.exchangeWithoutCache(ctx, m)
}
// ExchangeWithoutCache a batch of dns request, and it do NOT GET from cache
-func (r *Resolver) exchangeWithoutCache(m *D.Msg) (msg *D.Msg, err error) {
+func (r *Resolver) exchangeWithoutCache(ctx context.Context, m *D.Msg) (msg *D.Msg, err error) {
q := m.Question[0]
ret, err, shared := r.group.Do(q.String(), func() (result interface{}, err error) {
@@ -124,13 +129,13 @@ func (r *Resolver) exchangeWithoutCache(m *D.Msg) (msg *D.Msg, err error) {
isIPReq := isIPRequest(q)
if isIPReq {
- return r.ipExchange(m)
+ return r.ipExchange(ctx, m)
}
if matched := r.matchPolicy(m); len(matched) != 0 {
- return r.batchExchange(matched, m)
+ return r.batchExchange(ctx, matched, m)
}
- return r.batchExchange(r.main, m)
+ return r.batchExchange(ctx, r.main, m)
})
if err == nil {
@@ -143,8 +148,8 @@ func (r *Resolver) exchangeWithoutCache(m *D.Msg) (msg *D.Msg, err error) {
return
}
-func (r *Resolver) batchExchange(clients []dnsClient, m *D.Msg) (msg *D.Msg, err error) {
- fast, ctx := picker.WithTimeout(context.Background(), resolver.DefaultDNSTimeout)
+func (r *Resolver) batchExchange(ctx context.Context, clients []dnsClient, m *D.Msg) (msg *D.Msg, err error) {
+ fast, ctx := picker.WithTimeout(ctx, resolver.DefaultDNSTimeout)
for _, client := range clients {
r := client
fast.Go(func() (interface{}, error) {
@@ -209,21 +214,21 @@ func (r *Resolver) shouldOnlyQueryFallback(m *D.Msg) bool {
return false
}
-func (r *Resolver) ipExchange(m *D.Msg) (msg *D.Msg, err error) {
+func (r *Resolver) ipExchange(ctx context.Context, m *D.Msg) (msg *D.Msg, err error) {
if matched := r.matchPolicy(m); len(matched) != 0 {
- res := <-r.asyncExchange(matched, m)
+ res := <-r.asyncExchange(ctx, matched, m)
return res.Msg, res.Error
}
onlyFallback := r.shouldOnlyQueryFallback(m)
if onlyFallback {
- res := <-r.asyncExchange(r.fallback, m)
+ res := <-r.asyncExchange(ctx, r.fallback, m)
return res.Msg, res.Error
}
- msgCh := r.asyncExchange(r.main, m)
+ msgCh := r.asyncExchange(ctx, r.main, m)
if r.fallback == nil { // directly return if no fallback servers are available
res := <-msgCh
@@ -231,7 +236,7 @@ func (r *Resolver) ipExchange(m *D.Msg) (msg *D.Msg, err error) {
return
}
- fallbackMsg := r.asyncExchange(r.fallback, m)
+ fallbackMsg := r.asyncExchange(ctx, r.fallback, m)
res := <-msgCh
if res.Error == nil {
if ips := msgToIP(res.Msg); len(ips) != 0 {
@@ -287,10 +292,10 @@ func (r *Resolver) msgToDomain(msg *D.Msg) string {
return ""
}
-func (r *Resolver) asyncExchange(client []dnsClient, msg *D.Msg) <-chan *result {
+func (r *Resolver) asyncExchange(ctx context.Context, client []dnsClient, msg *D.Msg) <-chan *result {
ch := make(chan *result, 1)
go func() {
- res, err := r.batchExchange(client, msg)
+ res, err := r.batchExchange(ctx, client, msg)
ch <- &result{Msg: res, Error: err}
}()
return ch
diff --git a/dns/util.go b/dns/util.go
index e56aaeb5a..0c3f42e59 100644
--- a/dns/util.go
+++ b/dns/util.go
@@ -117,9 +117,13 @@ func isIPRequest(q D.Question) bool {
func transform(servers []NameServer, resolver *Resolver) []dnsClient {
ret := []dnsClient{}
for _, s := range servers {
- if s.Net == "https" {
+ switch s.Net {
+ case "https":
ret = append(ret, newDoHClient(s.Addr, resolver))
continue
+ case "dhcp":
+ ret = append(ret, newDHCPClient(s.Addr))
+ continue
}
host, port, _ := net.SplitHostPort(s.Addr)
diff --git a/go.mod b/go.mod
index 34915dd7a..d288f5fee 100644
--- a/go.mod
+++ b/go.mod
@@ -4,20 +4,21 @@ go 1.17
require (
github.com/Dreamacro/go-shadowsocks2 v0.1.7
- github.com/go-chi/chi/v5 v5.0.3
+ github.com/go-chi/chi/v5 v5.0.4
github.com/go-chi/cors v1.2.0
github.com/go-chi/render v1.0.1
github.com/gofrs/uuid v4.0.0+incompatible
github.com/gorilla/websocket v1.4.2
+ github.com/insomniacslk/dhcp v0.0.0-20210827173440-b95caade3eac
github.com/miekg/dns v1.1.43
github.com/oschwald/geoip2-golang v1.5.0
github.com/sirupsen/logrus v1.8.1
github.com/stretchr/testify v1.7.0
go.uber.org/atomic v1.9.0
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5
- golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d
+ golang.org/x/net v0.0.0-20210825183410-e898025ed96a
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
- golang.org/x/sys v0.0.0-20210817190340-bfb29a6856f2
+ golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e
gopkg.in/yaml.v2 v2.4.0
)
@@ -25,6 +26,7 @@ require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/oschwald/maxminddb-golang v1.8.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
+ github.com/u-root/uio v0.0.0-20210528114334-82958018845c // indirect
golang.org/x/text v0.3.6 // indirect
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
)
diff --git a/go.sum b/go.sum
index 2c433ac0a..f5346e536 100644
--- a/go.sum
+++ b/go.sum
@@ -3,16 +3,38 @@ github.com/Dreamacro/go-shadowsocks2 v0.1.7/go.mod h1:8p5G4cAj5ZlXwUR+Ww63gfSikr
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/go-chi/chi/v5 v5.0.3 h1:khYQBdPivkYG1s1TAzDQG1f6eX4kD2TItYVZexL5rS4=
-github.com/go-chi/chi/v5 v5.0.3/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
+github.com/fanliao/go-promise v0.0.0-20141029170127-1890db352a72/go.mod h1:PjfxuH4FZdUyfMdtBio2lsRr1AKEaVPwelzuHuh8Lqc=
+github.com/go-chi/chi/v5 v5.0.4 h1:5e494iHzsYBiyXQAHHuI4tyJS9M3V84OuX3ufIIGHFo=
+github.com/go-chi/chi/v5 v5.0.4/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
github.com/go-chi/cors v1.2.0 h1:tV1g1XENQ8ku4Bq3K9ub2AtgG+p16SmzeMSGTwrOKdE=
github.com/go-chi/cors v1.2.0/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58=
github.com/go-chi/render v1.0.1 h1:4/5tis2cKaNdnv9zFLfXzcquC9HbeZgCnxGnKrltBS8=
github.com/go-chi/render v1.0.1/go.mod h1:pq4Rr7HbnsdaeHagklXub+p6Wd16Af5l9koip1OvJns=
github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw=
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
+github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
+github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
+github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714/go.mod h1:2Goc3h8EklBH5mspfHFxBnEoURQCGzQQH1ga9Myjvis=
+github.com/insomniacslk/dhcp v0.0.0-20210827173440-b95caade3eac h1:IO6EfdRnPhxgKOsk9DbewdtQZHKZKnGlW7QCUttvNys=
+github.com/insomniacslk/dhcp v0.0.0-20210827173440-b95caade3eac/go.mod h1:h+MxyHxRg9NH3terB1nfRIUaQEcI0XOVkdR9LNBlp8E=
+github.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw=
+github.com/jsimonetti/rtnetlink v0.0.0-20200117123717-f846d4f6c1f4/go.mod h1:WGuG/smIU4J/54PblvSbh+xvCZmpJnFgr3ds6Z55XMQ=
+github.com/jsimonetti/rtnetlink v0.0.0-20201009170750-9c6f07d100c1/go.mod h1:hqoO/u39cqLeBLebZ8fWdE96O7FxrAsRYhnVOdgHxok=
+github.com/jsimonetti/rtnetlink v0.0.0-20201110080708-d2c240429e6c/go.mod h1:huN4d1phzjhlOsNIjFsw2SVRbwIHj3fJDMEU2SDPTmg=
+github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
+github.com/mdlayher/ethernet v0.0.0-20190606142754-0394541c37b7/go.mod h1:U6ZQobyTjI/tJyq2HG+i/dfSoFUt8/aZCM+GKtmFk/Y=
+github.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA=
+github.com/mdlayher/netlink v1.0.0/go.mod h1:KxeJAFOFLG6AjpyDkQ/iIhxygIUKD+vcwqcnu43w/+M=
+github.com/mdlayher/netlink v1.1.0/go.mod h1:H4WCitaheIsdF9yOYu8CFmCgQthAPIWZmcKp9uZHgmY=
+github.com/mdlayher/netlink v1.1.1/go.mod h1:WTYpFb/WTvlRJAyKhZL5/uy69TDDpHHu2VZmb2XgV7o=
+github.com/mdlayher/raw v0.0.0-20190606142536-fef19f00fc18/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg=
+github.com/mdlayher/raw v0.0.0-20191009151244-50f2db8cc065/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg=
github.com/miekg/dns v1.1.43 h1:JKfpVSCB84vrAmHzyrsxB5NAr5kLoMXZArPSw7Qlgyg=
github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4=
github.com/oschwald/geoip2-golang v1.5.0 h1:igg2yQIrrcRccB1ytFXqBfOHCjXWIoMv85lVJ1ONZzw=
@@ -23,35 +45,66 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
+github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
+github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/u-root/uio v0.0.0-20210528114334-82958018845c h1:BFvcl34IGnw8yvJi8hlqLFo9EshRInwWBs2M5fGWzQA=
+github.com/u-root/uio v0.0.0-20210528114334-82958018845c/go.mod h1:LpEX5FO/cB+WF4TYGY1V5qktpaZLkKkSegbr0V4eYXA=
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210317152858-513c2a44f670/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 h1:HWj/xjIHfjYU5nVXpTM0s39J9CbLn7Cc5a7IC5rwsMQ=
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190419010253-1f3472d942ba/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
+golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20191007182048-72f939374954/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
-golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d h1:LO7XpTYMwTqxjLcGWPijK3vRXg1aWdlNOVOHRq45d7c=
-golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20210825183410-e898025ed96a h1:bRuuGXV8wwSdGTB+CtJf+FjgO1APK1CoO39T4BN/XBw=
+golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190411185658-b44545bcd369/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190418153312-f0ce4c0180be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190606122018-79a91cf218c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191224085550-c709ea063b76/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201101102859-da207088b7d1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20210817190340-bfb29a6856f2 h1:c8PlLMqBbOHoqtjteWm5/kbe6rNY2pbRfbIMVnepueo=
-golang.org/x/sys v0.0.0-20210817190340-bfb29a6856f2/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e h1:XMgFehsDnnLGtjvjOfqWSUzt0alpTR1RSEuznObga2c=
+golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
diff --git a/hub/executor/executor.go b/hub/executor/executor.go
index 121e1d01d..5c002b64f 100644
--- a/hub/executor/executor.go
+++ b/hub/executor/executor.go
@@ -10,6 +10,7 @@ import (
"github.com/Dreamacro/clash/adapter/outboundgroup"
"github.com/Dreamacro/clash/component/auth"
"github.com/Dreamacro/clash/component/dialer"
+ "github.com/Dreamacro/clash/component/iface"
"github.com/Dreamacro/clash/component/profile"
"github.com/Dreamacro/clash/component/profile/cachefile"
"github.com/Dreamacro/clash/component/resolver"
@@ -171,13 +172,13 @@ func updateGeneral(general *config.General, force bool) {
resolver.DisableIPv6 = !general.IPv6
if general.Interface != "" {
- dialer.DialHook = dialer.DialerWithInterface(general.Interface)
- dialer.ListenPacketHook = dialer.ListenPacketWithInterface(general.Interface)
+ dialer.DefaultOptions = []dialer.Option{dialer.WithInterface(general.Interface)}
} else {
- dialer.DialHook = nil
- dialer.ListenPacketHook = nil
+ dialer.DefaultOptions = nil
}
+ iface.FlushCache()
+
if !force {
return
}
From 5b7f0de48b6f26ce1ec5f54422b2b5e50e956c5c Mon Sep 17 00:00:00 2001
From: Dreamacro <8615343+Dreamacro@users.noreply.github.com>
Date: Tue, 7 Sep 2021 20:16:07 +0800
Subject: [PATCH 57/96] Chore: update dependencies
---
go.mod | 4 ++--
go.sum | 8 ++++----
test/go.mod | 6 ++++--
test/go.sum | 38 +++++++++++++++++++++++++++++++++-----
4 files changed, 43 insertions(+), 13 deletions(-)
diff --git a/go.mod b/go.mod
index d288f5fee..e955449b8 100644
--- a/go.mod
+++ b/go.mod
@@ -16,9 +16,9 @@ require (
github.com/stretchr/testify v1.7.0
go.uber.org/atomic v1.9.0
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5
- golang.org/x/net v0.0.0-20210825183410-e898025ed96a
+ golang.org/x/net v0.0.0-20210903162142-ad29c8ab022f
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
- golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e
+ golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34
gopkg.in/yaml.v2 v2.4.0
)
diff --git a/go.sum b/go.sum
index f5346e536..d1d97cfc4 100644
--- a/go.sum
+++ b/go.sum
@@ -72,8 +72,8 @@ golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
-golang.org/x/net v0.0.0-20210825183410-e898025ed96a h1:bRuuGXV8wwSdGTB+CtJf+FjgO1APK1CoO39T4BN/XBw=
-golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20210903162142-ad29c8ab022f h1:w6wWR0H+nyVpbSAQbzVEIACVyr/h8l/BEkY6Sokc7Eg=
+golang.org/x/net v0.0.0-20210903162142-ad29c8ab022f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -95,8 +95,8 @@ golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e h1:XMgFehsDnnLGtjvjOfqWSUzt0alpTR1RSEuznObga2c=
-golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34 h1:GkvMjFtXUmahfDtashnc1mnrCtuBVcwse5QV2lUk/tI=
+golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
diff --git a/test/go.mod b/test/go.mod
index 97d3a79c6..990edb6c5 100644
--- a/test/go.mod
+++ b/test/go.mod
@@ -8,7 +8,7 @@ require (
github.com/docker/go-connections v0.4.0
github.com/miekg/dns v1.1.43
github.com/stretchr/testify v1.7.0
- golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d
+ golang.org/x/net v0.0.0-20210903162142-ad29c8ab022f
)
replace github.com/Dreamacro/clash => ../
@@ -25,6 +25,7 @@ require (
github.com/golang/protobuf v1.5.0 // indirect
github.com/gorilla/mux v1.8.0 // indirect
github.com/gorilla/websocket v1.4.2 // indirect
+ github.com/insomniacslk/dhcp v0.0.0-20210827173440-b95caade3eac // indirect
github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 // indirect
github.com/morikuni/aec v1.0.0 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
@@ -34,10 +35,11 @@ require (
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/sirupsen/logrus v1.8.1 // indirect
+ github.com/u-root/uio v0.0.0-20210528114334-82958018845c // indirect
go.uber.org/atomic v1.9.0 // indirect
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 // indirect
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
- golang.org/x/sys v0.0.0-20210817190340-bfb29a6856f2 // indirect
+ golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34 // indirect
golang.org/x/text v0.3.6 // indirect
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect
google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a // indirect
diff --git a/test/go.sum b/test/go.sum
index c2b68eafd..27d2c4de2 100644
--- a/test/go.sum
+++ b/test/go.sum
@@ -251,6 +251,7 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.m
github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
+github.com/fanliao/go-promise v0.0.0-20141029170127-1890db352a72/go.mod h1:PjfxuH4FZdUyfMdtBio2lsRr1AKEaVPwelzuHuh8Lqc=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k=
@@ -260,7 +261,7 @@ github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXt
github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY=
github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
-github.com/go-chi/chi/v5 v5.0.3/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
+github.com/go-chi/chi/v5 v5.0.4/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
github.com/go-chi/cors v1.2.0/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58=
github.com/go-chi/render v1.0.1/go.mod h1:pq4Rr7HbnsdaeHagklXub+p6Wd16Af5l9koip1OvJns=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
@@ -376,16 +377,23 @@ github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
+github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714/go.mod h1:2Goc3h8EklBH5mspfHFxBnEoURQCGzQQH1ga9Myjvis=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/imdario/mergo v0.3.10/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
+github.com/insomniacslk/dhcp v0.0.0-20210827173440-b95caade3eac h1:IO6EfdRnPhxgKOsk9DbewdtQZHKZKnGlW7QCUttvNys=
+github.com/insomniacslk/dhcp v0.0.0-20210827173440-b95caade3eac/go.mod h1:h+MxyHxRg9NH3terB1nfRIUaQEcI0XOVkdR9LNBlp8E=
github.com/j-keck/arping v0.0.0-20160618110441-2cf9dc699c56/go.mod h1:ymszkNOg6tORTn+6F6j+Jc8TOr5osrynvN6ivFWZ2GA=
github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
+github.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw=
+github.com/jsimonetti/rtnetlink v0.0.0-20200117123717-f846d4f6c1f4/go.mod h1:WGuG/smIU4J/54PblvSbh+xvCZmpJnFgr3ds6Z55XMQ=
+github.com/jsimonetti/rtnetlink v0.0.0-20201009170750-9c6f07d100c1/go.mod h1:hqoO/u39cqLeBLebZ8fWdE96O7FxrAsRYhnVOdgHxok=
+github.com/jsimonetti/rtnetlink v0.0.0-20201110080708-d2c240429e6c/go.mod h1:huN4d1phzjhlOsNIjFsw2SVRbwIHj3fJDMEU2SDPTmg=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
@@ -422,6 +430,13 @@ github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzp
github.com/mattn/go-shellwords v1.0.3/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
+github.com/mdlayher/ethernet v0.0.0-20190606142754-0394541c37b7/go.mod h1:U6ZQobyTjI/tJyq2HG+i/dfSoFUt8/aZCM+GKtmFk/Y=
+github.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA=
+github.com/mdlayher/netlink v1.0.0/go.mod h1:KxeJAFOFLG6AjpyDkQ/iIhxygIUKD+vcwqcnu43w/+M=
+github.com/mdlayher/netlink v1.1.0/go.mod h1:H4WCitaheIsdF9yOYu8CFmCgQthAPIWZmcKp9uZHgmY=
+github.com/mdlayher/netlink v1.1.1/go.mod h1:WTYpFb/WTvlRJAyKhZL5/uy69TDDpHHu2VZmb2XgV7o=
+github.com/mdlayher/raw v0.0.0-20190606142536-fef19f00fc18/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg=
+github.com/mdlayher/raw v0.0.0-20191009151244-50f2db8cc065/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg=
github.com/miekg/dns v1.1.43 h1:JKfpVSCB84vrAmHzyrsxB5NAr5kLoMXZArPSw7Qlgyg=
github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4=
github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
@@ -551,6 +566,7 @@ github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
+github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
@@ -585,6 +601,8 @@ github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG
github.com/tchap/go-patricia v2.2.6+incompatible/go.mod h1:bmLyhP68RS6kStMGxByiQ23RP/odRBOTVjwp2cDyi6I=
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
+github.com/u-root/uio v0.0.0-20210528114334-82958018845c h1:BFvcl34IGnw8yvJi8hlqLFo9EshRInwWBs2M5fGWzQA=
+github.com/u-root/uio v0.0.0-20210528114334-82958018845c/go.mod h1:LpEX5FO/cB+WF4TYGY1V5qktpaZLkKkSegbr0V4eYXA=
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
@@ -680,6 +698,7 @@ golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73r
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190419010253-1f3472d942ba/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
@@ -691,6 +710,7 @@ golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20191007182048-72f939374954/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
@@ -701,12 +721,13 @@ golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
-golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d h1:LO7XpTYMwTqxjLcGWPijK3vRXg1aWdlNOVOHRq45d7c=
-golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20210903162142-ad29c8ab022f h1:w6wWR0H+nyVpbSAQbzVEIACVyr/h8l/BEkY6Sokc7Eg=
+golang.org/x/net v0.0.0-20210903162142-ad29c8ab022f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -730,13 +751,16 @@ golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190411185658-b44545bcd369/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190418153312-f0ce4c0180be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190514135907-3a4b5fb9f71f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190522044717-8097e1b27ff5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190606122018-79a91cf218c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -749,6 +773,7 @@ golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -776,6 +801,8 @@ golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200916030750-2334cc1a136f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200922070232-aee5d888a860/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201101102859-da207088b7d1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201117170446-d9b008d0a637/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -786,10 +813,11 @@ golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20210817190340-bfb29a6856f2 h1:c8PlLMqBbOHoqtjteWm5/kbe6rNY2pbRfbIMVnepueo=
-golang.org/x/sys v0.0.0-20210817190340-bfb29a6856f2/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34 h1:GkvMjFtXUmahfDtashnc1mnrCtuBVcwse5QV2lUk/tI=
+golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
From 400dc923e0643d28b9b62405d5d5968f043659b2 Mon Sep 17 00:00:00 2001
From: maskedeken <52683904+maskedeken@users.noreply.github.com>
Date: Wed, 8 Sep 2021 14:44:24 +0800
Subject: [PATCH 58/96] Fix: vmess ws headers not set properly (#1595)
---
adapter/outbound/vmess.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/adapter/outbound/vmess.go b/adapter/outbound/vmess.go
index 445b1ef47..6ca82c15e 100644
--- a/adapter/outbound/vmess.go
+++ b/adapter/outbound/vmess.go
@@ -95,7 +95,7 @@ func (v *Vmess) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {
if len(v.option.WSOpts.Headers) != 0 {
header := http.Header{}
- for key, value := range v.option.WSHeaders {
+ for key, value := range v.option.WSOpts.Headers {
header.Add(key, value)
}
wsOpts.Headers = header
From 0c79d1207ef884c98458f62081d03f94a3c274ee Mon Sep 17 00:00:00 2001
From: bobo liu <7552030+fakeboboliu@users.noreply.github.com>
Date: Thu, 9 Sep 2021 20:30:34 +0800
Subject: [PATCH 59/96] Fix: potential overflow in ssr (#1600)
---
transport/ssr/protocol/auth_chain_a.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/transport/ssr/protocol/auth_chain_a.go b/transport/ssr/protocol/auth_chain_a.go
index 4ce55c1a6..906f8deb3 100644
--- a/transport/ssr/protocol/auth_chain_a.go
+++ b/transport/ssr/protocol/auth_chain_a.go
@@ -278,7 +278,7 @@ func getRandStartPos(length int, random *tools.XorShift128Plus) int {
if length == 0 {
return 0
}
- return int(random.Next()%8589934609) % length
+ return int(int64(random.Next()%8589934609) % int64(length))
}
func (a *authChainA) getRandLength(length int, lastHash []byte, random *tools.XorShift128Plus) int {
From d49b38b00f03c7c5a2f29fb7f639dcbee46c9461 Mon Sep 17 00:00:00 2001
From: Kr328
Date: Mon, 13 Sep 2021 23:43:28 +0800
Subject: [PATCH 60/96] Fix: should not unmarshal to pointer (#1615)
---
config/config.go | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/config/config.go b/config/config.go
index 824175129..004a935f0 100644
--- a/config/config.go
+++ b/config/config.go
@@ -22,7 +22,7 @@ import (
R "github.com/Dreamacro/clash/rule"
T "github.com/Dreamacro/clash/tunnel"
- yaml "gopkg.in/yaml.v2"
+ "gopkg.in/yaml.v2"
)
// General config
@@ -188,7 +188,7 @@ func UnmarshalRawConfig(buf []byte) (*RawConfig, error) {
},
}
- if err := yaml.Unmarshal(buf, &rawCfg); err != nil {
+ if err := yaml.Unmarshal(buf, rawCfg); err != nil {
return nil, err
}
From beb88cc46f01e2215934441287f1a553a9290e16 Mon Sep 17 00:00:00 2001
From: Kr328
Date: Mon, 13 Sep 2021 23:46:39 +0800
Subject: [PATCH 61/96] Fix: should not trust address of http.Client (#1616)
---
adapter/inbound/http.go | 4 ++--
listener/http/client.go | 8 +++++++-
2 files changed, 9 insertions(+), 3 deletions(-)
diff --git a/adapter/inbound/http.go b/adapter/inbound/http.go
index 94b9fc21f..89960cf34 100644
--- a/adapter/inbound/http.go
+++ b/adapter/inbound/http.go
@@ -9,8 +9,8 @@ import (
)
// NewHTTP receive normal http request and return HTTPContext
-func NewHTTP(target string, source net.Addr, conn net.Conn) *context.ConnContext {
- metadata := parseSocksAddr(socks5.ParseAddr(target))
+func NewHTTP(target socks5.Addr, source net.Addr, conn net.Conn) *context.ConnContext {
+ metadata := parseSocksAddr(target)
metadata.NetWork = C.TCP
metadata.Type = C.HTTP
if ip, port, err := parseAddr(source.String()); err == nil {
diff --git a/listener/http/client.go b/listener/http/client.go
index 3b5fd3842..15078b0ac 100644
--- a/listener/http/client.go
+++ b/listener/http/client.go
@@ -9,6 +9,7 @@ import (
"github.com/Dreamacro/clash/adapter/inbound"
C "github.com/Dreamacro/clash/constant"
+ "github.com/Dreamacro/clash/transport/socks5"
)
func newClient(source net.Addr, in chan<- C.ConnContext) *http.Client {
@@ -25,9 +26,14 @@ func newClient(source net.Addr, in chan<- C.ConnContext) *http.Client {
return nil, errors.New("unsupported network " + network)
}
+ dstAddr := socks5.ParseAddr(address)
+ if dstAddr == nil {
+ return nil, socks5.ErrAddressNotSupported
+ }
+
left, right := net.Pipe()
- in <- inbound.NewHTTP(address, source, right)
+ in <- inbound.NewHTTP(dstAddr, source, right)
return left, nil
},
From 55600c49c9299744c2c3d67dc72ac0d798bc3437 Mon Sep 17 00:00:00 2001
From: Dreamacro <8615343+Dreamacro@users.noreply.github.com>
Date: Mon, 13 Sep 2021 23:58:34 +0800
Subject: [PATCH 62/96] Fix: potential pitfalls
---
dns/client.go | 15 ++++++++++-----
1 file changed, 10 insertions(+), 5 deletions(-)
diff --git a/dns/client.go b/dns/client.go
index d386ed4c3..6a54f9fad 100644
--- a/dns/client.go
+++ b/dns/client.go
@@ -20,15 +20,20 @@ type client struct {
host string
}
-func (c *client) Exchange(m *D.Msg) (msg *D.Msg, err error) {
+func (c *client) Exchange(m *D.Msg) (*D.Msg, error) {
return c.ExchangeContext(context.Background(), m)
}
-func (c *client) ExchangeContext(ctx context.Context, m *D.Msg) (msg *D.Msg, err error) {
- var ip net.IP
+func (c *client) ExchangeContext(ctx context.Context, m *D.Msg) (*D.Msg, error) {
+ var (
+ ip net.IP
+ err error
+ )
if c.r == nil {
// a default ip dns
- ip = net.ParseIP(c.host)
+ if ip = net.ParseIP(c.host); ip == nil {
+ return nil, fmt.Errorf("dns %s not a valid ip", c.host)
+ }
} else {
if ip, err = resolver.ResolveIPWithResolver(c.host, c.r); err != nil {
return nil, fmt.Errorf("use default dns resolve failed: %w", err)
@@ -58,7 +63,7 @@ func (c *client) ExchangeContext(ctx context.Context, m *D.Msg) (msg *D.Msg, err
conn = tls.Client(conn, c.Client.TLSConfig)
}
- msg, _, err = c.Client.ExchangeWithConn(m, &D.Conn{
+ msg, _, err := c.Client.ExchangeWithConn(m, &D.Conn{
Conn: conn,
UDPSize: c.Client.UDPSize,
TsigSecret: c.Client.TsigSecret,
From f5806d92639db21a86a8f8418995ba7a47d8bcf3 Mon Sep 17 00:00:00 2001
From: Xuen Li
Date: Tue, 14 Sep 2021 00:08:23 +0800
Subject: [PATCH 63/96] Fix: http/https proxy authentication (#1613)
---
listener/http/proxy.go | 12 ++++++------
listener/http/utils.go | 16 ++++++++--------
2 files changed, 14 insertions(+), 14 deletions(-)
diff --git a/listener/http/proxy.go b/listener/http/proxy.go
index 449658cac..229106dfe 100644
--- a/listener/http/proxy.go
+++ b/listener/http/proxy.go
@@ -63,8 +63,8 @@ func HandleConn(c net.Conn, in chan<- C.ConnContext, cache *cache.Cache) {
request.RequestURI = ""
- RemoveHopByHopHeaders(request.Header)
- RemoveExtraHTTPHostPort(request)
+ removeHopByHopHeaders(request.Header)
+ removeExtraHTTPHostPort(request)
if request.URL.Scheme == "" || request.URL.Host == "" {
resp = responseWith(http.StatusBadRequest)
@@ -74,9 +74,9 @@ func HandleConn(c net.Conn, in chan<- C.ConnContext, cache *cache.Cache) {
resp = responseWith(http.StatusBadGateway)
}
}
- }
- RemoveHopByHopHeaders(resp.Header)
+ removeHopByHopHeaders(resp.Header)
+ }
if keepAlive {
resp.Header.Set("Proxy-Connection", "keep-alive")
@@ -98,7 +98,7 @@ func HandleConn(c net.Conn, in chan<- C.ConnContext, cache *cache.Cache) {
func authenticate(request *http.Request, cache *cache.Cache) *http.Response {
authenticator := authStore.Authenticator()
if authenticator != nil {
- credential := ParseBasicProxyAuthorization(request)
+ credential := parseBasicProxyAuthorization(request)
if credential == "" {
resp := responseWith(http.StatusProxyAuthRequired)
resp.Header.Set("Proxy-Authenticate", "Basic")
@@ -107,7 +107,7 @@ func authenticate(request *http.Request, cache *cache.Cache) *http.Response {
var authed interface{}
if authed = cache.Get(credential); authed == nil {
- user, pass, err := DecodeBasicProxyAuthorization(credential)
+ user, pass, err := decodeBasicProxyAuthorization(credential)
authed = err == nil && authenticator.Verify(user, pass)
cache.Put(credential, authed, time.Minute)
}
diff --git a/listener/http/utils.go b/listener/http/utils.go
index f3d7840c6..177607991 100644
--- a/listener/http/utils.go
+++ b/listener/http/utils.go
@@ -8,8 +8,8 @@ import (
"strings"
)
-// RemoveHopByHopHeaders remove hop-by-hop header
-func RemoveHopByHopHeaders(header http.Header) {
+// removeHopByHopHeaders remove hop-by-hop header
+func removeHopByHopHeaders(header http.Header) {
// Strip hop-by-hop header based on RFC:
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.5.1
// https://www.mnot.net/blog/2011/07/11/what_proxies_must_do
@@ -32,9 +32,9 @@ func RemoveHopByHopHeaders(header http.Header) {
}
}
-// RemoveExtraHTTPHostPort remove extra host port (example.com:80 --> example.com)
+// removeExtraHTTPHostPort remove extra host port (example.com:80 --> example.com)
// It resolves the behavior of some HTTP servers that do not handle host:80 (e.g. baidu.com)
-func RemoveExtraHTTPHostPort(req *http.Request) {
+func removeExtraHTTPHostPort(req *http.Request) {
host := req.Host
if host == "" {
host = req.URL.Host
@@ -48,8 +48,8 @@ func RemoveExtraHTTPHostPort(req *http.Request) {
req.URL.Host = host
}
-// ParseBasicProxyAuthorization parse header Proxy-Authorization and return base64-encoded credential
-func ParseBasicProxyAuthorization(request *http.Request) string {
+// parseBasicProxyAuthorization parse header Proxy-Authorization and return base64-encoded credential
+func parseBasicProxyAuthorization(request *http.Request) string {
value := request.Header.Get("Proxy-Authorization")
if !strings.HasPrefix(value, "Basic ") {
return ""
@@ -58,8 +58,8 @@ func ParseBasicProxyAuthorization(request *http.Request) string {
return value[6:] // value[len("Basic "):]
}
-// DecodeBasicProxyAuthorization decode base64-encoded credential
-func DecodeBasicProxyAuthorization(credential string) (string, string, error) {
+// decodeBasicProxyAuthorization decode base64-encoded credential
+func decodeBasicProxyAuthorization(credential string) (string, string, error) {
plain, err := base64.StdEncoding.DecodeString(credential)
if err != nil {
return "", "", err
From b0f83e401f612d294d456730286be2ca44c82bf8 Mon Sep 17 00:00:00 2001
From: Excited Codes <61885669+ExcitedCodes@users.noreply.github.com>
Date: Wed, 15 Sep 2021 16:45:57 +0800
Subject: [PATCH 64/96] Fix: socks4 request continues after authentication
failed (#1624)
---
transport/socks4/socks4.go | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/transport/socks4/socks4.go b/transport/socks4/socks4.go
index c6b2f2db5..c06bea20f 100644
--- a/transport/socks4/socks4.go
+++ b/transport/socks4/socks4.go
@@ -91,6 +91,7 @@ func ServerHandshake(rw io.ReadWriter, authenticator auth.Authenticator) (addr s
code = RequestGranted
} else {
code = RequestIdentdMismatched
+ err = ErrRequestIdentdMismatched
}
var reply [8]byte
@@ -99,7 +100,10 @@ func ServerHandshake(rw io.ReadWriter, authenticator auth.Authenticator) (addr s
copy(reply[4:8], dstIP)
copy(reply[2:4], dstPort)
- _, err = rw.Write(reply[:])
+ _, wErr := rw.Write(reply[:])
+ if err == nil {
+ err = wErr
+ }
return
}
From b3cd4ebbd3c34697c9fe87f7f536421ada5004cf Mon Sep 17 00:00:00 2001
From: Dreamacro <8615343+Dreamacro@users.noreply.github.com>
Date: Wed, 15 Sep 2021 20:21:30 +0800
Subject: [PATCH 65/96] Fix: use 1.17.x on github actions
---
.github/workflows/go.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml
index d8a514eae..2b9366f9f 100644
--- a/.github/workflows/go.yml
+++ b/.github/workflows/go.yml
@@ -9,7 +9,7 @@ jobs:
- name: Setup Go
uses: actions/setup-go@v2
with:
- go-version: 1.17
+ go-version: 1.17.x
- name: Check out code into the Go module directory
uses: actions/checkout@v2
From b398f1e6f37bde03da73c34994ccb62f831feb51 Mon Sep 17 00:00:00 2001
From: Dreamacro <8615343+Dreamacro@users.noreply.github.com>
Date: Sat, 18 Sep 2021 00:18:47 +0800
Subject: [PATCH 66/96] Chore: force set latest go version to action
---
.github/workflows/go.yml | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml
index 2b9366f9f..1058dd4f4 100644
--- a/.github/workflows/go.yml
+++ b/.github/workflows/go.yml
@@ -6,10 +6,15 @@ jobs:
name: Build
runs-on: ubuntu-latest
steps:
+ - name: Get latest go version
+ id: version
+ run: |
+ echo ::set-output name=go_version::$(curl -s https://raw.githubusercontent.com/actions/go-versions/main/versions-manifest.json | grep -oE '"version": "[0-9]{1}.[0-9]{1,}(.[0-9]{1,})?"' | head -1 | cut -d':' -f2 | sed 's/ //g; s/"//g')
+
- name: Setup Go
uses: actions/setup-go@v2
with:
- go-version: 1.17.x
+ go-version: ${{ steps.version.outputs.go_version }}
- name: Check out code into the Go module directory
uses: actions/checkout@v2
From 5b1a0a523fd0efadb8ef6199f1aee67ddaade34a Mon Sep 17 00:00:00 2001
From: Dreamacro <8615343+Dreamacro@users.noreply.github.com>
Date: Mon, 20 Sep 2021 17:22:40 +0800
Subject: [PATCH 67/96] Chore: update README.md
---
README.md | 14 ++++++--------
1 file changed, 6 insertions(+), 8 deletions(-)
diff --git a/README.md b/README.md
index b948b49d0..c0d7c7f72 100644
--- a/README.md
+++ b/README.md
@@ -12,9 +12,13 @@
+
+
+
+
## Features
@@ -22,7 +26,7 @@
- Local HTTP/HTTPS/SOCKS server with authentication support
- VMess, Shadowsocks, Trojan, Snell protocol support for remote connections
- Built-in DNS server that aims to minimize DNS pollution attack impact, supports DoH/DoT upstream and fake IP.
-- Rules based off domains, GEOIP, IP CIDR or ports to forward packets to different nodes
+- Rules based off domains, GEOIP, IPCIDR or Process to forward packets to different nodes
- Remote groups allow users to implement powerful rules. Supports automatic fallback, load balancing or auto select node based off latency
- Remote providers, allowing users to get node lists remotely instead of hardcoding in config
- Netfilter TCP redirecting. Deploy Clash on your Internet gateway with `iptables`.
@@ -47,16 +51,10 @@ If you want to build an application that uses clash as a library, check out the
* [riobard/go-shadowsocks2](https://github.com/riobard/go-shadowsocks2)
* [v2ray/v2ray-core](https://github.com/v2ray/v2ray-core)
+* [WireGuard/wireguard-go](https://github.com/WireGuard/wireguard-go)
## License
This software is released under the GPL-3.0 license.
[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2FDreamacro%2Fclash.svg?type=large)](https://app.fossa.io/projects/git%2Bgithub.com%2FDreamacro%2Fclash?ref=badge_large)
-
-## TODO
-
-- [x] Complementing the necessary rule operators
-- [x] Redir proxy
-- [x] UDP support
-- [x] Connection manager
From 70c8605cca3b9cba8598bad52d3bb6a36d77d032 Mon Sep 17 00:00:00 2001
From: Dreamacro <8615343+Dreamacro@users.noreply.github.com>
Date: Mon, 20 Sep 2021 21:02:18 +0800
Subject: [PATCH 68/96] Improve: use one bytes.Buffer pool
---
common/pool/buffer.go | 17 ++++++++++++++++
transport/gun/gun.go | 9 ++++-----
transport/simple-obfs/tls.go | 3 ++-
transport/snell/snell.go | 12 +++++-------
transport/ssr/obfs/http_simple.go | 6 ++----
transport/ssr/obfs/tls1.2_ticket_auth.go | 25 ++++++++++--------------
transport/ssr/protocol/packet.go | 8 +++-----
transport/ssr/protocol/stream.go | 6 ++----
transport/ssr/tools/bufPool.go | 13 +++---------
transport/trojan/trojan.go | 14 +++++--------
10 files changed, 53 insertions(+), 60 deletions(-)
create mode 100644 common/pool/buffer.go
diff --git a/common/pool/buffer.go b/common/pool/buffer.go
new file mode 100644
index 000000000..fb328b766
--- /dev/null
+++ b/common/pool/buffer.go
@@ -0,0 +1,17 @@
+package pool
+
+import (
+ "bytes"
+ "sync"
+)
+
+var bufferPool = sync.Pool{New: func() interface{} { return &bytes.Buffer{} }}
+
+func GetBuffer() *bytes.Buffer {
+ return bufferPool.Get().(*bytes.Buffer)
+}
+
+func PutBuffer(buf *bytes.Buffer) {
+ buf.Reset()
+ bufferPool.Put(buf)
+}
diff --git a/transport/gun/gun.go b/transport/gun/gun.go
index 3f97121f8..e60d13d75 100644
--- a/transport/gun/gun.go
+++ b/transport/gun/gun.go
@@ -5,7 +5,6 @@ package gun
import (
"bufio"
- "bytes"
"crypto/tls"
"encoding/binary"
"errors"
@@ -17,6 +16,8 @@ import (
"sync"
"time"
+ "github.com/Dreamacro/clash/common/pool"
+
"go.uber.org/atomic"
"golang.org/x/net/http2"
)
@@ -31,7 +32,6 @@ var (
"content-type": []string{"application/grpc"},
"user-agent": []string{"grpc-go/1.36.0"},
}
- bufferPool = sync.Pool{New: func() interface{} { return &bytes.Buffer{} }}
)
type DialFn = func(network, addr string) (net.Conn, error)
@@ -127,9 +127,8 @@ func (g *Conn) Write(b []byte) (n int, err error) {
grpcPayloadLen := uint32(varuintSize + 1 + len(b))
binary.BigEndian.PutUint32(grpcHeader[1:5], grpcPayloadLen)
- buf := bufferPool.Get().(*bytes.Buffer)
- defer bufferPool.Put(buf)
- defer buf.Reset()
+ buf := pool.GetBuffer()
+ defer pool.PutBuffer(buf)
buf.Write(grpcHeader)
buf.Write(protobufHeader[:varuintSize+1])
buf.Write(b)
diff --git a/transport/simple-obfs/tls.go b/transport/simple-obfs/tls.go
index 6484eb6c4..914cfe4af 100644
--- a/transport/simple-obfs/tls.go
+++ b/transport/simple-obfs/tls.go
@@ -102,7 +102,8 @@ func (to *TLSObfs) write(b []byte) (int, error) {
return len(b), err
}
- buf := &bytes.Buffer{}
+ buf := pool.GetBuffer()
+ defer pool.PutBuffer(buf)
buf.Write([]byte{0x17, 0x03, 0x03})
binary.Write(buf, binary.BigEndian, uint16(len(b)))
buf.Write(b)
diff --git a/transport/snell/snell.go b/transport/snell/snell.go
index ecbc90ee8..8966b4bb7 100644
--- a/transport/snell/snell.go
+++ b/transport/snell/snell.go
@@ -1,13 +1,13 @@
package snell
import (
- "bytes"
"encoding/binary"
"errors"
"fmt"
"io"
"net"
- "sync"
+
+ "github.com/Dreamacro/clash/common/pool"
"github.com/Dreamacro/go-shadowsocks2/shadowaead"
)
@@ -31,8 +31,7 @@ const (
)
var (
- bufferPool = sync.Pool{New: func() interface{} { return &bytes.Buffer{} }}
- endSignal = []byte{}
+ endSignal = []byte{}
)
type Snell struct {
@@ -79,9 +78,8 @@ func (s *Snell) Read(b []byte) (int, error) {
}
func WriteHeader(conn net.Conn, host string, port uint, version int) error {
- buf := bufferPool.Get().(*bytes.Buffer)
- buf.Reset()
- defer bufferPool.Put(buf)
+ buf := pool.GetBuffer()
+ defer pool.PutBuffer(buf)
buf.WriteByte(Version)
if version == Version2 {
buf.WriteByte(CommandConnectV2)
diff --git a/transport/ssr/obfs/http_simple.go b/transport/ssr/obfs/http_simple.go
index 26fb31247..c1ea76738 100644
--- a/transport/ssr/obfs/http_simple.go
+++ b/transport/ssr/obfs/http_simple.go
@@ -10,7 +10,6 @@ import (
"strings"
"github.com/Dreamacro/clash/common/pool"
- "github.com/Dreamacro/clash/transport/ssr/tools"
)
func init() {
@@ -102,9 +101,8 @@ func (c *httpConn) Write(b []byte) (int, error) {
hosts := strings.Split(host, ",")
host = hosts[rand.Intn(len(hosts))]
- buf := tools.BufPool.Get().(*bytes.Buffer)
- defer tools.BufPool.Put(buf)
- defer buf.Reset()
+ buf := pool.GetBuffer()
+ defer pool.PutBuffer(buf)
if c.post {
buf.WriteString("POST /")
} else {
diff --git a/transport/ssr/obfs/tls1.2_ticket_auth.go b/transport/ssr/obfs/tls1.2_ticket_auth.go
index d9141121c..10f2786ad 100644
--- a/transport/ssr/obfs/tls1.2_ticket_auth.go
+++ b/transport/ssr/obfs/tls1.2_ticket_auth.go
@@ -87,9 +87,8 @@ func (c *tls12TicketConn) Read(b []byte) (int, error) {
func (c *tls12TicketConn) Write(b []byte) (int, error) {
length := len(b)
if c.handshakeStatus == 8 {
- buf := tools.BufPool.Get().(*bytes.Buffer)
- defer tools.BufPool.Put(buf)
- defer buf.Reset()
+ buf := pool.GetBuffer()
+ defer pool.PutBuffer(buf)
for len(b) > 2048 {
size := rand.Intn(4096) + 100
if len(b) < size {
@@ -115,9 +114,8 @@ func (c *tls12TicketConn) Write(b []byte) (int, error) {
if c.handshakeStatus == 0 {
c.handshakeStatus = 1
- data := tools.BufPool.Get().(*bytes.Buffer)
- defer tools.BufPool.Put(data)
- defer data.Reset()
+ data := pool.GetBuffer()
+ defer pool.PutBuffer(data)
data.Write([]byte{3, 3})
c.packAuthData(data)
@@ -126,9 +124,8 @@ func (c *tls12TicketConn) Write(b []byte) (int, error) {
data.Write([]byte{0x00, 0x1c, 0xc0, 0x2b, 0xc0, 0x2f, 0xcc, 0xa9, 0xcc, 0xa8, 0xcc, 0x14, 0xcc, 0x13, 0xc0, 0x0a, 0xc0, 0x14, 0xc0, 0x09, 0xc0, 0x13, 0x00, 0x9c, 0x00, 0x35, 0x00, 0x2f, 0x00, 0x0a})
data.Write([]byte{0x1, 0x0})
- ext := tools.BufPool.Get().(*bytes.Buffer)
- defer tools.BufPool.Put(ext)
- defer ext.Reset()
+ ext := pool.GetBuffer()
+ defer pool.PutBuffer(ext)
host := c.getHost()
ext.Write([]byte{0xff, 0x01, 0x00, 0x01, 0x00})
@@ -145,9 +142,8 @@ func (c *tls12TicketConn) Write(b []byte) (int, error) {
binary.Write(data, binary.BigEndian, uint16(ext.Len()))
data.ReadFrom(ext)
- ret := tools.BufPool.Get().(*bytes.Buffer)
- defer tools.BufPool.Put(ret)
- defer ret.Reset()
+ ret := pool.GetBuffer()
+ defer pool.PutBuffer(ret)
ret.Write([]byte{0x16, 3, 1})
binary.Write(ret, binary.BigEndian, uint16(data.Len()+4))
@@ -161,9 +157,8 @@ func (c *tls12TicketConn) Write(b []byte) (int, error) {
}
return length, nil
} else if c.handshakeStatus == 1 && len(b) == 0 {
- buf := tools.BufPool.Get().(*bytes.Buffer)
- defer tools.BufPool.Put(buf)
- defer buf.Reset()
+ buf := pool.GetBuffer()
+ defer pool.PutBuffer(buf)
buf.Write([]byte{0x14, 3, 3, 0, 1, 1, 0x16, 3, 3, 0, 0x20})
tools.AppendRandBytes(buf, 22)
diff --git a/transport/ssr/protocol/packet.go b/transport/ssr/protocol/packet.go
index 621dc8c8f..249db70a2 100644
--- a/transport/ssr/protocol/packet.go
+++ b/transport/ssr/protocol/packet.go
@@ -1,10 +1,9 @@
package protocol
import (
- "bytes"
"net"
- "github.com/Dreamacro/clash/transport/ssr/tools"
+ "github.com/Dreamacro/clash/common/pool"
)
type PacketConn struct {
@@ -13,9 +12,8 @@ type PacketConn struct {
}
func (c *PacketConn) WriteTo(b []byte, addr net.Addr) (int, error) {
- buf := tools.BufPool.Get().(*bytes.Buffer)
- defer tools.BufPool.Put(buf)
- defer buf.Reset()
+ buf := pool.GetBuffer()
+ defer pool.PutBuffer(buf)
err := c.EncodePacket(buf, b)
if err != nil {
return 0, err
diff --git a/transport/ssr/protocol/stream.go b/transport/ssr/protocol/stream.go
index 25d46f74a..3c846157a 100644
--- a/transport/ssr/protocol/stream.go
+++ b/transport/ssr/protocol/stream.go
@@ -5,7 +5,6 @@ import (
"net"
"github.com/Dreamacro/clash/common/pool"
- "github.com/Dreamacro/clash/transport/ssr/tools"
)
type Conn struct {
@@ -37,9 +36,8 @@ func (c *Conn) Read(b []byte) (int, error) {
func (c *Conn) Write(b []byte) (int, error) {
bLength := len(b)
- buf := tools.BufPool.Get().(*bytes.Buffer)
- defer tools.BufPool.Put(buf)
- defer buf.Reset()
+ buf := pool.GetBuffer()
+ defer pool.PutBuffer(buf)
err := c.Encode(buf, b)
if err != nil {
return 0, err
diff --git a/transport/ssr/tools/bufPool.go b/transport/ssr/tools/bufPool.go
index f3c45c469..ac15c97db 100644
--- a/transport/ssr/tools/bufPool.go
+++ b/transport/ssr/tools/bufPool.go
@@ -2,17 +2,10 @@ package tools
import (
"bytes"
- "math/rand"
- "sync"
-
- "github.com/Dreamacro/clash/common/pool"
+ "crypto/rand"
+ "io"
)
-var BufPool = sync.Pool{New: func() interface{} { return &bytes.Buffer{} }}
-
func AppendRandBytes(b *bytes.Buffer, length int) {
- randBytes := pool.Get(length)
- defer pool.Put(randBytes)
- rand.Read(randBytes)
- b.Write(randBytes)
+ b.ReadFrom(io.LimitReader(rand.Reader, int64(length)))
}
diff --git a/transport/trojan/trojan.go b/transport/trojan/trojan.go
index d62e3f80d..d39cbec1e 100644
--- a/transport/trojan/trojan.go
+++ b/transport/trojan/trojan.go
@@ -1,7 +1,6 @@
package trojan
import (
- "bytes"
"crypto/sha256"
"crypto/tls"
"encoding/binary"
@@ -11,6 +10,7 @@ import (
"net"
"sync"
+ "github.com/Dreamacro/clash/common/pool"
"github.com/Dreamacro/clash/transport/socks5"
)
@@ -22,8 +22,6 @@ const (
var (
defaultALPN = []string{"h2", "http/1.1"}
crlf = []byte{'\r', '\n'}
-
- bufPool = sync.Pool{New: func() interface{} { return &bytes.Buffer{} }}
)
type Command = byte
@@ -67,9 +65,8 @@ func (t *Trojan) StreamConn(conn net.Conn) (net.Conn, error) {
}
func (t *Trojan) WriteHeader(w io.Writer, command Command, socks5Addr []byte) error {
- buf := bufPool.Get().(*bytes.Buffer)
- defer bufPool.Put(buf)
- defer buf.Reset()
+ buf := pool.GetBuffer()
+ defer pool.PutBuffer(buf)
buf.Write(t.hexPassword)
buf.Write(crlf)
@@ -89,9 +86,8 @@ func (t *Trojan) PacketConn(conn net.Conn) net.PacketConn {
}
func writePacket(w io.Writer, socks5Addr, payload []byte) (int, error) {
- buf := bufPool.Get().(*bytes.Buffer)
- defer bufPool.Put(buf)
- defer buf.Reset()
+ buf := pool.GetBuffer()
+ defer pool.PutBuffer(buf)
buf.Write(socks5Addr)
binary.Write(buf, binary.BigEndian, uint16(len(payload)))
From 9aeb4c8cfe83e77caef46594e27797dd8f30bec3 Mon Sep 17 00:00:00 2001
From: bobo liu <7552030+fakeboboliu@users.noreply.github.com>
Date: Tue, 28 Sep 2021 23:15:53 +0800
Subject: [PATCH 69/96] Improve: avoid bufconn twice (#1650)
---
common/net/bufconn.go | 3 +++
1 file changed, 3 insertions(+)
diff --git a/common/net/bufconn.go b/common/net/bufconn.go
index cb7433d2e..a50c7f030 100644
--- a/common/net/bufconn.go
+++ b/common/net/bufconn.go
@@ -11,6 +11,9 @@ type BufferedConn struct {
}
func NewBufferedConn(c net.Conn) *BufferedConn {
+ if bc, ok := c.(*BufferedConn); ok {
+ return bc
+ }
return &BufferedConn{bufio.NewReader(c), c}
}
From ced9749104e47d717a849a4ae18fd9c6ed0a0658 Mon Sep 17 00:00:00 2001
From: Kr328
Date: Thu, 30 Sep 2021 16:30:07 +0800
Subject: [PATCH 70/96] Fix: http proxy should response correct http version
(#1651)
---
listener/http/proxy.go | 24 +++++++++++-------------
1 file changed, 11 insertions(+), 13 deletions(-)
diff --git a/listener/http/proxy.go b/listener/http/proxy.go
index 229106dfe..23a73739a 100644
--- a/listener/http/proxy.go
+++ b/listener/http/proxy.go
@@ -1,6 +1,7 @@
package http
import (
+ "fmt"
"net"
"net/http"
"strings"
@@ -43,11 +44,8 @@ func HandleConn(c net.Conn, in chan<- C.ConnContext, cache *cache.Cache) {
if trusted {
if request.Method == http.MethodConnect {
- resp = responseWith(200)
- resp.Status = "Connection established"
- resp.ContentLength = -1
-
- if resp.Write(conn) != nil {
+ // Manual writing to support CONNECT for http 1.0 (workaround for uplay client)
+ if _, err = fmt.Fprintf(conn, "HTTP/%d.%d %03d %s\r\n\r\n", request.ProtoMajor, request.ProtoMinor, http.StatusOK, "Connection established"); err != nil {
break // close connection
}
@@ -67,11 +65,11 @@ func HandleConn(c net.Conn, in chan<- C.ConnContext, cache *cache.Cache) {
removeExtraHTTPHostPort(request)
if request.URL.Scheme == "" || request.URL.Host == "" {
- resp = responseWith(http.StatusBadRequest)
+ resp = responseWith(request, http.StatusBadRequest)
} else {
resp, err = client.Do(request)
if err != nil {
- resp = responseWith(http.StatusBadGateway)
+ resp = responseWith(request, http.StatusBadGateway)
}
}
@@ -100,7 +98,7 @@ func authenticate(request *http.Request, cache *cache.Cache) *http.Response {
if authenticator != nil {
credential := parseBasicProxyAuthorization(request)
if credential == "" {
- resp := responseWith(http.StatusProxyAuthRequired)
+ resp := responseWith(request, http.StatusProxyAuthRequired)
resp.Header.Set("Proxy-Authenticate", "Basic")
return resp
}
@@ -114,20 +112,20 @@ func authenticate(request *http.Request, cache *cache.Cache) *http.Response {
if !authed.(bool) {
log.Infoln("Auth failed from %s", request.RemoteAddr)
- return responseWith(http.StatusForbidden)
+ return responseWith(request, http.StatusForbidden)
}
}
return nil
}
-func responseWith(statusCode int) *http.Response {
+func responseWith(request *http.Request, statusCode int) *http.Response {
return &http.Response{
StatusCode: statusCode,
Status: http.StatusText(statusCode),
- Proto: "HTTP/1.1",
- ProtoMajor: 1,
- ProtoMinor: 1,
+ Proto: request.Proto,
+ ProtoMajor: request.ProtoMajor,
+ ProtoMinor: request.ProtoMinor,
Header: http.Header{},
}
}
From 537b672fcf9917c51003291bc73145d6713520f2 Mon Sep 17 00:00:00 2001
From: Dreamacro <8615343+Dreamacro@users.noreply.github.com>
Date: Mon, 4 Oct 2021 19:20:11 +0800
Subject: [PATCH 71/96] Change: use bbolt as cache db
---
component/profile/cachefile/cache.go | 119 +++++++++++++++++----------
constant/path.go | 6 +-
go.mod | 1 +
go.sum | 3 +
4 files changed, 83 insertions(+), 46 deletions(-)
diff --git a/component/profile/cachefile/cache.go b/component/profile/cachefile/cache.go
index b23eeb97f..e78e0cca6 100644
--- a/component/profile/cachefile/cache.go
+++ b/component/profile/cachefile/cache.go
@@ -10,45 +10,40 @@ import (
"github.com/Dreamacro/clash/component/profile"
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/log"
+
+ bolt "go.etcd.io/bbolt"
)
var (
initOnce sync.Once
fileMode os.FileMode = 0666
defaultCache *CacheFile
-)
-type cache struct {
- Selected map[string]string
-}
+ bucketSelected = []byte("selected")
+)
// CacheFile store and update the cache file
type CacheFile struct {
- path string
- model *cache
- buf *bytes.Buffer
- mux sync.Mutex
+ db *bolt.DB
}
func (c *CacheFile) SetSelected(group, selected string) {
if !profile.StoreSelected.Load() {
return
- }
-
- c.mux.Lock()
- defer c.mux.Unlock()
-
- model := c.element()
-
- model.Selected[group] = selected
- c.buf.Reset()
- if err := gob.NewEncoder(c.buf).Encode(model); err != nil {
- log.Warnln("[CacheFile] encode gob failed: %s", err.Error())
+ } else if c.db == nil {
return
}
- if err := ioutil.WriteFile(c.path, c.buf.Bytes(), fileMode); err != nil {
- log.Warnln("[CacheFile] write cache to %s failed: %s", c.path, err.Error())
+ err := c.db.Batch(func(t *bolt.Tx) error {
+ bucket, err := t.CreateBucketIfNotExists(bucketSelected)
+ if err != nil {
+ return err
+ }
+ return bucket.Put([]byte(group), []byte(selected))
+ })
+
+ if err != nil {
+ log.Warnln("[CacheFile] write cache to %s failed: %s", c.db.Path(), err.Error())
return
}
}
@@ -56,46 +51,80 @@ func (c *CacheFile) SetSelected(group, selected string) {
func (c *CacheFile) SelectedMap() map[string]string {
if !profile.StoreSelected.Load() {
return nil
+ } else if c.db == nil {
+ return nil
}
- c.mux.Lock()
- defer c.mux.Unlock()
-
- model := c.element()
-
mapping := map[string]string{}
- for k, v := range model.Selected {
- mapping[k] = v
- }
+ c.db.View(func(t *bolt.Tx) error {
+ bucket := t.Bucket(bucketSelected)
+ if bucket == nil {
+ return nil
+ }
+
+ c := bucket.Cursor()
+ for k, v := c.First(); k != nil; k, v = c.Next() {
+ mapping[string(k)] = string(v)
+ }
+ return nil
+ })
return mapping
}
-func (c *CacheFile) element() *cache {
- if c.model != nil {
- return c.model
- }
+func (c *CacheFile) Close() error {
+ return c.db.Close()
+}
+func migrateCache() {
+ defer func() {
+ db, err := bolt.Open(C.Path.Cache(), fileMode, nil)
+ if err != nil {
+ log.Warnln("[CacheFile] can't open cache file: %s", err.Error())
+ }
+ defaultCache = &CacheFile{
+ db: db,
+ }
+ }()
+
+ buf, err := ioutil.ReadFile(C.Path.OldCache())
+ if err != nil {
+ return
+ }
+ defer os.Remove(C.Path.OldCache())
+
+ // read old cache file
+ type cache struct {
+ Selected map[string]string
+ }
model := &cache{
Selected: map[string]string{},
}
+ bufReader := bytes.NewBuffer(buf)
+ gob.NewDecoder(bufReader).Decode(model)
- if buf, err := ioutil.ReadFile(c.path); err == nil {
- bufReader := bytes.NewBuffer(buf)
- gob.NewDecoder(bufReader).Decode(model)
+ // write to new cache file
+ db, err := bolt.Open(C.Path.Cache(), fileMode, nil)
+ if err != nil {
+ return
}
-
- c.model = model
- return c.model
+ defer db.Close()
+ db.Batch(func(t *bolt.Tx) error {
+ bucket, err := t.CreateBucketIfNotExists(bucketSelected)
+ if err != nil {
+ return err
+ }
+ for group, selected := range model.Selected {
+ if err := bucket.Put([]byte(group), []byte(selected)); err != nil {
+ return err
+ }
+ }
+ return nil
+ })
}
// Cache return singleton of CacheFile
func Cache() *CacheFile {
- initOnce.Do(func() {
- defaultCache = &CacheFile{
- path: C.Path.Cache(),
- buf: &bytes.Buffer{},
- }
- })
+ initOnce.Do(migrateCache)
return defaultCache
}
diff --git a/constant/path.go b/constant/path.go
index ba0e8c23b..781cc5f7c 100644
--- a/constant/path.go
+++ b/constant/path.go
@@ -55,6 +55,10 @@ func (p *path) MMDB() string {
return P.Join(p.homeDir, "Country.mmdb")
}
-func (p *path) Cache() string {
+func (p *path) OldCache() string {
return P.Join(p.homeDir, ".cache")
}
+
+func (p *path) Cache() string {
+ return P.Join(p.homeDir, "cache.db")
+}
diff --git a/go.mod b/go.mod
index e955449b8..dc79d77af 100644
--- a/go.mod
+++ b/go.mod
@@ -14,6 +14,7 @@ require (
github.com/oschwald/geoip2-golang v1.5.0
github.com/sirupsen/logrus v1.8.1
github.com/stretchr/testify v1.7.0
+ go.etcd.io/bbolt v1.3.6
go.uber.org/atomic v1.9.0
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5
golang.org/x/net v0.0.0-20210903162142-ad29c8ab022f
diff --git a/go.sum b/go.sum
index d1d97cfc4..1fbae8ce4 100644
--- a/go.sum
+++ b/go.sum
@@ -55,6 +55,8 @@ github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5Cc
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/u-root/uio v0.0.0-20210528114334-82958018845c h1:BFvcl34IGnw8yvJi8hlqLFo9EshRInwWBs2M5fGWzQA=
github.com/u-root/uio v0.0.0-20210528114334-82958018845c/go.mod h1:LpEX5FO/cB+WF4TYGY1V5qktpaZLkKkSegbr0V4eYXA=
+go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU=
+go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4=
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
@@ -87,6 +89,7 @@ golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191224085550-c709ea063b76/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201101102859-da207088b7d1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
From 4f1fac02abe706926f2f8139ec1752e24649fc39 Mon Sep 17 00:00:00 2001
From: Dreamacro <8615343+Dreamacro@users.noreply.github.com>
Date: Tue, 5 Oct 2021 12:42:21 +0800
Subject: [PATCH 72/96] Chore: add remove TODO
---
adapter/outbound/vmess.go | 36 +++++++++++++++-------------
component/profile/cachefile/cache.go | 1 +
test/go.mod | 1 +
test/go.sum | 3 +++
4 files changed, 24 insertions(+), 17 deletions(-)
diff --git a/adapter/outbound/vmess.go b/adapter/outbound/vmess.go
index 6ca82c15e..0dbb0f1bf 100644
--- a/adapter/outbound/vmess.go
+++ b/adapter/outbound/vmess.go
@@ -31,23 +31,25 @@ type Vmess struct {
}
type VmessOption struct {
- Name string `proxy:"name"`
- Server string `proxy:"server"`
- Port int `proxy:"port"`
- UUID string `proxy:"uuid"`
- AlterID int `proxy:"alterId"`
- Cipher string `proxy:"cipher"`
- TLS bool `proxy:"tls,omitempty"`
- UDP bool `proxy:"udp,omitempty"`
- Network string `proxy:"network,omitempty"`
- HTTPOpts HTTPOptions `proxy:"http-opts,omitempty"`
- HTTP2Opts HTTP2Options `proxy:"h2-opts,omitempty"`
- GrpcOpts GrpcOptions `proxy:"grpc-opts,omitempty"`
- WSOpts WSOptions `proxy:"ws-opts,omitempty"`
- WSPath string `proxy:"ws-path,omitempty"`
- WSHeaders map[string]string `proxy:"ws-headers,omitempty"`
- SkipCertVerify bool `proxy:"skip-cert-verify,omitempty"`
- ServerName string `proxy:"servername,omitempty"`
+ Name string `proxy:"name"`
+ Server string `proxy:"server"`
+ Port int `proxy:"port"`
+ UUID string `proxy:"uuid"`
+ AlterID int `proxy:"alterId"`
+ Cipher string `proxy:"cipher"`
+ UDP bool `proxy:"udp,omitempty"`
+ Network string `proxy:"network,omitempty"`
+ TLS bool `proxy:"tls,omitempty"`
+ SkipCertVerify bool `proxy:"skip-cert-verify,omitempty"`
+ ServerName string `proxy:"servername,omitempty"`
+ HTTPOpts HTTPOptions `proxy:"http-opts,omitempty"`
+ HTTP2Opts HTTP2Options `proxy:"h2-opts,omitempty"`
+ GrpcOpts GrpcOptions `proxy:"grpc-opts,omitempty"`
+ WSOpts WSOptions `proxy:"ws-opts,omitempty"`
+
+ // TODO: remove these until 2022
+ WSHeaders map[string]string `proxy:"ws-headers,omitempty"`
+ WSPath string `proxy:"ws-path,omitempty"`
}
type HTTPOptions struct {
diff --git a/component/profile/cachefile/cache.go b/component/profile/cachefile/cache.go
index e78e0cca6..ffd588615 100644
--- a/component/profile/cachefile/cache.go
+++ b/component/profile/cachefile/cache.go
@@ -75,6 +75,7 @@ func (c *CacheFile) Close() error {
return c.db.Close()
}
+// TODO: remove migrateCache until 2022
func migrateCache() {
defer func() {
db, err := bolt.Open(C.Path.Cache(), fileMode, nil)
diff --git a/test/go.mod b/test/go.mod
index 990edb6c5..3a8781517 100644
--- a/test/go.mod
+++ b/test/go.mod
@@ -36,6 +36,7 @@ require (
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/sirupsen/logrus v1.8.1 // indirect
github.com/u-root/uio v0.0.0-20210528114334-82958018845c // indirect
+ go.etcd.io/bbolt v1.3.6 // indirect
go.uber.org/atomic v1.9.0 // indirect
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 // indirect
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
diff --git a/test/go.sum b/test/go.sum
index 27d2c4de2..e018f54c7 100644
--- a/test/go.sum
+++ b/test/go.sum
@@ -629,6 +629,8 @@ github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
+go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU=
+go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4=
go.etcd.io/etcd v0.5.0-alpha.5.0.20200910180754-dd1b699fc489/go.mod h1:yVHk9ub3CSBatqGNg7GRmsnfLWtoW60w4eDYfh7vHDg=
go.mozilla.org/pkcs7 v0.0.0-20200128120323-432b2356ecb1/go.mod h1:SNgMg+EgDFwmvSmLRTNKC5fegJjB7v23qTQ0XLGUNHk=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
@@ -800,6 +802,7 @@ golang.org/x/sys v0.0.0-20200817155316-9781c653f443/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200916030750-2334cc1a136f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200922070232-aee5d888a860/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201101102859-da207088b7d1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
From b9d470cf79d145736fc87f73e3b7f58119e684a0 Mon Sep 17 00:00:00 2001
From: Dreamacro <8615343+Dreamacro@users.noreply.github.com>
Date: Tue, 5 Oct 2021 13:31:19 +0800
Subject: [PATCH 73/96] Fix: dhcp client should request special interface
---
dns/client.go | 13 +++++++++----
dns/dhcp.go | 7 +++++--
dns/resolver.go | 5 +++--
dns/util.go | 7 ++++---
4 files changed, 21 insertions(+), 11 deletions(-)
diff --git a/dns/client.go b/dns/client.go
index 6a54f9fad..5cb1fe029 100644
--- a/dns/client.go
+++ b/dns/client.go
@@ -15,9 +15,10 @@ import (
type client struct {
*D.Client
- r *Resolver
- port string
- host string
+ r *Resolver
+ port string
+ host string
+ iface string
}
func (c *client) Exchange(m *D.Msg) (*D.Msg, error) {
@@ -45,7 +46,11 @@ func (c *client) ExchangeContext(ctx context.Context, m *D.Msg) (*D.Msg, error)
network = "tcp"
}
- conn, err := dialer.DialContext(ctx, network, net.JoinHostPort(ip.String(), c.port))
+ options := []dialer.Option{}
+ if c.iface != "" {
+ options = append(options, dialer.WithInterface(c.iface))
+ }
+ conn, err := dialer.DialContext(ctx, network, net.JoinHostPort(ip.String(), c.port), options...)
if err != nil {
return nil, err
}
diff --git a/dns/dhcp.go b/dns/dhcp.go
index 94f8a36ce..f964cec8c 100644
--- a/dns/dhcp.go
+++ b/dns/dhcp.go
@@ -68,8 +68,11 @@ func (d *dhcpClient) resolve(ctx context.Context) (*Resolver, error) {
dns, err := dhcp.ResolveDNSFromDHCP(ctx, d.ifaceName)
if err == nil {
nameserver := make([]NameServer, 0, len(dns))
- for _, d := range dns {
- nameserver = append(nameserver, NameServer{Addr: net.JoinHostPort(d.String(), "53")})
+ for _, item := range dns {
+ nameserver = append(nameserver, NameServer{
+ Addr: net.JoinHostPort(item.String(), "53"),
+ Interface: d.ifaceName,
+ })
}
res = NewResolver(Config{
diff --git a/dns/resolver.go b/dns/resolver.go
index 914f1418e..8bbd0e8b2 100644
--- a/dns/resolver.go
+++ b/dns/resolver.go
@@ -302,8 +302,9 @@ func (r *Resolver) asyncExchange(ctx context.Context, client []dnsClient, msg *D
}
type NameServer struct {
- Net string
- Addr string
+ Net string
+ Addr string
+ Interface string
}
type FallbackFilter struct {
diff --git a/dns/util.go b/dns/util.go
index 0c3f42e59..b167809a4 100644
--- a/dns/util.go
+++ b/dns/util.go
@@ -138,9 +138,10 @@ func transform(servers []NameServer, resolver *Resolver) []dnsClient {
UDPSize: 4096,
Timeout: 5 * time.Second,
},
- port: port,
- host: host,
- r: resolver,
+ port: port,
+ host: host,
+ iface: s.Interface,
+ r: resolver,
})
}
return ret
From 66cb0b1218aecb2ea56852e6fba2933044f3dc10 Mon Sep 17 00:00:00 2001
From: Dreamacro <8615343+Dreamacro@users.noreply.github.com>
Date: Tue, 5 Oct 2021 22:47:26 +0800
Subject: [PATCH 74/96] Fix: cache kv db should not block on init
---
component/profile/cachefile/cache.go | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/component/profile/cachefile/cache.go b/component/profile/cachefile/cache.go
index ffd588615..28b05ee02 100644
--- a/component/profile/cachefile/cache.go
+++ b/component/profile/cachefile/cache.go
@@ -6,6 +6,7 @@ import (
"io/ioutil"
"os"
"sync"
+ "time"
"github.com/Dreamacro/clash/component/profile"
C "github.com/Dreamacro/clash/constant"
@@ -78,7 +79,7 @@ func (c *CacheFile) Close() error {
// TODO: remove migrateCache until 2022
func migrateCache() {
defer func() {
- db, err := bolt.Open(C.Path.Cache(), fileMode, nil)
+ db, err := bolt.Open(C.Path.Cache(), fileMode, &bolt.Options{Timeout: time.Second})
if err != nil {
log.Warnln("[CacheFile] can't open cache file: %s", err.Error())
}
From 1996bef9e6cad6ee954facc186ea70e411eb108c Mon Sep 17 00:00:00 2001
From: beyondkmp
Date: Thu, 7 Oct 2021 22:57:55 +0800
Subject: [PATCH 75/96] Chore: doh request should with id 0 (#1660)
---
dns/doh.go | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/dns/doh.go b/dns/doh.go
index 34375017d..53b0fb331 100644
--- a/dns/doh.go
+++ b/dns/doh.go
@@ -28,13 +28,19 @@ func (dc *dohClient) Exchange(m *D.Msg) (msg *D.Msg, err error) {
}
func (dc *dohClient) ExchangeContext(ctx context.Context, m *D.Msg) (msg *D.Msg, err error) {
- req, err := dc.newRequest(m)
+ // https://datatracker.ietf.org/doc/html/rfc8484#section-4.1
+ // In order to maximize cache friendliness, SHOULD use a DNS ID of 0 in every DNS request.
+ newM := *m
+ newM.Id = 0
+ req, err := dc.newRequest(&newM)
if err != nil {
return nil, err
}
req = req.WithContext(ctx)
- return dc.doRequest(req)
+ msg, err = dc.doRequest(req)
+ msg.Id = m.Id
+ return
}
// newRequest returns a new DoH request given a dns.Msg.
From 4ce35870fea0eeceb212f83110b9ab4be88e9281 Mon Sep 17 00:00:00 2001
From: Dreamacro <8615343+Dreamacro@users.noreply.github.com>
Date: Sat, 9 Oct 2021 20:35:06 +0800
Subject: [PATCH 76/96] Chore: remove deprecated ioutil
---
adapter/outbound/socks5.go | 3 +--
adapter/provider/fetcher.go | 5 ++---
adapter/provider/vehicle.go | 7 ++++---
component/process/process_linux.go | 14 +++++++++-----
component/profile/cachefile/cache.go | 3 +--
dns/doh.go | 4 ++--
hub/executor/executor.go | 3 +--
listener/socks/tcp.go | 3 +--
8 files changed, 21 insertions(+), 21 deletions(-)
diff --git a/adapter/outbound/socks5.go b/adapter/outbound/socks5.go
index 1402c6186..d97395575 100644
--- a/adapter/outbound/socks5.go
+++ b/adapter/outbound/socks5.go
@@ -6,7 +6,6 @@ import (
"errors"
"fmt"
"io"
- "io/ioutil"
"net"
"strconv"
@@ -116,7 +115,7 @@ func (ss *Socks5) DialUDP(metadata *C.Metadata) (_ C.PacketConn, err error) {
}
go func() {
- io.Copy(ioutil.Discard, c)
+ io.Copy(io.Discard, c)
c.Close()
// A UDP association terminates when the TCP connection that the UDP
// ASSOCIATE request arrived on terminates. RFC1928
diff --git a/adapter/provider/fetcher.go b/adapter/provider/fetcher.go
index 777e3aa54..d3c85ab56 100644
--- a/adapter/provider/fetcher.go
+++ b/adapter/provider/fetcher.go
@@ -3,7 +3,6 @@ package provider
import (
"bytes"
"crypto/md5"
- "io/ioutil"
"os"
"path/filepath"
"time"
@@ -45,7 +44,7 @@ func (f *fetcher) Initial() (interface{}, error) {
isLocal bool
)
if stat, fErr := os.Stat(f.vehicle.Path()); fErr == nil {
- buf, err = ioutil.ReadFile(f.vehicle.Path())
+ buf, err = os.ReadFile(f.vehicle.Path())
modTime := stat.ModTime()
f.updatedAt = &modTime
isLocal = true
@@ -165,7 +164,7 @@ func safeWrite(path string, buf []byte) error {
}
}
- return ioutil.WriteFile(path, buf, fileMode)
+ return os.WriteFile(path, buf, fileMode)
}
func newFetcher(name string, interval time.Duration, vehicle types.Vehicle, parser parser, onUpdate func(interface{})) *fetcher {
diff --git a/adapter/provider/vehicle.go b/adapter/provider/vehicle.go
index f556e69c4..4f08c317e 100644
--- a/adapter/provider/vehicle.go
+++ b/adapter/provider/vehicle.go
@@ -2,10 +2,11 @@ package provider
import (
"context"
- "io/ioutil"
+ "io"
"net"
"net/http"
"net/url"
+ "os"
"time"
"github.com/Dreamacro/clash/component/dialer"
@@ -25,7 +26,7 @@ func (f *FileVehicle) Path() string {
}
func (f *FileVehicle) Read() ([]byte, error) {
- return ioutil.ReadFile(f.path)
+ return os.ReadFile(f.path)
}
func NewFileVehicle(path string) *FileVehicle {
@@ -84,7 +85,7 @@ func (h *HTTPVehicle) Read() ([]byte, error) {
}
defer resp.Body.Close()
- buf, err := ioutil.ReadAll(resp.Body)
+ buf, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
diff --git a/component/process/process_linux.go b/component/process/process_linux.go
index fabe969c8..f77c10597 100644
--- a/component/process/process_linux.go
+++ b/component/process/process_linux.go
@@ -5,8 +5,8 @@ import (
"encoding/binary"
"fmt"
"io"
- "io/ioutil"
"net"
+ "os"
"path"
"path/filepath"
"syscall"
@@ -167,7 +167,7 @@ func unpackSocketDiagResponse(msg *syscall.NetlinkMessage) (inode, uid uint32) {
}
func resolveProcessNameByProcSearch(inode, uid int) (string, error) {
- files, err := ioutil.ReadDir(pathProc)
+ files, err := os.ReadDir(pathProc)
if err != nil {
return "", err
}
@@ -180,14 +180,18 @@ func resolveProcessNameByProcSearch(inode, uid int) (string, error) {
continue
}
- if f.Sys().(*syscall.Stat_t).Uid != uint32(uid) {
+ info, err := f.Info()
+ if err != nil {
+ return "", err
+ }
+ if info.Sys().(*syscall.Stat_t).Uid != uint32(uid) {
continue
}
processPath := path.Join(pathProc, f.Name())
fdPath := path.Join(processPath, "fd")
- fds, err := ioutil.ReadDir(fdPath)
+ fds, err := os.ReadDir(fdPath)
if err != nil {
continue
}
@@ -199,7 +203,7 @@ func resolveProcessNameByProcSearch(inode, uid int) (string, error) {
}
if bytes.Equal(buffer[:n], socket) {
- cmdline, err := ioutil.ReadFile(path.Join(processPath, "cmdline"))
+ cmdline, err := os.ReadFile(path.Join(processPath, "cmdline"))
if err != nil {
return "", err
}
diff --git a/component/profile/cachefile/cache.go b/component/profile/cachefile/cache.go
index 28b05ee02..a9d1bc5b9 100644
--- a/component/profile/cachefile/cache.go
+++ b/component/profile/cachefile/cache.go
@@ -3,7 +3,6 @@ package cachefile
import (
"bytes"
"encoding/gob"
- "io/ioutil"
"os"
"sync"
"time"
@@ -88,7 +87,7 @@ func migrateCache() {
}
}()
- buf, err := ioutil.ReadFile(C.Path.OldCache())
+ buf, err := os.ReadFile(C.Path.OldCache())
if err != nil {
return
}
diff --git a/dns/doh.go b/dns/doh.go
index 53b0fb331..3daa7f22b 100644
--- a/dns/doh.go
+++ b/dns/doh.go
@@ -3,7 +3,7 @@ package dns
import (
"bytes"
"context"
- "io/ioutil"
+ "io"
"net"
"net/http"
@@ -68,7 +68,7 @@ func (dc *dohClient) doRequest(req *http.Request) (msg *D.Msg, err error) {
}
defer resp.Body.Close()
- buf, err := ioutil.ReadAll(resp.Body)
+ buf, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
diff --git a/hub/executor/executor.go b/hub/executor/executor.go
index 5c002b64f..2147906f1 100644
--- a/hub/executor/executor.go
+++ b/hub/executor/executor.go
@@ -2,7 +2,6 @@ package executor
import (
"fmt"
- "io/ioutil"
"os"
"sync"
@@ -33,7 +32,7 @@ func readConfig(path string) ([]byte, error) {
if _, err := os.Stat(path); os.IsNotExist(err) {
return nil, err
}
- data, err := ioutil.ReadFile(path)
+ data, err := os.ReadFile(path)
if err != nil {
return nil, err
}
diff --git a/listener/socks/tcp.go b/listener/socks/tcp.go
index 49d0a1e31..29016f5b1 100644
--- a/listener/socks/tcp.go
+++ b/listener/socks/tcp.go
@@ -2,7 +2,6 @@ package socks
import (
"io"
- "io/ioutil"
"net"
"github.com/Dreamacro/clash/adapter/inbound"
@@ -102,7 +101,7 @@ func HandleSocks5(conn net.Conn, in chan<- C.ConnContext) {
}
if command == socks5.CmdUDPAssociate {
defer conn.Close()
- io.Copy(ioutil.Discard, conn)
+ io.Copy(io.Discard, conn)
return
}
in <- inbound.NewSocket(target, conn, C.SOCKS5)
From f1cf7e926972e8d0a3e2042bec89f0175d987e39 Mon Sep 17 00:00:00 2001
From: Dreamacro <8615343+Dreamacro@users.noreply.github.com>
Date: Sun, 10 Oct 2021 23:44:09 +0800
Subject: [PATCH 77/96] Style: use gofumpt for fmt
---
.github/workflows/go.yml | 5 ++---
Makefile | 4 ++++
adapter/provider/fetcher.go | 4 ++--
adapter/provider/parser.go | 4 +---
common/cache/lrucache_test.go | 1 -
common/murmur3/murmur32.go | 1 -
common/observable/observable_test.go | 2 +-
common/pool/alloc.go | 1 +
common/singledo/singledo_test.go | 2 +-
common/structure/structure_test.go | 6 ++++--
component/dialer/options.go | 4 +---
component/iface/iface.go | 6 ++++--
component/mmdb/mmdb.go | 6 ++++--
component/process/process_linux.go | 6 ++++--
component/profile/cachefile/cache.go | 3 +--
component/profile/profile.go | 6 ++----
component/trie/domain.go | 6 ++----
config/initial.go | 6 +++---
dns/filters.go | 1 +
dns/middleware.go | 6 ++++--
dns/resolver.go | 1 -
dns/util.go | 14 ++++++--------
hub/executor/executor.go | 4 +---
listener/auth/auth.go | 4 +---
log/level.go | 18 ++++++++----------
transport/gun/gun.go | 10 ++++------
transport/simple-obfs/tls.go | 1 +
transport/snell/cipher.go | 1 +
transport/snell/snell.go | 4 +---
transport/socks4/socks4.go | 2 +-
transport/ssr/protocol/auth_aes128_sha1.go | 6 ++++--
transport/vmess/header.go | 2 +-
transport/vmess/websocket.go | 1 +
tunnel/mode.go | 14 ++++++--------
34 files changed, 78 insertions(+), 84 deletions(-)
diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml
index 1058dd4f4..af6f9a91d 100644
--- a/.github/workflows/go.yml
+++ b/.github/workflows/go.yml
@@ -30,9 +30,8 @@ jobs:
- name: Get dependencies, run test and static check
run: |
go test ./...
- go vet ./...
- go install honnef.co/go/tools/cmd/staticcheck@latest
- staticcheck -- $(go list ./...)
+ go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
+ golangci-lint run --disable-all -E govet -E gofumpt -E megacheck ./...
- name: Build
if: startsWith(github.ref, 'refs/tags/')
diff --git a/Makefile b/Makefile
index 97328bc23..b6a5b22af 100644
--- a/Makefile
+++ b/Makefile
@@ -112,5 +112,9 @@ $(zip_releases): %.zip : %
all-arch: $(PLATFORM_LIST) $(WINDOWS_ARCH_LIST)
releases: $(gz_releases) $(zip_releases)
+
+lint:
+ golangci-lint run --disable-all -E govet -E gofumpt -E megacheck ./...
+
clean:
rm $(BINDIR)/*
diff --git a/adapter/provider/fetcher.go b/adapter/provider/fetcher.go
index d3c85ab56..6c1e96b43 100644
--- a/adapter/provider/fetcher.go
+++ b/adapter/provider/fetcher.go
@@ -12,8 +12,8 @@ import (
)
var (
- fileMode os.FileMode = 0666
- dirMode os.FileMode = 0755
+ fileMode os.FileMode = 0o666
+ dirMode os.FileMode = 0o755
)
type parser = func([]byte) (interface{}, error)
diff --git a/adapter/provider/parser.go b/adapter/provider/parser.go
index f326d4ccb..8a1739669 100644
--- a/adapter/provider/parser.go
+++ b/adapter/provider/parser.go
@@ -10,9 +10,7 @@ import (
types "github.com/Dreamacro/clash/constant/provider"
)
-var (
- errVehicleType = errors.New("unsupport vehicle type")
-)
+var errVehicleType = errors.New("unsupport vehicle type")
type healthCheckSchema struct {
Enable bool `provider:"enable"`
diff --git a/common/cache/lrucache_test.go b/common/cache/lrucache_test.go
index 13675bff3..8a04f7464 100644
--- a/common/cache/lrucache_test.go
+++ b/common/cache/lrucache_test.go
@@ -149,7 +149,6 @@ func TestSetWithExpire(t *testing.T) {
assert.Equal(t, nil, res)
assert.Equal(t, time.Time{}, expires)
assert.Equal(t, false, exist)
-
}
func TestStale(t *testing.T) {
diff --git a/common/murmur3/murmur32.go b/common/murmur3/murmur32.go
index 9861eecd8..e52b7937d 100644
--- a/common/murmur3/murmur32.go
+++ b/common/murmur3/murmur32.go
@@ -67,7 +67,6 @@ func (d *digest32) bmix(p []byte) (tail []byte) {
}
func (d *digest32) Sum32() (h1 uint32) {
-
h1 = d.h1
var k1 uint32
diff --git a/common/observable/observable_test.go b/common/observable/observable_test.go
index cb16ad399..b70feec87 100644
--- a/common/observable/observable_test.go
+++ b/common/observable/observable_test.go
@@ -38,7 +38,7 @@ func TestObservable_MultiSubscribe(t *testing.T) {
src := NewObservable(iter)
ch1, _ := src.Subscribe()
ch2, _ := src.Subscribe()
- var count = atomic.NewInt32(0)
+ count := atomic.NewInt32(0)
var wg sync.WaitGroup
wg.Add(2)
diff --git a/common/pool/alloc.go b/common/pool/alloc.go
index 6ae53c1db..710639af8 100644
--- a/common/pool/alloc.go
+++ b/common/pool/alloc.go
@@ -53,6 +53,7 @@ func (alloc *Allocator) Put(buf []byte) error {
}
//lint:ignore SA6002 ignore temporarily
+ //nolint
alloc.buffers[bits].Put(buf)
return nil
}
diff --git a/common/singledo/singledo_test.go b/common/singledo/singledo_test.go
index 2b0d5988b..c85795c20 100644
--- a/common/singledo/singledo_test.go
+++ b/common/singledo/singledo_test.go
@@ -12,7 +12,7 @@ import (
func TestBasic(t *testing.T) {
single := NewSingle(time.Millisecond * 30)
foo := 0
- var shardCount = atomic.NewInt32(0)
+ shardCount := atomic.NewInt32(0)
call := func() (interface{}, error) {
foo++
time.Sleep(time.Millisecond * 5)
diff --git a/common/structure/structure_test.go b/common/structure/structure_test.go
index 6e3e6290d..0feef28e8 100644
--- a/common/structure/structure_test.go
+++ b/common/structure/structure_test.go
@@ -5,8 +5,10 @@ import (
"testing"
)
-var decoder = NewDecoder(Option{TagName: "test"})
-var weakTypeDecoder = NewDecoder(Option{TagName: "test", WeaklyTypedInput: true})
+var (
+ decoder = NewDecoder(Option{TagName: "test"})
+ weakTypeDecoder = NewDecoder(Option{TagName: "test", WeaklyTypedInput: true})
+)
type Baz struct {
Foo int `test:"foo"`
diff --git a/component/dialer/options.go b/component/dialer/options.go
index 4b5d64c0e..33083864a 100644
--- a/component/dialer/options.go
+++ b/component/dialer/options.go
@@ -1,8 +1,6 @@
package dialer
-var (
- DefaultOptions []Option
-)
+var DefaultOptions []Option
type config struct {
skipDefault bool
diff --git a/component/iface/iface.go b/component/iface/iface.go
index 30c6a6bcb..4e9162601 100644
--- a/component/iface/iface.go
+++ b/component/iface/iface.go
@@ -15,8 +15,10 @@ type Interface struct {
HardwareAddr net.HardwareAddr
}
-var ErrIfaceNotFound = errors.New("interface not found")
-var ErrAddrNotFound = errors.New("addr not found")
+var (
+ ErrIfaceNotFound = errors.New("interface not found")
+ ErrAddrNotFound = errors.New("addr not found")
+)
var interfaces = singledo.NewSingle(time.Second * 20)
diff --git a/component/mmdb/mmdb.go b/component/mmdb/mmdb.go
index 08743985a..e120055d8 100644
--- a/component/mmdb/mmdb.go
+++ b/component/mmdb/mmdb.go
@@ -9,8 +9,10 @@ import (
"github.com/oschwald/geoip2-golang"
)
-var mmdb *geoip2.Reader
-var once sync.Once
+var (
+ mmdb *geoip2.Reader
+ once sync.Once
+)
func LoadFromBytes(buffer []byte) {
once.Do(func() {
diff --git a/component/process/process_linux.go b/component/process/process_linux.go
index f77c10597..be758a692 100644
--- a/component/process/process_linux.go
+++ b/component/process/process_linux.go
@@ -25,8 +25,10 @@ var nativeEndian = func() binary.ByteOrder {
return binary.LittleEndian
}()
-type SocketResolver func(network string, ip net.IP, srcPort int) (inode, uid int, err error)
-type ProcessNameResolver func(inode, uid int) (name string, err error)
+type (
+ SocketResolver func(network string, ip net.IP, srcPort int) (inode, uid int, err error)
+ ProcessNameResolver func(inode, uid int) (name string, err error)
+)
// export for android
var (
diff --git a/component/profile/cachefile/cache.go b/component/profile/cachefile/cache.go
index a9d1bc5b9..03f389a3a 100644
--- a/component/profile/cachefile/cache.go
+++ b/component/profile/cachefile/cache.go
@@ -16,7 +16,7 @@ import (
var (
initOnce sync.Once
- fileMode os.FileMode = 0666
+ fileMode os.FileMode = 0o666
defaultCache *CacheFile
bucketSelected = []byte("selected")
@@ -41,7 +41,6 @@ func (c *CacheFile) SetSelected(group, selected string) {
}
return bucket.Put([]byte(group), []byte(selected))
})
-
if err != nil {
log.Warnln("[CacheFile] write cache to %s failed: %s", c.db.Path(), err.Error())
return
diff --git a/component/profile/profile.go b/component/profile/profile.go
index ca9b1b884..e3d9e78cf 100644
--- a/component/profile/profile.go
+++ b/component/profile/profile.go
@@ -4,7 +4,5 @@ import (
"go.uber.org/atomic"
)
-var (
- // StoreSelected is a global switch for storing selected proxy to cache
- StoreSelected = atomic.NewBool(true)
-)
+// StoreSelected is a global switch for storing selected proxy to cache
+var StoreSelected = atomic.NewBool(true)
diff --git a/component/trie/domain.go b/component/trie/domain.go
index b4de4a707..ffd0b754a 100644
--- a/component/trie/domain.go
+++ b/component/trie/domain.go
@@ -12,10 +12,8 @@ const (
domainStep = "."
)
-var (
- // ErrInvalidDomain means insert domain is invalid
- ErrInvalidDomain = errors.New("invalid domain")
-)
+// ErrInvalidDomain means insert domain is invalid
+var ErrInvalidDomain = errors.New("invalid domain")
// DomainTrie contains the main logic for adding and searching nodes for domain segments.
// support wildcard domain (e.g *.google.com)
diff --git a/config/initial.go b/config/initial.go
index df8452b93..9d1a2db10 100644
--- a/config/initial.go
+++ b/config/initial.go
@@ -18,7 +18,7 @@ func downloadMMDB(path string) (err error) {
}
defer resp.Body.Close()
- f, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY, 0644)
+ f, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY, 0o644)
if err != nil {
return err
}
@@ -54,7 +54,7 @@ func initMMDB() error {
func Init(dir string) error {
// initial homedir
if _, err := os.Stat(dir); os.IsNotExist(err) {
- if err := os.MkdirAll(dir, 0777); err != nil {
+ if err := os.MkdirAll(dir, 0o777); err != nil {
return fmt.Errorf("can't create config directory %s: %s", dir, err.Error())
}
}
@@ -62,7 +62,7 @@ func Init(dir string) error {
// initial config.yaml
if _, err := os.Stat(C.Path.Config()); os.IsNotExist(err) {
log.Infoln("Can't find config, create a initial config file")
- f, err := os.OpenFile(C.Path.Config(), os.O_CREATE|os.O_WRONLY, 0644)
+ f, err := os.OpenFile(C.Path.Config(), os.O_CREATE|os.O_WRONLY, 0o644)
if err != nil {
return fmt.Errorf("can't create file %s: %s", C.Path.Config(), err.Error())
}
diff --git a/dns/filters.go b/dns/filters.go
index bacd7727f..30825a44a 100644
--- a/dns/filters.go
+++ b/dns/filters.go
@@ -32,6 +32,7 @@ func (inf *ipnetFilter) Match(ip net.IP) bool {
type fallbackDomainFilter interface {
Match(domain string) bool
}
+
type domainFilter struct {
tree *trie.DomainTrie
}
diff --git a/dns/middleware.go b/dns/middleware.go
index 782c0ef07..da84788d7 100644
--- a/dns/middleware.go
+++ b/dns/middleware.go
@@ -14,8 +14,10 @@ import (
D "github.com/miekg/dns"
)
-type handler func(ctx *context.DNSContext, r *D.Msg) (*D.Msg, error)
-type middleware func(next handler) handler
+type (
+ handler func(ctx *context.DNSContext, r *D.Msg) (*D.Msg, error)
+ middleware func(next handler) handler
+)
func withHosts(hosts *trie.DomainTrie) middleware {
return func(next handler) handler {
diff --git a/dns/resolver.go b/dns/resolver.go
index 8bbd0e8b2..bf544cb99 100644
--- a/dns/resolver.go
+++ b/dns/resolver.go
@@ -215,7 +215,6 @@ func (r *Resolver) shouldOnlyQueryFallback(m *D.Msg) bool {
}
func (r *Resolver) ipExchange(ctx context.Context, m *D.Msg) (msg *D.Msg, err error) {
-
if matched := r.matchPolicy(m); len(matched) != 0 {
res := <-r.asyncExchange(ctx, matched, m)
return res.Msg, res.Error
diff --git a/dns/util.go b/dns/util.go
index b167809a4..0e1badabc 100644
--- a/dns/util.go
+++ b/dns/util.go
@@ -13,14 +13,12 @@ import (
D "github.com/miekg/dns"
)
-var (
- // EnhancedModeMapping is a mapping for EnhancedMode enum
- EnhancedModeMapping = map[string]EnhancedMode{
- NORMAL.String(): NORMAL,
- FAKEIP.String(): FAKEIP,
- MAPPING.String(): MAPPING,
- }
-)
+// EnhancedModeMapping is a mapping for EnhancedMode enum
+var EnhancedModeMapping = map[string]EnhancedMode{
+ NORMAL.String(): NORMAL,
+ FAKEIP.String(): FAKEIP,
+ MAPPING.String(): MAPPING,
+}
const (
NORMAL EnhancedMode = iota
diff --git a/hub/executor/executor.go b/hub/executor/executor.go
index 2147906f1..ca8ee95de 100644
--- a/hub/executor/executor.go
+++ b/hub/executor/executor.go
@@ -24,9 +24,7 @@ import (
"github.com/Dreamacro/clash/tunnel"
)
-var (
- mux sync.Mutex
-)
+var mux sync.Mutex
func readConfig(path string) ([]byte, error) {
if _, err := os.Stat(path); os.IsNotExist(err) {
diff --git a/listener/auth/auth.go b/listener/auth/auth.go
index 2c29e186e..70473114d 100644
--- a/listener/auth/auth.go
+++ b/listener/auth/auth.go
@@ -4,9 +4,7 @@ import (
"github.com/Dreamacro/clash/component/auth"
)
-var (
- authenticator auth.Authenticator
-)
+var authenticator auth.Authenticator
func Authenticator() auth.Authenticator {
return authenticator
diff --git a/log/level.go b/log/level.go
index ea223c127..f70116a32 100644
--- a/log/level.go
+++ b/log/level.go
@@ -5,16 +5,14 @@ import (
"errors"
)
-var (
- // LogLevelMapping is a mapping for LogLevel enum
- LogLevelMapping = map[string]LogLevel{
- ERROR.String(): ERROR,
- WARNING.String(): WARNING,
- INFO.String(): INFO,
- DEBUG.String(): DEBUG,
- SILENT.String(): SILENT,
- }
-)
+// LogLevelMapping is a mapping for LogLevel enum
+var LogLevelMapping = map[string]LogLevel{
+ ERROR.String(): ERROR,
+ WARNING.String(): WARNING,
+ INFO.String(): INFO,
+ DEBUG.String(): DEBUG,
+ SILENT.String(): SILENT,
+}
const (
DEBUG LogLevel = iota
diff --git a/transport/gun/gun.go b/transport/gun/gun.go
index e60d13d75..f6f761166 100644
--- a/transport/gun/gun.go
+++ b/transport/gun/gun.go
@@ -27,12 +27,10 @@ var (
ErrSmallBuffer = errors.New("buffer too small")
)
-var (
- defaultHeader = http.Header{
- "content-type": []string{"application/grpc"},
- "user-agent": []string{"grpc-go/1.36.0"},
- }
-)
+var defaultHeader = http.Header{
+ "content-type": []string{"application/grpc"},
+ "user-agent": []string{"grpc-go/1.36.0"},
+}
type DialFn = func(network, addr string) (net.Conn, error)
diff --git a/transport/simple-obfs/tls.go b/transport/simple-obfs/tls.go
index 914cfe4af..1c609c15a 100644
--- a/transport/simple-obfs/tls.go
+++ b/transport/simple-obfs/tls.go
@@ -78,6 +78,7 @@ func (to *TLSObfs) Read(b []byte) (int, error) {
// type + ver = 3
return to.read(b, 3)
}
+
func (to *TLSObfs) Write(b []byte) (int, error) {
length := len(b)
for i := 0; i < length; i += chunkSize {
diff --git a/transport/snell/cipher.go b/transport/snell/cipher.go
index f778e6471..0f31aea53 100644
--- a/transport/snell/cipher.go
+++ b/transport/snell/cipher.go
@@ -20,6 +20,7 @@ func (sc *snellCipher) SaltSize() int { return 16 }
func (sc *snellCipher) Encrypter(salt []byte) (cipher.AEAD, error) {
return sc.makeAEAD(snellKDF(sc.psk, salt, sc.KeySize()))
}
+
func (sc *snellCipher) Decrypter(salt []byte) (cipher.AEAD, error) {
return sc.makeAEAD(snellKDF(sc.psk, salt, sc.KeySize()))
}
diff --git a/transport/snell/snell.go b/transport/snell/snell.go
index 8966b4bb7..64807b819 100644
--- a/transport/snell/snell.go
+++ b/transport/snell/snell.go
@@ -30,9 +30,7 @@ const (
Version byte = 1
)
-var (
- endSignal = []byte{}
-)
+var endSignal = []byte{}
type Snell struct {
net.Conn
diff --git a/transport/socks4/socks4.go b/transport/socks4/socks4.go
index c06bea20f..a29416241 100644
--- a/transport/socks4/socks4.go
+++ b/transport/socks4/socks4.go
@@ -184,7 +184,7 @@ func isReservedIP(ip net.IP) bool {
}
func readUntilNull(r io.Reader) ([]byte, error) {
- var buf = &bytes.Buffer{}
+ buf := &bytes.Buffer{}
var data [1]byte
for {
diff --git a/transport/ssr/protocol/auth_aes128_sha1.go b/transport/ssr/protocol/auth_aes128_sha1.go
index fab9d0081..8ce57d288 100644
--- a/transport/ssr/protocol/auth_aes128_sha1.go
+++ b/transport/ssr/protocol/auth_aes128_sha1.go
@@ -14,8 +14,10 @@ import (
"github.com/Dreamacro/clash/transport/ssr/tools"
)
-type hmacMethod func(key, data []byte) []byte
-type hashDigestMethod func([]byte) []byte
+type (
+ hmacMethod func(key, data []byte) []byte
+ hashDigestMethod func([]byte) []byte
+)
func init() {
register("auth_aes128_sha1", newAuthAES128SHA1, 9)
diff --git a/transport/vmess/header.go b/transport/vmess/header.go
index 27a734bed..67d407e6f 100644
--- a/transport/vmess/header.go
+++ b/transport/vmess/header.go
@@ -92,7 +92,7 @@ func sealVMessAEADHeader(key [16]byte, data []byte, t time.Time) []byte {
payloadHeaderAEADEncrypted = payloadHeaderAEAD.Seal(nil, payloadHeaderAEADNonce, data, generatedAuthID[:])
}
- var outputBuffer = &bytes.Buffer{}
+ outputBuffer := &bytes.Buffer{}
outputBuffer.Write(generatedAuthID[:])
outputBuffer.Write(payloadHeaderLengthAEADEncrypted)
diff --git a/transport/vmess/websocket.go b/transport/vmess/websocket.go
index f00e4c4bf..951fb5d0a 100644
--- a/transport/vmess/websocket.go
+++ b/transport/vmess/websocket.go
@@ -28,6 +28,7 @@ type websocketConn struct {
rMux sync.Mutex
wMux sync.Mutex
}
+
type websocketWithEarlyDataConn struct {
net.Conn
underlay net.Conn
diff --git a/tunnel/mode.go b/tunnel/mode.go
index 6e07a060a..696607215 100644
--- a/tunnel/mode.go
+++ b/tunnel/mode.go
@@ -8,14 +8,12 @@ import (
type TunnelMode int
-var (
- // ModeMapping is a mapping for Mode enum
- ModeMapping = map[string]TunnelMode{
- Global.String(): Global,
- Rule.String(): Rule,
- Direct.String(): Direct,
- }
-)
+// ModeMapping is a mapping for Mode enum
+var ModeMapping = map[string]TunnelMode{
+ Global.String(): Global,
+ Rule.String(): Rule,
+ Direct.String(): Direct,
+}
const (
Global TunnelMode = iota
From a1c2478e74a86b7160c558aef1ae6980a7d36f88 Mon Sep 17 00:00:00 2001
From: Dreamacro <8615343+Dreamacro@users.noreply.github.com>
Date: Mon, 11 Oct 2021 20:08:18 +0800
Subject: [PATCH 78/96] Chore: actions split lint and release
---
.github/workflows/linter.yml | 12 ++++++++++++
.github/workflows/{go.yml => release.yml} | 10 +++-------
2 files changed, 15 insertions(+), 7 deletions(-)
create mode 100644 .github/workflows/linter.yml
rename .github/workflows/{go.yml => release.yml} (81%)
diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml
new file mode 100644
index 000000000..26d318c30
--- /dev/null
+++ b/.github/workflows/linter.yml
@@ -0,0 +1,12 @@
+name: Linter
+on: [push, pull_request]
+jobs:
+ lint:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v2
+ - name: golangci-lint
+ uses: golangci/golangci-lint-action@v2
+ with:
+ version: latest
+ args: --disable-all -E govet -E gofumpt -E megacheck ./...
diff --git a/.github/workflows/go.yml b/.github/workflows/release.yml
similarity index 81%
rename from .github/workflows/go.yml
rename to .github/workflows/release.yml
index af6f9a91d..d4bad8a37 100644
--- a/.github/workflows/go.yml
+++ b/.github/workflows/release.yml
@@ -1,9 +1,7 @@
-name: Go
-on: [push, pull_request]
+name: Release
+on: [push]
jobs:
-
build:
- name: Build
runs-on: ubuntu-latest
steps:
- name: Get latest go version
@@ -27,11 +25,9 @@ jobs:
restore-keys: |
${{ runner.os }}-go-
- - name: Get dependencies, run test and static check
+ - name: Get dependencies, run test
run: |
go test ./...
- go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
- golangci-lint run --disable-all -E govet -E gofumpt -E megacheck ./...
- name: Build
if: startsWith(github.ref, 'refs/tags/')
From 3d5681cffd371ecdb9b340fd963872e8416d32e9 Mon Sep 17 00:00:00 2001
From: Dreamacro
Date: Mon, 11 Oct 2021 20:48:58 +0800
Subject: [PATCH 79/96] Feature: persistence fakeip (#1662)
---
component/fakeip/cachefile.go | 49 ++++++++++
component/fakeip/memory.go | 60 ++++++++++++
component/fakeip/pool.go | 95 ++++++++++--------
component/fakeip/pool_test.go | 141 ++++++++++++++++++++++++---
component/profile/cachefile/cache.go | 75 +++++++++++---
config/config.go | 13 ++-
dns/enhancer.go | 2 +-
dns/middleware.go | 2 +-
8 files changed, 364 insertions(+), 73 deletions(-)
create mode 100644 component/fakeip/cachefile.go
create mode 100644 component/fakeip/memory.go
diff --git a/component/fakeip/cachefile.go b/component/fakeip/cachefile.go
new file mode 100644
index 000000000..7ee889812
--- /dev/null
+++ b/component/fakeip/cachefile.go
@@ -0,0 +1,49 @@
+package fakeip
+
+import (
+ "net"
+
+ "github.com/Dreamacro/clash/component/profile/cachefile"
+)
+
+type cachefileStore struct {
+ cache *cachefile.CacheFile
+}
+
+// GetByHost implements store.GetByHost
+func (c *cachefileStore) GetByHost(host string) (net.IP, bool) {
+ elm := c.cache.GetFakeip([]byte(host))
+ if elm == nil {
+ return nil, false
+ }
+ return net.IP(elm), true
+}
+
+// PutByHost implements store.PutByHost
+func (c *cachefileStore) PutByHost(host string, ip net.IP) {
+ c.cache.PutFakeip([]byte(host), ip)
+}
+
+// GetByIP implements store.GetByIP
+func (c *cachefileStore) GetByIP(ip net.IP) (string, bool) {
+ elm := c.cache.GetFakeip(ip.To4())
+ if elm == nil {
+ return "", false
+ }
+ return string(elm), true
+}
+
+// PutByIP implements store.PutByIP
+func (c *cachefileStore) PutByIP(ip net.IP, host string) {
+ c.cache.PutFakeip(ip.To4(), []byte(host))
+}
+
+// Exist implements store.Exist
+func (c *cachefileStore) Exist(ip net.IP) bool {
+ _, exist := c.GetByIP(ip)
+ return exist
+}
+
+// CloneTo implements store.CloneTo
+// already persistence
+func (c *cachefileStore) CloneTo(store store) {}
diff --git a/component/fakeip/memory.go b/component/fakeip/memory.go
new file mode 100644
index 000000000..75d4a3b24
--- /dev/null
+++ b/component/fakeip/memory.go
@@ -0,0 +1,60 @@
+package fakeip
+
+import (
+ "net"
+
+ "github.com/Dreamacro/clash/common/cache"
+)
+
+type memoryStore struct {
+ cache *cache.LruCache
+}
+
+// GetByHost implements store.GetByHost
+func (m *memoryStore) GetByHost(host string) (net.IP, bool) {
+ if elm, exist := m.cache.Get(host); exist {
+ ip := elm.(net.IP)
+
+ // ensure ip --> host on head of linked list
+ m.cache.Get(ipToUint(ip.To4()))
+ return ip, true
+ }
+
+ return nil, false
+}
+
+// PutByHost implements store.PutByHost
+func (m *memoryStore) PutByHost(host string, ip net.IP) {
+ m.cache.Set(host, ip)
+}
+
+// GetByIP implements store.GetByIP
+func (m *memoryStore) GetByIP(ip net.IP) (string, bool) {
+ if elm, exist := m.cache.Get(ipToUint(ip.To4())); exist {
+ host := elm.(string)
+
+ // ensure host --> ip on head of linked list
+ m.cache.Get(host)
+ return host, true
+ }
+
+ return "", false
+}
+
+// PutByIP implements store.PutByIP
+func (m *memoryStore) PutByIP(ip net.IP, host string) {
+ m.cache.Set(ipToUint(ip.To4()), host)
+}
+
+// Exist implements store.Exist
+func (m *memoryStore) Exist(ip net.IP) bool {
+ return m.cache.Exist(ipToUint(ip.To4()))
+}
+
+// CloneTo implements store.CloneTo
+// only for memoryStore to memoryStore
+func (m *memoryStore) CloneTo(store store) {
+ if ms, ok := store.(*memoryStore); ok {
+ m.cache.CloneTo(ms.cache)
+ }
+}
diff --git a/component/fakeip/pool.go b/component/fakeip/pool.go
index 97d812ac3..180d5eb18 100644
--- a/component/fakeip/pool.go
+++ b/component/fakeip/pool.go
@@ -6,9 +6,19 @@ import (
"sync"
"github.com/Dreamacro/clash/common/cache"
+ "github.com/Dreamacro/clash/component/profile/cachefile"
"github.com/Dreamacro/clash/component/trie"
)
+type store interface {
+ GetByHost(host string) (net.IP, bool)
+ PutByHost(host string, ip net.IP)
+ GetByIP(ip net.IP) (string, bool)
+ PutByIP(ip net.IP, host string)
+ Exist(ip net.IP) bool
+ CloneTo(store)
+}
+
// Pool is a implementation about fake ip generator without storage
type Pool struct {
max uint32
@@ -18,25 +28,19 @@ type Pool struct {
mux sync.Mutex
host *trie.DomainTrie
ipnet *net.IPNet
- cache *cache.LruCache
+ store store
}
// Lookup return a fake ip with host
func (p *Pool) Lookup(host string) net.IP {
p.mux.Lock()
defer p.mux.Unlock()
- if elm, exist := p.cache.Get(host); exist {
- ip := elm.(net.IP)
-
- // ensure ip --> host on head of linked list
- n := ipToUint(ip.To4())
- offset := n - p.min + 1
- p.cache.Get(offset)
+ if ip, exist := p.store.GetByHost(host); exist {
return ip
}
ip := p.get(host)
- p.cache.Set(host, ip)
+ p.store.PutByHost(host, ip)
return ip
}
@@ -49,22 +53,11 @@ func (p *Pool) LookBack(ip net.IP) (string, bool) {
return "", false
}
- n := ipToUint(ip.To4())
- offset := n - p.min + 1
-
- if elm, exist := p.cache.Get(offset); exist {
- host := elm.(string)
-
- // ensure host --> ip on head of linked list
- p.cache.Get(host)
- return host, true
- }
-
- return "", false
+ return p.store.GetByIP(ip)
}
-// LookupHost return if domain in host
-func (p *Pool) LookupHost(domain string) bool {
+// ShouldSkipped return if domain should be skipped
+func (p *Pool) ShouldSkipped(domain string) bool {
if p.host == nil {
return false
}
@@ -80,9 +73,7 @@ func (p *Pool) Exist(ip net.IP) bool {
return false
}
- n := ipToUint(ip.To4())
- offset := n - p.min + 1
- return p.cache.Exist(offset)
+ return p.store.Exist(ip)
}
// Gateway return gateway ip
@@ -95,9 +86,9 @@ func (p *Pool) IPNet() *net.IPNet {
return p.ipnet
}
-// PatchFrom clone cache from old pool
-func (p *Pool) PatchFrom(o *Pool) {
- o.cache.CloneTo(p.cache)
+// CloneFrom clone cache from old pool
+func (p *Pool) CloneFrom(o *Pool) {
+ o.store.CloneTo(p.store)
}
func (p *Pool) get(host string) net.IP {
@@ -109,12 +100,13 @@ func (p *Pool) get(host string) net.IP {
break
}
- if !p.cache.Exist(p.offset) {
+ ip := uintToIP(p.min + p.offset - 1)
+ if !p.store.Exist(ip) {
break
}
}
ip := uintToIP(p.min + p.offset - 1)
- p.cache.Set(p.offset, host)
+ p.store.PutByIP(ip, host)
return ip
}
@@ -130,11 +122,24 @@ func uintToIP(v uint32) net.IP {
return net.IP{byte(v >> 24), byte(v >> 16), byte(v >> 8), byte(v)}
}
-// New return Pool instance
-func New(ipnet *net.IPNet, size int, host *trie.DomainTrie) (*Pool, error) {
- min := ipToUint(ipnet.IP) + 2
+type Options struct {
+ IPNet *net.IPNet
+ Host *trie.DomainTrie
- ones, bits := ipnet.Mask.Size()
+ // Size sets the maximum number of entries in memory
+ // and does not work if Persistence is true
+ Size int
+
+ // Persistence will save the data to disk.
+ // Size will not work and record will be fully stored.
+ Persistence bool
+}
+
+// New return Pool instance
+func New(options Options) (*Pool, error) {
+ min := ipToUint(options.IPNet.IP) + 2
+
+ ones, bits := options.IPNet.Mask.Size()
total := 1<
Date: Mon, 11 Oct 2021 21:05:38 +0800
Subject: [PATCH 80/96] Fix: #1660 panic
---
dns/doh.go | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/dns/doh.go b/dns/doh.go
index 3daa7f22b..943123551 100644
--- a/dns/doh.go
+++ b/dns/doh.go
@@ -39,7 +39,9 @@ func (dc *dohClient) ExchangeContext(ctx context.Context, m *D.Msg) (msg *D.Msg,
req = req.WithContext(ctx)
msg, err = dc.doRequest(req)
- msg.Id = m.Id
+ if err == nil {
+ msg.Id = m.Id
+ }
return
}
From 583b2a5ace5be91abf64c2073275d2bf4ca61e46 Mon Sep 17 00:00:00 2001
From: Dreamacro <8615343+Dreamacro@users.noreply.github.com>
Date: Thu, 14 Oct 2021 22:54:43 +0800
Subject: [PATCH 81/96] Change: use interface HardwareAddr for dhcp discovery
---
component/dhcp/dhcp.go | 22 ++++++++--------------
1 file changed, 8 insertions(+), 14 deletions(-)
diff --git a/component/dhcp/dhcp.go b/component/dhcp/dhcp.go
index b2ca6928f..b7e9f5069 100644
--- a/component/dhcp/dhcp.go
+++ b/component/dhcp/dhcp.go
@@ -3,9 +3,10 @@ package dhcp
import (
"context"
"errors"
- "math/rand"
"net"
+ "github.com/Dreamacro/clash/component/iface"
+
"github.com/insomniacslk/dhcp/dhcpv4"
)
@@ -23,7 +24,12 @@ func ResolveDNSFromDHCP(context context.Context, ifaceName string) ([]net.IP, er
result := make(chan []net.IP, 1)
- discovery, err := dhcpv4.NewDiscovery(randomHardware(), dhcpv4.WithBroadcast(true), dhcpv4.WithRequestedOptions(dhcpv4.OptionDomainNameServer))
+ ifaceObj, err := iface.ResolveInterface(ifaceName)
+ if err != nil {
+ return nil, err
+ }
+
+ discovery, err := dhcpv4.NewDiscovery(ifaceObj.HardwareAddr, dhcpv4.WithBroadcast(true), dhcpv4.WithRequestedOptions(dhcpv4.OptionDomainNameServer))
if err != nil {
return nil, err
}
@@ -80,15 +86,3 @@ func receiveOffer(conn net.PacketConn, id dhcpv4.TransactionID, result chan<- []
return
}
}
-
-func randomHardware() net.HardwareAddr {
- addr := make(net.HardwareAddr, 6)
-
- addr[0] = 0xff
-
- for i := 1; i < len(addr); i++ {
- addr[i] = byte(rand.Intn(254) + 1)
- }
-
- return addr
-}
From 68753b4ae11c7ca508bf422180e248b3ccd81068 Mon Sep 17 00:00:00 2001
From: Dreamacro <8615343+Dreamacro@users.noreply.github.com>
Date: Fri, 15 Oct 2021 21:44:53 +0800
Subject: [PATCH 82/96] Chore: contexify ProxyAdapter ListenPacket
---
.gitignore | 5 ++++-
adapter/adapter.go | 18 +++++++++++++++---
adapter/outbound/base.go | 5 +++--
adapter/outbound/direct.go | 6 +++---
adapter/outbound/reject.go | 4 ++--
adapter/outbound/shadowsocks.go | 6 +++---
adapter/outbound/shadowsocksr.go | 6 +++---
adapter/outbound/socks5.go | 8 +++-----
adapter/outbound/trojan.go | 6 ++----
adapter/outbound/vmess.go | 6 ++----
adapter/outboundgroup/fallback.go | 6 +++---
adapter/outboundgroup/loadbalance.go | 7 +++----
adapter/outboundgroup/selector.go | 6 +++---
adapter/outboundgroup/urltest.go | 6 +++---
constant/adapters.go | 19 +++++++++++++------
constant/provider/interface.go | 2 +-
test/Makefile | 8 ++++++++
test/README.md | 4 ++--
test/clash_test.go | 7 ++++---
tunnel/tunnel.go | 27 ++++++++++++++++-----------
20 files changed, 96 insertions(+), 66 deletions(-)
create mode 100644 test/Makefile
diff --git a/.gitignore b/.gitignore
index 0593cfd05..52efcc9bf 100644
--- a/.gitignore
+++ b/.gitignore
@@ -12,7 +12,7 @@ bin/*
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
-# dep
+# go mod vendor
vendor
# GoLand
@@ -20,3 +20,6 @@ vendor
# macOS file
.DS_Store
+
+# test suite
+test/config/cache*
diff --git a/adapter/adapter.go b/adapter/adapter.go
index 526866a5c..263301636 100644
--- a/adapter/adapter.go
+++ b/adapter/adapter.go
@@ -36,12 +36,24 @@ func (p *Proxy) Dial(metadata *C.Metadata) (C.Conn, error) {
// DialContext implements C.ProxyAdapter
func (p *Proxy) DialContext(ctx context.Context, metadata *C.Metadata) (C.Conn, error) {
conn, err := p.ProxyAdapter.DialContext(ctx, metadata)
- if err != nil {
- p.alive.Store(false)
- }
+ p.alive.Store(err == nil)
return conn, err
}
+// DialUDP implements C.ProxyAdapter
+func (p *Proxy) DialUDP(metadata *C.Metadata) (C.PacketConn, error) {
+ ctx, cancel := context.WithTimeout(context.Background(), C.DefaultUDPTimeout)
+ defer cancel()
+ return p.ListenPacketContext(ctx, metadata)
+}
+
+// ListenPacketContext implements C.ProxyAdapter
+func (p *Proxy) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (C.PacketConn, error) {
+ pc, err := p.ProxyAdapter.ListenPacketContext(ctx, metadata)
+ p.alive.Store(err == nil)
+ return pc, err
+}
+
// DelayHistory implements C.Proxy
func (p *Proxy) DelayHistory() []C.DelayHistory {
queue := p.history.Copy()
diff --git a/adapter/outbound/base.go b/adapter/outbound/base.go
index a001d799e..22c0142b0 100644
--- a/adapter/outbound/base.go
+++ b/adapter/outbound/base.go
@@ -1,6 +1,7 @@
package outbound
import (
+ "context"
"encoding/json"
"errors"
"net"
@@ -30,8 +31,8 @@ func (b *Base) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {
return c, errors.New("no support")
}
-// DialUDP implements C.ProxyAdapter
-func (b *Base) DialUDP(metadata *C.Metadata) (C.PacketConn, error) {
+// ListenPacketContext implements C.ProxyAdapter
+func (b *Base) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (C.PacketConn, error) {
return nil, errors.New("no support")
}
diff --git a/adapter/outbound/direct.go b/adapter/outbound/direct.go
index 4b53e306c..42433c410 100644
--- a/adapter/outbound/direct.go
+++ b/adapter/outbound/direct.go
@@ -22,9 +22,9 @@ func (d *Direct) DialContext(ctx context.Context, metadata *C.Metadata) (C.Conn,
return NewConn(c, d), nil
}
-// DialUDP implements C.ProxyAdapter
-func (d *Direct) DialUDP(metadata *C.Metadata) (C.PacketConn, error) {
- pc, err := dialer.ListenPacket(context.Background(), "udp", "")
+// ListenPacketContext implements C.ProxyAdapter
+func (d *Direct) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (C.PacketConn, error) {
+ pc, err := dialer.ListenPacket(ctx, "udp", "")
if err != nil {
return nil, err
}
diff --git a/adapter/outbound/reject.go b/adapter/outbound/reject.go
index 367504964..a97c6c711 100644
--- a/adapter/outbound/reject.go
+++ b/adapter/outbound/reject.go
@@ -19,8 +19,8 @@ func (r *Reject) DialContext(ctx context.Context, metadata *C.Metadata) (C.Conn,
return NewConn(&NopConn{}, r), nil
}
-// DialUDP implements C.ProxyAdapter
-func (r *Reject) DialUDP(metadata *C.Metadata) (C.PacketConn, error) {
+// ListenPacketContext implements C.ProxyAdapter
+func (r *Reject) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (C.PacketConn, error) {
return nil, errors.New("match reject rule")
}
diff --git a/adapter/outbound/shadowsocks.go b/adapter/outbound/shadowsocks.go
index 64b431a9b..0194954e7 100644
--- a/adapter/outbound/shadowsocks.go
+++ b/adapter/outbound/shadowsocks.go
@@ -87,9 +87,9 @@ func (ss *ShadowSocks) DialContext(ctx context.Context, metadata *C.Metadata) (_
return NewConn(c, ss), err
}
-// DialUDP implements C.ProxyAdapter
-func (ss *ShadowSocks) DialUDP(metadata *C.Metadata) (C.PacketConn, error) {
- pc, err := dialer.ListenPacket(context.Background(), "udp", "")
+// ListenPacketContext implements C.ProxyAdapter
+func (ss *ShadowSocks) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (C.PacketConn, error) {
+ pc, err := dialer.ListenPacket(ctx, "udp", "")
if err != nil {
return nil, err
}
diff --git a/adapter/outbound/shadowsocksr.go b/adapter/outbound/shadowsocksr.go
index 9ba8bc229..fb0dd7a5f 100644
--- a/adapter/outbound/shadowsocksr.go
+++ b/adapter/outbound/shadowsocksr.go
@@ -72,9 +72,9 @@ func (ssr *ShadowSocksR) DialContext(ctx context.Context, metadata *C.Metadata)
return NewConn(c, ssr), err
}
-// DialUDP implements C.ProxyAdapter
-func (ssr *ShadowSocksR) DialUDP(metadata *C.Metadata) (C.PacketConn, error) {
- pc, err := dialer.ListenPacket(context.Background(), "udp", "")
+// ListenPacketContext implements C.ProxyAdapter
+func (ssr *ShadowSocksR) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (C.PacketConn, error) {
+ pc, err := dialer.ListenPacket(ctx, "udp", "")
if err != nil {
return nil, err
}
diff --git a/adapter/outbound/socks5.go b/adapter/outbound/socks5.go
index d97395575..7714c5c52 100644
--- a/adapter/outbound/socks5.go
+++ b/adapter/outbound/socks5.go
@@ -76,10 +76,8 @@ func (ss *Socks5) DialContext(ctx context.Context, metadata *C.Metadata) (_ C.Co
return NewConn(c, ss), nil
}
-// DialUDP implements C.ProxyAdapter
-func (ss *Socks5) DialUDP(metadata *C.Metadata) (_ C.PacketConn, err error) {
- ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTCPTimeout)
- defer cancel()
+// ListenPacketContext implements C.ProxyAdapter
+func (ss *Socks5) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (_ C.PacketConn, err error) {
c, err := dialer.DialContext(ctx, "tcp", ss.addr)
if err != nil {
err = fmt.Errorf("%s connect error: %w", ss.addr, err)
@@ -109,7 +107,7 @@ func (ss *Socks5) DialUDP(metadata *C.Metadata) (_ C.PacketConn, err error) {
return
}
- pc, err := dialer.ListenPacket(context.Background(), "udp", "")
+ pc, err := dialer.ListenPacket(ctx, "udp", "")
if err != nil {
return
}
diff --git a/adapter/outbound/trojan.go b/adapter/outbound/trojan.go
index afed410fb..b8ea49e65 100644
--- a/adapter/outbound/trojan.go
+++ b/adapter/outbound/trojan.go
@@ -88,8 +88,8 @@ func (t *Trojan) DialContext(ctx context.Context, metadata *C.Metadata) (_ C.Con
return NewConn(c, t), err
}
-// DialUDP implements C.ProxyAdapter
-func (t *Trojan) DialUDP(metadata *C.Metadata) (_ C.PacketConn, err error) {
+// ListenPacketContext implements C.ProxyAdapter
+func (t *Trojan) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (_ C.PacketConn, err error) {
var c net.Conn
// grpc transport
@@ -100,8 +100,6 @@ func (t *Trojan) DialUDP(metadata *C.Metadata) (_ C.PacketConn, err error) {
}
defer safeConnClose(c, err)
} else {
- ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTCPTimeout)
- defer cancel()
c, err = dialer.DialContext(ctx, "tcp", t.addr)
if err != nil {
return nil, fmt.Errorf("%s connect error: %w", t.addr, err)
diff --git a/adapter/outbound/vmess.go b/adapter/outbound/vmess.go
index 0dbb0f1bf..209084ca8 100644
--- a/adapter/outbound/vmess.go
+++ b/adapter/outbound/vmess.go
@@ -215,8 +215,8 @@ func (v *Vmess) DialContext(ctx context.Context, metadata *C.Metadata) (_ C.Conn
return NewConn(c, v), err
}
-// DialUDP implements C.ProxyAdapter
-func (v *Vmess) DialUDP(metadata *C.Metadata) (_ C.PacketConn, err error) {
+// ListenPacketContext implements C.ProxyAdapter
+func (v *Vmess) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (_ C.PacketConn, err error) {
// vmess use stream-oriented udp with a special address, so we needs a net.UDPAddr
if !metadata.Resolved() {
ip, err := resolver.ResolveIP(metadata.Host)
@@ -237,8 +237,6 @@ func (v *Vmess) DialUDP(metadata *C.Metadata) (_ C.PacketConn, err error) {
c, err = v.client.StreamConn(c, parseVmessAddr(metadata))
} else {
- ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTCPTimeout)
- defer cancel()
c, err = dialer.DialContext(ctx, "tcp", v.addr)
if err != nil {
return nil, fmt.Errorf("%s connect error: %s", v.addr, err.Error())
diff --git a/adapter/outboundgroup/fallback.go b/adapter/outboundgroup/fallback.go
index da01d4de1..3221b5527 100644
--- a/adapter/outboundgroup/fallback.go
+++ b/adapter/outboundgroup/fallback.go
@@ -32,10 +32,10 @@ func (f *Fallback) DialContext(ctx context.Context, metadata *C.Metadata) (C.Con
return c, err
}
-// DialUDP implements C.ProxyAdapter
-func (f *Fallback) DialUDP(metadata *C.Metadata) (C.PacketConn, error) {
+// ListenPacketContext implements C.ProxyAdapter
+func (f *Fallback) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (C.PacketConn, error) {
proxy := f.findAliveProxy(true)
- pc, err := proxy.DialUDP(metadata)
+ pc, err := proxy.ListenPacketContext(ctx, metadata)
if err == nil {
pc.AppendToChains(f)
}
diff --git a/adapter/outboundgroup/loadbalance.go b/adapter/outboundgroup/loadbalance.go
index e529b53be..fb2840102 100644
--- a/adapter/outboundgroup/loadbalance.go
+++ b/adapter/outboundgroup/loadbalance.go
@@ -82,8 +82,8 @@ func (lb *LoadBalance) DialContext(ctx context.Context, metadata *C.Metadata) (c
return
}
-// DialUDP implements C.ProxyAdapter
-func (lb *LoadBalance) DialUDP(metadata *C.Metadata) (pc C.PacketConn, err error) {
+// ListenPacketContext implements C.ProxyAdapter
+func (lb *LoadBalance) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (pc C.PacketConn, err error) {
defer func() {
if err == nil {
pc.AppendToChains(lb)
@@ -91,8 +91,7 @@ func (lb *LoadBalance) DialUDP(metadata *C.Metadata) (pc C.PacketConn, err error
}()
proxy := lb.Unwrap(metadata)
-
- return proxy.DialUDP(metadata)
+ return proxy.ListenPacketContext(ctx, metadata)
}
// SupportUDP implements C.ProxyAdapter
diff --git a/adapter/outboundgroup/selector.go b/adapter/outboundgroup/selector.go
index 124539278..008e8af8d 100644
--- a/adapter/outboundgroup/selector.go
+++ b/adapter/outboundgroup/selector.go
@@ -28,9 +28,9 @@ func (s *Selector) DialContext(ctx context.Context, metadata *C.Metadata) (C.Con
return c, err
}
-// DialUDP implements C.ProxyAdapter
-func (s *Selector) DialUDP(metadata *C.Metadata) (C.PacketConn, error) {
- pc, err := s.selectedProxy(true).DialUDP(metadata)
+// ListenPacketContext implements C.ProxyAdapter
+func (s *Selector) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (C.PacketConn, error) {
+ pc, err := s.selectedProxy(true).ListenPacketContext(ctx, metadata)
if err == nil {
pc.AppendToChains(s)
}
diff --git a/adapter/outboundgroup/urltest.go b/adapter/outboundgroup/urltest.go
index 2a11cd23b..b27f12a44 100644
--- a/adapter/outboundgroup/urltest.go
+++ b/adapter/outboundgroup/urltest.go
@@ -42,9 +42,9 @@ func (u *URLTest) DialContext(ctx context.Context, metadata *C.Metadata) (c C.Co
return c, err
}
-// DialUDP implements C.ProxyAdapter
-func (u *URLTest) DialUDP(metadata *C.Metadata) (C.PacketConn, error) {
- pc, err := u.fast(true).DialUDP(metadata)
+// ListenPacketContext implements C.ProxyAdapter
+func (u *URLTest) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (C.PacketConn, error) {
+ pc, err := u.fast(true).ListenPacketContext(ctx, metadata)
if err == nil {
pc.AppendToChains(u)
}
diff --git a/constant/adapters.go b/constant/adapters.go
index 733d86b91..2f7006e96 100644
--- a/constant/adapters.go
+++ b/constant/adapters.go
@@ -29,6 +29,7 @@ const (
const (
DefaultTCPTimeout = 5 * time.Second
+ DefaultUDPTimeout = DefaultTCPTimeout
)
type Connection interface {
@@ -73,11 +74,14 @@ type PacketConn interface {
type ProxyAdapter interface {
Name() string
Type() AdapterType
+ Addr() string
+ SupportUDP() bool
+ MarshalJSON() ([]byte, error)
// StreamConn wraps a protocol around net.Conn with Metadata.
//
// Examples:
- // conn, _ := net.Dial("tcp", "host:port")
+ // conn, _ := net.DialContext(context.Background(), "tcp", "host:port")
// conn, _ = adapter.StreamConn(conn, metadata)
//
// It returns a C.Conn with protocol which start with
@@ -88,10 +92,8 @@ type ProxyAdapter interface {
// contains multiplexing-related reuse logic (if any)
DialContext(ctx context.Context, metadata *Metadata) (Conn, error)
- DialUDP(metadata *Metadata) (PacketConn, error)
- SupportUDP() bool
- MarshalJSON() ([]byte, error)
- Addr() string
+ ListenPacketContext(ctx context.Context, metadata *Metadata) (PacketConn, error)
+
// Unwrap extracts the proxy from a proxy-group. It returns nil when nothing to extract.
Unwrap(metadata *Metadata) Proxy
}
@@ -105,9 +107,14 @@ type Proxy interface {
ProxyAdapter
Alive() bool
DelayHistory() []DelayHistory
- Dial(metadata *Metadata) (Conn, error)
LastDelay() uint16
URLTest(ctx context.Context, url string) (uint16, error)
+
+ // Deprecated: use DialContext instead.
+ Dial(metadata *Metadata) (Conn, error)
+
+ // Deprecated: use DialPacketConn instead.
+ DialUDP(metadata *Metadata) (PacketConn, error)
}
// AdapterType is enum of adapter type
diff --git a/constant/provider/interface.go b/constant/provider/interface.go
index d3483cdcd..53bda7eac 100644
--- a/constant/provider/interface.go
+++ b/constant/provider/interface.go
@@ -67,7 +67,7 @@ type ProxyProvider interface {
Provider
Proxies() []constant.Proxy
// ProxiesWithTouch is used to inform the provider that the proxy is actually being used while getting the list of proxies.
- // Commonly used in Dial and DialUDP
+ // Commonly used in DialContext and DialPacketConn
ProxiesWithTouch() []constant.Proxy
HealthCheck()
}
diff --git a/test/Makefile b/test/Makefile
new file mode 100644
index 000000000..012d88d52
--- /dev/null
+++ b/test/Makefile
@@ -0,0 +1,8 @@
+lint:
+ golangci-lint run --disable-all -E govet -E gofumpt -E megacheck ./...
+
+test:
+ go test -p 1 -v ./...
+
+benchmark:
+ go test -benchmem -run=^$ -bench .
diff --git a/test/README.md b/test/README.md
index 823fc5446..a95f3aea6 100644
--- a/test/README.md
+++ b/test/README.md
@@ -45,7 +45,7 @@ Prerequisite
* docker (support Linux and macOS)
```
-$ go test -p 1 -v
+$ make test
```
benchmark (Linux)
@@ -55,5 +55,5 @@ benchmark (Linux)
> (change chunkSize to measure the maximum throughput of clash on your machine)
```
-$ go test -benchmem -run=^$ -bench .
+$ make benchmark
```
diff --git a/test/clash_test.go b/test/clash_test.go
index 4011b04a4..a3303a239 100644
--- a/test/clash_test.go
+++ b/test/clash_test.go
@@ -96,6 +96,7 @@ func init() {
images := []string{
ImageShadowsocks,
+ ImageShadowsocksRust,
ImageVmess,
ImageTrojan,
ImageSnell,
@@ -582,7 +583,7 @@ func testSuit(t *testing.T, proxy C.ProxyAdapter) {
return
}
- pc, err := proxy.DialUDP(&C.Metadata{
+ pc, err := proxy.ListenPacketContext(context.Background(), &C.Metadata{
NetWork: C.UDP,
DstIP: localIP,
DstPort: "10001",
@@ -595,7 +596,7 @@ func testSuit(t *testing.T, proxy C.ProxyAdapter) {
assert.NoError(t, testPingPongWithPacketConn(t, pc))
- pc, err = proxy.DialUDP(&C.Metadata{
+ pc, err = proxy.ListenPacketContext(context.Background(), &C.Metadata{
NetWork: C.UDP,
DstIP: localIP,
DstPort: "10001",
@@ -608,7 +609,7 @@ func testSuit(t *testing.T, proxy C.ProxyAdapter) {
assert.NoError(t, testLargeDataWithPacketConn(t, pc))
- pc, err = proxy.DialUDP(&C.Metadata{
+ pc, err = proxy.ListenPacketContext(context.Background(), &C.Metadata{
NetWork: C.UDP,
DstIP: localIP,
DstPort: "10001",
diff --git a/tunnel/tunnel.go b/tunnel/tunnel.go
index 2a35f0960..ccd6a58bd 100644
--- a/tunnel/tunnel.go
+++ b/tunnel/tunnel.go
@@ -1,6 +1,7 @@
package tunnel
import (
+ "context"
"fmt"
"net"
"runtime"
@@ -12,7 +13,7 @@ import (
"github.com/Dreamacro/clash/component/resolver"
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/constant/provider"
- "github.com/Dreamacro/clash/context"
+ icontext "github.com/Dreamacro/clash/context"
"github.com/Dreamacro/clash/log"
"github.com/Dreamacro/clash/tunnel/statistic"
)
@@ -209,14 +210,16 @@ func handleUDPConn(packet *inbound.PacketAdapter) {
cond.Broadcast()
}()
- ctx := context.NewPacketConnContext(metadata)
- proxy, rule, err := resolveMetadata(ctx, metadata)
+ pCtx := icontext.NewPacketConnContext(metadata)
+ proxy, rule, err := resolveMetadata(pCtx, metadata)
if err != nil {
log.Warnln("[UDP] Parse metadata failed: %s", err.Error())
return
}
- rawPc, err := proxy.DialUDP(metadata)
+ ctx, cancel := context.WithTimeout(context.Background(), C.DefaultUDPTimeout)
+ defer cancel()
+ rawPc, err := proxy.ListenPacketContext(ctx, metadata)
if err != nil {
if rule == nil {
log.Warnln("[UDP] dial %s to %s error: %s", proxy.Name(), metadata.RemoteAddress(), err.Error())
@@ -225,7 +228,7 @@ func handleUDPConn(packet *inbound.PacketAdapter) {
}
return
}
- ctx.InjectPacketConn(rawPc)
+ pCtx.InjectPacketConn(rawPc)
pc := statistic.NewUDPTracker(rawPc, statistic.DefaultManager, metadata, rule)
switch true {
@@ -246,10 +249,10 @@ func handleUDPConn(packet *inbound.PacketAdapter) {
}()
}
-func handleTCPConn(ctx C.ConnContext) {
- defer ctx.Conn().Close()
+func handleTCPConn(connCtx C.ConnContext) {
+ defer connCtx.Conn().Close()
- metadata := ctx.Metadata()
+ metadata := connCtx.Metadata()
if !metadata.Valid() {
log.Warnln("[Metadata] not valid: %#v", metadata)
return
@@ -260,13 +263,15 @@ func handleTCPConn(ctx C.ConnContext) {
return
}
- proxy, rule, err := resolveMetadata(ctx, metadata)
+ proxy, rule, err := resolveMetadata(connCtx, metadata)
if err != nil {
log.Warnln("[Metadata] parse failed: %s", err.Error())
return
}
- remoteConn, err := proxy.Dial(metadata)
+ ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTCPTimeout)
+ defer cancel()
+ remoteConn, err := proxy.DialContext(ctx, metadata)
if err != nil {
if rule == nil {
log.Warnln("[TCP] dial %s to %s error: %s", proxy.Name(), metadata.RemoteAddress(), err.Error())
@@ -289,7 +294,7 @@ func handleTCPConn(ctx C.ConnContext) {
log.Infoln("[TCP] %s --> %s doesn't match any rule using DIRECT", metadata.SourceAddress(), metadata.RemoteAddress())
}
- handleSocket(ctx, remoteConn)
+ handleSocket(connCtx, remoteConn)
}
func shouldResolveIP(rule C.Rule, metadata *C.Metadata) bool {
From df3a491d40c28c309e2cad8ba6d23c811e0e35a3 Mon Sep 17 00:00:00 2001
From: Dreamacro <8615343+Dreamacro@users.noreply.github.com>
Date: Sat, 16 Oct 2021 20:19:59 +0800
Subject: [PATCH 83/96] Feature: support trojan websocket
---
adapter/outbound/trojan.go | 35 ++++++++++++++++++++++++--
adapter/outbound/vmess.go | 12 +++++++--
test/clash_test.go | 2 ++
test/config/trojan-ws.json | 20 +++++++++++++++
test/trojan_test.go | 38 +++++++++++++++++++++++++++++
transport/trojan/trojan.go | 32 ++++++++++++++++++++++++
transport/v2ray-plugin/websocket.go | 23 ++++++++++++-----
transport/vmess/websocket.go | 15 ++----------
8 files changed, 154 insertions(+), 23 deletions(-)
create mode 100644 test/config/trojan-ws.json
diff --git a/adapter/outbound/trojan.go b/adapter/outbound/trojan.go
index b8ea49e65..8bea0cc8f 100644
--- a/adapter/outbound/trojan.go
+++ b/adapter/outbound/trojan.go
@@ -5,6 +5,7 @@ import (
"crypto/tls"
"fmt"
"net"
+ "net/http"
"strconv"
"github.com/Dreamacro/clash/component/dialer"
@@ -18,6 +19,7 @@ import (
type Trojan struct {
*Base
instance *trojan.Trojan
+ option *TrojanOption
// for gun mux
gunTLSConfig *tls.Config
@@ -36,6 +38,34 @@ type TrojanOption struct {
UDP bool `proxy:"udp,omitempty"`
Network string `proxy:"network,omitempty"`
GrpcOpts GrpcOptions `proxy:"grpc-opts,omitempty"`
+ WSOpts WSOptions `proxy:"ws-opts,omitempty"`
+}
+
+func (t *Trojan) plainStream(c net.Conn) (net.Conn, error) {
+ if t.option.Network == "ws" {
+ host, port, _ := net.SplitHostPort(t.addr)
+ wsOpts := &trojan.WebsocketOption{
+ Host: host,
+ Port: port,
+ Path: t.option.WSOpts.Path,
+ }
+
+ if t.option.SNI != "" {
+ wsOpts.Host = t.option.SNI
+ }
+
+ if len(t.option.WSOpts.Headers) != 0 {
+ header := http.Header{}
+ for key, value := range t.option.WSOpts.Headers {
+ header.Add(key, value)
+ }
+ wsOpts.Headers = header
+ }
+
+ return t.instance.StreamWebsocketConn(c, wsOpts)
+ }
+
+ return t.instance.StreamConn(c)
}
// StreamConn implements C.ProxyAdapter
@@ -44,7 +74,7 @@ func (t *Trojan) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error)
if t.transport != nil {
c, err = gun.StreamGunWithConn(c, t.gunTLSConfig, t.gunConfig)
} else {
- c, err = t.instance.StreamConn(c)
+ c, err = t.plainStream(c)
}
if err != nil {
@@ -106,7 +136,7 @@ func (t *Trojan) ListenPacketContext(ctx context.Context, metadata *C.Metadata)
}
defer safeConnClose(c, err)
tcpKeepAlive(c)
- c, err = t.instance.StreamConn(c)
+ c, err = t.plainStream(c)
if err != nil {
return nil, fmt.Errorf("%s connect error: %w", t.addr, err)
}
@@ -143,6 +173,7 @@ func NewTrojan(option TrojanOption) (*Trojan, error) {
udp: option.UDP,
},
instance: trojan.New(tOption),
+ option: &option,
}
if option.Network == "grpc" {
diff --git a/adapter/outbound/vmess.go b/adapter/outbound/vmess.go
index 209084ca8..b4db00ad9 100644
--- a/adapter/outbound/vmess.go
+++ b/adapter/outbound/vmess.go
@@ -105,8 +105,16 @@ func (v *Vmess) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {
if v.option.TLS {
wsOpts.TLS = true
- wsOpts.SkipCertVerify = v.option.SkipCertVerify
- wsOpts.ServerName = v.option.ServerName
+ wsOpts.TLSConfig = &tls.Config{
+ ServerName: host,
+ InsecureSkipVerify: v.option.SkipCertVerify,
+ NextProtos: []string{"http/1.1"},
+ }
+ if v.option.ServerName != "" {
+ wsOpts.TLSConfig.ServerName = v.option.ServerName
+ } else if host := wsOpts.Headers.Get("Host"); host != "" {
+ wsOpts.TLSConfig.ServerName = host
+ }
}
c, err = vmess.StreamWebsocketConn(c, wsOpts)
case "http":
diff --git a/test/clash_test.go b/test/clash_test.go
index a3303a239..5eb9d5bda 100644
--- a/test/clash_test.go
+++ b/test/clash_test.go
@@ -31,6 +31,7 @@ const (
ImageShadowsocksRust = "ghcr.io/shadowsocks/ssserver-rust:latest"
ImageVmess = "v2fly/v2fly-core:latest"
ImageTrojan = "trojangfw/trojan:latest"
+ ImageTrojanGo = "p4gefau1t/trojan-go:latest"
ImageSnell = "icpz/snell-server:latest"
ImageXray = "teddysun/xray:latest"
)
@@ -99,6 +100,7 @@ func init() {
ImageShadowsocksRust,
ImageVmess,
ImageTrojan,
+ ImageTrojanGo,
ImageSnell,
ImageXray,
}
diff --git a/test/config/trojan-ws.json b/test/config/trojan-ws.json
new file mode 100644
index 000000000..efc0acbd0
--- /dev/null
+++ b/test/config/trojan-ws.json
@@ -0,0 +1,20 @@
+{
+ "run_type": "server",
+ "local_addr": "0.0.0.0",
+ "local_port": 10002,
+ "disable_http_check": true,
+ "password": [
+ "example"
+ ],
+ "websocket": {
+ "enabled": true,
+ "path": "/",
+ "host": "example.org"
+ },
+ "ssl": {
+ "verify": true,
+ "cert": "/fullchain.pem",
+ "key": "/privkey.pem",
+ "sni": "example.org"
+ }
+}
\ No newline at end of file
diff --git a/test/trojan_test.go b/test/trojan_test.go
index a57dab99f..d1ab2a006 100644
--- a/test/trojan_test.go
+++ b/test/trojan_test.go
@@ -93,6 +93,44 @@ func TestClash_TrojanGrpc(t *testing.T) {
testSuit(t, proxy)
}
+func TestClash_TrojanWebsocket(t *testing.T) {
+ cfg := &container.Config{
+ Image: ImageTrojanGo,
+ ExposedPorts: defaultExposedPorts,
+ }
+ hostCfg := &container.HostConfig{
+ PortBindings: defaultPortBindings,
+ Binds: []string{
+ fmt.Sprintf("%s:/etc/trojan-go/config.json", C.Path.Resolve("trojan-ws.json")),
+ fmt.Sprintf("%s:/fullchain.pem", C.Path.Resolve("example.org.pem")),
+ fmt.Sprintf("%s:/privkey.pem", C.Path.Resolve("example.org-key.pem")),
+ },
+ }
+
+ id, err := startContainer(cfg, hostCfg, "trojan-ws")
+ if err != nil {
+ assert.FailNow(t, err.Error())
+ }
+ defer cleanContainer(id)
+
+ proxy, err := outbound.NewTrojan(outbound.TrojanOption{
+ Name: "trojan",
+ Server: localIP.String(),
+ Port: 10002,
+ Password: "example",
+ SNI: "example.org",
+ SkipCertVerify: true,
+ UDP: true,
+ Network: "ws",
+ })
+ if err != nil {
+ assert.FailNow(t, err.Error())
+ }
+
+ time.Sleep(waitTime)
+ testSuit(t, proxy)
+}
+
func Benchmark_Trojan(b *testing.B) {
cfg := &container.Config{
Image: ImageTrojan,
diff --git a/transport/trojan/trojan.go b/transport/trojan/trojan.go
index d39cbec1e..26e7adc7d 100644
--- a/transport/trojan/trojan.go
+++ b/transport/trojan/trojan.go
@@ -8,10 +8,12 @@ import (
"errors"
"io"
"net"
+ "net/http"
"sync"
"github.com/Dreamacro/clash/common/pool"
"github.com/Dreamacro/clash/transport/socks5"
+ "github.com/Dreamacro/clash/transport/vmess"
)
const (
@@ -38,6 +40,13 @@ type Option struct {
SkipCertVerify bool
}
+type WebsocketOption struct {
+ Host string
+ Port string
+ Path string
+ Headers http.Header
+}
+
type Trojan struct {
option *Option
hexPassword []byte
@@ -64,6 +73,29 @@ func (t *Trojan) StreamConn(conn net.Conn) (net.Conn, error) {
return tlsConn, nil
}
+func (t *Trojan) StreamWebsocketConn(conn net.Conn, wsOptions *WebsocketOption) (net.Conn, error) {
+ alpn := defaultALPN
+ if len(t.option.ALPN) != 0 {
+ alpn = t.option.ALPN
+ }
+
+ tlsConfig := &tls.Config{
+ NextProtos: alpn,
+ MinVersion: tls.VersionTLS12,
+ InsecureSkipVerify: t.option.SkipCertVerify,
+ ServerName: t.option.ServerName,
+ }
+
+ return vmess.StreamWebsocketConn(conn, &vmess.WebsocketConfig{
+ Host: wsOptions.Host,
+ Port: wsOptions.Port,
+ Path: wsOptions.Path,
+ Headers: wsOptions.Headers,
+ TLS: true,
+ TLSConfig: tlsConfig,
+ })
+}
+
func (t *Trojan) WriteHeader(w io.Writer, command Command, socks5Addr []byte) error {
buf := pool.GetBuffer()
defer pool.PutBuffer(buf)
diff --git a/transport/v2ray-plugin/websocket.go b/transport/v2ray-plugin/websocket.go
index 317c172fc..7591b4a86 100644
--- a/transport/v2ray-plugin/websocket.go
+++ b/transport/v2ray-plugin/websocket.go
@@ -1,6 +1,7 @@
package obfs
import (
+ "crypto/tls"
"net"
"net/http"
@@ -26,12 +27,22 @@ func NewV2rayObfs(conn net.Conn, option *Option) (net.Conn, error) {
}
config := &vmess.WebsocketConfig{
- Host: option.Host,
- Port: option.Port,
- Path: option.Path,
- TLS: option.TLS,
- Headers: header,
- SkipCertVerify: option.SkipCertVerify,
+ Host: option.Host,
+ Port: option.Port,
+ Path: option.Path,
+ Headers: header,
+ }
+
+ if option.TLS {
+ config.TLS = true
+ config.TLSConfig = &tls.Config{
+ ServerName: option.Host,
+ InsecureSkipVerify: option.SkipCertVerify,
+ NextProtos: []string{"http/1.1"},
+ }
+ if host := config.Headers.Get("Host"); host != "" {
+ config.TLSConfig.ServerName = host
+ }
}
var err error
diff --git a/transport/vmess/websocket.go b/transport/vmess/websocket.go
index 951fb5d0a..f769dcce8 100644
--- a/transport/vmess/websocket.go
+++ b/transport/vmess/websocket.go
@@ -45,8 +45,7 @@ type WebsocketConfig struct {
Path string
Headers http.Header
TLS bool
- SkipCertVerify bool
- ServerName string
+ TLSConfig *tls.Config
MaxEarlyData int
EarlyDataHeaderName string
}
@@ -254,17 +253,7 @@ func streamWebsocketConn(conn net.Conn, c *WebsocketConfig, earlyData *bytes.Buf
scheme := "ws"
if c.TLS {
scheme = "wss"
- dialer.TLSClientConfig = &tls.Config{
- ServerName: c.Host,
- InsecureSkipVerify: c.SkipCertVerify,
- NextProtos: []string{"http/1.1"},
- }
-
- if c.ServerName != "" {
- dialer.TLSClientConfig.ServerName = c.ServerName
- } else if host := c.Headers.Get("Host"); host != "" {
- dialer.TLSClientConfig.ServerName = host
- }
+ dialer.TLSClientConfig = c.TLSConfig
}
uri := url.URL{
From fea9d1c5e234d852e9cae41a51373ca44b2c08dc Mon Sep 17 00:00:00 2001
From: Dreamacro <8615343+Dreamacro@users.noreply.github.com>
Date: Sat, 16 Oct 2021 20:35:06 +0800
Subject: [PATCH 84/96] Fix: replace vmess grpc test image
---
test/vmess_test.go | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/test/vmess_test.go b/test/vmess_test.go
index b696fcea7..1483cf0af 100644
--- a/test/vmess_test.go
+++ b/test/vmess_test.go
@@ -304,13 +304,13 @@ func TestClash_VmessWebsocketTLS(t *testing.T) {
func TestClash_VmessGrpc(t *testing.T) {
cfg := &container.Config{
- Image: ImageXray,
+ Image: ImageVmess,
ExposedPorts: defaultExposedPorts,
}
hostCfg := &container.HostConfig{
PortBindings: defaultPortBindings,
Binds: []string{
- fmt.Sprintf("%s:/etc/xray/config.json", C.Path.Resolve("vmess-grpc.json")),
+ fmt.Sprintf("%s:/etc/v2ray/config.json", C.Path.Resolve("vmess-grpc.json")),
fmt.Sprintf("%s:/etc/ssl/v2ray/fullchain.pem", C.Path.Resolve("example.org.pem")),
fmt.Sprintf("%s:/etc/ssl/v2ray/privkey.pem", C.Path.Resolve("example.org-key.pem")),
},
From 81d5da51a3b0d84ed0a6f752c3e7c02e1065bce1 Mon Sep 17 00:00:00 2001
From: Dreamacro <8615343+Dreamacro@users.noreply.github.com>
Date: Mon, 18 Oct 2021 21:08:27 +0800
Subject: [PATCH 85/96] Fix: unexpected proxy dial behavior on mapping mode
---
config/config.go | 6 ++--
constant/dns.go | 70 ++++++++++++++++++++++++++++++++++++++++++++
constant/metadata.go | 18 ++++++++++++
dns/enhancer.go | 9 +++---
dns/middleware.go | 5 ++--
dns/resolver.go | 3 +-
dns/util.go | 66 -----------------------------------------
tunnel/tunnel.go | 6 ++--
8 files changed, 105 insertions(+), 78 deletions(-)
create mode 100644 constant/dns.go
diff --git a/config/config.go b/config/config.go
index f532c61a1..603523ec6 100644
--- a/config/config.go
+++ b/config/config.go
@@ -62,7 +62,7 @@ type DNS struct {
Fallback []dns.NameServer `yaml:"fallback"`
FallbackFilter FallbackFilter `yaml:"fallback-filter"`
Listen string `yaml:"listen"`
- EnhancedMode dns.EnhancedMode `yaml:"enhanced-mode"`
+ EnhancedMode C.DNSMode `yaml:"enhanced-mode"`
DefaultNameserver []dns.NameServer `yaml:"default-nameserver"`
FakeIPRange *fakeip.Pool
Hosts *trie.DomainTrie
@@ -107,7 +107,7 @@ type RawDNS struct {
Fallback []string `yaml:"fallback"`
FallbackFilter RawFallbackFilter `yaml:"fallback-filter"`
Listen string `yaml:"listen"`
- EnhancedMode dns.EnhancedMode `yaml:"enhanced-mode"`
+ EnhancedMode C.DNSMode `yaml:"enhanced-mode"`
FakeIPRange string `yaml:"fake-ip-range"`
FakeIPFilter []string `yaml:"fake-ip-filter"`
DefaultNameserver []string `yaml:"default-nameserver"`
@@ -584,7 +584,7 @@ func parseDNS(rawCfg *RawConfig, hosts *trie.DomainTrie) (*DNS, error) {
}
}
- if cfg.EnhancedMode == dns.FAKEIP {
+ if cfg.EnhancedMode == C.DNSFakeIP {
_, ipnet, err := net.ParseCIDR(cfg.FakeIPRange)
if err != nil {
return nil, err
diff --git a/constant/dns.go b/constant/dns.go
new file mode 100644
index 000000000..d1cd7a61c
--- /dev/null
+++ b/constant/dns.go
@@ -0,0 +1,70 @@
+package constant
+
+import (
+ "encoding/json"
+ "errors"
+)
+
+// DNSModeMapping is a mapping for EnhancedMode enum
+var DNSModeMapping = map[string]DNSMode{
+ DNSNormal.String(): DNSNormal,
+ DNSFakeIP.String(): DNSFakeIP,
+ DNSMapping.String(): DNSMapping,
+}
+
+const (
+ DNSNormal DNSMode = iota
+ DNSFakeIP
+ DNSMapping
+)
+
+type DNSMode int
+
+// UnmarshalYAML unserialize EnhancedMode with yaml
+func (e *DNSMode) UnmarshalYAML(unmarshal func(interface{}) error) error {
+ var tp string
+ if err := unmarshal(&tp); err != nil {
+ return err
+ }
+ mode, exist := DNSModeMapping[tp]
+ if !exist {
+ return errors.New("invalid mode")
+ }
+ *e = mode
+ return nil
+}
+
+// MarshalYAML serialize EnhancedMode with yaml
+func (e DNSMode) MarshalYAML() (interface{}, error) {
+ return e.String(), nil
+}
+
+// UnmarshalJSON unserialize EnhancedMode with json
+func (e *DNSMode) UnmarshalJSON(data []byte) error {
+ var tp string
+ json.Unmarshal(data, &tp)
+ mode, exist := DNSModeMapping[tp]
+ if !exist {
+ return errors.New("invalid mode")
+ }
+ *e = mode
+ return nil
+}
+
+// MarshalJSON serialize EnhancedMode with json
+func (e DNSMode) MarshalJSON() ([]byte, error) {
+ return json.Marshal(e.String())
+}
+
+func (e DNSMode) String() string {
+ switch e {
+ case DNSNormal:
+ return "normal"
+ case DNSFakeIP:
+ return "fake-ip"
+ case DNSMapping:
+ return "redir-host"
+ default:
+ return "unknown"
+ }
+}
diff --git a/constant/metadata.go b/constant/metadata.go
index 9fff773b3..822b4714d 100644
--- a/constant/metadata.go
+++ b/constant/metadata.go
@@ -71,6 +71,7 @@ type Metadata struct {
DstPort string `json:"destinationPort"`
AddrType int `json:"-"`
Host string `json:"host"`
+ DNSMode DNSMode `json:"dnsMode"`
}
func (m *Metadata) RemoteAddress() string {
@@ -85,6 +86,23 @@ func (m *Metadata) Resolved() bool {
return m.DstIP != nil
}
+// Pure is used to solve unexpected behavior
+// when dialing proxy connection in DNSMapping mode.
+func (m *Metadata) Pure() *Metadata {
+ if m.DNSMode == DNSMapping && m.DstIP != nil {
+ copy := *m
+ copy.Host = ""
+ if copy.DstIP.To4() != nil {
+ copy.AddrType = AtypIPv4
+ } else {
+ copy.AddrType = AtypIPv6
+ }
+ return ©
+ }
+
+ return m
+}
+
func (m *Metadata) UDPAddr() *net.UDPAddr {
if m.NetWork != UDP || m.DstIP == nil {
return nil
diff --git a/dns/enhancer.go b/dns/enhancer.go
index d2592e6e9..76f0f2628 100644
--- a/dns/enhancer.go
+++ b/dns/enhancer.go
@@ -5,20 +5,21 @@ import (
"github.com/Dreamacro/clash/common/cache"
"github.com/Dreamacro/clash/component/fakeip"
+ C "github.com/Dreamacro/clash/constant"
)
type ResolverEnhancer struct {
- mode EnhancedMode
+ mode C.DNSMode
fakePool *fakeip.Pool
mapping *cache.LruCache
}
func (h *ResolverEnhancer) FakeIPEnabled() bool {
- return h.mode == FAKEIP
+ return h.mode == C.DNSFakeIP
}
func (h *ResolverEnhancer) MappingEnabled() bool {
- return h.mode == FAKEIP || h.mode == MAPPING
+ return h.mode == C.DNSFakeIP || h.mode == C.DNSMapping
}
func (h *ResolverEnhancer) IsExistFakeIP(ip net.IP) bool {
@@ -75,7 +76,7 @@ func NewEnhancer(cfg Config) *ResolverEnhancer {
var fakePool *fakeip.Pool
var mapping *cache.LruCache
- if cfg.EnhancedMode != NORMAL {
+ if cfg.EnhancedMode != C.DNSNormal {
fakePool = cfg.Pool
mapping = cache.NewLRUCache(cache.WithSize(4096), cache.WithStale(true))
}
diff --git a/dns/middleware.go b/dns/middleware.go
index de0b3aff4..9d0da5968 100644
--- a/dns/middleware.go
+++ b/dns/middleware.go
@@ -8,6 +8,7 @@ import (
"github.com/Dreamacro/clash/common/cache"
"github.com/Dreamacro/clash/component/fakeip"
"github.com/Dreamacro/clash/component/trie"
+ C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/context"
"github.com/Dreamacro/clash/log"
@@ -178,11 +179,11 @@ func newHandler(resolver *Resolver, mapper *ResolverEnhancer) handler {
middlewares = append(middlewares, withHosts(resolver.hosts))
}
- if mapper.mode == FAKEIP {
+ if mapper.mode == C.DNSFakeIP {
middlewares = append(middlewares, withFakeIP(mapper.fakePool))
}
- if mapper.mode != NORMAL {
+ if mapper.mode != C.DNSNormal {
middlewares = append(middlewares, withMapping(mapper.mapping))
}
diff --git a/dns/resolver.go b/dns/resolver.go
index bf544cb99..91efbb8bc 100644
--- a/dns/resolver.go
+++ b/dns/resolver.go
@@ -14,6 +14,7 @@ import (
"github.com/Dreamacro/clash/component/fakeip"
"github.com/Dreamacro/clash/component/resolver"
"github.com/Dreamacro/clash/component/trie"
+ C "github.com/Dreamacro/clash/constant"
D "github.com/miekg/dns"
"golang.org/x/sync/singleflight"
@@ -317,7 +318,7 @@ type Config struct {
Main, Fallback []NameServer
Default []NameServer
IPv6 bool
- EnhancedMode EnhancedMode
+ EnhancedMode C.DNSMode
FallbackFilter FallbackFilter
Pool *fakeip.Pool
Hosts *trie.DomainTrie
diff --git a/dns/util.go b/dns/util.go
index 0e1badabc..d11870f81 100644
--- a/dns/util.go
+++ b/dns/util.go
@@ -2,8 +2,6 @@ package dns
import (
"crypto/tls"
- "encoding/json"
- "errors"
"net"
"time"
@@ -13,70 +11,6 @@ import (
D "github.com/miekg/dns"
)
-// EnhancedModeMapping is a mapping for EnhancedMode enum
-var EnhancedModeMapping = map[string]EnhancedMode{
- NORMAL.String(): NORMAL,
- FAKEIP.String(): FAKEIP,
- MAPPING.String(): MAPPING,
-}
-
-const (
- NORMAL EnhancedMode = iota
- FAKEIP
- MAPPING
-)
-
-type EnhancedMode int
-
-// UnmarshalYAML unserialize EnhancedMode with yaml
-func (e *EnhancedMode) UnmarshalYAML(unmarshal func(interface{}) error) error {
- var tp string
- if err := unmarshal(&tp); err != nil {
- return err
- }
- mode, exist := EnhancedModeMapping[tp]
- if !exist {
- return errors.New("invalid mode")
- }
- *e = mode
- return nil
-}
-
-// MarshalYAML serialize EnhancedMode with yaml
-func (e EnhancedMode) MarshalYAML() (interface{}, error) {
- return e.String(), nil
-}
-
-// UnmarshalJSON unserialize EnhancedMode with json
-func (e *EnhancedMode) UnmarshalJSON(data []byte) error {
- var tp string
- json.Unmarshal(data, &tp)
- mode, exist := EnhancedModeMapping[tp]
- if !exist {
- return errors.New("invalid mode")
- }
- *e = mode
- return nil
-}
-
-// MarshalJSON serialize EnhancedMode with json
-func (e EnhancedMode) MarshalJSON() ([]byte, error) {
- return json.Marshal(e.String())
-}
-
-func (e EnhancedMode) String() string {
- switch e {
- case NORMAL:
- return "normal"
- case FAKEIP:
- return "fake-ip"
- case MAPPING:
- return "redir-host"
- default:
- return "unknown"
- }
-}
-
func putMsgToCache(c *cache.LruCache, key string, msg *D.Msg) {
var ttl uint32
switch {
diff --git a/tunnel/tunnel.go b/tunnel/tunnel.go
index ccd6a58bd..dd64b0155 100644
--- a/tunnel/tunnel.go
+++ b/tunnel/tunnel.go
@@ -135,9 +135,11 @@ func preHandleMetadata(metadata *C.Metadata) error {
metadata.AddrType = C.AtypDomainName
if resolver.FakeIPEnabled() {
metadata.DstIP = nil
+ metadata.DNSMode = C.DNSFakeIP
} else if node := resolver.DefaultHosts.Search(host); node != nil {
// redir-host should lookup the hosts
metadata.DstIP = node.Data.(net.IP)
+ metadata.DNSMode = C.DNSMapping
}
} else if resolver.IsFakeIP(metadata.DstIP) {
return fmt.Errorf("fake DNS record %s missing", metadata.DstIP)
@@ -219,7 +221,7 @@ func handleUDPConn(packet *inbound.PacketAdapter) {
ctx, cancel := context.WithTimeout(context.Background(), C.DefaultUDPTimeout)
defer cancel()
- rawPc, err := proxy.ListenPacketContext(ctx, metadata)
+ rawPc, err := proxy.ListenPacketContext(ctx, metadata.Pure())
if err != nil {
if rule == nil {
log.Warnln("[UDP] dial %s to %s error: %s", proxy.Name(), metadata.RemoteAddress(), err.Error())
@@ -271,7 +273,7 @@ func handleTCPConn(connCtx C.ConnContext) {
ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTCPTimeout)
defer cancel()
- remoteConn, err := proxy.DialContext(ctx, metadata)
+ remoteConn, err := proxy.DialContext(ctx, metadata.Pure())
if err != nil {
if rule == nil {
log.Warnln("[TCP] dial %s to %s error: %s", proxy.Name(), metadata.RemoteAddress(), err.Error())
From 967932d02c14d45914c9dc106c483c55e380712f Mon Sep 17 00:00:00 2001
From: Dreamacro <8615343+Dreamacro@users.noreply.github.com>
Date: Mon, 18 Oct 2021 22:58:16 +0800
Subject: [PATCH 86/96] Fix: set dnsmode behavior
---
tunnel/tunnel.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tunnel/tunnel.go b/tunnel/tunnel.go
index dd64b0155..1c0075549 100644
--- a/tunnel/tunnel.go
+++ b/tunnel/tunnel.go
@@ -133,13 +133,13 @@ func preHandleMetadata(metadata *C.Metadata) error {
if exist {
metadata.Host = host
metadata.AddrType = C.AtypDomainName
+ metadata.DNSMode = C.DNSMapping
if resolver.FakeIPEnabled() {
metadata.DstIP = nil
metadata.DNSMode = C.DNSFakeIP
} else if node := resolver.DefaultHosts.Search(host); node != nil {
// redir-host should lookup the hosts
metadata.DstIP = node.Data.(net.IP)
- metadata.DNSMode = C.DNSMapping
}
} else if resolver.IsFakeIP(metadata.DstIP) {
return fmt.Errorf("fake DNS record %s missing", metadata.DstIP)
From c6cceeb0c589983ee0758f1bbbe6fd7ad1f3a1eb Mon Sep 17 00:00:00 2001
From: Dreamacro <8615343+Dreamacro@users.noreply.github.com>
Date: Tue, 19 Oct 2021 22:34:18 +0800
Subject: [PATCH 87/96] Chore: use alpn http 1.1 only on trojan websocket by
default
---
transport/trojan/trojan.go | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/transport/trojan/trojan.go b/transport/trojan/trojan.go
index 26e7adc7d..9d9a33b99 100644
--- a/transport/trojan/trojan.go
+++ b/transport/trojan/trojan.go
@@ -22,8 +22,10 @@ const (
)
var (
- defaultALPN = []string{"h2", "http/1.1"}
- crlf = []byte{'\r', '\n'}
+ defaultALPN = []string{"h2", "http/1.1"}
+ defaultWebsocketALPN = []string{"http/1.1"}
+
+ crlf = []byte{'\r', '\n'}
)
type Command = byte
@@ -74,7 +76,7 @@ func (t *Trojan) StreamConn(conn net.Conn) (net.Conn, error) {
}
func (t *Trojan) StreamWebsocketConn(conn net.Conn, wsOptions *WebsocketOption) (net.Conn, error) {
- alpn := defaultALPN
+ alpn := defaultWebsocketALPN
if len(t.option.ALPN) != 0 {
alpn = t.option.ALPN
}
From a7aea12aa69596edf9c3bad2352ebde303ea5d6e Mon Sep 17 00:00:00 2001
From: Blaise Wang
Date: Wed, 20 Oct 2021 13:44:05 +0800
Subject: [PATCH 88/96] Fix: remove ResponseHeaderTimeout limitation (#1690)
---
listener/http/client.go | 1 -
1 file changed, 1 deletion(-)
diff --git a/listener/http/client.go b/listener/http/client.go
index 15078b0ac..873a9a3c9 100644
--- a/listener/http/client.go
+++ b/listener/http/client.go
@@ -19,7 +19,6 @@ func newClient(source net.Addr, in chan<- C.ConnContext) *http.Client {
MaxIdleConns: 100,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
- ResponseHeaderTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
DialContext: func(context context.Context, network, address string) (net.Conn, error) {
if network != "tcp" && network != "tcp4" && network != "tcp6" {
From ebbc9604ce68b6484ab730a05cf02a639e619438 Mon Sep 17 00:00:00 2001
From: Dreamacro <8615343+Dreamacro@users.noreply.github.com>
Date: Wed, 27 Oct 2021 21:27:19 +0800
Subject: [PATCH 89/96] Chore: use uber max procs
---
go.mod | 1 +
go.sum | 12 +++++++++++-
main.go | 3 +++
tunnel/tunnel.go | 4 ++--
4 files changed, 17 insertions(+), 3 deletions(-)
diff --git a/go.mod b/go.mod
index dc79d77af..c608f7ad2 100644
--- a/go.mod
+++ b/go.mod
@@ -16,6 +16,7 @@ require (
github.com/stretchr/testify v1.7.0
go.etcd.io/bbolt v1.3.6
go.uber.org/atomic v1.9.0
+ go.uber.org/automaxprocs v1.4.0
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5
golang.org/x/net v0.0.0-20210903162142-ad29c8ab022f
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
diff --git a/go.sum b/go.sum
index 1fbae8ce4..cccc8ba34 100644
--- a/go.sum
+++ b/go.sum
@@ -28,6 +28,11 @@ github.com/jsimonetti/rtnetlink v0.0.0-20200117123717-f846d4f6c1f4/go.mod h1:WGu
github.com/jsimonetti/rtnetlink v0.0.0-20201009170750-9c6f07d100c1/go.mod h1:hqoO/u39cqLeBLebZ8fWdE96O7FxrAsRYhnVOdgHxok=
github.com/jsimonetti/rtnetlink v0.0.0-20201110080708-d2c240429e6c/go.mod h1:huN4d1phzjhlOsNIjFsw2SVRbwIHj3fJDMEU2SDPTmg=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
+github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
+github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/mdlayher/ethernet v0.0.0-20190606142754-0394541c37b7/go.mod h1:U6ZQobyTjI/tJyq2HG+i/dfSoFUt8/aZCM+GKtmFk/Y=
github.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA=
github.com/mdlayher/netlink v1.0.0/go.mod h1:KxeJAFOFLG6AjpyDkQ/iIhxygIUKD+vcwqcnu43w/+M=
@@ -50,6 +55,7 @@ github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
@@ -59,6 +65,8 @@ go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU=
go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4=
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
+go.uber.org/automaxprocs v1.4.0 h1:CpDZl6aOlLhReez+8S3eEotD7Jx0Os++lemPlMULQP0=
+go.uber.org/automaxprocs v1.4.0/go.mod h1:/mTEdr7LvHhs0v7mjdxDreTz1OG5zdZGqgOnhWiR/+Q=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210317152858-513c2a44f670/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
@@ -108,8 +116,10 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
diff --git a/main.go b/main.go
index 4a7dff0be..5d953ed69 100644
--- a/main.go
+++ b/main.go
@@ -14,6 +14,8 @@ import (
"github.com/Dreamacro/clash/hub"
"github.com/Dreamacro/clash/hub/executor"
"github.com/Dreamacro/clash/log"
+
+ "go.uber.org/automaxprocs/maxprocs"
)
var (
@@ -44,6 +46,7 @@ func init() {
}
func main() {
+ maxprocs.Set(maxprocs.Logger(func(string, ...interface{}) {}))
if version {
fmt.Printf("Clash %s %s %s with %s %s\n", C.Version, runtime.GOOS, runtime.GOARCH, runtime.Version(), C.BuildTime)
return
diff --git a/tunnel/tunnel.go b/tunnel/tunnel.go
index 1c0075549..f00a7bd02 100644
--- a/tunnel/tunnel.go
+++ b/tunnel/tunnel.go
@@ -98,8 +98,8 @@ func processUDP() {
func process() {
numUDPWorkers := 4
- if runtime.NumCPU() > numUDPWorkers {
- numUDPWorkers = runtime.NumCPU()
+ if num := runtime.GOMAXPROCS(0); num > numUDPWorkers {
+ numUDPWorkers = num
}
for i := 0; i < numUDPWorkers; i++ {
go processUDP()
From bcb301b730de889295d7f90ccf8aa8102f133727 Mon Sep 17 00:00:00 2001
From: Dreamacro <8615343+Dreamacro@users.noreply.github.com>
Date: Wed, 3 Nov 2021 22:26:51 +0800
Subject: [PATCH 90/96] Chore: adjust all udp alloc size
---
common/pool/pool.go | 5 +++++
listener/socks/udp.go | 2 +-
listener/tproxy/udp.go | 2 +-
tunnel/connection.go | 2 +-
4 files changed, 8 insertions(+), 3 deletions(-)
diff --git a/common/pool/pool.go b/common/pool/pool.go
index e6354f119..bee4887f5 100644
--- a/common/pool/pool.go
+++ b/common/pool/pool.go
@@ -5,6 +5,11 @@ const (
// but the maximum packet size of vmess/shadowsocks is about 16 KiB
// so define a buffer of 20 KiB to reduce the memory of each TCP relay
RelayBufferSize = 20 * 1024
+
+ // RelayBufferSize uses 20KiB, but due to the allocator it will actually
+ // request 32Kib. Most UDPs are smaller than the MTU, and the TUN's MTU
+ // set to 9000, so the UDP Buffer size set to 16Kib
+ UDPBufferSize = 16 * 1024
)
func Get(size int) []byte {
diff --git a/listener/socks/udp.go b/listener/socks/udp.go
index a2d215083..8bc439fb4 100644
--- a/listener/socks/udp.go
+++ b/listener/socks/udp.go
@@ -49,7 +49,7 @@ func NewUDP(addr string, in chan<- *inbound.PacketAdapter) (*UDPListener, error)
}
go func() {
for {
- buf := pool.Get(pool.RelayBufferSize)
+ buf := pool.Get(pool.UDPBufferSize)
n, remoteAddr, err := l.ReadFrom(buf)
if err != nil {
pool.Put(buf)
diff --git a/listener/tproxy/udp.go b/listener/tproxy/udp.go
index f3d8dbb3c..c7e6d99e3 100644
--- a/listener/tproxy/udp.go
+++ b/listener/tproxy/udp.go
@@ -57,7 +57,7 @@ func NewUDP(addr string, in chan<- *inbound.PacketAdapter) (*UDPListener, error)
go func() {
oob := make([]byte, 1024)
for {
- buf := pool.Get(pool.RelayBufferSize)
+ buf := pool.Get(pool.UDPBufferSize)
n, oobn, _, lAddr, err := c.ReadMsgUDP(buf, oob)
if err != nil {
pool.Put(buf)
diff --git a/tunnel/connection.go b/tunnel/connection.go
index 8c3b4cb61..45de46d7f 100644
--- a/tunnel/connection.go
+++ b/tunnel/connection.go
@@ -39,7 +39,7 @@ func handleUDPToRemote(packet C.UDPPacket, pc C.PacketConn, metadata *C.Metadata
}
func handleUDPToLocal(packet C.UDPPacket, pc net.PacketConn, key string, fAddr net.Addr) {
- buf := pool.Get(pool.RelayBufferSize)
+ buf := pool.Get(pool.UDPBufferSize)
defer pool.Put(buf)
defer natTable.Delete(key)
defer pc.Close()
From 1a7830f18ecd9185dedef1340b7d4fcd55c6e503 Mon Sep 17 00:00:00 2001
From: Dreamacro
Date: Sun, 7 Nov 2021 16:48:51 +0800
Subject: [PATCH 91/96] Feature: dial different NIC for all proxies (#1714)
---
adapter/adapter.go | 9 +++---
adapter/outbound/base.go | 43 +++++++++++++++++++++++-----
adapter/outbound/direct.go | 8 +++---
adapter/outbound/http.go | 12 ++++----
adapter/outbound/reject.go | 5 ++--
adapter/outbound/shadowsocks.go | 18 ++++++------
adapter/outbound/shadowsocksr.go | 18 ++++++------
adapter/outbound/snell.go | 16 ++++++-----
adapter/outbound/socks5.go | 20 +++++++------
adapter/outbound/trojan.go | 24 +++++++++-------
adapter/outbound/vmess.go | 24 +++++++++-------
adapter/outboundgroup/fallback.go | 19 +++++++-----
adapter/outboundgroup/loadbalance.go | 19 +++++++-----
adapter/outboundgroup/parser.go | 2 ++
adapter/outboundgroup/relay.go | 16 +++++++----
adapter/outboundgroup/selector.go | 19 +++++++-----
adapter/outboundgroup/urltest.go | 19 +++++++-----
component/dialer/dialer.go | 20 ++++++-------
component/dialer/options.go | 22 +++++++-------
constant/adapters.go | 6 ++--
hub/executor/executor.go | 6 +---
21 files changed, 206 insertions(+), 139 deletions(-)
diff --git a/adapter/adapter.go b/adapter/adapter.go
index 263301636..76bbe2e3d 100644
--- a/adapter/adapter.go
+++ b/adapter/adapter.go
@@ -10,6 +10,7 @@ import (
"time"
"github.com/Dreamacro/clash/common/queue"
+ "github.com/Dreamacro/clash/component/dialer"
C "github.com/Dreamacro/clash/constant"
"go.uber.org/atomic"
@@ -34,8 +35,8 @@ func (p *Proxy) Dial(metadata *C.Metadata) (C.Conn, error) {
}
// DialContext implements C.ProxyAdapter
-func (p *Proxy) DialContext(ctx context.Context, metadata *C.Metadata) (C.Conn, error) {
- conn, err := p.ProxyAdapter.DialContext(ctx, metadata)
+func (p *Proxy) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.Conn, error) {
+ conn, err := p.ProxyAdapter.DialContext(ctx, metadata, opts...)
p.alive.Store(err == nil)
return conn, err
}
@@ -48,8 +49,8 @@ func (p *Proxy) DialUDP(metadata *C.Metadata) (C.PacketConn, error) {
}
// ListenPacketContext implements C.ProxyAdapter
-func (p *Proxy) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (C.PacketConn, error) {
- pc, err := p.ProxyAdapter.ListenPacketContext(ctx, metadata)
+func (p *Proxy) ListenPacketContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.PacketConn, error) {
+ pc, err := p.ProxyAdapter.ListenPacketContext(ctx, metadata, opts...)
p.alive.Store(err == nil)
return pc, err
}
diff --git a/adapter/outbound/base.go b/adapter/outbound/base.go
index 22c0142b0..e028cd4e8 100644
--- a/adapter/outbound/base.go
+++ b/adapter/outbound/base.go
@@ -6,14 +6,16 @@ import (
"errors"
"net"
+ "github.com/Dreamacro/clash/component/dialer"
C "github.com/Dreamacro/clash/constant"
)
type Base struct {
- name string
- addr string
- tp C.AdapterType
- udp bool
+ name string
+ addr string
+ iface string
+ tp C.AdapterType
+ udp bool
}
// Name implements C.ProxyAdapter
@@ -32,7 +34,7 @@ func (b *Base) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {
}
// ListenPacketContext implements C.ProxyAdapter
-func (b *Base) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (C.PacketConn, error) {
+func (b *Base) ListenPacketContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.PacketConn, error) {
return nil, errors.New("no support")
}
@@ -58,8 +60,35 @@ func (b *Base) Unwrap(metadata *C.Metadata) C.Proxy {
return nil
}
-func NewBase(name string, addr string, tp C.AdapterType, udp bool) *Base {
- return &Base{name, addr, tp, udp}
+// DialOptions return []dialer.Option from struct
+func (b *Base) DialOptions(opts ...dialer.Option) []dialer.Option {
+ if b.iface != "" {
+ opts = append(opts, dialer.WithInterface(b.iface))
+ }
+
+ return opts
+}
+
+type BasicOption struct {
+ Interface string `proxy:"interface-name"`
+}
+
+type BaseOption struct {
+ Name string
+ Addr string
+ Type C.AdapterType
+ UDP bool
+ Interface string
+}
+
+func NewBase(opt BaseOption) *Base {
+ return &Base{
+ name: opt.Name,
+ addr: opt.Addr,
+ tp: opt.Type,
+ udp: opt.UDP,
+ iface: opt.Interface,
+ }
}
type conn struct {
diff --git a/adapter/outbound/direct.go b/adapter/outbound/direct.go
index 42433c410..4c4305f57 100644
--- a/adapter/outbound/direct.go
+++ b/adapter/outbound/direct.go
@@ -13,8 +13,8 @@ type Direct struct {
}
// DialContext implements C.ProxyAdapter
-func (d *Direct) DialContext(ctx context.Context, metadata *C.Metadata) (C.Conn, error) {
- c, err := dialer.DialContext(ctx, "tcp", metadata.RemoteAddress())
+func (d *Direct) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.Conn, error) {
+ c, err := dialer.DialContext(ctx, "tcp", metadata.RemoteAddress(), d.Base.DialOptions(opts...)...)
if err != nil {
return nil, err
}
@@ -23,8 +23,8 @@ func (d *Direct) DialContext(ctx context.Context, metadata *C.Metadata) (C.Conn,
}
// ListenPacketContext implements C.ProxyAdapter
-func (d *Direct) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (C.PacketConn, error) {
- pc, err := dialer.ListenPacket(ctx, "udp", "")
+func (d *Direct) ListenPacketContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.PacketConn, error) {
+ pc, err := dialer.ListenPacket(ctx, "udp", "", d.Base.DialOptions(opts...)...)
if err != nil {
return nil, err
}
diff --git a/adapter/outbound/http.go b/adapter/outbound/http.go
index b4dffdf78..7f480ce6b 100644
--- a/adapter/outbound/http.go
+++ b/adapter/outbound/http.go
@@ -25,6 +25,7 @@ type Http struct {
}
type HttpOption struct {
+ BasicOption
Name string `proxy:"name"`
Server string `proxy:"server"`
Port int `proxy:"port"`
@@ -53,8 +54,8 @@ func (h *Http) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {
}
// DialContext implements C.ProxyAdapter
-func (h *Http) DialContext(ctx context.Context, metadata *C.Metadata) (_ C.Conn, err error) {
- c, err := dialer.DialContext(ctx, "tcp", h.addr)
+func (h *Http) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (_ C.Conn, err error) {
+ c, err := dialer.DialContext(ctx, "tcp", h.addr, h.Base.DialOptions(opts...)...)
if err != nil {
return nil, fmt.Errorf("%s connect error: %w", h.addr, err)
}
@@ -131,9 +132,10 @@ func NewHttp(option HttpOption) *Http {
return &Http{
Base: &Base{
- name: option.Name,
- addr: net.JoinHostPort(option.Server, strconv.Itoa(option.Port)),
- tp: C.Http,
+ name: option.Name,
+ addr: net.JoinHostPort(option.Server, strconv.Itoa(option.Port)),
+ tp: C.Http,
+ iface: option.Interface,
},
user: option.UserName,
pass: option.Password,
diff --git a/adapter/outbound/reject.go b/adapter/outbound/reject.go
index a97c6c711..f1940d39a 100644
--- a/adapter/outbound/reject.go
+++ b/adapter/outbound/reject.go
@@ -7,6 +7,7 @@ import (
"net"
"time"
+ "github.com/Dreamacro/clash/component/dialer"
C "github.com/Dreamacro/clash/constant"
)
@@ -15,12 +16,12 @@ type Reject struct {
}
// DialContext implements C.ProxyAdapter
-func (r *Reject) DialContext(ctx context.Context, metadata *C.Metadata) (C.Conn, error) {
+func (r *Reject) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.Conn, error) {
return NewConn(&NopConn{}, r), nil
}
// ListenPacketContext implements C.ProxyAdapter
-func (r *Reject) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (C.PacketConn, error) {
+func (r *Reject) ListenPacketContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.PacketConn, error) {
return nil, errors.New("match reject rule")
}
diff --git a/adapter/outbound/shadowsocks.go b/adapter/outbound/shadowsocks.go
index 0194954e7..5e5ebd7c4 100644
--- a/adapter/outbound/shadowsocks.go
+++ b/adapter/outbound/shadowsocks.go
@@ -28,6 +28,7 @@ type ShadowSocks struct {
}
type ShadowSocksOption struct {
+ BasicOption
Name string `proxy:"name"`
Server string `proxy:"server"`
Port int `proxy:"port"`
@@ -74,8 +75,8 @@ func (ss *ShadowSocks) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, e
}
// DialContext implements C.ProxyAdapter
-func (ss *ShadowSocks) DialContext(ctx context.Context, metadata *C.Metadata) (_ C.Conn, err error) {
- c, err := dialer.DialContext(ctx, "tcp", ss.addr)
+func (ss *ShadowSocks) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (_ C.Conn, err error) {
+ c, err := dialer.DialContext(ctx, "tcp", ss.addr, ss.Base.DialOptions(opts...)...)
if err != nil {
return nil, fmt.Errorf("%s connect error: %w", ss.addr, err)
}
@@ -88,8 +89,8 @@ func (ss *ShadowSocks) DialContext(ctx context.Context, metadata *C.Metadata) (_
}
// ListenPacketContext implements C.ProxyAdapter
-func (ss *ShadowSocks) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (C.PacketConn, error) {
- pc, err := dialer.ListenPacket(ctx, "udp", "")
+func (ss *ShadowSocks) ListenPacketContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.PacketConn, error) {
+ pc, err := dialer.ListenPacket(ctx, "udp", "", ss.Base.DialOptions(opts...)...)
if err != nil {
return nil, err
}
@@ -154,10 +155,11 @@ func NewShadowSocks(option ShadowSocksOption) (*ShadowSocks, error) {
return &ShadowSocks{
Base: &Base{
- name: option.Name,
- addr: addr,
- tp: C.Shadowsocks,
- udp: option.UDP,
+ name: option.Name,
+ addr: addr,
+ tp: C.Shadowsocks,
+ udp: option.UDP,
+ iface: option.Interface,
},
cipher: ciph,
diff --git a/adapter/outbound/shadowsocksr.go b/adapter/outbound/shadowsocksr.go
index fb0dd7a5f..d244df406 100644
--- a/adapter/outbound/shadowsocksr.go
+++ b/adapter/outbound/shadowsocksr.go
@@ -24,6 +24,7 @@ type ShadowSocksR struct {
}
type ShadowSocksROption struct {
+ BasicOption
Name string `proxy:"name"`
Server string `proxy:"server"`
Port int `proxy:"port"`
@@ -59,8 +60,8 @@ func (ssr *ShadowSocksR) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn,
}
// DialContext implements C.ProxyAdapter
-func (ssr *ShadowSocksR) DialContext(ctx context.Context, metadata *C.Metadata) (_ C.Conn, err error) {
- c, err := dialer.DialContext(ctx, "tcp", ssr.addr)
+func (ssr *ShadowSocksR) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (_ C.Conn, err error) {
+ c, err := dialer.DialContext(ctx, "tcp", ssr.addr, ssr.Base.DialOptions(opts...)...)
if err != nil {
return nil, fmt.Errorf("%s connect error: %w", ssr.addr, err)
}
@@ -73,8 +74,8 @@ func (ssr *ShadowSocksR) DialContext(ctx context.Context, metadata *C.Metadata)
}
// ListenPacketContext implements C.ProxyAdapter
-func (ssr *ShadowSocksR) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (C.PacketConn, error) {
- pc, err := dialer.ListenPacket(ctx, "udp", "")
+func (ssr *ShadowSocksR) ListenPacketContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.PacketConn, error) {
+ pc, err := dialer.ListenPacket(ctx, "udp", "", ssr.Base.DialOptions(opts...)...)
if err != nil {
return nil, err
}
@@ -136,10 +137,11 @@ func NewShadowSocksR(option ShadowSocksROption) (*ShadowSocksR, error) {
return &ShadowSocksR{
Base: &Base{
- name: option.Name,
- addr: addr,
- tp: C.ShadowsocksR,
- udp: option.UDP,
+ name: option.Name,
+ addr: addr,
+ tp: C.ShadowsocksR,
+ udp: option.UDP,
+ iface: option.Interface,
},
cipher: coreCiph,
obfs: obfs,
diff --git a/adapter/outbound/snell.go b/adapter/outbound/snell.go
index 2dc16a511..40dcf0664 100644
--- a/adapter/outbound/snell.go
+++ b/adapter/outbound/snell.go
@@ -22,6 +22,7 @@ type Snell struct {
}
type SnellOption struct {
+ BasicOption
Name string `proxy:"name"`
Server string `proxy:"server"`
Port int `proxy:"port"`
@@ -57,8 +58,8 @@ func (s *Snell) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {
}
// DialContext implements C.ProxyAdapter
-func (s *Snell) DialContext(ctx context.Context, metadata *C.Metadata) (_ C.Conn, err error) {
- if s.version == snell.Version2 {
+func (s *Snell) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (_ C.Conn, err error) {
+ if s.version == snell.Version2 && len(opts) == 0 {
c, err := s.pool.Get()
if err != nil {
return nil, err
@@ -72,7 +73,7 @@ func (s *Snell) DialContext(ctx context.Context, metadata *C.Metadata) (_ C.Conn
return NewConn(c, s), err
}
- c, err := dialer.DialContext(ctx, "tcp", s.addr)
+ c, err := dialer.DialContext(ctx, "tcp", s.addr, s.Base.DialOptions(opts...)...)
if err != nil {
return nil, fmt.Errorf("%s connect error: %w", s.addr, err)
}
@@ -111,9 +112,10 @@ func NewSnell(option SnellOption) (*Snell, error) {
s := &Snell{
Base: &Base{
- name: option.Name,
- addr: addr,
- tp: C.Snell,
+ name: option.Name,
+ addr: addr,
+ tp: C.Snell,
+ iface: option.Interface,
},
psk: psk,
obfsOption: obfsOption,
@@ -122,7 +124,7 @@ func NewSnell(option SnellOption) (*Snell, error) {
if option.Version == snell.Version2 {
s.pool = snell.NewPool(func(ctx context.Context) (*snell.Snell, error) {
- c, err := dialer.DialContext(ctx, "tcp", addr)
+ c, err := dialer.DialContext(ctx, "tcp", addr, s.Base.DialOptions()...)
if err != nil {
return nil, err
}
diff --git a/adapter/outbound/socks5.go b/adapter/outbound/socks5.go
index 7714c5c52..874da9f14 100644
--- a/adapter/outbound/socks5.go
+++ b/adapter/outbound/socks5.go
@@ -24,6 +24,7 @@ type Socks5 struct {
}
type Socks5Option struct {
+ *BaseOption
Name string `proxy:"name"`
Server string `proxy:"server"`
Port int `proxy:"port"`
@@ -59,8 +60,8 @@ func (ss *Socks5) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error)
}
// DialContext implements C.ProxyAdapter
-func (ss *Socks5) DialContext(ctx context.Context, metadata *C.Metadata) (_ C.Conn, err error) {
- c, err := dialer.DialContext(ctx, "tcp", ss.addr)
+func (ss *Socks5) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (_ C.Conn, err error) {
+ c, err := dialer.DialContext(ctx, "tcp", ss.addr, ss.Base.DialOptions(opts...)...)
if err != nil {
return nil, fmt.Errorf("%s connect error: %w", ss.addr, err)
}
@@ -77,8 +78,8 @@ func (ss *Socks5) DialContext(ctx context.Context, metadata *C.Metadata) (_ C.Co
}
// ListenPacketContext implements C.ProxyAdapter
-func (ss *Socks5) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (_ C.PacketConn, err error) {
- c, err := dialer.DialContext(ctx, "tcp", ss.addr)
+func (ss *Socks5) ListenPacketContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (_ C.PacketConn, err error) {
+ c, err := dialer.DialContext(ctx, "tcp", ss.addr, ss.Base.DialOptions(opts...)...)
if err != nil {
err = fmt.Errorf("%s connect error: %w", ss.addr, err)
return
@@ -107,7 +108,7 @@ func (ss *Socks5) ListenPacketContext(ctx context.Context, metadata *C.Metadata)
return
}
- pc, err := dialer.ListenPacket(ctx, "udp", "")
+ pc, err := dialer.ListenPacket(ctx, "udp", "", ss.Base.DialOptions(opts...)...)
if err != nil {
return
}
@@ -148,10 +149,11 @@ func NewSocks5(option Socks5Option) *Socks5 {
return &Socks5{
Base: &Base{
- name: option.Name,
- addr: net.JoinHostPort(option.Server, strconv.Itoa(option.Port)),
- tp: C.Socks5,
- udp: option.UDP,
+ name: option.Name,
+ addr: net.JoinHostPort(option.Server, strconv.Itoa(option.Port)),
+ tp: C.Socks5,
+ udp: option.UDP,
+ iface: option.Interface,
},
user: option.UserName,
pass: option.Password,
diff --git a/adapter/outbound/trojan.go b/adapter/outbound/trojan.go
index 8bea0cc8f..35dbea1e0 100644
--- a/adapter/outbound/trojan.go
+++ b/adapter/outbound/trojan.go
@@ -28,6 +28,7 @@ type Trojan struct {
}
type TrojanOption struct {
+ BasicOption
Name string `proxy:"name"`
Server string `proxy:"server"`
Port int `proxy:"port"`
@@ -86,9 +87,9 @@ func (t *Trojan) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error)
}
// DialContext implements C.ProxyAdapter
-func (t *Trojan) DialContext(ctx context.Context, metadata *C.Metadata) (_ C.Conn, err error) {
+func (t *Trojan) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (_ C.Conn, err error) {
// gun transport
- if t.transport != nil {
+ if t.transport != nil && len(opts) == 0 {
c, err := gun.StreamGunWithTransport(t.transport, t.gunConfig)
if err != nil {
return nil, err
@@ -102,7 +103,7 @@ func (t *Trojan) DialContext(ctx context.Context, metadata *C.Metadata) (_ C.Con
return NewConn(c, t), nil
}
- c, err := dialer.DialContext(ctx, "tcp", t.addr)
+ c, err := dialer.DialContext(ctx, "tcp", t.addr, t.Base.DialOptions(opts...)...)
if err != nil {
return nil, fmt.Errorf("%s connect error: %w", t.addr, err)
}
@@ -119,18 +120,18 @@ func (t *Trojan) DialContext(ctx context.Context, metadata *C.Metadata) (_ C.Con
}
// ListenPacketContext implements C.ProxyAdapter
-func (t *Trojan) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (_ C.PacketConn, err error) {
+func (t *Trojan) ListenPacketContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (_ C.PacketConn, err error) {
var c net.Conn
// grpc transport
- if t.transport != nil {
+ if t.transport != nil && len(opts) == 0 {
c, err = gun.StreamGunWithTransport(t.transport, t.gunConfig)
if err != nil {
return nil, fmt.Errorf("%s connect error: %w", t.addr, err)
}
defer safeConnClose(c, err)
} else {
- c, err = dialer.DialContext(ctx, "tcp", t.addr)
+ c, err = dialer.DialContext(ctx, "tcp", t.addr, t.Base.DialOptions(opts...)...)
if err != nil {
return nil, fmt.Errorf("%s connect error: %w", t.addr, err)
}
@@ -167,10 +168,11 @@ func NewTrojan(option TrojanOption) (*Trojan, error) {
t := &Trojan{
Base: &Base{
- name: option.Name,
- addr: addr,
- tp: C.Trojan,
- udp: option.UDP,
+ name: option.Name,
+ addr: addr,
+ tp: C.Trojan,
+ udp: option.UDP,
+ iface: option.Interface,
},
instance: trojan.New(tOption),
option: &option,
@@ -178,7 +180,7 @@ func NewTrojan(option TrojanOption) (*Trojan, error) {
if option.Network == "grpc" {
dialFn := func(network, addr string) (net.Conn, error) {
- c, err := dialer.DialContext(context.Background(), "tcp", t.addr)
+ c, err := dialer.DialContext(context.Background(), "tcp", t.addr, t.Base.DialOptions()...)
if err != nil {
return nil, fmt.Errorf("%s connect error: %s", t.addr, err.Error())
}
diff --git a/adapter/outbound/vmess.go b/adapter/outbound/vmess.go
index b4db00ad9..6746eb518 100644
--- a/adapter/outbound/vmess.go
+++ b/adapter/outbound/vmess.go
@@ -31,6 +31,7 @@ type Vmess struct {
}
type VmessOption struct {
+ BasicOption
Name string `proxy:"name"`
Server string `proxy:"server"`
Port int `proxy:"port"`
@@ -195,9 +196,9 @@ func (v *Vmess) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {
}
// DialContext implements C.ProxyAdapter
-func (v *Vmess) DialContext(ctx context.Context, metadata *C.Metadata) (_ C.Conn, err error) {
+func (v *Vmess) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (_ C.Conn, err error) {
// gun transport
- if v.transport != nil {
+ if v.transport != nil && len(opts) == 0 {
c, err := gun.StreamGunWithTransport(v.transport, v.gunConfig)
if err != nil {
return nil, err
@@ -212,7 +213,7 @@ func (v *Vmess) DialContext(ctx context.Context, metadata *C.Metadata) (_ C.Conn
return NewConn(c, v), nil
}
- c, err := dialer.DialContext(ctx, "tcp", v.addr)
+ c, err := dialer.DialContext(ctx, "tcp", v.addr, v.Base.DialOptions(opts...)...)
if err != nil {
return nil, fmt.Errorf("%s connect error: %s", v.addr, err.Error())
}
@@ -224,7 +225,7 @@ func (v *Vmess) DialContext(ctx context.Context, metadata *C.Metadata) (_ C.Conn
}
// ListenPacketContext implements C.ProxyAdapter
-func (v *Vmess) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (_ C.PacketConn, err error) {
+func (v *Vmess) ListenPacketContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (_ C.PacketConn, err error) {
// vmess use stream-oriented udp with a special address, so we needs a net.UDPAddr
if !metadata.Resolved() {
ip, err := resolver.ResolveIP(metadata.Host)
@@ -236,7 +237,7 @@ func (v *Vmess) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (
var c net.Conn
// gun transport
- if v.transport != nil {
+ if v.transport != nil && len(opts) == 0 {
c, err = gun.StreamGunWithTransport(v.transport, v.gunConfig)
if err != nil {
return nil, err
@@ -245,7 +246,7 @@ func (v *Vmess) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (
c, err = v.client.StreamConn(c, parseVmessAddr(metadata))
} else {
- c, err = dialer.DialContext(ctx, "tcp", v.addr)
+ c, err = dialer.DialContext(ctx, "tcp", v.addr, v.Base.DialOptions(opts...)...)
if err != nil {
return nil, fmt.Errorf("%s connect error: %s", v.addr, err.Error())
}
@@ -285,10 +286,11 @@ func NewVmess(option VmessOption) (*Vmess, error) {
v := &Vmess{
Base: &Base{
- name: option.Name,
- addr: net.JoinHostPort(option.Server, strconv.Itoa(option.Port)),
- tp: C.Vmess,
- udp: option.UDP,
+ name: option.Name,
+ addr: net.JoinHostPort(option.Server, strconv.Itoa(option.Port)),
+ tp: C.Vmess,
+ udp: option.UDP,
+ iface: option.Interface,
},
client: client,
option: &option,
@@ -301,7 +303,7 @@ func NewVmess(option VmessOption) (*Vmess, error) {
}
case "grpc":
dialFn := func(network, addr string) (net.Conn, error) {
- c, err := dialer.DialContext(context.Background(), "tcp", v.addr)
+ c, err := dialer.DialContext(context.Background(), "tcp", v.addr, v.Base.DialOptions()...)
if err != nil {
return nil, fmt.Errorf("%s connect error: %s", v.addr, err.Error())
}
diff --git a/adapter/outboundgroup/fallback.go b/adapter/outboundgroup/fallback.go
index 3221b5527..2f9f0887f 100644
--- a/adapter/outboundgroup/fallback.go
+++ b/adapter/outboundgroup/fallback.go
@@ -6,6 +6,7 @@ import (
"github.com/Dreamacro/clash/adapter/outbound"
"github.com/Dreamacro/clash/common/singledo"
+ "github.com/Dreamacro/clash/component/dialer"
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/constant/provider"
)
@@ -23,9 +24,9 @@ func (f *Fallback) Now() string {
}
// DialContext implements C.ProxyAdapter
-func (f *Fallback) DialContext(ctx context.Context, metadata *C.Metadata) (C.Conn, error) {
+func (f *Fallback) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.Conn, error) {
proxy := f.findAliveProxy(true)
- c, err := proxy.DialContext(ctx, metadata)
+ c, err := proxy.DialContext(ctx, metadata, f.Base.DialOptions(opts...)...)
if err == nil {
c.AppendToChains(f)
}
@@ -33,9 +34,9 @@ func (f *Fallback) DialContext(ctx context.Context, metadata *C.Metadata) (C.Con
}
// ListenPacketContext implements C.ProxyAdapter
-func (f *Fallback) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (C.PacketConn, error) {
+func (f *Fallback) ListenPacketContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.PacketConn, error) {
proxy := f.findAliveProxy(true)
- pc, err := proxy.ListenPacketContext(ctx, metadata)
+ pc, err := proxy.ListenPacketContext(ctx, metadata, f.Base.DialOptions(opts...)...)
if err == nil {
pc.AppendToChains(f)
}
@@ -90,11 +91,15 @@ func (f *Fallback) findAliveProxy(touch bool) C.Proxy {
return proxies[0]
}
-func NewFallback(options *GroupCommonOption, providers []provider.ProxyProvider) *Fallback {
+func NewFallback(option *GroupCommonOption, providers []provider.ProxyProvider) *Fallback {
return &Fallback{
- Base: outbound.NewBase(options.Name, "", C.Fallback, false),
+ Base: outbound.NewBase(outbound.BaseOption{
+ Name: option.Name,
+ Type: C.Fallback,
+ Interface: option.Interface,
+ }),
single: singledo.NewSingle(defaultGetProxiesDuration),
providers: providers,
- disableUDP: options.DisableUDP,
+ disableUDP: option.DisableUDP,
}
}
diff --git a/adapter/outboundgroup/loadbalance.go b/adapter/outboundgroup/loadbalance.go
index fb2840102..df1c2ba49 100644
--- a/adapter/outboundgroup/loadbalance.go
+++ b/adapter/outboundgroup/loadbalance.go
@@ -10,6 +10,7 @@ import (
"github.com/Dreamacro/clash/adapter/outbound"
"github.com/Dreamacro/clash/common/murmur3"
"github.com/Dreamacro/clash/common/singledo"
+ "github.com/Dreamacro/clash/component/dialer"
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/constant/provider"
@@ -69,7 +70,7 @@ func jumpHash(key uint64, buckets int32) int32 {
}
// DialContext implements C.ProxyAdapter
-func (lb *LoadBalance) DialContext(ctx context.Context, metadata *C.Metadata) (c C.Conn, err error) {
+func (lb *LoadBalance) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (c C.Conn, err error) {
defer func() {
if err == nil {
c.AppendToChains(lb)
@@ -78,12 +79,12 @@ func (lb *LoadBalance) DialContext(ctx context.Context, metadata *C.Metadata) (c
proxy := lb.Unwrap(metadata)
- c, err = proxy.DialContext(ctx, metadata)
+ c, err = proxy.DialContext(ctx, metadata, lb.Base.DialOptions(opts...)...)
return
}
// ListenPacketContext implements C.ProxyAdapter
-func (lb *LoadBalance) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (pc C.PacketConn, err error) {
+func (lb *LoadBalance) ListenPacketContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (pc C.PacketConn, err error) {
defer func() {
if err == nil {
pc.AppendToChains(lb)
@@ -91,7 +92,7 @@ func (lb *LoadBalance) ListenPacketContext(ctx context.Context, metadata *C.Meta
}()
proxy := lb.Unwrap(metadata)
- return proxy.ListenPacketContext(ctx, metadata)
+ return proxy.ListenPacketContext(ctx, metadata, lb.Base.DialOptions(opts...)...)
}
// SupportUDP implements C.ProxyAdapter
@@ -158,7 +159,7 @@ func (lb *LoadBalance) MarshalJSON() ([]byte, error) {
})
}
-func NewLoadBalance(options *GroupCommonOption, providers []provider.ProxyProvider, strategy string) (lb *LoadBalance, err error) {
+func NewLoadBalance(option *GroupCommonOption, providers []provider.ProxyProvider, strategy string) (lb *LoadBalance, err error) {
var strategyFn strategyFn
switch strategy {
case "consistent-hashing":
@@ -169,10 +170,14 @@ func NewLoadBalance(options *GroupCommonOption, providers []provider.ProxyProvid
return nil, fmt.Errorf("%w: %s", errStrategy, strategy)
}
return &LoadBalance{
- Base: outbound.NewBase(options.Name, "", C.LoadBalance, false),
+ Base: outbound.NewBase(outbound.BaseOption{
+ Name: option.Name,
+ Type: C.LoadBalance,
+ Interface: option.Interface,
+ }),
single: singledo.NewSingle(defaultGetProxiesDuration),
providers: providers,
strategyFn: strategyFn,
- disableUDP: options.DisableUDP,
+ disableUDP: option.DisableUDP,
}, nil
}
diff --git a/adapter/outboundgroup/parser.go b/adapter/outboundgroup/parser.go
index cf97579f9..190d333de 100644
--- a/adapter/outboundgroup/parser.go
+++ b/adapter/outboundgroup/parser.go
@@ -4,6 +4,7 @@ import (
"errors"
"fmt"
+ "github.com/Dreamacro/clash/adapter/outbound"
"github.com/Dreamacro/clash/adapter/provider"
"github.com/Dreamacro/clash/common/structure"
C "github.com/Dreamacro/clash/constant"
@@ -19,6 +20,7 @@ var (
)
type GroupCommonOption struct {
+ outbound.BasicOption
Name string `group:"name"`
Type string `group:"type"`
Proxies []string `group:"proxies,omitempty"`
diff --git a/adapter/outboundgroup/relay.go b/adapter/outboundgroup/relay.go
index 78410a449..4ec4ffacf 100644
--- a/adapter/outboundgroup/relay.go
+++ b/adapter/outboundgroup/relay.go
@@ -19,7 +19,7 @@ type Relay struct {
}
// DialContext implements C.ProxyAdapter
-func (r *Relay) DialContext(ctx context.Context, metadata *C.Metadata) (C.Conn, error) {
+func (r *Relay) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.Conn, error) {
var proxies []C.Proxy
for _, proxy := range r.proxies(metadata, true) {
if proxy.Type() != C.Direct {
@@ -29,15 +29,15 @@ func (r *Relay) DialContext(ctx context.Context, metadata *C.Metadata) (C.Conn,
switch len(proxies) {
case 0:
- return outbound.NewDirect().DialContext(ctx, metadata)
+ return outbound.NewDirect().DialContext(ctx, metadata, r.Base.DialOptions(opts...)...)
case 1:
- return proxies[0].DialContext(ctx, metadata)
+ return proxies[0].DialContext(ctx, metadata, r.Base.DialOptions(opts...)...)
}
first := proxies[0]
last := proxies[len(proxies)-1]
- c, err := dialer.DialContext(ctx, "tcp", first.Addr())
+ c, err := dialer.DialContext(ctx, "tcp", first.Addr(), r.Base.DialOptions(opts...)...)
if err != nil {
return nil, fmt.Errorf("%s connect error: %w", first.Addr(), err)
}
@@ -100,9 +100,13 @@ func (r *Relay) proxies(metadata *C.Metadata, touch bool) []C.Proxy {
return proxies
}
-func NewRelay(options *GroupCommonOption, providers []provider.ProxyProvider) *Relay {
+func NewRelay(option *GroupCommonOption, providers []provider.ProxyProvider) *Relay {
return &Relay{
- Base: outbound.NewBase(options.Name, "", C.Relay, false),
+ Base: outbound.NewBase(outbound.BaseOption{
+ Name: option.Name,
+ Type: C.Relay,
+ Interface: option.Interface,
+ }),
single: singledo.NewSingle(defaultGetProxiesDuration),
providers: providers,
}
diff --git a/adapter/outboundgroup/selector.go b/adapter/outboundgroup/selector.go
index 008e8af8d..4ec67cd1d 100644
--- a/adapter/outboundgroup/selector.go
+++ b/adapter/outboundgroup/selector.go
@@ -7,6 +7,7 @@ import (
"github.com/Dreamacro/clash/adapter/outbound"
"github.com/Dreamacro/clash/common/singledo"
+ "github.com/Dreamacro/clash/component/dialer"
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/constant/provider"
)
@@ -20,8 +21,8 @@ type Selector struct {
}
// DialContext implements C.ProxyAdapter
-func (s *Selector) DialContext(ctx context.Context, metadata *C.Metadata) (C.Conn, error) {
- c, err := s.selectedProxy(true).DialContext(ctx, metadata)
+func (s *Selector) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.Conn, error) {
+ c, err := s.selectedProxy(true).DialContext(ctx, metadata, s.Base.DialOptions(opts...)...)
if err == nil {
c.AppendToChains(s)
}
@@ -29,8 +30,8 @@ func (s *Selector) DialContext(ctx context.Context, metadata *C.Metadata) (C.Con
}
// ListenPacketContext implements C.ProxyAdapter
-func (s *Selector) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (C.PacketConn, error) {
- pc, err := s.selectedProxy(true).ListenPacketContext(ctx, metadata)
+func (s *Selector) ListenPacketContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.PacketConn, error) {
+ pc, err := s.selectedProxy(true).ListenPacketContext(ctx, metadata, s.Base.DialOptions(opts...)...)
if err == nil {
pc.AppendToChains(s)
}
@@ -96,13 +97,17 @@ func (s *Selector) selectedProxy(touch bool) C.Proxy {
return elm.(C.Proxy)
}
-func NewSelector(options *GroupCommonOption, providers []provider.ProxyProvider) *Selector {
+func NewSelector(option *GroupCommonOption, providers []provider.ProxyProvider) *Selector {
selected := providers[0].Proxies()[0].Name()
return &Selector{
- Base: outbound.NewBase(options.Name, "", C.Selector, false),
+ Base: outbound.NewBase(outbound.BaseOption{
+ Name: option.Name,
+ Type: C.Selector,
+ Interface: option.Interface,
+ }),
single: singledo.NewSingle(defaultGetProxiesDuration),
providers: providers,
selected: selected,
- disableUDP: options.DisableUDP,
+ disableUDP: option.DisableUDP,
}
}
diff --git a/adapter/outboundgroup/urltest.go b/adapter/outboundgroup/urltest.go
index b27f12a44..6866db0df 100644
--- a/adapter/outboundgroup/urltest.go
+++ b/adapter/outboundgroup/urltest.go
@@ -7,6 +7,7 @@ import (
"github.com/Dreamacro/clash/adapter/outbound"
"github.com/Dreamacro/clash/common/singledo"
+ "github.com/Dreamacro/clash/component/dialer"
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/constant/provider"
)
@@ -34,8 +35,8 @@ func (u *URLTest) Now() string {
}
// DialContext implements C.ProxyAdapter
-func (u *URLTest) DialContext(ctx context.Context, metadata *C.Metadata) (c C.Conn, err error) {
- c, err = u.fast(true).DialContext(ctx, metadata)
+func (u *URLTest) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (c C.Conn, err error) {
+ c, err = u.fast(true).DialContext(ctx, metadata, u.Base.DialOptions(opts...)...)
if err == nil {
c.AppendToChains(u)
}
@@ -43,8 +44,8 @@ func (u *URLTest) DialContext(ctx context.Context, metadata *C.Metadata) (c C.Co
}
// ListenPacketContext implements C.ProxyAdapter
-func (u *URLTest) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (C.PacketConn, error) {
- pc, err := u.fast(true).ListenPacketContext(ctx, metadata)
+func (u *URLTest) ListenPacketContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.PacketConn, error) {
+ pc, err := u.fast(true).ListenPacketContext(ctx, metadata, u.Base.DialOptions(opts...)...)
if err == nil {
pc.AppendToChains(u)
}
@@ -133,13 +134,17 @@ func parseURLTestOption(config map[string]interface{}) []urlTestOption {
return opts
}
-func NewURLTest(commonOptions *GroupCommonOption, providers []provider.ProxyProvider, options ...urlTestOption) *URLTest {
+func NewURLTest(option *GroupCommonOption, providers []provider.ProxyProvider, options ...urlTestOption) *URLTest {
urlTest := &URLTest{
- Base: outbound.NewBase(commonOptions.Name, "", C.URLTest, false),
+ Base: outbound.NewBase(outbound.BaseOption{
+ Name: option.Name,
+ Type: C.URLTest,
+ Interface: option.Interface,
+ }),
single: singledo.NewSingle(defaultGetProxiesDuration),
fastSingle: singledo.NewSingle(time.Second * 10),
providers: providers,
- disableUDP: commonOptions.DisableUDP,
+ disableUDP: option.DisableUDP,
}
for _, option := range options {
diff --git a/component/dialer/dialer.go b/component/dialer/dialer.go
index 75bbb8687..87b62dd65 100644
--- a/component/dialer/dialer.go
+++ b/component/dialer/dialer.go
@@ -36,12 +36,12 @@ func DialContext(ctx context.Context, network, address string, options ...Option
}
func ListenPacket(ctx context.Context, network, address string, options ...Option) (net.PacketConn, error) {
- cfg := &config{}
+ cfg := &option{
+ interfaceName: DefaultInterface.Load(),
+ }
- if !cfg.skipDefault {
- for _, o := range DefaultOptions {
- o(cfg)
- }
+ for _, o := range DefaultOptions {
+ o(cfg)
}
for _, o := range options {
@@ -64,12 +64,12 @@ func ListenPacket(ctx context.Context, network, address string, options ...Optio
}
func dialContext(ctx context.Context, network string, destination net.IP, port string, options []Option) (net.Conn, error) {
- opt := &config{}
+ opt := &option{
+ interfaceName: DefaultInterface.Load(),
+ }
- if !opt.skipDefault {
- for _, o := range DefaultOptions {
- o(opt)
- }
+ for _, o := range DefaultOptions {
+ o(opt)
}
for _, o := range options {
diff --git a/component/dialer/options.go b/component/dialer/options.go
index 33083864a..96d9eb751 100644
--- a/component/dialer/options.go
+++ b/component/dialer/options.go
@@ -1,29 +1,27 @@
package dialer
-var DefaultOptions []Option
+import "go.uber.org/atomic"
-type config struct {
- skipDefault bool
+var (
+ DefaultOptions []Option
+ DefaultInterface = atomic.NewString("")
+)
+
+type option struct {
interfaceName string
addrReuse bool
}
-type Option func(opt *config)
+type Option func(opt *option)
func WithInterface(name string) Option {
- return func(opt *config) {
+ return func(opt *option) {
opt.interfaceName = name
}
}
func WithAddrReuse(reuse bool) Option {
- return func(opt *config) {
+ return func(opt *option) {
opt.addrReuse = reuse
}
}
-
-func WithSkipDefault(skip bool) Option {
- return func(opt *config) {
- opt.skipDefault = skip
- }
-}
diff --git a/constant/adapters.go b/constant/adapters.go
index 2f7006e96..59fde9601 100644
--- a/constant/adapters.go
+++ b/constant/adapters.go
@@ -5,6 +5,8 @@ import (
"fmt"
"net"
"time"
+
+ "github.com/Dreamacro/clash/component/dialer"
)
// Adapter Type
@@ -90,9 +92,9 @@ type ProxyAdapter interface {
// DialContext return a C.Conn with protocol which
// contains multiplexing-related reuse logic (if any)
- DialContext(ctx context.Context, metadata *Metadata) (Conn, error)
+ DialContext(ctx context.Context, metadata *Metadata, opts ...dialer.Option) (Conn, error)
- ListenPacketContext(ctx context.Context, metadata *Metadata) (PacketConn, error)
+ ListenPacketContext(ctx context.Context, metadata *Metadata, opts ...dialer.Option) (PacketConn, error)
// Unwrap extracts the proxy from a proxy-group. It returns nil when nothing to extract.
Unwrap(metadata *Metadata) Proxy
diff --git a/hub/executor/executor.go b/hub/executor/executor.go
index ca8ee95de..59f948817 100644
--- a/hub/executor/executor.go
+++ b/hub/executor/executor.go
@@ -168,11 +168,7 @@ func updateGeneral(general *config.General, force bool) {
tunnel.SetMode(general.Mode)
resolver.DisableIPv6 = !general.IPv6
- if general.Interface != "" {
- dialer.DefaultOptions = []dialer.Option{dialer.WithInterface(general.Interface)}
- } else {
- dialer.DefaultOptions = nil
- }
+ dialer.DefaultInterface.Store(general.Interface)
iface.FlushCache()
From d40e5e4fe6c11311ee1de82779a985c3ca47d03a Mon Sep 17 00:00:00 2001
From: Dreamacro <8615343+Dreamacro@users.noreply.github.com>
Date: Mon, 8 Nov 2021 00:31:08 +0800
Subject: [PATCH 92/96] Fix: codeql alerts
---
adapter/outbound/snell.go | 4 ++--
adapter/outbound/util.go | 2 +-
adapter/outbound/vmess.go | 2 +-
component/dialer/bind_others.go | 4 ++--
constant/metadata.go | 4 ++--
rule/port.go | 2 +-
6 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/adapter/outbound/snell.go b/adapter/outbound/snell.go
index 40dcf0664..d0a26ecc1 100644
--- a/adapter/outbound/snell.go
+++ b/adapter/outbound/snell.go
@@ -52,7 +52,7 @@ func streamConn(c net.Conn, option streamOption) *snell.Snell {
// StreamConn implements C.ProxyAdapter
func (s *Snell) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {
c = streamConn(c, streamOption{s.psk, s.version, s.addr, s.obfsOption})
- port, _ := strconv.Atoi(metadata.DstPort)
+ port, _ := strconv.ParseInt(metadata.DstPort, 10, 16)
err := snell.WriteHeader(c, metadata.String(), uint(port), s.version)
return c, err
}
@@ -65,7 +65,7 @@ func (s *Snell) DialContext(ctx context.Context, metadata *C.Metadata, opts ...d
return nil, err
}
- port, _ := strconv.Atoi(metadata.DstPort)
+ port, _ := strconv.ParseUint(metadata.DstPort, 10, 16)
if err = snell.WriteHeader(c, metadata.String(), uint(port), s.version); err != nil {
c.Close()
return nil, err
diff --git a/adapter/outbound/util.go b/adapter/outbound/util.go
index 0e1d4c8e5..b376522fa 100644
--- a/adapter/outbound/util.go
+++ b/adapter/outbound/util.go
@@ -21,7 +21,7 @@ func tcpKeepAlive(c net.Conn) {
func serializesSocksAddr(metadata *C.Metadata) []byte {
var buf [][]byte
aType := uint8(metadata.AddrType)
- p, _ := strconv.Atoi(metadata.DstPort)
+ p, _ := strconv.ParseUint(metadata.DstPort, 10, 16)
port := []byte{uint8(p >> 8), uint8(p & 0xff)}
switch metadata.AddrType {
case socks5.AtypDomainName:
diff --git a/adapter/outbound/vmess.go b/adapter/outbound/vmess.go
index 6746eb518..99ea531ca 100644
--- a/adapter/outbound/vmess.go
+++ b/adapter/outbound/vmess.go
@@ -353,7 +353,7 @@ func parseVmessAddr(metadata *C.Metadata) *vmess.DstAddr {
copy(addr[1:], []byte(metadata.Host))
}
- port, _ := strconv.Atoi(metadata.DstPort)
+ port, _ := strconv.ParseUint(metadata.DstPort, 10, 16)
return &vmess.DstAddr{
UDP: metadata.NetWork == C.UDP,
AddrType: addrType,
diff --git a/component/dialer/bind_others.go b/component/dialer/bind_others.go
index 7f1923aa2..e94946739 100644
--- a/component/dialer/bind_others.go
+++ b/component/dialer/bind_others.go
@@ -62,7 +62,7 @@ func bindIfaceToDialer(ifaceName string, dialer *net.Dialer, network string, des
if dialer.LocalAddr != nil {
_, port, err := net.SplitHostPort(dialer.LocalAddr.String())
if err == nil {
- local, _ = strconv.Atoi(port)
+ local, _ = strconv.ParseInt(port, 10, 16)
}
}
@@ -82,7 +82,7 @@ func bindIfaceToListenConfig(ifaceName string, _ *net.ListenConfig, network, add
port = "0"
}
- local, _ := strconv.Atoi(port)
+ local, _ := strconv.ParseInt(port, 10, 16)
addr, err := lookupLocalAddr(ifaceName, network, nil, local)
if err != nil {
diff --git a/constant/metadata.go b/constant/metadata.go
index 822b4714d..9cc49973f 100644
--- a/constant/metadata.go
+++ b/constant/metadata.go
@@ -107,10 +107,10 @@ func (m *Metadata) UDPAddr() *net.UDPAddr {
if m.NetWork != UDP || m.DstIP == nil {
return nil
}
- port, _ := strconv.Atoi(m.DstPort)
+ port, _ := strconv.ParseInt(m.DstPort, 10, 16)
return &net.UDPAddr{
IP: m.DstIP,
- Port: port,
+ Port: int(port),
}
}
diff --git a/rule/port.go b/rule/port.go
index 281a4c4df..b6e8abb1c 100644
--- a/rule/port.go
+++ b/rule/port.go
@@ -39,7 +39,7 @@ func (p *Port) ShouldResolveIP() bool {
}
func NewPort(port string, adapter string, isSource bool) (*Port, error) {
- _, err := strconv.Atoi(port)
+ _, err := strconv.ParseUint(port, 10, 16)
if err != nil {
return nil, errPayload
}
From e622d8dd38086f96c49726f4d6572135ce9847f6 Mon Sep 17 00:00:00 2001
From: Dreamacro <8615343+Dreamacro@users.noreply.github.com>
Date: Mon, 8 Nov 2021 13:29:37 +0800
Subject: [PATCH 93/96] Fix: parse dial interface option
---
adapter/outbound/base.go | 2 +-
common/structure/structure.go | 6 +++
common/structure/structure_test.go | 64 ++++++++++++++----------------
3 files changed, 37 insertions(+), 35 deletions(-)
diff --git a/adapter/outbound/base.go b/adapter/outbound/base.go
index e028cd4e8..15eedd1ae 100644
--- a/adapter/outbound/base.go
+++ b/adapter/outbound/base.go
@@ -70,7 +70,7 @@ func (b *Base) DialOptions(opts ...dialer.Option) []dialer.Option {
}
type BasicOption struct {
- Interface string `proxy:"interface-name"`
+ Interface string `proxy:"interface-name,omitempty" group:"interface-name,omitempty"`
}
type BaseOption struct {
diff --git a/common/structure/structure.go b/common/structure/structure.go
index 75579ffcb..07043abc4 100644
--- a/common/structure/structure.go
+++ b/common/structure/structure.go
@@ -37,6 +37,12 @@ func (d *Decoder) Decode(src map[string]interface{}, dst interface{}) error {
v := reflect.ValueOf(dst).Elem()
for idx := 0; idx < v.NumField(); idx++ {
field := t.Field(idx)
+ if field.Anonymous {
+ if err := d.decodeStruct(field.Name, src, v.Field(idx)); err != nil {
+ return err
+ }
+ continue
+ }
tag := field.Tag.Get(d.option.TagName)
str := strings.SplitN(tag, ",", 2)
diff --git a/common/structure/structure_test.go b/common/structure/structure_test.go
index 0feef28e8..69268fa60 100644
--- a/common/structure/structure_test.go
+++ b/common/structure/structure_test.go
@@ -1,8 +1,9 @@
package structure
import (
- "reflect"
"testing"
+
+ "github.com/stretchr/testify/assert"
)
var (
@@ -39,12 +40,8 @@ func TestStructure_Basic(t *testing.T) {
s := &Baz{}
err := decoder.Decode(rawMap, s)
- if err != nil {
- t.Fatal(err.Error())
- }
- if !reflect.DeepEqual(s, goal) {
- t.Fatalf("bad: %#v", s)
- }
+ assert.Nil(t, err)
+ assert.Equal(t, goal, s)
}
func TestStructure_Slice(t *testing.T) {
@@ -60,12 +57,8 @@ func TestStructure_Slice(t *testing.T) {
s := &BazSlice{}
err := decoder.Decode(rawMap, s)
- if err != nil {
- t.Fatal(err.Error())
- }
- if !reflect.DeepEqual(s, goal) {
- t.Fatalf("bad: %#v", s)
- }
+ assert.Nil(t, err)
+ assert.Equal(t, goal, s)
}
func TestStructure_Optional(t *testing.T) {
@@ -79,12 +72,8 @@ func TestStructure_Optional(t *testing.T) {
s := &BazOptional{}
err := decoder.Decode(rawMap, s)
- if err != nil {
- t.Fatal(err.Error())
- }
- if !reflect.DeepEqual(s, goal) {
- t.Fatalf("bad: %#v", s)
- }
+ assert.Nil(t, err)
+ assert.Equal(t, goal, s)
}
func TestStructure_MissingKey(t *testing.T) {
@@ -94,18 +83,14 @@ func TestStructure_MissingKey(t *testing.T) {
s := &Baz{}
err := decoder.Decode(rawMap, s)
- if err == nil {
- t.Fatalf("should throw error: %#v", s)
- }
+ assert.NotNilf(t, err, "should throw error: %#v", s)
}
func TestStructure_ParamError(t *testing.T) {
rawMap := map[string]interface{}{}
s := Baz{}
err := decoder.Decode(rawMap, s)
- if err == nil {
- t.Fatalf("should throw error: %#v", s)
- }
+ assert.NotNilf(t, err, "should throw error: %#v", s)
}
func TestStructure_SliceTypeError(t *testing.T) {
@@ -116,9 +101,7 @@ func TestStructure_SliceTypeError(t *testing.T) {
s := &BazSlice{}
err := decoder.Decode(rawMap, s)
- if err == nil {
- t.Fatalf("should throw error: %#v", s)
- }
+ assert.NotNilf(t, err, "should throw error: %#v", s)
}
func TestStructure_WeakType(t *testing.T) {
@@ -134,10 +117,23 @@ func TestStructure_WeakType(t *testing.T) {
s := &BazSlice{}
err := weakTypeDecoder.Decode(rawMap, s)
- if err != nil {
- t.Fatal(err.Error())
- }
- if !reflect.DeepEqual(s, goal) {
- t.Fatalf("bad: %#v", s)
- }
+ assert.Nil(t, err)
+ assert.Equal(t, goal, s)
+}
+
+func TestStructure_Nest(t *testing.T) {
+ rawMap := map[string]interface{}{
+ "foo": 1,
+ }
+
+ goal := BazOptional{
+ Foo: 1,
+ }
+
+ s := &struct {
+ BazOptional
+ }{}
+ err := decoder.Decode(rawMap, s)
+ assert.Nil(t, err)
+ assert.Equal(t, s.BazOptional, goal)
}
From bd2ea2b917aa84b7b91272a8197555e4710f4cd7 Mon Sep 17 00:00:00 2001
From: bobo liu <7552030+fakeboboliu@users.noreply.github.com>
Date: Mon, 8 Nov 2021 16:59:48 +0800
Subject: [PATCH 94/96] Feature: mark on socket (#1705)
---
adapter/outbound/base.go | 20 +++++++++----
adapter/outbound/socks5.go | 2 +-
adapter/outboundgroup/fallback.go | 7 +++--
adapter/outboundgroup/loadbalance.go | 7 +++--
adapter/outboundgroup/relay.go | 7 +++--
adapter/outboundgroup/selector.go | 7 +++--
adapter/outboundgroup/urltest.go | 7 +++--
component/dialer/dialer.go | 6 ++++
component/dialer/mark_linux.go | 44 ++++++++++++++++++++++++++++
component/dialer/mark_nonlinux.go | 27 +++++++++++++++++
component/dialer/options.go | 7 +++++
11 files changed, 119 insertions(+), 22 deletions(-)
create mode 100644 component/dialer/mark_linux.go
create mode 100644 component/dialer/mark_nonlinux.go
diff --git a/adapter/outbound/base.go b/adapter/outbound/base.go
index 15eedd1ae..e9119415e 100644
--- a/adapter/outbound/base.go
+++ b/adapter/outbound/base.go
@@ -16,6 +16,7 @@ type Base struct {
iface string
tp C.AdapterType
udp bool
+ rmark int
}
// Name implements C.ProxyAdapter
@@ -66,19 +67,25 @@ func (b *Base) DialOptions(opts ...dialer.Option) []dialer.Option {
opts = append(opts, dialer.WithInterface(b.iface))
}
+ if b.rmark != 0 {
+ opts = append(opts, dialer.WithRoutingMark(b.rmark))
+ }
+
return opts
}
type BasicOption struct {
- Interface string `proxy:"interface-name,omitempty" group:"interface-name,omitempty"`
+ Interface string `proxy:"interface-name,omitempty" group:"interface-name,omitempty"`
+ RoutingMark int `proxy:"routing-mark,omitempty" group:"routing-mark,omitempty"`
}
type BaseOption struct {
- Name string
- Addr string
- Type C.AdapterType
- UDP bool
- Interface string
+ Name string
+ Addr string
+ Type C.AdapterType
+ UDP bool
+ Interface string
+ RoutingMark int
}
func NewBase(opt BaseOption) *Base {
@@ -88,6 +95,7 @@ func NewBase(opt BaseOption) *Base {
tp: opt.Type,
udp: opt.UDP,
iface: opt.Interface,
+ rmark: opt.RoutingMark,
}
}
diff --git a/adapter/outbound/socks5.go b/adapter/outbound/socks5.go
index 874da9f14..d81c76140 100644
--- a/adapter/outbound/socks5.go
+++ b/adapter/outbound/socks5.go
@@ -24,7 +24,7 @@ type Socks5 struct {
}
type Socks5Option struct {
- *BaseOption
+ BasicOption
Name string `proxy:"name"`
Server string `proxy:"server"`
Port int `proxy:"port"`
diff --git a/adapter/outboundgroup/fallback.go b/adapter/outboundgroup/fallback.go
index 2f9f0887f..b08af487f 100644
--- a/adapter/outboundgroup/fallback.go
+++ b/adapter/outboundgroup/fallback.go
@@ -94,9 +94,10 @@ func (f *Fallback) findAliveProxy(touch bool) C.Proxy {
func NewFallback(option *GroupCommonOption, providers []provider.ProxyProvider) *Fallback {
return &Fallback{
Base: outbound.NewBase(outbound.BaseOption{
- Name: option.Name,
- Type: C.Fallback,
- Interface: option.Interface,
+ Name: option.Name,
+ Type: C.Fallback,
+ Interface: option.Interface,
+ RoutingMark: option.RoutingMark,
}),
single: singledo.NewSingle(defaultGetProxiesDuration),
providers: providers,
diff --git a/adapter/outboundgroup/loadbalance.go b/adapter/outboundgroup/loadbalance.go
index df1c2ba49..26c8052ad 100644
--- a/adapter/outboundgroup/loadbalance.go
+++ b/adapter/outboundgroup/loadbalance.go
@@ -171,9 +171,10 @@ func NewLoadBalance(option *GroupCommonOption, providers []provider.ProxyProvide
}
return &LoadBalance{
Base: outbound.NewBase(outbound.BaseOption{
- Name: option.Name,
- Type: C.LoadBalance,
- Interface: option.Interface,
+ Name: option.Name,
+ Type: C.LoadBalance,
+ Interface: option.Interface,
+ RoutingMark: option.RoutingMark,
}),
single: singledo.NewSingle(defaultGetProxiesDuration),
providers: providers,
diff --git a/adapter/outboundgroup/relay.go b/adapter/outboundgroup/relay.go
index 4ec4ffacf..393a69bb9 100644
--- a/adapter/outboundgroup/relay.go
+++ b/adapter/outboundgroup/relay.go
@@ -103,9 +103,10 @@ func (r *Relay) proxies(metadata *C.Metadata, touch bool) []C.Proxy {
func NewRelay(option *GroupCommonOption, providers []provider.ProxyProvider) *Relay {
return &Relay{
Base: outbound.NewBase(outbound.BaseOption{
- Name: option.Name,
- Type: C.Relay,
- Interface: option.Interface,
+ Name: option.Name,
+ Type: C.Relay,
+ Interface: option.Interface,
+ RoutingMark: option.RoutingMark,
}),
single: singledo.NewSingle(defaultGetProxiesDuration),
providers: providers,
diff --git a/adapter/outboundgroup/selector.go b/adapter/outboundgroup/selector.go
index 4ec67cd1d..47e4b87d0 100644
--- a/adapter/outboundgroup/selector.go
+++ b/adapter/outboundgroup/selector.go
@@ -101,9 +101,10 @@ func NewSelector(option *GroupCommonOption, providers []provider.ProxyProvider)
selected := providers[0].Proxies()[0].Name()
return &Selector{
Base: outbound.NewBase(outbound.BaseOption{
- Name: option.Name,
- Type: C.Selector,
- Interface: option.Interface,
+ Name: option.Name,
+ Type: C.Selector,
+ Interface: option.Interface,
+ RoutingMark: option.RoutingMark,
}),
single: singledo.NewSingle(defaultGetProxiesDuration),
providers: providers,
diff --git a/adapter/outboundgroup/urltest.go b/adapter/outboundgroup/urltest.go
index 6866db0df..47144c046 100644
--- a/adapter/outboundgroup/urltest.go
+++ b/adapter/outboundgroup/urltest.go
@@ -137,9 +137,10 @@ func parseURLTestOption(config map[string]interface{}) []urlTestOption {
func NewURLTest(option *GroupCommonOption, providers []provider.ProxyProvider, options ...urlTestOption) *URLTest {
urlTest := &URLTest{
Base: outbound.NewBase(outbound.BaseOption{
- Name: option.Name,
- Type: C.URLTest,
- Interface: option.Interface,
+ Name: option.Name,
+ Type: C.URLTest,
+ Interface: option.Interface,
+ RoutingMark: option.RoutingMark,
}),
single: singledo.NewSingle(defaultGetProxiesDuration),
fastSingle: singledo.NewSingle(time.Second * 10),
diff --git a/component/dialer/dialer.go b/component/dialer/dialer.go
index 87b62dd65..c84fcaa46 100644
--- a/component/dialer/dialer.go
+++ b/component/dialer/dialer.go
@@ -59,6 +59,9 @@ func ListenPacket(ctx context.Context, network, address string, options ...Optio
if cfg.addrReuse {
addrReuseToListenConfig(lc)
}
+ if cfg.routingMark != 0 {
+ bindMarkToListenConfig(cfg.routingMark, lc, network, address)
+ }
return lc.ListenPacket(ctx, network, address)
}
@@ -82,6 +85,9 @@ func dialContext(ctx context.Context, network string, destination net.IP, port s
return nil, err
}
}
+ if opt.routingMark != 0 {
+ bindMarkToDialer(opt.routingMark, dialer, network, destination)
+ }
return dialer.DialContext(ctx, network, net.JoinHostPort(destination.String(), port))
}
diff --git a/component/dialer/mark_linux.go b/component/dialer/mark_linux.go
new file mode 100644
index 000000000..79a2185e4
--- /dev/null
+++ b/component/dialer/mark_linux.go
@@ -0,0 +1,44 @@
+//go:build linux
+// +build linux
+
+package dialer
+
+import (
+ "net"
+ "syscall"
+)
+
+func bindMarkToDialer(mark int, dialer *net.Dialer, _ string, _ net.IP) {
+ dialer.Control = bindMarkToControl(mark, dialer.Control)
+}
+
+func bindMarkToListenConfig(mark int, lc *net.ListenConfig, _, address string) {
+ lc.Control = bindMarkToControl(mark, lc.Control)
+}
+
+func bindMarkToControl(mark int, chain controlFn) controlFn {
+ return func(network, address string, c syscall.RawConn) (err error) {
+ defer func() {
+ if err == nil && chain != nil {
+ err = chain(network, address, c)
+ }
+ }()
+
+ ipStr, _, err := net.SplitHostPort(address)
+ if err == nil {
+ ip := net.ParseIP(ipStr)
+ if ip != nil && !ip.IsGlobalUnicast() {
+ return
+ }
+ }
+
+ return c.Control(func(fd uintptr) {
+ switch network {
+ case "tcp4", "udp4":
+ syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_MARK, mark)
+ case "tcp6", "udp6":
+ syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_MARK, mark)
+ }
+ })
+ }
+}
diff --git a/component/dialer/mark_nonlinux.go b/component/dialer/mark_nonlinux.go
new file mode 100644
index 000000000..5d9befb1a
--- /dev/null
+++ b/component/dialer/mark_nonlinux.go
@@ -0,0 +1,27 @@
+//go:build !linux
+// +build !linux
+
+package dialer
+
+import (
+ "net"
+ "sync"
+
+ "github.com/Dreamacro/clash/log"
+)
+
+var printMarkWarnOnce sync.Once
+
+func printMarkWarn() {
+ printMarkWarnOnce.Do(func() {
+ log.Warnln("Routing mark on socket is not supported on current platform")
+ })
+}
+
+func bindMarkToDialer(mark int, dialer *net.Dialer, _ string, _ net.IP) {
+ printMarkWarn()
+}
+
+func bindMarkToListenConfig(mark int, lc *net.ListenConfig, _, address string) {
+ printMarkWarn()
+}
diff --git a/component/dialer/options.go b/component/dialer/options.go
index 96d9eb751..b3cca8105 100644
--- a/component/dialer/options.go
+++ b/component/dialer/options.go
@@ -10,6 +10,7 @@ var (
type option struct {
interfaceName string
addrReuse bool
+ routingMark int
}
type Option func(opt *option)
@@ -25,3 +26,9 @@ func WithAddrReuse(reuse bool) Option {
opt.addrReuse = reuse
}
}
+
+func WithRoutingMark(mark int) Option {
+ return func(opt *option) {
+ opt.routingMark = mark
+ }
+}
From b56d35040d38df288eb58a6b0a752cd84598817a Mon Sep 17 00:00:00 2001
From: Dreamacro <8615343+Dreamacro@users.noreply.github.com>
Date: Mon, 8 Nov 2021 20:48:29 +0800
Subject: [PATCH 95/96] Chore: update dependencies and rename profile props
---
config/config.go | 2 +-
go.mod | 12 ++++++------
go.sum | 24 +++++++++++------------
test/go.mod | 20 +++++++++----------
test/go.sum | 51 ++++++++++++++++++++++++++----------------------
5 files changed, 57 insertions(+), 52 deletions(-)
diff --git a/config/config.go b/config/config.go
index 603523ec6..a9abe71f8 100644
--- a/config/config.go
+++ b/config/config.go
@@ -80,7 +80,7 @@ type FallbackFilter struct {
// Profile config
type Profile struct {
StoreSelected bool `yaml:"store-selected"`
- StoreFakeIP bool `yaml:"store-fakeip"`
+ StoreFakeIP bool `yaml:"store-fake-ip"`
}
// Experimental config
diff --git a/go.mod b/go.mod
index c608f7ad2..e2ac4f2d9 100644
--- a/go.mod
+++ b/go.mod
@@ -4,12 +4,12 @@ go 1.17
require (
github.com/Dreamacro/go-shadowsocks2 v0.1.7
- github.com/go-chi/chi/v5 v5.0.4
+ github.com/go-chi/chi/v5 v5.0.5
github.com/go-chi/cors v1.2.0
github.com/go-chi/render v1.0.1
- github.com/gofrs/uuid v4.0.0+incompatible
+ github.com/gofrs/uuid v4.1.0+incompatible
github.com/gorilla/websocket v1.4.2
- github.com/insomniacslk/dhcp v0.0.0-20210827173440-b95caade3eac
+ github.com/insomniacslk/dhcp v0.0.0-20211026125128-ad197bcd36fd
github.com/miekg/dns v1.1.43
github.com/oschwald/geoip2-golang v1.5.0
github.com/sirupsen/logrus v1.8.1
@@ -17,10 +17,10 @@ require (
go.etcd.io/bbolt v1.3.6
go.uber.org/atomic v1.9.0
go.uber.org/automaxprocs v1.4.0
- golang.org/x/crypto v0.0.0-20210817164053-32db794688a5
- golang.org/x/net v0.0.0-20210903162142-ad29c8ab022f
+ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519
+ golang.org/x/net v0.0.0-20211105192438-b53810dc28af
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
- golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34
+ golang.org/x/sys v0.0.0-20211107104306-e0b2ad06fe42
gopkg.in/yaml.v2 v2.4.0
)
diff --git a/go.sum b/go.sum
index cccc8ba34..6ef69f45f 100644
--- a/go.sum
+++ b/go.sum
@@ -4,14 +4,14 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fanliao/go-promise v0.0.0-20141029170127-1890db352a72/go.mod h1:PjfxuH4FZdUyfMdtBio2lsRr1AKEaVPwelzuHuh8Lqc=
-github.com/go-chi/chi/v5 v5.0.4 h1:5e494iHzsYBiyXQAHHuI4tyJS9M3V84OuX3ufIIGHFo=
-github.com/go-chi/chi/v5 v5.0.4/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
+github.com/go-chi/chi/v5 v5.0.5 h1:l3RJ8T8TAqLsXFfah+RA6N4pydMbPwSdvNM+AFWvLUM=
+github.com/go-chi/chi/v5 v5.0.5/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
github.com/go-chi/cors v1.2.0 h1:tV1g1XENQ8ku4Bq3K9ub2AtgG+p16SmzeMSGTwrOKdE=
github.com/go-chi/cors v1.2.0/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58=
github.com/go-chi/render v1.0.1 h1:4/5tis2cKaNdnv9zFLfXzcquC9HbeZgCnxGnKrltBS8=
github.com/go-chi/render v1.0.1/go.mod h1:pq4Rr7HbnsdaeHagklXub+p6Wd16Af5l9koip1OvJns=
-github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw=
-github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
+github.com/gofrs/uuid v4.1.0+incompatible h1:sIa2eCvUTwgjbqXrPLfNwUf9S3i3mpH1O1atV+iL/Wk=
+github.com/gofrs/uuid v4.1.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
@@ -21,8 +21,8 @@ github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORR
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714/go.mod h1:2Goc3h8EklBH5mspfHFxBnEoURQCGzQQH1ga9Myjvis=
-github.com/insomniacslk/dhcp v0.0.0-20210827173440-b95caade3eac h1:IO6EfdRnPhxgKOsk9DbewdtQZHKZKnGlW7QCUttvNys=
-github.com/insomniacslk/dhcp v0.0.0-20210827173440-b95caade3eac/go.mod h1:h+MxyHxRg9NH3terB1nfRIUaQEcI0XOVkdR9LNBlp8E=
+github.com/insomniacslk/dhcp v0.0.0-20211026125128-ad197bcd36fd h1:jupbuQFZtwOBg/3EmK91/rGaYFkqCb9bwHOnwn7Cav0=
+github.com/insomniacslk/dhcp v0.0.0-20211026125128-ad197bcd36fd/go.mod h1:h+MxyHxRg9NH3terB1nfRIUaQEcI0XOVkdR9LNBlp8E=
github.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw=
github.com/jsimonetti/rtnetlink v0.0.0-20200117123717-f846d4f6c1f4/go.mod h1:WGuG/smIU4J/54PblvSbh+xvCZmpJnFgr3ds6Z55XMQ=
github.com/jsimonetti/rtnetlink v0.0.0-20201009170750-9c6f07d100c1/go.mod h1:hqoO/u39cqLeBLebZ8fWdE96O7FxrAsRYhnVOdgHxok=
@@ -70,8 +70,8 @@ go.uber.org/automaxprocs v1.4.0/go.mod h1:/mTEdr7LvHhs0v7mjdxDreTz1OG5zdZGqgOnhW
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210317152858-513c2a44f670/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
-golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 h1:HWj/xjIHfjYU5nVXpTM0s39J9CbLn7Cc5a7IC5rwsMQ=
-golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg=
+golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190419010253-1f3472d942ba/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
@@ -82,8 +82,8 @@ golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
-golang.org/x/net v0.0.0-20210903162142-ad29c8ab022f h1:w6wWR0H+nyVpbSAQbzVEIACVyr/h8l/BEkY6Sokc7Eg=
-golang.org/x/net v0.0.0-20210903162142-ad29c8ab022f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20211105192438-b53810dc28af h1:SMeNJG/vclJ5wyBBd4xupMsSJIHTd1coW9g7q6KOjmY=
+golang.org/x/net v0.0.0-20211105192438-b53810dc28af/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -106,8 +106,8 @@ golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34 h1:GkvMjFtXUmahfDtashnc1mnrCtuBVcwse5QV2lUk/tI=
-golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20211107104306-e0b2ad06fe42 h1:G2DDmludOQZoWbpCr7OKDxnl478ZBGMcOhrv+ooX/Q4=
+golang.org/x/sys v0.0.0-20211107104306-e0b2ad06fe42/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
diff --git a/test/go.mod b/test/go.mod
index 3a8781517..a43e4f5c9 100644
--- a/test/go.mod
+++ b/test/go.mod
@@ -3,29 +3,29 @@ module clash-test
go 1.17
require (
- github.com/Dreamacro/clash v1.6.6-0.20210905062555-c7b718f6512d
- github.com/docker/docker v20.10.8+incompatible
+ github.com/Dreamacro/clash v1.7.2-0.20211108085948-bd2ea2b917aa
+ github.com/docker/docker v20.10.10+incompatible
github.com/docker/go-connections v0.4.0
github.com/miekg/dns v1.1.43
github.com/stretchr/testify v1.7.0
- golang.org/x/net v0.0.0-20210903162142-ad29c8ab022f
+ golang.org/x/net v0.0.0-20211105192438-b53810dc28af
)
replace github.com/Dreamacro/clash => ../
require (
github.com/Dreamacro/go-shadowsocks2 v0.1.7 // indirect
- github.com/Microsoft/go-winio v0.5.0 // indirect
- github.com/containerd/containerd v1.5.5 // indirect
+ github.com/Microsoft/go-winio v0.5.1 // indirect
+ github.com/containerd/containerd v1.5.7 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/docker/distribution v2.7.1+incompatible // indirect
github.com/docker/go-units v0.4.0 // indirect
- github.com/gofrs/uuid v4.0.0+incompatible // indirect
+ github.com/gofrs/uuid v4.1.0+incompatible // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/protobuf v1.5.0 // indirect
github.com/gorilla/mux v1.8.0 // indirect
github.com/gorilla/websocket v1.4.2 // indirect
- github.com/insomniacslk/dhcp v0.0.0-20210827173440-b95caade3eac // indirect
+ github.com/insomniacslk/dhcp v0.0.0-20211026125128-ad197bcd36fd // indirect
github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 // indirect
github.com/morikuni/aec v1.0.0 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
@@ -38,13 +38,13 @@ require (
github.com/u-root/uio v0.0.0-20210528114334-82958018845c // indirect
go.etcd.io/bbolt v1.3.6 // indirect
go.uber.org/atomic v1.9.0 // indirect
- golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 // indirect
+ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 // indirect
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
- golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34 // indirect
+ golang.org/x/sys v0.0.0-20211107104306-e0b2ad06fe42 // indirect
golang.org/x/text v0.3.6 // indirect
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect
google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a // indirect
- google.golang.org/grpc v1.40.0 // indirect
+ google.golang.org/grpc v1.42.0 // indirect
google.golang.org/protobuf v1.26.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
diff --git a/test/go.sum b/test/go.sum
index e018f54c7..061bb3a4d 100644
--- a/test/go.sum
+++ b/test/go.sum
@@ -48,8 +48,8 @@ github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugX
github.com/Microsoft/go-winio v0.4.17-0.20210211115548-6eac466e5fa3/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
github.com/Microsoft/go-winio v0.4.17-0.20210324224401-5516f17a5958/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
github.com/Microsoft/go-winio v0.4.17/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
-github.com/Microsoft/go-winio v0.5.0 h1:Elr9Wn+sGKPlkaBvwu4mTrxtmOp3F3yV9qhaHbXGjwU=
-github.com/Microsoft/go-winio v0.5.0/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
+github.com/Microsoft/go-winio v0.5.1 h1:aPJp2QD7OOrhO5tQXqQoGSJc+DjDtWTGLOmNyAm6FgY=
+github.com/Microsoft/go-winio v0.5.1/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg=
github.com/Microsoft/hcsshim v0.8.7-0.20190325164909-8abdbb8205e4/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg=
github.com/Microsoft/hcsshim v0.8.7/go.mod h1:OHd7sQqRFrYd3RmSgbgji+ctCwkbq2wbEYNSzOYtcBQ=
@@ -57,7 +57,7 @@ github.com/Microsoft/hcsshim v0.8.9/go.mod h1:5692vkUqntj1idxauYlpoINNKeqCiG6Sg3
github.com/Microsoft/hcsshim v0.8.14/go.mod h1:NtVKoYxQuTLx6gEq0L96c9Ju4JbRJ4nY2ow3VK6a9Lg=
github.com/Microsoft/hcsshim v0.8.15/go.mod h1:x38A4YbHbdxJtc0sF6oIz+RG0npwSCAvn69iY6URG00=
github.com/Microsoft/hcsshim v0.8.16/go.mod h1:o5/SZqmR7x9JNKsW3pu+nqHm0MF8vbA+VxGOoXdC600=
-github.com/Microsoft/hcsshim v0.8.18/go.mod h1:+w2gRZ5ReXQhFOrvSQeNfhrYB/dg3oDwTOcER2fw4I4=
+github.com/Microsoft/hcsshim v0.8.21/go.mod h1:+w2gRZ5ReXQhFOrvSQeNfhrYB/dg3oDwTOcER2fw4I4=
github.com/Microsoft/hcsshim/test v0.0.0-20201218223536-d3e5debf77da/go.mod h1:5hlzMzRKMLyo42nCZ9oml8AdTlq/0cvIaBv6tK1RehU=
github.com/Microsoft/hcsshim/test v0.0.0-20210227013316-43a75bb4edd3/go.mod h1:mw7qgWloBUl75W/gVH3cQszUg1+gUITj7D6NY7ywVnY=
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
@@ -105,7 +105,10 @@ github.com/cilium/ebpf v0.6.2/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJ
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
-github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
+github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
+github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
+github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
+github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
github.com/containerd/aufs v0.0.0-20200908144142-dab0cbea06f4/go.mod h1:nukgQABAEopAHvB6j7cnP5zJ+/3aVcE7hCYqvIwAHyE=
github.com/containerd/aufs v0.0.0-20201003224125-76a6863f2989/go.mod h1:AkGGQs9NM2vtYHaUen+NljV0/baGCAPELGm2q9ZXpWU=
@@ -139,8 +142,8 @@ github.com/containerd/containerd v1.5.0-beta.3/go.mod h1:/wr9AVtEM7x9c+n0+stptlo
github.com/containerd/containerd v1.5.0-beta.4/go.mod h1:GmdgZd2zA2GYIBZ0w09ZvgqEq8EfBp/m3lcVZIvPHhI=
github.com/containerd/containerd v1.5.0-rc.0/go.mod h1:V/IXoMqNGgBlabz3tHD2TWDoTJseu1FGOKuoA4nNb2s=
github.com/containerd/containerd v1.5.1/go.mod h1:0DOxVqwDy2iZvrZp2JUx/E+hS0UNTVn7dJnIOwtYR4g=
-github.com/containerd/containerd v1.5.5 h1:q1gxsZsGZ8ddVe98yO6pR21b5xQSMiR61lD0W96pgQo=
-github.com/containerd/containerd v1.5.5/go.mod h1:oSTh0QpT1w6jYcGmbiSbxv9OSQYaa88mPyWIuU79zyo=
+github.com/containerd/containerd v1.5.7 h1:rQyoYtj4KddB3bxG6SAqd4+08gePNyJjRqvOIfV3rkM=
+github.com/containerd/containerd v1.5.7/go.mod h1:gyvv6+ugqY25TiXxcZC3L5yOeYgEw0QMhscqVp1AR9c=
github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
github.com/containerd/continuity v0.0.0-20190815185530-f2a389ac0a02/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
github.com/containerd/continuity v0.0.0-20191127005431-f65d91d395eb/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
@@ -226,8 +229,8 @@ github.com/docker/distribution v0.0.0-20190905152932-14b96e55d84c/go.mod h1:0+TT
github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug=
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
-github.com/docker/docker v20.10.8+incompatible h1:RVqD337BgQicVCzYrrlhLDWhq6OAD2PJDUg2LsEUvKM=
-github.com/docker/docker v20.10.8+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
+github.com/docker/docker v20.10.10+incompatible h1:GKkP0T7U4ks6X3lmmHKC2QDprnpRJor2Z5a8m62R9ZM=
+github.com/docker/docker v20.10.10+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
github.com/docker/go-events v0.0.0-20170721190031-9461782956ad/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA=
@@ -248,7 +251,7 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
-github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
+github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/fanliao/go-promise v0.0.0-20141029170127-1890db352a72/go.mod h1:PjfxuH4FZdUyfMdtBio2lsRr1AKEaVPwelzuHuh8Lqc=
@@ -261,7 +264,7 @@ github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXt
github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY=
github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
-github.com/go-chi/chi/v5 v5.0.4/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
+github.com/go-chi/chi/v5 v5.0.5/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
github.com/go-chi/cors v1.2.0/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58=
github.com/go-chi/render v1.0.1/go.mod h1:pq4Rr7HbnsdaeHagklXub+p6Wd16Af5l9koip1OvJns=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
@@ -287,8 +290,8 @@ github.com/godbus/dbus v0.0.0-20180201030542-885f9cc04c9c/go.mod h1:/YcGZj5zSblf
github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4=
github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
-github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw=
-github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
+github.com/gofrs/uuid v4.1.0+incompatible h1:sIa2eCvUTwgjbqXrPLfNwUf9S3i3mpH1O1atV+iL/Wk=
+github.com/gofrs/uuid v4.1.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gogo/googleapis v1.2.0/go.mod h1:Njal3psf3qN6dwBtQfUmBZh2ybovJ0tlu3o/AC7HYjU=
github.com/gogo/googleapis v1.4.0/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
@@ -383,9 +386,10 @@ github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJ
github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/imdario/mergo v0.3.10/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
+github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
-github.com/insomniacslk/dhcp v0.0.0-20210827173440-b95caade3eac h1:IO6EfdRnPhxgKOsk9DbewdtQZHKZKnGlW7QCUttvNys=
-github.com/insomniacslk/dhcp v0.0.0-20210827173440-b95caade3eac/go.mod h1:h+MxyHxRg9NH3terB1nfRIUaQEcI0XOVkdR9LNBlp8E=
+github.com/insomniacslk/dhcp v0.0.0-20211026125128-ad197bcd36fd h1:jupbuQFZtwOBg/3EmK91/rGaYFkqCb9bwHOnwn7Cav0=
+github.com/insomniacslk/dhcp v0.0.0-20211026125128-ad197bcd36fd/go.mod h1:h+MxyHxRg9NH3terB1nfRIUaQEcI0XOVkdR9LNBlp8E=
github.com/j-keck/arping v0.0.0-20160618110441-2cf9dc699c56/go.mod h1:ymszkNOg6tORTn+6F6j+Jc8TOr5osrynvN6ivFWZ2GA=
github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
@@ -492,7 +496,7 @@ github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59P
github.com/opencontainers/runc v1.0.0-rc8.0.20190926000215-3e425f80a8c9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
github.com/opencontainers/runc v1.0.0-rc9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
github.com/opencontainers/runc v1.0.0-rc93/go.mod h1:3NOsor4w32B2tC0Zbl8Knk4Wg84SM2ImC1fxBuqJ/H0=
-github.com/opencontainers/runc v1.0.1/go.mod h1:aTaHFFwQXuA71CiyxOdFFIorAoemI04suvGRQFzWTD0=
+github.com/opencontainers/runc v1.0.2/go.mod h1:aTaHFFwQXuA71CiyxOdFFIorAoemI04suvGRQFzWTD0=
github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opencontainers/runtime-spec v1.0.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opencontainers/runtime-spec v1.0.2-0.20190207185410-29686dbc5559/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
@@ -642,6 +646,7 @@ go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
+go.uber.org/automaxprocs v1.4.0/go.mod h1:/mTEdr7LvHhs0v7mjdxDreTz1OG5zdZGqgOnhWiR/+Q=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
@@ -658,8 +663,8 @@ golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210317152858-513c2a44f670/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
-golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 h1:HWj/xjIHfjYU5nVXpTM0s39J9CbLn7Cc5a7IC5rwsMQ=
-golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg=
+golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -728,8 +733,8 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
-golang.org/x/net v0.0.0-20210903162142-ad29c8ab022f h1:w6wWR0H+nyVpbSAQbzVEIACVyr/h8l/BEkY6Sokc7Eg=
-golang.org/x/net v0.0.0-20210903162142-ad29c8ab022f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20211105192438-b53810dc28af h1:SMeNJG/vclJ5wyBBd4xupMsSJIHTd1coW9g7q6KOjmY=
+golang.org/x/net v0.0.0-20211105192438-b53810dc28af/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -819,8 +824,8 @@ golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34 h1:GkvMjFtXUmahfDtashnc1mnrCtuBVcwse5QV2lUk/tI=
-golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20211107104306-e0b2ad06fe42 h1:G2DDmludOQZoWbpCr7OKDxnl478ZBGMcOhrv+ooX/Q4=
+golang.org/x/sys v0.0.0-20211107104306-e0b2ad06fe42/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -936,8 +941,8 @@ google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
-google.golang.org/grpc v1.40.0 h1:AGJ0Ih4mHjSeibYkFGh1dD9KJ/eOtZ93I6hoHhukQ5Q=
-google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
+google.golang.org/grpc v1.42.0 h1:XT2/MFpuPFsEX2fWh3YQtHkZ+WYZFQRfaUgLZYj/p6A=
+google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
From c9be614821d5c9b4cb3582c2eaebed89341c7f6e Mon Sep 17 00:00:00 2001
From: Dreamacro <8615343+Dreamacro@users.noreply.github.com>
Date: Mon, 8 Nov 2021 21:24:39 +0800
Subject: [PATCH 96/96] Fix: windows arm7 build
---
component/dialer/bind_others.go | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/component/dialer/bind_others.go b/component/dialer/bind_others.go
index e94946739..a74995b58 100644
--- a/component/dialer/bind_others.go
+++ b/component/dialer/bind_others.go
@@ -58,7 +58,7 @@ func bindIfaceToDialer(ifaceName string, dialer *net.Dialer, network string, des
return nil
}
- local := 0
+ local := int64(0)
if dialer.LocalAddr != nil {
_, port, err := net.SplitHostPort(dialer.LocalAddr.String())
if err == nil {
@@ -66,7 +66,7 @@ func bindIfaceToDialer(ifaceName string, dialer *net.Dialer, network string, des
}
}
- addr, err := lookupLocalAddr(ifaceName, network, destination, local)
+ addr, err := lookupLocalAddr(ifaceName, network, destination, int(local))
if err != nil {
return err
}
@@ -84,7 +84,7 @@ func bindIfaceToListenConfig(ifaceName string, _ *net.ListenConfig, network, add
local, _ := strconv.ParseInt(port, 10, 16)
- addr, err := lookupLocalAddr(ifaceName, network, nil, local)
+ addr, err := lookupLocalAddr(ifaceName, network, nil, int(local))
if err != nil {
return "", err
}