-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsql.go
90 lines (75 loc) · 2.08 KB
/
sql.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
package sql
import (
"bytes"
"fmt"
"net/url"
"github.com/alecthomas/template"
"github.com/coredns/coredns/plugin"
"github.com/coredns/coredns/plugin/pkg/dnsutil"
"github.com/coredns/coredns/request"
"github.com/glerchundi/coredns-sql/query"
"github.com/miekg/dns"
"golang.org/x/net/context"
)
const (
name = "sql"
)
// SQL is the plugin handler
type SQL struct {
Next plugin.Handler
Queryer query.Queryer
Queries map[uint16]*template.Template
Config *SQLConfig
}
type SQLConfig struct {
Zones []string
URL *url.URL
TLSArgs []string
Queries map[uint16]string
}
// ServeDNS implements the plugin.Handle interface.
func (d *SQL) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) {
state := request.Request{W: w, Req: r, Context: ctx}
zone := plugin.Zones(d.Config.Zones).Matches(state.Name())
if zone == "" {
return plugin.NextOrFailure(d.Name(), d.Next, ctx, w, r)
}
qtype := state.QType()
queryTemplate, ok := d.Queries[qtype]
if !ok {
return plugin.NextOrFailure(d.Name(), d.Next, ctx, w, r)
}
var queryRendered bytes.Buffer
err := queryTemplate.Execute(&queryRendered, struct {
Name string
Type uint16
}{Name: state.QName(), Type: qtype})
if err != nil {
return dns.RcodeServerFailure, plugin.Error(d.Name(), err)
}
records, err := d.Queryer.Query(queryRendered.String(), query.Scan(qtype))
if err != nil {
return dns.RcodeServerFailure, plugin.Error(d.Name(), err)
}
m := new(dns.Msg)
m.SetReply(r)
m.Authoritative, m.RecursionAvailable, m.Compress = true, true, true
m.Answer = append(m.Answer, records...)
m = dnsutil.Dedup(m)
state.SizeAndDo(m)
m, _ = state.Scrub(m)
w.WriteMsg(m)
return dns.RcodeSuccess, nil
}
// Name implements the Handler interface.
func (d *SQL) Name() string { return name }
func newDatabaseQueryer(u *url.URL, tlsArgs ...string) (query.Queryer, error) {
switch u.Scheme {
case "postgres", "postgresql":
return query.NewPostgresQueryer(u, tlsArgs...)
case "mysql":
return query.NewMySQLQueryer(u, tlsArgs...)
default:
return nil, fmt.Errorf("unsupported scheme: '%s'", u.Scheme)
}
}