Add miekg/dns 1.1.4

Signed-off-by: Erik Hollensbe <github@hollensbe.org>
This commit is contained in:
Erik Hollensbe 2019-02-06 21:41:25 +00:00
parent 9b8bbe3246
commit 9154e9aca8
54 changed files with 5803 additions and 4844 deletions

2
go.mod
View file

@ -66,7 +66,7 @@ require (
github.com/lib/pq v1.0.0 // indirect github.com/lib/pq v1.0.0 // indirect
github.com/lightstep/lightstep-tracer-go v0.15.6 // indirect github.com/lightstep/lightstep-tracer-go v0.15.6 // indirect
github.com/mattn/go-runewidth v0.0.3 // indirect github.com/mattn/go-runewidth v0.0.3 // indirect
github.com/miekg/dns v1.0.4 github.com/miekg/dns v1.1.4
github.com/mitchellh/go-homedir v0.0.0-20180523094522-3864e76763d9 // indirect github.com/mitchellh/go-homedir v0.0.0-20180523094522-3864e76763d9 // indirect
github.com/mitchellh/go-testing-interface v1.0.0 // indirect github.com/mitchellh/go-testing-interface v1.0.0 // indirect
github.com/mitchellh/reflectwalk v1.0.0 // indirect github.com/mitchellh/reflectwalk v1.0.0 // indirect

4
go.sum
View file

@ -174,8 +174,8 @@ github.com/mattn/go-runewidth v0.0.3 h1:a+kO+98RDGEfo6asOGMmpodZq4FNtnGP54yps8Bz
github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/miekg/dns v1.0.4 h1:Ec3LTJwwzqT1++63P12fhtdEbQhtPE7TBdD6rlhqrMM= github.com/miekg/dns v1.1.4 h1:rCMZsU2ScVSYcAsOXgmC6+AKOK+6pmQTOcw03nfwYV0=
github.com/miekg/dns v1.0.4/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.1.4/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/mitchellh/go-homedir v0.0.0-20180523094522-3864e76763d9 h1:Y94YB7jrsihrbGSqRNMwRWJ2/dCxr0hdC2oPRohkx0A= github.com/mitchellh/go-homedir v0.0.0-20180523094522-3864e76763d9 h1:Y94YB7jrsihrbGSqRNMwRWJ2/dCxr0hdC2oPRohkx0A=
github.com/mitchellh/go-homedir v0.0.0-20180523094522-3864e76763d9/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v0.0.0-20180523094522-3864e76763d9/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-testing-interface v1.0.0 h1:fzU/JVNcaqHQEcVFAKeR41fkiLdIPrefOvVG1VZ96U0= github.com/mitchellh/go-testing-interface v1.0.0 h1:fzU/JVNcaqHQEcVFAKeR41fkiLdIPrefOvVG1VZ96U0=

View file

@ -1,12 +1,10 @@
language: go language: go
sudo: false sudo: false
go:
- 1.9.x
- tip
env: go:
- TESTS="-race -v -bench=. -coverprofile=coverage.txt -covermode=atomic" - 1.10.x
- TESTS="-race -v ./..." - 1.11.x
- tip
before_install: before_install:
# don't use the miekg/dns when testing forks # don't use the miekg/dns when testing forks
@ -14,7 +12,7 @@ before_install:
- ln -s $TRAVIS_BUILD_DIR $GOPATH/src/github.com/miekg/ || true - ln -s $TRAVIS_BUILD_DIR $GOPATH/src/github.com/miekg/ || true
script: script:
- go test $TESTS - go test -race -v -bench=. -coverprofile=coverage.txt -covermode=atomic ./...
after_success: after_success:
- bash <(curl -s https://codecov.io/bash) - bash <(curl -s https://codecov.io/bash)

View file

@ -3,19 +3,55 @@
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:6914c49eed986dfb8dffb33516fa129c49929d4d873f41e073c83c11c372b870"
name = "golang.org/x/crypto" name = "golang.org/x/crypto"
packages = ["ed25519","ed25519/internal/edwards25519"] packages = [
revision = "b080dc9a8c480b08e698fb1219160d598526310f" "ed25519",
"ed25519/internal/edwards25519",
]
pruneopts = ""
revision = "e3636079e1a4c1f337f212cc5cd2aca108f6c900"
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:08e41d63f8dac84d83797368b56cf0b339e42d0224e5e56668963c28aec95685"
name = "golang.org/x/net" name = "golang.org/x/net"
packages = ["bpf","internal/iana","internal/socket","ipv4","ipv6"] packages = [
revision = "894f8ed5849b15b810ae41e9590a0d05395bba27" "bpf",
"context",
"internal/iana",
"internal/socket",
"ipv4",
"ipv6",
]
pruneopts = ""
revision = "4dfa2610cdf3b287375bbba5b8f2a14d3b01d8de"
[[projects]]
branch = "master"
digest = "1:b2ea75de0ccb2db2ac79356407f8a4cd8f798fe15d41b381c00abf3ae8e55ed1"
name = "golang.org/x/sync"
packages = ["errgroup"]
pruneopts = ""
revision = "1d60e4601c6fd243af51cc01ddf169918a5407ca"
[[projects]]
branch = "master"
digest = "1:149a432fabebb8221a80f77731b1cd63597197ded4f14af606ebe3a0959004ec"
name = "golang.org/x/sys"
packages = ["unix"]
pruneopts = ""
revision = "e4b3c5e9061176387e7cea65e4dc5853801f3fb7"
[solve-meta] [solve-meta]
analyzer-name = "dep" analyzer-name = "dep"
analyzer-version = 1 analyzer-version = 1
inputs-digest = "c4abc38abaeeeeb9be92455c9c02cae32841122b8982aaa067ef25bb8e86ff9d" input-imports = [
"golang.org/x/crypto/ed25519",
"golang.org/x/net/ipv4",
"golang.org/x/net/ipv6",
"golang.org/x/sync/errgroup",
"golang.org/x/sys/unix",
]
solver-name = "gps-cdcl" solver-name = "gps-cdcl"
solver-version = 1 solver-version = 1

View file

@ -24,3 +24,15 @@
[[constraint]] [[constraint]]
branch = "master" branch = "master"
name = "golang.org/x/crypto" name = "golang.org/x/crypto"
[[constraint]]
branch = "master"
name = "golang.org/x/net"
[[constraint]]
branch = "master"
name = "golang.org/x/sys"
[[constraint]]
branch = "master"
name = "golang.org/x/sync"

View file

@ -7,10 +7,10 @@
> Less is more. > Less is more.
Complete and usable DNS library. All widely used Resource Records are supported, including the Complete and usable DNS library. All Resource Records are supported, including the DNSSEC types.
DNSSEC types. It follows a lean and mean philosophy. If there is stuff you should know as a DNS It follows a lean and mean philosophy. If there is stuff you should know as a DNS programmer there
programmer there isn't a convenience function for it. Server side and client side programming is isn't a convenience function for it. Server side and client side programming is supported, i.e. you
supported, i.e. you can build servers and resolvers with it. can build servers and resolvers with it.
We try to keep the "master" branch as sane as possible and at the bleeding edge of standards, 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 two versions of Go. avoiding breaking changes wherever reasonable. We support the last two versions of Go.
@ -42,10 +42,9 @@ A not-so-up-to-date-list-that-may-be-actually-current:
* https://github.com/tianon/rawdns * https://github.com/tianon/rawdns
* https://mesosphere.github.io/mesos-dns/ * https://mesosphere.github.io/mesos-dns/
* https://pulse.turbobytes.com/ * https://pulse.turbobytes.com/
* https://play.google.com/store/apps/details?id=com.turbobytes.dig
* https://github.com/fcambus/statzone * https://github.com/fcambus/statzone
* https://github.com/benschw/dns-clb-go * https://github.com/benschw/dns-clb-go
* https://github.com/corny/dnscheck for http://public-dns.info/ * https://github.com/corny/dnscheck for <http://public-dns.info/>
* https://namesmith.io * https://namesmith.io
* https://github.com/miekg/unbound * https://github.com/miekg/unbound
* https://github.com/miekg/exdns * https://github.com/miekg/exdns
@ -56,7 +55,7 @@ A not-so-up-to-date-list-that-may-be-actually-current:
* https://github.com/bamarni/dockness * https://github.com/bamarni/dockness
* https://github.com/fffaraz/microdns * https://github.com/fffaraz/microdns
* http://kelda.io * http://kelda.io
* https://github.com/ipdcode/hades (JD.COM) * https://github.com/ipdcode/hades <https://jd.com>
* https://github.com/StackExchange/dnscontrol/ * https://github.com/StackExchange/dnscontrol/
* https://www.dnsperf.com/ * https://www.dnsperf.com/
* https://dnssectest.net/ * https://dnssectest.net/
@ -64,29 +63,32 @@ A not-so-up-to-date-list-that-may-be-actually-current:
* https://github.com/oif/apex * https://github.com/oif/apex
* https://github.com/jedisct1/dnscrypt-proxy * https://github.com/jedisct1/dnscrypt-proxy
* https://github.com/jedisct1/rpdns * https://github.com/jedisct1/rpdns
* https://github.com/xor-gate/sshfp
* https://github.com/rs/dnstrace
* https://blitiri.com.ar/p/dnss ([github mirror](https://github.com/albertito/dnss))
* https://github.com/semihalev/sdns
* https://render.com
Send pull request if you want to be listed here. Send pull request if you want to be listed here.
# Features # Features
* UDP/TCP queries, IPv4 and IPv6; * UDP/TCP queries, IPv4 and IPv6
* RFC 1035 zone file parsing ($INCLUDE, $ORIGIN, $TTL and $GENERATE (for all record types) are supported; * RFC 1035 zone file parsing ($INCLUDE, $ORIGIN, $TTL and $GENERATE (for all record types) are supported
* Fast: * Fast
* Reply speed around ~ 80K qps (faster hardware results in more qps); * Server side programming (mimicking the net/http package)
* Parsing RRs ~ 100K RR/s, that's 5M records in about 50 seconds; * Client side programming
* Server side programming (mimicking the net/http package); * DNSSEC: signing, validating and key generation for DSA, RSA, ECDSA and Ed25519
* Client side programming; * EDNS0, NSID, Cookies
* DNSSEC: signing, validating and key generation for DSA, RSA, ECDSA and Ed25519; * AXFR/IXFR
* EDNS0, NSID, Cookies; * TSIG, SIG(0)
* AXFR/IXFR; * DNS over TLS (DoT): encrypted connection between client and server over TCP
* TSIG, SIG(0); * DNS name compression
* DNS over TLS: optional encrypted connection between client and server;
* DNS name compression;
* Depends only on the standard library.
Have fun! Have fun!
Miek Gieben - 2010-2012 - <miek@miek.nl> Miek Gieben - 2010-2012 - <miek@miek.nl>
DNS Authors 2012-
# Building # Building
@ -98,8 +100,8 @@ work:
## Examples ## Examples
A short "how to use the API" is at the beginning of doc.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
when you call `godoc github.com/miekg/dns`). 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.
@ -157,12 +159,13 @@ Example programs can be found in the `github.com/miekg/exdns` repository.
* 7553 - URI record * 7553 - URI record
* 7858 - DNS over TLS: Initiation and Performance Considerations * 7858 - DNS over TLS: Initiation and Performance Considerations
* 7871 - EDNS0 Client Subnet * 7871 - EDNS0 Client Subnet
* 7873 - Domain Name System (DNS) Cookies (draft-ietf-dnsop-cookies) * 7873 - Domain Name System (DNS) Cookies
* 8080 - EdDSA for DNSSEC * 8080 - EdDSA for DNSSEC
* 8499 - DNS Terminology
## Loosely based upon ## Loosely Based Upon
* `ldns` * ldns - <https://nlnetlabs.nl/projects/ldns/about/>
* `NSD` * NSD - <https://nlnetlabs.nl/projects/nsd/about/>
* `Net::DNS` * Net::DNS - <http://www.net-dns.org/>
* `GRONG` * GRONG - <https://github.com/bortzmeyer/grong>

56
vendor/github.com/miekg/dns/acceptfunc.go generated vendored Normal file
View file

@ -0,0 +1,56 @@
package dns
// MsgAcceptFunc is used early in the server code to accept or reject a message with RcodeFormatError.
// It returns a MsgAcceptAction to indicate what should happen with the message.
type MsgAcceptFunc func(dh Header) MsgAcceptAction
// DefaultMsgAcceptFunc checks the request and will reject if:
//
// * isn't a request (don't respond in that case).
// * opcode isn't OpcodeQuery or OpcodeNotify
// * Zero bit isn't zero
// * has more than 1 question in the question section
// * has more than 1 RR in the Answer section
// * has more than 0 RRs in the Authority section
// * has more than 2 RRs in the Additional section
var DefaultMsgAcceptFunc MsgAcceptFunc = defaultMsgAcceptFunc
// MsgAcceptAction represents the action to be taken.
type MsgAcceptAction int
const (
MsgAccept MsgAcceptAction = iota // Accept the message
MsgReject // Reject the message with a RcodeFormatError
MsgIgnore // Ignore the error and send nothing back.
)
func defaultMsgAcceptFunc(dh Header) MsgAcceptAction {
if isResponse := dh.Bits&_QR != 0; isResponse {
return MsgIgnore
}
// Don't allow dynamic updates, because then the sections can contain a whole bunch of RRs.
opcode := int(dh.Bits>>11) & 0xF
if opcode != OpcodeQuery && opcode != OpcodeNotify {
return MsgReject
}
if isZero := dh.Bits&_Z != 0; isZero {
return MsgReject
}
if dh.Qdcount != 1 {
return MsgReject
}
// NOTIFY requests can have a SOA in the ANSWER section. See RFC 1996 Section 3.7 and 3.11.
if dh.Ancount > 1 {
return MsgReject
}
// IXFR request could have one SOA RR in the NS section. See RFC 1995, section 3.
if dh.Nscount > 1 {
return MsgReject
}
if dh.Arcount > 2 {
return MsgReject
}
return MsgAccept
}

View file

@ -13,16 +13,16 @@ import (
"time" "time"
) )
const dnsTimeout time.Duration = 2 * time.Second const (
const tcpIdleTimeout time.Duration = 8 * time.Second dnsTimeout time.Duration = 2 * time.Second
tcpIdleTimeout time.Duration = 8 * time.Second
)
// A Conn represents a connection to a DNS server. // A Conn represents a connection to a DNS server.
type Conn struct { type Conn struct {
net.Conn // a net.Conn holding the connection net.Conn // a net.Conn holding the connection
UDPSize uint16 // minimum receive buffer for UDP messages UDPSize uint16 // minimum receive buffer for UDP messages
TsigSecret map[string]string // secret(s) for Tsig map[<zonename>]<base64 secret>, zonename must be in canonical form (lowercase, fqdn, see RFC 4034 Section 6.2) TsigSecret map[string]string // secret(s) for Tsig map[<zonename>]<base64 secret>, zonename must be in canonical form (lowercase, fqdn, see RFC 4034 Section 6.2)
rtt time.Duration
t time.Time
tsigRequestMAC string tsigRequestMAC string
} }
@ -83,33 +83,22 @@ func (c *Client) Dial(address string) (conn *Conn, err error) {
// create a new dialer with the appropriate timeout // create a new dialer with the appropriate timeout
var d net.Dialer var d net.Dialer
if c.Dialer == nil { if c.Dialer == nil {
d = net.Dialer{} d = net.Dialer{Timeout: c.getTimeoutForRequest(c.dialTimeout())}
} else { } else {
d = net.Dialer(*c.Dialer) d = *c.Dialer
} }
d.Timeout = c.getTimeoutForRequest(c.writeTimeout())
network := "udp" network := c.Net
useTLS := false if network == "" {
network = "udp"
}
switch c.Net { useTLS := strings.HasPrefix(network, "tcp") && strings.HasSuffix(network, "-tls")
case "tcp-tls":
network = "tcp"
useTLS = true
case "tcp4-tls":
network = "tcp4"
useTLS = true
case "tcp6-tls":
network = "tcp6"
useTLS = true
default:
if c.Net != "" {
network = c.Net
}
}
conn = new(Conn) conn = new(Conn)
if useTLS { if useTLS {
network = strings.TrimSuffix(network, "-tls")
conn.Conn, err = tls.DialWithDialer(&d, network, address, c.TLSConfig) conn.Conn, err = tls.DialWithDialer(&d, network, address, c.TLSConfig)
} else { } else {
conn.Conn, err = d.Dial(network, address) conn.Conn, err = d.Dial(network, address)
@ -117,6 +106,7 @@ func (c *Client) Dial(address string) (conn *Conn, err error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
return conn, nil return conn, nil
} }
@ -177,8 +167,9 @@ func (c *Client) exchange(m *Msg, a string) (r *Msg, rtt time.Duration, err erro
} }
co.TsigSecret = c.TsigSecret co.TsigSecret = c.TsigSecret
t := time.Now()
// write with the appropriate write timeout // write with the appropriate write timeout
co.SetWriteDeadline(time.Now().Add(c.getTimeoutForRequest(c.writeTimeout()))) co.SetWriteDeadline(t.Add(c.getTimeoutForRequest(c.writeTimeout())))
if err = co.WriteMsg(m); err != nil { if err = co.WriteMsg(m); err != nil {
return nil, 0, err return nil, 0, err
} }
@ -188,7 +179,8 @@ func (c *Client) exchange(m *Msg, a string) (r *Msg, rtt time.Duration, err erro
if err == nil && r.Id != m.Id { if err == nil && r.Id != m.Id {
err = ErrId err = ErrId
} }
return r, co.rtt, err rtt = time.Since(t)
return r, rtt, err
} }
// ReadMsg reads a message from the connection co. // ReadMsg reads a message from the connection co.
@ -240,7 +232,6 @@ func (co *Conn) ReadMsgHeader(hdr *Header) ([]byte, error) {
} }
p = make([]byte, l) p = make([]byte, l)
n, err = tcpRead(r, p) n, err = tcpRead(r, p)
co.rtt = time.Since(co.t)
default: default:
if co.UDPSize > MinMsgSize { if co.UDPSize > MinMsgSize {
p = make([]byte, co.UDPSize) p = make([]byte, co.UDPSize)
@ -248,7 +239,6 @@ func (co *Conn) ReadMsgHeader(hdr *Header) ([]byte, error) {
p = make([]byte, MinMsgSize) p = make([]byte, MinMsgSize)
} }
n, err = co.Read(p) n, err = co.Read(p)
co.rtt = time.Since(co.t)
} }
if err != nil { if err != nil {
@ -330,16 +320,12 @@ func (co *Conn) Read(p []byte) (n int, err error) {
return 0, err return 0, err
} }
if l > len(p) { if l > len(p) {
return int(l), io.ErrShortBuffer return l, io.ErrShortBuffer
} }
return tcpRead(r, p[:l]) return tcpRead(r, p[:l])
} }
// UDP connection // UDP connection
n, err = co.Conn.Read(p) return co.Conn.Read(p)
if err != nil {
return n, err
}
return n, err
} }
// WriteMsg sends a message through the connection co. // WriteMsg sends a message through the connection co.
@ -361,12 +347,9 @@ func (co *Conn) WriteMsg(m *Msg) (err error) {
if err != nil { if err != nil {
return err return err
} }
co.t = time.Now() _, err = co.Write(out)
if _, err = co.Write(out); err != nil {
return err return err
} }
return nil
}
// 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) {
@ -387,8 +370,7 @@ func (co *Conn) Write(p []byte) (n int, err error) {
n, err := io.Copy(w, bytes.NewReader(p)) n, err := io.Copy(w, bytes.NewReader(p))
return int(n), err return int(n), err
} }
n, err = co.Conn.Write(p) return co.Conn.Write(p)
return n, err
} }
// Return the appropriate timeout for a specific request // Return the appropriate timeout for a specific request
@ -455,11 +437,7 @@ func ExchangeConn(c net.Conn, m *Msg) (r *Msg, err error) {
// 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) {
client := Client{Net: network, Dialer: &net.Dialer{Timeout: timeout}} client := Client{Net: network, Dialer: &net.Dialer{Timeout: timeout}}
conn, err = client.Dial(address) return client.Dial(address)
if err != nil {
return nil, err
}
return conn, nil
} }
// DialWithTLS connects to the address on the named network with TLS. // DialWithTLS connects to the address on the named network with TLS.
@ -468,12 +446,7 @@ func DialWithTLS(network, address string, tlsConfig *tls.Config) (conn *Conn, er
network += "-tls" network += "-tls"
} }
client := Client{Net: network, TLSConfig: tlsConfig} client := Client{Net: network, TLSConfig: tlsConfig}
conn, err = client.Dial(address) return client.Dial(address)
if err != nil {
return nil, err
}
return conn, nil
} }
// DialTimeoutWithTLS acts like DialWithTLS but takes a timeout. // DialTimeoutWithTLS acts like DialWithTLS but takes a timeout.
@ -482,11 +455,7 @@ func DialTimeoutWithTLS(network, address string, tlsConfig *tls.Config, timeout
network += "-tls" network += "-tls"
} }
client := Client{Net: network, Dialer: &net.Dialer{Timeout: timeout}, TLSConfig: tlsConfig} client := Client{Net: network, Dialer: &net.Dialer{Timeout: timeout}, TLSConfig: tlsConfig}
conn, err = client.Dial(address) return client.Dial(address)
if err != nil {
return nil, err
}
return conn, nil
} }
// ExchangeContext acts like Exchange, but honors the deadline on the provided // ExchangeContext acts like Exchange, but honors the deadline on the provided
@ -497,10 +466,11 @@ func (c *Client) ExchangeContext(ctx context.Context, m *Msg, a string) (r *Msg,
if deadline, ok := ctx.Deadline(); !ok { if deadline, ok := ctx.Deadline(); !ok {
timeout = 0 timeout = 0
} else { } else {
timeout = deadline.Sub(time.Now()) timeout = time.Until(deadline)
} }
// not passing the context to the underlying calls, as the API does not support // not passing the context to the underlying calls, as the API does not support
// context. For timeouts you should set up Client.Dialer and call Client.Exchange. // context. For timeouts you should set up Client.Dialer and call Client.Exchange.
// TODO(tmthrgd,miekg): this is a race condition.
c.Dialer = &net.Dialer{Timeout: timeout} c.Dialer = &net.Dialer{Timeout: timeout}
return c.Exchange(m, a) return c.Exchange(m, a)
} }

View file

