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 }