blackholing & prom
This commit is contained in:
parent
b11d4ede6c
commit
1e6c04ce76
6 changed files with 165 additions and 4 deletions
31
blackhole.go
31
blackhole.go
|
@ -1,6 +1,25 @@
|
|||
package pancheri
|
||||
|
||||
import "slices"
|
||||
import (
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
"slices"
|
||||
)
|
||||
|
||||
var (
|
||||
blockedDomains = promauto.NewGauge(prometheus.GaugeOpts{
|
||||
Name: "pancheri_blackhole_blocked_domains_total",
|
||||
Help: "Number of blocked domains on the blackhole blocklist",
|
||||
})
|
||||
blockHits = promauto.NewCounter(prometheus.CounterOpts{
|
||||
Name: "pancheri_blackhole_block_hits_total",
|
||||
Help: "Number of requests that have hit the blocklist",
|
||||
})
|
||||
blockMisses = promauto.NewCounter(prometheus.CounterOpts{
|
||||
Name: "pancheri_blackhole_misses_total",
|
||||
Help: "Number of requests that have missed the blocklist",
|
||||
})
|
||||
)
|
||||
|
||||
type BlackholeFile struct {
|
||||
DenyDomains []string `yaml:"deny_domains"`
|
||||
|
@ -11,5 +30,13 @@ type Blackholer struct {
|
|||
}
|
||||
|
||||
func (b *Blackholer) ShouldBlock(domain string) bool {
|
||||
return slices.Contains(b.DenyDomains, domain)
|
||||
blockedDomains.Set(float64(len(b.DenyDomains)))
|
||||
blocked := slices.Contains(b.DenyDomains, domain)
|
||||
if blocked {
|
||||
blockHits.Inc()
|
||||
} else {
|
||||
blockMisses.Inc()
|
||||
}
|
||||
|
||||
return blocked
|
||||
}
|
||||
|
|
|
@ -51,6 +51,18 @@ func main() {
|
|||
zones[authoritativeZone] = zone
|
||||
}
|
||||
|
||||
logrus.WithFields(logrus.Fields{
|
||||
"port": "2112",
|
||||
}).Info("starting promhttp listener")
|
||||
|
||||
go func() {
|
||||
err := pancheri.PromMain()
|
||||
if err != nil {
|
||||
logrus.Errorf("error in prom listener: %s", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}()
|
||||
|
||||
logrus.WithFields(logrus.Fields{
|
||||
"host": c.Server.Host,
|
||||
"port": c.Server.Port,
|
||||
|
@ -74,7 +86,7 @@ func main() {
|
|||
}).Info("enabling blackholer")
|
||||
|
||||
b = &pancheri.Blackholer{
|
||||
DenyDomains: *new([]string),
|
||||
DenyDomains: []string{},
|
||||
}
|
||||
|
||||
for _, file := range c.Blackhole.BlockLists {
|
||||
|
@ -104,6 +116,10 @@ func main() {
|
|||
logrus.WithFields(logrus.Fields{
|
||||
"file": file,
|
||||
}).Infof("loaded %d hosts", len(cfg.DenyDomains))
|
||||
|
||||
if !b.ShouldBlock("eu1.clevertap-prod.com") {
|
||||
logrus.Errorf("failed sanity check!")
|
||||
}
|
||||
}
|
||||
|
||||
logrus.WithFields(logrus.Fields{
|
||||
|
@ -117,6 +133,7 @@ func main() {
|
|||
A: &pancheri.Authority{
|
||||
Zones: zones,
|
||||
},
|
||||
B: b,
|
||||
}
|
||||
server := &dns.Server{
|
||||
Addr: c.Server.Host + ":" + c.Server.Port,
|
||||
|
|
9
go.mod
9
go.mod
|
@ -3,11 +3,20 @@ module git.e3t.cc/e3team/pancheri
|
|||
go 1.21
|
||||
|
||||
require (
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
|
||||
github.com/miekg/dns v1.1.56 // indirect
|
||||
github.com/prometheus/client_golang v1.17.0 // indirect
|
||||
github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 // indirect
|
||||
github.com/prometheus/common v0.44.0 // indirect
|
||||
github.com/prometheus/procfs v0.11.1 // indirect
|
||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||
golang.org/x/mod v0.12.0 // indirect
|
||||
golang.org/x/net v0.15.0 // indirect
|
||||
golang.org/x/sys v0.12.0 // indirect
|
||||
golang.org/x/tools v0.13.0 // indirect
|
||||
google.golang.org/protobuf v1.31.0 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
)
|
||||
|
|
25
go.sum
25
go.sum
|
@ -1,8 +1,27 @@
|
|||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
||||
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
|
||||
github.com/miekg/dns v1.1.56 h1:5imZaSeoRNvpM9SzWNhEcP9QliKiz20/dA2QabIGVnE=
|
||||
github.com/miekg/dns v1.1.56/go.mod h1:cRm6Oo2C8TY9ZS/TqsSrseAcncm74lfK5G+ikN2SWWY=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q=
|
||||
github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY=
|
||||
github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 h1:v7DLqVdK4VrYkVD5diGdl4sxJurKJEMnODWRJlxV9oM=
|
||||
github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU=
|
||||
github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY=
|
||||
github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY=
|
||||
github.com/prometheus/procfs v0.11.1 h1:xRC8Iq1yyca5ypa9n1EZnWZkt7dwcoRPQwX/5gwaUuI=
|
||||
github.com/prometheus/procfs v0.11.1/go.mod h1:eesXgaPo1q7lBpVMoMy0ZOFTth9hBn4W/y0/p/ScXhY=
|
||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
|
@ -11,11 +30,17 @@ golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
|
|||
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8=
|
||||
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
|
||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ=
|
||||
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
|
||||
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
|
|
73
handler.go
73
handler.go
|
@ -2,6 +2,8 @@ package pancheri
|
|||
|
||||
import (
|
||||
"github.com/miekg/dns"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
"github.com/sirupsen/logrus"
|
||||
"strings"
|
||||
)
|
||||
|
@ -13,14 +15,58 @@ type Handler struct {
|
|||
B *Blackholer
|
||||
}
|
||||
|
||||
func (h *Handler) ServeDNS(w dns.ResponseWriter, r *dns.Msg) {
|
||||
var (
|
||||
numberOfRequests = promauto.NewCounter(prometheus.CounterOpts{
|
||||
Name: "pancheri_handler_requests_total",
|
||||
Help: "Number of DNS requests that have been handled by pancheri",
|
||||
})
|
||||
numberOfARequests = promauto.NewCounter(prometheus.CounterOpts{
|
||||
Name: "pancheri_handler_a_requests_total",
|
||||
Help: "Number of type A DNS requests that have been handled by pancheri",
|
||||
})
|
||||
numberOfARequestsResultingInCNAME = promauto.NewCounter(prometheus.CounterOpts{
|
||||
Name: "pancheri_handler_a_to_cname_requests_total",
|
||||
Help: "Number of type A DNS requests that resolved as a CNAME that have been handled by pancheri",
|
||||
})
|
||||
numberOfAAAARequests = promauto.NewCounter(prometheus.CounterOpts{
|
||||
Name: "pancheri_handler_aaaa_requests_total",
|
||||
Help: "Number of type A DNS requests that have been handled by pancheri",
|
||||
})
|
||||
numberOfAAAARequestsResultingInCNAME = promauto.NewCounter(prometheus.CounterOpts{
|
||||
Name: "pancheri_handler_aaaa_to_cname_requests_total",
|
||||
Help: "Number of type AAAA DNS requests that resolved as a CNAME that have been handled by pancheri",
|
||||
})
|
||||
numberOfCNAMERequests = promauto.NewCounter(prometheus.CounterOpts{
|
||||
Name: "pancheri_handler_cname_requests_total",
|
||||
Help: "Number of type CNAME DNS requests that have been handled by pancheri",
|
||||
})
|
||||
numberOfTXTRequests = promauto.NewCounter(prometheus.CounterOpts{
|
||||
Name: "pancheri_handler_txt_requests_total",
|
||||
Help: "Number of type CNAME DNS requests that have been handled by pancheri",
|
||||
})
|
||||
numberOfUnsupportedRequests = promauto.NewCounter(prometheus.CounterOpts{
|
||||
Name: "pancheri_handler_unsupported_requests_total",
|
||||
Help: "Number of unsupported type requests that have been handled by pancheri",
|
||||
})
|
||||
numberOfMultiQuestionRequests = promauto.NewCounter(prometheus.CounterOpts{
|
||||
Name: "pancheri_handler_multiq_requests_total",
|
||||
Help: "Number of unsupported multi-question requests that have been handled by pancheri",
|
||||
})
|
||||
numberOfUpstreamedRequests = promauto.NewCounter(prometheus.CounterOpts{
|
||||
Name: "pancheri_handler_upstreamed_requests_total",
|
||||
Help: "Number of requests that were sent upstream",
|
||||
})
|
||||
)
|
||||
|
||||
func (h *Handler) ServeDNS(w dns.ResponseWriter, r *dns.Msg) {
|
||||
numberOfRequests.Inc()
|
||||
// figure out how we should resolve this
|
||||
msg := new(dns.Msg)
|
||||
msg.SetReply(r)
|
||||
msg.Authoritative = true
|
||||
|
||||
if len(r.Question) != 1 {
|
||||
numberOfMultiQuestionRequests.Inc()
|
||||
msg.Rcode = dns.RcodeFormatError
|
||||
err := w.WriteMsg(msg)
|
||||
if err != nil {
|
||||
|
@ -32,6 +78,23 @@ func (h *Handler) ServeDNS(w dns.ResponseWriter, r *dns.Msg) {
|
|||
|
||||
q := r.Question[0]
|
||||
|
||||
// is it blackholed?
|
||||
if h.B.ShouldBlock(strings.TrimRight(q.Name, ".")) {
|
||||
// return nxdomain
|
||||
// alright, send an nxdomain
|
||||
if r.RecursionDesired {
|
||||
msg.RecursionAvailable = true
|
||||
}
|
||||
msg.Rcode = dns.RcodeNameError
|
||||
|
||||
err := w.WriteMsg(msg)
|
||||
if err != nil {
|
||||
logrus.Errorf("error responding: %s", err)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// is it ours?
|
||||
for authority, zone := range h.A.Zones {
|
||||
if strings.HasSuffix(q.Name, authority) {
|
||||
|
@ -44,11 +107,13 @@ func (h *Handler) ServeDNS(w dns.ResponseWriter, r *dns.Msg) {
|
|||
}).Trace("responding to query for authoritative zone")
|
||||
|
||||
if q.Qtype == dns.TypeA {
|
||||
numberOfARequests.Inc()
|
||||
record, ok := zone.ARecords[q.Name]
|
||||
if !ok {
|
||||
// SPECIAL CASE: for A and AAAA records, return with a CNAME if and only if that cname exists
|
||||
cname, cok := zone.CNAMERecords[q.Name]
|
||||
if cok {
|
||||
numberOfARequestsResultingInCNAME.Inc()
|
||||
// return with the CNAME record instead and resolve the CNAME
|
||||
rendered := cname.Render()
|
||||
msg.Rcode = dns.RcodeSuccess
|
||||
|
@ -125,10 +190,12 @@ func (h *Handler) ServeDNS(w dns.ResponseWriter, r *dns.Msg) {
|
|||
return
|
||||
} else if q.Qtype == dns.TypeAAAA {
|
||||
record, ok := zone.AAAARecords[q.Name]
|
||||
numberOfAAAARequests.Inc()
|
||||
if !ok {
|
||||
// SPECIAL CASE: for A and AAAA records, return with a CNAME if and only if that cname exists
|
||||
cname, cok := zone.CNAMERecords[q.Name]
|
||||
if cok {
|
||||
numberOfAAAARequestsResultingInCNAME.Inc()
|
||||
// return with the CNAME record instead and resolve the CNAME
|
||||
rendered := cname.Render()
|
||||
msg.Rcode = dns.RcodeSuccess
|
||||
|
@ -205,6 +272,7 @@ func (h *Handler) ServeDNS(w dns.ResponseWriter, r *dns.Msg) {
|
|||
}
|
||||
return
|
||||
} else if q.Qtype == dns.TypeCNAME {
|
||||
numberOfCNAMERequests.Inc()
|
||||
record, ok := zone.CNAMERecords[q.Name]
|
||||
if !ok {
|
||||
// send an nxdomain
|
||||
|
@ -235,6 +303,7 @@ func (h *Handler) ServeDNS(w dns.ResponseWriter, r *dns.Msg) {
|
|||
}
|
||||
return
|
||||
} else if q.Qtype == dns.TypeTXT {
|
||||
numberOfTXTRequests.Inc()
|
||||
record, ok := zone.TXTRecords[q.Name]
|
||||
if !ok {
|
||||
// send an nxdomain
|
||||
|
@ -265,6 +334,7 @@ func (h *Handler) ServeDNS(w dns.ResponseWriter, r *dns.Msg) {
|
|||
}
|
||||
return
|
||||
} else {
|
||||
numberOfUnsupportedRequests.Inc()
|
||||
// not supported
|
||||
logrus.WithFields(logrus.Fields{
|
||||
"name": q.Name,
|
||||
|
@ -288,6 +358,7 @@ func (h *Handler) ServeDNS(w dns.ResponseWriter, r *dns.Msg) {
|
|||
}
|
||||
// no. do we have upstream resolution enabled?
|
||||
if h.C.Resolver.Enable {
|
||||
numberOfUpstreamedRequests.Inc()
|
||||
// alright, resolve it with the resolver
|
||||
resp, err := h.R.Resolve(q.Name, q.Qtype)
|
||||
resp.SetReply(r)
|
||||
|
|
12
stats.go
Normal file
12
stats.go
Normal file
|
@ -0,0 +1,12 @@
|
|||
package pancheri
|
||||
|
||||
import (
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func PromMain() error {
|
||||
http.Handle("/metrics", promhttp.Handler())
|
||||
err := http.ListenAndServe(":2112", nil)
|
||||
return err
|
||||
}
|
Loading…
Reference in a new issue