all repos

scratch @ 753ee96db5676dd9ecc5bf980cac917885c01de2

⭐ 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 = uint8
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) Write(b *bytes.Buffer) error {
69
	_ = binary.Write(b, binary.BigEndian, h.ID)
70
71
	_ = b.WriteByte((b2u8(h.RecursionDesired)) |
72
		(b2u8(h.TruncatedMessage) << 1) |
73
		(b2u8(h.AuthoritativeAnswer) << 2) |
74
		(h.OPCode << 3) |
75
		(b2u8(h.Response) << 7))
76
77
	_ = b.WriteByte(h.Rescode |
78
		(b2u8(h.CheckingDisabled) << 4) |
79
		(b2u8(h.AuthedData) << 5) |
80
		(b2u8(h.Z) << 6) |
81
		(b2u8(h.RecursionAvailable) << 7))
82
83
	_ = binary.Write(b, binary.BigEndian, h.Questions)
84
	_ = binary.Write(b, binary.BigEndian, h.Answers)
85
	_ = binary.Write(b, binary.BigEndian, h.AuthoritativeEntries)
86
	_ = binary.Write(b, binary.BigEndian, h.ResourceEntries)
87
	return nil
88
}
89
90
func (h *Header) unpackFlags(flags uint16) {
91
	h.RecursionDesired = flags&(1<<8) != 0
92
	h.TruncatedMessage = flags&(1<<9) != 0
93
	h.AuthoritativeAnswer = flags&(1<<10) != 0
94
	h.OPCode = uint8((flags >> 11) & 0xF)
95
	h.Response = flags&(1<<15) != 0
96
	h.Rescode = ResultCode(flags & 0xF)
97
	h.CheckingDisabled = flags&(1<<4) != 0
98
	h.AuthedData = flags&(1<<5) != 0
99
	h.Z = flags&(1<<6) != 0
100
	h.RecursionAvailable = flags&(1<<7) != 0
101
}
102
103
func (h Header) packFlags() uint16 {
104
	var flags uint16
105
	if h.RecursionDesired {
106
		flags |= 1 << 8
107
	}
108
	if h.TruncatedMessage {
109
		flags |= 1 << 9
110
	}
111
	if h.AuthoritativeAnswer {
112
		flags |= 1 << 10
113
	}
114
	flags |= uint16(h.OPCode) << 11
115
	if h.Response {
116
		flags |= 1 << 15
117
	}
118
	flags |= uint16(h.Rescode)
119
	if h.CheckingDisabled {
120
		flags |= 1 << 4
121
	}
122
	if h.AuthedData {
123
		flags |= 1 << 5
124
	}
125
	if h.Z {
126
		flags |= 1 << 6
127
	}
128
	if h.RecursionAvailable {
129
		flags |= 1 << 7
130
	}
131
	return flags
132
}
133
134
func b2u8(b bool) uint8 {
135
	if b {
136
		return 1
137
	}
138
	return 0
139
}