···
"tangled.sh/seiso.moe/magna"
14
-
var errNXDOMAIN = fmt.Errorf("nxdomain")
15
+
errNXDOMAIN = fmt.Errorf("alky: domain does not exist")
16
+
errOnlySOA = fmt.Errorf("alky: only an soa was reffered")
17
+
errNoServers = fmt.Errorf("alky: no servers responded")
18
+
errMaxDepth = fmt.Errorf("alky: maximum recursion depth exceeded")
19
+
errNonMatchingID = fmt.Errorf("alky: response ID mismatch")
20
+
errNonMatchingQuestion = fmt.Errorf("alky: response question mismatch")
21
+
errQueryTimeout = fmt.Errorf("alky: query timeout")
depthKey contextKey = "dns_recursion_depth"
···
func withIncrementedDepth(ctx context.Context, maxDepth int) (context.Context, error) {
23
-
return nil, fmt.Errorf("maximum recursion depth (%d) exceeded", maxDepth)
31
+
return nil, errMaxDepth
return context.WithValue(ctx, depthKey, depth+1), nil
···
msg.Header.NSCount = uint16(len(records))
76
+
} else if err == errOnlySOA {
77
+
msg = msg.SetRCode(magna.NOERROR)
78
+
msg.Authority = records
79
+
msg.Header.NSCount = uint16(len(records))
80
+
msg.Header.ANCount = 0
81
+
msg.Header.ARCount = 0
84
+
h.Logger.Warn("error", "error", err)
msg = msg.SetRCode(magna.SERVFAIL)
···
for _, s := range servers {
msg, err := queryServer(ctx, question, s, h.Timeout)
91
-
h.Logger.Warn("unable to resolve question", "server", s)
107
+
h.Logger.Warn("unable to resolve question", "server", s, "error", err)
111
+
if msg.Header.RCode == magna.NXDOMAIN {
112
+
_, authority := ExtractSOA(msg)
113
+
return authority, errNXDOMAIN
if ok, answers := ExtractAnswer(question, msg); ok {
if msg.Answer[0].RType == magna.CNAMEType {
cnameQuestion := magna.Question{QName: msg.Answer[0].RData.String(), QType: question.QType, QClass: question.QClass}
···
if ok, answers := h.HandleReferral(ctx, question, msg); ok {
return h.resolveQuestion(ctx, question, answers)
137
+
if ok, answers := ExtractSOA(msg); ok {
138
+
return answers, errOnlySOA
117
-
return []magna.ResourceRecord{}, nil
142
+
return []magna.ResourceRecord{}, errNoServers
func queryServer(ctx context.Context, question magna.Question, server string, timeout time.Duration) (magna.Message, error) {
146
+
ctx, cancel := context.WithTimeout(ctx, timeout)
conn, err := d.DialContext(ctx, "udp", fmt.Sprintf("%s:53", server))
···
conn.SetDeadline(time.Now().Add(timeout))
135
-
query := magna.CreateRequest(0, false)
158
+
query := magna.CreateRequest(magna.QUERY, false)
query = query.AddQuestion(question)
msg, err := query.Encode()
···
var response magna.Message
158
-
err = response.Decode(p)
181
+
if err := response.Decode(p); err != nil {
182
+
return magna.Message{}, err
185
+
if err := validateResponse(*query, response, question); err != nil {
186
+
return magna.Message{}, err
191
+
func validateResponse(query magna.Message, response magna.Message, question magna.Question) error {
192
+
if response.Header.ID != query.Header.ID {
193
+
return errNonMatchingID
195
+
if len(response.Question) < 1 || response.Question[0] != question {
196
+
return errNonMatchingQuestion
func ExtractAnswer(q magna.Question, r magna.Message) (bool, []magna.ResourceRecord) {
answers := make([]magna.ResourceRecord, 0, r.Header.ANCount)
for _, a := range r.Answer {
if a.RClass == q.QClass && strings.ToLower(a.Name) == strings.ToLower(q.QName) {
205
+
answers = append(answers, a)
209
+
if len(answers) <= 0 {
210
+
return false, []magna.ResourceRecord{}
213
+
return true, answers
216
+
func ExtractSOA(r magna.Message) (bool, []magna.ResourceRecord) {
217
+
answers := make([]magna.ResourceRecord, 0, r.Header.NSCount)
218
+
for _, a := range r.Authority {
219
+
if a.RType == magna.SOAType {
answers = append(answers, a)