delivery of blocking group as EDNS error(560) (#611)

This commit is contained in:
Kwitsch
2022-08-06 22:30:26 +02:00
committed by GitHub
parent a9500bf06d
commit 5e9eaa2965
7 changed files with 196 additions and 0 deletions
+1
View File
@@ -13,3 +13,4 @@ todo.txt
!docs/config.yml
node_modules
package-lock.json
.vscode/
+5
View File
@@ -428,6 +428,7 @@ type Config struct {
HostsFile HostsFileConfig `yaml:"hostsFile"`
FqdnOnly bool `yaml:"fqdnOnly" default:"false"`
Filtering FilteringConfig `yaml:"filtering"`
Ede EdeConfig `yaml:"ede"`
}
type BootstrapConfig bootstrapConfig // to avoid infinite recursion. See BootstrapConfig.UnmarshalYAML.
@@ -540,6 +541,10 @@ type FilteringConfig struct {
QueryTypes QTypeSet `yaml:"queryTypes"`
}
type EdeConfig struct {
Enable bool `yaml:"enable" default:"false"`
}
// nolint:gochecknoglobals
var (
config = &Config{}
+5
View File
@@ -218,3 +218,8 @@ logFormat: text
logTimestamp: true
# optional: obfuscate log output (replace all alphanumeric characters with *) for user sensitive data like request domains or responses to increase privacy. Default: false
logPrivacy: false
# optional: add EDE error codes to dns response
ede:
# enabled if true, Default: false
enable: true
+17
View File
@@ -633,6 +633,23 @@ Configuration parameters:
refreshPeriod: 30m
```
### Deliver EDE codes as EDNS0 option
DNS responses can be extended with EDE codes according to [RFC8914](https://datatracker.ietf.org/doc/rfc8914/).
Configuration parameters:
| Parameter | Type | Mandatory | Default value | Description |
|--------------------------|--------------------------------|-----------|---------------|----------------------------------------------------|
| ede.enable | bool | no | false | If true, DNS responses are deliverd with EDE codes |
!!! example
```yaml
ede:
enable: true
```
## SSL certificate configuration (DoH / TLS listener)
See [Wiki - Configuration of HTTPS](https://github.com/0xERR0R/blocky/wiki/Configuration-of-HTTPS-for-DoH-and-Rest-API)
+80
View File
@@ -0,0 +1,80 @@
package resolver
import (
"github.com/0xERR0R/blocky/config"
"github.com/0xERR0R/blocky/model"
"github.com/miekg/dns"
)
type EdeResolver struct {
NextResolver
config config.EdeConfig
}
func NewEdeResolver(cfg config.EdeConfig) ChainedResolver {
return &EdeResolver{
config: cfg,
}
}
func (r *EdeResolver) Resolve(request *model.Request) (*model.Response, error) {
resp, err := r.next.Resolve(request)
if r.config.Enable {
addExtraReasoning(resp)
}
return resp, err
}
func (r *EdeResolver) Configuration() (result []string) {
if r.config.Enable {
result = []string{"activated"}
} else {
result = []string{"deactivated"}
}
return result
}
func addExtraReasoning(res *model.Response) {
// dns.ExtendedErrorCodeOther seams broken in some clients
infocode := convertToExtendedErrorCode(res.RType)
if infocode > 0 {
opt := new(dns.OPT)
opt.Hdr.Name = "."
opt.Hdr.Rrtype = dns.TypeOPT
opt.Option = append(opt.Option, convertExtendedError(res, infocode))
res.Res.Extra = append(res.Res.Extra, opt)
}
}
func convertExtendedError(input *model.Response, infocode uint16) *dns.EDNS0_EDE {
return &dns.EDNS0_EDE{
InfoCode: infocode,
ExtraText: input.Reason,
}
}
func convertToExtendedErrorCode(input model.ResponseType) uint16 {
switch input {
case model.ResponseTypeRESOLVED:
return dns.ExtendedErrorCodeOther
case model.ResponseTypeCACHED:
return dns.ExtendedErrorCodeCachedError
case model.ResponseTypeCONDITIONAL:
return dns.ExtendedErrorCodeForgedAnswer
case model.ResponseTypeCUSTOMDNS:
return dns.ExtendedErrorCodeForgedAnswer
case model.ResponseTypeHOSTSFILE:
return dns.ExtendedErrorCodeForgedAnswer
case model.ResponseTypeNOTFQDN:
return dns.ExtendedErrorCodeBlocked
case model.ResponseTypeBLOCKED:
return dns.ExtendedErrorCodeBlocked
case model.ResponseTypeFILTERED:
return dns.ExtendedErrorCodeFiltered
default:
return dns.ExtendedErrorCodeOther
}
}
+87
View File
@@ -0,0 +1,87 @@
package resolver
import (
"github.com/0xERR0R/blocky/config"
"github.com/0xERR0R/blocky/model"
"github.com/miekg/dns"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"github.com/stretchr/testify/mock"
)
var _ = Describe("EdeResolver", func() {
var (
sut *EdeResolver
sutConfig config.EdeConfig
m *MockResolver
mockAnswer *dns.Msg
)
BeforeEach(func() {
mockAnswer = new(dns.Msg)
})
JustBeforeEach(func() {
m = &MockResolver{}
m.On("Resolve", mock.Anything).Return(&model.Response{
Res: mockAnswer,
RType: model.ResponseTypeCUSTOMDNS,
Reason: "Test",
}, nil)
sut = NewEdeResolver(sutConfig).(*EdeResolver)
sut.Next(m)
})
When("Ede is disabled", func() {
BeforeEach(func() {
sutConfig = config.EdeConfig{
Enable: false,
}
})
It("Shouldn't add EDE information", func() {
resp, err := sut.Resolve(newRequest("example.com", dns.Type(dns.TypeA)))
Expect(err).Should(Succeed())
Expect(resp.Res.Rcode).Should(Equal(dns.RcodeSuccess))
Expect(resp.RType).Should(Equal(model.ResponseTypeCUSTOMDNS))
Expect(resp.Res.Answer).Should(BeEmpty())
Expect(resp.Res.Extra).Should(BeEmpty())
// delegated to next resolver
Expect(m.Calls).Should(HaveLen(1))
})
It("Configure should output deactivated", func() {
c := sut.Configuration()
Expect(c).Should(HaveLen(1))
Expect(c[0]).Should(Equal("deactivated"))
})
})
When("Ede is enabled", func() {
BeforeEach(func() {
sutConfig = config.EdeConfig{
Enable: true,
}
})
It("Should add EDE information", func() {
resp, err := sut.Resolve(newRequest("example.com", dns.Type(dns.TypeA)))
Expect(err).Should(Succeed())
Expect(resp.Res.Rcode).Should(Equal(dns.RcodeSuccess))
Expect(resp.RType).Should(Equal(model.ResponseTypeCUSTOMDNS))
Expect(resp.Res.Answer).Should(BeEmpty())
Expect(resp.Res.Extra).Should(HaveLen(1))
opt, ok := resp.Res.Extra[0].(*dns.OPT)
Expect(ok).Should(BeTrue())
Expect(opt).ShouldNot(BeNil())
ede, ok := opt.Option[0].(*dns.EDNS0_EDE)
Expect(ok).Should(BeTrue())
Expect(ede.InfoCode).Should(Equal(dns.ExtendedErrorCodeForgedAnswer))
Expect(ede.ExtraText).Should(Equal("Test"))
})
It("Configure should output activated", func() {
c := sut.Configuration()
Expect(c).Should(HaveLen(1))
Expect(c[0]).Should(Equal("activated"))
})
})
})
+1
View File
@@ -399,6 +399,7 @@ func createQueryResolver(
resolver.NewFilteringResolver(cfg.Filtering),
resolver.NewFqdnOnlyResolver(*cfg),
clientNamesResolver,
resolver.NewEdeResolver(cfg.Ede),
resolver.NewQueryLoggingResolver(cfg.QueryLog),
resolver.NewMetricsResolver(cfg.Prometheus),
resolver.NewRewriterResolver(cfg.CustomDNS.RewriteConfig, resolver.NewCustomDNSResolver(cfg.CustomDNS)),