···
// 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) {
-
labels := make([]string, 0)
seen_offsets := make(map[int]struct{})
-
length, offset, err = getU8(buf, offset)
-
if length&0xC0 == 0xC0 {
-
sec, offset, err = getU8(buf, offset)
-
if _, found := seen_offsets[offset]; found {
return "", len(buf), &DomainCompressionError{}
-
seen_offsets[offset] = struct{}{}
-
offset = int(length&0x3F)<<8 | int(sec)
-
return "", len(buf), &InvalidLabelError{Length: int(length)}
-
label, offset, err = getSlice(buf, offset, int(length))
-
return "", len(buf), err
-
labels = append(labels, string(label))
-
return strings.Join(labels, "."), offset, 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 {
-
pos := uint16(len(bytes))
-
labels := strings.Split(domain_name, ".")
-
for i, label := range labels {
-
remaining_labels := strings.Join(labels[i:], ".")
-
if offset, found := (*offsets)[remaining_labels]; found {
pointer := 0xC000 | offset
return binary.BigEndian.AppendUint16(bytes, pointer)
-
(*offsets)[remaining_labels] = pos
-
bytes = append(bytes, uint8(len(label)))
-
bytes = append(bytes, []byte(label)...)
-
pos += 1 + uint16(len(label))
···
// 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) {
+
var builder strings.Builder
seen_offsets := make(map[int]struct{})
+
finalOffsetAfterJump := -1
+
currentOffset := offset
+
if _, found := seen_offsets[currentOffset]; found {
+
return "", len(buf), &DomainCompressionError{}
+
seen_offsets[currentOffset] = struct{}{}
+
length, nextOffsetAfterLen, err := getU8(buf, currentOffset)
+
currentOffset = nextOffsetAfterLen
+
if (length & 0xC0) == 0xC0 {
+
sec, nextOffsetAfterPtr, err := getU8(buf, nextOffsetAfterLen)
+
jumpTargetOffset := int(length&0x3F)<<8 | int(sec)
+
if jumpTargetOffset >= len(buf) {
+
return "", len(buf), &BufferOverflowError{Length: len(buf), Offset: jumpTargetOffset}
+
if _, found := seen_offsets[jumpTargetOffset]; found {
return "", len(buf), &DomainCompressionError{}
+
if finalOffsetAfterJump == -1 {
+
finalOffsetAfterJump = nextOffsetAfterPtr
+
currentOffset = jumpTargetOffset
+
return "", len(buf), &InvalidLabelError{Length: int(length)}
+
labelBytes, nextOffsetAfterLabel, err := getSlice(buf, nextOffsetAfterLen, int(length))
+
return "", len(buf), err
+
builder.Write(labelBytes)
+
currentOffset = nextOffsetAfterLabel
+
finalReadOffset := currentOffset
+
if finalOffsetAfterJump != -1 {
+
finalReadOffset = finalOffsetAfterJump
+
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 {
+
if domain_name == "." || domain_name == "" {
+
return append(bytes, 0)
+
labelIndices := []int{0}
+
for i, r := range domain_name {
+
labelIndices = append(labelIndices, i+1)
+
for i := 0; i < len(labelIndices); i++ {
+
suffix := domain_name[labelIndices[i]:]
+
if offset, found := (*offsets)[suffix]; found {
pointer := 0xC000 | offset
return binary.BigEndian.AppendUint16(bytes, pointer)
+
currentPos := uint16(len(bytes))
+
if currentPos <= 0x3FFF {
+
(*offsets)[suffix] = currentPos
+
start := labelIndices[i]
+
end := len(domain_name)
+
if i+1 < len(labelIndices) {
+
end = labelIndices[i+1] - 1
+
labelBytes := []byte(domain_name[start:end])
+
if len(labelBytes) == 0 {
+
if len(labelBytes) > 63 {
+
labelBytes = labelBytes[:63]
+
bytes = append(bytes, byte(len(labelBytes)))
+
bytes = append(bytes, labelBytes...)