Skip to content

Commit bfb077e

Browse files
trtstmianlancetaylor
authored andcommitted
net: allow a dns TXT record to contain more than one <character-string>
RFC 1035 3.3.14 allows a TXT record to contain one or more <character-string>s. The current implementation returns a "no such host" error if there is more than one <character-string> in the TXT record. Fixes #10482 Change-Id: I0ded258005e6b7ba45f687fecd10afa2b321bb77 Reviewed-on: https://go-review.googlesource.com/8966 Reviewed-by: Ian Lance Taylor <iant@golang.org> Run-TryBot: Ian Lance Taylor <iant@golang.org>
1 parent d12b532 commit bfb077e

File tree

2 files changed

+164
-1
lines changed

2 files changed

+164
-1
lines changed

src/net/dnsmsg.go

+17-1
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,23 @@ func (rr *dnsRR_TXT) Header() *dnsRR_Header {
306306
}
307307

308308
func (rr *dnsRR_TXT) Walk(f func(v interface{}, name, tag string) bool) bool {
309-
return rr.Hdr.Walk(f) && f(&rr.Txt, "Txt", "")
309+
if !rr.Hdr.Walk(f) {
310+
return false
311+
}
312+
var n uint16 = 0
313+
for n < rr.Hdr.Rdlength {
314+
var txt string
315+
if !f(&txt, "Txt", "") {
316+
return false
317+
}
318+
// more bytes than rr.Hdr.Rdlength said there woudld be
319+
if rr.Hdr.Rdlength-n < uint16(len(txt))+1 {
320+
return false
321+
}
322+
n += uint16(len(txt)) + 1
323+
rr.Txt += txt
324+
}
325+
return true
310326
}
311327

312328
type dnsRR_SRV struct {

src/net/dnsmsg_test.go

+147
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,93 @@ func TestDNSParseCorruptSRVReply(t *testing.T) {
9696
}
9797
}
9898

