···
// decode_domain decodes a domain name from a buffer starting at offset.
// It returns the domain name along with the offset and error.
func decode_domain(buf []byte, offset int) (string, int, error) {
11
-
labels := make([]string, 0)
11
+
var builder strings.Builder
seen_offsets := make(map[int]struct{})
15
+
finalOffsetAfterJump := -1
17
+
currentOffset := offset
21
-
length, offset, err = getU8(buf, offset)
20
+
if _, found := seen_offsets[currentOffset]; found {
21
+
return "", len(buf), &DomainCompressionError{}
23
+
seen_offsets[currentOffset] = struct{}{}
25
+
length, nextOffsetAfterLen, err := getU8(buf, currentOffset)
31
+
currentOffset = nextOffsetAfterLen
30
-
if length&0xC0 == 0xC0 {
31
-
sec, offset, err = getU8(buf, offset)
35
+
if (length & 0xC0) == 0xC0 {
36
+
sec, nextOffsetAfterPtr, err := getU8(buf, nextOffsetAfterLen)
37
-
prev_offset = offset
41
+
jumpTargetOffset := int(length&0x3F)<<8 | int(sec)
41
-
if _, found := seen_offsets[offset]; found {
43
+
if jumpTargetOffset >= len(buf) {
44
+
return "", len(buf), &BufferOverflowError{Length: len(buf), Offset: jumpTargetOffset}
46
+
if _, found := seen_offsets[jumpTargetOffset]; found {
return "", len(buf), &DomainCompressionError{}
45
-
seen_offsets[offset] = struct{}{}
46
-
offset = int(length&0x3F)<<8 | int(sec)
49
-
return "", len(buf), &InvalidLabelError{Length: int(length)}
50
+
if finalOffsetAfterJump == -1 {
51
+
finalOffsetAfterJump = nextOffsetAfterPtr
52
-
label, offset, err = getSlice(buf, offset, int(length))
54
-
return "", len(buf), err
54
+
currentOffset = jumpTargetOffset
57
-
labels = append(labels, string(label))
59
+
return "", len(buf), &InvalidLabelError{Length: int(length)}
62
+
labelBytes, nextOffsetAfterLabel, err := getSlice(buf, nextOffsetAfterLen, int(length))
64
+
return "", len(buf), err
68
+
builder.WriteByte('.')
70
+
builder.Write(labelBytes)
73
+
currentOffset = nextOffsetAfterLabel
62
-
offset = prev_offset
77
+
finalReadOffset := currentOffset
78
+
if finalOffsetAfterJump != -1 {
79
+
finalReadOffset = finalOffsetAfterJump
65
-
return strings.Join(labels, "."), offset, nil
82
+
return builder.String(), finalReadOffset, nil
// encode_domain returns the bytes of the input bytes appened with the encoded domain name.
func encode_domain(bytes []byte, domain_name string, offsets *map[string]uint16) []byte {
70
-
pos := uint16(len(bytes))
87
+
if domain_name == "." || domain_name == "" {
88
+
return append(bytes, 0)
72
-
labels := strings.Split(domain_name, ".")
73
-
for i, label := range labels {
74
-
remaining_labels := strings.Join(labels[i:], ".")
91
+
labelIndices := []int{0}
92
+
for i, r := range domain_name {
94
+
labelIndices = append(labelIndices, i+1)
76
-
if offset, found := (*offsets)[remaining_labels]; found {
98
+
for i := 0; i < len(labelIndices); i++ {
99
+
suffix := domain_name[labelIndices[i]:]
101
+
if offset, found := (*offsets)[suffix]; found {
pointer := 0xC000 | offset
return binary.BigEndian.AppendUint16(bytes, pointer)
81
-
(*offsets)[remaining_labels] = pos
82
-
bytes = append(bytes, uint8(len(label)))
83
-
bytes = append(bytes, []byte(label)...)
84
-
pos += 1 + uint16(len(label))
106
+
currentPos := uint16(len(bytes))
107
+
if currentPos <= 0x3FFF {
108
+
(*offsets)[suffix] = currentPos
111
+
start := labelIndices[i]
112
+
end := len(domain_name)
113
+
if i+1 < len(labelIndices) {
114
+
end = labelIndices[i+1] - 1
116
+
labelBytes := []byte(domain_name[start:end])
118
+
if len(labelBytes) == 0 {
121
+
if len(labelBytes) > 63 {
122
+
labelBytes = labelBytes[:63]
125
+
bytes = append(bytes, byte(len(labelBytes)))
126
+
bytes = append(bytes, labelBytes...)