[Refactor]
1.allow maybe empty group 2.use COMPATIBLE(DIRECT alias) when proxy group is empty 3.http provider pass through tunnel
This commit is contained in:
parent
ee6c1871a9
commit
b15344ec78
17 changed files with 135 additions and 50 deletions
|
@ -20,3 +20,16 @@ func NewSocket(target socks5.Addr, conn net.Conn, source C.Type) *context.ConnCo
|
|||
|
||||
return context.NewConnContext(conn, metadata)
|
||||
}
|
||||
|
||||
func NewInner(conn net.Conn, dst string, host string) *context.ConnContext {
|
||||
metadata := &C.Metadata{}
|
||||
metadata.NetWork = C.TCP
|
||||
metadata.Type = C.INNER
|
||||
metadata.DNSMode = C.DNSMapping
|
||||
metadata.AddrType = C.AtypDomainName
|
||||
metadata.Host = host
|
||||
if _, port, err := parseAddr(dst); err == nil {
|
||||
metadata.DstPort = port
|
||||
}
|
||||
return context.NewConnContext(conn, metadata)
|
||||
}
|
||||
|
|
|
@ -44,3 +44,13 @@ func NewDirect() *Direct {
|
|||
},
|
||||
}
|
||||
}
|
||||
|
||||
func NewCompatible() *Direct {
|
||||
return &Direct{
|
||||
Base: &Base{
|
||||
name: "COMPATIBLE",
|
||||
tp: C.Compatible,
|
||||
udp: true,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package outboundgroup
|
||||
|
||||
import (
|
||||
"github.com/Dreamacro/clash/tunnel"
|
||||
"regexp"
|
||||
"time"
|
||||
|
||||
|
@ -21,6 +22,7 @@ func getProvidersProxies(providers []provider.ProxyProvider, touch bool, filter
|
|||
proxies = append(proxies, provider.Proxies()...)
|
||||
}
|
||||
}
|
||||
|
||||
var filterReg *regexp.Regexp = nil
|
||||
matchedProxies := []C.Proxy{}
|
||||
if len(filter) > 0 {
|
||||
|
@ -32,8 +34,16 @@ func getProvidersProxies(providers []provider.ProxyProvider, touch bool, filter
|
|||
}
|
||||
//if no proxy matched, means bad filter, return all proxies
|
||||
if len(matchedProxies) > 0 {
|
||||
proxies = matchedProxies
|
||||
return matchedProxies
|
||||
} else {
|
||||
return append([]C.Proxy{}, tunnel.Proxies()["COMPATIBLE"])
|
||||
}
|
||||
} else {
|
||||
if len(proxies) == 0 {
|
||||
return append(proxies, tunnel.Proxies()["COMPATIBLE"])
|
||||
} else {
|
||||
return proxies
|
||||
}
|
||||
}
|
||||
return proxies
|
||||
|
||||
}
|
||||
|
|
|
@ -72,7 +72,7 @@ func (f *Fallback) onDialFailed() {
|
|||
} else {
|
||||
failedCount := f.failedTimes.Inc()
|
||||
log.Warnln("%s failed count: %d", f.Name(), failedCount)
|
||||
if failedCount >= 5 && failedCount < 6 {
|
||||
if failedCount >= 5 {
|
||||
log.Warnln("because %s failed multiple times, active health check", f.Name())
|
||||
for _, proxyProvider := range f.providers {
|
||||
go proxyProvider.HealthCheck()
|
||||
|
@ -97,10 +97,11 @@ func (f *Fallback) SupportUDP() bool {
|
|||
|
||||
// MarshalJSON implements C.ProxyAdapter
|
||||
func (f *Fallback) MarshalJSON() ([]byte, error) {
|
||||
var all []string
|
||||
all := make([]string, 0)
|
||||
for _, proxy := range f.proxies(false) {
|
||||
all = append(all, proxy.Name())
|
||||
}
|
||||
|
||||
return json.Marshal(map[string]interface{}{
|
||||
"type": f.Type().String(),
|
||||
"now": f.Now(),
|
||||
|
|
|
@ -150,10 +150,12 @@ func (lb *LoadBalance) proxies(touch bool) []C.Proxy {
|
|||
|
||||
// MarshalJSON implements C.ProxyAdapter
|
||||
func (lb *LoadBalance) MarshalJSON() ([]byte, error) {
|
||||
var all []string
|
||||
all := make([]string, 0)
|
||||
|
||||
for _, proxy := range lb.proxies(false) {
|
||||
all = append(all, proxy.Name())
|
||||
}
|
||||
|
||||
return json.Marshal(map[string]interface{}{
|
||||
"type": lb.Type().String(),
|
||||
"all": all,
|
||||
|
|
|
@ -23,7 +23,7 @@ type Relay struct {
|
|||
func (r *Relay) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.Conn, error) {
|
||||
var proxies []C.Proxy
|
||||
for _, proxy := range r.proxies(metadata, true) {
|
||||
if proxy.Type() != C.Direct {
|
||||
if proxy.Type() != C.Direct && proxy.Type() != C.Compatible {
|
||||
proxies = append(proxies, proxy)
|
||||
}
|
||||
}
|
||||
|
@ -69,10 +69,12 @@ func (r *Relay) DialContext(ctx context.Context, metadata *C.Metadata, opts ...d
|
|||
|
||||
// MarshalJSON implements C.ProxyAdapter
|
||||
func (r *Relay) MarshalJSON() ([]byte, error) {
|
||||
var all []string
|
||||
all := make([]string, 0)
|
||||
|
||||
for _, proxy := range r.rawProxies(false) {
|
||||
all = append(all, proxy.Name())
|
||||
}
|
||||
|
||||
return json.Marshal(map[string]interface{}{
|
||||
"type": r.Type().String(),
|
||||
"all": all,
|
||||
|
|
|
@ -50,7 +50,8 @@ func (s *Selector) SupportUDP() bool {
|
|||
|
||||
// MarshalJSON implements C.ProxyAdapter
|
||||
func (s *Selector) MarshalJSON() ([]byte, error) {
|
||||
var all []string
|
||||
all := make([]string, 0)
|
||||
|
||||
for _, proxy := range getProvidersProxies(s.providers, false, s.filter) {
|
||||
all = append(all, proxy.Name())
|
||||
}
|
||||
|
|
|
@ -125,10 +125,12 @@ func (u *URLTest) SupportUDP() bool {
|
|||
|
||||
// MarshalJSON implements C.ProxyAdapter
|
||||
func (u *URLTest) MarshalJSON() ([]byte, error) {
|
||||
var all []string
|
||||
all := make([]string, 0)
|
||||
|
||||
for _, proxy := range u.proxies(false) {
|
||||
all = append(all, proxy.Name())
|
||||
}
|
||||
|
||||
return json.Marshal(map[string]interface{}{
|
||||
"type": u.Type().String(),
|
||||
"now": u.Now(),
|
||||
|
@ -149,7 +151,7 @@ func (u *URLTest) onDialFailed() {
|
|||
} else {
|
||||
failedCount := u.failedTimes.Inc()
|
||||
log.Warnln("%s failed count: %d", u.Name(), failedCount)
|
||||
if failedCount >= 5 && failedCount < 6 {
|
||||
if failedCount >= 5 {
|
||||
log.Warnln("because %s failed multiple times, active health check", u.Name())
|
||||
for _, proxyProvider := range u.providers {
|
||||
go proxyProvider.HealthCheck()
|
||||
|
|
|
@ -67,6 +67,10 @@ func (pp *proxySetProvider) Initial() error {
|
|||
}
|
||||
|
||||
pp.onUpdate(elm)
|
||||
if pp.healthCheck.auto() {
|
||||
go pp.healthCheck.process()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -102,10 +106,6 @@ func NewProxySetProvider(name string, interval time.Duration, filter string, veh
|
|||
return nil, fmt.Errorf("invalid filter regex: %w", err)
|
||||
}
|
||||
|
||||
if hc.auto() {
|
||||
go hc.process()
|
||||
}
|
||||
|
||||
pd := &proxySetProvider{
|
||||
proxies: []C.Proxy{},
|
||||
healthCheck: hc,
|
||||
|
@ -190,6 +190,10 @@ func (cp *compatibleProvider) Update() error {
|
|||
}
|
||||
|
||||
func (cp *compatibleProvider) Initial() error {
|
||||
if cp.healthCheck.auto() {
|
||||
go cp.healthCheck.process()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -219,10 +223,6 @@ func NewCompatibleProvider(name string, proxies []C.Proxy, hc *HealthCheck) (*Co
|
|||
return nil, errors.New("provider need one proxy at least")
|
||||
}
|
||||
|
||||
if hc.auto() {
|
||||
go hc.process()
|
||||
}
|
||||
|
||||
pd := &compatibleProvider{
|
||||
name: name,
|
||||
proxies: proxies,
|
||||
|
|
|
@ -2,6 +2,7 @@ package provider
|
|||
|
||||
import (
|
||||
"context"
|
||||
"github.com/Dreamacro/clash/listener/inner"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
|
@ -10,7 +11,6 @@ import (
|
|||
"time"
|
||||
|
||||
netHttp "github.com/Dreamacro/clash/common/net"
|
||||
"github.com/Dreamacro/clash/component/dialer"
|
||||
types "github.com/Dreamacro/clash/constant/provider"
|
||||
)
|
||||
|
||||
|
@ -77,7 +77,8 @@ func (h *HTTPVehicle) Read() ([]byte, error) {
|
|||
TLSHandshakeTimeout: 10 * time.Second,
|
||||
ExpectContinueTimeout: 1 * time.Second,
|
||||
DialContext: func(ctx context.Context, network, address string) (net.Conn, error) {
|
||||
return dialer.DialContext(ctx, network, address)
|
||||
conn := inner.HandleTcp(address, uri.Hostname())
|
||||
return conn, nil
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -350,6 +350,7 @@ func parseProxies(cfg *RawConfig) (proxies map[string]C.Proxy, providersMap map[
|
|||
|
||||
proxies["DIRECT"] = adapter.NewProxy(outbound.NewDirect())
|
||||
proxies["REJECT"] = adapter.NewProxy(outbound.NewReject())
|
||||
proxies["COMPATIBLE"] = adapter.NewProxy(outbound.NewCompatible())
|
||||
proxyList = append(proxyList, "DIRECT", "REJECT")
|
||||
|
||||
// parse proxy
|
||||
|
@ -396,13 +397,6 @@ func parseProxies(cfg *RawConfig) (proxies map[string]C.Proxy, providersMap map[
|
|||
providersMap[name] = pd
|
||||
}
|
||||
|
||||
for _, rp := range providersMap {
|
||||
log.Infoln("Start initial provider %s", rp.Name())
|
||||
if err := rp.Initial(); err != nil {
|
||||
return nil, nil, fmt.Errorf("initial proxy provider %s error: %w", rp.Name(), err)
|
||||
}
|
||||
}
|
||||
|
||||
// parse proxy group
|
||||
for idx, mapping := range groupsConfig {
|
||||
group, err := outboundgroup.ParseProxyGroup(mapping, proxies, providersMap)
|
||||
|
@ -418,18 +412,6 @@ func parseProxies(cfg *RawConfig) (proxies map[string]C.Proxy, providersMap map[
|
|||
proxies[groupName] = adapter.NewProxy(group)
|
||||
}
|
||||
|
||||
// initial compatible provider
|
||||
for _, pd := range providersMap {
|
||||
if pd.VehicleType() != providerTypes.Compatible {
|
||||
continue
|
||||
}
|
||||
|
||||
log.Infoln("Start initial compatible provider %s", pd.Name())
|
||||
if err := pd.Initial(); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
var ps []C.Proxy
|
||||
for _, v := range proxyList {
|
||||
ps = append(ps, proxies[v])
|
||||
|
@ -511,13 +493,6 @@ func parseRules(cfg *RawConfig, proxies map[string]C.Proxy) ([]C.Rule, map[strin
|
|||
R.SetRuleProvider(rp)
|
||||
}
|
||||
|
||||
for _, ruleProvider := range ruleProviders {
|
||||
log.Infoln("Start initial provider %s", (*ruleProvider).Name())
|
||||
if err := (*ruleProvider).Initial(); err != nil {
|
||||
return nil, nil, fmt.Errorf("initial rule provider %s error: %w", (*ruleProvider).Name(), err)
|
||||
}
|
||||
}
|
||||
|
||||
var rules []C.Rule
|
||||
rulesConfig := cfg.Rule
|
||||
mode := cfg.Mode
|
||||
|
|
|
@ -13,7 +13,7 @@ import (
|
|||
const (
|
||||
Direct AdapterType = iota
|
||||
Reject
|
||||
|
||||
Compatible
|
||||
Shadowsocks
|
||||
ShadowsocksR
|
||||
Snell
|
||||
|
@ -128,7 +128,8 @@ func (at AdapterType) String() string {
|
|||
return "Direct"
|
||||
case Reject:
|
||||
return "Reject"
|
||||
|
||||
case Compatible:
|
||||
return "Compatible"
|
||||
case Shadowsocks:
|
||||
return "Shadowsocks"
|
||||
case ShadowsocksR:
|
||||
|
|
|
@ -24,6 +24,7 @@ const (
|
|||
REDIR
|
||||
TPROXY
|
||||
TUN
|
||||
INNER
|
||||
)
|
||||
|
||||
type NetWork int
|
||||
|
@ -59,6 +60,8 @@ func (t Type) String() string {
|
|||
return "TProxy"
|
||||
case TUN:
|
||||
return "Tun"
|
||||
case INNER:
|
||||
return "Inner"
|
||||
default:
|
||||
return "Unknown"
|
||||
}
|
||||
|
@ -94,6 +97,10 @@ func (m *Metadata) SourceDetail() string {
|
|||
if m.Process != "" {
|
||||
return fmt.Sprintf("%s(%s)", m.SourceAddress(), m.Process)
|
||||
} else {
|
||||
if m.Type == INNER {
|
||||
return fmt.Sprintf("[Clash]")
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%s", m.SourceAddress())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -74,15 +74,17 @@ func ApplyConfig(cfg *config.Config, force bool) {
|
|||
defer mux.Unlock()
|
||||
|
||||
updateUsers(cfg.Users)
|
||||
updateProxies(cfg.Proxies, cfg.Providers)
|
||||
updateRules(cfg.Rules, cfg.RuleProviders)
|
||||
updateHosts(cfg.Hosts)
|
||||
updateProfile(cfg)
|
||||
updateProxies(cfg.Proxies, cfg.Providers)
|
||||
updateRules(cfg.Rules, cfg.RuleProviders)
|
||||
updateIPTables(cfg.DNS, cfg.General, cfg.Tun)
|
||||
updateDNS(cfg.DNS, cfg.Tun)
|
||||
updateGeneral(cfg.General, cfg.Tun, force)
|
||||
updateTun(cfg.Tun)
|
||||
updateExperimental(cfg)
|
||||
|
||||
loadProvider(cfg.RuleProviders, cfg.Providers)
|
||||
}
|
||||
|
||||
func GetGeneral() *config.General {
|
||||
|
@ -175,6 +177,38 @@ func updateRules(rules []C.Rule, ruleProviders map[string]*provider.RuleProvider
|
|||
tunnel.UpdateRules(rules, ruleProviders)
|
||||
}
|
||||
|
||||
func loadProvider(ruleProviders map[string]*provider.RuleProvider, proxyProviders map[string]provider.ProxyProvider) {
|
||||
load := func(pv provider.Provider) {
|
||||
if pv.VehicleType() == provider.Compatible {
|
||||
log.Infoln("Start initial compatible provider %s", pv.Name())
|
||||
} else {
|
||||
log.Infoln("Start initial provider %s", (pv).Name())
|
||||
}
|
||||
|
||||
if err := (pv).Initial(); err != nil {
|
||||
switch pv.Type() {
|
||||
case provider.Proxy:
|
||||
{
|
||||
log.Warnln("initial proxy provider %s error: %v", (pv).Name(), err)
|
||||
}
|
||||
case provider.Rule:
|
||||
{
|
||||
log.Warnln("initial rule provider %s error: %v", (pv).Name(), err)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, proxyProvider := range proxyProviders {
|
||||
load(proxyProvider)
|
||||
}
|
||||
|
||||
for _, ruleProvider := range ruleProviders {
|
||||
load(*ruleProvider)
|
||||
}
|
||||
}
|
||||
|
||||
func updateGeneral(general *config.General, Tun *config.Tun, force bool) {
|
||||
tunnel.SetMode(general.Mode)
|
||||
resolver.DisableIPv6 = !general.IPv6
|
||||
|
|
20
listener/inner/tcp.go
Normal file
20
listener/inner/tcp.go
Normal file
|
@ -0,0 +1,20 @@
|
|||
package inner
|
||||
|
||||
import (
|
||||
"github.com/Dreamacro/clash/adapter/inbound"
|
||||
C "github.com/Dreamacro/clash/constant"
|
||||
"net"
|
||||
)
|
||||
|
||||
var tcpIn chan<- C.ConnContext
|
||||
|
||||
func New(in chan<- C.ConnContext) {
|
||||
tcpIn = in
|
||||
}
|
||||
|
||||
func HandleTcp(dst string, host string) net.Conn {
|
||||
conn1, conn2 := net.Pipe()
|
||||
context := inbound.NewInner(conn2, dst, host)
|
||||
tcpIn <- context
|
||||
return conn1
|
||||
}
|
|
@ -2,6 +2,7 @@ package proxy
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/Dreamacro/clash/listener/inner"
|
||||
"net"
|
||||
"runtime"
|
||||
"strconv"
|
||||
|
@ -124,6 +125,7 @@ func ReCreateSocks(port int, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.P
|
|||
log.Errorln("Start SOCKS server error: %s", err.Error())
|
||||
}
|
||||
}()
|
||||
inner.New(tcpIn)
|
||||
|
||||
addr := genAddr(bindAddress, port, allowLan)
|
||||
|
||||
|
|
|
@ -75,6 +75,10 @@ func (rp *ruleSetProvider) Behavior() P.RuleType {
|
|||
}
|
||||
|
||||
func (rp *ruleSetProvider) Match(metadata *C.Metadata) bool {
|
||||
if rp.count == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
switch rp.behavior {
|
||||
case P.Domain:
|
||||
return rp.DomainRules.Search(metadata.Host) != nil
|
||||
|
|
Loading…
Reference in a new issue