1package dns 2 3import ( 4 "fmt" 5 "regexp" 6 "strconv" 7 "strings" 8 "testing" 9) 10 11const ( 12 maxPrintableLabel = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789x" 13 tooLongLabel = maxPrintableLabel + "x" 14) 15 16var ( 17 longDomain = maxPrintableLabel[:53] + strings.TrimSuffix( 18 strings.Join([]string{".", ".", ".", ".", "."}, maxPrintableLabel[:49]), ".") 19 reChar = regexp.MustCompile(`.`) 20 i = -1 21 maxUnprintableLabel = reChar.ReplaceAllStringFunc(maxPrintableLabel, func(ch string) string { 22 if i++; i >= 32 { 23 i = 0 24 } 25 return fmt.Sprintf("\\%03d", i) 26 }) 27) 28 29func TestPackNoSideEffect(t *testing.T) { 30 m := new(Msg) 31 m.SetQuestion(Fqdn("example.com."), TypeNS) 32 33 a := new(Msg) 34 o := &OPT{ 35 Hdr: RR_Header{ 36 Name: ".", 37 Rrtype: TypeOPT, 38 }, 39 } 40 o.SetUDPSize(DefaultMsgSize) 41 42 a.Extra = append(a.Extra, o) 43 a.SetRcode(m, RcodeBadVers) 44 45 a.Pack() 46 if a.Rcode != RcodeBadVers { 47 t.Errorf("after pack: Rcode is expected to be BADVERS") 48 } 49} 50 51func TestUnpackDomainName(t *testing.T) { 52 var cases = []struct { 53 label string 54 input string 55 expectedOutput string 56 expectedError string 57 }{ 58 {"empty domain", 59 "\x00", 60 ".", 61 ""}, 62 {"long label", 63 string(63) + maxPrintableLabel + "\x00", 64 maxPrintableLabel + ".", 65 ""}, 66 {"unprintable label", 67 string(63) + regexp.MustCompile(`\\[0-9]+`).ReplaceAllStringFunc(maxUnprintableLabel, 68 func(escape string) string { 69 n, _ := strconv.ParseInt(escape[1:], 10, 8) 70 return string(n) 71 }) + "\x00", 72 maxUnprintableLabel + ".", 73 ""}, 74 {"long domain", 75 string(53) + strings.Replace(longDomain, ".", string(49), -1) + "\x00", 76 longDomain + ".", 77 ""}, 78 {"compression pointer", 79 // an unrealistic but functional test referencing an offset _inside_ a label 80 "\x03foo" + "\x05\x03com\x00" + "\x07example" + "\xC0\x05", 81 "foo.\\003com\\000.example.com.", 82 ""}, 83 84 {"too long domain", 85 string(54) + "x" + strings.Replace(longDomain, ".", string(49), -1) + "\x00", 86 "x" + longDomain + ".", 87 ErrLongDomain.Error()}, 88 {"too long by pointer", 89 // a matryoshka doll name to get over 255 octets after expansion via internal pointers 90 string([]byte{ 91 // 11 length values, first to last 92 40, 37, 34, 31, 28, 25, 22, 19, 16, 13, 0, 93 // 12 filler values 94 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 95 // 10 pointers, last to first 96 192, 10, 192, 9, 192, 8, 192, 7, 192, 6, 192, 5, 192, 4, 192, 3, 192, 2, 192, 1, 97 }), 98 "", 99 ErrLongDomain.Error()}, 100 {"long by pointer", 101 // a matryoshka doll name _not_ exceeding 255 octets after expansion 102 string([]byte{ 103 // 11 length values, first to last 104 37, 34, 31, 28, 25, 22, 19, 16, 13, 10, 0, 105 // 9 filler values 106 120, 120, 120, 120, 120, 120, 120, 120, 120, 107 // 10 pointers, last to first 108 192, 10, 192, 9, 192, 8, 192, 7, 192, 6, 192, 5, 192, 4, 192, 3, 192, 2, 192, 1, 109 }), 110 "" + 111 (`\"\031\028\025\022\019\016\013\010\000xxxxxxxxx` + 112 `\192\010\192\009\192\008\192\007\192\006\192\005\192\004\192\003\192\002.`) + 113 (`\031\028\025\022\019\016\013\010\000xxxxxxxxx` + 114 `\192\010\192\009\192\008\192\007\192\006\192\005\192\004\192\003.`) + 115 (`\028\025\022\019\016\013\010\000xxxxxxxxx` + 116 `\192\010\192\009\192\008\192\007\192\006\192\005\192\004.`) + 117 (`\025\022\019\016\013\010\000xxxxxxxxx` + 118 `\192\010\192\009\192\008\192\007\192\006\192\005.`) + 119 `\022\019\016\013\010\000xxxxxxxxx\192\010\192\009\192\008\192\007\192\006.` + 120 `\019\016\013\010\000xxxxxxxxx\192\010\192\009\192\008\192\007.` + 121 `\016\013\010\000xxxxxxxxx\192\010\192\009\192\008.` + 122 `\013\010\000xxxxxxxxx\192\010\192\009.` + 123 `\010\000xxxxxxxxx\192\010.` + 124 `\000xxxxxxxxx.`, 125 ""}, 126 {"truncated name", "\x07example\x03", "", "dns: buffer size too small"}, 127 {"non-absolute name", "\x07example\x03com", "", "dns: buffer size too small"}, 128 {"compression pointer cycle", 129 "\x03foo" + "\x03bar" + "\x07example" + "\xC0\x04", 130 "", 131 "dns: too many compression pointers"}, 132 {"reserved compression pointer 0b10", "\x07example\x80", "", "dns: bad rdata"}, 133 {"reserved compression pointer 0b01", "\x07example\x40", "", "dns: bad rdata"}, 134 } 135 for _, test := range cases { 136 output, idx, err := UnpackDomainName([]byte(test.input), 0) 137 if test.expectedOutput != "" && output != test.expectedOutput { 138 t.Errorf("%s: expected %s, got %s", test.label, test.expectedOutput, output) 139 } 140 if test.expectedError == "" && err != nil { 141 t.Errorf("%s: expected no error, got %d %v", test.label, idx, err) 142 } else if test.expectedError != "" && (err == nil || err.Error() != test.expectedError) { 143 t.Errorf("%s: expected error %s, got %d %v", test.label, test.expectedError, idx, err) 144 } 145 } 146} 147