Godeps changes for kube-dns

This commit is contained in:
Abhishek Shah 2016-05-04 16:22:06 -07:00
parent ae7809d71a
commit d2dd4911ca
39 changed files with 4162 additions and 2703 deletions

6
Godeps/Godeps.json generated
View File

@ -1335,7 +1335,7 @@
}, },
{ {
"ImportPath": "github.com/miekg/dns", "ImportPath": "github.com/miekg/dns",
"Rev": "3f504e8dabd5d562e997d19ce0200aa41973e1b2" "Rev": "c2b278e70f35902fd68b54b69238cd10bb1b7451"
}, },
{ {
"ImportPath": "github.com/mistifyio/go-zfs", "ImportPath": "github.com/mistifyio/go-zfs",
@ -1779,8 +1779,8 @@
}, },
{ {
"ImportPath": "github.com/skynetservices/skydns/msg", "ImportPath": "github.com/skynetservices/skydns/msg",
"Comment": "2.5.1a", "Comment": "2.5.3a-32-gf7b6fb7",
"Rev": "1be70b5b8aa07acccd972146d84011b670af88b4" "Rev": "f7b6fb74bcfab300b4e7e0e27b1fe6c0ed555f78"
}, },
{ {
"ImportPath": "github.com/spf13/cobra", "ImportPath": "github.com/spf13/cobra",

View File

@ -1,21 +1,7 @@
language: go language: go
sudo: false
go: go:
- 1.2 - 1.5
- 1.3 - 1.6
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
script: script:
- gvm cross $BUILD_GOOS $BUILD_GOARCH - go test -race -v -bench=.
- 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

View File

@ -10,9 +10,9 @@ If there is stuff you should know as a DNS programmer there isn't a convenience
function for it. Server side and client side programming is supported, i.e. you function for it. Server side and client side programming is supported, i.e. you
can build servers and resolvers with it. can build servers and resolvers with it.
If you like this, you may also be interested in: We try to keep the "master" branch as sane as possible and at the bleeding edge
of standards, avoiding breaking changes wherever reasonable. We support the last
* https://github.com/miekg/unbound -- Go wrapper for the Unbound resolver. two versions of Go, currently: 1.4 and 1.5.
# Goals # Goals
@ -24,6 +24,7 @@ If you like this, you may also be interested in:
A not-so-up-to-date-list-that-may-be-actually-current: A not-so-up-to-date-list-that-may-be-actually-current:
* https://cloudflare.com
* https://github.com/abh/geodns * https://github.com/abh/geodns
* http://www.statdns.com/ * http://www.statdns.com/
* http://www.dnsinspect.com/ * http://www.dnsinspect.com/
@ -32,8 +33,21 @@ A not-so-up-to-date-list-that-may-be-actually-current:
* https://github.com/fcambus/rrda * https://github.com/fcambus/rrda
* https://github.com/kenshinx/godns * https://github.com/kenshinx/godns
* https://github.com/skynetservices/skydns * https://github.com/skynetservices/skydns
* https://github.com/hashicorp/consul
* https://github.com/DevelopersPL/godnsagent * https://github.com/DevelopersPL/godnsagent
* https://github.com/duedil-ltd/discodns * https://github.com/duedil-ltd/discodns
* https://github.com/StalkR/dns-reverse-proxy
* https://github.com/tianon/rawdns
* https://mesosphere.github.io/mesos-dns/
* https://pulse.turbobytes.com/
* https://play.google.com/store/apps/details?id=com.turbobytes.dig
* https://github.com/fcambus/statzone
* https://github.com/benschw/dns-clb-go
* https://github.com/corny/dnscheck for http://public-dns.info/
* https://namesmith.io
* https://github.com/miekg/unbound
* https://github.com/miekg/exdns
* https://dnslookup.org
Send pull request if you want to be listed here. Send pull request if you want to be listed here.
@ -50,6 +64,7 @@ Send pull request if you want to be listed here.
* EDNS0, NSID; * EDNS0, NSID;
* AXFR/IXFR; * AXFR/IXFR;
* TSIG, SIG(0); * TSIG, SIG(0);
* DNS over TLS: optional encrypted connection between client and server;
* DNS name compression; * DNS name compression;
* Depends only on the standard library. * Depends only on the standard library.
@ -67,7 +82,7 @@ correctly, the following should work:
## Examples ## 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`). when you call `godoc github.com/miekg/dns`).
Example programs can be found in the `github.com/miekg/exdns` repository. Example programs can be found in the `github.com/miekg/exdns` repository.
@ -77,7 +92,7 @@ Example programs can be found in the `github.com/miekg/exdns` repository.
*all of them* *all of them*
* 103{4,5} - DNS standard * 103{4,5} - DNS standard
* 1348 - NSAP record * 1348 - NSAP record (removed the record)
* 1982 - Serial Arithmetic * 1982 - Serial Arithmetic
* 1876 - LOC record * 1876 - LOC record
* 1995 - IXFR * 1995 - IXFR
@ -95,7 +110,8 @@ Example programs can be found in the `github.com/miekg/exdns` repository.
* 3225 - DO bit (DNSSEC OK) * 3225 - DO bit (DNSSEC OK)
* 340{1,2,3} - NAPTR record * 340{1,2,3} - NAPTR record
* 3445 - Limiting the scope of (DNS)KEY * 3445 - Limiting the scope of (DNS)KEY
* 3597 - Unkown RRs * 3597 - Unknown RRs
* 4025 - IPSECKEY
* 403{3,4,5} - DNSSEC + validation functions * 403{3,4,5} - DNSSEC + validation functions
* 4255 - SSHFP record * 4255 - SSHFP record
* 4343 - Case insensitivity * 4343 - Case insensitivity
@ -114,13 +130,16 @@ Example programs can be found in the `github.com/miekg/exdns` repository.
* 6605 - ECDSA * 6605 - ECDSA
* 6725 - IANA Registry Update * 6725 - IANA Registry Update
* 6742 - ILNP DNS * 6742 - ILNP DNS
* 6840 - Clarifications and Implementation Notes for DNS Security
* 6844 - CAA record
* 6891 - EDNS0 update * 6891 - EDNS0 update
* 6895 - DNS IANA considerations * 6895 - DNS IANA considerations
* 6975 - Algorithm Understanding in DNSSEC * 6975 - Algorithm Understanding in DNSSEC
* 7043 - EUI48/EUI64 records * 7043 - EUI48/EUI64 records
* 7314 - DNS (EDNS) EXPIRE Option * 7314 - DNS (EDNS) EXPIRE Option
* xxxx - URI record (draft) * 7553 - URI record
* xxxx - EDNS0 DNS Update Lease (draft) * xxxx - EDNS0 DNS Update Lease (draft)
* yyyy - DNS over TLS: Initiation and Performance Considerations (draft)
## Loosely based upon ## Loosely based upon
@ -132,9 +151,7 @@ Example programs can be found in the `github.com/miekg/exdns` repository.
## TODO ## TODO
* privatekey.Precompute() when signing? * privatekey.Precompute() when signing?
* Last remaining RRs: APL, ATMA, A6 and NXT; * Last remaining RRs: APL, ATMA, A6, NSAP and NXT.
* Missing in parsing: ISDN, UNSPEC, ATMA; * Missing in parsing: ISDN, UNSPEC, NSAP and ATMA.
* CAA parsing is broken; * NSEC(3) cover/match/closest enclose.
* NSEC(3) cover/match/closest enclose; * Replies with TC bit are not parsed to the end.
* Replies with TC bit are not parsed to the end;
* Create IsMsg to validate a message before fully parsing it.

297
vendor/github.com/miekg/dns/client.go generated vendored
View File

@ -4,12 +4,13 @@ package dns
import ( import (
"bytes" "bytes"
"crypto/tls"
"io" "io"
"net" "net"
"time" "time"
) )
const dnsTimeout time.Duration = 2 * 1e9 const dnsTimeout time.Duration = 2 * time.Second
const tcpIdleTimeout time.Duration = 8 * time.Second const tcpIdleTimeout time.Duration = 8 * time.Second
// A Conn represents a connection to a DNS server. // A Conn represents a connection to a DNS server.
@ -24,11 +25,12 @@ type Conn struct {
// A Client defines parameters for a DNS client. // A Client defines parameters for a DNS client.
type Client struct { type Client struct {
Net string // if "tcp" a TCP query will be initiated, otherwise an UDP one (default is "" for UDP) Net string // if "tcp" or "tcp-tls" (DNS over TLS) a TCP query will be initiated, otherwise an UDP one (default is "" for UDP)
UDPSize uint16 // minimum receive buffer for UDP messages UDPSize uint16 // minimum receive buffer for UDP messages
DialTimeout time.Duration // net.DialTimeout (ns), defaults to 2 * 1e9 TLSConfig *tls.Config // TLS connection configuration
ReadTimeout time.Duration // net.Conn.SetReadTimeout value for connections (ns), defaults to 2 * 1e9 DialTimeout time.Duration // net.DialTimeout, defaults to 2 seconds
WriteTimeout time.Duration // net.Conn.SetWriteTimeout value for connections (ns), defaults to 2 * 1e9 ReadTimeout time.Duration // net.Conn.SetReadTimeout value for connections, defaults to 2 seconds
WriteTimeout time.Duration // net.Conn.SetWriteTimeout value for connections, defaults to 2 seconds
TsigSecret map[string]string // secret(s) for Tsig map[<zonename>]<base64 secret>, zonename must be fully qualified TsigSecret map[string]string // secret(s) for Tsig map[<zonename>]<base64 secret>, zonename must be fully qualified
SingleInflight bool // if true suppress multiple outstanding queries for the same Qname, Qtype and Qclass SingleInflight bool // if true suppress multiple outstanding queries for the same Qname, Qtype and Qclass
group singleflight group singleflight
@ -37,14 +39,7 @@ type Client struct {
// Exchange performs a synchronous UDP query. It sends the message m to the address // Exchange performs a synchronous UDP query. It sends the message m to the address
// contained in a and waits for an reply. Exchange does not retry a failed query, nor // contained in a and waits for an reply. Exchange does not retry a failed query, nor
// will it fall back to TCP in case of truncation. // will it fall back to TCP in case of truncation.
// If you need to send a DNS message on an already existing connection, you can use the // See client.Exchange for more information on setting larger buffer sizes.
// following:
//
// co := &dns.Conn{Conn: c} // c is your net.Conn
// co.WriteMsg(m)
// in, err := co.ReadMsg()
// co.Close()
//
func Exchange(m *Msg, a string) (r *Msg, err error) { func Exchange(m *Msg, a string) (r *Msg, err error) {
var co *Conn var co *Conn
co, err = DialTimeout("udp", a, dnsTimeout) co, err = DialTimeout("udp", a, dnsTimeout)
@ -53,12 +48,23 @@ func Exchange(m *Msg, a string) (r *Msg, err error) {
} }
defer co.Close() defer co.Close()
co.SetReadDeadline(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()
}
co.SetWriteDeadline(time.Now().Add(dnsTimeout)) co.SetWriteDeadline(time.Now().Add(dnsTimeout))
if err = co.WriteMsg(m); err != nil { if err = co.WriteMsg(m); err != nil {
return nil, err return nil, err
} }
co.SetReadDeadline(time.Now().Add(dnsTimeout))
r, err = co.ReadMsg() r, err = co.ReadMsg()
if err == nil && r.Id != m.Id {
err = ErrId
}
return r, err return r, err
} }
@ -79,6 +85,9 @@ func ExchangeConn(c net.Conn, m *Msg) (r *Msg, err error) {
return nil, err return nil, err
} }
r, err = co.ReadMsg() r, err = co.ReadMsg()
if err == nil && r.Id != m.Id {
err = ErrId
}
return r, err return r, err
} }
@ -90,6 +99,10 @@ func ExchangeConn(c net.Conn, m *Msg) (r *Msg, err error) {
// //
// Exchange does not retry a failed query, nor will it fall back to TCP in // Exchange does not retry a failed query, nor will it fall back to TCP in
// case of truncation. // case of truncation.
// It is up to the caller to create a message that allows for larger responses to be
// returned. Specifically this means adding an EDNS0 OPT RR that will advertise a larger
// buffer, see SetEdns0. Messsages without an OPT RR will fallback to the historic limit
// of 512 bytes.
func (c *Client) Exchange(m *Msg, a string) (r *Msg, rtt time.Duration, err error) { func (c *Client) Exchange(m *Msg, a string) (r *Msg, rtt time.Duration, err error) {
if !c.SingleInflight { if !c.SingleInflight {
return c.exchange(m, a) return c.exchange(m, a)
@ -115,31 +128,59 @@ func (c *Client) Exchange(m *Msg, a string) (r *Msg, rtt time.Duration, err erro
return r, rtt, nil return r, rtt, nil
} }
func (c *Client) exchange(m *Msg, a string) (r *Msg, rtt time.Duration, err error) { func (c *Client) dialTimeout() time.Duration {
timeout := dnsTimeout
var co *Conn
if c.DialTimeout != 0 { if c.DialTimeout != 0 {
timeout = c.DialTimeout return c.DialTimeout
} }
if c.Net == "" { return dnsTimeout
co, err = DialTimeout("udp", a, timeout) }
func (c *Client) readTimeout() time.Duration {
if c.ReadTimeout != 0 {
return c.ReadTimeout
}
return dnsTimeout
}
func (c *Client) writeTimeout() time.Duration {
if c.WriteTimeout != 0 {
return c.WriteTimeout
}
return dnsTimeout
}
func (c *Client) exchange(m *Msg, a string) (r *Msg, rtt time.Duration, err error) {
var co *Conn
network := "udp"
tls := false
switch c.Net {
case "tcp-tls":
network = "tcp"
tls = true
case "tcp4-tls":
network = "tcp4"
tls = true
case "tcp6-tls":
network = "tcp6"
tls = true
default:
if c.Net != "" {
network = c.Net
}
}
if tls {
co, err = DialTimeoutWithTLS(network, a, c.TLSConfig, c.dialTimeout())
} else { } else {
co, err = DialTimeout(c.Net, a, timeout) co, err = DialTimeout(network, a, c.dialTimeout())
} }
if err != nil { if err != nil {
return nil, 0, err return nil, 0, err
} }
timeout = dnsTimeout
if c.ReadTimeout != 0 {
timeout = c.ReadTimeout
}
co.SetReadDeadline(time.Now().Add(timeout))
timeout = dnsTimeout
if c.WriteTimeout != 0 {
timeout = c.WriteTimeout
}
co.SetWriteDeadline(time.Now().Add(timeout))
defer co.Close() defer co.Close()
opt := m.IsEdns0() opt := m.IsEdns0()
// If EDNS0 is used use that for size. // If EDNS0 is used use that for size.
if opt != nil && opt.UDPSize() >= MinMsgSize { if opt != nil && opt.UDPSize() >= MinMsgSize {
@ -149,11 +190,18 @@ func (c *Client) exchange(m *Msg, a string) (r *Msg, rtt time.Duration, err erro
if opt == nil && c.UDPSize >= MinMsgSize { if opt == nil && c.UDPSize >= MinMsgSize {
co.UDPSize = c.UDPSize co.UDPSize = c.UDPSize
} }
co.TsigSecret = c.TsigSecret co.TsigSecret = c.TsigSecret
co.SetWriteDeadline(time.Now().Add(c.writeTimeout()))
if err = co.WriteMsg(m); err != nil { if err = co.WriteMsg(m); err != nil {
return nil, 0, err return nil, 0, err
} }
co.SetReadDeadline(time.Now().Add(c.readTimeout()))
r, err = co.ReadMsg() r, err = co.ReadMsg()
if err == nil && r.Id != m.Id {
err = ErrId
}
return r, co.rtt, err return r, co.rtt, err
} }
@ -161,26 +209,21 @@ func (c *Client) exchange(m *Msg, a string) (r *Msg, rtt time.Duration, err erro
// If the received message contains a TSIG record the transaction // If the received message contains a TSIG record the transaction
// signature is verified. // signature is verified.
func (co *Conn) ReadMsg() (*Msg, error) { func (co *Conn) ReadMsg() (*Msg, error) {
var p []byte p, err := co.ReadMsgHeader(nil)
if err != nil {
return nil, err
}
m := new(Msg) m := new(Msg)
if _, ok := co.Conn.(*net.TCPConn); ok {
p = make([]byte, MaxMsgSize)
} else {
if co.UDPSize >= 512 {
p = make([]byte, co.UDPSize)
} else {
p = make([]byte, MinMsgSize)
}
}
n, err := co.Read(p)
if err != nil && n == 0 {
return nil, err
}
p = p[:n]
if err := m.Unpack(p); err != nil { if err := m.Unpack(p); err != nil {
// If ErrTruncated was returned, we still want to allow the user to use
// the message, but naively they can just check err if they don't want
// to use a truncated message
if err == ErrTruncated {
return m, err
}
return nil, err return nil, err
} }
co.rtt = time.Since(co.t)
if t := m.IsTsig(); t != nil { if t := m.IsTsig(); t != nil {
if _, ok := co.TsigSecret[t.Hdr.Name]; !ok { if _, ok := co.TsigSecret[t.Hdr.Name]; !ok {
return m, ErrSecret return m, ErrSecret
@ -191,6 +234,86 @@ func (co *Conn) ReadMsg() (*Msg, error) {
return m, err return m, err
} }
// ReadMsgHeader reads a DNS message, parses and populates hdr (when hdr is not nil).
// Returns message as a byte slice to be parsed with Msg.Unpack later on.
// Note that error handling on the message body is not possible as only the header is parsed.
func (co *Conn) ReadMsgHeader(hdr *Header) ([]byte, error) {
var (
p []byte
n int
err error
)
switch t := co.Conn.(type) {
case *net.TCPConn, *tls.Conn:
r := t.(io.Reader)
// First two bytes specify the length of the entire message.
l, err := tcpMsgLen(r)
if err != nil {
return nil, err
}
p = make([]byte, l)
n, err = tcpRead(r, p)
co.rtt = time.Since(co.t)
default:
if co.UDPSize > MinMsgSize {
p = make([]byte, co.UDPSize)
} else {
p = make([]byte, MinMsgSize)
}
n, err = co.Read(p)
co.rtt = time.Since(co.t)
}
if err != nil {
return nil, err
} else if n < headerSize {
return nil, ErrShortRead
}
p = p[:n]
if hdr != nil {
if _, err = UnpackStruct(hdr, p, 0); err != nil {
return nil, err
}
}
return p, err
}
// tcpMsgLen is a helper func to read first two bytes of stream as uint16 packet length.
func tcpMsgLen(t io.Reader) (int, error) {
p := []byte{0, 0}
n, err := t.Read(p)
if err != nil {
return 0, err
}
if n != 2 {
return 0, ErrShortRead
}
l, _ := unpackUint16(p, 0)
if l == 0 {
return 0, ErrShortRead
}
return int(l), nil
}
// tcpRead calls TCPConn.Read enough times to fill allocated buffer.
func tcpRead(t io.Reader, p []byte) (int, error) {
n, err := t.Read(p)
if err != nil {
return n, err
}
for n < len(p) {
j, err := t.Read(p[n:])
if err != nil {
return n, err
}
n += j
}
return n, err
}
// Read implements the net.Conn read method. // Read implements the net.Conn read method.
func (co *Conn) Read(p []byte) (n int, err error) { func (co *Conn) Read(p []byte) (n int, err error) {
if co.Conn == nil { if co.Conn == nil {
@ -199,32 +322,18 @@ func (co *Conn) Read(p []byte) (n int, err error) {
if len(p) < 2 { if len(p) < 2 {
return 0, io.ErrShortBuffer return 0, io.ErrShortBuffer
} }
if t, ok := co.Conn.(*net.TCPConn); ok { switch t := co.Conn.(type) {
n, err = t.Read(p[0:2]) case *net.TCPConn, *tls.Conn:
if err != nil || n != 2 { r := t.(io.Reader)
return n, err
l, err := tcpMsgLen(r)
if err != nil {
return 0, err
} }
l, _ := unpackUint16(p[0:2], 0) if l > len(p) {
if l == 0 {
return 0, ErrShortRead
}
if int(l) > len(p) {
return int(l), io.ErrShortBuffer return int(l), io.ErrShortBuffer
} }
n, err = t.Read(p[:l]) return tcpRead(r, p[:l])
if err != nil {
return n, err
}
i := n
for i < int(l) {
j, err := t.Read(p[i:int(l)])
if err != nil {
return i, err
}
i += j
}
n = i
return n, err
} }
// UDP connection // UDP connection
n, err = co.Conn.Read(p) n, err = co.Conn.Read(p)
@ -234,7 +343,7 @@ func (co *Conn) Read(p []byte) (n int, err error) {
return n, err return n, err
} }
// WriteMsg sends a message throught the connection co. // WriteMsg sends a message through the connection co.
// If the message m contains a TSIG record the transaction // If the message m contains a TSIG record the transaction
// signature is calculated. // signature is calculated.
func (co *Conn) WriteMsg(m *Msg) (err error) { func (co *Conn) WriteMsg(m *Msg) (err error) {
@ -245,7 +354,7 @@ func (co *Conn) WriteMsg(m *Msg) (err error) {
return ErrSecret return ErrSecret
} }
out, mac, err = TsigGenerate(m, co.TsigSecret[t.Hdr.Name], co.tsigRequestMAC, false) out, mac, err = TsigGenerate(m, co.TsigSecret[t.Hdr.Name], co.tsigRequestMAC, false)
// Set for the next read, allthough only used in zone transfers // Set for the next read, although only used in zone transfers
co.tsigRequestMAC = mac co.tsigRequestMAC = mac
} else { } else {
out, err = m.Pack() out, err = m.Pack()
@ -262,7 +371,10 @@ func (co *Conn) WriteMsg(m *Msg) (err error) {
// Write implements the net.Conn Write method. // Write implements the net.Conn Write method.
func (co *Conn) Write(p []byte) (n int, err error) { func (co *Conn) Write(p []byte) (n int, err error) {
if t, ok := co.Conn.(*net.TCPConn); ok { switch t := co.Conn.(type) {
case *net.TCPConn, *tls.Conn:
w := t.(io.Writer)
lp := len(p) lp := len(p)
if lp < 2 { if lp < 2 {
return 0, io.ErrShortBuffer return 0, io.ErrShortBuffer
@ -273,7 +385,7 @@ func (co *Conn) Write(p []byte) (n int, err error) {
l := make([]byte, 2, lp+2) l := make([]byte, 2, lp+2)
l[0], l[1] = packUint16(uint16(lp)) l[0], l[1] = packUint16(uint16(lp))
p = append(l, p...) p = append(l, p...)
n, err := io.Copy(t, bytes.NewReader(p)) n, err := io.Copy(w, bytes.NewReader(p))
return int(n), err return int(n), err
} }
n, err = co.Conn.(*net.UDPConn).Write(p) n, err = co.Conn.(*net.UDPConn).Write(p)
@ -290,7 +402,7 @@ func Dial(network, address string) (conn *Conn, err error) {
return conn, nil 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) { func DialTimeout(network, address string, timeout time.Duration) (conn *Conn, err error) {
conn = new(Conn) conn = new(Conn)
conn.Conn, err = net.DialTimeout(network, address, timeout) conn.Conn, err = net.DialTimeout(network, address, timeout)
@ -300,20 +412,25 @@ func DialTimeout(network, address string, timeout time.Duration) (conn *Conn, er
return conn, nil return conn, nil
} }
// Close implements the net.Conn Close method. // DialWithTLS connects to the address on the named network with TLS.
func (co *Conn) Close() error { return co.Conn.Close() } func DialWithTLS(network, address string, tlsConfig *tls.Config) (conn *Conn, err error) {
conn = new(Conn)
conn.Conn, err = tls.Dial(network, address, tlsConfig)
if err != nil {
return nil, err
}
return conn, nil
}
// LocalAddr implements the net.Conn LocalAddr method. // DialTimeoutWithTLS acts like DialWithTLS but takes a timeout.
func (co *Conn) LocalAddr() net.Addr { return co.Conn.LocalAddr() } func DialTimeoutWithTLS(network, address string, tlsConfig *tls.Config, timeout time.Duration) (conn *Conn, err error) {
var dialer net.Dialer
dialer.Timeout = timeout
// RemoteAddr implements the net.Conn RemoteAddr method. conn = new(Conn)
func (co *Conn) RemoteAddr() net.Addr { return co.Conn.RemoteAddr() } conn.Conn, err = tls.DialWithDialer(&dialer, network, address, tlsConfig)
if err != nil {
// SetDeadline implements the net.Conn SetDeadline method. return nil, err
func (co *Conn) SetDeadline(t time.Time) error { return co.Conn.SetDeadline(t) } }
return conn, nil
// SetReadDeadline implements the net.Conn SetReadDeadline method. }
func (co *Conn) SetReadDeadline(t time.Time) error { return co.Conn.SetReadDeadline(t) }
// SetWriteDeadline implements the net.Conn SetWriteDeadline method.
func (co *Conn) SetWriteDeadline(t time.Time) error { return co.Conn.SetWriteDeadline(t) }

View File

@ -7,7 +7,7 @@ import (
"strings" "strings"
) )
// Wraps the contents of the /etc/resolv.conf. // ClientConfig wraps the contents of the /etc/resolv.conf file.
type ClientConfig struct { type ClientConfig struct {
Servers []string // servers to use Servers []string // servers to use
Search []string // suffixes to append to local name Search []string // suffixes to append to local name
@ -26,14 +26,19 @@ func ClientConfigFromFile(resolvconf string) (*ClientConfig, error) {
} }
defer file.Close() defer file.Close()
c := new(ClientConfig) c := new(ClientConfig)
b := bufio.NewReader(file) scanner := bufio.NewScanner(file)
c.Servers = make([]string, 0) c.Servers = make([]string, 0)
c.Search = make([]string, 0) c.Search = make([]string, 0)
c.Port = "53" c.Port = "53"
c.Ndots = 1 c.Ndots = 1
c.Timeout = 5 c.Timeout = 5
c.Attempts = 2 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) f := strings.Fields(line)
if len(f) < 1 { if len(f) < 1 {
continue continue

View File

@ -24,7 +24,9 @@ func (dns *Msg) SetReply(request *Msg) *Msg {
return dns 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 { func (dns *Msg) SetQuestion(z string, t uint16) *Msg {
dns.Id = Id() dns.Id = Id()
dns.RecursionDesired = true dns.RecursionDesired = true
@ -33,7 +35,9 @@ func (dns *Msg) SetQuestion(z string, t uint16) *Msg {
return dns 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 { func (dns *Msg) SetNotify(z string) *Msg {
dns.Opcode = OpcodeNotify dns.Opcode = OpcodeNotify
dns.Authoritative = true dns.Authoritative = true
@ -73,13 +77,15 @@ func (dns *Msg) SetUpdate(z string) *Msg {
} }
// SetIxfr creates message for requesting an IXFR. // SetIxfr creates message for requesting an IXFR.
func (dns *Msg) SetIxfr(z string, serial uint32) *Msg { func (dns *Msg) SetIxfr(z string, serial uint32, ns, mbox string) *Msg {
dns.Id = Id() dns.Id = Id()
dns.Question = make([]Question, 1) dns.Question = make([]Question, 1)
dns.Ns = make([]RR, 1) dns.Ns = make([]RR, 1)
s := new(SOA) s := new(SOA)
s.Hdr = RR_Header{z, TypeSOA, ClassINET, defaultTtl, 0} s.Hdr = RR_Header{z, TypeSOA, ClassINET, defaultTtl, 0}
s.Serial = serial s.Serial = serial
s.Ns = ns
s.Mbox = mbox
dns.Question[0] = Question{z, TypeIXFR, ClassINET} dns.Question[0] = Question{z, TypeIXFR, ClassINET}
dns.Ns[0] = s dns.Ns[0] = s
return dns return dns
@ -144,11 +150,14 @@ func (dns *Msg) IsEdns0() *OPT {
return nil return nil
} }
// IsDomainName checks if s is a valid domainname, it returns // IsDomainName checks if s is a valid domain name, it returns the number of
// the number of labels and true, when a domain name is valid. // labels and true, when a domain name is valid. Note that non fully qualified
// Note that non fully qualified domain name is considered valid, in this case the // domain name is considered valid, in this case the last label is counted in
// last label is counted in the number of labels. // the number of labels. When false is returned the number of labels is not
// When false is returned the number of labels is not defined. // defined. Also note that this function is extremely liberal; almost any
// string is a valid domain name as the DNS is 8 bit protocol. It checks if each
// label fits in 63 characters, but there is no length check for the entire
// string s. I.e. a domain name longer than 255 characters is considered valid.
func IsDomainName(s string) (labels int, ok bool) { func IsDomainName(s string) (labels int, ok bool) {
_, labels, err := packDomainName(s, nil, 0, nil, false) _, labels, err := packDomainName(s, nil, 0, nil, false)
return labels, err == nil return labels, err == nil
@ -182,7 +191,34 @@ func IsFqdn(s string) bool {
return s[l-1] == '.' return s[l-1] == '.'
} }
// Fqdns return the fully qualified domain name from s. // IsRRset checks if a set of RRs is a valid RRset as defined by RFC 2181.
// This means the RRs need to have the same type, name, and class. Returns true
// if the RR set is valid, otherwise false.
func IsRRset(rrset []RR) bool {
if len(rrset) == 0 {
return false
}
if len(rrset) == 1 {
return true
}
rrHeader := rrset[0].Header()
rrType := rrHeader.Rrtype
rrClass := rrHeader.Class
rrName := rrHeader.Name
for _, rr := range rrset[1:] {
curRRHeader := rr.Header()
if curRRHeader.Rrtype != rrType || curRRHeader.Class != rrClass || curRRHeader.Name != rrName {
// Mismatch between the records, so this is not a valid rrset for
//signing/verifying
return false
}
}
return true
}
// Fqdn return the fully qualified domain name from s.
// If s is already fully qualified, it behaves as the identity function. // If s is already fully qualified, it behaves as the identity function.
func Fqdn(s string) string { func Fqdn(s string) string {
if IsFqdn(s) { if IsFqdn(s) {

119
vendor/github.com/miekg/dns/dns.go generated vendored
View File

@ -1,108 +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 package dns
import ( import "strconv"
"strconv"
)
const ( const (
year68 = 1 << 31 // For RFC1982 (Serial Arithmetic) calculations in 32 bits. year68 = 1 << 31 // For RFC1982 (Serial Arithmetic) calculations in 32 bits.
DefaultMsgSize = 4096 // Standard default for larger than 512 bytes. // DefaultMsgSize is the standard default for messages larger than 512 bytes.
MinMsgSize = 512 // Minimal size of a DNS packet. DefaultMsgSize = 4096
MaxMsgSize = 65536 // Largest possible DNS packet. // MinMsgSize is the minimal size of a DNS packet.
defaultTtl = 3600 // Default TTL. MinMsgSize = 512
// MaxMsgSize is the largest possible DNS packet.
MaxMsgSize = 65535
defaultTtl = 3600 // Default internal TTL.
) )
// Error represents a DNS error // Error represents a DNS error
@ -124,13 +32,11 @@ type RR interface {
String() string String() string
// copy returns a copy of the RR // copy returns a copy of the RR
copy() RR copy() RR
// len returns the length (in octects) of the uncompressed RR in wire format. // len returns the length (in octets) of the uncompressed RR in wire format.
len() int len() int
} }
// DNS resource records. // RR_Header is the header all DNS resource records share.
// There are many types of RRs,
// but they all share the same header.
type RR_Header struct { type RR_Header struct {
Name string `dns:"cdomain-name"` Name string `dns:"cdomain-name"`
Rrtype uint16 Rrtype uint16
@ -139,9 +45,10 @@ type RR_Header struct {
Rdlength uint16 // length of data after header 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 } 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) copy() RR { return nil }
func (h *RR_Header) copyHeader() *RR_Header { func (h *RR_Header) copyHeader() *RR_Header {

464
vendor/github.com/miekg/dns/dnssec.go generated vendored
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 package dns
import ( import (
@ -19,15 +6,14 @@ import (
"crypto/dsa" "crypto/dsa"
"crypto/ecdsa" "crypto/ecdsa"
"crypto/elliptic" "crypto/elliptic"
"crypto/md5" _ "crypto/md5"
"crypto/rand" "crypto/rand"
"crypto/rsa" "crypto/rsa"
"crypto/sha1" _ "crypto/sha1"
"crypto/sha256" _ "crypto/sha256"
"crypto/sha512" _ "crypto/sha512"
"encoding/asn1"
"encoding/hex" "encoding/hex"
"hash"
"io"
"math/big" "math/big"
"sort" "sort"
"strings" "strings"
@ -56,6 +42,38 @@ const (
PRIVATEOID uint8 = 254 PRIVATEOID uint8 = 254
) )
// Map for algorithm names.
var AlgorithmToString = map[uint8]string{
RSAMD5: "RSAMD5",
DH: "DH",
DSA: "DSA",
RSASHA1: "RSASHA1",
DSANSEC3SHA1: "DSA-NSEC3-SHA1",
RSASHA1NSEC3SHA1: "RSASHA1-NSEC3-SHA1",
RSASHA256: "RSASHA256",
RSASHA512: "RSASHA512",
ECCGOST: "ECC-GOST",
ECDSAP256SHA256: "ECDSAP256SHA256",
ECDSAP384SHA384: "ECDSAP384SHA384",
INDIRECT: "INDIRECT",
PRIVATEDNS: "PRIVATEDNS",
PRIVATEOID: "PRIVATEOID",
}
// Map of algorithm strings.
var StringToAlgorithm = reverseInt8(AlgorithmToString)
// Map of algorithm crypto hashes.
var AlgorithmToHash = map[uint8]crypto.Hash{
RSAMD5: crypto.MD5, // Deprecated in RFC 6725
RSASHA1: crypto.SHA1,
RSASHA1NSEC3SHA1: crypto.SHA1,
RSASHA256: crypto.SHA256,
ECDSAP256SHA256: crypto.SHA256,
ECDSAP384SHA384: crypto.SHA384,
RSASHA512: crypto.SHA512,
}
// DNSSEC hashing algorithm codes. // DNSSEC hashing algorithm codes.
const ( const (
_ uint8 = iota _ uint8 = iota
@ -66,6 +84,18 @@ const (
SHA512 // Experimental SHA512 // Experimental
) )
// Map for hash names.
var HashToString = map[uint8]string{
SHA1: "SHA1",
SHA256: "SHA256",
GOST94: "GOST94",
SHA384: "SHA384",
SHA512: "SHA512",
}
// Map of hash strings.
var StringToHash = reverseInt8(HashToString)
// DNSKEY flag values. // DNSKEY flag values.
const ( const (
SEP = 1 SEP = 1
@ -74,7 +104,7 @@ const (
) )
// The RRSIG needs to be converted to wireformat with some of // The RRSIG needs to be converted to wireformat with some of
// the rdata (the signature) missing. Use this struct to easy // the rdata (the signature) missing. Use this struct to ease
// the conversion (and re-use the pack/unpack functions). // the conversion (and re-use the pack/unpack functions).
type rrsigWireFmt struct { type rrsigWireFmt struct {
TypeCovered uint16 TypeCovered uint16
@ -182,35 +212,49 @@ func (k *DNSKEY) ToDS(h uint8) *DS {
// digest buffer // digest buffer
digest := append(owner, wire...) // another copy digest := append(owner, wire...) // another copy
var hash crypto.Hash
switch h { switch h {
case SHA1: case SHA1:
s := sha1.New() hash = crypto.SHA1
io.WriteString(s, string(digest))
ds.Digest = hex.EncodeToString(s.Sum(nil))
case SHA256: case SHA256:
s := sha256.New() hash = crypto.SHA256
io.WriteString(s, string(digest))
ds.Digest = hex.EncodeToString(s.Sum(nil))
case SHA384: case SHA384:
s := sha512.New384() hash = crypto.SHA384
io.WriteString(s, string(digest)) case SHA512:
ds.Digest = hex.EncodeToString(s.Sum(nil)) hash = crypto.SHA512
case GOST94:
/* I have no clue */
default: default:
return nil return nil
} }
s := hash.New()
s.Write(digest)
ds.Digest = hex.EncodeToString(s.Sum(nil))
return ds return ds
} }
// Sign signs an RRSet. The signature needs to be filled in with // ToCDNSKEY converts a DNSKEY record to a CDNSKEY record.
// the values: Inception, Expiration, KeyTag, SignerName and Algorithm. func (k *DNSKEY) ToCDNSKEY() *CDNSKEY {
// The rest is copied from the RRset. Sign returns true when the signing went OK, c := &CDNSKEY{DNSKEY: *k}
// otherwise false. c.Hdr = *k.Hdr.copyHeader()
// There is no check if RRSet is a proper (RFC 2181) RRSet. c.Hdr.Rrtype = TypeCDNSKEY
// If OrigTTL is non zero, it is used as-is, otherwise the TTL of the RRset return c
// is used as the OrigTTL. }
func (rr *RRSIG) Sign(k PrivateKey, rrset []RR) error {
// 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 a non-nill error when the signing went OK.
// There is no check if RRSet is a proper (RFC 2181) RRSet. If OrigTTL is non
// zero, it is used as-is, otherwise the TTL of the RRset is used as the
// OrigTTL.
func (rr *RRSIG) Sign(k crypto.Signer, rrset []RR) error {
if k == nil { if k == nil {
return ErrPrivKey return ErrPrivKey
} }
@ -256,72 +300,72 @@ func (rr *RRSIG) Sign(k PrivateKey, rrset []RR) error {
} }
signdata = append(signdata, wire...) signdata = append(signdata, wire...)
var sighash []byte hash, ok := AlgorithmToHash[rr.Algorithm]
var h hash.Hash if !ok {
var ch crypto.Hash // Only need for RSA
var intlen int
switch rr.Algorithm {
case DSA, DSANSEC3SHA1:
// Implicit in the ParameterSizes
case RSASHA1, RSASHA1NSEC3SHA1:
h = sha1.New()
ch = crypto.SHA1
case RSASHA256, ECDSAP256SHA256:
h = sha256.New()
ch = crypto.SHA256
intlen = 32
case ECDSAP384SHA384:
h = sha512.New384()
intlen = 48
case RSASHA512:
h = sha512.New()
ch = crypto.SHA512
case RSAMD5:
fallthrough // Deprecated in RFC 6725
default:
return ErrAlg return ErrAlg
} }
io.WriteString(h, string(signdata))
sighash = h.Sum(nil)
switch p := k.(type) { h := hash.New()
case *dsa.PrivateKey: h.Write(signdata)
r1, s1, err := dsa.Sign(rand.Reader, p, sighash)
if err != nil { signature, err := sign(k, h.Sum(nil), hash, rr.Algorithm)
return err if err != nil {
} return err
signature := []byte{0x4D} // T value, here the ASCII M for Miek (not used in DNSSEC)
signature = append(signature, intToBytes(r1, 20)...)
signature = append(signature, intToBytes(s1, 20)...)
rr.Signature = toBase64(signature)
case *rsa.PrivateKey:
// We can use nil as rand.Reader here (says AGL)
signature, err := rsa.SignPKCS1v15(nil, p, ch, sighash)
if err != nil {
return err
}
rr.Signature = toBase64(signature)
case *ecdsa.PrivateKey:
r1, s1, err := ecdsa.Sign(rand.Reader, p, sighash)
if err != nil {
return err
}
signature := intToBytes(r1, intlen)
signature = append(signature, intToBytes(s1, intlen)...)
rr.Signature = toBase64(signature)
default:
// Not given the correct key
return ErrKeyAlg
} }
rr.Signature = toBase64(signature)
return nil return nil
} }
func sign(k crypto.Signer, hashed []byte, hash crypto.Hash, alg uint8) ([]byte, error) {
signature, err := k.Sign(rand.Reader, hashed, hash)
if err != nil {
return nil, err
}
switch alg {
case RSASHA1, RSASHA1NSEC3SHA1, RSASHA256, RSASHA512:
return signature, nil
case ECDSAP256SHA256, ECDSAP384SHA384:
ecdsaSignature := &struct {
R, S *big.Int
}{}
if _, err := asn1.Unmarshal(signature, ecdsaSignature); err != nil {
return nil, err
}
var intlen int
switch alg {
case ECDSAP256SHA256:
intlen = 32
case ECDSAP384SHA384:
intlen = 48
}
signature := intToBytes(ecdsaSignature.R, intlen)
signature = append(signature, intToBytes(ecdsaSignature.S, intlen)...)
return signature, nil
// There is no defined interface for what a DSA backed crypto.Signer returns
case DSA, DSANSEC3SHA1:
// t := divRoundUp(divRoundUp(p.PublicKey.Y.BitLen(), 8)-64, 8)
// signature := []byte{byte(t)}
// signature = append(signature, intToBytes(r1, 20)...)
// signature = append(signature, intToBytes(s1, 20)...)
// rr.Signature = signature
}
return nil, ErrAlg
}
// Verify validates an RRSet with the signature and key. This is only the // Verify validates an RRSet with the signature and key. This is only the
// cryptographic test, the signature validity period must be checked separately. // cryptographic test, the signature validity period must be checked separately.
// This function copies the rdata of some RRs (to lowercase domain names) for the validation to work. // This function copies the rdata of some RRs (to lowercase domain names) for the validation to work.
func (rr *RRSIG) Verify(k *DNSKEY, rrset []RR) error { func (rr *RRSIG) Verify(k *DNSKEY, rrset []RR) error {
// First the easy checks // First the easy checks
if len(rrset) == 0 { if !IsRRset(rrset) {
return ErrRRset return ErrRRset
} }
if rr.KeyTag != k.KeyTag() { if rr.KeyTag != k.KeyTag() {
@ -339,14 +383,17 @@ func (rr *RRSIG) Verify(k *DNSKEY, rrset []RR) error {
if k.Protocol != 3 { if k.Protocol != 3 {
return ErrKey return ErrKey
} }
for _, r := range rrset {
if r.Header().Class != rr.Hdr.Class { // IsRRset checked that we have at least one RR and that the RRs in
return ErrRRset // the set have consistent type, class, and name. Also check that type and
} // class matches the RRSIG record.
if r.Header().Rrtype != rr.TypeCovered { if rrset[0].Header().Class != rr.Hdr.Class {
return ErrRRset return ErrRRset
}
} }
if rrset[0].Header().Rrtype != rr.TypeCovered {
return ErrRRset
}
// RFC 4035 5.3.2. Reconstructing the Signed Data // RFC 4035 5.3.2. Reconstructing the Signed Data
// Copy the sig, except the rrsig data // Copy the sig, except the rrsig data
sigwire := new(rrsigWireFmt) sigwire := new(rrsigWireFmt)
@ -373,8 +420,13 @@ func (rr *RRSIG) Verify(k *DNSKEY, rrset []RR) error {
sigbuf := rr.sigBuf() // Get the binary signature data sigbuf := rr.sigBuf() // Get the binary signature data
if rr.Algorithm == PRIVATEDNS { // PRIVATEOID if rr.Algorithm == PRIVATEDNS { // PRIVATEOID
// TODO(mg) // TODO(miek)
// remove the domain name and assume its our // remove the domain name and assume its ours?
}
hash, ok := AlgorithmToHash[rr.Algorithm]
if !ok {
return ErrAlg
} }
switch rr.Algorithm { switch rr.Algorithm {
@ -384,57 +436,37 @@ func (rr *RRSIG) Verify(k *DNSKEY, rrset []RR) error {
if pubkey == nil { if pubkey == nil {
return ErrKey return ErrKey
} }
// Setup the hash as defined for this alg.
var h hash.Hash h := hash.New()
var ch crypto.Hash h.Write(signeddata)
switch rr.Algorithm { return rsa.VerifyPKCS1v15(pubkey, hash, h.Sum(nil), sigbuf)
case RSAMD5:
h = md5.New()
ch = crypto.MD5
case RSASHA1, RSASHA1NSEC3SHA1:
h = sha1.New()
ch = crypto.SHA1
case RSASHA256:
h = sha256.New()
ch = crypto.SHA256
case RSASHA512:
h = sha512.New()
ch = crypto.SHA512
}
io.WriteString(h, string(signeddata))
sighash := h.Sum(nil)
return rsa.VerifyPKCS1v15(pubkey, ch, sighash, sigbuf)
case ECDSAP256SHA256, ECDSAP384SHA384: case ECDSAP256SHA256, ECDSAP384SHA384:
pubkey := k.publicKeyCurve() pubkey := k.publicKeyECDSA()
if pubkey == nil { if pubkey == nil {
return ErrKey return ErrKey
} }
var h hash.Hash
switch rr.Algorithm {
case ECDSAP256SHA256:
h = sha256.New()
case ECDSAP384SHA384:
h = sha512.New384()
}
io.WriteString(h, string(signeddata))
sighash := h.Sum(nil)
// Split sigbuf into the r and s coordinates // Split sigbuf into the r and s coordinates
r := big.NewInt(0) r := new(big.Int).SetBytes(sigbuf[:len(sigbuf)/2])
r.SetBytes(sigbuf[:len(sigbuf)/2]) s := new(big.Int).SetBytes(sigbuf[len(sigbuf)/2:])
s := big.NewInt(0)
s.SetBytes(sigbuf[len(sigbuf)/2:]) h := hash.New()
if ecdsa.Verify(pubkey, sighash, r, s) { h.Write(signeddata)
if ecdsa.Verify(pubkey, h.Sum(nil), r, s) {
return nil return nil
} }
return ErrSig return ErrSig
default:
return ErrAlg
} }
// Unknown alg
return ErrAlg
} }
// ValidityPeriod uses RFC1982 serial arithmetic to calculate // ValidityPeriod uses RFC1982 serial arithmetic to calculate
// if a signature period is valid. If t is the zero time, the // if a signature period is valid. If t is the zero time, the
// current time is taken other t is. // current time is taken other t is. Returns true if the signature
// is valid at the given time, otherwise returns false.
func (rr *RRSIG) ValidityPeriod(t time.Time) bool { func (rr *RRSIG) ValidityPeriod(t time.Time) bool {
var utc int64 var utc int64
if t.IsZero() { if t.IsZero() {
@ -450,39 +482,14 @@ func (rr *RRSIG) ValidityPeriod(t time.Time) bool {
} }
// Return the signatures base64 encodedig sigdata as a byte slice. // Return the signatures base64 encodedig sigdata as a byte slice.
func (s *RRSIG) sigBuf() []byte { func (rr *RRSIG) sigBuf() []byte {
sigbuf, err := fromBase64([]byte(s.Signature)) sigbuf, err := fromBase64([]byte(rr.Signature))
if err != nil { if err != nil {
return nil return nil
} }
return sigbuf return sigbuf
} }
// setPublicKeyInPrivate sets the public key in the private key.
func (k *DNSKEY) setPublicKeyInPrivate(p PrivateKey) bool {
switch t := p.(type) {
case *dsa.PrivateKey:
x := k.publicKeyDSA()
if x == nil {
return false
}
t.PublicKey = *x
case *rsa.PrivateKey:
x := k.publicKeyRSA()
if x == nil {
return false
}
t.PublicKey = *x
case *ecdsa.PrivateKey:
x := k.publicKeyCurve()
if x == nil {
return false
}
t.PublicKey = *x
}
return true
}
// publicKeyRSA returns the RSA public key from a DNSKEY record. // publicKeyRSA returns the RSA public key from a DNSKEY record.
func (k *DNSKEY) publicKeyRSA() *rsa.PublicKey { func (k *DNSKEY) publicKeyRSA() *rsa.PublicKey {
keybuf, err := fromBase64([]byte(k.PublicKey)) keybuf, err := fromBase64([]byte(k.PublicKey))
@ -521,8 +528,8 @@ func (k *DNSKEY) publicKeyRSA() *rsa.PublicKey {
return pubkey return pubkey
} }
// publicKeyCurve returns the Curve public key from the DNSKEY record. // publicKeyECDSA returns the Curve public key from the DNSKEY record.
func (k *DNSKEY) publicKeyCurve() *ecdsa.PublicKey { func (k *DNSKEY) publicKeyECDSA() *ecdsa.PublicKey {
keybuf, err := fromBase64([]byte(k.PublicKey)) keybuf, err := fromBase64([]byte(k.PublicKey))
if err != nil { if err != nil {
return nil return nil
@ -573,81 +580,6 @@ func (k *DNSKEY) publicKeyDSA() *dsa.PublicKey {
return pubkey return pubkey
} }
// Set the public key (the value E and N)
func (k *DNSKEY) setPublicKeyRSA(_E int, _N *big.Int) bool {
if _E == 0 || _N == nil {
return false
}
buf := exponentToBuf(_E)
buf = append(buf, _N.Bytes()...)
k.PublicKey = toBase64(buf)
return true
}
// Set the public key for Elliptic Curves
func (k *DNSKEY) setPublicKeyCurve(_X, _Y *big.Int) bool {
if _X == nil || _Y == nil {
return false
}
var intlen int
switch k.Algorithm {
case ECDSAP256SHA256:
intlen = 32
case ECDSAP384SHA384:
intlen = 48
}
k.PublicKey = toBase64(curveToBuf(_X, _Y, intlen))
return true
}
// Set the public key for DSA
func (k *DNSKEY) setPublicKeyDSA(_Q, _P, _G, _Y *big.Int) bool {
if _Q == nil || _P == nil || _G == nil || _Y == nil {
return false
}
buf := dsaToBuf(_Q, _P, _G, _Y)
k.PublicKey = toBase64(buf)
return true
}
// Set the public key (the values E and N) for RSA
// RFC 3110: Section 2. RSA Public KEY Resource Records
func exponentToBuf(_E int) []byte {
var buf []byte
i := big.NewInt(int64(_E))
if len(i.Bytes()) < 256 {
buf = make([]byte, 1)
buf[0] = uint8(len(i.Bytes()))
} else {
buf = make([]byte, 3)
buf[0] = 0
buf[1] = uint8(len(i.Bytes()) >> 8)
buf[2] = uint8(len(i.Bytes()))
}
buf = append(buf, i.Bytes()...)
return buf
}
// Set the public key for X and Y for Curve. The two
// values are just concatenated.
func curveToBuf(_X, _Y *big.Int, intlen int) []byte {
buf := intToBytes(_X, intlen)
buf = append(buf, intToBytes(_Y, intlen)...)
return buf
}
// Set the public key for X and Y for Curve. The two
// values are just concatenated.
func dsaToBuf(_Q, _P, _G, _Y *big.Int) []byte {
t := divRoundUp(divRoundUp(_G.BitLen(), 8)-64, 8)
buf := []byte{byte(t)}
buf = append(buf, intToBytes(_Q, 20)...)
buf = append(buf, intToBytes(_P, 64+t*8)...)
buf = append(buf, intToBytes(_G, 64+t*8)...)
buf = append(buf, intToBytes(_Y, 64+t*8)...)
return buf
}
type wireSlice [][]byte type wireSlice [][]byte
func (p wireSlice) Len() int { return len(p) } func (p wireSlice) Len() int { return len(p) }
@ -676,6 +608,12 @@ func rawSignatureData(rrset []RR, s *RRSIG) (buf []byte, err error) {
// NS, MD, MF, CNAME, SOA, MB, MG, MR, PTR, // NS, MD, MF, CNAME, SOA, MB, MG, MR, PTR,
// HINFO, MINFO, MX, RP, AFSDB, RT, SIG, PX, NXT, NAPTR, KX, // HINFO, MINFO, MX, RP, AFSDB, RT, SIG, PX, NXT, NAPTR, KX,
// SRV, DNAME, A6 // SRV, DNAME, A6
//
// RFC 6840 - Clarifications and Implementation Notes for DNS Security (DNSSEC):
// Section 6.2 of [RFC4034] also erroneously lists HINFO as a record
// that needs conversion to lowercase, and twice at that. Since HINFO
// records contain no domain names, they are not subject to case
// conversion.
switch x := r1.(type) { switch x := r1.(type) {
case *NS: case *NS:
x.Ns = strings.ToLower(x.Ns) x.Ns = strings.ToLower(x.Ns)
@ -716,41 +654,11 @@ func rawSignatureData(rrset []RR, s *RRSIG) (buf []byte, err error) {
wires[i] = wire wires[i] = wire
} }
sort.Sort(wires) 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...) buf = append(buf, wire...)
} }
return buf, nil return buf, nil
} }
// Map for algorithm names.
var AlgorithmToString = map[uint8]string{
RSAMD5: "RSAMD5",
DH: "DH",
DSA: "DSA",
RSASHA1: "RSASHA1",
DSANSEC3SHA1: "DSA-NSEC3-SHA1",
RSASHA1NSEC3SHA1: "RSASHA1-NSEC3-SHA1",
RSASHA256: "RSASHA256",
RSASHA512: "RSASHA512",
ECCGOST: "ECC-GOST",
ECDSAP256SHA256: "ECDSAP256SHA256",
ECDSAP384SHA384: "ECDSAP384SHA384",
INDIRECT: "INDIRECT",
PRIVATEDNS: "PRIVATEDNS",
PRIVATEOID: "PRIVATEOID",
}
// Map of algorithm strings.
var StringToAlgorithm = reverseInt8(AlgorithmToString)
// Map for hash names.
var HashToString = map[uint8]string{
SHA1: "SHA1",
SHA256: "SHA256",
GOST94: "GOST94",
SHA384: "SHA384",
SHA512: "SHA512",
}
// Map of hash strings.
var StringToHash = reverseInt8(HashToString)

156
vendor/github.com/miekg/dns/dnssec_keygen.go generated vendored Normal file
View File

@ -0,0 +1,156 @@
package dns
import (
"crypto"
"crypto/dsa"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/rsa"
"math/big"
)
// Generate generates a DNSKEY of the given bit size.
// The public part is put inside the DNSKEY record.
// The Algorithm in the key must be set as this will define
// 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 (k *DNSKEY) Generate(bits int) (crypto.PrivateKey, error) {
switch k.Algorithm {
case DSA, DSANSEC3SHA1:
if bits != 1024 {
return nil, ErrKeySize
}
case RSAMD5, RSASHA1, RSASHA256, RSASHA1NSEC3SHA1:
if bits < 512 || bits > 4096 {
return nil, ErrKeySize
}
case RSASHA512:
if bits < 1024 || bits > 4096 {
return nil, ErrKeySize
}
case ECDSAP256SHA256:
if bits != 256 {
return nil, ErrKeySize
}
case ECDSAP384SHA384:
if bits != 384 {
return nil, ErrKeySize
}
}
switch k.Algorithm {
case DSA, DSANSEC3SHA1:
params := new(dsa.Parameters)
if err := dsa.GenerateParameters(params, rand.Reader, dsa.L1024N160); err != nil {
return nil, err
}
priv := new(dsa.PrivateKey)
priv.PublicKey.Parameters = *params
err := dsa.GenerateKey(priv, rand.Reader)
if err != nil {
return nil, err
}
k.setPublicKeyDSA(params.Q, params.P, params.G, priv.PublicKey.Y)
return priv, nil
case RSAMD5, RSASHA1, RSASHA256, RSASHA512, RSASHA1NSEC3SHA1:
priv, err := rsa.GenerateKey(rand.Reader, bits)
if err != nil {
return nil, err
}
k.setPublicKeyRSA(priv.PublicKey.E, priv.PublicKey.N)
return priv, nil
case ECDSAP256SHA256, ECDSAP384SHA384:
var c elliptic.Curve
switch k.Algorithm {
case ECDSAP256SHA256:
c = elliptic.P256()
case ECDSAP384SHA384:
c = elliptic.P384()
}
priv, err := ecdsa.GenerateKey(c, rand.Reader)
if err != nil {
return nil, err
}
k.setPublicKeyECDSA(priv.PublicKey.X, priv.PublicKey.Y)
return priv, nil
default:
return nil, ErrAlg
}
}
// Set the public key (the value E and N)
func (k *DNSKEY) setPublicKeyRSA(_E int, _N *big.Int) bool {
if _E == 0 || _N == nil {
return false
}
buf := exponentToBuf(_E)
buf = append(buf, _N.Bytes()...)
k.PublicKey = toBase64(buf)
return true
}
// Set the public key for Elliptic Curves
func (k *DNSKEY) setPublicKeyECDSA(_X, _Y *big.Int) bool {
if _X == nil || _Y == nil {
return false
}
var intlen int
switch k.Algorithm {
case ECDSAP256SHA256:
intlen = 32
case ECDSAP384SHA384:
intlen = 48
}
k.PublicKey = toBase64(curveToBuf(_X, _Y, intlen))
return true
}
// Set the public key for DSA
func (k *DNSKEY) setPublicKeyDSA(_Q, _P, _G, _Y *big.Int) bool {
if _Q == nil || _P == nil || _G == nil || _Y == nil {
return false
}
buf := dsaToBuf(_Q, _P, _G, _Y)
k.PublicKey = toBase64(buf)
return true
}
// Set the public key (the values E and N) for RSA
// RFC 3110: Section 2. RSA Public KEY Resource Records
func exponentToBuf(_E int) []byte {
var buf []byte
i := big.NewInt(int64(_E))
if len(i.Bytes()) < 256 {
buf = make([]byte, 1)
buf[0] = uint8(len(i.Bytes()))
} else {
buf = make([]byte, 3)
buf[0] = 0
buf[1] = uint8(len(i.Bytes()) >> 8)
buf[2] = uint8(len(i.Bytes()))
}
buf = append(buf, i.Bytes()...)
return buf
}
// Set the public key for X and Y for Curve. The two
// values are just concatenated.
func curveToBuf(_X, _Y *big.Int, intlen int) []byte {
buf := intToBytes(_X, intlen)
buf = append(buf, intToBytes(_Y, intlen)...)
return buf
}
// Set the public key for X and Y for Curve. The two
// values are just concatenated.
func dsaToBuf(_Q, _P, _G, _Y *big.Int) []byte {
t := divRoundUp(divRoundUp(_G.BitLen(), 8)-64, 8)
buf := []byte{byte(t)}
buf = append(buf, intToBytes(_Q, 20)...)
buf = append(buf, intToBytes(_P, 64+t*8)...)
buf = append(buf, intToBytes(_G, 64+t*8)...)
buf = append(buf, intToBytes(_Y, 64+t*8)...)
return buf
}

View File

@ -1,15 +1,19 @@
package dns package dns
import ( import (
"crypto"
"crypto/dsa" "crypto/dsa"
"crypto/ecdsa" "crypto/ecdsa"
"crypto/rsa" "crypto/rsa"
"io" "io"
"math/big" "math/big"
"strconv"
"strings" "strings"
) )
func (k *DNSKEY) NewPrivateKey(s string) (PrivateKey, error) { // 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) (crypto.PrivateKey, error) {
if s[len(s)-1] != '\n' { // We need a closing newline if s[len(s)-1] != '\n' { // We need a closing newline
return k.ReadPrivateKey(strings.NewReader(s+"\n"), "") return k.ReadPrivateKey(strings.NewReader(s+"\n"), "")
} }
@ -18,9 +22,9 @@ func (k *DNSKEY) NewPrivateKey(s string) (PrivateKey, error) {
// ReadPrivateKey reads a private key from the io.Reader q. The string file is // ReadPrivateKey reads a private key from the io.Reader q. The string file is
// only used in error reporting. // only used in error reporting.
// The public key must be // The public key must be known, because some cryptographic algorithms embed
// known, because some cryptographic algorithms embed the public inside the privatekey. // the public inside the privatekey.
func (k *DNSKEY) ReadPrivateKey(q io.Reader, file string) (PrivateKey, error) { func (k *DNSKEY) ReadPrivateKey(q io.Reader, file string) (crypto.PrivateKey, error) {
m, e := parseKey(q, file) m, e := parseKey(q, file)
if m == nil { if m == nil {
return nil, e return nil, e
@ -32,57 +36,63 @@ func (k *DNSKEY) ReadPrivateKey(q io.Reader, file string) (PrivateKey, error) {
return nil, ErrPrivKey return nil, ErrPrivKey
} }
// TODO(mg): check if the pubkey matches the private key // TODO(mg): check if the pubkey matches the private key
switch m["algorithm"] { algo, err := strconv.Atoi(strings.SplitN(m["algorithm"], " ", 2)[0])
case "3 (DSA)": if err != nil {
p, e := readPrivateKeyDSA(m) return nil, ErrPrivKey
if e != nil { }
return nil, e switch uint8(algo) {
} case DSA:
if !k.setPublicKeyInPrivate(p) { priv, e := readPrivateKeyDSA(m)
return nil, ErrKey if e != nil {
} return nil, e
return p, e }
case "1 (RSAMD5)": pub := k.publicKeyDSA()
fallthrough if pub == nil {
case "5 (RSASHA1)": return nil, ErrKey
fallthrough }
case "7 (RSASHA1NSEC3SHA1)": priv.PublicKey = *pub
fallthrough return priv, e
case "8 (RSASHA256)": case RSAMD5:
fallthrough fallthrough
case "10 (RSASHA512)": case RSASHA1:
p, e := readPrivateKeyRSA(m) fallthrough
if e != nil { case RSASHA1NSEC3SHA1:
return nil, e fallthrough
} case RSASHA256:
if !k.setPublicKeyInPrivate(p) { fallthrough
return nil, ErrKey case RSASHA512:
} priv, e := readPrivateKeyRSA(m)
return p, e if e != nil {
case "12 (ECC-GOST)": return nil, e
p, e := readPrivateKeyGOST(m) }
if e != nil { pub := k.publicKeyRSA()
return nil, e if pub == nil {
} return nil, ErrKey
// setPublicKeyInPrivate(p) }
return p, e priv.PublicKey = *pub
case "13 (ECDSAP256SHA256)": return priv, e
fallthrough case ECCGOST:
case "14 (ECDSAP384SHA384)": return nil, ErrPrivKey
p, e := readPrivateKeyECDSA(m) case ECDSAP256SHA256:
if e != nil { fallthrough
return nil, e case ECDSAP384SHA384:
} priv, e := readPrivateKeyECDSA(m)
if !k.setPublicKeyInPrivate(p) { if e != nil {
return nil, ErrKey return nil, e
} }
return p, e pub := k.publicKeyECDSA()
if pub == nil {
return nil, ErrKey
}
priv.PublicKey = *pub
return priv, e
default:
return nil, ErrPrivKey
} }
return nil, ErrPrivKey
} }
// Read a private key (file) string and create a public key. Return the private key. // Read a private key (file) string and create a public key. Return the private key.
func readPrivateKeyRSA(m map[string]string) (PrivateKey, error) { func readPrivateKeyRSA(m map[string]string) (*rsa.PrivateKey, error) {
p := new(rsa.PrivateKey) p := new(rsa.PrivateKey)
p.Primes = []*big.Int{nil, nil} p.Primes = []*big.Int{nil, nil}
for k, v := range m { for k, v := range m {
@ -119,7 +129,7 @@ func readPrivateKeyRSA(m map[string]string) (PrivateKey, error) {
return p, nil return p, nil
} }
func readPrivateKeyDSA(m map[string]string) (PrivateKey, error) { func readPrivateKeyDSA(m map[string]string) (*dsa.PrivateKey, error) {
p := new(dsa.PrivateKey) p := new(dsa.PrivateKey)
p.X = big.NewInt(0) p.X = big.NewInt(0)
for k, v := range m { for k, v := range m {
@ -137,7 +147,7 @@ func readPrivateKeyDSA(m map[string]string) (PrivateKey, error) {
return p, nil return p, nil
} }
func readPrivateKeyECDSA(m map[string]string) (PrivateKey, error) { func readPrivateKeyECDSA(m map[string]string) (*ecdsa.PrivateKey, error) {
p := new(ecdsa.PrivateKey) p := new(ecdsa.PrivateKey)
p.D = big.NewInt(0) p.D = big.NewInt(0)
// TODO: validate that the required flags are present // TODO: validate that the required flags are present
@ -156,11 +166,6 @@ func readPrivateKeyECDSA(m map[string]string) (PrivateKey, error) {
return p, nil return p, nil
} }
func readPrivateKeyGOST(m map[string]string) (PrivateKey, error) {
// TODO(miek)
return nil, nil
}
// parseKey reads a private key from r. It returns a map[string]string, // parseKey reads a private key from r. It returns a map[string]string,
// with the key-value pairs, or an error when the file is not correct. // with the key-value pairs, or an error when the file is not correct.
func parseKey(r io.Reader, file string) (map[string]string, error) { func parseKey(r io.Reader, file string) (map[string]string, error) {
@ -173,9 +178,9 @@ func parseKey(r io.Reader, file string) (map[string]string, error) {
for l := range c { for l := range c {
// It should alternate // It should alternate
switch l.value { switch l.value {
case _KEY: case zKey:
k = l.token k = l.token
case _VALUE: case zValue:
if k == "" { if k == "" {
return nil, &ParseError{file, "no private key seen", l} return nil, &ParseError{file, "no private key seen", l}
} }
@ -205,14 +210,14 @@ func klexer(s *scan, c chan lex) {
} }
l.token = str l.token = str
if key { if key {
l.value = _KEY l.value = zKey
c <- l c <- l
// Next token is a space, eat it // Next token is a space, eat it
s.tokenText() s.tokenText()
key = false key = false
str = "" str = ""
} else { } else {
l.value = _VALUE l.value = zValue
} }
case ';': case ';':
commt = true commt = true
@ -221,7 +226,7 @@ func klexer(s *scan, c chan lex) {
// Reset a comment // Reset a comment
commt = false commt = false
} }
l.value = _VALUE l.value = zValue
l.token = str l.token = str
c <- l c <- l
str = "" str = ""
@ -238,7 +243,7 @@ func klexer(s *scan, c chan lex) {
if len(str) > 0 { if len(str) > 0 {
// Send remainder // Send remainder
l.token = str l.token = str
l.value = _VALUE l.value = zValue
c <- l c <- l
} }
} }

85
vendor/github.com/miekg/dns/dnssec_privkey.go generated vendored Normal file
View File

@ -0,0 +1,85 @@
package dns
import (
"crypto"
"crypto/dsa"
"crypto/ecdsa"
"crypto/rsa"
"math/big"
"strconv"
)
const format = "Private-key-format: v1.3\n"
// PrivateKeyString converts a PrivateKey to a string. This string has the same
// format as the private-key-file of BIND9 (Private-key-format: v1.3).
// It needs some info from the key (the algorithm), so its a method of the DNSKEY
// It supports rsa.PrivateKey, ecdsa.PrivateKey and dsa.PrivateKey
func (r *DNSKEY) PrivateKeyString(p crypto.PrivateKey) string {
algorithm := strconv.Itoa(int(r.Algorithm))
algorithm += " (" + AlgorithmToString[r.Algorithm] + ")"
switch p := p.(type) {
case *rsa.PrivateKey:
modulus := toBase64(p.PublicKey.N.Bytes())
e := big.NewInt(int64(p.PublicKey.E))
publicExponent := toBase64(e.Bytes())
privateExponent := toBase64(p.D.Bytes())
prime1 := toBase64(p.Primes[0].Bytes())
prime2 := toBase64(p.Primes[1].Bytes())
// 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)
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 +
"Algorithm: " + algorithm + "\n" +
"Modulus: " + modulus + "\n" +
"PublicExponent: " + publicExponent + "\n" +
"PrivateExponent: " + privateExponent + "\n" +
"Prime1: " + prime1 + "\n" +
"Prime2: " + prime2 + "\n" +
"Exponent1: " + exponent1 + "\n" +
"Exponent2: " + exponent2 + "\n" +
"Coefficient: " + coefficient + "\n"
case *ecdsa.PrivateKey:
var intlen int
switch r.Algorithm {
case ECDSAP256SHA256:
intlen = 32
case ECDSAP384SHA384:
intlen = 48
}
private := toBase64(intToBytes(p.D, intlen))
return format +
"Algorithm: " + algorithm + "\n" +
"PrivateKey: " + private + "\n"
case *dsa.PrivateKey:
T := divRoundUp(divRoundUp(p.PublicKey.Parameters.G.BitLen(), 8)-64, 8)
prime := toBase64(intToBytes(p.PublicKey.Parameters.P, 64+T*8))
subprime := toBase64(intToBytes(p.PublicKey.Parameters.Q, 20))
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 +
"Algorithm: " + algorithm + "\n" +
"Prime(p): " + prime + "\n" +
"Subprime(q): " + subprime + "\n" +
"Base(g): " + base + "\n" +
"Private_value(x): " + priv + "\n" +
"Public_value(y): " + pub + "\n"
default:
return ""
}
}

251
vendor/github.com/miekg/dns/doc.go generated vendored Normal file
View File

@ -0,0 +1,251 @@
/*
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 a 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(dns.Msg)
m.SetReply(r)
if r.IsTsig() != nil {
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.
see http://miek.nl/posts/2014/Sep/21/Private%20RRs%20and%20IDN%20in%20Go%20DNS/ for more
information.
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

156
vendor/github.com/miekg/dns/edns.go generated vendored
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 package dns
import ( import (
@ -44,18 +18,18 @@ const (
EDNS0SUBNET = 0x8 // client-subnet (RFC6891) EDNS0SUBNET = 0x8 // client-subnet (RFC6891)
EDNS0EXPIRE = 0x9 // EDNS0 expire EDNS0EXPIRE = 0x9 // EDNS0 expire
EDNS0SUBNETDRAFT = 0x50fa // Don't use! Use EDNS0SUBNET 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 _DO = 1 << 15 // dnssec ok
) )
// OPT is the EDNS0 RR appended to messages to convey extra (meta) information.
// See RFC 6891.
type OPT struct { type OPT struct {
Hdr RR_Header Hdr RR_Header
Option []EDNS0 `dns:"opt"` Option []EDNS0 `dns:"opt"`
} }
func (rr *OPT) Header() *RR_Header {
return &rr.Hdr
}
func (rr *OPT) String() string { func (rr *OPT) String() string {
s := "\n;; OPT PSEUDOSECTION:\n; EDNS: version " + strconv.Itoa(int(rr.Version())) + "; " s := "\n;; OPT PSEUDOSECTION:\n; EDNS: version " + strconv.Itoa(int(rr.Version())) + "; "
if rr.Do() { if rr.Do() {
@ -92,6 +66,8 @@ func (rr *OPT) String() string {
s += "\n; DS HASH UNDERSTOOD: " + o.String() s += "\n; DS HASH UNDERSTOOD: " + o.String()
case *EDNS0_N3U: case *EDNS0_N3U:
s += "\n; NSEC3 HASH UNDERSTOOD: " + o.String() s += "\n; NSEC3 HASH UNDERSTOOD: " + o.String()
case *EDNS0_LOCAL:
s += "\n; LOCAL OPT: " + o.String()
} }
} }
return s return s
@ -100,16 +76,13 @@ func (rr *OPT) String() string {
func (rr *OPT) len() int { func (rr *OPT) len() int {
l := rr.Hdr.len() l := rr.Hdr.len()
for i := 0; i < len(rr.Option); i++ { 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() lo, _ := rr.Option[i].pack()
l += 2 + len(lo) l += len(lo)
} }
return l return l
} }
func (rr *OPT) copy() RR {
return &OPT{*rr.Hdr.copyHeader(), rr.Option}
}
// return the old value -> delete SetVersion? // return the old value -> delete SetVersion?
// Version returns the EDNS version used. Only zero is defined. // Version returns the EDNS version used. Only zero is defined.
@ -195,7 +168,7 @@ func (e *EDNS0_NSID) Option() uint16 { return EDNS0NSID }
func (e *EDNS0_NSID) unpack(b []byte) error { e.Nsid = hex.EncodeToString(b); return nil } func (e *EDNS0_NSID) unpack(b []byte) error { e.Nsid = hex.EncodeToString(b); return nil }
func (e *EDNS0_NSID) String() string { return string(e.Nsid) } func (e *EDNS0_NSID) String() string { return string(e.Nsid) }
// The subnet EDNS0 option is used to give the remote nameserver // EDNS0_SUBNET is the subnet option that is used to give the remote nameserver
// an idea of where the client lives. It can then give back a different // an idea of where the client lives. It can then give back a different
// answer depending on the location or network topology. // answer depending on the location or network topology.
// Basic use pattern for creating an subnet option: // Basic use pattern for creating an subnet option:
@ -211,6 +184,11 @@ func (e *EDNS0_NSID) String() string { return string(e.Nsid) }
// e.Address = net.ParseIP("127.0.0.1").To4() // for IPv4 // e.Address = net.ParseIP("127.0.0.1").To4() // for IPv4
// // e.Address = net.ParseIP("2001:7b8:32a::2") // for IPV6 // // e.Address = net.ParseIP("2001:7b8:32a::2") // for IPV6
// o.Option = append(o.Option, e) // o.Option = append(o.Option, e)
//
// Note: the spec (draft-ietf-dnsop-edns-client-subnet-00) has some insane logic
// for which netmask applies to the address. This code will parse all the
// available bits when unpacking (up to optlen). When packing it will apply
// SourceNetmask. If you need more advanced logic, patches welcome and good luck.
type EDNS0_SUBNET struct { type EDNS0_SUBNET struct {
Code uint16 // Always EDNS0SUBNET Code uint16 // Always EDNS0SUBNET
Family uint16 // 1 for IP, 2 for IP6 Family uint16 // 1 for IP, 2 for IP6
@ -237,38 +215,22 @@ func (e *EDNS0_SUBNET) pack() ([]byte, error) {
if e.SourceNetmask > net.IPv4len*8 { if e.SourceNetmask > net.IPv4len*8 {
return nil, errors.New("dns: bad netmask") return nil, errors.New("dns: bad netmask")
} }
ip := make([]byte, net.IPv4len) if len(e.Address.To4()) != net.IPv4len {
a := e.Address.To4().Mask(net.CIDRMask(int(e.SourceNetmask), net.IPv4len*8)) return nil, errors.New("dns: bad address")
for i := 0; i < net.IPv4len; i++ {
if i+1 > len(e.Address) {
break
}
ip[i] = a[i]
} }
needLength := e.SourceNetmask / 8 ip := e.Address.To4().Mask(net.CIDRMask(int(e.SourceNetmask), net.IPv4len*8))
if e.SourceNetmask%8 > 0 { needLength := (e.SourceNetmask + 8 - 1) / 8 // division rounding up
needLength++ b = append(b, ip[:needLength]...)
}
ip = ip[:needLength]
b = append(b, ip...)
case 2: case 2:
if e.SourceNetmask > net.IPv6len*8 { if e.SourceNetmask > net.IPv6len*8 {
return nil, errors.New("dns: bad netmask") return nil, errors.New("dns: bad netmask")
} }
ip := make([]byte, net.IPv6len) if len(e.Address) != net.IPv6len {
a := e.Address.Mask(net.CIDRMask(int(e.SourceNetmask), net.IPv6len*8)) return nil, errors.New("dns: bad address")
for i := 0; i < net.IPv6len; i++ {
if i+1 > len(e.Address) {
break
}
ip[i] = a[i]
} }
needLength := e.SourceNetmask / 8 ip := e.Address.Mask(net.CIDRMask(int(e.SourceNetmask), net.IPv6len*8))
if e.SourceNetmask%8 > 0 { needLength := (e.SourceNetmask + 8 - 1) / 8 // division rounding up
needLength++ b = append(b, ip[:needLength]...)
}
ip = ip[:needLength]
b = append(b, ip...)
default: default:
return nil, errors.New("dns: bad address family") return nil, errors.New("dns: bad address family")
} }
@ -276,8 +238,7 @@ func (e *EDNS0_SUBNET) pack() ([]byte, error) {
} }
func (e *EDNS0_SUBNET) unpack(b []byte) error { func (e *EDNS0_SUBNET) unpack(b []byte) error {
lb := len(b) if len(b) < 4 {
if lb < 4 {
return ErrBuf return ErrBuf
} }
e.Family, _ = unpackUint16(b, 0) e.Family, _ = unpackUint16(b, 0)
@ -285,25 +246,27 @@ func (e *EDNS0_SUBNET) unpack(b []byte) error {
e.SourceScope = b[3] e.SourceScope = b[3]
switch e.Family { switch e.Family {
case 1: case 1:
addr := make([]byte, 4) if e.SourceNetmask > net.IPv4len*8 || e.SourceScope > net.IPv4len*8 {
for i := 0; i < int(e.SourceNetmask/8); i++ { return errors.New("dns: bad netmask")
if i >= len(addr) || 4+i >= len(b) { }
return ErrBuf addr := make([]byte, net.IPv4len)
} for i := 0; i < net.IPv4len && 4+i < len(b); i++ {
addr[i] = b[4+i] addr[i] = b[4+i]
} }
e.Address = net.IPv4(addr[0], addr[1], addr[2], addr[3]) e.Address = net.IPv4(addr[0], addr[1], addr[2], addr[3])
case 2: case 2:
addr := make([]byte, 16) if e.SourceNetmask > net.IPv6len*8 || e.SourceScope > net.IPv6len*8 {
for i := 0; i < int(e.SourceNetmask/8); i++ { return errors.New("dns: bad netmask")
if i >= len(addr) || 4+i >= len(b) { }
return ErrBuf addr := make([]byte, net.IPv6len)
} for i := 0; i < net.IPv6len && 4+i < len(b); i++ {
addr[i] = b[4+i] addr[i] = b[4+i]
} }
e.Address = net.IP{addr[0], addr[1], addr[2], addr[3], addr[4], e.Address = net.IP{addr[0], addr[1], addr[2], addr[3], addr[4],
addr[5], addr[6], addr[7], addr[8], addr[9], addr[10], addr[5], addr[6], addr[7], addr[8], addr[9], addr[10],
addr[11], addr[12], addr[13], addr[14], addr[15]} addr[11], addr[12], addr[13], addr[14], addr[15]}
default:
return errors.New("dns: bad address family")
} }
return nil return nil
} }
@ -320,7 +283,7 @@ func (e *EDNS0_SUBNET) String() (s string) {
return return
} }
// The UL (Update Lease) EDNS0 (draft RFC) option is used to tell the server to set // The EDNS0_UL (Update Lease) (draft RFC) option is used to tell the server to set
// an expiration on an update RR. This is helpful for clients that cannot clean // an expiration on an update RR. This is helpful for clients that cannot clean
// up after themselves. This is a draft RFC and more information can be found at // up after themselves. This is a draft RFC and more information can be found at
// http://files.dns-sd.org/draft-sekar-dns-ul.txt // http://files.dns-sd.org/draft-sekar-dns-ul.txt
@ -358,7 +321,7 @@ func (e *EDNS0_UL) unpack(b []byte) error {
return nil return nil
} }
// Long Lived Queries: http://tools.ietf.org/html/draft-sekar-dns-llq-01 // EDNS0_LLQ stands for Long Lived Queries: http://tools.ietf.org/html/draft-sekar-dns-llq-01
// Implemented for completeness, as the EDNS0 type code is assigned. // Implemented for completeness, as the EDNS0 type code is assigned.
type EDNS0_LLQ struct { type EDNS0_LLQ struct {
Code uint16 // Always EDNS0LLQ Code uint16 // Always EDNS0LLQ
@ -499,3 +462,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]) e.Expire = uint32(b[0])<<24 | uint32(b[1])<<16 | uint32(b[2])<<8 | uint32(b[3])
return nil return nil
} }
// The EDNS0_LOCAL 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
}

96
vendor/github.com/miekg/dns/format.go generated vendored Normal file
View File

@ -0,0 +1,96 @@
package dns
import (
"net"
"reflect"
"strconv"
)
// NumField returns the number of rdata fields r has.
func NumField(r RR) int {
return reflect.ValueOf(r).Elem().NumField() - 1 // Remove RR_Header
}
// Field returns the rdata field i as a string. Fields are indexed starting from 1.
// RR types that holds slice data, for instance the NSEC type bitmap will return a single
// string where the types are concatenated using a space.
// Accessing non existing fields will cause a panic.
func Field(r RR, i int) string {
if i == 0 {
return ""
}
d := reflect.ValueOf(r).Elem().Field(i)
switch k := d.Kind(); k {
case reflect.String:
return d.String()
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return strconv.FormatInt(d.Int(), 10)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return strconv.FormatUint(d.Uint(), 10)
case reflect.Slice:
switch reflect.ValueOf(r).Elem().Type().Field(i).Tag {
case `dns:"a"`:
// TODO(miek): Hmm store this as 16 bytes
if d.Len() < net.IPv6len {
return net.IPv4(byte(d.Index(0).Uint()),
byte(d.Index(1).Uint()),
byte(d.Index(2).Uint()),
byte(d.Index(3).Uint())).String()
}
return net.IPv4(byte(d.Index(12).Uint()),
byte(d.Index(13).Uint()),
byte(d.Index(14).Uint()),
byte(d.Index(15).Uint())).String()
case `dns:"aaaa"`:
return net.IP{
byte(d.Index(0).Uint()),
byte(d.Index(1).Uint()),
byte(d.Index(2).Uint()),
byte(d.Index(3).Uint()),
byte(d.Index(4).Uint()),
byte(d.Index(5).Uint()),
byte(d.Index(6).Uint()),
byte(d.Index(7).Uint()),
byte(d.Index(8).Uint()),
byte(d.Index(9).Uint()),
byte(d.Index(10).Uint()),
byte(d.Index(11).Uint()),
byte(d.Index(12).Uint()),
byte(d.Index(13).Uint()),
byte(d.Index(14).Uint()),
byte(d.Index(15).Uint()),
}.String()
case `dns:"nsec"`:
if d.Len() == 0 {
return ""
}
s := Type(d.Index(0).Uint()).String()
for i := 1; i < d.Len(); i++ {
s += " " + Type(d.Index(i).Uint()).String()
}
return s
case `dns:"wks"`:
if d.Len() == 0 {
return ""
}
s := strconv.Itoa(int(d.Index(0).Uint()))
for i := 0; i < d.Len(); i++ {
s += " " + strconv.Itoa(int(d.Index(i).Uint()))
}
return s
default:
// if it does not have a tag its a string slice
fallthrough
case `dns:"txt"`:
if d.Len() == 0 {
return ""
}
s := d.Index(0).String()
for i := 1; i < d.Len(); i++ {
s += " " + d.Index(i).String()
}
return s
}
}
return ""
}

157
vendor/github.com/miekg/dns/keygen.go generated vendored
View File

@ -1,157 +0,0 @@
package dns
import (
"crypto/dsa"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/rsa"
"math/big"
"strconv"
)
const _FORMAT = "Private-key-format: v1.3\n"
// Empty interface that is used as a wrapper around all possible
// private key implementations from the crypto package.
type PrivateKey interface{}
// Generate generates a DNSKEY of the given bit size.
// The public part is put inside the DNSKEY record.
// The Algorithm in the key must be set as this will define
// 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 {
case DSA, DSANSEC3SHA1:
if bits != 1024 {
return nil, ErrKeySize
}
case RSAMD5, RSASHA1, RSASHA256, RSASHA1NSEC3SHA1:
if bits < 512 || bits > 4096 {
return nil, ErrKeySize
}
case RSASHA512:
if bits < 1024 || bits > 4096 {
return nil, ErrKeySize
}
case ECDSAP256SHA256:
if bits != 256 {
return nil, ErrKeySize
}
case ECDSAP384SHA384:
if bits != 384 {
return nil, ErrKeySize
}
}
switch r.Algorithm {
case DSA, DSANSEC3SHA1:
params := new(dsa.Parameters)
if err := dsa.GenerateParameters(params, rand.Reader, dsa.L1024N160); err != nil {
return nil, err
}
priv := new(dsa.PrivateKey)
priv.PublicKey.Parameters = *params
err := dsa.GenerateKey(priv, rand.Reader)
if err != nil {
return nil, err
}
r.setPublicKeyDSA(params.Q, params.P, params.G, priv.PublicKey.Y)
return 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)
return priv, nil
case ECDSAP256SHA256, ECDSAP384SHA384:
var c elliptic.Curve
switch r.Algorithm {
case ECDSAP256SHA256:
c = elliptic.P256()
case ECDSAP384SHA384:
c = elliptic.P384()
}
priv, err := ecdsa.GenerateKey(c, rand.Reader)
if err != nil {
return nil, err
}
r.setPublicKeyCurve(priv.PublicKey.X, priv.PublicKey.Y)
return priv, nil
default:
return nil, ErrAlg
}
return nil, nil // Dummy return
}
// PrivateKeyString converts a PrivateKey to a string. This
// string has the same format as the private-key-file of BIND9 (Private-key-format: v1.3).
// It needs some info from the key (hashing, keytag), so its a method of the DNSKEY.
func (r *DNSKEY) PrivateKeyString(p PrivateKey) (s string) {
switch t := p.(type) {
case *rsa.PrivateKey:
algorithm := strconv.Itoa(int(r.Algorithm)) + " (" + AlgorithmToString[r.Algorithm] + ")"
modulus := toBase64(t.PublicKey.N.Bytes())
e := big.NewInt(int64(t.PublicKey.E))
publicExponent := toBase64(e.Bytes())
privateExponent := toBase64(t.D.Bytes())
prime1 := toBase64(t.Primes[0].Bytes())
prime2 := toBase64(t.Primes[1].Bytes())
// 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)
minusone := big.NewInt(-1)
p_1 := big.NewInt(0).Sub(t.Primes[0], one)
q_1 := big.NewInt(0).Sub(t.Primes[1], one)
exp1 := big.NewInt(0).Mod(t.D, p_1)
exp2 := big.NewInt(0).Mod(t.D, q_1)
coeff := big.NewInt(0).Exp(t.Primes[1], minusone, t.Primes[0])
exponent1 := toBase64(exp1.Bytes())
exponent2 := toBase64(exp2.Bytes())
coefficient := toBase64(coeff.Bytes())
s = _FORMAT +
"Algorithm: " + algorithm + "\n" +
"Modules: " + modulus + "\n" +
"PublicExponent: " + publicExponent + "\n" +
"PrivateExponent: " + privateExponent + "\n" +
"Prime1: " + prime1 + "\n" +
"Prime2: " + prime2 + "\n" +
"Exponent1: " + exponent1 + "\n" +
"Exponent2: " + exponent2 + "\n" +
"Coefficient: " + coefficient + "\n"
case *ecdsa.PrivateKey:
algorithm := strconv.Itoa(int(r.Algorithm)) + " (" + AlgorithmToString[r.Algorithm] + ")"
var intlen int
switch r.Algorithm {
case ECDSAP256SHA256:
intlen = 32
case ECDSAP384SHA384:
intlen = 48
}
private := toBase64(intToBytes(t.D, intlen))
s = _FORMAT +
"Algorithm: " + algorithm + "\n" +
"PrivateKey: " + private + "\n"
case *dsa.PrivateKey:
algorithm := strconv.Itoa(int(r.Algorithm)) + " (" + AlgorithmToString[r.Algorithm] + ")"
T := divRoundUp(divRoundUp(t.PublicKey.Parameters.G.BitLen(), 8)-64, 8)
prime := toBase64(intToBytes(t.PublicKey.Parameters.P, 64+T*8))
subprime := toBase64(intToBytes(t.PublicKey.Parameters.Q, 20))
base := toBase64(intToBytes(t.PublicKey.Parameters.G, 64+T*8))
priv := toBase64(intToBytes(t.X, 20))
pub := toBase64(intToBytes(t.PublicKey.Y, 64+T*8))
s = _FORMAT +
"Algorithm: " + algorithm + "\n" +
"Prime(p): " + prime + "\n" +
"Subprime(q): " + subprime + "\n" +
"Base(g): " + base + "\n" +
"Private_value(x): " + priv + "\n" +
"Public_value(y): " + pub + "\n"
}
return
}

View File

@ -4,9 +4,11 @@ package dns
// SplitDomainName splits a name string into it's labels. // SplitDomainName splits a name string into it's labels.
// www.miek.nl. returns []string{"www", "miek", "nl"} // www.miek.nl. returns []string{"www", "miek", "nl"}
// .www.miek.nl. returns []string{"", "www", "miek", "nl"},
// The root label (.) returns nil. Note that using // The root label (.) returns nil. Note that using
// strings.Split(s) will work in most cases, but does not handle // strings.Split(s) will work in most cases, but does not handle
// escaped dots (\.) for instance. // escaped dots (\.) for instance.
// s must be a syntactically valid domain name, see IsDomainName.
func SplitDomainName(s string) (labels []string) { func SplitDomainName(s string) (labels []string) {
if len(s) == 0 { if len(s) == 0 {
return nil return nil
@ -45,6 +47,8 @@ func SplitDomainName(s string) (labels []string) {
// //
// www.miek.nl. and miek.nl. have two labels in common: miek and nl // www.miek.nl. and miek.nl. have two labels in common: miek and nl
// www.miek.nl. and www.bla.nl. have one label in common: nl // www.miek.nl. and www.bla.nl. have one label in common: nl
//
// s1 and s2 must be syntactically valid domain names.
func CompareDomainName(s1, s2 string) (n int) { func CompareDomainName(s1, s2 string) (n int) {
s1 = Fqdn(s1) s1 = Fqdn(s1)
s2 = Fqdn(s2) s2 = Fqdn(s2)
@ -85,6 +89,7 @@ func CompareDomainName(s1, s2 string) (n int) {
} }
// CountLabel counts the the number of labels in the string s. // CountLabel counts the the number of labels in the string s.
// s must be a syntactically valid domain name.
func CountLabel(s string) (labels int) { func CountLabel(s string) (labels int) {
if s == "." { if s == "." {
return return
@ -98,12 +103,12 @@ func CountLabel(s string) (labels int) {
return return
} }
} }
panic("dns: not reached")
} }
// Split splits a name s into its label indexes. // Split splits a name s into its label indexes.
// www.miek.nl. returns []int{0, 4, 9}, www.miek.nl also returns []int{0, 4, 9}. // www.miek.nl. returns []int{0, 4, 9}, www.miek.nl also returns []int{0, 4, 9}.
// The root name (.) returns nil. Also see dns.SplitDomainName. // The root name (.) returns nil. Also see SplitDomainName.
// s must be a syntactically valid domain name.
func Split(s string) []int { func Split(s string) []int {
if s == "." { if s == "." {
return nil return nil
@ -119,12 +124,12 @@ func Split(s string) []int {
} }
idx = append(idx, off) idx = append(idx, off)
} }
panic("dns: not reached")
} }
// NextLabel returns the index of the start of the next label in the // NextLabel returns the index of the start of the next label in the
// string s starting at offset. // string s starting at offset.
// The bool end is true when the end of the string has been reached. // The bool end is true when the end of the string has been reached.
// Also see PrevLabel.
func NextLabel(s string, offset int) (i int, end bool) { func NextLabel(s string, offset int) (i int, end bool) {
quote := false quote := false
for i = offset; i < len(s)-1; i++ { for i = offset; i < len(s)-1; i++ {
@ -147,6 +152,7 @@ func NextLabel(s string, offset int) (i int, end bool) {
// PrevLabel returns the index of the label when starting from the right and // PrevLabel returns the index of the label when starting from the right and
// jumping n labels to the left. // jumping n labels to the left.
// The bool start is true when the start of the string has been overshot. // The bool start is true when the start of the string has been overshot.
// Also see NextLabel.
func PrevLabel(s string, n int) (i int, start bool) { func PrevLabel(s string, n int) (i int, start bool) {
if n == 0 { if n == 0 {
return len(s), false return len(s), false

559
vendor/github.com/miekg/dns/msg.go generated vendored
View File

@ -23,29 +23,40 @@ import (
const maxCompressionOffset = 2 << 13 // We have 14 bits for the compression pointer const maxCompressionOffset = 2 << 13 // We have 14 bits for the compression pointer
var ( var (
ErrAlg error = &Error{err: "bad algorithm"} // ErrAlg indicates an error with the (DNSSEC) algorithm.
ErrAuth error = &Error{err: "bad authentication"} ErrAlg error = &Error{err: "bad algorithm"}
ErrBuf error = &Error{err: "buffer size too small"} // ErrAuth indicates an error in the TSIG authentication.
ErrConnEmpty error = &Error{err: "conn has no connection"} ErrAuth error = &Error{err: "bad authentication"}
ErrConn error = &Error{err: "conn holds both UDP and TCP connection"} // ErrBuf indicates that the buffer used it too small for the message.
ErrBuf error = &Error{err: "buffer size too small"}
// 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"} ErrExtendedRcode error = &Error{err: "bad extended rcode"}
ErrFqdn error = &Error{err: "domain must be fully qualified"} // ErrFqdn indicates that a domain name does not have a closing dot.
ErrId error = &Error{err: "id mismatch"} ErrFqdn error = &Error{err: "domain must be fully qualified"}
ErrKeyAlg error = &Error{err: "bad key algorithm"} // ErrId indicates there is a mismatch with the message's ID.
ErrKey error = &Error{err: "bad key"} ErrId error = &Error{err: "id mismatch"}
ErrKeySize error = &Error{err: "bad key size"} // ErrKeyAlg indicates that the algorithm in the key is not valid.
ErrNoSig error = &Error{err: "no signature found"} ErrKeyAlg error = &Error{err: "bad key algorithm"}
ErrPrivKey error = &Error{err: "bad private key"} ErrKey error = &Error{err: "bad key"}
ErrRcode error = &Error{err: "bad rcode"} ErrKeySize error = &Error{err: "bad key size"}
ErrRdata error = &Error{err: "bad rdata"} ErrNoSig error = &Error{err: "no signature found"}
ErrRRset error = &Error{err: "bad rrset"} ErrPrivKey error = &Error{err: "bad private key"}
ErrSecret error = &Error{err: "no secrets defined"} ErrRcode error = &Error{err: "bad rcode"}
ErrServ error = &Error{err: "no servers could be reached"} ErrRdata error = &Error{err: "bad rdata"}
ErrShortRead error = &Error{err: "short read"} ErrRRset error = &Error{err: "bad rrset"}
ErrSig error = &Error{err: "bad signature"} ErrSecret error = &Error{err: "no secrets defined"}
ErrSigGen error = &Error{err: "bad signature generation"} ErrShortRead error = &Error{err: "short read"}
ErrSoa error = &Error{err: "no SOA"} // ErrSig indicates that a signature can not be cryptographically validated.
ErrTime error = &Error{err: "bad time"} ErrSig error = &Error{err: "bad signature"}
// 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"}
// ErrTruncated indicates that we failed to unpack a truncated message.
// We unpacked as much as we had so Msg can still be used, if desired.
ErrTruncated error = &Error{err: "failed to unpack truncated message"}
) )
// Id, by default, returns a 16 bits random number to be used as a // 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 } // dns.Id = func() uint16 { return 3 }
var Id func() uint16 = id var Id func() uint16 = id
// A manually-unpacked version of (id, bits). // MsgHdr is a a manually-unpacked version of (id, bits).
// This is in its own struct for easy printing.
type MsgHdr struct { type MsgHdr struct {
Id uint16 Id uint16
Response bool Response bool
@ -72,7 +82,7 @@ type MsgHdr struct {
Rcode int Rcode int
} }
// The layout of a DNS message. // Msg contains the layout of a DNS message.
type Msg struct { type Msg struct {
MsgHdr 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. 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,87 +92,10 @@ type Msg struct {
Extra []RR // Holds the RR(s) of the additional section. Extra []RR // Holds the RR(s) of the additional section.
} }
// Map of strings for each RR wire type. // StringToType is the reverse of TypeToString, needed for string parsing.
var TypeToString = map[uint16]string{
TypeA: "A",
TypeAAAA: "AAAA",
TypeAFSDB: "AFSDB",
TypeANY: "ANY", // Meta RR
TypeATMA: "ATMA",
TypeAXFR: "AXFR", // Meta RR
TypeCAA: "CAA",
TypeCDNSKEY: "CDNSKEY",
TypeCDS: "CDS",
TypeCERT: "CERT",
TypeCNAME: "CNAME",
TypeDHCID: "DHCID",
TypeDLV: "DLV",
TypeDNAME: "DNAME",
TypeDNSKEY: "DNSKEY",
TypeDS: "DS",
TypeEID: "EID",
TypeEUI48: "EUI48",
TypeEUI64: "EUI64",
TypeGID: "GID",
TypeGPOS: "GPOS",
TypeHINFO: "HINFO",
TypeHIP: "HIP",
TypeIPSECKEY: "IPSECKEY",
TypeISDN: "ISDN",
TypeIXFR: "IXFR", // Meta RR
TypeKEY: "KEY",
TypeKX: "KX",
TypeL32: "L32",
TypeL64: "L64",
TypeLOC: "LOC",
TypeLP: "LP",
TypeMB: "MB",
TypeMD: "MD",
TypeMF: "MF",
TypeMG: "MG",
TypeMINFO: "MINFO",
TypeMR: "MR",
TypeMX: "MX",
TypeNAPTR: "NAPTR",
TypeNID: "NID",
TypeNINFO: "NINFO",
TypeNIMLOC: "NIMLOC",
TypeNS: "NS",
TypeNSAP: "NSAP",
TypeNSAPPTR: "NSAP-PTR",
TypeNSEC3: "NSEC3",
TypeNSEC3PARAM: "NSEC3PARAM",
TypeNSEC: "NSEC",
TypeNULL: "NULL",
TypeOPT: "OPT",
TypeOPENPGPKEY: "OPENPGPKEY",
TypePTR: "PTR",
TypeRKEY: "RKEY",
TypeRP: "RP",
TypeRRSIG: "RRSIG",
TypeRT: "RT",
TypeSIG: "SIG",
TypeSOA: "SOA",
TypeSPF: "SPF",
TypeSRV: "SRV",
TypeSSHFP: "SSHFP",
TypeTA: "TA",
TypeTALINK: "TALINK",
TypeTKEY: "TKEY", // Meta RR
TypeTLSA: "TLSA",
TypeTSIG: "TSIG", // Meta RR
TypeTXT: "TXT",
TypePX: "PX",
TypeUID: "UID",
TypeUINFO: "UINFO",
TypeUNSPEC: "UNSPEC",
TypeURI: "URI",
TypeWKS: "WKS",
TypeX25: "X25",
}
// Reverse, needed for string parsing.
var StringToType = reverseInt16(TypeToString) var StringToType = reverseInt16(TypeToString)
// StringToClass is the reverse of ClassToString, needed for string parsing.
var StringToClass = reverseInt16(ClassToString) var StringToClass = reverseInt16(ClassToString)
// Map of opcodes strings. // Map of opcodes strings.
@ -171,7 +104,7 @@ var StringToOpcode = reverseInt(OpcodeToString)
// Map of rcodes strings. // Map of rcodes strings.
var StringToRcode = reverseInt(RcodeToString) 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{ var ClassToString = map[uint16]string{
ClassINET: "IN", ClassINET: "IN",
ClassCSNET: "CS", ClassCSNET: "CS",
@ -181,7 +114,7 @@ var ClassToString = map[uint16]string{
ClassANY: "ANY", ClassANY: "ANY",
} }
// Map of strings for opcodes. // OpcodeToString maps Opcodes to strings.
var OpcodeToString = map[int]string{ var OpcodeToString = map[int]string{
OpcodeQuery: "QUERY", OpcodeQuery: "QUERY",
OpcodeIQuery: "IQUERY", OpcodeIQuery: "IQUERY",
@ -190,7 +123,7 @@ var OpcodeToString = map[int]string{
OpcodeUpdate: "UPDATE", OpcodeUpdate: "UPDATE",
} }
// Map of strings for rcodes. // RcodeToString maps Rcodes to strings.
var RcodeToString = map[int]string{ var RcodeToString = map[int]string{
RcodeSuccess: "NOERROR", RcodeSuccess: "NOERROR",
RcodeFormatError: "FORMERR", RcodeFormatError: "FORMERR",
@ -225,7 +158,7 @@ var RcodeToString = map[int]string{
// PackDomainName packs a domain name s into msg[off:]. // PackDomainName packs a domain name s into msg[off:].
// If compression is wanted compress must be true and the compression // If compression is wanted compress must be true and the compression
// map needs to hold a mapping between domain names and offsets // map needs to hold a mapping between domain names and offsets
// pointing into msg[]. // pointing into msg.
func PackDomainName(s string, msg []byte, off int, compression map[string]int, compress bool) (off1 int, err error) { func PackDomainName(s string, msg []byte, off int, compression map[string]int, compress bool) (off1 int, err error) {
off1, _, err = packDomainName(s, msg, off, compression, compress) off1, _, err = packDomainName(s, msg, off, compression, compress)
return return
@ -264,7 +197,7 @@ func packDomainName(s string, msg []byte, off int, compression map[string]int, c
// Emit sequence of counted strings, chopping at dots. // Emit sequence of counted strings, chopping at dots.
begin := 0 begin := 0
bs := []byte(s) bs := []byte(s)
ro_bs, bs_fresh, escaped_dot := s, true, false roBs, bsFresh, escapedDot := s, true, false
for i := 0; i < ls; i++ { for i := 0; i < ls; i++ {
if bs[i] == '\\' { if bs[i] == '\\' {
for j := i; j < ls-1; j++ { for j := i; j < ls-1; j++ {
@ -288,13 +221,13 @@ func packDomainName(s string, msg []byte, off int, compression map[string]int, c
} else if bs[i] == 'n' { } else if bs[i] == 'n' {
bs[i] = '\n' bs[i] = '\n'
} }
escaped_dot = bs[i] == '.' escapedDot = bs[i] == '.'
bs_fresh = false bsFresh = false
continue continue
} }
if bs[i] == '.' { 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 // two dots back to back is not legal
return lenmsg, labels, ErrRdata return lenmsg, labels, ErrRdata
} }
@ -320,16 +253,16 @@ func packDomainName(s string, msg []byte, off int, compression map[string]int, c
} }
off++ off++
} }
if compress && !bs_fresh { if compress && !bsFresh {
ro_bs = string(bs) roBs = string(bs)
bs_fresh = true bsFresh = true
} }
// Dont try to compress '.' // Don't try to compress '.'
if compress && ro_bs[begin:] != "." { if compress && roBs[begin:] != "." {
if p, ok := compression[ro_bs[begin:]]; !ok { if p, ok := compression[roBs[begin:]]; !ok {
// Only offsets smaller than this can be used. // Only offsets smaller than this can be used.
if offset < maxCompressionOffset { if offset < maxCompressionOffset {
compression[ro_bs[begin:]] = offset compression[roBs[begin:]] = offset
} }
} else { } else {
// The first hit is the longest matching dname // The first hit is the longest matching dname
@ -348,7 +281,7 @@ func packDomainName(s string, msg []byte, off int, compression map[string]int, c
labels++ labels++
begin = i + 1 begin = i + 1
} }
escaped_dot = false escapedDot = false
} }
// Root label is special // Root label is special
if len(bs) == 1 && bs[0] == '.' { if len(bs) == 1 && bs[0] == '.' {
@ -401,9 +334,6 @@ Loop:
case 0x00: case 0x00:
if c == 0x00 { if c == 0x00 {
// end of name // end of name
if len(s) == 0 {
return ".", off, nil
}
break Loop break Loop
} }
// literal string // literal string
@ -464,6 +394,9 @@ Loop:
if ptr == 0 { if ptr == 0 {
off1 = off off1 = off
} }
if len(s) == 0 {
s = []byte(".")
}
return string(s), off1, nil return string(s), off1, nil
} }
@ -531,17 +464,46 @@ func packTxtString(s string, msg []byte, offset int, tmp []byte) (int, error) {
return offset, nil return offset, nil
} }
func unpackTxt(msg []byte, offset, rdend int) ([]string, int, error) { func packOctetString(s string, msg []byte, offset int, tmp []byte) (int, error) {
var err error if offset >= len(msg) {
var ss []string return offset, ErrBuf
}
bs := tmp[:len(s)]
copy(bs, s)
for i := 0; i < len(bs); i++ {
if len(msg) <= offset {
return offset, ErrBuf
}
if bs[i] == '\\' {
i++
if i == len(bs) {
break
}
// check for \DDD
if i+2 < len(bs) && isDigit(bs[i]) && isDigit(bs[i+1]) && isDigit(bs[i+2]) {
msg[offset] = dddToByte(bs[i:])
i += 2
} else {
msg[offset] = bs[i]
}
} else {
msg[offset] = bs[i]
}
offset++
}
return offset, nil
}
func unpackTxt(msg []byte, off0 int) (ss []string, off int, err error) {
off = off0
var s string var s string
for offset < rdend && err == nil { for off < len(msg) && err == nil {
s, offset, err = unpackTxtString(msg, offset) s, off, err = unpackTxtString(msg, off)
if err == nil { if err == nil {
ss = append(ss, s) ss = append(ss, s)
} }
} }
return ss, offset, err return
} }
func unpackTxtString(msg []byte, offset int) (string, int, error) { func unpackTxtString(msg []byte, offset int) (string, int, error) {
@ -652,6 +614,12 @@ func packStructValue(val reflect.Value, msg []byte, off int, compression map[str
off += len(b) off += len(b)
} }
case `dns:"a"`: case `dns:"a"`:
if val.Type().String() == "dns.IPSECKEY" {
// Field(2) is GatewayType, must be 1
if val.Field(2).Uint() != 1 {
continue
}
}
// It must be a slice of 4, even if it is 16, we encode // It must be a slice of 4, even if it is 16, we encode
// only the first 4 // only the first 4
if off+net.IPv4len > lenmsg { if off+net.IPv4len > lenmsg {
@ -676,6 +644,12 @@ func packStructValue(val reflect.Value, msg []byte, off int, compression map[str
return lenmsg, &Error{err: "overflow packing a"} return lenmsg, &Error{err: "overflow packing a"}
} }
case `dns:"aaaa"`: case `dns:"aaaa"`:
if val.Type().String() == "dns.IPSECKEY" {
// Field(2) is GatewayType, must be 2
if val.Field(2).Uint() != 2 {
continue
}
}
if fv.Len() == 0 { if fv.Len() == 0 {
break break
} }
@ -694,58 +668,49 @@ func packStructValue(val reflect.Value, msg []byte, off int, compression map[str
if val.Field(i).Len() == 0 { if val.Field(i).Len() == 0 {
break break
} }
var bitmapbyte uint16 off1 := off
for j := 0; j < val.Field(i).Len(); j++ { for j := 0; j < val.Field(i).Len(); j++ {
serv := uint16((fv.Index(j).Uint())) serv := int(fv.Index(j).Uint())
bitmapbyte = uint16(serv / 8) if off+serv/8+1 > len(msg) {
if int(bitmapbyte) > lenmsg { return len(msg), &Error{err: "overflow packing wks"}
return lenmsg, &Error{err: "overflow packing wks"} }
msg[off+serv/8] |= byte(1 << (7 - uint(serv%8)))
if off+serv/8+1 > off1 {
off1 = off + serv/8 + 1
} }
bit := uint16(serv) - bitmapbyte*8
msg[bitmapbyte] = byte(1 << (7 - bit))
} }
off += int(bitmapbyte) off = off1
case `dns:"nsec"`: // NSEC/NSEC3 case `dns:"nsec"`: // NSEC/NSEC3
// This is the uint16 type bitmap // This is the uint16 type bitmap
if val.Field(i).Len() == 0 { if val.Field(i).Len() == 0 {
// Do absolutely nothing // Do absolutely nothing
break break
} }
var lastwindow, lastlength uint16
lastwindow := uint16(0)
length := uint16(0)
if off+2 > lenmsg {
return lenmsg, &Error{err: "overflow packing nsecx"}
}
for j := 0; j < val.Field(i).Len(); j++ { for j := 0; j < val.Field(i).Len(); j++ {
t := uint16((fv.Index(j).Uint())) t := uint16(fv.Index(j).Uint())
window := uint16(t / 256) window := t / 256
if lastwindow != window { length := (t-window*256)/8 + 1
if window > lastwindow && lastlength != 0 {
// New window, jump to the new offset // New window, jump to the new offset
off += int(length) + 3 off += int(lastlength) + 2
if off > lenmsg { lastlength = 0
return lenmsg, &Error{err: "overflow packing nsecx bitmap"}
}
} }
length = (t - window*256) / 8 if window < lastwindow || length < lastlength {
bit := t - (window * 256) - (length * 8) return len(msg), &Error{err: "nsec bits out of order"}
if off+2+int(length) > lenmsg { }
return lenmsg, &Error{err: "overflow packing nsecx bitmap"} if off+2+int(length) > len(msg) {
return len(msg), &Error{err: "overflow packing nsec"}
} }
// Setting the window # // Setting the window #
msg[off] = byte(window) msg[off] = byte(window)
// Setting the octets length // Setting the octets length
msg[off+1] = byte(length + 1) msg[off+1] = byte(length)
// Setting the bit value for the type in the right octet // Setting the bit value for the type in the right octet
msg[off+2+int(length)] |= byte(1 << (7 - bit)) msg[off+1+int(length)] |= byte(1 << (7 - (t % 8)))
lastwindow = window lastwindow, lastlength = window, length
}
off += 2 + int(length)
off++
if off > lenmsg {
return lenmsg, &Error{err: "overflow packing nsecx bitmap"}
} }
off += int(lastlength) + 2
} }
case reflect.Struct: case reflect.Struct:
off, err = packStructValue(fv, msg, off, compression, compress) off, err = packStructValue(fv, msg, off, compression, compress)
@ -821,6 +786,13 @@ func packStructValue(val reflect.Value, msg []byte, off int, compression map[str
copy(msg[off:off+len(b64)], b64) copy(msg[off:off+len(b64)], b64)
off += len(b64) off += len(b64)
case `dns:"domain-name"`: case `dns:"domain-name"`:
if val.Type().String() == "dns.IPSECKEY" {
// Field(2) is GatewayType, 1 and 2 or used for addresses
x := val.Field(2).Uint()
if x == 1 || x == 2 {
continue
}
}
if off, err = PackDomainName(s, msg, off, compression, false && compress); err != nil { if off, err = PackDomainName(s, msg, off, compression, false && compress); err != nil {
return lenmsg, err return lenmsg, err
} }
@ -859,6 +831,12 @@ func packStructValue(val reflect.Value, msg []byte, off int, compression map[str
// length of string. String is RAW (not encoded in hex, nor base64) // length of string. String is RAW (not encoded in hex, nor base64)
copy(msg[off:off+len(s)], s) copy(msg[off:off+len(s)], s)
off += len(s) off += len(s)
case `dns:"octet"`:
bytesTmp := make([]byte, 256)
off, err = packOctetString(fv.String(), msg, off, bytesTmp)
if err != nil {
return lenmsg, err
}
case `dns:"txt"`: case `dns:"txt"`:
fallthrough fallthrough
case "": case "":
@ -890,17 +868,11 @@ func packStructCompress(any interface{}, msg []byte, off int, compression map[st
return off, err return off, err
} }
// TODO(miek): Fix use of rdlength here
// Unpack a reflect.StructValue from msg. // Unpack a reflect.StructValue from msg.
// Same restrictions as packStructValue. // Same restrictions as packStructValue.
func unpackStructValue(val reflect.Value, msg []byte, off int) (off1 int, err error) { func unpackStructValue(val reflect.Value, msg []byte, off int) (off1 int, err error) {
var lenrd int
lenmsg := len(msg) lenmsg := len(msg)
for i := 0; i < val.NumField(); i++ { for i := 0; i < val.NumField(); i++ {
if lenrd != 0 && lenrd == off {
break
}
if off > lenmsg { if off > lenmsg {
return lenmsg, &Error{"bad offset unpacking"} return lenmsg, &Error{"bad offset unpacking"}
} }
@ -912,7 +884,7 @@ func unpackStructValue(val reflect.Value, msg []byte, off int) (off1 int, err er
// therefore it's expected that this interface would be PrivateRdata // therefore it's expected that this interface would be PrivateRdata
switch data := fv.Interface().(type) { switch data := fv.Interface().(type) {
case PrivateRdata: case PrivateRdata:
n, err := data.Unpack(msg[off:lenrd]) n, err := data.Unpack(msg[off:])
if err != nil { if err != nil {
return lenmsg, err return lenmsg, err
} }
@ -926,9 +898,9 @@ 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")} return lenmsg, &Error{"bad tag unpacking slice: " + val.Type().Field(i).Tag.Get("dns")}
case `dns:"domain-name"`: case `dns:"domain-name"`:
// HIP record slice of name (or none) // HIP record slice of name (or none)
servers := make([]string, 0) var servers []string
var s string var s string
for off < lenrd { for off < lenmsg {
s, off, err = UnpackDomainName(msg, off) s, off, err = UnpackDomainName(msg, off)
if err != nil { if err != nil {
return lenmsg, err return lenmsg, err
@ -937,30 +909,30 @@ func unpackStructValue(val reflect.Value, msg []byte, off int) (off1 int, err er
} }
fv.Set(reflect.ValueOf(servers)) fv.Set(reflect.ValueOf(servers))
case `dns:"txt"`: case `dns:"txt"`:
if off == lenmsg || lenrd == off { if off == lenmsg {
break break
} }
var txt []string var txt []string
txt, off, err = unpackTxt(msg, off, lenrd) txt, off, err = unpackTxt(msg, off)
if err != nil { if err != nil {
return lenmsg, err return lenmsg, err
} }
fv.Set(reflect.ValueOf(txt)) fv.Set(reflect.ValueOf(txt))
case `dns:"opt"`: // edns0 case `dns:"opt"`: // edns0
if off == lenrd { if off == lenmsg {
// This is an EDNS0 (OPT Record) with no rdata // This is an EDNS0 (OPT Record) with no rdata
// We can safely return here. // We can safely return here.
break break
} }
edns := make([]EDNS0, 0) var edns []EDNS0
Option: Option:
code := uint16(0) code := uint16(0)
if off+2 > lenmsg { if off+4 > lenmsg {
return lenmsg, &Error{err: "overflow unpacking opt"} return lenmsg, &Error{err: "overflow unpacking opt"}
} }
code, off = unpackUint16(msg, off) code, off = unpackUint16(msg, off)
optlen, off1 := unpackUint16(msg, off) optlen, off1 := unpackUint16(msg, off)
if off1+int(optlen) > lenrd { if off1+int(optlen) > lenmsg {
return lenmsg, &Error{err: "overflow unpacking opt"} return lenmsg, &Error{err: "overflow unpacking opt"}
} }
switch code { switch code {
@ -1017,27 +989,44 @@ func unpackStructValue(val reflect.Value, msg []byte, off int) (off1 int, err er
edns = append(edns, e) edns = append(edns, e)
off = off1 + int(optlen) off = off1 + int(optlen)
default: 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) off = off1 + int(optlen)
} }
if off < lenrd { if off < lenmsg {
goto Option goto Option
} }
fv.Set(reflect.ValueOf(edns)) fv.Set(reflect.ValueOf(edns))
case `dns:"a"`: case `dns:"a"`:
if off == lenrd { if val.Type().String() == "dns.IPSECKEY" {
// Field(2) is GatewayType, must be 1
if val.Field(2).Uint() != 1 {
continue
}
}
if off == lenmsg {
break // dyn. update break // dyn. update
} }
if off+net.IPv4len > lenrd || off+net.IPv4len > lenmsg { if off+net.IPv4len > lenmsg {
return lenmsg, &Error{err: "overflow unpacking a"} return lenmsg, &Error{err: "overflow unpacking a"}
} }
fv.Set(reflect.ValueOf(net.IPv4(msg[off], msg[off+1], msg[off+2], msg[off+3]))) fv.Set(reflect.ValueOf(net.IPv4(msg[off], msg[off+1], msg[off+2], msg[off+3])))
off += net.IPv4len off += net.IPv4len
case `dns:"aaaa"`: case `dns:"aaaa"`:
if off == lenrd { if val.Type().String() == "dns.IPSECKEY" {
// Field(2) is GatewayType, must be 2
if val.Field(2).Uint() != 2 {
continue
}
}
if off == lenmsg {
break break
} }
if off+net.IPv6len > lenrd || off+net.IPv6len > lenmsg { if off+net.IPv6len > lenmsg {
return lenmsg, &Error{err: "overflow unpacking aaaa"} return lenmsg, &Error{err: "overflow unpacking aaaa"}
} }
fv.Set(reflect.ValueOf(net.IP{msg[off], msg[off+1], msg[off+2], msg[off+3], msg[off+4], fv.Set(reflect.ValueOf(net.IP{msg[off], msg[off+1], msg[off+2], msg[off+3], msg[off+4],
@ -1046,9 +1035,9 @@ func unpackStructValue(val reflect.Value, msg []byte, off int) (off1 int, err er
off += net.IPv6len off += net.IPv6len
case `dns:"wks"`: case `dns:"wks"`:
// Rest of the record is the bitmap // Rest of the record is the bitmap
serv := make([]uint16, 0) var serv []uint16
j := 0 j := 0
for off < lenrd { for off < lenmsg {
if off+1 > lenmsg { if off+1 > lenmsg {
return lenmsg, &Error{err: "overflow unpacking wks"} return lenmsg, &Error{err: "overflow unpacking wks"}
} }
@ -1083,36 +1072,39 @@ func unpackStructValue(val reflect.Value, msg []byte, off int) (off1 int, err er
} }
fv.Set(reflect.ValueOf(serv)) fv.Set(reflect.ValueOf(serv))
case `dns:"nsec"`: // NSEC/NSEC3 case `dns:"nsec"`: // NSEC/NSEC3
if off == lenrd { if off == len(msg) {
break break
} }
// Rest of the record is the type bitmap // Rest of the record is the type bitmap
if off+2 > lenrd || off+2 > lenmsg { var nsec []uint16
return lenmsg, &Error{err: "overflow unpacking nsecx"}
}
nsec := make([]uint16, 0)
length := 0 length := 0
window := 0 window := 0
for off+2 < lenrd { lastwindow := -1
for off < len(msg) {
if off+2 > len(msg) {
return len(msg), &Error{err: "overflow unpacking nsecx"}
}
window = int(msg[off]) window = int(msg[off])
length = int(msg[off+1]) length = int(msg[off+1])
//println("off, windows, length, end", off, window, length, endrr) off += 2
if window <= lastwindow {
// RFC 4034: Blocks are present in the NSEC RR RDATA in
// increasing numerical order.
return len(msg), &Error{err: "out of order NSEC block"}
}
if length == 0 { if length == 0 {
// A length window of zero is strange. If there // RFC 4034: Blocks with no types present MUST NOT be included.
// the window should not have been specified. Bail out return len(msg), &Error{err: "empty NSEC block"}
// println("dns: length == 0 when unpacking NSEC")
return lenmsg, &Error{err: "overflow unpacking nsecx"}
} }
if length > 32 { if length > 32 {
return lenmsg, &Error{err: "overflow unpacking nsecx"} return len(msg), &Error{err: "NSEC block too long"}
}
if off+length > len(msg) {
return len(msg), &Error{err: "overflowing NSEC block"}
} }
// Walk the bytes in the window - and check the bit settings... // Walk the bytes in the window and extract the type bits
off += 2
for j := 0; j < length; j++ { for j := 0; j < length; j++ {
if off+j+1 > lenmsg {
return lenmsg, &Error{err: "overflow unpacking nsecx"}
}
b := msg[off+j] b := msg[off+j]
// Check the bits one by one, and set the type // Check the bits one by one, and set the type
if b&0x80 == 0x80 { if b&0x80 == 0x80 {
@ -1141,6 +1133,7 @@ func unpackStructValue(val reflect.Value, msg []byte, off int) (off1 int, err er
} }
} }
off += length off += length
lastwindow = window
} }
fv.Set(reflect.ValueOf(nsec)) fv.Set(reflect.ValueOf(nsec))
} }
@ -1150,7 +1143,12 @@ func unpackStructValue(val reflect.Value, msg []byte, off int) (off1 int, err er
return lenmsg, err return lenmsg, err
} }
if val.Type().Field(i).Name == "Hdr" { if val.Type().Field(i).Name == "Hdr" {
lenrd = off + int(val.FieldByName("Hdr").FieldByName("Rdlength").Uint()) lenrd := off + int(val.FieldByName("Hdr").FieldByName("Rdlength").Uint())
if lenrd > lenmsg {
return lenmsg, &Error{err: "overflowing header size"}
}
msg = msg[:lenrd]
lenmsg = len(msg)
} }
case reflect.Uint8: case reflect.Uint8:
if off == lenmsg { if off == lenmsg {
@ -1181,6 +1179,9 @@ func unpackStructValue(val reflect.Value, msg []byte, off int) (off1 int, err er
fv.SetUint(uint64(uint32(msg[off])<<24 | uint32(msg[off+1])<<16 | uint32(msg[off+2])<<8 | uint32(msg[off+3]))) fv.SetUint(uint64(uint32(msg[off])<<24 | uint32(msg[off+1])<<16 | uint32(msg[off+2])<<8 | uint32(msg[off+3])))
off += 4 off += 4
case reflect.Uint64: case reflect.Uint64:
if off == lenmsg {
break
}
switch val.Type().Field(i).Tag { switch val.Type().Field(i).Tag {
default: default:
if off+8 > lenmsg { if off+8 > lenmsg {
@ -1206,32 +1207,42 @@ func unpackStructValue(val reflect.Value, msg []byte, off int) (off1 int, err er
switch val.Type().Field(i).Tag { switch val.Type().Field(i).Tag {
default: default:
return lenmsg, &Error{"bad tag unpacking string: " + val.Type().Field(i).Tag.Get("dns")} return lenmsg, &Error{"bad tag unpacking string: " + val.Type().Field(i).Tag.Get("dns")}
case `dns:"octet"`:
s = string(msg[off:])
off = lenmsg
case `dns:"hex"`: case `dns:"hex"`:
hexend := lenrd hexend := lenmsg
if val.FieldByName("Hdr").FieldByName("Rrtype").Uint() == uint64(TypeHIP) { if val.FieldByName("Hdr").FieldByName("Rrtype").Uint() == uint64(TypeHIP) {
hexend = off + int(val.FieldByName("HitLength").Uint()) hexend = off + int(val.FieldByName("HitLength").Uint())
} }
if hexend > lenrd || hexend > lenmsg { if hexend > lenmsg {
return lenmsg, &Error{err: "overflow unpacking hex"} return lenmsg, &Error{err: "overflow unpacking HIP hex"}
} }
s = hex.EncodeToString(msg[off:hexend]) s = hex.EncodeToString(msg[off:hexend])
off = hexend off = hexend
case `dns:"base64"`: case `dns:"base64"`:
// Rest of the RR is base64 encoded value // Rest of the RR is base64 encoded value
b64end := lenrd b64end := lenmsg
if val.FieldByName("Hdr").FieldByName("Rrtype").Uint() == uint64(TypeHIP) { if val.FieldByName("Hdr").FieldByName("Rrtype").Uint() == uint64(TypeHIP) {
b64end = off + int(val.FieldByName("PublicKeyLength").Uint()) b64end = off + int(val.FieldByName("PublicKeyLength").Uint())
} }
if b64end > lenrd || b64end > lenmsg { if b64end > lenmsg {
return lenmsg, &Error{err: "overflow unpacking base64"} return lenmsg, &Error{err: "overflow unpacking HIP base64"}
} }
s = toBase64(msg[off:b64end]) s = toBase64(msg[off:b64end])
off = b64end off = b64end
case `dns:"cdomain-name"`: case `dns:"cdomain-name"`:
fallthrough fallthrough
case `dns:"domain-name"`: case `dns:"domain-name"`:
if off == lenmsg { if val.Type().String() == "dns.IPSECKEY" {
// zero rdata foo, OK for dyn. updates // Field(2) is GatewayType, 1 and 2 or used for addresses
x := val.Field(2).Uint()
if x == 1 || x == 2 {
continue
}
}
if off == lenmsg && int(val.FieldByName("Hdr").FieldByName("Rdlength").Uint()) == 0 {
// zero rdata is ok for dyn updates, but only if rdlength is 0
break break
} }
s, off, err = UnpackDomainName(msg, off) s, off, err = UnpackDomainName(msg, off)
@ -1375,7 +1386,7 @@ func UnpackRR(msg []byte, off int) (rr RR, off1 int, err error) {
} }
end := off + int(h.Rdlength) end := off + int(h.Rdlength)
// make an rr of that type and re-unpack. // make an rr of that type and re-unpack.
mk, known := typeToRR[h.Rrtype] mk, known := TypeToRR[h.Rrtype]
if !known { if !known {
rr = new(RFC3597) rr = new(RFC3597)
} else { } else {
@ -1388,6 +1399,32 @@ func UnpackRR(msg []byte, off int) (rr RR, off1 int, err error) {
return rr, off, err return rr, off, err
} }
// unpackRRslice unpacks msg[off:] into an []RR.
// If we cannot unpack the whole array, then it will return nil
func unpackRRslice(l int, msg []byte, off int) (dst1 []RR, off1 int, err error) {
var r RR
// Optimistically make dst be the length that was sent
dst := make([]RR, 0, l)
for i := 0; i < l; i++ {
off1 := off
r, off, err = UnpackRR(msg, off)
if err != nil {
off = len(msg)
break
}
// If offset does not increase anymore, l is a lie
if off1 == off {
l = i
break
}
dst = append(dst, r)
}
if err != nil && off == len(msg) {
dst = nil
}
return dst, off, err
}
// Reverse a map // Reverse a map
func reverseInt8(m map[uint8]string) map[string]uint8 { func reverseInt8(m map[uint8]string) map[string]uint8 {
n := make(map[string]uint8) n := make(map[string]uint8)
@ -1586,52 +1623,48 @@ func (dns *Msg) Unpack(msg []byte) (err error) {
dns.CheckingDisabled = (dh.Bits & _CD) != 0 dns.CheckingDisabled = (dh.Bits & _CD) != 0
dns.Rcode = int(dh.Bits & 0xF) dns.Rcode = int(dh.Bits & 0xF)
// Arrays. // Optimistically use the count given to us in the header
dns.Question = make([]Question, dh.Qdcount) dns.Question = make([]Question, 0, int(dh.Qdcount))
dns.Answer = make([]RR, dh.Ancount)
dns.Ns = make([]RR, dh.Nscount)
dns.Extra = make([]RR, dh.Arcount)
for i := 0; i < len(dns.Question); i++ { var q Question
off, err = UnpackStruct(&dns.Question[i], msg, off) for i := 0; i < int(dh.Qdcount); i++ {
off1 := off
off, err = UnpackStruct(&q, msg, off)
if err != nil { if err != nil {
// Even if Truncated is set, we only will set ErrTruncated if we
// actually got the questions
return err return err
} }
} if off1 == off { // Offset does not increase anymore, dh.Qdcount is a lie!
// If we see a TC bit being set we return here, without dh.Qdcount = uint16(i)
// an error, because technically it isn't an error. So return break
// without parsing the potentially corrupt packet and hitting an error.
// TODO(miek): this isn't the best strategy!
if dns.Truncated {
dns.Answer = nil
dns.Ns = nil
dns.Extra = nil
return nil
}
for i := 0; i < len(dns.Answer); i++ {
dns.Answer[i], off, err = UnpackRR(msg, off)
if err != nil {
return err
} }
dns.Question = append(dns.Question, q)
} }
for i := 0; i < len(dns.Ns); i++ {
dns.Ns[i], off, err = UnpackRR(msg, off) dns.Answer, off, err = unpackRRslice(int(dh.Ancount), msg, off)
if err != nil { // The header counts might have been wrong so we need to update it
return err dh.Ancount = uint16(len(dns.Answer))
} if err == nil {
dns.Ns, off, err = unpackRRslice(int(dh.Nscount), msg, off)
} }
for i := 0; i < len(dns.Extra); i++ { // The header counts might have been wrong so we need to update it
dns.Extra[i], off, err = UnpackRR(msg, off) dh.Nscount = uint16(len(dns.Ns))
if err != nil { if err == nil {
return err dns.Extra, off, err = unpackRRslice(int(dh.Arcount), msg, off)
}
} }
// The header counts might have been wrong so we need to update it
dh.Arcount = uint16(len(dns.Extra))
if off != len(msg) { if off != len(msg) {
// TODO(miek) make this an error? // TODO(miek) make this an error?
// use PackOpt to let people tell how detailed the error reporting should be? // use PackOpt to let people tell how detailed the error reporting should be?
// println("dns: extra bytes in dns packet", off, "<", len(msg)) // println("dns: extra bytes in dns packet", off, "<", len(msg))
} else if dns.Truncated {
// Whether we ran into a an error or not, we want to return that it
// was truncated
err = ErrTruncated
} }
return nil return err
} }
// Convert a complete message to a string with dig-like output. // Convert a complete message to a string with dig-like output.
@ -1863,9 +1896,18 @@ func Copy(r RR) RR {
return r1 return r1
} }
// Len returns the length (in octets) of the uncompressed RR in wire format.
func Len(r RR) int {
return r.len()
}
// Copy returns a new *Msg which is a deep-copy of dns. // Copy returns a new *Msg which is a deep-copy of dns.
func (dns *Msg) Copy() *Msg { 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.MsgHdr = dns.MsgHdr
r1.Compress = dns.Compress r1.Compress = dns.Compress
@ -1874,25 +1916,34 @@ func (dns *Msg) Copy() *Msg {
copy(r1.Question, dns.Question) // TODO(miek): Question is an immutable value, ok to do a shallow-copy 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 { if len(dns.Answer) > 0 {
r1.Answer = make([]RR, len(dns.Answer)) rrbegin := rri
for i := 0; i < len(dns.Answer); i++ { 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 { if len(dns.Ns) > 0 {
r1.Ns = make([]RR, len(dns.Ns)) rrbegin := rri
for i := 0; i < len(dns.Ns); i++ { 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 { if len(dns.Extra) > 0 {
r1.Extra = make([]RR, len(dns.Extra)) rrbegin := rri
for i := 0; i < len(dns.Extra); i++ { 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 return r1

View File

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

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 package dns
import ( import (
@ -40,7 +33,7 @@ type PrivateRR struct {
func mkPrivateRR(rrtype uint16) *PrivateRR { func mkPrivateRR(rrtype uint16) *PrivateRR {
// Panics if RR is not an instance of PrivateRR. // Panics if RR is not an instance of PrivateRR.
rrfunc, ok := typeToRR[rrtype] rrfunc, ok := TypeToRR[rrtype]
if !ok { if !ok {
panic(fmt.Sprintf("dns: invalid operation with Private RR type %d", rrtype)) panic(fmt.Sprintf("dns: invalid operation with Private RR type %d", rrtype))
} }
@ -50,11 +43,13 @@ func mkPrivateRR(rrtype uint16) *PrivateRR {
case *PrivateRR: case *PrivateRR:
return rr return rr
} }
panic(fmt.Sprintf("dns: RR is not a PrivateRR, typeToRR[%d] generator returned %T", rrtype, anyrr)) panic(fmt.Sprintf("dns: RR is not a PrivateRR, TypeToRR[%d] generator returned %T", rrtype, anyrr))
} }
// Header return the RR header of r.
func (r *PrivateRR) Header() *RR_Header { return &r.Hdr } func (r *PrivateRR) Header() *RR_Header { return &r.Hdr }
func (r *PrivateRR) String() string { return r.Hdr.String() + r.Data.String() }
func (r *PrivateRR) String() string { return r.Hdr.String() + r.Data.String() }
// Private len and copy parts to satisfy RR interface. // Private len and copy parts to satisfy RR interface.
func (r *PrivateRR) len() int { return r.Hdr.len() + r.Data.Len() } func (r *PrivateRR) len() int { return r.Hdr.len() + r.Data.Len() }
@ -76,7 +71,7 @@ func (r *PrivateRR) copy() RR {
func PrivateHandle(rtypestr string, rtype uint16, generator func() PrivateRdata) { func PrivateHandle(rtypestr string, rtype uint16, generator func() PrivateRdata) {
rtypestr = strings.ToUpper(rtypestr) rtypestr = strings.ToUpper(rtypestr)
typeToRR[rtype] = func() RR { return &PrivateRR{RR_Header{}, generator()} } TypeToRR[rtype] = func() RR { return &PrivateRR{RR_Header{}, generator()} }
TypeToString[rtype] = rtypestr TypeToString[rtype] = rtypestr
StringToType[rtypestr] = rtype StringToType[rtypestr] = rtype
@ -91,9 +86,9 @@ func PrivateHandle(rtypestr string, rtype uint16, generator func() PrivateRdata)
// TODO(miek): we could also be returning _QUOTE, this might or might not // TODO(miek): we could also be returning _QUOTE, this might or might not
// be an issue (basically parsing TXT becomes hard) // be an issue (basically parsing TXT becomes hard)
switch l = <-c; l.value { switch l = <-c; l.value {
case _NEWLINE, _EOF: case zNewline, zEOF:
break FETCH break FETCH
case _STRING: case zString:
text = append(text, l.token) text = append(text, l.token)
} }
} }
@ -113,7 +108,7 @@ func PrivateHandle(rtypestr string, rtype uint16, generator func() PrivateRdata)
func PrivateHandleRemove(rtype uint16) { func PrivateHandleRemove(rtype uint16) {
rtypestr, ok := TypeToString[rtype] rtypestr, ok := TypeToString[rtype]
if ok { if ok {
delete(typeToRR, rtype) delete(TypeToRR, rtype)
delete(TypeToString, rtype) delete(TypeToString, rtype)
delete(typeToparserFunc, rtype) delete(typeToparserFunc, rtype)
delete(StringToType, rtypestr) delete(StringToType, rtypestr)

View File

@ -21,7 +21,7 @@ func rawSetQuestionLen(msg []byte, i uint16) bool {
return true return true
} }
// rawSetAnswerLen sets the lenght of the answer section. // rawSetAnswerLen sets the length of the answer section.
func rawSetAnswerLen(msg []byte, i uint16) bool { func rawSetAnswerLen(msg []byte, i uint16) bool {
if len(msg) < 8 { if len(msg) < 8 {
return false return false
@ -30,7 +30,7 @@ func rawSetAnswerLen(msg []byte, i uint16) bool {
return true return true
} }
// rawSetsNsLen sets the lenght of the authority section. // rawSetsNsLen sets the length of the authority section.
func rawSetNsLen(msg []byte, i uint16) bool { func rawSetNsLen(msg []byte, i uint16) bool {
if len(msg) < 10 { if len(msg) < 10 {
return false return false
@ -39,7 +39,7 @@ func rawSetNsLen(msg []byte, i uint16) bool {
return true return true
} }
// rawSetExtraLen sets the lenght of the additional section. // rawSetExtraLen sets the length of the additional section.
func rawSetExtraLen(msg []byte, i uint16) bool { func rawSetExtraLen(msg []byte, i uint16) bool {
if len(msg) < 12 { if len(msg) < 12 {
return false return false

84
vendor/github.com/miekg/dns/sanitize.go generated vendored Normal file
View File

@ -0,0 +1,84 @@
package dns
// Dedup removes identical RRs from rrs. It preserves the original ordering.
// The lowest TTL of any duplicates is used in the remaining one. Dedup modifies
// rrs.
// m is used to store the RRs temporay. If it is nil a new map will be allocated.
func Dedup(rrs []RR, m map[string]RR) []RR {
if m == nil {
m = make(map[string]RR)
}
// Save the keys, so we don't have to call normalizedString twice.
keys := make([]*string, 0, len(rrs))
for _, r := range rrs {
key := normalizedString(r)
keys = append(keys, &key)
if _, ok := m[key]; ok {
// Shortest TTL wins.
if m[key].Header().Ttl > r.Header().Ttl {
m[key].Header().Ttl = r.Header().Ttl
}
continue
}
m[key] = r
}
// If the length of the result map equals the amount of RRs we got,
// it means they were all different. We can then just return the original rrset.
if len(m) == len(rrs) {
return rrs
}
j := 0
for i, r := range rrs {
// If keys[i] lives in the map, we should copy and remove it.
if _, ok := m[*keys[i]]; ok {
delete(m, *keys[i])
rrs[j] = r
j++
}
if len(m) == 0 {
break
}
}
return rrs[:j]
}
// normalizedString returns a normalized string from r. The TTL
// is removed and the domain name is lowercased. We go from this:
// DomainName<TAB>TTL<TAB>CLASS<TAB>TYPE<TAB>RDATA to:
// lowercasename<TAB>CLASS<TAB>TYPE...
func normalizedString(r RR) string {
// A string Go DNS makes has: domainname<TAB>TTL<TAB>...
b := []byte(r.String())
// find the first non-escaped tab, then another, so we capture where the TTL lives.
esc := false
ttlStart, ttlEnd := 0, 0
for i := 0; i < len(b) && ttlEnd == 0; i++ {
switch {
case b[i] == '\\':
esc = !esc
case b[i] == '\t' && !esc:
if ttlStart == 0 {
ttlStart = i
continue
}
if ttlEnd == 0 {
ttlEnd = i
}
case b[i] >= 'A' && b[i] <= 'Z' && !esc:
b[i] += 32
default:
esc = false
}
}
// remove TTL.
copy(b[ttlStart:], b[ttlEnd:])
cut := ttlEnd - ttlStart
return string(b[:len(b)-cut])
}

311
vendor/github.com/miekg/dns/server.go generated vendored
View File

@ -4,12 +4,17 @@ package dns
import ( import (
"bytes" "bytes"
"crypto/tls"
"io" "io"
"net" "net"
"sync" "sync"
"time" "time"
) )
// Maximum number of TCP queries before we close the socket.
const maxTCPQueries = 128
// Handler is implemented by any value that implements ServeDNS.
type Handler interface { type Handler interface {
ServeDNS(w ResponseWriter, r *Msg) ServeDNS(w ResponseWriter, r *Msg)
} }
@ -43,9 +48,10 @@ type response struct {
tsigRequestMAC string tsigRequestMAC string
tsigSecret map[string]string // the tsig secrets tsigSecret map[string]string // the tsig secrets
udp *net.UDPConn // i/o connection if UDP was used udp *net.UDPConn // i/o connection if UDP was used
tcp *net.TCPConn // i/o connection if TCP was used tcp net.Conn // 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 remoteAddr net.Addr // address of the client
writer Writer // writer to output the raw DNS bits
} }
// ServeMux is an DNS request multiplexer. It matches the // ServeMux is an DNS request multiplexer. It matches the
@ -72,12 +78,12 @@ var DefaultServeMux = NewServeMux()
// Handler object that calls f. // Handler object that calls f.
type HandlerFunc func(ResponseWriter, *Msg) type HandlerFunc func(ResponseWriter, *Msg)
// ServerDNS calls f(w, r) // ServeDNS calls f(w, r).
func (f HandlerFunc) ServeDNS(w ResponseWriter, r *Msg) { func (f HandlerFunc) ServeDNS(w ResponseWriter, r *Msg) {
f(w, r) 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) { func HandleFailed(w ResponseWriter, r *Msg) {
m := new(Msg) m := new(Msg)
m.SetRcode(r, RcodeServerFailure) m.SetRcode(r, RcodeServerFailure)
@ -87,13 +93,35 @@ func HandleFailed(w ResponseWriter, r *Msg) {
func failedHandler() Handler { return HandlerFunc(HandleFailed) } func failedHandler() Handler { return HandlerFunc(HandleFailed) }
// ListenAndServe Starts a server on addresss and network speficied. Invoke handler // ListenAndServe Starts a server on address and network specified Invoke handler
// for incoming queries. // for incoming queries.
func ListenAndServe(addr string, network string, handler Handler) error { func ListenAndServe(addr string, network string, handler Handler) error {
server := &Server{Addr: addr, Net: network, Handler: handler} server := &Server{Addr: addr, Net: network, Handler: handler}
return server.ListenAndServe() return server.ListenAndServe()
} }
// ListenAndServeTLS acts like http.ListenAndServeTLS, more information in
// http://golang.org/pkg/net/http/#ListenAndServeTLS
func ListenAndServeTLS(addr, certFile, keyFile string, handler Handler) error {
cert, err := tls.LoadX509KeyPair(certFile, keyFile)
if err != nil {
return err
}
config := tls.Config{
Certificates: []tls.Certificate{cert},
}
server := &Server{
Addr: addr,
Net: "tcp-tls",
TLSConfig: &config,
Handler: handler,
}
return server.ListenAndServe()
}
// ActivateAndServe activates a server with a listener from systemd, // ActivateAndServe activates a server with a listener from systemd,
// l and p should not both be non-nil. // l and p should not both be non-nil.
// If both l and p are not nil only p will be used. // If both l and p are not nil only p will be used.
@ -121,10 +149,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 h, ok := mux.z[string(b[:l])]; ok { // 'causes garbage, might want to change the map key
if t != TypeDS { if t != TypeDS {
return h 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) off, end = NextLabel(q, off)
if end { if end {
@ -148,7 +175,7 @@ func (mux *ServeMux) Handle(pattern string, handler Handler) {
mux.m.Unlock() 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)) { func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Msg)) {
mux.Handle(pattern, HandlerFunc(handler)) mux.Handle(pattern, HandlerFunc(handler))
} }
@ -158,9 +185,9 @@ func (mux *ServeMux) HandleRemove(pattern string) {
if pattern == "" { if pattern == "" {
panic("dns: invalid pattern " + pattern) panic("dns: invalid pattern " + pattern)
} }
// don't need a mutex here, because deleting is OK, even if the mux.m.Lock()
// entry is note there.
delete(mux.z, Fqdn(pattern)) delete(mux.z, Fqdn(pattern))
mux.m.Unlock()
} }
// ServeDNS dispatches the request to the handler whose // ServeDNS dispatches the request to the handler whose
@ -197,14 +224,53 @@ func HandleFunc(pattern string, handler func(ResponseWriter, *Msg)) {
DefaultServeMux.HandleFunc(pattern, handler) DefaultServeMux.HandleFunc(pattern, handler)
} }
// Writer writes raw DNS messages; each call to Write should send an entire message.
type Writer interface {
io.Writer
}
// Reader reads raw DNS messages; each call to ReadTCP or ReadUDP should return an entire message.
type Reader interface {
// ReadTCP reads a raw message from a TCP connection. Implementations may alter
// connection properties, for example the read-deadline.
ReadTCP(conn net.Conn, timeout time.Duration) ([]byte, error)
// ReadUDP reads a raw message from a UDP connection. Implementations may alter
// connection properties, for example the read-deadline.
ReadUDP(conn *net.UDPConn, timeout time.Duration) ([]byte, *SessionUDP, error)
}
// defaultReader is an adapter for the Server struct that implements the Reader interface
// using the readTCP and readUDP func of the embedded Server.
type defaultReader struct {
*Server
}
func (dr *defaultReader) ReadTCP(conn net.Conn, timeout time.Duration) ([]byte, error) {
return dr.readTCP(conn, timeout)
}
func (dr *defaultReader) ReadUDP(conn *net.UDPConn, timeout time.Duration) ([]byte, *SessionUDP, error) {
return dr.readUDP(conn, timeout)
}
// DecorateReader is a decorator hook for extending or supplanting the functionality of a Reader.
// Implementations should never return a nil Reader.
type DecorateReader func(Reader) Reader
// DecorateWriter is a decorator hook for extending or supplanting the functionality of a Writer.
// Implementations should never return a nil Writer.
type DecorateWriter func(Writer) Writer
// A Server defines parameters for running an DNS server. // A Server defines parameters for running an DNS server.
type Server struct { type Server struct {
// Address to listen on, ":dns" if empty. // Address to listen on, ":dns" if empty.
Addr string Addr string
// if "tcp" it will invoke a TCP listener, otherwise an UDP one. // if "tcp" or "tcp-tls" (DNS over TLS) it will invoke a TCP listener, otherwise an UDP one
Net string Net string
// TCP Listener to use, this is to aid in systemd's socket activation. // TCP Listener to use, this is to aid in systemd's socket activation.
Listener net.Listener Listener net.Listener
// TLS connection configuration
TLSConfig *tls.Config
// UDP "Listener" to use, this is to aid in systemd's socket activation. // UDP "Listener" to use, this is to aid in systemd's socket activation.
PacketConn net.PacketConn PacketConn net.PacketConn
// Handler to invoke, dns.DefaultServeMux if nil. // Handler to invoke, dns.DefaultServeMux if nil.
@ -221,31 +287,30 @@ type Server struct {
// Secret(s) for Tsig map[<zonename>]<base64 secret>. // Secret(s) for Tsig map[<zonename>]<base64 secret>.
TsigSecret map[string]string TsigSecret map[string]string
// Unsafe instructs the server to disregard any sanity checks and directly hand the message to // Unsafe instructs the server to disregard any sanity checks and directly hand the message to
// the handler. It will specfically not check if the query has the QR bit not set. // the handler. It will specifically not check if the query has the QR bit not set.
Unsafe bool Unsafe bool
// If NotifyStartedFunc is set is is called, once the server has started listening. // If NotifyStartedFunc is set it is called once the server has started listening.
NotifyStartedFunc func() NotifyStartedFunc func()
// DecorateReader is optional, allows customization of the process that reads raw DNS messages.
DecorateReader DecorateReader
// DecorateWriter is optional, allows customization of the process that writes raw DNS messages.
DecorateWriter DecorateWriter
// For graceful shutdown. // Graceful shutdown handling
stopUDP chan bool
stopTCP chan bool
wgUDP sync.WaitGroup
wgTCP sync.WaitGroup
// make start/shutdown not racy inFlight sync.WaitGroup
lock sync.Mutex
lock sync.RWMutex
started bool started bool
} }
// ListenAndServe starts a nameserver on the configured address in *Server. // ListenAndServe starts a nameserver on the configured address in *Server.
func (srv *Server) ListenAndServe() error { func (srv *Server) ListenAndServe() error {
srv.lock.Lock() srv.lock.Lock()
defer srv.lock.Unlock()
if srv.started { if srv.started {
return &Error{err: "server already started"} return &Error{err: "server already started"}
} }
srv.stopUDP, srv.stopTCP = make(chan bool), make(chan bool)
srv.started = true
srv.lock.Unlock()
addr := srv.Addr addr := srv.Addr
if addr == "" { if addr == "" {
addr = ":domain" addr = ":domain"
@ -263,7 +328,30 @@ func (srv *Server) ListenAndServe() error {
if e != nil { if e != nil {
return e return e
} }
return srv.serveTCP(l) srv.Listener = l
srv.started = true
srv.lock.Unlock()
e = srv.serveTCP(l)
srv.lock.Lock() // to satisfy the defer at the top
return e
case "tcp-tls", "tcp4-tls", "tcp6-tls":
network := "tcp"
if srv.Net == "tcp4-tls" {
network = "tcp4"
} else if srv.Net == "tcp6" {
network = "tcp6"
}
l, e := tls.Listen(network, addr, srv.TLSConfig)
if e != nil {
return e
}
srv.Listener = l
srv.started = true
srv.lock.Unlock()
e = srv.serveTCP(l)
srv.lock.Lock() // to satisfy the defer at the top
return e
case "udp", "udp4", "udp6": case "udp", "udp4", "udp6":
a, e := net.ResolveUDPAddr(srv.Net, addr) a, e := net.ResolveUDPAddr(srv.Net, addr)
if e != nil { if e != nil {
@ -276,7 +364,12 @@ func (srv *Server) ListenAndServe() error {
if e := setUDPSocketOptions(l); e != nil { if e := setUDPSocketOptions(l); e != nil {
return e return e
} }
return srv.serveUDP(l) srv.PacketConn = l
srv.started = true
srv.lock.Unlock()
e = srv.serveUDP(l)
srv.lock.Lock() // to satisfy the defer at the top
return e
} }
return &Error{err: "bad network"} return &Error{err: "bad network"}
} }
@ -285,71 +378,62 @@ func (srv *Server) ListenAndServe() error {
// configured in *Server. Its main use is to start a server from systemd. // configured in *Server. Its main use is to start a server from systemd.
func (srv *Server) ActivateAndServe() error { func (srv *Server) ActivateAndServe() error {
srv.lock.Lock() srv.lock.Lock()
defer srv.lock.Unlock()
if srv.started { if srv.started {
return &Error{err: "server already started"} return &Error{err: "server already started"}
} }
srv.stopUDP, srv.stopTCP = make(chan bool), make(chan bool) pConn := srv.PacketConn
srv.started = true l := srv.Listener
srv.lock.Unlock() if pConn != nil {
if srv.PacketConn != nil {
if srv.UDPSize == 0 { if srv.UDPSize == 0 {
srv.UDPSize = MinMsgSize srv.UDPSize = MinMsgSize
} }
if t, ok := srv.PacketConn.(*net.UDPConn); ok { if t, ok := pConn.(*net.UDPConn); ok {
if e := setUDPSocketOptions(t); e != nil { if e := setUDPSocketOptions(t); e != nil {
return e return e
} }
return srv.serveUDP(t) srv.started = true
srv.lock.Unlock()
e := srv.serveUDP(t)
srv.lock.Lock() // to satisfy the defer at the top
return e
} }
} }
if srv.Listener != nil { if l != nil {
if t, ok := srv.Listener.(*net.TCPListener); ok { srv.started = true
return srv.serveTCP(t) srv.lock.Unlock()
} e := srv.serveTCP(l)
srv.lock.Lock() // to satisfy the defer at the top
return e
} }
return &Error{err: "bad listeners"} return &Error{err: "bad listeners"}
} }
// Shutdown gracefully shuts down a server. After a call to Shutdown, ListenAndServe and // Shutdown gracefully shuts down a server. After a call to Shutdown, ListenAndServe and
// ActivateAndServe will return. All in progress queries are completed before the server // ActivateAndServe will return. All in progress queries are completed before the server
// is taken down. If the Shutdown is taking longer than the reading timeout and error // is taken down. If the Shutdown is taking longer than the reading timeout an error
// is returned. // is returned.
func (srv *Server) Shutdown() error { func (srv *Server) Shutdown() error {
srv.lock.Lock() srv.lock.Lock()
if !srv.started { if !srv.started {
srv.lock.Unlock()
return &Error{err: "server not started"} return &Error{err: "server not started"}
} }
srv.started = false srv.started = false
srv.lock.Unlock() srv.lock.Unlock()
net, addr := srv.Net, srv.Addr
switch { if srv.PacketConn != nil {
case srv.Listener != nil: srv.PacketConn.Close()
a := srv.Listener.Addr() }
net, addr = a.Network(), a.String() if srv.Listener != nil {
case srv.PacketConn != nil: srv.Listener.Close()
a := srv.PacketConn.LocalAddr()
net, addr = a.Network(), a.String()
} }
fin := make(chan bool) fin := make(chan bool)
switch net { go func() {
case "tcp", "tcp4", "tcp6": srv.inFlight.Wait()
go func() { fin <- true
srv.stopTCP <- true }()
srv.wgTCP.Wait()
fin <- true
}()
case "udp", "udp4", "udp6":
go func() {
srv.stopUDP <- true
srv.wgUDP.Wait()
fin <- true
}()
}
c := &Client{Net: net}
go c.Exchange(new(Msg), addr) // extra query to help ReadXXX loop to pass
select { select {
case <-time.After(srv.getReadTimeout()): case <-time.After(srv.getReadTimeout()):
@ -369,14 +453,19 @@ func (srv *Server) getReadTimeout() time.Duration {
} }
// serveTCP starts a TCP listener for the server. // 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 { func (srv *Server) serveTCP(l net.Listener) error {
defer l.Close() defer l.Close()
if srv.NotifyStartedFunc != nil { if srv.NotifyStartedFunc != nil {
srv.NotifyStartedFunc() srv.NotifyStartedFunc()
} }
reader := Reader(&defaultReader{srv})
if srv.DecorateReader != nil {
reader = srv.DecorateReader(reader)
}
handler := srv.Handler handler := srv.Handler
if handler == nil { if handler == nil {
handler = DefaultServeMux handler = DefaultServeMux
@ -384,27 +473,30 @@ func (srv *Server) serveTCP(l *net.TCPListener) error {
rtimeout := srv.getReadTimeout() rtimeout := srv.getReadTimeout()
// deadline is not used here // deadline is not used here
for { for {
rw, e := l.AcceptTCP() rw, e := l.Accept()
if e != nil { if e != nil {
continue if neterr, ok := e.(net.Error); ok && neterr.Temporary() {
continue
}
return e
} }
m, e := srv.readTCP(rw, rtimeout) m, e := reader.ReadTCP(rw, rtimeout)
select { srv.lock.RLock()
case <-srv.stopTCP: if !srv.started {
srv.lock.RUnlock()
return nil return nil
default:
} }
srv.lock.RUnlock()
if e != nil { if e != nil {
continue continue
} }
srv.wgTCP.Add(1) srv.inFlight.Add(1)
go srv.serve(rw.RemoteAddr(), handler, m, nil, nil, rw) go srv.serve(rw.RemoteAddr(), handler, m, nil, nil, rw)
} }
panic("dns: not reached")
} }
// serveUDP starts a UDP listener for the server. // 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 { func (srv *Server) serveUDP(l *net.UDPConn) error {
defer l.Close() defer l.Close()
@ -412,6 +504,11 @@ func (srv *Server) serveUDP(l *net.UDPConn) error {
srv.NotifyStartedFunc() srv.NotifyStartedFunc()
} }
reader := Reader(&defaultReader{srv})
if srv.DecorateReader != nil {
reader = srv.DecorateReader(reader)
}
handler := srv.Handler handler := srv.Handler
if handler == nil { if handler == nil {
handler = DefaultServeMux handler = DefaultServeMux
@ -419,35 +516,39 @@ func (srv *Server) serveUDP(l *net.UDPConn) error {
rtimeout := srv.getReadTimeout() rtimeout := srv.getReadTimeout()
// deadline is not used here // deadline is not used here
for { for {
m, s, e := srv.readUDP(l, rtimeout) m, s, e := reader.ReadUDP(l, rtimeout)
select { srv.lock.RLock()
case <-srv.stopUDP: if !srv.started {
srv.lock.RUnlock()
return nil return nil
default:
} }
srv.lock.RUnlock()
if e != nil { if e != nil {
continue continue
} }
srv.wgUDP.Add(1) srv.inFlight.Add(1)
go srv.serve(s.RemoteAddr(), handler, m, l, s, nil) go srv.serve(s.RemoteAddr(), handler, m, l, s, nil)
} }
panic("dns: not reached")
} }
// Serve a new connection. // 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.Conn) {
defer srv.inFlight.Done()
w := &response{tsigSecret: srv.TsigSecret, udp: u, tcp: t, remoteAddr: a, udpSession: s} w := &response{tsigSecret: srv.TsigSecret, udp: u, tcp: t, remoteAddr: a, udpSession: s}
q := 0 if srv.DecorateWriter != nil {
defer func() { w.writer = srv.DecorateWriter(w)
if u != nil { } else {
srv.wgUDP.Done() w.writer = w
} }
if t != nil {
srv.wgTCP.Done() q := 0 // counter for the amount of TCP queries we get
}
}() reader := Reader(&defaultReader{srv})
if srv.DecorateReader != nil {
reader = srv.DecorateReader(reader)
}
Redo: Redo:
// Ideally we want use isMsg here before we allocate memory to actually parse the packet.
req := new(Msg) req := new(Msg)
err := req.Unpack(m) err := req.Unpack(m)
if err != nil { // Send a FormatError back if err != nil { // Send a FormatError back
@ -475,6 +576,15 @@ Redo:
h.ServeDNS(w, req) // Writes back to the client h.ServeDNS(w, req) // Writes back to the client
Exit: Exit:
if w.tcp == nil {
return
}
// TODO(miek): make this number configurable?
if q > maxTCPQueries { // close socket after this many queries
w.Close()
return
}
if w.hijacked { if w.hijacked {
return // client calls Close() return // client calls Close()
} }
@ -486,21 +596,16 @@ Exit:
if srv.IdleTimeout != nil { if srv.IdleTimeout != nil {
idleTimeout = srv.IdleTimeout() idleTimeout = srv.IdleTimeout()
} }
m, e := srv.readTCP(w.tcp, idleTimeout) m, e := reader.ReadTCP(w.tcp, idleTimeout)
if e == nil { if e == nil {
q++ q++
// TODO(miek): make this number configurable?
if q > 128 { // close socket after this many queries
w.Close()
return
}
goto Redo goto Redo
} }
w.Close() w.Close()
return return
} }
func (srv *Server) readTCP(conn *net.TCPConn, timeout time.Duration) ([]byte, error) { func (srv *Server) readTCP(conn net.Conn, timeout time.Duration) ([]byte, error) {
conn.SetReadDeadline(time.Now().Add(timeout)) conn.SetReadDeadline(time.Now().Add(timeout))
l := make([]byte, 2) l := make([]byte, 2)
n, err := conn.Read(l) n, err := conn.Read(l)
@ -535,10 +640,10 @@ func (srv *Server) readTCP(conn *net.TCPConn, timeout time.Duration) ([]byte, er
return m, nil 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)) conn.SetReadDeadline(time.Now().Add(timeout))
m := make([]byte, srv.UDPSize) 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 || n == 0 {
if e != nil { if e != nil {
return nil, nil, e return nil, nil, e
@ -558,7 +663,7 @@ func (w *response) WriteMsg(m *Msg) (err error) {
if err != nil { if err != nil {
return err return err
} }
_, err = w.Write(data) _, err = w.writer.Write(data)
return err return err
} }
} }
@ -566,7 +671,7 @@ func (w *response) WriteMsg(m *Msg) (err error) {
if err != nil { if err != nil {
return err return err
} }
_, err = w.Write(data) _, err = w.writer.Write(data)
return err return err
} }
@ -574,7 +679,7 @@ func (w *response) WriteMsg(m *Msg) (err error) {
func (w *response) Write(m []byte) (int, error) { func (w *response) Write(m []byte) (int, error) {
switch { switch {
case w.udp != nil: case w.udp != nil:
n, err := writeToSessionUDP(w.udp, m, w.udpSession) n, err := WriteToSessionUDP(w.udp, m, w.udpSession)
return n, err return n, err
case w.tcp != nil: case w.tcp != nil:
lm := len(m) lm := len(m)

74
vendor/github.com/miekg/dns/sig0.go generated vendored
View File

@ -1,25 +1,9 @@
// 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 package dns
import ( import (
"crypto" "crypto"
"crypto/dsa" "crypto/dsa"
"crypto/ecdsa" "crypto/ecdsa"
"crypto/rand"
"crypto/rsa" "crypto/rsa"
"math/big" "math/big"
"strings" "strings"
@ -29,7 +13,7 @@ import (
// Sign signs a dns.Msg. It fills the signature with the appropriate data. // Sign signs a dns.Msg. It fills the signature with the appropriate data.
// The SIG record should have the SignerName, KeyTag, Algorithm, Inception // The SIG record should have the SignerName, KeyTag, Algorithm, Inception
// and Expiration set. // and Expiration set.
func (rr *SIG) Sign(k PrivateKey, m *Msg) ([]byte, error) { func (rr *SIG) Sign(k crypto.Signer, m *Msg) ([]byte, error) {
if k == nil { if k == nil {
return nil, ErrPrivKey return nil, ErrPrivKey
} }
@ -57,56 +41,26 @@ func (rr *SIG) Sign(k PrivateKey, m *Msg) ([]byte, error) {
return nil, err return nil, err
} }
buf = buf[:off:cap(buf)] buf = buf[:off:cap(buf)]
var hash crypto.Hash
var intlen int hash, ok := AlgorithmToHash[rr.Algorithm]
switch rr.Algorithm { if !ok {
case DSA, RSASHA1:
hash = crypto.SHA1
case RSASHA256, ECDSAP256SHA256:
hash = crypto.SHA256
intlen = 32
case ECDSAP384SHA384:
hash = crypto.SHA384
intlen = 48
case RSASHA512:
hash = crypto.SHA512
default:
return nil, ErrAlg return nil, ErrAlg
} }
hasher := hash.New() hasher := hash.New()
// Write SIG rdata // Write SIG rdata
hasher.Write(buf[len(mbuf)+1+2+2+4+2:]) hasher.Write(buf[len(mbuf)+1+2+2+4+2:])
// Write message // Write message
hasher.Write(buf[:len(mbuf)]) hasher.Write(buf[:len(mbuf)])
hashed := hasher.Sum(nil)
var sig []byte signature, err := sign(k, hasher.Sum(nil), hash, rr.Algorithm)
switch p := k.(type) { if err != nil {
case *dsa.PrivateKey: return nil, err
t := divRoundUp(divRoundUp(p.PublicKey.Y.BitLen(), 8)-64, 8)
r1, s1, err := dsa.Sign(rand.Reader, p, hashed)
if err != nil {
return nil, err
}
sig = append(sig, byte(t))
sig = append(sig, intToBytes(r1, 20)...)
sig = append(sig, intToBytes(s1, 20)...)
case *rsa.PrivateKey:
sig, err = rsa.SignPKCS1v15(rand.Reader, p, hash, hashed)
if err != nil {
return nil, err
}
case *ecdsa.PrivateKey:
r1, s1, err := ecdsa.Sign(rand.Reader, p, hashed)
if err != nil {
return nil, err
}
sig = intToBytes(r1, intlen)
sig = append(sig, intToBytes(s1, intlen)...)
default:
return nil, ErrAlg
} }
rr.Signature = toBase64(sig)
rr.Signature = toBase64(signature)
sig := string(signature)
buf = append(buf, sig...) buf = append(buf, sig...)
if len(buf) > int(^uint16(0)) { if len(buf) > int(^uint16(0)) {
return nil, ErrBuf return nil, ErrBuf
@ -118,7 +72,7 @@ func (rr *SIG) Sign(k PrivateKey, m *Msg) ([]byte, error) {
buf[rdoff], buf[rdoff+1] = packUint16(rdlen) buf[rdoff], buf[rdoff+1] = packUint16(rdlen)
// Adjust additional count // Adjust additional count
adc, _ := unpackUint16(buf, 10) adc, _ := unpackUint16(buf, 10)
adc += 1 adc++
buf[10], buf[11] = packUint16(adc) buf[10], buf[11] = packUint16(adc)
return buf, nil return buf, nil
} }
@ -246,7 +200,7 @@ func (rr *SIG) Verify(k *KEY, buf []byte) error {
return rsa.VerifyPKCS1v15(pk, hash, hashed, sig) return rsa.VerifyPKCS1v15(pk, hash, hashed, sig)
} }
case ECDSAP256SHA256, ECDSAP384SHA384: case ECDSAP256SHA256, ECDSAP384SHA384:
pk := k.publicKeyCurve() pk := k.publicKeyECDSA()
r := big.NewInt(0) r := big.NewInt(0)
r.SetBytes(sig[:len(sig)/2]) r.SetBytes(sig[:len(sig)/2])
s := big.NewInt(0) s := big.NewInt(0)

View File

@ -25,7 +25,8 @@ func CertificateToDANE(selector, matchingType uint8, cert *x509.Certificate) (st
h := sha256.New() h := sha256.New()
switch selector { switch selector {
case 0: case 0:
return hex.EncodeToString(cert.Raw), nil io.WriteString(h, string(cert.Raw))
return hex.EncodeToString(h.Sum(nil)), nil
case 1: case 1:
io.WriteString(h, string(cert.RawSubjectPublicKeyInfo)) io.WriteString(h, string(cert.RawSubjectPublicKeyInfo))
return hex.EncodeToString(h.Sum(nil)), nil return hex.EncodeToString(h.Sum(nil)), nil
@ -34,7 +35,8 @@ func CertificateToDANE(selector, matchingType uint8, cert *x509.Certificate) (st
h := sha512.New() h := sha512.New()
switch selector { switch selector {
case 0: case 0:
return hex.EncodeToString(cert.Raw), nil io.WriteString(h, string(cert.Raw))
return hex.EncodeToString(h.Sum(nil)), nil
case 1: case 1:
io.WriteString(h, string(cert.RawSubjectPublicKeyInfo)) io.WriteString(h, string(cert.RawSubjectPublicKeyInfo))
return hex.EncodeToString(h.Sum(nil)), nil return hex.EncodeToString(h.Sum(nil)), nil
@ -80,5 +82,5 @@ func TLSAName(name, service, network string) (string, error) {
if e != nil { if e != nil {
return "", e return "", e
} }
return "_" + strconv.Itoa(p) + "_" + network + "." + name, nil return "_" + strconv.Itoa(p) + "._" + network + "." + name, nil
} }

78
vendor/github.com/miekg/dns/tsig.go generated vendored
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 and HmacSHA256.
//
// 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 package dns
import ( import (
@ -58,6 +5,7 @@ import (
"crypto/md5" "crypto/md5"
"crypto/sha1" "crypto/sha1"
"crypto/sha256" "crypto/sha256"
"crypto/sha512"
"encoding/hex" "encoding/hex"
"hash" "hash"
"io" "io"
@ -71,8 +19,11 @@ const (
HmacMD5 = "hmac-md5.sig-alg.reg.int." HmacMD5 = "hmac-md5.sig-alg.reg.int."
HmacSHA1 = "hmac-sha1." HmacSHA1 = "hmac-sha1."
HmacSHA256 = "hmac-sha256." HmacSHA256 = "hmac-sha256."
HmacSHA512 = "hmac-sha512."
) )
// TSIG is the RR the holds the transaction signature of a message.
// See RFC 2845 and RFC 4635.
type TSIG struct { type TSIG struct {
Hdr RR_Header Hdr RR_Header
Algorithm string `dns:"domain-name"` Algorithm string `dns:"domain-name"`
@ -86,10 +37,6 @@ type TSIG struct {
OtherData string `dns:"size-hex"` OtherData string `dns:"size-hex"`
} }
func (rr *TSIG) Header() *RR_Header {
return &rr.Hdr
}
// TSIG has no official presentation format, but this will suffice. // TSIG has no official presentation format, but this will suffice.
func (rr *TSIG) String() string { func (rr *TSIG) String() string {
@ -107,15 +54,6 @@ func (rr *TSIG) String() string {
return s return s
} }
func (rr *TSIG) len() int {
return rr.Hdr.len() + len(rr.Algorithm) + 1 + 6 +
4 + len(rr.MAC)/2 + 1 + 6 + len(rr.OtherData)/2 + 1
}
func (rr *TSIG) copy() RR {
return &TSIG{*rr.Hdr.copyHeader(), rr.Algorithm, rr.TimeSigned, rr.Fudge, rr.MACSize, rr.MAC, rr.OrigId, rr.Error, rr.OtherLen, rr.OtherData}
}
// The following values must be put in wireformat, so that the MAC can be calculated. // The following values must be put in wireformat, so that the MAC can be calculated.
// RFC 2845, section 3.4.2. TSIG Variables. // RFC 2845, section 3.4.2. TSIG Variables.
type tsigWireFmt struct { type tsigWireFmt struct {
@ -174,13 +112,15 @@ func TsigGenerate(m *Msg, secret, requestMAC string, timersOnly bool) ([]byte, s
t := new(TSIG) t := new(TSIG)
var h hash.Hash var h hash.Hash
switch rr.Algorithm { switch strings.ToLower(rr.Algorithm) {
case HmacMD5: case HmacMD5:
h = hmac.New(md5.New, []byte(rawsecret)) h = hmac.New(md5.New, []byte(rawsecret))
case HmacSHA1: case HmacSHA1:
h = hmac.New(sha1.New, []byte(rawsecret)) h = hmac.New(sha1.New, []byte(rawsecret))
case HmacSHA256: case HmacSHA256:
h = hmac.New(sha256.New, []byte(rawsecret)) h = hmac.New(sha256.New, []byte(rawsecret))
case HmacSHA512:
h = hmac.New(sha512.New, []byte(rawsecret))
default: default:
return nil, "", ErrKeyAlg return nil, "", ErrKeyAlg
} }
@ -238,13 +178,15 @@ func TsigVerify(msg []byte, secret, requestMAC string, timersOnly bool) error {
} }
var h hash.Hash var h hash.Hash
switch tsig.Algorithm { switch strings.ToLower(tsig.Algorithm) {
case HmacMD5: case HmacMD5:
h = hmac.New(md5.New, rawsecret) h = hmac.New(md5.New, rawsecret)
case HmacSHA1: case HmacSHA1:
h = hmac.New(sha1.New, rawsecret) h = hmac.New(sha1.New, rawsecret)
case HmacSHA256: case HmacSHA256:
h = hmac.New(sha256.New, rawsecret) h = hmac.New(sha256.New, rawsecret)
case HmacSHA512:
h = hmac.New(sha512.New, rawsecret)
default: default:
return ErrKeyAlg return ErrKeyAlg
} }

643
vendor/github.com/miekg/dns/types.go generated vendored

File diff suppressed because it is too large Load Diff

266
vendor/github.com/miekg/dns/types_generate.go generated vendored Normal file
View File

@ -0,0 +1,266 @@
//+build ignore
// types_generate.go is meant to run with go generate. It will use
// go/{importer,types} to track down all the RR struct types. Then for each type
// it will generate conversion tables (TypeToRR and TypeToString) and banal
// methods (len, Header, copy) based on the struct tags. The generated source is
// written to ztypes.go, and is meant to be checked into git.
package main
import (
"bytes"
"fmt"
"go/format"
"go/importer"
"go/types"
"log"
"os"
"strings"
"text/template"
)
var skipLen = map[string]struct{}{
"NSEC": {},
"NSEC3": {},
"OPT": {},
"WKS": {},
"IPSECKEY": {},
}
var packageHdr = `
// *** DO NOT MODIFY ***
// AUTOGENERATED BY go generate
package dns
import (
"encoding/base64"
"net"
)
`
var TypeToRR = template.Must(template.New("TypeToRR").Parse(`
// TypeToRR is a map of constructors for each RR type.
var TypeToRR = map[uint16]func() RR{
{{range .}}{{if ne . "RFC3597"}} Type{{.}}: func() RR { return new({{.}}) },
{{end}}{{end}} }
`))
var typeToString = template.Must(template.New("typeToString").Parse(`
// TypeToString is a map of strings for each RR type.
var TypeToString = map[uint16]string{
{{range .}}{{if ne . "NSAPPTR"}} Type{{.}}: "{{.}}",
{{end}}{{end}} TypeNSAPPTR: "NSAP-PTR",
}
`))
var headerFunc = template.Must(template.New("headerFunc").Parse(`
// Header() functions
{{range .}} func (rr *{{.}}) Header() *RR_Header { return &rr.Hdr }
{{end}}
`))
// getTypeStruct will take a type and the package scope, and return the
// (innermost) struct if the type is considered a RR type (currently defined as
// those structs beginning with a RR_Header, could be redefined as implementing
// the RR interface). The bool return value indicates if embedded structs were
// resolved.
func getTypeStruct(t types.Type, scope *types.Scope) (*types.Struct, bool) {
st, ok := t.Underlying().(*types.Struct)
if !ok {
return nil, false
}
if st.Field(0).Type() == scope.Lookup("RR_Header").Type() {
return st, false
}
if st.Field(0).Anonymous() {
st, _ := getTypeStruct(st.Field(0).Type(), scope)
return st, true
}
return nil, false
}
func main() {
// Import and type-check the package
pkg, err := importer.Default().Import("github.com/miekg/dns")
fatalIfErr(err)
scope := pkg.Scope()
// Collect constants like TypeX
var numberedTypes []string
for _, name := range scope.Names() {
o := scope.Lookup(name)
if o == nil || !o.Exported() {
continue
}
b, ok := o.Type().(*types.Basic)
if !ok || b.Kind() != types.Uint16 {
continue
}
if !strings.HasPrefix(o.Name(), "Type") {
continue
}
name := strings.TrimPrefix(o.Name(), "Type")
if name == "PrivateRR" {
continue
}
numberedTypes = append(numberedTypes, name)
}
// Collect actual types (*X)
var namedTypes []string
for _, name := range scope.Names() {
o := scope.Lookup(name)
if o == nil || !o.Exported() {
continue
}
if st, _ := getTypeStruct(o.Type(), scope); st == nil {
continue
}
if name == "PrivateRR" {
continue
}
// Check if corresponding TypeX exists
if scope.Lookup("Type"+o.Name()) == nil && o.Name() != "RFC3597" {
log.Fatalf("Constant Type%s does not exist.", o.Name())
}
namedTypes = append(namedTypes, o.Name())
}
b := &bytes.Buffer{}
b.WriteString(packageHdr)
// Generate TypeToRR
fatalIfErr(TypeToRR.Execute(b, namedTypes))
// Generate typeToString
fatalIfErr(typeToString.Execute(b, numberedTypes))
// Generate headerFunc
fatalIfErr(headerFunc.Execute(b, namedTypes))
// Generate len()
fmt.Fprint(b, "// len() functions\n")
for _, name := range namedTypes {
if _, ok := skipLen[name]; ok {
continue
}
o := scope.Lookup(name)
st, isEmbedded := getTypeStruct(o.Type(), scope)
if isEmbedded {
continue
}
fmt.Fprintf(b, "func (rr *%s) len() int {\n", name)
fmt.Fprintf(b, "l := rr.Hdr.len()\n")
for i := 1; i < st.NumFields(); i++ {
o := func(s string) { fmt.Fprintf(b, s, st.Field(i).Name()) }
if _, ok := st.Field(i).Type().(*types.Slice); ok {
switch st.Tag(i) {
case `dns:"-"`:
// ignored
case `dns:"cdomain-name"`, `dns:"domain-name"`, `dns:"txt"`:
o("for _, x := range rr.%s { l += len(x) + 1 }\n")
default:
log.Fatalln(name, st.Field(i).Name(), st.Tag(i))
}
continue
}
switch st.Tag(i) {
case `dns:"-"`:
// ignored
case `dns:"cdomain-name"`, `dns:"domain-name"`:
o("l += len(rr.%s) + 1\n")
case `dns:"octet"`:
o("l += len(rr.%s)\n")
case `dns:"base64"`:
o("l += base64.StdEncoding.DecodedLen(len(rr.%s))\n")
case `dns:"size-hex"`, `dns:"hex"`:
o("l += len(rr.%s)/2 + 1\n")
case `dns:"a"`:
o("l += net.IPv4len // %s\n")
case `dns:"aaaa"`:
o("l += net.IPv6len // %s\n")
case `dns:"txt"`:
o("for _, t := range rr.%s { l += len(t) + 1 }\n")
case `dns:"uint48"`:
o("l += 6 // %s\n")
case "":
switch st.Field(i).Type().(*types.Basic).Kind() {
case types.Uint8:
o("l += 1 // %s\n")
case types.Uint16:
o("l += 2 // %s\n")
case types.Uint32:
o("l += 4 // %s\n")
case types.Uint64:
o("l += 8 // %s\n")
case types.String:
o("l += len(rr.%s) + 1\n")
default:
log.Fatalln(name, st.Field(i).Name())
}
default:
log.Fatalln(name, st.Field(i).Name(), st.Tag(i))
}
}
fmt.Fprintf(b, "return l }\n")
}
// Generate copy()
fmt.Fprint(b, "// copy() functions\n")
for _, name := range namedTypes {
o := scope.Lookup(name)
st, isEmbedded := getTypeStruct(o.Type(), scope)
if isEmbedded {
continue
}
fmt.Fprintf(b, "func (rr *%s) copy() RR {\n", name)
fields := []string{"*rr.Hdr.copyHeader()"}
for i := 1; i < st.NumFields(); i++ {
f := st.Field(i).Name()
if sl, ok := st.Field(i).Type().(*types.Slice); ok {
t := sl.Underlying().String()
t = strings.TrimPrefix(t, "[]")
t = strings.TrimPrefix(t, "github.com/miekg/dns.")
fmt.Fprintf(b, "%s := make([]%s, len(rr.%s)); copy(%s, rr.%s)\n",
f, t, f, f, f)
fields = append(fields, f)
continue
}
if st.Field(i).Type().String() == "net.IP" {
fields = append(fields, "copyIP(rr."+f+")")
continue
}
fields = append(fields, "rr."+f)
}
fmt.Fprintf(b, "return &%s{%s}\n", name, strings.Join(fields, ","))
fmt.Fprintf(b, "}\n")
}
// gofmt
res, err := format.Source(b.Bytes())
if err != nil {
b.WriteTo(os.Stderr)
log.Fatal(err)
}
// write result
f, err := os.Create("ztypes.go")
fatalIfErr(err)
defer f.Close()
f.Write(res)
}
func fatalIfErr(err error) {
if err != nil {
log.Fatal(err)
}
}

19
vendor/github.com/miekg/dns/udp.go generated vendored
View File

@ -1,4 +1,4 @@
// +build !windows // +build !windows,!plan9
package dns package dns
@ -7,12 +7,15 @@ import (
"syscall" "syscall"
) )
type sessionUDP struct { // SessionUDP holds the remote address and the associated
// out-of-band data.
type SessionUDP struct {
raddr *net.UDPAddr raddr *net.UDPAddr
context []byte context []byte
} }
func (s *sessionUDP) RemoteAddr() net.Addr { return s.raddr } // RemoteAddr returns the remote network address.
func (s *SessionUDP) RemoteAddr() net.Addr { return s.raddr }
// setUDPSocketOptions sets the UDP socket options. // setUDPSocketOptions sets the UDP socket options.
// This function is implemented on a per platform basis. See udp_*.go for more details // This function is implemented on a per platform basis. See udp_*.go for more details
@ -37,19 +40,19 @@ func setUDPSocketOptions(conn *net.UDPConn) error {
return nil 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. // 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) oob := make([]byte, 40)
n, oobn, _, raddr, err := conn.ReadMsgUDP(b, oob) n, oobn, _, raddr, err := conn.ReadMsgUDP(b, oob)
if err != nil { if err != nil {
return n, nil, err 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. // 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) { func WriteToSessionUDP(conn *net.UDPConn, b []byte, session *SessionUDP) (int, error) {
n, _, err := conn.WriteMsgUDP(b, session.context, session.raddr) n, _, err := conn.WriteMsgUDP(b, session.context, session.raddr)
return n, err return n, err
} }

View File

@ -24,6 +24,12 @@ func setUDPSocketOptions4(conn *net.UDPConn) error {
if err := syscall.SetsockoptInt(int(file.Fd()), syscall.IPPROTO_IP, syscall.IP_PKTINFO, 1); err != nil { if err := syscall.SetsockoptInt(int(file.Fd()), syscall.IPPROTO_IP, syscall.IP_PKTINFO, 1); err != nil {
return err return err
} }
// Calling File() above results in the connection becoming blocking, we must fix that.
// See https://github.com/miekg/dns/issues/279
err = syscall.SetNonblock(int(file.Fd()), true)
if err != nil {
return err
}
return nil return nil
} }
@ -36,6 +42,10 @@ func setUDPSocketOptions6(conn *net.UDPConn) error {
if err := syscall.SetsockoptInt(int(file.Fd()), syscall.IPPROTO_IPV6, syscall.IPV6_RECVPKTINFO, 1); err != nil { if err := syscall.SetsockoptInt(int(file.Fd()), syscall.IPPROTO_IPV6, syscall.IPV6_RECVPKTINFO, 1); err != nil {
return err return err
} }
err = syscall.SetNonblock(int(file.Fd()), true)
if err != nil {
return err
}
return nil return nil
} }

View File

@ -1,4 +1,4 @@
// +build !linux // +build !linux,!plan9
package dns package dns

34
vendor/github.com/miekg/dns/udp_plan9.go generated vendored Normal file
View File

@ -0,0 +1,34 @@
package dns
import (
"net"
)
func setUDPSocketOptions(conn *net.UDPConn) error { return nil }
// SessionUDP holds the remote address and the associated
// out-of-band data.
type SessionUDP struct {
raddr *net.UDPAddr
context []byte
}
// RemoteAddr returns the remote network address.
func (s *SessionUDP) RemoteAddr() net.Addr { return s.raddr }
// 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) {
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
}
// 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" import "net"
type sessionUDP struct { type SessionUDP struct {
raddr *net.UDPAddr 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. // 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) n, raddr, err := conn.ReadFrom(b)
if err != nil { if err != nil {
return n, nil, err return n, nil, err
} }
session := &sessionUDP{raddr.(*net.UDPAddr)} session := &SessionUDP{raddr.(*net.UDPAddr)}
return n, session, err return n, session, err
} }
// writeToSessionUDP acts just like net.UDPConn.WritetTo(), but uses a *sessionUDP instead of a net.Addr. // 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) { func WriteToSessionUDP(conn *net.UDPConn, b []byte, session *SessionUDP) (int, error) {
n, err := conn.WriteTo(b, session.raddr) n, err := conn.WriteTo(b, session.raddr)
return n, err 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. // setUDPSocketOptions sets the UDP socket options.
// This function is implemented on a per platform basis. See udp_*.go for more details // This function is implemented on a per platform basis. See udp_*.go for more details

130
vendor/github.com/miekg/dns/update.go generated vendored
View File

@ -1,55 +1,24 @@
// 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 package dns
// NameUsed sets the RRs in the prereq section to // NameUsed sets the RRs in the prereq section to
// "Name is in use" RRs. RFC 2136 section 2.4.4. // "Name is in use" RRs. RFC 2136 section 2.4.4.
func (u *Msg) NameUsed(rr []RR) { func (u *Msg) NameUsed(rr []RR) {
u.Answer = make([]RR, len(rr)) if u.Answer == nil {
for i, r := range rr { u.Answer = make([]RR, 0, len(rr))
u.Answer[i] = &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: TypeANY, Class: ClassANY}} }
for _, r := range rr {
u.Answer = append(u.Answer, &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: TypeANY, Class: ClassANY}})
} }
} }
// NameNotUsed sets the RRs in the prereq section to // NameNotUsed sets the RRs in the prereq section to
// "Name is in not use" RRs. RFC 2136 section 2.4.5. // "Name is in not use" RRs. RFC 2136 section 2.4.5.
func (u *Msg) NameNotUsed(rr []RR) { func (u *Msg) NameNotUsed(rr []RR) {
u.Answer = make([]RR, len(rr)) if u.Answer == nil {
for i, r := range rr { u.Answer = make([]RR, 0, len(rr))
u.Answer[i] = &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: TypeANY, Class: ClassNONE}} }
for _, r := range rr {
u.Answer = append(u.Answer, &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: TypeANY, Class: ClassNONE}})
} }
} }
@ -59,34 +28,34 @@ func (u *Msg) Used(rr []RR) {
if len(u.Question) == 0 { if len(u.Question) == 0 {
panic("dns: empty question section") panic("dns: empty question section")
} }
u.Answer = make([]RR, len(rr)) if u.Answer == nil {
for i, r := range rr { u.Answer = make([]RR, 0, len(rr))
u.Answer[i] = r }
u.Answer[i].Header().Class = u.Question[0].Qclass for _, r := range rr {
r.Header().Class = u.Question[0].Qclass
u.Answer = append(u.Answer, r)
} }
} }
// RRsetUsed sets the RRs in the prereq section to // RRsetUsed sets the RRs in the prereq section to
// "RRset exists (value independent -- no rdata)" RRs. RFC 2136 section 2.4.1. // "RRset exists (value independent -- no rdata)" RRs. RFC 2136 section 2.4.1.
func (u *Msg) RRsetUsed(rr []RR) { func (u *Msg) RRsetUsed(rr []RR) {
u.Answer = make([]RR, len(rr)) if u.Answer == nil {
for i, r := range rr { u.Answer = make([]RR, 0, len(rr))
u.Answer[i] = r }
u.Answer[i].Header().Class = ClassANY for _, r := range rr {
u.Answer[i].Header().Ttl = 0 u.Answer = append(u.Answer, &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: r.Header().Rrtype, Class: ClassANY}})
u.Answer[i].Header().Rdlength = 0
} }
} }
// RRsetNotUsed sets the RRs in the prereq section to // RRsetNotUsed sets the RRs in the prereq section to
// "RRset does not exist" RRs. RFC 2136 section 2.4.3. // "RRset does not exist" RRs. RFC 2136 section 2.4.3.
func (u *Msg) RRsetNotUsed(rr []RR) { func (u *Msg) RRsetNotUsed(rr []RR) {
u.Answer = make([]RR, len(rr)) if u.Answer == nil {
for i, r := range rr { u.Answer = make([]RR, 0, len(rr))
u.Answer[i] = r }
u.Answer[i].Header().Class = ClassNONE for _, r := range rr {
u.Answer[i].Header().Rdlength = 0 u.Answer = append(u.Answer, &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: r.Header().Rrtype, Class: ClassNONE}})
u.Answer[i].Header().Ttl = 0
} }
} }
@ -95,44 +64,43 @@ func (u *Msg) Insert(rr []RR) {
if len(u.Question) == 0 { if len(u.Question) == 0 {
panic("dns: empty question section") panic("dns: empty question section")
} }
u.Ns = make([]RR, len(rr)) if u.Ns == nil {
for i, r := range rr { u.Ns = make([]RR, 0, len(rr))
u.Ns[i] = r }
u.Ns[i].Header().Class = u.Question[0].Qclass for _, r := range rr {
r.Header().Class = u.Question[0].Qclass
u.Ns = append(u.Ns, r)
} }
} }
// RemoveRRset creates a dynamic update packet that deletes an RRset, see RFC 2136 section 2.5.2. // RemoveRRset creates a dynamic update packet that deletes an RRset, see RFC 2136 section 2.5.2.
func (u *Msg) RemoveRRset(rr []RR) { func (u *Msg) RemoveRRset(rr []RR) {
m := make(map[RR_Header]struct{}) if u.Ns == nil {
u.Ns = make([]RR, 0, len(rr)) u.Ns = make([]RR, 0, len(rr))
}
for _, r := range rr { for _, r := range rr {
h := *r.Header().copyHeader() u.Ns = append(u.Ns, &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: r.Header().Rrtype, Class: ClassANY}})
h.Class = ClassANY
h.Ttl = 0
h.Rdlength = 0
if _, ok := m[h]; ok {
continue
}
m[h] = struct{}{}
u.Ns = append(u.Ns, &ANY{h})
} }
} }
// RemoveName creates a dynamic update packet that deletes all RRsets of a name, see RFC 2136 section 2.5.3 // RemoveName creates a dynamic update packet that deletes all RRsets of a name, see RFC 2136 section 2.5.3
func (u *Msg) RemoveName(rr []RR) { func (u *Msg) RemoveName(rr []RR) {
u.Ns = make([]RR, len(rr)) if u.Ns == nil {
for i, r := range rr { u.Ns = make([]RR, 0, len(rr))
u.Ns[i] = &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: TypeANY, Class: ClassANY}} }
for _, r := range rr {
u.Ns = append(u.Ns, &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: TypeANY, Class: ClassANY}})
} }
} }
// Remove creates a dynamic update packet deletes RR from the RRSset, see RFC 2136 section 2.5.4 // Remove creates a dynamic update packet deletes RR from a RRSset, see RFC 2136 section 2.5.4
func (u *Msg) Remove(rr []RR) { func (u *Msg) Remove(rr []RR) {
u.Ns = make([]RR, len(rr)) if u.Ns == nil {
for i, r := range rr { u.Ns = make([]RR, 0, len(rr))
u.Ns[i] = r }
u.Ns[i].Header().Class = ClassNONE for _, r := range rr {
u.Ns[i].Header().Ttl = 0 r.Header().Class = ClassNONE
r.Header().Ttl = 0
u.Ns = append(u.Ns, r)
} }
} }

54
vendor/github.com/miekg/dns/xfr.go generated vendored
View File

@ -13,9 +13,9 @@ type Envelope struct {
// A Transfer defines parameters that are used during a zone transfer. // A Transfer defines parameters that are used during a zone transfer.
type Transfer struct { type Transfer struct {
*Conn *Conn
DialTimeout time.Duration // net.DialTimeout (ns), defaults to 2 * 1e9 DialTimeout time.Duration // net.DialTimeout, defaults to 2 seconds
ReadTimeout time.Duration // net.Conn.SetReadTimeout value for connections (ns), defaults to 2 * 1e9 ReadTimeout time.Duration // net.Conn.SetReadTimeout value for connections, defaults to 2 seconds
WriteTimeout time.Duration // net.Conn.SetWriteTimeout value for connections (ns), defaults to 2 * 1e9 WriteTimeout time.Duration // net.Conn.SetWriteTimeout value for connections, defaults to 2 seconds
TsigSecret map[string]string // Secret(s) for Tsig map[<zonename>]<base64 secret>, zonename must be fully qualified TsigSecret map[string]string // Secret(s) for Tsig map[<zonename>]<base64 secret>, zonename must be fully qualified
tsigTimersOnly bool tsigTimersOnly bool
} }
@ -23,14 +23,26 @@ type Transfer struct {
// Think we need to away to stop the transfer // Think we need to away to stop the transfer
// In performs an incoming transfer with the server in a. // In performs an incoming transfer with the server in a.
// If you would like to set the source IP, or some other attribute
// of a Dialer for a Transfer, you can do so by specifying the attributes
// in the Transfer.Conn:
//
// d := net.Dialer{LocalAddr: transfer_source}
// con, err := d.Dial("tcp", master)
// dnscon := &dns.Conn{Conn:con}
// transfer = &dns.Transfer{Conn: dnscon}
// channel, err := transfer.In(message, master)
//
func (t *Transfer) In(q *Msg, a string) (env chan *Envelope, err error) { func (t *Transfer) In(q *Msg, a string) (env chan *Envelope, err error) {
timeout := dnsTimeout timeout := dnsTimeout
if t.DialTimeout != 0 { if t.DialTimeout != 0 {
timeout = t.DialTimeout timeout = t.DialTimeout
} }
t.Conn, err = DialTimeout("tcp", a, timeout) if t.Conn == nil {
if err != nil { t.Conn, err = DialTimeout("tcp", a, timeout)
return nil, err if err != nil {
return nil, err
}
} }
if err := t.WriteMsg(q); err != nil { if err := t.WriteMsg(q); err != nil {
return nil, err return nil, err
@ -91,7 +103,6 @@ func (t *Transfer) inAxfr(id uint16, c chan *Envelope) {
c <- &Envelope{in.Answer, nil} c <- &Envelope{in.Answer, nil}
} }
} }
panic("dns: not reached")
} }
func (t *Transfer) inIxfr(id uint16, c chan *Envelope) { func (t *Transfer) inIxfr(id uint16, c chan *Envelope) {
@ -107,7 +118,7 @@ func (t *Transfer) inIxfr(id uint16, c chan *Envelope) {
t.SetReadDeadline(time.Now().Add(timeout)) t.SetReadDeadline(time.Now().Add(timeout))
in, err := t.ReadMsg() in, err := t.ReadMsg()
if err != nil { if err != nil {
c <- &Envelope{in.Answer, err} c <- &Envelope{nil, err}
return return
} }
if id != in.Id { if id != in.Id {
@ -160,22 +171,18 @@ func (t *Transfer) inIxfr(id uint16, c chan *Envelope) {
// The server is responsible for sending the correct sequence of RRs through the // The server is responsible for sending the correct sequence of RRs through the
// channel ch. // channel ch.
func (t *Transfer) Out(w ResponseWriter, q *Msg, ch chan *Envelope) error { func (t *Transfer) Out(w ResponseWriter, q *Msg, ch chan *Envelope) error {
r := new(Msg) for x := range ch {
// Compress? r := new(Msg)
r.SetReply(q) // Compress?
r.Authoritative = true r.SetReply(q)
r.Authoritative = true
go func() { // assume it fits TODO(miek): fix
for x := range ch { r.Answer = append(r.Answer, x.RR...)
// assume it fits TODO(miek): fix if err := w.WriteMsg(r); err != nil {
r.Answer = append(r.Answer, x.RR...) return err
if err := w.WriteMsg(r); err != nil {
return
}
} }
w.TsigTimersOnly(true) }
r.Answer = nil w.TsigTimersOnly(true)
}()
return nil return nil
} }
@ -197,6 +204,7 @@ func (t *Transfer) ReadMsg() (*Msg, error) {
} }
// Need to work on the original message p, as that was used to calculate the tsig. // 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) err = TsigVerify(p, t.TsigSecret[ts.Hdr.Name], t.tsigRequestMAC, t.tsigTimersOnly)
t.tsigRequestMAC = ts.MAC
} }
return m, err return m, err
} }

View File

@ -1,6 +1,7 @@
package dns package dns
import ( import (
"bytes"
"fmt" "fmt"
"strconv" "strconv"
"strings" "strings"
@ -14,7 +15,7 @@ import (
// * [[ttl][class]] // * [[ttl][class]]
// * type // * type
// * rhs (rdata) // * rhs (rdata)
// But we are lazy here, only the range is parsed *all* occurences // But we are lazy here, only the range is parsed *all* occurrences
// of $ after that are interpreted. // of $ after that are interpreted.
// Any error are returned as a string value, the empty string signals // Any error are returned as a string value, the empty string signals
// "no error". // "no error".
@ -24,13 +25,13 @@ func generate(l lex, c chan lex, t chan *Token, o string) string {
if i+1 == len(l.token) { if i+1 == len(l.token) {
return "bad step in $GENERATE range" return "bad step in $GENERATE range"
} }
if s, e := strconv.Atoi(l.token[i+1:]); e != nil { if s, e := strconv.Atoi(l.token[i+1:]); e == nil {
return "bad step in $GENERATE range"
} else {
if s < 0 { if s < 0 {
return "bad step in $GENERATE range" return "bad step in $GENERATE range"
} }
step = s step = s
} else {
return "bad step in $GENERATE range"
} }
l.token = l.token[:i] 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 { if err != nil {
return "bad stop in $GENERATE range" 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" return "bad range in $GENERATE range"
} }
@ -55,14 +56,14 @@ func generate(l lex, c chan lex, t chan *Token, o string) string {
s := "" s := ""
BuildRR: BuildRR:
l = <-c l = <-c
if l.value != _NEWLINE && l.value != _EOF { if l.value != zNewline && l.value != zEOF {
s += l.token s += l.token
goto BuildRR goto BuildRR
} }
for i := start; i <= end; i += step { for i := start; i <= end; i += step {
var ( var (
escape bool escape bool
dom string dom bytes.Buffer
mod string mod string
err string err string
offset int offset int
@ -72,7 +73,7 @@ BuildRR:
switch s[j] { switch s[j] {
case '\\': case '\\':
if escape { if escape {
dom += "\\" dom.WriteByte('\\')
escape = false escape = false
continue continue
} }
@ -81,17 +82,17 @@ BuildRR:
mod = "%d" mod = "%d"
offset = 0 offset = 0
if escape { if escape {
dom += "$" dom.WriteByte('$')
escape = false escape = false
continue continue
} }
escape = false escape = false
if j+1 >= len(s) { // End of the string if j+1 >= len(s) { // End of the string
dom += fmt.Sprintf(mod, i+offset) dom.WriteString(fmt.Sprintf(mod, i+offset))
continue continue
} else { } else {
if s[j+1] == '$' { if s[j+1] == '$' {
dom += "$" dom.WriteByte('$')
j++ j++
continue continue
} }
@ -108,17 +109,17 @@ BuildRR:
} }
j += 2 + sep // Jump to it j += 2 + sep // Jump to it
} }
dom += fmt.Sprintf(mod, i+offset) dom.WriteString(fmt.Sprintf(mod, i+offset))
default: default:
if escape { // Pretty useless here if escape { // Pretty useless here
escape = false escape = false
continue continue
} }
dom += string(s[j]) dom.WriteByte(s[j])
} }
} }
// Re-parse the RR and send it on the current channel t // 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 { if e != nil {
return e.(*ParseError).err return e.(*ParseError).err
} }
@ -140,11 +141,11 @@ func modToPrintf(s string) (string, int, string) {
return "", 0, "bad base in $GENERATE" return "", 0, "bad base in $GENERATE"
} }
offset, err := strconv.Atoi(xs[0]) offset, err := strconv.Atoi(xs[0])
if err != nil { if err != nil || offset > 255 {
return "", 0, "bad offset in $GENERATE" return "", 0, "bad offset in $GENERATE"
} }
width, err := strconv.Atoi(xs[1]) width, err := strconv.Atoi(xs[1])
if err != nil { if err != nil || width > 255 {
return "", offset, "bad width in $GENERATE" return "", offset, "bad width in $GENERATE"
} }
switch { switch {

398
vendor/github.com/miekg/dns/zscan.go generated vendored
View File

@ -29,45 +29,45 @@ const maxUint16 = 1<<16 - 1
// * Handle braces - anywhere. // * Handle braces - anywhere.
const ( const (
// Zonefile // Zonefile
_EOF = iota zEOF = iota
_STRING zString
_BLANK zBlank
_QUOTE zQuote
_NEWLINE zNewline
_RRTYPE zRrtpe
_OWNER zOwner
_CLASS zClass
_DIRORIGIN // $ORIGIN zDirOrigin // $ORIGIN
_DIRTTL // $TTL zDirTtl // $TTL
_DIRINCLUDE // $INCLUDE zDirInclude // $INCLUDE
_DIRGENERATE // $GENERATE zDirGenerate // $GENERATE
// Privatekey file // Privatekey file
_VALUE zValue
_KEY zKey
_EXPECT_OWNER_DIR // Ownername zExpectOwnerDir // Ownername
_EXPECT_OWNER_BL // Whitespace after the ownername zExpectOwnerBl // Whitespace after the ownername
_EXPECT_ANY // Expect rrtype, ttl or class zExpectAny // Expect rrtype, ttl or class
_EXPECT_ANY_NOCLASS // Expect rrtype or ttl zExpectAnyNoClass // Expect rrtype or ttl
_EXPECT_ANY_NOCLASS_BL // The whitespace after _EXPECT_ANY_NOCLASS zExpectAnyNoClassBl // The whitespace after _EXPECT_ANY_NOCLASS
_EXPECT_ANY_NOTTL // Expect rrtype or class zExpectAnyNoTtl // Expect rrtype or class
_EXPECT_ANY_NOTTL_BL // Whitespace after _EXPECT_ANY_NOTTL zExpectAnyNoTtlBl // Whitespace after _EXPECT_ANY_NOTTL
_EXPECT_RRTYPE // Expect rrtype zExpectRrtype // Expect rrtype
_EXPECT_RRTYPE_BL // Whitespace BEFORE rrtype zExpectRrtypeBl // Whitespace BEFORE rrtype
_EXPECT_RDATA // The first element of the rdata zExpectRdata // The first element of the rdata
_EXPECT_DIRTTL_BL // Space after directive $TTL zExpectDirTtlBl // Space after directive $TTL
_EXPECT_DIRTTL // Directive $TTL zExpectDirTtl // Directive $TTL
_EXPECT_DIRORIGIN_BL // Space after directive $ORIGIN zExpectDirOriginBl // Space after directive $ORIGIN
_EXPECT_DIRORIGIN // Directive $ORIGIN zExpectDirOrigin // Directive $ORIGIN
_EXPECT_DIRINCLUDE_BL // Space after directive $INCLUDE zExpectDirIncludeBl // Space after directive $INCLUDE
_EXPECT_DIRINCLUDE // Directive $INCLUDE zExpectDirInclude // Directive $INCLUDE
_EXPECT_DIRGENERATE // Directive $GENERATE zExpectDirGenerate // Directive $GENERATE
_EXPECT_DIRGENERATE_BL // Space after directive $GENERATE zExpectDirGenerateBl // Space after directive $GENERATE
) )
// ParseError is a parsing error. It contains the parse error and the location in the io.Reader // ParseError is a parsing error. It contains the parse error and the location in the io.Reader
// where the error occured. // where the error occurred.
type ParseError struct { type ParseError struct {
file string file string
err string err string
@ -86,28 +86,32 @@ func (e *ParseError) Error() (s string) {
type lex struct { type lex struct {
token string // text of the token token string // text of the token
tokenUpper string // uppercase text of the token tokenUpper string // uppercase text of the token
length int // lenght of the token length int // length of the token
err bool // when true, token text has lexer error 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 line int // line in the file
column int // column 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 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 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 { type Token struct {
RR // the scanned resource record when error is not nil // The scanned resource record when error is not nil.
Error *ParseError // when an error occured, this has the error specifics RR
Comment string // a potential comment positioned after the RR and on the same line // When an error occurred, 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 returned. // NewRR reads the RR contained in the string s. Only the first RR is
// The class defaults to IN and TTL defaults to 3600. The full zone file // returned. If s contains no RR, return nil with no error. The class
// syntax like $TTL, $ORIGIN, etc. is supported. // defaults to IN and TTL defaults to 3600. The full zone file syntax
// All fields of the returned RR are set, except RR.Header().Rdlength which is set to 0. // like $TTL, $ORIGIN, etc. is supported. All fields of the returned
// RR are set, except RR.Header().Rdlength which is set to 0.
func NewRR(s string) (RR, error) { func NewRR(s string) (RR, error) {
if s[len(s)-1] != '\n' { // We need a closing newline if len(s) > 0 && s[len(s)-1] != '\n' { // We need a closing newline
return ReadRR(strings.NewReader(s+"\n"), "") return ReadRR(strings.NewReader(s+"\n"), "")
} }
return ReadRR(strings.NewReader(s), "") return ReadRR(strings.NewReader(s), "")
@ -117,17 +121,21 @@ func NewRR(s string) (RR, error) {
// See NewRR for more documentation. // See NewRR for more documentation.
func ReadRR(q io.Reader, filename string) (RR, error) { func ReadRR(q io.Reader, filename string) (RR, error) {
r := <-parseZoneHelper(q, ".", filename, 1) r := <-parseZoneHelper(q, ".", filename, 1)
if r == nil {
return nil, nil
}
if r.Error != nil { if r.Error != nil {
return nil, r.Error return nil, r.Error
} }
return r.RR, nil return r.RR, nil
} }
// ParseZone reads a RFC 1035 style one from r. It returns *Tokens on the // ParseZone reads a RFC 1035 style zonefile from r. It returns *Tokens on the
// returned channel, which consist out the parsed RR, a potential comment or an error. // returned channel, which consist out the parsed RR, a potential comment or an error.
// If there is an error the RR is nil. The string file is only used // If there is an error the RR is nil. The string file is only used
// in error reporting. The string origin is used as the initial origin, as // in error reporting. The string origin is used as the initial origin, as
// if the file would start with: $ORIGIN origin . // if the file would start with: $ORIGIN origin .
// The directives $INCLUDE, $ORIGIN, $TTL and $GENERATE are supported. // The directives $INCLUDE, $ORIGIN, $TTL and $GENERATE are supported.
// The channel t is closed by ParseZone when the end of r is reached. // The channel t is closed by ParseZone when the end of r is reached.
// //
@ -136,15 +144,17 @@ func ReadRR(q io.Reader, filename string) (RR, error) {
// //
// for x := range dns.ParseZone(strings.NewReader(z), "", "") { // for x := range dns.ParseZone(strings.NewReader(z), "", "") {
// if x.Error != nil { // if x.Error != nil {
// // Do something with x.RR // // log.Println(x.Error)
// } // } else {
// // Do something with x.RR
// }
// } // }
// //
// Comments specified after an RR (and on the same line!) are returned too: // Comments specified after an RR (and on the same line!) are returned too:
// //
// foo. IN A 10.0.0.1 ; this is a comment // foo. IN A 10.0.0.1 ; this is a comment
// //
// The text "; this is comment" is returned in Token.Comment . Comments inside the // The text "; this is comment" is returned in Token.Comment. Comments inside the
// RR are discarded. Comments on a line by themselves are discarded too. // RR are discarded. Comments on a line by themselves are discarded too.
func ParseZone(r io.Reader, origin, file string) chan *Token { func ParseZone(r io.Reader, origin, file string) chan *Token {
return parseZoneHelper(r, origin, file, 10000) return parseZoneHelper(r, origin, file, 10000)
@ -163,17 +173,17 @@ func parseZone(r io.Reader, origin, f string, t chan *Token, include int) {
} }
}() }()
s := scanInit(r) s := scanInit(r)
c := make(chan lex, 1000) c := make(chan lex)
// Start the lexer // Start the lexer
go zlexer(s, c) go zlexer(s, c)
// 6 possible beginnings of a line, _ is a space // 6 possible beginnings of a line, _ is a space
// 0. _RRTYPE -> all omitted until the rrtype // 0. zRRTYPE -> all omitted until the rrtype
// 1. _OWNER _ _RRTYPE -> class/ttl omitted // 1. zOwner _ zRrtype -> class/ttl omitted
// 2. _OWNER _ _STRING _ _RRTYPE -> class omitted // 2. zOwner _ zString _ zRrtype -> class omitted
// 3. _OWNER _ _STRING _ _CLASS _ _RRTYPE -> ttl/class // 3. zOwner _ zString _ zClass _ zRrtype -> ttl/class
// 4. _OWNER _ _CLASS _ _RRTYPE -> ttl omitted // 4. zOwner _ zClass _ zRrtype -> ttl omitted
// 5. _OWNER _ _CLASS _ _STRING _ _RRTYPE -> class/ttl (reversed) // 5. zOwner _ zClass _ zString _ zRrtype -> class/ttl (reversed)
// After detecting these, we know the _RRTYPE so we can jump to functions // After detecting these, we know the zRrtype so we can jump to functions
// handling the rdata for each of these types. // handling the rdata for each of these types.
if origin == "" { if origin == "" {
@ -185,7 +195,7 @@ func parseZone(r io.Reader, origin, f string, t chan *Token, include int) {
return return
} }
st := _EXPECT_OWNER_DIR // initial state st := zExpectOwnerDir // initial state
var h RR_Header var h RR_Header
var defttl uint32 = defaultTtl var defttl uint32 = defaultTtl
var prevName string var prevName string
@ -197,19 +207,19 @@ func parseZone(r io.Reader, origin, f string, t chan *Token, include int) {
} }
switch st { switch st {
case _EXPECT_OWNER_DIR: case zExpectOwnerDir:
// We can also expect a directive, like $TTL or $ORIGIN // We can also expect a directive, like $TTL or $ORIGIN
h.Ttl = defttl h.Ttl = defttl
h.Class = ClassINET h.Class = ClassINET
switch l.value { switch l.value {
case _NEWLINE: // Empty line case zNewline:
st = _EXPECT_OWNER_DIR st = zExpectOwnerDir
case _OWNER: case zOwner:
h.Name = l.token h.Name = l.token
if l.token[0] == '@' { if l.token[0] == '@' {
h.Name = origin h.Name = origin
prevName = h.Name prevName = h.Name
st = _EXPECT_OWNER_BL st = zExpectOwnerBl
break break
} }
if h.Name[l.length-1] != '.' { if h.Name[l.length-1] != '.' {
@ -221,59 +231,59 @@ func parseZone(r io.Reader, origin, f string, t chan *Token, include int) {
return return
} }
prevName = h.Name prevName = h.Name
st = _EXPECT_OWNER_BL st = zExpectOwnerBl
case _DIRTTL: case zDirTtl:
st = _EXPECT_DIRTTL_BL st = zExpectDirTtlBl
case _DIRORIGIN: case zDirOrigin:
st = _EXPECT_DIRORIGIN_BL st = zExpectDirOriginBl
case _DIRINCLUDE: case zDirInclude:
st = _EXPECT_DIRINCLUDE_BL st = zExpectDirIncludeBl
case _DIRGENERATE: case zDirGenerate:
st = _EXPECT_DIRGENERATE_BL st = zExpectDirGenerateBl
case _RRTYPE: // Everthing has been omitted, this is the first thing on the line case zRrtpe:
h.Name = prevName h.Name = prevName
h.Rrtype = l.torc h.Rrtype = l.torc
st = _EXPECT_RDATA st = zExpectRdata
case _CLASS: // First thing on the line is the class case zClass:
h.Name = prevName h.Name = prevName
h.Class = l.torc h.Class = l.torc
st = _EXPECT_ANY_NOCLASS_BL st = zExpectAnyNoClassBl
case _BLANK: case zBlank:
// Discard, can happen when there is nothing on the // Discard, can happen when there is nothing on the
// line except the RR type // line except the RR type
case _STRING: // First thing on the is the ttl case zString:
if ttl, ok := stringToTtl(l.token); !ok { ttl, ok := stringToTtl(l.token)
if !ok {
t <- &Token{Error: &ParseError{f, "not a TTL", l}} t <- &Token{Error: &ParseError{f, "not a TTL", l}}
return 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: default:
t <- &Token{Error: &ParseError{f, "syntax error at beginning", l}} t <- &Token{Error: &ParseError{f, "syntax error at beginning", l}}
return return
} }
case _EXPECT_DIRINCLUDE_BL: case zExpectDirIncludeBl:
if l.value != _BLANK { if l.value != zBlank {
t <- &Token{Error: &ParseError{f, "no blank after $INCLUDE-directive", l}} t <- &Token{Error: &ParseError{f, "no blank after $INCLUDE-directive", l}}
return return
} }
st = _EXPECT_DIRINCLUDE st = zExpectDirInclude
case _EXPECT_DIRINCLUDE: case zExpectDirInclude:
if l.value != _STRING { if l.value != zString {
t <- &Token{Error: &ParseError{f, "expecting $INCLUDE value, not this...", l}} t <- &Token{Error: &ParseError{f, "expecting $INCLUDE value, not this...", l}}
return return
} }
neworigin := origin // There may be optionally a new origin set after the filename, if not use current one neworigin := origin // There may be optionally a new origin set after the filename, if not use current one
l := <-c l := <-c
switch l.value { switch l.value {
case _BLANK: case zBlank:
l := <-c l := <-c
if l.value == _STRING { if l.value == zString {
if _, ok := IsDomainName(l.token); !ok { if _, ok := IsDomainName(l.token); !ok || l.length == 0 || l.err {
t <- &Token{Error: &ParseError{f, "bad origin name", l}} t <- &Token{Error: &ParseError{f, "bad origin name", l}}
return return
} }
@ -288,7 +298,7 @@ func parseZone(r io.Reader, origin, f string, t chan *Token, include int) {
neworigin = l.token neworigin = l.token
} }
} }
case _NEWLINE, _EOF: case zNewline, zEOF:
// Ok // Ok
default: default:
t <- &Token{Error: &ParseError{f, "garbage after $INCLUDE", l}} t <- &Token{Error: &ParseError{f, "garbage after $INCLUDE", l}}
@ -305,15 +315,15 @@ func parseZone(r io.Reader, origin, f string, t chan *Token, include int) {
return return
} }
parseZone(r1, l.token, neworigin, t, include+1) parseZone(r1, l.token, neworigin, t, include+1)
st = _EXPECT_OWNER_DIR st = zExpectOwnerDir
case _EXPECT_DIRTTL_BL: case zExpectDirTtlBl:
if l.value != _BLANK { if l.value != zBlank {
t <- &Token{Error: &ParseError{f, "no blank after $TTL-directive", l}} t <- &Token{Error: &ParseError{f, "no blank after $TTL-directive", l}}
return return
} }
st = _EXPECT_DIRTTL st = zExpectDirTtl
case _EXPECT_DIRTTL: case zExpectDirTtl:
if l.value != _STRING { if l.value != zString {
t <- &Token{Error: &ParseError{f, "expecting $TTL value, not this...", l}} t <- &Token{Error: &ParseError{f, "expecting $TTL value, not this...", l}}
return return
} }
@ -321,21 +331,21 @@ func parseZone(r io.Reader, origin, f string, t chan *Token, include int) {
t <- &Token{Error: e} t <- &Token{Error: e}
return 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}} t <- &Token{Error: &ParseError{f, "expecting $TTL value, not this...", l}}
return return
} else {
defttl = ttl
} }
st = _EXPECT_OWNER_DIR defttl = ttl
case _EXPECT_DIRORIGIN_BL: st = zExpectOwnerDir
if l.value != _BLANK { case zExpectDirOriginBl:
if l.value != zBlank {
t <- &Token{Error: &ParseError{f, "no blank after $ORIGIN-directive", l}} t <- &Token{Error: &ParseError{f, "no blank after $ORIGIN-directive", l}}
return return
} }
st = _EXPECT_DIRORIGIN st = zExpectDirOrigin
case _EXPECT_DIRORIGIN: case zExpectDirOrigin:
if l.value != _STRING { if l.value != zString {
t <- &Token{Error: &ParseError{f, "expecting $ORIGIN value, not this...", l}} t <- &Token{Error: &ParseError{f, "expecting $ORIGIN value, not this...", l}}
return return
} }
@ -355,15 +365,15 @@ func parseZone(r io.Reader, origin, f string, t chan *Token, include int) {
} else { } else {
origin = l.token origin = l.token
} }
st = _EXPECT_OWNER_DIR st = zExpectOwnerDir
case _EXPECT_DIRGENERATE_BL: case zExpectDirGenerateBl:
if l.value != _BLANK { if l.value != zBlank {
t <- &Token{Error: &ParseError{f, "no blank after $GENERATE-directive", l}} t <- &Token{Error: &ParseError{f, "no blank after $GENERATE-directive", l}}
return return
} }
st = _EXPECT_DIRGENERATE st = zExpectDirGenerate
case _EXPECT_DIRGENERATE: case zExpectDirGenerate:
if l.value != _STRING { if l.value != zString {
t <- &Token{Error: &ParseError{f, "expecting $GENERATE value, not this...", l}} t <- &Token{Error: &ParseError{f, "expecting $GENERATE value, not this...", l}}
return return
} }
@ -371,90 +381,90 @@ func parseZone(r io.Reader, origin, f string, t chan *Token, include int) {
t <- &Token{Error: &ParseError{f, e, l}} t <- &Token{Error: &ParseError{f, e, l}}
return return
} }
st = _EXPECT_OWNER_DIR st = zExpectOwnerDir
case _EXPECT_OWNER_BL: case zExpectOwnerBl:
if l.value != _BLANK { if l.value != zBlank {
t <- &Token{Error: &ParseError{f, "no blank after owner", l}} t <- &Token{Error: &ParseError{f, "no blank after owner", l}}
return return
} }
st = _EXPECT_ANY st = zExpectAny
case _EXPECT_ANY: case zExpectAny:
switch l.value { switch l.value {
case _RRTYPE: case zRrtpe:
h.Rrtype = l.torc h.Rrtype = l.torc
st = _EXPECT_RDATA st = zExpectRdata
case _CLASS: case zClass:
h.Class = l.torc h.Class = l.torc
st = _EXPECT_ANY_NOCLASS_BL st = zExpectAnyNoClassBl
case _STRING: // TTL is this case case zString:
if ttl, ok := stringToTtl(l.token); !ok { ttl, ok := stringToTtl(l.token)
if !ok {
t <- &Token{Error: &ParseError{f, "not a TTL", l}} t <- &Token{Error: &ParseError{f, "not a TTL", l}}
return 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: default:
t <- &Token{Error: &ParseError{f, "expecting RR type, TTL or class, not this...", l}} t <- &Token{Error: &ParseError{f, "expecting RR type, TTL or class, not this...", l}}
return return
} }
case _EXPECT_ANY_NOCLASS_BL: case zExpectAnyNoClassBl:
if l.value != _BLANK { if l.value != zBlank {
t <- &Token{Error: &ParseError{f, "no blank before class", l}} t <- &Token{Error: &ParseError{f, "no blank before class", l}}
return return
} }
st = _EXPECT_ANY_NOCLASS st = zExpectAnyNoClass
case _EXPECT_ANY_NOTTL_BL: case zExpectAnyNoTtlBl:
if l.value != _BLANK { if l.value != zBlank {
t <- &Token{Error: &ParseError{f, "no blank before TTL", l}} t <- &Token{Error: &ParseError{f, "no blank before TTL", l}}
return return
} }
st = _EXPECT_ANY_NOTTL st = zExpectAnyNoTtl
case _EXPECT_ANY_NOTTL: case zExpectAnyNoTtl:
switch l.value { switch l.value {
case _CLASS: case zClass:
h.Class = l.torc h.Class = l.torc
st = _EXPECT_RRTYPE_BL st = zExpectRrtypeBl
case _RRTYPE: case zRrtpe:
h.Rrtype = l.torc h.Rrtype = l.torc
st = _EXPECT_RDATA st = zExpectRdata
default: default:
t <- &Token{Error: &ParseError{f, "expecting RR type or class, not this...", l}} t <- &Token{Error: &ParseError{f, "expecting RR type or class, not this...", l}}
return return
} }
case _EXPECT_ANY_NOCLASS: case zExpectAnyNoClass:
switch l.value { switch l.value {
case _STRING: // TTL case zString:
if ttl, ok := stringToTtl(l.token); !ok { ttl, ok := stringToTtl(l.token)
if !ok {
t <- &Token{Error: &ParseError{f, "not a TTL", l}} t <- &Token{Error: &ParseError{f, "not a TTL", l}}
return return
} else {
h.Ttl = ttl
// defttl = ttl // don't set the def ttl anymore
} }
st = _EXPECT_RRTYPE_BL h.Ttl = ttl
case _RRTYPE: // defttl = ttl // don't set the def ttl anymore
st = zExpectRrtypeBl
case zRrtpe:
h.Rrtype = l.torc h.Rrtype = l.torc
st = _EXPECT_RDATA st = zExpectRdata
default: default:
t <- &Token{Error: &ParseError{f, "expecting RR type or TTL, not this...", l}} t <- &Token{Error: &ParseError{f, "expecting RR type or TTL, not this...", l}}
return return
} }
case _EXPECT_RRTYPE_BL: case zExpectRrtypeBl:
if l.value != _BLANK { if l.value != zBlank {
t <- &Token{Error: &ParseError{f, "no blank before RR type", l}} t <- &Token{Error: &ParseError{f, "no blank before RR type", l}}
return return
} }
st = _EXPECT_RRTYPE st = zExpectRrtype
case _EXPECT_RRTYPE: case zExpectRrtype:
if l.value != _RRTYPE { if l.value != zRrtpe {
t <- &Token{Error: &ParseError{f, "unknown RR type", l}} t <- &Token{Error: &ParseError{f, "unknown RR type", l}}
return return
} }
h.Rrtype = l.torc h.Rrtype = l.torc
st = _EXPECT_RDATA st = zExpectRdata
case _EXPECT_RDATA: case zExpectRdata:
r, e, c1 := setRR(h, c, origin, f) r, e, c1 := setRR(h, c, origin, f)
if e != nil { if e != nil {
// If e.lex is nil than we have encounter a unknown RR type // If e.lex is nil than we have encounter a unknown RR type
@ -466,7 +476,7 @@ func parseZone(r io.Reader, origin, f string, t chan *Token, include int) {
return return
} }
t <- &Token{RR: r, Comment: c1} 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 // If we get here, we and the h.Rrtype is still zero, we haven't parsed anything, this
@ -492,14 +502,14 @@ func zlexer(s *scan, c chan lex) {
for err == nil { for err == nil {
l.column = s.position.Column l.column = s.position.Column
l.line = s.position.Line l.line = s.position.Line
if stri > maxTok { if stri >= maxTok {
l.token = "token length insufficient for parsing" l.token = "token length insufficient for parsing"
l.err = true l.err = true
debug.Printf("[%+v]", l.token) debug.Printf("[%+v]", l.token)
c <- l c <- l
return return
} }
if comi > maxTok { if comi >= maxTok {
l.token = "comment length insufficient for parsing" l.token = "comment length insufficient for parsing"
l.err = true l.err = true
debug.Printf("[%+v]", l.token) debug.Printf("[%+v]", l.token)
@ -530,60 +540,60 @@ func zlexer(s *scan, c chan lex) {
// Space directly in the beginning, handled in the grammar // Space directly in the beginning, handled in the grammar
} else if owner { } else if owner {
// If we have a string and its the first, make it an 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.token = string(str[:stri])
l.tokenUpper = strings.ToUpper(l.token) l.tokenUpper = strings.ToUpper(l.token)
l.length = stri l.length = stri
// escape $... start with a \ not a $, so this will work // escape $... start with a \ not a $, so this will work
switch l.tokenUpper { switch l.tokenUpper {
case "$TTL": case "$TTL":
l.value = _DIRTTL l.value = zDirTtl
case "$ORIGIN": case "$ORIGIN":
l.value = _DIRORIGIN l.value = zDirOrigin
case "$INCLUDE": case "$INCLUDE":
l.value = _DIRINCLUDE l.value = zDirInclude
case "$GENERATE": case "$GENERATE":
l.value = _DIRGENERATE l.value = zDirGenerate
} }
debug.Printf("[7 %+v]", l.token) debug.Printf("[7 %+v]", l.token)
c <- l c <- l
} else { } else {
l.value = _STRING l.value = zString
l.token = string(str[:stri]) l.token = string(str[:stri])
l.tokenUpper = strings.ToUpper(l.token) l.tokenUpper = strings.ToUpper(l.token)
l.length = stri l.length = stri
if !rrtype { if !rrtype {
if t, ok := StringToType[l.tokenUpper]; ok { if t, ok := StringToType[l.tokenUpper]; ok {
l.value = _RRTYPE l.value = zRrtpe
l.torc = t l.torc = t
rrtype = true rrtype = true
} else { } else {
if strings.HasPrefix(l.tokenUpper, "TYPE") { 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.token = "unknown RR type"
l.err = true l.err = true
c <- l c <- l
return return
} else {
l.value = _RRTYPE
l.torc = t
} }
l.value = zRrtpe
l.torc = t
} }
} }
if t, ok := StringToClass[l.tokenUpper]; ok { if t, ok := StringToClass[l.tokenUpper]; ok {
l.value = _CLASS l.value = zClass
l.torc = t l.torc = t
} else { } else {
if strings.HasPrefix(l.tokenUpper, "CLASS") { 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.token = "unknown class"
l.err = true l.err = true
c <- l c <- l
return return
} else {
l.value = _CLASS
l.torc = t
} }
l.value = zClass
l.torc = t
} }
} }
} }
@ -593,7 +603,7 @@ func zlexer(s *scan, c chan lex) {
stri = 0 stri = 0
// I reverse space stuff here // I reverse space stuff here
if !space && !commt { if !space && !commt {
l.value = _BLANK l.value = zBlank
l.token = " " l.token = " "
l.length = 1 l.length = 1
debug.Printf("[5 %+v]", l.token) debug.Printf("[5 %+v]", l.token)
@ -615,7 +625,7 @@ func zlexer(s *scan, c chan lex) {
break break
} }
if stri > 0 { if stri > 0 {
l.value = _STRING l.value = zString
l.token = string(str[:stri]) l.token = string(str[:stri])
l.length = stri l.length = stri
debug.Printf("[4 %+v]", l.token) debug.Printf("[4 %+v]", l.token)
@ -651,7 +661,7 @@ func zlexer(s *scan, c chan lex) {
if brace == 0 { if brace == 0 {
owner = true owner = true
owner = true owner = true
l.value = _NEWLINE l.value = zNewline
l.token = "\n" l.token = "\n"
l.length = 1 l.length = 1
l.comment = string(com[:comi]) l.comment = string(com[:comi])
@ -669,14 +679,14 @@ func zlexer(s *scan, c chan lex) {
if brace == 0 { if brace == 0 {
// If there is previous text, we should output it here // If there is previous text, we should output it here
if stri != 0 { if stri != 0 {
l.value = _STRING l.value = zString
l.token = string(str[:stri]) l.token = string(str[:stri])
l.tokenUpper = strings.ToUpper(l.token) l.tokenUpper = strings.ToUpper(l.token)
l.length = stri l.length = stri
if !rrtype { if !rrtype {
if t, ok := StringToType[l.tokenUpper]; ok { if t, ok := StringToType[l.tokenUpper]; ok {
l.value = _RRTYPE l.value = zRrtpe
l.torc = t l.torc = t
rrtype = true rrtype = true
} }
@ -684,7 +694,7 @@ func zlexer(s *scan, c chan lex) {
debug.Printf("[2 %+v]", l.token) debug.Printf("[2 %+v]", l.token)
c <- l c <- l
} }
l.value = _NEWLINE l.value = zNewline
l.token = "\n" l.token = "\n"
l.length = 1 l.length = 1
debug.Printf("[1 %+v]", l.token) debug.Printf("[1 %+v]", l.token)
@ -728,7 +738,7 @@ func zlexer(s *scan, c chan lex) {
space = false space = false
// send previous gathered text and the quote // send previous gathered text and the quote
if stri != 0 { if stri != 0 {
l.value = _STRING l.value = zString
l.token = string(str[:stri]) l.token = string(str[:stri])
l.length = stri l.length = stri
@ -738,7 +748,7 @@ func zlexer(s *scan, c chan lex) {
} }
// send quote itself as separate token // send quote itself as separate token
l.value = _QUOTE l.value = zQuote
l.token = "\"" l.token = "\""
l.length = 1 l.length = 1
c <- l c <- l
@ -790,7 +800,7 @@ func zlexer(s *scan, c chan lex) {
// Send remainder // Send remainder
l.token = string(str[:stri]) l.token = string(str[:stri])
l.length = stri l.length = stri
l.value = _STRING l.value = zString
debug.Printf("[%+v]", l.token) debug.Printf("[%+v]", l.token)
c <- l c <- l
} }
@ -798,7 +808,11 @@ func zlexer(s *scan, c chan lex) {
// Extract the class number from CLASSxx // Extract the class number from CLASSxx
func classToInt(token string) (uint16, bool) { func classToInt(token string) (uint16, bool) {
class, ok := strconv.Atoi(token[5:]) offset := 5
if len(token) < offset+1 {
return 0, false
}
class, ok := strconv.Atoi(token[offset:])
if ok != nil || class > maxUint16 { if ok != nil || class > maxUint16 {
return 0, false return 0, false
} }
@ -807,7 +821,11 @@ func classToInt(token string) (uint16, bool) {
// Extract the rr number from TYPExxx // Extract the rr number from TYPExxx
func typeToInt(token string) (uint16, bool) { func typeToInt(token string) (uint16, bool) {
typ, ok := strconv.Atoi(token[4:]) offset := 4
if len(token) < offset+1 {
return 0, false
}
typ, ok := strconv.Atoi(token[offset:])
if ok != nil || typ > maxUint16 { if ok != nil || typ > maxUint16 {
return 0, false return 0, false
} }
@ -922,15 +940,15 @@ func slurpRemainder(c chan lex, f string) (*ParseError, string) {
l := <-c l := <-c
com := "" com := ""
switch l.value { switch l.value {
case _BLANK: case zBlank:
l = <-c l = <-c
com = l.comment com = l.comment
if l.value != _NEWLINE && l.value != _EOF { if l.value != zNewline && l.value != zEOF {
return &ParseError{f, "garbage after rdata", l}, "" return &ParseError{f, "garbage after rdata", l}, ""
} }
case _NEWLINE: case zNewline:
com = l.comment com = l.comment
case _EOF: case zEOF:
default: default:
return &ParseError{f, "garbage after rdata", l}, "" return &ParseError{f, "garbage after rdata", l}, ""
} }

1155
vendor/github.com/miekg/dns/zscan_rr.go generated vendored

File diff suppressed because it is too large Load Diff

842
vendor/github.com/miekg/dns/ztypes.go generated vendored Normal file
View File

@ -0,0 +1,842 @@
// *** DO NOT MODIFY ***
// AUTOGENERATED BY go generate
package dns
import (
"encoding/base64"
"net"
)
// TypeToRR is a map of constructors for each RR type.
var TypeToRR = map[uint16]func() RR{
TypeA: func() RR { return new(A) },
TypeAAAA: func() RR { return new(AAAA) },
TypeAFSDB: func() RR { return new(AFSDB) },
TypeANY: func() RR { return new(ANY) },
TypeCAA: func() RR { return new(CAA) },
TypeCDNSKEY: func() RR { return new(CDNSKEY) },
TypeCDS: func() RR { return new(CDS) },
TypeCERT: func() RR { return new(CERT) },
TypeCNAME: func() RR { return new(CNAME) },
TypeDHCID: func() RR { return new(DHCID) },
TypeDLV: func() RR { return new(DLV) },
TypeDNAME: func() RR { return new(DNAME) },
TypeDNSKEY: func() RR { return new(DNSKEY) },
TypeDS: func() RR { return new(DS) },
TypeEID: func() RR { return new(EID) },
TypeEUI48: func() RR { return new(EUI48) },
TypeEUI64: func() RR { return new(EUI64) },
TypeGID: func() RR { return new(GID) },
TypeGPOS: func() RR { return new(GPOS) },
TypeHINFO: func() RR { return new(HINFO) },
TypeHIP: func() RR { return new(HIP) },
TypeIPSECKEY: func() RR { return new(IPSECKEY) },
TypeKEY: func() RR { return new(KEY) },
TypeKX: func() RR { return new(KX) },
TypeL32: func() RR { return new(L32) },
TypeL64: func() RR { return new(L64) },
TypeLOC: func() RR { return new(LOC) },
TypeLP: func() RR { return new(LP) },
TypeMB: func() RR { return new(MB) },
TypeMD: func() RR { return new(MD) },
TypeMF: func() RR { return new(MF) },
TypeMG: func() RR { return new(MG) },
TypeMINFO: func() RR { return new(MINFO) },
TypeMR: func() RR { return new(MR) },
TypeMX: func() RR { return new(MX) },
TypeNAPTR: func() RR { return new(NAPTR) },
TypeNID: func() RR { return new(NID) },
TypeNIMLOC: func() RR { return new(NIMLOC) },
TypeNINFO: func() RR { return new(NINFO) },
TypeNS: func() RR { return new(NS) },
TypeNSAPPTR: func() RR { return new(NSAPPTR) },
TypeNSEC: func() RR { return new(NSEC) },
TypeNSEC3: func() RR { return new(NSEC3) },
TypeNSEC3PARAM: func() RR { return new(NSEC3PARAM) },
TypeOPENPGPKEY: func() RR { return new(OPENPGPKEY) },
TypeOPT: func() RR { return new(OPT) },
TypePTR: func() RR { return new(PTR) },
TypePX: func() RR { return new(PX) },
TypeRKEY: func() RR { return new(RKEY) },
TypeRP: func() RR { return new(RP) },
TypeRRSIG: func() RR { return new(RRSIG) },
TypeRT: func() RR { return new(RT) },
TypeSIG: func() RR { return new(SIG) },
TypeSOA: func() RR { return new(SOA) },
TypeSPF: func() RR { return new(SPF) },
TypeSRV: func() RR { return new(SRV) },
TypeSSHFP: func() RR { return new(SSHFP) },
TypeTA: func() RR { return new(TA) },
TypeTALINK: func() RR { return new(TALINK) },
TypeTKEY: func() RR { return new(TKEY) },
TypeTLSA: func() RR { return new(TLSA) },
TypeTSIG: func() RR { return new(TSIG) },
TypeTXT: func() RR { return new(TXT) },
TypeUID: func() RR { return new(UID) },
TypeUINFO: func() RR { return new(UINFO) },
TypeURI: func() RR { return new(URI) },
TypeWKS: func() RR { return new(WKS) },
TypeX25: func() RR { return new(X25) },
}
// TypeToString is a map of strings for each RR type.
var TypeToString = map[uint16]string{
TypeA: "A",
TypeAAAA: "AAAA",
TypeAFSDB: "AFSDB",
TypeANY: "ANY",
TypeATMA: "ATMA",
TypeAXFR: "AXFR",
TypeCAA: "CAA",
TypeCDNSKEY: "CDNSKEY",
TypeCDS: "CDS",
TypeCERT: "CERT",
TypeCNAME: "CNAME",
TypeDHCID: "DHCID",
TypeDLV: "DLV",
TypeDNAME: "DNAME",
TypeDNSKEY: "DNSKEY",
TypeDS: "DS",
TypeEID: "EID",
TypeEUI48: "EUI48",
TypeEUI64: "EUI64",
TypeGID: "GID",
TypeGPOS: "GPOS",
TypeHINFO: "HINFO",
TypeHIP: "HIP",
TypeIPSECKEY: "IPSECKEY",
TypeISDN: "ISDN",
TypeIXFR: "IXFR",
TypeKEY: "KEY",
TypeKX: "KX",
TypeL32: "L32",
TypeL64: "L64",
TypeLOC: "LOC",
TypeLP: "LP",
TypeMAILA: "MAILA",
TypeMAILB: "MAILB",
TypeMB: "MB",
TypeMD: "MD",
TypeMF: "MF",
TypeMG: "MG",
TypeMINFO: "MINFO",
TypeMR: "MR",
TypeMX: "MX",
TypeNAPTR: "NAPTR",
TypeNID: "NID",
TypeNIMLOC: "NIMLOC",
TypeNINFO: "NINFO",
TypeNS: "NS",
TypeNSEC: "NSEC",
TypeNSEC3: "NSEC3",
TypeNSEC3PARAM: "NSEC3PARAM",
TypeNULL: "NULL",
TypeNXT: "NXT",
TypeNone: "None",
TypeOPENPGPKEY: "OPENPGPKEY",
TypeOPT: "OPT",
TypePTR: "PTR",
TypePX: "PX",
TypeRKEY: "RKEY",
TypeRP: "RP",
TypeRRSIG: "RRSIG",
TypeRT: "RT",
TypeReserved: "Reserved",
TypeSIG: "SIG",
TypeSOA: "SOA",
TypeSPF: "SPF",
TypeSRV: "SRV",
TypeSSHFP: "SSHFP",
TypeTA: "TA",
TypeTALINK: "TALINK",
TypeTKEY: "TKEY",
TypeTLSA: "TLSA",
TypeTSIG: "TSIG",
TypeTXT: "TXT",
TypeUID: "UID",
TypeUINFO: "UINFO",
TypeUNSPEC: "UNSPEC",
TypeURI: "URI",
TypeWKS: "WKS",
TypeX25: "X25",
TypeNSAPPTR: "NSAP-PTR",
}
// Header() functions
func (rr *A) Header() *RR_Header { return &rr.Hdr }
func (rr *AAAA) Header() *RR_Header { return &rr.Hdr }
func (rr *AFSDB) Header() *RR_Header { return &rr.Hdr }
func (rr *ANY) Header() *RR_Header { return &rr.Hdr }
func (rr *CAA) Header() *RR_Header { return &rr.Hdr }
func (rr *CDNSKEY) Header() *RR_Header { return &rr.Hdr }
func (rr *CDS) Header() *RR_Header { return &rr.Hdr }
func (rr *CERT) Header() *RR_Header { return &rr.Hdr }
func (rr *CNAME) Header() *RR_Header { return &rr.Hdr }
func (rr *DHCID) Header() *RR_Header { return &rr.Hdr }
func (rr *DLV) Header() *RR_Header { return &rr.Hdr }
func (rr *DNAME) Header() *RR_Header { return &rr.Hdr }
func (rr *DNSKEY) Header() *RR_Header { return &rr.Hdr }
func (rr *DS) Header() *RR_Header { return &rr.Hdr }
func (rr *EID) Header() *RR_Header { return &rr.Hdr }
func (rr *EUI48) Header() *RR_Header { return &rr.Hdr }
func (rr *EUI64) Header() *RR_Header { return &rr.Hdr }
func (rr *GID) Header() *RR_Header { return &rr.Hdr }
func (rr *GPOS) Header() *RR_Header { return &rr.Hdr }
func (rr *HINFO) Header() *RR_Header { return &rr.Hdr }
func (rr *HIP) Header() *RR_Header { return &rr.Hdr }
func (rr *IPSECKEY) Header() *RR_Header { return &rr.Hdr }
func (rr *KEY) Header() *RR_Header { return &rr.Hdr }
func (rr *KX) Header() *RR_Header { return &rr.Hdr }
func (rr *L32) Header() *RR_Header { return &rr.Hdr }
func (rr *L64) Header() *RR_Header { return &rr.Hdr }
func (rr *LOC) Header() *RR_Header { return &rr.Hdr }
func (rr *LP) Header() *RR_Header { return &rr.Hdr }
func (rr *MB) Header() *RR_Header { return &rr.Hdr }
func (rr *MD) Header() *RR_Header { return &rr.Hdr }
func (rr *MF) Header() *RR_Header { return &rr.Hdr }
func (rr *MG) Header() *RR_Header { return &rr.Hdr }
func (rr *MINFO) Header() *RR_Header { return &rr.Hdr }
func (rr *MR) Header() *RR_Header { return &rr.Hdr }
func (rr *MX) Header() *RR_Header { return &rr.Hdr }
func (rr *NAPTR) Header() *RR_Header { return &rr.Hdr }
func (rr *NID) Header() *RR_Header { return &rr.Hdr }
func (rr *NIMLOC) Header() *RR_Header { return &rr.Hdr }
func (rr *NINFO) Header() *RR_Header { return &rr.Hdr }
func (rr *NS) Header() *RR_Header { return &rr.Hdr }
func (rr *NSAPPTR) Header() *RR_Header { return &rr.Hdr }
func (rr *NSEC) Header() *RR_Header { return &rr.Hdr }
func (rr *NSEC3) Header() *RR_Header { return &rr.Hdr }
func (rr *NSEC3PARAM) Header() *RR_Header { return &rr.Hdr }
func (rr *OPENPGPKEY) Header() *RR_Header { return &rr.Hdr }
func (rr *OPT) Header() *RR_Header { return &rr.Hdr }
func (rr *PTR) Header() *RR_Header { return &rr.Hdr }
func (rr *PX) Header() *RR_Header { return &rr.Hdr }
func (rr *RFC3597) Header() *RR_Header { return &rr.Hdr }
func (rr *RKEY) Header() *RR_Header { return &rr.Hdr }
func (rr *RP) Header() *RR_Header { return &rr.Hdr }
func (rr *RRSIG) Header() *RR_Header { return &rr.Hdr }
func (rr *RT) Header() *RR_Header { return &rr.Hdr }
func (rr *SIG) Header() *RR_Header { return &rr.Hdr }
func (rr *SOA) Header() *RR_Header { return &rr.Hdr }
func (rr *SPF) Header() *RR_Header { return &rr.Hdr }
func (rr *SRV) Header() *RR_Header { return &rr.Hdr }
func (rr *SSHFP) Header() *RR_Header { return &rr.Hdr }
func (rr *TA) Header() *RR_Header { return &rr.Hdr }
func (rr *TALINK) Header() *RR_Header { return &rr.Hdr }
func (rr *TKEY) Header() *RR_Header { return &rr.Hdr }
func (rr *TLSA) Header() *RR_Header { return &rr.Hdr }
func (rr *TSIG) Header() *RR_Header { return &rr.Hdr }
func (rr *TXT) Header() *RR_Header { return &rr.Hdr }
func (rr *UID) Header() *RR_Header { return &rr.Hdr }
func (rr *UINFO) Header() *RR_Header { return &rr.Hdr }
func (rr *URI) Header() *RR_Header { return &rr.Hdr }
func (rr *WKS) Header() *RR_Header { return &rr.Hdr }
func (rr *X25) Header() *RR_Header { return &rr.Hdr }
// len() functions
func (rr *A) len() int {
l := rr.Hdr.len()
l += net.IPv4len // A
return l
}
func (rr *AAAA) len() int {
l := rr.Hdr.len()
l += net.IPv6len // AAAA
return l
}
func (rr *AFSDB) len() int {
l := rr.Hdr.len()
l += 2 // Subtype
l += len(rr.Hostname) + 1
return l
}
func (rr *ANY) len() int {
l := rr.Hdr.len()
return l
}
func (rr *CAA) len() int {
l := rr.Hdr.len()
l += 1 // Flag
l += len(rr.Tag) + 1
l += len(rr.Value)
return l
}
func (rr *CERT) len() int {
l := rr.Hdr.len()
l += 2 // Type
l += 2 // KeyTag
l += 1 // Algorithm
l += base64.StdEncoding.DecodedLen(len(rr.Certificate))
return l
}
func (rr *CNAME) len() int {
l := rr.Hdr.len()
l += len(rr.Target) + 1
return l
}
func (rr *DHCID) len() int {
l := rr.Hdr.len()
l += base64.StdEncoding.DecodedLen(len(rr.Digest))
return l
}
func (rr *DNAME) len() int {
l := rr.Hdr.len()
l += len(rr.Target) + 1
return l
}
func (rr *DNSKEY) len() int {
l := rr.Hdr.len()
l += 2 // Flags
l += 1 // Protocol
l += 1 // Algorithm
l += base64.StdEncoding.DecodedLen(len(rr.PublicKey))
return l
}
func (rr *DS) len() int {
l := rr.Hdr.len()
l += 2 // KeyTag
l += 1 // Algorithm
l += 1 // DigestType
l += len(rr.Digest)/2 + 1
return l
}
func (rr *EID) len() int {
l := rr.Hdr.len()
l += len(rr.Endpoint)/2 + 1
return l
}
func (rr *EUI48) len() int {
l := rr.Hdr.len()
l += 6 // Address
return l
}
func (rr *EUI64) len() int {
l := rr.Hdr.len()
l += 8 // Address
return l
}
func (rr *GID) len() int {
l := rr.Hdr.len()
l += 4 // Gid
return l
}
func (rr *GPOS) len() int {
l := rr.Hdr.len()
l += len(rr.Longitude) + 1
l += len(rr.Latitude) + 1
l += len(rr.Altitude) + 1
return l
}
func (rr *HINFO) len() int {
l := rr.Hdr.len()
l += len(rr.Cpu) + 1
l += len(rr.Os) + 1
return l
}
func (rr *HIP) len() int {
l := rr.Hdr.len()
l += 1 // HitLength
l += 1 // PublicKeyAlgorithm
l += 2 // PublicKeyLength
l += len(rr.Hit)/2 + 1
l += base64.StdEncoding.DecodedLen(len(rr.PublicKey))
for _, x := range rr.RendezvousServers {
l += len(x) + 1
}
return l
}
func (rr *KX) len() int {
l := rr.Hdr.len()
l += 2 // Preference
l += len(rr.Exchanger) + 1
return l
}
func (rr *L32) len() int {
l := rr.Hdr.len()
l += 2 // Preference
l += net.IPv4len // Locator32
return l
}
func (rr *L64) len() int {
l := rr.Hdr.len()
l += 2 // Preference
l += 8 // Locator64
return l
}
func (rr *LOC) len() int {
l := rr.Hdr.len()
l += 1 // Version
l += 1 // Size
l += 1 // HorizPre
l += 1 // VertPre
l += 4 // Latitude
l += 4 // Longitude
l += 4 // Altitude
return l
}
func (rr *LP) len() int {
l := rr.Hdr.len()
l += 2 // Preference
l += len(rr.Fqdn) + 1
return l
}
func (rr *MB) len() int {
l := rr.Hdr.len()
l += len(rr.Mb) + 1
return l
}
func (rr *MD) len() int {
l := rr.Hdr.len()
l += len(rr.Md) + 1
return l
}
func (rr *MF) len() int {
l := rr.Hdr.len()
l += len(rr.Mf) + 1
return l
}
func (rr *MG) len() int {
l := rr.Hdr.len()
l += len(rr.Mg) + 1
return l
}
func (rr *MINFO) len() int {
l := rr.Hdr.len()
l += len(rr.Rmail) + 1
l += len(rr.Email) + 1
return l
}
func (rr *MR) len() int {
l := rr.Hdr.len()
l += len(rr.Mr) + 1
return l
}
func (rr *MX) len() int {
l := rr.Hdr.len()
l += 2 // Preference
l += len(rr.Mx) + 1
return l
}
func (rr *NAPTR) len() int {
l := rr.Hdr.len()
l += 2 // Order
l += 2 // Preference
l += len(rr.Flags) + 1
l += len(rr.Service) + 1
l += len(rr.Regexp) + 1
l += len(rr.Replacement) + 1
return l
}
func (rr *NID) len() int {
l := rr.Hdr.len()
l += 2 // Preference
l += 8 // NodeID
return l
}
func (rr *NIMLOC) len() int {
l := rr.Hdr.len()
l += len(rr.Locator)/2 + 1
return l
}
func (rr *NINFO) len() int {
l := rr.Hdr.len()
for _, x := range rr.ZSData {
l += len(x) + 1
}
return l
}
func (rr *NS) len() int {
l := rr.Hdr.len()
l += len(rr.Ns) + 1
return l
}
func (rr *NSAPPTR) len() int {
l := rr.Hdr.len()
l += len(rr.Ptr) + 1
return l
}
func (rr *NSEC3PARAM) len() int {
l := rr.Hdr.len()
l += 1 // Hash
l += 1 // Flags
l += 2 // Iterations
l += 1 // SaltLength
l += len(rr.Salt)/2 + 1
return l
}
func (rr *OPENPGPKEY) len() int {
l := rr.Hdr.len()
l += base64.StdEncoding.DecodedLen(len(rr.PublicKey))
return l
}
func (rr *PTR) len() int {
l := rr.Hdr.len()
l += len(rr.Ptr) + 1
return l
}
func (rr *PX) len() int {
l := rr.Hdr.len()
l += 2 // Preference
l += len(rr.Map822) + 1
l += len(rr.Mapx400) + 1
return l
}
func (rr *RFC3597) len() int {
l := rr.Hdr.len()
l += len(rr.Rdata)/2 + 1
return l
}
func (rr *RKEY) len() int {
l := rr.Hdr.len()
l += 2 // Flags
l += 1 // Protocol
l += 1 // Algorithm
l += base64.StdEncoding.DecodedLen(len(rr.PublicKey))
return l
}
func (rr *RP) len() int {
l := rr.Hdr.len()
l += len(rr.Mbox) + 1
l += len(rr.Txt) + 1
return l
}
func (rr *RRSIG) len() int {
l := rr.Hdr.len()
l += 2 // TypeCovered
l += 1 // Algorithm
l += 1 // Labels
l += 4 // OrigTtl
l += 4 // Expiration
l += 4 // Inception
l += 2 // KeyTag
l += len(rr.SignerName) + 1
l += base64.StdEncoding.DecodedLen(len(rr.Signature))
return l
}
func (rr *RT) len() int {
l := rr.Hdr.len()
l += 2 // Preference
l += len(rr.Host) + 1
return l
}
func (rr *SOA) len() int {
l := rr.Hdr.len()
l += len(rr.Ns) + 1
l += len(rr.Mbox) + 1
l += 4 // Serial
l += 4 // Refresh
l += 4 // Retry
l += 4 // Expire
l += 4 // Minttl
return l
}
func (rr *SPF) len() int {
l := rr.Hdr.len()
for _, x := range rr.Txt {
l += len(x) + 1
}
return l
}
func (rr *SRV) len() int {
l := rr.Hdr.len()
l += 2 // Priority
l += 2 // Weight
l += 2 // Port
l += len(rr.Target) + 1
return l
}
func (rr *SSHFP) len() int {
l := rr.Hdr.len()
l += 1 // Algorithm
l += 1 // Type
l += len(rr.FingerPrint)/2 + 1
return l
}
func (rr *TA) len() int {
l := rr.Hdr.len()
l += 2 // KeyTag
l += 1 // Algorithm
l += 1 // DigestType
l += len(rr.Digest)/2 + 1
return l
}
func (rr *TALINK) len() int {
l := rr.Hdr.len()
l += len(rr.PreviousName) + 1
l += len(rr.NextName) + 1
return l
}
func (rr *TKEY) len() int {
l := rr.Hdr.len()
l += len(rr.Algorithm) + 1
l += 4 // Inception
l += 4 // Expiration
l += 2 // Mode
l += 2 // Error
l += 2 // KeySize
l += len(rr.Key) + 1
l += 2 // OtherLen
l += len(rr.OtherData) + 1
return l
}
func (rr *TLSA) len() int {
l := rr.Hdr.len()
l += 1 // Usage
l += 1 // Selector
l += 1 // MatchingType
l += len(rr.Certificate)/2 + 1
return l
}
func (rr *TSIG) len() int {
l := rr.Hdr.len()
l += len(rr.Algorithm) + 1
l += 6 // TimeSigned
l += 2 // Fudge
l += 2 // MACSize
l += len(rr.MAC)/2 + 1
l += 2 // OrigId
l += 2 // Error
l += 2 // OtherLen
l += len(rr.OtherData)/2 + 1
return l
}
func (rr *TXT) len() int {
l := rr.Hdr.len()
for _, x := range rr.Txt {
l += len(x) + 1
}
return l
}
func (rr *UID) len() int {
l := rr.Hdr.len()
l += 4 // Uid
return l
}
func (rr *UINFO) len() int {
l := rr.Hdr.len()
l += len(rr.Uinfo) + 1
return l
}
func (rr *URI) len() int {
l := rr.Hdr.len()
l += 2 // Priority
l += 2 // Weight
l += len(rr.Target)
return l
}
func (rr *X25) len() int {
l := rr.Hdr.len()
l += len(rr.PSDNAddress) + 1
return l
}
// copy() functions
func (rr *A) copy() RR {
return &A{*rr.Hdr.copyHeader(), copyIP(rr.A)}
}
func (rr *AAAA) copy() RR {
return &AAAA{*rr.Hdr.copyHeader(), copyIP(rr.AAAA)}
}
func (rr *AFSDB) copy() RR {
return &AFSDB{*rr.Hdr.copyHeader(), rr.Subtype, rr.Hostname}
}
func (rr *ANY) copy() RR {
return &ANY{*rr.Hdr.copyHeader()}
}
func (rr *CAA) copy() RR {
return &CAA{*rr.Hdr.copyHeader(), rr.Flag, rr.Tag, rr.Value}
}
func (rr *CERT) copy() RR {
return &CERT{*rr.Hdr.copyHeader(), rr.Type, rr.KeyTag, rr.Algorithm, rr.Certificate}
}
func (rr *CNAME) copy() RR {
return &CNAME{*rr.Hdr.copyHeader(), rr.Target}
}
func (rr *DHCID) copy() RR {
return &DHCID{*rr.Hdr.copyHeader(), rr.Digest}
}
func (rr *DNAME) copy() RR {
return &DNAME{*rr.Hdr.copyHeader(), rr.Target}
}
func (rr *DNSKEY) copy() RR {
return &DNSKEY{*rr.Hdr.copyHeader(), rr.Flags, rr.Protocol, rr.Algorithm, rr.PublicKey}
}
func (rr *DS) copy() RR {
return &DS{*rr.Hdr.copyHeader(), rr.KeyTag, rr.Algorithm, rr.DigestType, rr.Digest}
}
func (rr *EID) copy() RR {
return &EID{*rr.Hdr.copyHeader(), rr.Endpoint}
}
func (rr *EUI48) copy() RR {
return &EUI48{*rr.Hdr.copyHeader(), rr.Address}
}
func (rr *EUI64) copy() RR {
return &EUI64{*rr.Hdr.copyHeader(), rr.Address}
}
func (rr *GID) copy() RR {
return &GID{*rr.Hdr.copyHeader(), rr.Gid}
}
func (rr *GPOS) copy() RR {
return &GPOS{*rr.Hdr.copyHeader(), rr.Longitude, rr.Latitude, rr.Altitude}
}
func (rr *HINFO) copy() RR {
return &HINFO{*rr.Hdr.copyHeader(), rr.Cpu, rr.Os}
}
func (rr *HIP) copy() RR {
RendezvousServers := make([]string, len(rr.RendezvousServers))
copy(RendezvousServers, rr.RendezvousServers)
return &HIP{*rr.Hdr.copyHeader(), rr.HitLength, rr.PublicKeyAlgorithm, rr.PublicKeyLength, rr.Hit, rr.PublicKey, RendezvousServers}
}
func (rr *IPSECKEY) copy() RR {
return &IPSECKEY{*rr.Hdr.copyHeader(), rr.Precedence, rr.GatewayType, rr.Algorithm, copyIP(rr.GatewayA), copyIP(rr.GatewayAAAA), rr.GatewayName, rr.PublicKey}
}
func (rr *KX) copy() RR {
return &KX{*rr.Hdr.copyHeader(), rr.Preference, rr.Exchanger}
}
func (rr *L32) copy() RR {
return &L32{*rr.Hdr.copyHeader(), rr.Preference, copyIP(rr.Locator32)}
}
func (rr *L64) copy() RR {
return &L64{*rr.Hdr.copyHeader(), rr.Preference, rr.Locator64}
}
func (rr *LOC) copy() RR {
return &LOC{*rr.Hdr.copyHeader(), rr.Version, rr.Size, rr.HorizPre, rr.VertPre, rr.Latitude, rr.Longitude, rr.Altitude}
}
func (rr *LP) copy() RR {
return &LP{*rr.Hdr.copyHeader(), rr.Preference, rr.Fqdn}
}
func (rr *MB) copy() RR {
return &MB{*rr.Hdr.copyHeader(), rr.Mb}
}
func (rr *MD) copy() RR {
return &MD{*rr.Hdr.copyHeader(), rr.Md}
}
func (rr *MF) copy() RR {
return &MF{*rr.Hdr.copyHeader(), rr.Mf}
}
func (rr *MG) copy() RR {
return &MG{*rr.Hdr.copyHeader(), rr.Mg}
}
func (rr *MINFO) copy() RR {
return &MINFO{*rr.Hdr.copyHeader(), rr.Rmail, rr.Email}
}
func (rr *MR) copy() RR {
return &MR{*rr.Hdr.copyHeader(), rr.Mr}
}
func (rr *MX) copy() RR {
return &MX{*rr.Hdr.copyHeader(), rr.Preference, rr.Mx}
}
func (rr *NAPTR) copy() RR {
return &NAPTR{*rr.Hdr.copyHeader(), rr.Order, rr.Preference, rr.Flags, rr.Service, rr.Regexp, rr.Replacement}
}
func (rr *NID) copy() RR {
return &NID{*rr.Hdr.copyHeader(), rr.Preference, rr.NodeID}
}
func (rr *NIMLOC) copy() RR {
return &NIMLOC{*rr.Hdr.copyHeader(), rr.Locator}
}
func (rr *NINFO) copy() RR {
ZSData := make([]string, len(rr.ZSData))
copy(ZSData, rr.ZSData)
return &NINFO{*rr.Hdr.copyHeader(), ZSData}
}
func (rr *NS) copy() RR {
return &NS{*rr.Hdr.copyHeader(), rr.Ns}
}
func (rr *NSAPPTR) copy() RR {
return &NSAPPTR{*rr.Hdr.copyHeader(), rr.Ptr}
}
func (rr *NSEC) copy() RR {
TypeBitMap := make([]uint16, len(rr.TypeBitMap))
copy(TypeBitMap, rr.TypeBitMap)
return &NSEC{*rr.Hdr.copyHeader(), rr.NextDomain, TypeBitMap}
}
func (rr *NSEC3) copy() RR {
TypeBitMap := make([]uint16, len(rr.TypeBitMap))
copy(TypeBitMap, rr.TypeBitMap)
return &NSEC3{*rr.Hdr.copyHeader(), rr.Hash, rr.Flags, rr.Iterations, rr.SaltLength, rr.Salt, rr.HashLength, rr.NextDomain, TypeBitMap}
}
func (rr *NSEC3PARAM) copy() RR {
return &NSEC3PARAM{*rr.Hdr.copyHeader(), rr.Hash, rr.Flags, rr.Iterations, rr.SaltLength, rr.Salt}
}
func (rr *OPENPGPKEY) copy() RR {
return &OPENPGPKEY{*rr.Hdr.copyHeader(), rr.PublicKey}
}
func (rr *OPT) copy() RR {
Option := make([]EDNS0, len(rr.Option))
copy(Option, rr.Option)
return &OPT{*rr.Hdr.copyHeader(), Option}
}
func (rr *PTR) copy() RR {
return &PTR{*rr.Hdr.copyHeader(), rr.Ptr}
}
func (rr *PX) copy() RR {
return &PX{*rr.Hdr.copyHeader(), rr.Preference, rr.Map822, rr.Mapx400}
}
func (rr *RFC3597) copy() RR {
return &RFC3597{*rr.Hdr.copyHeader(), rr.Rdata}
}
func (rr *RKEY) copy() RR {
return &RKEY{*rr.Hdr.copyHeader(), rr.Flags, rr.Protocol, rr.Algorithm, rr.PublicKey}
}
func (rr *RP) copy() RR {
return &RP{*rr.Hdr.copyHeader(), rr.Mbox, rr.Txt}
}
func (rr *RRSIG) copy() RR {
return &RRSIG{*rr.Hdr.copyHeader(), rr.TypeCovered, rr.Algorithm, rr.Labels, rr.OrigTtl, rr.Expiration, rr.Inception, rr.KeyTag, rr.SignerName, rr.Signature}
}
func (rr *RT) copy() RR {
return &RT{*rr.Hdr.copyHeader(), rr.Preference, rr.Host}
}
func (rr *SOA) copy() RR {
return &SOA{*rr.Hdr.copyHeader(), rr.Ns, rr.Mbox, rr.Serial, rr.Refresh, rr.Retry, rr.Expire, rr.Minttl}
}
func (rr *SPF) copy() RR {
Txt := make([]string, len(rr.Txt))
copy(Txt, rr.Txt)
return &SPF{*rr.Hdr.copyHeader(), Txt}
}
func (rr *SRV) copy() RR {
return &SRV{*rr.Hdr.copyHeader(), rr.Priority, rr.Weight, rr.Port, rr.Target}
}
func (rr *SSHFP) copy() RR {
return &SSHFP{*rr.Hdr.copyHeader(), rr.Algorithm, rr.Type, rr.FingerPrint}
}
func (rr *TA) copy() RR {
return &TA{*rr.Hdr.copyHeader(), rr.KeyTag, rr.Algorithm, rr.DigestType, rr.Digest}
}
func (rr *TALINK) copy() RR {
return &TALINK{*rr.Hdr.copyHeader(), rr.PreviousName, rr.NextName}
}
func (rr *TKEY) copy() RR {
return &TKEY{*rr.Hdr.copyHeader(), rr.Algorithm, rr.Inception, rr.Expiration, rr.Mode, rr.Error, rr.KeySize, rr.Key, rr.OtherLen, rr.OtherData}
}
func (rr *TLSA) copy() RR {
return &TLSA{*rr.Hdr.copyHeader(), rr.Usage, rr.Selector, rr.MatchingType, rr.Certificate}
}
func (rr *TSIG) copy() RR {
return &TSIG{*rr.Hdr.copyHeader(), rr.Algorithm, rr.TimeSigned, rr.Fudge, rr.MACSize, rr.MAC, rr.OrigId, rr.Error, rr.OtherLen, rr.OtherData}
}
func (rr *TXT) copy() RR {
Txt := make([]string, len(rr.Txt))
copy(Txt, rr.Txt)
return &TXT{*rr.Hdr.copyHeader(), Txt}
}
func (rr *UID) copy() RR {
return &UID{*rr.Hdr.copyHeader(), rr.Uid}
}
func (rr *UINFO) copy() RR {
return &UINFO{*rr.Hdr.copyHeader(), rr.Uinfo}
}
func (rr *URI) copy() RR {
return &URI{*rr.Hdr.copyHeader(), rr.Priority, rr.Weight, rr.Target}
}
func (rr *WKS) copy() RR {
BitMap := make([]uint16, len(rr.BitMap))
copy(BitMap, rr.BitMap)
return &WKS{*rr.Hdr.copyHeader(), copyIP(rr.Address), rr.Protocol, BitMap}
}
func (rr *X25) copy() RR {
return &X25{*rr.Hdr.copyHeader(), rr.PSDNAddress}
}

View File

@ -12,6 +12,14 @@ import (
"github.com/miekg/dns" "github.com/miekg/dns"
) )
// PathPrefix is the prefix used to store SkyDNS data in the backend.
// It defaults to `skydns`.
// You can change it by set `path-prefix` configuration or SKYDNS_PATH_PREFIX env. variable.
// Then:
// The SkyDNS's configuration object should be stored under the key "/mydns/config";
// The etcd path of domain `service.staging.skydns.local.` will be "/mydns/local/skydns/staging/service".
var PathPrefix string = "skydns"
// This *is* the rdata from a SRV record, but with a twist. // This *is* the rdata from a SRV record, but with a twist.
// Host (Target in SRV) must be a domain name, but if it looks like an IP // Host (Target in SRV) must be a domain name, but if it looks like an IP
// address (4/6), we will treat it like an IP address. // address (4/6), we will treat it like an IP address.
@ -29,7 +37,7 @@ type Service struct {
// the record lives to a DNS name and use this as the srv.Target. When // the record lives to a DNS name and use this as the srv.Target. When
// TargetStrip > 0 we strip the left most TargetStrip labels from the // TargetStrip > 0 we strip the left most TargetStrip labels from the
// DNS name. // DNS name.
TargetStrip int `json:"targetstrip",omitempty"` TargetStrip int `json:"targetstrip,omitempty"`
// Group is used to group (or *not* to group) different services // Group is used to group (or *not* to group) different services
// together. Services with an identical Group are returned in the same // together. Services with an identical Group are returned in the same
@ -42,17 +50,7 @@ type Service struct {
// NewSRV returns a new SRV record based on the Service. // NewSRV returns a new SRV record based on the Service.
func (s *Service) NewSRV(name string, weight uint16) *dns.SRV { func (s *Service) NewSRV(name string, weight uint16) *dns.SRV {
host := dns.Fqdn(s.Host) host := targetStrip(dns.Fqdn(s.Host), s.TargetStrip)
offset, end := 0, false
for i := 0; i < s.TargetStrip; i++ {
offset, end = dns.NextLabel(host, offset)
}
if end {
// We overshot the name, use the orignal one.
offset = 0
}
host = host[offset:]
return &dns.SRV{Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypeSRV, Class: dns.ClassINET, Ttl: s.Ttl}, return &dns.SRV{Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypeSRV, Class: dns.ClassINET, Ttl: s.Ttl},
Priority: uint16(s.Priority), Weight: weight, Port: uint16(s.Port), Target: host} Priority: uint16(s.Priority), Weight: weight, Port: uint16(s.Port), Target: host}
@ -60,17 +58,7 @@ func (s *Service) NewSRV(name string, weight uint16) *dns.SRV {
// NewMX returns a new MX record based on the Service. // NewMX returns a new MX record based on the Service.
func (s *Service) NewMX(name string) *dns.MX { func (s *Service) NewMX(name string) *dns.MX {
host := dns.Fqdn(s.Host) host := targetStrip(dns.Fqdn(s.Host), s.TargetStrip)
offset, end := 0, false
for i := 0; i < s.TargetStrip; i++ {
offset, end = dns.NextLabel(host, offset)
}
if end {
// We overshot the name, use the orignal one.
offset = 0
}
host = host[offset:]
return &dns.MX{Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypeMX, Class: dns.ClassINET, Ttl: s.Ttl}, return &dns.MX{Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypeMX, Class: dns.ClassINET, Ttl: s.Ttl},
Preference: uint16(s.Priority), Mx: host} Preference: uint16(s.Priority), Mx: host}
@ -118,10 +106,10 @@ func PathWithWildcard(s string) (string, bool) {
} }
for i, k := range l { for i, k := range l {
if k == "*" || k == "any" { if k == "*" || k == "any" {
return path.Join(append([]string{"/skydns/"}, l[:i]...)...), true return path.Join(append([]string{"/" + PathPrefix + "/"}, l[:i]...)...), true
} }
} }
return path.Join(append([]string{"/skydns/"}, l...)...), false return path.Join(append([]string{"/" + PathPrefix + "/"}, l...)...), false
} }
// Path converts a domainname to an etcd path. If s looks like service.staging.skydns.local., // Path converts a domainname to an etcd path. If s looks like service.staging.skydns.local.,
@ -131,7 +119,7 @@ func Path(s string) string {
for i, j := 0, len(l)-1; i < j; i, j = i+1, j-1 { for i, j := 0, len(l)-1; i < j; i, j = i+1, j-1 {
l[i], l[j] = l[j], l[i] l[i], l[j] = l[j], l[i]
} }
return path.Join(append([]string{"/skydns/"}, l...)...) return path.Join(append([]string{"/" + PathPrefix + "/"}, l...)...)
} }
// Domain is the opposite of Path. // Domain is the opposite of Path.
@ -213,3 +201,21 @@ func split255(s string) []string {
return sx return sx
} }
// targetStrip strips "targetstrip" labels from the left side of the fully qualified name.
func targetStrip(name string, targetStrip int) string {
if targetStrip == 0 {
return name
}
offset, end := 0, false
for i := 0; i < targetStrip; i++ {
offset, end = dns.NextLabel(name, offset)
}
if end {
// We overshot the name, use the orignal one.
offset = 0
}
name = name[offset:]
return name
}