plugin/acl : add support for Extended DNS Errors (#5532)

* plugin/acl : add support for Extended DNS Errors

Signed-off-by: Ondřej Benkovský <ondrej.benkovsky@jamf.com>

* fixup! plugin/acl : add support for Extended DNS Errors

Signed-off-by: Ondřej Benkovský <ondrej.benkovsky@jamf.com>
This commit is contained in:
Ondřej Benkovský 2022-07-25 16:44:13 +02:00 committed by GitHub
parent 50beb677ad
commit 2fe5273cd1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 247 additions and 235 deletions

View file

@ -69,8 +69,11 @@ RulesCheckLoop:
switch action {
case actionBlock:
{
m := new(dns.Msg)
m.SetRcode(r, dns.RcodeRefused)
m := new(dns.Msg).
SetRcode(r, dns.RcodeRefused).
SetEdns0(4096, true)
ede := dns.EDNS0_EDE{InfoCode: dns.ExtendedErrorCodeBlocked}
m.IsEdns0().Option = append(m.IsEdns0().Option, &ede)
w.WriteMsg(m)
RequestBlockCount.WithLabelValues(metrics.WithServer(ctx), zone).Inc()
return dns.RcodeSuccess, nil
@ -81,8 +84,11 @@ RulesCheckLoop:
}
case actionFilter:
{
m := new(dns.Msg)
m.SetRcode(r, dns.RcodeSuccess)
m := new(dns.Msg).
SetRcode(r, dns.RcodeSuccess).
SetEdns0(4096, true)
ede := dns.EDNS0_EDE{InfoCode: dns.ExtendedErrorCodeFiltered}
m.IsEdns0().Option = append(m.IsEdns0().Option, &ede)
w.WriteMsg(m)
RequestFilterCount.WithLabelValues(metrics.WithServer(ctx), zone).Inc()
return dns.RcodeSuccess, nil

View file

@ -13,6 +13,7 @@ import (
type testResponseWriter struct {
test.ResponseWriter
Rcode int
Msg *dns.Msg
}
func (t *testResponseWriter) setRemoteIP(ip string) {
@ -26,6 +27,7 @@ func (t *testResponseWriter) setZone(zone string) {
// WriteMsg implement dns.ResponseWriter interface.
func (t *testResponseWriter) WriteMsg(m *dns.Msg) error {
t.Rcode = m.Rcode
t.Msg = m
return nil
}
@ -42,373 +44,363 @@ func TestACLServeDNS(t *testing.T) {
qtype uint16
}
tests := []struct {
name string
config string
zones []string
args args
wantRcode int
wantErr bool
name string
config string
zones []string
args args
wantRcode int
wantErr bool
wantExtendedErrorCode uint16
}{
// IPv4 tests.
{
"Blacklist 1 BLOCKED",
`acl example.org {
name: "Blacklist 1 BLOCKED",
config: `acl example.org {
block type A net 192.168.0.0/16
}`,
[]string{},
args{
"www.example.org.",
"192.168.0.2",
dns.TypeA,
zones: []string{},
args: args{
domain: "www.example.org.",
sourceIP: "192.168.0.2",
qtype: dns.TypeA,
},
dns.RcodeRefused,
false,
wantRcode: dns.RcodeRefused,
wantExtendedErrorCode: dns.ExtendedErrorCodeBlocked,
},
{
"Blacklist 1 ALLOWED",
`acl example.org {
name: "Blacklist 1 ALLOWED",
config: `acl example.org {
block type A net 192.168.0.0/16
}`,
[]string{},
args{
"www.example.org.",
"192.167.0.2",
dns.TypeA,
zones: []string{},
args: args{
domain: "www.example.org.",
sourceIP: "192.167.0.2",
qtype: dns.TypeA,
},
dns.RcodeSuccess,
false,
wantRcode: dns.RcodeSuccess,
},
{
"Blacklist 2 BLOCKED",
`
name: "Blacklist 2 BLOCKED",
config: `
acl example.org {
block type * net 192.168.0.0/16
}`,
[]string{},
args{
"www.example.org.",
"192.168.0.2",
dns.TypeAAAA,
zones: []string{},
args: args{
domain: "www.example.org.",
sourceIP: "192.168.0.2",
qtype: dns.TypeAAAA,
},
dns.RcodeRefused,
false,
wantRcode: dns.RcodeRefused,
wantExtendedErrorCode: dns.ExtendedErrorCodeBlocked,
},
{
"Blacklist 3 BLOCKED",
`acl example.org {
name: "Blacklist 3 BLOCKED",
config: `acl example.org {
block type A
}`,
[]string{},
args{
"www.example.org.",
"10.1.0.2",
dns.TypeA,
zones: []string{},
args: args{
domain: "www.example.org.",
sourceIP: "10.1.0.2",
qtype: dns.TypeA,
},
dns.RcodeRefused,
false,
wantRcode: dns.RcodeRefused,
wantExtendedErrorCode: dns.ExtendedErrorCodeBlocked,
},
{
"Blacklist 3 ALLOWED",
`acl example.org {
name: "Blacklist 3 ALLOWED",
config: `acl example.org {
block type A
}`,
[]string{},
args{
"www.example.org.",
"10.1.0.2",
dns.TypeAAAA,
zones: []string{},
args: args{
domain: "www.example.org.",
sourceIP: "10.1.0.2",
qtype: dns.TypeAAAA,
},
dns.RcodeSuccess,
false,
wantRcode: dns.RcodeSuccess,
},
{
"Blacklist 4 Single IP BLOCKED",
`acl example.org {
name: "Blacklist 4 Single IP BLOCKED",
config: `acl example.org {
block type A net 192.168.1.2
}`,
[]string{},
args{
"www.example.org.",
"192.168.1.2",
dns.TypeA,
zones: []string{},
args: args{
domain: "www.example.org.",
sourceIP: "192.168.1.2",
qtype: dns.TypeA,
},
dns.RcodeRefused,
false,
wantRcode: dns.RcodeRefused,
wantExtendedErrorCode: dns.ExtendedErrorCodeBlocked,
},
{
"Blacklist 4 Single IP ALLOWED",
`acl example.org {
name: "Blacklist 4 Single IP ALLOWED",
config: `acl example.org {
block type A net 192.168.1.2
}`,
[]string{},
args{
"www.example.org.",
"192.168.1.3",
dns.TypeA,
zones: []string{},
args: args{
domain: "www.example.org.",
sourceIP: "192.168.1.3",
qtype: dns.TypeA,
},
dns.RcodeSuccess,
false,
wantRcode: dns.RcodeSuccess,
},
{
"Filter 1 FILTERED",
`acl example.org {
name: "Filter 1 FILTERED",
config: `acl example.org {
filter type A net 192.168.0.0/16
}`,
[]string{},
args{
"www.example.org.",
"192.168.0.2",
dns.TypeA,
zones: []string{},
args: args{
domain: "www.example.org.",
sourceIP: "192.168.0.2",
qtype: dns.TypeA,
},
dns.RcodeSuccess,
false,
wantRcode: dns.RcodeSuccess,
wantExtendedErrorCode: dns.ExtendedErrorCodeFiltered,
},
{
"Filter 1 ALLOWED",
`acl example.org {
name: "Filter 1 ALLOWED",
config: `acl example.org {
filter type A net 192.168.0.0/16
}`,
[]string{},
args{
"www.example.org.",
"192.167.0.2",
dns.TypeA,
zones: []string{},
args: args{
domain: "www.example.org.",
sourceIP: "192.167.0.2",
qtype: dns.TypeA,
},
dns.RcodeSuccess,
false,
wantRcode: dns.RcodeSuccess,
},
{
"Whitelist 1 ALLOWED",
`acl example.org {
name: "Whitelist 1 ALLOWED",
config: `acl example.org {
allow net 192.168.0.0/16
block
}`,
[]string{},
args{
"www.example.org.",
"192.168.0.2",
dns.TypeA,
zones: []string{},
args: args{
domain: "www.example.org.",
sourceIP: "192.168.0.2",
qtype: dns.TypeA,
},
dns.RcodeSuccess,
false,
wantRcode: dns.RcodeSuccess,
},
{
"Whitelist 1 REFUSED",
`acl example.org {
name: "Whitelist 1 REFUSED",
config: `acl example.org {
allow type * net 192.168.0.0/16
block
}`,
[]string{},
args{
"www.example.org.",
"10.1.0.2",
dns.TypeA,
zones: []string{},
args: args{
domain: "www.example.org.",
sourceIP: "10.1.0.2",
qtype: dns.TypeA,
},
dns.RcodeRefused,
false,
wantRcode: dns.RcodeRefused,
wantExtendedErrorCode: dns.ExtendedErrorCodeBlocked,
},
{
"Fine-Grained 1 REFUSED",
`acl a.example.org {
name: "Fine-Grained 1 REFUSED",
config: `acl a.example.org {
block type * net 192.168.1.0/24
}`,
[]string{"example.org"},
args{
"a.example.org.",
"192.168.1.2",
dns.TypeA,
zones: []string{"example.org"},
args: args{
domain: "a.example.org.",
sourceIP: "192.168.1.2",
qtype: dns.TypeA,
},
dns.RcodeRefused,
false,
wantRcode: dns.RcodeRefused,
wantExtendedErrorCode: dns.ExtendedErrorCodeBlocked,
},
{
"Fine-Grained 1 ALLOWED",
`acl a.example.org {
name: "Fine-Grained 1 ALLOWED",
config: `acl a.example.org {
block net 192.168.1.0/24
}`,
[]string{"example.org"},
args{
"www.example.org.",
"192.168.1.2",
dns.TypeA,
zones: []string{"example.org"},
args: args{
domain: "www.example.org.",
sourceIP: "192.168.1.2",
qtype: dns.TypeA,
},
dns.RcodeSuccess,
false,
wantRcode: dns.RcodeSuccess,
},
{
"Fine-Grained 2 REFUSED",
`acl example.org {
name: "Fine-Grained 2 REFUSED",
config: `acl example.org {
block net 192.168.1.0/24
}`,
[]string{"example.org"},
args{
"a.example.org.",
"192.168.1.2",
dns.TypeA,
zones: []string{"example.org"},
args: args{
domain: "a.example.org.",
sourceIP: "192.168.1.2",
qtype: dns.TypeA,
},
dns.RcodeRefused,
false,
wantRcode: dns.RcodeRefused,
wantExtendedErrorCode: dns.ExtendedErrorCodeBlocked,
},
{
"Fine-Grained 2 ALLOWED",
`acl {
name: "Fine-Grained 2 ALLOWED",
config: `acl {
block net 192.168.1.0/24
}`,
[]string{"example.org"},
args{
"a.example.com.",
"192.168.1.2",
dns.TypeA,
zones: []string{"example.org"},
args: args{
domain: "a.example.com.",
sourceIP: "192.168.1.2",
qtype: dns.TypeA,
},
dns.RcodeSuccess,
false,
wantRcode: dns.RcodeSuccess,
},
{
"Fine-Grained 3 REFUSED",
`acl a.example.org {
name: "Fine-Grained 3 REFUSED",
config: `acl a.example.org {
block net 192.168.1.0/24
}
acl b.example.org {
block type * net 192.168.2.0/24
}`,
[]string{"example.org"},
args{
"b.example.org.",
"192.168.2.2",
dns.TypeA,
zones: []string{"example.org"},
args: args{
domain: "b.example.org.",
sourceIP: "192.168.2.2",
qtype: dns.TypeA,
},
dns.RcodeRefused,
false,
wantRcode: dns.RcodeRefused,
wantExtendedErrorCode: dns.ExtendedErrorCodeBlocked,
},
{
"Fine-Grained 3 ALLOWED",
`acl a.example.org {
name: "Fine-Grained 3 ALLOWED",
config: `acl a.example.org {
block net 192.168.1.0/24
}
acl b.example.org {
block net 192.168.2.0/24
}`,
[]string{"example.org"},
args{
"b.example.org.",
"192.168.1.2",
dns.TypeA,
zones: []string{"example.org"},
args: args{
domain: "b.example.org.",
sourceIP: "192.168.1.2",
qtype: dns.TypeA,
},
dns.RcodeSuccess,
false,
wantRcode: dns.RcodeSuccess,
},
// IPv6 tests.
{
"Blacklist 1 BLOCKED IPv6",
`acl example.org {
name: "Blacklist 1 BLOCKED IPv6",
config: `acl example.org {
block type A net 2001:db8:abcd:0012::0/64
}`,
[]string{},
args{
"www.example.org.",
"2001:db8:abcd:0012::1230",
dns.TypeA,
zones: []string{},
args: args{
domain: "www.example.org.",
sourceIP: "2001:db8:abcd:0012::1230",
qtype: dns.TypeA,
},
dns.RcodeRefused,
false,
wantRcode: dns.RcodeRefused,
wantExtendedErrorCode: dns.ExtendedErrorCodeBlocked,
},
{
"Blacklist 1 ALLOWED IPv6",
`acl example.org {
name: "Blacklist 1 ALLOWED IPv6",
config: `acl example.org {
block type A net 2001:db8:abcd:0012::0/64
}`,
[]string{},
args{
"www.example.org.",
"2001:db8:abcd:0013::0",
dns.TypeA,
zones: []string{},
args: args{
domain: "www.example.org.",
sourceIP: "2001:db8:abcd:0013::0",
qtype: dns.TypeA,
},
dns.RcodeSuccess,
false,
wantRcode: dns.RcodeSuccess,
},
{
"Blacklist 2 BLOCKED IPv6",
`acl example.org {
name: "Blacklist 2 BLOCKED IPv6",
config: `acl example.org {
block type A
}`,
[]string{},
args{
"www.example.org.",
"2001:0db8:85a3:0000:0000:8a2e:0370:7334",
dns.TypeA,
zones: []string{},
args: args{
domain: "www.example.org.",
sourceIP: "2001:0db8:85a3:0000:0000:8a2e:0370:7334",
qtype: dns.TypeA,
},
dns.RcodeRefused,
false,
wantRcode: dns.RcodeRefused,
wantExtendedErrorCode: dns.ExtendedErrorCodeBlocked,
},
{
"Blacklist 3 Single IP BLOCKED IPv6",
`acl example.org {
name: "Blacklist 3 Single IP BLOCKED IPv6",
config: `acl example.org {
block type A net 2001:0db8:85a3:0000:0000:8a2e:0370:7334
}`,
[]string{},
args{
"www.example.org.",
"2001:0db8:85a3:0000:0000:8a2e:0370:7334",
dns.TypeA,
zones: []string{},
args: args{
domain: "www.example.org.",
sourceIP: "2001:0db8:85a3:0000:0000:8a2e:0370:7334",
qtype: dns.TypeA,
},
dns.RcodeRefused,
false,
wantRcode: dns.RcodeRefused,
wantExtendedErrorCode: dns.ExtendedErrorCodeBlocked,
},
{
"Blacklist 3 Single IP ALLOWED IPv6",
`acl example.org {
name: "Blacklist 3 Single IP ALLOWED IPv6",
config: `acl example.org {
block type A net 2001:0db8:85a3:0000:0000:8a2e:0370:7334
}`,
[]string{},
args{
"www.example.org.",
"2001:0db8:85a3:0000:0000:8a2e:0370:7335",
dns.TypeA,
zones: []string{},
args: args{
domain: "www.example.org.",
sourceIP: "2001:0db8:85a3:0000:0000:8a2e:0370:7335",
qtype: dns.TypeA,
},
dns.RcodeSuccess,
false,
wantRcode: dns.RcodeSuccess,
},
{
"Fine-Grained 1 REFUSED IPv6",
`acl a.example.org {
name: "Fine-Grained 1 REFUSED IPv6",
config: `acl a.example.org {
block type * net 2001:db8:abcd:0012::0/64
}`,
[]string{"example.org"},
args{
"a.example.org.",
"2001:db8:abcd:0012:2019::0",
dns.TypeA,
zones: []string{"example.org"},
args: args{
domain: "a.example.org.",
sourceIP: "2001:db8:abcd:0012:2019::0",
qtype: dns.TypeA,
},
dns.RcodeRefused,
false,
wantRcode: dns.RcodeRefused,
wantExtendedErrorCode: dns.ExtendedErrorCodeBlocked,
},
{
"Fine-Grained 1 ALLOWED IPv6",
`acl a.example.org {
name: "Fine-Grained 1 ALLOWED IPv6",
config: `acl a.example.org {
block net 2001:db8:abcd:0012::0/64
}`,
[]string{"example.org"},
args{
"www.example.org.",
"2001:db8:abcd:0012:2019::0",
dns.TypeA,
zones: []string{"example.org"},
args: args{
domain: "www.example.org.",
sourceIP: "2001:db8:abcd:0012:2019::0",
qtype: dns.TypeA,
},
dns.RcodeSuccess,
false,
wantRcode: dns.RcodeSuccess,
},
{
"Blacklist Address%ifname",
`acl example.org {
name: "Blacklist Address%ifname",
config: `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,
zones: []string{"eth0"},
args: args{
domain: "www.example.org.",
sourceIP: "2001:0db8:85a3:0000:0000:8a2e:0370:7334",
qtype: dns.TypeAAAA,
},
dns.RcodeRefused,
false,
wantRcode: dns.RcodeRefused,
wantExtendedErrorCode: dns.ExtendedErrorCodeBlocked,
},
}
@ -438,6 +430,20 @@ func TestACLServeDNS(t *testing.T) {
if w.Rcode != tt.wantRcode {
t.Errorf("Error: acl.ServeDNS() Rcode = %v, want %v", w.Rcode, tt.wantRcode)
}
if tt.wantExtendedErrorCode != 0 {
matched := false
for _, opt := range w.Msg.IsEdns0().Option {
if ede, ok := opt.(*dns.EDNS0_EDE); ok {
if ede.InfoCode != tt.wantExtendedErrorCode {
t.Errorf("Error: acl.ServeDNS() Extended DNS Error = %v, want %v", ede.InfoCode, tt.wantExtendedErrorCode)
}
matched = true
}
}
if !matched {
t.Error("Error: acl.ServeDNS() missing Extended DNS Error option")
}
}
})
}
}