diff --git a/plugin/acl/acl.go b/plugin/acl/acl.go index e684dc42c..9a7a8077d 100644 --- a/plugin/acl/acl.go +++ b/plugin/acl/acl.go @@ -3,9 +3,11 @@ package acl import ( "context" "net" + "strings" "github.com/coredns/coredns/plugin" "github.com/coredns/coredns/plugin/metrics" + clog "github.com/coredns/coredns/plugin/pkg/log" "github.com/coredns/coredns/request" "github.com/infobloxopen/go-trees/iptree" @@ -49,6 +51,8 @@ const ( actionFilter ) +var log = clog.NewWithPlugin("acl") + // ServeDNS implements the plugin.Handler interface. func (a ACL) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) { state := request.Request{W: w, Req: r} @@ -96,7 +100,19 @@ RulesCheckLoop: func matchWithPolicies(policies []policy, w dns.ResponseWriter, r *dns.Msg) action { state := request.Request{W: w, Req: r} - ip := net.ParseIP(state.IP()) + var ip net.IP + if idx := strings.IndexByte(state.IP(), '%'); idx >= 0 { + ip = net.ParseIP(state.IP()[:idx]) + } else { + ip = net.ParseIP(state.IP()) + } + + // if the parsing did not return a proper response then we simply return 'actionBlock' to + // block the query + if ip == nil { + log.Errorf("Blocking request. Unable to parse source address: %v", state.IP()) + return actionBlock + } qtype := state.QType() for _, policy := range policies { // dns.TypeNone matches all query types. diff --git a/plugin/acl/acl_test.go b/plugin/acl/acl_test.go index 0ab6c1d77..7b641cef5 100644 --- a/plugin/acl/acl_test.go +++ b/plugin/acl/acl_test.go @@ -19,6 +19,10 @@ func (t *testResponseWriter) setRemoteIP(ip string) { t.RemoteIP = ip } +func (t *testResponseWriter) setZone(zone string) { + t.Zone = zone +} + // WriteMsg implement dns.ResponseWriter interface. func (t *testResponseWriter) WriteMsg(m *dns.Msg) error { t.Rcode = m.Rcode @@ -392,6 +396,20 @@ func TestACLServeDNS(t *testing.T) { dns.RcodeSuccess, false, }, + { + "Blacklist Address%ifname", + `acl example.org { + block type AAAA net 2001:0db8:85a3:0000:0000:8a2e:0370:7334 + }`, + []string{"eth0"}, + args{ + "www.example.org.", + "2001:0db8:85a3:0000:0000:8a2e:0370:7334", + dns.TypeAAAA, + }, + dns.RcodeRefused, + false, + }, } ctx := context.Background() @@ -408,6 +426,9 @@ func TestACLServeDNS(t *testing.T) { w := &testResponseWriter{} m := new(dns.Msg) w.setRemoteIP(tt.args.sourceIP) + if len(tt.zones) > 0 { + w.setZone(tt.zones[0]) + } m.SetQuestion(tt.args.domain, tt.args.qtype) _, err = a.ServeDNS(ctx, w, m) if (err != nil) != tt.wantErr { diff --git a/plugin/test/responsewriter.go b/plugin/test/responsewriter.go index c66b0c969..32167008a 100644 --- a/plugin/test/responsewriter.go +++ b/plugin/test/responsewriter.go @@ -12,6 +12,7 @@ import ( type ResponseWriter struct { TCP bool // if TCP is true we return an TCP connection instead of an UDP one. RemoteIP string + Zone string } // LocalAddr returns the local address, 127.0.0.1:53 (UDP, TCP if t.TCP is true). @@ -33,9 +34,9 @@ func (t *ResponseWriter) RemoteAddr() net.Addr { ip := net.ParseIP(remoteIP) port := 40212 if t.TCP { - return &net.TCPAddr{IP: ip, Port: port, Zone: ""} + return &net.TCPAddr{IP: ip, Port: port, Zone: t.Zone} } - return &net.UDPAddr{IP: ip, Port: port, Zone: ""} + return &net.UDPAddr{IP: ip, Port: port, Zone: t.Zone} } // WriteMsg implements dns.ResponseWriter interface.