all repos

scratch @ 77539db

⭐ me doing recreational ~~drugs~~ programming

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
}