mirror of
https://github.com/coredns/coredns.git
synced 2025-11-01 02:33:14 -04:00
CIDR query routing (#1159)
* core: allow all CIDR ranges in zone specifications Allow (e.g.) a v4 reverse on a /17. If a zone is specified in such a way a FilterFunc is set in the config. This filter is checked against incoming queries. For all other queries this adds a 'x != nil' check which will not impact performace too much. Benchmark function is added as well to check for this as wel. Add multiple tests in tests/server_reverse_test.go. Benchmark shows in the non-reverse case this hardly impact the speed: ~~~ classless: pkg: github.com/coredns/coredns/core/dnsserver BenchmarkCoreServeDNS-4 1000000 1431 ns/op 16 B/op 1 allocs/op pkg: github.com/coredns/coredns/core/dnsserver BenchmarkCoreServeDNS-4 1000000 1429 ns/op 16 B/op 1 allocs/op master: pkg: github.com/coredns/coredns/core/dnsserver BenchmarkCoreServeDNS-4 1000000 1412 ns/op 16 B/op 1 allocs/op pkg: github.com/coredns/coredns/core/dnsserver BenchmarkCoreServeDNS-4 1000000 1429 ns/op 16 B/op 1 allocs/op ~~~ * README.md updates
This commit is contained in:
@@ -84,11 +84,10 @@ when resolving external pointing CNAMEs.
|
||||
|
||||
Reverse zones are supported. You need to make CoreDNS aware of the fact that you are also
|
||||
authoritative for the reverse. For instance if you want to add the reverse for 10.0.0.0/24, you'll
|
||||
need to add the zone `0.0.10.in-addr.arpa` to the list of zones. (The fun starts with IPv6 reverse zones
|
||||
in the ip6.arpa domain.) Showing a snippet of a Corefile:
|
||||
need to add the zone `0.0.10.in-addr.arpa` to the list of zones. Showing a snippet of a Corefile:
|
||||
|
||||
~~~
|
||||
etcd skydns.local 0.0.10.in-addr.arpa {
|
||||
etcd skydns.local 10.0.0.0/24 {
|
||||
stubzones
|
||||
...
|
||||
~~~
|
||||
|
||||
@@ -76,13 +76,12 @@ kubernetes [ZONES...] {
|
||||
|
||||
## Examples
|
||||
|
||||
Handle all queries in the `cluster.local` zone. Connect to Kubernetes in-cluster.
|
||||
Also handle all `PTR` requests for `10.0.0.0/16` . Verify the existence of pods when answering pod
|
||||
requests. Resolve upstream records against `10.102.3.10`. Note we show the entire server block
|
||||
here:
|
||||
Handle all queries in the `cluster.local` zone. Connect to Kubernetes in-cluster. Also handle all
|
||||
`in-addr.arpa` `PTR` requests for `10.0.0.0/17` . Verify the existence of pods when answering pod
|
||||
requests. Resolve upstream records against `10.102.3.10`. Note we show the entire server block here:
|
||||
|
||||
~~~ txt
|
||||
10.0.0.0/16 cluster.local {
|
||||
10.0.0.0/17 cluster.local {
|
||||
kubernetes {
|
||||
pods verified
|
||||
upstream 10.102.3.10:53
|
||||
|
||||
@@ -12,7 +12,7 @@ func TestKubernetesParseReverseZone(t *testing.T) {
|
||||
expectedZones []string // expected count of defined zones.
|
||||
}{
|
||||
{`kubernetes coredns.local 10.0.0.0/16`, []string{"coredns.local.", "0.10.in-addr.arpa."}},
|
||||
{`kubernetes coredns.local 10.0.0.0/17`, []string{"coredns.local.", "10.0.0.0/17."}},
|
||||
{`kubernetes coredns.local 10.0.0.0/17`, []string{"coredns.local.", "0.10.in-addr.arpa."}},
|
||||
}
|
||||
|
||||
for i, tc := range tests {
|
||||
|
||||
@@ -75,13 +75,14 @@ func (h Host) Normalize() string {
|
||||
|
||||
// The error can be ignore here, because this function is called after the corefile
|
||||
// has already been vetted.
|
||||
host, _, _ := SplitHostPort(s)
|
||||
host, _, _, _ := SplitHostPort(s)
|
||||
return Name(host).Normalize()
|
||||
}
|
||||
|
||||
// SplitHostPort splits s up in a host and port portion, taking reverse address notation into account.
|
||||
// String the string s should *not* be prefixed with any protocols, i.e. dns://
|
||||
func SplitHostPort(s string) (host, port string, err error) {
|
||||
// String the string s should *not* be prefixed with any protocols, i.e. dns://. The returned ipnet is the
|
||||
// *net.IPNet that is used when the zone is a reverse and a netmask is given.
|
||||
func SplitHostPort(s string) (host, port string, ipnet *net.IPNet, err error) {
|
||||
// If there is: :[0-9]+ on the end we assume this is the port. This works for (ascii) domain
|
||||
// names and our reverse syntax, which always needs a /mask *before* the port.
|
||||
// So from the back, find first colon, and then check if its a number.
|
||||
@@ -89,7 +90,7 @@ func SplitHostPort(s string) (host, port string, err error) {
|
||||
|
||||
colon := strings.LastIndex(s, ":")
|
||||
if colon == len(s)-1 {
|
||||
return "", "", fmt.Errorf("expecting data after last colon: %q", s)
|
||||
return "", "", nil, fmt.Errorf("expecting data after last colon: %q", s)
|
||||
}
|
||||
if colon != -1 {
|
||||
if p, err := strconv.Atoi(s[colon+1:]); err == nil {
|
||||
@@ -100,33 +101,34 @@ func SplitHostPort(s string) (host, port string, err error) {
|
||||
|
||||
// TODO(miek): this should take escaping into account.
|
||||
if len(host) > 255 {
|
||||
return "", "", fmt.Errorf("specified zone is too long: %d > 255", len(host))
|
||||
return "", "", nil, fmt.Errorf("specified zone is too long: %d > 255", len(host))
|
||||
}
|
||||
|
||||
_, d := dns.IsDomainName(host)
|
||||
if !d {
|
||||
return "", "", fmt.Errorf("zone is not a valid domain name: %s", host)
|
||||
return "", "", nil, fmt.Errorf("zone is not a valid domain name: %s", host)
|
||||
}
|
||||
|
||||
// Check if it parses as a reverse zone, if so we use that. Must be fully
|
||||
// specified IP and mask and mask % 8 = 0.
|
||||
ip, net, err := net.ParseCIDR(host)
|
||||
// Check if it parses as a reverse zone, if so we use that. Must be fully specified IP and mask.
|
||||
ip, n, err := net.ParseCIDR(host)
|
||||
ones, bits := 0, 0
|
||||
if err == nil {
|
||||
if rev, e := dns.ReverseAddr(ip.String()); e == nil {
|
||||
ones, bits := net.Mask.Size()
|
||||
if (bits-ones)%8 == 0 {
|
||||
offset, end := 0, false
|
||||
for i := 0; i < (bits-ones)/8; i++ {
|
||||
offset, end = dns.NextLabel(rev, offset)
|
||||
if end {
|
||||
break
|
||||
}
|
||||
ones, bits = n.Mask.Size()
|
||||
// Get the first lower octet boundary to see what encompassing zone we should be authoritative for.
|
||||
mod := (bits - ones) % 8
|
||||
nearest := (bits - ones) + mod
|
||||
offset, end := 0, false
|
||||
for i := 0; i < nearest/8; i++ {
|
||||
offset, end = dns.NextLabel(rev, offset)
|
||||
if end {
|
||||
break
|
||||
}
|
||||
host = rev[offset:]
|
||||
}
|
||||
host = rev[offset:]
|
||||
}
|
||||
}
|
||||
return host, port, nil
|
||||
return host, port, n, nil
|
||||
}
|
||||
|
||||
// Duplicated from core/dnsserver/address.go !
|
||||
|
||||
@@ -70,7 +70,7 @@ func TestNameNormalize(t *testing.T) {
|
||||
|
||||
func TestHostNormalize(t *testing.T) {
|
||||
hosts := []string{".:53", ".", "example.org:53", "example.org.", "example.org.:53", "example.org.",
|
||||
"10.0.0.0/8:53", "10.in-addr.arpa.", "10.0.0.0/9", "10.0.0.0/9.",
|
||||
"10.0.0.0/8:53", "10.in-addr.arpa.", "10.0.0.0/9", "10.in-addr.arpa.",
|
||||
"dns://example.org", "example.org."}
|
||||
|
||||
for i := 0; i < len(hosts); i += 2 {
|
||||
@@ -82,3 +82,31 @@ func TestHostNormalize(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSplitHostPortReverse(t *testing.T) {
|
||||
tests := map[string]int{
|
||||
"example.org.": 0,
|
||||
"10.0.0.0/9": 32 - 9,
|
||||
"10.0.0.0/8": 32 - 8,
|
||||
"10.0.0.0/17": 32 - 17,
|
||||
"10.0.0.0/0": 32 - 0,
|
||||
"10.0.0.0/64": 0,
|
||||
"10.0.0.0": 0,
|
||||
"10.0.0": 0,
|
||||
"2003::1/65": 128 - 65,
|
||||
}
|
||||
for in, expect := range tests {
|
||||
_, _, n, err := SplitHostPort(in)
|
||||
if err != nil {
|
||||
t.Errorf("Expected no error, got %q for %s", in, err)
|
||||
}
|
||||
if n == nil {
|
||||
continue
|
||||
}
|
||||
ones, bits := n.Mask.Size()
|
||||
got := bits - ones
|
||||
if got != expect {
|
||||
t.Errorf("Expected %d, got %d for %s", expect, got, in)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
// into an IP address. This works for ipv4 or ipv6.
|
||||
//
|
||||
// 54.119.58.176.in-addr.arpa. becomes 176.58.119.54. If the conversion
|
||||
// failes the empty string is returned.
|
||||
// fails the empty string is returned.
|
||||
func ExtractAddressFromReverse(reverseName string) string {
|
||||
search := ""
|
||||
|
||||
|
||||
Reference in New Issue
Block a user