github.com/yaling888/clash@v1.53.0/component/script/builtin.go (about)

     1  package script
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/phuslu/log"
     7  	"go.starlark.net/lib/time"
     8  	"go.starlark.net/starlark"
     9  	"go.starlark.net/starlarkstruct"
    10  
    11  	C "github.com/yaling888/clash/constant"
    12  )
    13  
    14  var moduleContext *starlarkstruct.Module
    15  
    16  func init() {
    17  	var (
    18  		resolveIPMethod   = starlark.NewBuiltin("resolve_ip", resolveIP)
    19  		inCidrMethod      = starlark.NewBuiltin("in_cidr", inCidr)
    20  		inIPSetMethod     = starlark.NewBuiltin("in_ipset", inIPSet)
    21  		geoIPMethod       = starlark.NewBuiltin("geoip", geoIP)
    22  		processNameMethod = starlark.NewBuiltin("resolve_process_name", resolveProcessName)
    23  		processPathMethod = starlark.NewBuiltin("resolve_process_path", resolveProcessPath)
    24  	)
    25  
    26  	moduleContext = &starlarkstruct.Module{
    27  		Name: "clash_ctx",
    28  		Members: starlark.StringDict{
    29  			"resolve_ip":           resolveIPMethod,
    30  			"in_cidr":              inCidrMethod,
    31  			"in_ipset":             inIPSetMethod,
    32  			"geoip":                geoIPMethod,
    33  			"resolve_process_name": processNameMethod,
    34  			"resolve_process_path": processPathMethod,
    35  			"log":                  starlark.NewBuiltin("log", log_),
    36  
    37  			"proxy_providers": newProxyProviders(),
    38  			"rule_providers":  newRuleProviders(),
    39  		},
    40  	}
    41  
    42  	starlark.Universe["time"] = time.Module
    43  	starlark.Universe["resolve_ip"] = resolveIPMethod
    44  	starlark.Universe["in_cidr"] = inCidrMethod
    45  	starlark.Universe["in_ipset"] = inIPSetMethod
    46  	starlark.Universe["geoip"] = geoIPMethod
    47  	starlark.Universe["match_provider"] = starlark.NewBuiltin("match_provider", matchRuleProviderByShortcut)
    48  	starlark.Universe["resolve_process_name"] = processNameMethod
    49  	starlark.Universe["resolve_process_path"] = processPathMethod
    50  	starlark.Universe["_clash_ctx"] = moduleContext
    51  }
    52  
    53  func resolveIP(thread *starlark.Thread, b *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
    54  	var s string
    55  	if err := starlark.UnpackPositionalArgs(b.Name(), args, kwargs, 1, &s); err != nil {
    56  		return nil, fmt.Errorf("call resolve_ip error: %w", err)
    57  	}
    58  
    59  	obj := thread.Local(metadataLocalKey)
    60  	if obj == nil {
    61  		return nil, fmt.Errorf("call resolve_ip error: metadata is nil")
    62  	}
    63  
    64  	mtd := obj.(*C.Metadata)
    65  
    66  	ip := uResolveIP(mtd, s)
    67  
    68  	return starlark.String(ip), nil
    69  }
    70  
    71  func resolveProcessName(thread *starlark.Thread, _ *starlark.Builtin, _ starlark.Tuple, _ []starlark.Tuple) (starlark.Value, error) {
    72  	obj := thread.Local(metadataLocalKey)
    73  	if obj == nil {
    74  		return nil, fmt.Errorf("call resolve_process_name error: metadata is nil")
    75  	}
    76  
    77  	mtd := obj.(*C.Metadata)
    78  
    79  	uResolveProcess(mtd)
    80  
    81  	return starlark.String(mtd.Process), nil
    82  }
    83  
    84  func resolveProcessPath(thread *starlark.Thread, _ *starlark.Builtin, _ starlark.Tuple, _ []starlark.Tuple) (starlark.Value, error) {
    85  	obj := thread.Local(metadataLocalKey)
    86  	if obj == nil {
    87  		return nil, fmt.Errorf("call resolve_process_path error: metadata is nil")
    88  	}
    89  
    90  	mtd := obj.(*C.Metadata)
    91  
    92  	uResolveProcess(mtd)
    93  
    94  	return starlark.String(mtd.ProcessPath), nil
    95  }
    96  
    97  func geoIP(_ *starlark.Thread, b *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (_ starlark.Value, err error) {
    98  	var s string
    99  	if err = starlark.UnpackPositionalArgs(b.Name(), args, kwargs, 1, &s); err != nil {
   100  		return nil, fmt.Errorf("call geo_ip error: %w", err)
   101  	}
   102  
   103  	return starlark.String(uGeoIP(s)), nil
   104  }
   105  
   106  func log_(_ *starlark.Thread, b *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
   107  	var s string
   108  	if err := starlark.UnpackPositionalArgs(b.Name(), args, kwargs, 1, &s); err != nil {
   109  		return nil, fmt.Errorf("call log error: %w", err)
   110  	}
   111  
   112  	log.Info().Msg(s)
   113  
   114  	return starlark.None, nil
   115  }
   116  
   117  func inCidr(_ *starlark.Thread, b *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (_ starlark.Value, err error) {
   118  	var s1, s2 string
   119  
   120  	defer func() {
   121  		if err != nil {
   122  			err = fmt.Errorf("call in_cidr error: %w", err)
   123  		}
   124  	}()
   125  
   126  	if err = starlark.UnpackPositionalArgs(b.Name(), args, kwargs, 2, &s1, &s2); err != nil {
   127  		return
   128  	}
   129  
   130  	var rs bool
   131  	rs, err = uInCidr(s1, s2)
   132  	if err != nil {
   133  		return
   134  	}
   135  
   136  	return starlark.Bool(rs), nil
   137  }
   138  
   139  func inIPSet(_ *starlark.Thread, b *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (_ starlark.Value, err error) {
   140  	var s1, s2 string
   141  
   142  	if err = starlark.UnpackPositionalArgs(b.Name(), args, kwargs, 2, &s1, &s2); err != nil {
   143  		return nil, fmt.Errorf("call in_ipset error: %w", err)
   144  	}
   145  
   146  	rs := uInIPSet(s1, s2)
   147  
   148  	return starlark.Bool(rs), nil
   149  }
   150  
   151  func matchRuleProvider(thread *starlark.Thread, b *starlark.Builtin, _ starlark.Tuple, _ []starlark.Tuple) (starlark.Value, error) {
   152  	obj := thread.Local(metadataLocalKey)
   153  	if obj == nil {
   154  		return nil, fmt.Errorf("call match_provider error: metadata is nil")
   155  	}
   156  
   157  	mtd := obj.(*C.Metadata)
   158  
   159  	rs, err := uMatchProvider(mtd, b.Name())
   160  	if err != nil {
   161  		return nil, err
   162  	}
   163  
   164  	return starlark.Bool(rs), nil
   165  }
   166  
   167  func matchRuleProviderByShortcut(thread *starlark.Thread, b *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
   168  	var s string
   169  	if err := starlark.UnpackPositionalArgs(b.Name(), args, kwargs, 1, &s); err != nil {
   170  		return nil, fmt.Errorf("call match_provider error: %w", err)
   171  	}
   172  
   173  	obj := thread.Local(metadataLocalKey)
   174  	if obj == nil {
   175  		return nil, fmt.Errorf("call match_provider error: metadata is nil")
   176  	}
   177  
   178  	mtd := obj.(*C.Metadata)
   179  
   180  	rs, err := uMatchProvider(mtd, s)
   181  	if err != nil {
   182  		return nil, err
   183  	}
   184  
   185  	return starlark.Bool(rs), nil
   186  }
   187  
   188  func metadataToStringDict(mtd *C.Metadata, dict starlark.StringDict) (starlark.StringDict, error) {
   189  	if dict == nil {
   190  		dict = make(starlark.StringDict)
   191  	}
   192  	dict["type"] = starlark.String(mtd.Type.String())
   193  	dict["network"] = starlark.String(mtd.NetWork.String())
   194  	dict["host"] = starlark.String(mtd.Host)
   195  	dict["process_name"] = starlark.String(mtd.Process)
   196  	dict["process_path"] = starlark.String(mtd.ProcessPath)
   197  	dict["src_ip"] = starlark.String(mtd.SrcIP.String())
   198  	dict["src_port"] = starlark.MakeUint64(uint64(mtd.SrcPort))
   199  
   200  	var dstIP string
   201  	if mtd.Resolved() {
   202  		dstIP = mtd.DstIP.String()
   203  	}
   204  	dict["dst_ip"] = starlark.String(dstIP)
   205  	dict["dst_port"] = starlark.MakeUint64(uint64(mtd.DstPort))
   206  	dict["user_agent"] = starlark.String(mtd.UserAgent)
   207  	dict["special_proxy"] = starlark.String(mtd.SpecialProxy)
   208  	dict["inbound_port"] = starlark.MakeUint64(uint64(mtd.OriginDst.Port()))
   209  
   210  	return dict, nil
   211  }
   212  
   213  func metadataToDict(mtd *C.Metadata) (val *starlark.Dict, err error) {
   214  	dict := starlark.NewDict(9)
   215  	err = dict.SetKey(starlark.String("type"), starlark.String(mtd.Type.String()))
   216  	if err != nil {
   217  		return
   218  	}
   219  	err = dict.SetKey(starlark.String("network"), starlark.String(mtd.NetWork.String()))
   220  	if err != nil {
   221  		return
   222  	}
   223  	err = dict.SetKey(starlark.String("host"), starlark.String(mtd.Host))
   224  	if err != nil {
   225  		return
   226  	}
   227  	err = dict.SetKey(starlark.String("src_ip"), starlark.String(mtd.SrcIP.String()))
   228  	if err != nil {
   229  		return
   230  	}
   231  	err = dict.SetKey(starlark.String("src_port"), starlark.String(mtd.SrcPort.String()))
   232  	if err != nil {
   233  		return
   234  	}
   235  
   236  	var dstIP string
   237  	if mtd.Resolved() {
   238  		dstIP = mtd.DstIP.String()
   239  	}
   240  	err = dict.SetKey(starlark.String("dst_ip"), starlark.String(dstIP))
   241  	if err != nil {
   242  		return
   243  	}
   244  	err = dict.SetKey(starlark.String("dst_port"), starlark.String(mtd.DstPort.String()))
   245  	if err != nil {
   246  		return
   247  	}
   248  	err = dict.SetKey(starlark.String("user_agent"), starlark.String(mtd.UserAgent))
   249  	if err != nil {
   250  		return
   251  	}
   252  	err = dict.SetKey(starlark.String("special_proxy"), starlark.String(mtd.SpecialProxy))
   253  	if err != nil {
   254  		return
   255  	}
   256  	err = dict.SetKey(starlark.String("inbound_port"), starlark.MakeUint64(uint64(mtd.OriginDst.Port())))
   257  	if err != nil {
   258  		return
   259  	}
   260  
   261  	val = dict
   262  	return
   263  }