scratch/dns-server/header.go (view raw)
| 1 | package main |
| 2 | |
| 3 | import ( |
| 4 | "bytes" |
| 5 | "encoding/binary" |
| 6 | "fmt" |
| 7 | ) |
| 8 | |
| 9 | type ResultCode uint |
| 10 | |
| 11 | const ( |
| 12 | NOERROR ResultCode = iota |
| 13 | FORMERR |
| 14 | SERVFAIL |
| 15 | NXDOMAIN |
| 16 | NOTIMP |
| 17 | REFUSED |
| 18 | ) |
| 19 | |
| 20 | type Header struct { |
| 21 | ID uint16 |
| 22 | |
| 23 | RecursionDesired bool |
| 24 | TruncatedMessage bool |
| 25 | AuthoritativeAnswer bool |
| 26 | OPCode uint8 |
| 27 | Response bool |
| 28 | Rescode ResultCode |
| 29 | CheckingDisabled bool |
| 30 | AuthedData bool |
| 31 | Z bool |
| 32 | RecursionAvailable bool |
| 33 | |
| 34 | Questions uint16 |
| 35 | Answers uint16 |
| 36 | AuthoritativeEntries uint16 |
| 37 | ResourceEntries uint16 |
| 38 | } |
| 39 | |
| 40 | func ReadHeader(r *bytes.Reader) (Header, error) { |
| 41 | var h Header |
| 42 | if err := binary.Read(r, binary.BigEndian, &h.ID); err != nil { |
| 43 | return h, fmt.Errorf("reading ID: %w", err) |
| 44 | } |
| 45 | |
| 46 | var flags uint16 |
| 47 | if err := binary.Read(r, binary.BigEndian, &flags); err != nil { |
| 48 | return h, fmt.Errorf("reading flags: %w", err) |
| 49 | } |
| 50 | h.unpackFlags(flags) |
| 51 | |
| 52 | if err := binary.Read(r, binary.BigEndian, &h.Questions); err != nil { |
| 53 | return h, fmt.Errorf("reading questions: %w", err) |
| 54 | } |
| 55 | if err := binary.Read(r, binary.BigEndian, &h.Answers); err != nil { |
| 56 | return h, fmt.Errorf("reading answers: %w", err) |
| 57 | } |
| 58 | if err := binary.Read(r, binary.BigEndian, &h.AuthoritativeEntries); err != nil { |
| 59 | return h, fmt.Errorf("reading auth entries: %w", err) |
| 60 | } |
| 61 | if err := binary.Read(r, binary.BigEndian, &h.ResourceEntries); err != nil { |
| 62 | return h, fmt.Errorf("reading resource entries: %w", err) |
| 63 | } |
| 64 | |
| 65 | return h, nil |
| 66 | } |
| 67 | |
| 68 | func (h *Header) unpackFlags(flags uint16) { |
| 69 | h.RecursionDesired = flags&(1<<8) != 0 |
| 70 | h.TruncatedMessage = flags&(1<<9) != 0 |
| 71 | h.AuthoritativeAnswer = flags&(1<<10) != 0 |
| 72 | h.OPCode = uint8((flags >> 11) & 0xF) |
| 73 | h.Response = flags&(1<<15) != 0 |
| 74 | h.Rescode = ResultCode(flags & 0xF) |
| 75 | h.CheckingDisabled = flags&(1<<4) != 0 |
| 76 | h.AuthedData = flags&(1<<5) != 0 |
| 77 | h.Z = flags&(1<<6) != 0 |
| 78 | h.RecursionAvailable = flags&(1<<7) != 0 |
| 79 | } |
| 80 | |
| 81 | func (h Header) packFlags() uint16 { |
| 82 | var flags uint16 |
| 83 | if h.RecursionDesired { |
| 84 | flags |= 1 << 8 |
| 85 | } |
| 86 | if h.TruncatedMessage { |
| 87 | flags |= 1 << 9 |
| 88 | } |
| 89 | if h.AuthoritativeAnswer { |
| 90 | flags |= 1 << 10 |
| 91 | } |
| 92 | flags |= uint16(h.OPCode) << 11 |
| 93 | if h.Response { |
| 94 | flags |= 1 << 15 |
| 95 | } |
| 96 | flags |= uint16(h.Rescode) |
| 97 | if h.CheckingDisabled { |
| 98 | flags |= 1 << 4 |
| 99 | } |
| 100 | if h.AuthedData { |
| 101 | flags |= 1 << 5 |
| 102 | } |
| 103 | if h.Z { |
| 104 | flags |= 1 << 6 |
| 105 | } |
| 106 | if h.RecursionAvailable { |
| 107 | flags |= 1 << 7 |
| 108 | } |
| 109 | return flags |
| 110 | } |