mihomo/component/script/clash_module_export.go
2021-11-17 16:03:47 +08:00

136 lines
2.8 KiB
Go

package script
/*
#include "clash_module.h"
*/
import "C"
import (
"net"
"strconv"
"strings"
"unsafe"
"github.com/Dreamacro/clash/component/mmdb"
"github.com/Dreamacro/clash/component/resolver"
"github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/log"
)
var (
ruleProviders = map[string]constant.Rule{}
pyThreadState *PyThreadState
)
func UpdateRuleProviders(rpd map[string]constant.Rule) {
ruleProviders = rpd
if Py_IsInitialized() {
pyThreadState = PyEval_SaveThread()
}
}
//export resolveIPCallbackFn
func resolveIPCallbackFn(cHost *C.char) *C.char {
host := C.GoString(cHost)
if len(host) == 0 {
cip := C.CString("")
defer C.free(unsafe.Pointer(cip))
return cip
}
if ip, err := resolver.ResolveIP(host); err == nil {
cip := C.CString(ip.String())
defer C.free(unsafe.Pointer(cip))
return cip
} else {
log.Errorln("[Script] resolve ip error: %s", err.Error())
cip := C.CString("")
defer C.free(unsafe.Pointer(cip))
return cip
}
}
//export geoipCallbackFn
func geoipCallbackFn(cIP *C.char) *C.char {
dstIP := net.ParseIP(C.GoString(cIP))
if dstIP == nil {
emptyC := C.CString("")
defer C.free(unsafe.Pointer(emptyC))
return emptyC
}
if dstIP.IsPrivate() || constant.TunBroadcastAddr.Equal(dstIP) {
lanC := C.CString("LAN")
defer C.free(unsafe.Pointer(lanC))
return lanC
}
record, _ := mmdb.Instance().Country(dstIP)
rc := C.CString(strings.ToUpper(record.Country.IsoCode))
defer C.free(unsafe.Pointer(rc))
return rc
}
//export ruleProviderCallbackFn
func ruleProviderCallbackFn(cProviderName *C.char, cMetadata *C.struct_Metadata) C.int {
//_type := C.GoString(cMetadata._type)
//network := C.GoString(cMetadata.network)
processName := C.GoString(cMetadata.process_name)
host := C.GoString(cMetadata.host)
srcIp := C.GoString(cMetadata.src_ip)
srcPort := strconv.Itoa(int(cMetadata.src_port))
dstIp := C.GoString(cMetadata.dst_ip)
dstPort := strconv.Itoa(int(cMetadata.dst_port))
dst := net.ParseIP(dstIp)
addrType := constant.AtypDomainName
if dst != nil {
if dst.To4() != nil {
addrType = constant.AtypIPv4
} else {
addrType = constant.AtypIPv6
}
}
metadata := &constant.Metadata{
Process: processName,
SrcIP: net.ParseIP(srcIp),
DstIP: dst,
SrcPort: srcPort,
DstPort: dstPort,
AddrType: addrType,
Host: host,
}
providerName := C.GoString(cProviderName)
rule, ok := ruleProviders[providerName]
if !ok {
log.Warnln("[Script] rule provider [%s] not found", providerName)
return C.int(0)
}
if strings.HasPrefix(providerName, "geosite:") {
if len(host) == 0 {
return C.int(0)
}
metadata.AddrType = constant.AtypDomainName
}
rs := rule.Match(metadata)
if rs {
return C.int(1)
}
return C.int(0)
}
//export logCallbackFn
func logCallbackFn(msg *C.char) {
log.Infoln(C.GoString(msg))
}