Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • ale/autoradio
1 result
Show changes
package dns
import (
"bytes"
"encoding/binary"
"errors"
"net"
"sort"
"strconv"
"strings"
)
type SVCBKey uint16
// Keys defined in draft-ietf-dnsop-svcb-https-01 Section 12.3.2.
const (
SVCB_MANDATORY SVCBKey = 0
SVCB_ALPN SVCBKey = 1
SVCB_NO_DEFAULT_ALPN SVCBKey = 2
SVCB_PORT SVCBKey = 3
SVCB_IPV4HINT SVCBKey = 4
SVCB_ECHCONFIG SVCBKey = 5
SVCB_IPV6HINT SVCBKey = 6
svcb_RESERVED SVCBKey = 65535
)
var svcbKeyToStringMap = map[SVCBKey]string{
SVCB_MANDATORY: "mandatory",
SVCB_ALPN: "alpn",
SVCB_NO_DEFAULT_ALPN: "no-default-alpn",
SVCB_PORT: "port",
SVCB_IPV4HINT: "ipv4hint",
SVCB_ECHCONFIG: "echconfig",
SVCB_IPV6HINT: "ipv6hint",
}
var svcbStringToKeyMap = reverseSVCBKeyMap(svcbKeyToStringMap)
func reverseSVCBKeyMap(m map[SVCBKey]string) map[string]SVCBKey {
n := make(map[string]SVCBKey, len(m))
for u, s := range m {
n[s] = u
}
return n
}
// String takes the numerical code of an SVCB key and returns its name.
// Returns an empty string for reserved keys.
// Accepts unassigned keys as well as experimental/private keys.
func (key SVCBKey) String() string {
if x := svcbKeyToStringMap[key]; x != "" {
return x
}
if key == svcb_RESERVED {
return ""
}
return "key" + strconv.FormatUint(uint64(key), 10)
}
// svcbStringToKey returns the numerical code of an SVCB key.
// Returns svcb_RESERVED for reserved/invalid keys.
// Accepts unassigned keys as well as experimental/private keys.
func svcbStringToKey(s string) SVCBKey {
if strings.HasPrefix(s, "key") {
a, err := strconv.ParseUint(s[3:], 10, 16)
// no leading zeros
// key shouldn't be registered
if err != nil || a == 65535 || s[3] == '0' || svcbKeyToStringMap[SVCBKey(a)] != "" {
return svcb_RESERVED
}
return SVCBKey(a)
}
if key, ok := svcbStringToKeyMap[s]; ok {
return key
}
return svcb_RESERVED
}
func (rr *SVCB) parse(c *zlexer, o string) *ParseError {
l, _ := c.Next()
i, e := strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err {
return &ParseError{l.token, "bad SVCB priority", l}
}
rr.Priority = uint16(i)
c.Next() // zBlank
l, _ = c.Next() // zString
rr.Target = l.token
name, nameOk := toAbsoluteName(l.token, o)
if l.err || !nameOk {
return &ParseError{l.token, "bad SVCB Target", l}
}
rr.Target = name
// Values (if any)
l, _ = c.Next()
var xs []SVCBKeyValue
// Helps require whitespace between pairs.
// Prevents key1000="a"key1001=...
canHaveNextKey := true
for l.value != zNewline && l.value != zEOF {
switch l.value {
case zString:
if !canHaveNextKey {
// The key we can now read was probably meant to be
// a part of the last value.
return &ParseError{l.token, "bad SVCB value quotation", l}
}
// In key=value pairs, value does not have to be quoted unless value
// contains whitespace. And keys don't need to have values.
// Similarly, keys with an equality signs after them don't need values.
// l.token includes at least up to the first equality sign.
idx := strings.IndexByte(l.token, '=')
var key, value string
if idx < 0 {
// Key with no value and no equality sign
key = l.token
} else if idx == 0 {
return &ParseError{l.token, "bad SVCB key", l}
} else {
key, value = l.token[:idx], l.token[idx+1:]
if value == "" {
// We have a key and an equality sign. Maybe we have nothing
// after "=" or we have a double quote.
l, _ = c.Next()
if l.value == zQuote {
// Only needed when value ends with double quotes.
// Any value starting with zQuote ends with it.
canHaveNextKey = false
l, _ = c.Next()
switch l.value {
case zString:
// We have a value in double quotes.
value = l.token
l, _ = c.Next()
if l.value != zQuote {
return &ParseError{l.token, "SVCB unterminated value", l}
}
case zQuote:
// There's nothing in double quotes.
default:
return &ParseError{l.token, "bad SVCB value", l}
}
}
}
}
kv := makeSVCBKeyValue(svcbStringToKey(key))
if kv == nil {
return &ParseError{l.token, "bad SVCB key", l}
}
if err := kv.parse(value); err != nil {
return &ParseError{l.token, err.Error(), l}
}
xs = append(xs, kv)
case zQuote:
return &ParseError{l.token, "SVCB key can't contain double quotes", l}
case zBlank:
canHaveNextKey = true
default:
return &ParseError{l.token, "bad SVCB values", l}
}
l, _ = c.Next()
}
rr.Value = xs
if rr.Priority == 0 && len(xs) > 0 {
return &ParseError{l.token, "SVCB aliasform can't have values", l}
}
return nil
}
// makeSVCBKeyValue returns an SVCBKeyValue struct with the key or nil for reserved keys.
func makeSVCBKeyValue(key SVCBKey) SVCBKeyValue {
switch key {
case SVCB_MANDATORY:
return new(SVCBMandatory)
case SVCB_ALPN:
return new(SVCBAlpn)
case SVCB_NO_DEFAULT_ALPN:
return new(SVCBNoDefaultAlpn)
case SVCB_PORT:
return new(SVCBPort)
case SVCB_IPV4HINT:
return new(SVCBIPv4Hint)
case SVCB_ECHCONFIG:
return new(SVCBECHConfig)
case SVCB_IPV6HINT:
return new(SVCBIPv6Hint)
case svcb_RESERVED:
return nil
default:
e := new(SVCBLocal)
e.KeyCode = key
return e
}
}
// SVCB RR. See RFC xxxx (https://tools.ietf.org/html/draft-ietf-dnsop-svcb-https-01).
type SVCB struct {
Hdr RR_Header
Priority uint16
Target string `dns:"domain-name"`
Value []SVCBKeyValue `dns:"pairs"` // Value must be empty if Priority is non-zero.
}
// HTTPS RR. Everything valid for SVCB applies to HTTPS as well.
// Except that the HTTPS record is intended for use with the HTTP and HTTPS protocols.
type HTTPS struct {
SVCB
}
func (rr *HTTPS) String() string {
return rr.SVCB.String()
}
func (rr *HTTPS) parse(c *zlexer, o string) *ParseError {
return rr.SVCB.parse(c, o)
}
// SVCBKeyValue defines a key=value pair for the SVCB RR type.
// An SVCB RR can have multiple SVCBKeyValues appended to it.
type SVCBKeyValue interface {
Key() SVCBKey // Key returns the numerical key code.
pack() ([]byte, error) // pack returns the encoded value.
unpack([]byte) error // unpack sets the value.
String() string // String returns the string representation of the value.
parse(string) error // parse sets the value to the given string representation of the value.
copy() SVCBKeyValue // copy returns a deep-copy of the pair.
len() int // len returns the length of value in the wire format.
}
// SVCBMandatory pair adds to required keys that must be interpreted for the RR
// to be functional.
// Basic use pattern for creating a mandatory option:
//
// s := &dns.SVCB{Hdr: dns.RR_Header{Name: ".", Rrtype: dns.TypeSVCB, Class: dns.ClassINET}}
// e := new(dns.SVCBMandatory)
// e.Code = []uint16{65403}
// s.Value = append(s.Value, e)
type SVCBMandatory struct {
Code []SVCBKey // Must not include mandatory
}
func (*SVCBMandatory) Key() SVCBKey { return SVCB_MANDATORY }
func (s *SVCBMandatory) String() string {
str := make([]string, len(s.Code))
for i, e := range s.Code {
str[i] = e.String()
}
return strings.Join(str, ",")
}
func (s *SVCBMandatory) pack() ([]byte, error) {
codes := append([]SVCBKey(nil), s.Code...)
sort.Slice(codes, func(i, j int) bool {
return codes[i] < codes[j]
})
b := make([]byte, 2*len(codes))
for i, e := range codes {
binary.BigEndian.PutUint16(b[2*i:], uint16(e))
}
return b, nil
}
func (s *SVCBMandatory) unpack(b []byte) error {
if len(b)%2 != 0 {
return errors.New("dns: svcbmandatory: value length is not a multiple of 2")
}
codes := make([]SVCBKey, 0, len(b)/2)
for i := 0; i < len(b); i += 2 {
// We assume strictly increasing order.
codes = append(codes, SVCBKey(binary.BigEndian.Uint16(b[i:])))
}
s.Code = codes
return nil
}
func (s *SVCBMandatory) parse(b string) error {
str := strings.Split(b, ",")
codes := make([]SVCBKey, 0, len(str))
for _, e := range str {
codes = append(codes, svcbStringToKey(e))
}
s.Code = codes
return nil
}
func (s *SVCBMandatory) len() int {
return 2 * len(s.Code)
}
func (s *SVCBMandatory) copy() SVCBKeyValue {
return &SVCBMandatory{
append([]SVCBKey(nil), s.Code...),
}
}
// SVCBAlpn pair is used to list supported connection protocols.
// Protocol ids can be found at:
// https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids
// Basic use pattern for creating an alpn option:
//
// h := new(dns.HTTPS)
// h.Hdr = dns.RR_Header{Name: ".", Rrtype: dns.TypeHTTPS, Class: dns.ClassINET}
// e := new(dns.SVCBAlpn)
// e.Alpn = []string{"h2", "http/1.1"}
// h.Value = append(o.Value, e)
type SVCBAlpn struct {
Alpn []string
}
func (*SVCBAlpn) Key() SVCBKey { return SVCB_ALPN }
func (s *SVCBAlpn) String() string { return strings.Join(s.Alpn, ",") }
func (s *SVCBAlpn) pack() ([]byte, error) {
// Liberally estimate the size of an alpn as 10 octets
b := make([]byte, 0, 10*len(s.Alpn))
for _, e := range s.Alpn {
if len(e) == 0 {
return nil, errors.New("dns: svcbalpn: empty alpn-id")
}
if len(e) > 255 {
return nil, errors.New("dns: svcbalpn: alpn-id too long")
}
b = append(b, byte(len(e)))
b = append(b, e...)
}
return b, nil
}
func (s *SVCBAlpn) unpack(b []byte) error {
// Estimate the size of the smallest alpn as 4 bytes
alpn := make([]string, 0, len(b)/4)
for i := 0; i < len(b); {
length := int(b[i])
i++
if i+length > len(b) {
return errors.New("dns: svcbalpn: alpn array overflowing")
}
alpn = append(alpn, string(b[i:i+length]))
i += length
}
s.Alpn = alpn
return nil
}
func (s *SVCBAlpn) parse(b string) error {
s.Alpn = strings.Split(b, ",")
return nil
}
func (s *SVCBAlpn) len() int {
var l int
for _, e := range s.Alpn {
l += 1 + len(e)
}
return l
}
func (s *SVCBAlpn) copy() SVCBKeyValue {
return &SVCBAlpn{
append([]string(nil), s.Alpn...),
}
}
// SVCBNoDefaultAlpn pair signifies no support for default connection protocols.
// Basic use pattern for creating a no-default-alpn option:
//
// s := &dns.SVCB{Hdr: dns.RR_Header{Name: ".", Rrtype: dns.TypeSVCB, Class: dns.ClassINET}}
// e := new(dns.SVCBNoDefaultAlpn)
// s.Value = append(s.Value, e)
type SVCBNoDefaultAlpn struct{}
func (*SVCBNoDefaultAlpn) Key() SVCBKey { return SVCB_NO_DEFAULT_ALPN }
func (*SVCBNoDefaultAlpn) copy() SVCBKeyValue { return &SVCBNoDefaultAlpn{} }
func (*SVCBNoDefaultAlpn) pack() ([]byte, error) { return []byte{}, nil }
func (*SVCBNoDefaultAlpn) String() string { return "" }
func (*SVCBNoDefaultAlpn) len() int { return 0 }
func (*SVCBNoDefaultAlpn) unpack(b []byte) error {
if len(b) != 0 {
return errors.New("dns: svcbnodefaultalpn: no_default_alpn must have no value")
}
return nil
}
func (*SVCBNoDefaultAlpn) parse(b string) error {
if len(b) != 0 {
return errors.New("dns: svcbnodefaultalpn: no_default_alpn must have no value")
}
return nil
}
// SVCBPort pair defines the port for connection.
// Basic use pattern for creating a port option:
//
// s := &dns.SVCB{Hdr: dns.RR_Header{Name: ".", Rrtype: dns.TypeSVCB, Class: dns.ClassINET}}
// e := new(dns.SVCBPort)
// e.Port = 80
// s.Value = append(s.Value, e)
type SVCBPort struct {
Port uint16
}
func (*SVCBPort) Key() SVCBKey { return SVCB_PORT }
func (*SVCBPort) len() int { return 2 }
func (s *SVCBPort) String() string { return strconv.FormatUint(uint64(s.Port), 10) }
func (s *SVCBPort) copy() SVCBKeyValue { return &SVCBPort{s.Port} }
func (s *SVCBPort) unpack(b []byte) error {
if len(b) != 2 {
return errors.New("dns: svcbport: port length is not exactly 2 octets")
}
s.Port = binary.BigEndian.Uint16(b)
return nil
}
func (s *SVCBPort) pack() ([]byte, error) {
b := make([]byte, 2)
binary.BigEndian.PutUint16(b, s.Port)
return b, nil
}
func (s *SVCBPort) parse(b string) error {
port, err := strconv.ParseUint(b, 10, 16)
if err != nil {
return errors.New("dns: svcbport: port out of range")
}
s.Port = uint16(port)
return nil
}
// SVCBIPv4Hint pair suggests an IPv4 address which may be used to open connections
// if A and AAAA record responses for SVCB's Target domain haven't been received.
// In that case, optionally, A and AAAA requests can be made, after which the connection
// to the hinted IP address may be terminated and a new connection may be opened.
// Basic use pattern for creating an ipv4hint option:
//
// h := new(dns.HTTPS)
// h.Hdr = dns.RR_Header{Name: ".", Rrtype: dns.TypeHTTPS, Class: dns.ClassINET}
// e := new(dns.SVCBIPv4Hint)
// e.Hint = []net.IP{net.IPv4(1,1,1,1).To4()}
//
// Or
//
// e.Hint = []net.IP{net.ParseIP("1.1.1.1").To4()}
// h.Value = append(h.Value, e)
type SVCBIPv4Hint struct {
Hint []net.IP
}
func (*SVCBIPv4Hint) Key() SVCBKey { return SVCB_IPV4HINT }
func (s *SVCBIPv4Hint) len() int { return 4 * len(s.Hint) }
func (s *SVCBIPv4Hint) pack() ([]byte, error) {
b := make([]byte, 0, 4*len(s.Hint))
for _, e := range s.Hint {
x := e.To4()
if x == nil {
return nil, errors.New("dns: svcbipv4hint: expected ipv4, hint is ipv6")
}
b = append(b, x...)
}
return b, nil
}
func (s *SVCBIPv4Hint) unpack(b []byte) error {
if len(b) == 0 || len(b)%4 != 0 {
return errors.New("dns: svcbipv4hint: ipv4 address byte array length is not a multiple of 4")
}
x := make([]net.IP, 0, len(b)/4)
for i := 0; i < len(b); i += 4 {
x = append(x, net.IP(b[i:i+4]))
}
s.Hint = x
return nil
}
func (s *SVCBIPv4Hint) String() string {
str := make([]string, len(s.Hint))
for i, e := range s.Hint {
x := e.To4()
if x == nil {
return "<nil>"
}
str[i] = x.String()
}
return strings.Join(str, ",")
}
func (s *SVCBIPv4Hint) parse(b string) error {
if strings.Contains(b, ":") {
return errors.New("dns: svcbipv4hint: expected ipv4, got ipv6")
}
str := strings.Split(b, ",")
dst := make([]net.IP, len(str))
for i, e := range str {
ip := net.ParseIP(e).To4()
if ip == nil {
return errors.New("dns: svcbipv4hint: bad ip")
}
dst[i] = ip
}
s.Hint = dst
return nil
}
func (s *SVCBIPv4Hint) copy() SVCBKeyValue {
return &SVCBIPv4Hint{
append([]net.IP(nil), s.Hint...),
}
}
// SVCBECHConfig pair contains the ECHConfig structure defined in draft-ietf-tls-esni [RFC xxxx].
// Basic use pattern for creating an echconfig option:
//
// h := new(dns.HTTPS)
// h.Hdr = dns.RR_Header{Name: ".", Rrtype: dns.TypeHTTPS, Class: dns.ClassINET}
// e := new(dns.SVCBECHConfig)
// e.ECH = []byte{0xfe, 0x08, ...}
// h.Value = append(h.Value, e)
type SVCBECHConfig struct {
ECH []byte
}
func (*SVCBECHConfig) Key() SVCBKey { return SVCB_ECHCONFIG }
func (s *SVCBECHConfig) String() string { return toBase64(s.ECH) }
func (s *SVCBECHConfig) len() int { return len(s.ECH) }
func (s *SVCBECHConfig) pack() ([]byte, error) {
return append([]byte(nil), s.ECH...), nil
}
func (s *SVCBECHConfig) copy() SVCBKeyValue {
return &SVCBECHConfig{
append([]byte(nil), s.ECH...),
}
}
func (s *SVCBECHConfig) unpack(b []byte) error {
s.ECH = append([]byte(nil), b...)
return nil
}
func (s *SVCBECHConfig) parse(b string) error {
x, err := fromBase64([]byte(b))
if err != nil {
return errors.New("dns: svcbechconfig: bad base64 echconfig")
}
s.ECH = x
return nil
}
// SVCBIPv6Hint pair suggests an IPv6 address which may be used to open connections
// if A and AAAA record responses for SVCB's Target domain haven't been received.
// In that case, optionally, A and AAAA requests can be made, after which the
// connection to the hinted IP address may be terminated and a new connection may be opened.
// Basic use pattern for creating an ipv6hint option:
//
// h := new(dns.HTTPS)
// h.Hdr = dns.RR_Header{Name: ".", Rrtype: dns.TypeHTTPS, Class: dns.ClassINET}
// e := new(dns.SVCBIPv6Hint)
// e.Hint = []net.IP{net.ParseIP("2001:db8::1")}
// h.Value = append(h.Value, e)
type SVCBIPv6Hint struct {
Hint []net.IP
}
func (*SVCBIPv6Hint) Key() SVCBKey { return SVCB_IPV6HINT }
func (s *SVCBIPv6Hint) len() int { return 16 * len(s.Hint) }
func (s *SVCBIPv6Hint) pack() ([]byte, error) {
b := make([]byte, 0, 16*len(s.Hint))
for _, e := range s.Hint {
if len(e) != net.IPv6len || e.To4() != nil {
return nil, errors.New("dns: svcbipv6hint: expected ipv6, hint is ipv4")
}
b = append(b, e...)
}
return b, nil
}
func (s *SVCBIPv6Hint) unpack(b []byte) error {
if len(b) == 0 || len(b)%16 != 0 {
return errors.New("dns: svcbipv6hint: ipv6 address byte array length not a multiple of 16")
}
x := make([]net.IP, 0, len(b)/16)
for i := 0; i < len(b); i += 16 {
ip := net.IP(b[i : i+16])
if ip.To4() != nil {
return errors.New("dns: svcbipv6hint: expected ipv6, got ipv4")
}
x = append(x, ip)
}
s.Hint = x
return nil
}
func (s *SVCBIPv6Hint) String() string {
str := make([]string, len(s.Hint))
for i, e := range s.Hint {
if x := e.To4(); x != nil {
return "<nil>"
}
str[i] = e.String()
}
return strings.Join(str, ",")
}
func (s *SVCBIPv6Hint) parse(b string) error {
if strings.Contains(b, ".") {
return errors.New("dns: svcbipv6hint: expected ipv6, got ipv4")
}
str := strings.Split(b, ",")
dst := make([]net.IP, len(str))
for i, e := range str {
ip := net.ParseIP(e)
if ip == nil {
return errors.New("dns: svcbipv6hint: bad ip")
}
dst[i] = ip
}
s.Hint = dst
return nil
}
func (s *SVCBIPv6Hint) copy() SVCBKeyValue {
return &SVCBIPv6Hint{
append([]net.IP(nil), s.Hint...),
}
}
// SVCBLocal pair is intended for experimental/private use. The key is recommended
// to be in the range [SVCB_PRIVATE_LOWER, SVCB_PRIVATE_UPPER].
// Basic use pattern for creating a keyNNNNN option:
//
// h := new(dns.HTTPS)
// h.Hdr = dns.RR_Header{Name: ".", Rrtype: dns.TypeHTTPS, Class: dns.ClassINET}
// e := new(dns.SVCBLocal)
// e.KeyCode = 65400
// e.Data = []byte("abc")
// h.Value = append(h.Value, e)
type SVCBLocal struct {
KeyCode SVCBKey // Never 65535 or any assigned keys.
Data []byte // All byte sequences are allowed.
}
func (s *SVCBLocal) Key() SVCBKey { return s.KeyCode }
func (s *SVCBLocal) pack() ([]byte, error) { return append([]byte(nil), s.Data...), nil }
func (s *SVCBLocal) len() int { return len(s.Data) }
func (s *SVCBLocal) unpack(b []byte) error {
s.Data = append([]byte(nil), b...)
return nil
}
func (s *SVCBLocal) String() string {
var str strings.Builder
str.Grow(4 * len(s.Data))
for _, e := range s.Data {
if ' ' <= e && e <= '~' {
switch e {
case '"', ';', ' ', '\\':
str.WriteByte('\\')
str.WriteByte(e)
default:
str.WriteByte(e)
}
} else {
str.WriteString(escapeByte(e))
}
}
return str.String()
}
func (s *SVCBLocal) parse(b string) error {
data := make([]byte, 0, len(b))
for i := 0; i < len(b); {
if b[i] != '\\' {
data = append(data, b[i])
i++
continue
}
if i+1 == len(b) {
return errors.New("dns: svcblocal: svcb private/experimental key escape unterminated")
}
if isDigit(b[i+1]) {
if i+3 < len(b) && isDigit(b[i+2]) && isDigit(b[i+3]) {
a, err := strconv.ParseUint(b[i+1:i+4], 10, 8)
if err == nil {
i += 4
data = append(data, byte(a))
continue
}
}
return errors.New("dns: svcblocal: svcb private/experimental key bad escaped octet")
} else {
data = append(data, b[i+1])
i += 2
}
}
s.Data = data
return nil
}
func (s *SVCBLocal) copy() SVCBKeyValue {
return &SVCBLocal{s.KeyCode,
append([]byte(nil), s.Data...),
}
}
func (rr *SVCB) String() string {
s := rr.Hdr.String() +
strconv.Itoa(int(rr.Priority)) + " " +
sprintName(rr.Target)
for _, e := range rr.Value {
s += " " + e.Key().String() + "=\"" + e.String() + "\""
}
return s
}
// areSVCBPairArraysEqual checks if SVCBKeyValue arrays are equal after sorting their
// copies. arrA and arrB have equal lengths, otherwise zduplicate.go wouldn't call this function.
func areSVCBPairArraysEqual(a []SVCBKeyValue, b []SVCBKeyValue) bool {
a = append([]SVCBKeyValue(nil), a...)
b = append([]SVCBKeyValue(nil), b...)
sort.Slice(a, func(i, j int) bool { return a[i].Key() < a[j].Key() })
sort.Slice(b, func(i, j int) bool { return b[i].Key() < b[j].Key() })
for i, e := range a {
if e.Key() != b[i].Key() {
return false
}
b1, err1 := e.pack()
b2, err2 := b[i].pack()
if err1 != nil || err2 != nil || !bytes.Equal(b1, b2) {
return false
}
}
return true
}
...@@ -2,7 +2,6 @@ package dns ...@@ -2,7 +2,6 @@ package dns
import ( import (
"crypto/hmac" "crypto/hmac"
"crypto/md5"
"crypto/sha1" "crypto/sha1"
"crypto/sha256" "crypto/sha256"
"crypto/sha512" "crypto/sha512"
...@@ -16,10 +15,13 @@ import ( ...@@ -16,10 +15,13 @@ import (
// HMAC hashing codes. These are transmitted as domain names. // HMAC hashing codes. These are transmitted as domain names.
const ( const (
HmacMD5 = "hmac-md5.sig-alg.reg.int."
HmacSHA1 = "hmac-sha1." HmacSHA1 = "hmac-sha1."
HmacSHA224 = "hmac-sha224."
HmacSHA256 = "hmac-sha256." HmacSHA256 = "hmac-sha256."
HmacSHA384 = "hmac-sha384."
HmacSHA512 = "hmac-sha512." HmacSHA512 = "hmac-sha512."
HmacMD5 = "hmac-md5.sig-alg.reg.int." // Deprecated: HmacMD5 is no longer supported.
) )
// TSIG is the RR the holds the transaction signature of a message. // TSIG is the RR the holds the transaction signature of a message.
...@@ -40,7 +42,7 @@ type TSIG struct { ...@@ -40,7 +42,7 @@ type TSIG struct {
// TSIG has no official presentation format, but this will suffice. // TSIG has no official presentation format, but this will suffice.
func (rr *TSIG) String() string { func (rr *TSIG) String() string {
s := "\n;; TSIG PSEUDOSECTION:\n" s := "\n;; TSIG PSEUDOSECTION:\n; " // add another semi-colon to signify TSIG does not have a presentation format
s += rr.Hdr.String() + s += rr.Hdr.String() +
" " + rr.Algorithm + " " + rr.Algorithm +
" " + tsigTimeToString(rr.TimeSigned) + " " + tsigTimeToString(rr.TimeSigned) +
...@@ -54,7 +56,7 @@ func (rr *TSIG) String() string { ...@@ -54,7 +56,7 @@ func (rr *TSIG) String() string {
return s return s
} }
func (rr *TSIG) parse(c *zlexer, origin, file string) *ParseError { func (rr *TSIG) parse(c *zlexer, origin string) *ParseError {
panic("dns: internal error: parse should never be called on TSIG") panic("dns: internal error: parse should never be called on TSIG")
} }
...@@ -111,32 +113,33 @@ func TsigGenerate(m *Msg, secret, requestMAC string, timersOnly bool) ([]byte, s ...@@ -111,32 +113,33 @@ func TsigGenerate(m *Msg, secret, requestMAC string, timersOnly bool) ([]byte, s
if err != nil { if err != nil {
return nil, "", err return nil, "", err
} }
buf := tsigBuffer(mbuf, rr, requestMAC, timersOnly) buf, err := tsigBuffer(mbuf, rr, requestMAC, timersOnly)
if err != nil {
return nil, "", err
}
t := new(TSIG) t := new(TSIG)
var h hash.Hash var h hash.Hash
switch strings.ToLower(rr.Algorithm) { switch CanonicalName(rr.Algorithm) {
case HmacMD5:
h = hmac.New(md5.New, rawsecret)
case HmacSHA1: case HmacSHA1:
h = hmac.New(sha1.New, rawsecret) h = hmac.New(sha1.New, rawsecret)
case HmacSHA224:
h = hmac.New(sha256.New224, rawsecret)
case HmacSHA256: case HmacSHA256:
h = hmac.New(sha256.New, rawsecret) h = hmac.New(sha256.New, rawsecret)
case HmacSHA384:
h = hmac.New(sha512.New384, rawsecret)
case HmacSHA512: case HmacSHA512:
h = hmac.New(sha512.New, rawsecret) h = hmac.New(sha512.New, rawsecret)
default: default:
return nil, "", ErrKeyAlg return nil, "", ErrKeyAlg
} }
h.Write(buf) h.Write(buf)
// Copy all TSIG fields except MAC and its size, which are filled using the computed digest.
*t = *rr
t.MAC = hex.EncodeToString(h.Sum(nil)) t.MAC = hex.EncodeToString(h.Sum(nil))
t.MACSize = uint16(len(t.MAC) / 2) // Size is half! t.MACSize = uint16(len(t.MAC) / 2) // Size is half!
t.Hdr = RR_Header{Name: rr.Hdr.Name, Rrtype: TypeTSIG, Class: ClassANY, Ttl: 0}
t.Fudge = rr.Fudge
t.TimeSigned = rr.TimeSigned
t.Algorithm = rr.Algorithm
t.OrigId = m.Id
tbuf := make([]byte, Len(t)) tbuf := make([]byte, Len(t))
off, err := PackRR(t, tbuf, 0, nil, false) off, err := PackRR(t, tbuf, 0, nil, false)
if err != nil { if err != nil {
...@@ -153,6 +156,11 @@ func TsigGenerate(m *Msg, secret, requestMAC string, timersOnly bool) ([]byte, s ...@@ -153,6 +156,11 @@ func TsigGenerate(m *Msg, secret, requestMAC string, timersOnly bool) ([]byte, s
// If the signature does not validate err contains the // If the signature does not validate err contains the
// error, otherwise it is nil. // error, otherwise it is nil.
func TsigVerify(msg []byte, secret, requestMAC string, timersOnly bool) error { func TsigVerify(msg []byte, secret, requestMAC string, timersOnly bool) error {
return tsigVerify(msg, secret, requestMAC, timersOnly, uint64(time.Now().Unix()))
}
// actual implementation of TsigVerify, taking the current time ('now') as a parameter for the convenience of tests.
func tsigVerify(msg []byte, secret, requestMAC string, timersOnly bool, now uint64) error {
rawsecret, err := fromBase64([]byte(secret)) rawsecret, err := fromBase64([]byte(secret))
if err != nil { if err != nil {
return err return err
...@@ -168,27 +176,21 @@ func TsigVerify(msg []byte, secret, requestMAC string, timersOnly bool) error { ...@@ -168,27 +176,21 @@ func TsigVerify(msg []byte, secret, requestMAC string, timersOnly bool) error {
return err return err
} }
buf := tsigBuffer(stripped, tsig, requestMAC, timersOnly) buf, err := tsigBuffer(stripped, tsig, requestMAC, timersOnly)
if err != nil {
// Fudge factor works both ways. A message can arrive before it was signed because return err
// of clock skew.
now := uint64(time.Now().Unix())
ti := now - tsig.TimeSigned
if now < tsig.TimeSigned {
ti = tsig.TimeSigned - now
}
if uint64(tsig.Fudge) < ti {
return ErrTime
} }
var h hash.Hash var h hash.Hash
switch strings.ToLower(tsig.Algorithm) { switch CanonicalName(tsig.Algorithm) {
case HmacMD5:
h = hmac.New(md5.New, rawsecret)
case HmacSHA1: case HmacSHA1:
h = hmac.New(sha1.New, rawsecret) h = hmac.New(sha1.New, rawsecret)
case HmacSHA224:
h = hmac.New(sha256.New224, rawsecret)
case HmacSHA256: case HmacSHA256:
h = hmac.New(sha256.New, rawsecret) h = hmac.New(sha256.New, rawsecret)
case HmacSHA384:
h = hmac.New(sha512.New384, rawsecret)
case HmacSHA512: case HmacSHA512:
h = hmac.New(sha512.New, rawsecret) h = hmac.New(sha512.New, rawsecret)
default: default:
...@@ -198,11 +200,24 @@ func TsigVerify(msg []byte, secret, requestMAC string, timersOnly bool) error { ...@@ -198,11 +200,24 @@ func TsigVerify(msg []byte, secret, requestMAC string, timersOnly bool) error {
if !hmac.Equal(h.Sum(nil), msgMAC) { if !hmac.Equal(h.Sum(nil), msgMAC) {
return ErrSig return ErrSig
} }
// Fudge factor works both ways. A message can arrive before it was signed because
// of clock skew.
// We check this after verifying the signature, following draft-ietf-dnsop-rfc2845bis
// instead of RFC2845, in order to prevent a security vulnerability as reported in CVE-2017-3142/3143.
ti := now - tsig.TimeSigned
if now < tsig.TimeSigned {
ti = tsig.TimeSigned - now
}
if uint64(tsig.Fudge) < ti {
return ErrTime
}
return nil return nil
} }
// Create a wiredata buffer for the MAC calculation. // Create a wiredata buffer for the MAC calculation.
func tsigBuffer(msgbuf []byte, rr *TSIG, requestMAC string, timersOnly bool) []byte { func tsigBuffer(msgbuf []byte, rr *TSIG, requestMAC string, timersOnly bool) ([]byte, error) {
var buf []byte var buf []byte
if rr.TimeSigned == 0 { if rr.TimeSigned == 0 {
rr.TimeSigned = uint64(time.Now().Unix()) rr.TimeSigned = uint64(time.Now().Unix())
...@@ -219,7 +234,10 @@ func tsigBuffer(msgbuf []byte, rr *TSIG, requestMAC string, timersOnly bool) []b ...@@ -219,7 +234,10 @@ func tsigBuffer(msgbuf []byte, rr *TSIG, requestMAC string, timersOnly bool) []b
m.MACSize = uint16(len(requestMAC) / 2) m.MACSize = uint16(len(requestMAC) / 2)
m.MAC = requestMAC m.MAC = requestMAC
buf = make([]byte, len(requestMAC)) // long enough buf = make([]byte, len(requestMAC)) // long enough
n, _ := packMacWire(m, buf) n, err := packMacWire(m, buf)
if err != nil {
return nil, err
}
buf = buf[:n] buf = buf[:n]
} }
...@@ -228,20 +246,26 @@ func tsigBuffer(msgbuf []byte, rr *TSIG, requestMAC string, timersOnly bool) []b ...@@ -228,20 +246,26 @@ func tsigBuffer(msgbuf []byte, rr *TSIG, requestMAC string, timersOnly bool) []b
tsig := new(timerWireFmt) tsig := new(timerWireFmt)
tsig.TimeSigned = rr.TimeSigned tsig.TimeSigned = rr.TimeSigned
tsig.Fudge = rr.Fudge tsig.Fudge = rr.Fudge
n, _ := packTimerWire(tsig, tsigvar) n, err := packTimerWire(tsig, tsigvar)
if err != nil {
return nil, err
}
tsigvar = tsigvar[:n] tsigvar = tsigvar[:n]
} else { } else {
tsig := new(tsigWireFmt) tsig := new(tsigWireFmt)
tsig.Name = strings.ToLower(rr.Hdr.Name) tsig.Name = CanonicalName(rr.Hdr.Name)
tsig.Class = ClassANY tsig.Class = ClassANY
tsig.Ttl = rr.Hdr.Ttl tsig.Ttl = rr.Hdr.Ttl
tsig.Algorithm = strings.ToLower(rr.Algorithm) tsig.Algorithm = CanonicalName(rr.Algorithm)
tsig.TimeSigned = rr.TimeSigned tsig.TimeSigned = rr.TimeSigned
tsig.Fudge = rr.Fudge tsig.Fudge = rr.Fudge
tsig.Error = rr.Error tsig.Error = rr.Error
tsig.OtherLen = rr.OtherLen tsig.OtherLen = rr.OtherLen
tsig.OtherData = rr.OtherData tsig.OtherData = rr.OtherData
n, _ := packTsigWire(tsig, tsigvar) n, err := packTsigWire(tsig, tsigvar)
if err != nil {
return nil, err
}
tsigvar = tsigvar[:n] tsigvar = tsigvar[:n]
} }
...@@ -251,7 +275,7 @@ func tsigBuffer(msgbuf []byte, rr *TSIG, requestMAC string, timersOnly bool) []b ...@@ -251,7 +275,7 @@ func tsigBuffer(msgbuf []byte, rr *TSIG, requestMAC string, timersOnly bool) []b
} else { } else {
buf = append(msgbuf, tsigvar...) buf = append(msgbuf, tsigvar...)
} }
return buf return buf, nil
} }
// Strip the TSIG from the raw message. // Strip the TSIG from the raw message.
......
package dns package dns
import ( import (
"bytes"
"fmt" "fmt"
"net" "net"
"strconv" "strconv"
...@@ -61,6 +62,7 @@ const ( ...@@ -61,6 +62,7 @@ const (
TypeCERT uint16 = 37 TypeCERT uint16 = 37
TypeDNAME uint16 = 39 TypeDNAME uint16 = 39
TypeOPT uint16 = 41 // EDNS TypeOPT uint16 = 41 // EDNS
TypeAPL uint16 = 42
TypeDS uint16 = 43 TypeDS uint16 = 43
TypeSSHFP uint16 = 44 TypeSSHFP uint16 = 44
TypeRRSIG uint16 = 46 TypeRRSIG uint16 = 46
...@@ -79,6 +81,8 @@ const ( ...@@ -79,6 +81,8 @@ const (
TypeCDNSKEY uint16 = 60 TypeCDNSKEY uint16 = 60
TypeOPENPGPKEY uint16 = 61 TypeOPENPGPKEY uint16 = 61
TypeCSYNC uint16 = 62 TypeCSYNC uint16 = 62
TypeSVCB uint16 = 64
TypeHTTPS uint16 = 65
TypeSPF uint16 = 99 TypeSPF uint16 = 99
TypeUINFO uint16 = 100 TypeUINFO uint16 = 100
TypeUID uint16 = 101 TypeUID uint16 = 101
...@@ -163,11 +167,11 @@ const ( ...@@ -163,11 +167,11 @@ const (
_RD = 1 << 8 // recursion desired _RD = 1 << 8 // recursion desired
_RA = 1 << 7 // recursion available _RA = 1 << 7 // recursion available
_Z = 1 << 6 // Z _Z = 1 << 6 // Z
_AD = 1 << 5 // authticated data _AD = 1 << 5 // authenticated data
_CD = 1 << 4 // checking disabled _CD = 1 << 4 // checking disabled
) )
// Various constants used in the LOC RR, See RFC 1887. // Various constants used in the LOC RR. See RFC 1887.
const ( const (
LOC_EQUATOR = 1 << 31 // RFC 1876, Section 2. LOC_EQUATOR = 1 << 31 // RFC 1876, Section 2.
LOC_PRIMEMERIDIAN = 1 << 31 // RFC 1876, Section 2. LOC_PRIMEMERIDIAN = 1 << 31 // RFC 1876, Section 2.
...@@ -207,8 +211,11 @@ var CertTypeToString = map[uint16]string{ ...@@ -207,8 +211,11 @@ var CertTypeToString = map[uint16]string{
//go:generate go run types_generate.go //go:generate go run types_generate.go
// Question holds a DNS question. There can be multiple questions in the // Question holds a DNS question. Usually there is just one. While the
// question section of a message. Usually there is just one. // original DNS RFCs allow multiple questions in the question section of a
// message, in practice it never works. Because most DNS servers see multiple
// questions as an error, it is recommended to only have one question per
// message.
type Question struct { type Question struct {
Name string `dns:"cdomain-name"` // "cdomain-name" specifies encoding (and may be compressed) Name string `dns:"cdomain-name"` // "cdomain-name" specifies encoding (and may be compressed)
Qtype uint16 Qtype uint16
...@@ -229,7 +236,7 @@ func (q *Question) String() (s string) { ...@@ -229,7 +236,7 @@ func (q *Question) String() (s string) {
return s return s
} }
// ANY is a wildcard record. See RFC 1035, Section 3.2.3. ANY // ANY is a wild card record. See RFC 1035, Section 3.2.3. ANY
// is named "*" there. // is named "*" there.
type ANY struct { type ANY struct {
Hdr RR_Header Hdr RR_Header
...@@ -238,7 +245,7 @@ type ANY struct { ...@@ -238,7 +245,7 @@ type ANY struct {
func (rr *ANY) String() string { return rr.Hdr.String() } func (rr *ANY) String() string { return rr.Hdr.String() }
func (rr *ANY) parse(c *zlexer, origin, file string) *ParseError { func (rr *ANY) parse(c *zlexer, origin string) *ParseError {
panic("dns: internal error: parse should never be called on ANY") panic("dns: internal error: parse should never be called on ANY")
} }
...@@ -253,7 +260,7 @@ func (rr *NULL) String() string { ...@@ -253,7 +260,7 @@ func (rr *NULL) String() string {
return ";" + rr.Hdr.String() + rr.Data return ";" + rr.Hdr.String() + rr.Data
} }
func (rr *NULL) parse(c *zlexer, origin, file string) *ParseError { func (rr *NULL) parse(c *zlexer, origin string) *ParseError {
panic("dns: internal error: parse should never be called on NULL") panic("dns: internal error: parse should never be called on NULL")
} }
...@@ -438,25 +445,47 @@ func (rr *TXT) String() string { return rr.Hdr.String() + sprintTxt(rr.Txt) } ...@@ -438,25 +445,47 @@ func (rr *TXT) String() string { return rr.Hdr.String() + sprintTxt(rr.Txt) }
func sprintName(s string) string { func sprintName(s string) string {
var dst strings.Builder var dst strings.Builder
dst.Grow(len(s))
for i := 0; i < len(s); { for i := 0; i < len(s); {
if i+1 < len(s) && s[i] == '\\' && s[i+1] == '.' { if s[i] == '.' {
dst.WriteString(s[i : i+2]) if dst.Len() != 0 {
i += 2 dst.WriteByte('.')
}
i++
continue continue
} }
b, n := nextByte(s, i) b, n := nextByte(s, i)
switch { if n == 0 {
case n == 0: // Drop "dangling" incomplete escapes.
i++ // dangling back slash if dst.Len() == 0 {
case b == '.': return s[:i]
dst.WriteByte('.') }
default: break
writeDomainNameByte(&dst, b) }
if isDomainNameLabelSpecial(b) {
if dst.Len() == 0 {
dst.Grow(len(s) * 2)
dst.WriteString(s[:i])
}
dst.WriteByte('\\')
dst.WriteByte(b)
} else if b < ' ' || b > '~' { // unprintable, use \DDD
if dst.Len() == 0 {
dst.Grow(len(s) * 2)
dst.WriteString(s[:i])
}
dst.WriteString(escapeByte(b))
} else {
if dst.Len() != 0 {
dst.WriteByte(b)
}
} }
i += n i += n
} }
if dst.Len() == 0 {
return s
}
return dst.String() return dst.String()
} }
...@@ -472,15 +501,10 @@ func sprintTxtOctet(s string) string { ...@@ -472,15 +501,10 @@ func sprintTxtOctet(s string) string {
} }
b, n := nextByte(s, i) b, n := nextByte(s, i)
switch { if n == 0 {
case n == 0:
i++ // dangling back slash i++ // dangling back slash
case b == '.': } else {
dst.WriteByte('.') writeTXTStringByte(&dst, b)
case b < ' ' || b > '~':
dst.WriteString(escapeByte(b))
default:
dst.WriteByte(b)
} }
i += n i += n
} }
...@@ -510,16 +534,6 @@ func sprintTxt(txt []string) string { ...@@ -510,16 +534,6 @@ func sprintTxt(txt []string) string {
return out.String() return out.String()
} }
func writeDomainNameByte(s *strings.Builder, b byte) {
switch b {
case '.', ' ', '\'', '@', ';', '(', ')': // additional chars to escape
s.WriteByte('\\')
s.WriteByte(b)
default:
writeTXTStringByte(s, b)
}
}
func writeTXTStringByte(s *strings.Builder, b byte) { func writeTXTStringByte(s *strings.Builder, b byte) {
switch { switch {
case b == '"' || b == '\\': case b == '"' || b == '\\':
...@@ -566,6 +580,17 @@ func escapeByte(b byte) string { ...@@ -566,6 +580,17 @@ func escapeByte(b byte) string {
return escapedByteLarge[int(b)*4 : int(b)*4+4] return escapedByteLarge[int(b)*4 : int(b)*4+4]
} }
// isDomainNameLabelSpecial returns true if
// a domain name label byte should be prefixed
// with an escaping backslash.
func isDomainNameLabelSpecial(b byte) bool {
switch b {
case '.', ' ', '\'', '@', ';', '(', ')', '"', '\\':
return true
}
return false
}
func nextByte(s string, offset int) (byte, int) { func nextByte(s string, offset int) (byte, int) {
if offset >= len(s) { if offset >= len(s) {
return 0, 0 return 0, 0
...@@ -738,8 +763,8 @@ type LOC struct { ...@@ -738,8 +763,8 @@ type LOC struct {
Altitude uint32 Altitude uint32
} }
// cmToM takes a cm value expressed in RFC1876 SIZE mantissa/exponent // cmToM takes a cm value expressed in RFC 1876 SIZE mantissa/exponent
// format and returns a string in m (two decimals for the cm) // format and returns a string in m (two decimals for the cm).
func cmToM(m, e uint8) string { func cmToM(m, e uint8) string {
if e < 2 { if e < 2 {
if e == 1 { if e == 1 {
...@@ -854,14 +879,7 @@ func (rr *NSEC) String() string { ...@@ -854,14 +879,7 @@ func (rr *NSEC) String() string {
func (rr *NSEC) len(off int, compression map[string]struct{}) int { func (rr *NSEC) len(off int, compression map[string]struct{}) int {
l := rr.Hdr.len(off, compression) l := rr.Hdr.len(off, compression)
l += domainNameLen(rr.NextDomain, off+l, compression, false) l += domainNameLen(rr.NextDomain, off+l, compression, false)
lastwindow := uint32(2 ^ 32 + 1) l += typeBitMapLen(rr.TypeBitMap)
for _, t := range rr.TypeBitMap {
window := t / 256
if uint32(window) != lastwindow {
l += 1 + 32
}
lastwindow = uint32(window)
}
return l return l
} }
...@@ -1020,14 +1038,7 @@ func (rr *NSEC3) String() string { ...@@ -1020,14 +1038,7 @@ func (rr *NSEC3) String() string {
func (rr *NSEC3) len(off int, compression map[string]struct{}) int { func (rr *NSEC3) len(off int, compression map[string]struct{}) int {
l := rr.Hdr.len(off, compression) l := rr.Hdr.len(off, compression)
l += 6 + len(rr.Salt)/2 + 1 + len(rr.NextDomain) + 1 l += 6 + len(rr.Salt)/2 + 1 + len(rr.NextDomain) + 1
lastwindow := uint32(2 ^ 32 + 1) l += typeBitMapLen(rr.TypeBitMap)
for _, t := range rr.TypeBitMap {
window := t / 256
if uint32(window) != lastwindow {
l += 1 + 32
}
lastwindow = uint32(window)
}
return l return l
} }
...@@ -1111,6 +1122,7 @@ type URI struct { ...@@ -1111,6 +1122,7 @@ type URI struct {
Target string `dns:"octet"` Target string `dns:"octet"`
} }
// rr.Target to be parsed as a sequence of character encoded octets according to RFC 3986
func (rr *URI) String() string { func (rr *URI) String() string {
return rr.Hdr.String() + strconv.Itoa(int(rr.Priority)) + return rr.Hdr.String() + strconv.Itoa(int(rr.Priority)) +
" " + strconv.Itoa(int(rr.Weight)) + " " + sprintTxtOctet(rr.Target) " " + strconv.Itoa(int(rr.Weight)) + " " + sprintTxtOctet(rr.Target)
...@@ -1272,6 +1284,7 @@ type CAA struct { ...@@ -1272,6 +1284,7 @@ type CAA struct {
Value string `dns:"octet"` Value string `dns:"octet"`
} }
// rr.Value Is the character-string encoding of the value field as specified in RFC 1035, Section 5.1.
func (rr *CAA) String() string { func (rr *CAA) String() string {
return rr.Hdr.String() + strconv.Itoa(int(rr.Flag)) + " " + rr.Tag + " " + sprintTxtOctet(rr.Value) return rr.Hdr.String() + strconv.Itoa(int(rr.Flag)) + " " + rr.Tag + " " + sprintTxtOctet(rr.Value)
} }
...@@ -1344,15 +1357,90 @@ func (rr *CSYNC) String() string { ...@@ -1344,15 +1357,90 @@ func (rr *CSYNC) String() string {
func (rr *CSYNC) len(off int, compression map[string]struct{}) int { func (rr *CSYNC) len(off int, compression map[string]struct{}) int {
l := rr.Hdr.len(off, compression) l := rr.Hdr.len(off, compression)
l += 4 + 2 l += 4 + 2
lastwindow := uint32(2 ^ 32 + 1) l += typeBitMapLen(rr.TypeBitMap)
for _, t := range rr.TypeBitMap { return l
window := t / 256 }
if uint32(window) != lastwindow {
l += 1 + 32 // APL RR. See RFC 3123.
type APL struct {
Hdr RR_Header
Prefixes []APLPrefix `dns:"apl"`
}
// APLPrefix is an address prefix hold by an APL record.
type APLPrefix struct {
Negation bool
Network net.IPNet
}
// String returns presentation form of the APL record.
func (rr *APL) String() string {
var sb strings.Builder
sb.WriteString(rr.Hdr.String())
for i, p := range rr.Prefixes {
if i > 0 {
sb.WriteByte(' ')
} }
lastwindow = uint32(window) sb.WriteString(p.str())
} }
return l return sb.String()
}
// str returns presentation form of the APL prefix.
func (p *APLPrefix) str() string {
var sb strings.Builder
if p.Negation {
sb.WriteByte('!')
}
switch len(p.Network.IP) {
case net.IPv4len:
sb.WriteByte('1')
case net.IPv6len:
sb.WriteByte('2')
}
sb.WriteByte(':')
switch len(p.Network.IP) {
case net.IPv4len:
sb.WriteString(p.Network.IP.String())
case net.IPv6len:
// add prefix for IPv4-mapped IPv6
if v4 := p.Network.IP.To4(); v4 != nil {
sb.WriteString("::ffff:")
}
sb.WriteString(p.Network.IP.String())
}
sb.WriteByte('/')
prefix, _ := p.Network.Mask.Size()
sb.WriteString(strconv.Itoa(prefix))
return sb.String()
}
// equals reports whether two APL prefixes are identical.
func (a *APLPrefix) equals(b *APLPrefix) bool {
return a.Negation == b.Negation &&
bytes.Equal(a.Network.IP, b.Network.IP) &&
bytes.Equal(a.Network.Mask, b.Network.Mask)
}
// copy returns a copy of the APL prefix.
func (p *APLPrefix) copy() APLPrefix {
return APLPrefix{
Negation: p.Negation,
Network: copyNet(p.Network),
}
}
// len returns size of the prefix in wire format.
func (p *APLPrefix) len() int {
// 4-byte header and the network address prefix (see Section 4 of RFC 3123)
prefix, _ := p.Network.Mask.Size()
return 4 + (prefix+7)/8
} }
// TimeToString translates the RRSIG's incep. and expir. times to the // TimeToString translates the RRSIG's incep. and expir. times to the
...@@ -1411,6 +1499,17 @@ func copyIP(ip net.IP) net.IP { ...@@ -1411,6 +1499,17 @@ func copyIP(ip net.IP) net.IP {
return p return p
} }
// copyNet returns a copy of a subnet.
func copyNet(n net.IPNet) net.IPNet {
m := make(net.IPMask, len(n.Mask))
copy(m, n.Mask)
return net.IPNet{
IP: copyIP(n.IP),
Mask: m,
}
}
// SplitN splits a string into N sized string chunks. // SplitN splits a string into N sized string chunks.
// This might become an exported function once. // This might become an exported function once.
func splitN(s string, n int) []string { func splitN(s string, n int) []string {
......
...@@ -3,13 +3,13 @@ package dns ...@@ -3,13 +3,13 @@ package dns
import "fmt" import "fmt"
// Version is current version of this library. // Version is current version of this library.
var Version = V{1, 1, 8} var Version = v{1, 1, 35}
// V holds the version of this library. // v holds the version of this library.
type V struct { type v struct {
Major, Minor, Patch int Major, Minor, Patch int
} }
func (v V) String() string { func (v v) String() string {
return fmt.Sprintf("%d.%d.%d", v.Major, v.Minor, v.Patch) return fmt.Sprintf("%d.%d.%d", v.Major, v.Minor, v.Patch)
} }
...@@ -182,14 +182,17 @@ func (t *Transfer) inIxfr(q *Msg, c chan *Envelope) { ...@@ -182,14 +182,17 @@ func (t *Transfer) inIxfr(q *Msg, c chan *Envelope) {
// //
// ch := make(chan *dns.Envelope) // ch := make(chan *dns.Envelope)
// tr := new(dns.Transfer) // tr := new(dns.Transfer)
// go tr.Out(w, r, ch) // var wg sync.WaitGroup
// go func() {
// tr.Out(w, r, ch)
// wg.Done()
// }()
// ch <- &dns.Envelope{RR: []dns.RR{soa, rr1, rr2, rr3, soa}} // ch <- &dns.Envelope{RR: []dns.RR{soa, rr1, rr2, rr3, soa}}
// close(ch) // close(ch)
// w.Hijack() // wg.Wait() // wait until everything is written out
// // w.Close() // Client closes connection // w.Close() // close connection
// //
// The server is responsible for sending the correct sequence of RRs through the // The server is responsible for sending the correct sequence of RRs through the channel ch.
// channel ch.
func (t *Transfer) Out(w ResponseWriter, q *Msg, ch chan *Envelope) error { func (t *Transfer) Out(w ResponseWriter, q *Msg, ch chan *Envelope) error {
for x := range ch { for x := range ch {
r := new(Msg) r := new(Msg)
...@@ -198,11 +201,14 @@ func (t *Transfer) Out(w ResponseWriter, q *Msg, ch chan *Envelope) error { ...@@ -198,11 +201,14 @@ func (t *Transfer) Out(w ResponseWriter, q *Msg, ch chan *Envelope) error {
r.Authoritative = true r.Authoritative = true
// assume it fits TODO(miek): fix // assume it fits TODO(miek): fix
r.Answer = append(r.Answer, x.RR...) r.Answer = append(r.Answer, x.RR...)
if tsig := q.IsTsig(); tsig != nil && w.TsigStatus() == nil {
r.SetTsig(tsig.Hdr.Name, tsig.Algorithm, tsig.Fudge, time.Now().Unix())
}
if err := w.WriteMsg(r); err != nil { if err := w.WriteMsg(r); err != nil {
return err return err
} }
w.TsigTimersOnly(true)
} }
w.TsigTimersOnly(true)
return nil return nil
} }
......
...@@ -52,6 +52,23 @@ func (r1 *ANY) isDuplicate(_r2 RR) bool { ...@@ -52,6 +52,23 @@ func (r1 *ANY) isDuplicate(_r2 RR) bool {
return true return true
} }
func (r1 *APL) isDuplicate(_r2 RR) bool {
r2, ok := _r2.(*APL)
if !ok {
return false
}
_ = r2
if len(r1.Prefixes) != len(r2.Prefixes) {
return false
}
for i := 0; i < len(r1.Prefixes); i++ {
if !r1.Prefixes[i].equals(&r2.Prefixes[i]) {
return false
}
}
return true
}
func (r1 *AVC) isDuplicate(_r2 RR) bool { func (r1 *AVC) isDuplicate(_r2 RR) bool {
r2, ok := _r2.(*AVC) r2, ok := _r2.(*AVC)
if !ok { if !ok {
...@@ -87,6 +104,48 @@ func (r1 *CAA) isDuplicate(_r2 RR) bool { ...@@ -87,6 +104,48 @@ func (r1 *CAA) isDuplicate(_r2 RR) bool {
return true return true
} }
func (r1 *CDNSKEY) isDuplicate(_r2 RR) bool {
r2, ok := _r2.(*CDNSKEY)
if !ok {
return false
}
_ = r2
if r1.Flags != r2.Flags {
return false
}
if r1.Protocol != r2.Protocol {
return false
}
if r1.Algorithm != r2.Algorithm {
return false
}
if r1.PublicKey != r2.PublicKey {
return false
}
return true
}
func (r1 *CDS) isDuplicate(_r2 RR) bool {
r2, ok := _r2.(*CDS)
if !ok {
return false
}
_ = r2
if r1.KeyTag != r2.KeyTag {
return false
}
if r1.Algorithm != r2.Algorithm {
return false
}
if r1.DigestType != r2.DigestType {
return false
}
if r1.Digest != r2.Digest {
return false
}
return true
}
func (r1 *CERT) isDuplicate(_r2 RR) bool { func (r1 *CERT) isDuplicate(_r2 RR) bool {
r2, ok := _r2.(*CERT) r2, ok := _r2.(*CERT)
if !ok { if !ok {
...@@ -155,6 +214,27 @@ func (r1 *DHCID) isDuplicate(_r2 RR) bool { ...@@ -155,6 +214,27 @@ func (r1 *DHCID) isDuplicate(_r2 RR) bool {
return true return true
} }
func (r1 *DLV) isDuplicate(_r2 RR) bool {
r2, ok := _r2.(*DLV)
if !ok {
return false
}
_ = r2
if r1.KeyTag != r2.KeyTag {
return false
}
if r1.Algorithm != r2.Algorithm {
return false
}
if r1.DigestType != r2.DigestType {
return false
}
if r1.Digest != r2.Digest {
return false
}
return true
}
func (r1 *DNAME) isDuplicate(_r2 RR) bool { func (r1 *DNAME) isDuplicate(_r2 RR) bool {
r2, ok := _r2.(*DNAME) r2, ok := _r2.(*DNAME)
if !ok { if !ok {
...@@ -322,6 +402,48 @@ func (r1 *HIP) isDuplicate(_r2 RR) bool { ...@@ -322,6 +402,48 @@ func (r1 *HIP) isDuplicate(_r2 RR) bool {
return true return true
} }
func (r1 *HTTPS) isDuplicate(_r2 RR) bool {
r2, ok := _r2.(*HTTPS)
if !ok {
return false
}
_ = r2
if r1.Priority != r2.Priority {
return false
}
if !isDuplicateName(r1.Target, r2.Target) {
return false
}
if len(r1.Value) != len(r2.Value) {
return false
}
if !areSVCBPairArraysEqual(r1.Value, r2.Value) {
return false
}
return true
}
func (r1 *KEY) isDuplicate(_r2 RR) bool {
r2, ok := _r2.(*KEY)
if !ok {
return false
}
_ = r2
if r1.Flags != r2.Flags {
return false
}
if r1.Protocol != r2.Protocol {
return false
}
if r1.Algorithm != r2.Algorithm {
return false
}
if r1.PublicKey != r2.PublicKey {
return false
}
return true
}
func (r1 *KX) isDuplicate(_r2 RR) bool { func (r1 *KX) isDuplicate(_r2 RR) bool {
r2, ok := _r2.(*KX) r2, ok := _r2.(*KX)
if !ok { if !ok {
...@@ -832,6 +954,42 @@ func (r1 *RT) isDuplicate(_r2 RR) bool { ...@@ -832,6 +954,42 @@ func (r1 *RT) isDuplicate(_r2 RR) bool {
return true return true
} }
func (r1 *SIG) isDuplicate(_r2 RR) bool {
r2, ok := _r2.(*SIG)
if !ok {
return false
}
_ = r2
if r1.TypeCovered != r2.TypeCovered {
return false
}
if r1.Algorithm != r2.Algorithm {
return false
}
if r1.Labels != r2.Labels {
return false
}
if r1.OrigTtl != r2.OrigTtl {
return false
}
if r1.Expiration != r2.Expiration {
return false
}
if r1.Inception != r2.Inception {
return false
}
if r1.KeyTag != r2.KeyTag {
return false
}
if !isDuplicateName(r1.SignerName, r2.SignerName) {
return false
}
if r1.Signature != r2.Signature {
return false
}
return true
}
func (r1 *SMIMEA) isDuplicate(_r2 RR) bool { func (r1 *SMIMEA) isDuplicate(_r2 RR) bool {
r2, ok := _r2.(*SMIMEA) r2, ok := _r2.(*SMIMEA)
if !ok { if !ok {
...@@ -939,6 +1097,27 @@ func (r1 *SSHFP) isDuplicate(_r2 RR) bool { ...@@ -939,6 +1097,27 @@ func (r1 *SSHFP) isDuplicate(_r2 RR) bool {
return true return true
} }
func (r1 *SVCB) isDuplicate(_r2 RR) bool {
r2, ok := _r2.(*SVCB)
if !ok {
return false
}
_ = r2
if r1.Priority != r2.Priority {
return false
}
if !isDuplicateName(r1.Target, r2.Target) {
return false
}
if len(r1.Value) != len(r2.Value) {
return false
}
if !areSVCBPairArraysEqual(r1.Value, r2.Value) {
return false
}
return true
}
func (r1 *TA) isDuplicate(_r2 RR) bool { func (r1 *TA) isDuplicate(_r2 RR) bool {
r2, ok := _r2.(*TA) r2, ok := _r2.(*TA)
if !ok { if !ok {
......
...@@ -36,6 +36,14 @@ func (rr *ANY) pack(msg []byte, off int, compression compressionMap, compress bo ...@@ -36,6 +36,14 @@ func (rr *ANY) pack(msg []byte, off int, compression compressionMap, compress bo
return off, nil return off, nil
} }
func (rr *APL) pack(msg []byte, off int, compression compressionMap, compress bool) (off1 int, err error) {
off, err = packDataApl(rr.Prefixes, msg, off)
if err != nil {
return off, err
}
return off, nil
}
func (rr *AVC) pack(msg []byte, off int, compression compressionMap, compress bool) (off1 int, err error) { func (rr *AVC) pack(msg []byte, off int, compression compressionMap, compress bool) (off1 int, err error) {
off, err = packStringTxt(rr.Txt, msg, off) off, err = packStringTxt(rr.Txt, msg, off)
if err != nil { if err != nil {
...@@ -308,6 +316,22 @@ func (rr *HIP) pack(msg []byte, off int, compression compressionMap, compress bo ...@@ -308,6 +316,22 @@ func (rr *HIP) pack(msg []byte, off int, compression compressionMap, compress bo
return off, nil return off, nil
} }
func (rr *HTTPS) pack(msg []byte, off int, compression compressionMap, compress bool) (off1 int, err error) {
off, err = packUint16(rr.Priority, msg, off)
if err != nil {
return off, err
}
off, err = packDomainName(rr.Target, msg, off, compression, false)
if err != nil {
return off, err
}
off, err = packDataSVCB(rr.Value, msg, off)
if err != nil {
return off, err
}
return off, nil
}
func (rr *KEY) pack(msg []byte, off int, compression compressionMap, compress bool) (off1 int, err error) { func (rr *KEY) pack(msg []byte, off int, compression compressionMap, compress bool) (off1 int, err error) {
off, err = packUint16(rr.Flags, msg, off) off, err = packUint16(rr.Flags, msg, off)
if err != nil { if err != nil {
...@@ -898,6 +922,22 @@ func (rr *SSHFP) pack(msg []byte, off int, compression compressionMap, compress ...@@ -898,6 +922,22 @@ func (rr *SSHFP) pack(msg []byte, off int, compression compressionMap, compress
return off, nil return off, nil
} }
func (rr *SVCB) pack(msg []byte, off int, compression compressionMap, compress bool) (off1 int, err error) {
off, err = packUint16(rr.Priority, msg, off)
if err != nil {
return off, err
}
off, err = packDomainName(rr.Target, msg, off, compression, false)
if err != nil {
return off, err
}
off, err = packDataSVCB(rr.Value, msg, off)
if err != nil {
return off, err
}
return off, nil
}
func (rr *TA) pack(msg []byte, off int, compression compressionMap, compress bool) (off1 int, err error) { func (rr *TA) pack(msg []byte, off int, compression compressionMap, compress bool) (off1 int, err error) {
off, err = packUint16(rr.KeyTag, msg, off) off, err = packUint16(rr.KeyTag, msg, off)
if err != nil { if err != nil {
...@@ -1127,6 +1167,17 @@ func (rr *ANY) unpack(msg []byte, off int) (off1 int, err error) { ...@@ -1127,6 +1167,17 @@ func (rr *ANY) unpack(msg []byte, off int) (off1 int, err error) {
return off, nil return off, nil
} }
func (rr *APL) unpack(msg []byte, off int) (off1 int, err error) {
rdStart := off
_ = rdStart
rr.Prefixes, off, err = unpackDataApl(msg, off)
if err != nil {
return off, err
}
return off, nil
}
func (rr *AVC) unpack(msg []byte, off int) (off1 int, err error) { func (rr *AVC) unpack(msg []byte, off int) (off1 int, err error) {
rdStart := off rdStart := off
_ = rdStart _ = rdStart
...@@ -1540,6 +1591,31 @@ func (rr *HIP) unpack(msg []byte, off int) (off1 int, err error) { ...@@ -1540,6 +1591,31 @@ func (rr *HIP) unpack(msg []byte, off int) (off1 int, err error) {
return off, nil return off, nil
} }
func (rr *HTTPS) unpack(msg []byte, off int) (off1 int, err error) {
rdStart := off
_ = rdStart
rr.Priority, off, err = unpackUint16(msg, off)
if err != nil {
return off, err
}
if off == len(msg) {
return off, nil
}
rr.Target, off, err = UnpackDomainName(msg, off)
if err != nil {
return off, err
}
if off == len(msg) {
return off, nil
}
rr.Value, off, err = unpackDataSVCB(msg, off)
if err != nil {
return off, err
}
return off, nil
}
func (rr *KEY) unpack(msg []byte, off int) (off1 int, err error) { func (rr *KEY) unpack(msg []byte, off int) (off1 int, err error) {
rdStart := off rdStart := off
_ = rdStart _ = rdStart
...@@ -2442,6 +2518,31 @@ func (rr *SSHFP) unpack(msg []byte, off int) (off1 int, err error) { ...@@ -2442,6 +2518,31 @@ func (rr *SSHFP) unpack(msg []byte, off int) (off1 int, err error) {
return off, nil return off, nil
} }
func (rr *SVCB) unpack(msg []byte, off int) (off1 int, err error) {
rdStart := off
_ = rdStart
rr.Priority, off, err = unpackUint16(msg, off)
if err != nil {
return off, err
}
if off == len(msg) {
return off, nil
}
rr.Target, off, err = UnpackDomainName(msg, off)
if err != nil {
return off, err
}
if off == len(msg) {
return off, nil
}
rr.Value, off, err = unpackDataSVCB(msg, off)
if err != nil {
return off, err
}
return off, nil
}
func (rr *TA) unpack(msg []byte, off int) (off1 int, err error) { func (rr *TA) unpack(msg []byte, off int) (off1 int, err error) {
rdStart := off rdStart := off
_ = rdStart _ = rdStart
......
...@@ -13,6 +13,7 @@ var TypeToRR = map[uint16]func() RR{ ...@@ -13,6 +13,7 @@ var TypeToRR = map[uint16]func() RR{
TypeAAAA: func() RR { return new(AAAA) }, TypeAAAA: func() RR { return new(AAAA) },
TypeAFSDB: func() RR { return new(AFSDB) }, TypeAFSDB: func() RR { return new(AFSDB) },
TypeANY: func() RR { return new(ANY) }, TypeANY: func() RR { return new(ANY) },
TypeAPL: func() RR { return new(APL) },
TypeAVC: func() RR { return new(AVC) }, TypeAVC: func() RR { return new(AVC) },
TypeCAA: func() RR { return new(CAA) }, TypeCAA: func() RR { return new(CAA) },
TypeCDNSKEY: func() RR { return new(CDNSKEY) }, TypeCDNSKEY: func() RR { return new(CDNSKEY) },
...@@ -32,6 +33,7 @@ var TypeToRR = map[uint16]func() RR{ ...@@ -32,6 +33,7 @@ var TypeToRR = map[uint16]func() RR{
TypeGPOS: func() RR { return new(GPOS) }, TypeGPOS: func() RR { return new(GPOS) },
TypeHINFO: func() RR { return new(HINFO) }, TypeHINFO: func() RR { return new(HINFO) },
TypeHIP: func() RR { return new(HIP) }, TypeHIP: func() RR { return new(HIP) },
TypeHTTPS: func() RR { return new(HTTPS) },
TypeKEY: func() RR { return new(KEY) }, TypeKEY: func() RR { return new(KEY) },
TypeKX: func() RR { return new(KX) }, TypeKX: func() RR { return new(KX) },
TypeL32: func() RR { return new(L32) }, TypeL32: func() RR { return new(L32) },
...@@ -69,6 +71,7 @@ var TypeToRR = map[uint16]func() RR{ ...@@ -69,6 +71,7 @@ var TypeToRR = map[uint16]func() RR{
TypeSPF: func() RR { return new(SPF) }, TypeSPF: func() RR { return new(SPF) },
TypeSRV: func() RR { return new(SRV) }, TypeSRV: func() RR { return new(SRV) },
TypeSSHFP: func() RR { return new(SSHFP) }, TypeSSHFP: func() RR { return new(SSHFP) },
TypeSVCB: func() RR { return new(SVCB) },
TypeTA: func() RR { return new(TA) }, TypeTA: func() RR { return new(TA) },
TypeTALINK: func() RR { return new(TALINK) }, TypeTALINK: func() RR { return new(TALINK) },
TypeTKEY: func() RR { return new(TKEY) }, TypeTKEY: func() RR { return new(TKEY) },
...@@ -87,6 +90,7 @@ var TypeToString = map[uint16]string{ ...@@ -87,6 +90,7 @@ var TypeToString = map[uint16]string{
TypeAAAA: "AAAA", TypeAAAA: "AAAA",
TypeAFSDB: "AFSDB", TypeAFSDB: "AFSDB",
TypeANY: "ANY", TypeANY: "ANY",
TypeAPL: "APL",
TypeATMA: "ATMA", TypeATMA: "ATMA",
TypeAVC: "AVC", TypeAVC: "AVC",
TypeAXFR: "AXFR", TypeAXFR: "AXFR",
...@@ -108,6 +112,7 @@ var TypeToString = map[uint16]string{ ...@@ -108,6 +112,7 @@ var TypeToString = map[uint16]string{
TypeGPOS: "GPOS", TypeGPOS: "GPOS",
TypeHINFO: "HINFO", TypeHINFO: "HINFO",
TypeHIP: "HIP", TypeHIP: "HIP",
TypeHTTPS: "HTTPS",
TypeISDN: "ISDN", TypeISDN: "ISDN",
TypeIXFR: "IXFR", TypeIXFR: "IXFR",
TypeKEY: "KEY", TypeKEY: "KEY",
...@@ -151,6 +156,7 @@ var TypeToString = map[uint16]string{ ...@@ -151,6 +156,7 @@ var TypeToString = map[uint16]string{
TypeSPF: "SPF", TypeSPF: "SPF",
TypeSRV: "SRV", TypeSRV: "SRV",
TypeSSHFP: "SSHFP", TypeSSHFP: "SSHFP",
TypeSVCB: "SVCB",
TypeTA: "TA", TypeTA: "TA",
TypeTALINK: "TALINK", TypeTALINK: "TALINK",
TypeTKEY: "TKEY", TypeTKEY: "TKEY",
...@@ -169,6 +175,7 @@ func (rr *A) Header() *RR_Header { return &rr.Hdr } ...@@ -169,6 +175,7 @@ func (rr *A) Header() *RR_Header { return &rr.Hdr }
func (rr *AAAA) Header() *RR_Header { return &rr.Hdr } func (rr *AAAA) Header() *RR_Header { return &rr.Hdr }
func (rr *AFSDB) Header() *RR_Header { return &rr.Hdr } func (rr *AFSDB) Header() *RR_Header { return &rr.Hdr }
func (rr *ANY) Header() *RR_Header { return &rr.Hdr } func (rr *ANY) Header() *RR_Header { return &rr.Hdr }
func (rr *APL) Header() *RR_Header { return &rr.Hdr }
func (rr *AVC) Header() *RR_Header { return &rr.Hdr } func (rr *AVC) Header() *RR_Header { return &rr.Hdr }
func (rr *CAA) Header() *RR_Header { return &rr.Hdr } func (rr *CAA) Header() *RR_Header { return &rr.Hdr }
func (rr *CDNSKEY) Header() *RR_Header { return &rr.Hdr } func (rr *CDNSKEY) Header() *RR_Header { return &rr.Hdr }
...@@ -188,6 +195,7 @@ func (rr *GID) Header() *RR_Header { return &rr.Hdr } ...@@ -188,6 +195,7 @@ func (rr *GID) Header() *RR_Header { return &rr.Hdr }
func (rr *GPOS) Header() *RR_Header { return &rr.Hdr } func (rr *GPOS) Header() *RR_Header { return &rr.Hdr }
func (rr *HINFO) Header() *RR_Header { return &rr.Hdr } func (rr *HINFO) Header() *RR_Header { return &rr.Hdr }
func (rr *HIP) Header() *RR_Header { return &rr.Hdr } func (rr *HIP) Header() *RR_Header { return &rr.Hdr }
func (rr *HTTPS) Header() *RR_Header { return &rr.Hdr }
func (rr *KEY) Header() *RR_Header { return &rr.Hdr } func (rr *KEY) Header() *RR_Header { return &rr.Hdr }
func (rr *KX) Header() *RR_Header { return &rr.Hdr } func (rr *KX) Header() *RR_Header { return &rr.Hdr }
func (rr *L32) Header() *RR_Header { return &rr.Hdr } func (rr *L32) Header() *RR_Header { return &rr.Hdr }
...@@ -226,6 +234,7 @@ func (rr *SOA) Header() *RR_Header { return &rr.Hdr } ...@@ -226,6 +234,7 @@ func (rr *SOA) Header() *RR_Header { return &rr.Hdr }
func (rr *SPF) Header() *RR_Header { return &rr.Hdr } func (rr *SPF) Header() *RR_Header { return &rr.Hdr }
func (rr *SRV) Header() *RR_Header { return &rr.Hdr } func (rr *SRV) Header() *RR_Header { return &rr.Hdr }
func (rr *SSHFP) Header() *RR_Header { return &rr.Hdr } func (rr *SSHFP) Header() *RR_Header { return &rr.Hdr }
func (rr *SVCB) Header() *RR_Header { return &rr.Hdr }
func (rr *TA) Header() *RR_Header { return &rr.Hdr } func (rr *TA) Header() *RR_Header { return &rr.Hdr }
func (rr *TALINK) Header() *RR_Header { return &rr.Hdr } func (rr *TALINK) Header() *RR_Header { return &rr.Hdr }
func (rr *TKEY) Header() *RR_Header { return &rr.Hdr } func (rr *TKEY) Header() *RR_Header { return &rr.Hdr }
...@@ -262,6 +271,13 @@ func (rr *ANY) len(off int, compression map[string]struct{}) int { ...@@ -262,6 +271,13 @@ func (rr *ANY) len(off int, compression map[string]struct{}) int {
l := rr.Hdr.len(off, compression) l := rr.Hdr.len(off, compression)
return l return l
} }
func (rr *APL) len(off int, compression map[string]struct{}) int {
l := rr.Hdr.len(off, compression)
for _, x := range rr.Prefixes {
l += x.len()
}
return l
}
func (rr *AVC) len(off int, compression map[string]struct{}) int { func (rr *AVC) len(off int, compression map[string]struct{}) int {
l := rr.Hdr.len(off, compression) l := rr.Hdr.len(off, compression)
for _, x := range rr.Txt { for _, x := range rr.Txt {
...@@ -312,12 +328,12 @@ func (rr *DS) len(off int, compression map[string]struct{}) int { ...@@ -312,12 +328,12 @@ func (rr *DS) len(off int, compression map[string]struct{}) int {
l += 2 // KeyTag l += 2 // KeyTag
l++ // Algorithm l++ // Algorithm
l++ // DigestType l++ // DigestType
l += len(rr.Digest)/2 + 1 l += len(rr.Digest) / 2
return l return l
} }
func (rr *EID) len(off int, compression map[string]struct{}) int { func (rr *EID) len(off int, compression map[string]struct{}) int {
l := rr.Hdr.len(off, compression) l := rr.Hdr.len(off, compression)
l += len(rr.Endpoint)/2 + 1 l += len(rr.Endpoint) / 2
return l return l
} }
func (rr *EUI48) len(off int, compression map[string]struct{}) int { func (rr *EUI48) len(off int, compression map[string]struct{}) int {
...@@ -452,7 +468,7 @@ func (rr *NID) len(off int, compression map[string]struct{}) int { ...@@ -452,7 +468,7 @@ func (rr *NID) len(off int, compression map[string]struct{}) int {
} }
func (rr *NIMLOC) len(off int, compression map[string]struct{}) int { func (rr *NIMLOC) len(off int, compression map[string]struct{}) int {
l := rr.Hdr.len(off, compression) l := rr.Hdr.len(off, compression)
l += len(rr.Locator)/2 + 1 l += len(rr.Locator) / 2
return l return l
} }
func (rr *NINFO) len(off int, compression map[string]struct{}) int { func (rr *NINFO) len(off int, compression map[string]struct{}) int {
...@@ -505,7 +521,7 @@ func (rr *PX) len(off int, compression map[string]struct{}) int { ...@@ -505,7 +521,7 @@ func (rr *PX) len(off int, compression map[string]struct{}) int {
} }
func (rr *RFC3597) len(off int, compression map[string]struct{}) int { func (rr *RFC3597) len(off int, compression map[string]struct{}) int {
l := rr.Hdr.len(off, compression) l := rr.Hdr.len(off, compression)
l += len(rr.Rdata)/2 + 1 l += len(rr.Rdata) / 2
return l return l
} }
func (rr *RKEY) len(off int, compression map[string]struct{}) int { func (rr *RKEY) len(off int, compression map[string]struct{}) int {
...@@ -546,7 +562,7 @@ func (rr *SMIMEA) len(off int, compression map[string]struct{}) int { ...@@ -546,7 +562,7 @@ func (rr *SMIMEA) len(off int, compression map[string]struct{}) int {
l++ // Usage l++ // Usage
l++ // Selector l++ // Selector
l++ // MatchingType l++ // MatchingType
l += len(rr.Certificate)/2 + 1 l += len(rr.Certificate) / 2
return l return l
} }
func (rr *SOA) len(off int, compression map[string]struct{}) int { func (rr *SOA) len(off int, compression map[string]struct{}) int {
...@@ -579,7 +595,16 @@ func (rr *SSHFP) len(off int, compression map[string]struct{}) int { ...@@ -579,7 +595,16 @@ func (rr *SSHFP) len(off int, compression map[string]struct{}) int {
l := rr.Hdr.len(off, compression) l := rr.Hdr.len(off, compression)
l++ // Algorithm l++ // Algorithm
l++ // Type l++ // Type
l += len(rr.FingerPrint)/2 + 1 l += len(rr.FingerPrint) / 2
return l
}
func (rr *SVCB) len(off int, compression map[string]struct{}) int {
l := rr.Hdr.len(off, compression)
l += 2 // Priority
l += domainNameLen(rr.Target, off+l, compression, false)
for _, x := range rr.Value {
l += 4 + int(x.len())
}
return l return l
} }
func (rr *TA) len(off int, compression map[string]struct{}) int { func (rr *TA) len(off int, compression map[string]struct{}) int {
...@@ -587,7 +612,7 @@ func (rr *TA) len(off int, compression map[string]struct{}) int { ...@@ -587,7 +612,7 @@ func (rr *TA) len(off int, compression map[string]struct{}) int {
l += 2 // KeyTag l += 2 // KeyTag
l++ // Algorithm l++ // Algorithm
l++ // DigestType l++ // DigestType
l += len(rr.Digest)/2 + 1 l += len(rr.Digest) / 2
return l return l
} }
func (rr *TALINK) len(off int, compression map[string]struct{}) int { func (rr *TALINK) len(off int, compression map[string]struct{}) int {
...@@ -614,7 +639,7 @@ func (rr *TLSA) len(off int, compression map[string]struct{}) int { ...@@ -614,7 +639,7 @@ func (rr *TLSA) len(off int, compression map[string]struct{}) int {
l++ // Usage l++ // Usage
l++ // Selector l++ // Selector
l++ // MatchingType l++ // MatchingType
l += len(rr.Certificate)/2 + 1 l += len(rr.Certificate) / 2
return l return l
} }
func (rr *TSIG) len(off int, compression map[string]struct{}) int { func (rr *TSIG) len(off int, compression map[string]struct{}) int {
...@@ -673,6 +698,13 @@ func (rr *AFSDB) copy() RR { ...@@ -673,6 +698,13 @@ func (rr *AFSDB) copy() RR {
func (rr *ANY) copy() RR { func (rr *ANY) copy() RR {
return &ANY{rr.Hdr} return &ANY{rr.Hdr}
} }
func (rr *APL) copy() RR {
Prefixes := make([]APLPrefix, len(rr.Prefixes))
for i, e := range rr.Prefixes {
Prefixes[i] = e.copy()
}
return &APL{rr.Hdr, Prefixes}
}
func (rr *AVC) copy() RR { func (rr *AVC) copy() RR {
Txt := make([]string, len(rr.Txt)) Txt := make([]string, len(rr.Txt))
copy(Txt, rr.Txt) copy(Txt, rr.Txt)
...@@ -681,6 +713,12 @@ func (rr *AVC) copy() RR { ...@@ -681,6 +713,12 @@ func (rr *AVC) copy() RR {
func (rr *CAA) copy() RR { func (rr *CAA) copy() RR {
return &CAA{rr.Hdr, rr.Flag, rr.Tag, rr.Value} return &CAA{rr.Hdr, rr.Flag, rr.Tag, rr.Value}
} }
func (rr *CDNSKEY) copy() RR {
return &CDNSKEY{*rr.DNSKEY.copy().(*DNSKEY)}
}
func (rr *CDS) copy() RR {
return &CDS{*rr.DS.copy().(*DS)}
}
func (rr *CERT) copy() RR { func (rr *CERT) copy() RR {
return &CERT{rr.Hdr, rr.Type, rr.KeyTag, rr.Algorithm, rr.Certificate} return &CERT{rr.Hdr, rr.Type, rr.KeyTag, rr.Algorithm, rr.Certificate}
} }
...@@ -695,6 +733,9 @@ func (rr *CSYNC) copy() RR { ...@@ -695,6 +733,9 @@ func (rr *CSYNC) copy() RR {
func (rr *DHCID) copy() RR { func (rr *DHCID) copy() RR {
return &DHCID{rr.Hdr, rr.Digest} return &DHCID{rr.Hdr, rr.Digest}
} }
func (rr *DLV) copy() RR {
return &DLV{*rr.DS.copy().(*DS)}
}
func (rr *DNAME) copy() RR { func (rr *DNAME) copy() RR {
return &DNAME{rr.Hdr, rr.Target} return &DNAME{rr.Hdr, rr.Target}
} }
...@@ -727,6 +768,12 @@ func (rr *HIP) copy() RR { ...@@ -727,6 +768,12 @@ func (rr *HIP) copy() RR {
copy(RendezvousServers, rr.RendezvousServers) copy(RendezvousServers, rr.RendezvousServers)
return &HIP{rr.Hdr, rr.HitLength, rr.PublicKeyAlgorithm, rr.PublicKeyLength, rr.Hit, rr.PublicKey, RendezvousServers} return &HIP{rr.Hdr, rr.HitLength, rr.PublicKeyAlgorithm, rr.PublicKeyLength, rr.Hit, rr.PublicKey, RendezvousServers}
} }
func (rr *HTTPS) copy() RR {
return &HTTPS{*rr.SVCB.copy().(*SVCB)}
}
func (rr *KEY) copy() RR {
return &KEY{*rr.DNSKEY.copy().(*DNSKEY)}
}
func (rr *KX) copy() RR { func (rr *KX) copy() RR {
return &KX{rr.Hdr, rr.Preference, rr.Exchanger} return &KX{rr.Hdr, rr.Preference, rr.Exchanger}
} }
...@@ -830,6 +877,9 @@ func (rr *RRSIG) copy() RR { ...@@ -830,6 +877,9 @@ func (rr *RRSIG) copy() RR {
func (rr *RT) copy() RR { func (rr *RT) copy() RR {
return &RT{rr.Hdr, rr.Preference, rr.Host} return &RT{rr.Hdr, rr.Preference, rr.Host}
} }
func (rr *SIG) copy() RR {
return &SIG{*rr.RRSIG.copy().(*RRSIG)}
}
func (rr *SMIMEA) copy() RR { func (rr *SMIMEA) copy() RR {
return &SMIMEA{rr.Hdr, rr.Usage, rr.Selector, rr.MatchingType, rr.Certificate} return &SMIMEA{rr.Hdr, rr.Usage, rr.Selector, rr.MatchingType, rr.Certificate}
} }
...@@ -847,6 +897,13 @@ func (rr *SRV) copy() RR { ...@@ -847,6 +897,13 @@ func (rr *SRV) copy() RR {
func (rr *SSHFP) copy() RR { func (rr *SSHFP) copy() RR {
return &SSHFP{rr.Hdr, rr.Algorithm, rr.Type, rr.FingerPrint} return &SSHFP{rr.Hdr, rr.Algorithm, rr.Type, rr.FingerPrint}
} }
func (rr *SVCB) copy() RR {
Value := make([]SVCBKeyValue, len(rr.Value))
for i, e := range rr.Value {
Value[i] = e.copy()
}
return &SVCB{rr.Hdr, rr.Priority, rr.Target, Value}
}
func (rr *TA) copy() RR { func (rr *TA) copy() RR {
return &TA{rr.Hdr, rr.KeyTag, rr.Algorithm, rr.DigestType, rr.Digest} return &TA{rr.Hdr, rr.KeyTag, rr.Algorithm, rr.DigestType, rr.Digest}
} }
......
...@@ -14,7 +14,7 @@ github.com/coreos/pkg/capnslog ...@@ -14,7 +14,7 @@ github.com/coreos/pkg/capnslog
github.com/dgrijalva/jwt-go github.com/dgrijalva/jwt-go
# github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4 # github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4
github.com/dustin/go-humanize github.com/dustin/go-humanize
# github.com/elazarl/go-bindata-assetfs v1.0.1-0.20180223160309-38087fe4dafb # github.com/elazarl/go-bindata-assetfs v1.0.1
## explicit ## explicit
github.com/elazarl/go-bindata-assetfs github.com/elazarl/go-bindata-assetfs
# github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32 # github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32
...@@ -70,7 +70,7 @@ github.com/konsorten/go-windows-terminal-sequences ...@@ -70,7 +70,7 @@ github.com/konsorten/go-windows-terminal-sequences
github.com/lpar/gzipped github.com/lpar/gzipped
# github.com/matttproud/golang_protobuf_extensions v1.0.1 # github.com/matttproud/golang_protobuf_extensions v1.0.1
github.com/matttproud/golang_protobuf_extensions/pbutil github.com/matttproud/golang_protobuf_extensions/pbutil
# github.com/miekg/dns v1.1.8 # github.com/miekg/dns v1.1.35
## explicit ## explicit
github.com/miekg/dns github.com/miekg/dns
# github.com/prometheus/client_golang v1.9.0 # github.com/prometheus/client_golang v1.9.0
......