Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions models/record.go
Original file line number Diff line number Diff line change
Expand Up @@ -390,9 +390,14 @@ func (rc *RecordConfig) ToRR() dns.RR {
// Fill in the data.
switch rdtype { // #rtype_variations
case dns.TypeA:
rr.(*dns.A).A = rc.GetTargetIP()
addr := rc.GetTargetIP()
s := addr.AsSlice()
rr.(*dns.A).A = s[0:4]
case dns.TypeAAAA:
rr.(*dns.AAAA).AAAA = rc.GetTargetIP()
addr := rc.GetTargetIP()
s := addr.AsSlice()
//rr.(*dns.AAAA).AAAA = net.IP(s)
rr.(*dns.AAAA).AAAA = s[0:16]
case dns.TypeCAA:
rr.(*dns.CAA).Flag = rc.CaaFlag
rr.(*dns.CAA).Tag = rc.CaaTag
Expand Down
18 changes: 9 additions & 9 deletions models/t_parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package models

import (
"fmt"
"net"
"net/netip"
)

// PopulateFromStringFunc populates a RecordConfig by parsing a common RFC1035-like format.
Expand Down Expand Up @@ -61,14 +61,14 @@ func (rc *RecordConfig) PopulateFromStringFunc(rtype, contents, origin string, t

switch rc.Type = rtype; rtype { // #rtype_variations
case "A":
ip := net.ParseIP(contents)
if ip == nil || ip.To4() == nil {
ip, err := netip.ParseAddr(contents)
if err != nil || !ip.Is4() {
return fmt.Errorf("invalid IP in A record: %s", contents)
}
return rc.SetTargetIP(ip) // Reformat to canonical form.
case "AAAA":
ip := net.ParseIP(contents)
if ip == nil || ip.To16() == nil {
ip, err := netip.ParseAddr(contents)
if err != nil || !ip.Is6() {
return fmt.Errorf("invalid IP in AAAA record: %s", contents)
}
return rc.SetTargetIP(ip) // Reformat to canonical form.
Expand Down Expand Up @@ -170,14 +170,14 @@ func (rc *RecordConfig) PopulateFromString(rtype, contents, origin string) error
}
switch rc.Type = rtype; rtype { // #rtype_variations
case "A":
ip := net.ParseIP(contents)
if ip == nil || ip.To4() == nil {
ip, err := netip.ParseAddr(contents)
if err != nil || !ip.Is4() {
return fmt.Errorf("invalid IP in A record: %s", contents)
}
return rc.SetTargetIP(ip) // Reformat to canonical form.
case "AAAA":
ip := net.ParseIP(contents)
if ip == nil || ip.To16() == nil {
ip, err := netip.ParseAddr(contents)
if err != nil || !ip.Is6() {
return fmt.Errorf("invalid IP in AAAA record: %s", contents)
}
return rc.SetTargetIP(ip) // Reformat to canonical form.
Expand Down
9 changes: 5 additions & 4 deletions models/target.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package models

import (
"fmt"
"net"
"net/netip"
"strings"

"github.com/StackExchange/dnscontrol/v4/pkg/txtutil"
Expand All @@ -21,11 +21,12 @@ func (rc *RecordConfig) GetTargetField() string {
}

// GetTargetIP returns the net.IP stored in .target.
func (rc *RecordConfig) GetTargetIP() net.IP {
func (rc *RecordConfig) GetTargetIP() netip.Addr {
if rc.Type != "A" && rc.Type != "AAAA" {
panic(fmt.Errorf("GetTargetIP called on an inappropriate rtype (%s)", rc.Type))
}
return net.ParseIP(rc.target)
ip, _ := netip.ParseAddr(rc.target)
return ip
}

// GetTargetCombinedFunc returns all the rdata fields of a RecordConfig as one
Expand Down Expand Up @@ -191,7 +192,7 @@ func (rc *RecordConfig) MustSetTarget(target string) {
}

// SetTargetIP sets the target to an IP, verifying this is an appropriate rtype.
func (rc *RecordConfig) SetTargetIP(ip net.IP) error {
func (rc *RecordConfig) SetTargetIP(ip netip.Addr) error {
// TODO(tlim): Verify the rtype is appropriate for an IP.
return rc.SetTarget(ip.String())
}
17 changes: 9 additions & 8 deletions pkg/normalize/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package normalize
import (
"errors"
"fmt"
"net"
"net/netip"
"slices"
"sort"
"strconv"
Expand All @@ -18,15 +18,15 @@ import (

// Returns false if target does not validate.
func checkIPv4(label string) error {
if net.ParseIP(label).To4() == nil {
if addr, err := netip.ParseAddr(label); err != nil || !addr.Is4() {
return fmt.Errorf("WARNING: target (%v) is not an IPv4 address", label)
}
return nil
}

// Returns false if target does not validate.
func checkIPv6(label string) error {
if net.ParseIP(label).To16() == nil {
if addr, err := netip.ParseAddr(label); err != nil || !addr.Is6() {
return fmt.Errorf("WARNING: target (%v) is not an IPv6 address", label)
}
return nil
Expand Down Expand Up @@ -308,7 +308,8 @@ func importTransform(srcDomain, dstDomain *models.DomainConfig,
}
switch rec.Type {
case "A":
trs, err := transform.IPToList(net.ParseIP(rec.GetTargetField()), transforms)
addr, _ := netip.ParseAddr(rec.GetTargetField())
trs, err := transform.IPToList(addr, transforms)
if err != nil {
return fmt.Errorf("import_transform: TransformIP(%v, %v) returned err=%w", rec.GetTargetField(), transforms, err)
}
Expand Down Expand Up @@ -453,7 +454,7 @@ func ValidateAndNormalizeConfig(config *models.DNSConfig) (errs []error) {
errs = append(errs, err)
}
} else if rec.Type == "A" || rec.Type == "AAAA" {
if err := rec.SetTarget(net.ParseIP(rec.GetTargetField()).String()); err != nil {
if err := rec.SetTargetIP(rec.GetTargetIP()); err != nil {
errs = append(errs, err)
}
} else if rec.Type == "PTR" {
Expand Down Expand Up @@ -889,13 +890,13 @@ func applyRecordTransforms(domain *models.DomainConfig) error {
if err != nil {
return err
}
ip := net.ParseIP(rec.GetTargetField()) // ip already validated above
newIPs, err := transform.IPToList(net.ParseIP(rec.GetTargetField()), table)
ip := rec.GetTargetIP()
newIPs, err := transform.IPToList(rec.GetTargetIP(), table)
if err != nil {
return err
}
for i, newIP := range newIPs {
if i == 0 && !newIP.Equal(ip) {
if i == 0 && newIP.Compare(ip) != 0 {
// replace target of first record if different
if err := rec.SetTarget(newIP.String()); err != nil {
return err
Expand Down
16 changes: 8 additions & 8 deletions pkg/prettyzone/sorting.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,18 +49,18 @@ func (z *ZoneGenData) Less(i, j int) bool {
switch a.Type { // #rtype_variations
case "A":
ta2, tb2 := a.GetTargetIP(), b.GetTargetIP()
ipa, ipb := ta2.To4(), tb2.To4()
if ipa == nil || ipb == nil {
log.Fatalf("should not happen: IPs are not 4 bytes: %#v %#v", ta2, tb2)
if !ta2.Is4() || !tb2.Is4() {
log.Fatalf("should not happen: Invalid IPv4 address: %s %s",
a.GetTargetIP().String(), b.GetTargetIP().String())
}
return bytes.Compare(ipa, ipb) == -1
return bytes.Compare(ta2.AsSlice(), tb2.AsSlice()) == -1
case "AAAA":
ta2, tb2 := a.GetTargetIP(), b.GetTargetIP()
ipa, ipb := ta2.To16(), tb2.To16()
if ipa == nil || ipb == nil {
log.Fatalf("should not happen: IPs are not 16 bytes: %#v %#v", ta2, tb2)
if !ta2.Is6() || !tb2.Is6() {
log.Fatalf("should not happen: Invalid IPv6 address: %s %s",
a.GetTargetIP().String(), b.GetTargetIP().String())
}
return bytes.Compare(ipa, ipb) == -1
return ta2.Compare(tb2) == -1
case "MX":
// sort by priority. If they are equal, sort by Mx.
if a.MxPreference == b.MxPreference {
Expand Down
2 changes: 1 addition & 1 deletion pkg/spflib/resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package spflib
import (
"encoding/json"
"fmt"
"net"
"net" // Not used for IP addresses.
"os"
"strings"
)
Expand Down
16 changes: 12 additions & 4 deletions pkg/transform/ptr.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ package transform

import (
"fmt"
"net"
"net" // Permitted import for using legacy net.CIDRMask and related functions.
"net/netip"
"regexp"
"strconv"
"strings"
Expand Down Expand Up @@ -35,8 +36,8 @@ func PtrNameMagic(name, domain string) (string, error) {

func ipv4magic(name, domain string) (string, error) {
// Not a valid IPv4 address. Leave it alone.
ip := net.ParseIP(name)
if ip == nil || ip.To4() == nil || !strings.Contains(name, ".") {
ip, err := netip.ParseAddr(name)
if err != nil || !ip.IsValid() || !ip.Is4() || !strings.Contains(name, ".") {
return name, nil
}

Expand Down Expand Up @@ -66,7 +67,14 @@ var isRfc4183Format3 = regexp.MustCompile(`(\d{1,3})-(\d{1,3})\.(\d{1,3})\.in-ad

// ipMatchesClasslessDomain returns true if ip is appropriate for domain.
// domain is a reverse DNS lookup zone (in-addr.arpa) as described in RFC2317.
func ipMatchesClasslessDomain(ip net.IP, domain string) int {
func ipMatchesClasslessDomain(ip_ netip.Addr, domain string) int {

// Converting netip.Addr to net.IP so we can use the legacy code, which is troublesome to translate.
// get Addr as []byte
s := ip_.AsSlice()
// convert bytes slice to net.IP type (it works as net.IP underlying type is also []byte so net.IP and []byte are identical)
ip := net.IP(s)

// The unofficial but preferred format in RFC2317:
m := isRfc2317Format1.FindStringSubmatch(domain)
if m != nil {
Expand Down
70 changes: 41 additions & 29 deletions pkg/transform/transform.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,33 +3,34 @@ package transform
import (
"errors"
"fmt"
"net"
"net/netip"
"strings"
)

// IPConversion describes an IP conversion.
type IPConversion struct {
Low, High net.IP
NewBases []net.IP
NewIPs []net.IP
Low, High netip.Addr
NewBases []netip.Addr
NewIPs []netip.Addr
}

func ipToUint(i net.IP) (uint32, error) {
parts := i.To4()
if parts == nil || len(parts) != 4 {
return 0, fmt.Errorf("%s is not an ipv4 address", parts.String())
func ipToUint(i netip.Addr) (uint32, error) {
if !i.Is4() {
return 0, fmt.Errorf("%s is not an ipv4 address", i.String())
}
parts := i.AsSlice()
r := uint32(parts[0])<<24 | uint32(parts[1])<<16 | uint32(parts[2])<<8 | uint32(parts[3])
return r, nil
}

// UintToIP convert a 32-bit into a net.IP.
func UintToIP(u uint32) net.IP {
return net.IPv4(
byte((u>>24)&255),
byte((u>>16)&255),
byte((u>>8)&255),
byte((u)&255))
// UintToIP convert a 32-bit into a netip.Addr.
func UintToIP(u uint32) netip.Addr {
return netip.AddrFrom4([4]byte{
byte((u >> 24) & 255),
byte((u >> 16) & 255),
byte((u >> 8) & 255),
byte((u) & 255),
})
}

// DecodeTransformTable turns a string-encoded table into a list of conversions.
Expand All @@ -45,25 +46,36 @@ func DecodeTransformTable(transforms string) ([]IPConversion, error) {
items[i] = strings.TrimSpace(item)
}

var err error
var tLow, tHigh netip.Addr
tLow, err = netip.ParseAddr(items[0])
if err != nil {
return nil, err
}
tHigh, err = netip.ParseAddr(items[1])
if err != nil {
return nil, err
}

con := IPConversion{
Low: net.ParseIP(items[0]),
High: net.ParseIP(items[1]),
Low: tLow,
High: tHigh,
}
parseList := func(s string) ([]net.IP, error) {
ips := []net.IP{}
parseList := func(s string) ([]netip.Addr, error) {
ips := []netip.Addr{}
for ip := range strings.SplitSeq(s, ",") {
if ip == "" {
continue
}
addr := net.ParseIP(ip)
if addr == nil {
return nil, fmt.Errorf("%s is not a valid ip address", ip)
addr, err := netip.ParseAddr(ip)
if err != nil {
return nil, err
}
ips = append(ips, addr)
}
return ips, nil
}
var err error
//var err error
if con.NewBases, err = parseList(items[2]); err != nil {
return nil, err
}
Expand All @@ -86,19 +98,19 @@ func DecodeTransformTable(transforms string) ([]IPConversion, error) {
}

// IP transforms a single ip address. If the transform results in multiple new targets, an error will be returned.
func IP(address net.IP, transforms []IPConversion) (net.IP, error) {
func IP(address netip.Addr, transforms []IPConversion) (netip.Addr, error) {
ips, err := IPToList(address, transforms)
if err != nil {
return nil, err
return netip.Addr{}, err
}
if len(ips) != 1 {
return nil, fmt.Errorf("exactly one IP expected. Got: %s", ips)
return netip.Addr{}, fmt.Errorf("exactly one IP expected. Got: %s", ips)
}
return ips[0], err
}

// IPToList manipulates an net.IP based on a list of IPConversions. It can potentially expand one ip address into multiple addresses.
func IPToList(address net.IP, transforms []IPConversion) ([]net.IP, error) {
func IPToList(address netip.Addr, transforms []IPConversion) ([]netip.Addr, error) {
thisIP, err := ipToUint(address)
if err != nil {
return nil, err
Expand All @@ -116,7 +128,7 @@ func IPToList(address net.IP, transforms []IPConversion) ([]net.IP, error) {
if len(conv.NewIPs) > 0 {
return conv.NewIPs, nil
}
list := []net.IP{}
list := []netip.Addr{}
for _, nb := range conv.NewBases {
newbase, err := ipToUint(nb)
if err != nil {
Expand All @@ -127,5 +139,5 @@ func IPToList(address net.IP, transforms []IPConversion) ([]net.IP, error) {
return list, nil
}
}
return []net.IP{address}, nil
return []netip.Addr{address}, nil
}
Loading
Loading