@ -91,7 +91,7 @@ func ClientConfigFromReader(resolvconf io.Reader) (*ClientConfig, error) {
n = 1 n = 1
} }
c.Timeout = n c.Timeout = n
case len(s) >= 8 && s[:9] == "attempts:": case len(s) >= 9 && s[:9] == "attempts:":
n, _ := strconv.Atoi(s[9:]) n, _ := strconv.Atoi(s[9:])
if n < 1 { if n < 1 {
n = 1 n = 1

View file

@ -1,188 +0,0 @@
//+build ignore
// compression_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 look to see if there are (compressible) names, if so it will add that
// type to compressionLenHelperType and comressionLenSearchType which "fake" the
// compression so that Len() is fast.
package main
import (
"bytes"
"fmt"
"go/format"
"go/importer"
"go/types"
"log"
"os"
)
var packageHdr = `
// Code generated by "go run compress_generate.go"; DO NOT EDIT.
package dns
`
// 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()
var domainTypes []string // Types that have a domain name in them (either compressible or not).
var cdomainTypes []string // Types that have a compressible domain name in them (subset of domainType)
Names:
for _, name := range scope.Names() {
o := scope.Lookup(name)
if o == nil || !o.Exported() {
continue
}
st, _ := getTypeStruct(o.Type(), scope)
if st == nil {
continue
}
if name == "PrivateRR" {
continue
}
if scope.Lookup("Type"+o.Name()) == nil && o.Name() != "RFC3597" {
log.Fatalf("Constant Type%s does not exist.", o.Name())
}
for i := 1; i < st.NumFields(); i++ {
if _, ok := st.Field(i).Type().(*types.Slice); ok {
if st.Tag(i) == `dns:"domain-name"` {
domainTypes = append(domainTypes, o.Name())
continue Names
}
if st.Tag(i) == `dns:"cdomain-name"` {
cdomainTypes = append(cdomainTypes, o.Name())
domainTypes = append(domainTypes, o.Name())
continue Names
}
continue
}
switch {
case st.Tag(i) == `dns:"domain-name"`:
domainTypes = append(domainTypes, o.Name())
continue Names
case st.Tag(i) == `dns:"cdomain-name"`:
cdomainTypes = append(cdomainTypes, o.Name())
domainTypes = append(domainTypes, o.Name())
continue Names
}
}
}
b := &bytes.Buffer{}
b.WriteString(packageHdr)
// compressionLenHelperType - all types that have domain-name/cdomain-name can be used for compressing names
fmt.Fprint(b, "func compressionLenHelperType(c map[string]int, r RR) {\n")
fmt.Fprint(b, "switch x := r.(type) {\n")
for _, name := range domainTypes {
o := scope.Lookup(name)
st, _ := getTypeStruct(o.Type(), scope)
fmt.Fprintf(b, "case *%s:\n", name)
for i := 1; i < st.NumFields(); i++ {
out := func(s string) { fmt.Fprintf(b, "compressionLenHelper(c, x.%s)\n", st.Field(i).Name()) }
if _, ok := st.Field(i).Type().(*types.Slice); ok {
switch st.Tag(i) {
case `dns:"domain-name"`:
fallthrough
case `dns:"cdomain-name"`:
// For HIP we need to slice over the elements in this slice.
fmt.Fprintf(b, `for i := range x.%s {
compressionLenHelper(c, x.%s[i])
}
`, st.Field(i).Name(), st.Field(i).Name())
}
continue
}
switch {
case st.Tag(i) == `dns:"cdomain-name"`:
fallthrough
case st.Tag(i) == `dns:"domain-name"`:
out(st.Field(i).Name())
}
}
}
fmt.Fprintln(b, "}\n}\n\n")
// compressionLenSearchType - search cdomain-tags types for compressible names.
fmt.Fprint(b, "func compressionLenSearchType(c map[string]int, r RR) (int, bool) {\n")
fmt.Fprint(b, "switch x := r.(type) {\n")
for _, name := range cdomainTypes {
o := scope.Lookup(name)
st, _ := getTypeStruct(o.Type(), scope)
fmt.Fprintf(b, "case *%s:\n", name)
j := 1
for i := 1; i < st.NumFields(); i++ {
out := func(s string, j int) {
fmt.Fprintf(b, "k%d, ok%d := compressionLenSearch(c, x.%s)\n", j, j, st.Field(i).Name())
}
// There are no slice types with names that can be compressed.
switch {
case st.Tag(i) == `dns:"cdomain-name"`:
out(st.Field(i).Name(), j)
j++
}
}
k := "k1"
ok := "ok1"
for i := 2; i < j; i++ {
k += fmt.Sprintf(" + k%d", i)
ok += fmt.Sprintf(" && ok%d", i)
}
fmt.Fprintf(b, "return %s, %s\n", k, ok)
}
fmt.Fprintln(b, "}\nreturn 0, false\n}\n\n")
// gofmt
res, err := format.Source(b.Bytes())
if err != nil {
b.WriteTo(os.Stderr)
log.Fatal(err)
}
f, err := os.Create("zcompress.go")
fatalIfErr(err)
defer f.Close()
f.Write(res)
}
func fatalIfErr(err error) {
if err != nil {
log.Fatal(err)
}
}

View file

@ -4,6 +4,7 @@ import (
"errors" "errors"
"net" "net"
"strconv" "strconv"
"strings"
) )
const hexDigit = "0123456789abcdef" const hexDigit = "0123456789abcdef"
@ -163,11 +164,72 @@ func (dns *Msg) IsEdns0() *OPT {
// the number of labels. When false is returned the number of labels is not // the number of labels. When false is returned the number of labels is not
// defined. Also note that this function is extremely liberal; almost any // 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 // 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 // label fits in 63 characters and that the entire name will fit into the 255
// string s. I.e. a domain name longer than 255 characters is considered valid. // octet wire format limit.
func IsDomainName(s string) (labels int, ok bool) { func IsDomainName(s string) (labels int, ok bool) {
_, labels, err := packDomainName(s, nil, 0, nil, false) // XXX: The logic in this function was copied from packDomainName and
return labels, err == nil // should be kept in sync with that function.
const lenmsg = 256
if len(s) == 0 { // Ok, for instance when dealing with update RR without any rdata.
return 0, false
}
s = Fqdn(s)
// Each dot ends a segment of the name. Except for escaped dots (\.), which
// are normal dots.
var (
off int
begin int
wasDot bool
)
for i := 0; i < len(s); i++ {
switch s[i] {
case '\\':
if off+1 > lenmsg {
return labels, false
}
// check for \DDD
if i+3 < len(s) && isDigit(s[i+1]) && isDigit(s[i+2]) && isDigit(s[i+3]) {
i += 3
begin += 3
} else {
i++
begin++
}
wasDot = false
case '.':
if wasDot {
// two dots back to back is not legal
return labels, false
}
wasDot = true
labelLen := i - begin
if labelLen >= 1<<6 { // top two bits of length must be clear
return labels, false
}
// off can already (we're in a loop) be bigger than lenmsg
// this happens when a name isn't fully qualified
off += 1 + labelLen
if off > lenmsg {
return labels, false
}
labels++
begin = i + 1
default:
wasDot = false
}
}
return labels, true
} }
// IsSubDomain checks if child is indeed a child of the parent. If child and parent // IsSubDomain checks if child is indeed a child of the parent. If child and parent
@ -181,7 +243,7 @@ func IsSubDomain(parent, child string) bool {
// The checking is performed on the binary payload. // The checking is performed on the binary payload.
func IsMsg(buf []byte) error { func IsMsg(buf []byte) error {
// Header // Header
if len(buf) < 12 { if len(buf) < headerSize {
return errors.New("dns: bad message header") return errors.New("dns: bad message header")
} }
// Header: Opcode // Header: Opcode
@ -191,11 +253,18 @@ func IsMsg(buf []byte) error {
// IsFqdn checks if a domain name is fully qualified. // IsFqdn checks if a domain name is fully qualified.
func IsFqdn(s string) bool { func IsFqdn(s string) bool {
l := len(s) s2 := strings.TrimSuffix(s, ".")
if l == 0 { if s == s2 {
return false return false
} }
return s[l-1] == '.'
i := strings.LastIndexFunc(s2, func(r rune) bool {
return r != '\\'
})
// Test whether we have an even number of escape sequences before
// the dot or none.
return (len(s2)-i)%2 != 0
} }
// IsRRset checks if a set of RRs is a valid RRset as defined by RFC 2181. // IsRRset checks if a set of RRs is a valid RRset as defined by RFC 2181.
@ -244,12 +313,19 @@ func ReverseAddr(addr string) (arpa string, err error) {
if ip == nil { if ip == nil {
return "", &Error{err: "unrecognized address: " + addr} return "", &Error{err: "unrecognized address: " + addr}
} }
if ip.To4() != nil { if v4 := ip.To4(); v4 != nil {
return strconv.Itoa(int(ip[15])) + "." + strconv.Itoa(int(ip[14])) + "." + strconv.Itoa(int(ip[13])) + "." + buf := make([]byte, 0, net.IPv4len*4+len("in-addr.arpa."))
strconv.Itoa(int(ip[12])) + ".in-addr.arpa.", nil // Add it, in reverse, to the buffer
for i := len(v4) - 1; i >= 0; i-- {
buf = strconv.AppendInt(buf, int64(v4[i]), 10)
buf = append(buf, '.')
}
// Append "in-addr.arpa." and return (buf already has the final .)
buf = append(buf, "in-addr.arpa."...)
return string(buf), nil
} }
// Must be IPv6 // Must be IPv6
buf := make([]byte, 0, len(ip)*4+len("ip6.arpa.")) buf := make([]byte, 0, net.IPv6len*4+len("ip6.arpa."))
// Add it, in reverse, to the buffer // Add it, in reverse, to the buffer
for i := len(ip) - 1; i >= 0; i-- { for i := len(ip) - 1; i >= 0; i-- {
v := ip[i] v := ip[i]

71
vendor/github.com/miekg/dns/dns.go generated vendored
View file

@ -34,10 +34,30 @@ type RR interface {
// copy returns a copy of the RR // copy returns a copy of the RR
copy() RR copy() RR
// len returns the length (in octets) of the uncompressed RR in wire format.
len() int // len returns the length (in octets) of the compressed or uncompressed RR in wire format.
// pack packs an RR into wire format. //
pack([]byte, int, map[string]int, bool) (int, error) // If compression is nil, the uncompressed size will be returned, otherwise the compressed
// size will be returned and domain names will be added to the map for future compression.
len(off int, compression map[string]struct{}) int
// pack packs the records RDATA into wire format. The header will
// already have been packed into msg.
pack(msg []byte, off int, compression compressionMap, compress bool) (off1 int, err error)
// unpack unpacks an RR from wire format.
//
// This will only be called on a new and empty RR type with only the header populated. It
// will only be called if the record's RDATA is non-empty.
unpack(msg []byte, off int) (off1 int, err error)
// parse parses an RR from zone file format.
//
// This will only be called on a new and empty RR type with only the header populated.
parse(c *zlexer, origin, file string) *ParseError
// isDuplicate returns whether the two RRs are duplicates.
isDuplicate(r2 RR) bool
} }
// RR_Header is the header all DNS resource records share. // RR_Header is the header all DNS resource records share.
@ -55,16 +75,6 @@ func (h *RR_Header) Header() *RR_Header { return h }
// Just to implement the RR interface. // Just to implement 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 {
r := new(RR_Header)
r.Name = h.Name
r.Rrtype = h.Rrtype
r.Class = h.Class
r.Ttl = h.Ttl
r.Rdlength = h.Rdlength
return r
}
func (h *RR_Header) String() string { func (h *RR_Header) String() string {
var s string var s string
@ -80,28 +90,45 @@ func (h *RR_Header) String() string {
return s return s
} }
func (h *RR_Header) len() int { func (h *RR_Header) len(off int, compression map[string]struct{}) int {
l := len(h.Name) + 1 l := domainNameLen(h.Name, off, compression, true)
l += 10 // rrtype(2) + class(2) + ttl(4) + rdlength(2) l += 10 // rrtype(2) + class(2) + ttl(4) + rdlength(2)
return l return l
} }
func (h *RR_Header) pack(msg []byte, off int, compression compressionMap, compress bool) (off1 int, err error) {
// RR_Header has no RDATA to pack.
return off, nil
}
func (h *RR_Header) unpack(msg []byte, off int) (int, error) {
panic("dns: internal error: unpack should never be called on RR_Header")
}
func (h *RR_Header) parse(c *zlexer, origin, file string) *ParseError {
panic("dns: internal error: parse should never be called on RR_Header")
}
// ToRFC3597 converts a known RR to the unknown RR representation from RFC 3597. // ToRFC3597 converts a known RR to the unknown RR representation from RFC 3597.
func (rr *RFC3597) ToRFC3597(r RR) error { func (rr *RFC3597) ToRFC3597(r RR) error {
buf := make([]byte, r.len()*2) buf := make([]byte, Len(r)*2)
off, err := PackRR(r, buf, 0, nil, false) headerEnd, off, err := packRR(r, buf, 0, compressionMap{}, false)
if err != nil { if err != nil {
return err return err
} }
buf = buf[:off] buf = buf[:off]
if int(r.Header().Rdlength) > off {
return ErrBuf *rr = RFC3597{Hdr: *r.Header()}
rr.Hdr.Rdlength = uint16(off - headerEnd)
if noRdata(rr.Hdr) {
return nil
} }
rfc3597, _, err := unpackRFC3597(*r.Header(), buf, off-int(r.Header().Rdlength)) _, err = rr.unpack(buf, headerEnd)
if err != nil { if err != nil {
return err return err
} }
*rr = *rfc3597.(*RFC3597)
return nil return nil
} }

View file

@ -67,12 +67,10 @@ var AlgorithmToString = map[uint8]string{
PRIVATEOID: "PRIVATEOID", PRIVATEOID: "PRIVATEOID",
} }
// StringToAlgorithm is the reverse of AlgorithmToString.
var StringToAlgorithm = reverseInt8(AlgorithmToString)
// AlgorithmToHash is a map of algorithm crypto hash IDs to crypto.Hash's. // AlgorithmToHash is a map of algorithm crypto hash IDs to crypto.Hash's.
var AlgorithmToHash = map[uint8]crypto.Hash{ var AlgorithmToHash = map[uint8]crypto.Hash{
RSAMD5: crypto.MD5, // Deprecated in RFC 6725 RSAMD5: crypto.MD5, // Deprecated in RFC 6725
DSA: crypto.SHA1,
RSASHA1: crypto.SHA1, RSASHA1: crypto.SHA1,
RSASHA1NSEC3SHA1: crypto.SHA1, RSASHA1NSEC3SHA1: crypto.SHA1,
RSASHA256: crypto.SHA256, RSASHA256: crypto.SHA256,
@ -101,9 +99,6 @@ var HashToString = map[uint8]string{
SHA512: "SHA512", SHA512: "SHA512",
} }
// StringToHash is a map of names to hash IDs.
var StringToHash = reverseInt8(HashToString)
// DNSKEY flag values. // DNSKEY flag values.
const ( const (
SEP = 1 SEP = 1
@ -172,7 +167,7 @@ func (k *DNSKEY) KeyTag() uint16 {
keytag += int(v) << 8 keytag += int(v) << 8
} }
} }
keytag += (keytag >> 16) & 0xFFFF keytag += keytag >> 16 & 0xFFFF
keytag &= 0xFFFF keytag &= 0xFFFF
} }
return uint16(keytag) return uint16(keytag)
@ -239,7 +234,7 @@ func (k *DNSKEY) ToDS(h uint8) *DS {
// ToCDNSKEY converts a DNSKEY record to a CDNSKEY record. // ToCDNSKEY converts a DNSKEY record to a CDNSKEY record.
func (k *DNSKEY) ToCDNSKEY() *CDNSKEY { func (k *DNSKEY) ToCDNSKEY() *CDNSKEY {
c := &CDNSKEY{DNSKEY: *k} c := &CDNSKEY{DNSKEY: *k}
c.Hdr = *k.Hdr.copyHeader() c.Hdr = k.Hdr
c.Hdr.Rrtype = TypeCDNSKEY c.Hdr.Rrtype = TypeCDNSKEY
return c return c
} }
@ -247,7 +242,7 @@ func (k *DNSKEY) ToCDNSKEY() *CDNSKEY {
// ToCDS converts a DS record to a CDS record. // ToCDS converts a DS record to a CDS record.
func (d *DS) ToCDS() *CDS { func (d *DS) ToCDS() *CDS {
c := &CDS{DS: *d} c := &CDS{DS: *d}
c.Hdr = *d.Hdr.copyHeader() c.Hdr = d.Hdr
c.Hdr.Rrtype = TypeCDS c.Hdr.Rrtype = TypeCDS
return c return c
} }
@ -267,16 +262,17 @@ func (rr *RRSIG) Sign(k crypto.Signer, rrset []RR) error {
return ErrKey return ErrKey
} }
h0 := rrset[0].Header()
rr.Hdr.Rrtype = TypeRRSIG rr.Hdr.Rrtype = TypeRRSIG
rr.Hdr.Name = rrset[0].Header().Name rr.Hdr.Name = h0.Name
rr.Hdr.Class = rrset[0].Header().Class rr.Hdr.Class = h0.Class
if rr.OrigTtl == 0 { // If set don't override if rr.OrigTtl == 0 { // If set don't override
rr.OrigTtl = rrset[0].Header().Ttl rr.OrigTtl = h0.Ttl
} }
rr.TypeCovered = rrset[0].Header().Rrtype rr.TypeCovered = h0.Rrtype
rr.Labels = uint8(CountLabel(rrset[0].Header().Name)) rr.Labels = uint8(CountLabel(h0.Name))
if strings.HasPrefix(rrset[0].Header().Name, "*") { if strings.HasPrefix(h0.Name, "*") {
rr.Labels-- // wildcard, remove from label count rr.Labels-- // wildcard, remove from label count
} }
@ -400,7 +396,7 @@ func (rr *RRSIG) Verify(k *DNSKEY, rrset []RR) error {
if rr.Algorithm != k.Algorithm { if rr.Algorithm != k.Algorithm {
return ErrKey return ErrKey
} }
if strings.ToLower(rr.SignerName) != strings.ToLower(k.Hdr.Name) { if !strings.EqualFold(rr.SignerName, k.Hdr.Name) {
return ErrKey return ErrKey
} }
if k.Protocol != 3 { if k.Protocol != 3 {
@ -410,10 +406,7 @@ func (rr *RRSIG) Verify(k *DNSKEY, rrset []RR) error {
// IsRRset checked that we have at least one RR and that the RRs in // IsRRset checked that we have at least one RR and that the RRs in
// the set have consistent type, class, and name. Also check that type and // the set have consistent type, class, and name. Also check that type and
// class matches the RRSIG record. // class matches the RRSIG record.
if rrset[0].Header().Class != rr.Hdr.Class { if h0 := rrset[0].Header(); h0.Class != rr.Hdr.Class || h0.Rrtype != rr.TypeCovered {
return ErrRRset
}
if rrset[0].Header().Rrtype != rr.TypeCovered {
return ErrRRset return ErrRRset
} }
@ -511,8 +504,8 @@ func (rr *RRSIG) ValidityPeriod(t time.Time) bool {
} }
modi := (int64(rr.Inception) - utc) / year68 modi := (int64(rr.Inception) - utc) / year68
mode := (int64(rr.Expiration) - utc) / year68 mode := (int64(rr.Expiration) - utc) / year68
ti := int64(rr.Inception) + (modi * year68) ti := int64(rr.Inception) + modi*year68
te := int64(rr.Expiration) + (mode * year68) te := int64(rr.Expiration) + mode*year68
return ti <= utc && utc <= te return ti <= utc && utc <= te
} }
@ -532,6 +525,11 @@ func (k *DNSKEY) publicKeyRSA() *rsa.PublicKey {
return nil return nil
} }
if len(keybuf) < 1+1+64 {
// Exponent must be at least 1 byte and modulus at least 64
return nil
}
// RFC 2537/3110, section 2. RSA Public KEY Resource Records // RFC 2537/3110, section 2. RSA Public KEY Resource Records
// Length is in the 0th byte, unless its zero, then it // Length is in the 0th byte, unless its zero, then it
// it in bytes 1 and 2 and its a 16 bit number // it in bytes 1 and 2 and its a 16 bit number
@ -541,25 +539,36 @@ func (k *DNSKEY) publicKeyRSA() *rsa.PublicKey {
explen = uint16(keybuf[1])<<8 | uint16(keybuf[2]) explen = uint16(keybuf[1])<<8 | uint16(keybuf[2])
keyoff = 3 keyoff = 3
} }
if explen > 4 || explen == 0 || keybuf[keyoff] == 0 {
// Exponent larger than supported by the crypto package,
// empty, or contains prohibited leading zero.
return nil
}
modoff := keyoff + int(explen)
modlen := len(keybuf) - modoff
if modlen < 64 || modlen > 512 || keybuf[modoff] == 0 {
// Modulus is too small, large, or contains prohibited leading zero.
return nil
}
pubkey := new(rsa.PublicKey) pubkey := new(rsa.PublicKey)
pubkey.N = big.NewInt(0) var expo uint64
shift := uint64((explen - 1) * 8) for i := 0; i < int(explen); i++ {
expo := uint64(0) expo <<= 8
for i := int(explen - 1); i > 0; i-- { expo |= uint64(keybuf[keyoff+i])
expo += uint64(keybuf[keyoff+i]) << shift
shift -= 8
} }
// Remainder if expo > 1<<31-1 {
expo += uint64(keybuf[keyoff]) // Larger exponent than supported by the crypto package.
if expo > (2<<31)+1 {
// Larger expo than supported.
// println("dns: F5 primes (or larger) are not supported")
return nil return nil
} }
pubkey.E = int(expo) pubkey.E = int(expo)
pubkey.N.SetBytes(keybuf[keyoff+int(explen):]) pubkey.N = big.NewInt(0)
pubkey.N.SetBytes(keybuf[modoff:])
return pubkey return pubkey
} }
@ -641,15 +650,16 @@ func rawSignatureData(rrset []RR, s *RRSIG) (buf []byte, err error) {
wires := make(wireSlice, len(rrset)) wires := make(wireSlice, len(rrset))
for i, r := range rrset { for i, r := range rrset {
r1 := r.copy() r1 := r.copy()
r1.Header().Ttl = s.OrigTtl h := r1.Header()
labels := SplitDomainName(r1.Header().Name) h.Ttl = s.OrigTtl
labels := SplitDomainName(h.Name)
// 6.2. Canonical RR Form. (4) - wildcards // 6.2. Canonical RR Form. (4) - wildcards
if len(labels) > int(s.Labels) { if len(labels) > int(s.Labels) {
// Wildcard // Wildcard
r1.Header().Name = "*." + strings.Join(labels[len(labels)-int(s.Labels):], ".") + "." h.Name = "*." + strings.Join(labels[len(labels)-int(s.Labels):], ".") + "."
} }
// RFC 4034: 6.2. Canonical RR Form. (2) - domain name to lowercase // RFC 4034: 6.2. Canonical RR Form. (2) - domain name to lowercase
r1.Header().Name = strings.ToLower(r1.Header().Name) h.Name = strings.ToLower(h.Name)
// 6.2. Canonical RR Form. (3) - domain rdata to lowercase. // 6.2. Canonical RR Form. (3) - domain rdata to lowercase.
// 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,
@ -707,7 +717,7 @@ func rawSignatureData(rrset []RR, s *RRSIG) (buf []byte, err error) {
x.Target = strings.ToLower(x.Target) x.Target = strings.ToLower(x.Target)
} }
// 6.2. Canonical RR Form. (5) - origTTL // 6.2. Canonical RR Form. (5) - origTTL
wire := make([]byte, r1.len()+1) // +1 to be safe(r) wire := make([]byte, Len(r1)+1) // +1 to be safe(r)
off, err1 := PackRR(r1, wire, 0, nil, false) off, err1 := PackRR(r1, wire, 0, nil, false)
if err1 != nil { if err1 != nil {
return nil, err1 return nil, err1

View file

@ -1,7 +1,7 @@
package dns package dns
import ( import (
"bytes" "bufio"
"crypto" "crypto"
"crypto/dsa" "crypto/dsa"
"crypto/ecdsa" "crypto/ecdsa"
@ -181,22 +181,10 @@ func readPrivateKeyED25519(m map[string]string) (ed25519.PrivateKey, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
if len(p1) != 32 { if len(p1) != ed25519.SeedSize {
return nil, ErrPrivKey return nil, ErrPrivKey
} }
// RFC 8080 and Golang's x/crypto/ed25519 differ as to how the p = ed25519.NewKeyFromSeed(p1)
// private keys are represented. RFC 8080 specifies that private
// keys be stored solely as the seed value (p1 above) while the
// ed25519 package represents them as the seed value concatenated
// to the public key, which is derived from the seed value.
//
// ed25519.GenerateKey reads exactly 32 bytes from the passed in
// io.Reader and uses them as the seed. It also derives the
// public key and produces a compatible private key.
_, p, err = ed25519.GenerateKey(bytes.NewReader(p1))
if err != nil {
return nil, err
}
case "created", "publish", "activate": case "created", "publish", "activate":
/* not used in Go (yet) */ /* not used in Go (yet) */
} }
@ -207,23 +195,12 @@ func readPrivateKeyED25519(m map[string]string) (ed25519.PrivateKey, error) {
// 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) {
s, cancel := scanInit(r)
m := make(map[string]string) m := make(map[string]string)
c := make(chan lex) var k string
k := ""
defer func() { c := newKLexer(r)
cancel()
// zlexer can send up to two tokens, the next one and possibly 1 remainders. for l, ok := c.Next(); ok; l, ok = c.Next() {
// Do a non-blocking read.
_, ok := <-c
_, ok = <-c
if !ok {
// too bad
}
}()
// Start the lexer
go klexer(s, c)
for l := range c {
// It should alternate // It should alternate
switch l.value { switch l.value {
case zKey: case zKey:
@ -232,41 +209,111 @@ func parseKey(r io.Reader, file string) (map[string]string, error) {
if k == "" { if k == "" {
return nil, &ParseError{file, "no private key seen", l} return nil, &ParseError{file, "no private key seen", l}
} }
//println("Setting", strings.ToLower(k), "to", l.token, "b")
m[strings.ToLower(k)] = l.token m[strings.ToLower(k)] = l.token
k = "" k = ""
} }
} }
// Surface any read errors from r.
if err := c.Err(); err != nil {
return nil, &ParseError{file: file, err: err.Error()}
}
return m, nil return m, nil
} }
// klexer scans the sourcefile and returns tokens on the channel c. type klexer struct {
func klexer(s *scan, c chan lex) { br io.ByteReader
var l lex
str := "" // Hold the current read text readErr error
commt := false
key := true line int
x, err := s.tokenText() column int
defer close(c)
for err == nil { key bool
l.column = s.position.Column
l.line = s.position.Line eol bool // end-of-line
}
func newKLexer(r io.Reader) *klexer {
br, ok := r.(io.ByteReader)
if !ok {
br = bufio.NewReaderSize(r, 1024)
}
return &klexer{
br: br,
line: 1,
key: true,
}
}
func (kl *klexer) Err() error {
if kl.readErr == io.EOF {
return nil
}
return kl.readErr
}
// readByte returns the next byte from the input
func (kl *klexer) readByte() (byte, bool) {
if kl.readErr != nil {
return 0, false
}
c, err := kl.br.ReadByte()
if err != nil {
kl.readErr = err
return 0, false
}
// delay the newline handling until the next token is delivered,
// fixes off-by-one errors when reporting a parse error.
if kl.eol {
kl.line++
kl.column = 0
kl.eol = false
}
if c == '\n' {
kl.eol = true
} else {
kl.column++
}
return c, true
}
func (kl *klexer) Next() (lex, bool) {
var (
l lex
str strings.Builder
commt bool
)
for x, ok := kl.readByte(); ok; x, ok = kl.readByte() {
l.line, l.column = kl.line, kl.column
switch x { switch x {
case ':': case ':':
if commt { if commt || !kl.key {
break break
} }
l.token = str
if key { kl.key = false
l.value = zKey
c <- l
// Next token is a space, eat it // Next token is a space, eat it
s.tokenText() kl.readByte()
key = false
str = "" l.value = zKey
} else { l.token = str.String()
l.value = zValue return l, true
}
case ';': case ';':
commt = true commt = true
case '\n': case '\n':
@ -274,24 +321,32 @@ func klexer(s *scan, c chan lex) {
// Reset a comment // Reset a comment
commt = false commt = false
} }
kl.key = true
l.value = zValue l.value = zValue
l.token = str l.token = str.String()
c <- l return l, true
str = ""
commt = false
key = true
default: default:
if commt { if commt {
break break
} }
str += string(x)
str.WriteByte(x)
} }
x, err = s.tokenText()
} }
if len(str) > 0 {
if kl.readErr != nil && kl.readErr != io.EOF {
// Don't return any tokens after a read error occurs.
return lex{value: zEOF}, false
}
if str.Len() > 0 {
// Send remainder // Send remainder
l.token = str
l.value = zValue l.value = zValue
c <- l l.token = str.String()
return l, true
} }
return lex{value: zEOF}, false
} }

View file

@ -82,7 +82,7 @@ func (r *DNSKEY) PrivateKeyString(p crypto.PrivateKey) string {
"Public_value(y): " + pub + "\n" "Public_value(y): " + pub + "\n"
case ed25519.PrivateKey: case ed25519.PrivateKey:
private := toBase64(p[:32]) private := toBase64(p.Seed())
return format + return format +
"Algorithm: " + algorithm + "\n" + "Algorithm: " + algorithm + "\n" +
"PrivateKey: " + private + "\n" "PrivateKey: " + private + "\n"

111
vendor/github.com/miekg/dns/doc.go generated vendored
View file

@ -1,20 +1,20 @@
/* /*
Package dns implements a full featured interface to the Domain Name System. Package dns implements a full featured interface to the Domain Name System.
Server- and client-side programming is supported. Both server- and client-side programming is supported. The package allows
The package allows complete control over what is sent out to the DNS. The package complete control over what is sent out to the DNS. The API follows the
API follows the less-is-more principle, by presenting a small, clean interface. less-is-more principle, by presenting a small, clean interface.
The package dns supports (asynchronous) querying/replying, incoming/outgoing zone transfers, It supports (asynchronous) querying/replying, incoming/outgoing zone transfers,
TSIG, EDNS0, dynamic updates, notifies and DNSSEC validation/signing. TSIG, EDNS0, dynamic updates, notifies and DNSSEC validation/signing.
Note that domain names MUST be fully qualified, before sending them, unqualified
Note that domain names MUST be fully qualified before sending them, unqualified
names in a message will result in a packing failure. names in a message will result in a packing failure.
Resource records are native types. They are not stored in wire format. Resource records are native types. They are not stored in wire format. Basic
Basic usage pattern for creating a new resource record: usage pattern for creating a new resource record:
r := new(dns.MX) r := new(dns.MX)
r.Hdr = dns.RR_Header{Name: "miek.nl.", Rrtype: dns.TypeMX, r.Hdr = dns.RR_Header{Name: "miek.nl.", Rrtype: dns.TypeMX, Class: dns.ClassINET, Ttl: 3600}
Class: dns.ClassINET, Ttl: 3600}
r.Preference = 10 r.Preference = 10
r.Mx = "mx.miek.nl." r.Mx = "mx.miek.nl."
@ -30,8 +30,8 @@ Or even:
mx, err := dns.NewRR("$ORIGIN nl.\nmiek 1H IN MX 10 mx.miek") mx, err := dns.NewRR("$ORIGIN nl.\nmiek 1H IN MX 10 mx.miek")
In the DNS messages are exchanged, these messages contain resource In the DNS messages are exchanged, these messages contain resource records
records (sets). Use pattern for creating a message: (sets). Use pattern for creating a message:
m := new(dns.Msg) m := new(dns.Msg)
m.SetQuestion("miek.nl.", dns.TypeMX) m.SetQuestion("miek.nl.", dns.TypeMX)
@ -40,8 +40,8 @@ Or when not certain if the domain name is fully qualified:
m.SetQuestion(dns.Fqdn("miek.nl"), dns.TypeMX) m.SetQuestion(dns.Fqdn("miek.nl"), dns.TypeMX)
The message m is now a message with the question section set to ask The message m is now a message with the question section set to ask the MX
the MX records for the miek.nl. zone. records for the miek.nl. zone.
The following is slightly more verbose, but more flexible: The following is slightly more verbose, but more flexible:
@ -51,9 +51,8 @@ The following is slightly more verbose, but more flexible:
m1.Question = make([]dns.Question, 1) m1.Question = make([]dns.Question, 1)
m1.Question[0] = dns.Question{"miek.nl.", dns.TypeMX, dns.ClassINET} m1.Question[0] = dns.Question{"miek.nl.", dns.TypeMX, dns.ClassINET}
After creating a message it can be sent. After creating a message it can be sent. Basic use pattern for synchronous
Basic use pattern for synchronous querying the DNS at a querying the DNS at a server configured on 127.0.0.1 and port 53:
server configured on 127.0.0.1 and port 53:
c := new(dns.Client) c := new(dns.Client)
in, rtt, err := c.Exchange(m1, "127.0.0.1:53") in, rtt, err := c.Exchange(m1, "127.0.0.1:53")
@ -73,11 +72,11 @@ and port to use for the connection:
Port: 12345, Port: 12345,
Zone: "", Zone: "",
} }
d := net.Dialer{ c.Dialer := &net.Dialer{
Timeout: 200 * time.Millisecond, Timeout: 200 * time.Millisecond,
LocalAddr: &laddr, LocalAddr: &laddr,
} }
in, rtt, err := c.ExchangeWithDialer(&d, m1, "8.8.8.8:53") in, rtt, err := c.Exchange(m1, "8.8.8.8:53")
If these "advanced" features are not needed, a simple UDP query can be sent, If these "advanced" features are not needed, a simple UDP query can be sent,
with: with:
@ -99,25 +98,24 @@ the Answer section:
Domain Name and TXT Character String Representations Domain Name and TXT Character String Representations
Both domain names and TXT character strings are converted to presentation Both domain names and TXT character strings are converted to presentation form
form both when unpacked and when converted to strings. both when unpacked and when converted to strings.
For TXT character strings, tabs, carriage returns and line feeds will be For TXT character strings, tabs, carriage returns and line feeds will be
converted to \t, \r and \n respectively. Back slashes and quotations marks converted to \t, \r and \n respectively. Back slashes and quotations marks will
will be escaped. Bytes below 32 and above 127 will be converted to \DDD be escaped. Bytes below 32 and above 127 will be converted to \DDD form.
form.
For domain names, in addition to the above rules brackets, periods, For domain names, in addition to the above rules brackets, periods, spaces,
spaces, semicolons and the at symbol are escaped. semicolons and the at symbol are escaped.
DNSSEC DNSSEC
DNSSEC (DNS Security Extension) adds a layer of security to the DNS. It DNSSEC (DNS Security Extension) adds a layer of security to the DNS. It uses
uses public key cryptography to sign resource records. The public key cryptography to sign resource records. The public keys are stored in
public keys are stored in DNSKEY records and the signatures in RRSIG records. DNSKEY records and the signatures in RRSIG records.
Requesting DNSSEC information for a zone is done by adding the DO (DNSSEC OK) bit Requesting DNSSEC information for a zone is done by adding the DO (DNSSEC OK)
to a request. bit to a request.
m := new(dns.Msg) m := new(dns.Msg)
m.SetEdns0(4096, true) m.SetEdns0(4096, true)
@ -126,9 +124,9 @@ Signature generation, signature verification and key generation are all supporte
DYNAMIC UPDATES DYNAMIC UPDATES
Dynamic updates reuses the DNS message format, but renames three of Dynamic updates reuses the DNS message format, but renames three of the
the sections. Question is Zone, Answer is Prerequisite, Authority is sections. Question is Zone, Answer is Prerequisite, Authority is Update, only
Update, only the Additional is not renamed. See RFC 2136 for the gory details. 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 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 certain resource records or names in a zone to specify if resource records
@ -145,10 +143,9 @@ DNS function shows which functions exist to specify the prerequisites.
NONE rrset empty RRset does not exist dns.RRsetNotUsed NONE rrset empty RRset does not exist dns.RRsetNotUsed
zone rrset rr RRset exists (value dep) dns.Used zone rrset rr RRset exists (value dep) dns.Used
The prerequisite section can also be left empty. The prerequisite section can also be left empty. If you have decided on the
If you have decided on the prerequisites you can tell what RRs should prerequisites you can tell what RRs should be added or deleted. The next table
be added or deleted. The next table shows the options you have and shows the options you have and what functions to call.
what functions to call.
3.4.2.6 - Table Of Metavalues Used In Update Section 3.4.2.6 - Table Of Metavalues Used In Update Section
@ -181,10 +178,10 @@ changes to the RRset after calling SetTsig() the signature will be incorrect.
... ...
// When sending the TSIG RR is calculated and filled in before sending // 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 When requesting an zone transfer (almost all TSIG usage is when requesting zone
TSIG, this is the basic use pattern. In this example we request an AXFR for transfers), with TSIG, this is the basic use pattern. In this example we
miek.nl. with TSIG key named "axfr." and secret "so6ZGir4GPAqINNh9U5c3A==" request an AXFR for miek.nl. with TSIG key named "axfr." and secret
and using the server 176.58.119.54: "so6ZGir4GPAqINNh9U5c3A==" and using the server 176.58.119.54:
t := new(dns.Transfer) t := new(dns.Transfer)
m := new(dns.Msg) m := new(dns.Msg)
@ -194,8 +191,8 @@ and using the server 176.58.119.54:
c, err := t.In(m, "176.58.119.54:53") c, err := t.In(m, "176.58.119.54:53")
for r := range c { ... } for r := range c { ... }
You can now read the records from the transfer as they come in. Each envelope is checked with TSIG. You can now read the records from the transfer as they come in. Each envelope
If something is not correct an error is returned. 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. Basic use pattern validating and replying to a message that has TSIG set.
@ -220,29 +217,30 @@ Basic use pattern validating and replying to a message that has TSIG set.
PRIVATE RRS PRIVATE RRS
RFC 6895 sets aside a range of type codes for private use. This range RFC 6895 sets aside a range of type codes for private use. This range is 65,280
is 65,280 - 65,534 (0xFF00 - 0xFFFE). When experimenting with new Resource Records these - 65,534 (0xFF00 - 0xFFFE). When experimenting with new Resource Records these
can be used, before requesting an official type code from IANA. can be used, before requesting an official type code from IANA.
see http://miek.nl/2014/September/21/idn-and-private-rr-in-go-dns/ for more See https://miek.nl/2014/September/21/idn-and-private-rr-in-go-dns/ for more
information. information.
EDNS0 EDNS0
EDNS0 is an extension mechanism for the DNS defined in RFC 2671 and updated EDNS0 is an extension mechanism for the DNS defined in RFC 2671 and updated by
by RFC 6891. It defines an new RR type, the OPT RR, which is then completely RFC 6891. It defines an new RR type, the OPT RR, which is then completely
abused. abused.
Basic use pattern for creating an (empty) OPT RR: Basic use pattern for creating an (empty) OPT RR:
o := new(dns.OPT) o := new(dns.OPT)
o.Hdr.Name = "." // MUST be the root zone, per definition. o.Hdr.Name = "." // MUST be the root zone, per definition.
o.Hdr.Rrtype = dns.TypeOPT o.Hdr.Rrtype = dns.TypeOPT
The rdata of an OPT RR consists out of a slice of EDNS0 (RFC 6891) The rdata of an OPT RR consists out of a slice of EDNS0 (RFC 6891) interfaces.
interfaces. Currently only a few have been standardized: EDNS0_NSID Currently only a few have been standardized: EDNS0_NSID (RFC 5001) and
(RFC 5001) and EDNS0_SUBNET (draft-vandergaast-edns-client-subnet-02). Note EDNS0_SUBNET (draft-vandergaast-edns-client-subnet-02). Note that these options
that these options may be combined in an OPT RR. may be combined in an OPT RR. Basic use pattern for a server to check if (and
Basic use pattern for a server to check if (and which) options are set: which) options are set:
// o is a dns.OPT // o is a dns.OPT
for _, s := range o.Option { for _, s := range o.Option {
@ -262,10 +260,9 @@ From RFC 2931:
... protection for glue records, DNS requests, protection for message headers ... protection for glue records, DNS requests, protection for message headers
on requests and responses, and protection of the overall integrity of a response. 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 It works like TSIG, except that SIG(0) uses public key cryptography, instead of
secret approach in TSIG. the shared secret approach in TSIG. Supported algorithms: DSA, ECDSAP256SHA256,
Supported algorithms: DSA, ECDSAP256SHA256, ECDSAP384SHA384, RSASHA1, RSASHA256 and ECDSAP384SHA384, RSASHA1, RSASHA256 and RSASHA512.
RSASHA512.
Signing subsequent messages in multi-message sessions is not implemented. Signing subsequent messages in multi-message sessions is not implemented.
*/ */

38
vendor/github.com/miekg/dns/duplicate.go generated vendored Normal file
View file

@ -0,0 +1,38 @@
package dns
//go:generate go run duplicate_generate.go
// IsDuplicate checks of r1 and r2 are duplicates of each other, excluding the TTL.
// So this means the header data is equal *and* the RDATA is the same. Return true
// is so, otherwise false.
// It's is a protocol violation to have identical RRs in a message.
func IsDuplicate(r1, r2 RR) bool {
// Check whether the record header is identical.
if !r1.Header().isDuplicate(r2.Header()) {
return false
}
// Check whether the RDATA is identical.
return r1.isDuplicate(r2)
}
func (r1 *RR_Header) isDuplicate(_r2 RR) bool {
r2, ok := _r2.(*RR_Header)
if !ok {
return false
}
if r1.Class != r2.Class {
return false
}
if r1.Rrtype != r2.Rrtype {
return false
}
if !isDulicateName(r1.Name, r2.Name) {
return false
}
// ignore TTL
return true
}
// isDulicateName checks if the domain names s1 and s2 are equal.
func isDulicateName(s1, s2 string) bool { return equal(s1, s2) }

144
vendor/github.com/miekg/dns/duplicate_generate.go generated vendored Normal file
View file

@ -0,0 +1,144 @@
//+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"
)
var packageHdr = `
// Code generated by "go run duplicate_generate.go"; DO NOT EDIT.
package dns
`
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 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" || name == "OPT" {
continue
}
namedTypes = append(namedTypes, o.Name())
}
b := &bytes.Buffer{}
b.WriteString(packageHdr)
// Generate the duplicate check for each type.
fmt.Fprint(b, "// isDuplicate() functions\n\n")
for _, name := range namedTypes {
o := scope.Lookup(name)
st, isEmbedded := getTypeStruct(o.Type(), scope)
if isEmbedded {
continue
}
fmt.Fprintf(b, "func (r1 *%s) isDuplicate(_r2 RR) bool {\n", name)
fmt.Fprintf(b, "r2, ok := _r2.(*%s)\n", name)
fmt.Fprint(b, "if !ok { return false }\n")
fmt.Fprint(b, "_ = r2\n")
for i := 1; i < st.NumFields(); i++ {
field := st.Field(i).Name()
o2 := func(s string) { fmt.Fprintf(b, s+"\n", field, field) }
o3 := func(s string) { fmt.Fprintf(b, s+"\n", field, field, field) }
// For some reason, a and aaaa don't pop up as *types.Slice here (mostly like because the are
// *indirectly* defined as a slice in the net package).
if _, ok := st.Field(i).Type().(*types.Slice); ok {
o2("if len(r1.%s) != len(r2.%s) {\nreturn false\n}")
if st.Tag(i) == `dns:"cdomain-name"` || st.Tag(i) == `dns:"domain-name"` {
o3(`for i := 0; i < len(r1.%s); i++ {
if !isDulicateName(r1.%s[i], r2.%s[i]) {
return false
}
}`)
continue
}
o3(`for i := 0; i < len(r1.%s); i++ {
if r1.%s[i] != r2.%s[i] {
return false
}
}`)
continue
}
switch st.Tag(i) {
case `dns:"-"`:
// ignored
case `dns:"a"`, `dns:"aaaa"`:
o2("if !r1.%s.Equal(r2.%s) {\nreturn false\n}")
case `dns:"cdomain-name"`, `dns:"domain-name"`:
o2("if !isDulicateName(r1.%s, r2.%s) {\nreturn false\n}")
default:
o2("if r1.%s != r2.%s {\nreturn false\n}")
}
}
fmt.Fprintf(b, "return true\n}\n\n")
}
// gofmt
res, err := format.Source(b.Bytes())
if err != nil {
b.WriteTo(os.Stderr)
log.Fatal(err)
}
// write result
f, err := os.Create("zduplicate.go")
fatalIfErr(err)
defer f.Close()
f.Write(res)
}
func fatalIfErr(err error) {
if err != nil {
log.Fatal(err)
}
}

82
vendor/github.com/miekg/dns/edns.go generated vendored
View file

