core: small cleanup (#877)

Add some docs about normalize.Host and normalize.Name. They are used
correctly in the middleware even though they are somewhat confusing,
esp when you copy from ServerBlockKeys in your middleware.
This commit is contained in:
Miek Gieben 2017-08-10 05:30:18 -07:00 committed by GitHub
parent 28447234b1
commit 3654361be2
7 changed files with 326 additions and 341 deletions

View file

@ -81,91 +81,88 @@ func autoParse(c *caddy.Controller) (Auto, error) {
config := dnsserver.GetConfig(c)
for c.Next() {
if c.Val() == "auto" {
// auto [ZONES...]
a.Zones.origins = make([]string, len(c.ServerBlockKeys))
copy(a.Zones.origins, c.ServerBlockKeys)
// auto [ZONES...]
a.Zones.origins = make([]string, len(c.ServerBlockKeys))
copy(a.Zones.origins, c.ServerBlockKeys)
args := c.RemainingArgs()
if len(args) > 0 {
a.Zones.origins = args
}
for i := range a.Zones.origins {
a.Zones.origins[i] = middleware.Host(a.Zones.origins[i]).Normalize()
}
args := c.RemainingArgs()
if len(args) > 0 {
a.Zones.origins = args
}
for i := range a.Zones.origins {
a.Zones.origins[i] = middleware.Host(a.Zones.origins[i]).Normalize()
}
for c.NextBlock() {
switch c.Val() {
case "directory": // directory DIR [REGEXP [TEMPLATE] [DURATION]]
if !c.NextArg() {
return a, c.ArgErr()
}
a.loader.directory = c.Val()
if !path.IsAbs(a.loader.directory) && config.Root != "" {
a.loader.directory = path.Join(config.Root, a.loader.directory)
}
_, err := os.Stat(a.loader.directory)
if err != nil {
if os.IsNotExist(err) {
log.Printf("[WARNING] Directory does not exist: %s", a.loader.directory)
} else {
return a, c.Errf("Unable to access root path '%s': %v", a.loader.directory, err)
}
for c.NextBlock() {
switch c.Val() {
case "directory": // directory DIR [REGEXP [TEMPLATE] [DURATION]]
if !c.NextArg() {
return a, c.ArgErr()
}
a.loader.directory = c.Val()
if !path.IsAbs(a.loader.directory) && config.Root != "" {
a.loader.directory = path.Join(config.Root, a.loader.directory)
}
_, err := os.Stat(a.loader.directory)
if err != nil {
if os.IsNotExist(err) {
log.Printf("[WARNING] Directory does not exist: %s", a.loader.directory)
} else {
return a, c.Errf("Unable to access root path '%s': %v", a.loader.directory, err)
}
}
// regexp
if c.NextArg() {
a.loader.re, err = regexp.Compile(c.Val())
if err != nil {
return a, err
}
if a.loader.re.NumSubexp() == 0 {
return a, c.Errf("Need at least one sub expression")
}
}
// template
if c.NextArg() {
a.loader.template = rewriteToExpand(c.Val())
}
// duration
if c.NextArg() {
i, err := strconv.Atoi(c.Val())
if err != nil {
return a, err
}
if i < 1 {
i = 1
}
a.loader.duration = time.Duration(i) * time.Second
}
case "no_reload":
a.loader.noReload = true
case "upstream":
args := c.RemainingArgs()
if len(args) == 0 {
return a, c.ArgErr()
}
ups, err := dnsutil.ParseHostPortOrFile(args...)
// regexp
if c.NextArg() {
a.loader.re, err = regexp.Compile(c.Val())
if err != nil {
return a, err
}
a.loader.proxy = proxy.NewLookup(ups)
default:
t, _, e := file.TransferParse(c, false)
if e != nil {
return a, e
}
if t != nil {
a.loader.transferTo = append(a.loader.transferTo, t...)
if a.loader.re.NumSubexp() == 0 {
return a, c.Errf("Need at least one sub expression")
}
}
}
// template
if c.NextArg() {
a.loader.template = rewriteToExpand(c.Val())
}
// duration
if c.NextArg() {
i, err := strconv.Atoi(c.Val())
if err != nil {
return a, err
}
if i < 1 {
i = 1
}
a.loader.duration = time.Duration(i) * time.Second
}
case "no_reload":
a.loader.noReload = true
case "upstream":
args := c.RemainingArgs()
if len(args) == 0 {
return a, c.ArgErr()
}
ups, err := dnsutil.ParseHostPortOrFile(args...)
if err != nil {
return a, err
}
a.loader.proxy = proxy.NewLookup(ups)
default:
t, _, e := file.TransferParse(c, false)
if e != nil {
return a, e
}
if t != nil {
a.loader.transferTo = append(a.loader.transferTo, t...)
}
}
}
}
return a, nil

View file

@ -42,36 +42,34 @@ func dnssecParse(c *caddy.Controller) ([]string, []*DNSKEY, int, error) {
capacity := defaultCap
for c.Next() {
if c.Val() == "dnssec" {
// dnssec [zones...]
zones = make([]string, len(c.ServerBlockKeys))
copy(zones, c.ServerBlockKeys)
args := c.RemainingArgs()
if len(args) > 0 {
zones = args
}
// dnssec [zones...]
zones = make([]string, len(c.ServerBlockKeys))
copy(zones, c.ServerBlockKeys)
args := c.RemainingArgs()
if len(args) > 0 {
zones = args
}
for c.NextBlock() {
switch c.Val() {
case "key":
k, e := keyParse(c)
if e != nil {
return nil, nil, 0, e
}
keys = append(keys, k...)
case "cache_capacity":
if !c.NextArg() {
return nil, nil, 0, c.ArgErr()
}
value := c.Val()
cacheCap, err := strconv.Atoi(value)
if err != nil {
return nil, nil, 0, err
}
capacity = cacheCap
for c.NextBlock() {
switch c.Val() {
case "key":
k, e := keyParse(c)
if e != nil {
return nil, nil, 0, e
}
keys = append(keys, k...)
case "cache_capacity":
if !c.NextArg() {
return nil, nil, 0, c.ArgErr()
}
value := c.Val()
cacheCap, err := strconv.Atoi(value)
if err != nil {
return nil, nil, 0, err
}
capacity = cacheCap
}
}
}
for i := range zones {

View file

@ -60,71 +60,69 @@ func etcdParse(c *caddy.Controller) (*Etcd, bool, error) {
stubzones = false
)
for c.Next() {
if c.Val() == "etcd" {
etc.Zones = c.RemainingArgs()
if len(etc.Zones) == 0 {
etc.Zones = make([]string, len(c.ServerBlockKeys))
copy(etc.Zones, c.ServerBlockKeys)
}
for i, str := range etc.Zones {
etc.Zones[i] = middleware.Host(str).Normalize()
}
etc.Zones = c.RemainingArgs()
if len(etc.Zones) == 0 {
etc.Zones = make([]string, len(c.ServerBlockKeys))
copy(etc.Zones, c.ServerBlockKeys)
}
for i, str := range etc.Zones {
etc.Zones[i] = middleware.Host(str).Normalize()
}
if c.NextBlock() {
for {
switch c.Val() {
case "stubzones":
stubzones = true
case "debug":
etc.Debugging = true
case "path":
if !c.NextArg() {
return &Etcd{}, false, c.ArgErr()
}
etc.PathPrefix = c.Val()
case "endpoint":
args := c.RemainingArgs()
if len(args) == 0 {
return &Etcd{}, false, c.ArgErr()
}
endpoints = args
case "upstream":
args := c.RemainingArgs()
if len(args) == 0 {
return &Etcd{}, false, c.ArgErr()
}
ups, err := dnsutil.ParseHostPortOrFile(args...)
if err != nil {
return &Etcd{}, false, err
}
etc.Proxy = proxy.NewLookup(ups)
case "tls": // cert key cacertfile
args := c.RemainingArgs()
tlsConfig, err = mwtls.NewTLSConfigFromArgs(args...)
if err != nil {
return &Etcd{}, false, err
}
default:
if c.Val() != "}" {
return &Etcd{}, false, c.Errf("unknown property '%s'", c.Val())
}
if c.NextBlock() {
for {
switch c.Val() {
case "stubzones":
stubzones = true
case "debug":
etc.Debugging = true
case "path":
if !c.NextArg() {
return &Etcd{}, false, c.ArgErr()
}
if !c.Next() {
break
etc.PathPrefix = c.Val()
case "endpoint":
args := c.RemainingArgs()
if len(args) == 0 {
return &Etcd{}, false, c.ArgErr()
}
endpoints = args
case "upstream":
args := c.RemainingArgs()
if len(args) == 0 {
return &Etcd{}, false, c.ArgErr()
}
ups, err := dnsutil.ParseHostPortOrFile(args...)
if err != nil {
return &Etcd{}, false, err
}
etc.Proxy = proxy.NewLookup(ups)
case "tls": // cert key cacertfile
args := c.RemainingArgs()
tlsConfig, err = mwtls.NewTLSConfigFromArgs(args...)
if err != nil {
return &Etcd{}, false, err
}
default:
if c.Val() != "}" {
return &Etcd{}, false, c.Errf("unknown property '%s'", c.Val())
}
}
if !c.Next() {
break
}
}
client, err := newEtcdClient(endpoints, tlsConfig)
if err != nil {
return &Etcd{}, false, err
}
etc.Client = client
etc.endpoints = endpoints
return &etc, stubzones, nil
}
client, err := newEtcdClient(endpoints, tlsConfig)
if err != nil {
return &Etcd{}, false, err
}
etc.Client = client
etc.endpoints = endpoints
return &etc, stubzones, nil
}
return &Etcd{}, false, nil
}

View file

@ -55,76 +55,74 @@ func fileParse(c *caddy.Controller) (Zones, error) {
config := dnsserver.GetConfig(c)
for c.Next() {
if c.Val() == "file" {
// file db.file [zones...]
if !c.NextArg() {
return Zones{}, c.ArgErr()
}
fileName := c.Val()
// file db.file [zones...]
if !c.NextArg() {
return Zones{}, c.ArgErr()
}
fileName := c.Val()
origins = make([]string, len(c.ServerBlockKeys))
copy(origins, c.ServerBlockKeys)
args := c.RemainingArgs()
if len(args) > 0 {
origins = args
}
origins = make([]string, len(c.ServerBlockKeys))
copy(origins, c.ServerBlockKeys)
args := c.RemainingArgs()
if len(args) > 0 {
origins = args
}
if !path.IsAbs(fileName) && config.Root != "" {
fileName = path.Join(config.Root, fileName)
}
if !path.IsAbs(fileName) && config.Root != "" {
fileName = path.Join(config.Root, fileName)
}
reader, err := os.Open(fileName)
if err != nil {
// bail out
reader, err := os.Open(fileName)
if err != nil {
// bail out
return Zones{}, err
}
for i := range origins {
origins[i] = middleware.Host(origins[i]).Normalize()
zone, err := Parse(reader, origins[i], fileName, 0)
if err == nil {
z[origins[i]] = zone
} else {
return Zones{}, err
}
names = append(names, origins[i])
}
for i := range origins {
origins[i] = middleware.Host(origins[i]).Normalize()
zone, err := Parse(reader, origins[i], fileName, 0)
if err == nil {
z[origins[i]] = zone
} else {
noReload := false
prxy := proxy.Proxy{}
t := []string{}
var e error
for c.NextBlock() {
switch c.Val() {
case "transfer":
t, _, e = TransferParse(c, false)
if e != nil {
return Zones{}, e
}
case "no_reload":
noReload = true
case "upstream":
args := c.RemainingArgs()
if len(args) == 0 {
return Zones{}, c.ArgErr()
}
ups, err := dnsutil.ParseHostPortOrFile(args...)
if err != nil {
return Zones{}, err
}
names = append(names, origins[i])
prxy = proxy.NewLookup(ups)
}
noReload := false
prxy := proxy.Proxy{}
t := []string{}
var e error
for c.NextBlock() {
switch c.Val() {
case "transfer":
t, _, e = TransferParse(c, false)
if e != nil {
return Zones{}, e
}
case "no_reload":
noReload = true
case "upstream":
args := c.RemainingArgs()
if len(args) == 0 {
return Zones{}, c.ArgErr()
}
ups, err := dnsutil.ParseHostPortOrFile(args...)
if err != nil {
return Zones{}, err
}
prxy = proxy.NewLookup(ups)
}
for _, origin := range origins {
if t != nil {
z[origin].TransferTo = append(z[origin].TransferTo, t...)
}
z[origin].NoReload = noReload
z[origin].Proxy = prxy
for _, origin := range origins {
if t != nil {
z[origin].TransferTo = append(z[origin].TransferTo, t...)
}
z[origin].NoReload = noReload
z[origin].Proxy = prxy
}
}
}

View file

@ -41,46 +41,44 @@ func hostsParse(c *caddy.Controller) (Hosts, error) {
config := dnsserver.GetConfig(c)
for c.Next() {
if c.Val() == "hosts" { // hosts [FILE] [ZONES...]
args := c.RemainingArgs()
if len(args) >= 1 {
h.path = args[0]
args = args[1:]
args := c.RemainingArgs()
if len(args) >= 1 {
h.path = args[0]
args = args[1:]
if !path.IsAbs(h.path) && config.Root != "" {
h.path = path.Join(config.Root, h.path)
}
_, err := os.Stat(h.path)
if err != nil {
if os.IsNotExist(err) {
log.Printf("[WARNING] File does not exist: %s", h.path)
} else {
return h, c.Errf("unable to access hosts file '%s': %v", h.path, err)
}
if !path.IsAbs(h.path) && config.Root != "" {
h.path = path.Join(config.Root, h.path)
}
_, err := os.Stat(h.path)
if err != nil {
if os.IsNotExist(err) {
log.Printf("[WARNING] File does not exist: %s", h.path)
} else {
return h, c.Errf("unable to access hosts file '%s': %v", h.path, err)
}
}
}
origins := make([]string, len(c.ServerBlockKeys))
copy(origins, c.ServerBlockKeys)
if len(args) > 0 {
origins = args
}
origins := make([]string, len(c.ServerBlockKeys))
copy(origins, c.ServerBlockKeys)
if len(args) > 0 {
origins = args
}
for i := range origins {
origins[i] = middleware.Host(origins[i]).Normalize()
}
h.Origins = origins
for i := range origins {
origins[i] = middleware.Host(origins[i]).Normalize()
}
h.Origins = origins
for c.NextBlock() {
switch c.Val() {
case "fallthrough":
args := c.RemainingArgs()
if len(args) == 0 {
h.Fallthrough = true
continue
}
return h, c.ArgErr()
for c.NextBlock() {
switch c.Val() {
case "fallthrough":
args := c.RemainingArgs()
if len(args) == 0 {
h.Fallthrough = true
continue
}
return h, c.ArgErr()
}
}
}

View file

@ -30,7 +30,8 @@ func (z Zones) Matches(qname string) string {
return zone
}
// Normalize fully qualifies all zones in z.
// Normalize fully qualifies all zones in z. The zones in Z must be domain names, without
// a port or protocol prefix.
func (z Zones) Normalize() {
for i := range z {
z[i] = Name(z[i]).Normalize()
@ -54,7 +55,7 @@ func (n Name) Normalize() string { return strings.ToLower(dns.Fqdn(string(n))) }
type (
// Host represents a host from the Corefile, may contain port.
Host string // Host represents a host from the Corefile, may contain port.
Host string
)
// Normalize will return the host portion of host, stripping

View file

@ -34,116 +34,111 @@ func setupReverse(c *caddy.Controller) error {
}
func reverseParse(c *caddy.Controller) (nets networks, fall bool, err error) {
// normalize zones, validation is almost done by dnsserver
// TODO(miek): need sane helpers for these.
zones := make([]string, len(c.ServerBlockKeys))
wildcard := false
// We copy from the serverblock, these contains Hosts.
for i, str := range c.ServerBlockKeys {
zones[i] = middleware.Host(str).Normalize()
}
for c.Next() {
if c.Val() == "reverse" {
var cidrs []*net.IPNet
var cidrs []*net.IPNet
// parse all networks
for _, cidr := range c.RemainingArgs() {
if cidr == "{" {
break
}
_, ipnet, err := net.ParseCIDR(cidr)
if err != nil {
return nil, false, c.Errf("network needs to be CIDR formatted: %q\n", cidr)
}
cidrs = append(cidrs, ipnet)
// parse all networks
for _, cidr := range c.RemainingArgs() {
if cidr == "{" {
break
}
if len(cidrs) == 0 {
return nil, false, c.ArgErr()
_, ipnet, err := net.ParseCIDR(cidr)
if err != nil {
return nil, false, c.Errf("network needs to be CIDR formatted: %q\n", cidr)
}
cidrs = append(cidrs, ipnet)
}
if len(cidrs) == 0 {
return nil, false, c.ArgErr()
}
// set defaults
var (
template = "ip-" + templateNameIP + ".{zone[1]}"
ttl = 60
)
for c.NextBlock() {
switch c.Val() {
case "hostname":
if !c.NextArg() {
return nil, false, c.ArgErr()
}
template = c.Val()
case "ttl":
if !c.NextArg() {
return nil, false, c.ArgErr()
}
ttl, err = strconv.Atoi(c.Val())
if err != nil {
return nil, false, err
}
case "wildcard":
wildcard = true
case "fallthrough":
fall = true
default:
// set defaults
var (
template = "ip-" + templateNameIP + ".{zone[1]}"
ttl = 60
)
for c.NextBlock() {
switch c.Val() {
case "hostname":
if !c.NextArg() {
return nil, false, c.ArgErr()
}
}
template = c.Val()
// prepare template
// replace {zone[index]} by the listen zone/domain of this config block
for i, zone := range zones {
// TODO: we should be smarter about actually replacing this. This works, but silently allows "zone[-1]"
// for instance.
template = strings.Replace(template, "{zone["+strconv.Itoa(i+1)+"]}", zone, 1)
}
if !strings.HasSuffix(template, ".") {
template += "."
}
// extract zone from template
templateZone := strings.SplitAfterN(template, ".", 2)
if len(templateZone) != 2 || templateZone[1] == "" {
return nil, false, c.Errf("cannot find domain in template '%v'", template)
}
// Create for each configured network in this stanza
for _, ipnet := range cidrs {
// precompile regex for hostname to ip matching
regexIP := regexMatchV4
if ipnet.IP.To4() == nil {
regexIP = regexMatchV6
case "ttl":
if !c.NextArg() {
return nil, false, c.ArgErr()
}
prefix := "^"
if wildcard {
prefix += ".*"
}
regex, err := regexp.Compile(
prefix + strings.Replace( // inject ip regex into template
regexp.QuoteMeta(template), // escape dots
regexp.QuoteMeta(templateNameIP),
regexIP,
1) + "$")
ttl, err = strconv.Atoi(c.Val())
if err != nil {
return nil, false, err
}
nets = append(nets, network{
IPnet: ipnet,
Zone: templateZone[1],
Template: template,
RegexMatchIP: regex,
TTL: uint32(ttl),
})
case "wildcard":
wildcard = true
case "fallthrough":
fall = true
default:
return nil, false, c.ArgErr()
}
}
// prepare template
// replace {zone[index]} by the listen zone/domain of this config block
for i, zone := range zones {
// TODO: we should be smarter about actually replacing this. This works, but silently allows "zone[-1]"
// for instance.
template = strings.Replace(template, "{zone["+strconv.Itoa(i+1)+"]}", zone, 1)
}
if !strings.HasSuffix(template, ".") {
template += "."
}
// extract zone from template
templateZone := strings.SplitAfterN(template, ".", 2)
if len(templateZone) != 2 || templateZone[1] == "" {
return nil, false, c.Errf("cannot find domain in template '%v'", template)
}
// Create for each configured network in this stanza
for _, ipnet := range cidrs {
// precompile regex for hostname to ip matching
regexIP := regexMatchV4
if ipnet.IP.To4() == nil {
regexIP = regexMatchV6
}
prefix := "^"
if wildcard {
prefix += ".*"
}
regex, err := regexp.Compile(
prefix + strings.Replace( // inject ip regex into template
regexp.QuoteMeta(template), // escape dots
regexp.QuoteMeta(templateNameIP),
regexIP,
1) + "$")
if err != nil {
return nil, false, err
}
nets = append(nets, network{
IPnet: ipnet,
Zone: templateZone[1],
Template: template,
RegexMatchIP: regex,
TTL: uint32(ttl),
})
}
}
// sort by cidr