mirror of
https://gitclone.com/github.com/MetaCubeX/Clash.Meta
synced 2025-05-13 13:38:06 +08:00
feat: Allow providers to set individual proxy and headers
This commit is contained in:
parent
19f7220c0b
commit
f3e23b1128
@ -44,6 +44,7 @@ type proxyProviderSchema struct {
|
|||||||
Type string `provider:"type"`
|
Type string `provider:"type"`
|
||||||
Path string `provider:"path,omitempty"`
|
Path string `provider:"path,omitempty"`
|
||||||
URL string `provider:"url,omitempty"`
|
URL string `provider:"url,omitempty"`
|
||||||
|
Proxy string `provider:"proxy,omitempty"`
|
||||||
Interval int `provider:"interval,omitempty"`
|
Interval int `provider:"interval,omitempty"`
|
||||||
Filter string `provider:"filter,omitempty"`
|
Filter string `provider:"filter,omitempty"`
|
||||||
ExcludeFilter string `provider:"exclude-filter,omitempty"`
|
ExcludeFilter string `provider:"exclude-filter,omitempty"`
|
||||||
@ -52,6 +53,7 @@ type proxyProviderSchema struct {
|
|||||||
|
|
||||||
HealthCheck healthCheckSchema `provider:"health-check,omitempty"`
|
HealthCheck healthCheckSchema `provider:"health-check,omitempty"`
|
||||||
Override OverrideSchema `provider:"override,omitempty"`
|
Override OverrideSchema `provider:"override,omitempty"`
|
||||||
|
Header map[string][]string `provider:"header,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func ParseProxyProvider(name string, mapping map[string]any) (types.ProxyProvider, error) {
|
func ParseProxyProvider(name string, mapping map[string]any) (types.ProxyProvider, error) {
|
||||||
@ -86,16 +88,14 @@ func ParseProxyProvider(name string, mapping map[string]any) (types.ProxyProvide
|
|||||||
path := C.Path.Resolve(schema.Path)
|
path := C.Path.Resolve(schema.Path)
|
||||||
vehicle = resource.NewFileVehicle(path)
|
vehicle = resource.NewFileVehicle(path)
|
||||||
case "http":
|
case "http":
|
||||||
|
path := C.Path.GetPathByHash("proxies", schema.URL)
|
||||||
if schema.Path != "" {
|
if schema.Path != "" {
|
||||||
path := C.Path.Resolve(schema.Path)
|
path = C.Path.Resolve(schema.Path)
|
||||||
if !features.CMFA && !C.Path.IsSafePath(path) {
|
if !features.CMFA && !C.Path.IsSafePath(path) {
|
||||||
return nil, fmt.Errorf("%w: %s", errSubPath, path)
|
return nil, fmt.Errorf("%w: %s", errSubPath, path)
|
||||||
}
|
}
|
||||||
vehicle = resource.NewHTTPVehicle(schema.URL, path)
|
|
||||||
} else {
|
|
||||||
path := C.Path.GetPathByHash("proxies", schema.URL)
|
|
||||||
vehicle = resource.NewHTTPVehicle(schema.URL, path)
|
|
||||||
}
|
}
|
||||||
|
vehicle = resource.NewHTTPVehicle(schema.URL, path, schema.Proxy, schema.Header)
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("%w: %s", errVehicleType, schema.Type)
|
return nil, fmt.Errorf("%w: %s", errVehicleType, schema.Type)
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,10 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func HttpRequest(ctx context.Context, url, method string, header map[string][]string, body io.Reader) (*http.Response, error) {
|
func HttpRequest(ctx context.Context, url, method string, header map[string][]string, body io.Reader) (*http.Response, error) {
|
||||||
UA := C.UA
|
return HttpRequestWithProxy(ctx, url, method, header, body, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func HttpRequestWithProxy(ctx context.Context, url, method string, header map[string][]string, body io.Reader, specialProxy string) (*http.Response, error) {
|
||||||
method = strings.ToUpper(method)
|
method = strings.ToUpper(method)
|
||||||
urlRes, err := URL.Parse(url)
|
urlRes, err := URL.Parse(url)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -32,7 +35,7 @@ func HttpRequest(ctx context.Context, url, method string, header map[string][]st
|
|||||||
}
|
}
|
||||||
|
|
||||||
if _, ok := header["User-Agent"]; !ok {
|
if _, ok := header["User-Agent"]; !ok {
|
||||||
req.Header.Set("User-Agent", UA)
|
req.Header.Set("User-Agent", C.UA)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -54,7 +57,7 @@ func HttpRequest(ctx context.Context, url, method string, header map[string][]st
|
|||||||
TLSHandshakeTimeout: 10 * time.Second,
|
TLSHandshakeTimeout: 10 * time.Second,
|
||||||
ExpectContinueTimeout: 1 * time.Second,
|
ExpectContinueTimeout: 1 * time.Second,
|
||||||
DialContext: func(ctx context.Context, network, address string) (net.Conn, error) {
|
DialContext: func(ctx context.Context, network, address string) (net.Conn, error) {
|
||||||
if conn, err := inner.HandleTcp(address); err == nil {
|
if conn, err := inner.HandleTcp(address, specialProxy); err == nil {
|
||||||
return conn, nil
|
return conn, nil
|
||||||
} else {
|
} else {
|
||||||
d := net.Dialer{}
|
d := net.Dialer{}
|
||||||
@ -66,5 +69,4 @@ func HttpRequest(ctx context.Context, url, method string, header map[string][]st
|
|||||||
|
|
||||||
client := http.Client{Transport: transport}
|
client := http.Client{Transport: transport}
|
||||||
return client.Do(req)
|
return client.Do(req)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -35,6 +35,8 @@ func NewFileVehicle(path string) *FileVehicle {
|
|||||||
type HTTPVehicle struct {
|
type HTTPVehicle struct {
|
||||||
url string
|
url string
|
||||||
path string
|
path string
|
||||||
|
proxy string
|
||||||
|
header http.Header
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *HTTPVehicle) Url() string {
|
func (h *HTTPVehicle) Url() string {
|
||||||
@ -52,7 +54,7 @@ func (h *HTTPVehicle) Path() string {
|
|||||||
func (h *HTTPVehicle) Read() ([]byte, error) {
|
func (h *HTTPVehicle) Read() ([]byte, error) {
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*20)
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second*20)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
resp, err := mihomoHttp.HttpRequest(ctx, h.url, http.MethodGet, nil, nil)
|
resp, err := mihomoHttp.HttpRequestWithProxy(ctx, h.url, http.MethodGet, h.header, nil, h.proxy)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -67,6 +69,6 @@ func (h *HTTPVehicle) Read() ([]byte, error) {
|
|||||||
return buf, nil
|
return buf, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewHTTPVehicle(url string, path string) *HTTPVehicle {
|
func NewHTTPVehicle(url string, path string, proxy string, header http.Header) *HTTPVehicle {
|
||||||
return &HTTPVehicle{url, path}
|
return &HTTPVehicle{url, path, proxy, header}
|
||||||
}
|
}
|
||||||
|
@ -413,7 +413,7 @@ func UnmarshalRawConfig(buf []byte) (*RawConfig, error) {
|
|||||||
ProxyGroup: []map[string]any{},
|
ProxyGroup: []map[string]any{},
|
||||||
TCPConcurrent: false,
|
TCPConcurrent: false,
|
||||||
FindProcessMode: P.FindProcessStrict,
|
FindProcessMode: P.FindProcessStrict,
|
||||||
GlobalUA: "clash.meta",
|
GlobalUA: "clash.meta/" + C.Version,
|
||||||
Tun: RawTun{
|
Tun: RawTun{
|
||||||
Enable: false,
|
Enable: false,
|
||||||
Device: "",
|
Device: "",
|
||||||
|
@ -16,7 +16,7 @@ skip-auth-prefixes: # 设置跳过验证的IP段
|
|||||||
lan-allowed-ips: # 允许连接的 IP 地址段,仅作用于 allow-lan 为 true, 默认值为 0.0.0.0/0 和::/0
|
lan-allowed-ips: # 允许连接的 IP 地址段,仅作用于 allow-lan 为 true, 默认值为 0.0.0.0/0 和::/0
|
||||||
- 0.0.0.0/0
|
- 0.0.0.0/0
|
||||||
- ::/0
|
- ::/0
|
||||||
lan-disallowed-ips: # 禁止连接的 IP 地址段, 黑名单优先级高于白名单, 默认值为空
|
lan-disallowed-ips: # 禁止连接的 IP 地址段,黑名单优先级高于白名单,默认值为空
|
||||||
- 192.168.0.3/32
|
- 192.168.0.3/32
|
||||||
|
|
||||||
# find-process-mode has 3 values:always, strict, off
|
# find-process-mode has 3 values:always, strict, off
|
||||||
@ -109,7 +109,7 @@ tun:
|
|||||||
# auto-detect-interface: true # 自动识别出口网卡
|
# auto-detect-interface: true # 自动识别出口网卡
|
||||||
# auto-route: true # 配置路由表
|
# auto-route: true # 配置路由表
|
||||||
# mtu: 9000 # 最大传输单元
|
# mtu: 9000 # 最大传输单元
|
||||||
# gso: false # 启用通用分段卸载, 仅支持 Linux
|
# gso: false # 启用通用分段卸载,仅支持 Linux
|
||||||
# gso-max-size: 65536 # 通用分段卸载包的最大大小
|
# gso-max-size: 65536 # 通用分段卸载包的最大大小
|
||||||
# strict-route: true # 将所有连接路由到 tun 来防止泄漏,但你的设备将无法其他设备被访问
|
# strict-route: true # 将所有连接路由到 tun 来防止泄漏,但你的设备将无法其他设备被访问
|
||||||
inet4-route-address: # 启用 auto-route 时使用自定义路由而不是默认路由
|
inet4-route-address: # 启用 auto-route 时使用自定义路由而不是默认路由
|
||||||
@ -119,9 +119,9 @@ tun:
|
|||||||
- "::/1"
|
- "::/1"
|
||||||
- "8000::/1"
|
- "8000::/1"
|
||||||
# endpoint-independent-nat: false # 启用独立于端点的 NAT
|
# endpoint-independent-nat: false # 启用独立于端点的 NAT
|
||||||
# include-interface: # 限制被路由的接口。默认不限制, 与 `exclude-interface` 冲突
|
# include-interface: # 限制被路由的接口。默认不限制,与 `exclude-interface` 冲突
|
||||||
# - "lan0"
|
# - "lan0"
|
||||||
# exclude-interface: # 排除路由的接口, 与 `include-interface` 冲突
|
# exclude-interface: # 排除路由的接口,与 `include-interface` 冲突
|
||||||
# - "lan1"
|
# - "lan1"
|
||||||
# include-uid: # UID 规则仅在 Linux 下被支持,并且需要 auto-route
|
# include-uid: # UID 规则仅在 Linux 下被支持,并且需要 auto-route
|
||||||
# - 0
|
# - 0
|
||||||
@ -338,7 +338,7 @@ proxies: # socks5
|
|||||||
# udp-over-tcp: false
|
# udp-over-tcp: false
|
||||||
# ip-version: ipv4 # 设置节点使用 IP 版本,可选:dual,ipv4,ipv6,ipv4-prefer,ipv6-prefer。默认使用 dual
|
# ip-version: ipv4 # 设置节点使用 IP 版本,可选:dual,ipv4,ipv6,ipv4-prefer,ipv6-prefer。默认使用 dual
|
||||||
# ipv4:仅使用 IPv4 ipv6:仅使用 IPv6
|
# ipv4:仅使用 IPv4 ipv6:仅使用 IPv6
|
||||||
# ipv4-prefer:优先使用 IPv4 对于 TCP 会进行双栈解析,并发链接但是优先使用 IPv4 链接,
|
# ipv4-prefer:优先使用 IPv4 对于 TCP 会进行双栈解析,并发链接但是优先使用 IPv4 链接,
|
||||||
# UDP 则为双栈解析,获取结果中的第一个 IPv4
|
# UDP 则为双栈解析,获取结果中的第一个 IPv4
|
||||||
# ipv6-prefer 同 ipv4-prefer
|
# ipv6-prefer 同 ipv4-prefer
|
||||||
# 现有协议都支持此参数,TCP 效果仅在开启 tcp-concurrent 生效
|
# 现有协议都支持此参数,TCP 效果仅在开启 tcp-concurrent 生效
|
||||||
@ -780,7 +780,7 @@ proxies: # socks5
|
|||||||
password: password
|
password: password
|
||||||
privateKey: path
|
privateKey: path
|
||||||
|
|
||||||
# dns出站会将请求劫持到内部dns模块,所有请求均在内部处理
|
# dns 出站会将请求劫持到内部 dns 模块,所有请求均在内部处理
|
||||||
- name: "dns-out"
|
- name: "dns-out"
|
||||||
type: dns
|
type: dns
|
||||||
proxy-groups:
|
proxy-groups:
|
||||||
@ -859,10 +859,19 @@ proxy-groups:
|
|||||||
# Mihomo 格式的节点或支持 *ray 的分享格式
|
# Mihomo 格式的节点或支持 *ray 的分享格式
|
||||||
proxy-providers:
|
proxy-providers:
|
||||||
provider1:
|
provider1:
|
||||||
type: http # http 的 path 可空置,默认储存路径为 homedir的proxies文件夹,文件名为url的md5
|
type: http # http 的 path 可空置,默认储存路径为 homedir 的 proxies 文件夹,文件名为 url 的 md5
|
||||||
url: "url"
|
url: "url"
|
||||||
interval: 3600
|
interval: 3600
|
||||||
path: ./provider1.yaml # 默认只允许存储在 mihomo 的 Home Dir,如果想存储到任意位置,添加环境变量 SKIP_SAFE_PATH_CHECK=1
|
path: ./provider1.yaml # 默认只允许存储在 mihomo 的 Home Dir,如果想存储到任意位置,添加环境变量 SKIP_SAFE_PATH_CHECK=1
|
||||||
|
proxy: DIRECT
|
||||||
|
header:
|
||||||
|
User-Agent:
|
||||||
|
- "Clash/v1.18.0"
|
||||||
|
- "mihomo/1.18.3"
|
||||||
|
# Accept:
|
||||||
|
# - 'application/vnd.github.v3.raw'
|
||||||
|
# Authorization:
|
||||||
|
# - 'token 1231231'
|
||||||
health-check:
|
health-check:
|
||||||
enable: true
|
enable: true
|
||||||
interval: 600
|
interval: 600
|
||||||
@ -892,8 +901,9 @@ rule-providers:
|
|||||||
behavior: classical # domain ipcidr
|
behavior: classical # domain ipcidr
|
||||||
interval: 259200
|
interval: 259200
|
||||||
path: /path/to/save/file.yaml # 默认只允许存储在 mihomo 的 Home Dir,如果想存储到任意位置,添加环境变量 SKIP_SAFE_PATH_CHECK=1
|
path: /path/to/save/file.yaml # 默认只允许存储在 mihomo 的 Home Dir,如果想存储到任意位置,添加环境变量 SKIP_SAFE_PATH_CHECK=1
|
||||||
type: http # http 的 path 可空置,默认储存路径为 homedir的rules文件夹,文件名为url的md5
|
type: http # http 的 path 可空置,默认储存路径为 homedir 的 rules 文件夹,文件名为 url 的 md5
|
||||||
url: "url"
|
url: "url"
|
||||||
|
proxy: DIRECT
|
||||||
rule2:
|
rule2:
|
||||||
behavior: classical
|
behavior: classical
|
||||||
interval: 259200
|
interval: 259200
|
||||||
|
@ -16,7 +16,7 @@ func New(t C.Tunnel) {
|
|||||||
tunnel = t
|
tunnel = t
|
||||||
}
|
}
|
||||||
|
|
||||||
func HandleTcp(address string) (conn net.Conn, err error) {
|
func HandleTcp(address string, proxy string) (conn net.Conn, err error) {
|
||||||
if tunnel == nil {
|
if tunnel == nil {
|
||||||
return nil, errors.New("tcp uninitialized")
|
return nil, errors.New("tcp uninitialized")
|
||||||
}
|
}
|
||||||
@ -28,6 +28,9 @@ func HandleTcp(address string) (conn net.Conn, err error) {
|
|||||||
metadata.Type = C.INNER
|
metadata.Type = C.INNER
|
||||||
metadata.DNSMode = C.DNSNormal
|
metadata.DNSMode = C.DNSNormal
|
||||||
metadata.Process = C.MihomoName
|
metadata.Process = C.MihomoName
|
||||||
|
if proxy != "" {
|
||||||
|
metadata.SpecialProxy = proxy
|
||||||
|
}
|
||||||
if h, port, err := net.SplitHostPort(address); err == nil {
|
if h, port, err := net.SplitHostPort(address); err == nil {
|
||||||
if port, err := strconv.ParseUint(port, 10, 16); err == nil {
|
if port, err := strconv.ParseUint(port, 10, 16); err == nil {
|
||||||
metadata.DstPort = uint16(port)
|
metadata.DstPort = uint16(port)
|
||||||
|
@ -21,6 +21,7 @@ type ruleProviderSchema struct {
|
|||||||
Behavior string `provider:"behavior"`
|
Behavior string `provider:"behavior"`
|
||||||
Path string `provider:"path,omitempty"`
|
Path string `provider:"path,omitempty"`
|
||||||
URL string `provider:"url,omitempty"`
|
URL string `provider:"url,omitempty"`
|
||||||
|
Proxy string `provider:"proxy,omitempty"`
|
||||||
Format string `provider:"format,omitempty"`
|
Format string `provider:"format,omitempty"`
|
||||||
Interval int `provider:"interval,omitempty"`
|
Interval int `provider:"interval,omitempty"`
|
||||||
}
|
}
|
||||||
@ -61,17 +62,14 @@ func ParseRuleProvider(name string, mapping map[string]interface{}, parse func(t
|
|||||||
path := C.Path.Resolve(schema.Path)
|
path := C.Path.Resolve(schema.Path)
|
||||||
vehicle = resource.NewFileVehicle(path)
|
vehicle = resource.NewFileVehicle(path)
|
||||||
case "http":
|
case "http":
|
||||||
|
path := C.Path.GetPathByHash("rules", schema.URL)
|
||||||
if schema.Path != "" {
|
if schema.Path != "" {
|
||||||
path := C.Path.Resolve(schema.Path)
|
path = C.Path.Resolve(schema.Path)
|
||||||
if !features.CMFA && !C.Path.IsSafePath(path) {
|
if !features.CMFA && !C.Path.IsSafePath(path) {
|
||||||
return nil, fmt.Errorf("%w: %s", errSubPath, path)
|
return nil, fmt.Errorf("%w: %s", errSubPath, path)
|
||||||
}
|
}
|
||||||
vehicle = resource.NewHTTPVehicle(schema.URL, path)
|
|
||||||
} else {
|
|
||||||
path := C.Path.GetPathByHash("rules", schema.URL)
|
|
||||||
vehicle = resource.NewHTTPVehicle(schema.URL, path)
|
|
||||||
}
|
}
|
||||||
|
vehicle = resource.NewHTTPVehicle(schema.URL, path, schema.Proxy, nil)
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("unsupported vehicle type: %s", schema.Type)
|
return nil, fmt.Errorf("unsupported vehicle type: %s", schema.Type)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user