dnscontrol/pkg/rfc4183/reverse.go
Tom Limoncelli 1d96981e11
NEW FEATURE: Add RFC4183 support to REV() (#2879)
Co-authored-by: Thomas Misilo <tmisilo@ksu.edu>
Co-authored-by: Jeffrey Cafferata <jeffrey@jcid.nl>
2024-04-03 16:01:55 -04:00

80 lines
1.9 KiB
Go

package rfc4183
import (
"fmt"
"net/netip"
"strings"
)
// ReverseDomainName implements RFC4183 for turning a CIDR block into
// a in-addr name. IP addresses are assumed to be /32 or /128 CIDR blocks.
// CIDR host bits are changed to 0s.
func ReverseDomainName(cidr string) (string, error) {
// Mask missing? Add it.
if !strings.Contains(cidr, "/") {
a, err := netip.ParseAddr(cidr)
if err != nil {
return "", fmt.Errorf("not an IP address: %w", err)
}
if a.Is4() {
cidr = cidr + "/32"
} else {
cidr = cidr + "/128"
}
}
// Parse the CIDR.
p, err := netip.ParsePrefix(cidr)
if err != nil {
return "", fmt.Errorf("not a CIDR block: %w", err)
}
// RFC4183 4.1 step 4: The notion of fewer than 8 mask bits is not reasonable.
if p.Bits() < 8 {
return "", fmt.Errorf("mask fewer than 8 bits is unreasonable: %s", cidr)
}
// Handle IPv6 separately:
if p.Addr().Is6() {
return reverseIPv6(p.Addr().AsSlice(), p.Bits())
}
// Zero out any host bits.
p = p.Masked()
// IPv4: Implement the RFC4183 process:
// 4.p Step 1
b := p.Addr().AsSlice()
x, y, z, w := b[0], b[1], b[2], b[3]
m := p.Bits()
if m == 8 {
return fmt.Sprintf("%d.in-addr.arpa", x), nil
}
if m == 16 {
return fmt.Sprintf("%d.%d.in-addr.arpa", y, x), nil
}
if m == 24 {
return fmt.Sprintf("%d.%d.%d.in-addr.arpa", z, y, x), nil
}
if m == 32 {
return fmt.Sprintf("%d.%d.%d.%d.in-addr.arpa", w, z, y, x), nil
}
// 4.1 Step 2
n := w // I don't understand why the RFC changes variable names at this point, but it does.
if m >= 24 && m <= 32 {
return fmt.Sprintf("%d-%d.%d.%d.%d.in-addr.arpa", n, m, z, y, x), nil
}
if m >= 16 && m < 24 {
return fmt.Sprintf("%d-%d.%d.%d.in-addr.arpa", z, m, y, x), nil
}
if m >= 8 && m < 16 {
return fmt.Sprintf("%d-%d.%d.in-addr.arpa", y, m, x), nil
}
return "", fmt.Errorf("fewer than 8 mask bits is not reasonable: %v", cidr)
}