Pull request: all: support more $dnsrewrite rr types
Merge in DNS/adguard-home from 2102-dnsrewrite-2 to master Updates #2102. Updates #2452. Squashed commit of the following: commit b41e57731b4f276e97202e172fa400067174653d Author: Ainar Garipov <A.Garipov@AdGuard.COM> Date: Tue Dec 22 20:40:56 2020 +0300 dnsforward: improve naming commit 70b832ce969d8cdcf4224d221e5e1e2057fba6ee Author: Ainar Garipov <A.Garipov@AdGuard.COM> Date: Tue Dec 22 19:36:21 2020 +0300 all: support more $dnsrewrite rr types
This commit is contained in:
168
internal/dnsforward/svcbmsg.go
Normal file
168
internal/dnsforward/svcbmsg.go
Normal file
@@ -0,0 +1,168 @@
|
||||
package dnsforward
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"net"
|
||||
"strconv"
|
||||
|
||||
"github.com/AdguardTeam/golibs/log"
|
||||
"github.com/AdguardTeam/urlfilter/rules"
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
// genAnswerHTTPS returns a properly initialized HTTPS resource record.
|
||||
//
|
||||
// See the comment on genAnswerSVCB for a list of current restrictions on
|
||||
// parameter values.
|
||||
func (s *Server) genAnswerHTTPS(req *dns.Msg, svcb *rules.DNSSVCB) (ans *dns.HTTPS) {
|
||||
ans = &dns.HTTPS{
|
||||
SVCB: *s.genAnswerSVCB(req, svcb),
|
||||
}
|
||||
|
||||
ans.Hdr.Rrtype = dns.TypeHTTPS
|
||||
|
||||
return ans
|
||||
}
|
||||
|
||||
// strToSVCBKey is the string-to-svcb-key mapping.
|
||||
//
|
||||
// See https://github.com/miekg/dns/blob/23c4faca9d32b0abbb6e179aa1aadc45ac53a916/svcb.go#L27.
|
||||
//
|
||||
// TODO(a.garipov): Propose exporting this API or something similar in the
|
||||
// github.com/miekg/dns module.
|
||||
var strToSVCBKey = map[string]dns.SVCBKey{
|
||||
"alpn": dns.SVCB_ALPN,
|
||||
"echconfig": dns.SVCB_ECHCONFIG,
|
||||
"ipv4hint": dns.SVCB_IPV4HINT,
|
||||
"ipv6hint": dns.SVCB_IPV6HINT,
|
||||
"mandatory": dns.SVCB_MANDATORY,
|
||||
"no-default-alpn": dns.SVCB_NO_DEFAULT_ALPN,
|
||||
"port": dns.SVCB_PORT,
|
||||
}
|
||||
|
||||
// svcbKeyHandler is a handler for one SVCB parameter key.
|
||||
type svcbKeyHandler func(valStr string) (val dns.SVCBKeyValue)
|
||||
|
||||
// svcbKeyHandlers are the supported SVCB parameters handlers.
|
||||
var svcbKeyHandlers = map[string]svcbKeyHandler{
|
||||
"alpn": func(valStr string) (val dns.SVCBKeyValue) {
|
||||
return &dns.SVCBAlpn{
|
||||
Alpn: []string{valStr},
|
||||
}
|
||||
},
|
||||
|
||||
"echconfig": func(valStr string) (val dns.SVCBKeyValue) {
|
||||
ech, err := base64.StdEncoding.DecodeString(valStr)
|
||||
if err != nil {
|
||||
log.Debug("can't parse svcb/https echconfig: %s; ignoring", err)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
return &dns.SVCBECHConfig{
|
||||
ECH: ech,
|
||||
}
|
||||
},
|
||||
|
||||
"ipv4hint": func(valStr string) (val dns.SVCBKeyValue) {
|
||||
ip := net.ParseIP(valStr)
|
||||
if ip4 := ip.To4(); ip == nil || ip4 == nil {
|
||||
log.Debug("can't parse svcb/https ipv4 hint %q; ignoring", valStr)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
return &dns.SVCBIPv4Hint{
|
||||
Hint: []net.IP{ip},
|
||||
}
|
||||
},
|
||||
|
||||
"ipv6hint": func(valStr string) (val dns.SVCBKeyValue) {
|
||||
ip := net.ParseIP(valStr)
|
||||
if ip == nil {
|
||||
log.Debug("can't parse svcb/https ipv6 hint %q; ignoring", valStr)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
return &dns.SVCBIPv6Hint{
|
||||
Hint: []net.IP{ip},
|
||||
}
|
||||
},
|
||||
|
||||
"mandatory": func(valStr string) (val dns.SVCBKeyValue) {
|
||||
code, ok := strToSVCBKey[valStr]
|
||||
if !ok {
|
||||
log.Debug("unknown svcb/https mandatory key %q, ignoring", valStr)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
return &dns.SVCBMandatory{
|
||||
Code: []dns.SVCBKey{code},
|
||||
}
|
||||
},
|
||||
|
||||
"no-default-alpn": func(_ string) (val dns.SVCBKeyValue) {
|
||||
return &dns.SVCBNoDefaultAlpn{}
|
||||
},
|
||||
|
||||
"port": func(valStr string) (val dns.SVCBKeyValue) {
|
||||
port64, err := strconv.ParseUint(valStr, 10, 16)
|
||||
if err != nil {
|
||||
log.Debug("can't parse svcb/https port: %s; ignoring", err)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
return &dns.SVCBPort{
|
||||
Port: uint16(port64),
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
// genAnswerSVCB returns a properly initialized SVCB resource record.
|
||||
//
|
||||
// Currently, there are several restrictions on how the parameters are parsed.
|
||||
// Firstly, the parsing of non-contiguous values isn't supported. Secondly, the
|
||||
// parsing of value-lists is not supported either.
|
||||
//
|
||||
// ipv4hint=127.0.0.1 // Supported.
|
||||
// ipv4hint="127.0.0.1" // Unsupported.
|
||||
// ipv4hint=127.0.0.1,127.0.0.2 // Unsupported.
|
||||
// ipv4hint="127.0.0.1,127.0.0.2" // Unsupported.
|
||||
//
|
||||
// TODO(a.garipov): Support all of these.
|
||||
func (s *Server) genAnswerSVCB(req *dns.Msg, svcb *rules.DNSSVCB) (ans *dns.SVCB) {
|
||||
ans = &dns.SVCB{
|
||||
Hdr: s.hdr(req, dns.TypeSVCB),
|
||||
Priority: svcb.Priority,
|
||||
Target: svcb.Target,
|
||||
}
|
||||
if len(svcb.Params) == 0 {
|
||||
return ans
|
||||
}
|
||||
|
||||
values := make([]dns.SVCBKeyValue, 0, len(svcb.Params))
|
||||
for k, valStr := range svcb.Params {
|
||||
handler, ok := svcbKeyHandlers[k]
|
||||
if !ok {
|
||||
log.Debug("unknown svcb/https key %q, ignoring", k)
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
val := handler(valStr)
|
||||
if val == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
values = append(values, val)
|
||||
}
|
||||
|
||||
if len(values) > 0 {
|
||||
ans.Value = values
|
||||
}
|
||||
|
||||
return ans
|
||||
}
|
||||
Reference in New Issue
Block a user