Repository: miekg/dns
Pull request #1471 (2023-07-05 13:35:29)

readme: add sdns to users
Before `sdns` was added to users list but deleted some reasons. I read the reasons but the project never be selling anything nor nxdomain/404. That was described like that on https://github.com/miekg/dns/commit/68df4402de4a2303c8dad5aea62450485d589d81

Could you please check and add again? 

Thanks.



Patch:
diff --git a/README.md b/README.md
index 06bea9fa..95bc08d5 100644
--- a/README.md
+++ b/README.md
@@ -81,6 +81,7 @@ A not-so-up-to-date-list-that-may-be-actually-current:
 * https://addr.tools/
 * https://dnscheck.tools/
 * https://github.com/egbakou/domainverifier
+* https://github.com/semihalev/sdns
 
 
 Send pull request if you want to be listed here.
diff --git a/msg.go b/msg.go
index d5049a4f..b05cf14e 100644
--- a/msg.go
+++ b/msg.go
@@ -896,23 +896,38 @@ func (dns *Msg) String() string {
 		return "<nil> MsgHdr"
 	}
 	s := dns.MsgHdr.String() + " "
-	s += "QUERY: " + strconv.Itoa(len(dns.Question)) + ", "
-	s += "ANSWER: " + strconv.Itoa(len(dns.Answer)) + ", "
-	s += "AUTHORITY: " + strconv.Itoa(len(dns.Ns)) + ", "
-	s += "ADDITIONAL: " + strconv.Itoa(len(dns.Extra)) + "\n"
+	if dns.MsgHdr.Opcode == OpcodeUpdate {
+		s += "ZONE: " + strconv.Itoa(len(dns.Question)) + ", "
+		s += "PREREQ: " + strconv.Itoa(len(dns.Answer)) + ", "
+		s += "UPDATE: " + strconv.Itoa(len(dns.Ns)) + ", "
+		s += "ADDITIONAL: " + strconv.Itoa(len(dns.Extra)) + "\n"
+	} else {
+		s += "QUERY: " + strconv.Itoa(len(dns.Question)) + ", "
+		s += "ANSWER: " + strconv.Itoa(len(dns.Answer)) + ", "
+		s += "AUTHORITY: " + strconv.Itoa(len(dns.Ns)) + ", "
+		s += "ADDITIONAL: " + strconv.Itoa(len(dns.Extra)) + "\n"
+	}
 	opt := dns.IsEdns0()
 	if opt != nil {
 		// OPT PSEUDOSECTION
 		s += opt.String() + "\n"
 	}
 	if len(dns.Question) > 0 {
-		s += "\n;; QUESTION SECTION:\n"
+		if dns.MsgHdr.Opcode == OpcodeUpdate {
+			s += "\n;; ZONE SECTION:\n"
+		} else {
+			s += "\n;; QUESTION SECTION:\n"
+		}
 		for _, r := range dns.Question {
 			s += r.String() + "\n"
 		}
 	}
 	if len(dns.Answer) > 0 {
-		s += "\n;; ANSWER SECTION:\n"
+		if dns.MsgHdr.Opcode == OpcodeUpdate {
+			s += "\n;; PREREQUISITE SECTION:\n"
+		} else {
+			s += "\n;; ANSWER SECTION:\n"
+		}
 		for _, r := range dns.Answer {
 			if r != nil {
 				s += r.String() + "\n"
@@ -920,7 +935,11 @@ func (dns *Msg) String() string {
 		}
 	}
 	if len(dns.Ns) > 0 {
-		s += "\n;; AUTHORITY SECTION:\n"
+		if dns.MsgHdr.Opcode == OpcodeUpdate {
+			s += "\n;; UPDATE SECTION:\n"
+		} else {
+			s += "\n;; AUTHORITY SECTION:\n"
+		}
 		for _, r := range dns.Ns {
 			if r != nil {
 				s += r.String() + "\n"
diff --git a/types.go b/types.go
index 03afeccd..c9a03dec 100644
--- a/types.go
+++ b/types.go
@@ -236,6 +236,9 @@ var CertTypeToString = map[uint16]string{
 	CertOID:     "OID",
 }
 
+// Prefix for IPv4 encoded as IPv6 address
+const ipv4InIPv6Prefix = "::ffff:"
+
 //go:generate go run types_generate.go
 
 // Question holds a DNS question. Usually there is just one. While the
@@ -751,6 +754,11 @@ func (rr *AAAA) String() string {
 	if rr.AAAA == nil {
 		return rr.Hdr.String()
 	}
+
+	if rr.AAAA.To4() != nil {
+		return rr.Hdr.String() + ipv4InIPv6Prefix + rr.AAAA.String()
+	}
+
 	return rr.Hdr.String() + rr.AAAA.String()
 }
 
@@ -1517,7 +1525,7 @@ func (a *APLPrefix) str() string {
 	case net.IPv6len:
 		// add prefix for IPv4-mapped IPv6
 		if v4 := a.Network.IP.To4(); v4 != nil {
-			sb.WriteString("::ffff:")
+			sb.WriteString(ipv4InIPv6Prefix)
 		}
 		sb.WriteString(a.Network.IP.String())
 	}


Test patch:
diff --git a/parse_test.go b/parse_test.go
index 364e7be4..0096e004 100644
--- a/parse_test.go
+++ b/parse_test.go
@@ -1686,6 +1686,33 @@ func TestNULLRecord(t *testing.T) {
 		t.Fatalf("Expected packet to contain NULL record")
 	}
 }
+func TestAAAAParsing(t *testing.T) {
+	tests := []string{
+		"2001:db8::1",
+		"1::1",
+		"2001:db81:d2b4:b6ba:50db:49cc:a8d1:5bb1",
+		"::ffff:192.0.2.0",
+	}
+
+	rrPrefix := ".\t1\tIN\tAAAA\t"
+
+	for num, tc := range tests {
+		t.Run(fmt.Sprintf("Test %d", num), func(t *testing.T) {
+			rr, err := NewRR(rrPrefix + tc)
+			if err != nil {
+				t.Fatalf("failed to parse RR: %s", err)
+			}
+			// Output presentation format and try to parse again
+			reparseRR, err := NewRR(rr.String())
+			if err != nil {
+				t.Fatalf("failed to reparse RR: %s", err)
+			}
+			if reparseRR.String() != rrPrefix+tc {
+				t.Errorf("expected %s,got %s", rrPrefix+tc, reparseRR.String())
+			}
+		})
+	}
+}
 
 func TestParseAPL(t *testing.T) {
 	tests := []struct {
diff --git a/update_test.go b/update_test.go
index f62eac3a..69c26e8b 100644
--- a/update_test.go
+++ b/update_test.go
@@ -126,19 +126,19 @@ func TestPreReqAndRemovals(t *testing.T) {
 	// end and the Example function trim these, thus they never match.
 	// TODO(miek): don't print these tabs and make this into an Example function.
 	expect := `;; opcode: UPDATE, status: NOERROR, id: 1234
-;; flags:; QUERY: 1, ANSWER: 5, AUTHORITY: 4, ADDITIONAL: 0
+;; flags:; ZONE: 1, PREREQ: 5, UPDATE: 4, ADDITIONAL: 0
 
-;; QUESTION SECTION:
+;; ZONE SECTION:
 ;example.org.	IN	 SOA
 
-;; ANSWER SECTION:
+;; PREREQUISITE SECTION:
 name_used.	0	CLASS255	ANY	
 name_not_used.	0	NONE	ANY	
 rrset_used1.	0	CLASS255	A	
 rrset_used2.	0	IN	A	127.0.0.1
 rrset_not_used.	0	NONE	A	
 
-;; AUTHORITY SECTION:
+;; UPDATE SECTION:
 remove1.	0	CLASS255	ANY	
 remove2.	0	CLASS255	A	
 remove3.	0	NONE	A	127.0.0.1