Merge branch 'master' of github.com:miekg/dns
This commit is contained in:
commit
7004ce03e8
|
@ -1,4 +1,4 @@
|
|||
CONTRIBUTORS
|
||||
# CONTRIBUTORS
|
||||
|
||||
* Miek Gieben - miek@miek.nl
|
||||
* Ask Bjørn Hansen
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Alternative (more granular) approach to a DNS library.
|
||||
# Alternative (more granular) approach to a DNS library
|
||||
|
||||
> Less is more.
|
||||
|
||||
|
|
|
@ -105,7 +105,7 @@ func (c *Client) Exchange(m *Msg, a string) (r *Msg, rtt time.Duration, err erro
|
|||
return r, rtt, err
|
||||
}
|
||||
if shared {
|
||||
return r.copy(), rtt, nil
|
||||
return r.Copy(), rtt, nil
|
||||
}
|
||||
return r, rtt, nil
|
||||
}
|
||||
|
|
|
@ -24,8 +24,8 @@ type ClientConfig struct {
|
|||
|
||||
// ClientConfigFromFile parses a resolv.conf(5) like file and returns
|
||||
// a *ClientConfig.
|
||||
func ClientConfigFromFile(conf string) (*ClientConfig, error) {
|
||||
file, err := os.Open(conf)
|
||||
func ClientConfigFromFile(resolvconf string) (*ClientConfig, error) {
|
||||
file, err := os.Open(resolvconf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -186,7 +186,7 @@ func Fqdn(s string) string {
|
|||
// Copied from the official Go code.
|
||||
|
||||
// ReverseAddr returns the in-addr.arpa. or ip6.arpa. hostname of the IP
|
||||
// address addr suitable for rDNS (PTR) record lookup or an error if it fails
|
||||
// address suitable for reverse DNS (PTR) record lookups or an error if it fails
|
||||
// to parse the IP address.
|
||||
func ReverseAddr(addr string) (arpa string, err error) {
|
||||
ip := net.ParseIP(addr)
|
||||
|
|
2
dns.go
2
dns.go
|
@ -91,7 +91,7 @@ import (
|
|||
|
||||
const (
|
||||
year68 = 1 << 31 // For RFC1982 (Serial Arithmetic) calculations in 32 bits.
|
||||
DefaultMsgSize = 4096 // Standard default for larger than 512 packets.
|
||||
DefaultMsgSize = 4096 // Standard default for larger than 512 bytes.
|
||||
MinMsgSize = 512 // Minimal size of a DNS packet.
|
||||
MaxMsgSize = 65536 // Largest possible DNS packet.
|
||||
defaultTtl = 3600 // Default TTL.
|
||||
|
|
|
@ -10,10 +10,12 @@ package dns
|
|||
// www.miek.nl. returns []string{"www", "miek", "nl"}
|
||||
// The root label (.) returns nil.
|
||||
func SplitDomainName(s string) (labels []string) {
|
||||
if len(s) == 0 {
|
||||
return nil
|
||||
}
|
||||
fqdnEnd := 0 // offset of the final '.' or the length of the name
|
||||
idx := Split(s)
|
||||
begin := 0
|
||||
|
||||
if s[len(s)-1] == '.' {
|
||||
fqdnEnd = len(s) - 1
|
||||
} else {
|
||||
|
|
31
msg.go
31
msg.go
|
@ -1290,6 +1290,12 @@ func (h *MsgHdr) String() string {
|
|||
// Pack packs a Msg: it is converted to to wire format.
|
||||
// If the dns.Compress is true the message will be in compressed wire format.
|
||||
func (dns *Msg) Pack() (msg []byte, err error) {
|
||||
return dns.PackBuffer(nil)
|
||||
}
|
||||
|
||||
// PackBuffer packs a Msg, using the given buffer buf. If buf is too small
|
||||
// a new buffer is allocated.
|
||||
func (dns *Msg) PackBuffer(buf []byte) (msg []byte, err error) {
|
||||
var dh Header
|
||||
var compression map[string]int
|
||||
if dns.Compress {
|
||||
|
@ -1335,7 +1341,11 @@ func (dns *Msg) Pack() (msg []byte, err error) {
|
|||
dh.Nscount = uint16(len(ns))
|
||||
dh.Arcount = uint16(len(extra))
|
||||
|
||||
msg = make([]byte, dns.packLen()+1)
|
||||
msg = buf
|
||||
if packLen := dns.packLen() + 1; len(msg) < packLen {
|
||||
msg = make([]byte, packLen)
|
||||
}
|
||||
|
||||
// Pack it in: header and then the pieces.
|
||||
off := 0
|
||||
off, err = packStructCompress(&dh, msg, off, compression, dns.Compress)
|
||||
|
@ -1545,18 +1555,27 @@ func (dns *Msg) Len() int {
|
|||
return l
|
||||
}
|
||||
|
||||
func (dns *Msg) copy() *Msg {
|
||||
// Copy returns a new *Msg which is a deep-copy of dns.
|
||||
func (dns *Msg) Copy() *Msg {
|
||||
r1 := new(Msg)
|
||||
r1.MsgHdr = dns.MsgHdr
|
||||
r1.Compress = dns.Compress
|
||||
|
||||
r1.Question = make([]Question, len(dns.Question))
|
||||
copy(r1.Question, dns.Question) // TODO(miek): Question is an immutable value, ok to do a shallow-copy
|
||||
|
||||
r1.Answer = make([]RR, len(dns.Answer))
|
||||
for i := 0; i < len(dns.Answer); i++ {
|
||||
r1.Answer[i] = dns.Answer[i].copy()
|
||||
}
|
||||
r1.Ns = make([]RR, len(dns.Ns))
|
||||
for i := 0; i < len(dns.Ns); i++ {
|
||||
r1.Ns[i] = dns.Ns[i].copy()
|
||||
}
|
||||
r1.Extra = make([]RR, len(dns.Extra))
|
||||
copy(r1.Question, dns.Question)
|
||||
copy(r1.Answer, dns.Answer)
|
||||
copy(r1.Ns, dns.Ns)
|
||||
copy(r1.Extra, dns.Extra)
|
||||
for i := 0; i < len(dns.Extra); i++ {
|
||||
r1.Extra[i] = dns.Extra[i].copy()
|
||||
}
|
||||
return r1
|
||||
}
|
||||
|
||||
|
|
|
@ -179,6 +179,7 @@ func TestQuotes(t *testing.T) {
|
|||
`t.example.com. IN TXT "a bc"`: "t.example.com.\t3600\tIN\tTXT\t\"a bc\"",
|
||||
`t.example.com. IN TXT "a
|
||||
bc"`: "t.example.com.\t3600\tIN\tTXT\t\"a\\n bc\"",
|
||||
`t.example.com. IN TXT ""`: "t.example.com.\t3600\tIN\tTXT\t\"\"",
|
||||
`t.example.com. IN TXT "a"`: "t.example.com.\t3600\tIN\tTXT\t\"a\"",
|
||||
`t.example.com. IN TXT "aa"`: "t.example.com.\t3600\tIN\tTXT\t\"aa\"",
|
||||
`t.example.com. IN TXT "aaa" ;`: "t.example.com.\t3600\tIN\tTXT\t\"aaa\"",
|
||||
|
@ -714,7 +715,7 @@ func TestTXT(t *testing.T) {
|
|||
if rr.String() != `_raop._tcp.local. 60 IN TXT "single value"` {
|
||||
t.Error("Bad representation of TXT record:", rr.String())
|
||||
}
|
||||
if rr.len() == 10 {
|
||||
if rr.len() != 28+1+12 {
|
||||
t.Error("Bad size of serialized record:", rr.len())
|
||||
}
|
||||
}
|
||||
|
@ -734,10 +735,30 @@ func TestTXT(t *testing.T) {
|
|||
if rr.String() != `_raop._tcp.local. 60 IN TXT "a=1" "b=2" "c=3" "d=4"` {
|
||||
t.Error("Bad representation of TXT multi value record:", rr.String())
|
||||
}
|
||||
if rr.len() != 44 {
|
||||
if rr.len() != 28+1+3+1+3+1+3+1+3 {
|
||||
t.Error("Bad size of serialized multi value record:", rr.len())
|
||||
}
|
||||
}
|
||||
|
||||
// Test empty-string in TXT record
|
||||
rr, err = NewRR(`_raop._tcp.local. 60 IN TXT ""`)
|
||||
if err != nil {
|
||||
t.Error("Failed to parse empty-string TXT record", err)
|
||||
} else if rr, ok := rr.(*TXT); !ok {
|
||||
t.Error("Wrong type, record should be of type TXT")
|
||||
} else {
|
||||
if len(rr.Txt) != 1 {
|
||||
t.Error("Bad size of TXT empty-string value:", len(rr.Txt))
|
||||
} else if rr.Txt[0] != "" {
|
||||
t.Error("Bad value for empty-string TXT record")
|
||||
}
|
||||
if rr.String() != `_raop._tcp.local. 60 IN TXT ""` {
|
||||
t.Error("Bad representation of empty-string TXT record:", rr.String())
|
||||
}
|
||||
if rr.len() != 28+1 {
|
||||
t.Error("Bad size of serialized record:", rr.len())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTypeXXXX(t *testing.T) {
|
||||
|
@ -792,3 +813,29 @@ func TestDigit(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseRRSIGTimestamp(t *testing.T) {
|
||||
tests := map[string]bool{
|
||||
`miek.nl. IN RRSIG SOA 8 2 43200 20140210031301 20140111031301 12051 miek.nl. MVZUyrYwq0iZhMFDDnVXD2BvuNiUJjSYlJAgzyAE6CF875BMvvZa+Sb0 RlSCL7WODQSQHhCx/fegHhVVF+Iz8N8kOLrmXD1+jO3Bm6Prl5UhcsPx WTBsg/kmxbp8sR1kvH4oZJtVfakG3iDerrxNaf0sQwhZzyfJQAqpC7pcBoc=`: true,
|
||||
`miek.nl. IN RRSIG SOA 8 2 43200 315565800 4102477800 12051 miek.nl. MVZUyrYwq0iZhMFDDnVXD2BvuNiUJjSYlJAgzyAE6CF875BMvvZa+Sb0 RlSCL7WODQSQHhCx/fegHhVVF+Iz8N8kOLrmXD1+jO3Bm6Prl5UhcsPx WTBsg/kmxbp8sR1kvH4oZJtVfakG3iDerrxNaf0sQwhZzyfJQAqpC7pcBoc=`: true,
|
||||
}
|
||||
for r, _ := range tests {
|
||||
_, e := NewRR(r)
|
||||
if e != nil {
|
||||
t.Fail()
|
||||
t.Logf("%s\n", e.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTxtEqual(t *testing.T) {
|
||||
rr1 := new(TXT)
|
||||
rr1.Hdr = RR_Header{Name: ".", Rrtype: TypeTXT, Class: ClassINET, Ttl: 0}
|
||||
rr1.Txt = []string{"a\"a", "\"", "b"}
|
||||
rr2, _ := NewRR(rr1.String())
|
||||
if rr1.String() != rr2.String() {
|
||||
// t.Fail() // This is not an error, but keep this test.
|
||||
t.Logf("These two TXT records should match")
|
||||
t.Logf("\n%s\n%s\n", rr1.String(), rr2.String())
|
||||
}
|
||||
}
|
||||
|
|
19
tsig.go
19
tsig.go
|
@ -29,7 +29,7 @@
|
|||
// t.TsigSecret = map[string]string{"axfr.": "so6ZGir4GPAqINNh9U5c3A=="}
|
||||
// m.SetAxfr("miek.nl.")
|
||||
// m.SetTsig("axfr.", dns.HmacMD5, 300, time.Now().Unix())
|
||||
// c, err := tr.In(m, "176.58.119.54:53")
|
||||
// c, err := t.In(m, "176.58.119.54:53")
|
||||
// for r := range c { /* r.RR */ }
|
||||
//
|
||||
// You can now read the records from the transfer as they come in. Each envelope is checked with TSIG.
|
||||
|
@ -217,12 +217,17 @@ func TsigVerify(msg []byte, secret, requestMAC string, timersOnly bool) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Srtip the TSIG from the incoming msg
|
||||
// Strip the TSIG from the incoming msg
|
||||
stripped, tsig, err := stripTsig(msg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
msgMAC, err := hex.DecodeString(tsig.MAC)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
buf := tsigBuffer(stripped, tsig, requestMAC, timersOnly)
|
||||
ti := uint64(time.Now().Unix()) - tsig.TimeSigned
|
||||
if uint64(tsig.Fudge) < ti {
|
||||
|
@ -232,16 +237,16 @@ func TsigVerify(msg []byte, secret, requestMAC string, timersOnly bool) error {
|
|||
var h hash.Hash
|
||||
switch tsig.Algorithm {
|
||||
case HmacMD5:
|
||||
h = hmac.New(md5.New, []byte(rawsecret))
|
||||
h = hmac.New(md5.New, rawsecret)
|
||||
case HmacSHA1:
|
||||
h = hmac.New(sha1.New, []byte(rawsecret))
|
||||
h = hmac.New(sha1.New, rawsecret)
|
||||
case HmacSHA256:
|
||||
h = hmac.New(sha256.New, []byte(rawsecret))
|
||||
h = hmac.New(sha256.New, rawsecret)
|
||||
default:
|
||||
return ErrKeyAlg
|
||||
}
|
||||
io.WriteString(h, string(buf))
|
||||
if strings.ToUpper(hex.EncodeToString(h.Sum(nil))) != strings.ToUpper(tsig.MAC) {
|
||||
h.Write(buf)
|
||||
if !hmac.Equal(h.Sum(nil), msgMAC) {
|
||||
return ErrSig
|
||||
}
|
||||
return nil
|
||||
|
|
23
types.go
23
types.go
|
@ -586,7 +586,7 @@ type A struct {
|
|||
}
|
||||
|
||||
func (rr *A) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *A) copy() RR { return &A{*rr.Hdr.copyHeader(), rr.A} }
|
||||
func (rr *A) copy() RR { return &A{*rr.Hdr.copyHeader(), copyIP(rr.A)} }
|
||||
func (rr *A) len() int { return rr.Hdr.len() + net.IPv4len }
|
||||
|
||||
func (rr *A) String() string {
|
||||
|
@ -602,7 +602,7 @@ type AAAA struct {
|
|||
}
|
||||
|
||||
func (rr *AAAA) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *AAAA) copy() RR { return &AAAA{*rr.Hdr.copyHeader(), rr.AAAA} }
|
||||
func (rr *AAAA) copy() RR { return &AAAA{*rr.Hdr.copyHeader(), copyIP(rr.AAAA)} }
|
||||
func (rr *AAAA) len() int { return rr.Hdr.len() + net.IPv6len }
|
||||
|
||||
func (rr *AAAA) String() string {
|
||||
|
@ -1264,7 +1264,7 @@ func (rr *WKS) len() int { return rr.Hdr.len() + net.IPv4len + 1 }
|
|||
func (rr *WKS) copy() RR {
|
||||
cp := make([]uint16, len(rr.BitMap), cap(rr.BitMap))
|
||||
copy(cp, rr.BitMap)
|
||||
return &WKS{*rr.Hdr.copyHeader(), rr.Address, rr.Protocol, cp}
|
||||
return &WKS{*rr.Hdr.copyHeader(), copyIP(rr.Address), rr.Protocol, cp}
|
||||
}
|
||||
|
||||
func (rr *WKS) String() (s string) {
|
||||
|
@ -1303,7 +1303,7 @@ type L32 struct {
|
|||
}
|
||||
|
||||
func (rr *L32) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *L32) copy() RR { return &L32{*rr.Hdr.copyHeader(), rr.Preference, rr.Locator32} }
|
||||
func (rr *L32) copy() RR { return &L32{*rr.Hdr.copyHeader(), rr.Preference, copyIP(rr.Locator32)} }
|
||||
func (rr *L32) len() int { return rr.Hdr.len() + net.IPv4len }
|
||||
|
||||
func (rr *L32) String() string {
|
||||
|
@ -1502,12 +1502,19 @@ func euiToString(eui uint64, bits int) (hex string) {
|
|||
return
|
||||
}
|
||||
|
||||
// copyIP returns a copy of ip.
|
||||
func copyIP(ip net.IP) net.IP {
|
||||
p := make(net.IP, len(ip))
|
||||
copy(p, ip)
|
||||
return p
|
||||
}
|
||||
|
||||
// Map of constructors for each RR wire type.
|
||||
var rr_mk = map[uint16]func() RR{
|
||||
TypeA: func() RR { return new(A) },
|
||||
TypeAAAA: func() RR { return new(AAAA) },
|
||||
TypeAFSDB: func() RR { return new(AFSDB) },
|
||||
// TypeCAA: func() RR { return new(CAA) },
|
||||
TypeA: func() RR { return new(A) },
|
||||
TypeAAAA: func() RR { return new(AAAA) },
|
||||
TypeAFSDB: func() RR { return new(AFSDB) },
|
||||
// TypeCAA: func() RR { return new(CAA) },
|
||||
TypeCDS: func() RR { return new(CDS) },
|
||||
TypeCERT: func() RR { return new(CERT) },
|
||||
TypeCNAME: func() RR { return new(CNAME) },
|
||||
|
|
20
zscan_rr.go
20
zscan_rr.go
|
@ -223,9 +223,11 @@ func endingToTxtSlice(c chan lex, errstr, f string) ([]string, *ParseError, stri
|
|||
switch l.value == _QUOTE {
|
||||
case true: // A number of quoted string
|
||||
s = make([]string, 0)
|
||||
empty := true
|
||||
for l.value != _NEWLINE && l.value != _EOF {
|
||||
switch l.value {
|
||||
case _STRING:
|
||||
empty = false
|
||||
s = append(s, l.token)
|
||||
case _BLANK:
|
||||
if quote {
|
||||
|
@ -233,7 +235,11 @@ func endingToTxtSlice(c chan lex, errstr, f string) ([]string, *ParseError, stri
|
|||
return nil, &ParseError{f, errstr, l}, ""
|
||||
}
|
||||
case _QUOTE:
|
||||
if empty && quote {
|
||||
s = append(s, "")
|
||||
}
|
||||
quote = !quote
|
||||
empty = true
|
||||
default:
|
||||
return nil, &ParseError{f, errstr, l}, ""
|
||||
}
|
||||
|
@ -1162,14 +1168,24 @@ func setRRSIG(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
|
|||
<-c // _BLANK
|
||||
l = <-c
|
||||
if i, err := StringToTime(l.token); err != nil {
|
||||
return nil, &ParseError{f, "bad RRSIG Expiration", l}, ""
|
||||
// Try to see if all numeric and use it as epoch
|
||||
if i, err := strconv.ParseInt(l.token, 10, 64); err == nil {
|
||||
// TODO(miek): error out on > MAX_UINT32, same below
|
||||
rr.Expiration = uint32(i)
|
||||
} else {
|
||||
return nil, &ParseError{f, "bad RRSIG Expiration", l}, ""
|
||||
}
|
||||
} else {
|
||||
rr.Expiration = i
|
||||
}
|
||||
<-c // _BLANK
|
||||
l = <-c
|
||||
if i, err := StringToTime(l.token); err != nil {
|
||||
return nil, &ParseError{f, "bad RRSIG Inception", l}, ""
|
||||
if i, err := strconv.ParseInt(l.token, 10, 64); err == nil {
|
||||
rr.Inception = uint32(i)
|
||||
} else {
|
||||
return nil, &ParseError{f, "bad RRSIG Inception", l}, ""
|
||||
}
|
||||
} else {
|
||||
rr.Inception = i
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue