Merge branch 'Alpha' into dev
This commit is contained in:
commit
abbbcb02c0
58 changed files with 1052 additions and 468 deletions
|
@ -16,11 +16,11 @@ RUN go mod download &&\
|
||||||
FROM alpine:latest
|
FROM alpine:latest
|
||||||
LABEL org.opencontainers.image.source="https://github.com/MetaCubeX/Clash.Meta"
|
LABEL org.opencontainers.image.source="https://github.com/MetaCubeX/Clash.Meta"
|
||||||
|
|
||||||
RUN apk add --no-cache ca-certificates tzdata
|
RUN apk add --no-cache ca-certificates tzdata iptables
|
||||||
|
|
||||||
VOLUME ["/root/.config/clash/"]
|
VOLUME ["/root/.config/clash/"]
|
||||||
|
|
||||||
COPY --from=builder /clash-config/ /root/.config/clash/
|
COPY --from=builder /clash-config/ /root/.config/clash/
|
||||||
COPY --from=builder /clash /clash
|
COPY --from=builder /clash /clash
|
||||||
RUN chmod +x /clash
|
RUN chmod +x /clash
|
||||||
ENTRYPOINT [ "/clash" ]
|
ENTRYPOINT [ "/clash" ]
|
||||||
|
|
|
@ -13,13 +13,14 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type Base struct {
|
type Base struct {
|
||||||
name string
|
name string
|
||||||
addr string
|
addr string
|
||||||
iface string
|
iface string
|
||||||
tp C.AdapterType
|
tp C.AdapterType
|
||||||
udp bool
|
udp bool
|
||||||
rmark int
|
rmark int
|
||||||
id string
|
id string
|
||||||
|
prefer C.DNSPrefer
|
||||||
}
|
}
|
||||||
|
|
||||||
// Name implements C.ProxyAdapter
|
// Name implements C.ProxyAdapter
|
||||||
|
@ -103,12 +104,25 @@ func (b *Base) DialOptions(opts ...dialer.Option) []dialer.Option {
|
||||||
opts = append(opts, dialer.WithRoutingMark(b.rmark))
|
opts = append(opts, dialer.WithRoutingMark(b.rmark))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch b.prefer {
|
||||||
|
case C.IPv4Only:
|
||||||
|
opts = append(opts, dialer.WithOnlySingleStack(true))
|
||||||
|
case C.IPv6Only:
|
||||||
|
opts = append(opts, dialer.WithOnlySingleStack(false))
|
||||||
|
case C.IPv4Prefer:
|
||||||
|
opts = append(opts, dialer.WithPreferIPv4())
|
||||||
|
case C.IPv6Prefer:
|
||||||
|
opts = append(opts, dialer.WithPreferIPv6())
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
return opts
|
return opts
|
||||||
}
|
}
|
||||||
|
|
||||||
type BasicOption struct {
|
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"`
|
RoutingMark int `proxy:"routing-mark,omitempty" group:"routing-mark,omitempty"`
|
||||||
|
IPVersion string `proxy:"ip-version,omitempty" group:"ip-version,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type BaseOption struct {
|
type BaseOption struct {
|
||||||
|
@ -118,16 +132,18 @@ type BaseOption struct {
|
||||||
UDP bool
|
UDP bool
|
||||||
Interface string
|
Interface string
|
||||||
RoutingMark int
|
RoutingMark int
|
||||||
|
Prefer C.DNSPrefer
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewBase(opt BaseOption) *Base {
|
func NewBase(opt BaseOption) *Base {
|
||||||
return &Base{
|
return &Base{
|
||||||
name: opt.Name,
|
name: opt.Name,
|
||||||
addr: opt.Addr,
|
addr: opt.Addr,
|
||||||
tp: opt.Type,
|
tp: opt.Type,
|
||||||
udp: opt.UDP,
|
udp: opt.UDP,
|
||||||
iface: opt.Interface,
|
iface: opt.Interface,
|
||||||
rmark: opt.RoutingMark,
|
rmark: opt.RoutingMark,
|
||||||
|
prefer: opt.Prefer,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,9 +40,10 @@ type directPacketConn struct {
|
||||||
func NewDirect() *Direct {
|
func NewDirect() *Direct {
|
||||||
return &Direct{
|
return &Direct{
|
||||||
Base: &Base{
|
Base: &Base{
|
||||||
name: "DIRECT",
|
name: "DIRECT",
|
||||||
tp: C.Direct,
|
tp: C.Direct,
|
||||||
udp: true,
|
udp: true,
|
||||||
|
prefer: C.DualStack,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -50,9 +51,10 @@ func NewDirect() *Direct {
|
||||||
func NewCompatible() *Direct {
|
func NewCompatible() *Direct {
|
||||||
return &Direct{
|
return &Direct{
|
||||||
Base: &Base{
|
Base: &Base{
|
||||||
name: "COMPATIBLE",
|
name: "COMPATIBLE",
|
||||||
tp: C.Compatible,
|
tp: C.Compatible,
|
||||||
udp: true,
|
udp: true,
|
||||||
|
prefer: C.DualStack,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -153,11 +153,12 @@ func NewHttp(option HttpOption) (*Http, error) {
|
||||||
|
|
||||||
return &Http{
|
return &Http{
|
||||||
Base: &Base{
|
Base: &Base{
|
||||||
name: option.Name,
|
name: option.Name,
|
||||||
addr: net.JoinHostPort(option.Server, strconv.Itoa(option.Port)),
|
addr: net.JoinHostPort(option.Server, strconv.Itoa(option.Port)),
|
||||||
tp: C.Http,
|
tp: C.Http,
|
||||||
iface: option.Interface,
|
iface: option.Interface,
|
||||||
rmark: option.RoutingMark,
|
rmark: option.RoutingMark,
|
||||||
|
prefer: C.NewDNSPrefer(option.IPVersion),
|
||||||
},
|
},
|
||||||
user: option.UserName,
|
user: option.UserName,
|
||||||
pass: option.Password,
|
pass: option.Password,
|
||||||
|
|
|
@ -4,27 +4,29 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
|
"encoding/base64"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
"fmt"
|
"fmt"
|
||||||
tlsC "github.com/Dreamacro/clash/component/tls"
|
|
||||||
"github.com/Dreamacro/clash/transport/hysteria/core"
|
|
||||||
"github.com/Dreamacro/clash/transport/hysteria/obfs"
|
|
||||||
"github.com/Dreamacro/clash/transport/hysteria/pmtud_fix"
|
|
||||||
"github.com/Dreamacro/clash/transport/hysteria/transport"
|
|
||||||
"github.com/lucas-clemente/quic-go"
|
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/lucas-clemente/quic-go"
|
||||||
|
"github.com/lucas-clemente/quic-go/congestion"
|
||||||
|
M "github.com/sagernet/sing/common/metadata"
|
||||||
|
|
||||||
"github.com/Dreamacro/clash/component/dialer"
|
"github.com/Dreamacro/clash/component/dialer"
|
||||||
|
tlsC "github.com/Dreamacro/clash/component/tls"
|
||||||
C "github.com/Dreamacro/clash/constant"
|
C "github.com/Dreamacro/clash/constant"
|
||||||
"github.com/Dreamacro/clash/log"
|
"github.com/Dreamacro/clash/log"
|
||||||
hyCongestion "github.com/Dreamacro/clash/transport/hysteria/congestion"
|
hyCongestion "github.com/Dreamacro/clash/transport/hysteria/congestion"
|
||||||
"github.com/lucas-clemente/quic-go/congestion"
|
"github.com/Dreamacro/clash/transport/hysteria/core"
|
||||||
M "github.com/sagernet/sing/common/metadata"
|
"github.com/Dreamacro/clash/transport/hysteria/obfs"
|
||||||
|
"github.com/Dreamacro/clash/transport/hysteria/pmtud_fix"
|
||||||
|
"github.com/Dreamacro/clash/transport/hysteria/transport"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -53,6 +55,9 @@ func (h *Hysteria) DialContext(ctx context.Context, metadata *C.Metadata, opts .
|
||||||
hyDialer: func() (net.PacketConn, error) {
|
hyDialer: func() (net.PacketConn, error) {
|
||||||
return dialer.ListenPacket(ctx, "udp", "", h.Base.DialOptions(opts...)...)
|
return dialer.ListenPacket(ctx, "udp", "", h.Base.DialOptions(opts...)...)
|
||||||
},
|
},
|
||||||
|
remoteAddr: func(addr string) (net.Addr, error) {
|
||||||
|
return resolveUDPAddrWithPrefer("udp", addr, h.prefer)
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
tcpConn, err := h.client.DialTCP(metadata.RemoteAddress(), &hdc)
|
tcpConn, err := h.client.DialTCP(metadata.RemoteAddress(), &hdc)
|
||||||
|
@ -69,6 +74,9 @@ func (h *Hysteria) ListenPacketContext(ctx context.Context, metadata *C.Metadata
|
||||||
hyDialer: func() (net.PacketConn, error) {
|
hyDialer: func() (net.PacketConn, error) {
|
||||||
return dialer.ListenPacket(ctx, "udp", "", h.Base.DialOptions(opts...)...)
|
return dialer.ListenPacket(ctx, "udp", "", h.Base.DialOptions(opts...)...)
|
||||||
},
|
},
|
||||||
|
remoteAddr: func(addr string) (net.Addr, error) {
|
||||||
|
return resolveUDPAddrWithPrefer("udp", addr, h.prefer)
|
||||||
|
},
|
||||||
}
|
}
|
||||||
udpConn, err := h.client.DialUDP(&hdc)
|
udpConn, err := h.client.DialUDP(&hdc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -79,23 +87,27 @@ func (h *Hysteria) ListenPacketContext(ctx context.Context, metadata *C.Metadata
|
||||||
|
|
||||||
type HysteriaOption struct {
|
type HysteriaOption struct {
|
||||||
BasicOption
|
BasicOption
|
||||||
Name string `proxy:"name"`
|
Name string `proxy:"name"`
|
||||||
Server string `proxy:"server"`
|
Server string `proxy:"server"`
|
||||||
Port int `proxy:"port"`
|
Port int `proxy:"port"`
|
||||||
Protocol string `proxy:"protocol,omitempty"`
|
Protocol string `proxy:"protocol,omitempty"`
|
||||||
Up string `proxy:"up"`
|
ObfsProtocol string `proxy:"obfs-protocol,omitempty"` // compatible with Stash
|
||||||
Down string `proxy:"down"`
|
Up string `proxy:"up"`
|
||||||
AuthString string `proxy:"auth_str,omitempty"`
|
UpSpeed int `proxy:"up-speed,omitempty"` // compatible with Stash
|
||||||
Obfs string `proxy:"obfs,omitempty"`
|
Down string `proxy:"down"`
|
||||||
SNI string `proxy:"sni,omitempty"`
|
DownSpeed int `proxy:"down-speed,omitempty"` // compatible with Stash
|
||||||
SkipCertVerify bool `proxy:"skip-cert-verify,omitempty"`
|
Auth string `proxy:"auth,omitempty"`
|
||||||
Fingerprint string `proxy:"fingerprint,omitempty"`
|
AuthString string `proxy:"auth_str,omitempty"`
|
||||||
ALPN string `proxy:"alpn,omitempty"`
|
Obfs string `proxy:"obfs,omitempty"`
|
||||||
CustomCA string `proxy:"ca,omitempty"`
|
SNI string `proxy:"sni,omitempty"`
|
||||||
CustomCAString string `proxy:"ca_str,omitempty"`
|
SkipCertVerify bool `proxy:"skip-cert-verify,omitempty"`
|
||||||
ReceiveWindowConn int `proxy:"recv_window_conn,omitempty"`
|
Fingerprint string `proxy:"fingerprint,omitempty"`
|
||||||
ReceiveWindow int `proxy:"recv_window,omitempty"`
|
ALPN []string `proxy:"alpn,omitempty"`
|
||||||
DisableMTUDiscovery bool `proxy:"disable_mtu_discovery,omitempty"`
|
CustomCA string `proxy:"ca,omitempty"`
|
||||||
|
CustomCAString string `proxy:"ca_str,omitempty"`
|
||||||
|
ReceiveWindowConn int `proxy:"recv_window_conn,omitempty"`
|
||||||
|
ReceiveWindow int `proxy:"recv_window,omitempty"`
|
||||||
|
DisableMTUDiscovery bool `proxy:"disable_mtu_discovery,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *HysteriaOption) Speed() (uint64, uint64, error) {
|
func (c *HysteriaOption) Speed() (uint64, uint64, error) {
|
||||||
|
@ -166,7 +178,7 @@ func NewHysteria(option HysteriaOption) (*Hysteria, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(option.ALPN) > 0 {
|
if len(option.ALPN) > 0 {
|
||||||
tlsConfig.NextProtos = []string{option.ALPN}
|
tlsConfig.NextProtos = option.ALPN
|
||||||
} else {
|
} else {
|
||||||
tlsConfig.NextProtos = []string{DefaultALPN}
|
tlsConfig.NextProtos = []string{DefaultALPN}
|
||||||
}
|
}
|
||||||
|
@ -180,15 +192,18 @@ func NewHysteria(option HysteriaOption) (*Hysteria, error) {
|
||||||
DisablePathMTUDiscovery: option.DisableMTUDiscovery,
|
DisablePathMTUDiscovery: option.DisableMTUDiscovery,
|
||||||
EnableDatagrams: true,
|
EnableDatagrams: true,
|
||||||
}
|
}
|
||||||
|
if option.ObfsProtocol != "" {
|
||||||
|
option.Protocol = option.ObfsProtocol
|
||||||
|
}
|
||||||
if option.Protocol == "" {
|
if option.Protocol == "" {
|
||||||
option.Protocol = DefaultProtocol
|
option.Protocol = DefaultProtocol
|
||||||
}
|
}
|
||||||
if option.ReceiveWindowConn == 0 {
|
if option.ReceiveWindowConn == 0 {
|
||||||
quicConfig.InitialStreamReceiveWindow = DefaultStreamReceiveWindow
|
quicConfig.InitialStreamReceiveWindow = DefaultStreamReceiveWindow / 10
|
||||||
quicConfig.MaxStreamReceiveWindow = DefaultStreamReceiveWindow
|
quicConfig.MaxStreamReceiveWindow = DefaultStreamReceiveWindow
|
||||||
}
|
}
|
||||||
if option.ReceiveWindow == 0 {
|
if option.ReceiveWindow == 0 {
|
||||||
quicConfig.InitialConnectionReceiveWindow = DefaultConnectionReceiveWindow
|
quicConfig.InitialConnectionReceiveWindow = DefaultConnectionReceiveWindow / 10
|
||||||
quicConfig.MaxConnectionReceiveWindow = DefaultConnectionReceiveWindow
|
quicConfig.MaxConnectionReceiveWindow = DefaultConnectionReceiveWindow
|
||||||
}
|
}
|
||||||
if !quicConfig.DisablePathMTUDiscovery && pmtud_fix.DisablePathMTUDiscovery {
|
if !quicConfig.DisablePathMTUDiscovery && pmtud_fix.DisablePathMTUDiscovery {
|
||||||
|
@ -196,6 +211,12 @@ func NewHysteria(option HysteriaOption) (*Hysteria, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var auth = []byte(option.AuthString)
|
var auth = []byte(option.AuthString)
|
||||||
|
if option.Auth != "" {
|
||||||
|
auth, err = base64.StdEncoding.DecodeString(option.Auth)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
var obfuscator obfs.Obfuscator
|
var obfuscator obfs.Obfuscator
|
||||||
if len(option.Obfs) > 0 {
|
if len(option.Obfs) > 0 {
|
||||||
obfuscator = obfs.NewXPlusObfuscator([]byte(option.Obfs))
|
obfuscator = obfs.NewXPlusObfuscator([]byte(option.Obfs))
|
||||||
|
@ -205,7 +226,12 @@ func NewHysteria(option HysteriaOption) (*Hysteria, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
if option.UpSpeed != 0 {
|
||||||
|
up = uint64(option.UpSpeed * mbpsToBps)
|
||||||
|
}
|
||||||
|
if option.DownSpeed != 0 {
|
||||||
|
down = uint64(option.DownSpeed * mbpsToBps)
|
||||||
|
}
|
||||||
client, err := core.NewClient(
|
client, err := core.NewClient(
|
||||||
addr, option.Protocol, auth, tlsConfig, quicConfig, clientTransport, up, down, func(refBPS uint64) congestion.CongestionControl {
|
addr, option.Protocol, auth, tlsConfig, quicConfig, clientTransport, up, down, func(refBPS uint64) congestion.CongestionControl {
|
||||||
return hyCongestion.NewBrutalSender(congestion.ByteCount(refBPS))
|
return hyCongestion.NewBrutalSender(congestion.ByteCount(refBPS))
|
||||||
|
@ -216,12 +242,13 @@ func NewHysteria(option HysteriaOption) (*Hysteria, error) {
|
||||||
}
|
}
|
||||||
return &Hysteria{
|
return &Hysteria{
|
||||||
Base: &Base{
|
Base: &Base{
|
||||||
name: option.Name,
|
name: option.Name,
|
||||||
addr: addr,
|
addr: addr,
|
||||||
tp: C.Hysteria,
|
tp: C.Hysteria,
|
||||||
udp: true,
|
udp: true,
|
||||||
iface: option.Interface,
|
iface: option.Interface,
|
||||||
rmark: option.RoutingMark,
|
rmark: option.RoutingMark,
|
||||||
|
prefer: C.NewDNSPrefer(option.IPVersion),
|
||||||
},
|
},
|
||||||
client: client,
|
client: client,
|
||||||
}, nil
|
}, nil
|
||||||
|
@ -287,8 +314,9 @@ func (c *hyPacketConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
type hyDialerWithContext struct {
|
type hyDialerWithContext struct {
|
||||||
hyDialer func() (net.PacketConn, error)
|
hyDialer func() (net.PacketConn, error)
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
|
remoteAddr func(host string) (net.Addr, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *hyDialerWithContext) ListenPacket() (net.PacketConn, error) {
|
func (h *hyDialerWithContext) ListenPacket() (net.PacketConn, error) {
|
||||||
|
@ -298,3 +326,7 @@ func (h *hyDialerWithContext) ListenPacket() (net.PacketConn, error) {
|
||||||
func (h *hyDialerWithContext) Context() context.Context {
|
func (h *hyDialerWithContext) Context() context.Context {
|
||||||
return h.ctx
|
return h.ctx
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *hyDialerWithContext) RemoteAddr(host string) (net.Addr, error) {
|
||||||
|
return h.remoteAddr(host)
|
||||||
|
}
|
||||||
|
|
|
@ -27,9 +27,10 @@ func (r *Reject) ListenPacketContext(ctx context.Context, metadata *C.Metadata,
|
||||||
func NewReject() *Reject {
|
func NewReject() *Reject {
|
||||||
return &Reject{
|
return &Reject{
|
||||||
Base: &Base{
|
Base: &Base{
|
||||||
name: "REJECT",
|
name: "REJECT",
|
||||||
tp: C.Reject,
|
tp: C.Reject,
|
||||||
udp: true,
|
udp: true,
|
||||||
|
prefer: C.DualStack,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,9 +38,10 @@ func NewReject() *Reject {
|
||||||
func NewPass() *Reject {
|
func NewPass() *Reject {
|
||||||
return &Reject{
|
return &Reject{
|
||||||
Base: &Base{
|
Base: &Base{
|
||||||
name: "PASS",
|
name: "PASS",
|
||||||
tp: C.Pass,
|
tp: C.Pass,
|
||||||
udp: true,
|
udp: true,
|
||||||
|
prefer: C.DualStack,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,8 +82,7 @@ func (ss *ShadowSocks) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, e
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if metadata.NetWork == C.UDP && ss.option.UDPOverTCP {
|
if metadata.NetWork == C.UDP && ss.option.UDPOverTCP {
|
||||||
metadata.Host = uot.UOTMagicAddress
|
return ss.method.DialConn(c, M.ParseSocksaddr(uot.UOTMagicAddress+":443"))
|
||||||
metadata.DstPort = "443"
|
|
||||||
}
|
}
|
||||||
return ss.method.DialConn(c, M.ParseSocksaddr(metadata.RemoteAddress()))
|
return ss.method.DialConn(c, M.ParseSocksaddr(metadata.RemoteAddress()))
|
||||||
}
|
}
|
||||||
|
@ -116,7 +115,7 @@ func (ss *ShadowSocks) ListenPacketContext(ctx context.Context, metadata *C.Meta
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
addr, err := resolveUDPAddr("udp", ss.addr)
|
addr, err := resolveUDPAddrWithPrefer("udp", ss.addr, ss.prefer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
pc.Close()
|
pc.Close()
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -186,12 +185,13 @@ func NewShadowSocks(option ShadowSocksOption) (*ShadowSocks, error) {
|
||||||
|
|
||||||
return &ShadowSocks{
|
return &ShadowSocks{
|
||||||
Base: &Base{
|
Base: &Base{
|
||||||
name: option.Name,
|
name: option.Name,
|
||||||
addr: addr,
|
addr: addr,
|
||||||
tp: C.Shadowsocks,
|
tp: C.Shadowsocks,
|
||||||
udp: option.UDP,
|
udp: option.UDP,
|
||||||
iface: option.Interface,
|
iface: option.Interface,
|
||||||
rmark: option.RoutingMark,
|
rmark: option.RoutingMark,
|
||||||
|
prefer: C.NewDNSPrefer(option.IPVersion),
|
||||||
},
|
},
|
||||||
method: method,
|
method: method,
|
||||||
|
|
||||||
|
|
|
@ -79,7 +79,7 @@ func (ssr *ShadowSocksR) ListenPacketContext(ctx context.Context, metadata *C.Me
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
addr, err := resolveUDPAddr("udp", ssr.addr)
|
addr, err := resolveUDPAddrWithPrefer("udp", ssr.addr, ssr.prefer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
pc.Close()
|
pc.Close()
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -143,12 +143,13 @@ func NewShadowSocksR(option ShadowSocksROption) (*ShadowSocksR, error) {
|
||||||
|
|
||||||
return &ShadowSocksR{
|
return &ShadowSocksR{
|
||||||
Base: &Base{
|
Base: &Base{
|
||||||
name: option.Name,
|
name: option.Name,
|
||||||
addr: addr,
|
addr: addr,
|
||||||
tp: C.ShadowsocksR,
|
tp: C.ShadowsocksR,
|
||||||
udp: option.UDP,
|
udp: option.UDP,
|
||||||
iface: option.Interface,
|
iface: option.Interface,
|
||||||
rmark: option.RoutingMark,
|
rmark: option.RoutingMark,
|
||||||
|
prefer: C.NewDNSPrefer(option.IPVersion),
|
||||||
},
|
},
|
||||||
cipher: coreCiph,
|
cipher: coreCiph,
|
||||||
obfs: obfs,
|
obfs: obfs,
|
||||||
|
|
|
@ -152,12 +152,13 @@ func NewSnell(option SnellOption) (*Snell, error) {
|
||||||
|
|
||||||
s := &Snell{
|
s := &Snell{
|
||||||
Base: &Base{
|
Base: &Base{
|
||||||
name: option.Name,
|
name: option.Name,
|
||||||
addr: addr,
|
addr: addr,
|
||||||
tp: C.Snell,
|
tp: C.Snell,
|
||||||
udp: option.UDP,
|
udp: option.UDP,
|
||||||
iface: option.Interface,
|
iface: option.Interface,
|
||||||
rmark: option.RoutingMark,
|
rmark: option.RoutingMark,
|
||||||
|
prefer: C.NewDNSPrefer(option.IPVersion),
|
||||||
},
|
},
|
||||||
psk: psk,
|
psk: psk,
|
||||||
obfsOption: obfsOption,
|
obfsOption: obfsOption,
|
||||||
|
|
|
@ -160,12 +160,13 @@ func NewSocks5(option Socks5Option) (*Socks5, error) {
|
||||||
|
|
||||||
return &Socks5{
|
return &Socks5{
|
||||||
Base: &Base{
|
Base: &Base{
|
||||||
name: option.Name,
|
name: option.Name,
|
||||||
addr: net.JoinHostPort(option.Server, strconv.Itoa(option.Port)),
|
addr: net.JoinHostPort(option.Server, strconv.Itoa(option.Port)),
|
||||||
tp: C.Socks5,
|
tp: C.Socks5,
|
||||||
udp: option.UDP,
|
udp: option.UDP,
|
||||||
iface: option.Interface,
|
iface: option.Interface,
|
||||||
rmark: option.RoutingMark,
|
rmark: option.RoutingMark,
|
||||||
|
prefer: C.NewDNSPrefer(option.IPVersion),
|
||||||
},
|
},
|
||||||
user: option.UserName,
|
user: option.UserName,
|
||||||
pass: option.Password,
|
pass: option.Password,
|
||||||
|
|
|
@ -209,12 +209,13 @@ func NewTrojan(option TrojanOption) (*Trojan, error) {
|
||||||
|
|
||||||
t := &Trojan{
|
t := &Trojan{
|
||||||
Base: &Base{
|
Base: &Base{
|
||||||
name: option.Name,
|
name: option.Name,
|
||||||
addr: addr,
|
addr: addr,
|
||||||
tp: C.Trojan,
|
tp: C.Trojan,
|
||||||
udp: option.UDP,
|
udp: option.UDP,
|
||||||
iface: option.Interface,
|
iface: option.Interface,
|
||||||
rmark: option.RoutingMark,
|
rmark: option.RoutingMark,
|
||||||
|
prefer: C.NewDNSPrefer(option.IPVersion),
|
||||||
},
|
},
|
||||||
instance: trojan.New(tOption),
|
instance: trojan.New(tOption),
|
||||||
option: &option,
|
option: &option,
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
xtls "github.com/xtls/go"
|
xtls "github.com/xtls/go"
|
||||||
"net"
|
"net"
|
||||||
|
"net/netip"
|
||||||
"strconv"
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
@ -74,6 +75,63 @@ func resolveUDPAddr(network, address string) (*net.UDPAddr, error) {
|
||||||
return net.ResolveUDPAddr(network, net.JoinHostPort(ip.String(), port))
|
return net.ResolveUDPAddr(network, net.JoinHostPort(ip.String(), port))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func resolveUDPAddrWithPrefer(network, address string, prefer C.DNSPrefer) (*net.UDPAddr, error) {
|
||||||
|
host, port, err := net.SplitHostPort(address)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var ip netip.Addr
|
||||||
|
switch prefer {
|
||||||
|
case C.IPv4Only:
|
||||||
|
ip, err = resolver.ResolveIPv4ProxyServerHost(host)
|
||||||
|
case C.IPv6Only:
|
||||||
|
ip, err = resolver.ResolveIPv6ProxyServerHost(host)
|
||||||
|
case C.IPv6Prefer:
|
||||||
|
var ips []netip.Addr
|
||||||
|
ips, err = resolver.ResolveAllIPProxyServerHost(host)
|
||||||
|
var fallback netip.Addr
|
||||||
|
if err == nil {
|
||||||
|
for _, addr := range ips {
|
||||||
|
if addr.Is6() {
|
||||||
|
ip = addr
|
||||||
|
break
|
||||||
|
} else {
|
||||||
|
if !fallback.IsValid() {
|
||||||
|
fallback = addr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ip = fallback
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
// C.IPv4Prefer, C.DualStack and other
|
||||||
|
var ips []netip.Addr
|
||||||
|
ips, err = resolver.ResolveAllIPProxyServerHost(host)
|
||||||
|
var fallback netip.Addr
|
||||||
|
if err == nil {
|
||||||
|
for _, addr := range ips {
|
||||||
|
if addr.Is4() {
|
||||||
|
ip = addr
|
||||||
|
break
|
||||||
|
} else {
|
||||||
|
if !fallback.IsValid() {
|
||||||
|
fallback = addr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !ip.IsValid() && fallback.IsValid() {
|
||||||
|
ip = fallback
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return net.ResolveUDPAddr(network, net.JoinHostPort(ip.String(), port))
|
||||||
|
}
|
||||||
|
|
||||||
func safeConnClose(c net.Conn, err error) {
|
func safeConnClose(c net.Conn, err error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = c.Close()
|
_ = c.Close()
|
||||||
|
|
|
@ -418,11 +418,12 @@ func NewVless(option VlessOption) (*Vless, error) {
|
||||||
|
|
||||||
v := &Vless{
|
v := &Vless{
|
||||||
Base: &Base{
|
Base: &Base{
|
||||||
name: option.Name,
|
name: option.Name,
|
||||||
addr: net.JoinHostPort(option.Server, strconv.Itoa(option.Port)),
|
addr: net.JoinHostPort(option.Server, strconv.Itoa(option.Port)),
|
||||||
tp: C.Vless,
|
tp: C.Vless,
|
||||||
udp: option.UDP,
|
udp: option.UDP,
|
||||||
iface: option.Interface,
|
iface: option.Interface,
|
||||||
|
prefer: C.NewDNSPrefer(option.IPVersion),
|
||||||
},
|
},
|
||||||
client: client,
|
client: client,
|
||||||
option: &option,
|
option: &option,
|
||||||
|
|
|
@ -52,6 +52,8 @@ type VmessOption struct {
|
||||||
GrpcOpts GrpcOptions `proxy:"grpc-opts,omitempty"`
|
GrpcOpts GrpcOptions `proxy:"grpc-opts,omitempty"`
|
||||||
WSOpts WSOptions `proxy:"ws-opts,omitempty"`
|
WSOpts WSOptions `proxy:"ws-opts,omitempty"`
|
||||||
PacketAddr bool `proxy:"packet-addr,omitempty"`
|
PacketAddr bool `proxy:"packet-addr,omitempty"`
|
||||||
|
XUDP bool `proxy:"xudp,omitempty"`
|
||||||
|
PacketEncoding string `proxy:"packet_encoding,omitempty"`
|
||||||
AuthenticatedLength bool `proxy:"authenticated-length,omitempty"`
|
AuthenticatedLength bool `proxy:"authenticated-length,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -197,7 +199,11 @@ func (v *Vmess) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if metadata.NetWork == C.UDP {
|
if metadata.NetWork == C.UDP {
|
||||||
return v.client.DialPacketConn(c, M.ParseSocksaddr(metadata.RemoteAddress()))
|
if v.option.XUDP {
|
||||||
|
return v.client.DialXUDPPacketConn(c, M.ParseSocksaddr(metadata.RemoteAddress()))
|
||||||
|
} else {
|
||||||
|
return v.client.DialPacketConn(c, M.ParseSocksaddr(metadata.RemoteAddress()))
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return v.client.DialConn(c, M.ParseSocksaddr(metadata.RemoteAddress()))
|
return v.client.DialConn(c, M.ParseSocksaddr(metadata.RemoteAddress()))
|
||||||
}
|
}
|
||||||
|
@ -244,6 +250,8 @@ func (v *Vmess) ListenPacketContext(ctx context.Context, metadata *C.Metadata, o
|
||||||
}
|
}
|
||||||
|
|
||||||
if v.option.PacketAddr {
|
if v.option.PacketAddr {
|
||||||
|
_metadata := *metadata // make a copy
|
||||||
|
metadata = &_metadata
|
||||||
metadata.Host = packetaddr.SeqPacketMagicAddress
|
metadata.Host = packetaddr.SeqPacketMagicAddress
|
||||||
metadata.DstPort = "443"
|
metadata.DstPort = "443"
|
||||||
}
|
}
|
||||||
|
@ -257,7 +265,11 @@ func (v *Vmess) ListenPacketContext(ctx context.Context, metadata *C.Metadata, o
|
||||||
}
|
}
|
||||||
defer safeConnClose(c, err)
|
defer safeConnClose(c, err)
|
||||||
|
|
||||||
c, err = v.client.DialPacketConn(c, M.ParseSocksaddr(metadata.RemoteAddress()))
|
if v.option.XUDP {
|
||||||
|
c, err = v.client.DialXUDPPacketConn(c, M.ParseSocksaddr(metadata.RemoteAddress()))
|
||||||
|
} else {
|
||||||
|
c, err = v.client.DialPacketConn(c, M.ParseSocksaddr(metadata.RemoteAddress()))
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
c, err = dialer.DialContext(ctx, "tcp", v.addr, v.Base.DialOptions(opts...)...)
|
c, err = dialer.DialContext(ctx, "tcp", v.addr, v.Base.DialOptions(opts...)...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -274,7 +286,7 @@ func (v *Vmess) ListenPacketContext(ctx context.Context, metadata *C.Metadata, o
|
||||||
}
|
}
|
||||||
|
|
||||||
if v.option.PacketAddr {
|
if v.option.PacketAddr {
|
||||||
return newPacketConn(&threadSafePacketConn{PacketConn: packetaddr.NewBindClient(c)}, v), nil
|
return newPacketConn(&threadSafePacketConn{PacketConn: packetaddr.NewBindConn(c)}, v), nil
|
||||||
} else if pc, ok := c.(net.PacketConn); ok {
|
} else if pc, ok := c.(net.PacketConn); ok {
|
||||||
return newPacketConn(&threadSafePacketConn{PacketConn: pc}, v), nil
|
return newPacketConn(&threadSafePacketConn{PacketConn: pc}, v), nil
|
||||||
}
|
}
|
||||||
|
@ -284,7 +296,7 @@ func (v *Vmess) ListenPacketContext(ctx context.Context, metadata *C.Metadata, o
|
||||||
// ListenPacketOnStreamConn implements C.ProxyAdapter
|
// ListenPacketOnStreamConn implements C.ProxyAdapter
|
||||||
func (v *Vmess) ListenPacketOnStreamConn(c net.Conn, metadata *C.Metadata) (_ C.PacketConn, err error) {
|
func (v *Vmess) ListenPacketOnStreamConn(c net.Conn, metadata *C.Metadata) (_ C.PacketConn, err error) {
|
||||||
if v.option.PacketAddr {
|
if v.option.PacketAddr {
|
||||||
return newPacketConn(&threadSafePacketConn{PacketConn: packetaddr.NewBindClient(c)}, v), nil
|
return newPacketConn(&threadSafePacketConn{PacketConn: packetaddr.NewBindConn(c)}, v), nil
|
||||||
} else if pc, ok := c.(net.PacketConn); ok {
|
} else if pc, ok := c.(net.PacketConn); ok {
|
||||||
return newPacketConn(&threadSafePacketConn{PacketConn: pc}, v), nil
|
return newPacketConn(&threadSafePacketConn{PacketConn: pc}, v), nil
|
||||||
}
|
}
|
||||||
|
@ -307,6 +319,16 @@ func NewVmess(option VmessOption) (*Vmess, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch option.PacketEncoding {
|
||||||
|
case "packetaddr":
|
||||||
|
option.PacketAddr = true
|
||||||
|
case "xudp":
|
||||||
|
option.XUDP = true
|
||||||
|
}
|
||||||
|
if option.XUDP {
|
||||||
|
option.PacketAddr = false
|
||||||
|
}
|
||||||
|
|
||||||
switch option.Network {
|
switch option.Network {
|
||||||
case "h2", "grpc":
|
case "h2", "grpc":
|
||||||
if !option.TLS {
|
if !option.TLS {
|
||||||
|
@ -316,12 +338,13 @@ func NewVmess(option VmessOption) (*Vmess, error) {
|
||||||
|
|
||||||
v := &Vmess{
|
v := &Vmess{
|
||||||
Base: &Base{
|
Base: &Base{
|
||||||
name: option.Name,
|
name: option.Name,
|
||||||
addr: net.JoinHostPort(option.Server, strconv.Itoa(option.Port)),
|
addr: net.JoinHostPort(option.Server, strconv.Itoa(option.Port)),
|
||||||
tp: C.Vmess,
|
tp: C.Vmess,
|
||||||
udp: option.UDP,
|
udp: option.UDP,
|
||||||
iface: option.Interface,
|
iface: option.Interface,
|
||||||
rmark: option.RoutingMark,
|
rmark: option.RoutingMark,
|
||||||
|
prefer: C.NewDNSPrefer(option.IPVersion),
|
||||||
},
|
},
|
||||||
client: client,
|
client: client,
|
||||||
option: &option,
|
option: &option,
|
||||||
|
|
|
@ -5,8 +5,10 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/Dreamacro/clash/component/resolver"
|
"github.com/Dreamacro/clash/component/resolver"
|
||||||
|
"go.uber.org/atomic"
|
||||||
"net"
|
"net"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -16,6 +18,8 @@ var (
|
||||||
actualDualStackDialContext = dualStackDialContext
|
actualDualStackDialContext = dualStackDialContext
|
||||||
tcpConcurrent = false
|
tcpConcurrent = false
|
||||||
DisableIPv6 = false
|
DisableIPv6 = false
|
||||||
|
ErrorInvalidedNetworkStack = errors.New("invalided network stack")
|
||||||
|
ErrorDisableIPv6 = errors.New("IPv6 is disabled, dialer cancel")
|
||||||
)
|
)
|
||||||
|
|
||||||
func DialContext(ctx context.Context, network, address string, options ...Option) (net.Conn, error) {
|
func DialContext(ctx context.Context, network, address string, options ...Option) (net.Conn, error) {
|
||||||
|
@ -32,13 +36,23 @@ func DialContext(ctx context.Context, network, address string, options ...Option
|
||||||
o(opt)
|
o(opt)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if opt.network == 4 || opt.network == 6 {
|
||||||
|
if strings.Contains(network, "tcp") {
|
||||||
|
network = "tcp"
|
||||||
|
} else {
|
||||||
|
network = "udp"
|
||||||
|
}
|
||||||
|
|
||||||
|
network = fmt.Sprintf("%s%d", network, opt.network)
|
||||||
|
}
|
||||||
|
|
||||||
switch network {
|
switch network {
|
||||||
case "tcp4", "tcp6", "udp4", "udp6":
|
case "tcp4", "tcp6", "udp4", "udp6":
|
||||||
return actualSingleDialContext(ctx, network, address, opt)
|
return actualSingleDialContext(ctx, network, address, opt)
|
||||||
case "tcp", "udp":
|
case "tcp", "udp":
|
||||||
return actualDualStackDialContext(ctx, network, address, opt)
|
return actualDualStackDialContext(ctx, network, address, opt)
|
||||||
default:
|
default:
|
||||||
return nil, errors.New("network invalid")
|
return nil, ErrorInvalidedNetworkStack
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,10 +70,6 @@ func ListenPacket(ctx context.Context, network, address string, options ...Optio
|
||||||
o(cfg)
|
o(cfg)
|
||||||
}
|
}
|
||||||
|
|
||||||
if DisableIPv6 {
|
|
||||||
network = "udp4"
|
|
||||||
}
|
|
||||||
|
|
||||||
lc := &net.ListenConfig{}
|
lc := &net.ListenConfig{}
|
||||||
if cfg.interfaceName != "" {
|
if cfg.interfaceName != "" {
|
||||||
addr, err := bindIfaceToListenConfig(cfg.interfaceName, lc, network, address)
|
addr, err := bindIfaceToListenConfig(cfg.interfaceName, lc, network, address)
|
||||||
|
@ -108,7 +118,7 @@ func dialContext(ctx context.Context, network string, destination netip.Addr, po
|
||||||
}
|
}
|
||||||
|
|
||||||
if DisableIPv6 && destination.Is6() {
|
if DisableIPv6 && destination.Is6() {
|
||||||
return nil, fmt.Errorf("IPv6 is diabled, dialer cancel")
|
return nil, ErrorDisableIPv6
|
||||||
}
|
}
|
||||||
|
|
||||||
return dialer.DialContext(ctx, network, net.JoinHostPort(destination.String(), port))
|
return dialer.DialContext(ctx, network, net.JoinHostPort(destination.String(), port))
|
||||||
|
@ -208,7 +218,6 @@ func concurrentDualStackDialContext(ctx context.Context, network, address string
|
||||||
}
|
}
|
||||||
|
|
||||||
var ips []netip.Addr
|
var ips []netip.Addr
|
||||||
|
|
||||||
if opt.direct {
|
if opt.direct {
|
||||||
ips, err = resolver.ResolveAllIP(host)
|
ips, err = resolver.ResolveAllIP(host)
|
||||||
} else {
|
} else {
|
||||||
|
@ -230,29 +239,49 @@ func concurrentDialContext(ctx context.Context, network string, ips []netip.Addr
|
||||||
ip netip.Addr
|
ip netip.Addr
|
||||||
net.Conn
|
net.Conn
|
||||||
error
|
error
|
||||||
resolved bool
|
isPrimary bool
|
||||||
|
done bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
preferCount := atomic.NewInt32(0)
|
||||||
results := make(chan dialResult)
|
results := make(chan dialResult)
|
||||||
tcpRacer := func(ctx context.Context, ip netip.Addr) {
|
tcpRacer := func(ctx context.Context, ip netip.Addr) {
|
||||||
result := dialResult{ip: ip}
|
result := dialResult{ip: ip, done: true}
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
select {
|
select {
|
||||||
case results <- result:
|
case results <- result:
|
||||||
case <-returned:
|
case <-returned:
|
||||||
if result.Conn != nil {
|
if result.Conn != nil {
|
||||||
result.Conn.Close()
|
_ = result.Conn.Close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
if strings.Contains(network, "tcp") {
|
||||||
v := "4"
|
network = "tcp"
|
||||||
if ip.Is6() {
|
} else {
|
||||||
v = "6"
|
network = "udp"
|
||||||
}
|
}
|
||||||
|
|
||||||
result.Conn, result.error = dialContext(ctx, network+v, ip, port, opt)
|
if ip.Is6() {
|
||||||
|
network += "6"
|
||||||
|
if opt.prefer != 4 {
|
||||||
|
result.isPrimary = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ip.Is4() {
|
||||||
|
network += "4"
|
||||||
|
if opt.prefer != 6 {
|
||||||
|
result.isPrimary = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if result.isPrimary {
|
||||||
|
preferCount.Add(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
result.Conn, result.error = dialContext(ctx, network, ip, port, opt)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, ip := range ips {
|
for _, ip := range ips {
|
||||||
|
@ -260,17 +289,38 @@ func concurrentDialContext(ctx context.Context, network string, ips []netip.Addr
|
||||||
}
|
}
|
||||||
|
|
||||||
connCount := len(ips)
|
connCount := len(ips)
|
||||||
|
var fallback dialResult
|
||||||
for i := 0; i < connCount; i++ {
|
for i := 0; i < connCount; i++ {
|
||||||
select {
|
select {
|
||||||
case res := <-results:
|
case res := <-results:
|
||||||
if res.error == nil {
|
if res.error == nil {
|
||||||
return res.Conn, nil
|
if res.isPrimary {
|
||||||
|
return res.Conn, nil
|
||||||
|
} else {
|
||||||
|
if !fallback.done || fallback.error != nil {
|
||||||
|
fallback = res
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if res.isPrimary {
|
||||||
|
preferCount.Add(-1)
|
||||||
|
if preferCount.Load() == 0 && fallback.done && fallback.error == nil {
|
||||||
|
return fallback.Conn, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
|
if fallback.done && fallback.error == nil {
|
||||||
|
return fallback.Conn, nil
|
||||||
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if fallback.done && fallback.error == nil {
|
||||||
|
return fallback.Conn, nil
|
||||||
|
}
|
||||||
|
|
||||||
return nil, fmt.Errorf("all ips %v tcp shake hands failed", ips)
|
return nil, fmt.Errorf("all ips %v tcp shake hands failed", ips)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -303,25 +353,45 @@ func singleDialContext(ctx context.Context, network string, address string, opt
|
||||||
}
|
}
|
||||||
|
|
||||||
func concurrentSingleDialContext(ctx context.Context, network string, address string, opt *option) (net.Conn, error) {
|
func concurrentSingleDialContext(ctx context.Context, network string, address string, opt *option) (net.Conn, error) {
|
||||||
|
switch network {
|
||||||
|
case "tcp4", "udp4":
|
||||||
|
return concurrentIPv4DialContext(ctx, network, address, opt)
|
||||||
|
default:
|
||||||
|
return concurrentIPv6DialContext(ctx, network, address, opt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func concurrentIPv4DialContext(ctx context.Context, network, address string, opt *option) (net.Conn, error) {
|
||||||
host, port, err := net.SplitHostPort(address)
|
host, port, err := net.SplitHostPort(address)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var ips []netip.Addr
|
var ips []netip.Addr
|
||||||
switch network {
|
if !opt.direct {
|
||||||
case "tcp4", "udp4":
|
ips, err = resolver.ResolveAllIPv4ProxyServerHost(host)
|
||||||
if !opt.direct {
|
} else {
|
||||||
ips, err = resolver.ResolveAllIPv4ProxyServerHost(host)
|
ips, err = resolver.ResolveAllIPv4(host)
|
||||||
} else {
|
}
|
||||||
ips, err = resolver.ResolveAllIPv4(host)
|
|
||||||
}
|
if err != nil {
|
||||||
default:
|
return nil, err
|
||||||
if !opt.direct {
|
}
|
||||||
ips, err = resolver.ResolveAllIPv6ProxyServerHost(host)
|
|
||||||
} else {
|
return concurrentDialContext(ctx, network, ips, port, opt)
|
||||||
ips, err = resolver.ResolveAllIPv6(host)
|
}
|
||||||
}
|
|
||||||
|
func concurrentIPv6DialContext(ctx context.Context, network, address string, opt *option) (net.Conn, error) {
|
||||||
|
host, port, err := net.SplitHostPort(address)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var ips []netip.Addr
|
||||||
|
if !opt.direct {
|
||||||
|
ips, err = resolver.ResolveAllIPv6ProxyServerHost(host)
|
||||||
|
} else {
|
||||||
|
ips, err = resolver.ResolveAllIPv6(host)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package dialer
|
package dialer
|
||||||
|
|
||||||
import "go.uber.org/atomic"
|
import (
|
||||||
|
"go.uber.org/atomic"
|
||||||
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
DefaultOptions []Option
|
DefaultOptions []Option
|
||||||
|
@ -13,6 +15,8 @@ type option struct {
|
||||||
addrReuse bool
|
addrReuse bool
|
||||||
routingMark int
|
routingMark int
|
||||||
direct bool
|
direct bool
|
||||||
|
network int
|
||||||
|
prefer int
|
||||||
}
|
}
|
||||||
|
|
||||||
type Option func(opt *option)
|
type Option func(opt *option)
|
||||||
|
@ -40,3 +44,25 @@ func WithDirect() Option {
|
||||||
opt.direct = true
|
opt.direct = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func WithPreferIPv4() Option {
|
||||||
|
return func(opt *option) {
|
||||||
|
opt.prefer = 4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithPreferIPv6() Option {
|
||||||
|
return func(opt *option) {
|
||||||
|
opt.prefer = 6
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithOnlySingleStack(isIPv4 bool) Option {
|
||||||
|
return func(opt *option) {
|
||||||
|
if isIPv4 {
|
||||||
|
opt.network = 4
|
||||||
|
} else {
|
||||||
|
opt.network = 6
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -41,7 +41,6 @@ type Resolver interface {
|
||||||
ResolveIPv4(host string) (ip netip.Addr, err error)
|
ResolveIPv4(host string) (ip netip.Addr, err error)
|
||||||
ResolveIPv6(host string) (ip netip.Addr, err error)
|
ResolveIPv6(host string) (ip netip.Addr, err error)
|
||||||
ResolveAllIP(host string) (ip []netip.Addr, err error)
|
ResolveAllIP(host string) (ip []netip.Addr, err error)
|
||||||
ResolveAllIPPrimaryIPv4(host string) (ips []netip.Addr, err error)
|
|
||||||
ResolveAllIPv4(host string) (ips []netip.Addr, err error)
|
ResolveAllIPv4(host string) (ips []netip.Addr, err error)
|
||||||
ResolveAllIPv6(host string) (ips []netip.Addr, err error)
|
ResolveAllIPv6(host string) (ips []netip.Addr, err error)
|
||||||
}
|
}
|
||||||
|
@ -74,10 +73,10 @@ func ResolveIPv6WithResolver(host string, r Resolver) (netip.Addr, error) {
|
||||||
|
|
||||||
// ResolveIPWithResolver same as ResolveIP, but with a resolver
|
// ResolveIPWithResolver same as ResolveIP, but with a resolver
|
||||||
func ResolveIPWithResolver(host string, r Resolver) (netip.Addr, error) {
|
func ResolveIPWithResolver(host string, r Resolver) (netip.Addr, error) {
|
||||||
if ips, err := ResolveAllIPPrimaryIPv4WithResolver(host, r); err == nil {
|
if ip, err := ResolveIPv4WithResolver(host, r); err == nil {
|
||||||
return ips[rand.Intn(len(ips))], nil
|
return ip, nil
|
||||||
} else {
|
} else {
|
||||||
return netip.Addr{}, err
|
return ResolveIPv6WithResolver(host, r)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,7 +94,6 @@ func ResolveIPv4ProxyServerHost(host string) (netip.Addr, error) {
|
||||||
return ip, nil
|
return ip, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ResolveIPv4(host)
|
return ResolveIPv4(host)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,7 +106,6 @@ func ResolveIPv6ProxyServerHost(host string) (netip.Addr, error) {
|
||||||
return ip, nil
|
return ip, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ResolveIPv6(host)
|
return ResolveIPv6(host)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,7 +118,6 @@ func ResolveProxyServerHost(host string) (netip.Addr, error) {
|
||||||
return ip, err
|
return ip, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ResolveIP(host)
|
return ResolveIP(host)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,7 +156,6 @@ func ResolveAllIPv6WithResolver(host string, r Resolver) ([]netip.Addr, error) {
|
||||||
|
|
||||||
return []netip.Addr{netip.AddrFrom16(*(*[16]byte)(ipAddrs[rand.Intn(len(ipAddrs))]))}, nil
|
return []netip.Addr{netip.AddrFrom16(*(*[16]byte)(ipAddrs[rand.Intn(len(ipAddrs))]))}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return []netip.Addr{}, ErrIPNotFound
|
return []netip.Addr{}, ErrIPNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -200,7 +195,6 @@ func ResolveAllIPv4WithResolver(host string, r Resolver) ([]netip.Addr, error) {
|
||||||
|
|
||||||
return []netip.Addr{netip.AddrFrom4(*(*[4]byte)(ip))}, nil
|
return []netip.Addr{netip.AddrFrom4(*(*[4]byte)(ip))}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return []netip.Addr{}, ErrIPNotFound
|
return []netip.Addr{}, ErrIPNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -232,39 +226,6 @@ func ResolveAllIPWithResolver(host string, r Resolver) ([]netip.Addr, error) {
|
||||||
|
|
||||||
return []netip.Addr{nnip.IpToAddr(ipAddr.IP)}, nil
|
return []netip.Addr{nnip.IpToAddr(ipAddr.IP)}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return []netip.Addr{}, ErrIPNotFound
|
|
||||||
}
|
|
||||||
|
|
||||||
func ResolveAllIPPrimaryIPv4WithResolver(host string, r Resolver) ([]netip.Addr, error) {
|
|
||||||
if node := DefaultHosts.Search(host); node != nil {
|
|
||||||
return []netip.Addr{node.Data}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
ip, err := netip.ParseAddr(host)
|
|
||||||
if err == nil {
|
|
||||||
return []netip.Addr{ip}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if r != nil {
|
|
||||||
if DisableIPv6 {
|
|
||||||
return r.ResolveAllIPv4(host)
|
|
||||||
}
|
|
||||||
|
|
||||||
return r.ResolveAllIPPrimaryIPv4(host)
|
|
||||||
} else if DisableIPv6 {
|
|
||||||
return ResolveAllIPv4(host)
|
|
||||||
}
|
|
||||||
|
|
||||||
if DefaultResolver == nil {
|
|
||||||
ipAddr, err := net.ResolveIPAddr("ip", host)
|
|
||||||
if err != nil {
|
|
||||||
return []netip.Addr{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return []netip.Addr{nnip.IpToAddr(ipAddr.IP)}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return []netip.Addr{}, ErrIPNotFound
|
return []netip.Addr{}, ErrIPNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -284,7 +245,6 @@ func ResolveAllIPv6ProxyServerHost(host string) ([]netip.Addr, error) {
|
||||||
if ProxyServerHostResolver != nil {
|
if ProxyServerHostResolver != nil {
|
||||||
return ResolveAllIPv6WithResolver(host, ProxyServerHostResolver)
|
return ResolveAllIPv6WithResolver(host, ProxyServerHostResolver)
|
||||||
}
|
}
|
||||||
|
|
||||||
return ResolveAllIPv6(host)
|
return ResolveAllIPv6(host)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -292,7 +252,6 @@ func ResolveAllIPv4ProxyServerHost(host string) ([]netip.Addr, error) {
|
||||||
if ProxyServerHostResolver != nil {
|
if ProxyServerHostResolver != nil {
|
||||||
return ResolveAllIPv4WithResolver(host, ProxyServerHostResolver)
|
return ResolveAllIPv4WithResolver(host, ProxyServerHostResolver)
|
||||||
}
|
}
|
||||||
|
|
||||||
return ResolveAllIPv4(host)
|
return ResolveAllIPv4(host)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -300,6 +259,5 @@ func ResolveAllIPProxyServerHost(host string) ([]netip.Addr, error) {
|
||||||
if ProxyServerHostResolver != nil {
|
if ProxyServerHostResolver != nil {
|
||||||
return ResolveAllIPWithResolver(host, ProxyServerHostResolver)
|
return ResolveAllIPWithResolver(host, ProxyServerHostResolver)
|
||||||
}
|
}
|
||||||
|
|
||||||
return ResolveAllIP(host)
|
return ResolveAllIP(host)
|
||||||
}
|
}
|
||||||
|
|
130
config/config.go
130
config/config.go
|
@ -153,6 +153,7 @@ type Config struct {
|
||||||
Hosts *trie.DomainTrie[netip.Addr]
|
Hosts *trie.DomainTrie[netip.Addr]
|
||||||
Profile *Profile
|
Profile *Profile
|
||||||
Rules []C.Rule
|
Rules []C.Rule
|
||||||
|
SubRules *map[string][]C.Rule
|
||||||
Users []auth.AuthUser
|
Users []auth.AuthUser
|
||||||
Proxies map[string]C.Proxy
|
Proxies map[string]C.Proxy
|
||||||
Providers map[string]providerTypes.ProxyProvider
|
Providers map[string]providerTypes.ProxyProvider
|
||||||
|
@ -233,6 +234,7 @@ type RawConfig struct {
|
||||||
Proxy []map[string]any `yaml:"proxies"`
|
Proxy []map[string]any `yaml:"proxies"`
|
||||||
ProxyGroup []map[string]any `yaml:"proxy-groups"`
|
ProxyGroup []map[string]any `yaml:"proxy-groups"`
|
||||||
Rule []string `yaml:"rules"`
|
Rule []string `yaml:"rules"`
|
||||||
|
SubRules map[string][]string `yaml:"sub-rules"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type RawGeoXUrl struct {
|
type RawGeoXUrl struct {
|
||||||
|
@ -381,12 +383,18 @@ func ParseRawConfig(rawCfg *RawConfig) (*Config, error) {
|
||||||
config.Proxies = proxies
|
config.Proxies = proxies
|
||||||
config.Providers = providers
|
config.Providers = providers
|
||||||
|
|
||||||
rules, ruleProviders, err := parseRules(rawCfg, proxies)
|
subRules, ruleProviders, err := parseSubRules(rawCfg, proxies)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
config.SubRules = subRules
|
||||||
|
config.RuleProviders = ruleProviders
|
||||||
|
|
||||||
|
rules, err := parseRules(rawCfg, proxies, subRules)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
config.Rules = rules
|
config.Rules = rules
|
||||||
config.RuleProviders = ruleProviders
|
|
||||||
|
|
||||||
hosts, err := parseHosts(rawCfg)
|
hosts, err := parseHosts(rawCfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -563,8 +571,9 @@ func parseProxies(cfg *RawConfig) (proxies map[string]C.Proxy, providersMap map[
|
||||||
return proxies, providersMap, nil
|
return proxies, providersMap, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseRules(cfg *RawConfig, proxies map[string]C.Proxy) ([]C.Rule, map[string]providerTypes.RuleProvider, error) {
|
func parseSubRules(cfg *RawConfig, proxies map[string]C.Proxy) (subRules *map[string][]C.Rule, ruleProviders map[string]providerTypes.RuleProvider, err error) {
|
||||||
ruleProviders := map[string]providerTypes.RuleProvider{}
|
ruleProviders = map[string]providerTypes.RuleProvider{}
|
||||||
|
subRules = &map[string][]C.Rule{}
|
||||||
log.Infoln("Geodata Loader mode: %s", geodata.LoaderName())
|
log.Infoln("Geodata Loader mode: %s", geodata.LoaderName())
|
||||||
// parse rule provider
|
// parse rule provider
|
||||||
for name, mapping := range cfg.RuleProvider {
|
for name, mapping := range cfg.RuleProvider {
|
||||||
|
@ -577,6 +586,102 @@ func parseRules(cfg *RawConfig, proxies map[string]C.Proxy) ([]C.Rule, map[strin
|
||||||
RP.SetRuleProvider(rp)
|
RP.SetRuleProvider(rp)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for name, rawRules := range cfg.SubRules {
|
||||||
|
var rules []C.Rule
|
||||||
|
for idx, line := range rawRules {
|
||||||
|
rawRule := trimArr(strings.Split(line, ","))
|
||||||
|
var (
|
||||||
|
payload string
|
||||||
|
target string
|
||||||
|
params []string
|
||||||
|
ruleName = strings.ToUpper(rawRule[0])
|
||||||
|
)
|
||||||
|
|
||||||
|
l := len(rawRule)
|
||||||
|
|
||||||
|
if ruleName == "NOT" || ruleName == "OR" || ruleName == "AND" || ruleName == "SUB-RULE" {
|
||||||
|
target = rawRule[l-1]
|
||||||
|
payload = strings.Join(rawRule[1:l-1], ",")
|
||||||
|
} else {
|
||||||
|
if l < 2 {
|
||||||
|
return nil, nil, fmt.Errorf("sub-rules[%d] [%s] error: format invalid", idx, line)
|
||||||
|
}
|
||||||
|
if l < 4 {
|
||||||
|
rawRule = append(rawRule, make([]string, 4-l)...)
|
||||||
|
}
|
||||||
|
if ruleName == "MATCH" {
|
||||||
|
l = 2
|
||||||
|
}
|
||||||
|
if l >= 3 {
|
||||||
|
l = 3
|
||||||
|
payload = rawRule[1]
|
||||||
|
}
|
||||||
|
target = rawRule[l-1]
|
||||||
|
params = rawRule[l:]
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := proxies[target]; !ok && ruleName != "SUB-RULE" {
|
||||||
|
return nil, nil, fmt.Errorf("sub-rules[%d:%s] [%s] error: proxy [%s] not found", idx, name, line, target)
|
||||||
|
}
|
||||||
|
|
||||||
|
params = trimArr(params)
|
||||||
|
parsed, parseErr := R.ParseRule(ruleName, payload, target, params, subRules)
|
||||||
|
if parseErr != nil {
|
||||||
|
return nil, nil, fmt.Errorf("sub-rules[%d] [%s] error: %s", idx, line, parseErr.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
rules = append(rules, parsed)
|
||||||
|
}
|
||||||
|
(*subRules)[name] = rules
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = verifySubRule(subRules); err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func verifySubRule(subRules *map[string][]C.Rule) error {
|
||||||
|
for name := range *subRules {
|
||||||
|
err := verifySubRuleCircularReferences(name, subRules, []string{})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func verifySubRuleCircularReferences(n string, subRules *map[string][]C.Rule, arr []string) error {
|
||||||
|
isInArray := func(v string, array []string) bool {
|
||||||
|
for _, c := range array {
|
||||||
|
if v == c {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
arr = append(arr, n)
|
||||||
|
for i, rule := range (*subRules)[n] {
|
||||||
|
if rule.RuleType() == C.SubRules {
|
||||||
|
if _, ok := (*subRules)[rule.Adapter()]; !ok {
|
||||||
|
return fmt.Errorf("sub-rule[%d:%s] error: [%s] not found", i, n, rule.Adapter())
|
||||||
|
}
|
||||||
|
if isInArray(rule.Adapter(), arr) {
|
||||||
|
arr = append(arr, rule.Adapter())
|
||||||
|
return fmt.Errorf("sub-rule error: circular references [%s]", strings.Join(arr, "->"))
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := verifySubRuleCircularReferences(rule.Adapter(), subRules, arr); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseRules(cfg *RawConfig, proxies map[string]C.Proxy, subRules *map[string][]C.Rule) ([]C.Rule, error) {
|
||||||
var rules []C.Rule
|
var rules []C.Rule
|
||||||
rulesConfig := cfg.Rule
|
rulesConfig := cfg.Rule
|
||||||
|
|
||||||
|
@ -592,12 +697,12 @@ func parseRules(cfg *RawConfig, proxies map[string]C.Proxy) ([]C.Rule, map[strin
|
||||||
|
|
||||||
l := len(rule)
|
l := len(rule)
|
||||||
|
|
||||||
if ruleName == "NOT" || ruleName == "OR" || ruleName == "AND" {
|
if ruleName == "NOT" || ruleName == "OR" || ruleName == "AND" || ruleName == "SUB-RULE" {
|
||||||
target = rule[l-1]
|
target = rule[l-1]
|
||||||
payload = strings.Join(rule[1:l-1], ",")
|
payload = strings.Join(rule[1:l-1], ",")
|
||||||
} else {
|
} else {
|
||||||
if l < 2 {
|
if l < 2 {
|
||||||
return nil, nil, fmt.Errorf("rules[%d] [%s] error: format invalid", idx, line)
|
return nil, fmt.Errorf("rules[%d] [%s] error: format invalid", idx, line)
|
||||||
}
|
}
|
||||||
if l < 4 {
|
if l < 4 {
|
||||||
rule = append(rule, make([]string, 4-l)...)
|
rule = append(rule, make([]string, 4-l)...)
|
||||||
|
@ -612,15 +717,18 @@ func parseRules(cfg *RawConfig, proxies map[string]C.Proxy) ([]C.Rule, map[strin
|
||||||
target = rule[l-1]
|
target = rule[l-1]
|
||||||
params = rule[l:]
|
params = rule[l:]
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, ok := proxies[target]; !ok {
|
if _, ok := proxies[target]; !ok {
|
||||||
return nil, nil, fmt.Errorf("rules[%d] [%s] error: proxy [%s] not found", idx, line, target)
|
if ruleName != "SUB-RULE" {
|
||||||
|
return nil, fmt.Errorf("rules[%d] [%s] error: proxy [%s] not found", idx, line, target)
|
||||||
|
} else if _, ok = (*subRules)[target]; !ok {
|
||||||
|
return nil, fmt.Errorf("rules[%d] [%s] error: sub-rule [%s] not found", idx, line, target)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
params = trimArr(params)
|
params = trimArr(params)
|
||||||
parsed, parseErr := R.ParseRule(ruleName, payload, target, params)
|
parsed, parseErr := R.ParseRule(ruleName, payload, target, params, subRules)
|
||||||
if parseErr != nil {
|
if parseErr != nil {
|
||||||
return nil, nil, fmt.Errorf("rules[%d] [%s] error: %s", idx, line, parseErr.Error())
|
return nil, fmt.Errorf("rules[%d] [%s] error: %s", idx, line, parseErr.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
rules = append(rules, parsed)
|
rules = append(rules, parsed)
|
||||||
|
@ -628,7 +736,7 @@ func parseRules(cfg *RawConfig, proxies map[string]C.Proxy) ([]C.Rule, map[strin
|
||||||
|
|
||||||
runtime.GC()
|
runtime.GC()
|
||||||
|
|
||||||
return rules, ruleProviders, nil
|
return rules, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseHosts(cfg *RawConfig) (*trie.DomainTrie[netip.Addr], error) {
|
func parseHosts(cfg *RawConfig) (*trie.DomainTrie[netip.Addr], error) {
|
||||||
|
|
|
@ -68,3 +68,46 @@ func (e DNSMode) String() string {
|
||||||
return "unknown"
|
return "unknown"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type DNSPrefer int
|
||||||
|
|
||||||
|
const (
|
||||||
|
DualStack DNSPrefer = iota
|
||||||
|
IPv4Only
|
||||||
|
IPv6Only
|
||||||
|
IPv4Prefer
|
||||||
|
IPv6Prefer
|
||||||
|
)
|
||||||
|
|
||||||
|
var dnsPreferMap = map[string]DNSPrefer{
|
||||||
|
DualStack.String(): DualStack,
|
||||||
|
IPv4Only.String(): IPv4Only,
|
||||||
|
IPv6Only.String(): IPv6Only,
|
||||||
|
IPv4Prefer.String(): IPv4Prefer,
|
||||||
|
IPv6Prefer.String(): IPv6Prefer,
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d DNSPrefer) String() string {
|
||||||
|
switch d {
|
||||||
|
case DualStack:
|
||||||
|
return "dual"
|
||||||
|
case IPv4Only:
|
||||||
|
return "ipv4"
|
||||||
|
case IPv6Only:
|
||||||
|
return "ipv6"
|
||||||
|
case IPv4Prefer:
|
||||||
|
return "ipv4-prefer"
|
||||||
|
case IPv6Prefer:
|
||||||
|
return "ipv6-prefer"
|
||||||
|
default:
|
||||||
|
return "dual"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDNSPrefer(prefer string) DNSPrefer {
|
||||||
|
if p, ok := dnsPreferMap[prefer]; ok {
|
||||||
|
return p
|
||||||
|
} else {
|
||||||
|
return DualStack
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ const (
|
||||||
Network
|
Network
|
||||||
Uid
|
Uid
|
||||||
INTYPE
|
INTYPE
|
||||||
|
SubRules
|
||||||
MATCH
|
MATCH
|
||||||
AND
|
AND
|
||||||
OR
|
OR
|
||||||
|
@ -65,6 +66,8 @@ func (rt RuleType) String() string {
|
||||||
return "Uid"
|
return "Uid"
|
||||||
case INTYPE:
|
case INTYPE:
|
||||||
return "InType"
|
return "InType"
|
||||||
|
case SubRules:
|
||||||
|
return "SubRules"
|
||||||
case AND:
|
case AND:
|
||||||
return "AND"
|
return "AND"
|
||||||
case OR:
|
case OR:
|
||||||
|
@ -78,7 +81,7 @@ func (rt RuleType) String() string {
|
||||||
|
|
||||||
type Rule interface {
|
type Rule interface {
|
||||||
RuleType() RuleType
|
RuleType() RuleType
|
||||||
Match(metadata *Metadata) bool
|
Match(metadata *Metadata) (bool, string)
|
||||||
Adapter() string
|
Adapter() string
|
||||||
Payload() string
|
Payload() string
|
||||||
ShouldResolveIP() bool
|
ShouldResolveIP() bool
|
||||||
|
|
34
default.nix
Executable file
34
default.nix
Executable file
|
@ -0,0 +1,34 @@
|
||||||
|
{ lib
|
||||||
|
, fetchFromGitHub
|
||||||
|
, buildGoModule
|
||||||
|
}:
|
||||||
|
buildGoModule rec {
|
||||||
|
pname = "clash-meta";
|
||||||
|
version = "dev";
|
||||||
|
src = ./.;
|
||||||
|
vendorSha256 = "sha256-7HjYcoqWA5gvPUc5psCgy0UTc17CBzBJ/OiGvII/iBA=";
|
||||||
|
|
||||||
|
# Do not build testing suit
|
||||||
|
excludedPackages = [ "./test" ];
|
||||||
|
|
||||||
|
CGO_ENABLED = 0;
|
||||||
|
|
||||||
|
ldflags = [
|
||||||
|
"-s"
|
||||||
|
"-w"
|
||||||
|
"-X github.com/Dreamacro/clash/constant.Version=${version}"
|
||||||
|
];
|
||||||
|
|
||||||
|
# network required
|
||||||
|
doCheck = false;
|
||||||
|
|
||||||
|
postInstall = ''
|
||||||
|
mv $out/bin/clash $out/bin/clash-meta
|
||||||
|
'';
|
||||||
|
|
||||||
|
meta = with lib; {
|
||||||
|
description = "Another Clash Kernel";
|
||||||
|
homepage = "https://github.com/MetaCubeX/Clash.Meta";
|
||||||
|
license = licenses.gpl3Only;
|
||||||
|
};
|
||||||
|
}
|
|
@ -88,7 +88,7 @@ func (r *Resolver) ResolveAllIP(host string) (ips []netip.Addr, err error) {
|
||||||
return nil, resolver.ErrIPNotFound
|
return nil, resolver.ErrIPNotFound
|
||||||
}
|
}
|
||||||
ips = append(ips, ipv6s...)
|
ips = append(ips, ipv6s...)
|
||||||
case <-time.After(1 * time.Millisecond):
|
case <-time.After(30 * time.Millisecond):
|
||||||
// wait ipv6 result
|
// wait ipv6 result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,19 +1,19 @@
|
||||||
# port: 7890 # HTTP(S) 代理服务器端口
|
# port: 7890 # HTTP(S) 代理服务器端口
|
||||||
# socks-port: 7891 # SOCKS5 代理端口
|
# socks-port: 7891 # SOCKS5 代理端口
|
||||||
mixed-port: 10801 # HTTP(S) 和 SOCKS 代理混合端口
|
mixed-port: 10801 # HTTP(S) 和 SOCKS 代理混合端口
|
||||||
# redir-port: 7892 # 透明代理端口 用于Linux和
|
# redir-port: 7892 # 透明代理端口,用于 Linux 和 MacOS
|
||||||
|
|
||||||
# Transparent proxy server port for Linux (TProxy TCP and TProxy UDP)
|
# Transparent proxy server port for Linux (TProxy TCP and TProxy UDP)
|
||||||
# tproxy-port: 7893
|
# tproxy-port: 7893
|
||||||
|
|
||||||
allow-lan: true # 允许局域网连接
|
allow-lan: true # 允许局域网连接
|
||||||
bind-address: "*" # 绑定IP地址,仅作用于 allow-lan 为true, '*'表示所有地址
|
bind-address: "*" # 绑定IP地址,仅作用于 allow-lan 为 true,'*'表示所有地址
|
||||||
|
|
||||||
mode: rule
|
mode: rule
|
||||||
|
|
||||||
log-level: debug #日志等级 silent/error/warning/info/debug
|
log-level: debug # 日志等级 silent/error/warning/info/debug
|
||||||
|
|
||||||
ipv6: true #开启IPv6总开关 关闭阻断所有IPv6和屏蔽DNS请求AAAA记录
|
ipv6: true # 开启 IPv6 总开关,关闭阻断所有 IPv6 链接和屏蔽 DNS 请求 AAAA 记录
|
||||||
|
|
||||||
external-controller: 0.0.0.0:9093 # RESTful API 监听地址
|
external-controller: 0.0.0.0:9093 # RESTful API 监听地址
|
||||||
|
|
||||||
|
@ -24,33 +24,33 @@ external-ui: /path/to/ui/folder # 配置WEB UI目录,使用http://{{external-c
|
||||||
|
|
||||||
# interface-name: en0 # 设置出口网卡
|
# interface-name: en0 # 设置出口网卡
|
||||||
|
|
||||||
# routing-mark: 6666 # 配置fwmark 仅用于Linux
|
# routing-mark: 6666 # 配置 fwmark 仅用于Linux
|
||||||
experimental:
|
experimental:
|
||||||
# 具体配置待定
|
# 具体配置待定
|
||||||
# 证书指纹,SHA256格式,补充校验TLS证书
|
# 证书指纹,SHA256格式,补充校验TLS证书
|
||||||
# 可使用 openssl x509 -noout -fingerprint -sha256 -inform pem -in yourcert.pem 获取
|
# 可使用 openssl x509 -noout -fingerprint -sha256 -inform pem -in yourcert.pem 获取
|
||||||
fingerprints:
|
fingerprints:
|
||||||
- "8F111FA9AD3CD8E917A118522CAC39EA33741B3BBE73F91CECE548D5CCB0E5E8" # 忽略大小写
|
- "8F111FA9AD3CD8E917A118522CAC39EA33741B3BBE73F91CECE548D5CCB0E5E8" # 忽略大小写
|
||||||
# 类似于/etc/hosts, 仅支持配置单个IP
|
# 类似于 /etc/hosts, 仅支持配置单个 IP
|
||||||
hosts:
|
hosts:
|
||||||
# '*.clash.dev': 127.0.0.1
|
# '*.clash.dev': 127.0.0.1
|
||||||
# '.dev': 127.0.0.1
|
# '.dev': 127.0.0.1
|
||||||
# 'alpha.clash.dev': '::1'
|
# 'alpha.clash.dev': '::1'
|
||||||
|
|
||||||
# Tun配置
|
# Tun 配置
|
||||||
tun:
|
tun:
|
||||||
enable: false
|
enable: false
|
||||||
stack: system # gvisor
|
stack: system # gvisor
|
||||||
dns-hijack:
|
dns-hijack:
|
||||||
- 198.18.0.2:53 # 需要劫持的DNS
|
- 198.18.0.2:53 # 需要劫持的 DNS
|
||||||
# auto-detect-interface: true # 自动识别interface
|
# auto-detect-interface: true # 自动识别出口网卡
|
||||||
# auto-route: true # 配置
|
# auto-route: true # 配置路由表
|
||||||
|
|
||||||
#ebpf配置
|
#ebpf配置
|
||||||
ebpf:
|
ebpf:
|
||||||
auto-redir: #redirect模式,仅支持TCP
|
auto-redir: # redirect 模式,仅支持 TCP
|
||||||
- eth0
|
- eth0
|
||||||
redirect-to-tun: #UDP+TCP,使用该功能请勿启用auto-route
|
redirect-to-tun: # UDP+TCP 使用该功能请勿启用 auto-route
|
||||||
- eth0
|
- eth0
|
||||||
|
|
||||||
# 嗅探域名 可选配置
|
# 嗅探域名 可选配置
|
||||||
|
@ -63,7 +63,7 @@ sniffer:
|
||||||
# 强制对此域名进行嗅探
|
# 强制对此域名进行嗅探
|
||||||
force-domain:
|
force-domain:
|
||||||
- +.v2ex.com
|
- +.v2ex.com
|
||||||
# 仅对白名单中的端口进行嗅探,默认为0-65535,推荐只对需要嗅探写的的常见端口嗅探
|
# 仅对白名单中的端口进行嗅探,默认为 443,80
|
||||||
port-whitelist:
|
port-whitelist:
|
||||||
- "80"
|
- "80"
|
||||||
- "443"
|
- "443"
|
||||||
|
@ -78,12 +78,12 @@ profile:
|
||||||
|
|
||||||
# DNS配置
|
# DNS配置
|
||||||
dns:
|
dns:
|
||||||
enable: false # 关闭将使用系统DNS
|
enable: false # 关闭将使用系统 DNS
|
||||||
listen: 0.0.0.0:53 # 开启DNS服务器监听
|
listen: 0.0.0.0:53 # 开启 DNS 服务器监听
|
||||||
# ipv6: false # false将返回AAAA的空结果
|
# ipv6: false # false 将返回 AAAA 的空结果
|
||||||
|
|
||||||
# 用于解析nameserver,fallbacky以及其他DNS服务器配置的,DNS服务域名
|
# 用于解析 nameserver,fallback 以及其他DNS服务器配置的,DNS 服务域名
|
||||||
# 只能使用纯IP地址,可使用加密DNS
|
# 只能使用纯 IP 地址,可使用加密 DNS
|
||||||
default-nameserver:
|
default-nameserver:
|
||||||
- 114.114.114.114
|
- 114.114.114.114
|
||||||
- 8.8.8.8
|
- 8.8.8.8
|
||||||
|
@ -93,7 +93,7 @@ dns:
|
||||||
|
|
||||||
fake-ip-range: 198.18.0.1/16 # fake-ip 池设置
|
fake-ip-range: 198.18.0.1/16 # fake-ip 池设置
|
||||||
|
|
||||||
# use-hosts: true # 查询hosts
|
# use-hosts: true # 查询 hosts
|
||||||
|
|
||||||
# 配置不使用fake-ip的域名
|
# 配置不使用fake-ip的域名
|
||||||
# fake-ip-filter:
|
# fake-ip-filter:
|
||||||
|
@ -101,40 +101,40 @@ dns:
|
||||||
# - localhost.ptlogin2.qq.com
|
# - localhost.ptlogin2.qq.com
|
||||||
|
|
||||||
# DNS主要域名配置
|
# DNS主要域名配置
|
||||||
# 支持 UDP,TCP,DoT,DoH,DoQ
|
# 支持 UDP,TCP,DoT,DoH,DoQ
|
||||||
# 这部分为主要DNS配置,影响所有直连,确保使用对大陆解析精准的DNS
|
# 这部分为主要 DNS 配置,影响所有直连,确保使用对大陆解析精准的 DNS
|
||||||
nameserver:
|
nameserver:
|
||||||
- 114.114.114.114 # default value
|
- 114.114.114.114 # default value
|
||||||
- 8.8.8.8 # default value
|
- 8.8.8.8 # default value
|
||||||
- tls://223.5.5.5:853 # DNS over TLS
|
- tls://223.5.5.5:853 # DNS over TLS
|
||||||
- https://doh.pub/dns-query # DNS over HTTPS
|
- https://doh.pub/dns-query # DNS over HTTPS
|
||||||
- https://dns.alidns.com/dns-query#h3=true # 强制HTTP/3
|
- https://dns.alidns.com/dns-query#h3=true # 强制HTTP/3
|
||||||
- https://mozilla.cloudflare-dns.com/dns-query#DNS&h3=true # 指定策略组和使用HTTP/3
|
- https://mozilla.cloudflare-dns.com/dns-query#DNS&h3=true # 指定策略组和使用 HTTP/3
|
||||||
- dhcp://en0 # dns from dhcp
|
- dhcp://en0 # dns from dhcp
|
||||||
- quic://dns.adguard.com:784 # DNS over QUIC
|
- quic://dns.adguard.com:784 # DNS over QUIC
|
||||||
# - '8.8.8.8#en0' # 兼容指定DNS出口网卡
|
# - '8.8.8.8#en0' # 兼容指定DNS出口网卡
|
||||||
|
|
||||||
# 当配置fallback时,会查询nameserver中返回的IP是否为CN,非必要配置
|
# 当配置 fallback 时,会查询 nameserver 中返回的 IP 是否为 CN,非必要配置
|
||||||
# 当不是CN,则使用fallback中的DNS查询结果
|
# 当不是 CN,则使用 fallback 中的 DNS 查询结果
|
||||||
# 确保配置fallback时能够正常查询
|
# 确保配置 fallback 时能够正常查询
|
||||||
# fallback:
|
# fallback:
|
||||||
# - tcp://1.1.1.1
|
# - tcp://1.1.1.1
|
||||||
# - 'tcp://1.1.1.1#ProxyGroupName' # 指定DNS过代理查询,ProxyGroupName为策略组名或节点名,过代理配置优先于配置出口网卡,当找不到策略组或节点名则设置为出口网卡
|
# - 'tcp://1.1.1.1#ProxyGroupName' # 指定 DNS 过代理查询,ProxyGroupName 为策略组名或节点名,过代理配置优先于配置出口网卡,当找不到策略组或节点名则设置为出口网卡
|
||||||
|
|
||||||
# 专用于节点域名解析的DNS服务器,非必要配置项
|
# 专用于节点域名解析的 DNS 服务器,非必要配置项
|
||||||
# 配置服务器若查询失败将使用nameserver,非并发查询
|
# 配置服务器若查询失败将使用 nameserver,非并发查询
|
||||||
# proxy-server-nameserver:
|
# proxy-server-nameserver:
|
||||||
# - https://dns.google/dns-query
|
# - https://dns.google/dns-query
|
||||||
# - tls://one.one.one.one
|
# - tls://one.one.one.one
|
||||||
|
|
||||||
# 配置fallback使用条件
|
# 配置 fallback 使用条件
|
||||||
# fallback-filter:
|
# fallback-filter:
|
||||||
# geoip: true # 配置是否使用geoip
|
# geoip: true # 配置是否使用 geoip
|
||||||
# geoip-code: CN # 当nameserver域名的IP查询geoip库为CN时,不使用fallback
|
# geoip-code: CN # 当 nameserver 域名的 IP 查询 geoip 库为 CN 时,不使用 fallback 中的 DNS 查询结果
|
||||||
# 配置强制fallback,优先于IP判断,具体分类自行查看geosite库
|
# 配置强制 fallback,优先于 IP 判断,具体分类自行查看 geosite 库
|
||||||
# geosite:
|
# geosite:
|
||||||
# - gfw
|
# - gfw
|
||||||
# 配置不需要使用fallback的IP CIDR
|
# 如果不匹配 ipcidr 则使用 nameservers 中的结果
|
||||||
# ipcidr:
|
# ipcidr:
|
||||||
# - 240.0.0.0/4
|
# - 240.0.0.0/4
|
||||||
# domain:
|
# domain:
|
||||||
|
@ -142,7 +142,7 @@ dns:
|
||||||
# - '+.facebook.com'
|
# - '+.facebook.com'
|
||||||
# - '+.youtube.com'
|
# - '+.youtube.com'
|
||||||
|
|
||||||
# 配置查询域名使用的DNS服务器
|
# 配置查询域名使用的 DNS 服务器
|
||||||
# nameserver-policy:
|
# nameserver-policy:
|
||||||
# 'www.baidu.com': '114.114.114.114'
|
# 'www.baidu.com': '114.114.114.114'
|
||||||
# '+.internal.crop.com': '10.0.0.1'
|
# '+.internal.crop.com': '10.0.0.1'
|
||||||
|
@ -164,7 +164,12 @@ proxies:
|
||||||
password: "password"
|
password: "password"
|
||||||
# udp: true
|
# udp: true
|
||||||
# udp-over-tcp: false
|
# udp-over-tcp: false
|
||||||
|
# ip-version: ipv4 # 设置节点使用 IP 版本,可选:dual,ipv4,ipv6,ipv4-prefer,ipv6-prefer。默认使用 dual
|
||||||
|
# ipv4:仅使用 IPv4 ipv6:仅使用 IPv6
|
||||||
|
# ipv4-prefer:优先使用 IPv4 对于 TCP 会进行双栈解析,并发链接但是优先使用 IPv4 链接,
|
||||||
|
# UDP 则为双栈解析,获取结果中的第一个 IPv4
|
||||||
|
# ipv6-prefer 同 ipv4-prefer
|
||||||
|
# 现有协议都支持此参数,TCP 效果仅在开启 tcp-concurrent 生效
|
||||||
- name: "ss2"
|
- name: "ss2"
|
||||||
type: ss
|
type: ss
|
||||||
server: server
|
server: server
|
||||||
|
@ -249,6 +254,7 @@ proxies:
|
||||||
# # headers:
|
# # headers:
|
||||||
# # Connection:
|
# # Connection:
|
||||||
# # - keep-alive
|
# # - keep-alive
|
||||||
|
# ip-version: ipv4 # 设置使用 IP 类型偏好,可选:ipv4,ipv6,dual,默认值:dual
|
||||||
|
|
||||||
- name: vmess-grpc
|
- name: vmess-grpc
|
||||||
server: server
|
server: server
|
||||||
|
@ -264,6 +270,7 @@ proxies:
|
||||||
# skip-cert-verify: true
|
# skip-cert-verify: true
|
||||||
grpc-opts:
|
grpc-opts:
|
||||||
grpc-service-name: "example"
|
grpc-service-name: "example"
|
||||||
|
# ip-version: ipv4
|
||||||
|
|
||||||
# socks5
|
# socks5
|
||||||
- name: "socks"
|
- name: "socks"
|
||||||
|
@ -276,6 +283,7 @@ proxies:
|
||||||
# fingerprint: xxxx
|
# fingerprint: xxxx
|
||||||
# skip-cert-verify: true
|
# skip-cert-verify: true
|
||||||
# udp: true
|
# udp: true
|
||||||
|
# ip-version: ipv6
|
||||||
|
|
||||||
# http
|
# http
|
||||||
- name: "http"
|
- name: "http"
|
||||||
|
@ -288,6 +296,7 @@ proxies:
|
||||||
# skip-cert-verify: true
|
# skip-cert-verify: true
|
||||||
# sni: custom.com
|
# sni: custom.com
|
||||||
# fingerprint: xxxx # 同 experimental.fingerprints 使用 sha256 指纹,配置协议独立的指纹,将忽略 experimental.fingerprints
|
# fingerprint: xxxx # 同 experimental.fingerprints 使用 sha256 指纹,配置协议独立的指纹,将忽略 experimental.fingerprints
|
||||||
|
# ip-version: dual
|
||||||
|
|
||||||
# Snell
|
# Snell
|
||||||
# Beware that there's currently no UDP support yet
|
# Beware that there's currently no UDP support yet
|
||||||
|
@ -389,9 +398,9 @@ proxies:
|
||||||
auth_str: yourpassword
|
auth_str: yourpassword
|
||||||
# obfs: obfs_str
|
# obfs: obfs_str
|
||||||
# alpn: h3
|
# alpn: h3
|
||||||
protocol: udp #支持udp/wechat-video/faketcp
|
protocol: udp # 支持 udp/wechat-video/faketcp
|
||||||
up: "30 Mbps" #若不写单位,默认为Mbps
|
up: "30 Mbps" # 若不写单位,默认为 Mbps
|
||||||
down: "200 Mbps" #若不写单位,默认为Mbps
|
down: "200 Mbps" # 若不写单位,默认为 Mbps
|
||||||
#sni: server.com
|
#sni: server.com
|
||||||
#skip-cert-verify: false
|
#skip-cert-verify: false
|
||||||
#recv_window_conn: 12582912
|
#recv_window_conn: 12582912
|
||||||
|
@ -422,7 +431,7 @@ proxies:
|
||||||
# udp: true
|
# udp: true
|
||||||
|
|
||||||
proxy-groups:
|
proxy-groups:
|
||||||
# 代理链,若落地协议支持UDP over TCP则可支持UDP
|
# 代理链,若落地协议支持 UDP over TCP 则可支持 UDP
|
||||||
# Traffic: clash <-> http <-> vmess <-> ss1 <-> ss2 <-> Internet
|
# Traffic: clash <-> http <-> vmess <-> ss1 <-> ss2 <-> Internet
|
||||||
- name: "relay"
|
- name: "relay"
|
||||||
type: relay
|
type: relay
|
||||||
|
@ -432,7 +441,7 @@ proxy-groups:
|
||||||
- ss1
|
- ss1
|
||||||
- ss2
|
- ss2
|
||||||
|
|
||||||
# url-test 将按照url测试结果使用延迟最低节点
|
# url-test 将按照 url 测试结果使用延迟最低节点
|
||||||
- name: "auto"
|
- name: "auto"
|
||||||
type: url-test
|
type: url-test
|
||||||
proxies:
|
proxies:
|
||||||
|
@ -444,7 +453,7 @@ proxy-groups:
|
||||||
url: "http://www.gstatic.com/generate_204"
|
url: "http://www.gstatic.com/generate_204"
|
||||||
interval: 300
|
interval: 300
|
||||||
|
|
||||||
# fallback 将按照url测试结果按照节点顺序选择
|
# fallback 将按照 url 测试结果按照节点顺序选择
|
||||||
- name: "fallback-auto"
|
- name: "fallback-auto"
|
||||||
type: fallback
|
type: fallback
|
||||||
proxies:
|
proxies:
|
||||||
|
@ -475,7 +484,7 @@ proxy-groups:
|
||||||
- vmess1
|
- vmess1
|
||||||
- auto
|
- auto
|
||||||
|
|
||||||
# 配置指定interface-name和fwmark的DIRECT
|
# 配置指定 interface-name 和 fwmark 的 DIRECT
|
||||||
- name: en1
|
- name: en1
|
||||||
type: select
|
type: select
|
||||||
interface-name: en1
|
interface-name: en1
|
||||||
|
@ -485,14 +494,14 @@ proxy-groups:
|
||||||
|
|
||||||
- name: UseProvider
|
- name: UseProvider
|
||||||
type: select
|
type: select
|
||||||
filter: "HK|TW" # 正则表达式,过滤provider1中节点名包含HK或TW
|
filter: "HK|TW" # 正则表达式,过滤 provider1 中节点名包含 HK 或 TW
|
||||||
use:
|
use:
|
||||||
- provider1
|
- provider1
|
||||||
proxies:
|
proxies:
|
||||||
- Proxy
|
- Proxy
|
||||||
- DIRECT
|
- DIRECT
|
||||||
|
|
||||||
# Clash格式的节点或支持*ray的分享格式
|
# Clash 格式的节点或支持 *ray 的分享格式
|
||||||
proxy-providers:
|
proxy-providers:
|
||||||
provider1:
|
provider1:
|
||||||
type: http
|
type: http
|
||||||
|
|
43
flake.lock
Normal file
43
flake.lock
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
{
|
||||||
|
"nodes": {
|
||||||
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1664638641,
|
||||||
|
"narHash": "sha256-r2gVLq9DD1A0Igv4AdkmpuuVykXmKVsJTAJinS/ZFrM=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "cb81a9ca94e7631bc67788d858e214d56571983a",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"ref": "master",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": "nixpkgs",
|
||||||
|
"utils": "utils"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"utils": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1659877975,
|
||||||
|
"narHash": "sha256-zllb8aq3YO3h8B/U0/J1WBgAL8EX5yWf5pMj3G0NAmc=",
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"rev": "c0e246b9b83f637f4681389ecabcb2681b4f3af0",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "root",
|
||||||
|
"version": 7
|
||||||
|
}
|
27
flake.nix
Normal file
27
flake.nix
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
description = "Another Clash Kernel";
|
||||||
|
|
||||||
|
inputs.nixpkgs.url = "github:NixOS/nixpkgs/master";
|
||||||
|
|
||||||
|
inputs.utils.url = "github:numtide/flake-utils";
|
||||||
|
|
||||||
|
outputs = { self, nixpkgs, utils }:
|
||||||
|
utils.lib.eachDefaultSystem
|
||||||
|
(system:
|
||||||
|
let
|
||||||
|
pkgs = nixpkgs.legacyPackages.${system};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
packages = rec{
|
||||||
|
clash-meta = pkgs.callPackage ./. { };
|
||||||
|
default = clash-meta;
|
||||||
|
};
|
||||||
|
|
||||||
|
apps = rec {
|
||||||
|
clash-meta = utils.lib.mkApp { drv = self.packages.${system}.clash-meta; };
|
||||||
|
default = clash-meta;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
67
go.mod
67
go.mod
|
@ -3,43 +3,44 @@ module github.com/Dreamacro/clash
|
||||||
go 1.19
|
go 1.19
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/cilium/ebpf v0.9.1
|
github.com/cilium/ebpf v0.9.3
|
||||||
github.com/coreos/go-iptables v0.6.0
|
github.com/coreos/go-iptables v0.6.0
|
||||||
github.com/database64128/tfo-go v1.1.0
|
github.com/database64128/tfo-go v1.1.2
|
||||||
github.com/dlclark/regexp2 v1.4.0
|
github.com/dlclark/regexp2 v1.7.0
|
||||||
github.com/go-chi/chi/v5 v5.0.7
|
github.com/go-chi/chi/v5 v5.0.7
|
||||||
github.com/go-chi/cors v1.2.1
|
github.com/go-chi/cors v1.2.1
|
||||||
github.com/go-chi/render v1.0.1
|
github.com/go-chi/render v1.0.2
|
||||||
github.com/gofrs/uuid v4.2.0+incompatible
|
github.com/gofrs/uuid v4.3.0+incompatible
|
||||||
github.com/google/gopacket v1.1.19
|
github.com/google/gopacket v1.1.19
|
||||||
github.com/gorilla/websocket v1.5.0
|
github.com/gorilla/websocket v1.5.0
|
||||||
github.com/hashicorp/golang-lru v0.5.4
|
github.com/hashicorp/golang-lru v0.5.4
|
||||||
github.com/insomniacslk/dhcp v0.0.0-20220504074936-1ca156eafb9f
|
github.com/insomniacslk/dhcp v0.0.0-20221001123530-5308ebe5334c
|
||||||
github.com/lucas-clemente/quic-go v0.27.2
|
github.com/lucas-clemente/quic-go v0.29.1
|
||||||
github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40
|
github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40
|
||||||
github.com/miekg/dns v1.1.49
|
github.com/miekg/dns v1.1.50
|
||||||
github.com/oschwald/geoip2-golang v1.7.0
|
github.com/oschwald/geoip2-golang v1.8.0
|
||||||
github.com/sagernet/sing v0.0.0-20220627234642-a817f7084d9c
|
github.com/sagernet/sing v0.0.0-20220921101604-86d7d510231f
|
||||||
github.com/sagernet/sing-shadowsocks v0.0.0-20220627234717-689e0165ef2c
|
github.com/sagernet/sing-shadowsocks v0.0.0-20220819002358-7461bb09a8f6
|
||||||
github.com/sagernet/sing-vmess v0.0.0-20220616051646-3d3fc5d01eec
|
github.com/sagernet/sing-vmess v0.0.0-20220921140858-b6a1bdee672f
|
||||||
github.com/sirupsen/logrus v1.8.1
|
github.com/sirupsen/logrus v1.9.0
|
||||||
github.com/stretchr/testify v1.7.2
|
github.com/stretchr/testify v1.8.0
|
||||||
github.com/vishvananda/netlink v1.2.1-beta.2
|
github.com/vishvananda/netlink v1.2.1-beta.2
|
||||||
github.com/xtls/go v0.0.0-20210920065950-d4af136d3672
|
github.com/xtls/go v0.0.0-20220914232946-0441cf4cf837
|
||||||
go.etcd.io/bbolt v1.3.6
|
go.etcd.io/bbolt v1.3.6
|
||||||
go.uber.org/atomic v1.9.0
|
go.uber.org/atomic v1.10.0
|
||||||
go.uber.org/automaxprocs v1.5.1
|
go.uber.org/automaxprocs v1.5.1
|
||||||
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e
|
golang.org/x/crypto v0.0.0-20220926161630-eccd6366d1be
|
||||||
golang.org/x/exp v0.0.0-20220608143224-64259d1afd70
|
golang.org/x/exp v0.0.0-20220930202632-ec3f01382ef9
|
||||||
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e
|
golang.org/x/net v0.0.0-20220930213112-107f3e3c3b0b
|
||||||
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f
|
golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0
|
||||||
golang.org/x/sys v0.0.0-20220712014510-0a85c31ab51e
|
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec
|
||||||
golang.org/x/time v0.0.0-20220411224347-583f2d630306
|
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af
|
||||||
golang.zx2c4.com/wireguard v0.0.0-20220601130007-6a08d81f6bc4
|
golang.zx2c4.com/wireguard v0.0.0-20220920152132-bb719d3a6e2c
|
||||||
golang.zx2c4.com/wireguard/windows v0.5.4-0.20220328111914-004c22c5647e
|
golang.zx2c4.com/wireguard/windows v0.5.4-0.20220328111914-004c22c5647e
|
||||||
google.golang.org/protobuf v1.28.0
|
google.golang.org/protobuf v1.28.1
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
gvisor.dev/gvisor v0.0.0-20220810234332-45096a971e66
|
gvisor.dev/gvisor v0.0.0-20220901235040-6ca97ef2ce1c
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
replace github.com/vishvananda/netlink => github.com/MetaCubeX/netlink v1.2.0-beta.0.20220529072258-d6853f887820
|
replace github.com/vishvananda/netlink => github.com/MetaCubeX/netlink v1.2.0-beta.0.20220529072258-d6853f887820
|
||||||
|
@ -47,27 +48,27 @@ replace github.com/vishvananda/netlink => github.com/MetaCubeX/netlink v1.2.0-be
|
||||||
replace github.com/lucas-clemente/quic-go => github.com/tobyxdd/quic-go v0.28.1-0.20220706211558-7780039ad599
|
replace github.com/lucas-clemente/quic-go => github.com/tobyxdd/quic-go v0.28.1-0.20220706211558-7780039ad599
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/ajg/form v1.5.1 // indirect
|
||||||
github.com/cheekybits/genny v1.0.0 // indirect
|
github.com/cheekybits/genny v1.0.0 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/fsnotify/fsnotify v1.5.4 // indirect
|
github.com/fsnotify/fsnotify v1.5.4 // indirect
|
||||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
|
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
|
||||||
github.com/google/btree v1.0.1 // indirect
|
github.com/google/btree v1.1.2 // indirect
|
||||||
github.com/klauspost/cpuid/v2 v2.0.12 // indirect
|
github.com/klauspost/cpuid/v2 v2.1.1 // indirect
|
||||||
github.com/marten-seemann/qpack v0.2.1 // indirect
|
github.com/marten-seemann/qpack v0.2.1 // indirect
|
||||||
github.com/marten-seemann/qtls-go1-16 v0.1.5 // indirect
|
github.com/marten-seemann/qtls-go1-16 v0.1.5 // indirect
|
||||||
github.com/marten-seemann/qtls-go1-17 v0.1.2 // indirect
|
github.com/marten-seemann/qtls-go1-17 v0.1.2 // indirect
|
||||||
github.com/marten-seemann/qtls-go1-18 v0.1.2 // indirect
|
github.com/marten-seemann/qtls-go1-18 v0.1.2 // indirect
|
||||||
github.com/marten-seemann/qtls-go1-19 v0.1.0-beta.1 // indirect
|
github.com/marten-seemann/qtls-go1-19 v0.1.0 // indirect
|
||||||
github.com/nxadm/tail v1.4.8 // indirect
|
github.com/nxadm/tail v1.4.8 // indirect
|
||||||
github.com/onsi/ginkgo v1.16.5 // indirect
|
github.com/onsi/ginkgo v1.16.5 // indirect
|
||||||
github.com/oschwald/maxminddb-golang v1.9.0 // indirect
|
github.com/oschwald/maxminddb-golang v1.10.0 // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
github.com/u-root/uio v0.0.0-20220204230159-dac05f7d2cb4 // indirect
|
github.com/u-root/uio v0.0.0-20220204230159-dac05f7d2cb4 // indirect
|
||||||
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect
|
github.com/vishvananda/netns v0.0.0-20220913150850-18c4f4234207 // indirect
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
|
||||||
golang.org/x/text v0.3.8-0.20220124021120-d1c84af989ab // indirect
|
golang.org/x/text v0.3.8-0.20220124021120-d1c84af989ab // indirect
|
||||||
golang.org/x/tools v0.1.10 // indirect
|
golang.org/x/tools v0.1.12 // indirect
|
||||||
golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df // indirect
|
|
||||||
golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224 // indirect
|
golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224 // indirect
|
||||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
|
||||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
|
||||||
|
|
135
go.sum
135
go.sum
|
@ -10,25 +10,27 @@ git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGy
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
github.com/MetaCubeX/netlink v1.2.0-beta.0.20220529072258-d6853f887820 h1:fGKWZ25VApYnuPZoNeqdH/nZtHa2XMajwH6Yj/OgoVc=
|
github.com/MetaCubeX/netlink v1.2.0-beta.0.20220529072258-d6853f887820 h1:fGKWZ25VApYnuPZoNeqdH/nZtHa2XMajwH6Yj/OgoVc=
|
||||||
github.com/MetaCubeX/netlink v1.2.0-beta.0.20220529072258-d6853f887820/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho=
|
github.com/MetaCubeX/netlink v1.2.0-beta.0.20220529072258-d6853f887820/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho=
|
||||||
|
github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU=
|
||||||
|
github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
|
||||||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
|
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
|
||||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||||
github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g=
|
github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g=
|
||||||
github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
|
github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
|
||||||
github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE=
|
github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE=
|
||||||
github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ=
|
github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ=
|
||||||
github.com/cilium/ebpf v0.9.1 h1:64sn2K3UKw8NbP/blsixRpF3nXuyhz/VjRlRzvlBRu4=
|
github.com/cilium/ebpf v0.9.3 h1:5KtxXZU+scyERvkJMEm16TbScVvuuMrlhPly78ZMbSc=
|
||||||
github.com/cilium/ebpf v0.9.1/go.mod h1:+OhNOIXx/Fnu1IE8bJz2dzOA+VSfyTfdNUVdlQnxUFY=
|
github.com/cilium/ebpf v0.9.3/go.mod h1:w27N4UjpaQ9X/DGrSugxUG+H+NhgntDuPb5lCzxCn8A=
|
||||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||||
github.com/coreos/go-iptables v0.6.0 h1:is9qnZMPYjLd8LYqmm/qlE+wwEgJIkTYdhV3rfZo4jk=
|
github.com/coreos/go-iptables v0.6.0 h1:is9qnZMPYjLd8LYqmm/qlE+wwEgJIkTYdhV3rfZo4jk=
|
||||||
github.com/coreos/go-iptables v0.6.0/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q=
|
github.com/coreos/go-iptables v0.6.0/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q=
|
||||||
github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||||
github.com/database64128/tfo-go v1.1.0 h1:VO0polyGNSAmr99nYw9GQeMz7ZOcQ/QbjlTwniHwfTQ=
|
github.com/database64128/tfo-go v1.1.2 h1:GwxtJp09BdUTVEoeT421t231eNZoGOCRkklbl4WI1kU=
|
||||||
github.com/database64128/tfo-go v1.1.0/go.mod h1:95pOT8bnV3P2Lmu9upHNWFHz6dYGJ9cr7pnb0tGQAG8=
|
github.com/database64128/tfo-go v1.1.2/go.mod h1:jgrSUPyOvTGQyn6irCOpk7L2W/q/0VLZZcovQiMi+bI=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
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 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/dlclark/regexp2 v1.4.0 h1:F1rxgk7p4uKjwIQxBs9oAXe5CqrXlCduYEJvrF4u93E=
|
github.com/dlclark/regexp2 v1.7.0 h1:7lJfhqlPssTb1WQx4yvTHN0uElPEv52sbaECrAQxjAo=
|
||||||
github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
|
github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
|
||||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||||
github.com/fanliao/go-promise v0.0.0-20141029170127-1890db352a72/go.mod h1:PjfxuH4FZdUyfMdtBio2lsRr1AKEaVPwelzuHuh8Lqc=
|
github.com/fanliao/go-promise v0.0.0-20141029170127-1890db352a72/go.mod h1:PjfxuH4FZdUyfMdtBio2lsRr1AKEaVPwelzuHuh8Lqc=
|
||||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
|
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
|
||||||
|
@ -44,13 +46,13 @@ github.com/go-chi/chi/v5 v5.0.7 h1:rDTPXLDHGATaeHvVlLcR4Qe0zftYethFucbjVQ1PxU8=
|
||||||
github.com/go-chi/chi/v5 v5.0.7/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
|
github.com/go-chi/chi/v5 v5.0.7/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
|
||||||
github.com/go-chi/cors v1.2.1 h1:xEC8UT3Rlp2QuWNEr4Fs/c2EAGVKBwy/1vHx3bppil4=
|
github.com/go-chi/cors v1.2.1 h1:xEC8UT3Rlp2QuWNEr4Fs/c2EAGVKBwy/1vHx3bppil4=
|
||||||
github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58=
|
github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58=
|
||||||
github.com/go-chi/render v1.0.1 h1:4/5tis2cKaNdnv9zFLfXzcquC9HbeZgCnxGnKrltBS8=
|
github.com/go-chi/render v1.0.2 h1:4ER/udB0+fMWB2Jlf15RV3F4A2FDuYi/9f+lFttR/Lg=
|
||||||
github.com/go-chi/render v1.0.1/go.mod h1:pq4Rr7HbnsdaeHagklXub+p6Wd16Af5l9koip1OvJns=
|
github.com/go-chi/render v1.0.2/go.mod h1:/gr3hVkmYR0YlEy3LxCuVRFzEu9Ruok+gFqbIofjao0=
|
||||||
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
|
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
|
||||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=
|
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=
|
||||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||||
github.com/gofrs/uuid v4.2.0+incompatible h1:yyYWMnhkhrKwwr8gAOcOCYxOOscHgDS9yZgBrnJfGa0=
|
github.com/gofrs/uuid v4.3.0+incompatible h1:CaSVZxm5B+7o45rtab4jC2G37WGYX1zQfuU2i6DSvnc=
|
||||||
github.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
github.com/gofrs/uuid v4.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||||
github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
|
github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
|
||||||
|
@ -71,15 +73,15 @@ github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaS
|
||||||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4=
|
github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU=
|
||||||
github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=
|
github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
|
||||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
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.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.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.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/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
|
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
|
||||||
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
|
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
|
||||||
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
||||||
github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8=
|
github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8=
|
||||||
|
@ -97,8 +99,8 @@ github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+l
|
||||||
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
||||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
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/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714/go.mod h1:2Goc3h8EklBH5mspfHFxBnEoURQCGzQQH1ga9Myjvis=
|
||||||
github.com/insomniacslk/dhcp v0.0.0-20220504074936-1ca156eafb9f h1:l1QCwn715k8nYkj4Ql50rzEog3WnMdrd4YYMMwemxEo=
|
github.com/insomniacslk/dhcp v0.0.0-20221001123530-5308ebe5334c h1:OCFM4+DXTWfNlyeoddrTwdup/ztkGSyAMR2UGcPckNQ=
|
||||||
github.com/insomniacslk/dhcp v0.0.0-20220504074936-1ca156eafb9f/go.mod h1:h+MxyHxRg9NH3terB1nfRIUaQEcI0XOVkdR9LNBlp8E=
|
github.com/insomniacslk/dhcp v0.0.0-20221001123530-5308ebe5334c/go.mod h1:h+MxyHxRg9NH3terB1nfRIUaQEcI0XOVkdR9LNBlp8E=
|
||||||
github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU=
|
github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU=
|
||||||
github.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw=
|
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-20200117123717-f846d4f6c1f4/go.mod h1:WGuG/smIU4J/54PblvSbh+xvCZmpJnFgr3ds6Z55XMQ=
|
||||||
|
@ -109,8 +111,8 @@ github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1
|
||||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||||
github.com/klauspost/cpuid/v2 v2.0.12 h1:p9dKCg8i4gmOxtv35DvrYoWqYzQrvEVdjQ762Y0OqZE=
|
github.com/klauspost/cpuid/v2 v2.1.1 h1:t0wUqjowdm8ezddV5k0tLWVklVuvLJpoHeb4WBdydm0=
|
||||||
github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c=
|
github.com/klauspost/cpuid/v2 v2.1.1/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
|
||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
|
@ -129,8 +131,9 @@ github.com/marten-seemann/qtls-go1-17 v0.1.2 h1:JADBlm0LYiVbuSySCHeY863dNkcpMmDR
|
||||||
github.com/marten-seemann/qtls-go1-17 v0.1.2/go.mod h1:C2ekUKcDdz9SDWxec1N/MvcXBpaX9l3Nx67XaR84L5s=
|
github.com/marten-seemann/qtls-go1-17 v0.1.2/go.mod h1:C2ekUKcDdz9SDWxec1N/MvcXBpaX9l3Nx67XaR84L5s=
|
||||||
github.com/marten-seemann/qtls-go1-18 v0.1.2 h1:JH6jmzbduz0ITVQ7ShevK10Av5+jBEKAHMntXmIV7kM=
|
github.com/marten-seemann/qtls-go1-18 v0.1.2 h1:JH6jmzbduz0ITVQ7ShevK10Av5+jBEKAHMntXmIV7kM=
|
||||||
github.com/marten-seemann/qtls-go1-18 v0.1.2/go.mod h1:mJttiymBAByA49mhlNZZGrH5u1uXYZJ+RW28Py7f4m4=
|
github.com/marten-seemann/qtls-go1-18 v0.1.2/go.mod h1:mJttiymBAByA49mhlNZZGrH5u1uXYZJ+RW28Py7f4m4=
|
||||||
github.com/marten-seemann/qtls-go1-19 v0.1.0-beta.1 h1:7m/WlWcSROrcK5NxuXaxYD32BZqe/LEEnBrWcH/cOqQ=
|
|
||||||
github.com/marten-seemann/qtls-go1-19 v0.1.0-beta.1/go.mod h1:5HTDWtVudo/WFsHKRNuOhWlbdjrfs5JHrYb0wIJqGpI=
|
github.com/marten-seemann/qtls-go1-19 v0.1.0-beta.1/go.mod h1:5HTDWtVudo/WFsHKRNuOhWlbdjrfs5JHrYb0wIJqGpI=
|
||||||
|
github.com/marten-seemann/qtls-go1-19 v0.1.0 h1:rLFKD/9mp/uq1SYGYuVZhm83wkmU95pK5df3GufyYYU=
|
||||||
|
github.com/marten-seemann/qtls-go1-19 v0.1.0/go.mod h1:5HTDWtVudo/WFsHKRNuOhWlbdjrfs5JHrYb0wIJqGpI=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||||
github.com/mdlayher/ethernet v0.0.0-20190606142754-0394541c37b7/go.mod h1:U6ZQobyTjI/tJyq2HG+i/dfSoFUt8/aZCM+GKtmFk/Y=
|
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 v0.0.0-20190409211403-11939a169225/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA=
|
||||||
|
@ -140,8 +143,8 @@ github.com/mdlayher/netlink v1.1.1/go.mod h1:WTYpFb/WTvlRJAyKhZL5/uy69TDDpHHu2VZ
|
||||||
github.com/mdlayher/raw v0.0.0-20190606142536-fef19f00fc18/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg=
|
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/mdlayher/raw v0.0.0-20191009151244-50f2db8cc065/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg=
|
||||||
github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4=
|
github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4=
|
||||||
github.com/miekg/dns v1.1.49 h1:qe0mQU3Z/XpFeE+AEBo2rqaS1IPBJ3anmqZ4XiZJVG8=
|
github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA=
|
||||||
github.com/miekg/dns v1.1.49/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME=
|
github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo=
|
github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo=
|
||||||
|
@ -161,10 +164,10 @@ github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1y
|
||||||
github.com/onsi/gomega v1.13.0 h1:7lLHu94wT9Ij0o6EWWclhu0aOh32VxhkwEJvzuWPeak=
|
github.com/onsi/gomega v1.13.0 h1:7lLHu94wT9Ij0o6EWWclhu0aOh32VxhkwEJvzuWPeak=
|
||||||
github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY=
|
github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY=
|
||||||
github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
|
github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
|
||||||
github.com/oschwald/geoip2-golang v1.7.0 h1:JW1r5AKi+vv2ujSxjKthySK3jo8w8oKWPyXsw+Qs/S8=
|
github.com/oschwald/geoip2-golang v1.8.0 h1:KfjYB8ojCEn/QLqsDU0AzrJ3R5Qa9vFlx3z6SLNcKTs=
|
||||||
github.com/oschwald/geoip2-golang v1.7.0/go.mod h1:mdI/C7iK7NVMcIDDtf4bCKMJ7r0o7UwGeCo9eiitCMQ=
|
github.com/oschwald/geoip2-golang v1.8.0/go.mod h1:R7bRvYjOeaoenAp9sKRS8GX5bJWcZ0laWO5+DauEktw=
|
||||||
github.com/oschwald/maxminddb-golang v1.9.0 h1:tIk4nv6VT9OiPyrnDAfJS1s1xKDQMZOsGojab6EjC1Y=
|
github.com/oschwald/maxminddb-golang v1.10.0 h1:Xp1u0ZhqkSuopaKmk1WwHtjF0H9Hd9181uj2MQ5Vndg=
|
||||||
github.com/oschwald/maxminddb-golang v1.9.0/go.mod h1:TK+s/Z2oZq0rSl4PSeAEoP0bgm82Cp5HyvYbt8K3zLY=
|
github.com/oschwald/maxminddb-golang v1.10.0/go.mod h1:Y2ELenReaLAZ0b400URyGwvYxHV1dLIxBuyOsyYjHK0=
|
||||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.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 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
@ -175,12 +178,12 @@ github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7q
|
||||||
github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||||
github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k=
|
github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k=
|
||||||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||||
github.com/sagernet/sing v0.0.0-20220627234642-a817f7084d9c h1:98QC0wtaD648MFPw82KaT1O9LloQgR4ZyIDtNtsno8Y=
|
github.com/sagernet/sing v0.0.0-20220921101604-86d7d510231f h1:GX416thAwyc0vHBOal/qplvdhFgYO2dHD5GqADCJ0Ig=
|
||||||
github.com/sagernet/sing v0.0.0-20220627234642-a817f7084d9c/go.mod h1:I67R/q5f67xDExL2kL3RLIP7kGJBOPkYXkpRAykgC+E=
|
github.com/sagernet/sing v0.0.0-20220921101604-86d7d510231f/go.mod h1:x3NHUeJBQwV75L51zwmLKQdLtRvR+M4PmXkfQtU1vIY=
|
||||||
github.com/sagernet/sing-shadowsocks v0.0.0-20220627234717-689e0165ef2c h1:Jhgjyb2jXL4GtwJec6/kgeTqaQXsvMiNX2wAkGOSD3I=
|
github.com/sagernet/sing-shadowsocks v0.0.0-20220819002358-7461bb09a8f6 h1:JJfDeYYhWunvtxsU/mOVNTmFQmnzGx9dY034qG6G3g4=
|
||||||
github.com/sagernet/sing-shadowsocks v0.0.0-20220627234717-689e0165ef2c/go.mod h1:ng5pxdNnKZWlxzZTXRqWeY0ftzhScPZmjgJGJeRuPYY=
|
github.com/sagernet/sing-shadowsocks v0.0.0-20220819002358-7461bb09a8f6/go.mod h1:EX3RbZvrwAkPI2nuGa78T2iQXmrkT+/VQtskjou42xM=
|
||||||
github.com/sagernet/sing-vmess v0.0.0-20220616051646-3d3fc5d01eec h1:jUSfKmyL6K9O2TvIvcVacZ4eNXHYbNSfdph+DRPyVlU=
|
github.com/sagernet/sing-vmess v0.0.0-20220921140858-b6a1bdee672f h1:xyJ3Wbibcug4DxLi/FCHX2Td667SfieyZv645b8+eEE=
|
||||||
github.com/sagernet/sing-vmess v0.0.0-20220616051646-3d3fc5d01eec/go.mod h1:jDZ8fJgOea7Y7MMHWgfqwLBVLnhtW2zuxS5wjtDaB84=
|
github.com/sagernet/sing-vmess v0.0.0-20220921140858-b6a1bdee672f/go.mod h1:bwhAdSNET1X+j9DOXGj9NIQR39xgcWIk1rOQ9lLD+gM=
|
||||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||||
github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY=
|
github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY=
|
||||||
github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM=
|
github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM=
|
||||||
|
@ -204,19 +207,21 @@ github.com/shurcooL/reactions v0.0.0-20181006231557-f2e0b4ca5b82/go.mod h1:TCR1l
|
||||||
github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||||
github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4=
|
github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4=
|
||||||
github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw=
|
github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw=
|
||||||
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
|
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
|
||||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
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/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||||
github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE=
|
github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE=
|
||||||
github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA=
|
github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
github.com/stretchr/testify v1.2.2/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.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
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.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s=
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
|
||||||
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
|
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
|
||||||
github.com/tobyxdd/quic-go v0.28.1-0.20220706211558-7780039ad599 h1:We+z04jRpTGxFggeGWf+GbinhlIk1I1kMMEgujhUfiA=
|
github.com/tobyxdd/quic-go v0.28.1-0.20220706211558-7780039ad599 h1:We+z04jRpTGxFggeGWf+GbinhlIk1I1kMMEgujhUfiA=
|
||||||
github.com/tobyxdd/quic-go v0.28.1-0.20220706211558-7780039ad599/go.mod h1:oGz5DKK41cJt5+773+BSO9BXDsREY4HLf7+0odGAPO0=
|
github.com/tobyxdd/quic-go v0.28.1-0.20220706211558-7780039ad599/go.mod h1:oGz5DKK41cJt5+773+BSO9BXDsREY4HLf7+0odGAPO0=
|
||||||
|
@ -226,17 +231,17 @@ github.com/u-root/uio v0.0.0-20220204230159-dac05f7d2cb4/go.mod h1:LpEX5FO/cB+WF
|
||||||
github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU=
|
github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU=
|
||||||
github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM=
|
github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM=
|
||||||
github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
|
github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
|
||||||
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 h1:gga7acRE695APm9hlsSMoOoE65U4/TcqNj90mc69Rlg=
|
github.com/vishvananda/netns v0.0.0-20220913150850-18c4f4234207 h1:nn7SOQy8xCu3iXNv7oiBhhEQtbWdnEOMnuKBlHvrqIM=
|
||||||
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
|
github.com/vishvananda/netns v0.0.0-20220913150850-18c4f4234207/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
|
||||||
github.com/xtls/go v0.0.0-20210920065950-d4af136d3672 h1:4mkzGhKqt3JO1BWYjtD3iRFyAx4ow67hmSqOcGjuxqQ=
|
github.com/xtls/go v0.0.0-20220914232946-0441cf4cf837 h1:AHhUwwFJGl27E46OpdJHplZkK09m7aETNBNzhT6t15M=
|
||||||
github.com/xtls/go v0.0.0-20210920065950-d4af136d3672/go.mod h1:YGGVbz9cOxyKFUmhW7LGaLZaMA0cPlHJinvAmVxEMSU=
|
github.com/xtls/go v0.0.0-20220914232946-0441cf4cf837/go.mod h1:YJTRELIWrGxR1s8xcEBgxcxBfwQfMGjdvNLTjN9XFgY=
|
||||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||||
go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU=
|
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/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4=
|
||||||
go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=
|
go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=
|
||||||
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
|
go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ=
|
||||||
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
|
||||||
go.uber.org/automaxprocs v1.5.1 h1:e1YG66Lrk73dn4qhg8WFSvhF0JuFQF0ERIp4rpuV8Qk=
|
go.uber.org/automaxprocs v1.5.1 h1:e1YG66Lrk73dn4qhg8WFSvhF0JuFQF0ERIp4rpuV8Qk=
|
||||||
go.uber.org/automaxprocs v1.5.1/go.mod h1:BF4eumQw0P9GtnuxxovUd06vwm1o18oMzFtK66vU6XU=
|
go.uber.org/automaxprocs v1.5.1/go.mod h1:BF4eumQw0P9GtnuxxovUd06vwm1o18oMzFtK66vU6XU=
|
||||||
go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE=
|
go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE=
|
||||||
|
@ -247,11 +252,11 @@ golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACk
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e h1:T8NU3HyQ8ClP4SEE+KbFlg6n0NhuTsN4MyznaarGsZM=
|
golang.org/x/crypto v0.0.0-20220926161630-eccd6366d1be h1:fmw3UbQh+nxngCAHrDCCztao/kbYFnWjoqop8dHx05A=
|
||||||
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
golang.org/x/crypto v0.0.0-20220926161630-eccd6366d1be/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20220608143224-64259d1afd70 h1:8uGxpY2cLF9H/NSHUiEWUIBZqIcsMzMWIMPCCUkyYgc=
|
golang.org/x/exp v0.0.0-20220930202632-ec3f01382ef9 h1:RjggHMcaTVp0LOVZcW0bo8alwHrOaCrGUDgfWUHhnN4=
|
||||||
golang.org/x/exp v0.0.0-20220608143224-64259d1afd70/go.mod h1:yh0Ynu2b5ZUe3MQfp2nM0ecK7wsgouWTDN0FNeJuIys=
|
golang.org/x/exp v0.0.0-20220930202632-ec3f01382ef9/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE=
|
||||||
golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
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-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||||
|
@ -259,8 +264,8 @@ golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPI
|
||||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 h1:kQgndtyPBW/JIYERgdxfwMYh3AVStj88WQTlNDi2a+o=
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
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-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-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
@ -285,8 +290,9 @@ golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwY
|
||||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||||
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
|
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
|
||||||
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e h1:TsQ7F31D3bUCLeqPT0u+yjp1guoArKaNKmCr22PYgTQ=
|
|
||||||
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||||
|
golang.org/x/net v0.0.0-20220930213112-107f3e3c3b0b h1:uKO3Js8lXGjpjdc4J3rqs0/Ex5yDKUGfk43tTYWVLas=
|
||||||
|
golang.org/x/net v0.0.0-20220930213112-107f3e3c3b0b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
|
@ -299,8 +305,8 @@ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJ
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/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-20201020160332-67f06af15bc9/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/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f h1:Ax0t5p6N38Ga0dThY21weqDEyz2oklo4IvDkpigvkD8=
|
golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0 h1:cu5kTvlzcw1Q5S9f5ip1/cpiB4nXvw1XYzFPGgzLUOY=
|
||||||
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/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-20180830151530-49385e6e1522/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-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
@ -315,7 +321,6 @@ golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||||
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/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-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-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
@ -337,8 +342,10 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220712014510-0a85c31ab51e h1:NHvCuwuS43lGnYhten69ZWqi2QOj/CiDNcKbVqwVoew=
|
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220712014510-0a85c31ab51e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec h1:BkDtF2Ih9xZ7le9ndzTA7KJow28VbQW3odyk/8drmuI=
|
||||||
|
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
@ -351,8 +358,8 @@ golang.org/x/text v0.3.8-0.20220124021120-d1c84af989ab h1:eHo2TTVBaAPw9lDGK2Gb9G
|
||||||
golang.org/x/text v0.3.8-0.20220124021120-d1c84af989ab/go.mod h1:EFNZuWvGYxIRUEX+K8UmCFwYmZjqcrnq15ZuVldZkZ0=
|
golang.org/x/text v0.3.8-0.20220124021120-d1c84af989ab/go.mod h1:EFNZuWvGYxIRUEX+K8UmCFwYmZjqcrnq15ZuVldZkZ0=
|
||||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/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-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20220411224347-583f2d630306 h1:+gHMid33q6pen7kv9xvT+JRinntgeXO2AeZVd0AWD3w=
|
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af h1:Yx9k8YCG3dvF87UAn2tu2HQLf2dt/eR1bXxpLMWeH+Y=
|
||||||
golang.org/x/time v0.0.0-20220411224347-583f2d630306/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/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-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
@ -365,18 +372,16 @@ golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapK
|
||||||
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
golang.org/x/tools v0.1.10 h1:QjFRCZxdOhBJ/UNgnBZLbNV13DlbnK0quyivTnXJM20=
|
golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU=
|
||||||
golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
|
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
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-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-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df h1:5Pf6pFKu98ODmgnpvkJ3kFUOQGGLIzLIkbzUHp47618=
|
|
||||||
golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
|
|
||||||
golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224 h1:Ug9qvr1myri/zFN6xL17LSCBGFDnphBBhzmILHsM5TY=
|
golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224 h1:Ug9qvr1myri/zFN6xL17LSCBGFDnphBBhzmILHsM5TY=
|
||||||
golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI=
|
golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI=
|
||||||
golang.zx2c4.com/wireguard v0.0.0-20220601130007-6a08d81f6bc4 h1:QlbNZ9SwDAepRQwgeWHLi3rfEMo/kVEU4SmgsNM7HmQ=
|
golang.zx2c4.com/wireguard v0.0.0-20220920152132-bb719d3a6e2c h1:Okh6a1xpnJslG9Mn84pId1Mn+Q8cvpo4HCeeFWHo0cA=
|
||||||
golang.zx2c4.com/wireguard v0.0.0-20220601130007-6a08d81f6bc4/go.mod h1:bVQfyl2sCM/QIIGHpWbFGfHPuDvqnCNkT6MQLTCjO/U=
|
golang.zx2c4.com/wireguard v0.0.0-20220920152132-bb719d3a6e2c/go.mod h1:enML0deDxY1ux+B6ANGiwtg0yAJi1rctkTpcHNAVPyg=
|
||||||
golang.zx2c4.com/wireguard/windows v0.5.4-0.20220328111914-004c22c5647e h1:yV04h6Tx19uDR6LvuEbR19cDU+3QrB9LuGjtF7F5G0w=
|
golang.zx2c4.com/wireguard/windows v0.5.4-0.20220328111914-004c22c5647e h1:yV04h6Tx19uDR6LvuEbR19cDU+3QrB9LuGjtF7F5G0w=
|
||||||
golang.zx2c4.com/wireguard/windows v0.5.4-0.20220328111914-004c22c5647e/go.mod h1:1CeiatTZwcwSFA3cAtMm8CQoroviTldnxd7DOgM/vI4=
|
golang.zx2c4.com/wireguard/windows v0.5.4-0.20220328111914-004c22c5647e/go.mod h1:1CeiatTZwcwSFA3cAtMm8CQoroviTldnxd7DOgM/vI4=
|
||||||
google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
|
google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
|
||||||
|
@ -403,8 +408,8 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi
|
||||||
google.golang.org/protobuf v1.23.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.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||||
google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
|
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
|
||||||
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/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-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 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||||
|
@ -423,8 +428,8 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o=
|
grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o=
|
||||||
gvisor.dev/gvisor v0.0.0-20220810234332-45096a971e66 h1:GrHxpIMY0lHZ3Q8rp3m4iOb0pJsnCQ/5AHaN9SXE69E=
|
gvisor.dev/gvisor v0.0.0-20220901235040-6ca97ef2ce1c h1:m5lcgWnL3OElQNVyp3qcncItJ2c0sQlSGjYK2+nJTA4=
|
||||||
gvisor.dev/gvisor v0.0.0-20220810234332-45096a971e66/go.mod h1:TIvkJD0sxe8pIob3p6T8IzxXunlp6yfgktvTNp+DGNM=
|
gvisor.dev/gvisor v0.0.0-20220901235040-6ca97ef2ce1c/go.mod h1:TIvkJD0sxe8pIob3p6T8IzxXunlp6yfgktvTNp+DGNM=
|
||||||
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
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-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
|
|
@ -88,7 +88,7 @@ startOver:
|
||||||
allowedIPs []netip.Prefix
|
allowedIPs []netip.Prefix
|
||||||
|
|
||||||
// add default
|
// add default
|
||||||
routeArr = []string{"0.0.0.0/0"}
|
routeArr = []string{"0.0.0.0/1"}
|
||||||
)
|
)
|
||||||
|
|
||||||
for _, route := range routeArr {
|
for _, route := range routeArr {
|
||||||
|
|
|
@ -5,7 +5,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
errPayload = errors.New("payload error")
|
errPayload = errors.New("payloadRule error")
|
||||||
initFlag bool
|
initFlag bool
|
||||||
noResolve = "no-resolve"
|
noResolve = "no-resolve"
|
||||||
)
|
)
|
||||||
|
|
|
@ -18,11 +18,11 @@ func (d *Domain) RuleType() C.RuleType {
|
||||||
return C.Domain
|
return C.Domain
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Domain) Match(metadata *C.Metadata) bool {
|
func (d *Domain) Match(metadata *C.Metadata) (bool, string) {
|
||||||
if metadata.AddrType != C.AtypDomainName {
|
if metadata.AddrType != C.AtypDomainName {
|
||||||
return false
|
return false, ""
|
||||||
}
|
}
|
||||||
return metadata.Host == d.domain
|
return metadata.Host == d.domain, d.adapter
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Domain) Adapter() string {
|
func (d *Domain) Adapter() string {
|
||||||
|
@ -47,4 +47,4 @@ func NewDomain(domain string, adapter string) *Domain {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ C.Rule = (*Domain)(nil)
|
//var _ C.Rule = (*Domain)(nil)
|
||||||
|
|
|
@ -18,12 +18,12 @@ func (dk *DomainKeyword) RuleType() C.RuleType {
|
||||||
return C.DomainKeyword
|
return C.DomainKeyword
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dk *DomainKeyword) Match(metadata *C.Metadata) bool {
|
func (dk *DomainKeyword) Match(metadata *C.Metadata) (bool, string) {
|
||||||
if metadata.AddrType != C.AtypDomainName {
|
if metadata.AddrType != C.AtypDomainName {
|
||||||
return false
|
return false, ""
|
||||||
}
|
}
|
||||||
domain := metadata.Host
|
domain := metadata.Host
|
||||||
return strings.Contains(domain, dk.keyword)
|
return strings.Contains(domain, dk.keyword), dk.adapter
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dk *DomainKeyword) Adapter() string {
|
func (dk *DomainKeyword) Adapter() string {
|
||||||
|
@ -48,4 +48,4 @@ func NewDomainKeyword(keyword string, adapter string) *DomainKeyword {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ C.Rule = (*DomainKeyword)(nil)
|
//var _ C.Rule = (*DomainKeyword)(nil)
|
||||||
|
|
|
@ -18,12 +18,12 @@ func (ds *DomainSuffix) RuleType() C.RuleType {
|
||||||
return C.DomainSuffix
|
return C.DomainSuffix
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ds *DomainSuffix) Match(metadata *C.Metadata) bool {
|
func (ds *DomainSuffix) Match(metadata *C.Metadata) (bool, string) {
|
||||||
if metadata.AddrType != C.AtypDomainName {
|
if metadata.AddrType != C.AtypDomainName {
|
||||||
return false
|
return false, ""
|
||||||
}
|
}
|
||||||
domain := metadata.Host
|
domain := metadata.Host
|
||||||
return strings.HasSuffix(domain, "."+ds.suffix) || domain == ds.suffix
|
return strings.HasSuffix(domain, "."+ds.suffix) || domain == ds.suffix, ds.adapter
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ds *DomainSuffix) Adapter() string {
|
func (ds *DomainSuffix) Adapter() string {
|
||||||
|
@ -48,4 +48,4 @@ func NewDomainSuffix(suffix string, adapter string) *DomainSuffix {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ C.Rule = (*DomainSuffix)(nil)
|
//var _ C.Rule = (*DomainSuffix)(nil)
|
||||||
|
|
|
@ -13,8 +13,8 @@ func (f *Match) RuleType() C.RuleType {
|
||||||
return C.MATCH
|
return C.MATCH
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *Match) Match(metadata *C.Metadata) bool {
|
func (f *Match) Match(metadata *C.Metadata) (bool, string) {
|
||||||
return true
|
return true, f.adapter
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *Match) Adapter() string {
|
func (f *Match) Adapter() string {
|
||||||
|
@ -32,4 +32,4 @@ func NewMatch(adapter string) *Match {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ C.Rule = (*Match)(nil)
|
//var _ C.Rule = (*Match)(nil)
|
||||||
|
|
|
@ -25,10 +25,10 @@ func (g *GEOIP) RuleType() C.RuleType {
|
||||||
return C.GEOIP
|
return C.GEOIP
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GEOIP) Match(metadata *C.Metadata) bool {
|
func (g *GEOIP) Match(metadata *C.Metadata) (bool, string) {
|
||||||
ip := metadata.DstIP
|
ip := metadata.DstIP
|
||||||
if !ip.IsValid() {
|
if !ip.IsValid() {
|
||||||
return false
|
return false, ""
|
||||||
}
|
}
|
||||||
|
|
||||||
if strings.EqualFold(g.country, "LAN") {
|
if strings.EqualFold(g.country, "LAN") {
|
||||||
|
@ -37,13 +37,13 @@ func (g *GEOIP) Match(metadata *C.Metadata) bool {
|
||||||
ip.IsLoopback() ||
|
ip.IsLoopback() ||
|
||||||
ip.IsMulticast() ||
|
ip.IsMulticast() ||
|
||||||
ip.IsLinkLocalUnicast() ||
|
ip.IsLinkLocalUnicast() ||
|
||||||
resolver.IsFakeBroadcastIP(ip)
|
resolver.IsFakeBroadcastIP(ip), g.adapter
|
||||||
}
|
}
|
||||||
if !C.GeodataMode {
|
if !C.GeodataMode {
|
||||||
record, _ := mmdb.Instance().Country(ip.AsSlice())
|
record, _ := mmdb.Instance().Country(ip.AsSlice())
|
||||||
return strings.EqualFold(record.Country.IsoCode, g.country)
|
return strings.EqualFold(record.Country.IsoCode, g.country), g.adapter
|
||||||
}
|
}
|
||||||
return g.geoIPMatcher.Match(ip.AsSlice())
|
return g.geoIPMatcher.Match(ip.AsSlice()), g.adapter
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GEOIP) Adapter() string {
|
func (g *GEOIP) Adapter() string {
|
||||||
|
@ -98,4 +98,4 @@ func NewGEOIP(country string, adapter string, noResolveIP bool) (*GEOIP, error)
|
||||||
return geoip, nil
|
return geoip, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ C.Rule = (*GEOIP)(nil)
|
//var _ C.Rule = (*GEOIP)(nil)
|
||||||
|
|
|
@ -23,13 +23,13 @@ func (gs *GEOSITE) RuleType() C.RuleType {
|
||||||
return C.GEOSITE
|
return C.GEOSITE
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gs *GEOSITE) Match(metadata *C.Metadata) bool {
|
func (gs *GEOSITE) Match(metadata *C.Metadata) (bool, string) {
|
||||||
if metadata.AddrType != C.AtypDomainName {
|
if metadata.AddrType != C.AtypDomainName {
|
||||||
return false
|
return false, ""
|
||||||
}
|
}
|
||||||
|
|
||||||
domain := metadata.Host
|
domain := metadata.Host
|
||||||
return gs.matcher.ApplyDomain(domain)
|
return gs.matcher.ApplyDomain(domain), gs.adapter
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gs *GEOSITE) Adapter() string {
|
func (gs *GEOSITE) Adapter() string {
|
||||||
|
@ -75,4 +75,4 @@ func NewGEOSITE(country string, adapter string) (*GEOSITE, error) {
|
||||||
return geoSite, nil
|
return geoSite, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ C.Rule = (*GEOSITE)(nil)
|
//var _ C.Rule = (*GEOSITE)(nil)
|
||||||
|
|
|
@ -13,13 +13,13 @@ type InType struct {
|
||||||
payload string
|
payload string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *InType) Match(metadata *C.Metadata) bool {
|
func (u *InType) Match(metadata *C.Metadata) (bool, string) {
|
||||||
for _, tp := range u.types {
|
for _, tp := range u.types {
|
||||||
if metadata.Type == tp {
|
if metadata.Type == tp {
|
||||||
return true
|
return true, u.adapter
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false
|
return false, ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *InType) RuleType() C.RuleType {
|
func (u *InType) RuleType() C.RuleType {
|
||||||
|
|
|
@ -35,12 +35,12 @@ func (i *IPCIDR) RuleType() C.RuleType {
|
||||||
return C.IPCIDR
|
return C.IPCIDR
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *IPCIDR) Match(metadata *C.Metadata) bool {
|
func (i *IPCIDR) Match(metadata *C.Metadata) (bool, string) {
|
||||||
ip := metadata.DstIP
|
ip := metadata.DstIP
|
||||||
if i.isSourceIP {
|
if i.isSourceIP {
|
||||||
ip = metadata.SrcIP
|
ip = metadata.SrcIP
|
||||||
}
|
}
|
||||||
return ip.IsValid() && i.ipnet.Contains(ip)
|
return ip.IsValid() && i.ipnet.Contains(ip), i.adapter
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *IPCIDR) Adapter() string {
|
func (i *IPCIDR) Adapter() string {
|
||||||
|
@ -74,4 +74,4 @@ func NewIPCIDR(s string, adapter string, opts ...IPCIDROption) (*IPCIDR, error)
|
||||||
return ipcidr, nil
|
return ipcidr, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ C.Rule = (*IPCIDR)(nil)
|
//var _ C.Rule = (*IPCIDR)(nil)
|
||||||
|
|
|
@ -22,7 +22,7 @@ func (is *IPSuffix) RuleType() C.RuleType {
|
||||||
return C.IPSuffix
|
return C.IPSuffix
|
||||||
}
|
}
|
||||||
|
|
||||||
func (is *IPSuffix) Match(metadata *C.Metadata) bool {
|
func (is *IPSuffix) Match(metadata *C.Metadata) (bool, string) {
|
||||||
ip := metadata.DstIP
|
ip := metadata.DstIP
|
||||||
if is.isSourceIP {
|
if is.isSourceIP {
|
||||||
ip = metadata.SrcIP
|
ip = metadata.SrcIP
|
||||||
|
@ -30,7 +30,7 @@ func (is *IPSuffix) Match(metadata *C.Metadata) bool {
|
||||||
|
|
||||||
mIPBytes := ip.AsSlice()
|
mIPBytes := ip.AsSlice()
|
||||||
if len(is.ipBytes) != len(mIPBytes) {
|
if len(is.ipBytes) != len(mIPBytes) {
|
||||||
return false
|
return false, ""
|
||||||
}
|
}
|
||||||
|
|
||||||
size := len(mIPBytes)
|
size := len(mIPBytes)
|
||||||
|
@ -38,15 +38,15 @@ func (is *IPSuffix) Match(metadata *C.Metadata) bool {
|
||||||
|
|
||||||
for i := bits / 8; i > 0; i-- {
|
for i := bits / 8; i > 0; i-- {
|
||||||
if is.ipBytes[size-i] != mIPBytes[size-i] {
|
if is.ipBytes[size-i] != mIPBytes[size-i] {
|
||||||
return false
|
return false, ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is.ipBytes[size-bits/8-1] << (8 - bits%8)) != (mIPBytes[size-bits/8-1] << (8 - bits%8)) {
|
if (is.ipBytes[size-bits/8-1] << (8 - bits%8)) != (mIPBytes[size-bits/8-1] << (8 - bits%8)) {
|
||||||
return false
|
return false, ""
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true, is.adapter
|
||||||
}
|
}
|
||||||
|
|
||||||
func (is *IPSuffix) Adapter() string {
|
func (is *IPSuffix) Adapter() string {
|
||||||
|
|
|
@ -36,8 +36,8 @@ func (n *NetworkType) RuleType() C.RuleType {
|
||||||
return C.Network
|
return C.Network
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *NetworkType) Match(metadata *C.Metadata) bool {
|
func (n *NetworkType) Match(metadata *C.Metadata) (bool, string) {
|
||||||
return n.network == metadata.NetWork
|
return n.network == metadata.NetWork, n.adapter
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *NetworkType) Adapter() string {
|
func (n *NetworkType) Adapter() string {
|
||||||
|
|
|
@ -24,11 +24,11 @@ func (p *Port) RuleType() C.RuleType {
|
||||||
return C.DstPort
|
return C.DstPort
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Port) Match(metadata *C.Metadata) bool {
|
func (p *Port) Match(metadata *C.Metadata) (bool, string) {
|
||||||
if p.isSource {
|
if p.isSource {
|
||||||
return p.matchPortReal(metadata.SrcPort)
|
return p.matchPortReal(metadata.SrcPort), p.adapter
|
||||||
}
|
}
|
||||||
return p.matchPortReal(metadata.DstPort)
|
return p.matchPortReal(metadata.DstPort), p.adapter
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Port) Adapter() string {
|
func (p *Port) Adapter() string {
|
||||||
|
|
|
@ -17,12 +17,12 @@ func (ps *Process) RuleType() C.RuleType {
|
||||||
return C.Process
|
return C.Process
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ps *Process) Match(metadata *C.Metadata) bool {
|
func (ps *Process) Match(metadata *C.Metadata) (bool, string) {
|
||||||
if ps.nameOnly {
|
if ps.nameOnly {
|
||||||
return strings.EqualFold(metadata.Process, ps.process)
|
return strings.EqualFold(metadata.Process, ps.process), ps.adapter
|
||||||
}
|
}
|
||||||
|
|
||||||
return strings.EqualFold(metadata.ProcessPath, ps.process)
|
return strings.EqualFold(metadata.ProcessPath, ps.process), ps.adapter
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ps *Process) Adapter() string {
|
func (ps *Process) Adapter() string {
|
||||||
|
|
|
@ -71,10 +71,10 @@ func (u *Uid) RuleType() C.RuleType {
|
||||||
return C.Uid
|
return C.Uid
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *Uid) Match(metadata *C.Metadata) bool {
|
func (u *Uid) Match(metadata *C.Metadata) (bool, string) {
|
||||||
srcPort, err := strconv.ParseUint(metadata.SrcPort, 10, 16)
|
srcPort, err := strconv.ParseUint(metadata.SrcPort, 10, 16)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
return false, ""
|
||||||
}
|
}
|
||||||
var uid int32
|
var uid int32
|
||||||
if metadata.Uid != nil {
|
if metadata.Uid != nil {
|
||||||
|
@ -83,15 +83,15 @@ func (u *Uid) Match(metadata *C.Metadata) bool {
|
||||||
metadata.Uid = &uid
|
metadata.Uid = &uid
|
||||||
} else {
|
} else {
|
||||||
log.Warnln("[UID] could not get uid from %s", metadata.String())
|
log.Warnln("[UID] could not get uid from %s", metadata.String())
|
||||||
return false
|
return false, ""
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, _uid := range u.uids {
|
for _, _uid := range u.uids {
|
||||||
if _uid.Contains(uid) {
|
if _uid.Contains(uid) {
|
||||||
return true
|
return true, u.adapter
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false
|
return false, ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *Uid) Adapter() string {
|
func (u *Uid) Adapter() string {
|
||||||
|
|
|
@ -20,9 +20,9 @@ func (A *AND) ShouldFindProcess() bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewAND(payload string, adapter string,
|
func NewAND(payload string, adapter string,
|
||||||
parse func(tp, payload, target string, params []string) (parsed C.Rule, parseErr error)) (*AND, error) {
|
parse func(tp, payload, target string, params []string, subRules *map[string][]C.Rule) (parsed C.Rule, parseErr error)) (*AND, error) {
|
||||||
and := &AND{Base: &common.Base{}, payload: payload, adapter: adapter}
|
and := &AND{Base: &common.Base{}, payload: payload, adapter: adapter}
|
||||||
rules, err := parseRuleByPayload(payload, parse)
|
rules, err := ParseRuleByPayload(payload, parse)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -45,14 +45,14 @@ func (A *AND) RuleType() C.RuleType {
|
||||||
return C.AND
|
return C.AND
|
||||||
}
|
}
|
||||||
|
|
||||||
func (A *AND) Match(metadata *C.Metadata) bool {
|
func (A *AND) Match(metadata *C.Metadata) (bool, string) {
|
||||||
for _, rule := range A.rules {
|
for _, rule := range A.rules {
|
||||||
if !rule.Match(metadata) {
|
if m, _ := rule.Match(metadata); !m {
|
||||||
return false
|
return false, ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true, A.adapter
|
||||||
}
|
}
|
||||||
|
|
||||||
func (A *AND) Adapter() string {
|
func (A *AND) Adapter() string {
|
||||||
|
|
|
@ -9,7 +9,7 @@ import (
|
||||||
_ "unsafe"
|
_ "unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
func parseRuleByPayload(payload string, parseRule func(tp, payload, target string, params []string) (parsed C.Rule, parseErr error)) ([]C.Rule, error) {
|
func ParseRuleByPayload(payload string, parseRule func(tp, payload, target string, params []string, subRules *map[string][]C.Rule) (parsed C.Rule, parseErr error)) ([]C.Rule, error) {
|
||||||
regex, err := regexp.Compile("\\(.*\\)")
|
regex, err := regexp.Compile("\\(.*\\)")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -59,13 +59,13 @@ func payloadToRule(subPayload string, parseRule func(tp, payload, target string,
|
||||||
return parseRule(tp, param[0], "", param[1:])
|
return parseRule(tp, param[0], "", param[1:])
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseLogicSubRule(parseRule func(tp, payload, target string, params []string) (parsed C.Rule, parseErr error)) func(tp, payload, target string, params []string) (parsed C.Rule, parseErr error) {
|
func parseLogicSubRule(parseRule func(tp, payload, target string, params []string, subRules *map[string][]C.Rule) (parsed C.Rule, parseErr error)) func(tp, payload, target string, params []string) (parsed C.Rule, parseErr error) {
|
||||||
return func(tp, payload, target string, params []string) (parsed C.Rule, parseErr error) {
|
return func(tp, payload, target string, params []string) (parsed C.Rule, parseErr error) {
|
||||||
switch tp {
|
switch tp {
|
||||||
case "MATCH":
|
case "MATCH", "SUB-RULE":
|
||||||
return nil, fmt.Errorf("unsupported rule type on logic rule")
|
return nil, fmt.Errorf("unsupported rule type [%s] on logic rule", tp)
|
||||||
default:
|
default:
|
||||||
return parseRule(tp, payload, target, params)
|
return parseRule(tp, payload, target, params, nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,14 +2,14 @@ package logic
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/Dreamacro/clash/constant"
|
C "github.com/Dreamacro/clash/constant"
|
||||||
RC "github.com/Dreamacro/clash/rules/common"
|
RC "github.com/Dreamacro/clash/rules/common"
|
||||||
RP "github.com/Dreamacro/clash/rules/provider"
|
RP "github.com/Dreamacro/clash/rules/provider"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ParseRule(tp, payload, target string, params []string) (parsed constant.Rule, parseErr error) {
|
func ParseRule(tp, payload, target string, params []string, subRules *map[string][]C.Rule) (parsed C.Rule, parseErr error) {
|
||||||
switch tp {
|
switch tp {
|
||||||
case "DOMAIN":
|
case "DOMAIN":
|
||||||
parsed = RC.NewDomain(payload, target)
|
parsed = RC.NewDomain(payload, target)
|
||||||
|
@ -46,6 +46,8 @@ func ParseRule(tp, payload, target string, params []string) (parsed constant.Rul
|
||||||
parsed, parseErr = RC.NewUid(payload, target)
|
parsed, parseErr = RC.NewUid(payload, target)
|
||||||
case "IN-TYPE":
|
case "IN-TYPE":
|
||||||
parsed, parseErr = RC.NewInType(payload, target)
|
parsed, parseErr = RC.NewInType(payload, target)
|
||||||
|
case "SUB-RULE":
|
||||||
|
parsed, parseErr = NewSubRule(payload, target, subRules, ParseRule)
|
||||||
case "AND":
|
case "AND":
|
||||||
parsed, parseErr = NewAND(payload, target, ParseRule)
|
parsed, parseErr = NewAND(payload, target, ParseRule)
|
||||||
case "OR":
|
case "OR":
|
||||||
|
@ -54,7 +56,7 @@ func ParseRule(tp, payload, target string, params []string) (parsed constant.Rul
|
||||||
parsed, parseErr = NewNOT(payload, target, ParseRule)
|
parsed, parseErr = NewNOT(payload, target, ParseRule)
|
||||||
case "RULE-SET":
|
case "RULE-SET":
|
||||||
noResolve := RC.HasNoResolve(params)
|
noResolve := RC.HasNoResolve(params)
|
||||||
parsed, parseErr = RP.NewRuleSet(payload, target, noResolve, ParseRule)
|
parsed, parseErr = RP.NewRuleSet(payload, target, noResolve)
|
||||||
case "MATCH":
|
case "MATCH":
|
||||||
parsed = RC.NewMatch(target)
|
parsed = RC.NewMatch(target)
|
||||||
parseErr = nil
|
parseErr = nil
|
||||||
|
@ -70,12 +72,13 @@ func TestAND(t *testing.T) {
|
||||||
assert.Equal(t, nil, err)
|
assert.Equal(t, nil, err)
|
||||||
assert.Equal(t, "DIRECT", and.adapter)
|
assert.Equal(t, "DIRECT", and.adapter)
|
||||||
assert.Equal(t, false, and.ShouldResolveIP())
|
assert.Equal(t, false, and.ShouldResolveIP())
|
||||||
assert.Equal(t, true, and.Match(&constant.Metadata{
|
m, _ := and.Match(&C.Metadata{
|
||||||
Host: "baidu.com",
|
Host: "baidu.com",
|
||||||
AddrType: constant.AtypDomainName,
|
AddrType: C.AtypDomainName,
|
||||||
NetWork: constant.TCP,
|
NetWork: C.TCP,
|
||||||
DstPort: "20000",
|
DstPort: "20000",
|
||||||
}))
|
})
|
||||||
|
assert.Equal(t, true, m)
|
||||||
|
|
||||||
and, err = NewAND("(DOMAIN,baidu.com),(NETWORK,TCP),(DST-PORT,10001-65535))", "DIRECT", ParseRule)
|
and, err = NewAND("(DOMAIN,baidu.com),(NETWORK,TCP),(DST-PORT,10001-65535))", "DIRECT", ParseRule)
|
||||||
assert.NotEqual(t, nil, err)
|
assert.NotEqual(t, nil, err)
|
||||||
|
@ -87,9 +90,10 @@ func TestAND(t *testing.T) {
|
||||||
func TestNOT(t *testing.T) {
|
func TestNOT(t *testing.T) {
|
||||||
not, err := NewNOT("((DST-PORT,6000-6500))", "REJECT", ParseRule)
|
not, err := NewNOT("((DST-PORT,6000-6500))", "REJECT", ParseRule)
|
||||||
assert.Equal(t, nil, err)
|
assert.Equal(t, nil, err)
|
||||||
assert.Equal(t, false, not.Match(&constant.Metadata{
|
m, _ := not.Match(&C.Metadata{
|
||||||
DstPort: "6100",
|
DstPort: "6100",
|
||||||
}))
|
})
|
||||||
|
assert.Equal(t, false, m)
|
||||||
|
|
||||||
_, err = NewNOT("((DST-PORT,5600-6666),(DOMAIN,baidu.com))", "DIRECT", ParseRule)
|
_, err = NewNOT("((DST-PORT,5600-6666),(DOMAIN,baidu.com))", "DIRECT", ParseRule)
|
||||||
assert.NotEqual(t, nil, err)
|
assert.NotEqual(t, nil, err)
|
||||||
|
@ -101,8 +105,9 @@ func TestNOT(t *testing.T) {
|
||||||
func TestOR(t *testing.T) {
|
func TestOR(t *testing.T) {
|
||||||
or, err := NewOR("((DOMAIN,baidu.com),(NETWORK,TCP),(DST-PORT,10001-65535))", "DIRECT", ParseRule)
|
or, err := NewOR("((DOMAIN,baidu.com),(NETWORK,TCP),(DST-PORT,10001-65535))", "DIRECT", ParseRule)
|
||||||
assert.Equal(t, nil, err)
|
assert.Equal(t, nil, err)
|
||||||
assert.Equal(t, true, or.Match(&constant.Metadata{
|
m, _ := or.Match(&C.Metadata{
|
||||||
NetWork: constant.TCP,
|
NetWork: C.TCP,
|
||||||
}))
|
})
|
||||||
|
assert.Equal(t, true, m)
|
||||||
assert.Equal(t, false, or.ShouldResolveIP())
|
assert.Equal(t, false, or.ShouldResolveIP())
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,9 +17,9 @@ func (not *NOT) ShouldFindProcess() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewNOT(payload string, adapter string, parse func(tp, payload, target string, params []string) (parsed C.Rule, parseErr error)) (*NOT, error) {
|
func NewNOT(payload string, adapter string, parse func(tp, payload, target string, params []string, subRules *map[string][]C.Rule) (parsed C.Rule, parseErr error)) (*NOT, error) {
|
||||||
not := &NOT{Base: &common.Base{}, adapter: adapter}
|
not := &NOT{Base: &common.Base{}, adapter: adapter}
|
||||||
rule, err := parseRuleByPayload(payload, parse)
|
rule, err := ParseRuleByPayload(payload, parse)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -38,8 +38,16 @@ func (not *NOT) RuleType() C.RuleType {
|
||||||
return C.NOT
|
return C.NOT
|
||||||
}
|
}
|
||||||
|
|
||||||
func (not *NOT) Match(metadata *C.Metadata) bool {
|
func (not *NOT) Match(metadata *C.Metadata) (bool, string) {
|
||||||
return not.rule == nil || !not.rule.Match(metadata)
|
if not.rule == nil {
|
||||||
|
return true, not.adapter
|
||||||
|
}
|
||||||
|
|
||||||
|
if m, _ := not.rule.Match(metadata); !m {
|
||||||
|
return true, not.adapter
|
||||||
|
}
|
||||||
|
|
||||||
|
return false, ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (not *NOT) Adapter() string {
|
func (not *NOT) Adapter() string {
|
||||||
|
|
|
@ -23,14 +23,14 @@ func (or *OR) RuleType() C.RuleType {
|
||||||
return C.OR
|
return C.OR
|
||||||
}
|
}
|
||||||
|
|
||||||
func (or *OR) Match(metadata *C.Metadata) bool {
|
func (or *OR) Match(metadata *C.Metadata) (bool, string) {
|
||||||
for _, rule := range or.rules {
|
for _, rule := range or.rules {
|
||||||
if rule.Match(metadata) {
|
if m, _ := rule.Match(metadata); m {
|
||||||
return true
|
return true, or.adapter
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return false, ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (or *OR) Adapter() string {
|
func (or *OR) Adapter() string {
|
||||||
|
@ -45,9 +45,9 @@ func (or *OR) ShouldResolveIP() bool {
|
||||||
return or.needIP
|
return or.needIP
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewOR(payload string, adapter string, parse func(tp, payload, target string, params []string) (parsed C.Rule, parseErr error)) (*OR, error) {
|
func NewOR(payload string, adapter string, parse func(tp, payload, target string, params []string, subRules *map[string][]C.Rule) (parsed C.Rule, parseErr error)) (*OR, error) {
|
||||||
or := &OR{Base: &common.Base{}, payload: payload, adapter: adapter}
|
or := &OR{Base: &common.Base{}, payload: payload, adapter: adapter}
|
||||||
rules, err := parseRuleByPayload(payload, parse)
|
rules, err := ParseRuleByPayload(payload, parse)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
91
rules/logic/sub_rules.go
Normal file
91
rules/logic/sub_rules.go
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
package logic
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
C "github.com/Dreamacro/clash/constant"
|
||||||
|
"github.com/Dreamacro/clash/rules/common"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SubRule struct {
|
||||||
|
*common.Base
|
||||||
|
payload string
|
||||||
|
payloadRule C.Rule
|
||||||
|
subName string
|
||||||
|
subRules *map[string][]C.Rule
|
||||||
|
shouldFindProcess *bool
|
||||||
|
shouldResolveIP *bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSubRule(payload, subName string, sub *map[string][]C.Rule,
|
||||||
|
parse func(tp, payload, target string, params []string, subRules *map[string][]C.Rule) (parsed C.Rule, parseErr error)) (*SubRule, error) {
|
||||||
|
payloadRule, err := ParseRuleByPayload(fmt.Sprintf("(%s)", payload), parse)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(payloadRule) != 1 {
|
||||||
|
return nil, fmt.Errorf("Sub-Rule rule must contain one rule")
|
||||||
|
}
|
||||||
|
|
||||||
|
return &SubRule{
|
||||||
|
Base: &common.Base{},
|
||||||
|
payload: payload,
|
||||||
|
payloadRule: payloadRule[0],
|
||||||
|
subName: subName,
|
||||||
|
subRules: sub,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *SubRule) RuleType() C.RuleType {
|
||||||
|
return C.SubRules
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *SubRule) Match(metadata *C.Metadata) (bool, string) {
|
||||||
|
|
||||||
|
return match(metadata, r.subName, r.subRules)
|
||||||
|
}
|
||||||
|
|
||||||
|
func match(metadata *C.Metadata, name string, subRules *map[string][]C.Rule) (bool, string) {
|
||||||
|
for _, rule := range (*subRules)[name] {
|
||||||
|
if m, a := rule.Match(metadata); m {
|
||||||
|
if rule.RuleType() == C.SubRules {
|
||||||
|
match(metadata, rule.Adapter(), subRules)
|
||||||
|
} else {
|
||||||
|
return m, a
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false, ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *SubRule) ShouldResolveIP() bool {
|
||||||
|
if r.shouldResolveIP == nil {
|
||||||
|
s := false
|
||||||
|
for _, rule := range (*r.subRules)[r.subName] {
|
||||||
|
s = s || rule.ShouldResolveIP()
|
||||||
|
}
|
||||||
|
r.shouldResolveIP = &s
|
||||||
|
}
|
||||||
|
|
||||||
|
return *r.shouldResolveIP
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *SubRule) ShouldFindProcess() bool {
|
||||||
|
if r.shouldFindProcess == nil {
|
||||||
|
s := false
|
||||||
|
for _, rule := range (*r.subRules)[r.subName] {
|
||||||
|
s = s || rule.ShouldFindProcess()
|
||||||
|
}
|
||||||
|
r.shouldFindProcess = &s
|
||||||
|
}
|
||||||
|
|
||||||
|
return *r.shouldFindProcess
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *SubRule) Adapter() string {
|
||||||
|
return r.subName
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *SubRule) Payload() string {
|
||||||
|
return r.payload
|
||||||
|
}
|
|
@ -8,7 +8,7 @@ import (
|
||||||
RP "github.com/Dreamacro/clash/rules/provider"
|
RP "github.com/Dreamacro/clash/rules/provider"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ParseRule(tp, payload, target string, params []string) (parsed C.Rule, parseErr error) {
|
func ParseRule(tp, payload, target string, params []string, subRules *map[string][]C.Rule) (parsed C.Rule, parseErr error) {
|
||||||
switch tp {
|
switch tp {
|
||||||
case "DOMAIN":
|
case "DOMAIN":
|
||||||
parsed = RC.NewDomain(payload, target)
|
parsed = RC.NewDomain(payload, target)
|
||||||
|
@ -45,6 +45,8 @@ func ParseRule(tp, payload, target string, params []string) (parsed C.Rule, pars
|
||||||
parsed, parseErr = RC.NewUid(payload, target)
|
parsed, parseErr = RC.NewUid(payload, target)
|
||||||
case "IN-TYPE":
|
case "IN-TYPE":
|
||||||
parsed, parseErr = RC.NewInType(payload, target)
|
parsed, parseErr = RC.NewInType(payload, target)
|
||||||
|
case "SUB-RULE":
|
||||||
|
parsed, parseErr = logic.NewSubRule(payload, target, subRules, ParseRule)
|
||||||
case "AND":
|
case "AND":
|
||||||
parsed, parseErr = logic.NewAND(payload, target, ParseRule)
|
parsed, parseErr = logic.NewAND(payload, target, ParseRule)
|
||||||
case "OR":
|
case "OR":
|
||||||
|
@ -53,7 +55,7 @@ func ParseRule(tp, payload, target string, params []string) (parsed C.Rule, pars
|
||||||
parsed, parseErr = logic.NewNOT(payload, target, ParseRule)
|
parsed, parseErr = logic.NewNOT(payload, target, ParseRule)
|
||||||
case "RULE-SET":
|
case "RULE-SET":
|
||||||
noResolve := RC.HasNoResolve(params)
|
noResolve := RC.HasNoResolve(params)
|
||||||
parsed, parseErr = RP.NewRuleSet(payload, target, noResolve, ParseRule)
|
parsed, parseErr = RP.NewRuleSet(payload, target, noResolve)
|
||||||
case "MATCH":
|
case "MATCH":
|
||||||
parsed = RC.NewMatch(target)
|
parsed = RC.NewMatch(target)
|
||||||
parseErr = nil
|
parseErr = nil
|
||||||
|
|
|
@ -16,7 +16,7 @@ type classicalStrategy struct {
|
||||||
|
|
||||||
func (c *classicalStrategy) Match(metadata *C.Metadata) bool {
|
func (c *classicalStrategy) Match(metadata *C.Metadata) bool {
|
||||||
for _, rule := range c.rules {
|
for _, rule := range c.rules {
|
||||||
if rule.Match(metadata) {
|
if m, _ := rule.Match(metadata); m {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -66,13 +66,13 @@ func ruleParse(ruleRaw string) (string, string, []string) {
|
||||||
return "", "", nil
|
return "", "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewClassicalStrategy(parse func(tp, payload, target string, params []string) (parsed C.Rule, parseErr error)) *classicalStrategy {
|
func NewClassicalStrategy(parse func(tp, payload, target string, params []string, subRules *map[string][]C.Rule) (parsed C.Rule, parseErr error)) *classicalStrategy {
|
||||||
return &classicalStrategy{rules: []C.Rule{}, parse: func(tp, payload, target string, params []string) (parsed C.Rule, parseErr error) {
|
return &classicalStrategy{rules: []C.Rule{}, parse: func(tp, payload, target string, params []string) (parsed C.Rule, parseErr error) {
|
||||||
switch tp {
|
switch tp {
|
||||||
case "MATCH":
|
case "MATCH", "SUB-RULE":
|
||||||
return nil, fmt.Errorf("unsupported rule type on rule-set")
|
return nil, fmt.Errorf("unsupported rule type on rule-set")
|
||||||
default:
|
default:
|
||||||
return parse(tp, payload, target, params)
|
return parse(tp, payload, target, params, nil)
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ type ruleProviderSchema struct {
|
||||||
Interval int `provider:"interval,omitempty"`
|
Interval int `provider:"interval,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func ParseRuleProvider(name string, mapping map[string]interface{}, parse func(tp, payload, target string, params []string) (parsed C.Rule, parseErr error)) (P.RuleProvider, error) {
|
func ParseRuleProvider(name string, mapping map[string]interface{}, parse func(tp, payload, target string, params []string, subRules *map[string][]C.Rule) (parsed C.Rule, parseErr error)) (P.RuleProvider, error) {
|
||||||
schema := &ruleProviderSchema{}
|
schema := &ruleProviderSchema{}
|
||||||
decoder := structure.NewDecoder(structure.Option{TagName: "provider", WeaklyTypedInput: true})
|
decoder := structure.NewDecoder(structure.Option{TagName: "provider", WeaklyTypedInput: true})
|
||||||
if err := decoder.Decode(mapping, schema); err != nil {
|
if err := decoder.Decode(mapping, schema); err != nil {
|
||||||
|
|
|
@ -103,7 +103,7 @@ func (rp *ruleSetProvider) MarshalJSON() ([]byte, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewRuleSetProvider(name string, behavior P.RuleType, interval time.Duration, vehicle P.Vehicle,
|
func NewRuleSetProvider(name string, behavior P.RuleType, interval time.Duration, vehicle P.Vehicle,
|
||||||
parse func(tp, payload, target string, params []string) (parsed C.Rule, parseErr error)) P.RuleProvider {
|
parse func(tp, payload, target string, params []string, subRules *map[string][]C.Rule) (parsed C.Rule, parseErr error)) P.RuleProvider {
|
||||||
rp := &ruleSetProvider{
|
rp := &ruleSetProvider{
|
||||||
behavior: behavior,
|
behavior: behavior,
|
||||||
}
|
}
|
||||||
|
@ -126,7 +126,7 @@ func NewRuleSetProvider(name string, behavior P.RuleType, interval time.Duration
|
||||||
return wrapper
|
return wrapper
|
||||||
}
|
}
|
||||||
|
|
||||||
func newStrategy(behavior P.RuleType, parse func(tp, payload, target string, params []string) (parsed C.Rule, parseErr error)) ruleStrategy {
|
func newStrategy(behavior P.RuleType, parse func(tp, payload, target string, params []string, subRules *map[string][]C.Rule) (parsed C.Rule, parseErr error)) ruleStrategy {
|
||||||
switch behavior {
|
switch behavior {
|
||||||
case P.Domain:
|
case P.Domain:
|
||||||
strategy := NewDomainStrategy()
|
strategy := NewDomainStrategy()
|
||||||
|
|
|
@ -23,8 +23,8 @@ func (rs *RuleSet) RuleType() C.RuleType {
|
||||||
return C.RuleSet
|
return C.RuleSet
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rs *RuleSet) Match(metadata *C.Metadata) bool {
|
func (rs *RuleSet) Match(metadata *C.Metadata) (bool, string) {
|
||||||
return rs.getProviders().Match(metadata)
|
return rs.getProviders().Match(metadata), rs.adapter
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rs *RuleSet) Adapter() string {
|
func (rs *RuleSet) Adapter() string {
|
||||||
|
@ -47,7 +47,7 @@ func (rs *RuleSet) getProviders() P.RuleProvider {
|
||||||
return rs.ruleProvider
|
return rs.ruleProvider
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewRuleSet(ruleProviderName string, adapter string, noResolveIP bool, parse func(tp, payload, target string, params []string) (parsed C.Rule, parseErr error)) (*RuleSet, error) {
|
func NewRuleSet(ruleProviderName string, adapter string, noResolveIP bool) (*RuleSet, error) {
|
||||||
rp, ok := RuleProviders()[ruleProviderName]
|
rp, ok := RuleProviders()[ruleProviderName]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("rule set %s not found", ruleProviderName)
|
return nil, fmt.Errorf("rule set %s not found", ruleProviderName)
|
||||||
|
|
18
transport/hysteria/obfs/dummy.go
Normal file
18
transport/hysteria/obfs/dummy.go
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
package obfs
|
||||||
|
|
||||||
|
type DummyObfuscator struct{}
|
||||||
|
|
||||||
|
func NewDummyObfuscator() *DummyObfuscator {
|
||||||
|
return &DummyObfuscator{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *DummyObfuscator) Deobfuscate(in []byte, out []byte) int {
|
||||||
|
if len(out) < len(in) {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return copy(out, in)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *DummyObfuscator) Obfuscate(in []byte, out []byte) int {
|
||||||
|
return copy(out, in)
|
||||||
|
}
|
|
@ -4,12 +4,10 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/Dreamacro/clash/component/resolver"
|
|
||||||
"github.com/Dreamacro/clash/transport/hysteria/conns/faketcp"
|
"github.com/Dreamacro/clash/transport/hysteria/conns/faketcp"
|
||||||
"github.com/Dreamacro/clash/transport/hysteria/conns/udp"
|
"github.com/Dreamacro/clash/transport/hysteria/conns/udp"
|
||||||
"github.com/Dreamacro/clash/transport/hysteria/conns/wechat"
|
"github.com/Dreamacro/clash/transport/hysteria/conns/wechat"
|
||||||
"github.com/Dreamacro/clash/transport/hysteria/obfs"
|
obfsPkg "github.com/Dreamacro/clash/transport/hysteria/obfs"
|
||||||
"github.com/Dreamacro/clash/transport/hysteria/utils"
|
|
||||||
"github.com/lucas-clemente/quic-go"
|
"github.com/lucas-clemente/quic-go"
|
||||||
"net"
|
"net"
|
||||||
)
|
)
|
||||||
|
@ -18,7 +16,7 @@ type ClientTransport struct {
|
||||||
Dialer *net.Dialer
|
Dialer *net.Dialer
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ct *ClientTransport) quicPacketConn(proto string, server string, obfs obfs.Obfuscator, dialer PacketDialer) (net.PacketConn, error) {
|
func (ct *ClientTransport) quicPacketConn(proto string, server string, obfs obfsPkg.Obfuscator, dialer PacketDialer) (net.PacketConn, error) {
|
||||||
if len(proto) == 0 || proto == "udp" {
|
if len(proto) == 0 || proto == "udp" {
|
||||||
conn, err := dialer.ListenPacket()
|
conn, err := dialer.ListenPacket()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -35,12 +33,10 @@ func (ct *ClientTransport) quicPacketConn(proto string, server string, obfs obfs
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if obfs != nil {
|
if obfs == nil {
|
||||||
oc := wechat.NewObfsWeChatUDPConn(conn, obfs)
|
obfs = obfsPkg.NewDummyObfuscator()
|
||||||
return oc, nil
|
|
||||||
} else {
|
|
||||||
return conn, nil
|
|
||||||
}
|
}
|
||||||
|
return wechat.NewObfsWeChatUDPConn(conn, obfs), nil
|
||||||
} else if proto == "faketcp" {
|
} else if proto == "faketcp" {
|
||||||
var conn *faketcp.TCPConn
|
var conn *faketcp.TCPConn
|
||||||
conn, err := faketcp.Dial("tcp", server)
|
conn, err := faketcp.Dial("tcp", server)
|
||||||
|
@ -61,29 +57,21 @@ func (ct *ClientTransport) quicPacketConn(proto string, server string, obfs obfs
|
||||||
type PacketDialer interface {
|
type PacketDialer interface {
|
||||||
ListenPacket() (net.PacketConn, error)
|
ListenPacket() (net.PacketConn, error)
|
||||||
Context() context.Context
|
Context() context.Context
|
||||||
|
RemoteAddr(host string) (net.Addr, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ct *ClientTransport) QUICDial(proto string, server string, tlsConfig *tls.Config, quicConfig *quic.Config, obfs obfs.Obfuscator, dialer PacketDialer) (quic.Connection, error) {
|
func (ct *ClientTransport) QUICDial(proto string, server string, tlsConfig *tls.Config, quicConfig *quic.Config, obfs obfsPkg.Obfuscator, dialer PacketDialer) (quic.Connection, error) {
|
||||||
ipStr, port, err := utils.SplitHostPort(server)
|
serverUDPAddr, err := dialer.RemoteAddr(server)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
ip, err := resolver.ResolveProxyServerHost(ipStr)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
serverUDPAddr := net.UDPAddr{
|
|
||||||
IP: net.ParseIP(ip.String()),
|
|
||||||
Port: int(port),
|
|
||||||
}
|
|
||||||
|
|
||||||
pktConn, err := ct.quicPacketConn(proto, serverUDPAddr.String(), obfs, dialer)
|
pktConn, err := ct.quicPacketConn(proto, serverUDPAddr.String(), obfs, dialer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
qs, err := quic.DialContext(dialer.Context(), pktConn, &serverUDPAddr, server, tlsConfig, quicConfig)
|
|
||||||
|
qs, err := quic.DialContext(dialer.Context(), pktConn, serverUDPAddr, server, tlsConfig, quicConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = pktConn.Close()
|
_ = pktConn.Close()
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
@ -241,6 +241,9 @@ func ReadPacket(r io.Reader, payload []byte) (net.Addr, int, error) {
|
||||||
return nil, 0, errors.New("remote address invalid")
|
return nil, 0, errors.New("remote address invalid")
|
||||||
}
|
}
|
||||||
uAddr := addr.UDPAddr()
|
uAddr := addr.UDPAddr()
|
||||||
|
if uAddr == nil {
|
||||||
|
return nil, 0, errors.New("parse addr error")
|
||||||
|
}
|
||||||
|
|
||||||
length := len(payload)
|
length := len(payload)
|
||||||
if n-headLen < length {
|
if n-headLen < length {
|
||||||
|
|
|
@ -250,6 +250,9 @@ func ReadPacket(r io.Reader, payload []byte) (net.Addr, int, int, error) {
|
||||||
return nil, 0, 0, errors.New("read addr error")
|
return nil, 0, 0, errors.New("read addr error")
|
||||||
}
|
}
|
||||||
uAddr := addr.UDPAddr()
|
uAddr := addr.UDPAddr()
|
||||||
|
if uAddr == nil {
|
||||||
|
return nil, 0, 0, errors.New("parse addr error")
|
||||||
|
}
|
||||||
|
|
||||||
if _, err = io.ReadFull(r, payload[:2]); err != nil {
|
if _, err = io.ReadFull(r, payload[:2]); err != nil {
|
||||||
return nil, 0, 0, errors.New("read length error")
|
return nil, 0, 0, errors.New("read length error")
|
||||||
|
|
|
@ -410,8 +410,8 @@ func match(metadata *C.Metadata) (C.Proxy, C.Rule, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if rule.Match(metadata) {
|
if matched, ada := rule.Match(metadata); matched {
|
||||||
adapter, ok := proxies[rule.Adapter()]
|
adapter, ok := proxies[ada]
|
||||||
if !ok {
|
if !ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue