2021-02-01 23:46:47 +00:00
|
|
|
package cooldns
|
|
|
|
|
|
|
|
import (
|
|
|
|
"io/ioutil"
|
|
|
|
"log"
|
|
|
|
"net"
|
|
|
|
"os"
|
|
|
|
|
|
|
|
"github.com/miekg/dns"
|
|
|
|
"gopkg.in/yaml.v3"
|
|
|
|
)
|
|
|
|
|
|
|
|
// config format of the config file
|
|
|
|
type config struct {
|
|
|
|
Zones []configZone `yaml:"zones"`
|
|
|
|
ACL []configACL `yaml:"acl"`
|
|
|
|
Forward configForward `yaml:"forward"`
|
|
|
|
Address string `yaml:"address"`
|
|
|
|
Blacklist []configBlacklist `yaml:"blacklist"`
|
|
|
|
TLS configTLS `yaml:"tls"`
|
|
|
|
Lego configLego `yaml:"lego"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type configForward struct {
|
2021-02-03 17:17:24 +00:00
|
|
|
Enable bool `yaml:"enable"`
|
2021-02-01 23:46:47 +00:00
|
|
|
ACL []string `yaml:"acl"`
|
|
|
|
Server string `yaml:"server"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type configACL struct {
|
|
|
|
Name string `yaml:"name"`
|
|
|
|
CIDR string `yaml:"cidr"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type configZone struct {
|
|
|
|
Zone string `yaml:"zone"`
|
|
|
|
File string `yaml:"file"`
|
|
|
|
ACL []string `yaml:"acl"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type configBlacklist struct {
|
|
|
|
URL string `yaml:"url"`
|
|
|
|
Format string `yaml:"format"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type configTLS struct {
|
|
|
|
Enable bool `yaml:"enable"`
|
|
|
|
Address string `yaml:"address"`
|
|
|
|
Cert string `yaml:"cert"`
|
|
|
|
Key string `yaml:"key"`
|
|
|
|
}
|
|
|
|
|
|
|
|
func loadConfig(configPath string) (*config, error) {
|
|
|
|
file, err := ioutil.ReadFile(configPath)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
var loadedConfig config
|
|
|
|
|
|
|
|
err = yaml.Unmarshal(file, &loadedConfig)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return &loadedConfig, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func loadZones(configZones []configZone) (zoneMap, error) {
|
|
|
|
zones := make(zoneMap)
|
|
|
|
for _, z := range configZones {
|
|
|
|
rrs, err := loadZonefile(z.File, z.Zone)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if zones[z.Zone] == nil {
|
|
|
|
zones[z.Zone] = make([]zoneView, 0)
|
|
|
|
}
|
|
|
|
zones[z.Zone] = append(zones[z.Zone], zoneView{
|
|
|
|
rr: createRRMap(rrs),
|
|
|
|
acl: z.ACL,
|
|
|
|
})
|
|
|
|
|
|
|
|
log.Printf("Loaded zone %s\n", z.Zone)
|
|
|
|
}
|
|
|
|
|
|
|
|
return zones, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// createRRMap order the rr into a structure that is more easy to use
|
|
|
|
func createRRMap(rrs []dns.RR) rrMap {
|
|
|
|
rrMap := make(rrMap)
|
|
|
|
for _, rr := range rrs {
|
|
|
|
if rrMap[rr.Header().Rrtype] == nil {
|
|
|
|
rrMap[rr.Header().Rrtype] = make(map[string][]dns.RR)
|
|
|
|
}
|
|
|
|
|
|
|
|
if rrMap[rr.Header().Rrtype][rr.Header().Name] == nil {
|
|
|
|
rrMap[rr.Header().Rrtype][rr.Header().Name] = make([]dns.RR, 0)
|
|
|
|
}
|
|
|
|
rrMap[rr.Header().Rrtype][rr.Header().Name] = append(rrMap[rr.Header().Rrtype][rr.Header().Name], rr)
|
|
|
|
}
|
|
|
|
|
|
|
|
return rrMap
|
|
|
|
}
|
|
|
|
|
|
|
|
func loadZonefile(filepath, origin string) ([]dns.RR, error) {
|
|
|
|
file, err := os.Open(filepath)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
parser := dns.NewZoneParser(file, origin, filepath)
|
|
|
|
|
|
|
|
var rrs = make([]dns.RR, 0)
|
|
|
|
|
|
|
|
for rr, ok := parser.Next(); ok; rr, ok = parser.Next() {
|
|
|
|
rrs = append(rrs, rr)
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := parser.Err(); err != nil {
|
|
|
|
log.Println(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return rrs, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// createACLList create a map with the CIDR and the name of the rule
|
|
|
|
func createACLList(config []configACL) (map[string]*net.IPNet, error) {
|
|
|
|
acls := make(map[string]*net.IPNet)
|
|
|
|
|
|
|
|
for _, aclRule := range config {
|
|
|
|
_, mask, err := net.ParseCIDR(aclRule.CIDR)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
acls[aclRule.Name] = mask
|
|
|
|
}
|
|
|
|
|
|
|
|
return acls, nil
|
|
|
|
}
|