-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathhttps.go
98 lines (81 loc) · 2.41 KB
/
https.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
// Package https implements a plugin that performs DNS-over-HTTPS proxying.
//
// See: RFC 8484 (https://tools.ietf.org/html/rfc8484)
package https
import (
"context"
"github.com/coredns/coredns/plugin"
"github.com/coredns/coredns/plugin/debug"
"github.com/coredns/coredns/request"
"github.com/miekg/dns"
)
// HTTPS represents a plugin instance that can proxy requests to another (DNS) server via DoH protocol.
// It has a list of proxies each representing one upstream proxy
type HTTPS struct {
from string
except []string
client dnsClient
Next plugin.Handler
}
type httpsOption func(h *HTTPS)
func withExcept(except []string) httpsOption {
return func(h *HTTPS) {
h.except = except
}
}
// newHTTPS returns a new HTTPS.
func newHTTPS(from string, client dnsClient, opts ...httpsOption) *HTTPS {
h := &HTTPS{from: from, client: client}
for _, o := range opts {
o(h)
}
return h
}
// Assert that HTTPS struct conforms to the plugin.Handler interface
var _ plugin.Handler = (*HTTPS)(nil)
// Name implements plugin.Handler.
func (*HTTPS) Name() string { return "https" }
// ServeDNS implements plugin.Handler.
func (h *HTTPS) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (status int, err error) {
state := request.Request{W: w, Req: r}
if !h.match(state) {
return plugin.NextOrFailure(h.Name(), h.Next, ctx, w, r)
}
dnsreq, err := r.Pack()
if err != nil {
return dns.RcodeServerFailure, err
}
result, err := h.client.Query(ctx, dnsreq)
if err != nil {
return dns.RcodeServerFailure, err
}
// Check if the reply is correct; if not return FormErr.
// maybe useful to extract this logic from forward, grpc and https plugins to common place
if !state.Match(result) {
debug.Hexdumpf(result, "Wrong reply for id: %d, %s %d", result.Id, state.QName(), state.QType())
formerr := new(dns.Msg)
formerr.SetRcode(state.Req, dns.RcodeFormatError)
err = w.WriteMsg(formerr)
return
}
err = w.WriteMsg(result)
return
}
// TODO extract this logic from forward, grpc and https plugins to common place
func (h *HTTPS) match(state request.Request) bool {
if !plugin.Name(h.from).Matches(state.Name()) || !h.isAllowedDomain(state.Name()) {
return false
}
return true
}
func (h *HTTPS) isAllowedDomain(name string) bool {
if dns.Name(name) == dns.Name(h.from) {
return true
}
for _, ignore := range h.except {
if plugin.Name(ignore).Matches(name) {
return false
}
}
return true
}