@ -78,8 +78,8 @@ func (rr *OPT) String() string {
return s return s
} }
func (rr *OPT) len() int { func (rr *OPT) len(off int, compression map[string]struct{}) int {
l := rr.Hdr.len() l := rr.Hdr.len(off, compression)
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. l += 4 // Account for 2-byte option code and 2-byte option length.
lo, _ := rr.Option[i].pack() lo, _ := rr.Option[i].pack()
@ -88,26 +88,34 @@ func (rr *OPT) len() int {
return l return l
} }
func (rr *OPT) parse(c *zlexer, origin, file string) *ParseError {
panic("dns: internal error: parse should never be called on OPT")
}
func (r1 *OPT) isDuplicate(r2 RR) bool { return false }
// 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.
func (rr *OPT) Version() uint8 { func (rr *OPT) Version() uint8 {
return uint8((rr.Hdr.Ttl & 0x00FF0000) >> 16) return uint8(rr.Hdr.Ttl & 0x00FF0000 >> 16)
} }
// SetVersion sets the version of EDNS. This is usually zero. // SetVersion sets the version of EDNS. This is usually zero.
func (rr *OPT) SetVersion(v uint8) { func (rr *OPT) SetVersion(v uint8) {
rr.Hdr.Ttl = rr.Hdr.Ttl&0xFF00FFFF | (uint32(v) << 16) rr.Hdr.Ttl = rr.Hdr.Ttl&0xFF00FFFF | uint32(v)<<16
} }
// ExtendedRcode returns the EDNS extended RCODE field (the upper 8 bits of the TTL). // ExtendedRcode returns the EDNS extended RCODE field (the upper 8 bits of the TTL).
func (rr *OPT) ExtendedRcode() int { func (rr *OPT) ExtendedRcode() int {
return int((rr.Hdr.Ttl & 0xFF000000) >> 24) return int(rr.Hdr.Ttl&0xFF000000>>24) << 4
} }
// SetExtendedRcode sets the EDNS extended RCODE field. // SetExtendedRcode sets the EDNS extended RCODE field.
func (rr *OPT) SetExtendedRcode(v uint8) { //
rr.Hdr.Ttl = rr.Hdr.Ttl&0x00FFFFFF | (uint32(v) << 24) // If the RCODE is not an extended RCODE, will reset the extended RCODE field to 0.
func (rr *OPT) SetExtendedRcode(v uint16) {
rr.Hdr.Ttl = rr.Hdr.Ttl&0x00FFFFFF | uint32(v>>4)<<24
} }
// UDPSize returns the UDP buffer size. // UDPSize returns the UDP buffer size.
@ -151,6 +159,8 @@ type EDNS0 interface {
unpack([]byte) error unpack([]byte) error
// String returns the string representation of the option. // String returns the string representation of the option.
String() string String() string
// copy returns a deep-copy of the option.
copy() EDNS0
} }
// EDNS0_NSID option is used to retrieve a nameserver // EDNS0_NSID option is used to retrieve a nameserver
@ -181,7 +191,8 @@ func (e *EDNS0_NSID) pack() ([]byte, error) {
// Option implements the EDNS0 interface. // Option implements the EDNS0 interface.
func (e *EDNS0_NSID) Option() uint16 { return EDNS0NSID } // Option returns the option code. func (e *EDNS0_NSID) Option() uint16 { return EDNS0NSID } // Option returns the option code.
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 e.Nsid }
func (e *EDNS0_NSID) copy() EDNS0 { return &EDNS0_NSID{e.Code, e.Nsid} }
// EDNS0_SUBNET is the subnet option that 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. See RFC 7871. It can then give back a different // an idea of where the client lives. See RFC 7871. It can then give back a different
@ -271,22 +282,16 @@ func (e *EDNS0_SUBNET) unpack(b []byte) error {
if e.SourceNetmask > net.IPv4len*8 || e.SourceScope > net.IPv4len*8 { if e.SourceNetmask > net.IPv4len*8 || e.SourceScope > net.IPv4len*8 {
return errors.New("dns: bad netmask") return errors.New("dns: bad netmask")
} }
addr := make([]byte, net.IPv4len) addr := make(net.IP, net.IPv4len)
for i := 0; i < net.IPv4len && 4+i < len(b); i++ { copy(addr, b[4:])
addr[i] = b[4+i] e.Address = addr.To16()
}
e.Address = net.IPv4(addr[0], addr[1], addr[2], addr[3])
case 2: case 2:
if e.SourceNetmask > net.IPv6len*8 || e.SourceScope > net.IPv6len*8 { if e.SourceNetmask > net.IPv6len*8 || e.SourceScope > net.IPv6len*8 {
return errors.New("dns: bad netmask") return errors.New("dns: bad netmask")
} }
addr := make([]byte, net.IPv6len) addr := make(net.IP, net.IPv6len)
for i := 0; i < net.IPv6len && 4+i < len(b); i++ { copy(addr, b[4:])
addr[i] = b[4+i] e.Address = addr
}
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[11], addr[12], addr[13], addr[14], addr[15]}
default: default:
return errors.New("dns: bad address family") return errors.New("dns: bad address family")
} }
@ -305,6 +310,16 @@ func (e *EDNS0_SUBNET) String() (s string) {
return return
} }
func (e *EDNS0_SUBNET) copy() EDNS0 {
return &EDNS0_SUBNET{
e.Code,
e.Family,
e.SourceNetmask,
e.SourceScope,
e.Address,
}
}
// The EDNS0_COOKIE option is used to add a DNS Cookie to a message. // The EDNS0_COOKIE option is used to add a DNS Cookie to a message.
// //
// o := new(dns.OPT) // o := new(dns.OPT)
@ -340,6 +355,7 @@ func (e *EDNS0_COOKIE) pack() ([]byte, error) {
func (e *EDNS0_COOKIE) Option() uint16 { return EDNS0COOKIE } func (e *EDNS0_COOKIE) Option() uint16 { return EDNS0COOKIE }
func (e *EDNS0_COOKIE) unpack(b []byte) error { e.Cookie = hex.EncodeToString(b); return nil } func (e *EDNS0_COOKIE) unpack(b []byte) error { e.Cookie = hex.EncodeToString(b); return nil }
func (e *EDNS0_COOKIE) String() string { return e.Cookie } func (e *EDNS0_COOKIE) String() string { return e.Cookie }
func (e *EDNS0_COOKIE) copy() EDNS0 { return &EDNS0_COOKIE{e.Code, e.Cookie} }
// The EDNS0_UL (Update Lease) (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
@ -361,6 +377,7 @@ type EDNS0_UL struct {
// Option implements the EDNS0 interface. // Option implements the EDNS0 interface.
func (e *EDNS0_UL) Option() uint16 { return EDNS0UL } func (e *EDNS0_UL) Option() uint16 { return EDNS0UL }
func (e *EDNS0_UL) String() string { return strconv.FormatUint(uint64(e.Lease), 10) } func (e *EDNS0_UL) String() string { return strconv.FormatUint(uint64(e.Lease), 10) }
func (e *EDNS0_UL) copy() EDNS0 { return &EDNS0_UL{e.Code, e.Lease} }
// Copied: http://golang.org/src/pkg/net/dnsmsg.go // Copied: http://golang.org/src/pkg/net/dnsmsg.go
func (e *EDNS0_UL) pack() ([]byte, error) { func (e *EDNS0_UL) pack() ([]byte, error) {
@ -415,10 +432,13 @@ func (e *EDNS0_LLQ) unpack(b []byte) error {
func (e *EDNS0_LLQ) String() string { func (e *EDNS0_LLQ) String() string {
s := strconv.FormatUint(uint64(e.Version), 10) + " " + strconv.FormatUint(uint64(e.Opcode), 10) + s := strconv.FormatUint(uint64(e.Version), 10) + " " + strconv.FormatUint(uint64(e.Opcode), 10) +
" " + strconv.FormatUint(uint64(e.Error), 10) + " " + strconv.FormatUint(uint64(e.Id), 10) + " " + strconv.FormatUint(uint64(e.Error), 10) + " " + strconv.FormatUint(e.Id, 10) +
" " + strconv.FormatUint(uint64(e.LeaseLife), 10) " " + strconv.FormatUint(uint64(e.LeaseLife), 10)
return s return s
} }
func (e *EDNS0_LLQ) copy() EDNS0 {
return &EDNS0_LLQ{e.Code, e.Version, e.Opcode, e.Error, e.Id, e.LeaseLife}
}
// EDNS0_DUA implements the EDNS0 "DNSSEC Algorithm Understood" option. See RFC 6975. // EDNS0_DUA implements the EDNS0 "DNSSEC Algorithm Understood" option. See RFC 6975.
type EDNS0_DAU struct { type EDNS0_DAU struct {
@ -442,6 +462,7 @@ func (e *EDNS0_DAU) String() string {
} }
return s return s
} }
func (e *EDNS0_DAU) copy() EDNS0 { return &EDNS0_DAU{e.Code, e.AlgCode} }
// EDNS0_DHU implements the EDNS0 "DS Hash Understood" option. See RFC 6975. // EDNS0_DHU implements the EDNS0 "DS Hash Understood" option. See RFC 6975.
type EDNS0_DHU struct { type EDNS0_DHU struct {
@ -465,6 +486,7 @@ func (e *EDNS0_DHU) String() string {
} }
return s return s
} }
func (e *EDNS0_DHU) copy() EDNS0 { return &EDNS0_DHU{e.Code, e.AlgCode} }
// EDNS0_N3U implements the EDNS0 "NSEC3 Hash Understood" option. See RFC 6975. // EDNS0_N3U implements the EDNS0 "NSEC3 Hash Understood" option. See RFC 6975.
type EDNS0_N3U struct { type EDNS0_N3U struct {
@ -489,6 +511,7 @@ func (e *EDNS0_N3U) String() string {
} }
return s return s
} }
func (e *EDNS0_N3U) copy() EDNS0 { return &EDNS0_N3U{e.Code, e.AlgCode} }
// EDNS0_EXPIRE implementes the EDNS0 option as described in RFC 7314. // EDNS0_EXPIRE implementes the EDNS0 option as described in RFC 7314.
type EDNS0_EXPIRE struct { type EDNS0_EXPIRE struct {
@ -499,13 +522,11 @@ type EDNS0_EXPIRE struct {
// Option implements the EDNS0 interface. // Option implements the EDNS0 interface.
func (e *EDNS0_EXPIRE) Option() uint16 { return EDNS0EXPIRE } func (e *EDNS0_EXPIRE) Option() uint16 { return EDNS0EXPIRE }
func (e *EDNS0_EXPIRE) String() string { return strconv.FormatUint(uint64(e.Expire), 10) } func (e *EDNS0_EXPIRE) String() string { return strconv.FormatUint(uint64(e.Expire), 10) }
func (e *EDNS0_EXPIRE) copy() EDNS0 { return &EDNS0_EXPIRE{e.Code, e.Expire} }
func (e *EDNS0_EXPIRE) pack() ([]byte, error) { func (e *EDNS0_EXPIRE) pack() ([]byte, error) {
b := make([]byte, 4) b := make([]byte, 4)
b[0] = byte(e.Expire >> 24) binary.BigEndian.PutUint32(b, e.Expire)
b[1] = byte(e.Expire >> 16)
b[2] = byte(e.Expire >> 8)
b[3] = byte(e.Expire)
return b, nil return b, nil
} }
@ -540,6 +561,11 @@ func (e *EDNS0_LOCAL) Option() uint16 { return e.Code }
func (e *EDNS0_LOCAL) String() string { func (e *EDNS0_LOCAL) String() string {
return strconv.FormatInt(int64(e.Code), 10) + ":0x" + hex.EncodeToString(e.Data) return strconv.FormatInt(int64(e.Code), 10) + ":0x" + hex.EncodeToString(e.Data)
} }
func (e *EDNS0_LOCAL) copy() EDNS0 {
b := make([]byte, len(e.Data))
copy(b, e.Data)
return &EDNS0_LOCAL{e.Code, b}
}
func (e *EDNS0_LOCAL) pack() ([]byte, error) { func (e *EDNS0_LOCAL) pack() ([]byte, error) {
b := make([]byte, len(e.Data)) b := make([]byte, len(e.Data))
@ -612,6 +638,7 @@ func (e *EDNS0_TCP_KEEPALIVE) String() (s string) {
} }
return return
} }
func (e *EDNS0_TCP_KEEPALIVE) copy() EDNS0 { return &EDNS0_TCP_KEEPALIVE{e.Code, e.Length, e.Timeout} }
// EDNS0_PADDING option is used to add padding to a request/response. The default // EDNS0_PADDING option is used to add padding to a request/response. The default
// value of padding SHOULD be 0x0 but other values MAY be used, for instance if // value of padding SHOULD be 0x0 but other values MAY be used, for instance if
@ -625,3 +652,8 @@ func (e *EDNS0_PADDING) Option() uint16 { return EDNS0PADDING }
func (e *EDNS0_PADDING) pack() ([]byte, error) { return e.Padding, nil } func (e *EDNS0_PADDING) pack() ([]byte, error) { return e.Padding, nil }
func (e *EDNS0_PADDING) unpack(b []byte) error { e.Padding = b; return nil } func (e *EDNS0_PADDING) unpack(b []byte) error { e.Padding = b; return nil }
func (e *EDNS0_PADDING) String() string { return fmt.Sprintf("%0X", e.Padding) } func (e *EDNS0_PADDING) String() string { return fmt.Sprintf("%0X", e.Padding) }
func (e *EDNS0_PADDING) copy() EDNS0 {
b := make([]byte, len(e.Padding))
copy(b, e.Padding)
return &EDNS0_PADDING{b}
}

View file

@ -20,7 +20,7 @@ func Field(r RR, i int) string {
return "" return ""
} }
d := reflect.ValueOf(r).Elem().Field(i) d := reflect.ValueOf(r).Elem().Field(i)
switch k := d.Kind(); k { switch d.Kind() {
case reflect.String: case reflect.String:
return d.String() return d.String()
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:

View file

@ -2,8 +2,8 @@ package dns
import ( import (
"bytes" "bytes"
"errors"
"fmt" "fmt"
"io"
"strconv" "strconv"
"strings" "strings"
) )
@ -18,142 +18,225 @@ import (
// * rhs (rdata) // * rhs (rdata)
// But we are lazy here, only the range is parsed *all* occurrences // 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 func (zp *ZoneParser) generate(l lex) (RR, bool) {
// "no error". token := l.token
func generate(l lex, c chan lex, t chan *Token, o string) string {
step := 1 step := 1
if i := strings.IndexAny(l.token, "/"); i != -1 { if i := strings.IndexByte(token, '/'); i >= 0 {
if i+1 == len(l.token) { if i+1 == len(token) {
return "bad step in $GENERATE range" return zp.setParseError("bad step in $GENERATE range", l)
} }
if s, err := strconv.Atoi(l.token[i+1:]); err == nil {
if s < 0 { s, err := strconv.Atoi(token[i+1:])
return "bad step in $GENERATE range" if err != nil || s <= 0 {
return zp.setParseError("bad step in $GENERATE range", l)
} }
step = s step = s
} else { token = token[:i]
return "bad step in $GENERATE range"
} }
l.token = l.token[:i]
} sx := strings.SplitN(token, "-", 2)
sx := strings.SplitN(l.token, "-", 2)
if len(sx) != 2 { if len(sx) != 2 {
return "bad start-stop in $GENERATE range" return zp.setParseError("bad start-stop in $GENERATE range", l)
} }
start, err := strconv.Atoi(sx[0]) start, err := strconv.Atoi(sx[0])
if err != nil { if err != nil {
return "bad start in $GENERATE range" return zp.setParseError("bad start in $GENERATE range", l)
} }
end, err := strconv.Atoi(sx[1]) end, err := strconv.Atoi(sx[1])
if err != nil { if err != nil {
return "bad stop in $GENERATE range" return zp.setParseError("bad stop in $GENERATE range", l)
} }
if end < 0 || start < 0 || end < start { if end < 0 || start < 0 || end < start {
return "bad range in $GENERATE range" return zp.setParseError("bad range in $GENERATE range", l)
} }
<-c // _BLANK zp.c.Next() // _BLANK
// Create a complete new string, which we then parse again. // Create a complete new string, which we then parse again.
s := "" var s string
BuildRR: for l, ok := zp.c.Next(); ok; l, ok = zp.c.Next() {
l = <-c if l.err {
if l.value != zNewline && l.value != zEOF { return zp.setParseError("bad data in $GENERATE directive", l)
s += l.token }
goto BuildRR if l.value == zNewline {
break
} }
for i := start; i <= end; i += step {
var (
escape bool
dom bytes.Buffer
mod string
err error
offset int
)
for j := 0; j < len(s); j++ { // No 'range' because we need to jump around s += l.token
switch s[j] { }
r := &generateReader{
s: s,
cur: start,
start: start,
end: end,
step: step,
file: zp.file,
lex: &l,
}
zp.sub = NewZoneParser(r, zp.origin, zp.file)
zp.sub.includeDepth, zp.sub.includeAllowed = zp.includeDepth, zp.includeAllowed
zp.sub.SetDefaultTTL(defaultTtl)
return zp.subNext()
}
type generateReader struct {
s string
si int
cur int
start int
end int
step int
mod bytes.Buffer
escape bool
eof bool
file string
lex *lex
}
func (r *generateReader) parseError(msg string, end int) *ParseError {
r.eof = true // Make errors sticky.
l := *r.lex
l.token = r.s[r.si-1 : end]
l.column += r.si // l.column starts one zBLANK before r.s
return &ParseError{r.file, msg, l}
}
func (r *generateReader) Read(p []byte) (int, error) {
// NewZLexer, through NewZoneParser, should use ReadByte and
// not end up here.
panic("not implemented")
}
func (r *generateReader) ReadByte() (byte, error) {
if r.eof {
return 0, io.EOF
}
if r.mod.Len() > 0 {
return r.mod.ReadByte()
}
if r.si >= len(r.s) {
r.si = 0
r.cur += r.step
r.eof = r.cur > r.end || r.cur < 0
return '\n', nil
}
si := r.si
r.si++
switch r.s[si] {
case '\\': case '\\':
if escape { if r.escape {
dom.WriteByte('\\') r.escape = false
escape = false return '\\', nil
continue
} }
escape = true
r.escape = true
return r.ReadByte()
case '$': case '$':
mod = "%d" if r.escape {
offset = 0 r.escape = false
if escape { return '$', nil
dom.WriteByte('$')
escape = false
continue
} }
escape = false
if j+1 >= len(s) { // End of the string mod := "%d"
dom.WriteString(fmt.Sprintf(mod, i+offset))
continue if si >= len(r.s)-1 {
} else { // End of the string
if s[j+1] == '$' { fmt.Fprintf(&r.mod, mod, r.cur)
dom.WriteByte('$') return r.mod.ReadByte()
j++
continue
} }
if r.s[si+1] == '$' {
r.si++
return '$', nil
} }
var offset int
// Search for { and } // Search for { and }
if s[j+1] == '{' { // Modifier block if r.s[si+1] == '{' {
sep := strings.Index(s[j+2:], "}") // Modifier block
if sep == -1 { sep := strings.Index(r.s[si+2:], "}")
return "bad modifier in $GENERATE" if sep < 0 {
return 0, r.parseError("bad modifier in $GENERATE", len(r.s))
} }
mod, offset, err = modToPrintf(s[j+2 : j+2+sep])
if err != nil { var errMsg string
return err.Error() mod, offset, errMsg = modToPrintf(r.s[si+2 : si+2+sep])
if errMsg != "" {
return 0, r.parseError(errMsg, si+3+sep)
} }
j += 2 + sep // Jump to it if r.start+offset < 0 || r.end+offset > 1<<31-1 {
return 0, r.parseError("bad offset in $GENERATE", si+3+sep)
} }
dom.WriteString(fmt.Sprintf(mod, i+offset))
r.si += 2 + sep // Jump to it
}
fmt.Fprintf(&r.mod, mod, r.cur+offset)
return r.mod.ReadByte()
default: default:
if escape { // Pretty useless here if r.escape { // Pretty useless here
escape = false r.escape = false
continue return r.ReadByte()
} }
dom.WriteByte(s[j])
return r.s[si], nil
} }
} }
// Re-parse the RR and send it on the current channel t
rx, err := NewRR("$ORIGIN " + o + "\n" + dom.String())
if err != nil {
return err.Error()
}
t <- &Token{RR: rx}
// Its more efficient to first built the rrlist and then parse it in
// one go! But is this a problem?
}
return ""
}
// Convert a $GENERATE modifier 0,0,d to something Printf can deal with. // Convert a $GENERATE modifier 0,0,d to something Printf can deal with.
func modToPrintf(s string) (string, int, error) { func modToPrintf(s string) (string, int, string) {
xs := strings.SplitN(s, ",", 3) // Modifier is { offset [ ,width [ ,base ] ] } - provide default
if len(xs) != 3 { // values for optional width and type, if necessary.
return "", 0, errors.New("bad modifier in $GENERATE") var offStr, widthStr, base string
switch xs := strings.Split(s, ","); len(xs) {
case 1:
offStr, widthStr, base = xs[0], "0", "d"
case 2:
offStr, widthStr, base = xs[0], xs[1], "d"
case 3:
offStr, widthStr, base = xs[0], xs[1], xs[2]
default:
return "", 0, "bad modifier in $GENERATE"
} }
// xs[0] is offset, xs[1] is width, xs[2] is base
if xs[2] != "o" && xs[2] != "d" && xs[2] != "x" && xs[2] != "X" { switch base {
return "", 0, errors.New("bad base in $GENERATE") case "o", "d", "x", "X":
default:
return "", 0, "bad base in $GENERATE"
} }
offset, err := strconv.Atoi(xs[0])
if err != nil || offset > 255 { offset, err := strconv.Atoi(offStr)
return "", 0, errors.New("bad offset in $GENERATE") if err != nil {
return "", 0, "bad offset in $GENERATE"
} }
width, err := strconv.Atoi(xs[1])
if err != nil || width > 255 { width, err := strconv.Atoi(widthStr)
return "", offset, errors.New("bad width in $GENERATE") if err != nil || width < 0 || width > 255 {
return "", 0, "bad width in $GENERATE"
} }
switch {
case width < 0: if width == 0 {
return "", offset, errors.New("bad width in $GENERATE") return "%" + base, offset, ""
case width == 0:
return "%" + xs[1] + xs[2], offset, nil
} }
return "%0" + xs[1] + xs[2], offset, nil
return "%0" + widthStr + base, offset, ""
} }

View file

@ -16,7 +16,7 @@ func SplitDomainName(s string) (labels []string) {
fqdnEnd := 0 // offset of the final '.' or the length of the name fqdnEnd := 0 // offset of the final '.' or the length of the name
idx := Split(s) idx := Split(s)
begin := 0 begin := 0
if s[len(s)-1] == '.' { if IsFqdn(s) {
fqdnEnd = len(s) - 1 fqdnEnd = len(s) - 1
} else { } else {
fqdnEnd = len(s) fqdnEnd = len(s)
@ -36,8 +36,7 @@ func SplitDomainName(s string) (labels []string) {
} }
} }
labels = append(labels, s[begin:fqdnEnd]) return append(labels, s[begin:fqdnEnd])
return labels
} }
// CompareDomainName compares the names s1 and s2 and // CompareDomainName compares the names s1 and s2 and
@ -178,10 +177,10 @@ func equal(a, b string) bool {
ai := a[i] ai := a[i]
bi := b[i] bi := b[i]
if ai >= 'A' && ai <= 'Z' { if ai >= 'A' && ai <= 'Z' {
ai |= ('a' - 'A') ai |= 'a' - 'A'
} }
if bi >= 'A' && bi <= 'Z' { if bi >= 'A' && bi <= 'Z' {
bi |= ('a' - 'A') bi |= 'a' - 'A'
} }
if ai != bi { if ai != bi {
return false return false

44
vendor/github.com/miekg/dns/listen_go111.go generated vendored Normal file
View file

@ -0,0 +1,44 @@
// +build go1.11
// +build aix darwin dragonfly freebsd linux netbsd openbsd
package dns
import (
"context"
"net"
"syscall"
"golang.org/x/sys/unix"
)
const supportsReusePort = true
func reuseportControl(network, address string, c syscall.RawConn) error {
var opErr error
err := c.Control(func(fd uintptr) {
opErr = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_REUSEPORT, 1)
})
if err != nil {
return err
}
return opErr
}
func listenTCP(network, addr string, reuseport bool) (net.Listener, error) {
var lc net.ListenConfig
if reuseport {
lc.Control = reuseportControl
}
return lc.Listen(context.Background(), network, addr)
}
func listenUDP(network, addr string, reuseport bool) (net.PacketConn, error) {
var lc net.ListenConfig
if reuseport {
lc.Control = reuseportControl
}
return lc.ListenPacket(context.Background(), network, addr)
}

23
vendor/github.com/miekg/dns/listen_go_not111.go generated vendored Normal file
View file

@ -0,0 +1,23 @@
// +build !go1.11 !aix,!darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd
package dns
import "net"
const supportsReusePort = false
func listenTCP(network, addr string, reuseport bool) (net.Listener, error) {
if reuseport {
// TODO(tmthrgd): return an error?
}
return net.Listen(network, addr)
}
func listenUDP(network, addr string, reuseport bool) (net.PacketConn, error) {
if reuseport {
// TODO(tmthrgd): return an error?
}
return net.ListenPacket(network, addr)
}

675
vendor/github.com/miekg/dns/msg.go generated vendored
View file

@ -9,7 +9,6 @@
package dns package dns
//go:generate go run msg_generate.go //go:generate go run msg_generate.go
//go:generate go run compress_generate.go
import ( import (
crand "crypto/rand" crand "crypto/rand"
@ -18,12 +17,35 @@ import (
"math/big" "math/big"
"math/rand" "math/rand"
"strconv" "strconv"
"strings"
"sync" "sync"
) )
const ( const (
maxCompressionOffset = 2 << 13 // We have 14 bits for the compression pointer maxCompressionOffset = 2 << 13 // We have 14 bits for the compression pointer
maxDomainNameWireOctets = 255 // See RFC 1035 section 2.3.4 maxDomainNameWireOctets = 255 // See RFC 1035 section 2.3.4
// This is the maximum number of compression pointers that should occur in a
// semantically valid message. Each label in a domain name must be at least one
// octet and is separated by a period. The root label won't be represented by a
// compression pointer to a compression pointer, hence the -2 to exclude the
// smallest valid root label.
//
// It is possible to construct a valid message that has more compression pointers
// than this, and still doesn't loop, by pointing to a previous pointer. This is
// not something a well written implementation should ever do, so we leave them
// to trip the maximum compression pointer check.
maxCompressionPointers = (maxDomainNameWireOctets+1)/2 - 2
// This is the maximum length of a domain name in presentation format. The
// maximum wire length of a domain name is 255 octets (see above), with the
// maximum label length being 63. The wire format requires one extra byte over
// the presentation format, reducing the number of octets by 1. Each label in
// the name will be separated by a single period, with each octet in the label
// expanding to at most 4 bytes (\DDD). If all other labels are of the maximum
// length, then the final label can only be 61 octets long to not exceed the
// maximum allowed wire length.
maxDomainNamePresentationLength = 61*4 + 1 + 63*4 + 1 + 63*4 + 1 + 63*4 + 1
) )
// Errors defined in this package. // Errors defined in this package.
@ -49,7 +71,6 @@ var (
ErrSig error = &Error{err: "bad signature"} // ErrSig indicates that a signature can not be cryptographically validated. ErrSig error = &Error{err: "bad signature"} // ErrSig indicates that a signature can not be cryptographically validated.
ErrSoa error = &Error{err: "no SOA"} // ErrSOA indicates that no SOA RR was seen when doing zone transfers. ErrSoa error = &Error{err: "no SOA"} // ErrSOA indicates that no SOA RR was seen when doing zone transfers.
ErrTime error = &Error{err: "bad time"} // ErrTime indicates a timing error in TSIG authentication. ErrTime error = &Error{err: "bad time"} // ErrTime indicates a timing error in TSIG authentication.
ErrTruncated error = &Error{err: "failed to unpack truncated message"} // 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.
) )
// 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
@ -151,7 +172,7 @@ var RcodeToString = map[int]string{
RcodeFormatError: "FORMERR", RcodeFormatError: "FORMERR",
RcodeServerFailure: "SERVFAIL", RcodeServerFailure: "SERVFAIL",
RcodeNameError: "NXDOMAIN", RcodeNameError: "NXDOMAIN",
RcodeNotImplemented: "NOTIMPL", RcodeNotImplemented: "NOTIMP",
RcodeRefused: "REFUSED", RcodeRefused: "REFUSED",
RcodeYXDomain: "YXDOMAIN", // See RFC 2136 RcodeYXDomain: "YXDOMAIN", // See RFC 2136
RcodeYXRrset: "YXRRSET", RcodeYXRrset: "YXRRSET",
@ -169,6 +190,39 @@ var RcodeToString = map[int]string{
RcodeBadCookie: "BADCOOKIE", RcodeBadCookie: "BADCOOKIE",
} }
// compressionMap is used to allow a more efficient compression map
// to be used for internal packDomainName calls without changing the
// signature or functionality of public API.
//
// In particular, map[string]uint16 uses 25% less per-entry memory
// than does map[string]int.
type compressionMap struct {
ext map[string]int // external callers
int map[string]uint16 // internal callers
}
func (m compressionMap) valid() bool {
return m.int != nil || m.ext != nil
}
func (m compressionMap) insert(s string, pos int) {
if m.ext != nil {
m.ext[s] = pos
} else {
m.int[s] = uint16(pos)
}
}
func (m compressionMap) find(s string) (int, bool) {
if m.ext != nil {
pos, ok := m.ext[s]
return pos, ok
}
pos, ok := m.int[s]
return int(pos), ok
}
// Domain names are a sequence of counted strings // Domain names are a sequence of counted strings
// split at the dots. They end with a zero-length string. // split at the dots. They end with a zero-length string.
@ -177,143 +231,156 @@ var RcodeToString = map[int]string{
// 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) return packDomainName(s, msg, off, compressionMap{ext: compression}, compress)
return
} }
func packDomainName(s string, msg []byte, off int, compression map[string]int, compress bool) (off1 int, labels int, err error) { func packDomainName(s string, msg []byte, off int, compression compressionMap, compress bool) (off1 int, err error) {
// special case if msg == nil // XXX: A logical copy of this function exists in IsDomainName and
lenmsg := 256 // should be kept in sync with this function.
if msg != nil {
lenmsg = len(msg)
}
ls := len(s) ls := len(s)
if ls == 0 { // Ok, for instance when dealing with update RR without any rdata. if ls == 0 { // Ok, for instance when dealing with update RR without any rdata.
return off, 0, nil return off, nil
}
// If not fully qualified, error out, but only if msg == nil #ugly
switch {
case msg == nil:
if s[ls-1] != '.' {
s += "."
ls++
}
case msg != nil:
if s[ls-1] != '.' {
return lenmsg, 0, ErrFqdn
} }
// If not fully qualified, error out.
if !IsFqdn(s) {
return len(msg), ErrFqdn
} }
// Each dot ends a segment of the name. // Each dot ends a segment of the name.
// We trade each dot byte for a length byte. // We trade each dot byte for a length byte.
// Except for escaped dots (\.), which are normal dots. // Except for escaped dots (\.), which are normal dots.
// There is also a trailing zero. // There is also a trailing zero.
// Compression // Compression
nameoffset := -1
pointer := -1 pointer := -1
// Emit sequence of counted strings, chopping at dots. // Emit sequence of counted strings, chopping at dots.
begin := 0 var (
bs := []byte(s) begin int
roBs, bsFresh, escapedDot := s, true, false compBegin int
compOff int
bs []byte
wasDot bool
)
loop:
for i := 0; i < ls; i++ { for i := 0; i < ls; i++ {
if bs[i] == '\\' { var c byte
for j := i; j < ls-1; j++ { if bs == nil {
bs[j] = bs[j+1] c = s[i]
} } else {
ls-- c = bs[i]
if off+1 > lenmsg {
return lenmsg, labels, ErrBuf
}
// check for \DDD
if i+2 < ls && isDigit(bs[i]) && isDigit(bs[i+1]) && isDigit(bs[i+2]) {
bs[i] = dddToByte(bs[i:])
for j := i + 1; j < ls-2; j++ {
bs[j] = bs[j+2]
}
ls -= 2
}
escapedDot = bs[i] == '.'
bsFresh = false
continue
} }
if bs[i] == '.' { switch c {
if i > 0 && bs[i-1] == '.' && !escapedDot { case '\\':
if off+1 > len(msg) {
return len(msg), ErrBuf
}
if bs == nil {
bs = []byte(s)
}
// check for \DDD
if i+3 < ls && isDigit(bs[i+1]) && isDigit(bs[i+2]) && isDigit(bs[i+3]) {
bs[i] = dddToByte(bs[i+1:])
copy(bs[i+1:ls-3], bs[i+4:])
ls -= 3
compOff += 3
} else {
copy(bs[i:ls-1], bs[i+1:])
ls--
compOff++
}
wasDot = false
case '.':
if wasDot {
// two dots back to back is not legal // two dots back to back is not legal
return lenmsg, labels, ErrRdata return len(msg), ErrRdata
} }
if i-begin >= 1<<6 { // top two bits of length must be clear wasDot = true
return lenmsg, labels, ErrRdata
labelLen := i - begin
if labelLen >= 1<<6 { // top two bits of length must be clear
return len(msg), ErrRdata
} }
// off can already (we're in a loop) be bigger than len(msg) // off can already (we're in a loop) be bigger than len(msg)
// this happens when a name isn't fully qualified // this happens when a name isn't fully qualified
if off+1 > lenmsg { if off+1+labelLen > len(msg) {
return lenmsg, labels, ErrBuf return len(msg), ErrBuf
}
if msg != nil {
msg[off] = byte(i - begin)
}
offset := off
off++
for j := begin; j < i; j++ {
if off+1 > lenmsg {
return lenmsg, labels, ErrBuf
}
if msg != nil {
msg[off] = bs[j]
}
off++
}
if compress && !bsFresh {
roBs = string(bs)
bsFresh = true
} }
// Don't try to compress '.' // Don't try to compress '.'
// We should only compress when compress it true, but we should also still pick // We should only compress when compress is true, but we should also still pick
// up names that can be used for *future* compression(s). // up names that can be used for *future* compression(s).
if compression != nil && roBs[begin:] != "." { if compression.valid() && !isRootLabel(s, bs, begin, ls) {
if p, ok := compression[roBs[begin:]]; !ok { if p, ok := compression.find(s[compBegin:]); ok {
// Only offsets smaller than this can be used.
if offset < maxCompressionOffset {
compression[roBs[begin:]] = offset
}
} else {
// The first hit is the longest matching dname // The first hit is the longest matching dname
// keep the pointer offset we get back and store // keep the pointer offset we get back and store
// the offset of the current name, because that's // the offset of the current name, because that's
// where we need to insert the pointer later // where we need to insert the pointer later
// If compress is true, we're allowed to compress this dname // If compress is true, we're allowed to compress this dname
if pointer == -1 && compress { if compress {
pointer = p // Where to point to pointer = p // Where to point to
nameoffset = offset // Where to point from break loop
break }
} else if off < maxCompressionOffset {
// Only offsets smaller than maxCompressionOffset can be used.
compression.insert(s[compBegin:], off)
} }
} }
// The following is covered by the length check above.
msg[off] = byte(labelLen)
if bs == nil {
copy(msg[off+1:], s[begin:i])
} else {
copy(msg[off+1:], bs[begin:i])
} }
labels++ off += 1 + labelLen
begin = i + 1 begin = i + 1
compBegin = begin + compOff
default:
wasDot = false
} }
escapedDot = false
} }
// Root label is special // Root label is special
if len(bs) == 1 && bs[0] == '.' { if isRootLabel(s, bs, 0, ls) {
return off, labels, nil return off, nil
} }
// If we did compression and we find something add the pointer here // If we did compression and we find something add the pointer here
if pointer != -1 { if pointer != -1 {
// We have two bytes (14 bits) to put the pointer in // We have two bytes (14 bits) to put the pointer in
// if msg == nil, we will never do compression binary.BigEndian.PutUint16(msg[off:], uint16(pointer^0xC000))
binary.BigEndian.PutUint16(msg[nameoffset:], uint16(pointer^0xC000)) return off + 2, nil
off = nameoffset + 1
goto End
} }
if msg != nil && off < len(msg) {
if off < len(msg) {
msg[off] = 0 msg[off] = 0
} }
End:
off++ return off + 1, nil
return off, labels, nil }
// isRootLabel returns whether s or bs, from off to end, is the root
// label ".".
//
// If bs is nil, s will be checked, otherwise bs will be checked.
func isRootLabel(s string, bs []byte, off, end int) bool {
if bs == nil {
return s[off:end] == "."
}
return end-off == 1 && bs[off] == '.'
} }
// Unpack a domain name. // Unpack a domain name.
@ -330,12 +397,16 @@ End:
// In theory, the pointers are only allowed to jump backward. // In theory, the pointers are only allowed to jump backward.
// We let them jump anywhere and stop jumping after a while. // We let them jump anywhere and stop jumping after a while.
// UnpackDomainName unpacks a domain name into a string. // UnpackDomainName unpacks a domain name into a string. It returns
// the name, the new offset into msg and any error that occurred.
//
// When an error is encountered, the unpacked name will be discarded
// and len(msg) will be returned as the offset.
func UnpackDomainName(msg []byte, off int) (string, int, error) { func UnpackDomainName(msg []byte, off int) (string, int, error) {
s := make([]byte, 0, 64) s := make([]byte, 0, maxDomainNamePresentationLength)
off1 := 0 off1 := 0
lenmsg := len(msg) lenmsg := len(msg)
maxLen := maxDomainNameWireOctets budget := maxDomainNameWireOctets
ptr := 0 // number of pointers followed ptr := 0 // number of pointers followed
Loop: Loop:
for { for {
@ -354,27 +425,19 @@ Loop:
if off+c > lenmsg { if off+c > lenmsg {
return "", lenmsg, ErrBuf return "", lenmsg, ErrBuf
} }
budget -= c + 1 // +1 for the label separator
if budget <= 0 {
return "", lenmsg, ErrLongDomain
}
for j := off; j < off+c; j++ { for j := off; j < off+c; j++ {
switch b := msg[j]; b { switch b := msg[j]; b {
case '.', '(', ')', ';', ' ', '@': case '.', '(', ')', ';', ' ', '@':
fallthrough fallthrough
case '"', '\\': case '"', '\\':
s = append(s, '\\', b) s = append(s, '\\', b)
// presentation-format \X escapes add an extra byte
maxLen++
default: default:
if b < 32 || b >= 127 { // unprintable, use \DDD if b < ' ' || b > '~' { // unprintable, use \DDD
var buf [3]byte s = append(s, escapeByte(b)...)
bufs := strconv.AppendInt(buf[:0], int64(b), 10)
s = append(s, '\\')
for i := 0; i < 3-len(bufs); i++ {
s = append(s, '0')
}
for _, r := range bufs {
s = append(s, r)
}
// presentation-format \DDD escapes add 3 extra bytes
maxLen += 3
} else { } else {
s = append(s, b) s = append(s, b)
} }
@ -396,7 +459,7 @@ Loop:
if ptr == 0 { if ptr == 0 {
off1 = off off1 = off
} }
if ptr++; ptr > 10 { if ptr++; ptr > maxCompressionPointers {
return "", lenmsg, &Error{err: "too many compression pointers"} return "", lenmsg, &Error{err: "too many compression pointers"}
} }
// pointer should guarantee that it advances and points forwards at least // pointer should guarantee that it advances and points forwards at least
@ -412,10 +475,7 @@ Loop:
off1 = off off1 = off
} }
if len(s) == 0 { if len(s) == 0 {
s = []byte(".") return ".", off1, nil
} else if len(s) >= maxLen {
// error if the name is too long, but don't throw it away
return string(s), lenmsg, ErrLongDomain
} }
return string(s), off1, nil return string(s), off1, nil
} }
@ -512,7 +572,7 @@ func unpackTxt(msg []byte, off0 int) (ss []string, off int, err error) {
off = off0 off = off0
var s string var s string
for off < len(msg) && err == nil { for off < len(msg) && err == nil {
s, off, err = unpackTxtString(msg, off) s, off, err = unpackString(msg, off)
if err == nil { if err == nil {
ss = append(ss, s) ss = append(ss, s)
} }
@ -520,43 +580,16 @@ func unpackTxt(msg []byte, off0 int) (ss []string, off int, err error) {
return return
} }
func unpackTxtString(msg []byte, offset int) (string, int, error) {
if offset+1 > len(msg) {
return "", offset, &Error{err: "overflow unpacking txt"}
}
l := int(msg[offset])
if offset+l+1 > len(msg) {
return "", offset, &Error{err: "overflow unpacking txt"}
}
s := make([]byte, 0, l)
for _, b := range msg[offset+1 : offset+1+l] {
switch b {
case '"', '\\':
s = append(s, '\\', b)
default:
if b < 32 || b > 127 { // unprintable
var buf [3]byte
bufs := strconv.AppendInt(buf[:0], int64(b), 10)
s = append(s, '\\')
for i := 0; i < 3-len(bufs); i++ {
s = append(s, '0')
}
for _, r := range bufs {
s = append(s, r)
}
} else {
s = append(s, b)
}
}
}
offset += 1 + l
return string(s), offset, nil
}
// Helpers for dealing with escaped bytes // Helpers for dealing with escaped bytes
func isDigit(b byte) bool { return b >= '0' && b <= '9' } func isDigit(b byte) bool { return b >= '0' && b <= '9' }
func dddToByte(s []byte) byte { func dddToByte(s []byte) byte {
_ = s[2] // bounds check hint to compiler; see golang.org/issue/14808
return byte((s[0]-'0')*100 + (s[1]-'0')*10 + (s[2] - '0'))
}
func dddStringToByte(s string) byte {
_ = s[2] // bounds check hint to compiler; see golang.org/issue/14808
return byte((s[0]-'0')*100 + (s[1]-'0')*10 + (s[2] - '0')) return byte((s[0]-'0')*100 + (s[1]-'0')*10 + (s[2] - '0'))
} }
@ -574,19 +607,38 @@ func intToBytes(i *big.Int, length int) []byte {
// PackRR packs a resource record rr into msg[off:]. // PackRR packs a resource record rr into msg[off:].
// See PackDomainName for documentation about the compression. // See PackDomainName for documentation about the compression.
func PackRR(rr RR, msg []byte, off int, compression map[string]int, compress bool) (off1 int, err error) { func PackRR(rr RR, msg []byte, off int, compression map[string]int, compress bool) (off1 int, err error) {
if rr == nil { headerEnd, off1, err := packRR(rr, msg, off, compressionMap{ext: compression}, compress)
return len(msg), &Error{err: "nil rr"} if err == nil {
// packRR no longer sets the Rdlength field on the rr, but
// callers might be expecting it so we set it here.
rr.Header().Rdlength = uint16(off1 - headerEnd)
}
return off1, err
} }
off1, err = rr.pack(msg, off, compression, compress) func packRR(rr RR, msg []byte, off int, compression compressionMap, compress bool) (headerEnd int, off1 int, err error) {
if rr == nil {
return len(msg), len(msg), &Error{err: "nil rr"}
}
headerEnd, err = rr.Header().packHeader(msg, off, compression, compress)
if err != nil { if err != nil {
return len(msg), err return headerEnd, len(msg), err
} }
// TODO(miek): Not sure if this is needed? If removed we can remove rawmsg.go as well.
if rawSetRdlength(msg, off, off1) { off1, err = rr.pack(msg, headerEnd, compression, compress)
return off1, nil if err != nil {
return headerEnd, len(msg), err
} }
return off, ErrRdata
rdlength := off1 - headerEnd
if int(uint16(rdlength)) != rdlength { // overflow
return headerEnd, len(msg), ErrRdata
}
// The RDLENGTH field is the last field in the header and we set it here.
binary.BigEndian.PutUint16(msg[headerEnd-2:], uint16(rdlength))
return headerEnd, off1, nil
} }
// UnpackRR unpacks msg[off:] into an RR. // UnpackRR unpacks msg[off:] into an RR.
@ -595,17 +647,35 @@ func UnpackRR(msg []byte, off int) (rr RR, off1 int, err error) {
if err != nil { if err != nil {
return nil, len(msg), err return nil, len(msg), err
} }
return UnpackRRWithHeader(h, msg, off)
}
// UnpackRRWithHeader unpacks the record type specific payload given an existing
// RR_Header.
func UnpackRRWithHeader(h RR_Header, msg []byte, off int) (rr RR, off1 int, err error) {
if newFn, ok := TypeToRR[h.Rrtype]; ok {
rr = newFn()
*rr.Header() = h
} else {
rr = &RFC3597{Hdr: h}
}
if noRdata(h) {
return rr, off, nil
}
end := off + int(h.Rdlength) end := off + int(h.Rdlength)
if fn, known := typeToUnpack[h.Rrtype]; !known { off, err = rr.unpack(msg, off)
rr, off, err = unpackRFC3597(h, msg, off) if err != nil {
} else { return nil, end, err
rr, off, err = fn(h, msg, off)
} }
if off != end { if off != end {
return &h, end, &Error{err: "bad rdlength"} return &h, end, &Error{err: "bad rdlength"}
} }
return rr, off, err
return rr, off, nil
} }
// unpackRRslice unpacks msg[off:] into an []RR. // unpackRRslice unpacks msg[off:] into an []RR.
@ -684,35 +754,37 @@ func (dns *Msg) Pack() (msg []byte, err error) {
return dns.PackBuffer(nil) return dns.PackBuffer(nil)
} }
// PackBuffer packs a Msg, using the given buffer buf. If buf is too small // PackBuffer packs a Msg, using the given buffer buf. If buf is too small a new buffer is allocated.
// a new buffer is allocated.
func (dns *Msg) PackBuffer(buf []byte) (msg []byte, err error) { func (dns *Msg) PackBuffer(buf []byte) (msg []byte, err error) {
// We use a similar function in tsig.go's stripTsig. // If this message can't be compressed, avoid filling the
var ( // compression map and creating garbage.
dh Header if dns.Compress && dns.isCompressible() {
compression map[string]int compression := make(map[string]uint16) // Compression pointer mappings.
) return dns.packBufferWithCompressionMap(buf, compressionMap{int: compression}, true)
if dns.Compress {
compression = make(map[string]int) // Compression pointer mappings
} }
return dns.packBufferWithCompressionMap(buf, compressionMap{}, false)
}
// packBufferWithCompressionMap packs a Msg, using the given buffer buf.
func (dns *Msg) packBufferWithCompressionMap(buf []byte, compression compressionMap, compress bool) (msg []byte, err error) {
if dns.Rcode < 0 || dns.Rcode > 0xFFF { if dns.Rcode < 0 || dns.Rcode > 0xFFF {
return nil, ErrRcode return nil, ErrRcode
} }
if dns.Rcode > 0xF {
// Regular RCODE field is 4 bits // Set extended rcode unconditionally if we have an opt, this will allow
opt := dns.IsEdns0() // reseting the extended rcode bits if they need to.
if opt == nil { if opt := dns.IsEdns0(); opt != nil {
opt.SetExtendedRcode(uint16(dns.Rcode))
} else if dns.Rcode > 0xF {
// If Rcode is an extended one and opt is nil, error out.
return nil, ErrExtendedRcode return nil, ErrExtendedRcode
} }
opt.SetExtendedRcode(uint8(dns.Rcode >> 4))
dns.Rcode &= 0xF
}
// Convert convenient Msg into wire-like Header. // Convert convenient Msg into wire-like Header.
var dh Header
dh.Id = dns.Id dh.Id = dns.Id
dh.Bits = uint16(dns.Opcode)<<11 | uint16(dns.Rcode) dh.Bits = uint16(dns.Opcode)<<11 | uint16(dns.Rcode&0xF)
if dns.Response { if dns.Response {
dh.Bits |= _QR dh.Bits |= _QR
} }
@ -738,50 +810,44 @@ func (dns *Msg) PackBuffer(buf []byte) (msg []byte, err error) {
dh.Bits |= _CD dh.Bits |= _CD
} }
// Prepare variable sized arrays. dh.Qdcount = uint16(len(dns.Question))
question := dns.Question dh.Ancount = uint16(len(dns.Answer))
answer := dns.Answer dh.Nscount = uint16(len(dns.Ns))
ns := dns.Ns dh.Arcount = uint16(len(dns.Extra))
extra := dns.Extra
dh.Qdcount = uint16(len(question))
dh.Ancount = uint16(len(answer))
dh.Nscount = uint16(len(ns))
dh.Arcount = uint16(len(extra))
// We need the uncompressed length here, because we first pack it and then compress it. // We need the uncompressed length here, because we first pack it and then compress it.
msg = buf msg = buf
uncompressedLen := compressedLen(dns, false) uncompressedLen := msgLenWithCompressionMap(dns, nil)
if packLen := uncompressedLen + 1; len(msg) < packLen { if packLen := uncompressedLen + 1; len(msg) < packLen {
msg = make([]byte, packLen) msg = make([]byte, packLen)
} }
// Pack it in: header and then the pieces. // Pack it in: header and then the pieces.
off := 0 off := 0
off, err = dh.pack(msg, off, compression, dns.Compress) off, err = dh.pack(msg, off, compression, compress)
if err != nil { if err != nil {
return nil, err return nil, err
} }
for i := 0; i < len(question); i++ { for _, r := range dns.Question {
off, err = question[i].pack(msg, off, compression, dns.Compress) off, err = r.pack(msg, off, compression, compress)
if err != nil { if err != nil {
return nil, err return nil, err
} }
} }
for i := 0; i < len(answer); i++ { for _, r := range dns.Answer {
off, err = PackRR(answer[i], msg, off, compression, dns.Compress) _, off, err = packRR(r, msg, off, compression, compress)
if err != nil { if err != nil {
return nil, err return nil, err
} }
} }
for i := 0; i < len(ns); i++ { for _, r := range dns.Ns {
off, err = PackRR(ns[i], msg, off, compression, dns.Compress) _, off, err = packRR(r, msg, off, compression, compress)
if err != nil { if err != nil {
return nil, err return nil, err
} }
} }
for i := 0; i < len(extra); i++ { for _, r := range dns.Extra {
off, err = PackRR(extra[i], msg, off, compression, dns.Compress) _, off, err = packRR(r, msg, off, compression, compress)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -789,28 +855,7 @@ func (dns *Msg) PackBuffer(buf []byte) (msg []byte, err error) {
return msg[:off], nil return msg[:off], nil
} }
// Unpack unpacks a binary message to a Msg structure. func (dns *Msg) unpack(dh Header, msg []byte, off int) (err error) {
func (dns *Msg) Unpack(msg []byte) (err error) {
var (
dh Header
off int
)
if dh, off, err = unpackMsgHdr(msg, off); err != nil {
return err
}
dns.Id = dh.Id
dns.Response = (dh.Bits & _QR) != 0
dns.Opcode = int(dh.Bits>>11) & 0xF
dns.Authoritative = (dh.Bits & _AA) != 0
dns.Truncated = (dh.Bits & _TC) != 0
dns.RecursionDesired = (dh.Bits & _RD) != 0
dns.RecursionAvailable = (dh.Bits & _RA) != 0
dns.Zero = (dh.Bits & _Z) != 0
dns.AuthenticatedData = (dh.Bits & _AD) != 0
dns.CheckingDisabled = (dh.Bits & _CD) != 0
dns.Rcode = int(dh.Bits & 0xF)
// If we are at the end of the message we should return *just* the // If we are at the end of the message we should return *just* the
// header. This can still be useful to the caller. 9.9.9.9 sends these // header. This can still be useful to the caller. 9.9.9.9 sends these
// when responding with REFUSED for instance. // when responding with REFUSED for instance.
@ -829,8 +874,6 @@ func (dns *Msg) Unpack(msg []byte) (err error) {
var q Question var q Question
q, off, err = unpackQuestion(msg, off) q, off, err = unpackQuestion(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 off1 == off { // Offset does not increase anymore, dh.Qdcount is a lie!
@ -854,16 +897,29 @@ func (dns *Msg) Unpack(msg []byte) (err error) {
// The header counts might have been wrong so we need to update it // The header counts might have been wrong so we need to update it
dh.Arcount = uint16(len(dns.Extra)) dh.Arcount = uint16(len(dns.Extra))
// Set extended Rcode
if opt := dns.IsEdns0(); opt != nil {
dns.Rcode |= opt.ExtendedRcode()
}
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 err return err
}
// Unpack unpacks a binary message to a Msg structure.
func (dns *Msg) Unpack(msg []byte) (err error) {
dh, off, err := unpackMsgHdr(msg, 0)
if err != nil {
return err
}
dns.setHdr(dh)
return dns.unpack(dh, msg, off)
} }
// Convert a complete message to a string with dig-like output. // Convert a complete message to a string with dig-like output.
@ -909,107 +965,117 @@ func (dns *Msg) String() string {
return s return s
} }
// isCompressible returns whether the msg may be compressible.
func (dns *Msg) isCompressible() bool {
// If we only have one question, there is nothing we can ever compress.
return len(dns.Question) > 1 || len(dns.Answer) > 0 ||
len(dns.Ns) > 0 || len(dns.Extra) > 0
}
// Len returns the message length when in (un)compressed wire format. // Len returns the message length when in (un)compressed wire format.
// If dns.Compress is true compression it is taken into account. Len() // If dns.Compress is true compression it is taken into account. Len()
// is provided to be a faster way to get the size of the resulting packet, // is provided to be a faster way to get the size of the resulting packet,
// than packing it, measuring the size and discarding the buffer. // than packing it, measuring the size and discarding the buffer.
func (dns *Msg) Len() int { return compressedLen(dns, dns.Compress) } func (dns *Msg) Len() int {
// If this message can't be compressed, avoid filling the
// compressedLen returns the message length when in compressed wire format // compression map and creating garbage.
// when compress is true, otherwise the uncompressed length is returned. if dns.Compress && dns.isCompressible() {
func compressedLen(dns *Msg, compress bool) int { compression := make(map[string]struct{})
// We always return one more than needed. return msgLenWithCompressionMap(dns, compression)
l := 12 // Message header is always 12 bytes
if compress {
compression := map[string]int{}
for _, r := range dns.Question {
l += r.len()
compressionLenHelper(compression, r.Name)
} }
l += compressionLenSlice(compression, dns.Answer)
l += compressionLenSlice(compression, dns.Ns) return msgLenWithCompressionMap(dns, nil)
l += compressionLenSlice(compression, dns.Extra) }
} else {
func msgLenWithCompressionMap(dns *Msg, compression map[string]struct{}) int {
l := headerSize
for _, r := range dns.Question { for _, r := range dns.Question {
l += r.len() l += r.len(l, compression)
} }
for _, r := range dns.Answer { for _, r := range dns.Answer {
if r != nil { if r != nil {
l += r.len() l += r.len(l, compression)
} }
} }
for _, r := range dns.Ns { for _, r := range dns.Ns {
if r != nil { if r != nil {
l += r.len() l += r.len(l, compression)
} }
} }
for _, r := range dns.Extra { for _, r := range dns.Extra {
if r != nil { if r != nil {
l += r.len() l += r.len(l, compression)
}
} }
} }
return l return l
} }
func compressionLenSlice(c map[string]int, rs []RR) int { func domainNameLen(s string, off int, compression map[string]struct{}, compress bool) int {
var l int if s == "" || s == "." {
for _, r := range rs { return 1
if r == nil { }
escaped := strings.Contains(s, "\\")
if compression != nil && (compress || off < maxCompressionOffset) {
// compressionLenSearch will insert the entry into the compression
// map if it doesn't contain it.
if l, ok := compressionLenSearch(compression, s, off); ok && compress {
if escaped {
return escapedNameLen(s[:l]) + 2
}
return l + 2
}
}
if escaped {
return escapedNameLen(s) + 1
}
return len(s) + 1
}
func escapedNameLen(s string) int {
nameLen := len(s)
for i := 0; i < len(s); i++ {
if s[i] != '\\' {
continue continue
} }
l += r.len()
k, ok := compressionLenSearch(c, r.Header().Name)
if ok {
l += 1 - k
}
compressionLenHelper(c, r.Header().Name)
k, ok = compressionLenSearchType(c, r)
if ok {
l += 1 - k
}
compressionLenHelperType(c, r)
}
return l
}
// Put the parts of the name in the compression map. if i+3 < len(s) && isDigit(s[i+1]) && isDigit(s[i+2]) && isDigit(s[i+3]) {
func compressionLenHelper(c map[string]int, s string) { nameLen -= 3
pref := "" i += 3
lbs := Split(s) } else {
for j := len(lbs) - 1; j >= 0; j-- { nameLen--
pref = s[lbs[j]:] i++
if _, ok := c[pref]; !ok {
c[pref] = len(pref)
}
} }
} }
// Look for each part in the compression map and returns its length, return nameLen
// keep on searching so we get the longest match.
func compressionLenSearch(c map[string]int, s string) (int, bool) {
off := 0
end := false
if s == "" { // don't bork on bogus data
return 0, false
} }
for {
func compressionLenSearch(c map[string]struct{}, s string, msgOff int) (int, bool) {
for off, end := 0, false; !end; off, end = NextLabel(s, off) {
if _, ok := c[s[off:]]; ok { if _, ok := c[s[off:]]; ok {
return len(s[off:]), true return off, true
} }
if end {
break if msgOff+off < maxCompressionOffset {
c[s[off:]] = struct{}{}
} }
off, end = NextLabel(s, off)
} }
return 0, false return 0, false
} }
// Copy returns a new RR which is a deep-copy of r. // Copy returns a new RR which is a deep-copy of r.
func Copy(r RR) RR { r1 := r.copy(); return r1 } func Copy(r RR) RR { return r.copy() }
// Len returns the length (in octets) of the uncompressed RR in wire format. // Len returns the length (in octets) of the uncompressed RR in wire format.
func Len(r RR) int { return r.len() } func Len(r RR) int { return r.len(0, nil) }
// 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 { return dns.CopyTo(new(Msg)) } func (dns *Msg) Copy() *Msg { return dns.CopyTo(new(Msg)) }
@ -1057,8 +1123,8 @@ func (dns *Msg) CopyTo(r1 *Msg) *Msg {
return r1 return r1
} }
func (q *Question) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) { func (q *Question) pack(msg []byte, off int, compression compressionMap, compress bool) (int, error) {
off, err := PackDomainName(q.Name, msg, off, compression, compress) off, err := packDomainName(q.Name, msg, off, compression, compress)
if err != nil { if err != nil {
return off, err return off, err
} }
@ -1099,7 +1165,7 @@ func unpackQuestion(msg []byte, off int) (Question, int, error) {
return q, off, err return q, off, err
} }
func (dh *Header) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) { func (dh *Header) pack(msg []byte, off int, compression compressionMap, compress bool) (int, error) {
off, err := packUint16(dh.Id, msg, off) off, err := packUint16(dh.Id, msg, off)
if err != nil { if err != nil {
return off, err return off, err
@ -1121,8 +1187,11 @@ func (dh *Header) pack(msg []byte, off int, compression map[string]int, compress
return off, err return off, err
} }
off, err = packUint16(dh.Arcount, msg, off) off, err = packUint16(dh.Arcount, msg, off)
if err != nil {
return off, err return off, err
} }
return off, nil
}
func unpackMsgHdr(msg []byte, off int) (Header, int, error) { func unpackMsgHdr(msg []byte, off int) (Header, int, error) {
var ( var (
@ -1150,5 +1219,23 @@ func unpackMsgHdr(msg []byte, off int) (Header, int, error) {
return dh, off, err return dh, off, err
} }
dh.Arcount, off, err = unpackUint16(msg, off) dh.Arcount, off, err = unpackUint16(msg, off)
if err != nil {
return dh, off, err return dh, off, err
} }
return dh, off, nil
}
// setHdr set the header in the dns using the binary data in dh.
func (dns *Msg) setHdr(dh Header) {
dns.Id = dh.Id
dns.Response = dh.Bits&_QR != 0
dns.Opcode = int(dh.Bits>>11) & 0xF
dns.Authoritative = dh.Bits&_AA != 0
dns.Truncated = dh.Bits&_TC != 0
dns.RecursionDesired = dh.Bits&_RD != 0
dns.RecursionAvailable = dh.Bits&_RA != 0
dns.Zero = dh.Bits&_Z != 0 // _Z covers the zero bit, which should be zero; not sure why we set it to the opposite.
dns.AuthenticatedData = dh.Bits&_AD != 0
dns.CheckingDisabled = dh.Bits&_CD != 0
dns.Rcode = int(dh.Bits & 0xF)
}

View file

@ -80,13 +80,7 @@ func main() {
o := scope.Lookup(name) o := scope.Lookup(name)
st, _ := getTypeStruct(o.Type(), scope) st, _ := getTypeStruct(o.Type(), scope)
fmt.Fprintf(b, "func (rr *%s) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {\n", name) fmt.Fprintf(b, "func (rr *%s) pack(msg []byte, off int, compression compressionMap, compress bool) (off1 int, err error) {\n", name)
fmt.Fprint(b, `off, err := rr.Hdr.pack(msg, off, compression, compress)
if err != nil {
return off, err
}
headerEnd := off
`)
for i := 1; i < st.NumFields(); i++ { for i := 1; i < st.NumFields(); i++ {
o := func(s string) { o := func(s string) {
fmt.Fprintf(b, s, st.Field(i).Name()) fmt.Fprintf(b, s, st.Field(i).Name())
@ -106,7 +100,7 @@ return off, err
case `dns:"nsec"`: case `dns:"nsec"`:
o("off, err = packDataNsec(rr.%s, msg, off)\n") o("off, err = packDataNsec(rr.%s, msg, off)\n")
case `dns:"domain-name"`: case `dns:"domain-name"`:
o("off, err = packDataDomainNames(rr.%s, msg, off, compression, compress)\n") o("off, err = packDataDomainNames(rr.%s, msg, off, compression, false)\n")
default: default:
log.Fatalln(name, st.Field(i).Name(), st.Tag(i)) log.Fatalln(name, st.Field(i).Name(), st.Tag(i))
} }
@ -116,9 +110,9 @@ return off, err
switch { switch {
case st.Tag(i) == `dns:"-"`: // ignored case st.Tag(i) == `dns:"-"`: // ignored
case st.Tag(i) == `dns:"cdomain-name"`: case st.Tag(i) == `dns:"cdomain-name"`:
o("off, err = PackDomainName(rr.%s, msg, off, compression, compress)\n") o("off, err = packDomainName(rr.%s, msg, off, compression, compress)\n")
case st.Tag(i) == `dns:"domain-name"`: case st.Tag(i) == `dns:"domain-name"`:
o("off, err = PackDomainName(rr.%s, msg, off, compression, false)\n") o("off, err = packDomainName(rr.%s, msg, off, compression, false)\n")
case st.Tag(i) == `dns:"a"`: case st.Tag(i) == `dns:"a"`:
o("off, err = packDataA(rr.%s, msg, off)\n") o("off, err = packDataA(rr.%s, msg, off)\n")
case st.Tag(i) == `dns:"aaaa"`: case st.Tag(i) == `dns:"aaaa"`:
@ -154,7 +148,8 @@ if rr.%s != "-" {
fallthrough fallthrough
case st.Tag(i) == `dns:"hex"`: case st.Tag(i) == `dns:"hex"`:
o("off, err = packStringHex(rr.%s, msg, off)\n") o("off, err = packStringHex(rr.%s, msg, off)\n")
case st.Tag(i) == `dns:"any"`:
o("off, err = packStringAny(rr.%s, msg, off)\n")
case st.Tag(i) == `dns:"octet"`: case st.Tag(i) == `dns:"octet"`:
o("off, err = packStringOctet(rr.%s, msg, off)\n") o("off, err = packStringOctet(rr.%s, msg, off)\n")
case st.Tag(i) == "": case st.Tag(i) == "":
@ -176,8 +171,6 @@ if rr.%s != "-" {
log.Fatalln(name, st.Field(i).Name(), st.Tag(i)) log.Fatalln(name, st.Field(i).Name(), st.Tag(i))
} }
} }
// We have packed everything, only now we know the rdlength of this RR
fmt.Fprintln(b, "rr.Header().Rdlength = uint16(off-headerEnd)")
fmt.Fprintln(b, "return off, nil }\n") fmt.Fprintln(b, "return off, nil }\n")
} }
@ -186,14 +179,8 @@ if rr.%s != "-" {
o := scope.Lookup(name) o := scope.Lookup(name)
st, _ := getTypeStruct(o.Type(), scope) st, _ := getTypeStruct(o.Type(), scope)
fmt.Fprintf(b, "func unpack%s(h RR_Header, msg []byte, off int) (RR, int, error) {\n", name) fmt.Fprintf(b, "func (rr *%s) unpack(msg []byte, off int) (off1 int, err error) {\n", name)
fmt.Fprintf(b, "rr := new(%s)\n", name) fmt.Fprint(b, `rdStart := off
fmt.Fprint(b, "rr.Hdr = h\n")
fmt.Fprint(b, `if noRdata(h) {
return rr, off, nil
}
var err error
rdStart := off
_ = rdStart _ = rdStart
`) `)
@ -201,7 +188,7 @@ _ = rdStart
o := func(s string) { o := func(s string) {
fmt.Fprintf(b, s, st.Field(i).Name()) fmt.Fprintf(b, s, st.Field(i).Name())
fmt.Fprint(b, `if err != nil { fmt.Fprint(b, `if err != nil {
return rr, off, err return off, err
} }
`) `)
} }
@ -221,7 +208,7 @@ return rr, off, err
log.Fatalln(name, st.Field(i).Name(), st.Tag(i)) log.Fatalln(name, st.Field(i).Name(), st.Tag(i))
} }
fmt.Fprint(b, `if err != nil { fmt.Fprint(b, `if err != nil {
return rr, off, err return off, err
} }
`) `)
continue continue
@ -264,6 +251,8 @@ return rr, off, err
o("rr.%s, off, err = unpackStringBase64(msg, off, rdStart + int(rr.Hdr.Rdlength))\n") o("rr.%s, off, err = unpackStringBase64(msg, off, rdStart + int(rr.Hdr.Rdlength))\n")
case `dns:"hex"`: case `dns:"hex"`:
o("rr.%s, off, err = unpackStringHex(msg, off, rdStart + int(rr.Hdr.Rdlength))\n") o("rr.%s, off, err = unpackStringHex(msg, off, rdStart + int(rr.Hdr.Rdlength))\n")
case `dns:"any"`:
o("rr.%s, off, err = unpackStringAny(msg, off, rdStart + int(rr.Hdr.Rdlength))\n")
case `dns:"octet"`: case `dns:"octet"`:
o("rr.%s, off, err = unpackStringOctet(msg, off)\n") o("rr.%s, off, err = unpackStringOctet(msg, off)\n")
case "": case "":
@ -287,22 +276,13 @@ return rr, off, err
// If we've hit len(msg) we return without error. // If we've hit len(msg) we return without error.
if i < st.NumFields()-1 { if i < st.NumFields()-1 {
fmt.Fprintf(b, `if off == len(msg) { fmt.Fprintf(b, `if off == len(msg) {
return rr, off, nil return off, nil
} }
`) `)
} }
} }
fmt.Fprintf(b, "return rr, off, err }\n\n") fmt.Fprintf(b, "return off, nil }\n\n")
} }
// Generate typeToUnpack map
fmt.Fprintln(b, "var typeToUnpack = map[uint16]func(RR_Header, []byte, int) (RR, int, error){")
for _, name := range namedTypes {
if name == "RFC3597" {
continue
}
fmt.Fprintf(b, "Type%s: unpack%s,\n", name, name)
}
fmt.Fprintln(b, "}\n")
// gofmt // gofmt
res, err := format.Source(b.Bytes()) res, err := format.Source(b.Bytes())

