a go dns packet parser
at main 4.2 kB view raw
1package magna 2 3import ( 4 "fmt" 5 "math/rand" 6) 7 8// Decode decodes a DNS packet. 9func (m *Message) Decode(buf []byte) (err error) { 10 // gets checked when parsing additional records 11 m.HasEDNS = false 12 13 offset, err := m.Header.Decode(buf, 0) 14 if err != nil { 15 return fmt.Errorf("failed to decode message header: %w", err) 16 } 17 18 m.Question = make([]Question, 0, m.Header.QDCount) 19 for i := range m.Header.QDCount { 20 var question Question 21 offset, err = question.Decode(buf, offset) 22 if err != nil { 23 return fmt.Errorf("failed to decode question #%d: %w", i+1, err) 24 } 25 26 m.Question = append(m.Question, question) 27 } 28 29 m.Answer = make([]ResourceRecord, 0, m.Header.ANCount) 30 for i := range m.Header.ANCount { 31 var rr ResourceRecord 32 offset, err = rr.Decode(buf, offset) 33 if err != nil { 34 return fmt.Errorf("failed to decode answer record #%d: %w", i+1, err) 35 } 36 37 m.Answer = append(m.Answer, rr) 38 } 39 40 m.Authority = make([]ResourceRecord, 0, m.Header.NSCount) 41 for i := range m.Header.NSCount { 42 var rr ResourceRecord 43 offset, err = rr.Decode(buf, offset) 44 if err != nil { 45 return fmt.Errorf("failed to decode authority record #%d: %w", i+1, err) 46 } 47 48 m.Authority = append(m.Authority, rr) 49 } 50 51 m.Additional = make([]ResourceRecord, 0, m.Header.ARCount) 52 for i := range m.Header.ARCount { 53 var rr ResourceRecord 54 offset, err = rr.Decode(buf, offset) 55 if err != nil { 56 return fmt.Errorf("failed to decode additional record #%d: %w", i+1, err) 57 } 58 59 if rr.RType == OPTType { 60 opt, ok := rr.RData.(*OPT) 61 if !ok { 62 // this should never fail 63 return fmt.Errorf("unable to parse RData as OPT") 64 } 65 66 m.HasEDNS = true 67 m.ExtendedRCode = uint8(rr.TTL >> 24 & 0xFF000000) 68 m.EDNSVersion = uint8((rr.TTL & 0x00FF0000) >> 16) 69 m.EDNSFlags = uint16(rr.TTL & 0x0000FFFF) 70 m.EDNSOptions = opt.Options 71 m.UDPSize = uint16(rr.RClass) 72 } 73 74 m.Additional = append(m.Additional, rr) 75 } 76 77 if !m.HasEDNS { 78 m.ExtendedRCode = 0 79 m.EDNSVersion = 0 80 m.EDNSFlags = 0 81 m.EDNSOptions = make([]EDNSOption, 0) 82 m.UDPSize = 512 // default in rfc-1035 section 2.3.4. 83 } 84 85 return nil 86} 87 88// Encode encodes a message to a DNS packet. 89// TODO: set truncation bit if over 512 and udp is protocol 90func (m *Message) Encode() ([]byte, error) { 91 m.offsets = make(map[string]uint16) 92 bytes := make([]byte, 0, 512) 93 94 headerBytes := m.Header.Encode() 95 bytes = append(bytes, headerBytes...) 96 97 var err error 98 99 for i, question := range m.Question { 100 bytes, err = question.Encode(bytes, &m.offsets) 101 if err != nil { 102 return nil, fmt.Errorf("failed to encode question #%d (%s): %w", i+1, question.QName, err) 103 } 104 } 105 106 for i, answer := range m.Answer { 107 bytes, err = answer.Encode(bytes, &m.offsets) 108 if err != nil { 109 return nil, fmt.Errorf("failed to encode answer record #%d (%s): %w", i+1, answer.Name, err) 110 } 111 } 112 113 for i, authority := range m.Authority { 114 bytes, err = authority.Encode(bytes, &m.offsets) 115 if err != nil { 116 return nil, fmt.Errorf("failed to encode authority record #%d (%s): %w", i+1, authority.Name, err) 117 } 118 } 119 120 for i, additional := range m.Additional { 121 bytes, err = additional.Encode(bytes, &m.offsets) 122 if err != nil { 123 return nil, fmt.Errorf("failed to encode additional record #%d (%s): %w", i+1, additional.Name, err) 124 } 125 } 126 127 return bytes, nil 128} 129 130func CreateRequest(op OPCode, rd bool) *Message { 131 return &Message{ 132 Header: Header{ 133 ID: uint16(rand.Intn(65534) + 1), 134 QR: false, 135 OPCode: op, 136 AA: false, 137 TC: false, 138 RD: rd, 139 RA: false, 140 Z: 0, 141 RCode: NOERROR, 142 QDCount: 0, 143 ARCount: 0, 144 NSCount: 0, 145 ANCount: 0, 146 }, 147 Question: make([]Question, 0), 148 Answer: make([]ResourceRecord, 0), 149 Additional: make([]ResourceRecord, 0), 150 Authority: make([]ResourceRecord, 0), 151 } 152} 153 154func (m *Message) CreateReply(req *Message) *Message { 155 m.Header.ID = req.Header.ID 156 m.Header.QR = true 157 m.Header.OPCode = req.Header.OPCode 158 159 return m 160} 161 162func (m *Message) AddQuestion(q Question) *Message { 163 m.Header.QDCount += 1 164 m.Question = append(m.Question, q) 165 166 return m 167} 168 169func (m *Message) SetRCode(rc RCode) *Message { 170 m.Header.RCode = rc 171 172 return m 173}