feat: add config dir as extern geosite search dir. fix #41

This commit is contained in:
mzz2017 2023-03-25 00:57:04 +08:00
parent 07ff753cf3
commit 2ff7e1ba47
5 changed files with 68 additions and 63 deletions

View File

@ -74,17 +74,17 @@ var (
logrus.SetLevel(log.Level)
log.Infof("Include config files: [%v]", strings.Join(includes, ", "))
if err := Run(log, conf); err != nil {
if err := Run(log, conf, []string{filepath.Dir(cfgFile)}); err != nil {
logrus.Fatalln(err)
}
},
}
)
func Run(log *logrus.Logger, conf *config.Config) (err error) {
func Run(log *logrus.Logger, conf *config.Config, externGeoDataDirs []string) (err error) {
// New ControlPlane.
c, err := newControlPlane(log, nil, nil, conf)
c, err := newControlPlane(log, nil, nil, conf, externGeoDataDirs)
if err != nil {
return err
}
@ -172,13 +172,13 @@ loop:
obj := c.EjectBpf()
dnsCache := c.CloneDnsCache()
log.Warnln("[Reload] Load new control plane")
newC, err := newControlPlane(log, obj, dnsCache, newConf)
newC, err := newControlPlane(log, obj, dnsCache, newConf, externGeoDataDirs)
if err != nil {
log.WithFields(logrus.Fields{
"err": err,
}).Errorln("[Reload] Failed to reload; try to roll back configuration")
// Load last config back.
newC, err = newControlPlane(log, obj, dnsCache, conf)
newC, err = newControlPlane(log, obj, dnsCache, conf, externGeoDataDirs)
if err != nil {
sdnotify.Stopping()
obj.Close()
@ -216,7 +216,7 @@ loop:
return nil
}
func newControlPlane(log *logrus.Logger, bpf interface{}, dnsCache map[string]*control.DnsCache, conf *config.Config) (c *control.ControlPlane, err error) {
func newControlPlane(log *logrus.Logger, bpf interface{}, dnsCache map[string]*control.DnsCache, conf *config.Config, externGeoDataDirs []string) (c *control.ControlPlane, err error) {
// Deep copy to prevent modification.
conf = deepcopy.Copy(conf).(*config.Config)
@ -277,6 +277,7 @@ func newControlPlane(log *logrus.Logger, bpf interface{}, dnsCache map[string]*c
&conf.Routing,
&conf.Global,
&conf.Dns,
externGeoDataDirs,
)
if err != nil {
return nil, err

View File

@ -29,20 +29,23 @@ type CacheItem struct {
}
type LocationFinder struct {
mu sync.Mutex
m map[string]CacheItem
mu sync.Mutex
m map[string]CacheItem
externDirs []string
}
func NewLocationFinder() *LocationFinder {
func NewLocationFinder(externDirPath []string) *LocationFinder {
return &LocationFinder{
mu: sync.Mutex{},
m: map[string]CacheItem{},
mu: sync.Mutex{},
m: map[string]CacheItem{},
externDirs: externDirPath,
}
}
func (c *LocationFinder) GetLocationAsset(log *logrus.Logger, filename string) (path string, err error) {
c.mu.Lock()
defer c.mu.Unlock()
// Search cache.
if item, ok := c.m[filename]; ok && time.Now().Before(item.CacheDeadline) {
return item.Path, nil
}
@ -63,63 +66,55 @@ func (c *LocationFinder) GetLocationAsset(log *logrus.Logger, filename string) (
}
}()
// Search dirs.
var searchDirs []string
folder := "dae"
location := os.Getenv("DAE_LOCATION_ASSET")
// check if DAE_LOCATION_ASSET is set
if location != "" {
// add DAE_LOCATION_ASSET to search path
searchPaths := []string{
filepath.Join(location, filename),
searchDirs = []string{
location,
}
// additional paths for non windows platforms
if runtime.GOOS != "windows" {
searchPaths = append(
searchPaths,
filepath.Join("/usr/local/share", folder, filename),
filepath.Join("/usr/share", folder, filename),
searchDirs = append(
searchDirs,
filepath.Join("/usr/local/share", folder),
filepath.Join("/usr/share", folder),
)
}
searchDirs := make([]string, len(searchPaths))
for i := range searchDirs {
searchDirs[i] = filepath.Dir(searchPaths[i])
}
log.Debugf(`Search "%v" in [%v]`, filename, strings.Join(searchDirs, ", "))
for _, searchPath := range searchPaths {
if _, err = os.Stat(searchPath); err != nil && errors.Is(err, fs.ErrNotExist) {
continue
}
log.Debugf(`Found "%v" at %v`, filename, searchPath)
// return the first path that exists
return searchPath, nil
}
return "", fmt.Errorf("%v: %w in [%v]", filename, os.ErrNotExist, strings.Join(searchDirs, ", "))
searchDirs = append(searchDirs, c.externDirs...)
} else {
if runtime.GOOS != "windows" {
// search XDG data directories on non windows platform
searchDirs := append([]string{xdg.DataHome}, xdg.DataDirs...)
// Search XDG data directories on non windows platform
searchDirs = append([]string{xdg.DataHome}, xdg.DataDirs...)
for i := range searchDirs {
searchDirs[i] = filepath.Join(searchDirs[i], folder)
}
log.Debugf(`Search "%v" in [%v]`, filename, strings.Join(searchDirs, ", "))
relpath := filepath.Join(folder, filename)
fullpath, err := xdg.SearchDataFile(relpath)
if err != nil {
return "", fmt.Errorf("%v: %w in [%v]", filename, os.ErrNotExist, strings.Join(searchDirs, ", "))
}
log.Debugf(`Found "%v" at %v`, filename, fullpath)
return fullpath, nil
searchDirs = append(searchDirs, c.externDirs...)
} else {
searchDirs = append([]string{}, c.externDirs...)
// fallback to the old behavior of using only current dir on Windows
path := filepath.Join("./", filename)
if absPath, e := filepath.Abs(path); e == nil {
path = absPath
pwd := "./"
if absPath, e := filepath.Abs(pwd); e == nil {
pwd = absPath
}
if _, err := os.Stat(path); errors.Is(err, os.ErrNotExist) {
return "", fmt.Errorf("%v: %w in %v", filename, os.ErrNotExist, path)
}
return path, nil
searchDirs = append(searchDirs, pwd)
}
}
log.Debugf(`Search "%v" in [%v]`, filename, strings.Join(searchDirs, ", "))
for _, searchDir := range searchDirs {
searchPath := filepath.Join(searchDir, filename)
if _, err = os.Stat(searchPath); err != nil {
if errors.Is(err, fs.ErrNotExist) {
continue
}
return "", err
}
log.Debugf(`Found "%v" at %v`, filename, searchPath)
// return the first path that exists
return searchPath, nil
}
return "", fmt.Errorf("%v: %w in [%v]", filename, os.ErrNotExist, strings.Join(searchDirs, ", "))
}
var DefaultLocationFinder = NewLocationFinder()

View File

@ -8,6 +8,7 @@ package dns
import (
"fmt"
"github.com/daeuniverse/dae/common"
"github.com/daeuniverse/dae/common/assets"
"github.com/daeuniverse/dae/common/consts"
"github.com/daeuniverse/dae/component/routing"
"github.com/daeuniverse/dae/config"
@ -30,12 +31,14 @@ type Dns struct {
}
type NewOption struct {
Logger *logrus.Logger
LocationFinder *assets.LocationFinder
UpstreamReadyCallback func(dnsUpstream *Upstream) (err error)
}
func New(log *logrus.Logger, dns *config.Dns, opt *NewOption) (s *Dns, err error) {
func New(dns *config.Dns, opt *NewOption) (s *Dns, err error) {
s = &Dns{
log: log,
log: opt.Logger,
upstream2Index: map[*Upstream]int{
nil: int(consts.DnsRequestOutboundIndex_AsIs),
},
@ -79,21 +82,21 @@ func New(log *logrus.Logger, dns *config.Dns, opt *NewOption) (s *Dns, err error
}
// Optimize routings.
if dns.Routing.Request.Rules, err = routing.ApplyRulesOptimizers(dns.Routing.Request.Rules,
&routing.DatReaderOptimizer{Logger: log},
&routing.DatReaderOptimizer{Logger: opt.Logger, LocationFinder: opt.LocationFinder},
&routing.MergeAndSortRulesOptimizer{},
&routing.DeduplicateParamsOptimizer{},
); err != nil {
return nil, err
}
if dns.Routing.Response.Rules, err = routing.ApplyRulesOptimizers(dns.Routing.Response.Rules,
&routing.DatReaderOptimizer{Logger: log},
&routing.DatReaderOptimizer{Logger: opt.Logger, LocationFinder: opt.LocationFinder},
&routing.MergeAndSortRulesOptimizer{},
&routing.DeduplicateParamsOptimizer{},
); err != nil {
return nil, err
}
// Parse request routing.
reqMatcherBuilder, err := NewRequestMatcherBuilder(log, dns.Routing.Request.Rules, upstreamName2Id, dns.Routing.Request.Fallback)
reqMatcherBuilder, err := NewRequestMatcherBuilder(opt.Logger, dns.Routing.Request.Rules, upstreamName2Id, dns.Routing.Request.Fallback)
if err != nil {
return nil, fmt.Errorf("failed to build DNS request routing: %w", err)
}
@ -102,7 +105,7 @@ func New(log *logrus.Logger, dns *config.Dns, opt *NewOption) (s *Dns, err error
return nil, fmt.Errorf("failed to build DNS request routing: %w", err)
}
// Parse response routing.
respMatcherBuilder, err := NewResponseMatcherBuilder(log, dns.Routing.Response.Rules, upstreamName2Id, dns.Routing.Response.Fallback)
respMatcherBuilder, err := NewResponseMatcherBuilder(opt.Logger, dns.Routing.Response.Rules, upstreamName2Id, dns.Routing.Response.Fallback)
if err != nil {
return nil, fmt.Errorf("failed to build DNS response routing: %w", err)
}

View File

@ -7,12 +7,12 @@ package routing
import (
"fmt"
"github.com/mohae/deepcopy"
"github.com/sirupsen/logrus"
"github.com/daeuniverse/dae/common/assets"
"github.com/daeuniverse/dae/common/consts"
"github.com/daeuniverse/dae/pkg/config_parser"
"github.com/daeuniverse/dae/pkg/geodata"
"github.com/mohae/deepcopy"
"github.com/sirupsen/logrus"
"net/netip"
"sort"
"strings"
@ -153,14 +153,15 @@ func (o *DeduplicateParamsOptimizer) Optimize(rules []*config_parser.RoutingRule
}
type DatReaderOptimizer struct {
Logger *logrus.Logger
LocationFinder *assets.LocationFinder
Logger *logrus.Logger
}
func (o *DatReaderOptimizer) loadGeoSite(filename string, code string) (params []*config_parser.Param, err error) {
if !strings.HasSuffix(filename, ".dat") {
filename += ".dat"
}
filePath, err := assets.DefaultLocationFinder.GetLocationAsset(o.Logger, filename)
filePath, err := o.LocationFinder.GetLocationAsset(o.Logger, filename)
if err != nil {
o.Logger.Debugf("Failed to read geosite \"%v:%v\": %v", filename, code, err)
return nil, err
@ -205,7 +206,7 @@ func (o *DatReaderOptimizer) loadGeoIp(filename string, code string) (params []*
if !strings.HasSuffix(filename, ".dat") {
filename += ".dat"
}
filePath, err := assets.DefaultLocationFinder.GetLocationAsset(o.Logger, filename)
filePath, err := o.LocationFinder.GetLocationAsset(o.Logger, filename)
if err != nil {
o.Logger.Debugf("Failed to read geoip \"%v:%v\": %v", filename, code, err)
return nil, err

View File

@ -12,6 +12,7 @@ import (
"github.com/cilium/ebpf"
"github.com/cilium/ebpf/rlimit"
"github.com/daeuniverse/dae/common"
"github.com/daeuniverse/dae/common/assets"
"github.com/daeuniverse/dae/common/consts"
"github.com/daeuniverse/dae/common/netutils"
"github.com/daeuniverse/dae/component/dns"
@ -71,6 +72,7 @@ func NewControlPlane(
routingA *config.Routing,
global *config.Global,
dnsConfig *config.Dns,
externGeoDataDirs []string,
) (*ControlPlane, error) {
var err error
@ -290,10 +292,11 @@ func NewControlPlane(
outboundId2Name[uint8(i)] = o.Name
}
// Apply rules optimizers.
locationFinder := assets.NewLocationFinder(externGeoDataDirs)
var rules []*config_parser.RoutingRule
if rules, err = routing.ApplyRulesOptimizers(routingA.Rules,
&routing.AliasOptimizer{},
&routing.DatReaderOptimizer{Logger: log},
&routing.DatReaderOptimizer{Logger: log, LocationFinder: locationFinder},
&routing.MergeAndSortRulesOptimizer{},
&routing.DeduplicateParamsOptimizer{},
); err != nil {
@ -348,7 +351,9 @@ func NewControlPlane(
}()
/// DNS upstream.
dnsUpstream, err := dns.New(log, dnsConfig, &dns.NewOption{
dnsUpstream, err := dns.New(dnsConfig, &dns.NewOption{
Logger: log,
LocationFinder: locationFinder,
UpstreamReadyCallback: plane.dnsUpstreamReadyCallback,
})
if err != nil {