|
| 1 | +package datahub |
| 2 | + |
| 3 | +import ( |
| 4 | + "context" |
| 5 | + "strings" |
| 6 | + "sync" |
| 7 | + "time" |
| 8 | + |
| 9 | + "github.com/allegro/bigcache" |
| 10 | + "github.com/c-robinson/iplib" |
| 11 | + "github.com/ca17/datahub/plugin/pkg/datatable" |
| 12 | + "github.com/ca17/datahub/plugin/pkg/loader" |
| 13 | + "github.com/ca17/datahub/plugin/pkg/netutils" |
| 14 | + "github.com/ca17/datahub/plugin/pkg/v2data" |
| 15 | + "github.com/coredns/coredns/plugin" |
| 16 | + "github.com/miekg/dns" |
| 17 | + "github.com/robfig/cron/v3" |
| 18 | +) |
| 19 | + |
| 20 | +var cronParser = cron.NewParser( |
| 21 | + cron.SecondOptional | cron.Minute | cron.Hour | cron.Dom | cron.Month | cron.Dow | cron.Descriptor, |
| 22 | +) |
| 23 | + |
| 24 | +type Datahub struct { |
| 25 | + nlmLock sync.RWMutex |
| 26 | + dlmLock sync.RWMutex |
| 27 | + ktLock sync.RWMutex |
| 28 | + Next plugin.Handler |
| 29 | + geoipCacheTags []string |
| 30 | + geositeCacheTags []string |
| 31 | + geoipNetListMap map[string]*netutils.NetList |
| 32 | + geositeDoaminListMap map[string]*netutils.DomainList |
| 33 | + keywordTableMap map[string]*datatable.DataTable |
| 34 | + geoipPath string |
| 35 | + geositePath string |
| 36 | + geodatUpgradeUrl string |
| 37 | + geodatUpgradeCron string |
| 38 | + sched *cron.Cron |
| 39 | + matchCache *bigcache.BigCache |
| 40 | + reloadCron string |
| 41 | + debug bool |
| 42 | +} |
| 43 | + |
| 44 | +func (dh *Datahub) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) { |
| 45 | + return plugin.NextOrFailure(dh.Name(), dh.Next, ctx, w, r) |
| 46 | +} |
| 47 | + |
| 48 | +func (dh *Datahub) Name() string { return "datahub" } |
| 49 | + |
| 50 | +func NewDatahub() *Datahub { |
| 51 | + mc, _ := bigcache.NewBigCache(bigcache.DefaultConfig(time.Second * 3600)) |
| 52 | + return &Datahub{ |
| 53 | + nlmLock: sync.RWMutex{}, |
| 54 | + dlmLock: sync.RWMutex{}, |
| 55 | + geoipNetListMap: make(map[string]*netutils.NetList), |
| 56 | + geositeDoaminListMap: make(map[string]*netutils.DomainList), |
| 57 | + keywordTableMap: make(map[string]*datatable.DataTable), |
| 58 | + matchCache: mc, |
| 59 | + sched: cron.New(cron.WithParser(cronParser)), |
| 60 | + } |
| 61 | +} |
| 62 | + |
| 63 | +func (dh *Datahub) getDomainListByTag(tag string) *netutils.DomainList{ |
| 64 | + dh.dlmLock.RLock() |
| 65 | + defer dh.dlmLock.RUnlock() |
| 66 | + return dh.geositeDoaminListMap[tag] |
| 67 | +} |
| 68 | + |
| 69 | +func (dh *Datahub) getNetListByTag(tag string) *netutils.NetList{ |
| 70 | + dh.nlmLock.RLock() |
| 71 | + defer dh.nlmLock.RUnlock() |
| 72 | + return dh.geoipNetListMap[tag] |
| 73 | +} |
| 74 | + |
| 75 | +func (dh *Datahub) getKeywordTableByTag(tag string) *datatable.DataTable{ |
| 76 | + dh.ktLock.RLock() |
| 77 | + defer dh.ktLock.RUnlock() |
| 78 | + return dh.keywordTableMap[tag] |
| 79 | +} |
| 80 | + |
| 81 | +// 根据 tag 从 geoip.dat 加载 geoip 数据 |
| 82 | +func (dh *Datahub) reloadGeoipNetListByTag(tags []string, cache bool) error { |
| 83 | + if !cache { |
| 84 | + loader.RemoveCache(dh.geoipPath) |
| 85 | + } |
| 86 | + tagitems, err := loader.LoadGeoIPFromDATByTags(dh.geoipPath, tags) |
| 87 | + if err != nil { |
| 88 | + return err |
| 89 | + } |
| 90 | + dh.nlmLock.Lock() |
| 91 | + defer dh.nlmLock.Unlock() |
| 92 | + for _, dataitems := range tagitems { |
| 93 | + var nets []iplib.Net |
| 94 | + for _, data := range dataitems.GetCidr() { |
| 95 | + _net := iplib.NewNet(data.GetIp(), int(data.GetPrefix())) |
| 96 | + nets = append(nets, _net) |
| 97 | + } |
| 98 | + |
| 99 | + dh.geoipNetListMap[dataitems.GetCountryCode()] = netutils.NewNetList(nets) |
| 100 | + |
| 101 | + } |
| 102 | + return nil |
| 103 | +} |
| 104 | + |
| 105 | +// 根据 tag 从 geosite.dat 加载 geosite 数据 |
| 106 | +func (dh *Datahub) reloadGeositeDmoainListByTag(tags []string, cache bool) error { |
| 107 | + if !cache { |
| 108 | + loader.RemoveCache(dh.geositePath) |
| 109 | + } |
| 110 | + tagitems, err := loader.LoadGeoSiteFromDATByTags(dh.geositePath, tags) |
| 111 | + if err != nil { |
| 112 | + return err |
| 113 | + } |
| 114 | + dh.dlmLock.Lock() |
| 115 | + defer dh.dlmLock.Unlock() |
| 116 | + for _, dataitems := range tagitems { |
| 117 | + var sites []string |
| 118 | + var regexs []string |
| 119 | + for _, data := range dataitems.GetDomain() { |
| 120 | + switch data.Type { |
| 121 | + case v2data.Domain_Full, v2data.Domain_Domain: |
| 122 | + sites = append(sites, data.GetValue()) |
| 123 | + case v2data.Domain_Regex: |
| 124 | + regexs = append(regexs, data.GetValue()) |
| 125 | + } |
| 126 | + } |
| 127 | + dmlist := netutils.NewDomainList() |
| 128 | + dmlist.InitDomainData(netutils.MatchFullType, sites) |
| 129 | + dmlist.InitDomainData(netutils.MatchRegexType, regexs) |
| 130 | + dh.geositeDoaminListMap[dataitems.GetCountryCode()] = dmlist |
| 131 | + } |
| 132 | + return nil |
| 133 | +} |
| 134 | + |
| 135 | +func (dh *Datahub) parseKeywordTableByTag(tag string, from string) error { |
| 136 | + tag = strings.ToUpper(tag) |
| 137 | + table, err := datatable.NewFromArgs(datatable.DateTypeKeywordTable, tag, from ) |
| 138 | + if err != nil { |
| 139 | + return err |
| 140 | + } |
| 141 | + table.LoadAll() |
| 142 | + dh.ktLock.Lock() |
| 143 | + defer dh.ktLock.Unlock() |
| 144 | + dh.keywordTableMap[tag] = table |
| 145 | + return nil |
| 146 | +} |
| 147 | + |
| 148 | +func (dh *Datahub) OnStartup() error { |
| 149 | + dh.startSched() |
| 150 | + return nil |
| 151 | +} |
| 152 | + |
| 153 | +func (dh *Datahub) OnShutdown() error { |
| 154 | + dh.stopSched() |
| 155 | + return nil |
| 156 | +} |
| 157 | + |
| 158 | +func (dh *Datahub) debugPrint() { |
| 159 | + log.Info("geoip_path ", dh.geositePath) |
| 160 | + log.Info("geosite_path ", dh.geositePath) |
| 161 | + log.Info("geoip_cache ", dh.geoipCacheTags) |
| 162 | + log.Info("geosite_cache ", dh.geositeCacheTags) |
| 163 | + log.Info("geodat_upgrade_url ", dh.geodatUpgradeUrl) |
| 164 | + log.Info("geodat_upgrade_cron ", dh.geodatUpgradeCron) |
| 165 | + for k, v := range dh.geoipNetListMap { |
| 166 | + log.Infof("geoip_cache %s total %d", k, v.Len()) |
| 167 | + } |
| 168 | + for k, v := range dh.geositeDoaminListMap { |
| 169 | + log.Infof("geosite_cache %s full_domain:%d regex_domain:%d", k, v.FullLen(), v.RegexLen()) |
| 170 | + } |
| 171 | + for k, v := range dh.keywordTableMap { |
| 172 | + log.Infof("keyword_table %s total %d",k, v.Len()) |
| 173 | + } |
| 174 | +} |
0 commit comments