updated vendored mdns libs

This commit is contained in:
Juan Batiz-Benet 2015-04-22 00:49:40 -07:00
parent 73c3888812
commit 58d6d1e7b6
45 changed files with 1685 additions and 1483 deletions

4
Godeps/Godeps.json generated
View File

@ -125,7 +125,7 @@
},
{
"ImportPath": "github.com/hashicorp/mdns",
"Rev": "e4aba3430cd7360a45a596da8eacff13abb8ae2d"
"Rev": "2b439d37011456df8ff83a70ffd1cd6046410113"
},
{
"ImportPath": "github.com/hashicorp/yamux",
@ -228,7 +228,7 @@
},
{
"ImportPath": "github.com/miekg/dns",
"Rev": "a76c0a363dd4798064787c742fdf54a593787e91"
"Rev": "5a357a6fc5e85268b929350aa6423e2d56dcc4ff"
},
{
"ImportPath": "github.com/mitchellh/go-homedir",

View File

@ -236,7 +236,7 @@ func (c *client) query(params *QueryParam) error {
select {
case resp := <-msgCh:
var inp *ServiceEntry
for _, answer := range resp.Answer {
for _, answer := range append(resp.Answer, resp.Extra...) {
// TODO(reddaly): Check that response corresponds to serviceAddr?
switch rr := answer.(type) {
case *dns.PTR:

View File

@ -267,6 +267,8 @@ func (s *Server) handleQuestion(q dns.Question) (multicastRecs, unicastRecs []dn
// sendResponse is used to send a response packet
func (s *Server) sendResponse(resp *dns.Msg, from net.Addr, unicast bool) error {
// TODO(reddaly): Respect the unicast argument, and allow sending responses
// over multicast.
buf, err := resp.Pack()
if err != nil {
return err
@ -274,27 +276,11 @@ func (s *Server) sendResponse(resp *dns.Msg, from net.Addr, unicast bool) error
// Determine the socket to send from
addr := from.(*net.UDPAddr)
var conn *net.UDPConn
if addr.IP.To4() != nil {
conn = s.ipv4List
_, err = s.ipv4List.WriteToUDP(buf, addr)
return err
} else {
conn = s.ipv6List
_, err = s.ipv6List.WriteToUDP(buf, addr)
return err
}
// Determine the address to send to if not unicast
if !unicast {
if addr.IP.To4() != nil {
addr = ipv4Addr
} else {
addr = ipv6Addr
}
}
// Guard against a missing connection or address
if conn == nil || addr == nil {
return fmt.Errorf("Unable to respond, missing connection (%v) or address (%v)",
conn, addr)
}
_, err = conn.WriteToUDP(buf, addr)
return err
}

View File

@ -99,7 +99,7 @@ func NewMDNSService(instance, service, domain, hostName string, port int, ips []
if err != nil {
// Try appending the host domain suffix and lookup again
// (required for Linux-based hosts)
tmpHostName := fmt.Sprintf("%s%s.", hostName, domain)
tmpHostName := fmt.Sprintf("%s%s", hostName, domain)
ips, err = net.LookupIP(tmpHostName)

View File

@ -1,21 +1,6 @@
language: go
go:
- 1.2
- 1.3
env:
# "gvm update" resets GOOS and GOARCH environment variable, workaround it by setting
# BUILD_GOOS and BUILD_GOARCH and overriding GOARCH and GOOS in the build script
global:
- BUILD_GOARCH=amd64
matrix:
- BUILD_GOOS=linux
- BUILD_GOOS=darwin
- BUILD_GOOS=windows
- 1.4
script:
- gvm cross $BUILD_GOOS $BUILD_GOARCH
- GOARCH=$BUILD_GOARCH GOOS=$BUILD_GOOS go build
# only test on linux
# also specify -short; the crypto tests fail in weird ways *sometimes*
# See issue #151
- if [ $BUILD_GOOS == "linux" ]; then GOARCH=$BUILD_GOARCH GOOS=$BUILD_GOOS go test -short -bench=.; fi
- go test -short -bench=.

View File

@ -35,6 +35,7 @@ A not-so-up-to-date-list-that-may-be-actually-current:
* https://github.com/DevelopersPL/godnsagent
* https://github.com/duedil-ltd/discodns
* https://github.com/StalkR/dns-reverse-proxy
* https://github.com/tianon/rawdns
Send pull request if you want to be listed here.
@ -68,7 +69,7 @@ correctly, the following should work:
## Examples
A short "how to use the API" is at the beginning of dns.go (this also will show
A short "how to use the API" is at the beginning of doc.go (this also will show
when you call `godoc github.com/miekg/dns`).
Example programs can be found in the `github.com/miekg/exdns` repository.

View File

@ -55,6 +55,13 @@ func Exchange(m *Msg, a string) (r *Msg, err error) {
defer co.Close()
co.SetReadDeadline(time.Now().Add(dnsTimeout))
co.SetWriteDeadline(time.Now().Add(dnsTimeout))
opt := m.IsEdns0()
// If EDNS0 is used use that for size.
if opt != nil && opt.UDPSize() >= MinMsgSize {
co.UDPSize = opt.UDPSize()
}
if err = co.WriteMsg(m); err != nil {
return nil, err
}
@ -290,7 +297,7 @@ func Dial(network, address string) (conn *Conn, err error) {
return conn, nil
}
// Dialtimeout acts like Dial but takes a timeout.
// DialTimeout acts like Dial but takes a timeout.
func DialTimeout(network, address string, timeout time.Duration) (conn *Conn, err error) {
conn = new(Conn)
conn.Conn, err = net.DialTimeout(network, address, timeout)

View File

@ -1,6 +1,7 @@
package dns
import (
"strconv"
"testing"
"time"
)
@ -11,7 +12,7 @@ func TestClientSync(t *testing.T) {
s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
if err != nil {
t.Fatalf("Unable to run test server: %s", err)
t.Fatalf("Unable to run test server: %v", err)
}
defer s.Shutdown()
@ -19,26 +20,20 @@ func TestClientSync(t *testing.T) {
m.SetQuestion("miek.nl.", TypeSOA)
c := new(Client)
r, _, e := c.Exchange(m, addrstr)
if e != nil {
t.Logf("failed to exchange: %s", e.Error())
t.Fail()
r, _, err := c.Exchange(m, addrstr)
if err != nil {
t.Errorf("failed to exchange: %v", err)
}
if r != nil && r.Rcode != RcodeSuccess {
t.Log("failed to get an valid answer")
t.Fail()
t.Logf("%v\n", r)
t.Errorf("failed to get an valid answer\n%v", r)
}
// And now with plain Exchange().
r, e = Exchange(m, addrstr)
if e != nil {
t.Logf("failed to exchange: %s", e.Error())
t.Fail()
r, err = Exchange(m, addrstr)
if err != nil {
t.Errorf("failed to exchange: %v", err)
}
if r != nil && r.Rcode != RcodeSuccess {
t.Log("failed to get an valid answer")
t.Fail()
t.Logf("%v\n", r)
t.Errorf("failed to get an valid answer\n%v", r)
}
}
@ -48,7 +43,7 @@ func TestClientEDNS0(t *testing.T) {
s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
if err != nil {
t.Fatalf("Unable to run test server: %s", err)
t.Fatalf("Unable to run test server: %v", err)
}
defer s.Shutdown()
@ -57,6 +52,58 @@ func TestClientEDNS0(t *testing.T) {
m.SetEdns0(2048, true)
c := new(Client)
r, _, err := c.Exchange(m, addrstr)
if err != nil {
t.Errorf("failed to exchange: %v", err)
}
if r != nil && r.Rcode != RcodeSuccess {
t.Errorf("failed to get an valid answer\n%v", r)
}
}
// Validates the transmission and parsing of local EDNS0 options.
func TestClientEDNS0Local(t *testing.T) {
optStr1 := "1979:0x0707"
optStr2 := strconv.Itoa(EDNS0LOCALSTART) + ":0x0601"
handler := func(w ResponseWriter, req *Msg) {
m := new(Msg)
m.SetReply(req)
m.Extra = make([]RR, 1, 2)
m.Extra[0] = &TXT{Hdr: RR_Header{Name: m.Question[0].Name, Rrtype: TypeTXT, Class: ClassINET, Ttl: 0}, Txt: []string{"Hello local edns"}}
// If the local options are what we expect, then reflect them back.
ec1 := req.Extra[0].(*OPT).Option[0].(*EDNS0_LOCAL).String()
ec2 := req.Extra[0].(*OPT).Option[1].(*EDNS0_LOCAL).String()
if ec1 == optStr1 && ec2 == optStr2 {
m.Extra = append(m.Extra, req.Extra[0])
}
w.WriteMsg(m)
}
HandleFunc("miek.nl.", handler)
defer HandleRemove("miek.nl.")
s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
if err != nil {
t.Fatalf("Unable to run test server: %s", err)
}
defer s.Shutdown()
m := new(Msg)
m.SetQuestion("miek.nl.", TypeTXT)
// Add two local edns options to the query.
ec1 := &EDNS0_LOCAL{Code: 1979, Data: []byte{7, 7}}
ec2 := &EDNS0_LOCAL{Code: EDNS0LOCALSTART, Data: []byte{6, 1}}
o := &OPT{Hdr: RR_Header{Name: ".", Rrtype: TypeOPT}, Option: []EDNS0{ec1, ec2}}
m.Extra = append(m.Extra, o)
c := new(Client)
r, _, e := c.Exchange(m, addrstr)
if e != nil {
@ -65,7 +112,28 @@ func TestClientEDNS0(t *testing.T) {
}
if r != nil && r.Rcode != RcodeSuccess {
t.Log("failed to get an valid answer")
t.Log("failed to get a valid answer")
t.Fail()
t.Logf("%v\n", r)
}
txt := r.Extra[0].(*TXT).Txt[0]
if txt != "Hello local edns" {
t.Log("Unexpected result for miek.nl", txt, "!= Hello local edns")
t.Fail()
}
// Validate the local options in the reply.
got := r.Extra[1].(*OPT).Option[0].(*EDNS0_LOCAL).String()
if got != optStr1 {
t.Log("failed to get local edns0 answer; got %s, expected %s", got, optStr1)
t.Fail()
t.Logf("%v\n", r)
}
got = r.Extra[1].(*OPT).Option[1].(*EDNS0_LOCAL).String()
if got != optStr2 {
t.Log("failed to get local edns0 answer; got %s, expected %s", got, optStr2)
t.Fail()
t.Logf("%v\n", r)
}
@ -77,7 +145,7 @@ func TestSingleSingleInflight(t *testing.T) {
s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
if err != nil {
t.Fatalf("Unable to run test server: %s", err)
t.Fatalf("Unable to run test server: %v", err)
}
defer s.Shutdown()
@ -106,8 +174,7 @@ Loop:
first = rtt
} else {
if first != rtt {
t.Log("all rtts should be equal")
t.Fail()
t.Errorf("all rtts should be equal. got %d want %d", rtt, first)
}
}
i++
@ -127,14 +194,14 @@ func ExampleUpdateLeaseTSIG(t *testing.T) {
rrs[0] = rr
m.Insert(rrs)
lease_rr := new(OPT)
lease_rr.Hdr.Name = "."
lease_rr.Hdr.Rrtype = TypeOPT
leaseRr := new(OPT)
leaseRr.Hdr.Name = "."
leaseRr.Hdr.Rrtype = TypeOPT
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)
leaseRr.Option = append(leaseRr.Option, e)
m.Extra = append(m.Extra, leaseRr)
c := new(Client)
m.SetTsig("polvi.", HmacMD5, 300, time.Now().Unix())
@ -142,7 +209,6 @@ func ExampleUpdateLeaseTSIG(t *testing.T) {
_, _, err := c.Exchange(m, "127.0.0.1:53")
if err != nil {
t.Log(err.Error())
t.Fail()
t.Error(err)
}
}

View File

@ -7,7 +7,7 @@ import (
"strings"
)
// Wraps the contents of the /etc/resolv.conf.
// ClientConfig wraps the contents of the /etc/resolv.conf file.
type ClientConfig struct {
Servers []string // servers to use
Search []string // suffixes to append to local name
@ -26,14 +26,19 @@ func ClientConfigFromFile(resolvconf string) (*ClientConfig, error) {
}
defer file.Close()
c := new(ClientConfig)
b := bufio.NewReader(file)
scanner := bufio.NewScanner(file)
c.Servers = make([]string, 0)
c.Search = make([]string, 0)
c.Port = "53"
c.Ndots = 1
c.Timeout = 5
c.Attempts = 2
for line, ok := b.ReadString('\n'); ok == nil; line, ok = b.ReadString('\n') {
for scanner.Scan() {
if err := scanner.Err(); err != nil {
return nil, err
}
line := scanner.Text()
f := strings.Fields(line)
if len(f) < 1 {
continue

View File

@ -0,0 +1,55 @@
package dns
import (
"io/ioutil"
"os"
"path/filepath"
"testing"
)
const normal string = `
# Comment
domain somedomain.com
nameserver 10.28.10.2
nameserver 11.28.10.1
`
const missingNewline string = `
domain somedomain.com
nameserver 10.28.10.2
nameserver 11.28.10.1` // <- NOTE: NO newline.
func testConfig(t *testing.T, data string) {
tempDir, err := ioutil.TempDir("", "")
if err != nil {
t.Fatalf("TempDir: %v", err)
}
defer os.RemoveAll(tempDir)
path := filepath.Join(tempDir, "resolv.conf")
if err := ioutil.WriteFile(path, []byte(data), 0644); err != nil {
t.Fatalf("WriteFile: %v", err)
}
cc, err := ClientConfigFromFile(path)
if err != nil {
t.Errorf("error parsing resolv.conf: %v", err)
}
if l := len(cc.Servers); l != 2 {
t.Errorf("incorrect number of nameservers detected: %d", l)
}
if l := len(cc.Search); l != 1 {
t.Errorf("domain directive not parsed correctly: %v", cc.Search)
} else {
if cc.Search[0] != "somedomain.com" {
t.Errorf("domain is unexpected: %v", cc.Search[0])
}
}
}
func TestNameserver(t *testing.T) {
testConfig(t, normal)
}
func TestMissingFinalNewLine(t *testing.T) {
testConfig(t, missingNewline)
}

View File

@ -24,7 +24,9 @@ func (dns *Msg) SetReply(request *Msg) *Msg {
return dns
}
// SetQuestion creates a question message.
// SetQuestion creates a question message, it sets the Question
// section, generates an Id and sets the RecursionDesired (RD)
// bit to true.
func (dns *Msg) SetQuestion(z string, t uint16) *Msg {
dns.Id = Id()
dns.RecursionDesired = true
@ -33,7 +35,9 @@ func (dns *Msg) SetQuestion(z string, t uint16) *Msg {
return dns
}
// SetNotify creates a notify message.
// SetNotify creates a notify message, it sets the Question
// section, generates an Id and sets the Authoritative (AA)
// bit to true.
func (dns *Msg) SetNotify(z string) *Msg {
dns.Opcode = OpcodeNotify
dns.Authoritative = true
@ -184,7 +188,7 @@ func IsFqdn(s string) bool {
return s[l-1] == '.'
}
// Fqdns return the fully qualified domain name from s.
// Fqdn return the fully qualified domain name from s.
// If s is already fully qualified, it behaves as the identity function.
func Fqdn(s string) string {
if IsFqdn(s) {

View File

@ -1,106 +1,16 @@
// Package dns implements a full featured interface to the Domain Name System.
// Server- and client-side programming is supported.
// The package allows complete control over what is send out to the DNS. The package
// API follows the less-is-more principle, by presenting a small, clean interface.
//
// The package dns supports (asynchronous) querying/replying, incoming/outgoing zone transfers,
// TSIG, EDNS0, dynamic updates, notifies and DNSSEC validation/signing.
// Note that domain names MUST be fully qualified, before sending them, unqualified
// names in a message will result in a packing failure.
//
// Resource records are native types. They are not stored in wire format.
// Basic usage pattern for creating a new resource record:
//
// r := new(dns.MX)
// r.Hdr = dns.RR_Header{Name: "miek.nl.", Rrtype: dns.TypeMX, Class: dns.ClassINET, Ttl: 3600}
// r.Preference = 10
// r.Mx = "mx.miek.nl."
//
// Or directly from a string:
//
// mx, err := dns.NewRR("miek.nl. 3600 IN MX 10 mx.miek.nl.")
//
// Or when the default TTL (3600) and class (IN) suit you:
//
// mx, err := dns.NewRR("miek.nl. MX 10 mx.miek.nl.")
//
// Or even:
//
// mx, err := dns.NewRR("$ORIGIN nl.\nmiek 1H IN MX 10 mx.miek")
//
// In the DNS messages are exchanged, these messages contain resource
// records (sets). Use pattern for creating a message:
//
// m := new(dns.Msg)
// m.SetQuestion("miek.nl.", dns.TypeMX)
//
// Or when not certain if the domain name is fully qualified:
//
// m.SetQuestion(dns.Fqdn("miek.nl"), dns.TypeMX)
//
// The message m is now a message with the question section set to ask
// the MX records for the miek.nl. zone.
//
// The following is slightly more verbose, but more flexible:
//
// m1 := new(dns.Msg)
// m1.Id = dns.Id()
// m1.RecursionDesired = true
// m1.Question = make([]dns.Question, 1)
// m1.Question[0] = dns.Question{"miek.nl.", dns.TypeMX, dns.ClassINET}
//
// After creating a message it can be send.
// Basic use pattern for synchronous querying the DNS at a
// server configured on 127.0.0.1 and port 53:
//
// c := new(dns.Client)
// in, rtt, err := c.Exchange(m1, "127.0.0.1:53")
//
// Suppressing
// multiple outstanding queries (with the same question, type and class) is as easy as setting:
//
// c.SingleInflight = true
//
// If these "advanced" features are not needed, a simple UDP query can be send,
// with:
//
// in, err := dns.Exchange(m1, "127.0.0.1:53")
//
// When this functions returns you will get dns message. 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.
//
// Each of these sections (except the Question section) contain a []RR. Basic
// use pattern for accessing the rdata of a TXT RR as the first RR in
// the Answer section:
//
// if t, ok := in.Answer[0].(*dns.TXT); ok {
// // do something with t.Txt
// }
//
// Domain Name and TXT Character String Representations
//
// Both domain names and TXT character strings are converted to presentation
// form both when unpacked and when converted to strings.
//
// For TXT character strings, tabs, carriage returns and line feeds will be
// converted to \t, \r and \n respectively. Back slashes and quotations marks
// will be escaped. Bytes below 32 and above 127 will be converted to \DDD
// form.
//
// For domain names, in addition to the above rules brackets, periods,
// spaces, semicolons and the at symbol are escaped.
package dns
import "strconv"
const (
year68 = 1 << 31 // For RFC1982 (Serial Arithmetic) calculations in 32 bits.
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.
year68 = 1 << 31 // For RFC1982 (Serial Arithmetic) calculations in 32 bits.
// DefaultMsgSize is the standard default for messages larger than 512 bytes.
DefaultMsgSize = 4096
// MinMsgSize is the minimal size of a DNS packet.
MinMsgSize = 512
// MaxMsgSize is the largest possible DNS packet.
MaxMsgSize = 65535
defaultTtl = 3600 // Default internal TTL.
)
// Error represents a DNS error
@ -137,9 +47,10 @@ type RR_Header struct {
Rdlength uint16 // length of data after header
}
// Header returns itself. This is here to make RR_Header implement the RR interface.
func (h *RR_Header) Header() *RR_Header { return h }
// Just to imlement the RR interface
// Just to imlement the RR interface.
func (h *RR_Header) copy() RR { return nil }
func (h *RR_Header) copyHeader() *RR_Header {

View File

@ -17,13 +17,11 @@ func TestPackUnpack(t *testing.T) {
out.Answer[0] = key
msg, err := out.Pack()
if err != nil {
t.Log("failed to pack msg with DNSKEY")
t.Fail()
t.Error("failed to pack msg with DNSKEY")
}
in := new(Msg)
if in.Unpack(msg) != nil {
t.Log("failed to unpack msg with DNSKEY")
t.Fail()
t.Error("failed to unpack msg with DNSKEY")
}
sig := new(RRSIG)
@ -35,13 +33,11 @@ func TestPackUnpack(t *testing.T) {
out.Answer[0] = sig
msg, err = out.Pack()
if err != nil {
t.Log("failed to pack msg with RRSIG")
t.Fail()
t.Error("failed to pack msg with RRSIG")
}
if in.Unpack(msg) != nil {
t.Log("failed to unpack msg with RRSIG")
t.Fail()
t.Error("failed to unpack msg with RRSIG")
}
}
@ -62,8 +58,7 @@ func TestPackUnpack2(t *testing.T) {
m.Answer[0] = rr
_, err := m.Pack()
if err != nil {
t.Log("Packing failed: " + err.Error())
t.Fail()
t.Error("Packing failed: ", err)
return
}
}
@ -90,16 +85,14 @@ func TestPackUnpack3(t *testing.T) {
m.Answer[0] = rr
b, err := m.Pack()
if err != nil {
t.Log("packing failed: " + err.Error())
t.Fail()
t.Error("packing failed: ", err)
return
}
var unpackMsg Msg
err = unpackMsg.Unpack(b)
if err != nil {
t.Log("unpacking failed")
t.Fail()
t.Error("unpacking failed")
return
}
}
@ -111,10 +104,9 @@ func TestBailiwick(t *testing.T) {
}
for parent, child := range yes {
if !IsSubDomain(parent, child) {
t.Logf("%s should be child of %s\n", child, parent)
t.Logf("comparelabels %d", CompareDomainName(parent, child))
t.Logf("lenlabels %d %d", CountLabel(parent), CountLabel(child))
t.Fail()
t.Errorf("%s should be child of %s", child, parent)
t.Errorf("comparelabels %d", CompareDomainName(parent, child))
t.Errorf("lenlabels %d %d", CountLabel(parent), CountLabel(child))
}
}
no := map[string]string{
@ -126,10 +118,9 @@ func TestBailiwick(t *testing.T) {
}
for parent, child := range no {
if IsSubDomain(parent, child) {
t.Logf("%s should not be child of %s\n", child, parent)
t.Logf("comparelabels %d", CompareDomainName(parent, child))
t.Logf("lenlabels %d %d", CountLabel(parent), CountLabel(child))
t.Fail()
t.Errorf("%s should not be child of %s", child, parent)
t.Errorf("comparelabels %d", CompareDomainName(parent, child))
t.Errorf("lenlabels %d %d", CountLabel(parent), CountLabel(child))
}
}
}
@ -142,13 +133,11 @@ func TestPack(t *testing.T) {
for _, r := range rr {
m.Answer[0], err = NewRR(r)
if err != nil {
t.Logf("failed to create RR: %s\n", err.Error())
t.Fail()
t.Errorf("failed to create RR: %v", err)
continue
}
if _, err := m.Pack(); err != nil {
t.Logf("packing failed: %s\n", err.Error())
t.Fail()
t.Errorf("packing failed: %v", err)
}
}
x := new(Msg)
@ -160,20 +149,17 @@ func TestPack(t *testing.T) {
// This crashes due to the fact the a.ntpns.org isn't a FQDN
// How to recover() from a remove panic()?
if _, err := x.Pack(); err == nil {
t.Log("packing should fail")
t.Fail()
t.Error("packing should fail")
}
x.Answer = make([]RR, 1)
x.Answer[0], err = NewRR(rr[0])
if _, err := x.Pack(); err == nil {
t.Log("packing should fail")
t.Fail()
t.Error("packing should fail")
}
x.Question = make([]Question, 1)
x.Question[0] = Question{";sd#edddds鍛↙赏‘℅∥↙xzztsestxssweewwsssstx@s@Z嵌e@cn.pool.ntp.org.", TypeA, ClassINET}
if _, err := x.Pack(); err == nil {
t.Log("packing should fail")
t.Fail()
t.Error("packing should fail")
}
}
@ -186,11 +172,10 @@ func TestPackNAPTR(t *testing.T) {
rr, _ := NewRR(n)
msg := make([]byte, rr.len())
if off, err := PackRR(rr, msg, 0, nil, false); err != nil {
t.Logf("packing failed: %s", err.Error())
t.Logf("length %d, need more than %d\n", rr.len(), off)
t.Fail()
t.Errorf("packing failed: %v", err)
t.Errorf("length %d, need more than %d", rr.len(), off)
} else {
t.Logf("buf size needed: %d\n", off)
t.Logf("buf size needed: %d", off)
}
}
}
@ -229,12 +214,10 @@ func TestMsgCompressLength(t *testing.T) {
buf, err := msg.Pack()
if err != nil {
t.Error(err)
t.Fail()
}
if predicted < len(buf) {
t.Errorf("predicted compressed length is wrong: predicted %s (len=%d) %d, actual %d\n",
t.Errorf("predicted compressed length is wrong: predicted %s (len=%d) %d, actual %d",
msg.Question[0].Name, len(msg.Answer), predicted, len(buf))
t.Fail()
}
}
}
@ -261,12 +244,10 @@ func TestMsgLength(t *testing.T) {
buf, err := msg.Pack()
if err != nil {
t.Error(err)
t.Fail()
}
if predicted < len(buf) {
t.Errorf("predicted length is wrong: predicted %s (len=%d), actual %d\n",
t.Errorf("predicted length is wrong: predicted %s (len=%d), actual %d",
msg.Question[0].Name, predicted, len(buf))
t.Fail()
}
}
}
@ -400,10 +381,10 @@ func BenchmarkMsgUnpack(b *testing.B) {
name1 := "12345678901234567890123456789012345.12345678.123."
rrMx, _ := NewRR(name1 + " 3600 IN MX 10 " + name1)
msg := makeMsg(name1, []RR{rrMx, rrMx}, nil, nil)
msg_buf, _ := msg.Pack()
msgBuf, _ := msg.Pack()
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = msg.Unpack(msg_buf)
_ = msg.Unpack(msgBuf)
}
}
@ -441,7 +422,7 @@ func TestToRFC3597(t *testing.T) {
x := new(RFC3597)
x.ToRFC3597(a)
if x.String() != `miek.nl. 3600 CLASS1 TYPE1 \# 4 0a000101` {
t.Fail()
t.Error("string mismatch")
}
}
@ -453,10 +434,9 @@ func TestNoRdataPack(t *testing.T) {
}
r := fn()
*r.Header() = RR_Header{Name: "miek.nl.", Rrtype: typ, Class: ClassINET, Ttl: 3600}
_, e := PackRR(r, data, 0, nil, false)
if e != nil {
t.Logf("failed to pack RR with zero rdata: %s: %s\n", TypeToString[typ], e.Error())
t.Fail()
_, err := PackRR(r, data, 0, nil, false)
if err != nil {
t.Errorf("failed to pack RR with zero rdata: %s: %v", TypeToString[typ], err)
}
}
}
@ -472,17 +452,17 @@ func TestNoRdataUnpack(t *testing.T) {
}
r := fn()
*r.Header() = RR_Header{Name: "miek.nl.", Rrtype: typ, Class: ClassINET, Ttl: 3600}
off, e := PackRR(r, data, 0, nil, false)
if e != nil {
// Should always works, TestNoDataPack should have catched this
off, err := PackRR(r, data, 0, nil, false)
if err != nil {
// Should always works, TestNoDataPack should have caught this
t.Errorf("failed to pack RR: %v", err)
continue
}
rr, _, e := UnpackRR(data[:off], 0)
if e != nil {
t.Logf("failed to unpack RR with zero rdata: %s: %s\n", TypeToString[typ], e.Error())
t.Fail()
rr, _, err := UnpackRR(data[:off], 0)
if err != nil {
t.Errorf("failed to unpack RR with zero rdata: %s: %v", TypeToString[typ], err)
}
t.Logf("%s\n", rr)
t.Log(rr)
}
}
@ -510,6 +490,48 @@ func TestCopy(t *testing.T) {
}
}
func TestMsgCopy(t *testing.T) {
m := new(Msg)
m.SetQuestion("miek.nl.", TypeA)
rr, _ := NewRR("miek.nl. 2311 IN A 127.0.0.1")
m.Answer = []RR{rr}
rr, _ = NewRR("miek.nl. 2311 IN NS 127.0.0.1")
m.Ns = []RR{rr}
m1 := m.Copy()
if m.String() != m1.String() {
t.Fatalf("Msg.Copy() failed %s != %s", m.String(), m1.String())
}
m1.Answer[0], _ = NewRR("somethingelse.nl. 2311 IN A 127.0.0.1")
if m.String() == m1.String() {
t.Fatalf("Msg.Copy() failed; change to copy changed template %s", m.String())
}
rr, _ = NewRR("miek.nl. 2311 IN A 127.0.0.2")
m1.Answer = append(m1.Answer, rr)
if m1.Ns[0].String() == m1.Answer[1].String() {
t.Fatalf("Msg.Copy() failed; append changed underlying array %s", m1.Ns[0].String())
}
}
func BenchmarkCopy(b *testing.B) {
b.ReportAllocs()
m := new(Msg)
m.SetQuestion("miek.nl.", TypeA)
rr, _ := NewRR("miek.nl. 2311 IN A 127.0.0.1")
m.Answer = []RR{rr}
rr, _ = NewRR("miek.nl. 2311 IN NS 127.0.0.1")
m.Ns = []RR{rr}
rr, _ = NewRR("miek.nl. 2311 IN A 127.0.0.1")
m.Extra = []RR{rr}
b.ResetTimer()
for i := 0; i < b.N; i++ {
m.Copy()
}
}
func TestPackIPSECKEY(t *testing.T) {
tests := []string{
"38.2.0.192.in-addr.arpa. 7200 IN IPSECKEY ( 10 1 2 192.0.2.38 AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== )",
@ -521,18 +543,39 @@ func TestPackIPSECKEY(t *testing.T) {
buf := make([]byte, 1024)
for _, t1 := range tests {
rr, _ := NewRR(t1)
off, e := PackRR(rr, buf, 0, nil, false)
if e != nil {
t.Logf("failed to pack IPSECKEY %s: %s\n", e, t1)
t.Fail()
off, err := PackRR(rr, buf, 0, nil, false)
if err != nil {
t.Errorf("failed to pack IPSECKEY %v: %s", err, t1)
continue
}
rr, _, e = UnpackRR(buf[:off], 0)
if e != nil {
t.Logf("failed to unpack IPSECKEY %s: %s\n", e, t1)
t.Fail()
rr, _, err = UnpackRR(buf[:off], 0)
if err != nil {
t.Errorf("failed to unpack IPSECKEY %v: %s", err, t1)
}
t.Logf("%s\n", rr)
t.Log(rr)
}
}
func TestMsgPackBuffer(t *testing.T) {
var testMessages = []string{
// news.ycombinator.com.in.escapemg.com. IN A, response
"586285830001000000010000046e6577730b79636f6d62696e61746f7203636f6d02696e086573636170656d6703636f6d0000010001c0210006000100000e10002c036e7332c02103646e730b67726f6f7665736861726bc02d77ed50e600002a3000000e1000093a8000000e10",
// news.ycombinator.com.in.escapemg.com. IN A, question
"586201000001000000000000046e6577730b79636f6d62696e61746f7203636f6d02696e086573636170656d6703636f6d0000010001",
"398781020001000000000000046e6577730b79636f6d62696e61746f7203636f6d0000010001",
}
for i, hexData := range testMessages {
// we won't fail the decoding of the hex
input, _ := hex.DecodeString(hexData)
m := new(Msg)
if err := m.Unpack(input); err != nil {
t.Errorf("packet %d failed to unpack", i)
continue
}
t.Logf("packet %d %s", i, m.String())
}
}

View File

@ -1,16 +1,3 @@
// DNSSEC
//
// DNSSEC (DNS Security Extension) adds a layer of security to the DNS. It
// uses public key cryptography to sign resource records. The
// public keys are stored in DNSKEY records and the signatures in RRSIG records.
//
// Requesting DNSSEC information for a zone is done by adding the DO (DNSSEC OK) bit
// to an request.
//
// m := new(dns.Msg)
// m.SetEdns0(4096, true)
//
// Signature generation, signature verification and key generation are all supported.
package dns
import (
@ -202,6 +189,22 @@ func (k *DNSKEY) ToDS(h uint8) *DS {
return ds
}
// ToCDNSKEY converts a DNSKEY record to a CDNSKEY record.
func (k *DNSKEY) ToCDNSKEY() *CDNSKEY {
c := &CDNSKEY{DNSKEY: *k}
c.Hdr = *k.Hdr.copyHeader()
c.Hdr.Rrtype = TypeCDNSKEY
return c
}
// ToCDS converts a DS record to a CDS record.
func (d *DS) ToCDS() *CDS {
c := &CDS{DS: *d}
c.Hdr = *d.Hdr.copyHeader()
c.Hdr.Rrtype = TypeCDS
return c
}
// Sign signs an RRSet. The signature needs to be filled in with
// the values: Inception, Expiration, KeyTag, SignerName and Algorithm.
// The rest is copied from the RRset. Sign returns true when the signing went OK,
@ -422,8 +425,8 @@ func (rr *RRSIG) ValidityPeriod(t time.Time) bool {
}
// Return the signatures base64 encodedig sigdata as a byte slice.
func (s *RRSIG) sigBuf() []byte {
sigbuf, err := fromBase64([]byte(s.Signature))
func (rr *RRSIG) sigBuf() []byte {
sigbuf, err := fromBase64([]byte(rr.Signature))
if err != nil {
return nil
}
@ -588,7 +591,10 @@ func rawSignatureData(rrset []RR, s *RRSIG) (buf []byte, err error) {
wires[i] = wire
}
sort.Sort(wires)
for _, wire := range wires {
for i, wire := range wires {
if i > 0 && bytes.Equal(wire, wires[i-1]) {
continue
}
buf = append(buf, wire...)
}
return buf, nil

View File

@ -15,8 +15,8 @@ import (
// what kind of DNSKEY will be generated.
// The ECDSA algorithms imply a fixed keysize, in that case
// bits should be set to the size of the algorithm.
func (r *DNSKEY) Generate(bits int) (PrivateKey, error) {
switch r.Algorithm {
func (k *DNSKEY) Generate(bits int) (PrivateKey, error) {
switch k.Algorithm {
case DSA, DSANSEC3SHA1:
if bits != 1024 {
return nil, ErrKeySize
@ -39,7 +39,7 @@ func (r *DNSKEY) Generate(bits int) (PrivateKey, error) {
}
}
switch r.Algorithm {
switch k.Algorithm {
case DSA, DSANSEC3SHA1:
params := new(dsa.Parameters)
if err := dsa.GenerateParameters(params, rand.Reader, dsa.L1024N160); err != nil {
@ -51,18 +51,18 @@ func (r *DNSKEY) Generate(bits int) (PrivateKey, error) {
if err != nil {
return nil, err
}
r.setPublicKeyDSA(params.Q, params.P, params.G, priv.PublicKey.Y)
k.setPublicKeyDSA(params.Q, params.P, params.G, priv.PublicKey.Y)
return (*DSAPrivateKey)(priv), nil
case RSAMD5, RSASHA1, RSASHA256, RSASHA512, RSASHA1NSEC3SHA1:
priv, err := rsa.GenerateKey(rand.Reader, bits)
if err != nil {
return nil, err
}
r.setPublicKeyRSA(priv.PublicKey.E, priv.PublicKey.N)
k.setPublicKeyRSA(priv.PublicKey.E, priv.PublicKey.N)
return (*RSAPrivateKey)(priv), nil
case ECDSAP256SHA256, ECDSAP384SHA384:
var c elliptic.Curve
switch r.Algorithm {
switch k.Algorithm {
case ECDSAP256SHA256:
c = elliptic.P256()
case ECDSAP384SHA384:
@ -72,7 +72,7 @@ func (r *DNSKEY) Generate(bits int) (PrivateKey, error) {
if err != nil {
return nil, err
}
r.setPublicKeyECDSA(priv.PublicKey.X, priv.PublicKey.Y)
k.setPublicKeyECDSA(priv.PublicKey.X, priv.PublicKey.Y)
return (*ECDSAPrivateKey)(priv), nil
default:
return nil, ErrAlg

View File

@ -9,6 +9,8 @@ import (
"strings"
)
// NewPrivateKey returns a PrivateKey by parsing the string s.
// s should be in the same form of the BIND private key files.
func (k *DNSKEY) NewPrivateKey(s string) (PrivateKey, error) {
if s[len(s)-1] != '\n' { // We need a closing newline
return k.ReadPrivateKey(strings.NewReader(s+"\n"), "")
@ -170,9 +172,9 @@ func parseKey(r io.Reader, file string) (map[string]string, error) {
for l := range c {
// It should alternate
switch l.value {
case _KEY:
case zKey:
k = l.token
case _VALUE:
case zValue:
if k == "" {
return nil, &ParseError{file, "no private key seen", l}
}
@ -202,14 +204,14 @@ func klexer(s *scan, c chan lex) {
}
l.token = str
if key {
l.value = _KEY
l.value = zKey
c <- l
// Next token is a space, eat it
s.tokenText()
key = false
str = ""
} else {
l.value = _VALUE
l.value = zValue
}
case ';':
commt = true
@ -218,7 +220,7 @@ func klexer(s *scan, c chan lex) {
// Reset a comment
commt = false
}
l.value = _VALUE
l.value = zValue
l.token = str
c <- l
str = ""
@ -235,7 +237,7 @@ func klexer(s *scan, c chan lex) {
if len(str) > 0 {
// Send remainder
l.token = str
l.value = _VALUE
l.value = zValue
c <- l
}
}

View File

@ -10,8 +10,9 @@ import (
"strconv"
)
const _FORMAT = "Private-key-format: v1.3\n"
const format = "Private-key-format: v1.3\n"
// PrivateKey ... TODO(miek)
type PrivateKey interface {
Sign([]byte, uint8) ([]byte, error)
String(uint8) string
@ -53,17 +54,17 @@ func (p *RSAPrivateKey) String(alg uint8) string {
// Calculate Exponent1/2 and Coefficient as per: http://en.wikipedia.org/wiki/RSA#Using_the_Chinese_remainder_algorithm
// and from: http://code.google.com/p/go/issues/detail?id=987
one := big.NewInt(1)
p_1 := big.NewInt(0).Sub(p.Primes[0], one)
q_1 := big.NewInt(0).Sub(p.Primes[1], one)
exp1 := big.NewInt(0).Mod(p.D, p_1)
exp2 := big.NewInt(0).Mod(p.D, q_1)
p1 := big.NewInt(0).Sub(p.Primes[0], one)
q1 := big.NewInt(0).Sub(p.Primes[1], one)
exp1 := big.NewInt(0).Mod(p.D, p1)
exp2 := big.NewInt(0).Mod(p.D, q1)
coeff := big.NewInt(0).ModInverse(p.Primes[1], p.Primes[0])
exponent1 := toBase64(exp1.Bytes())
exponent2 := toBase64(exp2.Bytes())
coefficient := toBase64(coeff.Bytes())
return _FORMAT +
return format +
"Algorithm: " + algorithm + "\n" +
"Modulus: " + modulus + "\n" +
"PublicExponent: " + publicExponent + "\n" +
@ -106,7 +107,7 @@ func (p *ECDSAPrivateKey) String(alg uint8) string {
intlen = 48
}
private := toBase64(intToBytes(p.D, intlen))
return _FORMAT +
return format +
"Algorithm: " + algorithm + "\n" +
"PrivateKey: " + private + "\n"
}
@ -133,7 +134,7 @@ func (p *DSAPrivateKey) String(alg uint8) string {
base := toBase64(intToBytes(p.PublicKey.Parameters.G, 64+T*8))
priv := toBase64(intToBytes(p.X, 20))
pub := toBase64(intToBytes(p.PublicKey.Y, 64+T*8))
return _FORMAT +
return format +
"Algorithm: " + algorithm + "\n" +
"Prime(p): " + prime + "\n" +
"Subprime(q): " + subprime + "\n" +

View File

@ -45,8 +45,8 @@ func TestGenerateEC(t *testing.T) {
key.Protocol = 3
key.Algorithm = ECDSAP256SHA256
privkey, _ := key.Generate(256)
t.Logf("%s\n", key.String())
t.Logf("%s\n", key.PrivateKeyString(privkey))
t.Log(key.String())
t.Log(key.PrivateKeyString(privkey))
}
func TestGenerateDSA(t *testing.T) {
@ -62,8 +62,8 @@ func TestGenerateDSA(t *testing.T) {
key.Protocol = 3
key.Algorithm = DSA
privkey, _ := key.Generate(1024)
t.Logf("%s\n", key.String())
t.Logf("%s\n", key.PrivateKeyString(privkey))
t.Log(key.String())
t.Log(key.PrivateKeyString(privkey))
}
func TestGenerateRSA(t *testing.T) {
@ -79,8 +79,8 @@ func TestGenerateRSA(t *testing.T) {
key.Protocol = 3
key.Algorithm = RSASHA256
privkey, _ := key.Generate(1024)
t.Logf("%s\n", key.String())
t.Logf("%s\n", key.PrivateKeyString(privkey))
t.Log(key.String())
t.Log(key.PrivateKeyString(privkey))
}
func TestSecure(t *testing.T) {
@ -107,10 +107,9 @@ func TestSecure(t *testing.T) {
key.Algorithm = RSASHA256
key.PublicKey = "AwEAAcNEU67LJI5GEgF9QLNqLO1SMq1EdoQ6E9f85ha0k0ewQGCblyW2836GiVsm6k8Kr5ECIoMJ6fZWf3CQSQ9ycWfTyOHfmI3eQ/1Covhb2y4bAmL/07PhrL7ozWBW3wBfM335Ft9xjtXHPy7ztCbV9qZ4TVDTW/Iyg0PiwgoXVesz"
// It should validate. Period is checked seperately, so this will keep on working
// It should validate. Period is checked separately, so this will keep on working
if sig.Verify(key, []RR{soa}) != nil {
t.Log("failure to validate")
t.Fail()
t.Error("failure to validate")
}
}
@ -131,15 +130,13 @@ func TestSignature(t *testing.T) {
// Should not be valid
if sig.ValidityPeriod(time.Now()) {
t.Log("should not be valid")
t.Fail()
t.Error("should not be valid")
}
sig.Inception = 315565800 //Tue Jan 1 10:10:00 CET 1980
sig.Expiration = 4102477800 //Fri Jan 1 10:10:00 CET 2100
if !sig.ValidityPeriod(time.Now()) {
t.Log("should be valid")
t.Fail()
t.Error("should be valid")
}
}
@ -196,16 +193,14 @@ func TestSignVerify(t *testing.T) {
for _, r := range []RR{soa, soa1, srv} {
if sig.Sign(privkey, []RR{r}) != nil {
t.Log("failure to sign the record")
t.Fail()
t.Error("failure to sign the record")
continue
}
if sig.Verify(key, []RR{r}) != nil {
t.Log("failure to validate")
t.Fail()
t.Error("failure to validate")
continue
}
t.Logf("validated: %s\n", r.Header().Name)
t.Logf("validated: %s", r.Header().Name)
}
}
@ -234,16 +229,14 @@ func Test65534(t *testing.T) {
sig.SignerName = key.Hdr.Name
sig.Algorithm = RSASHA256
if err := sig.Sign(privkey, []RR{t6}); err != nil {
t.Log(err)
t.Log("failure to sign the TYPE65534 record")
t.Fail()
t.Error(err)
t.Error("failure to sign the TYPE65534 record")
}
if err := sig.Verify(key, []RR{t6}); err != nil {
t.Log(err)
t.Log("failure to validate")
t.Fail()
t.Error(err)
t.Error("failure to validate")
} else {
t.Logf("validated: %s\n", t6.Header().Name)
t.Logf("validated: %s", t6.Header().Name)
}
}
@ -271,13 +264,11 @@ Coefficient: UuRoNqe7YHnKmQzE6iDWKTMIWTuoqqrFAmXPmKQnC+Y+BQzOVEHUo9bXdDnoI9hzXP1
t.Fatal(err)
}
if pubkey.(*DNSKEY).PublicKey != "AwEAAZuMCu2FdugHkTrXYgl5qixvcDw1aDDlvL46/xJKbHBAHY16fNUb2b65cwko2Js/aJxUYJbZk5dwCDZxYfrfbZVtDPQuc3o8QaChVxC7/JYz2AHc9qHvqQ1j4VrH71RWINlQo6VYjzN/BGpMhOZoZOEwzp1HfsOE3lNYcoWU1smL" {
t.Log("pubkey is not what we've read")
t.Fail()
t.Error("pubkey is not what we've read")
}
if pubkey.(*DNSKEY).PrivateKeyString(privkey) != privStr {
t.Log("privkey is not what we've read")
t.Logf("%v", pubkey.(*DNSKEY).PrivateKeyString(privkey))
t.Fail()
t.Error("privkey is not what we've read")
t.Errorf("%v", pubkey.(*DNSKEY).PrivateKeyString(privkey))
}
}
@ -294,8 +285,7 @@ func TestTag(t *testing.T) {
tag := key.KeyTag()
if tag != 12051 {
t.Logf("wrong key tag: %d for key %v\n", tag, key)
t.Fail()
t.Errorf("wrong key tag: %d for key %v", tag, key)
}
}
@ -335,13 +325,11 @@ func TestKeyRSA(t *testing.T) {
sig.SignerName = key.Hdr.Name
if err := sig.Sign(priv, []RR{soa}); err != nil {
t.Logf("failed to sign")
t.Fail()
t.Error("failed to sign")
return
}
if err := sig.Verify(key, []RR{soa}); err != nil {
t.Logf("failed to verify")
t.Fail()
t.Error("failed to verify")
}
}
@ -358,8 +346,7 @@ func TestKeyToDS(t *testing.T) {
ds := key.ToDS(SHA1)
if strings.ToUpper(ds.Digest) != "B5121BDB5B8D86D0CC5FFAFBAAABE26C3E20BAC1" {
t.Logf("wrong DS digest for SHA1\n%v\n", ds)
t.Fail()
t.Errorf("wrong DS digest for SHA1\n%v", ds)
}
}
@ -384,23 +371,18 @@ Activate: 20110302104537`
k := xk.(*DNSKEY)
p, err := k.NewPrivateKey(priv)
if err != nil {
t.Logf("%v\n", err)
t.Fail()
t.Error(err)
}
switch priv := p.(type) {
case *RSAPrivateKey:
if 65537 != priv.PublicKey.E {
t.Log("exponenent should be 65537")
t.Fail()
t.Error("exponenent should be 65537")
}
default:
t.Logf("we should have read an RSA key: %v", priv)
t.Fail()
t.Errorf("we should have read an RSA key: %v", priv)
}
if k.KeyTag() != 37350 {
t.Logf("%d %v\n", k.KeyTag(), k)
t.Log("keytag should be 37350")
t.Fail()
t.Errorf("keytag should be 37350, got %d %v", k.KeyTag(), k)
}
soa := new(SOA)
@ -423,9 +405,7 @@ Activate: 20110302104537`
sig.Sign(p, []RR{soa})
if sig.Signature != "D5zsobpQcmMmYsUMLxCVEtgAdCvTu8V/IEeP4EyLBjqPJmjt96bwM9kqihsccofA5LIJ7DN91qkCORjWSTwNhzCv7bMyr2o5vBZElrlpnRzlvsFIoAZCD9xg6ZY7ZyzUJmU6IcTwG4v3xEYajcpbJJiyaw/RqR90MuRdKPiBzSo=" {
t.Log("signature is not correct")
t.Logf("%v\n", sig)
t.Fail()
t.Errorf("signature is not correct: %v", sig)
}
}
@ -440,13 +420,13 @@ PrivateKey: WURgWHCcYIYUPWgeLmiPY2DJJk02vgrmTfitxgqcL4vwW7BOrbawVmVe0d9V94SR`
eckey, err := NewRR(pub)
if err != nil {
t.Fatal(err.Error())
t.Fatal(err)
}
privkey, err := eckey.(*DNSKEY).NewPrivateKey(priv)
if err != nil {
t.Fatal(err.Error())
t.Fatal(err)
}
// TODO: Create seperate test for this
// TODO: Create separate test for this
ds := eckey.(*DNSKEY).ToDS(SHA384)
if ds.KeyTag != 10771 {
t.Fatal("wrong keytag on DS")
@ -467,22 +447,21 @@ PrivateKey: WURgWHCcYIYUPWgeLmiPY2DJJk02vgrmTfitxgqcL4vwW7BOrbawVmVe0d9V94SR`
t.Fatal("failure to sign the record")
}
if e := sig.Verify(eckey.(*DNSKEY), []RR{a}); e != nil {
t.Logf("\n%s\n%s\n%s\n\n%s\n\n",
if err := sig.Verify(eckey.(*DNSKEY), []RR{a}); err != nil {
t.Fatalf("Failure to validate:\n%s\n%s\n%s\n\n%s\n\n%v",
eckey.(*DNSKEY).String(),
a.String(),
sig.String(),
eckey.(*DNSKEY).PrivateKeyString(privkey),
err,
)
t.Fatalf("failure to validate: %s", e.Error())
}
}
func TestSignVerifyECDSA2(t *testing.T) {
srv1, err := NewRR("srv.miek.nl. IN SRV 1000 800 0 web1.miek.nl.")
if err != nil {
t.Fatalf(err.Error())
t.Fatal(err)
}
srv := srv1.(*SRV)
@ -518,14 +497,13 @@ func TestSignVerifyECDSA2(t *testing.T) {
err = sig.Verify(key, []RR{srv})
if err != nil {
t.Logf("\n%s\n%s\n%s\n\n%s\n\n",
t.Logf("Failure to validate:\n%s\n%s\n%s\n\n%s\n\n%v",
key.String(),
srv.String(),
sig.String(),
key.PrivateKeyString(privkey),
err,
)
t.Fatal("Failure to validate:", err)
}
}
@ -540,11 +518,11 @@ Algorithm: 13 (ECDSAP256SHA256)
PrivateKey: GU6SnQ/Ou+xC5RumuIUIuJZteXT2z0O/ok1s38Et6mQ=`
rrDNSKEY, err := NewRR(exDNSKEY)
if err != nil {
t.Fatal(err.Error())
t.Fatal(err)
}
priv, err := rrDNSKEY.(*DNSKEY).NewPrivateKey(exPriv)
if err != nil {
t.Fatal(err.Error())
t.Fatal(err)
}
exDS := `example.net. 3600 IN DS 55648 13 2 (
@ -552,11 +530,11 @@ PrivateKey: GU6SnQ/Ou+xC5RumuIUIuJZteXT2z0O/ok1s38Et6mQ=`
e2770ce6d6e37df61d17 )`
rrDS, err := NewRR(exDS)
if err != nil {
t.Fatal(err.Error())
t.Fatal(err)
}
ourDS := rrDNSKEY.(*DNSKEY).ToDS(SHA256)
if !reflect.DeepEqual(ourDS, rrDS.(*DS)) {
t.Errorf("DS record differs:\n%v\n%v\n", ourDS, rrDS.(*DS))
t.Errorf("DS record differs:\n%v\n%v", ourDS, rrDS.(*DS))
}
exA := `www.example.net. 3600 IN A 192.0.2.1`
@ -566,11 +544,11 @@ PrivateKey: GU6SnQ/Ou+xC5RumuIUIuJZteXT2z0O/ok1s38Et6mQ=`
yGmt+3SNruPFKG7tZoLBLlUzGGus7ZwmwWep666VCw== )`
rrA, err := NewRR(exA)
if err != nil {
t.Fatal(err.Error())
t.Fatal(err)
}
rrRRSIG, err := NewRR(exRRSIG)
if err != nil {
t.Fatal(err.Error())
t.Fatal(err)
}
if err = rrRRSIG.(*RRSIG).Verify(rrDNSKEY.(*DNSKEY), []RR{rrA}); err != nil {
t.Errorf("Failure to validate the spec RRSIG: %v", err)
@ -588,7 +566,7 @@ PrivateKey: GU6SnQ/Ou+xC5RumuIUIuJZteXT2z0O/ok1s38Et6mQ=`
ourRRSIG.Inception, _ = StringToTime("20100812100439")
err = ourRRSIG.Sign(priv, []RR{rrA})
if err != nil {
t.Fatal(err.Error())
t.Fatal(err)
}
if err = ourRRSIG.Verify(rrDNSKEY.(*DNSKEY), []RR{rrA}); err != nil {
@ -599,7 +577,7 @@ PrivateKey: GU6SnQ/Ou+xC5RumuIUIuJZteXT2z0O/ok1s38Et6mQ=`
rrRRSIG.(*RRSIG).Signature = ""
ourRRSIG.Signature = ""
if !reflect.DeepEqual(ourRRSIG, rrRRSIG.(*RRSIG)) {
t.Fatalf("RRSIG record differs:\n%v\n%v\n", ourRRSIG, rrRRSIG.(*RRSIG))
t.Fatalf("RRSIG record differs:\n%v\n%v", ourRRSIG, rrRRSIG.(*RRSIG))
}
}
@ -614,11 +592,11 @@ Algorithm: 14 (ECDSAP384SHA384)
PrivateKey: WURgWHCcYIYUPWgeLmiPY2DJJk02vgrmTfitxgqcL4vwW7BOrbawVmVe0d9V94SR`
rrDNSKEY, err := NewRR(exDNSKEY)
if err != nil {
t.Fatal(err.Error())
t.Fatal(err)
}
priv, err := rrDNSKEY.(*DNSKEY).NewPrivateKey(exPriv)
if err != nil {
t.Fatal(err.Error())
t.Fatal(err)
}
exDS := `example.net. 3600 IN DS 10771 14 4 (
@ -627,11 +605,11 @@ PrivateKey: WURgWHCcYIYUPWgeLmiPY2DJJk02vgrmTfitxgqcL4vwW7BOrbawVmVe0d9V94SR`
6df983d6 )`
rrDS, err := NewRR(exDS)
if err != nil {
t.Fatal(err.Error())
t.Fatal(err)
}
ourDS := rrDNSKEY.(*DNSKEY).ToDS(SHA384)
if !reflect.DeepEqual(ourDS, rrDS.(*DS)) {
t.Fatalf("DS record differs:\n%v\n%v\n", ourDS, rrDS.(*DS))
t.Fatalf("DS record differs:\n%v\n%v", ourDS, rrDS.(*DS))
}
exA := `www.example.net. 3600 IN A 192.0.2.1`
@ -642,11 +620,11 @@ PrivateKey: WURgWHCcYIYUPWgeLmiPY2DJJk02vgrmTfitxgqcL4vwW7BOrbawVmVe0d9V94SR`
WTSSPdz7wnqXL5bdcJzusdnI0RSMROxxwGipWcJm )`
rrA, err := NewRR(exA)
if err != nil {
t.Fatal(err.Error())
t.Fatal(err)
}
rrRRSIG, err := NewRR(exRRSIG)
if err != nil {
t.Fatal(err.Error())
t.Fatal(err)
}
if err = rrRRSIG.(*RRSIG).Verify(rrDNSKEY.(*DNSKEY), []RR{rrA}); err != nil {
t.Errorf("Failure to validate the spec RRSIG: %v", err)
@ -664,7 +642,7 @@ PrivateKey: WURgWHCcYIYUPWgeLmiPY2DJJk02vgrmTfitxgqcL4vwW7BOrbawVmVe0d9V94SR`
ourRRSIG.Inception, _ = StringToTime("20100812102025")
err = ourRRSIG.Sign(priv, []RR{rrA})
if err != nil {
t.Fatal(err.Error())
t.Fatal(err)
}
if err = ourRRSIG.Verify(rrDNSKEY.(*DNSKEY), []RR{rrA}); err != nil {
@ -675,6 +653,6 @@ PrivateKey: WURgWHCcYIYUPWgeLmiPY2DJJk02vgrmTfitxgqcL4vwW7BOrbawVmVe0d9V94SR`
rrRRSIG.(*RRSIG).Signature = ""
ourRRSIG.Signature = ""
if !reflect.DeepEqual(ourRRSIG, rrRRSIG.(*RRSIG)) {
t.Fatalf("RRSIG record differs:\n%v\n%v\n", ourRRSIG, rrRRSIG.(*RRSIG))
t.Fatalf("RRSIG record differs:\n%v\n%v", ourRRSIG, rrRRSIG.(*RRSIG))
}
}

247
Godeps/_workspace/src/github.com/miekg/dns/doc.go generated vendored Normal file
View File

@ -0,0 +1,247 @@
/*
Package dns implements a full featured interface to the Domain Name System.
Server- and client-side programming is supported.
The package allows complete control over what is send out to the DNS. The package
API follows the less-is-more principle, by presenting a small, clean interface.
The package dns supports (asynchronous) querying/replying, incoming/outgoing zone transfers,
TSIG, EDNS0, dynamic updates, notifies and DNSSEC validation/signing.
Note that domain names MUST be fully qualified, before sending them, unqualified
names in a message will result in a packing failure.
Resource records are native types. They are not stored in wire format.
Basic usage pattern for creating a new resource record:
r := new(dns.MX)
r.Hdr = dns.RR_Header{Name: "miek.nl.", Rrtype: dns.TypeMX, Class: dns.ClassINET, Ttl: 3600}
r.Preference = 10
r.Mx = "mx.miek.nl."
Or directly from a string:
mx, err := dns.NewRR("miek.nl. 3600 IN MX 10 mx.miek.nl.")
Or when the default TTL (3600) and class (IN) suit you:
mx, err := dns.NewRR("miek.nl. MX 10 mx.miek.nl.")
Or even:
mx, err := dns.NewRR("$ORIGIN nl.\nmiek 1H IN MX 10 mx.miek")
In the DNS messages are exchanged, these messages contain resource
records (sets). Use pattern for creating a message:
m := new(dns.Msg)
m.SetQuestion("miek.nl.", dns.TypeMX)
Or when not certain if the domain name is fully qualified:
m.SetQuestion(dns.Fqdn("miek.nl"), dns.TypeMX)
The message m is now a message with the question section set to ask
the MX records for the miek.nl. zone.
The following is slightly more verbose, but more flexible:
m1 := new(dns.Msg)
m1.Id = dns.Id()
m1.RecursionDesired = true
m1.Question = make([]dns.Question, 1)
m1.Question[0] = dns.Question{"miek.nl.", dns.TypeMX, dns.ClassINET}
After creating a message it can be send.
Basic use pattern for synchronous querying the DNS at a
server configured on 127.0.0.1 and port 53:
c := new(dns.Client)
in, rtt, err := c.Exchange(m1, "127.0.0.1:53")
Suppressing
multiple outstanding queries (with the same question, type and class) is as easy as setting:
c.SingleInflight = true
If these "advanced" features are not needed, a simple UDP query can be send,
with:
in, err := dns.Exchange(m1, "127.0.0.1:53")
When this functions returns you will get dns message. 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.
Each of these sections (except the Question section) contain a []RR. Basic
use pattern for accessing the rdata of a TXT RR as the first RR in
the Answer section:
if t, ok := in.Answer[0].(*dns.TXT); ok {
// do something with t.Txt
}
Domain Name and TXT Character String Representations
Both domain names and TXT character strings are converted to presentation
form both when unpacked and when converted to strings.
For TXT character strings, tabs, carriage returns and line feeds will be
converted to \t, \r and \n respectively. Back slashes and quotations marks
will be escaped. Bytes below 32 and above 127 will be converted to \DDD
form.
For domain names, in addition to the above rules brackets, periods,
spaces, semicolons and the at symbol are escaped.
DNSSEC
DNSSEC (DNS Security Extension) adds a layer of security to the DNS. It
uses public key cryptography to sign resource records. The
public keys are stored in DNSKEY records and the signatures in RRSIG records.
Requesting DNSSEC information for a zone is done by adding the DO (DNSSEC OK) bit
to an request.
m := new(dns.Msg)
m.SetEdns0(4096, true)
Signature generation, signature verification and key generation are all supported.
DYNAMIC UPDATES
Dynamic updates reuses the DNS message format, but renames three of
the sections. Question is Zone, Answer is Prerequisite, Authority is
Update, only the Additional is not renamed. See RFC 2136 for the gory details.
You can set a rather complex set of rules for the existence of absence of
certain resource records or names in a zone to specify if resource records
should be added or removed. The table from RFC 2136 supplemented with the Go
DNS function shows which functions exist to specify the prerequisites.
3.2.4 - Table Of Metavalues Used In Prerequisite Section
CLASS TYPE RDATA Meaning Function
--------------------------------------------------------------
ANY ANY empty Name is in use dns.NameUsed
ANY rrset empty RRset exists (value indep) dns.RRsetUsed
NONE ANY empty Name is not in use dns.NameNotUsed
NONE rrset empty RRset does not exist dns.RRsetNotUsed
zone rrset rr RRset exists (value dep) dns.Used
The prerequisite section can also be left empty.
If you have decided on the prerequisites you can tell what RRs should
be added or deleted. The next table shows the options you have and
what functions to call.
3.4.2.6 - Table Of Metavalues Used In Update Section
CLASS TYPE RDATA Meaning Function
---------------------------------------------------------------
ANY ANY empty Delete all RRsets from name dns.RemoveName
ANY rrset empty Delete an RRset dns.RemoveRRset
NONE rrset rr Delete an RR from RRset dns.Remove
zone rrset rr Add to an RRset dns.Insert
TRANSACTION SIGNATURE
An TSIG or transaction signature adds a HMAC TSIG record to each message sent.
The supported algorithms include: HmacMD5, HmacSHA1, HmacSHA256 and HmacSHA512.
Basic use pattern when querying with a TSIG name "axfr." (note that these key names
must be fully qualified - as they are domain names) and the base64 secret
"so6ZGir4GPAqINNh9U5c3A==":
c := new(dns.Client)
c.TsigSecret = map[string]string{"axfr.": "so6ZGir4GPAqINNh9U5c3A=="}
m := new(dns.Msg)
m.SetQuestion("miek.nl.", dns.TypeMX)
m.SetTsig("axfr.", dns.HmacMD5, 300, time.Now().Unix())
...
// When sending the TSIG RR is calculated and filled in before sending
When requesting an zone transfer (almost all TSIG usage is when requesting zone transfers), with
TSIG, this is the basic use pattern. In this example we request an AXFR for
miek.nl. with TSIG key named "axfr." and secret "so6ZGir4GPAqINNh9U5c3A=="
and using the server 176.58.119.54:
t := new(dns.Transfer)
m := new(dns.Msg)
t.TsigSecret = map[string]string{"axfr.": "so6ZGir4GPAqINNh9U5c3A=="}
m.SetAxfr("miek.nl.")
m.SetTsig("axfr.", dns.HmacMD5, 300, time.Now().Unix())
c, err := t.In(m, "176.58.119.54:53")
for r := range c { ... }
You can now read the records from the transfer as they come in. Each envelope is checked with TSIG.
If something is not correct an error is returned.
Basic use pattern validating and replying to a message that has TSIG set.
server := &dns.Server{Addr: ":53", Net: "udp"}
server.TsigSecret = map[string]string{"axfr.": "so6ZGir4GPAqINNh9U5c3A=="}
go server.ListenAndServe()
dns.HandleFunc(".", handleRequest)
func handleRequest(w dns.ResponseWriter, r *dns.Msg) {
m := new(Msg)
m.SetReply(r)
if r.IsTsig() {
if w.TsigStatus() == nil {
// *Msg r has an TSIG record and it was validated
m.SetTsig("axfr.", dns.HmacMD5, 300, time.Now().Unix())
} else {
// *Msg r has an TSIG records and it was not valided
}
}
w.WriteMsg(m)
}
PRIVATE RRS
RFC 6895 sets aside a range of type codes for private use. This range
is 65,280 - 65,534 (0xFF00 - 0xFFFE). When experimenting with new Resource Records these
can be used, before requesting an official type code from IANA.
EDNS0
EDNS0 is an extension mechanism for the DNS defined in RFC 2671 and updated
by RFC 6891. It defines an new RR type, the OPT RR, which is then completely
abused.
Basic use pattern for creating an (empty) OPT RR:
o := new(dns.OPT)
o.Hdr.Name = "." // MUST be the root zone, per definition.
o.Hdr.Rrtype = dns.TypeOPT
The rdata of an OPT RR consists out of a slice of EDNS0 (RFC 6891)
interfaces. Currently only a few have been standardized: EDNS0_NSID
(RFC 5001) and EDNS0_SUBNET (draft-vandergaast-edns-client-subnet-02). Note
that these options may be combined in an OPT RR.
Basic use pattern for a server to check if (and which) options are set:
// o is a dns.OPT
for _, s := range o.Option {
switch e := s.(type) {
case *dns.EDNS0_NSID:
// do stuff with e.Nsid
case *dns.EDNS0_SUBNET:
// access e.Family, e.Address, etc.
}
}
SIG(0)
From RFC 2931:
SIG(0) provides protection for DNS transactions and requests ....
... protection for glue records, DNS requests, protection for message headers
on requests and responses, and protection of the overall integrity of a response.
It works like TSIG, except that SIG(0) uses public key cryptography, instead of the shared
secret approach in TSIG.
Supported algorithms: DSA, ECDSAP256SHA256, ECDSAP384SHA384, RSASHA1, RSASHA256 and
RSASHA512.
Signing subsequent messages in multi-message sessions is not implemented.
*/
package dns

View File

@ -1,29 +1,3 @@
// EDNS0
//
// EDNS0 is an extension mechanism for the DNS defined in RFC 2671 and updated
// by RFC 6891. It defines an new RR type, the OPT RR, which is then completely
// abused.
// Basic use pattern for creating an (empty) OPT RR:
//
// o := new(dns.OPT)
// o.Hdr.Name = "." // MUST be the root zone, per definition.
// o.Hdr.Rrtype = dns.TypeOPT
//
// The rdata of an OPT RR consists out of a slice of EDNS0 (RFC 6891)
// interfaces. Currently only a few have been standardized: EDNS0_NSID
// (RFC 5001) and EDNS0_SUBNET (draft-vandergaast-edns-client-subnet-02). Note
// that these options may be combined in an OPT RR.
// Basic use pattern for a server to check if (and which) options are set:
//
// // o is a dns.OPT
// for _, s := range o.Option {
// switch e := s.(type) {
// case *dns.EDNS0_NSID:
// // do stuff with e.Nsid
// case *dns.EDNS0_SUBNET:
// // access e.Family, e.Address, etc.
// }
// }
package dns
import (
@ -44,9 +18,13 @@ const (
EDNS0SUBNET = 0x8 // client-subnet (RFC6891)
EDNS0EXPIRE = 0x9 // EDNS0 expire
EDNS0SUBNETDRAFT = 0x50fa // Don't use! Use EDNS0SUBNET
EDNS0LOCALSTART = 0xFDE9 // Beginning of range reserved for local/experimental use (RFC6891)
EDNS0LOCALEND = 0xFFFE // End of range reserved for local/experimental use (RFC6891)
_DO = 1 << 15 // dnssec ok
)
// OPT is the EDNS0 RR appended to messages to convey extra (meta) information.
// See RFC 6891.
type OPT struct {
Hdr RR_Header
Option []EDNS0 `dns:"opt"`
@ -92,6 +70,8 @@ func (rr *OPT) String() string {
s += "\n; DS HASH UNDERSTOOD: " + o.String()
case *EDNS0_N3U:
s += "\n; NSEC3 HASH UNDERSTOOD: " + o.String()
case *EDNS0_LOCAL:
s += "\n; LOCAL OPT: " + o.String()
}
}
return s
@ -100,8 +80,9 @@ func (rr *OPT) String() string {
func (rr *OPT) len() int {
l := rr.Hdr.len()
for i := 0; i < len(rr.Option); i++ {
l += 4 // Account for 2-byte option code and 2-byte option length.
lo, _ := rr.Option[i].pack()
l += 2 + len(lo)
l += len(lo)
}
return l
}
@ -499,3 +480,44 @@ func (e *EDNS0_EXPIRE) unpack(b []byte) error {
e.Expire = uint32(b[0])<<24 | uint32(b[1])<<16 | uint32(b[2])<<8 | uint32(b[3])
return nil
}
// The local EDNS0 option is used for local/experimental purposes. The option
// code is recommended to be within the range [EDNS0LOCALSTART, EDNS0LOCALEND]
// (RFC6891), although any unassigned code can actually be used. The content of
// the option is made available in Data, unaltered.
// Basic use pattern for creating a local option:
//
// o := new(dns.OPT)
// o.Hdr.Name = "."
// o.Hdr.Rrtype = dns.TypeOPT
// e := new(dns.EDNS0_LOCAL)
// e.Code = dns.EDNS0LOCALSTART
// e.Data = []byte{72, 82, 74}
// o.Option = append(o.Option, e)
type EDNS0_LOCAL struct {
Code uint16
Data []byte
}
func (e *EDNS0_LOCAL) Option() uint16 { return e.Code }
func (e *EDNS0_LOCAL) String() string {
return strconv.FormatInt(int64(e.Code), 10) + ":0x" + hex.EncodeToString(e.Data)
}
func (e *EDNS0_LOCAL) pack() ([]byte, error) {
b := make([]byte, len(e.Data))
copied := copy(b, e.Data)
if copied != len(e.Data) {
return nil, ErrBuf
}
return b, nil
}
func (e *EDNS0_LOCAL) unpack(b []byte) error {
e.Data = make([]byte, len(b))
copied := copy(e.Data, b)
if copied != len(b) {
return ErrBuf
}
return nil
}

View File

@ -216,8 +216,9 @@ func decode(b []byte) []byte {
}
out := make([]rune, 0, len(b))
b = b[len(_PREFIX):]
for pos, x := range b {
if x == _DELIMITER {
for pos := len(b) - 1; pos >= 0; pos-- {
// only last delimiter is our interest
if b[pos] == _DELIMITER {
out = append(out, bytes.Runes(b[:pos])...)
b = b[pos+1:] // trim source string
break

View File

@ -9,10 +9,12 @@ var testcases = [][2]string{
{"", ""},
{"a", "a"},
{"A-B", "a-b"},
{"A-B-C", "a-b-c"},
{"AbC", "abc"},
{"я", "xn--41a"},
{"zя", "xn--z-0ub"},
{"ЯZ", "xn--z-zub"},
{"а-я", "xn----7sb8g"},
{"إختبار", "xn--kgbechtv"},
{"آزمایشی", "xn--hgbk6aj7f53bba"},
{"测试", "xn--0zwm56d"},
@ -24,6 +26,7 @@ var testcases = [][2]string{
{"טעסט", "xn--deba0ad"},
{"テスト", "xn--zckzah"},
{"பரிட்சை", "xn--hlcj6aya9esc7a"},
{"mamão-com-açúcar", "xn--mamo-com-acar-yeb1e6q"},
}
func TestEncodeDecodePunycode(t *testing.T) {

View File

@ -13,34 +13,27 @@ func TestCompareDomainName(t *testing.T) {
s6 := "miek.nl"
if CompareDomainName(s1, s2) != 2 {
t.Logf("%s with %s should be %d", s1, s2, 2)
t.Fail()
t.Errorf("%s with %s should be %d", s1, s2, 2)
}
if CompareDomainName(s1, s3) != 1 {
t.Logf("%s with %s should be %d", s1, s3, 1)
t.Fail()
t.Errorf("%s with %s should be %d", s1, s3, 1)
}
if CompareDomainName(s3, s4) != 0 {
t.Logf("%s with %s should be %d", s3, s4, 0)
t.Fail()
t.Errorf("%s with %s should be %d", s3, s4, 0)
}
// Non qualified tests
if CompareDomainName(s1, s5) != 1 {
t.Logf("%s with %s should be %d", s1, s5, 1)
t.Fail()
t.Errorf("%s with %s should be %d", s1, s5, 1)
}
if CompareDomainName(s1, s6) != 2 {
t.Logf("%s with %s should be %d", s1, s5, 2)
t.Fail()
t.Errorf("%s with %s should be %d", s1, s5, 2)
}
if CompareDomainName(s1, ".") != 0 {
t.Logf("%s with %s should be %d", s1, s5, 0)
t.Fail()
t.Errorf("%s with %s should be %d", s1, s5, 0)
}
if CompareDomainName(".", ".") != 0 {
t.Logf("%s with %s should be %d", ".", ".", 0)
t.Fail()
t.Errorf("%s with %s should be %d", ".", ".", 0)
}
}
@ -59,10 +52,9 @@ func TestSplit(t *testing.T) {
}
for s, i := range splitter {
if x := len(Split(s)); x != i {
t.Logf("labels should be %d, got %d: %s %v\n", i, x, s, Split(s))
t.Fail()
t.Errorf("labels should be %d, got %d: %s %v", i, x, s, Split(s))
} else {
t.Logf("%s %v\n", s, Split(s))
t.Logf("%s %v", s, Split(s))
}
}
}
@ -78,13 +70,11 @@ func TestSplit2(t *testing.T) {
switch len(i) {
case 1:
if x[0] != i[0] {
t.Logf("labels should be %v, got %v: %s\n", i, x, s)
t.Fail()
t.Errorf("labels should be %v, got %v: %s", i, x, s)
}
default:
if x[0] != i[0] || x[1] != i[1] || x[2] != i[2] {
t.Logf("labels should be %v, got %v: %s\n", i, x, s)
t.Fail()
t.Errorf("labels should be %v, got %v: %s", i, x, s)
}
}
}
@ -113,8 +103,7 @@ func TestPrevLabel(t *testing.T) {
for s, i := range prever {
x, ok := PrevLabel(s.string, s.int)
if i != x {
t.Logf("label should be %d, got %d, %t: preving %d, %s\n", i, x, ok, s.int, s.string)
t.Fail()
t.Errorf("label should be %d, got %d, %t: preving %d, %s", i, x, ok, s.int, s.string)
}
}
}
@ -129,8 +118,7 @@ func TestCountLabel(t *testing.T) {
for s, i := range splitter {
x := CountLabel(s)
if x != i {
t.Logf("CountLabel should have %d, got %d\n", i, x)
t.Fail()
t.Errorf("CountLabel should have %d, got %d", i, x)
}
}
}
@ -149,14 +137,12 @@ domainLoop:
for domain, splits := range labels {
parts := SplitDomainName(domain)
if len(parts) != len(splits) {
t.Logf("SplitDomainName returned %v for %s, expected %v", parts, domain, splits)
t.Fail()
t.Errorf("SplitDomainName returned %v for %s, expected %v", parts, domain, splits)
continue domainLoop
}
for i := range parts {
if parts[i] != splits[i] {
t.Logf("SplitDomainName returned %v for %s, expected %v", parts, domain, splits)
t.Fail()
t.Errorf("SplitDomainName returned %v for %s, expected %v", parts, domain, splits)
continue domainLoop
}
}
@ -180,9 +166,8 @@ func TestIsDomainName(t *testing.T) {
for d, ok := range names {
l, k := IsDomainName(d)
if ok.ok != k || ok.lab != l {
t.Logf(" got %v %d for %s ", k, l, d)
t.Logf("have %v %d for %s ", ok.ok, ok.lab, d)
t.Fail()
t.Errorf(" got %v %d for %s ", k, l, d)
t.Errorf("have %v %d for %s ", ok.ok, ok.lab, d)
}
}
}

View File

@ -23,29 +23,40 @@ import (
const maxCompressionOffset = 2 << 13 // We have 14 bits for the compression pointer
var (
ErrAlg error = &Error{err: "bad algorithm"}
ErrAuth error = &Error{err: "bad authentication"}
ErrBuf error = &Error{err: "buffer size too small"}
ErrConnEmpty error = &Error{err: "conn has no connection"}
ErrConn error = &Error{err: "conn holds both UDP and TCP connection"}
// ErrAlg indicates an error with the (DNSSEC) algorithm.
ErrAlg error = &Error{err: "bad algorithm"}
// ErrAuth indicates an error in the TSIG authentication.
ErrAuth error = &Error{err: "bad authentication"}
// ErrBuf indicates that the buffer used it too small for the message.
ErrBuf error = &Error{err: "buffer size too small"}
// ErrConn indicates that a connection has both a TCP and UDP socket.
ErrConn error = &Error{err: "conn holds both UDP and TCP connection"}
// ErrConnEmpty indicates a connection is being uses before it is initialized.
ErrConnEmpty error = &Error{err: "conn has no connection"}
// ErrExtendedRcode ...
ErrExtendedRcode error = &Error{err: "bad extended rcode"}
ErrFqdn error = &Error{err: "domain must be fully qualified"}
ErrId error = &Error{err: "id mismatch"}
ErrKeyAlg error = &Error{err: "bad key algorithm"}
ErrKey error = &Error{err: "bad key"}
ErrKeySize error = &Error{err: "bad key size"}
ErrNoSig error = &Error{err: "no signature found"}
ErrPrivKey error = &Error{err: "bad private key"}
ErrRcode error = &Error{err: "bad rcode"}
ErrRdata error = &Error{err: "bad rdata"}
ErrRRset error = &Error{err: "bad rrset"}
ErrSecret error = &Error{err: "no secrets defined"}
ErrServ error = &Error{err: "no servers could be reached"}
ErrShortRead error = &Error{err: "short read"}
ErrSig error = &Error{err: "bad signature"}
ErrSigGen error = &Error{err: "bad signature generation"}
ErrSoa error = &Error{err: "no SOA"}
ErrTime error = &Error{err: "bad time"}
// ErrFqdn indicates that a domain name does not have a closing dot.
ErrFqdn error = &Error{err: "domain must be fully qualified"}
// ErrId indicates there is a mismatch with the message's ID.
ErrId error = &Error{err: "id mismatch"}
ErrKeyAlg error = &Error{err: "bad key algorithm"}
ErrKey error = &Error{err: "bad key"}
ErrKeySize error = &Error{err: "bad key size"}
ErrNoSig error = &Error{err: "no signature found"}
ErrPrivKey error = &Error{err: "bad private key"}
ErrRcode error = &Error{err: "bad rcode"}
ErrRdata error = &Error{err: "bad rdata"}
ErrRRset error = &Error{err: "bad rrset"}
ErrSecret error = &Error{err: "no secrets defined"}
ErrShortRead error = &Error{err: "short read"}
// ErrSig indicates that a signature can not be cryptographically validated.
ErrSig error = &Error{err: "bad signature"}
// ErrSigGen indicates a faulure to generate a signature.
ErrSigGen error = &Error{err: "bad signature generation"}
// ErrSOA indicates that no SOA RR was seen when doing zone transfers.
ErrSoa error = &Error{err: "no SOA"}
// ErrTime indicates a timing error in TSIG authentication.
ErrTime error = &Error{err: "bad time"}
)
// Id, by default, returns a 16 bits random number to be used as a
@ -56,8 +67,7 @@ var (
// dns.Id = func() uint16 { return 3 }
var Id func() uint16 = id
// A manually-unpacked version of (id, bits).
// This is in its own struct for easy printing.
// MsgHdr is a a manually-unpacked version of (id, bits).
type MsgHdr struct {
Id uint16
Response bool
@ -72,7 +82,7 @@ type MsgHdr struct {
Rcode int
}
// The layout of a DNS message.
// Msg contains the layout of a DNS message.
type Msg struct {
MsgHdr
Compress bool `json:"-"` // If true, the message will be compressed when converted to wire format. This not part of the official DNS packet format.
@ -82,7 +92,7 @@ type Msg struct {
Extra []RR // Holds the RR(s) of the additional section.
}
// Map of strings for each RR wire type.
// TypeToString is a map of strings for each RR wire type.
var TypeToString = map[uint16]string{
TypeA: "A",
TypeAAAA: "AAAA",
@ -161,8 +171,10 @@ var TypeToString = map[uint16]string{
TypeX25: "X25",
}
// Reverse, needed for string parsing.
// StringToType is the reverse of TypeToString, needed for string parsing.
var StringToType = reverseInt16(TypeToString)
// StringToClass is the reverse of ClassToString, needed for string parsing.
var StringToClass = reverseInt16(ClassToString)
// Map of opcodes strings.
@ -171,7 +183,7 @@ var StringToOpcode = reverseInt(OpcodeToString)
// Map of rcodes strings.
var StringToRcode = reverseInt(RcodeToString)
// Map of strings for each CLASS wire type.
// ClassToString is a maps Classes to strings for each CLASS wire type.
var ClassToString = map[uint16]string{
ClassINET: "IN",
ClassCSNET: "CS",
@ -181,7 +193,7 @@ var ClassToString = map[uint16]string{
ClassANY: "ANY",
}
// Map of strings for opcodes.
// OpcodeToString maps Opcodes to strings.
var OpcodeToString = map[int]string{
OpcodeQuery: "QUERY",
OpcodeIQuery: "IQUERY",
@ -190,7 +202,7 @@ var OpcodeToString = map[int]string{
OpcodeUpdate: "UPDATE",
}
// Map of strings for rcodes.
// RcodeToString maps Rcodes to strings.
var RcodeToString = map[int]string{
RcodeSuccess: "NOERROR",
RcodeFormatError: "FORMERR",
@ -264,7 +276,7 @@ func packDomainName(s string, msg []byte, off int, compression map[string]int, c
// Emit sequence of counted strings, chopping at dots.
begin := 0
bs := []byte(s)
ro_bs, bs_fresh, escaped_dot := s, true, false
roBs, bsFresh, escapedDot := s, true, false
for i := 0; i < ls; i++ {
if bs[i] == '\\' {
for j := i; j < ls-1; j++ {
@ -288,13 +300,13 @@ func packDomainName(s string, msg []byte, off int, compression map[string]int, c
} else if bs[i] == 'n' {
bs[i] = '\n'
}
escaped_dot = bs[i] == '.'
bs_fresh = false
escapedDot = bs[i] == '.'
bsFresh = false
continue
}
if bs[i] == '.' {
if i > 0 && bs[i-1] == '.' && !escaped_dot {
if i > 0 && bs[i-1] == '.' && !escapedDot {
// two dots back to back is not legal
return lenmsg, labels, ErrRdata
}
@ -320,16 +332,16 @@ func packDomainName(s string, msg []byte, off int, compression map[string]int, c
}
off++
}
if compress && !bs_fresh {
ro_bs = string(bs)
bs_fresh = true
if compress && !bsFresh {
roBs = string(bs)
bsFresh = true
}
// Dont try to compress '.'
if compress && ro_bs[begin:] != "." {
if p, ok := compression[ro_bs[begin:]]; !ok {
if compress && roBs[begin:] != "." {
if p, ok := compression[roBs[begin:]]; !ok {
// Only offsets smaller than this can be used.
if offset < maxCompressionOffset {
compression[ro_bs[begin:]] = offset
compression[roBs[begin:]] = offset
}
} else {
// The first hit is the longest matching dname
@ -348,7 +360,7 @@ func packDomainName(s string, msg []byte, off int, compression map[string]int, c
labels++
begin = i + 1
}
escaped_dot = false
escapedDot = false
}
// Root label is special
if len(bs) == 1 && bs[0] == '.' {
@ -945,7 +957,7 @@ func unpackStructValue(val reflect.Value, msg []byte, off int) (off1 int, err er
return lenmsg, &Error{"bad tag unpacking slice: " + val.Type().Field(i).Tag.Get("dns")}
case `dns:"domain-name"`:
// HIP record slice of name (or none)
servers := make([]string, 0)
var servers []string
var s string
for off < lenrd {
s, off, err = UnpackDomainName(msg, off)
@ -971,7 +983,7 @@ func unpackStructValue(val reflect.Value, msg []byte, off int) (off1 int, err er
// We can safely return here.
break
}
edns := make([]EDNS0, 0)
var edns []EDNS0
Option:
code := uint16(0)
if off+2 > lenmsg {
@ -1036,7 +1048,12 @@ func unpackStructValue(val reflect.Value, msg []byte, off int) (off1 int, err er
edns = append(edns, e)
off = off1 + int(optlen)
default:
// do nothing?
e := new(EDNS0_LOCAL)
e.Code = code
if err := e.unpack(msg[off1 : off1+int(optlen)]); err != nil {
return lenmsg, err
}
edns = append(edns, e)
off = off1 + int(optlen)
}
if off < lenrd {
@ -1077,7 +1094,7 @@ func unpackStructValue(val reflect.Value, msg []byte, off int) (off1 int, err er
off += net.IPv6len
case `dns:"wks"`:
// Rest of the record is the bitmap
serv := make([]uint16, 0)
var serv []uint16
j := 0
for off < lenrd {
if off+1 > lenmsg {
@ -1121,7 +1138,7 @@ func unpackStructValue(val reflect.Value, msg []byte, off int) (off1 int, err er
if off+2 > lenrd || off+2 > lenmsg {
return lenmsg, &Error{err: "overflow unpacking nsecx"}
}
nsec := make([]uint16, 0)
var nsec []uint16
length := 0
window := 0
for off+2 < lenrd {
@ -1903,7 +1920,11 @@ func Copy(r RR) RR {
// Copy returns a new *Msg which is a deep-copy of dns.
func (dns *Msg) Copy() *Msg {
r1 := new(Msg)
return dns.CopyTo(new(Msg))
}
// CopyTo copies the contents to the provided message using a deep-copy and returns the copy.
func (dns *Msg) CopyTo(r1 *Msg) *Msg {
r1.MsgHdr = dns.MsgHdr
r1.Compress = dns.Compress
@ -1912,25 +1933,34 @@ func (dns *Msg) Copy() *Msg {
copy(r1.Question, dns.Question) // TODO(miek): Question is an immutable value, ok to do a shallow-copy
}
rrArr := make([]RR, len(dns.Answer)+len(dns.Ns)+len(dns.Extra))
var rri int
if len(dns.Answer) > 0 {
r1.Answer = make([]RR, len(dns.Answer))
rrbegin := rri
for i := 0; i < len(dns.Answer); i++ {
r1.Answer[i] = dns.Answer[i].copy()
rrArr[rri] = dns.Answer[i].copy()
rri++
}
r1.Answer = rrArr[rrbegin:rri:rri]
}
if len(dns.Ns) > 0 {
r1.Ns = make([]RR, len(dns.Ns))
rrbegin := rri
for i := 0; i < len(dns.Ns); i++ {
r1.Ns[i] = dns.Ns[i].copy()
rrArr[rri] = dns.Ns[i].copy()
rri++
}
r1.Ns = rrArr[rrbegin:rri:rri]
}
if len(dns.Extra) > 0 {
r1.Extra = make([]RR, len(dns.Extra))
rrbegin := rri
for i := 0; i < len(dns.Extra); i++ {
r1.Extra[i] = dns.Extra[i].copy()
rrArr[rri] = dns.Extra[i].copy()
rri++
}
r1.Extra = rrArr[rrbegin:rri:rri]
}
return r1

View File

@ -50,6 +50,8 @@ func HashName(label string, ha uint8, iter uint16, salt string) string {
return toBase32(nsec3)
}
// Denialer is an interface that should be implemented by types that are used to denial
// answers in DNSSEC.
type Denialer interface {
// Cover will check if the (unhashed) name is being covered by this NSEC or NSEC3.
Cover(name string) bool

View File

@ -7,14 +7,12 @@ import (
func TestPackNsec3(t *testing.T) {
nsec3 := HashName("dnsex.nl.", SHA1, 0, "DEAD")
if nsec3 != "ROCCJAE8BJJU7HN6T7NG3TNM8ACRS87J" {
t.Logf("%v\n", nsec3)
t.Fail()
t.Error(nsec3)
}
nsec3 = HashName("a.b.c.example.org.", SHA1, 2, "DEAD")
if nsec3 != "6LQ07OAHBTOOEU2R9ANI2AT70K5O0RCG" {
t.Logf("%v\n", nsec3)
t.Fail()
t.Error(nsec3)
}
}
@ -22,12 +20,10 @@ func TestNsec3(t *testing.T) {
// examples taken from .nl
nsec3, _ := NewRR("39p91242oslggest5e6a7cci4iaeqvnk.nl. IN NSEC3 1 1 5 F10E9F7EA83FC8F3 39P99DCGG0MDLARTCRMCF6OFLLUL7PR6 NS DS RRSIG")
if !nsec3.(*NSEC3).Cover("snasajsksasasa.nl.") { // 39p94jrinub66hnpem8qdpstrec86pg3
t.Logf("39p94jrinub66hnpem8qdpstrec86pg3. should be covered by 39p91242oslggest5e6a7cci4iaeqvnk.nl. - 39P99DCGG0MDLARTCRMCF6OFLLUL7PR6")
t.Fail()
t.Error("39p94jrinub66hnpem8qdpstrec86pg3. should be covered by 39p91242oslggest5e6a7cci4iaeqvnk.nl. - 39P99DCGG0MDLARTCRMCF6OFLLUL7PR6")
}
nsec3, _ = NewRR("sk4e8fj94u78smusb40o1n0oltbblu2r.nl. IN NSEC3 1 1 5 F10E9F7EA83FC8F3 SK4F38CQ0ATIEI8MH3RGD0P5I4II6QAN NS SOA TXT RRSIG DNSKEY NSEC3PARAM")
if !nsec3.(*NSEC3).Match("nl.") { // sk4e8fj94u78smusb40o1n0oltbblu2r.nl.
t.Logf("sk4e8fj94u78smusb40o1n0oltbblu2r.nl. should match sk4e8fj94u78smusb40o1n0oltbblu2r.nl.")
t.Fail()
t.Error("sk4e8fj94u78smusb40o1n0oltbblu2r.nl. should match sk4e8fj94u78smusb40o1n0oltbblu2r.nl.")
}
}

View File

@ -20,19 +20,16 @@ func TestDotInName(t *testing.T) {
PackDomainName("aa\\.bb.nl.", buf, 0, nil, false)
// index 3 must be a real dot
if buf[3] != '.' {
t.Log("dot should be a real dot")
t.Fail()
t.Error("dot should be a real dot")
}
if buf[6] != 2 {
t.Log("this must have the value 2")
t.Fail()
t.Error("this must have the value 2")
}
dom, _, _ := UnpackDomainName(buf, 0)
// printing it should yield the backspace again
if dom != "aa\\.bb.nl." {
t.Log("dot should have been escaped: " + dom)
t.Fail()
t.Error("dot should have been escaped: ", dom)
}
}
@ -41,7 +38,7 @@ func TestDotLastInLabel(t *testing.T) {
buf := make([]byte, 20)
_, err := PackDomainName(sample, buf, 0, nil, false)
if err != nil {
t.Fatalf("unexpected error packing domain: %s", err)
t.Fatalf("unexpected error packing domain: %v", err)
}
dom, _, _ := UnpackDomainName(buf, 0)
if dom != sample {
@ -52,19 +49,17 @@ func TestDotLastInLabel(t *testing.T) {
func TestTooLongDomainName(t *testing.T) {
l := "aaabbbcccdddeeefffggghhhiiijjjkkklllmmmnnnooopppqqqrrrsssttt."
dom := l + l + l + l + l + l + l
_, e := NewRR(dom + " IN A 127.0.0.1")
if e == nil {
t.Log("should be too long")
t.Fail()
_, err := NewRR(dom + " IN A 127.0.0.1")
if err == nil {
t.Error("should be too long")
} else {
t.Logf("error is %s", e.Error())
t.Logf("error is %v", err)
}
_, e = NewRR("..com. IN A 127.0.0.1")
if e == nil {
t.Log("should fail")
t.Fail()
_, err = NewRR("..com. IN A 127.0.0.1")
if err == nil {
t.Error("should fail")
} else {
t.Logf("error is %s", e.Error())
t.Logf("error is %v", err)
}
}
@ -76,19 +71,16 @@ func TestDomainName(t *testing.T) {
for _, ts := range tests {
if _, err := PackDomainName(ts, dbuff, 0, nil, false); err != nil {
t.Log("not a valid domain name")
t.Fail()
t.Error("not a valid domain name")
continue
}
n, _, err := UnpackDomainName(dbuff, 0)
if err != nil {
t.Log("failed to unpack packed domain name")
t.Fail()
t.Error("failed to unpack packed domain name")
continue
}
if ts != n {
t.Logf("must be equal: in: %s, out: %s\n", ts, n)
t.Fail()
t.Errorf("must be equal: in: %s, out: %s", ts, n)
}
}
}
@ -110,26 +102,23 @@ func TestDomainNameAndTXTEscapes(t *testing.T) {
s := rr1.String()
rr2, err := NewRR(s)
if err != nil {
t.Logf("Error parsing unpacked RR's string: %v", err)
t.Logf(" Bytes: %v\n", rrbytes)
t.Logf("String: %v\n", s)
t.Fail()
t.Errorf("Error parsing unpacked RR's string: %v", err)
t.Errorf(" Bytes: %v", rrbytes)
t.Errorf("String: %v", s)
}
repacked := make([]byte, len(rrbytes))
if _, err := PackRR(rr2, repacked, 0, nil, false); err != nil {
t.Logf("error packing parsed RR: %v", err)
t.Logf(" original Bytes: %v\n", rrbytes)
t.Logf("unpacked Struct: %V\n", rr1)
t.Logf(" parsed Struct: %V\n", rr2)
t.Fail()
t.Errorf("error packing parsed RR: %v", err)
t.Errorf(" original Bytes: %v", rrbytes)
t.Errorf("unpacked Struct: %v", rr1)
t.Errorf(" parsed Struct: %v", rr2)
}
if !bytes.Equal(repacked, rrbytes) {
t.Log("packed bytes don't match original bytes")
t.Logf(" original bytes: %v", rrbytes)
t.Logf(" packed bytes: %v", repacked)
t.Logf("unpacked struct: %V", rr1)
t.Logf(" parsed struct: %V", rr2)
t.Fail()
t.Error("packed bytes don't match original bytes")
t.Errorf(" original bytes: %v", rrbytes)
t.Errorf(" packed bytes: %v", repacked)
t.Errorf("unpacked struct: %v", rr1)
t.Errorf(" parsed struct: %v", rr2)
}
}
}
@ -206,16 +195,16 @@ func TestDomainQuick(t *testing.T) {
buf := make([]byte, 255)
off, err := PackDomainName(ds, buf, 0, nil, false)
if err != nil {
t.Logf("error packing domain: %s", err.Error())
t.Logf(" bytes: %v\n", db)
t.Logf("string: %v\n", ds)
t.Errorf("error packing domain: %v", err)
t.Errorf(" bytes: %v", db)
t.Errorf("string: %v", ds)
return false
}
if !bytes.Equal(db, buf[:off]) {
t.Logf("repacked domain doesn't match original:")
t.Logf("src bytes: %v", db)
t.Logf(" string: %v", ds)
t.Logf("out bytes: %v", buf[:off])
t.Errorf("repacked domain doesn't match original:")
t.Errorf("src bytes: %v", db)
t.Errorf(" string: %v", ds)
t.Errorf("out bytes: %v", buf[:off])
return false
}
return true
@ -248,7 +237,13 @@ func GenerateTXT(r *rand.Rand, size int) []byte {
return rd
}
func TestTXTRRQuick(t *testing.T) {
// Ok, 2 things. 1) this test breaks with the new functionality of splitting up larger txt
// chunks into 255 byte pieces. 2) I don't like the random nature of this thing, because I can't
// place the quotes where they need to be.
// So either add some code the places the quotes in just the right spots, make this non random
// or do something else.
// Disabled for now. (miek)
func testTXTRRQuick(t *testing.T) {
s := rand.NewSource(0)
r := rand.New(s)
typeAndClass := []byte{
@ -272,15 +267,15 @@ func TestTXTRRQuick(t *testing.T) {
buf := make([]byte, len(rrbytes)*3)
off, err := PackRR(rr, buf, 0, nil, false)
if err != nil {
t.Logf("pack Error: %s\nRR: %V", err.Error(), rr)
t.Errorf("pack Error: %v\nRR: %v", err, rr)
return false
}
buf = buf[:off]
if !bytes.Equal(buf, rrbytes) {
t.Logf("packed bytes don't match original bytes")
t.Logf("src bytes: %v", rrbytes)
t.Logf(" struct: %V", rr)
t.Logf("oUt bytes: %v", buf)
t.Errorf("packed bytes don't match original bytes")
t.Errorf("src bytes: %v", rrbytes)
t.Errorf(" struct: %v", rr)
t.Errorf("out bytes: %v", buf)
return false
}
if len(rdata) == 0 {
@ -290,35 +285,35 @@ func TestTXTRRQuick(t *testing.T) {
rrString := rr.String()
rr2, err := NewRR(rrString)
if err != nil {
t.Logf("error parsing own output: %s", err.Error())
t.Logf("struct: %V", rr)
t.Logf("string: %v", rrString)
t.Errorf("error parsing own output: %v", err)
t.Errorf("struct: %v", rr)
t.Errorf("string: %v", rrString)
return false
}
if rr2.String() != rrString {
t.Logf("parsed rr.String() doesn't match original string")
t.Logf("original: %v", rrString)
t.Logf(" parsed: %v", rr2.String())
t.Errorf("parsed rr.String() doesn't match original string")
t.Errorf("original: %v", rrString)
t.Errorf(" parsed: %v", rr2.String())
return false
}
buf = make([]byte, len(rrbytes)*3)
off, err = PackRR(rr2, buf, 0, nil, false)
if err != nil {
t.Logf("error packing parsed rr: %s", err.Error())
t.Logf("unpacked Struct: %V", rr)
t.Logf(" string: %v", rrString)
t.Logf(" parsed Struct: %V", rr2)
t.Errorf("error packing parsed rr: %v", err)
t.Errorf("unpacked Struct: %v", rr)
t.Errorf(" string: %v", rrString)
t.Errorf(" parsed Struct: %v", rr2)
return false
}
buf = buf[:off]
if !bytes.Equal(buf, rrbytes) {
t.Logf("parsed packed bytes don't match original bytes")
t.Logf(" source bytes: %v", rrbytes)
t.Logf("unpacked struct: %V", rr)
t.Logf(" string: %v", rrString)
t.Logf(" parsed struct: %V", rr2)
t.Logf(" repacked bytes: %v", buf)
t.Errorf("parsed packed bytes don't match original bytes")
t.Errorf(" source bytes: %v", rrbytes)
t.Errorf("unpacked struct: %v", rr)
t.Errorf(" string: %v", rrString)
t.Errorf(" parsed struct: %v", rr2)
t.Errorf(" repacked bytes: %v", buf)
return false
}
return true
@ -345,15 +340,13 @@ func TestParseDirectiveMisc(t *testing.T) {
"ONE.MY-ROOTS.NET. 3600000 IN A 192.168.1.1": "ONE.MY-ROOTS.NET.\t3600000\tIN\tA\t192.168.1.1",
}
for i, o := range tests {
rr, e := NewRR(i)
if e != nil {
t.Log("failed to parse RR: " + e.Error())
t.Fail()
rr, err := NewRR(i)
if err != nil {
t.Error("failed to parse RR: ", err)
continue
}
if rr.String() != o {
t.Logf("`%s' should be equal to\n`%s', but is `%s'\n", i, o, rr.String())
t.Fail()
t.Errorf("`%s' should be equal to\n`%s', but is `%s'", i, o, rr.String())
} else {
t.Logf("RR is OK: `%s'", rr.String())
}
@ -369,15 +362,13 @@ func TestNSEC(t *testing.T) {
"localhost.dnssex.nl. IN NSEC www.dnssex.nl. A RRSIG NSec Type65534": "localhost.dnssex.nl.\t3600\tIN\tNSEC\twww.dnssex.nl. A RRSIG NSEC TYPE65534",
}
for i, o := range nsectests {
rr, e := NewRR(i)
if e != nil {
t.Log("failed to parse RR: " + e.Error())
t.Fail()
rr, err := NewRR(i)
if err != nil {
t.Error("failed to parse RR: ", err)
continue
}
if rr.String() != o {
t.Logf("`%s' should be equal to\n`%s', but is `%s'\n", i, o, rr.String())
t.Fail()
t.Errorf("`%s' should be equal to\n`%s', but is `%s'", i, o, rr.String())
} else {
t.Logf("RR is OK: `%s'", rr.String())
}
@ -390,15 +381,13 @@ func TestParseLOC(t *testing.T) {
"SW1A2AA.find.me.uk. LOC 51 0 0.0 N 00 07 39.611 W 0.00m 0.00m 0.00m 0.00m": "SW1A2AA.find.me.uk.\t3600\tIN\tLOC\t51 00 0.000 N 00 07 39.611 W 0m 0.00m 0.00m 0.00m",
}
for i, o := range lt {
rr, e := NewRR(i)
if e != nil {
t.Log("failed to parse RR: " + e.Error())
t.Fail()
rr, err := NewRR(i)
if err != nil {
t.Error("failed to parse RR: ", err)
continue
}
if rr.String() != o {
t.Logf("`%s' should be equal to\n`%s', but is `%s'\n", i, o, rr.String())
t.Fail()
t.Errorf("`%s' should be equal to\n`%s', but is `%s'", i, o, rr.String())
} else {
t.Logf("RR is OK: `%s'", rr.String())
}
@ -410,15 +399,13 @@ func TestParseDS(t *testing.T) {
"example.net. 3600 IN DS 40692 12 3 22261A8B0E0D799183E35E24E2AD6BB58533CBA7E3B14D659E9CA09B 2071398F": "example.net.\t3600\tIN\tDS\t40692 12 3 22261A8B0E0D799183E35E24E2AD6BB58533CBA7E3B14D659E9CA09B2071398F",
}
for i, o := range dt {
rr, e := NewRR(i)
if e != nil {
t.Log("failed to parse RR: " + e.Error())
t.Fail()
rr, err := NewRR(i)
if err != nil {
t.Error("failed to parse RR: ", err)
continue
}
if rr.String() != o {
t.Logf("`%s' should be equal to\n`%s', but is `%s'\n", i, o, rr.String())
t.Fail()
t.Errorf("`%s' should be equal to\n`%s', but is `%s'", i, o, rr.String())
} else {
t.Logf("RR is OK: `%s'", rr.String())
}
@ -446,15 +433,13 @@ func TestQuotes(t *testing.T) {
"cid.urn.arpa. NAPTR 100 10 \"\" \"\" \"/urn:cid:.+@([^\\.]+\\.)(.*)$/\\2/i\" .": "cid.urn.arpa.\t3600\tIN\tNAPTR\t100 10 \"\" \"\" \"/urn:cid:.+@([^\\.]+\\.)(.*)$/\\2/i\" .",
}
for i, o := range tests {
rr, e := NewRR(i)
if e != nil {
t.Log("failed to parse RR: " + e.Error())
t.Fail()
rr, err := NewRR(i)
if err != nil {
t.Error("failed to parse RR: ", err)
continue
}
if rr.String() != o {
t.Logf("`%s' should be equal to\n`%s', but is\n`%s'\n", i, o, rr.String())
t.Fail()
t.Errorf("`%s' should be equal to\n`%s', but is\n`%s'", i, o, rr.String())
} else {
t.Logf("RR is OK: `%s'", rr.String())
}
@ -471,15 +456,13 @@ func TestParseClass(t *testing.T) {
"t.example.com. NONE A 127.0.0.1": "t.example.com. 3600 NONE A 127.0.0.1",
}
for i, o := range tests {
rr, e := NewRR(i)
if e != nil {
t.Log("failed to parse RR: " + e.Error())
t.Fail()
rr, err := NewRR(i)
if err != nil {
t.Error("failed to parse RR: ", err)
continue
}
if rr.String() != o {
t.Logf("`%s' should be equal to\n`%s', but is\n`%s'\n", i, o, rr.String())
t.Fail()
t.Errorf("`%s' should be equal to\n`%s', but is\n`%s'", i, o, rr.String())
} else {
t.Logf("RR is OK: `%s'", rr.String())
}
@ -524,15 +507,13 @@ func TestBrace(t *testing.T) {
)`: "miek.nl.\t86400\tIN\tSOA\telektron.atoom.net. miekg.atoom.net. 2009032802 21600 7200 604800 3600",
}
for i, o := range tests {
rr, e := NewRR(i)
if e != nil {
t.Log("failed to parse RR: " + e.Error() + "\n\t" + i)
t.Fail()
rr, err := NewRR(i)
if err != nil {
t.Errorf("failed to parse RR: %v\n\t%s", err, i)
continue
}
if rr.String() != o {
t.Logf("`%s' should be equal to\n`%s', but is `%s'\n", i, o, rr.String())
t.Fail()
t.Errorf("`%s' should be equal to\n`%s', but is `%s'", i, o, rr.String())
} else {
t.Logf("RR is OK: `%s'", rr.String())
}
@ -555,8 +536,7 @@ func TestParseFailure(t *testing.T) {
for _, s := range tests {
_, err := NewRR(s)
if err == nil {
t.Logf("should have triggered an error: \"%s\"", s)
t.Fail()
t.Errorf("should have triggered an error: \"%s\"", s)
}
}
}
@ -577,11 +557,10 @@ test IN CNAME test.a.example.com.
for x := range to {
i++
if x.Error != nil {
t.Logf("%s\n", x.Error)
t.Fail()
t.Error(x.Error)
continue
}
t.Logf("%s\n", x.RR)
t.Log(x.RR)
}
delta := time.Now().UnixNano() - start
t.Logf("%d RRs parsed in %.2f s (%.2f RR/s)", i, float32(delta)/1e9, float32(i)/(float32(delta)/1e9))
@ -625,7 +604,7 @@ moutamassey NS ns01.yahoodomains.jp.
`
to := ParseZone(strings.NewReader(zone), "", "testzone")
for x := range to {
fmt.Printf("%s\n", x.RR)
fmt.Println(x.RR)
}
// Output:
// name. 3600 IN SOA a6.nstld.com. hostmaster.nic.name. 203362132 300 300 1209600 300
@ -658,7 +637,7 @@ func ExampleHIP() {
b1slImA8YVJyuIDsj7kwzG7jnERNqnWxZ48AWkskmdHaVDP4BcelrTI3rMXdXF5D
rvs.example.com. )`
if hip, err := NewRR(h); err == nil {
fmt.Printf("%s\n", hip.String())
fmt.Println(hip.String())
}
// Output:
// www.example.com. 3600 IN HIP 2 200100107B1A74DF365639CC39F1D578 AwEAAbdxyhNuSutc5EMzxTs9LBPCIkOFH8cIvM4p9+LrV4e19WzK00+CI6zBCQTdtWsuxKbWIy87UOoJTwkUs7lBu+Upr1gsNrut79ryra+bSRGQb1slImA8YVJyuIDsj7kwzG7jnERNqnWxZ48AWkskmdHaVDP4BcelrTI3rMXdXF5D rvs.example.com.
@ -673,30 +652,30 @@ b1slImA8YVJyuIDsj7kwzG7jnERNqnWxZ48AWkskmdHaVDP4BcelrTI3rMXdXF5D
rvs2.example.com. )`
rr, err := NewRR(h)
if err != nil {
t.Fatalf("failed to parse RR: %s", err)
t.Fatalf("failed to parse RR: %v", err)
}
t.Logf("RR: %s", rr)
msg := new(Msg)
msg.Answer = []RR{rr, rr}
bytes, err := msg.Pack()
if err != nil {
t.Fatalf("failed to pack msg: %s", err)
t.Fatalf("failed to pack msg: %v", err)
}
if err := msg.Unpack(bytes); err != nil {
t.Fatalf("failed to unpack msg: %s", err)
t.Fatalf("failed to unpack msg: %v", err)
}
if len(msg.Answer) != 2 {
t.Fatalf("2 answers expected: %V", msg)
t.Fatalf("2 answers expected: %v", msg)
}
for i, rr := range msg.Answer {
rr := rr.(*HIP)
t.Logf("RR: %s", rr)
if l := len(rr.RendezvousServers); l != 2 {
t.Fatalf("2 servers expected, only %d in record %d:\n%V", l, i, msg)
t.Fatalf("2 servers expected, only %d in record %d:\n%v", l, i, msg)
}
for j, s := range []string{"rvs1.example.com.", "rvs2.example.com."} {
if rr.RendezvousServers[j] != s {
t.Fatalf("expected server %d of record %d to be %s:\n%V", j, i, s, msg)
t.Fatalf("expected server %d of record %d to be %s:\n%v", j, i, s, msg)
}
}
}
@ -705,7 +684,7 @@ b1slImA8YVJyuIDsj7kwzG7jnERNqnWxZ48AWkskmdHaVDP4BcelrTI3rMXdXF5D
func ExampleSOA() {
s := "example.com. 1000 SOA master.example.com. admin.example.com. 1 4294967294 4294967293 4294967295 100"
if soa, err := NewRR(s); err == nil {
fmt.Printf("%s\n", soa.String())
fmt.Println(soa.String())
}
// Output:
// example.com. 1000 IN SOA master.example.com. admin.example.com. 1 4294967294 4294967293 4294967295 100
@ -715,8 +694,7 @@ func TestLineNumberError(t *testing.T) {
s := "example.com. 1000 SOA master.example.com. admin.example.com. monkey 4294967294 4294967293 4294967295 100"
if _, err := NewRR(s); err != nil {
if err.Error() != "dns: bad SOA zone parameter: \"monkey\" at line: 1:68" {
t.Logf("not expecting this error: " + err.Error())
t.Fail()
t.Error("not expecting this error: ", err)
}
}
}
@ -733,15 +711,13 @@ func TestLineNumberError2(t *testing.T) {
`example.com 1000 IN TALINK ( a.example.com. b...example.com.
)`: "dns: bad TALINK NextName: \"b...example.com.\" at line: 2:1"}
for in, err := range tests {
_, e := NewRR(in)
if e == nil {
t.Fail()
for in, errStr := range tests {
_, err := NewRR(in)
if err == nil {
t.Error("err is nil")
} else {
if e.Error() != err {
t.Logf("%s\n", in)
t.Logf("error should be %s is %s\n", err, e.Error())
t.Fail()
if err.Error() != errStr {
t.Errorf("%s: error should be %s is %v", in, errStr, err)
}
}
}
@ -756,8 +732,7 @@ func TestRfc1982(t *testing.T) {
strtests := []string{"20120525134203", "19700101000000", "20380119031408"}
for _, v := range strtests {
if x, _ := StringToTime(v); v != TimeToString(x) {
t.Logf("1982 arithmetic string failure %s (%s:%d)", v, TimeToString(x), x)
t.Fail()
t.Errorf("1982 arithmetic string failure %s (%s:%d)", v, TimeToString(x), x)
}
}
@ -767,8 +742,7 @@ func TestRfc1982(t *testing.T) {
}
for i, v := range inttests {
if TimeToString(i) != v {
t.Logf("1982 arithmetic int failure %d:%s (%s)", i, v, TimeToString(i))
t.Fail()
t.Errorf("1982 arithmetic int failure %d:%s (%s)", i, v, TimeToString(i))
}
}
@ -785,16 +759,14 @@ func TestRfc1982(t *testing.T) {
x, _ := StringToTime(from)
y := TimeToString(x)
if y != to {
t.Logf("1982 arithmetic future failure %s:%s (%s)", from, to, y)
t.Fail()
t.Errorf("1982 arithmetic future failure %s:%s (%s)", from, to, y)
}
}
}
func TestEmpty(t *testing.T) {
for _ = range ParseZone(strings.NewReader(""), "", "") {
t.Logf("should be empty")
t.Fail()
t.Errorf("should be empty")
}
}
@ -819,7 +791,7 @@ func TestLowercaseTokens(t *testing.T) {
for _, testrr := range testrecords {
_, err := NewRR(testrr)
if err != nil {
t.Errorf("failed to parse %#v, got %s", testrr, err.Error())
t.Errorf("failed to parse %#v, got %v", testrr, err)
}
}
}
@ -830,7 +802,7 @@ func ExampleGenerate() {
to := ParseZone(strings.NewReader(zone), "0.0.192.IN-ADDR.ARPA.", "")
for x := range to {
if x.Error == nil {
fmt.Printf("%s\n", x.RR.String())
fmt.Println(x.RR.String())
}
}
// Output:
@ -881,25 +853,25 @@ func TestSRVPacking(t *testing.T) {
_, err := msg.Pack()
if err != nil {
t.Fatalf("couldn't pack %v\n", msg)
t.Fatalf("couldn't pack %v: %v", msg, err)
}
}
func TestParseBackslash(t *testing.T) {
if r, e := NewRR("nul\\000gap.test.globnix.net. 600 IN A 192.0.2.10"); e != nil {
t.Fatalf("could not create RR with \\000 in it")
if r, err := NewRR("nul\\000gap.test.globnix.net. 600 IN A 192.0.2.10"); err != nil {
t.Errorf("could not create RR with \\000 in it")
} else {
t.Logf("parsed %s\n", r.String())
t.Logf("parsed %s", r.String())
}
if r, e := NewRR(`nul\000gap.test.globnix.net. 600 IN TXT "Hello\123"`); e != nil {
t.Fatalf("could not create RR with \\000 in it")
if r, err := NewRR(`nul\000gap.test.globnix.net. 600 IN TXT "Hello\123"`); err != nil {
t.Errorf("could not create RR with \\000 in it")
} else {
t.Logf("parsed %s\n", r.String())
t.Logf("parsed %s", r.String())
}
if r, e := NewRR(`m\ @\ iek.nl. IN 3600 A 127.0.0.1`); e != nil {
t.Fatalf("could not create RR with \\ and \\@ in it")
if r, err := NewRR(`m\ @\ iek.nl. IN 3600 A 127.0.0.1`); err != nil {
t.Errorf("could not create RR with \\ and \\@ in it")
} else {
t.Logf("parsed %s\n", r.String())
t.Logf("parsed %s", r.String())
}
}
@ -919,9 +891,9 @@ func TestILNP(t *testing.T) {
"host1.example.com.\t3600\tIN\tLP\t20 l32-subnet1.example.com.",
}
for _, t1 := range tests {
r, e := NewRR(t1)
if e != nil {
t.Fatalf("an error occured: %s\n", e.Error())
r, err := NewRR(t1)
if err != nil {
t.Fatalf("an error occurred: %v", err)
} else {
if t1 != r.String() {
t.Fatalf("strings should be equal %s %s", t1, r.String())
@ -941,15 +913,13 @@ func TestNsapGposEidNimloc(t *testing.T) {
"VAXA. IN EID 3141592653589793": "VAXA.\t3600\tIN\tEID\t3141592653589793",
}
for i, o := range dt {
rr, e := NewRR(i)
if e != nil {
t.Log("failed to parse RR: " + e.Error())
t.Fail()
rr, err := NewRR(i)
if err != nil {
t.Error("failed to parse RR: ", err)
continue
}
if rr.String() != o {
t.Logf("`%s' should be equal to\n`%s', but is `%s'\n", i, o, rr.String())
t.Fail()
t.Errorf("`%s' should be equal to\n`%s', but is `%s'", i, o, rr.String())
} else {
t.Logf("RR is OK: `%s'", rr.String())
}
@ -962,15 +932,13 @@ func TestPX(t *testing.T) {
"ab.net2.it. IN PX 10 ab.net2.it. O-ab.PRMD-net2.ADMDb.C-it.": "ab.net2.it.\t3600\tIN\tPX\t10 ab.net2.it. O-ab.PRMD-net2.ADMDb.C-it.",
}
for i, o := range dt {
rr, e := NewRR(i)
if e != nil {
t.Log("failed to parse RR: " + e.Error())
t.Fail()
rr, err := NewRR(i)
if err != nil {
t.Error("failed to parse RR: ", err)
continue
}
if rr.String() != o {
t.Logf("`%s' should be equal to\n`%s', but is `%s'\n", i, o, rr.String())
t.Fail()
t.Errorf("`%s' should be equal to\n`%s', but is `%s'", i, o, rr.String())
} else {
t.Logf("RR is OK: `%s'", rr.String())
}
@ -1004,8 +972,7 @@ foo. IN TXT "THIS IS TEXT MAN"; this is comment 8
if x.Error == nil {
if x.Comment != "" {
if _, ok := comments[x.Comment]; !ok {
t.Logf("wrong comment %s", x.Comment)
t.Fail()
t.Errorf("wrong comment %s", x.Comment)
}
}
}
@ -1018,14 +985,12 @@ func TestEUIxx(t *testing.T) {
"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()
r, err := NewRR(i)
if err != nil {
t.Errorf("failed to parse %s: %v", i, err)
}
if r.String() != o {
t.Logf("want %s, got %s\n", o, r.String())
t.Fail()
t.Errorf("want %s, got %s", o, r.String())
}
}
}
@ -1037,14 +1002,12 @@ func TestUserRR(t *testing.T) {
"host.example. IN UINFO \"Miek Gieben\"": "host.example.\t3600\tIN\tUINFO\t\"Miek Gieben\"",
}
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()
r, err := NewRR(i)
if err != nil {
t.Errorf("failed to parse %s: %v", i, err)
}
if r.String() != o {
t.Logf("want %s, got %s\n", o, r.String())
t.Fail()
t.Errorf("want %s, got %s", o, r.String())
}
}
}
@ -1109,30 +1072,42 @@ func TestTXT(t *testing.T) {
t.Error("bad size of serialized record:", rr.len())
}
}
// Test TXT record with chunk larger than 255 bytes, they should be split up, by the parser
s := ""
for i := 0; i < 255; i++ {
s += "a"
}
s += "b"
rr, err = NewRR(`test.local. 60 IN TXT "` + s + `"`)
if err != nil {
t.Error("failed to parse empty-string TXT record", err)
}
if rr.(*TXT).Txt[1] != "b" {
t.Errorf("Txt should have two chunk, last one my be 'b', but is %s", rr.(*TXT).Txt[1])
}
t.Log(rr.String())
}
func TestTypeXXXX(t *testing.T) {
_, err := NewRR("example.com IN TYPE1234 \\# 4 aabbccdd")
if err != nil {
t.Logf("failed to parse TYPE1234 RR: %s", err.Error())
t.Fail()
t.Errorf("failed to parse TYPE1234 RR: %v", err)
}
_, err = NewRR("example.com IN TYPE655341 \\# 8 aabbccddaabbccdd")
if err == nil {
t.Logf("this should not work, for TYPE655341")
t.Fail()
t.Errorf("this should not work, for TYPE655341")
}
_, err = NewRR("example.com IN TYPE1 \\# 4 0a000001")
if err == nil {
t.Logf("this should not work")
t.Fail()
t.Errorf("this should not work")
}
}
func TestPTR(t *testing.T) {
_, err := NewRR("144.2.0.192.in-addr.arpa. 900 IN PTR ilouse03146p0\\(.example.com.")
if err != nil {
t.Error("failed to parse ", err.Error())
t.Error("failed to parse ", err)
}
}
@ -1147,13 +1122,13 @@ func TestDigit(t *testing.T) {
"miek\\004.nl. 100 IN TXT \"A\"": 4,
}
for s, i := range tests {
r, e := NewRR(s)
r, err := NewRR(s)
buf := make([]byte, 40)
if e != nil {
t.Fatalf("failed to parse %s\n", e.Error())
if err != nil {
t.Fatalf("failed to parse %v", err)
}
PackRR(r, buf, 0, nil, false)
t.Logf("%v\n", buf)
t.Log(buf)
if buf[5] != i {
t.Fatalf("5 pos must be %d, is %d", i, buf[5])
}
@ -1169,11 +1144,10 @@ func TestParseRRSIGTimestamp(t *testing.T) {
`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())
for r := range tests {
_, err := NewRR(r)
if err != nil {
t.Error(err)
}
}
}
@ -1184,11 +1158,10 @@ func TestTxtEqual(t *testing.T) {
rr1.Txt = []string{"a\"a", "\"", "b"}
rr2, _ := NewRR(rr1.String())
if rr1.String() != rr2.String() {
t.Logf("these two TXT records should match")
t.Logf("\n%s\n%s\n", rr1.String(), rr2.String())
t.Fail() // This is not an error, but keep this test.
// This is not an error, but keep this test.
t.Errorf("these two TXT records should match:\n%s\n%s", rr1.String(), rr2.String())
}
t.Logf("\n%s\n%s\n", rr1.String(), rr2.String())
t.Logf("%s\n%s", rr1.String(), rr2.String())
}
func TestTxtLong(t *testing.T) {
@ -1202,8 +1175,7 @@ func TestTxtLong(t *testing.T) {
}
str := rr1.String()
if len(str) < len(rr1.Txt[0]) {
t.Logf("string conversion should work")
t.Fail()
t.Error("string conversion should work")
}
}
@ -1217,7 +1189,7 @@ func TestMalformedPackets(t *testing.T) {
for _, packet := range packets {
data, _ := hex.DecodeString(packet)
// for _, v := range data {
// t.Logf("%s ", string(v))
// t.Log(v)
// }
var msg Msg
msg.Unpack(data)
@ -1253,15 +1225,14 @@ func TestNewPrivateKey(t *testing.T) {
key.Algorithm = algo.name
privkey, err := key.Generate(algo.bits)
if err != nil {
t.Fatal(err.Error())
t.Fatal(err)
}
newPrivKey, err := key.NewPrivateKey(key.PrivateKeyString(privkey))
if err != nil {
t.Log(key.String())
t.Log(key.PrivateKeyString(privkey))
t.Fatal(err.Error())
t.Error(key.String())
t.Error(key.PrivateKeyString(privkey))
t.Fatal(err)
}
switch newPrivKey := newPrivKey.(type) {
@ -1270,7 +1241,7 @@ func TestNewPrivateKey(t *testing.T) {
}
if !reflect.DeepEqual(privkey, newPrivKey) {
t.Errorf("[%v] Private keys differ:\n%#v\n%#v\n", AlgorithmToString[algo.name], privkey, newPrivKey)
t.Errorf("[%v] Private keys differ:\n%#v\n%#v", AlgorithmToString[algo.name], privkey, newPrivKey)
}
}
}
@ -1286,7 +1257,7 @@ func TestNewRRSpecial(t *testing.T) {
rr, err = NewRR("; comment")
expect = ""
if err != nil {
t.Errorf("unexpected err: %s", err)
t.Errorf("unexpected err: %v", err)
}
if rr != nil {
t.Errorf("unexpected result: [%s] != [%s]", rr, expect)
@ -1295,7 +1266,7 @@ func TestNewRRSpecial(t *testing.T) {
rr, err = NewRR("")
expect = ""
if err != nil {
t.Errorf("unexpected err: %s", err)
t.Errorf("unexpected err: %v", err)
}
if rr != nil {
t.Errorf("unexpected result: [%s] != [%s]", rr, expect)
@ -1304,7 +1275,7 @@ func TestNewRRSpecial(t *testing.T) {
rr, err = NewRR("$ORIGIN foo.")
expect = ""
if err != nil {
t.Errorf("unexpected err: %s", err)
t.Errorf("unexpected err: %v", err)
}
if rr != nil {
t.Errorf("unexpected result: [%s] != [%s]", rr, expect)
@ -1313,7 +1284,7 @@ func TestNewRRSpecial(t *testing.T) {
rr, err = NewRR(" ")
expect = ""
if err != nil {
t.Errorf("unexpected err: %s", err)
t.Errorf("unexpected err: %v", err)
}
if rr != nil {
t.Errorf("unexpected result: [%s] != [%s]", rr, expect)
@ -1322,7 +1293,7 @@ func TestNewRRSpecial(t *testing.T) {
rr, err = NewRR("\n")
expect = ""
if err != nil {
t.Errorf("unexpected err: %s", err)
t.Errorf("unexpected err: %v", err)
}
if rr != nil {
t.Errorf("unexpected result: [%s] != [%s]", rr, expect)
@ -1331,7 +1302,7 @@ func TestNewRRSpecial(t *testing.T) {
rr, err = NewRR("foo. A 1.1.1.1\nbar. A 2.2.2.2")
expect = "foo.\t3600\tIN\tA\t1.1.1.1"
if err != nil {
t.Errorf("unexpected err: %s", err)
t.Errorf("unexpected err: %v", err)
}
if rr == nil || rr.String() != expect {
t.Errorf("unexpected result: [%s] != [%s]", rr, expect)
@ -1394,15 +1365,13 @@ func TestParseIPSECKEY(t *testing.T) {
for i := 0; i < len(tests)-1; i++ {
t1 := tests[i]
e1 := tests[i+1]
r, e := NewRR(t1)
if e != nil {
t.Logf("failed to parse IPSECKEY %s", e)
r, err := NewRR(t1)
if err != nil {
t.Errorf("failed to parse IPSECKEY %v", err)
continue
}
if r.String() != e1 {
t.Logf("these two IPSECKEY records should match")
t.Logf("\n%s\n%s\n", r.String(), e1)
t.Fail()
t.Errorf("these two IPSECKEY records should match:\n%s\n%s", r.String(), e1)
}
i++
}

View File

@ -1,10 +1,3 @@
/*
PRIVATE RR
RFC 6895 sets aside a range of type codes for private use. This range
is 65,280 - 65,534 (0xFF00 - 0xFFFE). When experimenting with new Resource Records these
can be used, before requesting an official type code from IANA.
*/
package dns
import (
@ -91,9 +84,9 @@ func PrivateHandle(rtypestr string, rtype uint16, generator func() PrivateRdata)
// TODO(miek): we could also be returning _QUOTE, this might or might not
// be an issue (basically parsing TXT becomes hard)
switch l = <-c; l.value {
case _NEWLINE, _EOF:
case zNewline, zEOF:
break FETCH
case _STRING:
case zString:
text = append(text, l.token)
}
}

View File

@ -1,9 +1,10 @@
package dns_test
import (
"github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/miekg/dns"
"strings"
"testing"
"github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/miekg/dns"
)
const TypeISBN uint16 = 0x0F01
@ -75,7 +76,7 @@ func TestPrivateByteSlice(t *testing.T) {
buf := make([]byte, 100)
off, err := dns.PackRR(rr, buf, 0, nil, false)
if err != nil {
t.Errorf("got error packing ISBN: %s", err)
t.Errorf("got error packing ISBN: %v", err)
}
custrr := rr.(*dns.PrivateRR)
@ -85,7 +86,7 @@ func TestPrivateByteSlice(t *testing.T) {
rr1, off1, err := dns.UnpackRR(buf[:off], 0)
if err != nil {
t.Errorf("got error unpacking ISBN: %s", err)
t.Errorf("got error unpacking ISBN: %v", err)
}
if off1 != off {

View File

@ -10,6 +10,7 @@ import (
"time"
)
// Handler is implemented by any value that implements ServeDNS.
type Handler interface {
ServeDNS(w ResponseWriter, r *Msg)
}
@ -44,7 +45,7 @@ type response struct {
tsigSecret map[string]string // the tsig secrets
udp *net.UDPConn // i/o connection if UDP was used
tcp *net.TCPConn // i/o connection if TCP was used
udpSession *sessionUDP // oob data to get egress interface right
udpSession *SessionUDP // oob data to get egress interface right
remoteAddr net.Addr // address of the client
}
@ -72,12 +73,12 @@ var DefaultServeMux = NewServeMux()
// Handler object that calls f.
type HandlerFunc func(ResponseWriter, *Msg)
// ServerDNS calls f(w, r)
// ServeDNS calls f(w, r).
func (f HandlerFunc) ServeDNS(w ResponseWriter, r *Msg) {
f(w, r)
}
// FailedHandler returns a HandlerFunc that returns SERVFAIL for every request it gets.
// HandleFailed returns a HandlerFunc that returns SERVFAIL for every request it gets.
func HandleFailed(w ResponseWriter, r *Msg) {
m := new(Msg)
m.SetRcode(r, RcodeServerFailure)
@ -121,10 +122,9 @@ func (mux *ServeMux) match(q string, t uint16) Handler {
if h, ok := mux.z[string(b[:l])]; ok { // 'causes garbage, might want to change the map key
if t != TypeDS {
return h
} else {
// Continue for DS to see if we have a parent too, if so delegeate to the parent
handler = h
}
// Continue for DS to see if we have a parent too, if so delegeate to the parent
handler = h
}
off, end = NextLabel(q, off)
if end {
@ -148,7 +148,7 @@ func (mux *ServeMux) Handle(pattern string, handler Handler) {
mux.m.Unlock()
}
// Handle adds a handler to the ServeMux for pattern.
// HandleFunc adds a handler function to the ServeMux for pattern.
func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Msg)) {
mux.Handle(pattern, HandlerFunc(handler))
}
@ -264,6 +264,7 @@ func (srv *Server) ListenAndServe() error {
if e != nil {
return e
}
srv.Listener = l
return srv.serveTCP(l)
case "udp", "udp4", "udp6":
a, e := net.ResolveUDPAddr(srv.Net, addr)
@ -277,6 +278,7 @@ func (srv *Server) ListenAndServe() error {
if e := setUDPSocketOptions(l); e != nil {
return e
}
srv.PacketConn = l
return srv.serveUDP(l)
}
return &Error{err: "bad network"}
@ -372,7 +374,7 @@ func (srv *Server) getReadTimeout() time.Duration {
}
// serveTCP starts a TCP listener for the server.
// Each request is handled in a seperate goroutine.
// Each request is handled in a separate goroutine.
func (srv *Server) serveTCP(l *net.TCPListener) error {
defer l.Close()
@ -407,7 +409,7 @@ func (srv *Server) serveTCP(l *net.TCPListener) error {
}
// serveUDP starts a UDP listener for the server.
// Each request is handled in a seperate goroutine.
// Each request is handled in a separate goroutine.
func (srv *Server) serveUDP(l *net.UDPConn) error {
defer l.Close()
@ -438,7 +440,7 @@ func (srv *Server) serveUDP(l *net.UDPConn) error {
}
// Serve a new connection.
func (srv *Server) serve(a net.Addr, h Handler, m []byte, u *net.UDPConn, s *sessionUDP, t *net.TCPConn) {
func (srv *Server) serve(a net.Addr, h Handler, m []byte, u *net.UDPConn, s *SessionUDP, t *net.TCPConn) {
w := &response{tsigSecret: srv.TsigSecret, udp: u, tcp: t, remoteAddr: a, udpSession: s}
q := 0
defer func() {
@ -537,10 +539,10 @@ func (srv *Server) readTCP(conn *net.TCPConn, timeout time.Duration) ([]byte, er
return m, nil
}
func (srv *Server) readUDP(conn *net.UDPConn, timeout time.Duration) ([]byte, *sessionUDP, error) {
func (srv *Server) readUDP(conn *net.UDPConn, timeout time.Duration) ([]byte, *SessionUDP, error) {
conn.SetReadDeadline(time.Now().Add(timeout))
m := make([]byte, srv.UDPSize)
n, s, e := readFromSessionUDP(conn, m)
n, s, e := ReadFromSessionUDP(conn, m)
if e != nil || n == 0 {
if e != nil {
return nil, nil, e
@ -576,7 +578,7 @@ func (w *response) WriteMsg(m *Msg) (err error) {
func (w *response) Write(m []byte) (int, error) {
switch {
case w.udp != nil:
n, err := writeToSessionUDP(w.udp, m, w.udpSession)
n, err := WriteToSessionUDP(w.udp, m, w.udpSession)
return n, err
case w.tcp != nil:
lm := len(m)

View File

@ -95,7 +95,7 @@ func TestServing(t *testing.T) {
s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
if err != nil {
t.Fatalf("Unable to run test server: %s", err)
t.Fatalf("Unable to run test server: %v", err)
}
defer s.Shutdown()
@ -104,38 +104,32 @@ func TestServing(t *testing.T) {
m.SetQuestion("miek.nl.", TypeTXT)
r, _, err := c.Exchange(m, addrstr)
if err != nil || len(r.Extra) == 0 {
t.Log("failed to exchange miek.nl", err)
t.Fatal()
t.Fatal("failed to exchange miek.nl", err)
}
txt := r.Extra[0].(*TXT).Txt[0]
if txt != "Hello world" {
t.Log("Unexpected result for miek.nl", txt, "!= Hello world")
t.Fail()
t.Error("Unexpected result for miek.nl", txt, "!= Hello world")
}
m.SetQuestion("example.com.", TypeTXT)
r, _, err = c.Exchange(m, addrstr)
if err != nil {
t.Log("failed to exchange example.com", err)
t.Fatal()
t.Fatal("failed to exchange example.com", err)
}
txt = r.Extra[0].(*TXT).Txt[0]
if txt != "Hello example" {
t.Log("Unexpected result for example.com", txt, "!= Hello example")
t.Fail()
t.Error("Unexpected result for example.com", txt, "!= Hello example")
}
// Test Mixes cased as noticed by Ask.
m.SetQuestion("eXaMplE.cOm.", TypeTXT)
r, _, err = c.Exchange(m, addrstr)
if err != nil {
t.Log("failed to exchange eXaMplE.cOm", err)
t.Fail()
t.Error("failed to exchange eXaMplE.cOm", err)
}
txt = r.Extra[0].(*TXT).Txt[0]
if txt != "Hello example" {
t.Log("Unexpected result for example.com", txt, "!= Hello example")
t.Fail()
t.Error("Unexpected result for example.com", txt, "!= Hello example")
}
}
@ -147,7 +141,7 @@ func BenchmarkServe(b *testing.B) {
s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
if err != nil {
b.Fatalf("Unable to run test server: %s", err)
b.Fatalf("Unable to run test server: %v", err)
}
defer s.Shutdown()
@ -169,7 +163,7 @@ func benchmarkServe6(b *testing.B) {
a := runtime.GOMAXPROCS(4)
s, addrstr, err := RunLocalUDPServer("[::1]:0")
if err != nil {
b.Fatalf("Unable to run test server: %s", err)
b.Fatalf("Unable to run test server: %v", err)
}
defer s.Shutdown()
@ -200,7 +194,7 @@ func BenchmarkServeCompress(b *testing.B) {
a := runtime.GOMAXPROCS(4)
s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
if err != nil {
b.Fatalf("Unable to run test server: %s", err)
b.Fatalf("Unable to run test server: %v", err)
}
defer s.Shutdown()
@ -301,7 +295,7 @@ func TestServingLargeResponses(t *testing.T) {
s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
if err != nil {
t.Fatalf("Unable to run test server: %s", err)
t.Fatalf("Unable to run test server: %v", err)
}
defer s.Shutdown()
@ -316,8 +310,7 @@ func TestServingLargeResponses(t *testing.T) {
M.Unlock()
_, _, err = c.Exchange(m, addrstr)
if err != nil {
t.Logf("failed to exchange: %s", err.Error())
t.Fail()
t.Errorf("failed to exchange: %v", err)
}
// This must fail
M.Lock()
@ -325,15 +318,13 @@ func TestServingLargeResponses(t *testing.T) {
M.Unlock()
_, _, err = c.Exchange(m, addrstr)
if err == nil {
t.Logf("failed to fail exchange, this should generate packet error")
t.Fail()
t.Error("failed to fail exchange, this should generate packet error")
}
// But this must work again
c.UDPSize = 7000
_, _, err = c.Exchange(m, addrstr)
if err != nil {
t.Logf("failed to exchange: %s", err.Error())
t.Fail()
t.Errorf("failed to exchange: %v", err)
}
}
@ -344,7 +335,7 @@ func TestServingResponse(t *testing.T) {
HandleFunc("miek.nl.", HelloServer)
s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
if err != nil {
t.Fatalf("Unable to run test server: %s", err)
t.Fatalf("Unable to run test server: %v", err)
}
c := new(Client)
@ -353,49 +344,46 @@ func TestServingResponse(t *testing.T) {
m.Response = false
_, _, err = c.Exchange(m, addrstr)
if err != nil {
t.Log("failed to exchange", err)
t.Fatal()
t.Fatal("failed to exchange", err)
}
m.Response = true
_, _, err = c.Exchange(m, addrstr)
if err == nil {
t.Log("exchanged response message")
t.Fatal()
t.Fatal("exchanged response message")
}
s.Shutdown()
s, addrstr, err = RunLocalUDPServerUnsafe("127.0.0.1:0")
if err != nil {
t.Fatalf("Unable to run test server: %s", err)
t.Fatalf("Unable to run test server: %v", err)
}
defer s.Shutdown()
m.Response = true
_, _, err = c.Exchange(m, addrstr)
if err != nil {
t.Log("could exchanged response message in Unsafe mode")
t.Fatal()
t.Fatal("could exchanged response message in Unsafe mode")
}
}
func TestShutdownTCP(t *testing.T) {
s, _, err := RunLocalTCPServer("127.0.0.1:0")
if err != nil {
t.Fatalf("Unable to run test server: %s", err)
t.Fatalf("Unable to run test server: %v", err)
}
err = s.Shutdown()
if err != nil {
t.Errorf("Could not shutdown test TCP server, %s", err)
t.Errorf("Could not shutdown test TCP server, %v", err)
}
}
func TestShutdownUDP(t *testing.T) {
s, _, err := RunLocalUDPServer("127.0.0.1:0")
if err != nil {
t.Fatalf("Unable to run test server: %s", err)
t.Fatalf("Unable to run test server: %v", err)
}
err = s.Shutdown()
if err != nil {
t.Errorf("Could not shutdown test UDP server, %s", err)
t.Errorf("Could not shutdown test UDP server, %v", err)
}
}

View File

@ -1,18 +1,3 @@
// SIG(0)
//
// From RFC 2931:
//
// SIG(0) provides protection for DNS transactions and requests ....
// ... protection for glue records, DNS requests, protection for message headers
// on requests and responses, and protection of the overall integrity of a response.
//
// It works like TSIG, except that SIG(0) uses public key cryptography, instead of the shared
// secret approach in TSIG.
// Supported algorithms: DSA, ECDSAP256SHA256, ECDSAP384SHA384, RSASHA1, RSASHA256 and
// RSASHA512.
//
// Signing subsequent messages in multi-message sessions is not implemented.
//
package dns
import (
@ -92,7 +77,7 @@ func (rr *SIG) Sign(k PrivateKey, m *Msg) ([]byte, error) {
buf[rdoff], buf[rdoff+1] = packUint16(rdlen)
// Adjust additional count
adc, _ := unpackUint16(buf, 10)
adc += 1
adc++
buf[10], buf[11] = packUint16(adc)
return buf, nil
}

View File

@ -27,8 +27,7 @@ func TestSIG0(t *testing.T) {
}
pk, err := keyrr.Generate(keysize)
if err != nil {
t.Logf("Failed to generate key for “%s”: %v", algstr, err)
t.Fail()
t.Errorf("Failed to generate key for “%s”: %v", algstr, err)
continue
}
now := uint32(time.Now().Unix())
@ -43,19 +42,16 @@ func TestSIG0(t *testing.T) {
sigrr.SignerName = keyrr.Hdr.Name
mb, err := sigrr.Sign(pk, m)
if err != nil {
t.Logf("Failed to sign message using “%s”: %v", algstr, err)
t.Fail()
t.Errorf("Failed to sign message using “%s”: %v", algstr, err)
continue
}
m := new(Msg)
if err := m.Unpack(mb); err != nil {
t.Logf("Failed to unpack message signed using “%s”: %v", algstr, err)
t.Fail()
t.Errorf("Failed to unpack message signed using “%s”: %v", algstr, err)
continue
}
if len(m.Extra) != 1 {
t.Logf("Missing SIG for message signed using “%s”", algstr)
t.Fail()
t.Errorf("Missing SIG for message signed using “%s”", algstr)
continue
}
var sigrrwire *SIG
@ -63,8 +59,7 @@ func TestSIG0(t *testing.T) {
case *SIG:
sigrrwire = rr
default:
t.Logf("Expected SIG RR, instead: %v", rr)
t.Fail()
t.Errorf("Expected SIG RR, instead: %v", rr)
continue
}
for _, rr := range []*SIG{sigrr, sigrrwire} {
@ -73,23 +68,20 @@ func TestSIG0(t *testing.T) {
id = "sigrrwire"
}
if err := rr.Verify(keyrr, mb); err != nil {
t.Logf("Failed to verify “%s” signed SIG(%s): %v", algstr, id, err)
t.Fail()
t.Errorf("Failed to verify “%s” signed SIG(%s): %v", algstr, id, err)
continue
}
}
mb[13]++
if err := sigrr.Verify(keyrr, mb); err == nil {
t.Logf("Verify succeeded on an altered message using “%s”", algstr)
t.Fail()
t.Errorf("Verify succeeded on an altered message using “%s”", algstr)
continue
}
sigrr.Expiration = 2
sigrr.Inception = 1
mb, _ = sigrr.Sign(pk, m)
if err := sigrr.Verify(keyrr, mb); err == nil {
t.Logf("Verify succeeded on an expired message using “%s”", algstr)
t.Fail()
t.Errorf("Verify succeeded on an expired message using “%s”", algstr)
continue
}
}

View File

@ -25,7 +25,8 @@ func CertificateToDANE(selector, matchingType uint8, cert *x509.Certificate) (st
h := sha256.New()
switch selector {
case 0:
return hex.EncodeToString(cert.Raw), nil
io.WriteString(h, string(cert.Raw))
return hex.EncodeToString(h.Sum(nil)), nil
case 1:
io.WriteString(h, string(cert.RawSubjectPublicKeyInfo))
return hex.EncodeToString(h.Sum(nil)), nil
@ -34,7 +35,8 @@ func CertificateToDANE(selector, matchingType uint8, cert *x509.Certificate) (st
h := sha512.New()
switch selector {
case 0:
return hex.EncodeToString(cert.Raw), nil
io.WriteString(h, string(cert.Raw))
return hex.EncodeToString(h.Sum(nil)), nil
case 1:
io.WriteString(h, string(cert.RawSubjectPublicKeyInfo))
return hex.EncodeToString(h.Sum(nil)), nil

View File

@ -1,56 +1,3 @@
// TRANSACTION SIGNATURE
//
// An TSIG or transaction signature adds a HMAC TSIG record to each message sent.
// The supported algorithms include: HmacMD5, HmacSHA1, HmacSHA256 and HmacSHA512.
//
// Basic use pattern when querying with a TSIG name "axfr." (note that these key names
// must be fully qualified - as they are domain names) and the base64 secret
// "so6ZGir4GPAqINNh9U5c3A==":
//
// c := new(dns.Client)
// c.TsigSecret = map[string]string{"axfr.": "so6ZGir4GPAqINNh9U5c3A=="}
// m := new(dns.Msg)
// m.SetQuestion("miek.nl.", dns.TypeMX)
// m.SetTsig("axfr.", dns.HmacMD5, 300, time.Now().Unix())
// ...
// // When sending the TSIG RR is calculated and filled in before sending
//
// When requesting an zone transfer (almost all TSIG usage is when requesting zone transfers), with
// TSIG, this is the basic use pattern. In this example we request an AXFR for
// miek.nl. with TSIG key named "axfr." and secret "so6ZGir4GPAqINNh9U5c3A=="
// and using the server 176.58.119.54:
//
// t := new(dns.Transfer)
// m := new(dns.Msg)
// t.TsigSecret = map[string]string{"axfr.": "so6ZGir4GPAqINNh9U5c3A=="}
// m.SetAxfr("miek.nl.")
// m.SetTsig("axfr.", dns.HmacMD5, 300, time.Now().Unix())
// 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.
// If something is not correct an error is returned.
//
// Basic use pattern validating and replying to a message that has TSIG set.
//
// server := &dns.Server{Addr: ":53", Net: "udp"}
// server.TsigSecret = map[string]string{"axfr.": "so6ZGir4GPAqINNh9U5c3A=="}
// go server.ListenAndServe()
// dns.HandleFunc(".", handleRequest)
//
// func handleRequest(w dns.ResponseWriter, r *dns.Msg) {
// m := new(Msg)
// m.SetReply(r)
// if r.IsTsig() {
// if w.TsigStatus() == nil {
// // *Msg r has an TSIG record and it was validated
// m.SetTsig("axfr.", dns.HmacMD5, 300, time.Now().Unix())
// } else {
// // *Msg r has an TSIG records and it was not valided
// }
// }
// w.WriteMsg(m)
// }
package dns
import (
@ -75,6 +22,8 @@ const (
HmacSHA512 = "hmac-sha512."
)
// TSIG is the RR the holds the transaction signature of a message.
// See RFC 2845 and RFC 4635.
type TSIG struct {
Hdr RR_Header
Algorithm string `dns:"domain-name"`

View File

@ -10,9 +10,12 @@ import (
)
type (
Type uint16 // Type is a DNS type.
Class uint16 // Class is a DNS class.
Name string // Name is a DNS domain name.
// Type is a DNS type.
Type uint16
// Class is a DNS class.
Class uint16
// Name is a DNS domain name.
Name string
)
// Packet formats
@ -20,6 +23,7 @@ type (
// Wire constants and supported types.
const (
// valid RR_Header.Rrtype and Question.qtype
TypeNone uint16 = 0
TypeA uint16 = 1
TypeNS uint16 = 2
@ -91,7 +95,9 @@ const (
TypeTKEY uint16 = 249
TypeTSIG uint16 = 250
// valid Question.Qtype only
TypeIXFR uint16 = 251
TypeAXFR uint16 = 252
TypeMAILB uint16 = 253
@ -105,6 +111,7 @@ const (
TypeReserved uint16 = 65535
// valid Question.Qclass
ClassINET = 1
ClassCSNET = 2
ClassCHAOS = 3
@ -113,6 +120,7 @@ const (
ClassANY = 255
// Msg.rcode
RcodeSuccess = 0
RcodeFormatError = 1
RcodeServerFailure = 2
@ -133,11 +141,11 @@ const (
RcodeBadAlg = 21
RcodeBadTrunc = 22 // TSIG
// Opcode
// Opcode, there is no 3
OpcodeQuery = 0
OpcodeIQuery = 1
OpcodeStatus = 2
// There is no 3
OpcodeNotify = 4
OpcodeUpdate = 5
)
@ -198,7 +206,8 @@ var CertTypeToString = map[uint16]string{
var StringToCertType = reverseInt16(CertTypeToString)
// DNS queries.
// Question holds a DNS question. There can be multiple questions in the
// question section of a message. Usually there is just one.
type Question struct {
Name string `dns:"cdomain-name"` // "cdomain-name" specifies encoding (and may be compressed)
Qtype uint16
@ -801,7 +810,7 @@ func cmToM(m, e uint8) string {
s := fmt.Sprintf("%d", m)
for e > 2 {
s += "0"
e -= 1
e--
}
return s
}
@ -838,7 +847,7 @@ func (rr *LOC) String() string {
lon = lon % LOC_HOURS
s += fmt.Sprintf("%02d %02d %0.3f %s ", h, m, (float64(lon) / 1000), ew)
var alt float64 = float64(rr.Altitude) / 100
var alt = float64(rr.Altitude) / 100
alt -= LOC_ALTITUDEBASE
if rr.Altitude%100 != 0 {
s += fmt.Sprintf("%.2fm ", alt)

View File

@ -7,12 +7,12 @@ import (
"syscall"
)
type sessionUDP struct {
type SessionUDP struct {
raddr *net.UDPAddr
context []byte
}
func (s *sessionUDP) RemoteAddr() net.Addr { return s.raddr }
func (s *SessionUDP) RemoteAddr() net.Addr { return s.raddr }
// setUDPSocketOptions sets the UDP socket options.
// This function is implemented on a per platform basis. See udp_*.go for more details
@ -37,19 +37,19 @@ func setUDPSocketOptions(conn *net.UDPConn) error {
return nil
}
// readFromSessionUDP acts just like net.UDPConn.ReadFrom(), but returns a session object instead of a
// ReadFromSessionUDP acts just like net.UDPConn.ReadFrom(), but returns a session object instead of a
// net.UDPAddr.
func readFromSessionUDP(conn *net.UDPConn, b []byte) (int, *sessionUDP, error) {
func ReadFromSessionUDP(conn *net.UDPConn, b []byte) (int, *SessionUDP, error) {
oob := make([]byte, 40)
n, oobn, _, raddr, err := conn.ReadMsgUDP(b, oob)
if err != nil {
return n, nil, err
}
return n, &sessionUDP{raddr, oob[:oobn]}, err
return n, &SessionUDP{raddr, oob[:oobn]}, err
}
// writeToSessionUDP acts just like net.UDPConn.WritetTo(), but uses a *sessionUDP instead of a net.Addr.
func writeToSessionUDP(conn *net.UDPConn, b []byte, session *sessionUDP) (int, error) {
// WriteToSessionUDP acts just like net.UDPConn.WritetTo(), but uses a *SessionUDP instead of a net.Addr.
func WriteToSessionUDP(conn *net.UDPConn, b []byte, session *SessionUDP) (int, error) {
n, _, err := conn.WriteMsgUDP(b, session.context, session.raddr)
return n, err
}

View File

@ -4,28 +4,28 @@ package dns
import "net"
type sessionUDP struct {
type SessionUDP struct {
raddr *net.UDPAddr
}
// readFromSessionUDP acts just like net.UDPConn.ReadFrom(), but returns a session object instead of a
// ReadFromSessionUDP acts just like net.UDPConn.ReadFrom(), but returns a session object instead of a
// net.UDPAddr.
func readFromSessionUDP(conn *net.UDPConn, b []byte) (int, *sessionUDP, error) {
func ReadFromSessionUDP(conn *net.UDPConn, b []byte) (int, *SessionUDP, error) {
n, raddr, err := conn.ReadFrom(b)
if err != nil {
return n, nil, err
}
session := &sessionUDP{raddr.(*net.UDPAddr)}
session := &SessionUDP{raddr.(*net.UDPAddr)}
return n, session, err
}
// writeToSessionUDP acts just like net.UDPConn.WritetTo(), but uses a *sessionUDP instead of a net.Addr.
func writeToSessionUDP(conn *net.UDPConn, b []byte, session *sessionUDP) (int, error) {
// WriteToSessionUDP acts just like net.UDPConn.WritetTo(), but uses a *SessionUDP instead of a net.Addr.
func WriteToSessionUDP(conn *net.UDPConn, b []byte, session *SessionUDP) (int, error) {
n, err := conn.WriteTo(b, session.raddr)
return n, err
}
func (s *sessionUDP) RemoteAddr() net.Addr { return s.raddr }
func (s *SessionUDP) RemoteAddr() net.Addr { return s.raddr }
// setUDPSocketOptions sets the UDP socket options.
// This function is implemented on a per platform basis. See udp_*.go for more details

View File

@ -1,38 +1,3 @@
// DYNAMIC UPDATES
//
// Dynamic updates reuses the DNS message format, but renames three of
// the sections. Question is Zone, Answer is Prerequisite, Authority is
// Update, only the Additional is not renamed. See RFC 2136 for the gory details.
//
// You can set a rather complex set of rules for the existence of absence of
// certain resource records or names in a zone to specify if resource records
// should be added or removed. The table from RFC 2136 supplemented with the Go
// DNS function shows which functions exist to specify the prerequisites.
//
// 3.2.4 - Table Of Metavalues Used In Prerequisite Section
//
// CLASS TYPE RDATA Meaning Function
// --------------------------------------------------------------
// ANY ANY empty Name is in use dns.NameUsed
// ANY rrset empty RRset exists (value indep) dns.RRsetUsed
// NONE ANY empty Name is not in use dns.NameNotUsed
// NONE rrset empty RRset does not exist dns.RRsetNotUsed
// zone rrset rr RRset exists (value dep) dns.Used
//
// The prerequisite section can also be left empty.
// If you have decided on the prerequisites you can tell what RRs should
// be added or deleted. The next table shows the options you have and
// what functions to call.
//
// 3.4.2.6 - Table Of Metavalues Used In Update Section
//
// CLASS TYPE RDATA Meaning Function
// ---------------------------------------------------------------
// ANY ANY empty Delete all RRsets from name dns.RemoveName
// ANY rrset empty Delete an RRset dns.RemoveRRset
// NONE rrset rr Delete an RR from RRset dns.Remove
// zone rrset rr Add to an RRset dns.Insert
//
package dns
// NameUsed sets the RRs in the prereq section to

View File

@ -12,10 +12,9 @@ func TestDynamicUpdateParsing(t *testing.T) {
typ == "TSIG" || typ == "ISDN" || typ == "UNSPEC" || typ == "NULL" || typ == "ATMA" {
continue
}
r, e := NewRR(prefix + typ)
if e != nil {
t.Log("failure to parse: " + prefix + typ)
t.Fail()
r, err := NewRR(prefix + typ)
if err != nil {
t.Errorf("failure to parse: %s %s: %v", prefix, typ, err)
} else {
t.Logf("parsed: %s", r.String())
}
@ -31,8 +30,7 @@ func TestDynamicUpdateUnpack(t *testing.T) {
msg := new(Msg)
err := msg.Unpack(buf)
if err != nil {
t.Log("failed to unpack: " + err.Error() + "\n" + msg.String())
t.Fail()
t.Errorf("failed to unpack: %v\n%s", err, msg.String())
}
}
@ -45,13 +43,11 @@ func TestDynamicUpdateZeroRdataUnpack(t *testing.T) {
rr.Rrtype = n
bytes, err := m.Pack()
if err != nil {
t.Logf("failed to pack %s: %v", s, err)
t.Fail()
t.Errorf("failed to pack %s: %v", s, err)
continue
}
if err := new(Msg).Unpack(bytes); err != nil {
t.Logf("failed to unpack %s: %v", s, err)
t.Fail()
t.Errorf("failed to unpack %s: %v", s, err)
}
}
}
@ -82,8 +78,7 @@ func TestRemoveRRset(t *testing.T) {
if err := tmp.Unpack(actual); err != nil {
t.Fatalf("Error unpacking actual msg: %v", err)
}
t.Logf("Expected msg:\n%s", expectstr)
t.Logf("Actual msg:\n%v", tmp)
t.Fail()
t.Errorf("Expected msg:\n%s", expectstr)
t.Errorf("Actual msg:\n%v", tmp)
}
}

View File

@ -193,6 +193,7 @@ func (t *Transfer) ReadMsg() (*Msg, error) {
}
// Need to work on the original message p, as that was used to calculate the tsig.
err = TsigVerify(p, t.TsigSecret[ts.Hdr.Name], t.tsigRequestMAC, t.tsigTimersOnly)
t.tsigRequestMAC = ts.MAC
}
return m, err
}

View File

@ -7,8 +7,8 @@ import (
)
func getIP(s string) string {
a, e := net.LookupAddr(s)
if e != nil {
a, err := net.LookupAddr(s)
if err != nil {
return ""
}
return a[0]
@ -28,17 +28,15 @@ func testClientAXFR(t *testing.T) {
tr := new(Transfer)
if a, err := tr.In(m, net.JoinHostPort(server, "53")); err != nil {
t.Log("failed to setup axfr: " + err.Error())
t.Fatal()
t.Fatal("failed to setup axfr: ", err)
} else {
for ex := range a {
if ex.Error != nil {
t.Logf("error %s\n", ex.Error.Error())
t.Fail()
t.Errorf("error %v", ex.Error)
break
}
for _, rr := range ex.RR {
t.Logf("%s\n", rr.String())
t.Log(rr.String())
}
}
}
@ -56,14 +54,11 @@ func testClientAXFRMultipleEnvelopes(t *testing.T) {
tr := new(Transfer)
if a, err := tr.In(m, net.JoinHostPort(server, "53")); err != nil {
t.Log("Failed to setup axfr" + err.Error() + "for server: " + server)
t.Fail()
return
t.Fatalf("Failed to setup axfr %v for server: %v", err, server)
} else {
for ex := range a {
if ex.Error != nil {
t.Logf("Error %s\n", ex.Error.Error())
t.Fail()
t.Errorf("Error %v", ex.Error)
break
}
}
@ -82,17 +77,15 @@ func testClientTsigAXFR(t *testing.T) {
tr.TsigSecret = map[string]string{"axfr.": "so6ZGir4GPAqINNh9U5c3A=="}
if a, err := tr.In(m, "176.58.119.54:53"); err != nil {
t.Log("failed to setup axfr: " + err.Error())
t.Fatal()
t.Fatal("failed to setup axfr: ", err)
} else {
for ex := range a {
if ex.Error != nil {
t.Logf("error %s\n", ex.Error.Error())
t.Fail()
t.Errorf("error %v", ex.Error)
break
}
for _, rr := range ex.RR {
t.Logf("%s\n", rr.String())
t.Log(rr.String())
}
}
}

View File

@ -1,6 +1,7 @@
package dns
import (
"bytes"
"fmt"
"strconv"
"strings"
@ -24,13 +25,13 @@ func generate(l lex, c chan lex, t chan *Token, o string) string {
if i+1 == len(l.token) {
return "bad step in $GENERATE range"
}
if s, e := strconv.Atoi(l.token[i+1:]); e != nil {
return "bad step in $GENERATE range"
} else {
if s, e := strconv.Atoi(l.token[i+1:]); e == nil {
if s < 0 {
return "bad step in $GENERATE range"
}
step = s
} else {
return "bad step in $GENERATE range"
}
l.token = l.token[:i]
}
@ -46,7 +47,7 @@ func generate(l lex, c chan lex, t chan *Token, o string) string {
if err != nil {
return "bad stop in $GENERATE range"
}
if end < 0 || start < 0 || end <= start {
if end < 0 || start < 0 || end < start {
return "bad range in $GENERATE range"
}
@ -55,14 +56,14 @@ func generate(l lex, c chan lex, t chan *Token, o string) string {
s := ""
BuildRR:
l = <-c
if l.value != _NEWLINE && l.value != _EOF {
if l.value != zNewline && l.value != zEOF {
s += l.token
goto BuildRR
}
for i := start; i <= end; i += step {
var (
escape bool
dom string
dom bytes.Buffer
mod string
err string
offset int
@ -72,7 +73,7 @@ BuildRR:
switch s[j] {
case '\\':
if escape {
dom += "\\"
dom.WriteByte('\\')
escape = false
continue
}
@ -81,17 +82,17 @@ BuildRR:
mod = "%d"
offset = 0
if escape {
dom += "$"
dom.WriteByte('$')
escape = false
continue
}
escape = false
if j+1 >= len(s) { // End of the string
dom += fmt.Sprintf(mod, i+offset)
dom.WriteString(fmt.Sprintf(mod, i+offset))
continue
} else {
if s[j+1] == '$' {
dom += "$"
dom.WriteByte('$')
j++
continue
}
@ -108,17 +109,17 @@ BuildRR:
}
j += 2 + sep // Jump to it
}
dom += fmt.Sprintf(mod, i+offset)
dom.WriteString(fmt.Sprintf(mod, i+offset))
default:
if escape { // Pretty useless here
escape = false
continue
}
dom += string(s[j])
dom.WriteByte(s[j])
}
}
// Re-parse the RR and send it on the current channel t
rx, e := NewRR("$ORIGIN " + o + "\n" + dom)
rx, e := NewRR("$ORIGIN " + o + "\n" + dom.String())
if e != nil {
return e.(*ParseError).err
}

View File

@ -29,41 +29,41 @@ const maxUint16 = 1<<16 - 1
// * Handle braces - anywhere.
const (
// Zonefile
_EOF = iota
_STRING
_BLANK
_QUOTE
_NEWLINE
_RRTYPE
_OWNER
_CLASS
_DIRORIGIN // $ORIGIN
_DIRTTL // $TTL
_DIRINCLUDE // $INCLUDE
_DIRGENERATE // $GENERATE
zEOF = iota
zString
zBlank
zQuote
zNewline
zRrtpe
zOwner
zClass
zDirOrigin // $ORIGIN
zDirTtl // $TTL
zDirInclude // $INCLUDE
zDirGenerate // $GENERATE
// Privatekey file
_VALUE
_KEY
zValue
zKey
_EXPECT_OWNER_DIR // Ownername
_EXPECT_OWNER_BL // Whitespace after the ownername
_EXPECT_ANY // Expect rrtype, ttl or class
_EXPECT_ANY_NOCLASS // Expect rrtype or ttl
_EXPECT_ANY_NOCLASS_BL // The whitespace after _EXPECT_ANY_NOCLASS
_EXPECT_ANY_NOTTL // Expect rrtype or class
_EXPECT_ANY_NOTTL_BL // Whitespace after _EXPECT_ANY_NOTTL
_EXPECT_RRTYPE // Expect rrtype
_EXPECT_RRTYPE_BL // Whitespace BEFORE rrtype
_EXPECT_RDATA // The first element of the rdata
_EXPECT_DIRTTL_BL // Space after directive $TTL
_EXPECT_DIRTTL // Directive $TTL
_EXPECT_DIRORIGIN_BL // Space after directive $ORIGIN
_EXPECT_DIRORIGIN // Directive $ORIGIN
_EXPECT_DIRINCLUDE_BL // Space after directive $INCLUDE
_EXPECT_DIRINCLUDE // Directive $INCLUDE
_EXPECT_DIRGENERATE // Directive $GENERATE
_EXPECT_DIRGENERATE_BL // Space after directive $GENERATE
zExpectOwnerDir // Ownername
zExpectOwnerBl // Whitespace after the ownername
zExpectAny // Expect rrtype, ttl or class
zExpectAnyNoClass // Expect rrtype or ttl
zExpectAnyNoClassBl // The whitespace after _EXPECT_ANY_NOCLASS
zExpectAnyNoTtl // Expect rrtype or class
zExpectAnyNoTtlBl // Whitespace after _EXPECT_ANY_NOTTL
zExpectRrtype // Expect rrtype
zExpectRrtypeBl // Whitespace BEFORE rrtype
zExpectRdata // The first element of the rdata
zExpectDirTtlBl // Space after directive $TTL
zExpectDirTtl // Directive $TTL
zExpectDirOriginBl // Space after directive $ORIGIN
zExpectDirOrigin // Directive $ORIGIN
zExpectDirIncludeBl // Space after directive $INCLUDE
zExpectDirInclude // Directive $INCLUDE
zExpectDirGenerate // Directive $GENERATE
zExpectDirGenerateBl // Space after directive $GENERATE
)
// ParseError is a parsing error. It contains the parse error and the location in the io.Reader
@ -88,18 +88,21 @@ type lex struct {
tokenUpper string // uppercase text of the token
length int // lenght of the token
err bool // when true, token text has lexer error
value uint8 // value: _STRING, _BLANK, etc.
value uint8 // value: zString, _BLANK, etc.
line int // line in the file
column int // column in the file
torc uint16 // type or class as parsed in the lexer, we only need to look this up in the grammar
comment string // any comment text seen
}
// *Tokens are returned when a zone file is parsed.
// Token holds the token that are returned when a zone file is parsed.
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 and on the same line
// The scanned resource record when error is not nil.
RR
// When an error occured, this has the error specifics.
Error *ParseError
// A potential comment positioned after the RR and on the same line.
Comment string
}
// NewRR reads the RR contained in the string s. Only the first RR is
@ -168,17 +171,17 @@ func parseZone(r io.Reader, origin, f string, t chan *Token, include int) {
}
}()
s := scanInit(r)
c := make(chan lex, 1000)
c := make(chan lex)
// Start the lexer
go zlexer(s, c)
// 6 possible beginnings of a line, _ is a space
// 0. _RRTYPE -> all omitted until the rrtype
// 1. _OWNER _ _RRTYPE -> class/ttl omitted
// 2. _OWNER _ _STRING _ _RRTYPE -> class omitted
// 3. _OWNER _ _STRING _ _CLASS _ _RRTYPE -> ttl/class
// 4. _OWNER _ _CLASS _ _RRTYPE -> ttl omitted
// 5. _OWNER _ _CLASS _ _STRING _ _RRTYPE -> class/ttl (reversed)
// After detecting these, we know the _RRTYPE so we can jump to functions
// 0. zRRTYPE -> all omitted until the rrtype
// 1. zOwner _ zRrtype -> class/ttl omitted
// 2. zOwner _ zString _ zRrtype -> class omitted
// 3. zOwner _ zString _ zClass _ zRrtype -> ttl/class
// 4. zOwner _ zClass _ zRrtype -> ttl omitted
// 5. zOwner _ zClass _ zString _ zRrtype -> class/ttl (reversed)
// After detecting these, we know the zRrtype so we can jump to functions
// handling the rdata for each of these types.
if origin == "" {
@ -190,7 +193,7 @@ func parseZone(r io.Reader, origin, f string, t chan *Token, include int) {
return
}
st := _EXPECT_OWNER_DIR // initial state
st := zExpectOwnerDir // initial state
var h RR_Header
var defttl uint32 = defaultTtl
var prevName string
@ -202,19 +205,19 @@ func parseZone(r io.Reader, origin, f string, t chan *Token, include int) {
}
switch st {
case _EXPECT_OWNER_DIR:
case zExpectOwnerDir:
// We can also expect a directive, like $TTL or $ORIGIN
h.Ttl = defttl
h.Class = ClassINET
switch l.value {
case _NEWLINE: // Empty line
st = _EXPECT_OWNER_DIR
case _OWNER:
case zNewline:
st = zExpectOwnerDir
case zOwner:
h.Name = l.token
if l.token[0] == '@' {
h.Name = origin
prevName = h.Name
st = _EXPECT_OWNER_BL
st = zExpectOwnerBl
break
}
if h.Name[l.length-1] != '.' {
@ -226,58 +229,58 @@ func parseZone(r io.Reader, origin, f string, t chan *Token, include int) {
return
}
prevName = h.Name
st = _EXPECT_OWNER_BL
case _DIRTTL:
st = _EXPECT_DIRTTL_BL
case _DIRORIGIN:
st = _EXPECT_DIRORIGIN_BL
case _DIRINCLUDE:
st = _EXPECT_DIRINCLUDE_BL
case _DIRGENERATE:
st = _EXPECT_DIRGENERATE_BL
case _RRTYPE: // Everthing has been omitted, this is the first thing on the line
st = zExpectOwnerBl
case zDirTtl:
st = zExpectDirTtlBl
case zDirOrigin:
st = zExpectDirOriginBl
case zDirInclude:
st = zExpectDirIncludeBl
case zDirGenerate:
st = zExpectDirGenerateBl
case zRrtpe:
h.Name = prevName
h.Rrtype = l.torc
st = _EXPECT_RDATA
case _CLASS: // First thing on the line is the class
st = zExpectRdata
case zClass:
h.Name = prevName
h.Class = l.torc
st = _EXPECT_ANY_NOCLASS_BL
case _BLANK:
st = zExpectAnyNoClassBl
case zBlank:
// Discard, can happen when there is nothing on the
// line except the RR type
case _STRING: // First thing on the is the ttl
if ttl, ok := stringToTtl(l.token); !ok {
case zString:
ttl, ok := stringToTtl(l.token)
if !ok {
t <- &Token{Error: &ParseError{f, "not a TTL", l}}
return
} else {
h.Ttl = ttl
// Don't about the defttl, we should take the $TTL value
// defttl = ttl
}
st = _EXPECT_ANY_NOTTL_BL
h.Ttl = ttl
// Don't about the defttl, we should take the $TTL value
// defttl = ttl
st = zExpectAnyNoTtlBl
default:
t <- &Token{Error: &ParseError{f, "syntax error at beginning", l}}
return
}
case _EXPECT_DIRINCLUDE_BL:
if l.value != _BLANK {
case zExpectDirIncludeBl:
if l.value != zBlank {
t <- &Token{Error: &ParseError{f, "no blank after $INCLUDE-directive", l}}
return
}
st = _EXPECT_DIRINCLUDE
case _EXPECT_DIRINCLUDE:
if l.value != _STRING {
st = zExpectDirInclude
case zExpectDirInclude:
if l.value != zString {
t <- &Token{Error: &ParseError{f, "expecting $INCLUDE value, not this...", l}}
return
}
neworigin := origin // There may be optionally a new origin set after the filename, if not use current one
l := <-c
switch l.value {
case _BLANK:
case zBlank:
l := <-c
if l.value == _STRING {
if l.value == zString {
if _, ok := IsDomainName(l.token); !ok {
t <- &Token{Error: &ParseError{f, "bad origin name", l}}
return
@ -293,7 +296,7 @@ func parseZone(r io.Reader, origin, f string, t chan *Token, include int) {
neworigin = l.token
}
}
case _NEWLINE, _EOF:
case zNewline, zEOF:
// Ok
default:
t <- &Token{Error: &ParseError{f, "garbage after $INCLUDE", l}}
@ -310,15 +313,15 @@ func parseZone(r io.Reader, origin, f string, t chan *Token, include int) {
return
}
parseZone(r1, l.token, neworigin, t, include+1)
st = _EXPECT_OWNER_DIR
case _EXPECT_DIRTTL_BL:
if l.value != _BLANK {
st = zExpectOwnerDir
case zExpectDirTtlBl:
if l.value != zBlank {
t <- &Token{Error: &ParseError{f, "no blank after $TTL-directive", l}}
return
}
st = _EXPECT_DIRTTL
case _EXPECT_DIRTTL:
if l.value != _STRING {
st = zExpectDirTtl
case zExpectDirTtl:
if l.value != zString {
t <- &Token{Error: &ParseError{f, "expecting $TTL value, not this...", l}}
return
}
@ -326,21 +329,21 @@ func parseZone(r io.Reader, origin, f string, t chan *Token, include int) {
t <- &Token{Error: e}
return
}
if ttl, ok := stringToTtl(l.token); !ok {
ttl, ok := stringToTtl(l.token)
if !ok {
t <- &Token{Error: &ParseError{f, "expecting $TTL value, not this...", l}}
return
} else {
defttl = ttl
}
st = _EXPECT_OWNER_DIR
case _EXPECT_DIRORIGIN_BL:
if l.value != _BLANK {
defttl = ttl
st = zExpectOwnerDir
case zExpectDirOriginBl:
if l.value != zBlank {
t <- &Token{Error: &ParseError{f, "no blank after $ORIGIN-directive", l}}
return
}
st = _EXPECT_DIRORIGIN
case _EXPECT_DIRORIGIN:
if l.value != _STRING {
st = zExpectDirOrigin
case zExpectDirOrigin:
if l.value != zString {
t <- &Token{Error: &ParseError{f, "expecting $ORIGIN value, not this...", l}}
return
}
@ -360,15 +363,15 @@ func parseZone(r io.Reader, origin, f string, t chan *Token, include int) {
} else {
origin = l.token
}
st = _EXPECT_OWNER_DIR
case _EXPECT_DIRGENERATE_BL:
if l.value != _BLANK {
st = zExpectOwnerDir
case zExpectDirGenerateBl:
if l.value != zBlank {
t <- &Token{Error: &ParseError{f, "no blank after $GENERATE-directive", l}}
return
}
st = _EXPECT_DIRGENERATE
case _EXPECT_DIRGENERATE:
if l.value != _STRING {
st = zExpectDirGenerate
case zExpectDirGenerate:
if l.value != zString {
t <- &Token{Error: &ParseError{f, "expecting $GENERATE value, not this...", l}}
return
}
@ -376,90 +379,90 @@ func parseZone(r io.Reader, origin, f string, t chan *Token, include int) {
t <- &Token{Error: &ParseError{f, e, l}}
return
}
st = _EXPECT_OWNER_DIR
case _EXPECT_OWNER_BL:
if l.value != _BLANK {
st = zExpectOwnerDir
case zExpectOwnerBl:
if l.value != zBlank {
t <- &Token{Error: &ParseError{f, "no blank after owner", l}}
return
}
st = _EXPECT_ANY
case _EXPECT_ANY:
st = zExpectAny
case zExpectAny:
switch l.value {
case _RRTYPE:
case zRrtpe:
h.Rrtype = l.torc
st = _EXPECT_RDATA
case _CLASS:
st = zExpectRdata
case zClass:
h.Class = l.torc
st = _EXPECT_ANY_NOCLASS_BL
case _STRING: // TTL is this case
if ttl, ok := stringToTtl(l.token); !ok {
st = zExpectAnyNoClassBl
case zString:
ttl, ok := stringToTtl(l.token)
if !ok {
t <- &Token{Error: &ParseError{f, "not a TTL", l}}
return
} else {
h.Ttl = ttl
// defttl = ttl // don't set the defttl here
}
st = _EXPECT_ANY_NOTTL_BL
h.Ttl = ttl
// defttl = ttl // don't set the defttl here
st = zExpectAnyNoTtlBl
default:
t <- &Token{Error: &ParseError{f, "expecting RR type, TTL or class, not this...", l}}
return
}
case _EXPECT_ANY_NOCLASS_BL:
if l.value != _BLANK {
case zExpectAnyNoClassBl:
if l.value != zBlank {
t <- &Token{Error: &ParseError{f, "no blank before class", l}}
return
}
st = _EXPECT_ANY_NOCLASS
case _EXPECT_ANY_NOTTL_BL:
if l.value != _BLANK {
st = zExpectAnyNoClass
case zExpectAnyNoTtlBl:
if l.value != zBlank {
t <- &Token{Error: &ParseError{f, "no blank before TTL", l}}
return
}
st = _EXPECT_ANY_NOTTL
case _EXPECT_ANY_NOTTL:
st = zExpectAnyNoTtl
case zExpectAnyNoTtl:
switch l.value {
case _CLASS:
case zClass:
h.Class = l.torc
st = _EXPECT_RRTYPE_BL
case _RRTYPE:
st = zExpectRrtypeBl
case zRrtpe:
h.Rrtype = l.torc
st = _EXPECT_RDATA
st = zExpectRdata
default:
t <- &Token{Error: &ParseError{f, "expecting RR type or class, not this...", l}}
return
}
case _EXPECT_ANY_NOCLASS:
case zExpectAnyNoClass:
switch l.value {
case _STRING: // TTL
if ttl, ok := stringToTtl(l.token); !ok {
case zString:
ttl, ok := stringToTtl(l.token)
if !ok {
t <- &Token{Error: &ParseError{f, "not a TTL", l}}
return
} else {
h.Ttl = ttl
// defttl = ttl // don't set the def ttl anymore
}
st = _EXPECT_RRTYPE_BL
case _RRTYPE:
h.Ttl = ttl
// defttl = ttl // don't set the def ttl anymore
st = zExpectRrtypeBl
case zRrtpe:
h.Rrtype = l.torc
st = _EXPECT_RDATA
st = zExpectRdata
default:
t <- &Token{Error: &ParseError{f, "expecting RR type or TTL, not this...", l}}
return
}
case _EXPECT_RRTYPE_BL:
if l.value != _BLANK {
case zExpectRrtypeBl:
if l.value != zBlank {
t <- &Token{Error: &ParseError{f, "no blank before RR type", l}}
return
}
st = _EXPECT_RRTYPE
case _EXPECT_RRTYPE:
if l.value != _RRTYPE {
st = zExpectRrtype
case zExpectRrtype:
if l.value != zRrtpe {
t <- &Token{Error: &ParseError{f, "unknown RR type", l}}
return
}
h.Rrtype = l.torc
st = _EXPECT_RDATA
case _EXPECT_RDATA:
st = zExpectRdata
case zExpectRdata:
r, e, c1 := setRR(h, c, origin, f)
if e != nil {
// If e.lex is nil than we have encounter a unknown RR type
@ -471,7 +474,7 @@ func parseZone(r io.Reader, origin, f string, t chan *Token, include int) {
return
}
t <- &Token{RR: r, Comment: c1}
st = _EXPECT_OWNER_DIR
st = zExpectOwnerDir
}
}
// If we get here, we and the h.Rrtype is still zero, we haven't parsed anything, this
@ -535,60 +538,60 @@ func zlexer(s *scan, c chan lex) {
// Space directly in the beginning, handled in the grammar
} else if owner {
// If we have a string and its the first, make it an owner
l.value = _OWNER
l.value = zOwner
l.token = string(str[:stri])
l.tokenUpper = strings.ToUpper(l.token)
l.length = stri
// escape $... start with a \ not a $, so this will work
switch l.tokenUpper {
case "$TTL":
l.value = _DIRTTL
l.value = zDirTtl
case "$ORIGIN":
l.value = _DIRORIGIN
l.value = zDirOrigin
case "$INCLUDE":
l.value = _DIRINCLUDE
l.value = zDirInclude
case "$GENERATE":
l.value = _DIRGENERATE
l.value = zDirGenerate
}
debug.Printf("[7 %+v]", l.token)
c <- l
} else {
l.value = _STRING
l.value = zString
l.token = string(str[:stri])
l.tokenUpper = strings.ToUpper(l.token)
l.length = stri
if !rrtype {
if t, ok := StringToType[l.tokenUpper]; ok {
l.value = _RRTYPE
l.value = zRrtpe
l.torc = t
rrtype = true
} else {
if strings.HasPrefix(l.tokenUpper, "TYPE") {
if t, ok := typeToInt(l.token); !ok {
t, ok := typeToInt(l.token)
if !ok {
l.token = "unknown RR type"
l.err = true
c <- l
return
} else {
l.value = _RRTYPE
l.torc = t
}
l.value = zRrtpe
l.torc = t
}
}
if t, ok := StringToClass[l.tokenUpper]; ok {
l.value = _CLASS
l.value = zClass
l.torc = t
} else {
if strings.HasPrefix(l.tokenUpper, "CLASS") {
if t, ok := classToInt(l.token); !ok {
t, ok := classToInt(l.token)
if !ok {
l.token = "unknown class"
l.err = true
c <- l
return
} else {
l.value = _CLASS
l.torc = t
}
l.value = zClass
l.torc = t
}
}
}
@ -598,7 +601,7 @@ func zlexer(s *scan, c chan lex) {
stri = 0
// I reverse space stuff here
if !space && !commt {
l.value = _BLANK
l.value = zBlank
l.token = " "
l.length = 1
debug.Printf("[5 %+v]", l.token)
@ -620,7 +623,7 @@ func zlexer(s *scan, c chan lex) {
break
}
if stri > 0 {
l.value = _STRING
l.value = zString
l.token = string(str[:stri])
l.length = stri
debug.Printf("[4 %+v]", l.token)
@ -656,7 +659,7 @@ func zlexer(s *scan, c chan lex) {
if brace == 0 {
owner = true
owner = true
l.value = _NEWLINE
l.value = zNewline
l.token = "\n"
l.length = 1
l.comment = string(com[:comi])
@ -674,14 +677,14 @@ func zlexer(s *scan, c chan lex) {
if brace == 0 {
// If there is previous text, we should output it here
if stri != 0 {
l.value = _STRING
l.value = zString
l.token = string(str[:stri])
l.tokenUpper = strings.ToUpper(l.token)
l.length = stri
if !rrtype {
if t, ok := StringToType[l.tokenUpper]; ok {
l.value = _RRTYPE
l.value = zRrtpe
l.torc = t
rrtype = true
}
@ -689,7 +692,7 @@ func zlexer(s *scan, c chan lex) {
debug.Printf("[2 %+v]", l.token)
c <- l
}
l.value = _NEWLINE
l.value = zNewline
l.token = "\n"
l.length = 1
debug.Printf("[1 %+v]", l.token)
@ -733,7 +736,7 @@ func zlexer(s *scan, c chan lex) {
space = false
// send previous gathered text and the quote
if stri != 0 {
l.value = _STRING
l.value = zString
l.token = string(str[:stri])
l.length = stri
@ -743,7 +746,7 @@ func zlexer(s *scan, c chan lex) {
}
// send quote itself as separate token
l.value = _QUOTE
l.value = zQuote
l.token = "\""
l.length = 1
c <- l
@ -795,7 +798,7 @@ func zlexer(s *scan, c chan lex) {
// Send remainder
l.token = string(str[:stri])
l.length = stri
l.value = _STRING
l.value = zString
debug.Printf("[%+v]", l.token)
c <- l
}
@ -927,15 +930,15 @@ func slurpRemainder(c chan lex, f string) (*ParseError, string) {
l := <-c
com := ""
switch l.value {
case _BLANK:
case zBlank:
l = <-c
com = l.comment
if l.value != _NEWLINE && l.value != _EOF {
if l.value != zNewline && l.value != zEOF {
return &ParseError{f, "garbage after rdata", l}, ""
}
case _NEWLINE:
case zNewline:
com = l.comment
case _EOF:
case zEOF:
default:
return &ParseError{f, "garbage after rdata", l}, ""
}

File diff suppressed because it is too large Load Diff