a go dns packet parser
1package magna 2 3import ( 4 "encoding/binary" 5 "strings" 6) 7 8// decode_domain decodes a domain name from a buffer starting at offset. 9// It returns the domain name along with the offset and error. 10func decode_domain(buf []byte, offset int) (string, int, error) { 11 labels := make([]string, 0) 12 seen_offsets := make(map[int]struct{}) 13 has_jumped := false 14 prev_offset := 0 15 16 var length uint8 17 var label []byte 18 var sec byte 19 var err error 20 for { 21 length, offset, err = getU8(buf, offset) 22 if err != nil { 23 return "", len(buf), err 24 } 25 26 if length == 0 { 27 break 28 } 29 30 if length&0xC0 == 0xC0 { 31 sec, offset, err = getU8(buf, offset) 32 if err != nil { 33 return "", len(buf), err 34 } 35 36 if !has_jumped { 37 prev_offset = offset 38 has_jumped = true 39 } 40 41 if _, found := seen_offsets[offset]; found { 42 return "", len(buf), &DomainCompressionError{} 43 } 44 45 seen_offsets[offset] = struct{}{} 46 offset = int(sec) 47 } else { 48 if length > 63 { 49 return "", len(buf), &InvalidLabelError{Length: int(length)} 50 } 51 52 label, offset, err = getSlice(buf, offset, int(length)) 53 if err != nil { 54 return "", len(buf), err 55 } 56 57 labels = append(labels, string(label)) 58 } 59 } 60 61 if has_jumped { 62 offset = prev_offset 63 } 64 65 return strings.Join(labels, "."), offset, nil 66} 67 68// encode_domain returns the bytes of the input bytes appened with the encoded domain name. 69func encode_domain(bytes []byte, domain_name string, offsets *map[string]uint8) []byte { 70 pos := uint8(len(bytes)) 71 72 labels := strings.Split(domain_name, ".") 73 for i, label := range labels { 74 remaining_labels := strings.Join(labels[i:], ".") 75 76 if offset, found := (*offsets)[remaining_labels]; found { 77 pointer := 0xC000 | uint16(offset) 78 bytes = binary.BigEndian.AppendUint16(bytes, pointer) 79 80 return bytes 81 } 82 83 bytes = append(bytes, uint8(len(label))) 84 bytes = append(bytes, []byte(label)...) 85 86 (*offsets)[remaining_labels] = pos 87 pos += 1 + uint8(len(label)) 88 } 89 90 bytes = append(bytes, 0) 91 return bytes 92}