mirror of
https://github.com/miekg/dns.git
synced 2025-08-11 03:56:58 +02:00
* do not modify dns.Rcode when packing to wire format When the message has an EDNS0 option in the additional section and dns.Msg.Rcode is set to an extended rcode, dns.Msg.PackBuffer() modifies dns.Msg.Rcode. If you were to `Pack` the message and log it after, the Rcode would show NOERROR. Running the test before the change would error with: ``` === RUN TestPackNoSideEffect --- FAIL: TestPackNoSideEffect (0.00s) msg_test.go:51: after pack: Rcode is expected to be BADVERS ``` after fixing dns.Msg.PackBuffer(), all tests are still passing. Fixes #674 * address comments from PR#675
147 lines
4.7 KiB
Go
147 lines
4.7 KiB
Go
package dns
|
|
|
|
import (
|
|
"fmt"
|
|
"regexp"
|
|
"strconv"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
const (
|
|
maxPrintableLabel = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789x"
|
|
tooLongLabel = maxPrintableLabel + "x"
|
|
)
|
|
|
|
var (
|
|
longDomain = maxPrintableLabel[:53] + strings.TrimSuffix(
|
|
strings.Join([]string{".", ".", ".", ".", "."}, maxPrintableLabel[:49]), ".")
|
|
reChar = regexp.MustCompile(`.`)
|
|
i = -1
|
|
maxUnprintableLabel = reChar.ReplaceAllStringFunc(maxPrintableLabel, func(ch string) string {
|
|
if i++; i >= 32 {
|
|
i = 0
|
|
}
|
|
return fmt.Sprintf("\\%03d", i)
|
|
})
|
|
)
|
|
|
|
func TestPackNoSideEffect(t *testing.T) {
|
|
m := new(Msg)
|
|
m.SetQuestion(Fqdn("example.com."), TypeNS)
|
|
|
|
a := new(Msg)
|
|
o := &OPT{
|
|
Hdr: RR_Header{
|
|
Name: ".",
|
|
Rrtype: TypeOPT,
|
|
},
|
|
}
|
|
o.SetUDPSize(DefaultMsgSize)
|
|
|
|
a.Extra = append(a.Extra, o)
|
|
a.SetRcode(m, RcodeBadVers)
|
|
|
|
a.Pack()
|
|
if a.Rcode != RcodeBadVers {
|
|
t.Errorf("after pack: Rcode is expected to be BADVERS")
|
|
}
|
|
}
|
|
|
|
func TestUnpackDomainName(t *testing.T) {
|
|
var cases = []struct {
|
|
label string
|
|
input string
|
|
expectedOutput string
|
|
expectedError string
|
|
}{
|
|
{"empty domain",
|
|
"\x00",
|
|
".",
|
|
""},
|
|
{"long label",
|
|
string(63) + maxPrintableLabel + "\x00",
|
|
maxPrintableLabel + ".",
|
|
""},
|
|
{"unprintable label",
|
|
string(63) + regexp.MustCompile(`\\[0-9]+`).ReplaceAllStringFunc(maxUnprintableLabel,
|
|
func(escape string) string {
|
|
n, _ := strconv.ParseInt(escape[1:], 10, 8)
|
|
return string(n)
|
|
}) + "\x00",
|
|
maxUnprintableLabel + ".",
|
|
""},
|
|
{"long domain",
|
|
string(53) + strings.Replace(longDomain, ".", string(49), -1) + "\x00",
|
|
longDomain + ".",
|
|
""},
|
|
{"compression pointer",
|
|
// an unrealistic but functional test referencing an offset _inside_ a label
|
|
"\x03foo" + "\x05\x03com\x00" + "\x07example" + "\xC0\x05",
|
|
"foo.\\003com\\000.example.com.",
|
|
""},
|
|
|
|
{"too long domain",
|
|
string(54) + "x" + strings.Replace(longDomain, ".", string(49), -1) + "\x00",
|
|
"x" + longDomain + ".",
|
|
ErrLongDomain.Error()},
|
|
{"too long by pointer",
|
|
// a matryoshka doll name to get over 255 octets after expansion via internal pointers
|
|
string([]byte{
|
|
// 11 length values, first to last
|
|
40, 37, 34, 31, 28, 25, 22, 19, 16, 13, 0,
|
|
// 12 filler values
|
|
120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120,
|
|
// 10 pointers, last to first
|
|
192, 10, 192, 9, 192, 8, 192, 7, 192, 6, 192, 5, 192, 4, 192, 3, 192, 2, 192, 1,
|
|
}),
|
|
"",
|
|
ErrLongDomain.Error()},
|
|
{"long by pointer",
|
|
// a matryoshka doll name _not_ exceeding 255 octets after expansion
|
|
string([]byte{
|
|
// 11 length values, first to last
|
|
37, 34, 31, 28, 25, 22, 19, 16, 13, 10, 0,
|
|
// 9 filler values
|
|
120, 120, 120, 120, 120, 120, 120, 120, 120,
|
|
// 10 pointers, last to first
|
|
192, 10, 192, 9, 192, 8, 192, 7, 192, 6, 192, 5, 192, 4, 192, 3, 192, 2, 192, 1,
|
|
}),
|
|
"" +
|
|
(`\"\031\028\025\022\019\016\013\010\000xxxxxxxxx` +
|
|
`\192\010\192\009\192\008\192\007\192\006\192\005\192\004\192\003\192\002.`) +
|
|
(`\031\028\025\022\019\016\013\010\000xxxxxxxxx` +
|
|
`\192\010\192\009\192\008\192\007\192\006\192\005\192\004\192\003.`) +
|
|
(`\028\025\022\019\016\013\010\000xxxxxxxxx` +
|
|
`\192\010\192\009\192\008\192\007\192\006\192\005\192\004.`) +
|
|
(`\025\022\019\016\013\010\000xxxxxxxxx` +
|
|
`\192\010\192\009\192\008\192\007\192\006\192\005.`) +
|
|
`\022\019\016\013\010\000xxxxxxxxx\192\010\192\009\192\008\192\007\192\006.` +
|
|
`\019\016\013\010\000xxxxxxxxx\192\010\192\009\192\008\192\007.` +
|
|
`\016\013\010\000xxxxxxxxx\192\010\192\009\192\008.` +
|
|
`\013\010\000xxxxxxxxx\192\010\192\009.` +
|
|
`\010\000xxxxxxxxx\192\010.` +
|
|
`\000xxxxxxxxx.`,
|
|
""},
|
|
{"truncated name", "\x07example\x03", "", "dns: buffer size too small"},
|
|
{"non-absolute name", "\x07example\x03com", "", "dns: buffer size too small"},
|
|
{"compression pointer cycle",
|
|
"\x03foo" + "\x03bar" + "\x07example" + "\xC0\x04",
|
|
"",
|
|
"dns: too many compression pointers"},
|
|
{"reserved compression pointer 0b10", "\x07example\x80", "", "dns: bad rdata"},
|
|
{"reserved compression pointer 0b01", "\x07example\x40", "", "dns: bad rdata"},
|
|
}
|
|
for _, test := range cases {
|
|
output, idx, err := UnpackDomainName([]byte(test.input), 0)
|
|
if test.expectedOutput != "" && output != test.expectedOutput {
|
|
t.Errorf("%s: expected %s, got %s", test.label, test.expectedOutput, output)
|
|
}
|
|
if test.expectedError == "" && err != nil {
|
|
t.Errorf("%s: expected no error, got %d %v", test.label, idx, err)
|
|
} else if test.expectedError != "" && (err == nil || err.Error() != test.expectedError) {
|
|
t.Errorf("%s: expected error %s, got %d %v", test.label, test.expectedError, idx, err)
|
|
}
|
|
}
|
|
}
|