a go dns packet parser
1package magna 2 3import ( 4 "testing" 5 6 "github.com/stretchr/testify/assert" 7) 8 9func BenchmarkDecodeDomainSimple(b *testing.B) { 10 input := []byte{3, 'w', 'w', 'w', 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 3, 'c', 'o', 'm', 0} 11 for i := 0; i < b.N; i++ { 12 _, _, _ = decode_domain(input, 0) 13 } 14} 15 16func BenchmarkDecodeDomainCompressed(b *testing.B) { 17 input := []byte{ 18 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 0x03, 'c', 'o', 'm', 0x00, 19 0x03, 'f', 'o', 'o', 0xc0, 0x00, 20 } 21 offset := 13 22 b.ResetTimer() 23 for i := 0; i < b.N; i++ { 24 _, _, _ = decode_domain(input, offset) 25 } 26} 27 28func BenchmarkEncodeDomainSimple(b *testing.B) { 29 domain := "www.example.com" 30 offsets := make(map[string]uint16) 31 out := make([]byte, 0, 64) 32 b.ResetTimer() 33 for i := 0; i < b.N; i++ { 34 _ = encode_domain(out[:0], domain, &offsets) 35 for k := range offsets { 36 delete(offsets, k) 37 } 38 } 39} 40 41func BenchmarkEncodeDomainWithCompression(b *testing.B) { 42 domain1 := "www.example.com" 43 domain2 := "mail.example.com" 44 offsets := make(map[string]uint16) 45 out := make([]byte, 0, 128) 46 b.ResetTimer() 47 for i := 0; i < b.N; i++ { 48 tempOut := encode_domain(out[:0], domain1, &offsets) 49 _ = encode_domain(tempOut, domain2, &offsets) 50 for k := range offsets { 51 delete(offsets, k) 52 } 53 } 54} 55 56func TestDecodeDomain(t *testing.T) { 57 tests := []struct { 58 name string 59 offset int 60 input []byte 61 expectedDomain string 62 expectedOffset int 63 expectedError error 64 }{ 65 { 66 name: "Simple domain", 67 input: []byte{3, 'w', 'w', 'w', 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 3, 'c', 'o', 'm', 0}, 68 expectedDomain: "www.example.com", 69 expectedOffset: 17, 70 expectedError: nil, 71 }, 72 { 73 name: "Domain with compression", 74 offset: 17, 75 input: []byte{3, 'w', 'w', 'w', 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 3, 'c', 'o', 'm', 0, 3, 'f', 'o', 'o', 0xC0, 0}, 76 expectedDomain: "foo.www.example.com", 77 expectedOffset: 23, 78 expectedError: nil, 79 }, 80 { 81 name: "Invalid label length", 82 input: []byte{64, 'x'}, 83 expectedDomain: "", 84 expectedOffset: 2, 85 expectedError: &InvalidLabelError{Length: 64}, 86 }, 87 { 88 name: "Compression loop", 89 input: []byte{0xC0, 0, 0xC0, 0}, 90 expectedDomain: "", 91 expectedOffset: 4, 92 expectedError: &DomainCompressionError{}, 93 }, 94 { 95 name: "Truncated input", 96 input: []byte{3, 'w', 'w'}, 97 expectedDomain: "", 98 expectedOffset: 3, 99 expectedError: &BufferOverflowError{Length: 3, Offset: 4}, 100 }, 101 } 102 103 for _, tt := range tests { 104 t.Run(tt.name, func(t *testing.T) { 105 domain, offset, err := decode_domain(tt.input, tt.offset) 106 107 t.Log(tt.name) 108 assert.Equal(t, tt.expectedError, err) 109 assert.Equal(t, tt.expectedDomain, domain) 110 assert.Equal(t, tt.expectedOffset, offset) 111 }) 112 } 113} 114 115func TestEncodeDomain(t *testing.T) { 116 tests := []struct { 117 name string 118 input string 119 offsets map[string]uint16 120 expected []byte 121 newOffsets map[string]uint16 122 }{ 123 { 124 name: "Simple domain", 125 input: "example.com", 126 offsets: make(map[string]uint16), 127 expected: []byte{7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 3, 'c', 'o', 'm', 0}, 128 newOffsets: map[string]uint16{"example.com": 0, "com": 8}, 129 }, 130 { 131 name: "Domain with existing offset", 132 input: "test.example.com", 133 offsets: map[string]uint16{"example.com": 10}, 134 expected: []byte{4, 't', 'e', 's', 't', 0xC0, 0x0A}, 135 newOffsets: map[string]uint16{"test.example.com": 0, "example.com": 10}, 136 }, 137 { 138 name: "Multiple subdomains", 139 input: "a.b.c.d", 140 offsets: make(map[string]uint16), 141 expected: []byte{1, 'a', 1, 'b', 1, 'c', 1, 'd', 0}, 142 newOffsets: map[string]uint16{"a.b.c.d": 0, "b.c.d": 2, "c.d": 4, "d": 6}, 143 }, 144 } 145 146 for _, tt := range tests { 147 t.Run(tt.name, func(t *testing.T) { 148 result := encode_domain([]byte{}, tt.input, &tt.offsets) 149 assert.Equal(t, tt.expected, result, "Encoded domain does not match expected output") 150 assert.Equal(t, tt.newOffsets, tt.offsets, "Offsets map does not match expected state") 151 }) 152 } 153} 154 155func FuzzDecodeDomain(f *testing.F) { 156 testcases := [][]byte{ 157 { 158 0x03, 0x63, 0x6f, 0x6d, 0x00, 159 }, 160 { 161 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x01, 0x63, 0xC0, 0x00, 162 }, 163 { 164 0x03, 0x63, 0x6f, 0x6d, 0xC0, 0x00, 165 }, 166 } 167 for _, tc := range testcases { 168 f.Add(tc) 169 } 170 f.Fuzz(func(t *testing.T, msg []byte) { 171 decode_domain(msg, 0) 172 }) 173}