99+
func TestDNSParseTXTReply(t *testing.T) {
100+
expectedTxt1 := "v=spf1 redirect=_spf.google.com"
101+
expectedTxt2 := "v=spf1 ip4:69.63.179.25 ip4:69.63.178.128/25 ip4:69.63.184.0/25 " +
102+
"ip4:66.220.144.128/25 ip4:66.220.155.0/24 " +
103+
"ip4:69.171.232.0/25 ip4:66.220.157.0/25 " +
104+
"ip4:69.171.244.0/24 mx -all"
105+
106+
replies := []string{dnsTXTReply1, dnsTXTReply2}
107+
expectedTxts := []string{expectedTxt1, expectedTxt2}
108+
109+
for i := range replies {
110+
data, err := hex.DecodeString(replies[i])
111+
if err != nil {
112+
t.Fatal(err)
113+
}
114+
115+
msg := new(dnsMsg)
116+
ok := msg.Unpack(data)
117+
if !ok {
118+
t.Errorf("test %d: unpacking packet failed", i)
119+
continue
120+
}
121+
122+
if len(msg.answer) != 1 {
123+
t.Errorf("test %d: len(rr.answer) = %d; want 1", i, len(msg.answer))
124+
continue
125+
}
126+
127+
rr := msg.answer[0]
128+
rrTXT, ok := rr.(*dnsRR_TXT)
129+
if !ok {
130+
t.Errorf("test %d: answer[0] = %T; want *dnsRR_TXT", i, rr)
131+
continue
132+
}
133+
134+
if rrTXT.Txt != expectedTxts[i] {
135+
t.Errorf("test %d: Txt = %s; want %s", i, rrTXT.Txt, expectedTxts[i])
136+
}
137+
}
138+
}
139+
140+
func TestDNSParseTXTCorruptDataLengthReply(t *testing.T) {
141+
replies := []string{dnsTXTCorruptDataLengthReply1, dnsTXTCorruptDataLengthReply2}
142+
143+
for i := range replies {
144+
data, err := hex.DecodeString(replies[i])
145+
if err != nil {
146+
t.Fatal(err)
147+
}
148+
149+
msg := new(dnsMsg)
150+
ok := msg.Unpack(data)
151+
if ok {
152+
t.Errorf("test %d: expected to fail on unpacking corrupt packet", i)
153+
}
154+
}
155+
}
156+
157+
func TestDNSParseTXTCorruptTXTLengthReply(t *testing.T) {
158+
replies := []string{dnsTXTCorruptTXTLengthReply1, dnsTXTCorruptTXTLengthReply2}
159+
160+
for i := range replies {
161+
data, err := hex.DecodeString(replies[i])
162+
if err != nil {
163+
t.Fatal(err)
164+
}
165+
166+
msg := new(dnsMsg)
167+
ok := msg.Unpack(data)
168+
// Unpacking should succeed, but we should just get the header.
169+
if !ok {
170+
t.Errorf("test %d: unpacking packet failed", i)
171+
continue
172+
}
173+
174+
if len(msg.answer) != 1 {
175+
t.Errorf("test %d: len(rr.answer) = %d; want 1", i, len(msg.answer))
176+
continue
177+
}
178+
179+
rr := msg.answer[0]
180+
if _, justHeader := rr.(*dnsRR_Header); !justHeader {
181+
t.Errorf("test %d: rr = %T; expected *dnsRR_Header", i, rr)
182+
}
183+
}
184+
}
185+
99186
// Valid DNS SRV reply
100187
const dnsSRVReply = "0901818000010005000000000c5f786d70702d736572766572045f74637006676f6f67" +
101188
"6c6503636f6d0000210001c00c002100010000012c00210014000014950c786d70702d" +
@@ -117,3 +204,63 @@ const dnsSRVCorruptReply = "0901818000010005000000000c5f786d70702d73657276657204
117204
"6503636f6d00c00c002100010000012c00200005000014950b786d70702d7365727665" +
118205
"72016c06676f6f676c6503636f6d00c00c002100010000012c00FF0014000014950c78" +
119206
"6d70702d73657276657231016c06676f6f676c6503636f6d00"
207+
208+
// TXT reply with one <character-string>
209+
const dnsTXTReply1 = "b3458180000100010004000505676d61696c03636f6d0000100001c00c001000010000012c00" +
210+
"201f763d737066312072656469726563743d5f7370662e676f6f676c652e636f6dc00" +
211+
"c0002000100025d4c000d036e733406676f6f676c65c012c00c0002000100025d4c00" +
212+
"06036e7331c057c00c0002000100025d4c0006036e7333c057c00c0002000100025d4" +
213+
"c0006036e7332c057c06c00010001000248b50004d8ef200ac09000010001000248b5" +
214+
"0004d8ef220ac07e00010001000248b50004d8ef240ac05300010001000248b50004d" +
215+
"8ef260a0000291000000000000000"
216+
217+
// TXT reply with more than one <character-string>.
218+
// See https://tools.ietf.org/html/rfc1035#section-3.3.14
219+
const dnsTXTReply2 = "a0a381800001000100020002045f7370660866616365626f6f6b03636f6d0000100001c00c0010000" +
220+
"100000e1000af7f763d73706631206970343a36392e36332e3137392e3235206970343a36392e" +
221+
"36332e3137382e3132382f3235206970343a36392e36332e3138342e302f3235206970343a363" +
222+
"62e3232302e3134342e3132382f3235206970343a36362e3232302e3135352e302f3234206970" +
223+
"343a36392e3137312e3233322e302f323520692e70343a36362e3232302e3135372e302f32352" +
224+
"06970343a36392e3137312e3234342e302f3234206d78202d616c6cc0110002000100025d1500" +
225+
"070161026e73c011c0110002000100025d1500040162c0ecc0ea0001000100025d15000445abe" +
226+
"f0cc0fd0001000100025d15000445abff0c"
227+
228+
// DataLength field should be sum of all TXT fields. In this case it's less.
229+
const dnsTXTCorruptDataLengthReply1 = "a0a381800001000100020002045f7370660866616365626f6f6b03636f6d0000100001c00c0010000" +
230+
"100000e1000967f763d73706631206970343a36392e36332e3137392e3235206970343a36392e" +
231+
"36332e3137382e3132382f3235206970343a36392e36332e3138342e302f3235206970343a363" +
232+
"62e3232302e3134342e3132382f3235206970343a36362e3232302e3135352e302f3234206970" +
233+
"343a36392e3137312e3233322e302f323520692e70343a36362e3232302e3135372e302f32352" +
234+
"06970343a36392e3137312e3234342e302f3234206d78202d616c6cc0110002000100025d1500" +
235+
"070161026e73c011c0110002000100025d1500040162c0ecc0ea0001000100025d15000445abe" +
236+
"f0cc0fd0001000100025d15000445abff0c"
237+
238+
// Same as above but DataLength is more than sum of TXT fields.
239+
const dnsTXTCorruptDataLengthReply2 = "a0a381800001000100020002045f7370660866616365626f6f6b03636f6d0000100001c00c0010000" +
240+
"100000e1001227f763d73706631206970343a36392e36332e3137392e3235206970343a36392e" +
241+
"36332e3137382e3132382f3235206970343a36392e36332e3138342e302f3235206970343a363" +
242+
"62e3232302e3134342e3132382f3235206970343a36362e3232302e3135352e302f3234206970" +
243+
"343a36392e3137312e3233322e302f323520692e70343a36362e3232302e3135372e302f32352" +
244+
"06970343a36392e3137312e3234342e302f3234206d78202d616c6cc0110002000100025d1500" +
245+
"070161026e73c011c0110002000100025d1500040162c0ecc0ea0001000100025d15000445abe" +
246+
"f0cc0fd0001000100025d15000445abff0c"
247+
248+
// TXT Length field is less than actual length.
249+
const dnsTXTCorruptTXTLengthReply1 = "a0a381800001000100020002045f7370660866616365626f6f6b03636f6d0000100001c00c0010000" +
250+
"100000e1000af7f763d73706631206970343a36392e36332e3137392e3235206970343a36392e" +
251+
"36332e3137382e3132382f3235206970343a36392e36332e3138342e302f3235206970343a363" +
252+
"62e3232302e3134342e3132382f3235206970343a36362e3232302e3135352e302f3234206970" +
253+
"343a36392e3137312e3233322e302f323520691470343a36362e3232302e3135372e302f32352" +
254+
"06970343a36392e3137312e3234342e302f3234206d78202d616c6cc0110002000100025d1500" +
255+
"070161026e73c011c0110002000100025d1500040162c0ecc0ea0001000100025d15000445abe" +
256+
"f0cc0fd0001000100025d15000445abff0c"
257+
258+
// TXT Length field is more than actual length.
259+
const dnsTXTCorruptTXTLengthReply2 = "a0a381800001000100020002045f7370660866616365626f6f6b03636f6d0000100001c00c0010000" +
260+
"100000e1000af7f763d73706631206970343a36392e36332e3137392e3235206970343a36392e" +
261+
"36332e3137382e3132382f3235206970343a36392e36332e3138342e302f3235206970343a363" +
262+
"62e3232302e3134342e3132382f3235206970343a36362e3232302e3135352e302f3234206970" +
263+
"343a36392e3137312e3233322e302f323520693370343a36362e3232302e3135372e302f32352" +
264+
"06970343a36392e3137312e3234342e302f3234206d78202d616c6cc0110002000100025d1500" +
265+
"070161026e73c011c0110002000100025d1500040162c0ecc0ea0001000100025d15000445abe" +
266+
"f0cc0fd0001000100025d15000445abff0c"

0 commit comments

Comments
 (0)