mirror of
https://github.com/linka-cloud/coredns-split.git
synced 2024-12-30 13:00:46 +00:00
add fallback nameserver, rework configuration
Signed-off-by: Adphi <philippe.adrien.nousse@gmail.com>
This commit is contained in:
parent
5bb565b2ab
commit
14e35b5a5e
24
README.md
24
README.md
@ -63,17 +63,27 @@ This plugin reports readiness to the ready plugin. It will be immediately ready.
|
||||
|
||||
## Examples
|
||||
|
||||
In this configuration, we forward all queries to 9.9.9.9 and filter out A records pointing to an IP address
|
||||
in the 10.10.10.0/24 network except for queries coming from the 192.168.0.0/24 and 192.168.1.0/24 networks.
|
||||
In this configuration, we forward all queries to 10.10.10.1 and to 9.9.9.9 if 10.10.10.1 did not respond.
|
||||
|
||||
**If only used with the forward plugin, the private dns server must be configured as the first forwarded server in the list. Alose, the policy must be configured as sequential, so that the first server is always tried first and the second only if the first do not return any answer.**
|
||||
|
||||
We filter out A records pointing to an IP address in the 10.10.10.0/24 network except for queries coming from the 192.168.0.0/24 and 192.168.1.0/24 networks.
|
||||
If the allowed networks are not defined, the plugin will allow the requests from the same network, e.g. 10.10.10.0/24.
|
||||
|
||||
If the record exists both as public and private, the private record will be filtered, resulting with no records at all.
|
||||
So you can provide a fallback server that will be used to get the public record.
|
||||
|
||||
~~~ corefile
|
||||
. {
|
||||
example {
|
||||
10.10.10.0/24 {
|
||||
net 192.168.0.0/24 192.168.1.0/24
|
||||
}
|
||||
split {
|
||||
net 10.10.10.0/24 allow 192.168.0.0/24 192.168.1.0/24
|
||||
net 10.1.1.0/24 10.1.2.0/24 # implicitely: allow 10.1.1.0/24 10.1.2.0/24
|
||||
fallback 8.8.8.8
|
||||
}
|
||||
file example.org
|
||||
forward . 9.9.9.9 {
|
||||
policy sequential
|
||||
}
|
||||
forward . 9.9.9.9
|
||||
}
|
||||
~~~
|
||||
|
||||
|
15
example.org
Normal file
15
example.org
Normal file
@ -0,0 +1,15 @@
|
||||
$ORIGIN example.org.
|
||||
@ 3600 IN SOA ns1.example.org. hostmaster.example.org. (
|
||||
2003080800 ; serial number
|
||||
12h ; refresh
|
||||
15m ; update retry
|
||||
3w ; expiry
|
||||
2h ; minimum
|
||||
)
|
||||
ns1 IN A 127.0.0.1
|
||||
www IN A 100.100.100.10
|
||||
net1 IN A 10.10.10.10
|
||||
net2 IN A 10.1.1.10
|
||||
net2 IN A 12.12.12.10
|
||||
net3 IN A 10.1.2.10
|
||||
net3 IN A 12.12.13.10
|
114
go.mod
114
go.mod
@ -4,30 +4,118 @@ go 1.17
|
||||
|
||||
require (
|
||||
github.com/coredns/caddy v1.1.1
|
||||
github.com/coredns/coredns v1.9.1
|
||||
github.com/miekg/dns v1.1.47
|
||||
github.com/prometheus/client_golang v1.12.1
|
||||
github.com/coredns/coredns v1.10.0
|
||||
github.com/miekg/dns v1.1.50
|
||||
github.com/prometheus/client_golang v1.13.0
|
||||
)
|
||||
|
||||
require (
|
||||
cloud.google.com/go/compute v1.7.0 // indirect
|
||||
github.com/Azure/azure-sdk-for-go v66.0.0+incompatible // indirect
|
||||
github.com/Azure/go-autorest v14.2.0+incompatible // indirect
|
||||
github.com/Azure/go-autorest/autorest v0.11.28 // indirect
|
||||
github.com/Azure/go-autorest/autorest/adal v0.9.18 // indirect
|
||||
github.com/Azure/go-autorest/autorest/azure/auth v0.5.11 // indirect
|
||||
github.com/Azure/go-autorest/autorest/azure/cli v0.4.5 // indirect
|
||||
github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect
|
||||
github.com/Azure/go-autorest/autorest/to v0.2.0 // indirect
|
||||
github.com/Azure/go-autorest/logger v0.2.1 // indirect
|
||||
github.com/Azure/go-autorest/tracing v0.6.0 // indirect
|
||||
github.com/DataDog/datadog-agent/pkg/obfuscate v0.0.0-20211129110424-6491aa3bf583 // indirect
|
||||
github.com/DataDog/datadog-go v4.8.2+incompatible // indirect
|
||||
github.com/DataDog/datadog-go/v5 v5.0.2 // indirect
|
||||
github.com/DataDog/sketches-go v1.2.1 // indirect
|
||||
github.com/Microsoft/go-winio v0.5.1 // indirect
|
||||
github.com/PuerkitoBio/purell v1.1.1 // indirect
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
|
||||
github.com/antonmedv/expr v1.9.0 // indirect
|
||||
github.com/apparentlymart/go-cidr v1.1.0 // indirect
|
||||
github.com/aws/aws-sdk-go v1.44.95 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.1.2 // indirect
|
||||
github.com/coreos/go-semver v0.3.0 // indirect
|
||||
github.com/coreos/go-systemd/v22 v22.3.2 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/dgraph-io/ristretto v0.1.0 // indirect
|
||||
github.com/dimchansky/utfbom v1.1.1 // indirect
|
||||
github.com/dnstap/golang-dnstap v0.4.0 // indirect
|
||||
github.com/dustin/go-humanize v1.0.0 // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.8.0 // indirect
|
||||
github.com/farsightsec/golang-framestream v0.3.0 // indirect
|
||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 // indirect
|
||||
github.com/go-logr/logr v1.2.3 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.19.5 // indirect
|
||||
github.com/go-openapi/jsonreference v0.19.5 // indirect
|
||||
github.com/go-openapi/swag v0.19.14 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang-jwt/jwt/v4 v4.2.0 // indirect
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/google/gnostic v0.5.7-v3refs // indirect
|
||||
github.com/google/go-cmp v0.5.8 // indirect
|
||||
github.com/google/gofuzz v1.2.0 // indirect
|
||||
github.com/google/uuid v1.3.0 // indirect
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.1.0 // indirect
|
||||
github.com/googleapis/gax-go/v2 v2.4.0 // indirect
|
||||
github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645 // indirect
|
||||
github.com/imdario/mergo v0.3.12 // indirect
|
||||
github.com/infobloxopen/go-trees v0.0.0-20200715205103-96a057b8dfb9 // indirect
|
||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492 // indirect
|
||||
github.com/opentracing/opentracing-go v1.2.0 // indirect
|
||||
github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5 // indirect
|
||||
github.com/openzipkin/zipkin-go v0.4.0 // indirect
|
||||
github.com/oschwald/geoip2-golang v1.8.0 // indirect
|
||||
github.com/oschwald/maxminddb-golang v1.10.0 // indirect
|
||||
github.com/philhofer/fwd v1.1.1 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/prometheus/client_model v0.2.0 // indirect
|
||||
github.com/prometheus/common v0.32.1 // indirect
|
||||
github.com/prometheus/procfs v0.7.3 // indirect
|
||||
golang.org/x/mod v0.4.2 // indirect
|
||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd // indirect
|
||||
golang.org/x/sys v0.0.0-20220209214540-3681064d5158 // indirect
|
||||
github.com/prometheus/common v0.37.0 // indirect
|
||||
github.com/prometheus/procfs v0.8.0 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/tinylib/msgp v1.1.2 // indirect
|
||||
go.etcd.io/etcd/api/v3 v3.5.4 // indirect
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.4 // indirect
|
||||
go.etcd.io/etcd/client/v3 v3.5.4 // indirect
|
||||
go.opencensus.io v0.23.0 // indirect
|
||||
go.uber.org/atomic v1.9.0 // indirect
|
||||
go.uber.org/multierr v1.6.0 // indirect
|
||||
go.uber.org/zap v1.17.0 // indirect
|
||||
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa // indirect
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b // indirect
|
||||
golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094 // indirect
|
||||
golang.org/x/sys v0.0.0-20220804214406-8e32c043e418 // indirect
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
||||
google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c // indirect
|
||||
google.golang.org/grpc v1.44.0 // indirect
|
||||
google.golang.org/protobuf v1.27.1 // indirect
|
||||
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect
|
||||
golang.org/x/tools v0.1.12 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f // indirect
|
||||
google.golang.org/api v0.95.0 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f // indirect
|
||||
google.golang.org/grpc v1.49.0 // indirect
|
||||
google.golang.org/protobuf v1.28.1 // indirect
|
||||
gopkg.in/DataDog/dd-trace-go.v1 v1.41.0 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
k8s.io/api v0.25.0 // indirect
|
||||
k8s.io/apimachinery v0.25.0 // indirect
|
||||
k8s.io/client-go v0.24.4 // indirect
|
||||
k8s.io/klog/v2 v2.80.1 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20220803162953-67bda5d908f1 // indirect
|
||||
k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed // indirect
|
||||
sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect
|
||||
sigs.k8s.io/yaml v1.2.0 // indirect
|
||||
)
|
||||
|
75
setup.go
75
setup.go
@ -14,40 +14,67 @@ func init() { plugin.Register("split", setup) }
|
||||
// setup is the function that gets called when the config parser see the token "example". Setup is responsible
|
||||
// for parsing any extra options the example plugin may have. The first token this function sees is "example".
|
||||
func setup(c *caddy.Controller) error {
|
||||
s := Split{}
|
||||
var s Split
|
||||
for c.Next() {
|
||||
r := rule{}
|
||||
args := c.RemainingArgs()
|
||||
r.zones = plugin.OriginsFromArgsOrServerBlock(args, c.ServerBlockKeys)
|
||||
if c.NextBlock() {
|
||||
n := network{}
|
||||
_, ipnet, err := net.ParseCIDR(c.Val())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
n.record = ipnet
|
||||
for c.NextBlock() {
|
||||
for c.NextLine() {
|
||||
a := c.Val()
|
||||
_ = a
|
||||
argsLoop:
|
||||
for _, v := range c.RemainingArgs() {
|
||||
r := Rule{
|
||||
Zones: plugin.OriginsFromArgsOrServerBlock(c.RemainingArgs(), c.ServerBlockKeys),
|
||||
}
|
||||
log.Debug("zones", r.Zones)
|
||||
for c.NextBlock() {
|
||||
prop := c.Val()
|
||||
args := c.RemainingArgs()
|
||||
switch prop {
|
||||
case "net":
|
||||
log.Debug("net", args)
|
||||
if len(args) == 0 {
|
||||
return c.Errf("net: expected at least 1 argument, got 0")
|
||||
}
|
||||
var nets []*net.IPNet
|
||||
var allow bool
|
||||
var allowNets []*net.IPNet
|
||||
for _, v := range args {
|
||||
switch v {
|
||||
case "allow":
|
||||
allow = true
|
||||
default:
|
||||
_, ipnet, err := net.ParseCIDR(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, vv := range n.allowed {
|
||||
if vv.Contains(ipnet.IP) {
|
||||
continue argsLoop
|
||||
}
|
||||
if allow {
|
||||
allowNets = append(allowNets, ipnet)
|
||||
} else {
|
||||
nets = append(nets, ipnet)
|
||||
}
|
||||
n.allowed = append(n.allowed, ipnet)
|
||||
}
|
||||
}
|
||||
r.networks = append(r.networks, n)
|
||||
if len(allowNets) == 0 {
|
||||
allowNets = nets[:]
|
||||
}
|
||||
for _, v := range nets {
|
||||
r.Networks = append(r.Networks, Network{
|
||||
RecordNetwork: v,
|
||||
Allowed: allowNets,
|
||||
})
|
||||
}
|
||||
case "fallback":
|
||||
log.Debug("fallback", args)
|
||||
if r.Fallback != nil {
|
||||
return c.Errf("fallback already set")
|
||||
}
|
||||
if len(args) != 1 {
|
||||
return c.Errf("fallback: expected 1 argument, got %d", len(args))
|
||||
}
|
||||
ip := net.ParseIP(args[0])
|
||||
if ip == nil {
|
||||
return c.Errf("fallback: invalid IP %s", args[0])
|
||||
}
|
||||
r.Fallback = ip
|
||||
default:
|
||||
return c.Errf("unknown property '%s'", prop)
|
||||
}
|
||||
s.Rule = append(s.Rule, r)
|
||||
}
|
||||
s.Rules = append(s.Rules, r)
|
||||
}
|
||||
|
||||
// Add the Plugin to CoreDNS, so Servers can use it in their plugin chain.
|
||||
|
45
split.go
45
split.go
@ -22,17 +22,18 @@ var log = clog.NewWithPlugin("split")
|
||||
type Split struct {
|
||||
Next plugin.Handler
|
||||
|
||||
Rule []rule
|
||||
Rules []Rule
|
||||
}
|
||||
|
||||
type rule struct {
|
||||
zones []string
|
||||
networks []network
|
||||
type Rule struct {
|
||||
Zones []string
|
||||
Networks []Network
|
||||
Fallback net.IP
|
||||
}
|
||||
|
||||
type network struct {
|
||||
record *net.IPNet
|
||||
allowed []*net.IPNet
|
||||
type Network struct {
|
||||
RecordNetwork *net.IPNet
|
||||
Allowed []*net.IPNet
|
||||
}
|
||||
|
||||
// ServeDNS implements the plugin.Handler interface. This method gets called when example is used
|
||||
@ -65,21 +66,21 @@ type ResponsePrinter struct {
|
||||
state request.Request
|
||||
r *dns.Msg
|
||||
src net.IP
|
||||
rules []rule
|
||||
rules []Rule
|
||||
}
|
||||
|
||||
// NewResponsePrinter returns ResponseWriter.
|
||||
func (s Split) NewResponsePrinter(w dns.ResponseWriter, r *dns.Msg) *ResponsePrinter {
|
||||
state := request.Request{W: w, Req: r}
|
||||
ip := net.ParseIP(state.IP())
|
||||
return &ResponsePrinter{ResponseWriter: w, r: r, src: ip, rules: s.Rule, state: state}
|
||||
return &ResponsePrinter{ResponseWriter: w, r: r, src: ip, rules: s.Rules, state: state}
|
||||
}
|
||||
|
||||
// WriteMsg calls the underlying ResponseWriter's WriteMsg method and prints "example" to standard output.
|
||||
func (r *ResponsePrinter) WriteMsg(res *dns.Msg) error {
|
||||
var rule rule
|
||||
var rule Rule
|
||||
for _, v := range r.rules {
|
||||
zone := plugin.Zones(v.zones).Matches(r.state.Name())
|
||||
zone := plugin.Zones(v.Zones).Matches(r.state.Name())
|
||||
if zone == "" {
|
||||
continue
|
||||
}
|
||||
@ -94,9 +95,9 @@ func (r *ResponsePrinter) WriteMsg(res *dns.Msg) error {
|
||||
answers = append(answers, v)
|
||||
continue
|
||||
}
|
||||
var net *network
|
||||
for _, vv := range rule.networks {
|
||||
if vv.record.Contains(rec.A) {
|
||||
var net *Network
|
||||
for _, vv := range rule.Networks {
|
||||
if vv.RecordNetwork.Contains(rec.A) {
|
||||
net = &vv
|
||||
break
|
||||
}
|
||||
@ -106,7 +107,7 @@ func (r *ResponsePrinter) WriteMsg(res *dns.Msg) error {
|
||||
continue
|
||||
}
|
||||
allowed := false
|
||||
for _, vv := range net.allowed {
|
||||
for _, vv := range net.Allowed {
|
||||
if vv.Contains(r.src) {
|
||||
allowed = true
|
||||
break
|
||||
@ -124,5 +125,19 @@ func (r *ResponsePrinter) WriteMsg(res *dns.Msg) error {
|
||||
} else {
|
||||
res.Answer = answers
|
||||
}
|
||||
if len(res.Answer) != 0 {
|
||||
return r.ResponseWriter.WriteMsg(res)
|
||||
}
|
||||
if rule.Fallback == nil {
|
||||
return nil
|
||||
}
|
||||
c := new(dns.Client)
|
||||
req := r.state.Req.Copy()
|
||||
req.Id = dns.Id()
|
||||
in, _, err := c.Exchange(req, rule.Fallback.String()+":53")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
res.Answer = append(res.Answer, in.Answer...)
|
||||
return r.ResponseWriter.WriteMsg(res)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user