[release-branch.go1.11] net: concatenate multiple TXT strings in single TXT record

When go resolver was changed to use dnsmessage.Parser, LookupTXT
returned two strings in one record as two different records. This change
reverts back to concatenating multiple strings in a single
TXT record.

Updates #27763
Fixes #27886

Change-Id: Ice226fcb2be4be58853de34ed35b4627acb429ea
Reviewed-on: https://go-review.googlesource.com/136955
Reviewed-by: Ian Gudger <igudger@google.com>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Run-TryBot: Ian Gudger <igudger@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
(cherry picked from commit 7b3b160323b56b357832549fbab7a60d27688ec1)
Reviewed-on: https://go-review.googlesource.com/138177
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
Reviewed-by: Katie Hockman <katie@golang.org>
diff --git a/src/net/dnsclient_unix_test.go b/src/net/dnsclient_unix_test.go
index 9e4ebcc..9482fc4 100644
--- a/src/net/dnsclient_unix_test.go
+++ b/src/net/dnsclient_unix_test.go
@@ -1568,3 +1568,56 @@
 		t.Fatal("exhange failed:", err)
 	}
 }
+
+// Issue 27763: verify that two strings in one TXT record are concatenated.
+func TestTXTRecordTwoStrings(t *testing.T) {
+	fake := fakeDNSServer{
+		rh: func(n, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
+			r := dnsmessage.Message{
+				Header: dnsmessage.Header{
+					ID:       q.Header.ID,
+					Response: true,
+					RCode:    dnsmessage.RCodeSuccess,
+				},
+				Questions: q.Questions,
+				Answers: []dnsmessage.Resource{
+					{
+						Header: dnsmessage.ResourceHeader{
+							Name:  q.Questions[0].Name,
+							Type:  dnsmessage.TypeA,
+							Class: dnsmessage.ClassINET,
+						},
+						Body: &dnsmessage.TXTResource{
+							TXT: []string{"string1 ", "string2"},
+						},
+					},
+					{
+						Header: dnsmessage.ResourceHeader{
+							Name:  q.Questions[0].Name,
+							Type:  dnsmessage.TypeA,
+							Class: dnsmessage.ClassINET,
+						},
+						Body: &dnsmessage.TXTResource{
+							TXT: []string{"onestring"},
+						},
+					},
+				},
+			}
+			return r, nil
+		},
+	}
+	r := Resolver{PreferGo: true, Dial: fake.DialContext}
+	txt, err := r.lookupTXT(context.Background(), "golang.org")
+	if err != nil {
+		t.Fatal("LookupTXT failed:", err)
+	}
+	if want := 2; len(txt) != want {
+		t.Fatalf("len(txt), got %d, want %d", len(txt), want)
+	}
+	if want := "string1 string2"; txt[0] != want {
+		t.Errorf("txt[0], got %q, want %q", txt[0], want)
+	}
+	if want := "onestring"; txt[1] != want {
+		t.Errorf("txt[1], got %q, want %q", txt[1], want)
+	}
+}
diff --git a/src/net/lookup_unix.go b/src/net/lookup_unix.go
index 2c3191a..f55ef59 100644
--- a/src/net/lookup_unix.go
+++ b/src/net/lookup_unix.go
@@ -299,11 +299,21 @@
 				Server: server,
 			}
 		}
-		if len(txts) == 0 {
-			txts = txt.TXT
-		} else {
-			txts = append(txts, txt.TXT...)
+		// Multiple strings in one TXT record need to be
+		// concatenated without separator to be consistent
+		// with previous Go resolver.
+		n := 0
+		for _, s := range txt.TXT {
+			n += len(s)
 		}
+		txtJoin := make([]byte, 0, n)
+		for _, s := range txt.TXT {
+			txtJoin = append(txtJoin, s...)
+		}
+		if len(txts) == 0 {
+			txts = make([]string, 0, 1)
+		}
+		txts = append(txts, string(txtJoin))
 	}
 	return txts, nil
 }