Add IsDuplicate function (#699)

The makes checking for duplicates more efficient, as you don't have to
use String() and re-parse elements from it anymore.

Fixes #679
This commit is contained in:
Miek Gieben 2018-06-23 09:12:31 +01:00 committed by GitHub
parent f90eb8fb45
commit df46691620
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 1188 additions and 0 deletions

25
duplicate.go Normal file
View File

@ -0,0 +1,25 @@
package dns
//go:generate go run duplicate_generate.go
// IsDuplicate checks of r1 and r2 are duplicates of each other, excluding the TTL.
// So this means the header data is equal *and* the RDATA is the same. Return true
// is so, otherwise false.
// It's is a protocol violation to have identical RRs in a message.
func IsDuplicate(r1, r2 RR) bool {
if r1.Header().Class != r2.Header().Class {
return false
}
if r1.Header().Rrtype != r2.Header().Rrtype {
return false
}
if !isDulicateName(r1.Header().Name, r2.Header().Name) {
return false
}
// ignore TTL
return isDuplicateRdata(r1, r2)
}
// isDulicateName checks if the domain names s1 and s2 are equal.
func isDulicateName(s1, s2 string) bool { return equal(s1, s2) }

158
duplicate_generate.go Normal file
View File

@ -0,0 +1,158 @@
//+build ignore
// types_generate.go is meant to run with go generate. It will use
// go/{importer,types} to track down all the RR struct types. Then for each type
// it will generate conversion tables (TypeToRR and TypeToString) and banal
// methods (len, Header, copy) based on the struct tags. The generated source is
// written to ztypes.go, and is meant to be checked into git.
package main
import (
"bytes"
"fmt"
"go/format"
"go/importer"
"go/types"
"log"
"os"
)
var packageHdr = `
// Code generated by "go run duplicate_generate.go"; DO NOT EDIT.
package dns
`
func getTypeStruct(t types.Type, scope *types.Scope) (*types.Struct, bool) {
st, ok := t.Underlying().(*types.Struct)
if !ok {
return nil, false
}
if st.Field(0).Type() == scope.Lookup("RR_Header").Type() {
return st, false
}
if st.Field(0).Anonymous() {
st, _ := getTypeStruct(st.Field(0).Type(), scope)
return st, true
}
return nil, false
}
func main() {
// Import and type-check the package
pkg, err := importer.Default().Import("github.com/miekg/dns")
fatalIfErr(err)
scope := pkg.Scope()
// Collect actual types (*X)
var namedTypes []string
for _, name := range scope.Names() {
o := scope.Lookup(name)
if o == nil || !o.Exported() {
continue
}
if st, _ := getTypeStruct(o.Type(), scope); st == nil {
continue
}
if name == "PrivateRR" || name == "RFC3597" {
continue
}
if name == "OPT" || name == "ANY" || name == "IXFR" || name == "AXFR" {
continue
}
namedTypes = append(namedTypes, o.Name())
}
b := &bytes.Buffer{}
b.WriteString(packageHdr)
// Generate the giant switch that calls the correct function for each type.
fmt.Fprint(b, "// isDuplicateRdata calls the rdata specific functions\n")
fmt.Fprint(b, "func isDuplicateRdata(r1, r2 RR) bool {\n")
fmt.Fprint(b, "switch r1.Header().Rrtype {\n")
for _, name := range namedTypes {
o := scope.Lookup(name)
_, isEmbedded := getTypeStruct(o.Type(), scope)
if isEmbedded {
continue
}
fmt.Fprintf(b, "case Type%s:\nreturn isDuplicate%s(r1.(*%s), r2.(*%s))\n", name, name, name, name)
}
fmt.Fprintf(b, "}\nreturn false\n}\n")
// Generate the duplicate check for each type.
fmt.Fprint(b, "// isDuplicate() functions\n\n")
for _, name := range namedTypes {
o := scope.Lookup(name)
st, isEmbedded := getTypeStruct(o.Type(), scope)
if isEmbedded {
continue
}
fmt.Fprintf(b, "func isDuplicate%s(r1, r2 *%s) bool {\n", name, name)
for i := 1; i < st.NumFields(); i++ {
field := st.Field(i).Name()
o2 := func(s string) { fmt.Fprintf(b, s+"\n", field, field) }
o3 := func(s string) { fmt.Fprintf(b, s+"\n", field, field, field) }
// For some reason, a and aaaa don't pop up as *types.Slice here (mostly like because the are
// *indirectly* defined as a slice in the net package).
if _, ok := st.Field(i).Type().(*types.Slice); ok || st.Tag(i) == `dns:"a"` || st.Tag(i) == `dns:"aaaa"` {
o2("if len(r1.%s) != len(r2.%s) {\nreturn false\n}")
if st.Tag(i) == `dns:"cdomain-name"` || st.Tag(i) == `dns:"domain-name"` {
o3(`for i := 0; i < len(r1.%s); i++ {
if !isDulicateName(r1.%s[i], r2.%s[i]) {
return false
}
}`)
continue
}
o3(`for i := 0; i < len(r1.%s); i++ {
if r1.%s[i] != r2.%s[i] {
return false
}
}`)
continue
}
switch st.Tag(i) {
case `dns:"-"`:
// ignored
case `dns:"cdomain-name"`, `dns:"domain-name"`:
o2("if !isDulicateName(r1.%s, r2.%s) {\nreturn false\n}")
default:
o2("if r1.%s != r2.%s {\nreturn false\n}")
}
}
fmt.Fprintf(b, "return true\n}\n\n")
}
// gofmt
res, err := format.Source(b.Bytes())
if err != nil {
b.WriteTo(os.Stderr)
log.Fatal(err)
}
// write result
f, err := os.Create("zduplicate.go")
fatalIfErr(err)
defer f.Close()
f.Write(res)
}
func fatalIfErr(err error) {
if err != nil {
log.Fatal(err)
}
}

61
duplicate_test.go Normal file
View File

@ -0,0 +1,61 @@
package dns
import "testing"
func TestDuplicateA(t *testing.T) {
a1, _ := NewRR("www.example.org. 2700 IN A 127.0.0.1")
a2, _ := NewRR("www.example.org. IN A 127.0.0.1")
if !IsDuplicate(a1, a2) {
t.Errorf("expected %s/%s to be duplicates, but got false", a1.String(), a2.String())
}
a2, _ = NewRR("www.example.org. IN A 127.0.0.2")
if IsDuplicate(a1, a2) {
t.Errorf("expected %s/%s not to be duplicates, but got true", a1.String(), a2.String())
}
}
func TestDuplicateTXT(t *testing.T) {
a1, _ := NewRR("www.example.org. IN TXT \"aa\"")
a2, _ := NewRR("www.example.org. IN TXT \"aa\"")
if !IsDuplicate(a1, a2) {
t.Errorf("expected %s/%s to be duplicates, but got false", a1.String(), a2.String())
}
a2, _ = NewRR("www.example.org. IN TXT \"aa\" \"bb\"")
if IsDuplicate(a1, a2) {
t.Errorf("expected %s/%s not to be duplicates, but got true", a1.String(), a2.String())
}
a1, _ = NewRR("www.example.org. IN TXT \"aa\" \"bc\"")
if IsDuplicate(a1, a2) {
t.Errorf("expected %s/%s not to be duplicates, but got true", a1.String(), a2.String())
}
}
func TestDuplicateOwner(t *testing.T) {
a1, _ := NewRR("www.example.org. IN A 127.0.0.1")
a2, _ := NewRR("www.example.org. IN A 127.0.0.1")
if !IsDuplicate(a1, a2) {
t.Errorf("expected %s/%s to be duplicates, but got false", a1.String(), a2.String())
}
a2, _ = NewRR("WWw.exaMPle.org. IN A 127.0.0.2")
if IsDuplicate(a1, a2) {
t.Errorf("expected %s/%s to be duplicates, but got false", a1.String(), a2.String())
}
}
func TestDuplicateDomain(t *testing.T) {
a1, _ := NewRR("www.example.org. IN CNAME example.org.")
a2, _ := NewRR("www.example.org. IN CNAME example.org.")
if !IsDuplicate(a1, a2) {
t.Errorf("expected %s/%s to be duplicates, but got false", a1.String(), a2.String())
}
a2, _ = NewRR("www.example.org. IN CNAME exAMPLe.oRG.")
if !IsDuplicate(a1, a2) {
t.Errorf("expected %s/%s to be duplicates, but got false", a1.String(), a2.String())
}
}

View File

@ -5,6 +5,7 @@ package dns
// rrs.
// m is used to store the RRs temporary. If it is nil a new map will be allocated.
func Dedup(rrs []RR, m map[string]RR) []RR {
if m == nil {
m = make(map[string]RR)
}

943
zduplicate.go Normal file
View File

@ -0,0 +1,943 @@
// Code generated by "go run duplicate_generate.go"; DO NOT EDIT.
package dns
// isDuplicateRdata calls the rdata specific functions
func isDuplicateRdata(r1, r2 RR) bool {
switch r1.Header().Rrtype {
case TypeA:
return isDuplicateA(r1.(*A), r2.(*A))
case TypeAAAA:
return isDuplicateAAAA(r1.(*AAAA), r2.(*AAAA))
case TypeAFSDB:
return isDuplicateAFSDB(r1.(*AFSDB), r2.(*AFSDB))
case TypeAVC:
return isDuplicateAVC(r1.(*AVC), r2.(*AVC))
case TypeCAA:
return isDuplicateCAA(r1.(*CAA), r2.(*CAA))
case TypeCERT:
return isDuplicateCERT(r1.(*CERT), r2.(*CERT))
case TypeCNAME:
return isDuplicateCNAME(r1.(*CNAME), r2.(*CNAME))
case TypeCSYNC:
return isDuplicateCSYNC(r1.(*CSYNC), r2.(*CSYNC))
case TypeDHCID:
return isDuplicateDHCID(r1.(*DHCID), r2.(*DHCID))
case TypeDNAME:
return isDuplicateDNAME(r1.(*DNAME), r2.(*DNAME))
case TypeDNSKEY:
return isDuplicateDNSKEY(r1.(*DNSKEY), r2.(*DNSKEY))
case TypeDS:
return isDuplicateDS(r1.(*DS), r2.(*DS))
case TypeEID:
return isDuplicateEID(r1.(*EID), r2.(*EID))
case TypeEUI48:
return isDuplicateEUI48(r1.(*EUI48), r2.(*EUI48))
case TypeEUI64:
return isDuplicateEUI64(r1.(*EUI64), r2.(*EUI64))
case TypeGID:
return isDuplicateGID(r1.(*GID), r2.(*GID))
case TypeGPOS:
return isDuplicateGPOS(r1.(*GPOS), r2.(*GPOS))
case TypeHINFO:
return isDuplicateHINFO(r1.(*HINFO), r2.(*HINFO))
case TypeHIP:
return isDuplicateHIP(r1.(*HIP), r2.(*HIP))
case TypeKX:
return isDuplicateKX(r1.(*KX), r2.(*KX))
case TypeL32:
return isDuplicateL32(r1.(*L32), r2.(*L32))
case TypeL64:
return isDuplicateL64(r1.(*L64), r2.(*L64))
case TypeLOC:
return isDuplicateLOC(r1.(*LOC), r2.(*LOC))
case TypeLP:
return isDuplicateLP(r1.(*LP), r2.(*LP))
case TypeMB:
return isDuplicateMB(r1.(*MB), r2.(*MB))
case TypeMD:
return isDuplicateMD(r1.(*MD), r2.(*MD))
case TypeMF:
return isDuplicateMF(r1.(*MF), r2.(*MF))
case TypeMG:
return isDuplicateMG(r1.(*MG), r2.(*MG))
case TypeMINFO:
return isDuplicateMINFO(r1.(*MINFO), r2.(*MINFO))
case TypeMR:
return isDuplicateMR(r1.(*MR), r2.(*MR))
case TypeMX:
return isDuplicateMX(r1.(*MX), r2.(*MX))
case TypeNAPTR:
return isDuplicateNAPTR(r1.(*NAPTR), r2.(*NAPTR))
case TypeNID:
return isDuplicateNID(r1.(*NID), r2.(*NID))
case TypeNIMLOC:
return isDuplicateNIMLOC(r1.(*NIMLOC), r2.(*NIMLOC))
case TypeNINFO:
return isDuplicateNINFO(r1.(*NINFO), r2.(*NINFO))
case TypeNS:
return isDuplicateNS(r1.(*NS), r2.(*NS))
case TypeNSAPPTR:
return isDuplicateNSAPPTR(r1.(*NSAPPTR), r2.(*NSAPPTR))
case TypeNSEC:
return isDuplicateNSEC(r1.(*NSEC), r2.(*NSEC))
case TypeNSEC3:
return isDuplicateNSEC3(r1.(*NSEC3), r2.(*NSEC3))
case TypeNSEC3PARAM:
return isDuplicateNSEC3PARAM(r1.(*NSEC3PARAM), r2.(*NSEC3PARAM))
case TypeOPENPGPKEY:
return isDuplicateOPENPGPKEY(r1.(*OPENPGPKEY), r2.(*OPENPGPKEY))
case TypePTR:
return isDuplicatePTR(r1.(*PTR), r2.(*PTR))
case TypePX:
return isDuplicatePX(r1.(*PX), r2.(*PX))
case TypeRKEY:
return isDuplicateRKEY(r1.(*RKEY), r2.(*RKEY))
case TypeRP:
return isDuplicateRP(r1.(*RP), r2.(*RP))
case TypeRRSIG:
return isDuplicateRRSIG(r1.(*RRSIG), r2.(*RRSIG))
case TypeRT:
return isDuplicateRT(r1.(*RT), r2.(*RT))
case TypeSMIMEA:
return isDuplicateSMIMEA(r1.(*SMIMEA), r2.(*SMIMEA))
case TypeSOA:
return isDuplicateSOA(r1.(*SOA), r2.(*SOA))
case TypeSPF:
return isDuplicateSPF(r1.(*SPF), r2.(*SPF))
case TypeSRV:
return isDuplicateSRV(r1.(*SRV), r2.(*SRV))
case TypeSSHFP:
return isDuplicateSSHFP(r1.(*SSHFP), r2.(*SSHFP))
case TypeTA:
return isDuplicateTA(r1.(*TA), r2.(*TA))
case TypeTALINK:
return isDuplicateTALINK(r1.(*TALINK), r2.(*TALINK))
case TypeTKEY:
return isDuplicateTKEY(r1.(*TKEY), r2.(*TKEY))
case TypeTLSA:
return isDuplicateTLSA(r1.(*TLSA), r2.(*TLSA))
case TypeTSIG:
return isDuplicateTSIG(r1.(*TSIG), r2.(*TSIG))
case TypeTXT:
return isDuplicateTXT(r1.(*TXT), r2.(*TXT))
case TypeUID:
return isDuplicateUID(r1.(*UID), r2.(*UID))
case TypeUINFO:
return isDuplicateUINFO(r1.(*UINFO), r2.(*UINFO))
case TypeURI:
return isDuplicateURI(r1.(*URI), r2.(*URI))
case TypeX25:
return isDuplicateX25(r1.(*X25), r2.(*X25))
}
return false
}
// isDuplicate() functions
func isDuplicateA(r1, r2 *A) bool {
if len(r1.A) != len(r2.A) {
return false
}
for i := 0; i < len(r1.A); i++ {
if r1.A[i] != r2.A[i] {
return false
}
}
return true
}
func isDuplicateAAAA(r1, r2 *AAAA) bool {
if len(r1.AAAA) != len(r2.AAAA) {
return false
}
for i := 0; i < len(r1.AAAA); i++ {
if r1.AAAA[i] != r2.AAAA[i] {
return false
}
}
return true
}
func isDuplicateAFSDB(r1, r2 *AFSDB) bool {
if r1.Subtype != r2.Subtype {
return false
}
if !isDulicateName(r1.Hostname, r2.Hostname) {
return false
}
return true
}
func isDuplicateAVC(r1, r2 *AVC) bool {
if len(r1.Txt) != len(r2.Txt) {
return false
}
for i := 0; i < len(r1.Txt); i++ {
if r1.Txt[i] != r2.Txt[i] {
return false
}
}
return true
}
func isDuplicateCAA(r1, r2 *CAA) bool {
if r1.Flag != r2.Flag {
return false
}
if r1.Tag != r2.Tag {
return false
}
if r1.Value != r2.Value {
return false
}
return true
}
func isDuplicateCERT(r1, r2 *CERT) bool {
if r1.Type != r2.Type {
return false
}
if r1.KeyTag != r2.KeyTag {
return false
}
if r1.Algorithm != r2.Algorithm {
return false
}
if r1.Certificate != r2.Certificate {
return false
}
return true
}
func isDuplicateCNAME(r1, r2 *CNAME) bool {
if !isDulicateName(r1.Target, r2.Target) {
return false
}
return true
}
func isDuplicateCSYNC(r1, r2 *CSYNC) bool {
if r1.Serial != r2.Serial {
return false
}
if r1.Flags != r2.Flags {
return false
}
if len(r1.TypeBitMap) != len(r2.TypeBitMap) {
return false
}
for i := 0; i < len(r1.TypeBitMap); i++ {
if r1.TypeBitMap[i] != r2.TypeBitMap[i] {
return false
}
}
return true
}
func isDuplicateDHCID(r1, r2 *DHCID) bool {
if r1.Digest != r2.Digest {
return false
}
return true
}
func isDuplicateDNAME(r1, r2 *DNAME) bool {
if !isDulicateName(r1.Target, r2.Target) {
return false
}
return true
}
func isDuplicateDNSKEY(r1, r2 *DNSKEY) bool {
if r1.Flags != r2.Flags {
return false
}
if r1.Protocol != r2.Protocol {
return false
}
if r1.Algorithm != r2.Algorithm {
return false
}
if r1.PublicKey != r2.PublicKey {
return false
}
return true
}
func isDuplicateDS(r1, r2 *DS) bool {
if r1.KeyTag != r2.KeyTag {
return false
}
if r1.Algorithm != r2.Algorithm {
return false
}
if r1.DigestType != r2.DigestType {
return false
}
if r1.Digest != r2.Digest {
return false
}
return true
}
func isDuplicateEID(r1, r2 *EID) bool {
if r1.Endpoint != r2.Endpoint {
return false
}
return true
}
func isDuplicateEUI48(r1, r2 *EUI48) bool {
if r1.Address != r2.Address {
return false
}
return true
}
func isDuplicateEUI64(r1, r2 *EUI64) bool {
if r1.Address != r2.Address {
return false
}
return true
}
func isDuplicateGID(r1, r2 *GID) bool {
if r1.Gid != r2.Gid {
return false
}
return true
}
func isDuplicateGPOS(r1, r2 *GPOS) bool {
if r1.Longitude != r2.Longitude {
return false
}
if r1.Latitude != r2.Latitude {
return false
}
if r1.Altitude != r2.Altitude {
return false
}
return true
}
func isDuplicateHINFO(r1, r2 *HINFO) bool {
if r1.Cpu != r2.Cpu {
return false
}
if r1.Os != r2.Os {
return false
}
return true
}
func isDuplicateHIP(r1, r2 *HIP) bool {
if r1.HitLength != r2.HitLength {
return false
}
if r1.PublicKeyAlgorithm != r2.PublicKeyAlgorithm {
return false
}
if r1.PublicKeyLength != r2.PublicKeyLength {
return false
}
if r1.Hit != r2.Hit {
return false
}
if r1.PublicKey != r2.PublicKey {
return false
}
if len(r1.RendezvousServers) != len(r2.RendezvousServers) {
return false
}
for i := 0; i < len(r1.RendezvousServers); i++ {
if !isDulicateName(r1.RendezvousServers[i], r2.RendezvousServers[i]) {
return false
}
}
return true
}
func isDuplicateKX(r1, r2 *KX) bool {
if r1.Preference != r2.Preference {
return false
}
if !isDulicateName(r1.Exchanger, r2.Exchanger) {
return false
}
return true
}
func isDuplicateL32(r1, r2 *L32) bool {
if r1.Preference != r2.Preference {
return false
}
if len(r1.Locator32) != len(r2.Locator32) {
return false
}
for i := 0; i < len(r1.Locator32); i++ {
if r1.Locator32[i] != r2.Locator32[i] {
return false
}
}
return true
}
func isDuplicateL64(r1, r2 *L64) bool {
if r1.Preference != r2.Preference {
return false
}
if r1.Locator64 != r2.Locator64 {
return false
}
return true
}
func isDuplicateLOC(r1, r2 *LOC) bool {
if r1.Version != r2.Version {
return false
}
if r1.Size != r2.Size {
return false
}
if r1.HorizPre != r2.HorizPre {
return false
}
if r1.VertPre != r2.VertPre {
return false
}
if r1.Latitude != r2.Latitude {
return false
}
if r1.Longitude != r2.Longitude {
return false
}
if r1.Altitude != r2.Altitude {
return false
}
return true
}
func isDuplicateLP(r1, r2 *LP) bool {
if r1.Preference != r2.Preference {
return false
}
if !isDulicateName(r1.Fqdn, r2.Fqdn) {
return false
}
return true
}
func isDuplicateMB(r1, r2 *MB) bool {
if !isDulicateName(r1.Mb, r2.Mb) {
return false
}
return true
}
func isDuplicateMD(r1, r2 *MD) bool {
if !isDulicateName(r1.Md, r2.Md) {
return false
}
return true
}
func isDuplicateMF(r1, r2 *MF) bool {
if !isDulicateName(r1.Mf, r2.Mf) {
return false
}
return true
}
func isDuplicateMG(r1, r2 *MG) bool {
if !isDulicateName(r1.Mg, r2.Mg) {
return false
}
return true
}
func isDuplicateMINFO(r1, r2 *MINFO) bool {
if !isDulicateName(r1.Rmail, r2.Rmail) {
return false
}
if !isDulicateName(r1.Email, r2.Email) {
return false
}
return true
}
func isDuplicateMR(r1, r2 *MR) bool {
if !isDulicateName(r1.Mr, r2.Mr) {
return false
}
return true
}
func isDuplicateMX(r1, r2 *MX) bool {
if r1.Preference != r2.Preference {
return false
}
if !isDulicateName(r1.Mx, r2.Mx) {
return false
}
return true
}
func isDuplicateNAPTR(r1, r2 *NAPTR) bool {
if r1.Order != r2.Order {
return false
}
if r1.Preference != r2.Preference {
return false
}
if r1.Flags != r2.Flags {
return false
}
if r1.Service != r2.Service {
return false
}
if r1.Regexp != r2.Regexp {
return false
}
if !isDulicateName(r1.Replacement, r2.Replacement) {
return false
}
return true
}
func isDuplicateNID(r1, r2 *NID) bool {
if r1.Preference != r2.Preference {
return false
}
if r1.NodeID != r2.NodeID {
return false
}
return true
}
func isDuplicateNIMLOC(r1, r2 *NIMLOC) bool {
if r1.Locator != r2.Locator {
return false
}
return true
}
func isDuplicateNINFO(r1, r2 *NINFO) bool {
if len(r1.ZSData) != len(r2.ZSData) {
return false
}
for i := 0; i < len(r1.ZSData); i++ {
if r1.ZSData[i] != r2.ZSData[i] {
return false
}
}
return true
}
func isDuplicateNS(r1, r2 *NS) bool {
if !isDulicateName(r1.Ns, r2.Ns) {
return false
}
return true
}
func isDuplicateNSAPPTR(r1, r2 *NSAPPTR) bool {
if !isDulicateName(r1.Ptr, r2.Ptr) {
return false
}
return true
}
func isDuplicateNSEC(r1, r2 *NSEC) bool {
if !isDulicateName(r1.NextDomain, r2.NextDomain) {
return false
}
if len(r1.TypeBitMap) != len(r2.TypeBitMap) {
return false
}
for i := 0; i < len(r1.TypeBitMap); i++ {
if r1.TypeBitMap[i] != r2.TypeBitMap[i] {
return false
}
}
return true
}
func isDuplicateNSEC3(r1, r2 *NSEC3) bool {
if r1.Hash != r2.Hash {
return false
}
if r1.Flags != r2.Flags {
return false
}
if r1.Iterations != r2.Iterations {
return false
}
if r1.SaltLength != r2.SaltLength {
return false
}
if r1.Salt != r2.Salt {
return false
}
if r1.HashLength != r2.HashLength {
return false
}
if r1.NextDomain != r2.NextDomain {
return false
}
if len(r1.TypeBitMap) != len(r2.TypeBitMap) {
return false
}
for i := 0; i < len(r1.TypeBitMap); i++ {
if r1.TypeBitMap[i] != r2.TypeBitMap[i] {
return false
}
}
return true
}
func isDuplicateNSEC3PARAM(r1, r2 *NSEC3PARAM) bool {
if r1.Hash != r2.Hash {
return false
}
if r1.Flags != r2.Flags {
return false
}
if r1.Iterations != r2.Iterations {
return false
}
if r1.SaltLength != r2.SaltLength {
return false
}
if r1.Salt != r2.Salt {
return false
}
return true
}
func isDuplicateOPENPGPKEY(r1, r2 *OPENPGPKEY) bool {
if r1.PublicKey != r2.PublicKey {
return false
}
return true
}
func isDuplicatePTR(r1, r2 *PTR) bool {
if !isDulicateName(r1.Ptr, r2.Ptr) {
return false
}
return true
}
func isDuplicatePX(r1, r2 *PX) bool {
if r1.Preference != r2.Preference {
return false
}
if !isDulicateName(r1.Map822, r2.Map822) {
return false
}
if !isDulicateName(r1.Mapx400, r2.Mapx400) {
return false
}
return true
}
func isDuplicateRKEY(r1, r2 *RKEY) bool {
if r1.Flags != r2.Flags {
return false
}
if r1.Protocol != r2.Protocol {
return false
}
if r1.Algorithm != r2.Algorithm {
return false
}
if r1.PublicKey != r2.PublicKey {
return false
}
return true
}
func isDuplicateRP(r1, r2 *RP) bool {
if !isDulicateName(r1.Mbox, r2.Mbox) {
return false
}
if !isDulicateName(r1.Txt, r2.Txt) {
return false
}
return true
}
func isDuplicateRRSIG(r1, r2 *RRSIG) bool {
if r1.TypeCovered != r2.TypeCovered {
return false
}
if r1.Algorithm != r2.Algorithm {
return false
}
if r1.Labels != r2.Labels {
return false
}
if r1.OrigTtl != r2.OrigTtl {
return false
}
if r1.Expiration != r2.Expiration {
return false
}
if r1.Inception != r2.Inception {
return false
}
if r1.KeyTag != r2.KeyTag {
return false
}
if !isDulicateName(r1.SignerName, r2.SignerName) {
return false
}
if r1.Signature != r2.Signature {
return false
}
return true
}
func isDuplicateRT(r1, r2 *RT) bool {
if r1.Preference != r2.Preference {
return false
}
if !isDulicateName(r1.Host, r2.Host) {
return false
}
return true
}
func isDuplicateSMIMEA(r1, r2 *SMIMEA) bool {
if r1.Usage != r2.Usage {
return false
}
if r1.Selector != r2.Selector {
return false
}
if r1.MatchingType != r2.MatchingType {
return false
}
if r1.Certificate != r2.Certificate {
return false
}
return true
}
func isDuplicateSOA(r1, r2 *SOA) bool {
if !isDulicateName(r1.Ns, r2.Ns) {
return false
}
if !isDulicateName(r1.Mbox, r2.Mbox) {
return false
}
if r1.Serial != r2.Serial {
return false
}
if r1.Refresh != r2.Refresh {
return false
}
if r1.Retry != r2.Retry {
return false
}
if r1.Expire != r2.Expire {
return false
}
if r1.Minttl != r2.Minttl {
return false
}
return true
}
func isDuplicateSPF(r1, r2 *SPF) bool {
if len(r1.Txt) != len(r2.Txt) {
return false
}
for i := 0; i < len(r1.Txt); i++ {
if r1.Txt[i] != r2.Txt[i] {
return false
}
}
return true
}
func isDuplicateSRV(r1, r2 *SRV) bool {
if r1.Priority != r2.Priority {
return false
}
if r1.Weight != r2.Weight {
return false
}
if r1.Port != r2.Port {
return false
}
if !isDulicateName(r1.Target, r2.Target) {
return false
}
return true
}
func isDuplicateSSHFP(r1, r2 *SSHFP) bool {
if r1.Algorithm != r2.Algorithm {
return false
}
if r1.Type != r2.Type {
return false
}
if r1.FingerPrint != r2.FingerPrint {
return false
}
return true
}
func isDuplicateTA(r1, r2 *TA) bool {
if r1.KeyTag != r2.KeyTag {
return false
}
if r1.Algorithm != r2.Algorithm {
return false
}
if r1.DigestType != r2.DigestType {
return false
}
if r1.Digest != r2.Digest {
return false
}
return true
}
func isDuplicateTALINK(r1, r2 *TALINK) bool {
if !isDulicateName(r1.PreviousName, r2.PreviousName) {
return false
}
if !isDulicateName(r1.NextName, r2.NextName) {
return false
}
return true
}
func isDuplicateTKEY(r1, r2 *TKEY) bool {
if !isDulicateName(r1.Algorithm, r2.Algorithm) {
return false
}
if r1.Inception != r2.Inception {
return false
}
if r1.Expiration != r2.Expiration {
return false
}
if r1.Mode != r2.Mode {
return false
}
if r1.Error != r2.Error {
return false
}
if r1.KeySize != r2.KeySize {
return false
}
if r1.Key != r2.Key {
return false
}
if r1.OtherLen != r2.OtherLen {
return false
}
if r1.OtherData != r2.OtherData {
return false
}
return true
}
func isDuplicateTLSA(r1, r2 *TLSA) bool {
if r1.Usage != r2.Usage {
return false
}
if r1.Selector != r2.Selector {
return false
}
if r1.MatchingType != r2.MatchingType {
return false
}
if r1.Certificate != r2.Certificate {
return false
}
return true
}
func isDuplicateTSIG(r1, r2 *TSIG) bool {
if !isDulicateName(r1.Algorithm, r2.Algorithm) {
return false
}
if r1.TimeSigned != r2.TimeSigned {
return false
}
if r1.Fudge != r2.Fudge {
return false
}
if r1.MACSize != r2.MACSize {
return false
}
if r1.MAC != r2.MAC {
return false
}
if r1.OrigId != r2.OrigId {
return false
}
if r1.Error != r2.Error {
return false
}
if r1.OtherLen != r2.OtherLen {
return false
}
if r1.OtherData != r2.OtherData {
return false
}
return true
}
func isDuplicateTXT(r1, r2 *TXT) bool {
if len(r1.Txt) != len(r2.Txt) {
return false
}
for i := 0; i < len(r1.Txt); i++ {
if r1.Txt[i] != r2.Txt[i] {
return false
}
}
return true
}
func isDuplicateUID(r1, r2 *UID) bool {
if r1.Uid != r2.Uid {
return false
}
return true
}
func isDuplicateUINFO(r1, r2 *UINFO) bool {
if r1.Uinfo != r2.Uinfo {
return false
}
return true
}
func isDuplicateURI(r1, r2 *URI) bool {
if r1.Priority != r2.Priority {
return false
}
if r1.Weight != r2.Weight {
return false
}
if r1.Target != r2.Target {
return false
}
return true
}
func isDuplicateX25(r1, r2 *X25) bool {
if r1.PSDNAddress != r2.PSDNAddress {
return false
}
return true
}