Merge branch 'master' of github.com:miekg/dns

This commit is contained in:
Miek Gieben 2013-04-18 11:24:11 +02:00
commit d3f6b37ffc
8 changed files with 163 additions and 19 deletions

View File

@ -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
View File

@ -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
View File

@ -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

View File

@ -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()
}
}
}

View File

@ -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
View File

@ -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

View File

@ -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) },
}

View File

@ -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