mirror of
https://github.com/StackExchange/dnscontrol.git
synced 2024-05-11 05:55:12 +00:00
NEW FEATURE: Add RFC4183 support to REV() (#2879)
Co-authored-by: Thomas Misilo <tmisilo@ksu.edu> Co-authored-by: Jeffrey Cafferata <jeffrey@jcid.nl>
This commit is contained in:
79
pkg/rfc4183/reverse.go
Normal file
79
pkg/rfc4183/reverse.go
Normal file
@ -0,0 +1,79 @@
|
||||
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)
|
||||
|
||||
}
|
Reference in New Issue
Block a user