Skip to content

Commit

Permalink
feat(sudn): refactor and expand supported special use domains RFCs
Browse files Browse the repository at this point in the history
  • Loading branch information
ThinkChaos committed Jul 14, 2023
1 parent 6028a64 commit 56633da
Show file tree
Hide file tree
Showing 11 changed files with 364 additions and 234 deletions.
1 change: 1 addition & 0 deletions config/config.go
Expand Up @@ -208,6 +208,7 @@ type Config struct {
FqdnOnly FqdnOnlyConfig `yaml:"fqdnOnly"`
Filtering FilteringConfig `yaml:"filtering"`
Ede EdeConfig `yaml:"ede"`
SUDN SUDNConfig `yaml:"specialUseDomains"`

// Deprecated options
Deprecated struct {
Expand Down
25 changes: 25 additions & 0 deletions config/sudn.go
@@ -0,0 +1,25 @@
package config

import (
"github.com/sirupsen/logrus"
)

// SUDNConfig configuration for Special Use Domain Names
type SUDNConfig struct {
// These are "recommended for private use" but not mandatory.
// If a user wishes to use one, it will most likely be via conditional
// upstream or custom DNS, which come before SUDN in the resolver chain.
// Thus defaulting to `true` and returning NXDOMAIN here should not conflict.
RFC6762AppendixG bool `yaml:"rfc6762-appendixG" default:"true"`
}

// IsEnabled implements `config.Configurable`.
func (c *SUDNConfig) IsEnabled() bool {
// The Special Use RFCs are always active
return true
}

// LogConfig implements `config.Configurable`.
func (c *SUDNConfig) LogConfig(logger *logrus.Entry) {
logger.Debugf("rfc6762-appendixG = %v", c.RFC6762AppendixG)
}
34 changes: 34 additions & 0 deletions config/sudn_test.go
@@ -0,0 +1,34 @@
package config

import (
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)

var _ = Describe("SUDNConfig", func() {
var cfg SUDNConfig

suiteBeforeEach()

BeforeEach(func() {
var err error

cfg, err = WithDefaults[SUDNConfig]()
Expect(err).Should(Succeed())
})

Describe("IsEnabled", func() {
It("is true", func() {
Expect(cfg.IsEnabled()).Should(BeTrue())
})
})

Describe("LogConfig", func() {
It("should log configuration", func() {
cfg.LogConfig(logger)

Expect(hook.Calls).ShouldNot(BeEmpty())
Expect(hook.Messages).Should(ContainElement(ContainSubstring("rfc6762-appendixG = true")))
})
})
})
6 changes: 6 additions & 0 deletions docs/config.yml
Expand Up @@ -319,3 +319,9 @@ log:
ede:
# enabled if true, Default: false
enable: true

# optional: configure optional Special Use Domain Names (SUDN)
specialUseDomains:
# optional: block recomended private TLDs
# default: true
rfc6762-appendixG: true
18 changes: 18 additions & 0 deletions docs/configuration.md
Expand Up @@ -671,6 +671,24 @@ Configuration parameters:
enable: true
```

## Special Use Domain Names

SUDN (Special Use Domain Names) are always enabled as they are required by various RFCs.
Some RFCs have optional recommendations, which are configurable as described below.

Configuration parameters:

| Parameter | Type | Mandatory | Default value | Description |
|-------------------------------------|------|-----------|---------------|-----------------------------------------------------------------------------------------------|
| specialUseDomains.rfc6762-appendixG | bool | no | true | Block TLDs listed in [RFC 6762 Appendix G](https://www.rfc-editor.org/rfc/rfc6762#appendix-G) |

!!! example

```yaml
specialUseDomains:
rfc6762-appendixG: 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)
Expand Down
29 changes: 20 additions & 9 deletions helpertest/helper.go
Expand Up @@ -12,6 +12,7 @@ import (

"github.com/miekg/dns"
"github.com/onsi/gomega"
"github.com/onsi/gomega/gcustom"
"github.com/onsi/gomega/types"
)

Expand All @@ -22,6 +23,7 @@ const (
MX = dns.Type(dns.TypeMX)
PTR = dns.Type(dns.TypePTR)
TXT = dns.Type(dns.TypeTXT)
DS = dns.Type(dns.TypeDS)
)

// TempFile creates temp file with passed data
Expand Down Expand Up @@ -76,21 +78,30 @@ func HaveNoAnswer() types.GomegaMatcher {
}

func HaveReason(reason string) types.GomegaMatcher {
return gomega.WithTransform(func(m *model.Response) string {
return m.Reason
}, gomega.Equal(reason))
return gcustom.MakeMatcher(func(m *model.Response) (bool, error) {
return m.Reason == reason, nil
}).WithTemplate(
"Expected:\n{{.Actual}}\n{{.To}} have reason:\n{{format .Data 1}}",
reason,
)
}

func HaveResponseType(c model.ResponseType) types.GomegaMatcher {
return gomega.WithTransform(func(m *model.Response) model.ResponseType {
return m.RType
}, gomega.Equal(c))
return gcustom.MakeMatcher(func(m *model.Response) (bool, error) {
return m.RType == c, nil
}).WithTemplate(
"Expected:\n{{.Actual}}\n{{.To}} have ResponseType:\n{{format .Data 1}}",
c.String(),
)
}

func HaveReturnCode(code int) types.GomegaMatcher {
return gomega.WithTransform(func(m *model.Response) int {
return m.Res.Rcode
}, gomega.Equal(code))
return gcustom.MakeMatcher(func(m *model.Response) (bool, error) {
return m.Res.Rcode == code, nil
}).WithTemplate(
"Expected:\n{{.Actual}}\n{{.To}} have RCode:\n{{format .Data 1}}",
fmt.Sprintf("%d (%s)", code, dns.RcodeToString[code]),
)
}

func toFirstRR(actual interface{}) (dns.RR, error) {
Expand Down
1 change: 1 addition & 0 deletions log/mock_entry.go
Expand Up @@ -10,6 +10,7 @@ import (
func NewMockEntry() (*logrus.Entry, *MockLoggerHook) {
logger := logrus.New()
logger.Out = io.Discard
logger.Level = logrus.TraceLevel

entry := logrus.Entry{Logger: logger}
hook := MockLoggerHook{}
Expand Down
12 changes: 4 additions & 8 deletions resolver/resolver.go
Expand Up @@ -39,21 +39,17 @@ func newRequestWithClient(question string, rType dns.Type, ip string, clientName
}
}

// newResponseMsg creates a new dns.Msg as response for a request
func newResponseMsg(request *model.Request) *dns.Msg {
// newResponse creates a response to the given request
func newResponse(request *model.Request, rcode int, rtype model.ResponseType, reason string) *model.Response {
response := new(dns.Msg)
response.SetReply(request.Req)
response.Rcode = rcode

return response
}

// returnResponseModel wrapps a dns.Msg into a model.Response
func returnResponseModel(response *dns.Msg, rtype model.ResponseType, reason string) (*model.Response, error) {
return &model.Response{
Res: response,
RType: rtype,
Reason: reason,
}, nil
}
}

func newRequestWithClientID(question string, rType dns.Type, ip, requestClientID string) *model.Request {
Expand Down

0 comments on commit 56633da

Please sign in to comment.