Merge branch 'master' of github.com:miekg/dns
This commit is contained in:
commit
d3f6b37ffc
|
@ -6,6 +6,8 @@
|
|||
* Test all rdata packing with zero rdata -- allowed for dynamic updates
|
||||
* Ratelimiting?
|
||||
* NSEC3/NSEC support function for generating NXDOMAIN respsonse?
|
||||
* Actually mimic net/ ? Dial. Read/Write ?
|
||||
* Make compare/split labels faster
|
||||
|
||||
## Nice to have
|
||||
|
||||
|
|
2
dns.go
2
dns.go
|
@ -63,7 +63,7 @@
|
|||
//
|
||||
// For asynchronous queries it is easy to wrap Exchange() in a goroutine.
|
||||
//
|
||||
// From a birds eye view a dns message consists out of four sections.
|
||||
// A dns message consists out of four sections.
|
||||
// The question section: in.Question, the answer section: in.Answer,
|
||||
// the authority section: in.Ns and the additional section: in.Extra.
|
||||
//
|
||||
|
|
2
msg.go
2
msg.go
|
@ -129,6 +129,8 @@ var TypeToString = map[uint16]string{
|
|||
TypeL32: "L32",
|
||||
TypeL64: "L64",
|
||||
TypeLP: "LP",
|
||||
TypeEUI48: "EUI48",
|
||||
TypeEUI64: "EUI64",
|
||||
TypeTKEY: "TKEY", // Meta RR
|
||||
TypeTSIG: "TSIG", // Meta RR
|
||||
TypeAXFR: "AXFR", // Meta RR
|
||||
|
|
|
@ -738,3 +738,21 @@ foo. IN TXT "THIS IS TEXT MAN"; this is comment 8
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestEUIxx(t *testing.T) {
|
||||
tests := map[string]string{
|
||||
"host.example. IN EUI48 00-00-5e-90-01-2a": "host.example.\t3600\tIN\tEUI48\t00-00-5e-90-01-2a",
|
||||
"host.example. IN EUI64 00-00-5e-ef-00-00-00-2a": "host.example.\t3600\tIN\tEUI64\t00-00-5e-ef-00-00-00-2a",
|
||||
}
|
||||
for i, o := range tests {
|
||||
r, e := NewRR(i)
|
||||
if e != nil {
|
||||
t.Logf("Failed to parse %s: %s\n", i, e.Error())
|
||||
t.Fail()
|
||||
}
|
||||
if r.String() != o {
|
||||
t.Logf("Want %s, got %s\n", o, r.String())
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ func rawSetId(msg []byte, i uint16) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
// rawSetQuestionLen sets the lenght of the question section.
|
||||
// rawSetQuestionLen sets the length of the question section.
|
||||
func rawSetQuestionLen(msg []byte, i uint16) bool {
|
||||
if len(msg) < 6 {
|
||||
return false
|
||||
|
|
32
tlsa.go
32
tlsa.go
|
@ -5,65 +5,73 @@ import (
|
|||
"crypto/sha512"
|
||||
"crypto/x509"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"io"
|
||||
"net"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// CertificateToDANE converts a certificate to a hex string as used in the TLSA record.
|
||||
func CertificateToDANE(selector, matchingType uint8, cert *x509.Certificate) string {
|
||||
func CertificateToDANE(selector, matchingType uint8, cert *x509.Certificate) (string, error) {
|
||||
switch matchingType {
|
||||
case 0:
|
||||
switch selector {
|
||||
case 0:
|
||||
return hex.EncodeToString(cert.Raw)
|
||||
return hex.EncodeToString(cert.Raw), nil
|
||||
case 1:
|
||||
return hex.EncodeToString(cert.RawSubjectPublicKeyInfo)
|
||||
return hex.EncodeToString(cert.RawSubjectPublicKeyInfo), nil
|
||||
}
|
||||
case 1:
|
||||
h := sha256.New()
|
||||
switch selector {
|
||||
case 0:
|
||||
return hex.EncodeToString(cert.Raw)
|
||||
return hex.EncodeToString(cert.Raw), nil
|
||||
case 1:
|
||||
io.WriteString(h, string(cert.RawSubjectPublicKeyInfo))
|
||||
return hex.EncodeToString(h.Sum(nil))
|
||||
return hex.EncodeToString(h.Sum(nil)), nil
|
||||
}
|
||||
case 2:
|
||||
h := sha512.New()
|
||||
switch selector {
|
||||
case 0:
|
||||
return hex.EncodeToString(cert.Raw)
|
||||
return hex.EncodeToString(cert.Raw), nil
|
||||
case 1:
|
||||
io.WriteString(h, string(cert.RawSubjectPublicKeyInfo))
|
||||
return hex.EncodeToString(h.Sum(nil))
|
||||
return hex.EncodeToString(h.Sum(nil)), nil
|
||||
}
|
||||
}
|
||||
return ""
|
||||
return "", errors.New("dns: bad TLSA MatchingType or TLSA Selector")
|
||||
}
|
||||
|
||||
// Sign creates a TLSA record from an SSL certificate.
|
||||
func (r *TLSA) Sign(usage, selector, matchingType int, cert *x509.Certificate) error {
|
||||
func (r *TLSA) Sign(usage, selector, matchingType int, cert *x509.Certificate) (err error) {
|
||||
r.Hdr.Rrtype = TypeTLSA
|
||||
r.Usage = uint8(usage)
|
||||
r.Selector = uint8(selector)
|
||||
r.MatchingType = uint8(matchingType)
|
||||
|
||||
r.Certificate = CertificateToDANE(r.Selector, r.MatchingType, cert)
|
||||
r.Certificate, err = CertificateToDANE(r.Selector, r.MatchingType, cert)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Verify verifies a TLSA record against an SSL certificate. If it is OK
|
||||
// a nil error is returned.
|
||||
func (r *TLSA) Verify(cert *x509.Certificate) error {
|
||||
if r.Certificate == CertificateToDANE(r.Selector, r.MatchingType, cert) {
|
||||
c, err := CertificateToDANE(r.Selector, r.MatchingType, cert)
|
||||
if err != nil {
|
||||
return err // Not also ErrSig?
|
||||
}
|
||||
if r.Certificate == c {
|
||||
return nil
|
||||
}
|
||||
return ErrSig // ErrSig, really?
|
||||
}
|
||||
|
||||
// TLSAName returns the ownername of a TLSA resource record as per the
|
||||
// rules specified in RFC 6698, Section 3.
|
||||
// rules specified in RFC 6698, Section 3.
|
||||
func TLSAName(name, service, network string) (string, error) {
|
||||
if !IsFqdn(name) {
|
||||
return "", ErrFqdn
|
||||
|
|
60
types.go
60
types.go
|
@ -72,6 +72,8 @@ const (
|
|||
TypeL32 uint16 = 105
|
||||
TypeL64 uint16 = 106
|
||||
TypeLP uint16 = 107
|
||||
TypeEUI48 uint16 = 108
|
||||
TypeEUI64 uint16 = 109
|
||||
|
||||
TypeTKEY uint16 = 249
|
||||
TypeTSIG uint16 = 250
|
||||
|
@ -1049,7 +1051,7 @@ func (rr *NSEC3) String() string {
|
|||
s += strconv.Itoa(int(rr.Hash)) +
|
||||
" " + strconv.Itoa(int(rr.Flags)) +
|
||||
" " + strconv.Itoa(int(rr.Iterations)) +
|
||||
" " + saltString(rr.Salt) +
|
||||
" " + saltToString(rr.Salt) +
|
||||
" " + rr.NextDomain
|
||||
for i := 0; i < len(rr.TypeBitMap); i++ {
|
||||
if _, ok := TypeToString[rr.TypeBitMap[i]]; ok {
|
||||
|
@ -1085,7 +1087,7 @@ func (rr *NSEC3PARAM) String() string {
|
|||
s += strconv.Itoa(int(rr.Hash)) +
|
||||
" " + strconv.Itoa(int(rr.Flags)) +
|
||||
" " + strconv.Itoa(int(rr.Iterations)) +
|
||||
" " + saltString(rr.Salt)
|
||||
" " + saltToString(rr.Salt)
|
||||
return s
|
||||
}
|
||||
|
||||
|
@ -1373,6 +1375,38 @@ func (rr *LP) len() int {
|
|||
return rr.Hdr.len() + 2 + len(rr.Fqdn) + 1
|
||||
}
|
||||
|
||||
type EUI48 struct {
|
||||
Hdr RR_Header
|
||||
Address uint64 `dns:"uint48"`
|
||||
}
|
||||
|
||||
func (rr *EUI48) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *EUI48) copy() RR { return &EUI48{*rr.Hdr.copyHeader(), rr.Address} }
|
||||
|
||||
func (rr *EUI48) String() string {
|
||||
return rr.Hdr.String() + euiToString(rr.Address, 48)
|
||||
}
|
||||
|
||||
func (rr *EUI48) len() int {
|
||||
return rr.Hdr.len() + 6
|
||||
}
|
||||
|
||||
type EUI64 struct {
|
||||
Hdr RR_Header
|
||||
Address uint64
|
||||
}
|
||||
|
||||
func (rr *EUI64) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *EUI64) copy() RR { return &EUI64{*rr.Hdr.copyHeader(), rr.Address} }
|
||||
|
||||
func (rr *EUI64) String() string {
|
||||
return rr.Hdr.String() + euiToString(rr.Address, 64)
|
||||
}
|
||||
|
||||
func (rr *EUI64) len() int {
|
||||
return rr.Hdr.len() + 8
|
||||
}
|
||||
|
||||
// TimeToString translates the RRSIG's incep. and expir. times to the
|
||||
// string representation used when printing the record.
|
||||
// It takes serial arithmetic (RFC 1982) into account.
|
||||
|
@ -1385,7 +1419,7 @@ func TimeToString(t uint32) string {
|
|||
return ti.Format("20060102150405")
|
||||
}
|
||||
|
||||
// StringToTime translates the RRSIG's incep. and expir. times from
|
||||
// StringToTime translates the RRSIG's incep. and expir. times from
|
||||
// string values like "20110403154150" to an 32 bit integer.
|
||||
// It takes serial arithmetic (RFC 1982) into account.
|
||||
func StringToTime(s string) (uint32, error) {
|
||||
|
@ -1400,9 +1434,9 @@ func StringToTime(s string) (uint32, error) {
|
|||
return uint32(t.Unix() - (mod * year68)), nil
|
||||
}
|
||||
|
||||
// saltString converts a NSECX salt to uppercase and
|
||||
// saltToString converts a NSECX salt to uppercase and
|
||||
// returns "-" when it is empty
|
||||
func saltString(s string) string {
|
||||
func saltToString(s string) string {
|
||||
if len(s) == 0 {
|
||||
return "-"
|
||||
}
|
||||
|
@ -1426,6 +1460,20 @@ func cmToString(mantissa, exponent uint8) string {
|
|||
panic("dns: not reached")
|
||||
}
|
||||
|
||||
func euiToString(eui uint64, bits int) (hex string) {
|
||||
switch bits {
|
||||
case 64:
|
||||
hex = fmt.Sprintf("%16.16x", eui)
|
||||
hex = hex[0:2] + "-" + hex[2:4] + "-" + hex[4:6] + "-" + hex[6:8] +
|
||||
"-" + hex[8:10] + "-" + hex[10:12] + "-" + hex[12:14] + "-" + hex[14:16]
|
||||
case 48:
|
||||
hex = fmt.Sprintf("%12.12x", eui)
|
||||
hex = hex[0:2] + "-" + hex[2:4] + "-" + hex[4:6] + "-" + hex[6:8] +
|
||||
"-" + hex[8:10] + "-" + hex[10:12]
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Map of constructors for each RR wire type.
|
||||
var rr_mk = map[uint16]func() RR{
|
||||
TypeCNAME: func() RR { return new(CNAME) },
|
||||
|
@ -1479,4 +1527,6 @@ var rr_mk = map[uint16]func() RR{
|
|||
TypeL32: func() RR { return new(L32) },
|
||||
TypeL64: func() RR { return new(L64) },
|
||||
TypeLP: func() RR { return new(LP) },
|
||||
TypeEUI48: func() RR { return new(EUI48) },
|
||||
TypeEUI64: func() RR { return new(EUI64) },
|
||||
}
|
||||
|
|
64
zscan_rr.go
64
zscan_rr.go
|
@ -100,6 +100,12 @@ func setRR(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
|
|||
case TypeNSEC3PARAM:
|
||||
r, e = setNSEC3PARAM(h, c, f)
|
||||
goto Slurp
|
||||
case TypeEUI48:
|
||||
r, e = setEUI48(h, c, f)
|
||||
goto Slurp
|
||||
case TypeEUI64:
|
||||
r, e = setEUI64(h, c, f)
|
||||
goto Slurp
|
||||
// These types have a variable ending: either chunks of txt or chunks/base64 or hex.
|
||||
// They need to search for the end of the RR themselves, hence they look for the ending
|
||||
// newline. Thus there is no need to slurp the remainder, because there is none.
|
||||
|
@ -1271,6 +1277,64 @@ func setNSEC3PARAM(h RR_Header, c chan lex, f string) (RR, *ParseError) {
|
|||
return rr, nil
|
||||
}
|
||||
|
||||
func setEUI48(h RR_Header, c chan lex, f string) (RR, *ParseError) {
|
||||
rr := new(EUI48)
|
||||
rr.Hdr = h
|
||||
|
||||
l := <-c
|
||||
if len(l.token) != 17 {
|
||||
return nil, &ParseError{f, "bad EUI48 Address", l}
|
||||
}
|
||||
addr := make([]byte, 12)
|
||||
dash := 0
|
||||
for i := 0; i < 10; i += 2 {
|
||||
addr[i] = l.token[i+dash]
|
||||
addr[i+1] = l.token[i+1+dash]
|
||||
dash++
|
||||
if l.token[i+1+dash] != '-' {
|
||||
return nil, &ParseError{f, "bad EUI48 Address", l}
|
||||
}
|
||||
}
|
||||
addr[10] = l.token[15]
|
||||
addr[11] = l.token[16]
|
||||
|
||||
if i, e := strconv.ParseUint(string(addr), 16, 48); e != nil {
|
||||
return nil, &ParseError{f, "bad EUI48 Address", l}
|
||||
} else {
|
||||
rr.Address = i
|
||||
}
|
||||
return rr, nil
|
||||
}
|
||||
|
||||
func setEUI64(h RR_Header, c chan lex, f string) (RR, *ParseError) {
|
||||
rr := new(EUI64)
|
||||
rr.Hdr = h
|
||||
|
||||
l := <-c
|
||||
if len(l.token) != 23 {
|
||||
return nil, &ParseError{f, "bad EUI64 Address", l}
|
||||
}
|
||||
addr := make([]byte, 16)
|
||||
dash := 0
|
||||
for i := 0; i < 14; i += 2 {
|
||||
addr[i] = l.token[i+dash]
|
||||
addr[i+1] = l.token[i+1+dash]
|
||||
dash++
|
||||
if l.token[i+1+dash] != '-' {
|
||||
return nil, &ParseError{f, "bad EUI64 Address", l}
|
||||
}
|
||||
}
|
||||
addr[14] = l.token[21]
|
||||
addr[15] = l.token[22]
|
||||
|
||||
if i, e := strconv.ParseUint(string(addr), 16, 64); e != nil {
|
||||
return nil, &ParseError{f, "bad EUI68 Address", l}
|
||||
} else {
|
||||
rr.Address = uint64(i)
|
||||
}
|
||||
return rr, nil
|
||||
}
|
||||
|
||||
func setWKS(h RR_Header, c chan lex, f string) (RR, *ParseError, string) {
|
||||
rr := new(WKS)
|
||||
rr.Hdr = h
|
||||
|
|
Loading…
Reference in New Issue