Merge branch 'master' of github.com:miekg/dns
This commit is contained in:
commit
6d46e39bc7
2
LICENSE
2
LICENSE
|
@ -1,4 +1,4 @@
|
|||
Extensions of the original work are copyright (c) 2010 - 2012 Miek Gieben
|
||||
Extensions of the original work are copyright (c) 2011 Miek Gieben
|
||||
|
||||
As this is fork of the official Go code the same license applies:
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ A not-so-up-to-date-list-that-may-be-actually-current:
|
|||
* RFC 1035 zone file parsing ($INCLUDE, $ORIGIN, $TTL and $GENERATE [for all record types]
|
||||
are supported);
|
||||
* Fast:
|
||||
* Reply speed around ~ 50K qps (faster hardware results in more qps);
|
||||
* Reply speed around ~ 80K qps (faster hardware results in more qps);
|
||||
* Parsing RRs with ~ 100K RR/s, that's 5M records in about 50 seconds;
|
||||
* Server side programming (mimicking the net/http package);
|
||||
* Client side programming;
|
||||
|
@ -103,6 +103,7 @@ with: `go build`.
|
|||
* xxxx - URI record (draft)
|
||||
* xxxx - EDNS0 DNS Update Lease (draft)
|
||||
* xxxx - IEU48/IEU64 records (draft)
|
||||
* xxxx - Algorithm-Signal (draft)
|
||||
|
||||
## Loosely based upon
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# TODO
|
||||
|
||||
* Support for on-the-fly-signing
|
||||
* Support for on-the-fly-signing or check how to do it
|
||||
* Use BIND10 memory efficient zone structure?
|
||||
* NSEC3 support propper in the zone structure(s)
|
||||
* Test all rdata packing with zero rdata -- allowed for dynamic updates
|
||||
|
@ -12,11 +12,11 @@
|
|||
|
||||
## Nice to have
|
||||
|
||||
* Speed, we can always go faster. A simple reflect server now hits 45/50K qps
|
||||
* Speed, we can always go faster. A simple reflect server now hits 75/80K qps
|
||||
* go test; only works correct on my machine
|
||||
* privatekey.Precompute() when signing?
|
||||
|
||||
## RR not implemented
|
||||
## RRs not implemented
|
||||
|
||||
These are deprecated, or rarely used (or just a bitch to implement).
|
||||
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2011 Miek Gieben. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package dns
|
||||
|
||||
// A client implementation.
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2011 Miek Gieben. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package dns
|
||||
|
||||
import (
|
||||
|
@ -98,8 +102,8 @@ func TestUpdateLeaseTSIG(t *testing.T) {
|
|||
lease_rr := new(OPT)
|
||||
lease_rr.Hdr.Name = "."
|
||||
lease_rr.Hdr.Rrtype = TypeOPT
|
||||
e := new(EDNS0_UPDATE_LEASE)
|
||||
e.Code = EDNS0UPDATELEASE
|
||||
e := new(EDNS0_UL)
|
||||
e.Code = EDNS0UL
|
||||
e.Lease = 120
|
||||
lease_rr.Option = append(lease_rr.Option, e)
|
||||
m.Extra = append(m.Extra, lease_rr)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// Extensions of the original work are copyright (c) 2011 Miek Gieben
|
||||
|
||||
package dns
|
||||
|
||||
|
@ -25,10 +26,10 @@ type ClientConfig struct {
|
|||
// a *ClientConfig.
|
||||
func ClientConfigFromFile(conf string) (*ClientConfig, error) {
|
||||
file, err := os.Open(conf)
|
||||
defer file.Close()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer file.Close()
|
||||
c := new(ClientConfig)
|
||||
b := bufio.NewReader(file)
|
||||
c.Servers = make([]string, 0)
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2011 Miek Gieben. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package dns
|
||||
|
||||
import (
|
||||
|
|
2
dns.go
2
dns.go
|
@ -1,7 +1,7 @@
|
|||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// Extended and bugfixes by Miek Gieben. Copyright 2010-2012.
|
||||
// Extensions of the original work are copyright (c) 2011 Miek Gieben
|
||||
|
||||
// Package dns implements a full featured interface to the Domain Name System.
|
||||
// Server- and client-side programming is supported.
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2011 Miek Gieben. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package dns
|
||||
|
||||
import (
|
||||
|
|
16
dnssec.go
16
dnssec.go
|
@ -1,4 +1,6 @@
|
|||
// Copyright 2012 Miek Gieben. All rights reserved.
|
||||
// Copyright 2011 Miek Gieben. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// DNSSEC
|
||||
//
|
||||
|
@ -720,3 +722,15 @@ var AlgorithmToString = map[uint8]string{
|
|||
|
||||
// Map of algorithm strings.
|
||||
var StringToAlgorithm = reverseInt8(AlgorithmToString)
|
||||
|
||||
// Map for hash names.
|
||||
var HashToString = map[uint8]string{
|
||||
SHA1: "SHA1",
|
||||
SHA256: "SHA256",
|
||||
GOST94: "GOST94",
|
||||
SHA384: "SHA384",
|
||||
SHA512: "SHA512",
|
||||
}
|
||||
|
||||
// Map of hash strings.
|
||||
var StringToHash = reverseInt8(HashToString)
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2011 Miek Gieben. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package dns
|
||||
|
||||
import (
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2011 Miek Gieben. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package dns
|
||||
|
||||
// Find better solution
|
||||
|
|
202
edns.go
202
edns.go
|
@ -1,7 +1,12 @@
|
|||
// Copyright 2011 Miek Gieben. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// EDNS0
|
||||
//
|
||||
// EDNS0 is an extension mechanism for the DNS defined in RFC 2671. It defines a
|
||||
// standard RR type, the OPT RR, which is then completely abused.
|
||||
// EDNS0 is an extension mechanism for the DNS defined in RFC 2671 and updated
|
||||
// by RFC 6891. It defines a standard RR type, the OPT RR, which is then completely
|
||||
// abused.
|
||||
// Basic use pattern for creating an (empty) OPT RR:
|
||||
//
|
||||
// o := new(dns.OPT)
|
||||
|
@ -33,11 +38,13 @@ import (
|
|||
|
||||
// EDNS0 Option codes.
|
||||
const (
|
||||
EDNS0LLQ = 0x1 // not used
|
||||
EDNS0UL = 0x2 // not used
|
||||
EDNS0UPDATELEASE = 0x2 // update lease draft
|
||||
EDNS0LLQ = 0x1 // long lived queries: http://tools.ietf.org/html/draft-sekar-dns-llq-01
|
||||
EDNS0UL = 0x2 // update lease draft: http://files.dns-sd.org/draft-sekar-dns-ul.txt
|
||||
EDNS0NSID = 0x3 // nsid (RFC5001)
|
||||
EDNS0SUBNET = 0x50fa // client-subnet draft
|
||||
EDNS0SUBNET = 0x50fa // client-subnet draft: http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-01
|
||||
EDNS0DAU = 0x5 // DNSSEC Algorithm Understood - not the final number!
|
||||
EDNS0DHU = 0x6 // DS Hash Understood - not the final number!
|
||||
EDNS0N3U = 0x7 // NSEC3 Hash Understood - not the final number!
|
||||
_DO = 1 << 7 // dnssec ok
|
||||
)
|
||||
|
||||
|
@ -73,8 +80,16 @@ func (rr *OPT) String() string {
|
|||
}
|
||||
case *EDNS0_SUBNET:
|
||||
s += "\n; SUBNET: " + o.String()
|
||||
case *EDNS0_UPDATE_LEASE:
|
||||
s += "\n; LEASE: " + o.String()
|
||||
case *EDNS0_UL:
|
||||
s += "\n; UPDATE LEASE: " + o.String()
|
||||
case *EDNS0_LLQ:
|
||||
s += "\n; LONG LIVED QUERIES: " + o.String()
|
||||
case *EDNS0_DAU:
|
||||
s += "\n; DNSSEC ALGORITHM UNDERSTOOD: " + o.String()
|
||||
case *EDNS0_DHU:
|
||||
s += "\n; DS HASH UNDERSTOOD: " + o.String()
|
||||
case *EDNS0_N3U:
|
||||
s += "\n; NSEC3 HASH UNDERSTOOD: " + o.String()
|
||||
}
|
||||
}
|
||||
return s
|
||||
|
@ -227,6 +242,11 @@ func (e *EDNS0_SUBNET) pack() ([]byte, error) {
|
|||
}
|
||||
ip[i] = a[i]
|
||||
}
|
||||
needLength := e.SourceNetmask / 8
|
||||
if e.SourceNetmask%8 > 0 {
|
||||
needLength++
|
||||
}
|
||||
ip = ip[:needLength]
|
||||
b = append(b, ip...)
|
||||
case 2:
|
||||
if e.SourceNetmask > net.IPv6len*8 {
|
||||
|
@ -240,7 +260,11 @@ func (e *EDNS0_SUBNET) pack() ([]byte, error) {
|
|||
}
|
||||
ip[i] = a[i]
|
||||
}
|
||||
// chop off ip a SourceNetmask/8: ip = ip[:e.SourceNetmask/8] ?
|
||||
needLength := e.SourceNetmask / 8
|
||||
if e.SourceNetmask%8 > 0 {
|
||||
needLength++
|
||||
}
|
||||
ip = ip[:needLength]
|
||||
b = append(b, ip...)
|
||||
default:
|
||||
return nil, errors.New("dns: bad address family")
|
||||
|
@ -293,7 +317,7 @@ func (e *EDNS0_SUBNET) String() (s string) {
|
|||
return
|
||||
}
|
||||
|
||||
// The UPDATE_LEASE EDNS0 (draft RFC) option is used to tell the server to set
|
||||
// The UL (Update Lease) EDNS0 (draft RFC) option is used to tell the server to set
|
||||
// an expiration on an update RR. This is helpful for clients that cannot clean
|
||||
// up after themselves. This is a draft RFC and more information can be found at
|
||||
// http://files.dns-sd.org/draft-sekar-dns-ul.txt
|
||||
|
@ -301,22 +325,21 @@ func (e *EDNS0_SUBNET) String() (s string) {
|
|||
// o := new(dns.OPT)
|
||||
// o.Hdr.Name = "."
|
||||
// o.Hdr.Rrtype = dns.TypeOPT
|
||||
// e := new(dns.EDNS0_UPDATE_LEASE)
|
||||
// e.Code = dns.EDNS0UPDATELEASE
|
||||
// e := new(dns.EDNS0_UL)
|
||||
// e.Code = dns.EDNS0UL
|
||||
// e.Lease = 120 // in seconds
|
||||
// o.Option = append(o.Option, e)
|
||||
|
||||
type EDNS0_UPDATE_LEASE struct {
|
||||
Code uint16 // Always EDNS0UPDATELEASE
|
||||
type EDNS0_UL struct {
|
||||
Code uint16 // Always EDNS0UL
|
||||
Lease uint32
|
||||
}
|
||||
|
||||
func (e *EDNS0_UPDATE_LEASE) Option() uint16 {
|
||||
return EDNS0UPDATELEASE
|
||||
func (e *EDNS0_UL) Option() uint16 {
|
||||
return EDNS0UL
|
||||
}
|
||||
|
||||
// Copied: http://golang.org/src/pkg/net/dnsmsg.go
|
||||
func (e *EDNS0_UPDATE_LEASE) pack() ([]byte, error) {
|
||||
func (e *EDNS0_UL) pack() ([]byte, error) {
|
||||
b := make([]byte, 4)
|
||||
b[0] = byte(e.Lease >> 24)
|
||||
b[1] = byte(e.Lease >> 16)
|
||||
|
@ -325,10 +348,147 @@ func (e *EDNS0_UPDATE_LEASE) pack() ([]byte, error) {
|
|||
return b, nil
|
||||
}
|
||||
|
||||
func (e *EDNS0_UPDATE_LEASE) unpack(b []byte) {
|
||||
func (e *EDNS0_UL) unpack(b []byte) {
|
||||
e.Lease = uint32(b[0])<<24 | uint32(b[1])<<16 | uint32(b[2])<<8 | uint32(b[3])
|
||||
}
|
||||
|
||||
func (e *EDNS0_UPDATE_LEASE) String() string {
|
||||
return strconv.Itoa(int(e.Lease))
|
||||
func (e *EDNS0_UL) String() string {
|
||||
return strconv.FormatUint(uint64(e.Lease), 10)
|
||||
}
|
||||
|
||||
// Long Lived Queries: http://tools.ietf.org/html/draft-sekar-dns-llq-01
|
||||
// Implemented for completeness, as the EDNS0 type code is assigned.
|
||||
type EDNS0_LLQ struct {
|
||||
Code uint16 // Always EDNS0LLQ
|
||||
Version uint16
|
||||
Opcode uint16
|
||||
Error uint16
|
||||
Id uint64
|
||||
LeaseLife uint32
|
||||
}
|
||||
|
||||
func (e *EDNS0_LLQ) Option() uint16 {
|
||||
return EDNS0LLQ
|
||||
}
|
||||
|
||||
func (e *EDNS0_LLQ) pack() ([]byte, error) {
|
||||
b := make([]byte, 18)
|
||||
b[0], b[1] = packUint16(e.Version)
|
||||
b[2], b[3] = packUint16(e.Opcode)
|
||||
b[4], b[5] = packUint16(e.Error)
|
||||
b[6] = byte(e.Id >> 56)
|
||||
b[7] = byte(e.Id >> 48)
|
||||
b[8] = byte(e.Id >> 40)
|
||||
b[9] = byte(e.Id >> 32)
|
||||
b[10] = byte(e.Id >> 24)
|
||||
b[11] = byte(e.Id >> 16)
|
||||
b[12] = byte(e.Id >> 8)
|
||||
b[13] = byte(e.Id)
|
||||
b[14] = byte(e.LeaseLife >> 24)
|
||||
b[15] = byte(e.LeaseLife >> 16)
|
||||
b[16] = byte(e.LeaseLife >> 8)
|
||||
b[17] = byte(e.LeaseLife)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (e *EDNS0_LLQ) unpack(b []byte) {
|
||||
e.Version, _ = unpackUint16(b, 0)
|
||||
e.Opcode, _ = unpackUint16(b, 2)
|
||||
e.Error, _ = unpackUint16(b, 4)
|
||||
e.Id = uint64(b[6])<<56 | uint64(b[6+1])<<48 | uint64(b[6+2])<<40 |
|
||||
uint64(b[6+3])<<32 | uint64(b[6+4])<<24 | uint64(b[6+5])<<16 | uint64(b[6+6])<<8 | uint64(b[6+7])
|
||||
e.LeaseLife = uint32(b[14])<<24 | uint32(b[14+1])<<16 | uint32(b[14+2])<<8 | uint32(b[14+3])
|
||||
}
|
||||
|
||||
func (e *EDNS0_LLQ) String() string {
|
||||
s := strconv.FormatUint(uint64(e.Version), 10) + " " + strconv.FormatUint(uint64(e.Opcode), 10) +
|
||||
" " + strconv.FormatUint(uint64(e.Error), 10) + " " + strconv.FormatUint(uint64(e.Id), 10) +
|
||||
" " + strconv.FormatUint(uint64(e.LeaseLife), 10)
|
||||
return s
|
||||
}
|
||||
|
||||
type EDNS0_DAU struct {
|
||||
Code uint16 // Always EDNS0DAU
|
||||
AlgCode []uint8
|
||||
}
|
||||
|
||||
func (e *EDNS0_DAU) Option() uint16 {
|
||||
return EDNS0DAU
|
||||
}
|
||||
func (e *EDNS0_DAU) pack() ([]byte, error) {
|
||||
return e.AlgCode, nil
|
||||
}
|
||||
|
||||
func (e *EDNS0_DAU) unpack(b []byte) {
|
||||
e.AlgCode = b
|
||||
}
|
||||
|
||||
func (e *EDNS0_DAU) String() string {
|
||||
s := ""
|
||||
for i := 0; i < len(e.AlgCode); i++ {
|
||||
if a, ok := AlgorithmToString[e.AlgCode[i]]; ok {
|
||||
s += " " + a
|
||||
} else {
|
||||
s += " " + strconv.Itoa(int(e.AlgCode[i]))
|
||||
}
|
||||
}
|
||||
return s
|
||||
|
||||
}
|
||||
|
||||
type EDNS0_DHU struct {
|
||||
Code uint16 // Always EDNS0DHU
|
||||
AlgCode []uint8
|
||||
}
|
||||
|
||||
func (e *EDNS0_DHU) Option() uint16 {
|
||||
return EDNS0DHU
|
||||
}
|
||||
func (e *EDNS0_DHU) pack() ([]byte, error) {
|
||||
return e.AlgCode, nil
|
||||
}
|
||||
|
||||
func (e *EDNS0_DHU) unpack(b []byte) {
|
||||
e.AlgCode = b
|
||||
}
|
||||
|
||||
func (e *EDNS0_DHU) String() string {
|
||||
s := ""
|
||||
for i := 0; i < len(e.AlgCode); i++ {
|
||||
if a, ok := HashToString[e.AlgCode[i]]; ok {
|
||||
s += " " + a
|
||||
} else {
|
||||
s += " " + strconv.Itoa(int(e.AlgCode[i]))
|
||||
}
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
type EDNS0_N3U struct {
|
||||
Code uint16 // Always EDNS0N3U
|
||||
AlgCode []uint8
|
||||
}
|
||||
|
||||
func (e *EDNS0_N3U) Option() uint16 {
|
||||
return EDNS0N3U
|
||||
}
|
||||
func (e *EDNS0_N3U) pack() ([]byte, error) {
|
||||
return e.AlgCode, nil
|
||||
}
|
||||
|
||||
func (e *EDNS0_N3U) unpack(b []byte) {
|
||||
e.AlgCode = b
|
||||
}
|
||||
|
||||
func (e *EDNS0_N3U) String() string {
|
||||
// Re-use the hash map
|
||||
s := ""
|
||||
for i := 0; i < len(e.AlgCode); i++ {
|
||||
if a, ok := HashToString[e.AlgCode[i]]; ok {
|
||||
s += " " + a
|
||||
} else {
|
||||
s += " " + strconv.Itoa(int(e.AlgCode[i]))
|
||||
}
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2011 Miek Gieben. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Chaos is a small program that prints the version.bind and hostname.bind
|
||||
// for each address of the nameserver given as argument.
|
||||
package main
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2011 Miek Gieben. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Go equivalent of the "DNS & BIND" book check-soa program.
|
||||
package main
|
||||
|
||||
|
|
17
ex/q/q.go
17
ex/q/q.go
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2011 Miek Gieben. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Q is a small utility which acts and behaves like 'dig' from BIND.
|
||||
// It is meant to stay lean and mean, while having a bunch of handy
|
||||
// features, like -check which checks if a packet is correctly signed (without
|
||||
|
@ -47,8 +51,6 @@ func main() {
|
|||
flag.PrintDefaults()
|
||||
}
|
||||
|
||||
conf, _ := dns.ClientConfigFromFile("/etc/resolv.conf")
|
||||
nameserver := "@" + conf.Servers[0]
|
||||
qtype := uint16(0)
|
||||
qclass := uint16(dns.ClassINET)
|
||||
var qname []string
|
||||
|
@ -70,6 +72,8 @@ func main() {
|
|||
}
|
||||
}
|
||||
|
||||
var nameserver string
|
||||
|
||||
Flags:
|
||||
for i := 0; i < flag.NArg(); i++ {
|
||||
// If it starts with @ it is a nameserver
|
||||
|
@ -109,6 +113,15 @@ Flags:
|
|||
qtype = dns.TypeA
|
||||
}
|
||||
|
||||
if len(nameserver) == 0 {
|
||||
conf, err := dns.ClientConfigFromFile("/etc/resolv.conf")
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
os.Exit(2)
|
||||
}
|
||||
nameserver = "@" + conf.Servers[0]
|
||||
}
|
||||
|
||||
nameserver = string([]byte(nameserver)[1:]) // chop off @
|
||||
// if the nameserver is from /etc/resolv.conf the [ and ] are already
|
||||
// added, thereby breaking net.ParseIP. Check for this and don't
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2011 Miek Gieben. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Reflect is a small name server which sends back the IP address of its client, the
|
||||
// recursive resolver.
|
||||
// When queried for type A (resp. AAAA), it sends back the IPv4 (resp. v6) address.
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2011 Miek Gieben. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package dns
|
||||
|
||||
import (
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2011 Miek Gieben. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package dns
|
||||
|
||||
import (
|
||||
|
|
4
kscan.go
4
kscan.go
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2011 Miek Gieben. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package dns
|
||||
|
||||
import (
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2011 Miek Gieben. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package dns
|
||||
|
||||
// Holds a bunch of helper functions for dealing with labels.
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2011 Miek Gieben. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package dns
|
||||
|
||||
import (
|
||||
|
|
28
msg.go
28
msg.go
|
@ -1,6 +1,7 @@
|
|||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// Extensions of the original work are copyright (c) 2011 Miek Gieben
|
||||
|
||||
// DNS packet assembly, see RFC 1035. Converting from - Unpack() -
|
||||
// and to - Pack() - wire format.
|
||||
|
@ -670,6 +671,7 @@ func structValue(any interface{}) reflect.Value {
|
|||
return reflect.ValueOf(any).Elem()
|
||||
}
|
||||
|
||||
// PackStruct packs any structure to wire format.
|
||||
func PackStruct(any interface{}, msg []byte, off int) (off1 int, err error) {
|
||||
off, err = packStructValue(structValue(any), msg, off, nil, false)
|
||||
return off, err
|
||||
|
@ -750,8 +752,28 @@ func unpackStructValue(val reflect.Value, msg []byte, off int) (off1 int, err er
|
|||
e.unpack(msg[off1 : off1+int(optlen)])
|
||||
edns = append(edns, e)
|
||||
off = off1 + int(optlen)
|
||||
case EDNS0UPDATELEASE:
|
||||
e := new(EDNS0_UPDATE_LEASE)
|
||||
case EDNS0UL:
|
||||
e := new(EDNS0_UL)
|
||||
e.unpack(msg[off1 : off1+int(optlen)])
|
||||
edns = append(edns, e)
|
||||
off = off1 + int(optlen)
|
||||
case EDNS0LLQ:
|
||||
e := new(EDNS0_LLQ)
|
||||
e.unpack(msg[off1 : off1+int(optlen)])
|
||||
edns = append(edns, e)
|
||||
off = off1 + int(optlen)
|
||||
case EDNS0DAU:
|
||||
e := new(EDNS0_DAU)
|
||||
e.unpack(msg[off1 : off1+int(optlen)])
|
||||
edns = append(edns, e)
|
||||
off = off1 + int(optlen)
|
||||
case EDNS0DHU:
|
||||
e := new(EDNS0_DHU)
|
||||
e.unpack(msg[off1 : off1+int(optlen)])
|
||||
edns = append(edns, e)
|
||||
off = off1 + int(optlen)
|
||||
case EDNS0N3U:
|
||||
e := new(EDNS0_N3U)
|
||||
e.unpack(msg[off1 : off1+int(optlen)])
|
||||
edns = append(edns, e)
|
||||
off = off1 + int(optlen)
|
||||
|
@ -1032,6 +1054,8 @@ func unpackUint16(msg []byte, off int) (v uint16, off1 int) {
|
|||
return
|
||||
}
|
||||
|
||||
// UnpackStruct unpacks a binary message from offset off to the interface
|
||||
// value given.
|
||||
func UnpackStruct(any interface{}, msg []byte, off int) (off1 int, err error) {
|
||||
off, err = unpackStructValue(structValue(any), msg, off)
|
||||
return off, err
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2011 Miek Gieben. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package dns
|
||||
|
||||
import (
|
||||
|
|
4
nsecx.go
4
nsecx.go
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2011 Miek Gieben. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package dns
|
||||
|
||||
import (
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2011 Miek Gieben. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package dns
|
||||
|
||||
import (
|
||||
|
@ -141,28 +145,29 @@ func TestDotInName(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestParseZone(t *testing.T) {
|
||||
zone := `z1.miek.nl. 86400 IN RRSIG NSEC 8 3 86400 20110823011301 20110724011301 12051 miek.nl. lyRljEQFOmajcdo6bBI67DsTlQTGU3ag9vlE07u7ynqt9aYBXyE9mkasAK4V0oI32YGb2pOSB6RbbdHwUmSt+cYhOA49tl2t0Qoi3pH21dicJiupdZuyjfqUEqJlQoEhNXGtP/pRvWjNA4pQeOsOAoWq/BDcWCSQB9mh2LvUOH4= ; {keyid = sksak}
|
||||
z2.miek.nl. 86400 IN NSEC miek.nl. TXT RRSIG NSEC
|
||||
zone := `z3.miek.nl. 86400 IN RRSIG NSEC 8 3 86400 20110823011301 20110724011301 12051 miek.nl. lyRljEQFOmajcdo6bBI67DsTlQTGU3ag9vlE07u7ynqt9aYBXyE9mkasAK4V0oI32YGb2pOSB6RbbdHwUmSt+cYhOA49tl2t0Qoi3pH21dicJiupdZuyjfqUEqJlQoEhNXGtP/pRvWjNA4pQeOsOAoWq/BDcWCSQB9mh2LvUOH4= ; {keyid = sksak}
|
||||
z1.miek.nl. 86400 IN NSEC miek.nl. TXT RRSIG NSEC
|
||||
$TTL 100
|
||||
z3.miek.nl. IN NSEC miek.nl. TXT RRSIG NSEC`
|
||||
z2.miek.nl. IN NSEC miek.nl. TXT RRSIG NSEC`
|
||||
to := ParseZone(strings.NewReader(zone), "", "")
|
||||
i := 0
|
||||
z := NewZone("miek.nl.")
|
||||
for x := range to {
|
||||
if x.Error == nil {
|
||||
switch i {
|
||||
case 0:
|
||||
case 1:
|
||||
if x.RR.Header().Name != "z1.miek.nl." {
|
||||
t.Log("Failed to parse z1")
|
||||
t.Fail()
|
||||
}
|
||||
case 1:
|
||||
case 2:
|
||||
if x.RR.Header().Name != "z2.miek.nl." {
|
||||
t.Log("Failed to parse z2")
|
||||
t.Fail()
|
||||
}
|
||||
case 2:
|
||||
if x.RR.String() != "z3.miek.nl.\t100\tIN\tNSEC\tmiek.nl. TXT RRSIG NSEC" {
|
||||
t.Logf("Failed to parse z3 %s", x.RR.String())
|
||||
case 0:
|
||||
if x.RR.Header().Name != "z3.miek.nl." {
|
||||
t.Logf("Failed to parse z3 %s")
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
@ -171,6 +176,20 @@ z3.miek.nl. IN NSEC miek.nl. TXT RRSIG NSEC`
|
|||
t.Fail()
|
||||
}
|
||||
i++
|
||||
z.Insert(x.RR)
|
||||
}
|
||||
if len(z.sortedNames.nsecNames) != 3 {
|
||||
t.Log("Length not 3?")
|
||||
t.Fail()
|
||||
}
|
||||
if z.sortedNames.nsecNames[0] != "z1.miek.nl." || z.sortedNames.nsecNames[1] != "z2.miek.nl." || z.sortedNames.nsecNames[2] != "z3.miek.nl." {
|
||||
t.Logf("Not all names correct %v\n", z.sortedNames.nsecNames)
|
||||
t.Fail()
|
||||
}
|
||||
z.RemoveName("z2.miek.nl.")
|
||||
if z.sortedNames.nsecNames[0] != "z1.miek.nl." || z.sortedNames.nsecNames[1] != "z3.miek.nl." {
|
||||
t.Logf("Not all names correct %v\n", z.sortedNames.nsecNames)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2012 Miek Gieben. All rights reserved.
|
||||
// Copyright 2011 Miek Gieben. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2011 Miek Gieben. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package dns
|
||||
|
||||
// Implement a simple scanner, return a byte stream from an io reader.
|
||||
|
|
54
server.go
54
server.go
|
@ -7,7 +7,6 @@
|
|||
package dns
|
||||
|
||||
import (
|
||||
"github.com/miekg/radix"
|
||||
"net"
|
||||
"sync"
|
||||
"time"
|
||||
|
@ -56,12 +55,12 @@ type response struct {
|
|||
// is also registered), otherwise the child gets the query.
|
||||
// ServeMux is also safe for concurrent access from multiple goroutines.
|
||||
type ServeMux struct {
|
||||
r *radix.Radix
|
||||
z map[string]Handler
|
||||
m *sync.RWMutex
|
||||
}
|
||||
|
||||
// NewServeMux allocates and returns a new ServeMux.
|
||||
func NewServeMux() *ServeMux { return &ServeMux{r: radix.New(), m: new(sync.RWMutex)} }
|
||||
func NewServeMux() *ServeMux { return &ServeMux{z: make(map[string]Handler), m: new(sync.RWMutex)} }
|
||||
|
||||
// DefaultServeMux is the default ServeMux used by Serve.
|
||||
var DefaultServeMux = NewServeMux()
|
||||
|
@ -70,7 +69,7 @@ var DefaultServeMux = NewServeMux()
|
|||
var Authors = []string{"Miek Gieben", "Ask Bjørn Hansen", "Dave Cheney", "Dusty Wilson", "Peter van Dijk"}
|
||||
|
||||
// Version holds the current version.
|
||||
var Version = "v1.0"
|
||||
var Version = "v1.2"
|
||||
|
||||
// The HandlerFunc type is an adapter to allow the use of
|
||||
// ordinary functions as DNS handlers. If f is a function
|
||||
|
@ -165,27 +164,40 @@ func ListenAndServe(addr string, network string, handler Handler) error {
|
|||
return server.ListenAndServe()
|
||||
}
|
||||
|
||||
func (mux *ServeMux) match(zone string, t uint16) Handler {
|
||||
func (mux *ServeMux) match(q string, t uint16) Handler {
|
||||
mux.m.RLock()
|
||||
defer mux.m.RUnlock()
|
||||
if h, e := mux.r.Find(toRadixName(zone)); e {
|
||||
// If we got queried for a DS record, we must see if we
|
||||
// if we also serve the parent. We then redirect the query to it.
|
||||
var (
|
||||
handler Handler
|
||||
lastdot int = -1
|
||||
lastbyte byte
|
||||
seendot bool = true
|
||||
)
|
||||
for i := 0; i < len(q); i++ {
|
||||
if seendot {
|
||||
if h, ok := mux.z[q[lastdot+1:]]; ok {
|
||||
if t != TypeDS {
|
||||
return h.Value.(Handler)
|
||||
}
|
||||
if d := h.Up(); d != nil {
|
||||
return d.Value.(Handler)
|
||||
}
|
||||
// No parent zone found, let the original handler take care of it
|
||||
return h.Value.(Handler)
|
||||
return h
|
||||
} else {
|
||||
if h == nil {
|
||||
return nil
|
||||
// Continue for DS to see if we have a parent too, if so delegeate to the parent
|
||||
handler = h
|
||||
}
|
||||
return h.Value.(Handler)
|
||||
}
|
||||
panic("dns: not reached")
|
||||
}
|
||||
|
||||
if q[i] == '.' && lastbyte != '\\' {
|
||||
lastdot = i
|
||||
seendot = true
|
||||
} else {
|
||||
seendot = false
|
||||
}
|
||||
lastbyte = q[i]
|
||||
}
|
||||
// Wildcard match, if we have found nothing try the root zone as a last resort.
|
||||
if h, ok := mux.z["."]; ok {
|
||||
return h
|
||||
}
|
||||
return handler
|
||||
}
|
||||
|
||||
// Handle adds a handler to the ServeMux for pattern.
|
||||
|
@ -194,7 +206,7 @@ func (mux *ServeMux) Handle(pattern string, handler Handler) {
|
|||
panic("dns: invalid pattern " + pattern)
|
||||
}
|
||||
mux.m.Lock()
|
||||
mux.r.Insert(toRadixName(Fqdn(pattern)), handler)
|
||||
mux.z[Fqdn(pattern)] = handler
|
||||
mux.m.Unlock()
|
||||
}
|
||||
|
||||
|
@ -209,7 +221,7 @@ func (mux *ServeMux) HandleRemove(pattern string) {
|
|||
panic("dns: invalid pattern " + pattern)
|
||||
}
|
||||
mux.m.Lock()
|
||||
mux.r.Remove(toRadixName(Fqdn(pattern)))
|
||||
delete(mux.z, Fqdn(pattern))
|
||||
mux.m.Unlock()
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2011 Miek Gieben. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package dns
|
||||
|
||||
import (
|
||||
|
@ -96,3 +100,13 @@ func TestDotAsCatchAllWildcard(t *testing.T) {
|
|||
t.Error("boe. match failed")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRootServer(t *testing.T) {
|
||||
mux := NewServeMux()
|
||||
mux.Handle(".", HandlerFunc(HelloServer))
|
||||
|
||||
handler := mux.match(".", TypeNS)
|
||||
if handler == nil {
|
||||
t.Error("root match failed")
|
||||
}
|
||||
}
|
||||
|
|
4
tlsa.go
4
tlsa.go
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2011 Miek Gieben. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package dns
|
||||
|
||||
import (
|
||||
|
|
4
tsig.go
4
tsig.go
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2011 Miek Gieben. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// TRANSACTION SIGNATURE (TSIG)
|
||||
//
|
||||
// An TSIG or transaction signature adds a HMAC TSIG record to each message sent.
|
||||
|
|
5
types.go
5
types.go
|
@ -1,7 +1,7 @@
|
|||
// copyright 2009 The Go Authors. All rights reserved.
|
||||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// Extended and bugfixes by Miek Gieben
|
||||
// Extensions of the original work are copyright (c) 2011 Miek Gieben
|
||||
|
||||
package dns
|
||||
|
||||
|
@ -19,6 +19,7 @@ import (
|
|||
// Wire constants and supported types.
|
||||
const (
|
||||
// valid RR_Header.Rrtype and Question.qtype
|
||||
TypeNone uint16 = 0
|
||||
TypeA uint16 = 1
|
||||
TypeNS uint16 = 2
|
||||
TypeMD uint16 = 3
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2011 Miek Gieben. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// DYNAMIC UPDATES
|
||||
//
|
||||
// Dynamic updates reuses the DNS message format, but renames three of
|
||||
|
|
4
xfr.go
4
xfr.go
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2011 Miek Gieben. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package dns
|
||||
|
||||
// Envelope is used when doing [IA]XFR with a remote server.
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2011 Miek Gieben. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package dns
|
||||
|
||||
import (
|
||||
|
|
415
zone.go
415
zone.go
|
@ -1,10 +1,12 @@
|
|||
// Copyright 2011 Miek Gieben. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package dns
|
||||
|
||||
// A structure for handling zone data
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/miekg/radix"
|
||||
"math/rand"
|
||||
"runtime"
|
||||
"sort"
|
||||
|
@ -13,18 +15,35 @@ import (
|
|||
"time"
|
||||
)
|
||||
|
||||
// TODO(mg): the memory footprint could be reduced when we would chop off the
|
||||
// the zone's origin from every RR. However they are given to us as pointers
|
||||
// and as such require copies when we fiddle with them...
|
||||
|
||||
// Zone represents a DNS zone. It's safe for concurrent use by
|
||||
// multilpe goroutines.
|
||||
type Zone struct {
|
||||
Origin string // Origin of the zone
|
||||
olabels []string // origin cut up in labels, just to speed up the isSubDomain method
|
||||
Wildcard int // Whenever we see a wildcard name, this is incremented
|
||||
olen int // Origin length
|
||||
olabels []string // Origin cut up in labels, just to speed up the isSubDomain method
|
||||
expired bool // Slave zone is expired
|
||||
ModTime time.Time // When is the zone last modified
|
||||
*radix.Radix // Zone data
|
||||
Names map[string]*ZoneData // Zone data, indexed by owner name
|
||||
*sortedNames // Sorted names for either NSEC or NSEC3
|
||||
*sync.RWMutex
|
||||
// The zone's security status, supported values are TypeNone for no DNSSEC,
|
||||
// TypeNSEC for an NSEC type zone and TypeNSEC3 for an NSEC3 signed zone.
|
||||
Security int
|
||||
}
|
||||
|
||||
type sortedNames struct {
|
||||
// A sorted list of all names in the zone.
|
||||
nsecNames []string
|
||||
// A sorted list of all hashed names in the zone, the hash parameters are taken from the NSEC3PARAM
|
||||
// record located in the zone's apex.
|
||||
nsec3Names []string
|
||||
}
|
||||
|
||||
// Used for nsec(3) bitmap sorting
|
||||
type uint16Slice []uint16
|
||||
|
||||
func (p uint16Slice) Len() int { return len(p) }
|
||||
|
@ -57,7 +76,7 @@ type SignatureConfig struct {
|
|||
// SignerRoutines specifies the number of signing goroutines, if not
|
||||
// set runtime.NumCPU() + 1 is used as the value.
|
||||
SignerRoutines int
|
||||
// SOA Minttl value must be used as the ttl on NSEC/NSEC3 records.
|
||||
// The zone's SOA Minttl value must be used as the ttl on NSEC/NSEC3 records.
|
||||
Minttl uint32
|
||||
}
|
||||
|
||||
|
@ -71,7 +90,7 @@ func newSignatureConfig() *SignatureConfig {
|
|||
// Minttl value is zero.
|
||||
var DefaultSignatureConfig = newSignatureConfig()
|
||||
|
||||
// NewZone creates an initialized zone with Origin set to origin.
|
||||
// NewZone creates an initialized zone with Origin set to the lower cased origin.
|
||||
func NewZone(origin string) *Zone {
|
||||
if origin == "" {
|
||||
origin = "."
|
||||
|
@ -81,74 +100,37 @@ func NewZone(origin string) *Zone {
|
|||
}
|
||||
z := new(Zone)
|
||||
z.Origin = Fqdn(strings.ToLower(origin))
|
||||
z.olen = len(z.Origin)
|
||||
z.olabels = SplitLabels(z.Origin)
|
||||
z.Radix = radix.New()
|
||||
z.Names = make(map[string]*ZoneData)
|
||||
z.RWMutex = new(sync.RWMutex)
|
||||
z.ModTime = time.Now().UTC()
|
||||
z.sortedNames = &sortedNames{make([]string, 0), make([]string, 0)}
|
||||
return z
|
||||
}
|
||||
|
||||
// ZoneData holds all the RRs having their owner name equal to Name.
|
||||
// In theory we can remove the ownernames from the RRs, because they are all the same,
|
||||
// however, cutting the RR and possibly copying into a new structure requires memory too.
|
||||
// For now: just leave the RRs as-is.
|
||||
|
||||
// ZoneData holds all the RRs for a specific owner name.
|
||||
type ZoneData struct {
|
||||
Name string // Domain name for this node
|
||||
RR map[uint16][]RR // Map of the RR type to the RR
|
||||
Signatures map[uint16][]*RRSIG // DNSSEC signatures for the RRs, stored under type covered
|
||||
Signature map[uint16][]*RRSIG // DNSSEC signatures for the RRs, stored under type covered
|
||||
NonAuth bool // Always false, except for NSsets that differ from z.Origin
|
||||
*sync.RWMutex
|
||||
}
|
||||
|
||||
// NewZoneData creates a new zone data element.
|
||||
func NewZoneData(s string) *ZoneData {
|
||||
func NewZoneData() *ZoneData {
|
||||
zd := new(ZoneData)
|
||||
zd.Name = s
|
||||
zd.RR = make(map[uint16][]RR)
|
||||
zd.Signatures = make(map[uint16][]*RRSIG)
|
||||
zd.RWMutex = new(sync.RWMutex)
|
||||
zd.Signature = make(map[uint16][]*RRSIG)
|
||||
return zd
|
||||
}
|
||||
|
||||
// toRadixName reverses a domain name so that when we store it in the radix tree
|
||||
// we preserve the nsec ordering of the zone (this idea was stolen from NSD).
|
||||
// Each label is also lowercased.
|
||||
func toRadixName(d string) string {
|
||||
if d == "" || d == "." {
|
||||
return "."
|
||||
}
|
||||
s := ""
|
||||
ld := len(d)
|
||||
if d[ld-1] != '.' {
|
||||
d = d + "."
|
||||
ld++
|
||||
}
|
||||
var lastdot int
|
||||
var lastbyte byte
|
||||
var lastlastbyte byte
|
||||
for i := 0; i < len(d); i++ {
|
||||
if d[i] == '.' {
|
||||
switch {
|
||||
case lastbyte != '\\':
|
||||
fallthrough
|
||||
case lastbyte == '\\' && lastlastbyte == '\\':
|
||||
s = d[lastdot:i] + "." + s
|
||||
lastdot = i + 1
|
||||
continue
|
||||
}
|
||||
}
|
||||
lastlastbyte = lastbyte
|
||||
lastbyte = d[i]
|
||||
}
|
||||
return "." + strings.ToLower(s[:len(s)-1])
|
||||
}
|
||||
|
||||
// String returns a string representation of a ZoneData. There is no
|
||||
// String for the entire zone, because this will (most likely) take up
|
||||
// a huge amount of memory. Basic use pattern for printing an entire
|
||||
// zone:
|
||||
//
|
||||
// // z contains the zone
|
||||
// z.Radix.NextDo(func(i interface{}) {
|
||||
// fmt.Printf("%s", i.(*dns.ZoneData).String()) })
|
||||
//
|
||||
// a huge amount of memory.
|
||||
func (zd *ZoneData) String() string {
|
||||
var (
|
||||
s string
|
||||
|
@ -158,8 +140,8 @@ func (zd *ZoneData) String() string {
|
|||
// There is only one SOA, but it may have multiple sigs
|
||||
if soa, ok := zd.RR[TypeSOA]; ok {
|
||||
s += soa[0].String() + "\n"
|
||||
if _, ok := zd.Signatures[TypeSOA]; ok {
|
||||
for _, sig := range zd.Signatures[TypeSOA] {
|
||||
if _, ok := zd.Signature[TypeSOA]; ok {
|
||||
for _, sig := range zd.Signature[TypeSOA] {
|
||||
s += sig.String() + "\n"
|
||||
}
|
||||
}
|
||||
|
@ -174,8 +156,8 @@ Types:
|
|||
}
|
||||
s += rr.String() + "\n"
|
||||
}
|
||||
if _, ok := zd.Signatures[t]; ok {
|
||||
for _, rr := range zd.Signatures[t] {
|
||||
if _, ok := zd.Signature[t]; ok {
|
||||
for _, rr := range zd.Signature[t] {
|
||||
s += rr.String() + "\n"
|
||||
}
|
||||
}
|
||||
|
@ -184,8 +166,8 @@ Types:
|
|||
// There is only one NSEC, but it may have multiple sigs
|
||||
if soa, ok := zd.RR[TypeNSEC]; ok {
|
||||
s += soa[0].String() + "\n"
|
||||
if _, ok := zd.Signatures[TypeNSEC]; ok {
|
||||
for _, sig := range zd.Signatures[TypeNSEC] {
|
||||
if _, ok := zd.Signature[TypeNSEC]; ok {
|
||||
for _, sig := range zd.Signature[TypeNSEC] {
|
||||
s += sig.String() + "\n"
|
||||
}
|
||||
}
|
||||
|
@ -193,29 +175,21 @@ Types:
|
|||
return s
|
||||
}
|
||||
|
||||
// Insert inserts the RR r into the zone. There is no check for duplicate data, although
|
||||
// Remove will remove all duplicates.
|
||||
// Insert inserts the RR r into the zone.
|
||||
func (z *Zone) Insert(r RR) error {
|
||||
z.Lock()
|
||||
defer z.Unlock()
|
||||
if !z.isSubDomain(r.Header().Name) {
|
||||
return &Error{Err: "out of zone data", Name: r.Header().Name}
|
||||
}
|
||||
|
||||
key := toRadixName(r.Header().Name)
|
||||
z.Lock()
|
||||
z.ModTime = time.Now().UTC()
|
||||
zd, exact := z.Radix.Find(key)
|
||||
if !exact {
|
||||
// Not an exact match, so insert new value
|
||||
defer z.Unlock()
|
||||
// Check if it's a wildcard name
|
||||
if len(r.Header().Name) > 1 && r.Header().Name[0] == '*' && r.Header().Name[1] == '.' {
|
||||
z.Wildcard++
|
||||
}
|
||||
zd := NewZoneData(r.Header().Name)
|
||||
zd, ok := z.Names[r.Header().Name]
|
||||
if !ok {
|
||||
zd = NewZoneData()
|
||||
switch t := r.Header().Rrtype; t {
|
||||
case TypeRRSIG:
|
||||
sigtype := r.(*RRSIG).TypeCovered
|
||||
zd.Signatures[sigtype] = append(zd.Signatures[sigtype], r.(*RRSIG))
|
||||
zd.Signature[sigtype] = append(zd.Signature[sigtype], r.(*RRSIG))
|
||||
case TypeNS:
|
||||
// NS records with other names than z.Origin are non-auth
|
||||
if r.Header().Name != z.Origin {
|
||||
|
@ -225,24 +199,25 @@ func (z *Zone) Insert(r RR) error {
|
|||
default:
|
||||
zd.RR[t] = append(zd.RR[t], r)
|
||||
}
|
||||
z.Radix.Insert(key, zd)
|
||||
z.Names[r.Header().Name] = zd
|
||||
i := sort.SearchStrings(z.sortedNames.nsecNames, r.Header().Name)
|
||||
z.sortedNames.nsecNames = append(z.sortedNames.nsecNames, "")
|
||||
copy(z.sortedNames.nsecNames[i+1:], z.sortedNames.nsecNames[i:])
|
||||
z.sortedNames.nsecNames[i] = r.Header().Name
|
||||
return nil
|
||||
}
|
||||
z.Unlock()
|
||||
zd.Value.(*ZoneData).Lock()
|
||||
defer zd.Value.(*ZoneData).Unlock()
|
||||
// Name already there
|
||||
switch t := r.Header().Rrtype; t {
|
||||
case TypeRRSIG:
|
||||
sigtype := r.(*RRSIG).TypeCovered
|
||||
zd.Value.(*ZoneData).Signatures[sigtype] = append(zd.Value.(*ZoneData).Signatures[sigtype], r.(*RRSIG))
|
||||
zd.Signature[sigtype] = append(zd.Signature[sigtype], r.(*RRSIG))
|
||||
case TypeNS:
|
||||
if r.Header().Name != z.Origin {
|
||||
zd.Value.(*ZoneData).NonAuth = true
|
||||
zd.NonAuth = true
|
||||
}
|
||||
fallthrough
|
||||
default:
|
||||
zd.Value.(*ZoneData).RR[t] = append(zd.Value.(*ZoneData).RR[t], r)
|
||||
zd.RR[t] = append(zd.RR[t], r)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -250,61 +225,43 @@ func (z *Zone) Insert(r RR) error {
|
|||
// Remove removes the RR r from the zone. If the RR can not be found,
|
||||
// this is a no-op.
|
||||
func (z *Zone) Remove(r RR) error {
|
||||
key := toRadixName(r.Header().Name)
|
||||
z.Lock()
|
||||
z.ModTime = time.Now().UTC()
|
||||
zd, exact := z.Radix.Find(key)
|
||||
if !exact {
|
||||
defer z.Unlock()
|
||||
zd, ok := z.Names[r.Header().Name]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
z.Unlock()
|
||||
zd.Value.(*ZoneData).Lock()
|
||||
defer zd.Value.(*ZoneData).Unlock()
|
||||
remove := false
|
||||
z.ModTime = time.Now().UTC()
|
||||
switch t := r.Header().Rrtype; t {
|
||||
case TypeRRSIG:
|
||||
sigtype := r.(*RRSIG).TypeCovered
|
||||
for i, zr := range zd.Value.(*ZoneData).Signatures[sigtype] {
|
||||
for i, zr := range zd.Signature[sigtype] {
|
||||
if r == zr {
|
||||
zd.Value.(*ZoneData).Signatures[sigtype] = append(zd.Value.(*ZoneData).Signatures[sigtype][:i], zd.Value.(*ZoneData).Signatures[sigtype][i+1:]...)
|
||||
remove = true
|
||||
zd.Signature[sigtype] = append(zd.Signature[sigtype][:i], zd.Signature[sigtype][i+1:]...)
|
||||
}
|
||||
}
|
||||
if remove {
|
||||
// If every Signature of the covering type is removed, removed the type from the map
|
||||
if len(zd.Value.(*ZoneData).Signatures[sigtype]) == 0 {
|
||||
delete(zd.Value.(*ZoneData).Signatures, sigtype)
|
||||
}
|
||||
if len(zd.Signature[sigtype]) == 0 {
|
||||
delete(zd.Signature, sigtype)
|
||||
}
|
||||
default:
|
||||
for i, zr := range zd.Value.(*ZoneData).RR[t] {
|
||||
for i, zr := range zd.RR[t] {
|
||||
// Matching RR
|
||||
if r == zr {
|
||||
zd.Value.(*ZoneData).RR[t] = append(zd.Value.(*ZoneData).RR[t][:i], zd.Value.(*ZoneData).RR[t][i+1:]...)
|
||||
remove = true
|
||||
zd.RR[t] = append(zd.RR[t][:i], zd.RR[t][i+1:]...)
|
||||
}
|
||||
}
|
||||
if remove {
|
||||
// If every RR of this type is removed, removed the type from the map
|
||||
if len(zd.Value.(*ZoneData).RR[t]) == 0 {
|
||||
delete(zd.Value.(*ZoneData).RR, t)
|
||||
if len(zd.RR[t]) == 0 {
|
||||
delete(zd.RR, t)
|
||||
}
|
||||
}
|
||||
}
|
||||
if !remove {
|
||||
return nil
|
||||
}
|
||||
|
||||
if len(r.Header().Name) > 1 && r.Header().Name[0] == '*' && r.Header().Name[1] == '.' {
|
||||
z.Wildcard--
|
||||
if z.Wildcard < 0 {
|
||||
z.Wildcard = 0
|
||||
}
|
||||
}
|
||||
if len(zd.Value.(*ZoneData).RR) == 0 && len(zd.Value.(*ZoneData).Signatures) == 0 {
|
||||
// Entire node is empty, remove it from the Radix tree
|
||||
z.Radix.Remove(key)
|
||||
if len(zd.RR) == 0 && len(zd.Signature) == 0 {
|
||||
// Entire node is empty, remove it from the Zone too
|
||||
delete(z.Names, r.Header().Name)
|
||||
i := sort.SearchStrings(z.sortedNames.nsecNames, r.Header().Name)
|
||||
// we actually removed something if we are here, so i must be something sensible
|
||||
copy(z.sortedNames.nsecNames[i:], z.sortedNames.nsecNames[i+1:])
|
||||
z.sortedNames.nsecNames[len(z.sortedNames.nsecNames)-1] = ""
|
||||
z.sortedNames.nsecNames = z.sortedNames.nsecNames[:len(z.sortedNames.nsecNames)-1]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -312,17 +269,18 @@ func (z *Zone) Remove(r RR) error {
|
|||
// RemoveName removes all the RRs with ownername matching s from the zone. Typical use of this
|
||||
// method is when processing a RemoveName dynamic update packet.
|
||||
func (z *Zone) RemoveName(s string) error {
|
||||
key := toRadixName(s)
|
||||
z.Lock()
|
||||
z.ModTime = time.Now().UTC()
|
||||
defer z.Unlock()
|
||||
z.Radix.Remove(key)
|
||||
if len(s) > 1 && s[0] == '*' && s[1] == '.' {
|
||||
z.Wildcard--
|
||||
if z.Wildcard < 0 {
|
||||
z.Wildcard = 0
|
||||
}
|
||||
_, ok := z.Names[s]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
z.ModTime = time.Now().UTC()
|
||||
delete(z.Names, s)
|
||||
i := sort.SearchStrings(z.sortedNames.nsecNames, s)
|
||||
copy(z.sortedNames.nsecNames[i:], z.sortedNames.nsecNames[i+1:])
|
||||
z.sortedNames.nsecNames[len(z.sortedNames.nsecNames)-1] = ""
|
||||
z.sortedNames.nsecNames = z.sortedNames.nsecNames[:len(z.sortedNames.nsecNames)-1]
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -330,80 +288,87 @@ func (z *Zone) RemoveName(s string) error {
|
|||
// Typical use of this method is when processing a RemoveRRset dynamic update packet.
|
||||
func (z *Zone) RemoveRRset(s string, t uint16) error {
|
||||
z.Lock()
|
||||
z.ModTime = time.Now().UTC()
|
||||
zd, exact := z.Radix.Find(toRadixName(s))
|
||||
if !exact {
|
||||
defer z.Unlock()
|
||||
zd, ok := z.Names[s]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
z.Unlock()
|
||||
zd.Value.(*ZoneData).Lock()
|
||||
defer zd.Value.(*ZoneData).Unlock()
|
||||
z.ModTime = time.Now().UTC()
|
||||
switch t {
|
||||
case TypeRRSIG:
|
||||
// empty all signature maps
|
||||
for covert, _ := range zd.Value.(*ZoneData).Signatures {
|
||||
delete(zd.Value.(*ZoneData).Signatures, covert)
|
||||
for cover, _ := range zd.Signature {
|
||||
delete(zd.Signature, cover)
|
||||
}
|
||||
default:
|
||||
// empty all rr maps
|
||||
for t, _ := range zd.Value.(*ZoneData).RR {
|
||||
delete(zd.Value.(*ZoneData).RR, t)
|
||||
for t, _ := range zd.RR {
|
||||
delete(zd.RR, t)
|
||||
}
|
||||
}
|
||||
if len(zd.RR) == 0 && len(zd.Signature) == 0 {
|
||||
// Entire node is empty, remove it from the Zone too
|
||||
delete(z.Names, s)
|
||||
i := sort.SearchStrings(z.sortedNames.nsecNames, s)
|
||||
// we actually removed something if we are here, so i must be something sensible
|
||||
copy(z.sortedNames.nsecNames[i:], z.sortedNames.nsecNames[i+1:])
|
||||
z.sortedNames.nsecNames[len(z.sortedNames.nsecNames)-1] = ""
|
||||
z.sortedNames.nsecNames = z.sortedNames.nsecNames[:len(z.sortedNames.nsecNames)-1]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Apex returns the zone's apex records (SOA, NS and possibly other). If the
|
||||
// Apex returns the zone's apex records (SOA, NS and possibly others). If the
|
||||
// apex can not be found (thereby making it an illegal DNS zone) it returns nil.
|
||||
// Updating the zone's SOA serial, provided the apex exists:
|
||||
//
|
||||
// z.Apex.RR[TypeSOA][0].(*SOA).Serial++
|
||||
//
|
||||
// Note the a) this increment is not protected by locks and b) if you use DNSSEC
|
||||
// you MUST resign the SOA record.
|
||||
// Apex is safe for concurrent use.
|
||||
func (z *Zone) Apex() *ZoneData {
|
||||
apex, e := z.Find(z.Origin)
|
||||
if !e {
|
||||
fmt.Printf("%#v\n", apex)
|
||||
z.RLock()
|
||||
defer z.RUnlock()
|
||||
apex, ok := z.Names[z.Origin]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return apex
|
||||
}
|
||||
|
||||
// Find looks up the ownername s in the zone and returns the
|
||||
// data and true when an exact match is found. If an exact find isn't
|
||||
// possible the first parent node with a non-nil Value is returned and
|
||||
// the boolean is false.
|
||||
func (z *Zone) Find(s string) (node *ZoneData, exact bool) {
|
||||
// Find looks up the ownername s in the zone and returns the data or nil
|
||||
// when nothing can be found. Find is safe for concurrent use.
|
||||
func (z *Zone) Find(s string) *ZoneData {
|
||||
z.RLock()
|
||||
defer z.RUnlock()
|
||||
n, e := z.Radix.Find(toRadixName(s))
|
||||
if n == nil {
|
||||
return nil, false
|
||||
node, ok := z.Names[s]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
node = n.Value.(*ZoneData)
|
||||
exact = e
|
||||
return
|
||||
}
|
||||
|
||||
// FindFunc works like Find, but the function f is executed on
|
||||
// each node which has a non-nil Value during the tree traversal.
|
||||
// If f returns true, that node is returned.
|
||||
func (z *Zone) FindFunc(s string, f func(interface{}) bool) (*ZoneData, bool, bool) {
|
||||
z.RLock()
|
||||
defer z.RUnlock()
|
||||
zd, e, b := z.Radix.FindFunc(toRadixName(s), f)
|
||||
if zd == nil {
|
||||
return nil, false, false
|
||||
}
|
||||
return zd.Value.(*ZoneData), e, b
|
||||
return node
|
||||
}
|
||||
|
||||
func (z *Zone) isSubDomain(child string) bool {
|
||||
return compareLabelsSlice(z.olabels, strings.ToLower(child)) == len(z.olabels)
|
||||
}
|
||||
|
||||
// compareLabels behaves exactly as CompareLabels expect that l1 is already
|
||||
// a tokenize (in labels) version of the domain name. This saves memory and is faster.
|
||||
func compareLabelsSlice(l1 []string, s2 string) (n int) {
|
||||
l2 := SplitLabels(s2)
|
||||
|
||||
x1 := len(l1) - 1
|
||||
x2 := len(l2) - 1
|
||||
for {
|
||||
if x1 < 0 || x2 < 0 {
|
||||
break
|
||||
}
|
||||
if l1[x1] == l2[x2] {
|
||||
n++
|
||||
} else {
|
||||
break
|
||||
}
|
||||
x1--
|
||||
x2--
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Sign (re)signs the zone z with the given keys.
|
||||
// NSECs and RRSIGs are added as needed.
|
||||
// The public keys themselves are not added to the zone.
|
||||
|
@ -427,42 +392,38 @@ func (z *Zone) Sign(keys map[*DNSKEY]PrivateKey, config *SignatureConfig) error
|
|||
if config == nil {
|
||||
config = DefaultSignatureConfig
|
||||
}
|
||||
// Pre-calc the key tag
|
||||
// Pre-calc the key tags
|
||||
keytags := make(map[*DNSKEY]uint16)
|
||||
for k, _ := range keys {
|
||||
keytags[k] = k.KeyTag()
|
||||
}
|
||||
|
||||
errChan := make(chan error)
|
||||
radChan := make(chan *radix.Radix, config.SignerRoutines*2)
|
||||
zonChan := make(chan *ZoneData, config.SignerRoutines*2)
|
||||
|
||||
// Start the signer goroutines
|
||||
wg := new(sync.WaitGroup)
|
||||
wg.Add(config.SignerRoutines)
|
||||
for i := 0; i < config.SignerRoutines; i++ {
|
||||
go signerRoutine(wg, keys, keytags, config, radChan, errChan)
|
||||
go signerRoutine(z, wg, keys, keytags, config, zonChan, errChan)
|
||||
}
|
||||
|
||||
apex, e := z.Radix.Find(toRadixName(z.Origin))
|
||||
if !e {
|
||||
return ErrSoa
|
||||
}
|
||||
config.Minttl = apex.Value.(*ZoneData).RR[TypeSOA][0].(*SOA).Minttl
|
||||
next := apex.Next()
|
||||
radChan <- apex
|
||||
|
||||
var err error
|
||||
apex := z.Apex()
|
||||
if apex == nil {
|
||||
return ErrSoa
|
||||
}
|
||||
config.Minttl = apex.RR[TypeSOA][0].(*SOA).Minttl
|
||||
Sign:
|
||||
for next.Value.(*ZoneData).Name != z.Origin {
|
||||
for name := range z.Names {
|
||||
select {
|
||||
case err = <-errChan:
|
||||
break Sign
|
||||
default:
|
||||
radChan <- next
|
||||
next = next.Next()
|
||||
zonChan <- z.Names[name]
|
||||
}
|
||||
}
|
||||
close(radChan)
|
||||
close(zonChan)
|
||||
close(errChan)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -471,16 +432,36 @@ Sign:
|
|||
return nil
|
||||
}
|
||||
|
||||
// Sign3 (re)signs the zone z with the given keys, NSEC3s and RRSIGs are
|
||||
// added as needed. Bla bla Identical to zone.Sign.
|
||||
func (z *Zone) Sign3(keys map[*DNSKEY]PrivateKey, config *SignatureConfig) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// signerRoutine is a small helper routine to make the concurrent signing work.
|
||||
func signerRoutine(wg *sync.WaitGroup, keys map[*DNSKEY]PrivateKey, keytags map[*DNSKEY]uint16, config *SignatureConfig, in chan *radix.Radix, err chan error) {
|
||||
func signerRoutine(z *Zone, wg *sync.WaitGroup, keys map[*DNSKEY]PrivateKey, keytags map[*DNSKEY]uint16, config *SignatureConfig, in chan *ZoneData, err chan error) {
|
||||
next := ""
|
||||
defer wg.Done()
|
||||
for {
|
||||
select {
|
||||
case data, ok := <-in:
|
||||
case node, ok := <-in:
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
e := data.Value.(*ZoneData).Sign(data.Next().Value.(*ZoneData).Name, keys, keytags, config)
|
||||
name := ""
|
||||
for x := range node.RR {
|
||||
name = node.RR[x][0].Header().Name
|
||||
break
|
||||
}
|
||||
i := sort.SearchStrings(z.sortedNames.nsecNames, name)
|
||||
if z.sortedNames.nsecNames[i] == name {
|
||||
if i+1 > len(z.sortedNames.nsecNames) {
|
||||
next = z.Origin
|
||||
} else {
|
||||
next = z.sortedNames.nsecNames[i+1]
|
||||
}
|
||||
}
|
||||
e := node.Sign(next, keys, keytags, config)
|
||||
if e != nil {
|
||||
err <- e
|
||||
return
|
||||
|
@ -489,20 +470,20 @@ func signerRoutine(wg *sync.WaitGroup, keys map[*DNSKEY]PrivateKey, keytags map[
|
|||
}
|
||||
}
|
||||
|
||||
// Sign signs a single ZoneData node. The zonedata itself is locked for writing,
|
||||
// during the execution. It is important that the nodes' next record does not
|
||||
// change. The caller must take care that the zone itself is also locked for writing.
|
||||
// Sign signs a single ZoneData node.
|
||||
// The caller must take care that the zone itself is also locked for writing.
|
||||
// For a more complete description see zone.Sign.
|
||||
// Note, because this method has no (direct)
|
||||
// access to the zone's SOA record, the SOA's Minttl value should be set in *config.
|
||||
func (node *ZoneData) Sign(next string, keys map[*DNSKEY]PrivateKey, keytags map[*DNSKEY]uint16, config *SignatureConfig) error {
|
||||
node.Lock()
|
||||
defer node.Unlock()
|
||||
|
||||
n, nsecok := node.RR[TypeNSEC]
|
||||
bitmap := []uint16{TypeNSEC, TypeRRSIG}
|
||||
bitmapEqual := true
|
||||
name := ""
|
||||
for t, _ := range node.RR {
|
||||
if name == "" {
|
||||
name = node.RR[t][0].Header().Name
|
||||
}
|
||||
if nsecok {
|
||||
// Check if the current (if available) nsec has these types too
|
||||
// Grr O(n^2)
|
||||
|
@ -536,14 +517,14 @@ func (node *ZoneData) Sign(next string, keys map[*DNSKEY]PrivateKey, keytags map
|
|||
if n[0].(*NSEC).NextDomain != next || !bitmapEqual {
|
||||
n[0].(*NSEC).NextDomain = next
|
||||
n[0].(*NSEC).TypeBitMap = bitmap
|
||||
node.Signatures[TypeNSEC] = nil // drop all sigs
|
||||
node.Signature[TypeNSEC] = nil // drop all sigs
|
||||
}
|
||||
} else {
|
||||
// No NSEC at all, create one
|
||||
nsec := &NSEC{Hdr: RR_Header{node.Name, TypeNSEC, ClassINET, config.Minttl, 0}, NextDomain: next}
|
||||
nsec := &NSEC{Hdr: RR_Header{name, TypeNSEC, ClassINET, config.Minttl, 0}, NextDomain: next}
|
||||
nsec.TypeBitMap = bitmap
|
||||
node.RR[TypeNSEC] = []RR{nsec}
|
||||
node.Signatures[TypeNSEC] = nil // drop all sigs (just in case)
|
||||
node.Signature[TypeNSEC] = nil // drop all sigs (just in case)
|
||||
}
|
||||
|
||||
// Walk all keys, and check the sigs
|
||||
|
@ -564,7 +545,7 @@ func (node *ZoneData) Sign(next string, keys map[*DNSKEY]PrivateKey, keytags map
|
|||
}
|
||||
}
|
||||
|
||||
j, q := signatures(node.Signatures[t], keytags[k])
|
||||
j, q := signatures(node.Signature[t], keytags[k])
|
||||
if q == nil || now.Sub(uint32ToTime(q.Expiration)) < config.Refresh { // no there, are almost expired
|
||||
s := new(RRSIG)
|
||||
s.SignerName = k.Hdr.Name
|
||||
|
@ -579,27 +560,27 @@ func (node *ZoneData) Sign(next string, keys map[*DNSKEY]PrivateKey, keytags map
|
|||
return e
|
||||
}
|
||||
if q != nil {
|
||||
node.Signatures[t][j] = s // replace the signature
|
||||
node.Signature[t][j] = s // replace the signature
|
||||
} else {
|
||||
node.Signatures[t] = append(node.Signatures[t], s) // add it
|
||||
node.Signature[t] = append(node.Signature[t], s) // add it
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// All signatures have been made are refreshed. Now check the all signatures for expiraton
|
||||
for i, s := range node.Signatures {
|
||||
for i, s := range node.Signature {
|
||||
// s is another slice
|
||||
for i1, s1 := range s {
|
||||
if now.Sub(uint32ToTime(s1.Expiration)) < config.Refresh {
|
||||
// can only happen if made with an unknown key, drop the sig
|
||||
node.Signatures[i] = append(node.Signatures[i][:i1], node.Signatures[i][i1+1:]...)
|
||||
node.Signature[i] = append(node.Signature[i][:i1], node.Signature[i][i1+1:]...)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Return the signature for the typecovered and make with the keytag. It
|
||||
// Return the signature for the typecovered and made with the keytag. It
|
||||
// returns the index of the RRSIG and the RRSIG itself.
|
||||
func signatures(signatures []*RRSIG, keytag uint16) (int, *RRSIG) {
|
||||
for i, s := range signatures {
|
||||
|
@ -639,25 +620,3 @@ func jitterDuration(d time.Duration) time.Duration {
|
|||
}
|
||||
return -time.Duration(jitter)
|
||||
}
|
||||
|
||||
// compareLabels behaves exactly as CompareLabels expect that l1 is already
|
||||
// a tokenize (in labels) version of the domain name. This saves memory and is faster.
|
||||
func compareLabelsSlice(l1 []string, s2 string) (n int) {
|
||||
l2 := SplitLabels(s2)
|
||||
|
||||
x1 := len(l1) - 1
|
||||
x2 := len(l2) - 1
|
||||
for {
|
||||
if x1 < 0 || x2 < 0 {
|
||||
break
|
||||
}
|
||||
if l1[x1] == l2[x2] {
|
||||
n++
|
||||
} else {
|
||||
break
|
||||
}
|
||||
x1--
|
||||
x2--
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
40
zone_test.go
40
zone_test.go
|
@ -1,30 +1,18 @@
|
|||
// Copyright 2011 Miek Gieben. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package dns
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestRadixName(t *testing.T) {
|
||||
tests := map[string]string{".": ".",
|
||||
"www.miek.nl.": ".nl.miek.www",
|
||||
"miek.nl.": ".nl.miek",
|
||||
"mi\\.ek.nl.": ".nl.mi\\.ek",
|
||||
`mi\\.ek.nl.`: `.nl.ek.mi\\`,
|
||||
"": "."}
|
||||
for i, o := range tests {
|
||||
t.Logf("%s %v\n", i, SplitLabels(i))
|
||||
if x := toRadixName(i); x != o {
|
||||
t.Logf("%s should convert to %s, not %s\n", i, o, x)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestInsert(t *testing.T) {
|
||||
z := NewZone("miek.nl.")
|
||||
mx, _ := NewRR("foo.miek.nl. MX 10 mx.miek.nl.")
|
||||
z.Insert(mx)
|
||||
_, exact := z.Find("foo.miek.nl.")
|
||||
if exact != true {
|
||||
t.Fail() // insert broken?
|
||||
node := z.Find("foo.miek.nl.")
|
||||
if node == nil {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -32,14 +20,14 @@ func TestRemove(t *testing.T) {
|
|||
z := NewZone("miek.nl.")
|
||||
mx, _ := NewRR("foo.miek.nl. MX 10 mx.miek.nl.")
|
||||
z.Insert(mx)
|
||||
zd, exact := z.Find("foo.miek.nl.")
|
||||
if exact != true {
|
||||
t.Fail() // insert broken?
|
||||
node := z.Find("foo.miek.nl.")
|
||||
if node == nil {
|
||||
t.Fail()
|
||||
}
|
||||
z.Remove(mx)
|
||||
zd, exact = z.Find("foo.miek.nl.")
|
||||
if exact != false {
|
||||
println(zd.String())
|
||||
t.Errorf("zd(%s) exact(%s) still exists", zd, exact) // it should no longer be in the zone
|
||||
node = z.Find("foo.miek.nl.")
|
||||
if node != nil {
|
||||
println(node.String())
|
||||
t.Errorf("node(%s) still exists", node)
|
||||
}
|
||||
}
|
||||
|
|
8
zscan.go
8
zscan.go
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2011 Miek Gieben. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package dns
|
||||
|
||||
import (
|
||||
|
@ -96,7 +100,7 @@ type lex struct {
|
|||
type Token struct {
|
||||
RR // the scanned resource record when error is not nil
|
||||
Error *ParseError // when an error occured, this has the error specifics
|
||||
Comment string // A potential comment positioned after the RR, but on the same line
|
||||
Comment string // A potential comment positioned after the RR and on the same line
|
||||
}
|
||||
|
||||
// NewRR reads the RR contained in the string s. Only the first RR is returned.
|
||||
|
@ -140,7 +144,7 @@ func ReadRR(q io.Reader, filename string) (RR, error) {
|
|||
//
|
||||
// foo. IN A 10.0.0.1 ; this is a comment
|
||||
//
|
||||
// The text "; this is comment" is returned in Token.comment . Comments inside the
|
||||
// The text "; this is comment" is returned in Token.Comment . Comments inside the
|
||||
// RR are discarded. Comments on a line by themselves are discarded too.
|
||||
func ParseZone(r io.Reader, origin, file string) chan Token {
|
||||
return parseZoneHelper(r, origin, file, 10000)
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2011 Miek Gieben. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package dns
|
||||
|
||||
import (
|
||||
|
|
Loading…
Reference in New Issue