View file

@ -6,7 +6,7 @@ import (
"encoding/binary" "encoding/binary"
"encoding/hex" "encoding/hex"
"net" "net"
"strconv" "strings"
) )
// helper functions called from the generated zmsg.go // helper functions called from the generated zmsg.go
@ -99,14 +99,14 @@ func unpackHeader(msg []byte, off int) (rr RR_Header, off1 int, truncmsg []byte,
return hdr, off, msg, err return hdr, off, msg, err
} }
// pack packs an RR header, returning the offset to the end of the header. // packHeader packs an RR header, returning the offset to the end of the header.
// See PackDomainName for documentation about the compression. // See PackDomainName for documentation about the compression.
func (hdr RR_Header) pack(msg []byte, off int, compression map[string]int, compress bool) (off1 int, err error) { func (hdr RR_Header) packHeader(msg []byte, off int, compression compressionMap, compress bool) (int, error) {
if off == len(msg) { if off == len(msg) {
return off, nil return off, nil
} }
off, err = PackDomainName(hdr.Name, msg, off, compression, compress) off, err := packDomainName(hdr.Name, msg, off, compression, compress)
if err != nil { if err != nil {
return len(msg), err return len(msg), err
} }
@ -122,7 +122,7 @@ func (hdr RR_Header) pack(msg []byte, off int, compression map[string]int, compr
if err != nil { if err != nil {
return len(msg), err return len(msg), err
} }
off, err = packUint16(hdr.Rdlength, msg, off) off, err = packUint16(0, msg, off) // The RDLENGTH field will be set later in packRR.
if err != nil { if err != nil {
return len(msg), err return len(msg), err
} }
@ -141,20 +141,24 @@ func truncateMsgFromRdlength(msg []byte, off int, rdlength uint16) (truncmsg []b
return msg[:lenrd], nil return msg[:lenrd], nil
} }
var base32HexNoPadEncoding = base32.HexEncoding.WithPadding(base32.NoPadding)
func fromBase32(s []byte) (buf []byte, err error) { func fromBase32(s []byte) (buf []byte, err error) {
for i, b := range s { for i, b := range s {
if b >= 'a' && b <= 'z' { if b >= 'a' && b <= 'z' {
s[i] = b - 32 s[i] = b - 32
} }
} }
buflen := base32.HexEncoding.DecodedLen(len(s)) buflen := base32HexNoPadEncoding.DecodedLen(len(s))
buf = make([]byte, buflen) buf = make([]byte, buflen)
n, err := base32.HexEncoding.Decode(buf, s) n, err := base32HexNoPadEncoding.Decode(buf, s)
buf = buf[:n] buf = buf[:n]
return return
} }
func toBase32(b []byte) string { return base32.HexEncoding.EncodeToString(b) } func toBase32(b []byte) string {
return base32HexNoPadEncoding.EncodeToString(b)
}
func fromBase64(s []byte) (buf []byte, err error) { func fromBase64(s []byte) (buf []byte, err error) {
buflen := base64.StdEncoding.DecodedLen(len(s)) buflen := base64.StdEncoding.DecodedLen(len(s))
@ -173,14 +177,14 @@ func unpackUint8(msg []byte, off int) (i uint8, off1 int, err error) {
if off+1 > len(msg) { if off+1 > len(msg) {
return 0, len(msg), &Error{err: "overflow unpacking uint8"} return 0, len(msg), &Error{err: "overflow unpacking uint8"}
} }
return uint8(msg[off]), off + 1, nil return msg[off], off + 1, nil
} }
func packUint8(i uint8, msg []byte, off int) (off1 int, err error) { func packUint8(i uint8, msg []byte, off int) (off1 int, err error) {
if off+1 > len(msg) { if off+1 > len(msg) {
return len(msg), &Error{err: "overflow packing uint8"} return len(msg), &Error{err: "overflow packing uint8"}
} }
msg[off] = byte(i) msg[off] = i
return off + 1, nil return off + 1, nil
} }
@ -219,8 +223,8 @@ func unpackUint48(msg []byte, off int) (i uint64, off1 int, err error) {
return 0, len(msg), &Error{err: "overflow unpacking uint64 as uint48"} return 0, len(msg), &Error{err: "overflow unpacking uint64 as uint48"}
} }
// Used in TSIG where the last 48 bits are occupied, so for now, assume a uint48 (6 bytes) // Used in TSIG where the last 48 bits are occupied, so for now, assume a uint48 (6 bytes)
i = (uint64(uint64(msg[off])<<40 | uint64(msg[off+1])<<32 | uint64(msg[off+2])<<24 | uint64(msg[off+3])<<16 | i = uint64(msg[off])<<40 | uint64(msg[off+1])<<32 | uint64(msg[off+2])<<24 | uint64(msg[off+3])<<16 |
uint64(msg[off+4])<<8 | uint64(msg[off+5]))) uint64(msg[off+4])<<8 | uint64(msg[off+5])
off += 6 off += 6
return i, off, nil return i, off, nil
} }
@ -263,29 +267,21 @@ func unpackString(msg []byte, off int) (string, int, error) {
if off+l+1 > len(msg) { if off+l+1 > len(msg) {
return "", off, &Error{err: "overflow unpacking txt"} return "", off, &Error{err: "overflow unpacking txt"}
} }
s := make([]byte, 0, l) var s strings.Builder
s.Grow(l)
for _, b := range msg[off+1 : off+1+l] { for _, b := range msg[off+1 : off+1+l] {
switch b { switch {
case '"', '\\': case b == '"' || b == '\\':
s = append(s, '\\', b) s.WriteByte('\\')
s.WriteByte(b)
case b < ' ' || b > '~': // unprintable
s.WriteString(escapeByte(b))
default: default:
if b < 32 || b > 127 { // unprintable s.WriteByte(b)
var buf [3]byte
bufs := strconv.AppendInt(buf[:0], int64(b), 10)
s = append(s, '\\')
for i := 0; i < 3-len(bufs); i++ {
s = append(s, '0')
}
for _, r := range bufs {
s = append(s, r)
}
} else {
s = append(s, b)
}
} }
} }
off += 1 + l off += 1 + l
return string(s), off, nil return s.String(), off, nil
} }
func packString(s string, msg []byte, off int) (int, error) { func packString(s string, msg []byte, off int) (int, error) {
@ -359,7 +355,7 @@ func packStringHex(s string, msg []byte, off int) (int, error) {
if err != nil { if err != nil {
return len(msg), err return len(msg), err
} }
if off+(len(h)) > len(msg) { if off+len(h) > len(msg) {
return len(msg), &Error{err: "overflow packing hex"} return len(msg), &Error{err: "overflow packing hex"}
} }
copy(msg[off:off+len(h)], h) copy(msg[off:off+len(h)], h)
@ -367,6 +363,22 @@ func packStringHex(s string, msg []byte, off int) (int, error) {
return off, nil return off, nil
} }
func unpackStringAny(msg []byte, off, end int) (string, int, error) {
if end > len(msg) {
return "", len(msg), &Error{err: "overflow unpacking anything"}
}
return string(msg[off:end]), end, nil
}
func packStringAny(s string, msg []byte, off int) (int, error) {
if off+len(s) > len(msg) {
return len(msg), &Error{err: "overflow packing anything"}
}
copy(msg[off:off+len(s)], s)
off += len(s)
return off, nil
}
func unpackStringTxt(msg []byte, off int) ([]string, int, error) { func unpackStringTxt(msg []byte, off int) ([]string, int, error) {
txt, off, err := unpackTxt(msg, off) txt, off, err := unpackTxt(msg, off)
if err != nil { if err != nil {
@ -387,7 +399,7 @@ func packStringTxt(s []string, msg []byte, off int) (int, error) {
func unpackDataOpt(msg []byte, off int) ([]EDNS0, int, error) { func unpackDataOpt(msg []byte, off int) ([]EDNS0, int, error) {
var edns []EDNS0 var edns []EDNS0
Option: Option:
code := uint16(0) var code uint16
if off+4 > len(msg) { if off+4 > len(msg) {
return nil, len(msg), &Error{err: "overflow unpacking opt"} return nil, len(msg), &Error{err: "overflow unpacking opt"}
} }
@ -599,7 +611,7 @@ func packDataNsec(bitmap []uint16, msg []byte, off int) (int, error) {
// Setting the octets length // Setting the octets length
msg[off+1] = byte(length) 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+1+int(length)] |= byte(1 << (7 - (t % 8))) msg[off+1+int(length)] |= byte(1 << (7 - t%8))
lastwindow, lastlength = window, length lastwindow, lastlength = window, length
} }
off += int(lastlength) + 2 off += int(lastlength) + 2
@ -625,10 +637,10 @@ func unpackDataDomainNames(msg []byte, off, end int) ([]string, int, error) {
return servers, off, nil return servers, off, nil
} }
func packDataDomainNames(names []string, msg []byte, off int, compression map[string]int, compress bool) (int, error) { func packDataDomainNames(names []string, msg []byte, off int, compression compressionMap, compress bool) (int, error) {
var err error var err error
for j := 0; j < len(names); j++ { for j := 0; j < len(names); j++ {
off, err = PackDomainName(names[j], msg, off, compression, false && compress) off, err = packDomainName(names[j], msg, off, compression, compress)
if err != nil { if err != nil {
return len(msg), err return len(msg), err
} }

47
vendor/github.com/miekg/dns/nsecx.go generated vendored
View file

@ -2,49 +2,44 @@ package dns
import ( import (
"crypto/sha1" "crypto/sha1"
"hash" "encoding/hex"
"strings" "strings"
) )
type saltWireFmt struct {
Salt string `dns:"size-hex"`
}
// HashName hashes a string (label) according to RFC 5155. It returns the hashed string in uppercase. // HashName hashes a string (label) according to RFC 5155. It returns the hashed string in uppercase.
func HashName(label string, ha uint8, iter uint16, salt string) string { func HashName(label string, ha uint8, iter uint16, salt string) string {
saltwire := new(saltWireFmt) if ha != SHA1 {
saltwire.Salt = salt return ""
wire := make([]byte, DefaultMsgSize) }
n, err := packSaltWire(saltwire, wire)
wireSalt := make([]byte, hex.DecodedLen(len(salt)))
n, err := packStringHex(salt, wireSalt, 0)
if err != nil { if err != nil {
return "" return ""
} }
wire = wire[:n] wireSalt = wireSalt[:n]
name := make([]byte, 255) name := make([]byte, 255)
off, err := PackDomainName(strings.ToLower(label), name, 0, nil, false) off, err := PackDomainName(strings.ToLower(label), name, 0, nil, false)
if err != nil { if err != nil {
return "" return ""
} }
name = name[:off] name = name[:off]
var s hash.Hash
switch ha {
case SHA1:
s = sha1.New()
default:
return ""
}
s := sha1.New()
// k = 0 // k = 0
s.Write(name) s.Write(name)
s.Write(wire) s.Write(wireSalt)
nsec3 := s.Sum(nil) nsec3 := s.Sum(nil)
// k > 0 // k > 0
for k := uint16(0); k < iter; k++ { for k := uint16(0); k < iter; k++ {
s.Reset() s.Reset()
s.Write(nsec3) s.Write(nsec3)
s.Write(wire) s.Write(wireSalt)
nsec3 = s.Sum(nsec3[:0]) nsec3 = s.Sum(nsec3[:0])
} }
return toBase32(nsec3) return toBase32(nsec3)
} }
@ -63,8 +58,10 @@ func (rr *NSEC3) Cover(name string) bool {
} }
nextHash := rr.NextDomain nextHash := rr.NextDomain
if ownerHash == nextHash { // empty interval
return false // if empty interval found, try cover wildcard hashes so nameHash shouldn't match with ownerHash
if ownerHash == nextHash && nameHash != ownerHash { // empty interval
return true
} }
if ownerHash > nextHash { // end of zone if ownerHash > nextHash { // end of zone
if nameHash > ownerHash { // covered since there is nothing after ownerHash if nameHash > ownerHash { // covered since there is nothing after ownerHash
@ -96,11 +93,3 @@ func (rr *NSEC3) Match(name string) bool {
} }
return false return false
} }
func packSaltWire(sw *saltWireFmt, msg []byte) (int, error) {
off, err := packStringHex(sw.Salt, msg, 0)
if err != nil {
return off, err
}
return off, nil
}

View file

@ -39,25 +39,30 @@ func mkPrivateRR(rrtype uint16) *PrivateRR {
} }
anyrr := rrfunc() anyrr := rrfunc()
switch rr := anyrr.(type) { rr, ok := anyrr.(*PrivateRR)
case *PrivateRR: if !ok {
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))
} }
return rr
}
// Header return the RR header of r. // 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(off int, compression map[string]struct{}) int {
l := r.Hdr.len(off, compression)
l += r.Data.Len()
return l
}
func (r *PrivateRR) copy() RR { func (r *PrivateRR) copy() RR {
// make new RR like this: // make new RR like this:
rr := mkPrivateRR(r.Hdr.Rrtype) rr := mkPrivateRR(r.Hdr.Rrtype)
newh := r.Hdr.copyHeader() rr.Hdr = r.Hdr
rr.Hdr = *newh
err := r.Data.Copy(rr.Data) err := r.Data.Copy(rr.Data)
if err != nil { if err != nil {
@ -65,21 +70,47 @@ func (r *PrivateRR) copy() RR {
} }
return rr return rr
} }
func (r *PrivateRR) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
off, err := r.Hdr.pack(msg, off, compression, compress) func (r *PrivateRR) pack(msg []byte, off int, compression compressionMap, compress bool) (int, error) {
if err != nil {
return off, err
}
headerEnd := off
n, err := r.Data.Pack(msg[off:]) n, err := r.Data.Pack(msg[off:])
if err != nil { if err != nil {
return len(msg), err return len(msg), err
} }
off += n off += n
r.Header().Rdlength = uint16(off - headerEnd)
return off, nil return off, nil
} }
func (r *PrivateRR) unpack(msg []byte, off int) (int, error) {
off1, err := r.Data.Unpack(msg[off:])
off += off1
return off, err
}
func (r *PrivateRR) parse(c *zlexer, origin, file string) *ParseError {
var l lex
text := make([]string, 0, 2) // could be 0..N elements, median is probably 1
Fetch:
for {
// TODO(miek): we could also be returning _QUOTE, this might or might not
// be an issue (basically parsing TXT becomes hard)
switch l, _ = c.Next(); l.value {
case zNewline, zEOF:
break Fetch
case zString:
text = append(text, l.token)
}
}
err := r.Data.Parse(text)
if err != nil {
return &ParseError{file, err.Error(), l}
}
return nil
}
func (r1 *PrivateRR) isDuplicate(r2 RR) bool { return false }
// PrivateHandle registers a private resource record type. It requires // PrivateHandle registers a private resource record type. It requires
// string and numeric representation of private RR type and generator function as argument. // string and numeric representation of private RR type and generator function as argument.
func PrivateHandle(rtypestr string, rtype uint16, generator func() PrivateRdata) { func PrivateHandle(rtypestr string, rtype uint16, generator func() PrivateRdata) {
@ -88,62 +119,14 @@ func PrivateHandle(rtypestr string, rtype uint16, generator func() PrivateRdata)
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
typeToUnpack[rtype] = func(h RR_Header, msg []byte, off int) (RR, int, error) {
if noRdata(h) {
return &h, off, nil
}
var err error
rr := mkPrivateRR(h.Rrtype)
rr.Hdr = h
off1, err := rr.Data.Unpack(msg[off:])
off += off1
if err != nil {
return rr, off, err
}
return rr, off, err
} }
setPrivateRR := func(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { // PrivateHandleRemove removes definitions required to support private RR type.
rr := mkPrivateRR(h.Rrtype)
rr.Hdr = h
var l lex
text := make([]string, 0, 2) // could be 0..N elements, median is probably 1
Fetch:
for {
// TODO(miek): we could also be returning _QUOTE, this might or might not
// be an issue (basically parsing TXT becomes hard)
switch l = <-c; l.value {
case zNewline, zEOF:
break Fetch
case zString:
text = append(text, l.token)
}
}
err := rr.Data.Parse(text)
if err != nil {
return nil, &ParseError{f, err.Error(), l}, ""
}
return rr, nil, ""
}
typeToparserFunc[rtype] = parserFunc{setPrivateRR, true}
}
// PrivateHandleRemove removes defenitions required to support private RR type.
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(StringToType, rtypestr) delete(StringToType, rtypestr)
delete(typeToUnpack, rtype)
} }
return
} }

