cloudflared-mirror/vendor/github.com/coredns/coredns/plugin/pkg/cidr/cidr.go

84 lines
2.2 KiB
Go

// Package cidr contains functions that deal with classless reverse zones in the DNS.
package cidr
import (
"math"
"net"
"strings"
"github.com/apparentlymart/go-cidr/cidr"
"github.com/miekg/dns"
)
// Split returns a slice of non-overlapping subnets that in union equal the subnet n,
// and where each subnet falls on a reverse name segment boundary.
// for ipv4 this is any multiple of 8 bits (/8, /16, /24 or /32)
// for ipv6 this is any multiple of 4 bits
func Split(n *net.IPNet) []string {
boundary := 8
nstr := n.String()
if strings.Contains(nstr, ":") {
boundary = 4
}
ones, _ := n.Mask.Size()
if ones%boundary == 0 {
return []string{n.String()}
}
mask := int(math.Ceil(float64(ones)/float64(boundary))) * boundary
networks := nets(n, mask)
cidrs := make([]string, len(networks))
for i := range networks {
cidrs[i] = networks[i].String()
}
return cidrs
}
// nets return a slice of prefixes with the desired mask subnetted from original network.
func nets(network *net.IPNet, newPrefixLen int) []*net.IPNet {
prefixLen, _ := network.Mask.Size()
maxSubnets := int(math.Exp2(float64(newPrefixLen)) / math.Exp2(float64(prefixLen)))
nets := []*net.IPNet{{network.IP, net.CIDRMask(newPrefixLen, 8*len(network.IP))}}
for i := 1; i < maxSubnets; i++ {
next, exceeds := cidr.NextSubnet(nets[len(nets)-1], newPrefixLen)
nets = append(nets, next)
if exceeds {
break
}
}
return nets
}
// Reverse return the reverse zones that are authoritative for each net in ns.
func Reverse(nets []string) []string {
rev := make([]string, len(nets))
for i := range nets {
ip, n, _ := net.ParseCIDR(nets[i])
r, err1 := dns.ReverseAddr(ip.String())
if err1 != nil {
continue
}
ones, bits := n.Mask.Size()
// get the size, in bits, of each portion of hostname defined in the reverse address. (8 for IPv4, 4 for IPv6)
sizeDigit := 8
if len(n.IP) == net.IPv6len {
sizeDigit = 4
}
// Get the first lower octet boundary to see what encompassing zone we should be authoritative for.
mod := (bits - ones) % sizeDigit
nearest := (bits - ones) + mod
offset := 0
var end bool
for i := 0; i < nearest/sizeDigit; i++ {
offset, end = dns.NextLabel(r, offset)
if end {
break
}
}
rev[i] = r[offset:]
}
return rev
}