2022-09-12 14:02:08 +08:00

112 lines
3.4 KiB
Go

package provider
import (
"context"
"fmt"
"github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/option"
"github.com/sagernet/sing-box/outbound"
"gopkg.in/yaml.v3"
)
var (
clashProxyParsers = make(map[string]func(context.Context, adapter.Router,
log.ContextLogger, map[string]interface{}) (adapter.Outbound, error))
)
type ClashProviderResolver struct {
}
func (r *ClashProviderResolver) GetOutbounds(rawData []byte, ctx context.Context,
router adapter.Router, logger log.ContextLogger) []adapter.Outbound {
data := make(map[string]interface{}, 0)
yaml.Unmarshal(rawData, &data)
outbounds := make([]adapter.Outbound, 0)
proxies, ok := data["proxies"]
if !ok {
return outbounds
}
proxyList, ok := proxies.([]interface{})
if !ok {
return outbounds
}
for _, proxy := range proxyList {
if proxyItem, ok := proxy.(map[string]interface{}); ok {
newOutbound, err := parseClashProxy(ctx, router, logger, proxyItem)
if err == nil {
outbounds = append(outbounds, newOutbound)
}
}
}
return outbounds
}
func parseClashProxy(ctx context.Context, router adapter.Router,
logger log.ContextLogger, proxyItem map[string]interface{}) (res adapter.Outbound, err error) {
defer func() {
if r := recover(); r != nil {
logger.Warn("cannot parse proxy: ", r)
res = nil
err = fmt.Errorf("cannot parse proxy: %v", r)
}
}()
if proxyType, ok := proxyItem["type"].(string); ok {
if parser, ok := clashProxyParsers[proxyType]; ok {
return parser(ctx, router, logger, proxyItem)
}
}
return nil, fmt.Errorf("unkown proxy type")
}
func parseClashSsProxy(ctx context.Context, router adapter.Router,
logger log.ContextLogger, proxyItem map[string]interface{}) (res adapter.Outbound, err error) {
options := option.ShadowsocksOutboundOptions{
DialerOptions: option.DialerOptions{},
ServerOptions: option.ServerOptions{
Server: proxyItem["server"].(string),
ServerPort: uint16(proxyItem["port"].(int))},
Password: proxyItem["password"].(string),
Method: proxyItem["cipher"].(string),
}
if udpEnabled, ok := proxyItem["udp"].(bool); ok && !udpEnabled {
options.Network = "tcp"
}
return outbound.NewShadowsocks(
ctx, router, logger,
proxyItem["name"].(string),
options,
)
}
func ParseClashTrojanProxy(ctx context.Context, router adapter.Router,
logger log.ContextLogger, proxyItem map[string]interface{}) (res adapter.Outbound, err error) {
options := option.TrojanOutboundOptions{
DialerOptions: option.DialerOptions{},
ServerOptions: option.ServerOptions{
Server: proxyItem["server"].(string),
ServerPort: uint16(proxyItem["port"].(int))},
Password: proxyItem["password"].(string),
TLS: &option.OutboundTLSOptions{},
Multiplex: &option.MultiplexOptions{},
Transport: &option.V2RayTransportOptions{},
}
if udpEnabled, ok := proxyItem["udp"].(bool); ok && !udpEnabled {
options.Network = "tcp"
}
if sni, ok := proxyItem["sni"].(string); ok {
options.TLS.ServerName = sni
}
if skipCertVerity, ok := proxyItem["skip-cert-verify"].(bool); ok && skipCertVerity {
options.TLS.Insecure = true
}
return outbound.NewTrojan(ctx, router, logger, proxyItem["name"].(string), options)
}
func init() {
clashProxyParsers["ss"] = parseClashSsProxy
clashProxyParsers["trojan"] = ParseClashTrojanProxy
outbound.InjectClashProviderResolver("clash", &ClashProviderResolver{})
}