View file

@ -1,49 +0,0 @@
package dns
import "encoding/binary"
// rawSetRdlength sets the rdlength in the header of
// the RR. The offset 'off' must be positioned at the
// start of the header of the RR, 'end' must be the
// end of the RR.
func rawSetRdlength(msg []byte, off, end int) bool {
l := len(msg)
Loop:
for {
if off+1 > l {
return false
}
c := int(msg[off])
off++
switch c & 0xC0 {
case 0x00:
if c == 0x00 {
// End of the domainname
break Loop
}
if off+c > l {
return false
}
off += c
case 0xC0:
// pointer, next byte included, ends domainname
off++
break Loop
}
}
// The domainname has been seen, we at the start of the fixed part in the header.
// Type is 2 bytes, class is 2 bytes, ttl 4 and then 2 bytes for the length.
off += 2 + 2 + 4
if off+2 > l {
return false
}
//off+1 is the end of the header, 'end' is the end of the rr
//so 'end' - 'off+2' is the length of the rdata
rdatalen := end - (off + 2)
if rdatalen > 0xFFFF {
return false
}
binary.BigEndian.PutUint16(msg[off:], uint16(rdatalen))
return true
}

View file

@ -12,6 +12,20 @@ var StringToOpcode = reverseInt(OpcodeToString)
// StringToRcode is a map of rcodes to strings. // StringToRcode is a map of rcodes to strings.
var StringToRcode = reverseInt(RcodeToString) var StringToRcode = reverseInt(RcodeToString)
func init() {
// Preserve previous NOTIMP typo, see github.com/miekg/dns/issues/733.
StringToRcode["NOTIMPL"] = RcodeNotImplemented
}
// StringToAlgorithm is the reverse of AlgorithmToString.
var StringToAlgorithm = reverseInt8(AlgorithmToString)
// StringToHash is a map of names to hash IDs.
var StringToHash = reverseInt8(HashToString)
// StringToCertType is the reverseof CertTypeToString.
var StringToCertType = reverseInt16(CertTypeToString)
// 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, len(m)) n := make(map[string]uint8, len(m))

View file

@ -5,6 +5,7 @@ package dns
// rrs. // rrs.
// m is used to store the RRs temporary. If it is nil a new map will be allocated. // m is used to store the RRs temporary. If it is nil a new map will be allocated.
func Dedup(rrs []RR, m map[string]RR) []RR { func Dedup(rrs []RR, m map[string]RR) []RR {
if m == nil { if m == nil {
m = make(map[string]RR) m = make(map[string]RR)
} }
@ -14,10 +15,11 @@ func Dedup(rrs []RR, m map[string]RR) []RR {
for _, r := range rrs { for _, r := range rrs {
key := normalizedString(r) key := normalizedString(r)
keys = append(keys, &key) keys = append(keys, &key)
if _, ok := m[key]; ok { if mr, ok := m[key]; ok {
// Shortest TTL wins. // Shortest TTL wins.
if m[key].Header().Ttl > r.Header().Ttl { rh, mrh := r.Header(), mr.Header()
m[key].Header().Ttl = r.Header().Ttl if mrh.Ttl > rh.Ttl {
mrh.Ttl = rh.Ttl
} }
continue continue
} }

1020
vendor/github.com/miekg/dns/scan.go generated vendored

File diff suppressed because it is too large Load diff

1720
vendor/github.com/miekg/dns/scan_rr.go generated vendored

File diff suppressed because it is too large Load diff

View file

@ -1,56 +0,0 @@
package dns
// Implement a simple scanner, return a byte stream from an io reader.
import (
"bufio"
"context"
"io"
"text/scanner"
)
type scan struct {
src *bufio.Reader
position scanner.Position
eof bool // Have we just seen a eof
ctx context.Context
}
func scanInit(r io.Reader) (*scan, context.CancelFunc) {
s := new(scan)
s.src = bufio.NewReader(r)
s.position.Line = 1
ctx, cancel := context.WithCancel(context.Background())
s.ctx = ctx
return s, cancel
}
// tokenText returns the next byte from the input
func (s *scan) tokenText() (byte, error) {
c, err := s.src.ReadByte()
if err != nil {
return c, err
}
select {
case <-s.ctx.Done():
return c, context.Canceled
default:
break
}
// delay the newline handling until the next token is delivered,
// fixes off-by-one errors when reporting a parse error.
if s.eof == true {
s.position.Line++
s.position.Column = 0
s.eof = false
}
if c == '\n' {
s.eof = true
return c, nil
}
s.position.Column++
return c, nil
}

147
vendor/github.com/miekg/dns/serve_mux.go generated vendored Normal file
View file

@ -0,0 +1,147 @@
package dns
import (
"strings"
"sync"
)
// ServeMux is an DNS request multiplexer. It matches the zone name of
// each incoming request against a list of registered patterns add calls
// the handler for the pattern that most closely matches the zone name.
//
// ServeMux is DNSSEC aware, meaning that queries for the DS record are
// redirected to the parent zone (if that is also registered), otherwise
// the child gets the query.
//
// ServeMux is also safe for concurrent access from multiple goroutines.
//
// The zero ServeMux is empty and ready for use.
type ServeMux struct {
z map[string]Handler
m sync.RWMutex
}
// NewServeMux allocates and returns a new ServeMux.
func NewServeMux() *ServeMux {
return new(ServeMux)
}
// DefaultServeMux is the default ServeMux used by Serve.
var DefaultServeMux = NewServeMux()
func (mux *ServeMux) match(q string, t uint16) Handler {
mux.m.RLock()
defer mux.m.RUnlock()
if mux.z == nil {
return nil
}
var handler Handler
// TODO(tmthrgd): Once https://go-review.googlesource.com/c/go/+/137575
// lands in a go release, replace the following with strings.ToLower.
var sb strings.Builder
for i := 0; i < len(q); i++ {
c := q[i]
if !(c >= 'A' && c <= 'Z') {
continue
}
sb.Grow(len(q))
sb.WriteString(q[:i])
for ; i < len(q); i++ {
c := q[i]
if c >= 'A' && c <= 'Z' {
c += 'a' - 'A'
}
sb.WriteByte(c)
}
q = sb.String()
break
}
for off, end := 0, false; !end; off, end = NextLabel(q, off) {
if h, ok := mux.z[q[off:]]; ok {
if t != TypeDS {
return h
}
// Continue for DS to see if we have a parent too, if so delegate to the parent
handler = h
}
}
// Wildcard match, if we have found nothing try the root zone as a last resort.
if h, ok := mux.z["."]; ok {
return h
}
return handler
}
// Handle adds a handler to the ServeMux for pattern.
func (mux *ServeMux) Handle(pattern string, handler Handler) {
if pattern == "" {
panic("dns: invalid pattern " + pattern)
}
mux.m.Lock()
if mux.z == nil {
mux.z = make(map[string]Handler)
}
mux.z[Fqdn(pattern)] = handler
mux.m.Unlock()
}
// HandleFunc adds a handler function to the ServeMux for pattern.
func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Msg)) {
mux.Handle(pattern, HandlerFunc(handler))
}
// HandleRemove deregisters the handler specific for pattern from the ServeMux.
func (mux *ServeMux) HandleRemove(pattern string) {
if pattern == "" {
panic("dns: invalid pattern " + pattern)
}
mux.m.Lock()
delete(mux.z, Fqdn(pattern))
mux.m.Unlock()
}
// ServeDNS dispatches the request to the handler whose pattern most
// closely matches the request message.
//
// ServeDNS is DNSSEC aware, meaning that queries for the DS record
// are redirected to the parent zone (if that is also registered),
// otherwise the child gets the query.
//
// If no handler is found, or there is no question, a standard SERVFAIL
// message is returned
func (mux *ServeMux) ServeDNS(w ResponseWriter, req *Msg) {
var h Handler
if len(req.Question) >= 1 { // allow more than one question
h = mux.match(req.Question[0].Name, req.Question[0].Qtype)
}
if h != nil {
h.ServeDNS(w, req)
} else {
HandleFailed(w, req)
}
}
// Handle registers the handler with the given pattern
// in the DefaultServeMux. The documentation for
// ServeMux explains how patterns are matched.
func Handle(pattern string, handler Handler) { DefaultServeMux.Handle(pattern, handler) }
// HandleRemove deregisters the handle with the given pattern
// in the DefaultServeMux.
func HandleRemove(pattern string) { DefaultServeMux.HandleRemove(pattern) }
// HandleFunc registers the handler function with the given pattern
// in the DefaultServeMux.
func HandleFunc(pattern string, handler func(ResponseWriter, *Msg)) {
DefaultServeMux.HandleFunc(pattern, handler)
}

711
vendor/github.com/miekg/dns/server.go generated vendored
View file

@ -4,22 +4,54 @@ package dns
import ( import (
"bytes" "bytes"
"context"
"crypto/tls" "crypto/tls"
"encoding/binary" "encoding/binary"
"errors"
"io" "io"
"net" "net"
"strings"
"sync" "sync"
"sync/atomic"
"time" "time"
) )
// Maximum number of TCP queries before we close the socket. // Default maximum number of TCP queries before we close the socket.
const maxTCPQueries = 128 const maxTCPQueries = 128
// The maximum number of idle workers.
//
// This controls the maximum number of workers that are allowed to stay
// idle waiting for incoming requests before being torn down.
//
// If this limit is reached, the server will just keep spawning new
// workers (goroutines) for each incoming request. In this case, each
// worker will only be used for a single request.
const maxIdleWorkersCount = 10000
// The maximum length of time a worker may idle for before being destroyed.
const idleWorkerTimeout = 10 * time.Second
// aLongTimeAgo is a non-zero time, far in the past, used for
// immediate cancelation of network operations.
var aLongTimeAgo = time.Unix(1, 0)
// Handler is implemented by any value that implements ServeDNS. // 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)
} }
// The HandlerFunc type is an adapter to allow the use of
// ordinary functions as DNS handlers. If f is a function
// with the appropriate signature, HandlerFunc(f) is a
// Handler object that calls f.
type HandlerFunc func(ResponseWriter, *Msg)
// ServeDNS calls f(w, r).
func (f HandlerFunc) ServeDNS(w ResponseWriter, r *Msg) {
f(w, r)
}
// A ResponseWriter interface is used by an DNS handler to // A ResponseWriter interface is used by an DNS handler to
// construct an DNS response. // construct an DNS response.
type ResponseWriter interface { type ResponseWriter interface {
@ -42,46 +74,25 @@ type ResponseWriter interface {
Hijack() Hijack()
} }
// A ConnectionStater interface is used by a DNS Handler to access TLS connection state
// when available.
type ConnectionStater interface {
ConnectionState() *tls.ConnectionState
}
type response struct { type response struct {
msg []byte
closed bool // connection has been closed
hijacked bool // connection has been hijacked by handler hijacked bool // connection has been hijacked by handler
tsigStatus error
tsigTimersOnly bool tsigTimersOnly bool
tsigStatus error
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.Conn // 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
writer Writer // writer to output the raw DNS bits writer Writer // writer to output the raw DNS bits
} wg *sync.WaitGroup // for gracefull shutdown
// ServeMux is an DNS request multiplexer. It matches the
// zone name of each incoming request against a list of
// registered patterns add calls the handler for the pattern
// that most closely matches the zone name. ServeMux is DNSSEC aware, meaning
// that queries for the DS record are redirected to the parent zone (if that
// is also registered), otherwise the child gets the query.
// ServeMux is also safe for concurrent access from multiple goroutines.
type ServeMux struct {
z map[string]Handler
m *sync.RWMutex
}
// NewServeMux allocates and returns a new ServeMux.
func NewServeMux() *ServeMux { return &ServeMux{z: make(map[string]Handler), m: new(sync.RWMutex)} }
// DefaultServeMux is the default ServeMux used by Serve.
var DefaultServeMux = NewServeMux()
// The HandlerFunc type is an adapter to allow the use of
// ordinary functions as DNS handlers. If f is a function
// with the appropriate signature, HandlerFunc(f) is a
// Handler object that calls f.
type HandlerFunc func(ResponseWriter, *Msg)
// ServeDNS calls f(w, r).
func (f HandlerFunc) ServeDNS(w ResponseWriter, r *Msg) {
f(w, r)
} }
// HandleFailed returns a HandlerFunc that returns SERVFAIL for every request it gets. // HandleFailed returns a HandlerFunc that returns SERVFAIL for every request it gets.
@ -92,8 +103,6 @@ func HandleFailed(w ResponseWriter, r *Msg) {
w.WriteMsg(m) w.WriteMsg(m)
} }
func failedHandler() Handler { return HandlerFunc(HandleFailed) }
// ListenAndServe Starts a server on address and network specified 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 {
@ -132,99 +141,6 @@ func ActivateAndServe(l net.Listener, p net.PacketConn, handler Handler) error {
return server.ActivateAndServe() return server.ActivateAndServe()
} }
func (mux *ServeMux) match(q string, t uint16) Handler {
mux.m.RLock()
defer mux.m.RUnlock()
var handler Handler
b := make([]byte, len(q)) // worst case, one label of length q
off := 0
end := false
for {
l := len(q[off:])
for i := 0; i < l; i++ {
b[i] = q[off+i]
if b[i] >= 'A' && b[i] <= 'Z' {
b[i] |= ('a' - 'A')
}
}
if h, ok := mux.z[string(b[:l])]; ok { // causes garbage, might want to change the map key
if t != TypeDS {
return h
}
// Continue for DS to see if we have a parent too, if so delegeate to the parent
handler = h
}
off, end = NextLabel(q, off)
if end {
break
}
}
// Wildcard match, if we have found nothing try the root zone as a last resort.
if h, ok := mux.z["."]; ok {
return h
}
return handler
}
// Handle adds a handler to the ServeMux for pattern.
func (mux *ServeMux) Handle(pattern string, handler Handler) {
if pattern == "" {
panic("dns: invalid pattern " + pattern)
}
mux.m.Lock()
mux.z[Fqdn(pattern)] = handler
mux.m.Unlock()
}
// HandleFunc adds a handler function to the ServeMux for pattern.
func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Msg)) {
mux.Handle(pattern, HandlerFunc(handler))
}
// HandleRemove deregistrars the handler specific for pattern from the ServeMux.
func (mux *ServeMux) HandleRemove(pattern string) {
if pattern == "" {
panic("dns: invalid pattern " + pattern)
}
mux.m.Lock()
delete(mux.z, Fqdn(pattern))
mux.m.Unlock()
}
// ServeDNS dispatches the request to the handler whose
// pattern most closely matches the request message. If DefaultServeMux
// is used the correct thing for DS queries is done: a possible parent
// is sought.
// If no handler is found a standard SERVFAIL message is returned
// If the request message does not have exactly one question in the
// question section a SERVFAIL is returned, unlesss Unsafe is true.
func (mux *ServeMux) ServeDNS(w ResponseWriter, request *Msg) {
var h Handler
if len(request.Question) < 1 { // allow more than one question
h = failedHandler()
} else {
if h = mux.match(request.Question[0].Name, request.Question[0].Qtype); h == nil {
h = failedHandler()
}
}
h.ServeDNS(w, request)
}
// Handle registers the handler with the given pattern
// in the DefaultServeMux. The documentation for
// ServeMux explains how patterns are matched.
func Handle(pattern string, handler Handler) { DefaultServeMux.Handle(pattern, handler) }
// HandleRemove deregisters the handle with the given pattern
// in the DefaultServeMux.
func HandleRemove(pattern string) { DefaultServeMux.HandleRemove(pattern) }
// HandleFunc registers the handler function with the given pattern
// in the DefaultServeMux.
func HandleFunc(pattern string, handler func(ResponseWriter, *Msg)) {
DefaultServeMux.HandleFunc(pattern, handler)
}
// Writer writes raw DNS messages; each call to Write should send an entire message. // Writer writes raw DNS messages; each call to Write should send an entire message.
type Writer interface { type Writer interface {
io.Writer io.Writer
@ -246,11 +162,11 @@ type defaultReader struct {
*Server *Server
} }
func (dr *defaultReader) ReadTCP(conn net.Conn, timeout time.Duration) ([]byte, error) { func (dr defaultReader) ReadTCP(conn net.Conn, timeout time.Duration) ([]byte, error) {
return dr.readTCP(conn, timeout) return dr.readTCP(conn, timeout)
} }
func (dr *defaultReader) ReadUDP(conn *net.UDPConn, timeout time.Duration) ([]byte, *SessionUDP, error) { func (dr defaultReader) ReadUDP(conn *net.UDPConn, timeout time.Duration) ([]byte, *SessionUDP, error) {
return dr.readUDP(conn, timeout) return dr.readUDP(conn, timeout)
} }
@ -287,87 +203,170 @@ type Server struct {
IdleTimeout func() time.Duration IdleTimeout func() time.Duration
// Secret(s) for Tsig map[<zonename>]<base64 secret>. The zonename must be in canonical form (lowercase, fqdn, see RFC 4034 Section 6.2). // Secret(s) for Tsig map[<zonename>]<base64 secret>. The zonename must be in canonical form (lowercase, fqdn, see RFC 4034 Section 6.2).
TsigSecret map[string]string TsigSecret map[string]string
// Unsafe instructs the server to disregard any sanity checks and directly hand the message to
// the handler. It will specifically not check if the query has the QR bit not set.
Unsafe bool
// If NotifyStartedFunc is set it 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 is optional, allows customization of the process that reads raw DNS messages.
DecorateReader DecorateReader DecorateReader DecorateReader
// DecorateWriter is optional, allows customization of the process that writes raw DNS messages. // DecorateWriter is optional, allows customization of the process that writes raw DNS messages.
DecorateWriter DecorateWriter DecorateWriter DecorateWriter
// Maximum number of TCP queries before we close the socket. Default is maxTCPQueries (unlimited if -1).
MaxTCPQueries int
// Whether to set the SO_REUSEPORT socket option, allowing multiple listeners to be bound to a single address.
// It is only supported on go1.11+ and when using ListenAndServe.
ReusePort bool
// AcceptMsgFunc will check the incoming message and will reject it early in the process.
// By default DefaultMsgAcceptFunc will be used.
MsgAcceptFunc MsgAcceptFunc
// UDP packet or TCP connection queue
queue chan *response
// Workers count
workersCount int32
// Shutdown handling // Shutdown handling
lock sync.RWMutex lock sync.RWMutex
started bool started bool
shutdown chan struct{}
conns map[net.Conn]struct{}
// A pool for UDP message buffers.
udpPool sync.Pool
}
func (srv *Server) isStarted() bool {
srv.lock.RLock()
started := srv.started
srv.lock.RUnlock()
return started
}
func (srv *Server) worker(w *response) {
srv.serve(w)
for {
count := atomic.LoadInt32(&srv.workersCount)
if count > maxIdleWorkersCount {
return
}
if atomic.CompareAndSwapInt32(&srv.workersCount, count, count+1) {
break
}
}
defer atomic.AddInt32(&srv.workersCount, -1)
inUse := false
timeout := time.NewTimer(idleWorkerTimeout)
defer timeout.Stop()
LOOP:
for {
select {
case w, ok := <-srv.queue:
if !ok {
break LOOP
}
inUse = true
srv.serve(w)
case <-timeout.C:
if !inUse {
break LOOP
}
inUse = false
timeout.Reset(idleWorkerTimeout)
}
}
}
func (srv *Server) spawnWorker(w *response) {
select {
case srv.queue <- w:
default:
go srv.worker(w)
}
}
func makeUDPBuffer(size int) func() interface{} {
return func() interface{} {
return make([]byte, size)
}
}
func (srv *Server) init() {
srv.queue = make(chan *response)
srv.shutdown = make(chan struct{})
srv.conns = make(map[net.Conn]struct{})
if srv.UDPSize == 0 {
srv.UDPSize = MinMsgSize
}
if srv.MsgAcceptFunc == nil {
srv.MsgAcceptFunc = defaultMsgAcceptFunc
}
srv.udpPool.New = makeUDPBuffer(srv.UDPSize)
}
func unlockOnce(l sync.Locker) func() {
var once sync.Once
return func() { once.Do(l.Unlock) }
} }
// 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 {
unlock := unlockOnce(&srv.lock)
srv.lock.Lock() srv.lock.Lock()
defer srv.lock.Unlock() defer unlock()
if srv.started { if srv.started {
return &Error{err: "server already started"} return &Error{err: "server already started"}
} }
addr := srv.Addr addr := srv.Addr
if addr == "" { if addr == "" {
addr = ":domain" addr = ":domain"
} }
if srv.UDPSize == 0 {
srv.UDPSize = MinMsgSize srv.init()
} defer close(srv.queue)
switch srv.Net { switch srv.Net {
case "tcp", "tcp4", "tcp6": case "tcp", "tcp4", "tcp6":
a, err := net.ResolveTCPAddr(srv.Net, addr) l, err := listenTCP(srv.Net, addr, srv.ReusePort)
if err != nil {
return err
}
l, err := net.ListenTCP(srv.Net, a)
if err != nil { if err != nil {
return err return err
} }
srv.Listener = l srv.Listener = l
srv.started = true srv.started = true
srv.lock.Unlock() unlock()
err = srv.serveTCP(l) return srv.serveTCP(l)
srv.lock.Lock() // to satisfy the defer at the top
return err
case "tcp-tls", "tcp4-tls", "tcp6-tls": case "tcp-tls", "tcp4-tls", "tcp6-tls":
network := "tcp" if srv.TLSConfig == nil || (len(srv.TLSConfig.Certificates) == 0 && srv.TLSConfig.GetCertificate == nil) {
if srv.Net == "tcp4-tls" { return errors.New("dns: neither Certificates nor GetCertificate set in Config")
network = "tcp4"
} else if srv.Net == "tcp6-tls" {
network = "tcp6"
} }
network := strings.TrimSuffix(srv.Net, "-tls")
l, err := tls.Listen(network, addr, srv.TLSConfig) l, err := listenTCP(network, addr, srv.ReusePort)
if err != nil { if err != nil {
return err return err
} }
l = tls.NewListener(l, srv.TLSConfig)
srv.Listener = l srv.Listener = l
srv.started = true srv.started = true
srv.lock.Unlock() unlock()
err = srv.serveTCP(l) return srv.serveTCP(l)
srv.lock.Lock() // to satisfy the defer at the top
return err
case "udp", "udp4", "udp6": case "udp", "udp4", "udp6":
a, err := net.ResolveUDPAddr(srv.Net, addr) l, err := listenUDP(srv.Net, addr, srv.ReusePort)
if err != nil { if err != nil {
return err return err
} }
l, err := net.ListenUDP(srv.Net, a) u := l.(*net.UDPConn)
if err != nil { if e := setUDPSocketOptions(u); e != nil {
return err
}
if e := setUDPSocketOptions(l); e != nil {
return e return e
} }
srv.PacketConn = l srv.PacketConn = l
srv.started = true srv.started = true
srv.lock.Unlock() unlock()
err = srv.serveUDP(l) return srv.serveUDP(u)
srv.lock.Lock() // to satisfy the defer at the top
return err
} }
return &Error{err: "bad network"} return &Error{err: "bad network"}
} }
@ -375,17 +374,20 @@ func (srv *Server) ListenAndServe() error {
// ActivateAndServe starts a nameserver with the PacketConn or Listener // ActivateAndServe starts a nameserver with the PacketConn or Listener
// 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 {
unlock := unlockOnce(&srv.lock)
srv.lock.Lock() srv.lock.Lock()
defer srv.lock.Unlock() defer unlock()
if srv.started { if srv.started {
return &Error{err: "server already started"} return &Error{err: "server already started"}
} }
srv.init()
defer close(srv.queue)
pConn := srv.PacketConn pConn := srv.PacketConn
l := srv.Listener l := srv.Listener
if pConn != nil { if pConn != nil {
if srv.UDPSize == 0 {
srv.UDPSize = MinMsgSize
}
// Check PacketConn interface's type is valid and value // Check PacketConn interface's type is valid and value
// is not nil // is not nil
if t, ok := pConn.(*net.UDPConn); ok && t != nil { if t, ok := pConn.(*net.UDPConn); ok && t != nil {
@ -393,18 +395,14 @@ func (srv *Server) ActivateAndServe() error {
return e return e
} }
srv.started = true srv.started = true
srv.lock.Unlock() unlock()
e := srv.serveUDP(t) return srv.serveUDP(t)
srv.lock.Lock() // to satisfy the defer at the top
return e
} }
} }
if l != nil { if l != nil {
srv.started = true srv.started = true
srv.lock.Unlock() unlock()
e := srv.serveTCP(l) return 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"}
} }
@ -412,34 +410,66 @@ func (srv *Server) ActivateAndServe() error {
// Shutdown shuts down a server. After a call to Shutdown, ListenAndServe and // Shutdown shuts down a server. After a call to Shutdown, ListenAndServe and
// ActivateAndServe will return. // ActivateAndServe will return.
func (srv *Server) Shutdown() error { func (srv *Server) Shutdown() error {
return srv.ShutdownContext(context.Background())
}
// ShutdownContext shuts down a server. After a call to ShutdownContext,
// ListenAndServe and ActivateAndServe will return.
//
// A context.Context may be passed to limit how long to wait for connections
// to terminate.
func (srv *Server) ShutdownContext(ctx context.Context) error {
srv.lock.Lock() srv.lock.Lock()
if !srv.started { if !srv.started {
srv.lock.Unlock() srv.lock.Unlock()
return &Error{err: "server not started"} return &Error{err: "server not started"}
} }
srv.started = false srv.started = false
if srv.PacketConn != nil {
srv.PacketConn.SetReadDeadline(aLongTimeAgo) // Unblock reads
}
if srv.Listener != nil {
srv.Listener.Close()
}
for rw := range srv.conns {
rw.SetReadDeadline(aLongTimeAgo) // Unblock reads
}
srv.lock.Unlock() srv.lock.Unlock()
if testShutdownNotify != nil {
testShutdownNotify.Broadcast()
}
var ctxErr error
select {
case <-srv.shutdown:
case <-ctx.Done():
ctxErr = ctx.Err()
}
if srv.PacketConn != nil { if srv.PacketConn != nil {
srv.PacketConn.Close() srv.PacketConn.Close()
} }
if srv.Listener != nil {
srv.Listener.Close() return ctxErr
}
return nil
} }
var testShutdownNotify *sync.Cond
// getReadTimeout is a helper func to use system timeout if server did not intend to change it. // getReadTimeout is a helper func to use system timeout if server did not intend to change it.
func (srv *Server) getReadTimeout() time.Duration { func (srv *Server) getReadTimeout() time.Duration {
rtimeout := dnsTimeout
if srv.ReadTimeout != 0 { if srv.ReadTimeout != 0 {
rtimeout = srv.ReadTimeout return srv.ReadTimeout
} }
return rtimeout return dnsTimeout
} }
// serveTCP starts a TCP listener for the server. // serveTCP starts a TCP listener for the server.
// Each request is handled in a separate goroutine.
func (srv *Server) serveTCP(l net.Listener) error { func (srv *Server) serveTCP(l net.Listener) error {
defer l.Close() defer l.Close()
@ -447,44 +477,39 @@ func (srv *Server) serveTCP(l net.Listener) error {
srv.NotifyStartedFunc() srv.NotifyStartedFunc()
} }
reader := Reader(&defaultReader{srv}) var wg sync.WaitGroup
if srv.DecorateReader != nil { defer func() {
reader = srv.DecorateReader(reader) wg.Wait()
} close(srv.shutdown)
}()
handler := srv.Handler for srv.isStarted() {
if handler == nil {
handler = DefaultServeMux
}
rtimeout := srv.getReadTimeout()
// deadline is not used here
for {
rw, err := l.Accept() rw, err := l.Accept()
srv.lock.RLock() if err != nil {
if !srv.started { if !srv.isStarted() {
srv.lock.RUnlock()
return nil return nil
} }
srv.lock.RUnlock()
if err != nil {
if neterr, ok := err.(net.Error); ok && neterr.Temporary() { if neterr, ok := err.(net.Error); ok && neterr.Temporary() {
continue continue
} }
return err return err
} }
go func() { srv.lock.Lock()
m, err := reader.ReadTCP(rw, rtimeout) // Track the connection to allow unblocking reads on shutdown.
if err != nil { srv.conns[rw] = struct{}{}
rw.Close() srv.lock.Unlock()
return wg.Add(1)
} srv.spawnWorker(&response{
srv.serve(rw.RemoteAddr(), handler, m, nil, nil, rw) tsigSecret: srv.TsigSecret,
}() tcp: rw,
wg: &wg,
})
} }
return nil
} }
// serveUDP starts a UDP listener for the server. // serveUDP starts a UDP listener for the server.
// 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()
@ -492,112 +517,187 @@ func (srv *Server) serveUDP(l *net.UDPConn) error {
srv.NotifyStartedFunc() srv.NotifyStartedFunc()
} }
reader := Reader(&defaultReader{srv}) reader := Reader(defaultReader{srv})
if srv.DecorateReader != nil { if srv.DecorateReader != nil {
reader = srv.DecorateReader(reader) reader = srv.DecorateReader(reader)
} }
handler := srv.Handler var wg sync.WaitGroup
if handler == nil { defer func() {
handler = DefaultServeMux wg.Wait()
} close(srv.shutdown)
}()
rtimeout := srv.getReadTimeout() rtimeout := srv.getReadTimeout()
// deadline is not used here // deadline is not used here
for { for srv.isStarted() {
m, s, err := reader.ReadUDP(l, rtimeout) m, s, err := reader.ReadUDP(l, rtimeout)
srv.lock.RLock() if err != nil {
if !srv.started { if !srv.isStarted() {
srv.lock.RUnlock()
return nil return nil
} }
srv.lock.RUnlock()
if err != nil {
if netErr, ok := err.(net.Error); ok && netErr.Temporary() { if netErr, ok := err.(net.Error); ok && netErr.Temporary() {
continue continue
} }
return err return err
} }
if len(m) < headerSize { if len(m) < headerSize {
if cap(m) == srv.UDPSize {
srv.udpPool.Put(m[:srv.UDPSize])
}
continue continue
} }
go srv.serve(s.RemoteAddr(), handler, m, l, s, nil) wg.Add(1)
} srv.spawnWorker(&response{
msg: m,
tsigSecret: srv.TsigSecret,
udp: l,
udpSession: s,
wg: &wg,
})
} }
// Serve a new connection. return nil
func (srv *Server) serve(a net.Addr, h Handler, m []byte, u *net.UDPConn, s *SessionUDP, t net.Conn) { }
w := &response{tsigSecret: srv.TsigSecret, udp: u, tcp: t, remoteAddr: a, udpSession: s}
func (srv *Server) serve(w *response) {
if srv.DecorateWriter != nil { if srv.DecorateWriter != nil {
w.writer = srv.DecorateWriter(w) w.writer = srv.DecorateWriter(w)
} else { } else {
w.writer = w w.writer = w
} }
q := 0 // counter for the amount of TCP queries we get if w.udp != nil {
// serve UDP
srv.serveDNS(w)
reader := Reader(&defaultReader{srv}) w.wg.Done()
return
}
defer func() {
if !w.hijacked {
w.Close()
}
srv.lock.Lock()
delete(srv.conns, w.tcp)
srv.lock.Unlock()
w.wg.Done()
}()
reader := Reader(defaultReader{srv})
if srv.DecorateReader != nil { if srv.DecorateReader != nil {
reader = srv.DecorateReader(reader) reader = srv.DecorateReader(reader)
} }
Redo:
req := new(Msg) idleTimeout := tcpIdleTimeout
err := req.Unpack(m) if srv.IdleTimeout != nil {
if err != nil { // Send a FormatError back idleTimeout = srv.IdleTimeout()
x := new(Msg)
x.SetRcodeFormatError(req)
w.WriteMsg(x)
goto Exit
} }
if !srv.Unsafe && req.Response {
goto Exit timeout := srv.getReadTimeout()
limit := srv.MaxTCPQueries
if limit == 0 {
limit = maxTCPQueries
}
for q := 0; (q < limit || limit == -1) && srv.isStarted(); q++ {
var err error
w.msg, err = reader.ReadTCP(w.tcp, timeout)
if err != nil {
// TODO(tmthrgd): handle error
break
}
srv.serveDNS(w)
if w.tcp == nil {
break // Close() was called
}
if w.hijacked {
break // client will call Close() themselves
}
// The first read uses the read timeout, the rest use the
// idle timeout.
timeout = idleTimeout
}
}
func (srv *Server) disposeBuffer(w *response) {
if w.udp != nil && cap(w.msg) == srv.UDPSize {
srv.udpPool.Put(w.msg[:srv.UDPSize])
}
w.msg = nil
}
func (srv *Server) serveDNS(w *response) {
dh, off, err := unpackMsgHdr(w.msg, 0)
if err != nil {
// Let client hang, they are sending crap; any reply can be used to amplify.
return
}
req := new(Msg)
req.setHdr(dh)
switch srv.MsgAcceptFunc(dh) {
case MsgAccept:
case MsgIgnore:
return
case MsgReject:
req.SetRcodeFormatError(req)
// Are we allowed to delete any OPT records here?
req.Ns, req.Answer, req.Extra = nil, nil, nil
w.WriteMsg(req)
srv.disposeBuffer(w)
return
}
if err := req.unpack(dh, w.msg, off); err != nil {
req.SetRcodeFormatError(req)
req.Ns, req.Answer, req.Extra = nil, nil, nil
w.WriteMsg(req)
srv.disposeBuffer(w)
return
} }
w.tsigStatus = nil w.tsigStatus = nil
if w.tsigSecret != nil { if w.tsigSecret != nil {
if t := req.IsTsig(); t != nil { if t := req.IsTsig(); t != nil {
secret := t.Hdr.Name if secret, ok := w.tsigSecret[t.Hdr.Name]; ok {
if _, ok := w.tsigSecret[secret]; !ok { w.tsigStatus = TsigVerify(w.msg, secret, "", false)
w.tsigStatus = ErrKeyAlg } else {
w.tsigStatus = ErrSecret
} }
w.tsigStatus = TsigVerify(m, w.tsigSecret[secret], "", false)
w.tsigTimersOnly = false w.tsigTimersOnly = false
w.tsigRequestMAC = req.Extra[len(req.Extra)-1].(*TSIG).MAC w.tsigRequestMAC = req.Extra[len(req.Extra)-1].(*TSIG).MAC
} }
} }
h.ServeDNS(w, req) // Writes back to the client
Exit: srv.disposeBuffer(w)
if w.tcp == nil {
return handler := srv.Handler
} if handler == nil {
// TODO(miek): make this number configurable? handler = DefaultServeMux
if q > maxTCPQueries { // close socket after this many queries
w.Close()
return
} }
if w.hijacked { handler.ServeDNS(w, req) // Writes back to the client
return // client calls Close()
}
if u != nil { // UDP, "close" and return
w.Close()
return
}
idleTimeout := tcpIdleTimeout
if srv.IdleTimeout != nil {
idleTimeout = srv.IdleTimeout()
}
m, err = reader.ReadTCP(w.tcp, idleTimeout)
if err == nil {
q++
goto Redo
}
w.Close()
return
} }
func (srv *Server) readTCP(conn net.Conn, timeout time.Duration) ([]byte, error) { func (srv *Server) readTCP(conn net.Conn, timeout time.Duration) ([]byte, error) {
// If we race with ShutdownContext, the read deadline may
// have been set in the distant past to unblock the read
// below. We must not override it, otherwise we may block
// ShutdownContext.
srv.lock.RLock()
if srv.started {
conn.SetReadDeadline(time.Now().Add(timeout)) conn.SetReadDeadline(time.Now().Add(timeout))
}
srv.lock.RUnlock()
l := make([]byte, 2) l := make([]byte, 2)
n, err := conn.Read(l) n, err := conn.Read(l)
if err != nil || n != 2 { if err != nil || n != 2 {
@ -632,10 +732,17 @@ func (srv *Server) readTCP(conn net.Conn, timeout time.Duration) ([]byte, error)
} }
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) {
srv.lock.RLock()
if srv.started {
// See the comment in readTCP above.
conn.SetReadDeadline(time.Now().Add(timeout)) conn.SetReadDeadline(time.Now().Add(timeout))
m := make([]byte, srv.UDPSize) }
srv.lock.RUnlock()
m := srv.udpPool.Get().([]byte)
n, s, err := ReadFromSessionUDP(conn, m) n, s, err := ReadFromSessionUDP(conn, m)
if err != nil { if err != nil {
srv.udpPool.Put(m)
return nil, nil, err return nil, nil, err
} }
m = m[:n] m = m[:n]
@ -644,6 +751,10 @@ func (srv *Server) readUDP(conn *net.UDPConn, timeout time.Duration) ([]byte, *S
// WriteMsg implements the ResponseWriter.WriteMsg method. // WriteMsg implements the ResponseWriter.WriteMsg method.
func (w *response) WriteMsg(m *Msg) (err error) { func (w *response) WriteMsg(m *Msg) (err error) {
if w.closed {
return &Error{err: "WriteMsg called after Close"}
}
var data []byte var data []byte
if w.tsigSecret != nil { // if no secrets, dont check for the tsig (which is a longer check) if w.tsigSecret != nil { // if no secrets, dont check for the tsig (which is a longer check)
if t := m.IsTsig(); t != nil { if t := m.IsTsig(); t != nil {
@ -665,10 +776,13 @@ func (w *response) WriteMsg(m *Msg) (err error) {
// Write implements the ResponseWriter.Write method. // Write implements the ResponseWriter.Write method.
func (w *response) Write(m []byte) (int, error) { func (w *response) Write(m []byte) (int, error) {
if w.closed {
return 0, &Error{err: "Write called after Close"}
}
switch { switch {
case w.udp != nil: case w.udp != nil:
n, err := WriteToSessionUDP(w.udp, m, w.udpSession) return WriteToSessionUDP(w.udp, m, w.udpSession)
return n, err
case w.tcp != nil: case w.tcp != nil:
lm := len(m) lm := len(m)
if lm < 2 { if lm < 2 {
@ -683,20 +797,34 @@ func (w *response) Write(m []byte) (int, error) {
n, err := io.Copy(w.tcp, bytes.NewReader(m)) n, err := io.Copy(w.tcp, bytes.NewReader(m))
return int(n), err return int(n), err
default:
panic("dns: internal error: udp and tcp both nil")
} }
panic("not reached")
} }
// LocalAddr implements the ResponseWriter.LocalAddr method. // LocalAddr implements the ResponseWriter.LocalAddr method.
func (w *response) LocalAddr() net.Addr { func (w *response) LocalAddr() net.Addr {
if w.tcp != nil { switch {
return w.tcp.LocalAddr() case w.udp != nil:
}
return w.udp.LocalAddr() return w.udp.LocalAddr()
case w.tcp != nil:
return w.tcp.LocalAddr()
default:
panic("dns: internal error: udp and tcp both nil")
}
} }
// RemoteAddr implements the ResponseWriter.RemoteAddr method. // RemoteAddr implements the ResponseWriter.RemoteAddr method.
func (w *response) RemoteAddr() net.Addr { return w.remoteAddr } func (w *response) RemoteAddr() net.Addr {
switch {
case w.udpSession != nil:
return w.udpSession.RemoteAddr()
case w.tcp != nil:
return w.tcp.RemoteAddr()
default:
panic("dns: internal error: udpSession and tcp both nil")
}
}
// TsigStatus implements the ResponseWriter.TsigStatus method. // TsigStatus implements the ResponseWriter.TsigStatus method.
func (w *response) TsigStatus() error { return w.tsigStatus } func (w *response) TsigStatus() error { return w.tsigStatus }
@ -709,11 +837,30 @@ func (w *response) Hijack() { w.hijacked = true }
// Close implements the ResponseWriter.Close method // Close implements the ResponseWriter.Close method
func (w *response) Close() error { func (w *response) Close() error {
if w.closed {
return &Error{err: "connection already closed"}
}
w.closed = true
switch {
case w.udp != nil:
// Can't close the udp conn, as that is actually the listener. // Can't close the udp conn, as that is actually the listener.
if w.tcp != nil { return nil
e := w.tcp.Close() case w.tcp != nil:
w.tcp = nil return w.tcp.Close()
return e default:
panic("dns: internal error: udp and tcp both nil")
}
}
// ConnectionState() implements the ConnectionStater.ConnectionState() interface.
func (w *response) ConnectionState() *tls.ConnectionState {
type tlsConnectionStater interface {
ConnectionState() tls.ConnectionState
}
if v, ok := w.tcp.(tlsConnectionStater); ok {
t := v.ConnectionState()
return &t
} }
return nil return nil
} }

19
vendor/github.com/miekg/dns/sig0.go generated vendored
View file

@ -21,15 +21,11 @@ func (rr *SIG) Sign(k crypto.Signer, m *Msg) ([]byte, error) {
if rr.KeyTag == 0 || len(rr.SignerName) == 0 || rr.Algorithm == 0 { if rr.KeyTag == 0 || len(rr.SignerName) == 0 || rr.Algorithm == 0 {
return nil, ErrKey return nil, ErrKey
} }
rr.Header().Rrtype = TypeSIG
rr.Header().Class = ClassANY
rr.Header().Ttl = 0
rr.Header().Name = "."
rr.OrigTtl = 0
rr.TypeCovered = 0
rr.Labels = 0
buf := make([]byte, m.Len()+rr.len()) rr.Hdr = RR_Header{Name: ".", Rrtype: TypeSIG, Class: ClassANY, Ttl: 0}
rr.OrigTtl, rr.TypeCovered, rr.Labels = 0, 0, 0
buf := make([]byte, m.Len()+Len(rr))
mbuf, err := m.PackBuffer(buf) mbuf, err := m.PackBuffer(buf)
if err != nil { if err != nil {
return nil, err return nil, err
@ -107,7 +103,7 @@ func (rr *SIG) Verify(k *KEY, buf []byte) error {
anc := binary.BigEndian.Uint16(buf[6:]) anc := binary.BigEndian.Uint16(buf[6:])
auc := binary.BigEndian.Uint16(buf[8:]) auc := binary.BigEndian.Uint16(buf[8:])
adc := binary.BigEndian.Uint16(buf[10:]) adc := binary.BigEndian.Uint16(buf[10:])
offset := 12 offset := headerSize
var err error var err error
for i := uint16(0); i < qdc && offset < buflen; i++ { for i := uint16(0); i < qdc && offset < buflen; i++ {
_, offset, err = UnpackDomainName(buf, offset) _, offset, err = UnpackDomainName(buf, offset)
@ -127,8 +123,7 @@ func (rr *SIG) Verify(k *KEY, buf []byte) error {
if offset+1 >= buflen { if offset+1 >= buflen {
continue continue
} }
var rdlen uint16 rdlen := binary.BigEndian.Uint16(buf[offset:])
rdlen = binary.BigEndian.Uint16(buf[offset:])
offset += 2 offset += 2
offset += int(rdlen) offset += int(rdlen)
} }
@ -168,7 +163,7 @@ func (rr *SIG) Verify(k *KEY, buf []byte) error {
} }
// If key has come from the DNS name compression might // If key has come from the DNS name compression might
// have mangled the case of the name // have mangled the case of the name
if strings.ToLower(signername) != strings.ToLower(k.Header().Name) { if !strings.EqualFold(signername, k.Header().Name) {
return &Error{err: "signer name doesn't match key name"} return &Error{err: "signer name doesn't match key name"}
} }
sigend := offset sigend := offset

View file

@ -23,6 +23,8 @@ type call struct {
type singleflight struct { type singleflight struct {
sync.Mutex // protects m sync.Mutex // protects m
m map[string]*call // lazily initialized m map[string]*call // lazily initialized
dontDeleteForTesting bool // this is only to be used by TestConcurrentExchanges
} }
// Do executes and returns the results of the given function, making // Do executes and returns the results of the given function, making
@ -49,9 +51,11 @@ func (g *singleflight) Do(key string, fn func() (*Msg, time.Duration, error)) (v
c.val, c.rtt, c.err = fn() c.val, c.rtt, c.err = fn()
c.wg.Done() c.wg.Done()
if !g.dontDeleteForTesting {
g.Lock() g.Lock()
delete(g.m, key) delete(g.m, key)
g.Unlock() g.Unlock()
}
return c.val, c.rtt, c.err, c.dups > 0 return c.val, c.rtt, c.err, c.dups > 0
} }

View file

@ -14,11 +14,8 @@ func (r *SMIMEA) Sign(usage, selector, matchingType int, cert *x509.Certificate)
r.MatchingType = uint8(matchingType) r.MatchingType = uint8(matchingType)
r.Certificate, err = CertificateToDANE(r.Selector, r.MatchingType, cert) r.Certificate, err = CertificateToDANE(r.Selector, r.MatchingType, cert)
if err != nil {
return err return err
} }
return nil
}
// Verify verifies a SMIMEA record against an SSL certificate. If it is OK // Verify verifies a SMIMEA record against an SSL certificate. If it is OK
// a nil error is returned. // a nil error is returned.

View file

@ -14,11 +14,8 @@ func (r *TLSA) Sign(usage, selector, matchingType int, cert *x509.Certificate) (
r.MatchingType = uint8(matchingType) r.MatchingType = uint8(matchingType)
r.Certificate, err = CertificateToDANE(r.Selector, r.MatchingType, cert) r.Certificate, err = CertificateToDANE(r.Selector, r.MatchingType, cert)
if err != nil {
return err return err
} }
return nil
}
// Verify verifies a TLSA record against an SSL certificate. If it is OK // Verify verifies a TLSA record against an SSL certificate. If it is OK
// a nil error is returned. // a nil error is returned.

21
vendor/github.com/miekg/dns/tsig.go generated vendored
View file

@ -54,6 +54,10 @@ func (rr *TSIG) String() string {
return s return s
} }
func (rr *TSIG) parse(c *zlexer, origin, file string) *ParseError {
panic("dns: internal error: parse should never be called on TSIG")
}
// 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 {
@ -113,13 +117,13 @@ func TsigGenerate(m *Msg, secret, requestMAC string, timersOnly bool) ([]byte, s
var h hash.Hash var h hash.Hash
switch strings.ToLower(rr.Algorithm) { switch strings.ToLower(rr.Algorithm) {
case HmacMD5: case HmacMD5:
h = hmac.New(md5.New, []byte(rawsecret)) h = hmac.New(md5.New, rawsecret)
case HmacSHA1: case HmacSHA1:
h = hmac.New(sha1.New, []byte(rawsecret)) h = hmac.New(sha1.New, rawsecret)
case HmacSHA256: case HmacSHA256:
h = hmac.New(sha256.New, []byte(rawsecret)) h = hmac.New(sha256.New, rawsecret)
case HmacSHA512: case HmacSHA512:
h = hmac.New(sha512.New, []byte(rawsecret)) h = hmac.New(sha512.New, rawsecret)
default: default:
return nil, "", ErrKeyAlg return nil, "", ErrKeyAlg
} }
@ -133,13 +137,12 @@ func TsigGenerate(m *Msg, secret, requestMAC string, timersOnly bool) ([]byte, s
t.Algorithm = rr.Algorithm t.Algorithm = rr.Algorithm
t.OrigId = m.Id t.OrigId = m.Id
tbuf := make([]byte, t.len()) tbuf := make([]byte, Len(t))
if off, err := PackRR(t, tbuf, 0, nil, false); err == nil { off, err := PackRR(t, tbuf, 0, nil, false)
tbuf = tbuf[:off] // reset to actual size used if err != nil {
} else {
return nil, "", err return nil, "", err
} }
mbuf = append(mbuf, tbuf...) mbuf = append(mbuf, tbuf[:off]...)
// Update the ArCount directly in the buffer. // Update the ArCount directly in the buffer.
binary.BigEndian.PutUint16(mbuf[10:], uint16(len(m.Extra)+1)) binary.BigEndian.PutUint16(mbuf[10:], uint16(len(m.Extra)+1))

251
vendor/github.com/miekg/dns/types.go generated vendored
View file

@ -205,9 +205,6 @@ var CertTypeToString = map[uint16]string{
CertOID: "OID", CertOID: "OID",
} }
// StringToCertType is the reverseof CertTypeToString.
var StringToCertType = reverseInt16(CertTypeToString)
//go:generate go run types_generate.go //go:generate go run types_generate.go
// Question holds a DNS question. There can be multiple questions in the // Question holds a DNS question. There can be multiple questions in the
@ -218,8 +215,10 @@ type Question struct {
Qclass uint16 Qclass uint16
} }
func (q *Question) len() int { func (q *Question) len(off int, compression map[string]struct{}) int {
return len(q.Name) + 1 + 2 + 2 l := domainNameLen(q.Name, off, compression, true)
l += 2 + 2
return l
} }
func (q *Question) String() (s string) { func (q *Question) String() (s string) {
@ -239,6 +238,25 @@ type ANY struct {
func (rr *ANY) String() string { return rr.Hdr.String() } func (rr *ANY) String() string { return rr.Hdr.String() }
func (rr *ANY) parse(c *zlexer, origin, file string) *ParseError {
panic("dns: internal error: parse should never be called on ANY")
}
// NULL RR. See RFC 1035.
type NULL struct {
Hdr RR_Header
Data string `dns:"any"`
}
func (rr *NULL) String() string {
// There is no presentation format; prefix string with a comment.
return ";" + rr.Hdr.String() + rr.Data
}
func (rr *NULL) parse(c *zlexer, origin, file string) *ParseError {
panic("dns: internal error: parse should never be called on NULL")
}
// CNAME RR. See RFC 1034. // CNAME RR. See RFC 1034.
type CNAME struct { type CNAME struct {
Hdr RR_Header Hdr RR_Header
@ -330,7 +348,7 @@ func (rr *MX) String() string {
type AFSDB struct { type AFSDB struct {
Hdr RR_Header Hdr RR_Header
Subtype uint16 Subtype uint16
Hostname string `dns:"cdomain-name"` Hostname string `dns:"domain-name"`
} }
func (rr *AFSDB) String() string { func (rr *AFSDB) String() string {
@ -351,7 +369,7 @@ func (rr *X25) String() string {
type RT struct { type RT struct {
Hdr RR_Header Hdr RR_Header
Preference uint16 Preference uint16
Host string `dns:"cdomain-name"` Host string `dns:"domain-name"` // RFC 3597 prohibits compressing records not defined in RFC 1035.
} }
func (rr *RT) String() string { func (rr *RT) String() string {
@ -419,128 +437,154 @@ type TXT struct {
func (rr *TXT) String() string { return rr.Hdr.String() + sprintTxt(rr.Txt) } func (rr *TXT) String() string { return rr.Hdr.String() + sprintTxt(rr.Txt) }
func sprintName(s string) string { func sprintName(s string) string {
src := []byte(s) var dst strings.Builder
dst := make([]byte, 0, len(src)) dst.Grow(len(s))
for i := 0; i < len(src); { for i := 0; i < len(s); {
if i+1 < len(src) && src[i] == '\\' && src[i+1] == '.' { if i+1 < len(s) && s[i] == '\\' && s[i+1] == '.' {
dst = append(dst, src[i:i+2]...) dst.WriteString(s[i : i+2])
i += 2 i += 2
} else { continue
b, n := nextByte(src, i) }
if n == 0 {
b, n := nextByte(s, i)
switch {
case n == 0:
i++ // dangling back slash i++ // dangling back slash
} else if b == '.' { case b == '.':
dst = append(dst, b) dst.WriteByte('.')
} else { default:
dst = appendDomainNameByte(dst, b) writeDomainNameByte(&dst, b)
} }
i += n i += n
} }
} return dst.String()
return string(dst)
} }
func sprintTxtOctet(s string) string { func sprintTxtOctet(s string) string {
src := []byte(s) var dst strings.Builder
dst := make([]byte, 0, len(src)) dst.Grow(2 + len(s))
dst = append(dst, '"') dst.WriteByte('"')
for i := 0; i < len(src); { for i := 0; i < len(s); {
if i+1 < len(src) && src[i] == '\\' && src[i+1] == '.' { if i+1 < len(s) && s[i] == '\\' && s[i+1] == '.' {
dst = append(dst, src[i:i+2]...) dst.WriteString(s[i : i+2])
i += 2 i += 2
} else { continue
b, n := nextByte(src, i)
if n == 0 {
i++ // dangling back slash
} else if b == '.' {
dst = append(dst, b)
} else {
if b < ' ' || b > '~' {
dst = appendByte(dst, b)
} else {
dst = append(dst, b)
} }
b, n := nextByte(s, i)
switch {
case n == 0:
i++ // dangling back slash
case b == '.':
dst.WriteByte('.')
case b < ' ' || b > '~':
dst.WriteString(escapeByte(b))
default:
dst.WriteByte(b)
} }
i += n i += n
} }
} dst.WriteByte('"')
dst = append(dst, '"') return dst.String()
return string(dst)
} }
func sprintTxt(txt []string) string { func sprintTxt(txt []string) string {
var out []byte var out strings.Builder
for i, s := range txt { for i, s := range txt {
out.Grow(3 + len(s))
if i > 0 { if i > 0 {
out = append(out, ` "`...) out.WriteString(` "`)
} else { } else {
out = append(out, '"') out.WriteByte('"')
} }
bs := []byte(s) for j := 0; j < len(s); {
for j := 0; j < len(bs); { b, n := nextByte(s, j)
b, n := nextByte(bs, j)
if n == 0 { if n == 0 {
break break
} }
out = appendTXTStringByte(out, b) writeTXTStringByte(&out, b)
j += n j += n
} }
out = append(out, '"') out.WriteByte('"')
} }
return string(out) return out.String()
} }
func appendDomainNameByte(s []byte, b byte) []byte { func writeDomainNameByte(s *strings.Builder, b byte) {
switch b { switch b {
case '.', ' ', '\'', '@', ';', '(', ')': // additional chars to escape case '.', ' ', '\'', '@', ';', '(', ')': // additional chars to escape
return append(s, '\\', b) s.WriteByte('\\')
s.WriteByte(b)
default:
writeTXTStringByte(s, b)
} }
return appendTXTStringByte(s, b)
} }
func appendTXTStringByte(s []byte, b byte) []byte { func writeTXTStringByte(s *strings.Builder, b byte) {
switch b { switch {
case '"', '\\': case b == '"' || b == '\\':
return append(s, '\\', b) s.WriteByte('\\')
s.WriteByte(b)
case b < ' ' || b > '~':
s.WriteString(escapeByte(b))
default:
s.WriteByte(b)
} }
if b < ' ' || b > '~' {
return appendByte(s, b)
}
return append(s, b)
} }
func appendByte(s []byte, b byte) []byte { const (
var buf [3]byte escapedByteSmall = "" +
bufs := strconv.AppendInt(buf[:0], int64(b), 10) `\000\001\002\003\004\005\006\007\008\009` +
s = append(s, '\\') `\010\011\012\013\014\015\016\017\018\019` +
for i := 0; i < 3-len(bufs); i++ { `\020\021\022\023\024\025\026\027\028\029` +
s = append(s, '0') `\030\031`
} escapedByteLarge = `\127\128\129` +
for _, r := range bufs { `\130\131\132\133\134\135\136\137\138\139` +
s = append(s, r) `\140\141\142\143\144\145\146\147\148\149` +
} `\150\151\152\153\154\155\156\157\158\159` +
return s `\160\161\162\163\164\165\166\167\168\169` +
`\170\171\172\173\174\175\176\177\178\179` +
`\180\181\182\183\184\185\186\187\188\189` +
`\190\191\192\193\194\195\196\197\198\199` +
`\200\201\202\203\204\205\206\207\208\209` +
`\210\211\212\213\214\215\216\217\218\219` +
`\220\221\222\223\224\225\226\227\228\229` +
`\230\231\232\233\234\235\236\237\238\239` +
`\240\241\242\243\244\245\246\247\248\249` +
`\250\251\252\253\254\255`
)
// escapeByte returns the \DDD escaping of b which must
// satisfy b < ' ' || b > '~'.
func escapeByte(b byte) string {
if b < ' ' {
return escapedByteSmall[b*4 : b*4+4]
} }
func nextByte(b []byte, offset int) (byte, int) { b -= '~' + 1
if offset >= len(b) { // The cast here is needed as b*4 may overflow byte.
return escapedByteLarge[int(b)*4 : int(b)*4+4]
}
func nextByte(s string, offset int) (byte, int) {
if offset >= len(s) {
return 0, 0 return 0, 0
} }
if b[offset] != '\\' { if s[offset] != '\\' {
// not an escape sequence // not an escape sequence
return b[offset], 1 return s[offset], 1
} }
switch len(b) - offset { switch len(s) - offset {
case 1: // dangling escape case 1: // dangling escape
return 0, 0 return 0, 0
case 2, 3: // too short to be \ddd case 2, 3: // too short to be \ddd
default: // maybe \ddd default: // maybe \ddd
if isDigit(b[offset+1]) && isDigit(b[offset+2]) && isDigit(b[offset+3]) { if isDigit(s[offset+1]) && isDigit(s[offset+2]) && isDigit(s[offset+3]) {
return dddToByte(b[offset+1:]), 4 return dddStringToByte(s[offset+1:]), 4
} }
} }
// not \ddd, just an RFC 1035 "quoted" character // not \ddd, just an RFC 1035 "quoted" character
return b[offset+1], 2 return s[offset+1], 2
} }
// SPF RR. See RFC 4408, Section 3.1.1. // SPF RR. See RFC 4408, Section 3.1.1.
@ -728,7 +772,7 @@ func (rr *LOC) String() string {
lat = lat % LOC_DEGREES lat = lat % LOC_DEGREES
m := lat / LOC_HOURS m := lat / LOC_HOURS
lat = lat % LOC_HOURS lat = lat % LOC_HOURS
s += fmt.Sprintf("%02d %02d %0.3f %s ", h, m, (float64(lat) / 1000), ns) s += fmt.Sprintf("%02d %02d %0.3f %s ", h, m, float64(lat)/1000, ns)
lon := rr.Longitude lon := rr.Longitude
ew := "E" ew := "E"
@ -742,7 +786,7 @@ func (rr *LOC) String() string {
lon = lon % LOC_DEGREES lon = lon % LOC_DEGREES
m = lon / LOC_HOURS m = lon / LOC_HOURS
lon = lon % LOC_HOURS lon = lon % LOC_HOURS
s += fmt.Sprintf("%02d %02d %0.3f %s ", h, m, (float64(lon) / 1000), ew) s += fmt.Sprintf("%02d %02d %0.3f %s ", h, m, float64(lon)/1000, ew)
var alt = float64(rr.Altitude) / 100 var alt = float64(rr.Altitude) / 100
alt -= LOC_ALTITUDEBASE alt -= LOC_ALTITUDEBASE
@ -752,9 +796,9 @@ func (rr *LOC) String() string {
s += fmt.Sprintf("%.0fm ", alt) s += fmt.Sprintf("%.0fm ", alt)
} }
s += cmToM((rr.Size&0xf0)>>4, rr.Size&0x0f) + "m " s += cmToM(rr.Size&0xf0>>4, rr.Size&0x0f) + "m "
s += cmToM((rr.HorizPre&0xf0)>>4, rr.HorizPre&0x0f) + "m " s += cmToM(rr.HorizPre&0xf0>>4, rr.HorizPre&0x0f) + "m "
s += cmToM((rr.VertPre&0xf0)>>4, rr.VertPre&0x0f) + "m" s += cmToM(rr.VertPre&0xf0>>4, rr.VertPre&0x0f) + "m"
return s return s
} }
@ -807,8 +851,9 @@ func (rr *NSEC) String() string {
return s return s
} }
func (rr *NSEC) len() int { func (rr *NSEC) len(off int, compression map[string]struct{}) int {
l := rr.Hdr.len() + len(rr.NextDomain) + 1 l := rr.Hdr.len(off, compression)
l += domainNameLen(rr.NextDomain, off+l, compression, false)
lastwindow := uint32(2 ^ 32 + 1) lastwindow := uint32(2 ^ 32 + 1)
for _, t := range rr.TypeBitMap { for _, t := range rr.TypeBitMap {
window := t / 256 window := t / 256
@ -972,8 +1017,9 @@ func (rr *NSEC3) String() string {
return s return s
} }
func (rr *NSEC3) len() int { func (rr *NSEC3) len(off int, compression map[string]struct{}) int {
l := rr.Hdr.len() + 6 + len(rr.Salt)/2 + 1 + len(rr.NextDomain) + 1 l := rr.Hdr.len(off, compression)
l += 6 + len(rr.Salt)/2 + 1 + len(rr.NextDomain) + 1
lastwindow := uint32(2 ^ 32 + 1) lastwindow := uint32(2 ^ 32 + 1)
for _, t := range rr.TypeBitMap { for _, t := range rr.TypeBitMap {
window := t / 256 window := t / 256
@ -1020,10 +1066,16 @@ type TKEY struct {
// TKEY has no official presentation format, but this will suffice. // TKEY has no official presentation format, but this will suffice.
func (rr *TKEY) String() string { func (rr *TKEY) String() string {
s := "\n;; TKEY PSEUDOSECTION:\n" s := ";" + rr.Hdr.String() +
s += rr.Hdr.String() + " " + rr.Algorithm + " " + " " + rr.Algorithm +
strconv.Itoa(int(rr.KeySize)) + " " + rr.Key + " " + " " + TimeToString(rr.Inception) +
strconv.Itoa(int(rr.OtherLen)) + " " + rr.OtherData " " + TimeToString(rr.Expiration) +
" " + strconv.Itoa(int(rr.Mode)) +
" " + strconv.Itoa(int(rr.Error)) +
" " + strconv.Itoa(int(rr.KeySize)) +
" " + rr.Key +
" " + strconv.Itoa(int(rr.OtherLen)) +
" " + rr.OtherData
return s return s
} }
@ -1289,8 +1341,9 @@ func (rr *CSYNC) String() string {
return s return s
} }
func (rr *CSYNC) len() int { func (rr *CSYNC) len(off int, compression map[string]struct{}) int {
l := rr.Hdr.len() + 4 + 2 l := rr.Hdr.len(off, compression)
l += 4 + 2
lastwindow := uint32(2 ^ 32 + 1) lastwindow := uint32(2 ^ 32 + 1)
for _, t := range rr.TypeBitMap { for _, t := range rr.TypeBitMap {
window := t / 256 window := t / 256
@ -1306,11 +1359,11 @@ func (rr *CSYNC) len() int {
// string representation used when printing the record. // string representation used when printing the record.
// It takes serial arithmetic (RFC 1982) into account. // It takes serial arithmetic (RFC 1982) into account.
func TimeToString(t uint32) string { func TimeToString(t uint32) string {
mod := ((int64(t) - time.Now().Unix()) / year68) - 1 mod := (int64(t)-time.Now().Unix())/year68 - 1
if mod < 0 { if mod < 0 {
mod = 0 mod = 0
} }
ti := time.Unix(int64(t)-(mod*year68), 0).UTC() ti := time.Unix(int64(t)-mod*year68, 0).UTC()
return ti.Format("20060102150405") return ti.Format("20060102150405")
} }
@ -1322,11 +1375,11 @@ func StringToTime(s string) (uint32, error) {
if err != nil { if err != nil {
return 0, err return 0, err
} }
mod := (t.Unix() / year68) - 1 mod := t.Unix()/year68 - 1
if mod < 0 { if mod < 0 {
mod = 0 mod = 0
} }
return uint32(t.Unix() - (mod * year68)), nil return uint32(t.Unix() - mod*year68), nil
} }
// saltToString converts a NSECX salt to uppercase and returns "-" when it is empty. // saltToString converts a NSECX salt to uppercase and returns "-" when it is empty.

View file

@ -153,8 +153,8 @@ func main() {
if isEmbedded { if isEmbedded {
continue continue
} }
fmt.Fprintf(b, "func (rr *%s) len() int {\n", name) fmt.Fprintf(b, "func (rr *%s) len(off int, compression map[string]struct{}) int {\n", name)
fmt.Fprintf(b, "l := rr.Hdr.len()\n") fmt.Fprintf(b, "l := rr.Hdr.len(off, compression)\n")
for i := 1; i < st.NumFields(); i++ { for i := 1; i < st.NumFields(); i++ {
o := func(s string) { fmt.Fprintf(b, s, st.Field(i).Name()) } o := func(s string) { fmt.Fprintf(b, s, st.Field(i).Name()) }
@ -162,7 +162,11 @@ func main() {
switch st.Tag(i) { switch st.Tag(i) {
case `dns:"-"`: case `dns:"-"`:
// ignored // ignored
case `dns:"cdomain-name"`, `dns:"domain-name"`, `dns:"txt"`: case `dns:"cdomain-name"`:
o("for _, x := range rr.%s { l += domainNameLen(x, off+l, compression, true) }\n")
case `dns:"domain-name"`:
o("for _, x := range rr.%s { l += domainNameLen(x, off+l, compression, false) }\n")
case `dns:"txt"`:
o("for _, x := range rr.%s { l += len(x) + 1 }\n") o("for _, x := range rr.%s { l += len(x) + 1 }\n")
default: default:
log.Fatalln(name, st.Field(i).Name(), st.Tag(i)) log.Fatalln(name, st.Field(i).Name(), st.Tag(i))
@ -173,8 +177,10 @@ func main() {
switch { switch {
case st.Tag(i) == `dns:"-"`: case st.Tag(i) == `dns:"-"`:
// ignored // ignored
case st.Tag(i) == `dns:"cdomain-name"`, st.Tag(i) == `dns:"domain-name"`: case st.Tag(i) == `dns:"cdomain-name"`:
o("l += len(rr.%s) + 1\n") o("l += domainNameLen(rr.%s, off+l, compression, true)\n")
case st.Tag(i) == `dns:"domain-name"`:
o("l += domainNameLen(rr.%s, off+l, compression, false)\n")
case st.Tag(i) == `dns:"octet"`: case st.Tag(i) == `dns:"octet"`:
o("l += len(rr.%s)\n") o("l += len(rr.%s)\n")
case strings.HasPrefix(st.Tag(i), `dns:"size-base64`): case strings.HasPrefix(st.Tag(i), `dns:"size-base64`):
@ -187,6 +193,8 @@ func main() {
fallthrough fallthrough
case st.Tag(i) == `dns:"hex"`: case st.Tag(i) == `dns:"hex"`:
o("l += len(rr.%s)/2 + 1\n") o("l += len(rr.%s)/2 + 1\n")
case st.Tag(i) == `dns:"any"`:
o("l += len(rr.%s)\n")
case st.Tag(i) == `dns:"a"`: case st.Tag(i) == `dns:"a"`:
o("l += net.IPv4len // %s\n") o("l += net.IPv4len // %s\n")
case st.Tag(i) == `dns:"aaaa"`: case st.Tag(i) == `dns:"aaaa"`:
@ -226,7 +234,7 @@ func main() {
continue continue
} }
fmt.Fprintf(b, "func (rr *%s) copy() RR {\n", name) fmt.Fprintf(b, "func (rr *%s) copy() RR {\n", name)
fields := []string{"*rr.Hdr.copyHeader()"} fields := []string{"rr.Hdr"}
for i := 1; i < st.NumFields(); i++ { for i := 1; i < st.NumFields(); i++ {
f := st.Field(i).Name() f := st.Field(i).Name()
if sl, ok := st.Field(i).Type().(*types.Slice); ok { if sl, ok := st.Field(i).Type().(*types.Slice); ok {
@ -236,6 +244,13 @@ func main() {
splits := strings.Split(t, ".") splits := strings.Split(t, ".")
t = splits[len(splits)-1] t = splits[len(splits)-1]
} }
// For the EDNS0 interface (used in the OPT RR), we need to call the copy method on each element.
if t == "EDNS0" {
fmt.Fprintf(b, "%s := make([]%s, len(rr.%s));\nfor i,e := range rr.%s {\n %s[i] = e.copy()\n}\n",
f, t, f, f, f)
fields = append(fields, f)
continue
}
fmt.Fprintf(b, "%s := make([]%s, len(rr.%s)); copy(%s, rr.%s)\n", fmt.Fprintf(b, "%s := make([]%s, len(rr.%s)); copy(%s, rr.%s)\n",
f, t, f, f, f) f, t, f, f, f)
fields = append(fields, f) fields = append(fields, f)

31
vendor/github.com/miekg/dns/udp.go generated vendored
View file

@ -9,6 +9,22 @@ import (
"golang.org/x/net/ipv6" "golang.org/x/net/ipv6"
) )
// This is the required size of the OOB buffer to pass to ReadMsgUDP.
var udpOOBSize = func() int {
// We can't know whether we'll get an IPv4 control message or an
// IPv6 control message ahead of time. To get around this, we size
// the buffer equal to the largest of the two.
oob4 := ipv4.NewControlMessage(ipv4.FlagDst | ipv4.FlagInterface)
oob6 := ipv6.NewControlMessage(ipv6.FlagDst | ipv6.FlagInterface)
if len(oob4) > len(oob6) {
return len(oob4)
}
return len(oob6)
}()
// SessionUDP holds the remote address and the associated // SessionUDP holds the remote address and the associated
// out-of-band data. // out-of-band data.
type SessionUDP struct { type SessionUDP struct {
@ -22,7 +38,7 @@ func (s *SessionUDP) RemoteAddr() net.Addr { return s.raddr }
// 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, udpOOBSize)
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
@ -53,18 +69,15 @@ func parseDstFromOOB(oob []byte) net.IP {
// Start with IPv6 and then fallback to IPv4 // Start with IPv6 and then fallback to IPv4
// TODO(fastest963): Figure out a way to prefer one or the other. Looking at // TODO(fastest963): Figure out a way to prefer one or the other. Looking at
// the lvl of the header for a 0 or 41 isn't cross-platform. // the lvl of the header for a 0 or 41 isn't cross-platform.
var dst net.IP
cm6 := new(ipv6.ControlMessage) cm6 := new(ipv6.ControlMessage)
if cm6.Parse(oob) == nil { if cm6.Parse(oob) == nil && cm6.Dst != nil {
dst = cm6.Dst return cm6.Dst
} }
if dst == nil {
cm4 := new(ipv4.ControlMessage) cm4 := new(ipv4.ControlMessage)
if cm4.Parse(oob) == nil { if cm4.Parse(oob) == nil && cm4.Dst != nil {
dst = cm4.Dst return cm4.Dst
} }
} return nil
return dst
} }
// correctSource takes oob data and returns new oob data with the Src equal to the Dst // correctSource takes oob data and returns new oob data with the Src equal to the Dst

View file

@ -20,15 +20,13 @@ func ReadFromSessionUDP(conn *net.UDPConn, b []byte) (int, *SessionUDP, error) {
if err != nil { if err != nil {
return n, nil, err return n, nil, err
} }
session := &SessionUDP{raddr.(*net.UDPAddr)} return n, &SessionUDP{raddr.(*net.UDPAddr)}, err
return n, session, err
} }
// WriteToSessionUDP acts just like net.UDPConn.WriteTo(), but uses a *SessionUDP instead of a net.Addr. // WriteToSessionUDP acts just like net.UDPConn.WriteTo(), but uses a *SessionUDP instead of a net.Addr.
// TODO(fastest963): Once go1.10 is released, use WriteMsgUDP. // TODO(fastest963): Once go1.10 is released, use WriteMsgUDP.
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) return conn.WriteTo(b, session.raddr)
return n, err
} }
// TODO(fastest963): Once go1.10 is released and we can use *MsgUDP methods // TODO(fastest963): Once go1.10 is released and we can use *MsgUDP methods

View file

@ -44,7 +44,8 @@ func (u *Msg) RRsetUsed(rr []RR) {
u.Answer = make([]RR, 0, len(rr)) u.Answer = make([]RR, 0, len(rr))
} }
for _, r := range rr { for _, r := range rr {
u.Answer = append(u.Answer, &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: r.Header().Rrtype, Class: ClassANY}}) h := r.Header()
u.Answer = append(u.Answer, &ANY{Hdr: RR_Header{Name: h.Name, Ttl: 0, Rrtype: h.Rrtype, Class: ClassANY}})
} }
} }
@ -55,7 +56,8 @@ func (u *Msg) RRsetNotUsed(rr []RR) {
u.Answer = make([]RR, 0, len(rr)) u.Answer = make([]RR, 0, len(rr))
} }
for _, r := range rr { for _, r := range rr {
u.Answer = append(u.Answer, &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: r.Header().Rrtype, Class: ClassNONE}}) h := r.Header()
u.Answer = append(u.Answer, &ANY{Hdr: RR_Header{Name: h.Name, Ttl: 0, Rrtype: h.Rrtype, Class: ClassNONE}})
} }
} }
@ -79,7 +81,8 @@ func (u *Msg) RemoveRRset(rr []RR) {
u.Ns = make([]RR, 0, len(rr)) u.Ns = make([]RR, 0, len(rr))
} }
for _, r := range rr { for _, r := range rr {
u.Ns = append(u.Ns, &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: r.Header().Rrtype, Class: ClassANY}}) h := r.Header()
u.Ns = append(u.Ns, &ANY{Hdr: RR_Header{Name: h.Name, Ttl: 0, Rrtype: h.Rrtype, Class: ClassANY}})
} }
} }
@ -99,8 +102,9 @@ func (u *Msg) Remove(rr []RR) {
u.Ns = make([]RR, 0, len(rr)) u.Ns = make([]RR, 0, len(rr))
} }
for _, r := range rr { for _, r := range rr {
r.Header().Class = ClassNONE h := r.Header()
r.Header().Ttl = 0 h.Class = ClassNONE
h.Ttl = 0
u.Ns = append(u.Ns, r) u.Ns = append(u.Ns, r)
} }
} }

View file

@ -3,7 +3,7 @@ package dns
import "fmt" import "fmt"
// Version is current version of this library. // Version is current version of this library.
var Version = V{1, 0, 4} var Version = V{1, 1, 4}
// V holds the version of this library. // V holds the version of this library.
type V struct { type V struct {

38
vendor/github.com/miekg/dns/xfr.go generated vendored
View file

@ -35,30 +35,36 @@ type Transfer struct {
// channel, err := transfer.In(message, master) // 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) {
switch q.Question[0].Qtype {
case TypeAXFR, TypeIXFR:
default:
return nil, &Error{"unsupported question type"}
}
timeout := dnsTimeout timeout := dnsTimeout
if t.DialTimeout != 0 { if t.DialTimeout != 0 {
timeout = t.DialTimeout timeout = t.DialTimeout
} }
if t.Conn == nil { if t.Conn == nil {
t.Conn, err = DialTimeout("tcp", a, timeout) t.Conn, err = DialTimeout("tcp", a, timeout)
if err != nil { if err != nil {
return nil, err return nil, err
} }
} }
if err := t.WriteMsg(q); err != nil { if err := t.WriteMsg(q); err != nil {
return nil, err return nil, err
} }
env = make(chan *Envelope) env = make(chan *Envelope)
go func() { switch q.Question[0].Qtype {
if q.Question[0].Qtype == TypeAXFR { case TypeAXFR:
go t.inAxfr(q, env) go t.inAxfr(q, env)
return case TypeIXFR:
}
if q.Question[0].Qtype == TypeIXFR {
go t.inIxfr(q, env) go t.inIxfr(q, env)
return
} }
}()
return env, nil return env, nil
} }
@ -111,7 +117,7 @@ func (t *Transfer) inAxfr(q *Msg, c chan *Envelope) {
} }
func (t *Transfer) inIxfr(q *Msg, c chan *Envelope) { func (t *Transfer) inIxfr(q *Msg, c chan *Envelope) {
serial := uint32(0) // The first serial seen is the current server serial var serial uint32 // The first serial seen is the current server serial
axfr := true axfr := true
n := 0 n := 0
qser := q.Ns[0].(*SOA).Serial qser := q.Ns[0].(*SOA).Serial
@ -237,24 +243,18 @@ func (t *Transfer) WriteMsg(m *Msg) (err error) {
if err != nil { if err != nil {
return err return err
} }
if _, err = t.Write(out); err != nil { _, err = t.Write(out)
return err return err
} }
return nil
}
func isSOAFirst(in *Msg) bool { func isSOAFirst(in *Msg) bool {
if len(in.Answer) > 0 { return len(in.Answer) > 0 &&
return in.Answer[0].Header().Rrtype == TypeSOA in.Answer[0].Header().Rrtype == TypeSOA
}
return false
} }
func isSOALast(in *Msg) bool { func isSOALast(in *Msg) bool {
if len(in.Answer) > 0 { return len(in.Answer) > 0 &&
return in.Answer[len(in.Answer)-1].Header().Rrtype == TypeSOA in.Answer[len(in.Answer)-1].Header().Rrtype == TypeSOA
}
return false
} }
const errXFR = "bad xfr rcode: %d" const errXFR = "bad xfr rcode: %d"

View file

@ -1,118 +0,0 @@
// Code generated by "go run compress_generate.go"; DO NOT EDIT.
package dns
func compressionLenHelperType(c map[string]int, r RR) {
switch x := r.(type) {
case *AFSDB:
compressionLenHelper(c, x.Hostname)
case *CNAME:
compressionLenHelper(c, x.Target)
case *DNAME:
compressionLenHelper(c, x.Target)
case *HIP:
for i := range x.RendezvousServers {
compressionLenHelper(c, x.RendezvousServers[i])
}
case *KX:
compressionLenHelper(c, x.Exchanger)
case *LP:
compressionLenHelper(c, x.Fqdn)
case *MB:
compressionLenHelper(c, x.Mb)
case *MD:
compressionLenHelper(c, x.Md)
case *MF:
compressionLenHelper(c, x.Mf)
case *MG:
compressionLenHelper(c, x.Mg)
case *MINFO:
compressionLenHelper(c, x.Rmail)
compressionLenHelper(c, x.Email)
case *MR:
compressionLenHelper(c, x.Mr)
case *MX:
compressionLenHelper(c, x.Mx)
case *NAPTR:
compressionLenHelper(c, x.Replacement)
case *NS:
compressionLenHelper(c, x.Ns)
case *NSAPPTR:
compressionLenHelper(c, x.Ptr)
case *NSEC:
compressionLenHelper(c, x.NextDomain)
case *PTR:
compressionLenHelper(c, x.Ptr)
case *PX:
compressionLenHelper(c, x.Map822)
compressionLenHelper(c, x.Mapx400)
case *RP:
compressionLenHelper(c, x.Mbox)
compressionLenHelper(c, x.Txt)
case *RRSIG:
compressionLenHelper(c, x.SignerName)
case *RT:
compressionLenHelper(c, x.Host)
case *SIG:
compressionLenHelper(c, x.SignerName)
case *SOA:
compressionLenHelper(c, x.Ns)
compressionLenHelper(c, x.Mbox)
case *SRV:
compressionLenHelper(c, x.Target)
case *TALINK:
compressionLenHelper(c, x.PreviousName)
compressionLenHelper(c, x.NextName)
case *TKEY:
compressionLenHelper(c, x.Algorithm)
case *TSIG:
compressionLenHelper(c, x.Algorithm)
}
}
func compressionLenSearchType(c map[string]int, r RR) (int, bool) {
switch x := r.(type) {
case *AFSDB:
k1, ok1 := compressionLenSearch(c, x.Hostname)
return k1, ok1
case *CNAME:
k1, ok1 := compressionLenSearch(c, x.Target)
return k1, ok1
case *MB:
k1, ok1 := compressionLenSearch(c, x.Mb)
return k1, ok1
case *MD:
k1, ok1 := compressionLenSearch(c, x.Md)
return k1, ok1
case *MF:
k1, ok1 := compressionLenSearch(c, x.Mf)
return k1, ok1
case *MG:
k1, ok1 := compressionLenSearch(c, x.Mg)
return k1, ok1
case *MINFO:
k1, ok1 := compressionLenSearch(c, x.Rmail)
k2, ok2 := compressionLenSearch(c, x.Email)
return k1 + k2, ok1 && ok2
case *MR:
k1, ok1 := compressionLenSearch(c, x.Mr)
return k1, ok1
case *MX:
k1, ok1 := compressionLenSearch(c, x.Mx)
return k1, ok1
case *NS:
k1, ok1 := compressionLenSearch(c, x.Ns)
return k1, ok1
case *PTR:
k1, ok1 := compressionLenSearch(c, x.Ptr)
return k1, ok1
case *RT:
k1, ok1 := compressionLenSearch(c, x.Host)
return k1, ok1
case *SOA:
k1, ok1 := compressionLenSearch(c, x.Ns)
k2, ok2 := compressionLenSearch(c, x.Mbox)
return k1 + k2, ok1 && ok2
}
return 0, false
}

1140
vendor/github.com/miekg/dns/zduplicate.go generated vendored Normal file

File diff suppressed because it is too large Load diff

2039
vendor/github.com/miekg/dns/zmsg.go generated vendored

File diff suppressed because it is too large Load diff

450
vendor/github.com/miekg/dns/ztypes.go generated vendored
View file

@ -54,6 +54,7 @@ var TypeToRR = map[uint16]func() RR{
TypeNSEC: func() RR { return new(NSEC) }, TypeNSEC: func() RR { return new(NSEC) },
TypeNSEC3: func() RR { return new(NSEC3) }, TypeNSEC3: func() RR { return new(NSEC3) },
TypeNSEC3PARAM: func() RR { return new(NSEC3PARAM) }, TypeNSEC3PARAM: func() RR { return new(NSEC3PARAM) },
TypeNULL: func() RR { return new(NULL) },
TypeOPENPGPKEY: func() RR { return new(OPENPGPKEY) }, TypeOPENPGPKEY: func() RR { return new(OPENPGPKEY) },
TypeOPT: func() RR { return new(OPT) }, TypeOPT: func() RR { return new(OPT) },
TypePTR: func() RR { return new(PTR) }, TypePTR: func() RR { return new(PTR) },
@ -209,6 +210,7 @@ func (rr *NSAPPTR) Header() *RR_Header { return &rr.Hdr }
func (rr *NSEC) 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 *NSEC3) Header() *RR_Header { return &rr.Hdr }
func (rr *NSEC3PARAM) Header() *RR_Header { return &rr.Hdr } func (rr *NSEC3PARAM) Header() *RR_Header { return &rr.Hdr }
func (rr *NULL) Header() *RR_Header { return &rr.Hdr }
func (rr *OPENPGPKEY) 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 *OPT) Header() *RR_Header { return &rr.Hdr }
func (rr *PTR) Header() *RR_Header { return &rr.Hdr } func (rr *PTR) Header() *RR_Header { return &rr.Hdr }
@ -236,144 +238,144 @@ func (rr *URI) Header() *RR_Header { return &rr.Hdr }
func (rr *X25) Header() *RR_Header { return &rr.Hdr } func (rr *X25) Header() *RR_Header { return &rr.Hdr }
// len() functions // len() functions
func (rr *A) len() int { func (rr *A) len(off int, compression map[string]struct{}) int {
l := rr.Hdr.len() l := rr.Hdr.len(off, compression)
l += net.IPv4len // A l += net.IPv4len // A
return l return l
} }
func (rr *AAAA) len() int { func (rr *AAAA) len(off int, compression map[string]struct{}) int {
l := rr.Hdr.len() l := rr.Hdr.len(off, compression)
l += net.IPv6len // AAAA l += net.IPv6len // AAAA
return l return l
} }
func (rr *AFSDB) len() int { func (rr *AFSDB) len(off int, compression map[string]struct{}) int {
l := rr.Hdr.len() l := rr.Hdr.len(off, compression)
l += 2 // Subtype l += 2 // Subtype
l += len(rr.Hostname) + 1 l += domainNameLen(rr.Hostname, off+l, compression, false)
return l return l
} }
func (rr *ANY) len() int { func (rr *ANY) len(off int, compression map[string]struct{}) int {
l := rr.Hdr.len() l := rr.Hdr.len(off, compression)
return l return l
} }
func (rr *AVC) len() int { func (rr *AVC) len(off int, compression map[string]struct{}) int {
l := rr.Hdr.len() l := rr.Hdr.len(off, compression)
for _, x := range rr.Txt { for _, x := range rr.Txt {
l += len(x) + 1 l += len(x) + 1
} }
return l return l
} }
func (rr *CAA) len() int { func (rr *CAA) len(off int, compression map[string]struct{}) int {
l := rr.Hdr.len() l := rr.Hdr.len(off, compression)
l++ // Flag l++ // Flag
l += len(rr.Tag) + 1 l += len(rr.Tag) + 1
l += len(rr.Value) l += len(rr.Value)
return l return l
} }
func (rr *CERT) len() int { func (rr *CERT) len(off int, compression map[string]struct{}) int {
l := rr.Hdr.len() l := rr.Hdr.len(off, compression)
l += 2 // Type l += 2 // Type
l += 2 // KeyTag l += 2 // KeyTag
l++ // Algorithm l++ // Algorithm
l += base64.StdEncoding.DecodedLen(len(rr.Certificate)) l += base64.StdEncoding.DecodedLen(len(rr.Certificate))
return l return l
} }
func (rr *CNAME) len() int { func (rr *CNAME) len(off int, compression map[string]struct{}) int {
l := rr.Hdr.len() l := rr.Hdr.len(off, compression)
l += len(rr.Target) + 1 l += domainNameLen(rr.Target, off+l, compression, true)
return l return l
} }
func (rr *DHCID) len() int { func (rr *DHCID) len(off int, compression map[string]struct{}) int {
l := rr.Hdr.len() l := rr.Hdr.len(off, compression)
l += base64.StdEncoding.DecodedLen(len(rr.Digest)) l += base64.StdEncoding.DecodedLen(len(rr.Digest))
return l return l
} }
func (rr *DNAME) len() int { func (rr *DNAME) len(off int, compression map[string]struct{}) int {
l := rr.Hdr.len() l := rr.Hdr.len(off, compression)
l += len(rr.Target) + 1 l += domainNameLen(rr.Target, off+l, compression, false)
return l return l
} }
func (rr *DNSKEY) len() int { func (rr *DNSKEY) len(off int, compression map[string]struct{}) int {
l := rr.Hdr.len() l := rr.Hdr.len(off, compression)
l += 2 // Flags l += 2 // Flags
l++ // Protocol l++ // Protocol
l++ // Algorithm l++ // Algorithm
l += base64.StdEncoding.DecodedLen(len(rr.PublicKey)) l += base64.StdEncoding.DecodedLen(len(rr.PublicKey))
return l return l
} }
func (rr *DS) len() int { func (rr *DS) len(off int, compression map[string]struct{}) int {
l := rr.Hdr.len() l := rr.Hdr.len(off, compression)
l += 2 // KeyTag l += 2 // KeyTag
l++ // Algorithm l++ // Algorithm
l++ // DigestType l++ // DigestType
l += len(rr.Digest)/2 + 1 l += len(rr.Digest)/2 + 1
return l return l
} }
func (rr *EID) len() int { func (rr *EID) len(off int, compression map[string]struct{}) int {
l := rr.Hdr.len() l := rr.Hdr.len(off, compression)
l += len(rr.Endpoint)/2 + 1 l += len(rr.Endpoint)/2 + 1
return l return l
} }
func (rr *EUI48) len() int { func (rr *EUI48) len(off int, compression map[string]struct{}) int {
l := rr.Hdr.len() l := rr.Hdr.len(off, compression)
l += 6 // Address l += 6 // Address
return l return l
} }
func (rr *EUI64) len() int { func (rr *EUI64) len(off int, compression map[string]struct{}) int {
l := rr.Hdr.len() l := rr.Hdr.len(off, compression)
l += 8 // Address l += 8 // Address
return l return l
} }
func (rr *GID) len() int { func (rr *GID) len(off int, compression map[string]struct{}) int {
l := rr.Hdr.len() l := rr.Hdr.len(off, compression)
l += 4 // Gid l += 4 // Gid
return l return l
} }
func (rr *GPOS) len() int { func (rr *GPOS) len(off int, compression map[string]struct{}) int {
l := rr.Hdr.len() l := rr.Hdr.len(off, compression)
l += len(rr.Longitude) + 1 l += len(rr.Longitude) + 1
l += len(rr.Latitude) + 1 l += len(rr.Latitude) + 1
l += len(rr.Altitude) + 1 l += len(rr.Altitude) + 1
return l return l
} }
func (rr *HINFO) len() int { func (rr *HINFO) len(off int, compression map[string]struct{}) int {
l := rr.Hdr.len() l := rr.Hdr.len(off, compression)
l += len(rr.Cpu) + 1 l += len(rr.Cpu) + 1
l += len(rr.Os) + 1 l += len(rr.Os) + 1
return l return l
} }
func (rr *HIP) len() int { func (rr *HIP) len(off int, compression map[string]struct{}) int {
l := rr.Hdr.len() l := rr.Hdr.len(off, compression)
l++ // HitLength l++ // HitLength
l++ // PublicKeyAlgorithm l++ // PublicKeyAlgorithm
l += 2 // PublicKeyLength l += 2 // PublicKeyLength
l += len(rr.Hit) / 2 l += len(rr.Hit) / 2
l += base64.StdEncoding.DecodedLen(len(rr.PublicKey)) l += base64.StdEncoding.DecodedLen(len(rr.PublicKey))
for _, x := range rr.RendezvousServers { for _, x := range rr.RendezvousServers {
l += len(x) + 1 l += domainNameLen(x, off+l, compression, false)
} }
return l return l
} }
func (rr *KX) len() int { func (rr *KX) len(off int, compression map[string]struct{}) int {
l := rr.Hdr.len() l := rr.Hdr.len(off, compression)
l += 2 // Preference l += 2 // Preference
l += len(rr.Exchanger) + 1 l += domainNameLen(rr.Exchanger, off+l, compression, false)
return l return l
} }
func (rr *L32) len() int { func (rr *L32) len(off int, compression map[string]struct{}) int {
l := rr.Hdr.len() l := rr.Hdr.len(off, compression)
l += 2 // Preference l += 2 // Preference
l += net.IPv4len // Locator32 l += net.IPv4len // Locator32
return l return l
} }
func (rr *L64) len() int { func (rr *L64) len(off int, compression map[string]struct{}) int {
l := rr.Hdr.len() l := rr.Hdr.len(off, compression)
l += 2 // Preference l += 2 // Preference
l += 8 // Locator64 l += 8 // Locator64
return l return l
} }
func (rr *LOC) len() int { func (rr *LOC) len(off int, compression map[string]struct{}) int {
l := rr.Hdr.len() l := rr.Hdr.len(off, compression)
l++ // Version l++ // Version
l++ // Size l++ // Size
l++ // HorizPre l++ // HorizPre
@ -383,89 +385,89 @@ func (rr *LOC) len() int {
l += 4 // Altitude l += 4 // Altitude
return l return l
} }
func (rr *LP) len() int { func (rr *LP) len(off int, compression map[string]struct{}) int {
l := rr.Hdr.len() l := rr.Hdr.len(off, compression)
l += 2 // Preference l += 2 // Preference
l += len(rr.Fqdn) + 1 l += domainNameLen(rr.Fqdn, off+l, compression, false)
return l return l
} }
func (rr *MB) len() int { func (rr *MB) len(off int, compression map[string]struct{}) int {
l := rr.Hdr.len() l := rr.Hdr.len(off, compression)
l += len(rr.Mb) + 1 l += domainNameLen(rr.Mb, off+l, compression, true)
return l return l
} }
func (rr *MD) len() int { func (rr *MD) len(off int, compression map[string]struct{}) int {
l := rr.Hdr.len() l := rr.Hdr.len(off, compression)
l += len(rr.Md) + 1 l += domainNameLen(rr.Md, off+l, compression, true)
return l return l
} }
func (rr *MF) len() int { func (rr *MF) len(off int, compression map[string]struct{}) int {
l := rr.Hdr.len() l := rr.Hdr.len(off, compression)
l += len(rr.Mf) + 1 l += domainNameLen(rr.Mf, off+l, compression, true)
return l return l
} }
func (rr *MG) len() int { func (rr *MG) len(off int, compression map[string]struct{}) int {
l := rr.Hdr.len() l := rr.Hdr.len(off, compression)
l += len(rr.Mg) + 1 l += domainNameLen(rr.Mg, off+l, compression, true)
return l return l
} }
func (rr *MINFO) len() int { func (rr *MINFO) len(off int, compression map[string]struct{}) int {
l := rr.Hdr.len() l := rr.Hdr.len(off, compression)
l += len(rr.Rmail) + 1 l += domainNameLen(rr.Rmail, off+l, compression, true)
l += len(rr.Email) + 1 l += domainNameLen(rr.Email, off+l, compression, true)
return l return l
} }
func (rr *MR) len() int { func (rr *MR) len(off int, compression map[string]struct{}) int {
l := rr.Hdr.len() l := rr.Hdr.len(off, compression)
l += len(rr.Mr) + 1 l += domainNameLen(rr.Mr, off+l, compression, true)
return l return l
} }
func (rr *MX) len() int { func (rr *MX) len(off int, compression map[string]struct{}) int {
l := rr.Hdr.len() l := rr.Hdr.len(off, compression)
l += 2 // Preference l += 2 // Preference
l += len(rr.Mx) + 1 l += domainNameLen(rr.Mx, off+l, compression, true)
return l return l
} }
func (rr *NAPTR) len() int { func (rr *NAPTR) len(off int, compression map[string]struct{}) int {
l := rr.Hdr.len() l := rr.Hdr.len(off, compression)
l += 2 // Order l += 2 // Order
l += 2 // Preference l += 2 // Preference
l += len(rr.Flags) + 1 l += len(rr.Flags) + 1
l += len(rr.Service) + 1 l += len(rr.Service) + 1
l += len(rr.Regexp) + 1 l += len(rr.Regexp) + 1
l += len(rr.Replacement) + 1 l += domainNameLen(rr.Replacement, off+l, compression, false)
return l return l
} }
func (rr *NID) len() int { func (rr *NID) len(off int, compression map[string]struct{}) int {
l := rr.Hdr.len() l := rr.Hdr.len(off, compression)
l += 2 // Preference l += 2 // Preference
l += 8 // NodeID l += 8 // NodeID
return l return l
} }
func (rr *NIMLOC) len() int { func (rr *NIMLOC) len(off int, compression map[string]struct{}) int {
l := rr.Hdr.len() l := rr.Hdr.len(off, compression)
l += len(rr.Locator)/2 + 1 l += len(rr.Locator)/2 + 1
return l return l
} }
func (rr *NINFO) len() int { func (rr *NINFO) len(off int, compression map[string]struct{}) int {
l := rr.Hdr.len() l := rr.Hdr.len(off, compression)
for _, x := range rr.ZSData { for _, x := range rr.ZSData {
l += len(x) + 1 l += len(x) + 1
} }
return l return l
} }
func (rr *NS) len() int { func (rr *NS) len(off int, compression map[string]struct{}) int {
l := rr.Hdr.len() l := rr.Hdr.len(off, compression)
l += len(rr.Ns) + 1 l += domainNameLen(rr.Ns, off+l, compression, true)
return l return l
} }
func (rr *NSAPPTR) len() int { func (rr *NSAPPTR) len(off int, compression map[string]struct{}) int {
l := rr.Hdr.len() l := rr.Hdr.len(off, compression)
l += len(rr.Ptr) + 1 l += domainNameLen(rr.Ptr, off+l, compression, false)
return l return l
} }
func (rr *NSEC3PARAM) len() int { func (rr *NSEC3PARAM) len(off int, compression map[string]struct{}) int {
l := rr.Hdr.len() l := rr.Hdr.len(off, compression)
l++ // Hash l++ // Hash
l++ // Flags l++ // Flags
l += 2 // Iterations l += 2 // Iterations
@ -473,44 +475,49 @@ func (rr *NSEC3PARAM) len() int {
l += len(rr.Salt) / 2 l += len(rr.Salt) / 2
return l return l
} }
func (rr *OPENPGPKEY) len() int { func (rr *NULL) len(off int, compression map[string]struct{}) int {
l := rr.Hdr.len() l := rr.Hdr.len(off, compression)
l += len(rr.Data)
return l
}
func (rr *OPENPGPKEY) len(off int, compression map[string]struct{}) int {
l := rr.Hdr.len(off, compression)
l += base64.StdEncoding.DecodedLen(len(rr.PublicKey)) l += base64.StdEncoding.DecodedLen(len(rr.PublicKey))
return l return l
} }
func (rr *PTR) len() int { func (rr *PTR) len(off int, compression map[string]struct{}) int {
l := rr.Hdr.len() l := rr.Hdr.len(off, compression)
l += len(rr.Ptr) + 1 l += domainNameLen(rr.Ptr, off+l, compression, true)
return l return l
} }
func (rr *PX) len() int { func (rr *PX) len(off int, compression map[string]struct{}) int {
l := rr.Hdr.len() l := rr.Hdr.len(off, compression)
l += 2 // Preference l += 2 // Preference
l += len(rr.Map822) + 1 l += domainNameLen(rr.Map822, off+l, compression, false)
l += len(rr.Mapx400) + 1 l += domainNameLen(rr.Mapx400, off+l, compression, false)
return l return l
} }
func (rr *RFC3597) len() int { func (rr *RFC3597) len(off int, compression map[string]struct{}) int {
l := rr.Hdr.len() l := rr.Hdr.len(off, compression)
l += len(rr.Rdata)/2 + 1 l += len(rr.Rdata)/2 + 1
return l return l
} }
func (rr *RKEY) len() int { func (rr *RKEY) len(off int, compression map[string]struct{}) int {
l := rr.Hdr.len() l := rr.Hdr.len(off, compression)
l += 2 // Flags l += 2 // Flags
l++ // Protocol l++ // Protocol
l++ // Algorithm l++ // Algorithm
l += base64.StdEncoding.DecodedLen(len(rr.PublicKey)) l += base64.StdEncoding.DecodedLen(len(rr.PublicKey))
return l return l
} }
func (rr *RP) len() int { func (rr *RP) len(off int, compression map[string]struct{}) int {
l := rr.Hdr.len() l := rr.Hdr.len(off, compression)
l += len(rr.Mbox) + 1 l += domainNameLen(rr.Mbox, off+l, compression, false)
l += len(rr.Txt) + 1 l += domainNameLen(rr.Txt, off+l, compression, false)
return l return l
} }
func (rr *RRSIG) len() int { func (rr *RRSIG) len(off int, compression map[string]struct{}) int {
l := rr.Hdr.len() l := rr.Hdr.len(off, compression)
l += 2 // TypeCovered l += 2 // TypeCovered
l++ // Algorithm l++ // Algorithm
l++ // Labels l++ // Labels
@ -518,28 +525,28 @@ func (rr *RRSIG) len() int {
l += 4 // Expiration l += 4 // Expiration
l += 4 // Inception l += 4 // Inception
l += 2 // KeyTag l += 2 // KeyTag
l += len(rr.SignerName) + 1 l += domainNameLen(rr.SignerName, off+l, compression, false)
l += base64.StdEncoding.DecodedLen(len(rr.Signature)) l += base64.StdEncoding.DecodedLen(len(rr.Signature))
return l return l
} }
func (rr *RT) len() int { func (rr *RT) len(off int, compression map[string]struct{}) int {
l := rr.Hdr.len() l := rr.Hdr.len(off, compression)
l += 2 // Preference l += 2 // Preference
l += len(rr.Host) + 1 l += domainNameLen(rr.Host, off+l, compression, false)
return l return l
} }
func (rr *SMIMEA) len() int { func (rr *SMIMEA) len(off int, compression map[string]struct{}) int {
l := rr.Hdr.len() l := rr.Hdr.len(off, compression)
l++ // Usage l++ // Usage
l++ // Selector l++ // Selector
l++ // MatchingType l++ // MatchingType
l += len(rr.Certificate)/2 + 1 l += len(rr.Certificate)/2 + 1
return l return l
} }
func (rr *SOA) len() int { func (rr *SOA) len(off int, compression map[string]struct{}) int {
l := rr.Hdr.len() l := rr.Hdr.len(off, compression)
l += len(rr.Ns) + 1 l += domainNameLen(rr.Ns, off+l, compression, true)
l += len(rr.Mbox) + 1 l += domainNameLen(rr.Mbox, off+l, compression, true)
l += 4 // Serial l += 4 // Serial
l += 4 // Refresh l += 4 // Refresh
l += 4 // Retry l += 4 // Retry
@ -547,45 +554,45 @@ func (rr *SOA) len() int {
l += 4 // Minttl l += 4 // Minttl
return l return l
} }
func (rr *SPF) len() int { func (rr *SPF) len(off int, compression map[string]struct{}) int {
l := rr.Hdr.len() l := rr.Hdr.len(off, compression)
for _, x := range rr.Txt { for _, x := range rr.Txt {
l += len(x) + 1 l += len(x) + 1
} }
return l return l
} }
func (rr *SRV) len() int { func (rr *SRV) len(off int, compression map[string]struct{}) int {
l := rr.Hdr.len() l := rr.Hdr.len(off, compression)
l += 2 // Priority l += 2 // Priority
l += 2 // Weight l += 2 // Weight
l += 2 // Port l += 2 // Port
l += len(rr.Target) + 1 l += domainNameLen(rr.Target, off+l, compression, false)
return l return l
} }
func (rr *SSHFP) len() int { func (rr *SSHFP) len(off int, compression map[string]struct{}) int {
l := rr.Hdr.len() l := rr.Hdr.len(off, compression)
l++ // Algorithm l++ // Algorithm
l++ // Type l++ // Type
l += len(rr.FingerPrint)/2 + 1 l += len(rr.FingerPrint)/2 + 1
return l return l
} }
func (rr *TA) len() int { func (rr *TA) len(off int, compression map[string]struct{}) int {
l := rr.Hdr.len() l := rr.Hdr.len(off, compression)
l += 2 // KeyTag l += 2 // KeyTag
l++ // Algorithm l++ // Algorithm
l++ // DigestType l++ // DigestType
l += len(rr.Digest)/2 + 1 l += len(rr.Digest)/2 + 1
return l return l
} }
func (rr *TALINK) len() int { func (rr *TALINK) len(off int, compression map[string]struct{}) int {
l := rr.Hdr.len() l := rr.Hdr.len(off, compression)
l += len(rr.PreviousName) + 1 l += domainNameLen(rr.PreviousName, off+l, compression, false)
l += len(rr.NextName) + 1 l += domainNameLen(rr.NextName, off+l, compression, false)
return l return l
} }
func (rr *TKEY) len() int { func (rr *TKEY) len(off int, compression map[string]struct{}) int {
l := rr.Hdr.len() l := rr.Hdr.len(off, compression)
l += len(rr.Algorithm) + 1 l += domainNameLen(rr.Algorithm, off+l, compression, false)
l += 4 // Inception l += 4 // Inception
l += 4 // Expiration l += 4 // Expiration
l += 2 // Mode l += 2 // Mode
@ -596,17 +603,17 @@ func (rr *TKEY) len() int {
l += len(rr.OtherData) / 2 l += len(rr.OtherData) / 2
return l return l
} }
func (rr *TLSA) len() int { func (rr *TLSA) len(off int, compression map[string]struct{}) int {
l := rr.Hdr.len() l := rr.Hdr.len(off, compression)
l++ // Usage l++ // Usage
l++ // Selector l++ // Selector
l++ // MatchingType l++ // MatchingType
l += len(rr.Certificate)/2 + 1 l += len(rr.Certificate)/2 + 1
return l return l
} }
func (rr *TSIG) len() int { func (rr *TSIG) len(off int, compression map[string]struct{}) int {
l := rr.Hdr.len() l := rr.Hdr.len(off, compression)
l += len(rr.Algorithm) + 1 l += domainNameLen(rr.Algorithm, off+l, compression, false)
l += 6 // TimeSigned l += 6 // TimeSigned
l += 2 // Fudge l += 2 // Fudge
l += 2 // MACSize l += 2 // MACSize
@ -617,247 +624,252 @@ func (rr *TSIG) len() int {
l += len(rr.OtherData) / 2 l += len(rr.OtherData) / 2
return l return l
} }
func (rr *TXT) len() int { func (rr *TXT) len(off int, compression map[string]struct{}) int {
l := rr.Hdr.len() l := rr.Hdr.len(off, compression)
for _, x := range rr.Txt { for _, x := range rr.Txt {
l += len(x) + 1 l += len(x) + 1
} }
return l return l
} }
func (rr *UID) len() int { func (rr *UID) len(off int, compression map[string]struct{}) int {
l := rr.Hdr.len() l := rr.Hdr.len(off, compression)
l += 4 // Uid l += 4 // Uid
return l return l
} }
func (rr *UINFO) len() int { func (rr *UINFO) len(off int, compression map[string]struct{}) int {
l := rr.Hdr.len() l := rr.Hdr.len(off, compression)
l += len(rr.Uinfo) + 1 l += len(rr.Uinfo) + 1
return l return l
} }
func (rr *URI) len() int { func (rr *URI) len(off int, compression map[string]struct{}) int {
l := rr.Hdr.len() l := rr.Hdr.len(off, compression)
l += 2 // Priority l += 2 // Priority
l += 2 // Weight l += 2 // Weight
l += len(rr.Target) l += len(rr.Target)
return l return l
} }
func (rr *X25) len() int { func (rr *X25) len(off int, compression map[string]struct{}) int {
l := rr.Hdr.len() l := rr.Hdr.len(off, compression)
l += len(rr.PSDNAddress) + 1 l += len(rr.PSDNAddress) + 1
return l return l
} }
// copy() functions // copy() functions
func (rr *A) copy() RR { func (rr *A) copy() RR {
return &A{*rr.Hdr.copyHeader(), copyIP(rr.A)} return &A{rr.Hdr, copyIP(rr.A)}
} }
func (rr *AAAA) copy() RR { func (rr *AAAA) copy() RR {
return &AAAA{*rr.Hdr.copyHeader(), copyIP(rr.AAAA)} return &AAAA{rr.Hdr, copyIP(rr.AAAA)}
} }
func (rr *AFSDB) copy() RR { func (rr *AFSDB) copy() RR {
return &AFSDB{*rr.Hdr.copyHeader(), rr.Subtype, rr.Hostname} return &AFSDB{rr.Hdr, rr.Subtype, rr.Hostname}
} }
func (rr *ANY) copy() RR { func (rr *ANY) copy() RR {
return &ANY{*rr.Hdr.copyHeader()} return &ANY{rr.Hdr}
} }
func (rr *AVC) copy() RR { func (rr *AVC) copy() RR {
Txt := make([]string, len(rr.Txt)) Txt := make([]string, len(rr.Txt))
copy(Txt, rr.Txt) copy(Txt, rr.Txt)
return &AVC{*rr.Hdr.copyHeader(), Txt} return &AVC{rr.Hdr, Txt}
} }
func (rr *CAA) copy() RR { func (rr *CAA) copy() RR {
return &CAA{*rr.Hdr.copyHeader(), rr.Flag, rr.Tag, rr.Value} return &CAA{rr.Hdr, rr.Flag, rr.Tag, rr.Value}
} }
func (rr *CERT) copy() RR { func (rr *CERT) copy() RR {
return &CERT{*rr.Hdr.copyHeader(), rr.Type, rr.KeyTag, rr.Algorithm, rr.Certificate} return &CERT{rr.Hdr, rr.Type, rr.KeyTag, rr.Algorithm, rr.Certificate}
} }
func (rr *CNAME) copy() RR { func (rr *CNAME) copy() RR {
return &CNAME{*rr.Hdr.copyHeader(), rr.Target} return &CNAME{rr.Hdr, rr.Target}
} }
func (rr *CSYNC) copy() RR { func (rr *CSYNC) copy() RR {
TypeBitMap := make([]uint16, len(rr.TypeBitMap)) TypeBitMap := make([]uint16, len(rr.TypeBitMap))
copy(TypeBitMap, rr.TypeBitMap) copy(TypeBitMap, rr.TypeBitMap)
return &CSYNC{*rr.Hdr.copyHeader(), rr.Serial, rr.Flags, TypeBitMap} return &CSYNC{rr.Hdr, rr.Serial, rr.Flags, TypeBitMap}
} }
func (rr *DHCID) copy() RR { func (rr *DHCID) copy() RR {
return &DHCID{*rr.Hdr.copyHeader(), rr.Digest} return &DHCID{rr.Hdr, rr.Digest}
} }
func (rr *DNAME) copy() RR { func (rr *DNAME) copy() RR {
return &DNAME{*rr.Hdr.copyHeader(), rr.Target} return &DNAME{rr.Hdr, rr.Target}
} }
func (rr *DNSKEY) copy() RR { func (rr *DNSKEY) copy() RR {
return &DNSKEY{*rr.Hdr.copyHeader(), rr.Flags, rr.Protocol, rr.Algorithm, rr.PublicKey} return &DNSKEY{rr.Hdr, rr.Flags, rr.Protocol, rr.Algorithm, rr.PublicKey}
} }
func (rr *DS) copy() RR { func (rr *DS) copy() RR {
return &DS{*rr.Hdr.copyHeader(), rr.KeyTag, rr.Algorithm, rr.DigestType, rr.Digest} return &DS{rr.Hdr, rr.KeyTag, rr.Algorithm, rr.DigestType, rr.Digest}
} }
func (rr *EID) copy() RR { func (rr *EID) copy() RR {
return &EID{*rr.Hdr.copyHeader(), rr.Endpoint} return &EID{rr.Hdr, rr.Endpoint}
} }
func (rr *EUI48) copy() RR { func (rr *EUI48) copy() RR {
return &EUI48{*rr.Hdr.copyHeader(), rr.Address} return &EUI48{rr.Hdr, rr.Address}
} }
func (rr *EUI64) copy() RR { func (rr *EUI64) copy() RR {
return &EUI64{*rr.Hdr.copyHeader(), rr.Address} return &EUI64{rr.Hdr, rr.Address}
} }
func (rr *GID) copy() RR { func (rr *GID) copy() RR {
return &GID{*rr.Hdr.copyHeader(), rr.Gid} return &GID{rr.Hdr, rr.Gid}
} }
func (rr *GPOS) copy() RR { func (rr *GPOS) copy() RR {
return &GPOS{*rr.Hdr.copyHeader(), rr.Longitude, rr.Latitude, rr.Altitude} return &GPOS{rr.Hdr, rr.Longitude, rr.Latitude, rr.Altitude}
} }
func (rr *HINFO) copy() RR { func (rr *HINFO) copy() RR {
return &HINFO{*rr.Hdr.copyHeader(), rr.Cpu, rr.Os} return &HINFO{rr.Hdr, rr.Cpu, rr.Os}
} }
func (rr *HIP) copy() RR { func (rr *HIP) copy() RR {
RendezvousServers := make([]string, len(rr.RendezvousServers)) RendezvousServers := make([]string, len(rr.RendezvousServers))
copy(RendezvousServers, rr.RendezvousServers) copy(RendezvousServers, rr.RendezvousServers)
return &HIP{*rr.Hdr.copyHeader(), rr.HitLength, rr.PublicKeyAlgorithm, rr.PublicKeyLength, rr.Hit, rr.PublicKey, RendezvousServers} return &HIP{rr.Hdr, rr.HitLength, rr.PublicKeyAlgorithm, rr.PublicKeyLength, rr.Hit, rr.PublicKey, RendezvousServers}
} }
func (rr *KX) copy() RR { func (rr *KX) copy() RR {
return &KX{*rr.Hdr.copyHeader(), rr.Preference, rr.Exchanger} return &KX{rr.Hdr, rr.Preference, rr.Exchanger}
} }
func (rr *L32) copy() RR { func (rr *L32) copy() RR {
return &L32{*rr.Hdr.copyHeader(), rr.Preference, copyIP(rr.Locator32)} return &L32{rr.Hdr, rr.Preference, copyIP(rr.Locator32)}
} }
func (rr *L64) copy() RR { func (rr *L64) copy() RR {
return &L64{*rr.Hdr.copyHeader(), rr.Preference, rr.Locator64} return &L64{rr.Hdr, rr.Preference, rr.Locator64}
} }
func (rr *LOC) copy() RR { func (rr *LOC) copy() RR {
return &LOC{*rr.Hdr.copyHeader(), rr.Version, rr.Size, rr.HorizPre, rr.VertPre, rr.Latitude, rr.Longitude, rr.Altitude} return &LOC{rr.Hdr, rr.Version, rr.Size, rr.HorizPre, rr.VertPre, rr.Latitude, rr.Longitude, rr.Altitude}
} }
func (rr *LP) copy() RR { func (rr *LP) copy() RR {
return &LP{*rr.Hdr.copyHeader(), rr.Preference, rr.Fqdn} return &LP{rr.Hdr, rr.Preference, rr.Fqdn}
} }
func (rr *MB) copy() RR { func (rr *MB) copy() RR {
return &MB{*rr.Hdr.copyHeader(), rr.Mb} return &MB{rr.Hdr, rr.Mb}
} }
func (rr *MD) copy() RR { func (rr *MD) copy() RR {
return &MD{*rr.Hdr.copyHeader(), rr.Md} return &MD{rr.Hdr, rr.Md}
} }
func (rr *MF) copy() RR { func (rr *MF) copy() RR {
return &MF{*rr.Hdr.copyHeader(), rr.Mf} return &MF{rr.Hdr, rr.Mf}
} }
func (rr *MG) copy() RR { func (rr *MG) copy() RR {
return &MG{*rr.Hdr.copyHeader(), rr.Mg} return &MG{rr.Hdr, rr.Mg}
} }
func (rr *MINFO) copy() RR { func (rr *MINFO) copy() RR {
return &MINFO{*rr.Hdr.copyHeader(), rr.Rmail, rr.Email} return &MINFO{rr.Hdr, rr.Rmail, rr.Email}
} }
func (rr *MR) copy() RR { func (rr *MR) copy() RR {
return &MR{*rr.Hdr.copyHeader(), rr.Mr} return &MR{rr.Hdr, rr.Mr}
} }
func (rr *MX) copy() RR { func (rr *MX) copy() RR {
return &MX{*rr.Hdr.copyHeader(), rr.Preference, rr.Mx} return &MX{rr.Hdr, rr.Preference, rr.Mx}
} }
func (rr *NAPTR) copy() RR { func (rr *NAPTR) copy() RR {
return &NAPTR{*rr.Hdr.copyHeader(), rr.Order, rr.Preference, rr.Flags, rr.Service, rr.Regexp, rr.Replacement} return &NAPTR{rr.Hdr, rr.Order, rr.Preference, rr.Flags, rr.Service, rr.Regexp, rr.Replacement}
} }
func (rr *NID) copy() RR { func (rr *NID) copy() RR {
return &NID{*rr.Hdr.copyHeader(), rr.Preference, rr.NodeID} return &NID{rr.Hdr, rr.Preference, rr.NodeID}
} }
func (rr *NIMLOC) copy() RR { func (rr *NIMLOC) copy() RR {
return &NIMLOC{*rr.Hdr.copyHeader(), rr.Locator} return &NIMLOC{rr.Hdr, rr.Locator}
} }
func (rr *NINFO) copy() RR { func (rr *NINFO) copy() RR {
ZSData := make([]string, len(rr.ZSData)) ZSData := make([]string, len(rr.ZSData))
copy(ZSData, rr.ZSData) copy(ZSData, rr.ZSData)
return &NINFO{*rr.Hdr.copyHeader(), ZSData} return &NINFO{rr.Hdr, ZSData}
} }
func (rr *NS) copy() RR { func (rr *NS) copy() RR {
return &NS{*rr.Hdr.copyHeader(), rr.Ns} return &NS{rr.Hdr, rr.Ns}
} }
func (rr *NSAPPTR) copy() RR { func (rr *NSAPPTR) copy() RR {
return &NSAPPTR{*rr.Hdr.copyHeader(), rr.Ptr} return &NSAPPTR{rr.Hdr, rr.Ptr}
} }
func (rr *NSEC) copy() RR { func (rr *NSEC) copy() RR {
TypeBitMap := make([]uint16, len(rr.TypeBitMap)) TypeBitMap := make([]uint16, len(rr.TypeBitMap))
copy(TypeBitMap, rr.TypeBitMap) copy(TypeBitMap, rr.TypeBitMap)
return &NSEC{*rr.Hdr.copyHeader(), rr.NextDomain, TypeBitMap} return &NSEC{rr.Hdr, rr.NextDomain, TypeBitMap}
} }
func (rr *NSEC3) copy() RR { func (rr *NSEC3) copy() RR {
TypeBitMap := make([]uint16, len(rr.TypeBitMap)) TypeBitMap := make([]uint16, len(rr.TypeBitMap))
copy(TypeBitMap, 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} return &NSEC3{rr.Hdr, rr.Hash, rr.Flags, rr.Iterations, rr.SaltLength, rr.Salt, rr.HashLength, rr.NextDomain, TypeBitMap}
} }
func (rr *NSEC3PARAM) copy() RR { func (rr *NSEC3PARAM) copy() RR {
return &NSEC3PARAM{*rr.Hdr.copyHeader(), rr.Hash, rr.Flags, rr.Iterations, rr.SaltLength, rr.Salt} return &NSEC3PARAM{rr.Hdr, rr.Hash, rr.Flags, rr.Iterations, rr.SaltLength, rr.Salt}
}
func (rr *NULL) copy() RR {
return &NULL{rr.Hdr, rr.Data}
} }
func (rr *OPENPGPKEY) copy() RR { func (rr *OPENPGPKEY) copy() RR {
return &OPENPGPKEY{*rr.Hdr.copyHeader(), rr.PublicKey} return &OPENPGPKEY{rr.Hdr, rr.PublicKey}
} }
func (rr *OPT) copy() RR { func (rr *OPT) copy() RR {
Option := make([]EDNS0, len(rr.Option)) Option := make([]EDNS0, len(rr.Option))
copy(Option, rr.Option) for i, e := range rr.Option {
return &OPT{*rr.Hdr.copyHeader(), Option} Option[i] = e.copy()
}
return &OPT{rr.Hdr, Option}
} }
func (rr *PTR) copy() RR { func (rr *PTR) copy() RR {
return &PTR{*rr.Hdr.copyHeader(), rr.Ptr} return &PTR{rr.Hdr, rr.Ptr}
} }
func (rr *PX) copy() RR { func (rr *PX) copy() RR {
return &PX{*rr.Hdr.copyHeader(), rr.Preference, rr.Map822, rr.Mapx400} return &PX{rr.Hdr, rr.Preference, rr.Map822, rr.Mapx400}
} }
func (rr *RFC3597) copy() RR { func (rr *RFC3597) copy() RR {
return &RFC3597{*rr.Hdr.copyHeader(), rr.Rdata} return &RFC3597{rr.Hdr, rr.Rdata}
} }
func (rr *RKEY) copy() RR { func (rr *RKEY) copy() RR {
return &RKEY{*rr.Hdr.copyHeader(), rr.Flags, rr.Protocol, rr.Algorithm, rr.PublicKey} return &RKEY{rr.Hdr, rr.Flags, rr.Protocol, rr.Algorithm, rr.PublicKey}
} }
func (rr *RP) copy() RR { func (rr *RP) copy() RR {
return &RP{*rr.Hdr.copyHeader(), rr.Mbox, rr.Txt} return &RP{rr.Hdr, rr.Mbox, rr.Txt}
} }
func (rr *RRSIG) copy() RR { 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} return &RRSIG{rr.Hdr, rr.TypeCovered, rr.Algorithm, rr.Labels, rr.OrigTtl, rr.Expiration, rr.Inception, rr.KeyTag, rr.SignerName, rr.Signature}
} }
func (rr *RT) copy() RR { func (rr *RT) copy() RR {
return &RT{*rr.Hdr.copyHeader(), rr.Preference, rr.Host} return &RT{rr.Hdr, rr.Preference, rr.Host}
} }
func (rr *SMIMEA) copy() RR { func (rr *SMIMEA) copy() RR {
return &SMIMEA{*rr.Hdr.copyHeader(), rr.Usage, rr.Selector, rr.MatchingType, rr.Certificate} return &SMIMEA{rr.Hdr, rr.Usage, rr.Selector, rr.MatchingType, rr.Certificate}
} }
func (rr *SOA) copy() RR { func (rr *SOA) copy() RR {
return &SOA{*rr.Hdr.copyHeader(), rr.Ns, rr.Mbox, rr.Serial, rr.Refresh, rr.Retry, rr.Expire, rr.Minttl} return &SOA{rr.Hdr, rr.Ns, rr.Mbox, rr.Serial, rr.Refresh, rr.Retry, rr.Expire, rr.Minttl}
} }
func (rr *SPF) copy() RR { func (rr *SPF) copy() RR {
Txt := make([]string, len(rr.Txt)) Txt := make([]string, len(rr.Txt))
copy(Txt, rr.Txt) copy(Txt, rr.Txt)
return &SPF{*rr.Hdr.copyHeader(), Txt} return &SPF{rr.Hdr, Txt}
} }
func (rr *SRV) copy() RR { func (rr *SRV) copy() RR {
return &SRV{*rr.Hdr.copyHeader(), rr.Priority, rr.Weight, rr.Port, rr.Target} return &SRV{rr.Hdr, rr.Priority, rr.Weight, rr.Port, rr.Target}
} }
func (rr *SSHFP) copy() RR { func (rr *SSHFP) copy() RR {
return &SSHFP{*rr.Hdr.copyHeader(), rr.Algorithm, rr.Type, rr.FingerPrint} return &SSHFP{rr.Hdr, rr.Algorithm, rr.Type, rr.FingerPrint}
} }
func (rr *TA) copy() RR { func (rr *TA) copy() RR {
return &TA{*rr.Hdr.copyHeader(), rr.KeyTag, rr.Algorithm, rr.DigestType, rr.Digest} return &TA{rr.Hdr, rr.KeyTag, rr.Algorithm, rr.DigestType, rr.Digest}
} }
func (rr *TALINK) copy() RR { func (rr *TALINK) copy() RR {
return &TALINK{*rr.Hdr.copyHeader(), rr.PreviousName, rr.NextName} return &TALINK{rr.Hdr, rr.PreviousName, rr.NextName}
} }
func (rr *TKEY) copy() RR { 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} return &TKEY{rr.Hdr, rr.Algorithm, rr.Inception, rr.Expiration, rr.Mode, rr.Error, rr.KeySize, rr.Key, rr.OtherLen, rr.OtherData}
} }
func (rr *TLSA) copy() RR { func (rr *TLSA) copy() RR {
return &TLSA{*rr.Hdr.copyHeader(), rr.Usage, rr.Selector, rr.MatchingType, rr.Certificate} return &TLSA{rr.Hdr, rr.Usage, rr.Selector, rr.MatchingType, rr.Certificate}
} }
func (rr *TSIG) copy() RR { 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} return &TSIG{rr.Hdr, rr.Algorithm, rr.TimeSigned, rr.Fudge, rr.MACSize, rr.MAC, rr.OrigId, rr.Error, rr.OtherLen, rr.OtherData}
} }
func (rr *TXT) copy() RR { func (rr *TXT) copy() RR {
Txt := make([]string, len(rr.Txt)) Txt := make([]string, len(rr.Txt))
copy(Txt, rr.Txt) copy(Txt, rr.Txt)
return &TXT{*rr.Hdr.copyHeader(), Txt} return &TXT{rr.Hdr, Txt}
} }
func (rr *UID) copy() RR { func (rr *UID) copy() RR {
return &UID{*rr.Hdr.copyHeader(), rr.Uid} return &UID{rr.Hdr, rr.Uid}
} }
func (rr *UINFO) copy() RR { func (rr *UINFO) copy() RR {
return &UINFO{*rr.Hdr.copyHeader(), rr.Uinfo} return &UINFO{rr.Hdr, rr.Uinfo}
} }
func (rr *URI) copy() RR { func (rr *URI) copy() RR {
return &URI{*rr.Hdr.copyHeader(), rr.Priority, rr.Weight, rr.Target} return &URI{rr.Hdr, rr.Priority, rr.Weight, rr.Target}
} }
func (rr *X25) copy() RR { func (rr *X25) copy() RR {
return &X25{*rr.Hdr.copyHeader(), rr.PSDNAddress} return &X25{rr.Hdr, rr.PSDNAddress}
} }

2
vendor/modules.txt vendored
View file

@ -191,7 +191,7 @@ github.com/julienschmidt/httprouter
github.com/kr/logfmt github.com/kr/logfmt
# github.com/matttproud/golang_protobuf_extensions v1.0.1 # github.com/matttproud/golang_protobuf_extensions v1.0.1
github.com/matttproud/golang_protobuf_extensions/pbutil github.com/matttproud/golang_protobuf_extensions/pbutil
# github.com/miekg/dns v1.0.4 # github.com/miekg/dns v1.1.4
github.com/miekg/dns github.com/miekg/dns
# github.com/mitchellh/go-homedir v0.0.0-20180523094522-3864e76763d9 # github.com/mitchellh/go-homedir v0.0.0-20180523094522-3864e76763d9
github.com/mitchellh/go-homedir github.com/mitchellh/go-homedir