mirror of https://github.com/status-im/consul.git
Vendor update miekg/dns to pick up bugfixes and features (#3547)
This commit is contained in:
parent
467f74586f
commit
285dbe2d76
|
@ -1,4 +1,5 @@
|
||||||
[![Build Status](https://travis-ci.org/miekg/dns.svg?branch=master)](https://travis-ci.org/miekg/dns)
|
[![Build Status](https://travis-ci.org/miekg/dns.svg?branch=master)](https://travis-ci.org/miekg/dns)
|
||||||
|
[![](https://godoc.org/github.com/miekg/dns?status.svg)](https://godoc.org/github.com/miekg/dns)
|
||||||
|
|
||||||
# Alternative (more granular) approach to a DNS library
|
# Alternative (more granular) approach to a DNS library
|
||||||
|
|
||||||
|
@ -12,18 +13,19 @@ can build servers and resolvers with it.
|
||||||
|
|
||||||
We try to keep the "master" branch as sane as possible and at the bleeding edge
|
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
|
of standards, avoiding breaking changes wherever reasonable. We support the last
|
||||||
two versions of Go, currently: 1.5 and 1.6.
|
two versions of Go, currently: 1.7 and 1.8.
|
||||||
|
|
||||||
# Goals
|
# Goals
|
||||||
|
|
||||||
* KISS;
|
* KISS;
|
||||||
* Fast;
|
* Fast;
|
||||||
* Small API, if its easy to code in Go, don't make a function for it.
|
* Small API. If it's easy to code in Go, don't make a function for it.
|
||||||
|
|
||||||
# Users
|
# Users
|
||||||
|
|
||||||
A not-so-up-to-date-list-that-may-be-actually-current:
|
A not-so-up-to-date-list-that-may-be-actually-current:
|
||||||
|
|
||||||
|
* https://github.com/coredns/coredns
|
||||||
* https://cloudflare.com
|
* https://cloudflare.com
|
||||||
* https://github.com/abh/geodns
|
* https://github.com/abh/geodns
|
||||||
* http://www.statdns.com/
|
* http://www.statdns.com/
|
||||||
|
@ -50,6 +52,14 @@ A not-so-up-to-date-list-that-may-be-actually-current:
|
||||||
* https://dnslookup.org
|
* https://dnslookup.org
|
||||||
* https://github.com/looterz/grimd
|
* https://github.com/looterz/grimd
|
||||||
* https://github.com/phamhongviet/serf-dns
|
* https://github.com/phamhongviet/serf-dns
|
||||||
|
* https://github.com/mehrdadrad/mylg
|
||||||
|
* https://github.com/bamarni/dockness
|
||||||
|
* https://github.com/fffaraz/microdns
|
||||||
|
* http://quilt.io
|
||||||
|
* https://github.com/ipdcode/hades (JD.COM)
|
||||||
|
* https://github.com/StackExchange/dnscontrol/
|
||||||
|
* https://www.dnsperf.com/
|
||||||
|
* https://dnssectest.net/
|
||||||
|
|
||||||
Send pull request if you want to be listed here.
|
Send pull request if you want to be listed here.
|
||||||
|
|
||||||
|
@ -138,6 +148,7 @@ Example programs can be found in the `github.com/miekg/exdns` repository.
|
||||||
* 6975 - Algorithm Understanding in DNSSEC
|
* 6975 - Algorithm Understanding in DNSSEC
|
||||||
* 7043 - EUI48/EUI64 records
|
* 7043 - EUI48/EUI64 records
|
||||||
* 7314 - DNS (EDNS) EXPIRE Option
|
* 7314 - DNS (EDNS) EXPIRE Option
|
||||||
|
* 7828 - edns-tcp-keepalive EDNS0 Option
|
||||||
* 7553 - URI record
|
* 7553 - URI record
|
||||||
* 7858 - DNS over TLS: Initiation and Performance Considerations (draft)
|
* 7858 - DNS over TLS: Initiation and Performance Considerations (draft)
|
||||||
* 7873 - Domain Name System (DNS) Cookies (draft-ietf-dnsop-cookies)
|
* 7873 - Domain Name System (DNS) Cookies (draft-ietf-dnsop-cookies)
|
||||||
|
|
|
@ -4,6 +4,7 @@ package dns
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"io"
|
"io"
|
||||||
|
@ -39,7 +40,7 @@ type Client struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exchange performs a synchronous UDP query. It sends the message m to the address
|
// Exchange performs a synchronous UDP query. It sends the message m to the address
|
||||||
// contained in a and waits for an reply. Exchange does not retry a failed query, nor
|
// contained in a and waits for a reply. Exchange does not retry a failed query, nor
|
||||||
// will it fall back to TCP in case of truncation.
|
// will it fall back to TCP in case of truncation.
|
||||||
// See client.Exchange for more information on setting larger buffer sizes.
|
// See client.Exchange for more information on setting larger buffer sizes.
|
||||||
func Exchange(m *Msg, a string) (r *Msg, err error) {
|
func Exchange(m *Msg, a string) (r *Msg, err error) {
|
||||||
|
@ -70,6 +71,43 @@ func Exchange(m *Msg, a string) (r *Msg, err error) {
|
||||||
return r, err
|
return r, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ExchangeContext performs a synchronous UDP query, like Exchange. It
|
||||||
|
// additionally obeys deadlines from the passed Context.
|
||||||
|
func ExchangeContext(ctx context.Context, m *Msg, a string) (r *Msg, err error) {
|
||||||
|
// Combine context deadline with built-in timeout. Context chooses whichever
|
||||||
|
// is sooner.
|
||||||
|
timeoutCtx, cancel := context.WithTimeout(ctx, dnsTimeout)
|
||||||
|
defer cancel()
|
||||||
|
deadline, _ := timeoutCtx.Deadline()
|
||||||
|
|
||||||
|
co := new(Conn)
|
||||||
|
dialer := net.Dialer{}
|
||||||
|
co.Conn, err = dialer.DialContext(timeoutCtx, "udp", a)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer co.Conn.Close()
|
||||||
|
|
||||||
|
opt := m.IsEdns0()
|
||||||
|
// If EDNS0 is used use that for size.
|
||||||
|
if opt != nil && opt.UDPSize() >= MinMsgSize {
|
||||||
|
co.UDPSize = opt.UDPSize()
|
||||||
|
}
|
||||||
|
|
||||||
|
co.SetWriteDeadline(deadline)
|
||||||
|
if err = co.WriteMsg(m); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
co.SetReadDeadline(deadline)
|
||||||
|
r, err = co.ReadMsg()
|
||||||
|
if err == nil && r.Id != m.Id {
|
||||||
|
err = ErrId
|
||||||
|
}
|
||||||
|
return r, err
|
||||||
|
}
|
||||||
|
|
||||||
// ExchangeConn performs a synchronous query. It sends the message m via the connection
|
// ExchangeConn performs a synchronous query. It sends the message m via the connection
|
||||||
// c and waits for a reply. The connection c is not closed by ExchangeConn.
|
// c and waits for a reply. The connection c is not closed by ExchangeConn.
|
||||||
// This function is going away, but can easily be mimicked:
|
// This function is going away, but can easily be mimicked:
|
||||||
|
@ -93,8 +131,8 @@ func ExchangeConn(c net.Conn, m *Msg) (r *Msg, err error) {
|
||||||
return r, err
|
return r, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exchange performs an synchronous query. It sends the message m to the address
|
// Exchange performs a synchronous query. It sends the message m to the address
|
||||||
// contained in a and waits for an reply. Basic use pattern with a *dns.Client:
|
// contained in a and waits for a reply. Basic use pattern with a *dns.Client:
|
||||||
//
|
//
|
||||||
// c := new(dns.Client)
|
// c := new(dns.Client)
|
||||||
// in, rtt, err := c.Exchange(message, "127.0.0.1:53")
|
// in, rtt, err := c.Exchange(message, "127.0.0.1:53")
|
||||||
|
@ -103,11 +141,21 @@ func ExchangeConn(c net.Conn, m *Msg) (r *Msg, err error) {
|
||||||
// case of truncation.
|
// case of truncation.
|
||||||
// It is up to the caller to create a message that allows for larger responses to be
|
// It is up to the caller to create a message that allows for larger responses to be
|
||||||
// returned. Specifically this means adding an EDNS0 OPT RR that will advertise a larger
|
// returned. Specifically this means adding an EDNS0 OPT RR that will advertise a larger
|
||||||
// buffer, see SetEdns0. Messsages without an OPT RR will fallback to the historic limit
|
// buffer, see SetEdns0. Messages without an OPT RR will fallback to the historic limit
|
||||||
// of 512 bytes.
|
// of 512 bytes.
|
||||||
func (c *Client) Exchange(m *Msg, a string) (r *Msg, rtt time.Duration, err error) {
|
func (c *Client) Exchange(m *Msg, a string) (r *Msg, rtt time.Duration, err error) {
|
||||||
|
return c.ExchangeContext(context.Background(), m, a)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExchangeContext acts like Exchange, but honors the deadline on the provided
|
||||||
|
// context, if present. If there is both a context deadline and a configured
|
||||||
|
// timeout on the client, the earliest of the two takes effect.
|
||||||
|
func (c *Client) ExchangeContext(ctx context.Context, m *Msg, a string) (
|
||||||
|
r *Msg,
|
||||||
|
rtt time.Duration,
|
||||||
|
err error) {
|
||||||
if !c.SingleInflight {
|
if !c.SingleInflight {
|
||||||
return c.exchange(m, a)
|
return c.exchange(ctx, m, a)
|
||||||
}
|
}
|
||||||
// This adds a bunch of garbage, TODO(miek).
|
// This adds a bunch of garbage, TODO(miek).
|
||||||
t := "nop"
|
t := "nop"
|
||||||
|
@ -119,14 +167,14 @@ func (c *Client) Exchange(m *Msg, a string) (r *Msg, rtt time.Duration, err erro
|
||||||
cl = cl1
|
cl = cl1
|
||||||
}
|
}
|
||||||
r, rtt, err, shared := c.group.Do(m.Question[0].Name+t+cl, func() (*Msg, time.Duration, error) {
|
r, rtt, err, shared := c.group.Do(m.Question[0].Name+t+cl, func() (*Msg, time.Duration, error) {
|
||||||
return c.exchange(m, a)
|
return c.exchange(ctx, m, a)
|
||||||
})
|
})
|
||||||
|
if r != nil && shared {
|
||||||
|
r = r.Copy()
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return r, rtt, err
|
return r, rtt, err
|
||||||
}
|
}
|
||||||
if shared {
|
|
||||||
return r.Copy(), rtt, nil
|
|
||||||
}
|
|
||||||
return r, rtt, nil
|
return r, rtt, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -154,7 +202,7 @@ func (c *Client) writeTimeout() time.Duration {
|
||||||
return dnsTimeout
|
return dnsTimeout
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) exchange(m *Msg, a string) (r *Msg, rtt time.Duration, err error) {
|
func (c *Client) exchange(ctx context.Context, m *Msg, a string) (r *Msg, rtt time.Duration, err error) {
|
||||||
var co *Conn
|
var co *Conn
|
||||||
network := "udp"
|
network := "udp"
|
||||||
tls := false
|
tls := false
|
||||||
|
@ -180,10 +228,13 @@ func (c *Client) exchange(m *Msg, a string) (r *Msg, rtt time.Duration, err erro
|
||||||
deadline = time.Now().Add(c.Timeout)
|
deadline = time.Now().Add(c.Timeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dialDeadline := deadlineOrTimeoutOrCtx(ctx, deadline, c.dialTimeout())
|
||||||
|
dialTimeout := dialDeadline.Sub(time.Now())
|
||||||
|
|
||||||
if tls {
|
if tls {
|
||||||
co, err = DialTimeoutWithTLS(network, a, c.TLSConfig, c.dialTimeout())
|
co, err = DialTimeoutWithTLS(network, a, c.TLSConfig, dialTimeout)
|
||||||
} else {
|
} else {
|
||||||
co, err = DialTimeout(network, a, c.dialTimeout())
|
co, err = DialTimeout(network, a, dialTimeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -202,12 +253,12 @@ func (c *Client) exchange(m *Msg, a string) (r *Msg, rtt time.Duration, err erro
|
||||||
}
|
}
|
||||||
|
|
||||||
co.TsigSecret = c.TsigSecret
|
co.TsigSecret = c.TsigSecret
|
||||||
co.SetWriteDeadline(deadlineOrTimeout(deadline, c.writeTimeout()))
|
co.SetWriteDeadline(deadlineOrTimeoutOrCtx(ctx, deadline, c.writeTimeout()))
|
||||||
if err = co.WriteMsg(m); err != nil {
|
if err = co.WriteMsg(m); err != nil {
|
||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
co.SetReadDeadline(deadlineOrTimeout(deadline, c.readTimeout()))
|
co.SetReadDeadline(deadlineOrTimeoutOrCtx(ctx, deadline, c.readTimeout()))
|
||||||
r, err = co.ReadMsg()
|
r, err = co.ReadMsg()
|
||||||
if err == nil && r.Id != m.Id {
|
if err == nil && r.Id != m.Id {
|
||||||
err = ErrId
|
err = ErrId
|
||||||
|
@ -300,6 +351,18 @@ func tcpMsgLen(t io.Reader) (int, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// As seen with my local router/switch, retursn 1 byte on the above read,
|
||||||
|
// resulting a a ShortRead. Just write it out (instead of loop) and read the
|
||||||
|
// other byte.
|
||||||
|
if n == 1 {
|
||||||
|
n1, err := t.Read(p[1:])
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
n += n1
|
||||||
|
}
|
||||||
|
|
||||||
if n != 2 {
|
if n != 2 {
|
||||||
return 0, ErrShortRead
|
return 0, ErrShortRead
|
||||||
}
|
}
|
||||||
|
@ -400,7 +463,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.(*net.UDPConn).Write(p)
|
n, err = co.Conn.Write(p)
|
||||||
return n, err
|
return n, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -447,9 +510,22 @@ func DialTimeoutWithTLS(network, address string, tlsConfig *tls.Config, timeout
|
||||||
return conn, nil
|
return conn, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// deadlineOrTimeout chooses between the provided deadline and timeout
|
||||||
|
// by always preferring the deadline so long as it's non-zero (regardless
|
||||||
|
// of which is bigger), and returns the equivalent deadline value.
|
||||||
func deadlineOrTimeout(deadline time.Time, timeout time.Duration) time.Time {
|
func deadlineOrTimeout(deadline time.Time, timeout time.Duration) time.Time {
|
||||||
if deadline.IsZero() {
|
if deadline.IsZero() {
|
||||||
return time.Now().Add(timeout)
|
return time.Now().Add(timeout)
|
||||||
}
|
}
|
||||||
return deadline
|
return deadline
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// deadlineOrTimeoutOrCtx returns the earliest of: a context deadline, or the
|
||||||
|
// output of deadlineOrtimeout.
|
||||||
|
func deadlineOrTimeoutOrCtx(ctx context.Context, deadline time.Time, timeout time.Duration) time.Time {
|
||||||
|
result := deadlineOrTimeout(deadline, timeout)
|
||||||
|
if ctxDeadline, ok := ctx.Deadline(); ok && ctxDeadline.Before(result) {
|
||||||
|
result = ctxDeadline
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
|
@ -97,3 +97,35 @@ func ClientConfigFromFile(resolvconf string) (*ClientConfig, error) {
|
||||||
}
|
}
|
||||||
return c, nil
|
return c, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NameList returns all of the names that should be queried based on the
|
||||||
|
// config. It is based off of go's net/dns name building, but it does not
|
||||||
|
// check the length of the resulting names.
|
||||||
|
func (c *ClientConfig) NameList(name string) []string {
|
||||||
|
// if this domain is already fully qualified, no append needed.
|
||||||
|
if IsFqdn(name) {
|
||||||
|
return []string{name}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check to see if the name has more labels than Ndots. Do this before making
|
||||||
|
// the domain fully qualified.
|
||||||
|
hasNdots := CountLabel(name) > c.Ndots
|
||||||
|
// Make the domain fully qualified.
|
||||||
|
name = Fqdn(name)
|
||||||
|
|
||||||
|
// Make a list of names based off search.
|
||||||
|
names := []string{}
|
||||||
|
|
||||||
|
// If name has enough dots, try that first.
|
||||||
|
if hasNdots {
|
||||||
|
names = append(names, name)
|
||||||
|
}
|
||||||
|
for _, s := range c.Search {
|
||||||
|
names = append(names, Fqdn(name+s))
|
||||||
|
}
|
||||||
|
// If we didn't have enough dots, try after suffixes.
|
||||||
|
if !hasNdots {
|
||||||
|
names = append(names, name)
|
||||||
|
}
|
||||||
|
return names
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,184 @@
|
||||||
|
//+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 = `
|
||||||
|
// *** DO NOT MODIFY ***
|
||||||
|
// AUTOGENERATED BY go generate from compress_generate.go
|
||||||
|
|
||||||
|
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()
|
||||||
|
|
||||||
|
domainTypes := map[string]bool{} // Types that have a domain name in them (either comressible or not).
|
||||||
|
cdomainTypes := map[string]bool{} // Types that have a compressible domain name in them (subset of domainType)
|
||||||
|
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[o.Name()] = true
|
||||||
|
}
|
||||||
|
if st.Tag(i) == `dns:"cdomain-name"` {
|
||||||
|
cdomainTypes[o.Name()] = true
|
||||||
|
domainTypes[o.Name()] = true
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case st.Tag(i) == `dns:"domain-name"`:
|
||||||
|
domainTypes[o.Name()] = true
|
||||||
|
case st.Tag(i) == `dns:"cdomain-name"`:
|
||||||
|
cdomainTypes[o.Name()] = true
|
||||||
|
domainTypes[o.Name()] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
package dns
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/sha256"
|
||||||
|
"crypto/sha512"
|
||||||
|
"crypto/x509"
|
||||||
|
"encoding/hex"
|
||||||
|
"errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CertificateToDANE converts a certificate to a hex string as used in the TLSA or SMIMEA records.
|
||||||
|
func CertificateToDANE(selector, matchingType uint8, cert *x509.Certificate) (string, error) {
|
||||||
|
switch matchingType {
|
||||||
|
case 0:
|
||||||
|
switch selector {
|
||||||
|
case 0:
|
||||||
|
return hex.EncodeToString(cert.Raw), nil
|
||||||
|
case 1:
|
||||||
|
return hex.EncodeToString(cert.RawSubjectPublicKeyInfo), nil
|
||||||
|
}
|
||||||
|
case 1:
|
||||||
|
h := sha256.New()
|
||||||
|
switch selector {
|
||||||
|
case 0:
|
||||||
|
h.Write(cert.Raw)
|
||||||
|
return hex.EncodeToString(h.Sum(nil)), nil
|
||||||
|
case 1:
|
||||||
|
h.Write(cert.RawSubjectPublicKeyInfo)
|
||||||
|
return hex.EncodeToString(h.Sum(nil)), nil
|
||||||
|
}
|
||||||
|
case 2:
|
||||||
|
h := sha512.New()
|
||||||
|
switch selector {
|
||||||
|
case 0:
|
||||||
|
h.Write(cert.Raw)
|
||||||
|
return hex.EncodeToString(h.Sum(nil)), nil
|
||||||
|
case 1:
|
||||||
|
h.Write(cert.RawSubjectPublicKeyInfo)
|
||||||
|
return hex.EncodeToString(h.Sum(nil)), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "", errors.New("dns: bad MatchingType or Selector")
|
||||||
|
}
|
|
@ -13,9 +13,12 @@ const hexDigit = "0123456789abcdef"
|
||||||
// SetReply creates a reply message from a request message.
|
// SetReply creates a reply message from a request message.
|
||||||
func (dns *Msg) SetReply(request *Msg) *Msg {
|
func (dns *Msg) SetReply(request *Msg) *Msg {
|
||||||
dns.Id = request.Id
|
dns.Id = request.Id
|
||||||
dns.RecursionDesired = request.RecursionDesired // Copy rd bit
|
|
||||||
dns.Response = true
|
dns.Response = true
|
||||||
dns.Opcode = OpcodeQuery
|
dns.Opcode = request.Opcode
|
||||||
|
if dns.Opcode == OpcodeQuery {
|
||||||
|
dns.RecursionDesired = request.RecursionDesired // Copy rd bit
|
||||||
|
dns.CheckingDisabled = request.CheckingDisabled // Copy cd bit
|
||||||
|
}
|
||||||
dns.Rcode = RcodeSuccess
|
dns.Rcode = RcodeSuccess
|
||||||
if len(request.Question) > 0 {
|
if len(request.Question) > 0 {
|
||||||
dns.Question = make([]Question, 1)
|
dns.Question = make([]Question, 1)
|
||||||
|
@ -102,11 +105,11 @@ func (dns *Msg) SetAxfr(z string) *Msg {
|
||||||
// SetTsig appends a TSIG RR to the message.
|
// SetTsig appends a TSIG RR to the message.
|
||||||
// This is only a skeleton TSIG RR that is added as the last RR in the
|
// This is only a skeleton TSIG RR that is added as the last RR in the
|
||||||
// additional section. The Tsig is calculated when the message is being send.
|
// additional section. The Tsig is calculated when the message is being send.
|
||||||
func (dns *Msg) SetTsig(z, algo string, fudge, timesigned int64) *Msg {
|
func (dns *Msg) SetTsig(z, algo string, fudge uint16, timesigned int64) *Msg {
|
||||||
t := new(TSIG)
|
t := new(TSIG)
|
||||||
t.Hdr = RR_Header{z, TypeTSIG, ClassANY, 0, 0}
|
t.Hdr = RR_Header{z, TypeTSIG, ClassANY, 0, 0}
|
||||||
t.Algorithm = algo
|
t.Algorithm = algo
|
||||||
t.Fudge = 300
|
t.Fudge = fudge
|
||||||
t.TimeSigned = uint64(timesigned)
|
t.TimeSigned = uint64(timesigned)
|
||||||
t.OrigId = dns.Id
|
t.OrigId = dns.Id
|
||||||
dns.Extra = append(dns.Extra, t)
|
dns.Extra = append(dns.Extra, t)
|
||||||
|
|
|
@ -43,7 +43,7 @@ const (
|
||||||
PRIVATEOID uint8 = 254
|
PRIVATEOID uint8 = 254
|
||||||
)
|
)
|
||||||
|
|
||||||
// Map for algorithm names.
|
// AlgorithmToString is a map of algorithm IDs to algorithm names.
|
||||||
var AlgorithmToString = map[uint8]string{
|
var AlgorithmToString = map[uint8]string{
|
||||||
RSAMD5: "RSAMD5",
|
RSAMD5: "RSAMD5",
|
||||||
DH: "DH",
|
DH: "DH",
|
||||||
|
@ -61,10 +61,10 @@ var AlgorithmToString = map[uint8]string{
|
||||||
PRIVATEOID: "PRIVATEOID",
|
PRIVATEOID: "PRIVATEOID",
|
||||||
}
|
}
|
||||||
|
|
||||||
// Map of algorithm strings.
|
// StringToAlgorithm is the reverse of AlgorithmToString.
|
||||||
var StringToAlgorithm = reverseInt8(AlgorithmToString)
|
var StringToAlgorithm = reverseInt8(AlgorithmToString)
|
||||||
|
|
||||||
// Map of algorithm crypto hashes.
|
// 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
|
||||||
RSASHA1: crypto.SHA1,
|
RSASHA1: crypto.SHA1,
|
||||||
|
@ -85,7 +85,7 @@ const (
|
||||||
SHA512 // Experimental
|
SHA512 // Experimental
|
||||||
)
|
)
|
||||||
|
|
||||||
// Map for hash names.
|
// HashToString is a map of hash IDs to names.
|
||||||
var HashToString = map[uint8]string{
|
var HashToString = map[uint8]string{
|
||||||
SHA1: "SHA1",
|
SHA1: "SHA1",
|
||||||
SHA256: "SHA256",
|
SHA256: "SHA256",
|
||||||
|
@ -94,7 +94,7 @@ var HashToString = map[uint8]string{
|
||||||
SHA512: "SHA512",
|
SHA512: "SHA512",
|
||||||
}
|
}
|
||||||
|
|
||||||
// Map of hash strings.
|
// StringToHash is a map of names to hash IDs.
|
||||||
var StringToHash = reverseInt8(HashToString)
|
var StringToHash = reverseInt8(HashToString)
|
||||||
|
|
||||||
// DNSKEY flag values.
|
// DNSKEY flag values.
|
||||||
|
@ -208,9 +208,6 @@ func (k *DNSKEY) ToDS(h uint8) *DS {
|
||||||
// "|" denotes concatenation
|
// "|" denotes concatenation
|
||||||
// DNSKEY RDATA = Flags | Protocol | Algorithm | Public Key.
|
// DNSKEY RDATA = Flags | Protocol | Algorithm | Public Key.
|
||||||
|
|
||||||
// digest buffer
|
|
||||||
digest := append(owner, wire...) // another copy
|
|
||||||
|
|
||||||
var hash crypto.Hash
|
var hash crypto.Hash
|
||||||
switch h {
|
switch h {
|
||||||
case SHA1:
|
case SHA1:
|
||||||
|
@ -226,7 +223,8 @@ func (k *DNSKEY) ToDS(h uint8) *DS {
|
||||||
}
|
}
|
||||||
|
|
||||||
s := hash.New()
|
s := hash.New()
|
||||||
s.Write(digest)
|
s.Write(owner)
|
||||||
|
s.Write(wire)
|
||||||
ds.Digest = hex.EncodeToString(s.Sum(nil))
|
ds.Digest = hex.EncodeToString(s.Sum(nil))
|
||||||
return ds
|
return ds
|
||||||
}
|
}
|
||||||
|
@ -297,7 +295,6 @@ func (rr *RRSIG) Sign(k crypto.Signer, rrset []RR) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
signdata = append(signdata, wire...)
|
|
||||||
|
|
||||||
hash, ok := AlgorithmToHash[rr.Algorithm]
|
hash, ok := AlgorithmToHash[rr.Algorithm]
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -306,6 +303,7 @@ func (rr *RRSIG) Sign(k crypto.Signer, rrset []RR) error {
|
||||||
|
|
||||||
h := hash.New()
|
h := hash.New()
|
||||||
h.Write(signdata)
|
h.Write(signdata)
|
||||||
|
h.Write(wire)
|
||||||
|
|
||||||
signature, err := sign(k, h.Sum(nil), hash, rr.Algorithm)
|
signature, err := sign(k, h.Sum(nil), hash, rr.Algorithm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -415,7 +413,6 @@ func (rr *RRSIG) Verify(k *DNSKEY, rrset []RR) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
signeddata = append(signeddata, wire...)
|
|
||||||
|
|
||||||
sigbuf := rr.sigBuf() // Get the binary signature data
|
sigbuf := rr.sigBuf() // Get the binary signature data
|
||||||
if rr.Algorithm == PRIVATEDNS { // PRIVATEOID
|
if rr.Algorithm == PRIVATEDNS { // PRIVATEOID
|
||||||
|
@ -438,6 +435,7 @@ func (rr *RRSIG) Verify(k *DNSKEY, rrset []RR) error {
|
||||||
|
|
||||||
h := hash.New()
|
h := hash.New()
|
||||||
h.Write(signeddata)
|
h.Write(signeddata)
|
||||||
|
h.Write(wire)
|
||||||
return rsa.VerifyPKCS1v15(pubkey, hash, h.Sum(nil), sigbuf)
|
return rsa.VerifyPKCS1v15(pubkey, hash, h.Sum(nil), sigbuf)
|
||||||
|
|
||||||
case ECDSAP256SHA256, ECDSAP384SHA384:
|
case ECDSAP256SHA256, ECDSAP384SHA384:
|
||||||
|
@ -452,6 +450,7 @@ func (rr *RRSIG) Verify(k *DNSKEY, rrset []RR) error {
|
||||||
|
|
||||||
h := hash.New()
|
h := hash.New()
|
||||||
h.Write(signeddata)
|
h.Write(signeddata)
|
||||||
|
h.Write(wire)
|
||||||
if ecdsa.Verify(pubkey, h.Sum(nil), r, s) {
|
if ecdsa.Verify(pubkey, h.Sum(nil), r, s) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -516,7 +515,7 @@ func (k *DNSKEY) publicKeyRSA() *rsa.PublicKey {
|
||||||
}
|
}
|
||||||
// Remainder
|
// Remainder
|
||||||
expo += uint64(keybuf[keyoff])
|
expo += uint64(keybuf[keyoff])
|
||||||
if expo > 2<<31 {
|
if expo > (2<<31)+1 {
|
||||||
// Larger expo than supported.
|
// Larger expo than supported.
|
||||||
// println("dns: F5 primes (or larger) are not supported")
|
// println("dns: F5 primes (or larger) are not supported")
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -121,17 +121,17 @@ func (k *DNSKEY) setPublicKeyDSA(_Q, _P, _G, _Y *big.Int) bool {
|
||||||
// RFC 3110: Section 2. RSA Public KEY Resource Records
|
// RFC 3110: Section 2. RSA Public KEY Resource Records
|
||||||
func exponentToBuf(_E int) []byte {
|
func exponentToBuf(_E int) []byte {
|
||||||
var buf []byte
|
var buf []byte
|
||||||
i := big.NewInt(int64(_E))
|
i := big.NewInt(int64(_E)).Bytes()
|
||||||
if len(i.Bytes()) < 256 {
|
if len(i) < 256 {
|
||||||
buf = make([]byte, 1)
|
buf = make([]byte, 1, 1+len(i))
|
||||||
buf[0] = uint8(len(i.Bytes()))
|
buf[0] = uint8(len(i))
|
||||||
} else {
|
} else {
|
||||||
buf = make([]byte, 3)
|
buf = make([]byte, 3, 3+len(i))
|
||||||
buf[0] = 0
|
buf[0] = 0
|
||||||
buf[1] = uint8(len(i.Bytes()) >> 8)
|
buf[1] = uint8(len(i) >> 8)
|
||||||
buf[2] = uint8(len(i.Bytes()))
|
buf[2] = uint8(len(i))
|
||||||
}
|
}
|
||||||
buf = append(buf, i.Bytes()...)
|
buf = append(buf, i...)
|
||||||
return buf
|
return buf
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ import (
|
||||||
// NewPrivateKey returns a PrivateKey by parsing the string s.
|
// NewPrivateKey returns a PrivateKey by parsing the string s.
|
||||||
// s should be in the same form of the BIND private key files.
|
// s should be in the same form of the BIND private key files.
|
||||||
func (k *DNSKEY) NewPrivateKey(s string) (crypto.PrivateKey, error) {
|
func (k *DNSKEY) NewPrivateKey(s string) (crypto.PrivateKey, error) {
|
||||||
if s[len(s)-1] != '\n' { // We need a closing newline
|
if s == "" || s[len(s)-1] != '\n' { // We need a closing newline
|
||||||
return k.ReadPrivateKey(strings.NewReader(s+"\n"), "")
|
return k.ReadPrivateKey(strings.NewReader(s+"\n"), "")
|
||||||
}
|
}
|
||||||
return k.ReadPrivateKey(strings.NewReader(s), "")
|
return k.ReadPrivateKey(strings.NewReader(s), "")
|
||||||
|
@ -36,7 +36,7 @@ func (k *DNSKEY) ReadPrivateKey(q io.Reader, file string) (crypto.PrivateKey, er
|
||||||
return nil, ErrPrivKey
|
return nil, ErrPrivKey
|
||||||
}
|
}
|
||||||
// TODO(mg): check if the pubkey matches the private key
|
// TODO(mg): check if the pubkey matches the private key
|
||||||
algo, err := strconv.Atoi(strings.SplitN(m["algorithm"], " ", 2)[0])
|
algo, err := strconv.ParseUint(strings.SplitN(m["algorithm"], " ", 2)[0], 10, 8)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, ErrPrivKey
|
return nil, ErrPrivKey
|
||||||
}
|
}
|
||||||
|
|
|
@ -203,7 +203,7 @@ RFC 6895 sets aside a range of type codes for private use. This range
|
||||||
is 65,280 - 65,534 (0xFF00 - 0xFFFE). When experimenting with new Resource Records these
|
is 65,280 - 65,534 (0xFF00 - 0xFFFE). When experimenting with new Resource Records these
|
||||||
can be used, before requesting an official type code from IANA.
|
can be used, before requesting an official type code from IANA.
|
||||||
|
|
||||||
see http://miek.nl/posts/2014/Sep/21/Private%20RRs%20and%20IDN%20in%20Go%20DNS/ for more
|
see http://miek.nl/2014/September/21/idn-and-private-rr-in-go-dns/ for more
|
||||||
information.
|
information.
|
||||||
|
|
||||||
EDNS0
|
EDNS0
|
||||||
|
|
|
@ -4,25 +4,27 @@ import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"strconv"
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
// EDNS0 Option codes.
|
// EDNS0 Option codes.
|
||||||
const (
|
const (
|
||||||
EDNS0LLQ = 0x1 // long lived queries: http://tools.ietf.org/html/draft-sekar-dns-llq-01
|
EDNS0LLQ = 0x1 // long lived queries: http://tools.ietf.org/html/draft-sekar-dns-llq-01
|
||||||
EDNS0UL = 0x2 // update lease draft: http://files.dns-sd.org/draft-sekar-dns-ul.txt
|
EDNS0UL = 0x2 // update lease draft: http://files.dns-sd.org/draft-sekar-dns-ul.txt
|
||||||
EDNS0NSID = 0x3 // nsid (RFC5001)
|
EDNS0NSID = 0x3 // nsid (RFC5001)
|
||||||
EDNS0DAU = 0x5 // DNSSEC Algorithm Understood
|
EDNS0DAU = 0x5 // DNSSEC Algorithm Understood
|
||||||
EDNS0DHU = 0x6 // DS Hash Understood
|
EDNS0DHU = 0x6 // DS Hash Understood
|
||||||
EDNS0N3U = 0x7 // NSEC3 Hash Understood
|
EDNS0N3U = 0x7 // NSEC3 Hash Understood
|
||||||
EDNS0SUBNET = 0x8 // client-subnet (RFC6891)
|
EDNS0SUBNET = 0x8 // client-subnet (RFC6891)
|
||||||
EDNS0EXPIRE = 0x9 // EDNS0 expire
|
EDNS0EXPIRE = 0x9 // EDNS0 expire
|
||||||
EDNS0COOKIE = 0xa // EDNS0 Cookie
|
EDNS0COOKIE = 0xa // EDNS0 Cookie
|
||||||
EDNS0SUBNETDRAFT = 0x50fa // Don't use! Use EDNS0SUBNET
|
EDNS0TCPKEEPALIVE = 0xb // EDNS0 tcp keep alive (RFC7828)
|
||||||
EDNS0LOCALSTART = 0xFDE9 // Beginning of range reserved for local/experimental use (RFC6891)
|
EDNS0SUBNETDRAFT = 0x50fa // Don't use! Use EDNS0SUBNET
|
||||||
EDNS0LOCALEND = 0xFFFE // End of range reserved for local/experimental use (RFC6891)
|
EDNS0LOCALSTART = 0xFDE9 // Beginning of range reserved for local/experimental use (RFC6891)
|
||||||
_DO = 1 << 15 // dnssec ok
|
EDNS0LOCALEND = 0xFFFE // End of range reserved for local/experimental use (RFC6891)
|
||||||
|
_DO = 1 << 15 // dnssec ok
|
||||||
)
|
)
|
||||||
|
|
||||||
// OPT is the EDNS0 RR appended to messages to convey extra (meta) information.
|
// OPT is the EDNS0 RR appended to messages to convey extra (meta) information.
|
||||||
|
@ -128,8 +130,18 @@ func (rr *OPT) Do() bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetDo sets the DO (DNSSEC OK) bit.
|
// SetDo sets the DO (DNSSEC OK) bit.
|
||||||
func (rr *OPT) SetDo() {
|
// If we pass an argument, set the DO bit to that value.
|
||||||
rr.Hdr.Ttl |= _DO
|
// It is possible to pass 2 or more arguments. Any arguments after the 1st is silently ignored.
|
||||||
|
func (rr *OPT) SetDo(do ...bool) {
|
||||||
|
if len(do) == 1 {
|
||||||
|
if do[0] {
|
||||||
|
rr.Hdr.Ttl |= _DO
|
||||||
|
} else {
|
||||||
|
rr.Hdr.Ttl &^= _DO
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
rr.Hdr.Ttl |= _DO
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// EDNS0 defines an EDNS0 Option. An OPT RR can have multiple options appended to it.
|
// EDNS0 defines an EDNS0 Option. An OPT RR can have multiple options appended to it.
|
||||||
|
@ -145,7 +157,7 @@ type EDNS0 interface {
|
||||||
String() string
|
String() string
|
||||||
}
|
}
|
||||||
|
|
||||||
// The nsid EDNS0 option is used to retrieve a nameserver
|
// EDNS0_NSID option is used to retrieve a nameserver
|
||||||
// identifier. When sending a request Nsid must be set to the empty string
|
// identifier. When sending a request Nsid must be set to the empty string
|
||||||
// The identifier is an opaque string encoded as hex.
|
// The identifier is an opaque string encoded as hex.
|
||||||
// Basic use pattern for creating an nsid option:
|
// Basic use pattern for creating an nsid option:
|
||||||
|
@ -185,7 +197,7 @@ func (e *EDNS0_NSID) String() string { return string(e.Nsid) }
|
||||||
// e := new(dns.EDNS0_SUBNET)
|
// e := new(dns.EDNS0_SUBNET)
|
||||||
// e.Code = dns.EDNS0SUBNET
|
// e.Code = dns.EDNS0SUBNET
|
||||||
// e.Family = 1 // 1 for IPv4 source address, 2 for IPv6
|
// e.Family = 1 // 1 for IPv4 source address, 2 for IPv6
|
||||||
// e.NetMask = 32 // 32 for IPV4, 128 for IPv6
|
// e.SourceNetmask = 32 // 32 for IPV4, 128 for IPv6
|
||||||
// e.SourceScope = 0
|
// e.SourceScope = 0
|
||||||
// e.Address = net.ParseIP("127.0.0.1").To4() // for IPv4
|
// e.Address = net.ParseIP("127.0.0.1").To4() // for IPv4
|
||||||
// // e.Address = net.ParseIP("2001:7b8:32a::2") // for IPV6
|
// // e.Address = net.ParseIP("2001:7b8:32a::2") // for IPV6
|
||||||
|
@ -289,7 +301,7 @@ func (e *EDNS0_SUBNET) String() (s string) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// The Cookie EDNS0 option
|
// The EDNS0_COOKIE option is used to add a DNS Cookie to a message.
|
||||||
//
|
//
|
||||||
// o := new(dns.OPT)
|
// o := new(dns.OPT)
|
||||||
// o.Hdr.Name = "."
|
// o.Hdr.Name = "."
|
||||||
|
@ -530,3 +542,56 @@ func (e *EDNS0_LOCAL) unpack(b []byte) error {
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EDNS0_TCP_KEEPALIVE is an EDNS0 option that instructs the server to keep
|
||||||
|
// the TCP connection alive. See RFC 7828.
|
||||||
|
type EDNS0_TCP_KEEPALIVE struct {
|
||||||
|
Code uint16 // Always EDNSTCPKEEPALIVE
|
||||||
|
Length uint16 // the value 0 if the TIMEOUT is omitted, the value 2 if it is present;
|
||||||
|
Timeout uint16 // an idle timeout value for the TCP connection, specified in units of 100 milliseconds, encoded in network byte order.
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *EDNS0_TCP_KEEPALIVE) Option() uint16 { return EDNS0TCPKEEPALIVE }
|
||||||
|
|
||||||
|
func (e *EDNS0_TCP_KEEPALIVE) pack() ([]byte, error) {
|
||||||
|
if e.Timeout != 0 && e.Length != 2 {
|
||||||
|
return nil, errors.New("dns: timeout specified but length is not 2")
|
||||||
|
}
|
||||||
|
if e.Timeout == 0 && e.Length != 0 {
|
||||||
|
return nil, errors.New("dns: timeout not specified but length is not 0")
|
||||||
|
}
|
||||||
|
b := make([]byte, 4+e.Length)
|
||||||
|
binary.BigEndian.PutUint16(b[0:], e.Code)
|
||||||
|
binary.BigEndian.PutUint16(b[2:], e.Length)
|
||||||
|
if e.Length == 2 {
|
||||||
|
binary.BigEndian.PutUint16(b[4:], e.Timeout)
|
||||||
|
}
|
||||||
|
return b, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *EDNS0_TCP_KEEPALIVE) unpack(b []byte) error {
|
||||||
|
if len(b) < 4 {
|
||||||
|
return ErrBuf
|
||||||
|
}
|
||||||
|
e.Length = binary.BigEndian.Uint16(b[2:4])
|
||||||
|
if e.Length != 0 && e.Length != 2 {
|
||||||
|
return errors.New("dns: length mismatch, want 0/2 but got " + strconv.FormatUint(uint64(e.Length), 10))
|
||||||
|
}
|
||||||
|
if e.Length == 2 {
|
||||||
|
if len(b) < 6 {
|
||||||
|
return ErrBuf
|
||||||
|
}
|
||||||
|
e.Timeout = binary.BigEndian.Uint16(b[4:6])
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *EDNS0_TCP_KEEPALIVE) String() (s string) {
|
||||||
|
s = "use tcp keep-alive"
|
||||||
|
if e.Length == 0 {
|
||||||
|
s += ", timeout omitted"
|
||||||
|
} else {
|
||||||
|
s += fmt.Sprintf(", timeout %dms", e.Timeout*100)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package dns
|
package dns
|
||||||
|
|
||||||
|
import "strings"
|
||||||
|
|
||||||
// Holds a bunch of helper functions for dealing with labels.
|
// Holds a bunch of helper functions for dealing with labels.
|
||||||
|
|
||||||
// SplitDomainName splits a name string into it's labels.
|
// SplitDomainName splits a name string into it's labels.
|
||||||
|
@ -50,6 +52,7 @@ func SplitDomainName(s string) (labels []string) {
|
||||||
//
|
//
|
||||||
// s1 and s2 must be syntactically valid domain names.
|
// s1 and s2 must be syntactically valid domain names.
|
||||||
func CompareDomainName(s1, s2 string) (n int) {
|
func CompareDomainName(s1, s2 string) (n int) {
|
||||||
|
s1, s2 = strings.ToLower(s1), strings.ToLower(s2)
|
||||||
s1 = Fqdn(s1)
|
s1 = Fqdn(s1)
|
||||||
s2 = Fqdn(s2)
|
s2 = Fqdn(s2)
|
||||||
l1 := Split(s1)
|
l1 := Split(s1)
|
||||||
|
|
|
@ -9,42 +9,35 @@
|
||||||
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"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
const (
|
||||||
// Initialize default math/rand source using crypto/rand to provide better
|
maxCompressionOffset = 2 << 13 // We have 14 bits for the compression pointer
|
||||||
// security without the performance trade-off.
|
maxDomainNameWireOctets = 255 // See RFC 1035 section 2.3.4
|
||||||
buf := make([]byte, 8)
|
)
|
||||||
_, err := crand.Read(buf)
|
|
||||||
if err != nil {
|
|
||||||
// Failed to read from cryptographic source, fallback to default initial
|
|
||||||
// seed (1) by returning early
|
|
||||||
return
|
|
||||||
}
|
|
||||||
seed := binary.BigEndian.Uint64(buf)
|
|
||||||
rand.Seed(int64(seed))
|
|
||||||
}
|
|
||||||
|
|
||||||
const maxCompressionOffset = 2 << 13 // We have 14 bits for the compression pointer
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ErrAlg error = &Error{err: "bad algorithm"} // ErrAlg indicates an error with the (DNSSEC) algorithm.
|
ErrAlg error = &Error{err: "bad algorithm"} // ErrAlg indicates an error with the (DNSSEC) algorithm.
|
||||||
ErrAuth error = &Error{err: "bad authentication"} // ErrAuth indicates an error in the TSIG authentication.
|
ErrAuth error = &Error{err: "bad authentication"} // ErrAuth indicates an error in the TSIG authentication.
|
||||||
ErrBuf error = &Error{err: "buffer size too small"} // ErrBuf indicates that the buffer used it too small for the message.
|
ErrBuf error = &Error{err: "buffer size too small"} // ErrBuf indicates that the buffer used is too small for the message.
|
||||||
ErrConnEmpty error = &Error{err: "conn has no connection"} // ErrConnEmpty indicates a connection is being uses before it is initialized.
|
ErrConnEmpty error = &Error{err: "conn has no connection"} // ErrConnEmpty indicates a connection is being used before it is initialized.
|
||||||
ErrExtendedRcode error = &Error{err: "bad extended rcode"} // ErrExtendedRcode ...
|
ErrExtendedRcode error = &Error{err: "bad extended rcode"} // ErrExtendedRcode ...
|
||||||
ErrFqdn error = &Error{err: "domain must be fully qualified"} // ErrFqdn indicates that a domain name does not have a closing dot.
|
ErrFqdn error = &Error{err: "domain must be fully qualified"} // ErrFqdn indicates that a domain name does not have a closing dot.
|
||||||
ErrId error = &Error{err: "id mismatch"} // ErrId indicates there is a mismatch with the message's ID.
|
ErrId error = &Error{err: "id mismatch"} // ErrId indicates there is a mismatch with the message's ID.
|
||||||
ErrKeyAlg error = &Error{err: "bad key algorithm"} // ErrKeyAlg indicates that the algorithm in the key is not valid.
|
ErrKeyAlg error = &Error{err: "bad key algorithm"} // ErrKeyAlg indicates that the algorithm in the key is not valid.
|
||||||
ErrKey error = &Error{err: "bad key"}
|
ErrKey error = &Error{err: "bad key"}
|
||||||
ErrKeySize error = &Error{err: "bad key size"}
|
ErrKeySize error = &Error{err: "bad key size"}
|
||||||
|
ErrLongDomain error = &Error{err: fmt.Sprintf("domain name exceeded %d wire-format octets", maxDomainNameWireOctets)}
|
||||||
ErrNoSig error = &Error{err: "no signature found"}
|
ErrNoSig error = &Error{err: "no signature found"}
|
||||||
ErrPrivKey error = &Error{err: "bad private key"}
|
ErrPrivKey error = &Error{err: "bad private key"}
|
||||||
ErrRcode error = &Error{err: "bad rcode"}
|
ErrRcode error = &Error{err: "bad rcode"}
|
||||||
|
@ -58,7 +51,7 @@ var (
|
||||||
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.
|
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
|
||||||
// message id. The random provided should be good enough. This being a
|
// message id. The random provided should be good enough. This being a
|
||||||
// variable the function can be reassigned to a custom function.
|
// variable the function can be reassigned to a custom function.
|
||||||
// For instance, to make it return a static value:
|
// For instance, to make it return a static value:
|
||||||
|
@ -66,11 +59,45 @@ var (
|
||||||
// dns.Id = func() uint16 { return 3 }
|
// dns.Id = func() uint16 { return 3 }
|
||||||
var Id func() uint16 = id
|
var Id func() uint16 = id
|
||||||
|
|
||||||
|
var (
|
||||||
|
idLock sync.Mutex
|
||||||
|
idRand *rand.Rand
|
||||||
|
)
|
||||||
|
|
||||||
// id returns a 16 bits random number to be used as a
|
// id returns a 16 bits random number to be used as a
|
||||||
// message id. The random provided should be good enough.
|
// message id. The random provided should be good enough.
|
||||||
func id() uint16 {
|
func id() uint16 {
|
||||||
id32 := rand.Uint32()
|
idLock.Lock()
|
||||||
return uint16(id32)
|
|
||||||
|
if idRand == nil {
|
||||||
|
// This (partially) works around
|
||||||
|
// https://github.com/golang/go/issues/11833 by only
|
||||||
|
// seeding idRand upon the first call to id.
|
||||||
|
|
||||||
|
var seed int64
|
||||||
|
var buf [8]byte
|
||||||
|
|
||||||
|
if _, err := crand.Read(buf[:]); err == nil {
|
||||||
|
seed = int64(binary.LittleEndian.Uint64(buf[:]))
|
||||||
|
} else {
|
||||||
|
seed = rand.Int63()
|
||||||
|
}
|
||||||
|
|
||||||
|
idRand = rand.New(rand.NewSource(seed))
|
||||||
|
}
|
||||||
|
|
||||||
|
// The call to idRand.Uint32 must be within the
|
||||||
|
// mutex lock because *rand.Rand is not safe for
|
||||||
|
// concurrent use.
|
||||||
|
//
|
||||||
|
// There is no added performance overhead to calling
|
||||||
|
// idRand.Uint32 inside a mutex lock over just
|
||||||
|
// calling rand.Uint32 as the global math/rand rng
|
||||||
|
// is internally protected by a sync.Mutex.
|
||||||
|
id := uint16(idRand.Uint32())
|
||||||
|
|
||||||
|
idLock.Unlock()
|
||||||
|
return id
|
||||||
}
|
}
|
||||||
|
|
||||||
// MsgHdr is a a manually-unpacked version of (id, bits).
|
// MsgHdr is a a manually-unpacked version of (id, bits).
|
||||||
|
@ -203,12 +230,6 @@ func packDomainName(s string, msg []byte, off int, compression map[string]int, c
|
||||||
bs[j] = bs[j+2]
|
bs[j] = bs[j+2]
|
||||||
}
|
}
|
||||||
ls -= 2
|
ls -= 2
|
||||||
} else if bs[i] == 't' {
|
|
||||||
bs[i] = '\t'
|
|
||||||
} else if bs[i] == 'r' {
|
|
||||||
bs[i] = '\r'
|
|
||||||
} else if bs[i] == 'n' {
|
|
||||||
bs[i] = '\n'
|
|
||||||
}
|
}
|
||||||
escapedDot = bs[i] == '.'
|
escapedDot = bs[i] == '.'
|
||||||
bsFresh = false
|
bsFresh = false
|
||||||
|
@ -247,7 +268,9 @@ func packDomainName(s string, msg []byte, off int, compression map[string]int, c
|
||||||
bsFresh = true
|
bsFresh = true
|
||||||
}
|
}
|
||||||
// Don't try to compress '.'
|
// Don't try to compress '.'
|
||||||
if compress && roBs[begin:] != "." {
|
// We should only compress when compress it true, but we should also still pick
|
||||||
|
// up names that can be used for *future* compression(s).
|
||||||
|
if compression != nil && roBs[begin:] != "." {
|
||||||
if p, ok := compression[roBs[begin:]]; !ok {
|
if p, ok := compression[roBs[begin:]]; !ok {
|
||||||
// Only offsets smaller than this can be used.
|
// Only offsets smaller than this can be used.
|
||||||
if offset < maxCompressionOffset {
|
if offset < maxCompressionOffset {
|
||||||
|
@ -311,6 +334,7 @@ func UnpackDomainName(msg []byte, off int) (string, int, error) {
|
||||||
s := make([]byte, 0, 64)
|
s := make([]byte, 0, 64)
|
||||||
off1 := 0
|
off1 := 0
|
||||||
lenmsg := len(msg)
|
lenmsg := len(msg)
|
||||||
|
maxLen := maxDomainNameWireOctets
|
||||||
ptr := 0 // number of pointers followed
|
ptr := 0 // number of pointers followed
|
||||||
Loop:
|
Loop:
|
||||||
for {
|
for {
|
||||||
|
@ -335,12 +359,10 @@ Loop:
|
||||||
fallthrough
|
fallthrough
|
||||||
case '"', '\\':
|
case '"', '\\':
|
||||||
s = append(s, '\\', b)
|
s = append(s, '\\', b)
|
||||||
case '\t':
|
// presentation-format \X escapes add an extra byte
|
||||||
s = append(s, '\\', 't')
|
maxLen += 1
|
||||||
case '\r':
|
|
||||||
s = append(s, '\\', 'r')
|
|
||||||
default:
|
default:
|
||||||
if b < 32 || b >= 127 { // unprintable use \DDD
|
if b < 32 || b >= 127 { // unprintable, use \DDD
|
||||||
var buf [3]byte
|
var buf [3]byte
|
||||||
bufs := strconv.AppendInt(buf[:0], int64(b), 10)
|
bufs := strconv.AppendInt(buf[:0], int64(b), 10)
|
||||||
s = append(s, '\\')
|
s = append(s, '\\')
|
||||||
|
@ -350,6 +372,8 @@ Loop:
|
||||||
for _, r := range bufs {
|
for _, r := range bufs {
|
||||||
s = append(s, r)
|
s = append(s, r)
|
||||||
}
|
}
|
||||||
|
// presentation-format \DDD escapes add 3 extra bytes
|
||||||
|
maxLen += 3
|
||||||
} else {
|
} else {
|
||||||
s = append(s, b)
|
s = append(s, b)
|
||||||
}
|
}
|
||||||
|
@ -374,6 +398,9 @@ Loop:
|
||||||
if ptr++; ptr > 10 {
|
if ptr++; ptr > 10 {
|
||||||
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
|
||||||
|
// but the condition on previous three lines guarantees that it's
|
||||||
|
// at least loop-free
|
||||||
off = (c^0xC0)<<8 | int(c1)
|
off = (c^0xC0)<<8 | int(c1)
|
||||||
default:
|
default:
|
||||||
// 0x80 and 0x40 are reserved
|
// 0x80 and 0x40 are reserved
|
||||||
|
@ -385,6 +412,9 @@ Loop:
|
||||||
}
|
}
|
||||||
if len(s) == 0 {
|
if len(s) == 0 {
|
||||||
s = []byte(".")
|
s = []byte(".")
|
||||||
|
} 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
|
||||||
}
|
}
|
||||||
|
@ -431,12 +461,6 @@ func packTxtString(s string, msg []byte, offset int, tmp []byte) (int, error) {
|
||||||
if i+2 < len(bs) && isDigit(bs[i]) && isDigit(bs[i+1]) && isDigit(bs[i+2]) {
|
if i+2 < len(bs) && isDigit(bs[i]) && isDigit(bs[i+1]) && isDigit(bs[i+2]) {
|
||||||
msg[offset] = dddToByte(bs[i:])
|
msg[offset] = dddToByte(bs[i:])
|
||||||
i += 2
|
i += 2
|
||||||
} else if bs[i] == 't' {
|
|
||||||
msg[offset] = '\t'
|
|
||||||
} else if bs[i] == 'r' {
|
|
||||||
msg[offset] = '\r'
|
|
||||||
} else if bs[i] == 'n' {
|
|
||||||
msg[offset] = '\n'
|
|
||||||
} else {
|
} else {
|
||||||
msg[offset] = bs[i]
|
msg[offset] = bs[i]
|
||||||
}
|
}
|
||||||
|
@ -508,12 +532,6 @@ func unpackTxtString(msg []byte, offset int) (string, int, error) {
|
||||||
switch b {
|
switch b {
|
||||||
case '"', '\\':
|
case '"', '\\':
|
||||||
s = append(s, '\\', b)
|
s = append(s, '\\', b)
|
||||||
case '\t':
|
|
||||||
s = append(s, `\t`...)
|
|
||||||
case '\r':
|
|
||||||
s = append(s, `\r`...)
|
|
||||||
case '\n':
|
|
||||||
s = append(s, `\n`...)
|
|
||||||
default:
|
default:
|
||||||
if b < 32 || b > 127 { // unprintable
|
if b < 32 || b > 127 { // unprintable
|
||||||
var buf [3]byte
|
var buf [3]byte
|
||||||
|
@ -732,12 +750,10 @@ func (dns *Msg) PackBuffer(buf []byte) (msg []byte, err error) {
|
||||||
|
|
||||||
// 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
|
||||||
compress := dns.Compress
|
uncompressedLen := compressedLen(dns, false)
|
||||||
dns.Compress = false
|
if packLen := uncompressedLen + 1; len(msg) < packLen {
|
||||||
if packLen := dns.Len() + 1; len(msg) < packLen {
|
|
||||||
msg = make([]byte, packLen)
|
msg = make([]byte, packLen)
|
||||||
}
|
}
|
||||||
dns.Compress = compress
|
|
||||||
|
|
||||||
// Pack it in: header and then the pieces.
|
// Pack it in: header and then the pieces.
|
||||||
off := 0
|
off := 0
|
||||||
|
@ -781,9 +797,6 @@ func (dns *Msg) Unpack(msg []byte) (err error) {
|
||||||
if dh, off, err = unpackMsgHdr(msg, off); err != nil {
|
if dh, off, err = unpackMsgHdr(msg, off); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if off == len(msg) {
|
|
||||||
return ErrTruncated
|
|
||||||
}
|
|
||||||
|
|
||||||
dns.Id = dh.Id
|
dns.Id = dh.Id
|
||||||
dns.Response = (dh.Bits & _QR) != 0
|
dns.Response = (dh.Bits & _QR) != 0
|
||||||
|
@ -797,6 +810,10 @@ func (dns *Msg) Unpack(msg []byte) (err error) {
|
||||||
dns.CheckingDisabled = (dh.Bits & _CD) != 0
|
dns.CheckingDisabled = (dh.Bits & _CD) != 0
|
||||||
dns.Rcode = int(dh.Bits & 0xF)
|
dns.Rcode = int(dh.Bits & 0xF)
|
||||||
|
|
||||||
|
if off == len(msg) {
|
||||||
|
return ErrTruncated
|
||||||
|
}
|
||||||
|
|
||||||
// Optimistically use the count given to us in the header
|
// Optimistically use the count given to us in the header
|
||||||
dns.Question = make([]Question, 0, int(dh.Qdcount))
|
dns.Question = make([]Question, 0, int(dh.Qdcount))
|
||||||
|
|
||||||
|
@ -889,16 +906,18 @@ func (dns *Msg) String() string {
|
||||||
// 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 {
|
func (dns *Msg) Len() int { return compressedLen(dns, dns.Compress) }
|
||||||
|
|
||||||
|
// compressedLen returns the message length when in compressed wire format
|
||||||
|
// when compress is true, otherwise the uncompressed length is returned.
|
||||||
|
func compressedLen(dns *Msg, compress bool) int {
|
||||||
// We always return one more than needed.
|
// We always return one more than needed.
|
||||||
l := 12 // Message header is always 12 bytes
|
l := 12 // Message header is always 12 bytes
|
||||||
var compression map[string]int
|
compression := map[string]int{}
|
||||||
if dns.Compress {
|
|
||||||
compression = make(map[string]int)
|
|
||||||
}
|
|
||||||
for i := 0; i < len(dns.Question); i++ {
|
for i := 0; i < len(dns.Question); i++ {
|
||||||
l += dns.Question[i].len()
|
l += dns.Question[i].len()
|
||||||
if dns.Compress {
|
if compress {
|
||||||
compressionLenHelper(compression, dns.Question[i].Name)
|
compressionLenHelper(compression, dns.Question[i].Name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -907,7 +926,7 @@ func (dns *Msg) Len() int {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
l += dns.Answer[i].len()
|
l += dns.Answer[i].len()
|
||||||
if dns.Compress {
|
if compress {
|
||||||
k, ok := compressionLenSearch(compression, dns.Answer[i].Header().Name)
|
k, ok := compressionLenSearch(compression, dns.Answer[i].Header().Name)
|
||||||
if ok {
|
if ok {
|
||||||
l += 1 - k
|
l += 1 - k
|
||||||
|
@ -925,7 +944,7 @@ func (dns *Msg) Len() int {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
l += dns.Ns[i].len()
|
l += dns.Ns[i].len()
|
||||||
if dns.Compress {
|
if compress {
|
||||||
k, ok := compressionLenSearch(compression, dns.Ns[i].Header().Name)
|
k, ok := compressionLenSearch(compression, dns.Ns[i].Header().Name)
|
||||||
if ok {
|
if ok {
|
||||||
l += 1 - k
|
l += 1 - k
|
||||||
|
@ -943,7 +962,7 @@ func (dns *Msg) Len() int {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
l += dns.Extra[i].len()
|
l += dns.Extra[i].len()
|
||||||
if dns.Compress {
|
if compress {
|
||||||
k, ok := compressionLenSearch(compression, dns.Extra[i].Header().Name)
|
k, ok := compressionLenSearch(compression, dns.Extra[i].Header().Name)
|
||||||
if ok {
|
if ok {
|
||||||
l += 1 - k
|
l += 1 - k
|
||||||
|
@ -991,97 +1010,6 @@ func compressionLenSearch(c map[string]int, s string) (int, bool) {
|
||||||
return 0, false
|
return 0, false
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(miek): should add all types, because the all can be *used* for compression. Autogenerate from msg_generate and put in zmsg.go
|
|
||||||
func compressionLenHelperType(c map[string]int, r RR) {
|
|
||||||
switch x := r.(type) {
|
|
||||||
case *NS:
|
|
||||||
compressionLenHelper(c, x.Ns)
|
|
||||||
case *MX:
|
|
||||||
compressionLenHelper(c, x.Mx)
|
|
||||||
case *CNAME:
|
|
||||||
compressionLenHelper(c, x.Target)
|
|
||||||
case *PTR:
|
|
||||||
compressionLenHelper(c, x.Ptr)
|
|
||||||
case *SOA:
|
|
||||||
compressionLenHelper(c, x.Ns)
|
|
||||||
compressionLenHelper(c, x.Mbox)
|
|
||||||
case *MB:
|
|
||||||
compressionLenHelper(c, x.Mb)
|
|
||||||
case *MG:
|
|
||||||
compressionLenHelper(c, x.Mg)
|
|
||||||
case *MR:
|
|
||||||
compressionLenHelper(c, x.Mr)
|
|
||||||
case *MF:
|
|
||||||
compressionLenHelper(c, x.Mf)
|
|
||||||
case *MD:
|
|
||||||
compressionLenHelper(c, x.Md)
|
|
||||||
case *RT:
|
|
||||||
compressionLenHelper(c, x.Host)
|
|
||||||
case *RP:
|
|
||||||
compressionLenHelper(c, x.Mbox)
|
|
||||||
compressionLenHelper(c, x.Txt)
|
|
||||||
case *MINFO:
|
|
||||||
compressionLenHelper(c, x.Rmail)
|
|
||||||
compressionLenHelper(c, x.Email)
|
|
||||||
case *AFSDB:
|
|
||||||
compressionLenHelper(c, x.Hostname)
|
|
||||||
case *SRV:
|
|
||||||
compressionLenHelper(c, x.Target)
|
|
||||||
case *NAPTR:
|
|
||||||
compressionLenHelper(c, x.Replacement)
|
|
||||||
case *RRSIG:
|
|
||||||
compressionLenHelper(c, x.SignerName)
|
|
||||||
case *NSEC:
|
|
||||||
compressionLenHelper(c, x.NextDomain)
|
|
||||||
// HIP?
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only search on compressing these types.
|
|
||||||
func compressionLenSearchType(c map[string]int, r RR) (int, bool) {
|
|
||||||
switch x := r.(type) {
|
|
||||||
case *NS:
|
|
||||||
return compressionLenSearch(c, x.Ns)
|
|
||||||
case *MX:
|
|
||||||
return compressionLenSearch(c, x.Mx)
|
|
||||||
case *CNAME:
|
|
||||||
return compressionLenSearch(c, x.Target)
|
|
||||||
case *DNAME:
|
|
||||||
return compressionLenSearch(c, x.Target)
|
|
||||||
case *PTR:
|
|
||||||
return compressionLenSearch(c, x.Ptr)
|
|
||||||
case *SOA:
|
|
||||||
k, ok := compressionLenSearch(c, x.Ns)
|
|
||||||
k1, ok1 := compressionLenSearch(c, x.Mbox)
|
|
||||||
if !ok && !ok1 {
|
|
||||||
return 0, false
|
|
||||||
}
|
|
||||||
return k + k1, true
|
|
||||||
case *MB:
|
|
||||||
return compressionLenSearch(c, x.Mb)
|
|
||||||
case *MG:
|
|
||||||
return compressionLenSearch(c, x.Mg)
|
|
||||||
case *MR:
|
|
||||||
return compressionLenSearch(c, x.Mr)
|
|
||||||
case *MF:
|
|
||||||
return compressionLenSearch(c, x.Mf)
|
|
||||||
case *MD:
|
|
||||||
return compressionLenSearch(c, x.Md)
|
|
||||||
case *RT:
|
|
||||||
return compressionLenSearch(c, x.Host)
|
|
||||||
case *MINFO:
|
|
||||||
k, ok := compressionLenSearch(c, x.Rmail)
|
|
||||||
k1, ok1 := compressionLenSearch(c, x.Email)
|
|
||||||
if !ok && !ok1 {
|
|
||||||
return 0, false
|
|
||||||
}
|
|
||||||
return k + k1, true
|
|
||||||
case *AFSDB:
|
|
||||||
return compressionLenSearch(c, x.Hostname)
|
|
||||||
}
|
|
||||||
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 { r1 := r.copy(); return r1 }
|
||||||
|
|
||||||
|
|
|
@ -117,9 +117,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"`:
|
||||||
fallthrough
|
|
||||||
case st.Tag(i) == `dns:"domain-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"`:
|
||||||
|
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"`:
|
||||||
|
@ -139,8 +139,17 @@ return off, err
|
||||||
case st.Tag(i) == `dns:"base64"`:
|
case st.Tag(i) == `dns:"base64"`:
|
||||||
o("off, err = packStringBase64(rr.%s, msg, off)\n")
|
o("off, err = packStringBase64(rr.%s, msg, off)\n")
|
||||||
|
|
||||||
case strings.HasPrefix(st.Tag(i), `dns:"size-hex:SaltLength`): // Hack to fix empty salt length for NSEC3
|
case strings.HasPrefix(st.Tag(i), `dns:"size-hex:SaltLength`):
|
||||||
o("if rr.%s == \"-\" { /* do nothing, empty salt */ }\n")
|
// directly write instead of using o() so we get the error check in the correct place
|
||||||
|
field := st.Field(i).Name()
|
||||||
|
fmt.Fprintf(b, `// Only pack salt if value is not "-", i.e. empty
|
||||||
|
if rr.%s != "-" {
|
||||||
|
off, err = packStringHex(rr.%s, msg, off)
|
||||||
|
if err != nil {
|
||||||
|
return off, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`, field, field)
|
||||||
continue
|
continue
|
||||||
case strings.HasPrefix(st.Tag(i), `dns:"size-hex`): // size-hex can be packed just like hex
|
case strings.HasPrefix(st.Tag(i), `dns:"size-hex`): // size-hex can be packed just like hex
|
||||||
fallthrough
|
fallthrough
|
||||||
|
|
|
@ -96,7 +96,7 @@ func unpackHeader(msg []byte, off int) (rr RR_Header, off1 int, truncmsg []byte,
|
||||||
return hdr, len(msg), msg, err
|
return hdr, len(msg), msg, err
|
||||||
}
|
}
|
||||||
msg, err = truncateMsgFromRdlength(msg, off, hdr.Rdlength)
|
msg, err = truncateMsgFromRdlength(msg, off, hdr.Rdlength)
|
||||||
return hdr, off, msg, nil
|
return hdr, off, msg, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// pack packs an RR header, returning the offset to the end of the header.
|
// pack packs an RR header, returning the offset to the end of the header.
|
||||||
|
@ -142,6 +142,11 @@ func truncateMsgFromRdlength(msg []byte, off int, rdlength uint16) (truncmsg []b
|
||||||
}
|
}
|
||||||
|
|
||||||
func fromBase32(s []byte) (buf []byte, err error) {
|
func fromBase32(s []byte) (buf []byte, err error) {
|
||||||
|
for i, b := range s {
|
||||||
|
if b >= 'a' && b <= 'z' {
|
||||||
|
s[i] = b - 32
|
||||||
|
}
|
||||||
|
}
|
||||||
buflen := base32.HexEncoding.DecodedLen(len(s))
|
buflen := base32.HexEncoding.DecodedLen(len(s))
|
||||||
buf = make([]byte, buflen)
|
buf = make([]byte, buflen)
|
||||||
n, err := base32.HexEncoding.Decode(buf, s)
|
n, err := base32.HexEncoding.Decode(buf, s)
|
||||||
|
@ -263,8 +268,6 @@ func unpackString(msg []byte, off int) (string, int, error) {
|
||||||
switch b {
|
switch b {
|
||||||
case '"', '\\':
|
case '"', '\\':
|
||||||
s = append(s, '\\', b)
|
s = append(s, '\\', b)
|
||||||
case '\t', '\r', '\n':
|
|
||||||
s = append(s, b)
|
|
||||||
default:
|
default:
|
||||||
if b < 32 || b > 127 { // unprintable
|
if b < 32 || b > 127 { // unprintable
|
||||||
var buf [3]byte
|
var buf [3]byte
|
||||||
|
|
|
@ -3,7 +3,6 @@ package dns
|
||||||
import (
|
import (
|
||||||
"crypto/sha1"
|
"crypto/sha1"
|
||||||
"hash"
|
"hash"
|
||||||
"io"
|
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -36,75 +35,63 @@ func HashName(label string, ha uint8, iter uint16, salt string) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// k = 0
|
// k = 0
|
||||||
name = append(name, wire...)
|
s.Write(name)
|
||||||
io.WriteString(s, string(name))
|
s.Write(wire)
|
||||||
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()
|
||||||
nsec3 = append(nsec3, wire...)
|
s.Write(nsec3)
|
||||||
io.WriteString(s, string(nsec3))
|
s.Write(wire)
|
||||||
nsec3 = s.Sum(nil)
|
nsec3 = s.Sum(nsec3[:0])
|
||||||
}
|
}
|
||||||
return toBase32(nsec3)
|
return toBase32(nsec3)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Denialer is an interface that should be implemented by types that are used to denial
|
// Cover returns true if a name is covered by the NSEC3 record
|
||||||
// answers in DNSSEC.
|
|
||||||
type Denialer interface {
|
|
||||||
// Cover will check if the (unhashed) name is being covered by this NSEC or NSEC3.
|
|
||||||
Cover(name string) bool
|
|
||||||
// Match will check if the ownername matches the (unhashed) name for this NSEC3 or NSEC3.
|
|
||||||
Match(name string) bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cover implements the Denialer interface.
|
|
||||||
func (rr *NSEC) Cover(name string) bool {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Match implements the Denialer interface.
|
|
||||||
func (rr *NSEC) Match(name string) bool {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cover implements the Denialer interface.
|
|
||||||
func (rr *NSEC3) Cover(name string) bool {
|
func (rr *NSEC3) Cover(name string) bool {
|
||||||
// FIXME(miek): check if the zones match
|
nameHash := HashName(name, rr.Hash, rr.Iterations, rr.Salt)
|
||||||
// FIXME(miek): check if we're not dealing with parent nsec3
|
owner := strings.ToUpper(rr.Hdr.Name)
|
||||||
hname := HashName(name, rr.Hash, rr.Iterations, rr.Salt)
|
labelIndices := Split(owner)
|
||||||
labels := Split(rr.Hdr.Name)
|
if len(labelIndices) < 2 {
|
||||||
if len(labels) < 2 {
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
hash := strings.ToUpper(rr.Hdr.Name[labels[0] : labels[1]-1]) // -1 to remove the dot
|
ownerHash := owner[:labelIndices[1]-1]
|
||||||
if hash == rr.NextDomain {
|
ownerZone := owner[labelIndices[1]:]
|
||||||
return false // empty interval
|
if !IsSubDomain(ownerZone, strings.ToUpper(name)) { // name is outside owner zone
|
||||||
}
|
|
||||||
if hash > rr.NextDomain { // last name, points to apex
|
|
||||||
// hname > hash
|
|
||||||
// hname > rr.NextDomain
|
|
||||||
// TODO(miek)
|
|
||||||
}
|
|
||||||
if hname <= hash {
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if hname >= rr.NextDomain {
|
|
||||||
|
nextHash := rr.NextDomain
|
||||||
|
if ownerHash == nextHash { // empty interval
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
if ownerHash > nextHash { // end of zone
|
||||||
|
if nameHash > ownerHash { // covered since there is nothing after ownerHash
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return nameHash < nextHash // if nameHash is before beginning of zone it is covered
|
||||||
|
}
|
||||||
|
if nameHash < ownerHash { // nameHash is before ownerHash, not covered
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return nameHash < nextHash // if nameHash is before nextHash is it covered (between ownerHash and nextHash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Match implements the Denialer interface.
|
// Match returns true if a name matches the NSEC3 record
|
||||||
func (rr *NSEC3) Match(name string) bool {
|
func (rr *NSEC3) Match(name string) bool {
|
||||||
// FIXME(miek): Check if we are in the same zone
|
nameHash := HashName(name, rr.Hash, rr.Iterations, rr.Salt)
|
||||||
hname := HashName(name, rr.Hash, rr.Iterations, rr.Salt)
|
owner := strings.ToUpper(rr.Hdr.Name)
|
||||||
labels := Split(rr.Hdr.Name)
|
labelIndices := Split(owner)
|
||||||
if len(labels) < 2 {
|
if len(labelIndices) < 2 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
hash := strings.ToUpper(rr.Hdr.Name[labels[0] : labels[1]-1]) // -1 to remove the .
|
ownerHash := owner[:labelIndices[1]-1]
|
||||||
if hash == hname {
|
ownerZone := owner[labelIndices[1]:]
|
||||||
|
if !IsSubDomain(ownerZone, strings.ToUpper(name)) { // name is outside owner zone
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if ownerHash == nameHash {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
|
|
@ -6,10 +6,10 @@ var StringToType = reverseInt16(TypeToString)
|
||||||
// StringToClass is the reverse of ClassToString, needed for string parsing.
|
// StringToClass is the reverse of ClassToString, needed for string parsing.
|
||||||
var StringToClass = reverseInt16(ClassToString)
|
var StringToClass = reverseInt16(ClassToString)
|
||||||
|
|
||||||
// Map of opcodes strings.
|
// StringToOpcode is a map of opcodes to strings.
|
||||||
var StringToOpcode = reverseInt(OpcodeToString)
|
var StringToOpcode = reverseInt(OpcodeToString)
|
||||||
|
|
||||||
// Map of rcodes strings.
|
// StringToRcode is a map of rcodes to strings.
|
||||||
var StringToRcode = reverseInt(RcodeToString)
|
var StringToRcode = reverseInt(RcodeToString)
|
||||||
|
|
||||||
// Reverse a map
|
// Reverse a map
|
||||||
|
|
|
@ -278,8 +278,7 @@ func parseZone(r io.Reader, origin, f string, t chan *Token, include int) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
neworigin := origin // There may be optionally a new origin set after the filename, if not use current one
|
neworigin := origin // There may be optionally a new origin set after the filename, if not use current one
|
||||||
l := <-c
|
switch l := <-c; l.value {
|
||||||
switch l.value {
|
|
||||||
case zBlank:
|
case zBlank:
|
||||||
l := <-c
|
l := <-c
|
||||||
if l.value == zString {
|
if l.value == zString {
|
||||||
|
@ -627,6 +626,7 @@ func zlexer(s *scan, c chan lex) {
|
||||||
if stri > 0 {
|
if stri > 0 {
|
||||||
l.value = zString
|
l.value = zString
|
||||||
l.token = string(str[:stri])
|
l.token = string(str[:stri])
|
||||||
|
l.tokenUpper = strings.ToUpper(l.token)
|
||||||
l.length = stri
|
l.length = stri
|
||||||
debug.Printf("[4 %+v]", l.token)
|
debug.Printf("[4 %+v]", l.token)
|
||||||
c <- l
|
c <- l
|
||||||
|
@ -663,6 +663,7 @@ func zlexer(s *scan, c chan lex) {
|
||||||
owner = true
|
owner = true
|
||||||
l.value = zNewline
|
l.value = zNewline
|
||||||
l.token = "\n"
|
l.token = "\n"
|
||||||
|
l.tokenUpper = l.token
|
||||||
l.length = 1
|
l.length = 1
|
||||||
l.comment = string(com[:comi])
|
l.comment = string(com[:comi])
|
||||||
debug.Printf("[3 %+v %+v]", l.token, l.comment)
|
debug.Printf("[3 %+v %+v]", l.token, l.comment)
|
||||||
|
@ -696,6 +697,7 @@ func zlexer(s *scan, c chan lex) {
|
||||||
}
|
}
|
||||||
l.value = zNewline
|
l.value = zNewline
|
||||||
l.token = "\n"
|
l.token = "\n"
|
||||||
|
l.tokenUpper = l.token
|
||||||
l.length = 1
|
l.length = 1
|
||||||
debug.Printf("[1 %+v]", l.token)
|
debug.Printf("[1 %+v]", l.token)
|
||||||
c <- l
|
c <- l
|
||||||
|
@ -740,6 +742,7 @@ func zlexer(s *scan, c chan lex) {
|
||||||
if stri != 0 {
|
if stri != 0 {
|
||||||
l.value = zString
|
l.value = zString
|
||||||
l.token = string(str[:stri])
|
l.token = string(str[:stri])
|
||||||
|
l.tokenUpper = strings.ToUpper(l.token)
|
||||||
l.length = stri
|
l.length = stri
|
||||||
|
|
||||||
debug.Printf("[%+v]", l.token)
|
debug.Printf("[%+v]", l.token)
|
||||||
|
@ -750,6 +753,7 @@ func zlexer(s *scan, c chan lex) {
|
||||||
// send quote itself as separate token
|
// send quote itself as separate token
|
||||||
l.value = zQuote
|
l.value = zQuote
|
||||||
l.token = "\""
|
l.token = "\""
|
||||||
|
l.tokenUpper = l.token
|
||||||
l.length = 1
|
l.length = 1
|
||||||
c <- l
|
c <- l
|
||||||
quote = !quote
|
quote = !quote
|
||||||
|
@ -775,6 +779,7 @@ func zlexer(s *scan, c chan lex) {
|
||||||
brace--
|
brace--
|
||||||
if brace < 0 {
|
if brace < 0 {
|
||||||
l.token = "extra closing brace"
|
l.token = "extra closing brace"
|
||||||
|
l.tokenUpper = l.token
|
||||||
l.err = true
|
l.err = true
|
||||||
debug.Printf("[%+v]", l.token)
|
debug.Printf("[%+v]", l.token)
|
||||||
c <- l
|
c <- l
|
||||||
|
@ -799,11 +804,18 @@ func zlexer(s *scan, c chan lex) {
|
||||||
if stri > 0 {
|
if stri > 0 {
|
||||||
// Send remainder
|
// Send remainder
|
||||||
l.token = string(str[:stri])
|
l.token = string(str[:stri])
|
||||||
|
l.tokenUpper = strings.ToUpper(l.token)
|
||||||
l.length = stri
|
l.length = stri
|
||||||
l.value = zString
|
l.value = zString
|
||||||
debug.Printf("[%+v]", l.token)
|
debug.Printf("[%+v]", l.token)
|
||||||
c <- l
|
c <- l
|
||||||
}
|
}
|
||||||
|
if brace != 0 {
|
||||||
|
l.token = "unbalanced brace"
|
||||||
|
l.tokenUpper = l.token
|
||||||
|
l.err = true
|
||||||
|
c <- l
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract the class number from CLASSxx
|
// Extract the class number from CLASSxx
|
||||||
|
@ -812,8 +824,8 @@ func classToInt(token string) (uint16, bool) {
|
||||||
if len(token) < offset+1 {
|
if len(token) < offset+1 {
|
||||||
return 0, false
|
return 0, false
|
||||||
}
|
}
|
||||||
class, ok := strconv.Atoi(token[offset:])
|
class, err := strconv.ParseUint(token[offset:], 10, 16)
|
||||||
if ok != nil || class > maxUint16 {
|
if err != nil {
|
||||||
return 0, false
|
return 0, false
|
||||||
}
|
}
|
||||||
return uint16(class), true
|
return uint16(class), true
|
||||||
|
@ -825,8 +837,8 @@ func typeToInt(token string) (uint16, bool) {
|
||||||
if len(token) < offset+1 {
|
if len(token) < offset+1 {
|
||||||
return 0, false
|
return 0, false
|
||||||
}
|
}
|
||||||
typ, ok := strconv.Atoi(token[offset:])
|
typ, err := strconv.ParseUint(token[offset:], 10, 16)
|
||||||
if ok != nil || typ > maxUint16 {
|
if err != nil {
|
||||||
return 0, false
|
return 0, false
|
||||||
}
|
}
|
||||||
return uint16(typ), true
|
return uint16(typ), true
|
||||||
|
|
|
@ -64,74 +64,63 @@ func endingToString(c chan lex, errstr, f string) (string, *ParseError, string)
|
||||||
return s, nil, l.comment
|
return s, nil, l.comment
|
||||||
}
|
}
|
||||||
|
|
||||||
// A remainder of the rdata with embedded spaces, return the parsed string slice (sans the spaces)
|
// A remainder of the rdata with embedded spaces, split on unquoted whitespace
|
||||||
// or an error
|
// and return the parsed string slice or an error
|
||||||
func endingToTxtSlice(c chan lex, errstr, f string) ([]string, *ParseError, string) {
|
func endingToTxtSlice(c chan lex, errstr, f string) ([]string, *ParseError, string) {
|
||||||
// Get the remaining data until we see a zNewline
|
// Get the remaining data until we see a zNewline
|
||||||
quote := false
|
|
||||||
l := <-c
|
l := <-c
|
||||||
var s []string
|
|
||||||
if l.err {
|
if l.err {
|
||||||
return s, &ParseError{f, errstr, l}, ""
|
return nil, &ParseError{f, errstr, l}, ""
|
||||||
}
|
}
|
||||||
switch l.value == zQuote {
|
|
||||||
case true: // A number of quoted string
|
|
||||||
s = make([]string, 0)
|
|
||||||
empty := true
|
|
||||||
for l.value != zNewline && l.value != zEOF {
|
|
||||||
if l.err {
|
|
||||||
return nil, &ParseError{f, errstr, l}, ""
|
|
||||||
}
|
|
||||||
switch l.value {
|
|
||||||
case zString:
|
|
||||||
empty = false
|
|
||||||
if len(l.token) > 255 {
|
|
||||||
// split up tokens that are larger than 255 into 255-chunks
|
|
||||||
sx := []string{}
|
|
||||||
p, i := 0, 255
|
|
||||||
for {
|
|
||||||
if i <= len(l.token) {
|
|
||||||
sx = append(sx, l.token[p:i])
|
|
||||||
} else {
|
|
||||||
sx = append(sx, l.token[p:])
|
|
||||||
break
|
|
||||||
|
|
||||||
}
|
// Build the slice
|
||||||
p, i = p+255, i+255
|
s := make([]string, 0)
|
||||||
}
|
quote := false
|
||||||
s = append(s, sx...)
|
empty := false
|
||||||
break
|
for l.value != zNewline && l.value != zEOF {
|
||||||
}
|
if l.err {
|
||||||
|
|
||||||
s = append(s, l.token)
|
|
||||||
case zBlank:
|
|
||||||
if quote {
|
|
||||||
// zBlank can only be seen in between txt parts.
|
|
||||||
return nil, &ParseError{f, errstr, l}, ""
|
|
||||||
}
|
|
||||||
case zQuote:
|
|
||||||
if empty && quote {
|
|
||||||
s = append(s, "")
|
|
||||||
}
|
|
||||||
quote = !quote
|
|
||||||
empty = true
|
|
||||||
default:
|
|
||||||
return nil, &ParseError{f, errstr, l}, ""
|
|
||||||
}
|
|
||||||
l = <-c
|
|
||||||
}
|
|
||||||
if quote {
|
|
||||||
return nil, &ParseError{f, errstr, l}, ""
|
return nil, &ParseError{f, errstr, l}, ""
|
||||||
}
|
}
|
||||||
case false: // Unquoted text record
|
switch l.value {
|
||||||
s = make([]string, 1)
|
case zString:
|
||||||
for l.value != zNewline && l.value != zEOF {
|
empty = false
|
||||||
if l.err {
|
if len(l.token) > 255 {
|
||||||
return s, &ParseError{f, errstr, l}, ""
|
// split up tokens that are larger than 255 into 255-chunks
|
||||||
|
sx := []string{}
|
||||||
|
p, i := 0, 255
|
||||||
|
for {
|
||||||
|
if i <= len(l.token) {
|
||||||
|
sx = append(sx, l.token[p:i])
|
||||||
|
} else {
|
||||||
|
sx = append(sx, l.token[p:])
|
||||||
|
break
|
||||||
|
|
||||||
|
}
|
||||||
|
p, i = p+255, i+255
|
||||||
|
}
|
||||||
|
s = append(s, sx...)
|
||||||
|
break
|
||||||
}
|
}
|
||||||
s[0] += l.token
|
|
||||||
l = <-c
|
s = append(s, l.token)
|
||||||
|
case zBlank:
|
||||||
|
if quote {
|
||||||
|
// zBlank can only be seen in between txt parts.
|
||||||
|
return nil, &ParseError{f, errstr, l}, ""
|
||||||
|
}
|
||||||
|
case zQuote:
|
||||||
|
if empty && quote {
|
||||||
|
s = append(s, "")
|
||||||
|
}
|
||||||
|
quote = !quote
|
||||||
|
empty = true
|
||||||
|
default:
|
||||||
|
return nil, &ParseError{f, errstr, l}, ""
|
||||||
}
|
}
|
||||||
|
l = <-c
|
||||||
|
}
|
||||||
|
if quote {
|
||||||
|
return nil, &ParseError{f, errstr, l}, ""
|
||||||
}
|
}
|
||||||
return s, nil, l.comment
|
return s, nil, l.comment
|
||||||
}
|
}
|
||||||
|
@ -458,7 +447,7 @@ func setMX(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
|
||||||
if l.length == 0 {
|
if l.length == 0 {
|
||||||
return rr, nil, ""
|
return rr, nil, ""
|
||||||
}
|
}
|
||||||
i, e := strconv.Atoi(l.token)
|
i, e := strconv.ParseUint(l.token, 10, 16)
|
||||||
if e != nil || l.err {
|
if e != nil || l.err {
|
||||||
return nil, &ParseError{f, "bad MX Pref", l}, ""
|
return nil, &ParseError{f, "bad MX Pref", l}, ""
|
||||||
}
|
}
|
||||||
|
@ -487,7 +476,7 @@ func setRT(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
|
||||||
if l.length == 0 {
|
if l.length == 0 {
|
||||||
return rr, nil, ""
|
return rr, nil, ""
|
||||||
}
|
}
|
||||||
i, e := strconv.Atoi(l.token)
|
i, e := strconv.ParseUint(l.token, 10, 16)
|
||||||
if e != nil {
|
if e != nil {
|
||||||
return nil, &ParseError{f, "bad RT Preference", l}, ""
|
return nil, &ParseError{f, "bad RT Preference", l}, ""
|
||||||
}
|
}
|
||||||
|
@ -517,7 +506,7 @@ func setAFSDB(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
|
||||||
if l.length == 0 {
|
if l.length == 0 {
|
||||||
return rr, nil, ""
|
return rr, nil, ""
|
||||||
}
|
}
|
||||||
i, e := strconv.Atoi(l.token)
|
i, e := strconv.ParseUint(l.token, 10, 16)
|
||||||
if e != nil || l.err {
|
if e != nil || l.err {
|
||||||
return nil, &ParseError{f, "bad AFSDB Subtype", l}, ""
|
return nil, &ParseError{f, "bad AFSDB Subtype", l}, ""
|
||||||
}
|
}
|
||||||
|
@ -562,7 +551,7 @@ func setKX(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
|
||||||
if l.length == 0 {
|
if l.length == 0 {
|
||||||
return rr, nil, ""
|
return rr, nil, ""
|
||||||
}
|
}
|
||||||
i, e := strconv.Atoi(l.token)
|
i, e := strconv.ParseUint(l.token, 10, 16)
|
||||||
if e != nil || l.err {
|
if e != nil || l.err {
|
||||||
return nil, &ParseError{f, "bad KX Pref", l}, ""
|
return nil, &ParseError{f, "bad KX Pref", l}, ""
|
||||||
}
|
}
|
||||||
|
@ -676,7 +665,7 @@ func setSOA(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
|
||||||
if l.err {
|
if l.err {
|
||||||
return nil, &ParseError{f, "bad SOA zone parameter", l}, ""
|
return nil, &ParseError{f, "bad SOA zone parameter", l}, ""
|
||||||
}
|
}
|
||||||
if j, e := strconv.Atoi(l.token); e != nil {
|
if j, e := strconv.ParseUint(l.token, 10, 32); e != nil {
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
// Serial should be a number
|
// Serial should be a number
|
||||||
return nil, &ParseError{f, "bad SOA zone parameter", l}, ""
|
return nil, &ParseError{f, "bad SOA zone parameter", l}, ""
|
||||||
|
@ -716,21 +705,21 @@ func setSRV(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
|
||||||
if l.length == 0 {
|
if l.length == 0 {
|
||||||
return rr, nil, ""
|
return rr, nil, ""
|
||||||
}
|
}
|
||||||
i, e := strconv.Atoi(l.token)
|
i, e := strconv.ParseUint(l.token, 10, 16)
|
||||||
if e != nil || l.err {
|
if e != nil || l.err {
|
||||||
return nil, &ParseError{f, "bad SRV Priority", l}, ""
|
return nil, &ParseError{f, "bad SRV Priority", l}, ""
|
||||||
}
|
}
|
||||||
rr.Priority = uint16(i)
|
rr.Priority = uint16(i)
|
||||||
<-c // zBlank
|
<-c // zBlank
|
||||||
l = <-c // zString
|
l = <-c // zString
|
||||||
i, e = strconv.Atoi(l.token)
|
i, e = strconv.ParseUint(l.token, 10, 16)
|
||||||
if e != nil || l.err {
|
if e != nil || l.err {
|
||||||
return nil, &ParseError{f, "bad SRV Weight", l}, ""
|
return nil, &ParseError{f, "bad SRV Weight", l}, ""
|
||||||
}
|
}
|
||||||
rr.Weight = uint16(i)
|
rr.Weight = uint16(i)
|
||||||
<-c // zBlank
|
<-c // zBlank
|
||||||
l = <-c // zString
|
l = <-c // zString
|
||||||
i, e = strconv.Atoi(l.token)
|
i, e = strconv.ParseUint(l.token, 10, 16)
|
||||||
if e != nil || l.err {
|
if e != nil || l.err {
|
||||||
return nil, &ParseError{f, "bad SRV Port", l}, ""
|
return nil, &ParseError{f, "bad SRV Port", l}, ""
|
||||||
}
|
}
|
||||||
|
@ -760,14 +749,14 @@ func setNAPTR(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
|
||||||
if l.length == 0 {
|
if l.length == 0 {
|
||||||
return rr, nil, ""
|
return rr, nil, ""
|
||||||
}
|
}
|
||||||
i, e := strconv.Atoi(l.token)
|
i, e := strconv.ParseUint(l.token, 10, 16)
|
||||||
if e != nil || l.err {
|
if e != nil || l.err {
|
||||||
return nil, &ParseError{f, "bad NAPTR Order", l}, ""
|
return nil, &ParseError{f, "bad NAPTR Order", l}, ""
|
||||||
}
|
}
|
||||||
rr.Order = uint16(i)
|
rr.Order = uint16(i)
|
||||||
<-c // zBlank
|
<-c // zBlank
|
||||||
l = <-c // zString
|
l = <-c // zString
|
||||||
i, e = strconv.Atoi(l.token)
|
i, e = strconv.ParseUint(l.token, 10, 16)
|
||||||
if e != nil || l.err {
|
if e != nil || l.err {
|
||||||
return nil, &ParseError{f, "bad NAPTR Preference", l}, ""
|
return nil, &ParseError{f, "bad NAPTR Preference", l}, ""
|
||||||
}
|
}
|
||||||
|
@ -896,7 +885,7 @@ func setLOC(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
|
||||||
if l.length == 0 {
|
if l.length == 0 {
|
||||||
return rr, nil, ""
|
return rr, nil, ""
|
||||||
}
|
}
|
||||||
i, e := strconv.Atoi(l.token)
|
i, e := strconv.ParseUint(l.token, 10, 32)
|
||||||
if e != nil || l.err {
|
if e != nil || l.err {
|
||||||
return nil, &ParseError{f, "bad LOC Latitude", l}, ""
|
return nil, &ParseError{f, "bad LOC Latitude", l}, ""
|
||||||
}
|
}
|
||||||
|
@ -908,7 +897,7 @@ func setLOC(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
|
||||||
if rr.Latitude, ok = locCheckNorth(l.token, rr.Latitude); ok {
|
if rr.Latitude, ok = locCheckNorth(l.token, rr.Latitude); ok {
|
||||||
goto East
|
goto East
|
||||||
}
|
}
|
||||||
i, e = strconv.Atoi(l.token)
|
i, e = strconv.ParseUint(l.token, 10, 32)
|
||||||
if e != nil || l.err {
|
if e != nil || l.err {
|
||||||
return nil, &ParseError{f, "bad LOC Latitude minutes", l}, ""
|
return nil, &ParseError{f, "bad LOC Latitude minutes", l}, ""
|
||||||
}
|
}
|
||||||
|
@ -934,7 +923,7 @@ East:
|
||||||
// East
|
// East
|
||||||
<-c // zBlank
|
<-c // zBlank
|
||||||
l = <-c
|
l = <-c
|
||||||
if i, e := strconv.Atoi(l.token); e != nil || l.err {
|
if i, e := strconv.ParseUint(l.token, 10, 32); e != nil || l.err {
|
||||||
return nil, &ParseError{f, "bad LOC Longitude", l}, ""
|
return nil, &ParseError{f, "bad LOC Longitude", l}, ""
|
||||||
} else {
|
} else {
|
||||||
rr.Longitude = 1000 * 60 * 60 * uint32(i)
|
rr.Longitude = 1000 * 60 * 60 * uint32(i)
|
||||||
|
@ -945,7 +934,7 @@ East:
|
||||||
if rr.Longitude, ok = locCheckEast(l.token, rr.Longitude); ok {
|
if rr.Longitude, ok = locCheckEast(l.token, rr.Longitude); ok {
|
||||||
goto Altitude
|
goto Altitude
|
||||||
}
|
}
|
||||||
if i, e := strconv.Atoi(l.token); e != nil || l.err {
|
if i, e := strconv.ParseUint(l.token, 10, 32); e != nil || l.err {
|
||||||
return nil, &ParseError{f, "bad LOC Longitude minutes", l}, ""
|
return nil, &ParseError{f, "bad LOC Longitude minutes", l}, ""
|
||||||
} else {
|
} else {
|
||||||
rr.Longitude += 1000 * 60 * uint32(i)
|
rr.Longitude += 1000 * 60 * uint32(i)
|
||||||
|
@ -1027,7 +1016,7 @@ func setHIP(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
|
||||||
if l.length == 0 {
|
if l.length == 0 {
|
||||||
return rr, nil, l.comment
|
return rr, nil, l.comment
|
||||||
}
|
}
|
||||||
i, e := strconv.Atoi(l.token)
|
i, e := strconv.ParseUint(l.token, 10, 8)
|
||||||
if e != nil || l.err {
|
if e != nil || l.err {
|
||||||
return nil, &ParseError{f, "bad HIP PublicKeyAlgorithm", l}, ""
|
return nil, &ParseError{f, "bad HIP PublicKeyAlgorithm", l}, ""
|
||||||
}
|
}
|
||||||
|
@ -1088,14 +1077,14 @@ func setCERT(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
|
||||||
}
|
}
|
||||||
if v, ok := StringToCertType[l.token]; ok {
|
if v, ok := StringToCertType[l.token]; ok {
|
||||||
rr.Type = v
|
rr.Type = v
|
||||||
} else if i, e := strconv.Atoi(l.token); e != nil {
|
} else if i, e := strconv.ParseUint(l.token, 10, 16); e != nil {
|
||||||
return nil, &ParseError{f, "bad CERT Type", l}, ""
|
return nil, &ParseError{f, "bad CERT Type", l}, ""
|
||||||
} else {
|
} else {
|
||||||
rr.Type = uint16(i)
|
rr.Type = uint16(i)
|
||||||
}
|
}
|
||||||
<-c // zBlank
|
<-c // zBlank
|
||||||
l = <-c // zString
|
l = <-c // zString
|
||||||
i, e := strconv.Atoi(l.token)
|
i, e := strconv.ParseUint(l.token, 10, 16)
|
||||||
if e != nil || l.err {
|
if e != nil || l.err {
|
||||||
return nil, &ParseError{f, "bad CERT KeyTag", l}, ""
|
return nil, &ParseError{f, "bad CERT KeyTag", l}, ""
|
||||||
}
|
}
|
||||||
|
@ -1104,7 +1093,7 @@ func setCERT(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
|
||||||
l = <-c // zString
|
l = <-c // zString
|
||||||
if v, ok := StringToAlgorithm[l.token]; ok {
|
if v, ok := StringToAlgorithm[l.token]; ok {
|
||||||
rr.Algorithm = v
|
rr.Algorithm = v
|
||||||
} else if i, e := strconv.Atoi(l.token); e != nil {
|
} else if i, e := strconv.ParseUint(l.token, 10, 8); e != nil {
|
||||||
return nil, &ParseError{f, "bad CERT Algorithm", l}, ""
|
return nil, &ParseError{f, "bad CERT Algorithm", l}, ""
|
||||||
} else {
|
} else {
|
||||||
rr.Algorithm = uint8(i)
|
rr.Algorithm = uint8(i)
|
||||||
|
@ -1159,21 +1148,21 @@ func setRRSIG(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
|
||||||
}
|
}
|
||||||
<-c // zBlank
|
<-c // zBlank
|
||||||
l = <-c
|
l = <-c
|
||||||
i, err := strconv.Atoi(l.token)
|
i, err := strconv.ParseUint(l.token, 10, 8)
|
||||||
if err != nil || l.err {
|
if err != nil || l.err {
|
||||||
return nil, &ParseError{f, "bad RRSIG Algorithm", l}, ""
|
return nil, &ParseError{f, "bad RRSIG Algorithm", l}, ""
|
||||||
}
|
}
|
||||||
rr.Algorithm = uint8(i)
|
rr.Algorithm = uint8(i)
|
||||||
<-c // zBlank
|
<-c // zBlank
|
||||||
l = <-c
|
l = <-c
|
||||||
i, err = strconv.Atoi(l.token)
|
i, err = strconv.ParseUint(l.token, 10, 8)
|
||||||
if err != nil || l.err {
|
if err != nil || l.err {
|
||||||
return nil, &ParseError{f, "bad RRSIG Labels", l}, ""
|
return nil, &ParseError{f, "bad RRSIG Labels", l}, ""
|
||||||
}
|
}
|
||||||
rr.Labels = uint8(i)
|
rr.Labels = uint8(i)
|
||||||
<-c // zBlank
|
<-c // zBlank
|
||||||
l = <-c
|
l = <-c
|
||||||
i, err = strconv.Atoi(l.token)
|
i, err = strconv.ParseUint(l.token, 10, 32)
|
||||||
if err != nil || l.err {
|
if err != nil || l.err {
|
||||||
return nil, &ParseError{f, "bad RRSIG OrigTtl", l}, ""
|
return nil, &ParseError{f, "bad RRSIG OrigTtl", l}, ""
|
||||||
}
|
}
|
||||||
|
@ -1204,7 +1193,7 @@ func setRRSIG(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
|
||||||
}
|
}
|
||||||
<-c // zBlank
|
<-c // zBlank
|
||||||
l = <-c
|
l = <-c
|
||||||
i, err = strconv.Atoi(l.token)
|
i, err = strconv.ParseUint(l.token, 10, 16)
|
||||||
if err != nil || l.err {
|
if err != nil || l.err {
|
||||||
return nil, &ParseError{f, "bad RRSIG KeyTag", l}, ""
|
return nil, &ParseError{f, "bad RRSIG KeyTag", l}, ""
|
||||||
}
|
}
|
||||||
|
@ -1285,21 +1274,21 @@ func setNSEC3(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
|
||||||
if l.length == 0 {
|
if l.length == 0 {
|
||||||
return rr, nil, l.comment
|
return rr, nil, l.comment
|
||||||
}
|
}
|
||||||
i, e := strconv.Atoi(l.token)
|
i, e := strconv.ParseUint(l.token, 10, 8)
|
||||||
if e != nil || l.err {
|
if e != nil || l.err {
|
||||||
return nil, &ParseError{f, "bad NSEC3 Hash", l}, ""
|
return nil, &ParseError{f, "bad NSEC3 Hash", l}, ""
|
||||||
}
|
}
|
||||||
rr.Hash = uint8(i)
|
rr.Hash = uint8(i)
|
||||||
<-c // zBlank
|
<-c // zBlank
|
||||||
l = <-c
|
l = <-c
|
||||||
i, e = strconv.Atoi(l.token)
|
i, e = strconv.ParseUint(l.token, 10, 8)
|
||||||
if e != nil || l.err {
|
if e != nil || l.err {
|
||||||
return nil, &ParseError{f, "bad NSEC3 Flags", l}, ""
|
return nil, &ParseError{f, "bad NSEC3 Flags", l}, ""
|
||||||
}
|
}
|
||||||
rr.Flags = uint8(i)
|
rr.Flags = uint8(i)
|
||||||
<-c // zBlank
|
<-c // zBlank
|
||||||
l = <-c
|
l = <-c
|
||||||
i, e = strconv.Atoi(l.token)
|
i, e = strconv.ParseUint(l.token, 10, 16)
|
||||||
if e != nil || l.err {
|
if e != nil || l.err {
|
||||||
return nil, &ParseError{f, "bad NSEC3 Iterations", l}, ""
|
return nil, &ParseError{f, "bad NSEC3 Iterations", l}, ""
|
||||||
}
|
}
|
||||||
|
@ -1353,21 +1342,21 @@ func setNSEC3PARAM(h RR_Header, c chan lex, o, f string) (RR, *ParseError, strin
|
||||||
if l.length == 0 {
|
if l.length == 0 {
|
||||||
return rr, nil, ""
|
return rr, nil, ""
|
||||||
}
|
}
|
||||||
i, e := strconv.Atoi(l.token)
|
i, e := strconv.ParseUint(l.token, 10, 8)
|
||||||
if e != nil || l.err {
|
if e != nil || l.err {
|
||||||
return nil, &ParseError{f, "bad NSEC3PARAM Hash", l}, ""
|
return nil, &ParseError{f, "bad NSEC3PARAM Hash", l}, ""
|
||||||
}
|
}
|
||||||
rr.Hash = uint8(i)
|
rr.Hash = uint8(i)
|
||||||
<-c // zBlank
|
<-c // zBlank
|
||||||
l = <-c
|
l = <-c
|
||||||
i, e = strconv.Atoi(l.token)
|
i, e = strconv.ParseUint(l.token, 10, 8)
|
||||||
if e != nil || l.err {
|
if e != nil || l.err {
|
||||||
return nil, &ParseError{f, "bad NSEC3PARAM Flags", l}, ""
|
return nil, &ParseError{f, "bad NSEC3PARAM Flags", l}, ""
|
||||||
}
|
}
|
||||||
rr.Flags = uint8(i)
|
rr.Flags = uint8(i)
|
||||||
<-c // zBlank
|
<-c // zBlank
|
||||||
l = <-c
|
l = <-c
|
||||||
i, e = strconv.Atoi(l.token)
|
i, e = strconv.ParseUint(l.token, 10, 16)
|
||||||
if e != nil || l.err {
|
if e != nil || l.err {
|
||||||
return nil, &ParseError{f, "bad NSEC3PARAM Iterations", l}, ""
|
return nil, &ParseError{f, "bad NSEC3PARAM Iterations", l}, ""
|
||||||
}
|
}
|
||||||
|
@ -1451,14 +1440,14 @@ func setSSHFP(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
|
||||||
if l.length == 0 {
|
if l.length == 0 {
|
||||||
return rr, nil, ""
|
return rr, nil, ""
|
||||||
}
|
}
|
||||||
i, e := strconv.Atoi(l.token)
|
i, e := strconv.ParseUint(l.token, 10, 8)
|
||||||
if e != nil || l.err {
|
if e != nil || l.err {
|
||||||
return nil, &ParseError{f, "bad SSHFP Algorithm", l}, ""
|
return nil, &ParseError{f, "bad SSHFP Algorithm", l}, ""
|
||||||
}
|
}
|
||||||
rr.Algorithm = uint8(i)
|
rr.Algorithm = uint8(i)
|
||||||
<-c // zBlank
|
<-c // zBlank
|
||||||
l = <-c
|
l = <-c
|
||||||
i, e = strconv.Atoi(l.token)
|
i, e = strconv.ParseUint(l.token, 10, 8)
|
||||||
if e != nil || l.err {
|
if e != nil || l.err {
|
||||||
return nil, &ParseError{f, "bad SSHFP Type", l}, ""
|
return nil, &ParseError{f, "bad SSHFP Type", l}, ""
|
||||||
}
|
}
|
||||||
|
@ -1480,21 +1469,21 @@ func setDNSKEYs(h RR_Header, c chan lex, o, f, typ string) (RR, *ParseError, str
|
||||||
if l.length == 0 {
|
if l.length == 0 {
|
||||||
return rr, nil, l.comment
|
return rr, nil, l.comment
|
||||||
}
|
}
|
||||||
i, e := strconv.Atoi(l.token)
|
i, e := strconv.ParseUint(l.token, 10, 16)
|
||||||
if e != nil || l.err {
|
if e != nil || l.err {
|
||||||
return nil, &ParseError{f, "bad " + typ + " Flags", l}, ""
|
return nil, &ParseError{f, "bad " + typ + " Flags", l}, ""
|
||||||
}
|
}
|
||||||
rr.Flags = uint16(i)
|
rr.Flags = uint16(i)
|
||||||
<-c // zBlank
|
<-c // zBlank
|
||||||
l = <-c // zString
|
l = <-c // zString
|
||||||
i, e = strconv.Atoi(l.token)
|
i, e = strconv.ParseUint(l.token, 10, 8)
|
||||||
if e != nil || l.err {
|
if e != nil || l.err {
|
||||||
return nil, &ParseError{f, "bad " + typ + " Protocol", l}, ""
|
return nil, &ParseError{f, "bad " + typ + " Protocol", l}, ""
|
||||||
}
|
}
|
||||||
rr.Protocol = uint8(i)
|
rr.Protocol = uint8(i)
|
||||||
<-c // zBlank
|
<-c // zBlank
|
||||||
l = <-c // zString
|
l = <-c // zString
|
||||||
i, e = strconv.Atoi(l.token)
|
i, e = strconv.ParseUint(l.token, 10, 8)
|
||||||
if e != nil || l.err {
|
if e != nil || l.err {
|
||||||
return nil, &ParseError{f, "bad " + typ + " Algorithm", l}, ""
|
return nil, &ParseError{f, "bad " + typ + " Algorithm", l}, ""
|
||||||
}
|
}
|
||||||
|
@ -1536,21 +1525,21 @@ func setRKEY(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
|
||||||
if l.length == 0 {
|
if l.length == 0 {
|
||||||
return rr, nil, l.comment
|
return rr, nil, l.comment
|
||||||
}
|
}
|
||||||
i, e := strconv.Atoi(l.token)
|
i, e := strconv.ParseUint(l.token, 10, 16)
|
||||||
if e != nil || l.err {
|
if e != nil || l.err {
|
||||||
return nil, &ParseError{f, "bad RKEY Flags", l}, ""
|
return nil, &ParseError{f, "bad RKEY Flags", l}, ""
|
||||||
}
|
}
|
||||||
rr.Flags = uint16(i)
|
rr.Flags = uint16(i)
|
||||||
<-c // zBlank
|
<-c // zBlank
|
||||||
l = <-c // zString
|
l = <-c // zString
|
||||||
i, e = strconv.Atoi(l.token)
|
i, e = strconv.ParseUint(l.token, 10, 8)
|
||||||
if e != nil || l.err {
|
if e != nil || l.err {
|
||||||
return nil, &ParseError{f, "bad RKEY Protocol", l}, ""
|
return nil, &ParseError{f, "bad RKEY Protocol", l}, ""
|
||||||
}
|
}
|
||||||
rr.Protocol = uint8(i)
|
rr.Protocol = uint8(i)
|
||||||
<-c // zBlank
|
<-c // zBlank
|
||||||
l = <-c // zString
|
l = <-c // zString
|
||||||
i, e = strconv.Atoi(l.token)
|
i, e = strconv.ParseUint(l.token, 10, 8)
|
||||||
if e != nil || l.err {
|
if e != nil || l.err {
|
||||||
return nil, &ParseError{f, "bad RKEY Algorithm", l}, ""
|
return nil, &ParseError{f, "bad RKEY Algorithm", l}, ""
|
||||||
}
|
}
|
||||||
|
@ -1621,14 +1610,14 @@ func setDSs(h RR_Header, c chan lex, o, f, typ string) (RR, *ParseError, string)
|
||||||
if l.length == 0 {
|
if l.length == 0 {
|
||||||
return rr, nil, l.comment
|
return rr, nil, l.comment
|
||||||
}
|
}
|
||||||
i, e := strconv.Atoi(l.token)
|
i, e := strconv.ParseUint(l.token, 10, 16)
|
||||||
if e != nil || l.err {
|
if e != nil || l.err {
|
||||||
return nil, &ParseError{f, "bad " + typ + " KeyTag", l}, ""
|
return nil, &ParseError{f, "bad " + typ + " KeyTag", l}, ""
|
||||||
}
|
}
|
||||||
rr.KeyTag = uint16(i)
|
rr.KeyTag = uint16(i)
|
||||||
<-c // zBlank
|
<-c // zBlank
|
||||||
l = <-c
|
l = <-c
|
||||||
if i, e := strconv.Atoi(l.token); e != nil {
|
if i, e = strconv.ParseUint(l.token, 10, 8); e != nil {
|
||||||
i, ok := StringToAlgorithm[l.tokenUpper]
|
i, ok := StringToAlgorithm[l.tokenUpper]
|
||||||
if !ok || l.err {
|
if !ok || l.err {
|
||||||
return nil, &ParseError{f, "bad " + typ + " Algorithm", l}, ""
|
return nil, &ParseError{f, "bad " + typ + " Algorithm", l}, ""
|
||||||
|
@ -1639,7 +1628,7 @@ func setDSs(h RR_Header, c chan lex, o, f, typ string) (RR, *ParseError, string)
|
||||||
}
|
}
|
||||||
<-c // zBlank
|
<-c // zBlank
|
||||||
l = <-c
|
l = <-c
|
||||||
i, e = strconv.Atoi(l.token)
|
i, e = strconv.ParseUint(l.token, 10, 8)
|
||||||
if e != nil || l.err {
|
if e != nil || l.err {
|
||||||
return nil, &ParseError{f, "bad " + typ + " DigestType", l}, ""
|
return nil, &ParseError{f, "bad " + typ + " DigestType", l}, ""
|
||||||
}
|
}
|
||||||
|
@ -1680,14 +1669,14 @@ func setTA(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
|
||||||
if l.length == 0 {
|
if l.length == 0 {
|
||||||
return rr, nil, l.comment
|
return rr, nil, l.comment
|
||||||
}
|
}
|
||||||
i, e := strconv.Atoi(l.token)
|
i, e := strconv.ParseUint(l.token, 10, 16)
|
||||||
if e != nil || l.err {
|
if e != nil || l.err {
|
||||||
return nil, &ParseError{f, "bad TA KeyTag", l}, ""
|
return nil, &ParseError{f, "bad TA KeyTag", l}, ""
|
||||||
}
|
}
|
||||||
rr.KeyTag = uint16(i)
|
rr.KeyTag = uint16(i)
|
||||||
<-c // zBlank
|
<-c // zBlank
|
||||||
l = <-c
|
l = <-c
|
||||||
if i, e := strconv.Atoi(l.token); e != nil {
|
if i, e := strconv.ParseUint(l.token, 10, 8); e != nil {
|
||||||
i, ok := StringToAlgorithm[l.tokenUpper]
|
i, ok := StringToAlgorithm[l.tokenUpper]
|
||||||
if !ok || l.err {
|
if !ok || l.err {
|
||||||
return nil, &ParseError{f, "bad TA Algorithm", l}, ""
|
return nil, &ParseError{f, "bad TA Algorithm", l}, ""
|
||||||
|
@ -1698,7 +1687,7 @@ func setTA(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
|
||||||
}
|
}
|
||||||
<-c // zBlank
|
<-c // zBlank
|
||||||
l = <-c
|
l = <-c
|
||||||
i, e = strconv.Atoi(l.token)
|
i, e = strconv.ParseUint(l.token, 10, 8)
|
||||||
if e != nil || l.err {
|
if e != nil || l.err {
|
||||||
return nil, &ParseError{f, "bad TA DigestType", l}, ""
|
return nil, &ParseError{f, "bad TA DigestType", l}, ""
|
||||||
}
|
}
|
||||||
|
@ -1718,21 +1707,21 @@ func setTLSA(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
|
||||||
if l.length == 0 {
|
if l.length == 0 {
|
||||||
return rr, nil, l.comment
|
return rr, nil, l.comment
|
||||||
}
|
}
|
||||||
i, e := strconv.Atoi(l.token)
|
i, e := strconv.ParseUint(l.token, 10, 8)
|
||||||
if e != nil || l.err {
|
if e != nil || l.err {
|
||||||
return nil, &ParseError{f, "bad TLSA Usage", l}, ""
|
return nil, &ParseError{f, "bad TLSA Usage", l}, ""
|
||||||
}
|
}
|
||||||
rr.Usage = uint8(i)
|
rr.Usage = uint8(i)
|
||||||
<-c // zBlank
|
<-c // zBlank
|
||||||
l = <-c
|
l = <-c
|
||||||
i, e = strconv.Atoi(l.token)
|
i, e = strconv.ParseUint(l.token, 10, 8)
|
||||||
if e != nil || l.err {
|
if e != nil || l.err {
|
||||||
return nil, &ParseError{f, "bad TLSA Selector", l}, ""
|
return nil, &ParseError{f, "bad TLSA Selector", l}, ""
|
||||||
}
|
}
|
||||||
rr.Selector = uint8(i)
|
rr.Selector = uint8(i)
|
||||||
<-c // zBlank
|
<-c // zBlank
|
||||||
l = <-c
|
l = <-c
|
||||||
i, e = strconv.Atoi(l.token)
|
i, e = strconv.ParseUint(l.token, 10, 8)
|
||||||
if e != nil || l.err {
|
if e != nil || l.err {
|
||||||
return nil, &ParseError{f, "bad TLSA MatchingType", l}, ""
|
return nil, &ParseError{f, "bad TLSA MatchingType", l}, ""
|
||||||
}
|
}
|
||||||
|
@ -1746,6 +1735,41 @@ func setTLSA(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
|
||||||
return rr, nil, c1
|
return rr, nil, c1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func setSMIMEA(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
|
||||||
|
rr := new(SMIMEA)
|
||||||
|
rr.Hdr = h
|
||||||
|
l := <-c
|
||||||
|
if l.length == 0 {
|
||||||
|
return rr, nil, l.comment
|
||||||
|
}
|
||||||
|
i, e := strconv.ParseUint(l.token, 10, 8)
|
||||||
|
if e != nil || l.err {
|
||||||
|
return nil, &ParseError{f, "bad SMIMEA Usage", l}, ""
|
||||||
|
}
|
||||||
|
rr.Usage = uint8(i)
|
||||||
|
<-c // zBlank
|
||||||
|
l = <-c
|
||||||
|
i, e = strconv.ParseUint(l.token, 10, 8)
|
||||||
|
if e != nil || l.err {
|
||||||
|
return nil, &ParseError{f, "bad SMIMEA Selector", l}, ""
|
||||||
|
}
|
||||||
|
rr.Selector = uint8(i)
|
||||||
|
<-c // zBlank
|
||||||
|
l = <-c
|
||||||
|
i, e = strconv.ParseUint(l.token, 10, 8)
|
||||||
|
if e != nil || l.err {
|
||||||
|
return nil, &ParseError{f, "bad SMIMEA MatchingType", l}, ""
|
||||||
|
}
|
||||||
|
rr.MatchingType = uint8(i)
|
||||||
|
// So this needs be e2 (i.e. different than e), because...??t
|
||||||
|
s, e2, c1 := endingToString(c, "bad SMIMEA Certificate", f)
|
||||||
|
if e2 != nil {
|
||||||
|
return nil, e2, c1
|
||||||
|
}
|
||||||
|
rr.Certificate = s
|
||||||
|
return rr, nil, c1
|
||||||
|
}
|
||||||
|
|
||||||
func setRFC3597(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
|
func setRFC3597(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
|
||||||
rr := new(RFC3597)
|
rr := new(RFC3597)
|
||||||
rr.Hdr = h
|
rr.Hdr = h
|
||||||
|
@ -1783,6 +1807,18 @@ func setSPF(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
|
||||||
return rr, nil, c1
|
return rr, nil, c1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func setAVC(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
|
||||||
|
rr := new(AVC)
|
||||||
|
rr.Hdr = h
|
||||||
|
|
||||||
|
s, e, c1 := endingToTxtSlice(c, "bad AVC Txt", f)
|
||||||
|
if e != nil {
|
||||||
|
return nil, e, ""
|
||||||
|
}
|
||||||
|
rr.Txt = s
|
||||||
|
return rr, nil, c1
|
||||||
|
}
|
||||||
|
|
||||||
func setTXT(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
|
func setTXT(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
|
||||||
rr := new(TXT)
|
rr := new(TXT)
|
||||||
rr.Hdr = h
|
rr.Hdr = h
|
||||||
|
@ -1818,14 +1854,14 @@ func setURI(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
|
||||||
return rr, nil, ""
|
return rr, nil, ""
|
||||||
}
|
}
|
||||||
|
|
||||||
i, e := strconv.Atoi(l.token)
|
i, e := strconv.ParseUint(l.token, 10, 16)
|
||||||
if e != nil || l.err {
|
if e != nil || l.err {
|
||||||
return nil, &ParseError{f, "bad URI Priority", l}, ""
|
return nil, &ParseError{f, "bad URI Priority", l}, ""
|
||||||
}
|
}
|
||||||
rr.Priority = uint16(i)
|
rr.Priority = uint16(i)
|
||||||
<-c // zBlank
|
<-c // zBlank
|
||||||
l = <-c
|
l = <-c
|
||||||
i, e = strconv.Atoi(l.token)
|
i, e = strconv.ParseUint(l.token, 10, 16)
|
||||||
if e != nil || l.err {
|
if e != nil || l.err {
|
||||||
return nil, &ParseError{f, "bad URI Weight", l}, ""
|
return nil, &ParseError{f, "bad URI Weight", l}, ""
|
||||||
}
|
}
|
||||||
|
@ -1864,7 +1900,7 @@ func setNID(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
|
||||||
if l.length == 0 {
|
if l.length == 0 {
|
||||||
return rr, nil, ""
|
return rr, nil, ""
|
||||||
}
|
}
|
||||||
i, e := strconv.Atoi(l.token)
|
i, e := strconv.ParseUint(l.token, 10, 16)
|
||||||
if e != nil || l.err {
|
if e != nil || l.err {
|
||||||
return nil, &ParseError{f, "bad NID Preference", l}, ""
|
return nil, &ParseError{f, "bad NID Preference", l}, ""
|
||||||
}
|
}
|
||||||
|
@ -1887,7 +1923,7 @@ func setL32(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
|
||||||
if l.length == 0 {
|
if l.length == 0 {
|
||||||
return rr, nil, ""
|
return rr, nil, ""
|
||||||
}
|
}
|
||||||
i, e := strconv.Atoi(l.token)
|
i, e := strconv.ParseUint(l.token, 10, 16)
|
||||||
if e != nil || l.err {
|
if e != nil || l.err {
|
||||||
return nil, &ParseError{f, "bad L32 Preference", l}, ""
|
return nil, &ParseError{f, "bad L32 Preference", l}, ""
|
||||||
}
|
}
|
||||||
|
@ -1909,7 +1945,7 @@ func setLP(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
|
||||||
if l.length == 0 {
|
if l.length == 0 {
|
||||||
return rr, nil, ""
|
return rr, nil, ""
|
||||||
}
|
}
|
||||||
i, e := strconv.Atoi(l.token)
|
i, e := strconv.ParseUint(l.token, 10, 16)
|
||||||
if e != nil || l.err {
|
if e != nil || l.err {
|
||||||
return nil, &ParseError{f, "bad LP Preference", l}, ""
|
return nil, &ParseError{f, "bad LP Preference", l}, ""
|
||||||
}
|
}
|
||||||
|
@ -1942,7 +1978,7 @@ func setL64(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
|
||||||
if l.length == 0 {
|
if l.length == 0 {
|
||||||
return rr, nil, ""
|
return rr, nil, ""
|
||||||
}
|
}
|
||||||
i, e := strconv.Atoi(l.token)
|
i, e := strconv.ParseUint(l.token, 10, 16)
|
||||||
if e != nil || l.err {
|
if e != nil || l.err {
|
||||||
return nil, &ParseError{f, "bad L64 Preference", l}, ""
|
return nil, &ParseError{f, "bad L64 Preference", l}, ""
|
||||||
}
|
}
|
||||||
|
@ -1964,7 +2000,7 @@ func setUID(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
|
||||||
if l.length == 0 {
|
if l.length == 0 {
|
||||||
return rr, nil, ""
|
return rr, nil, ""
|
||||||
}
|
}
|
||||||
i, e := strconv.Atoi(l.token)
|
i, e := strconv.ParseUint(l.token, 10, 32)
|
||||||
if e != nil || l.err {
|
if e != nil || l.err {
|
||||||
return nil, &ParseError{f, "bad UID Uid", l}, ""
|
return nil, &ParseError{f, "bad UID Uid", l}, ""
|
||||||
}
|
}
|
||||||
|
@ -1979,7 +2015,7 @@ func setGID(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
|
||||||
if l.length == 0 {
|
if l.length == 0 {
|
||||||
return rr, nil, ""
|
return rr, nil, ""
|
||||||
}
|
}
|
||||||
i, e := strconv.Atoi(l.token)
|
i, e := strconv.ParseUint(l.token, 10, 32)
|
||||||
if e != nil || l.err {
|
if e != nil || l.err {
|
||||||
return nil, &ParseError{f, "bad GID Gid", l}, ""
|
return nil, &ParseError{f, "bad GID Gid", l}, ""
|
||||||
}
|
}
|
||||||
|
@ -1992,9 +2028,12 @@ func setUINFO(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
|
||||||
rr.Hdr = h
|
rr.Hdr = h
|
||||||
s, e, c1 := endingToTxtSlice(c, "bad UINFO Uinfo", f)
|
s, e, c1 := endingToTxtSlice(c, "bad UINFO Uinfo", f)
|
||||||
if e != nil {
|
if e != nil {
|
||||||
return nil, e, ""
|
return nil, e, c1
|
||||||
}
|
}
|
||||||
rr.Uinfo = s[0] // silently discard anything above
|
if ln := len(s); ln == 0 {
|
||||||
|
return rr, nil, c1
|
||||||
|
}
|
||||||
|
rr.Uinfo = s[0] // silently discard anything after the first character-string
|
||||||
return rr, nil, c1
|
return rr, nil, c1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2006,7 +2045,7 @@ func setPX(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
|
||||||
if l.length == 0 {
|
if l.length == 0 {
|
||||||
return rr, nil, ""
|
return rr, nil, ""
|
||||||
}
|
}
|
||||||
i, e := strconv.Atoi(l.token)
|
i, e := strconv.ParseUint(l.token, 10, 16)
|
||||||
if e != nil || l.err {
|
if e != nil || l.err {
|
||||||
return nil, &ParseError{f, "bad PX Preference", l}, ""
|
return nil, &ParseError{f, "bad PX Preference", l}, ""
|
||||||
}
|
}
|
||||||
|
@ -2052,7 +2091,7 @@ func setCAA(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
|
||||||
if l.length == 0 {
|
if l.length == 0 {
|
||||||
return rr, nil, l.comment
|
return rr, nil, l.comment
|
||||||
}
|
}
|
||||||
i, err := strconv.Atoi(l.token)
|
i, err := strconv.ParseUint(l.token, 10, 8)
|
||||||
if err != nil || l.err {
|
if err != nil || l.err {
|
||||||
return nil, &ParseError{f, "bad CAA Flag", l}, ""
|
return nil, &ParseError{f, "bad CAA Flag", l}, ""
|
||||||
}
|
}
|
||||||
|
@ -2128,8 +2167,10 @@ var typeToparserFunc = map[uint16]parserFunc{
|
||||||
TypeRP: {setRP, false},
|
TypeRP: {setRP, false},
|
||||||
TypeRRSIG: {setRRSIG, true},
|
TypeRRSIG: {setRRSIG, true},
|
||||||
TypeRT: {setRT, false},
|
TypeRT: {setRT, false},
|
||||||
|
TypeSMIMEA: {setSMIMEA, true},
|
||||||
TypeSOA: {setSOA, false},
|
TypeSOA: {setSOA, false},
|
||||||
TypeSPF: {setSPF, true},
|
TypeSPF: {setSPF, true},
|
||||||
|
TypeAVC: {setAVC, true},
|
||||||
TypeSRV: {setSRV, false},
|
TypeSRV: {setSRV, false},
|
||||||
TypeSSHFP: {setSSHFP, true},
|
TypeSSHFP: {setSSHFP, true},
|
||||||
TypeTALINK: {setTALINK, false},
|
TypeTALINK: {setTALINK, false},
|
||||||
|
|
|
@ -147,7 +147,7 @@ func (mux *ServeMux) match(q string, t uint16) Handler {
|
||||||
b[i] |= ('a' - 'A')
|
b[i] |= ('a' - 'A')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if h, ok := mux.z[string(b[:l])]; ok { // 'causes garbage, might want to change the map key
|
if h, ok := mux.z[string(b[:l])]; ok { // causes garbage, might want to change the map key
|
||||||
if t != TypeDS {
|
if t != TypeDS {
|
||||||
return h
|
return h
|
||||||
}
|
}
|
||||||
|
@ -339,7 +339,7 @@ func (srv *Server) ListenAndServe() error {
|
||||||
network := "tcp"
|
network := "tcp"
|
||||||
if srv.Net == "tcp4-tls" {
|
if srv.Net == "tcp4-tls" {
|
||||||
network = "tcp4"
|
network = "tcp4"
|
||||||
} else if srv.Net == "tcp6" {
|
} else if srv.Net == "tcp6-tls" {
|
||||||
network = "tcp6"
|
network = "tcp6"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -389,7 +389,9 @@ func (srv *Server) ActivateAndServe() error {
|
||||||
if srv.UDPSize == 0 {
|
if srv.UDPSize == 0 {
|
||||||
srv.UDPSize = MinMsgSize
|
srv.UDPSize = MinMsgSize
|
||||||
}
|
}
|
||||||
if t, ok := pConn.(*net.UDPConn); ok {
|
// Check PacketConn interface's type is valid and value
|
||||||
|
// is not nil
|
||||||
|
if t, ok := pConn.(*net.UDPConn); ok && t != nil {
|
||||||
if e := setUDPSocketOptions(t); e != nil {
|
if e := setUDPSocketOptions(t); e != nil {
|
||||||
return e
|
return e
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,16 +60,15 @@ func (rr *SIG) Sign(k crypto.Signer, m *Msg) ([]byte, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
rr.Signature = toBase64(signature)
|
rr.Signature = toBase64(signature)
|
||||||
sig := string(signature)
|
|
||||||
|
|
||||||
buf = append(buf, sig...)
|
buf = append(buf, signature...)
|
||||||
if len(buf) > int(^uint16(0)) {
|
if len(buf) > int(^uint16(0)) {
|
||||||
return nil, ErrBuf
|
return nil, ErrBuf
|
||||||
}
|
}
|
||||||
// Adjust sig data length
|
// Adjust sig data length
|
||||||
rdoff := len(mbuf) + 1 + 2 + 2 + 4
|
rdoff := len(mbuf) + 1 + 2 + 2 + 4
|
||||||
rdlen := binary.BigEndian.Uint16(buf[rdoff:])
|
rdlen := binary.BigEndian.Uint16(buf[rdoff:])
|
||||||
rdlen += uint16(len(sig))
|
rdlen += uint16(len(signature))
|
||||||
binary.BigEndian.PutUint16(buf[rdoff:], rdlen)
|
binary.BigEndian.PutUint16(buf[rdoff:], rdlen)
|
||||||
// Adjust additional count
|
// Adjust additional count
|
||||||
adc := binary.BigEndian.Uint16(buf[10:])
|
adc := binary.BigEndian.Uint16(buf[10:])
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
package dns
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/sha256"
|
||||||
|
"crypto/x509"
|
||||||
|
"encoding/hex"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Sign creates a SMIMEA record from an SSL certificate.
|
||||||
|
func (r *SMIMEA) Sign(usage, selector, matchingType int, cert *x509.Certificate) (err error) {
|
||||||
|
r.Hdr.Rrtype = TypeSMIMEA
|
||||||
|
r.Usage = uint8(usage)
|
||||||
|
r.Selector = uint8(selector)
|
||||||
|
r.MatchingType = uint8(matchingType)
|
||||||
|
|
||||||
|
r.Certificate, err = CertificateToDANE(r.Selector, r.MatchingType, cert)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify verifies a SMIMEA record against an SSL certificate. If it is OK
|
||||||
|
// a nil error is returned.
|
||||||
|
func (r *SMIMEA) Verify(cert *x509.Certificate) error {
|
||||||
|
c, err := CertificateToDANE(r.Selector, r.MatchingType, cert)
|
||||||
|
if err != nil {
|
||||||
|
return err // Not also ErrSig?
|
||||||
|
}
|
||||||
|
if r.Certificate == c {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return ErrSig // ErrSig, really?
|
||||||
|
}
|
||||||
|
|
||||||
|
// SMIMEAName returns the ownername of a SMIMEA resource record as per the
|
||||||
|
// format specified in RFC 'draft-ietf-dane-smime-12' Section 2 and 3
|
||||||
|
func SMIMEAName(email, domain string) (string, error) {
|
||||||
|
hasher := sha256.New()
|
||||||
|
hasher.Write([]byte(email))
|
||||||
|
|
||||||
|
// RFC Section 3: "The local-part is hashed using the SHA2-256
|
||||||
|
// algorithm with the hash truncated to 28 octets and
|
||||||
|
// represented in its hexadecimal representation to become the
|
||||||
|
// left-most label in the prepared domain name"
|
||||||
|
return hex.EncodeToString(hasher.Sum(nil)[:28]) + "." + "_smimecert." + domain, nil
|
||||||
|
}
|
|
@ -1,50 +1,11 @@
|
||||||
package dns
|
package dns
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/sha256"
|
|
||||||
"crypto/sha512"
|
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"encoding/hex"
|
|
||||||
"errors"
|
|
||||||
"io"
|
|
||||||
"net"
|
"net"
|
||||||
"strconv"
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CertificateToDANE converts a certificate to a hex string as used in the TLSA record.
|
|
||||||
func CertificateToDANE(selector, matchingType uint8, cert *x509.Certificate) (string, error) {
|
|
||||||
switch matchingType {
|
|
||||||
case 0:
|
|
||||||
switch selector {
|
|
||||||
case 0:
|
|
||||||
return hex.EncodeToString(cert.Raw), nil
|
|
||||||
case 1:
|
|
||||||
return hex.EncodeToString(cert.RawSubjectPublicKeyInfo), nil
|
|
||||||
}
|
|
||||||
case 1:
|
|
||||||
h := sha256.New()
|
|
||||||
switch selector {
|
|
||||||
case 0:
|
|
||||||
io.WriteString(h, string(cert.Raw))
|
|
||||||
return hex.EncodeToString(h.Sum(nil)), nil
|
|
||||||
case 1:
|
|
||||||
io.WriteString(h, string(cert.RawSubjectPublicKeyInfo))
|
|
||||||
return hex.EncodeToString(h.Sum(nil)), nil
|
|
||||||
}
|
|
||||||
case 2:
|
|
||||||
h := sha512.New()
|
|
||||||
switch selector {
|
|
||||||
case 0:
|
|
||||||
io.WriteString(h, string(cert.Raw))
|
|
||||||
return hex.EncodeToString(h.Sum(nil)), nil
|
|
||||||
case 1:
|
|
||||||
io.WriteString(h, string(cert.RawSubjectPublicKeyInfo))
|
|
||||||
return hex.EncodeToString(h.Sum(nil)), nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return "", errors.New("dns: bad TLSA MatchingType or TLSA Selector")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sign creates a TLSA record from an SSL certificate.
|
// Sign creates a TLSA record from an SSL certificate.
|
||||||
func (r *TLSA) Sign(usage, selector, matchingType int, cert *x509.Certificate) (err error) {
|
func (r *TLSA) Sign(usage, selector, matchingType int, cert *x509.Certificate) (err error) {
|
||||||
r.Hdr.Rrtype = TypeTLSA
|
r.Hdr.Rrtype = TypeTLSA
|
||||||
|
|
|
@ -9,7 +9,6 @@ import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"hash"
|
"hash"
|
||||||
"io"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
@ -124,7 +123,7 @@ func TsigGenerate(m *Msg, secret, requestMAC string, timersOnly bool) ([]byte, s
|
||||||
default:
|
default:
|
||||||
return nil, "", ErrKeyAlg
|
return nil, "", ErrKeyAlg
|
||||||
}
|
}
|
||||||
io.WriteString(h, string(buf))
|
h.Write(buf)
|
||||||
t.MAC = hex.EncodeToString(h.Sum(nil))
|
t.MAC = hex.EncodeToString(h.Sum(nil))
|
||||||
t.MACSize = uint16(len(t.MAC) / 2) // Size is half!
|
t.MACSize = uint16(len(t.MAC) / 2) // Size is half!
|
||||||
|
|
||||||
|
|
|
@ -70,6 +70,7 @@ const (
|
||||||
TypeNSEC3 uint16 = 50
|
TypeNSEC3 uint16 = 50
|
||||||
TypeNSEC3PARAM uint16 = 51
|
TypeNSEC3PARAM uint16 = 51
|
||||||
TypeTLSA uint16 = 52
|
TypeTLSA uint16 = 52
|
||||||
|
TypeSMIMEA uint16 = 53
|
||||||
TypeHIP uint16 = 55
|
TypeHIP uint16 = 55
|
||||||
TypeNINFO uint16 = 56
|
TypeNINFO uint16 = 56
|
||||||
TypeRKEY uint16 = 57
|
TypeRKEY uint16 = 57
|
||||||
|
@ -90,6 +91,7 @@ const (
|
||||||
TypeEUI64 uint16 = 109
|
TypeEUI64 uint16 = 109
|
||||||
TypeURI uint16 = 256
|
TypeURI uint16 = 256
|
||||||
TypeCAA uint16 = 257
|
TypeCAA uint16 = 257
|
||||||
|
TypeAVC uint16 = 258
|
||||||
|
|
||||||
TypeTKEY uint16 = 249
|
TypeTKEY uint16 = 249
|
||||||
TypeTSIG uint16 = 250
|
TypeTSIG uint16 = 250
|
||||||
|
@ -113,27 +115,27 @@ const (
|
||||||
ClassNONE = 254
|
ClassNONE = 254
|
||||||
ClassANY = 255
|
ClassANY = 255
|
||||||
|
|
||||||
// Message Response Codes.
|
// Message Response Codes, see https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml
|
||||||
RcodeSuccess = 0
|
RcodeSuccess = 0 // NoError - No Error [DNS]
|
||||||
RcodeFormatError = 1
|
RcodeFormatError = 1 // FormErr - Format Error [DNS]
|
||||||
RcodeServerFailure = 2
|
RcodeServerFailure = 2 // ServFail - Server Failure [DNS]
|
||||||
RcodeNameError = 3
|
RcodeNameError = 3 // NXDomain - Non-Existent Domain [DNS]
|
||||||
RcodeNotImplemented = 4
|
RcodeNotImplemented = 4 // NotImp - Not Implemented [DNS]
|
||||||
RcodeRefused = 5
|
RcodeRefused = 5 // Refused - Query Refused [DNS]
|
||||||
RcodeYXDomain = 6
|
RcodeYXDomain = 6 // YXDomain - Name Exists when it should not [DNS Update]
|
||||||
RcodeYXRrset = 7
|
RcodeYXRrset = 7 // YXRRSet - RR Set Exists when it should not [DNS Update]
|
||||||
RcodeNXRrset = 8
|
RcodeNXRrset = 8 // NXRRSet - RR Set that should exist does not [DNS Update]
|
||||||
RcodeNotAuth = 9
|
RcodeNotAuth = 9 // NotAuth - Server Not Authoritative for zone [DNS Update]
|
||||||
RcodeNotZone = 10
|
RcodeNotZone = 10 // NotZone - Name not contained in zone [DNS Update/TSIG]
|
||||||
RcodeBadSig = 16 // TSIG
|
RcodeBadSig = 16 // BADSIG - TSIG Signature Failure [TSIG]
|
||||||
RcodeBadVers = 16 // EDNS0
|
RcodeBadVers = 16 // BADVERS - Bad OPT Version [EDNS0]
|
||||||
RcodeBadKey = 17
|
RcodeBadKey = 17 // BADKEY - Key not recognized [TSIG]
|
||||||
RcodeBadTime = 18
|
RcodeBadTime = 18 // BADTIME - Signature out of time window [TSIG]
|
||||||
RcodeBadMode = 19 // TKEY
|
RcodeBadMode = 19 // BADMODE - Bad TKEY Mode [TKEY]
|
||||||
RcodeBadName = 20
|
RcodeBadName = 20 // BADNAME - Duplicate key name [TKEY]
|
||||||
RcodeBadAlg = 21
|
RcodeBadAlg = 21 // BADALG - Algorithm not supported [TKEY]
|
||||||
RcodeBadTrunc = 22 // TSIG
|
RcodeBadTrunc = 22 // BADTRUNC - Bad Truncation [TSIG]
|
||||||
RcodeBadCookie = 23 // DNS Cookies
|
RcodeBadCookie = 23 // BADCOOKIE - Bad/missing Server Cookie [DNS Cookies]
|
||||||
|
|
||||||
// Message Opcodes. There is no 3.
|
// Message Opcodes. There is no 3.
|
||||||
OpcodeQuery = 0
|
OpcodeQuery = 0
|
||||||
|
@ -143,7 +145,7 @@ const (
|
||||||
OpcodeUpdate = 5
|
OpcodeUpdate = 5
|
||||||
)
|
)
|
||||||
|
|
||||||
// Headers is the wire format for the DNS packet header.
|
// Header is the wire format for the DNS packet header.
|
||||||
type Header struct {
|
type Header struct {
|
||||||
Id uint16
|
Id uint16
|
||||||
Bits uint16
|
Bits uint16
|
||||||
|
@ -479,12 +481,6 @@ func appendDomainNameByte(s []byte, b byte) []byte {
|
||||||
|
|
||||||
func appendTXTStringByte(s []byte, b byte) []byte {
|
func appendTXTStringByte(s []byte, b byte) []byte {
|
||||||
switch b {
|
switch b {
|
||||||
case '\t':
|
|
||||||
return append(s, '\\', 't')
|
|
||||||
case '\r':
|
|
||||||
return append(s, '\\', 'r')
|
|
||||||
case '\n':
|
|
||||||
return append(s, '\\', 'n')
|
|
||||||
case '"', '\\':
|
case '"', '\\':
|
||||||
return append(s, '\\', b)
|
return append(s, '\\', b)
|
||||||
}
|
}
|
||||||
|
@ -524,17 +520,8 @@ func nextByte(b []byte, offset int) (byte, int) {
|
||||||
return dddToByte(b[offset+1:]), 4
|
return dddToByte(b[offset+1:]), 4
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// not \ddd, maybe a control char
|
// not \ddd, just an RFC 1035 "quoted" character
|
||||||
switch b[offset+1] {
|
return b[offset+1], 2
|
||||||
case 't':
|
|
||||||
return '\t', 2
|
|
||||||
case 'r':
|
|
||||||
return '\r', 2
|
|
||||||
case 'n':
|
|
||||||
return '\n', 2
|
|
||||||
default:
|
|
||||||
return b[offset+1], 2
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type SPF struct {
|
type SPF struct {
|
||||||
|
@ -544,6 +531,13 @@ type SPF struct {
|
||||||
|
|
||||||
func (rr *SPF) String() string { return rr.Hdr.String() + sprintTxt(rr.Txt) }
|
func (rr *SPF) String() string { return rr.Hdr.String() + sprintTxt(rr.Txt) }
|
||||||
|
|
||||||
|
type AVC struct {
|
||||||
|
Hdr RR_Header
|
||||||
|
Txt []string `dns:"txt"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rr *AVC) String() string { return rr.Hdr.String() + sprintTxt(rr.Txt) }
|
||||||
|
|
||||||
type SRV struct {
|
type SRV struct {
|
||||||
Hdr RR_Header
|
Hdr RR_Header
|
||||||
Priority uint16
|
Priority uint16
|
||||||
|
@ -1047,6 +1041,28 @@ func (rr *TLSA) String() string {
|
||||||
" " + rr.Certificate
|
" " + rr.Certificate
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SMIMEA struct {
|
||||||
|
Hdr RR_Header
|
||||||
|
Usage uint8
|
||||||
|
Selector uint8
|
||||||
|
MatchingType uint8
|
||||||
|
Certificate string `dns:"hex"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rr *SMIMEA) String() string {
|
||||||
|
s := rr.Hdr.String() +
|
||||||
|
strconv.Itoa(int(rr.Usage)) +
|
||||||
|
" " + strconv.Itoa(int(rr.Selector)) +
|
||||||
|
" " + strconv.Itoa(int(rr.MatchingType))
|
||||||
|
|
||||||
|
// Every Nth char needs a space on this output. If we output
|
||||||
|
// this as one giant line, we can't read it can in because in some cases
|
||||||
|
// the cert length overflows scan.maxTok (2048).
|
||||||
|
sx := splitN(rr.Certificate, 1024) // conservative value here
|
||||||
|
s += " " + strings.Join(sx, " ")
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
type HIP struct {
|
type HIP struct {
|
||||||
Hdr RR_Header
|
Hdr RR_Header
|
||||||
HitLength uint8
|
HitLength uint8
|
||||||
|
@ -1247,3 +1263,25 @@ func copyIP(ip net.IP) net.IP {
|
||||||
copy(p, ip)
|
copy(p, ip)
|
||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SplitN splits a string into N sized string chunks.
|
||||||
|
// This might become an exported function once.
|
||||||
|
func splitN(s string, n int) []string {
|
||||||
|
if len(s) < n {
|
||||||
|
return []string{s}
|
||||||
|
}
|
||||||
|
sx := []string{}
|
||||||
|
p, i := 0, n
|
||||||
|
for {
|
||||||
|
if i <= len(s) {
|
||||||
|
sx = append(sx, s[p:i])
|
||||||
|
} else {
|
||||||
|
sx = append(sx, s[p:])
|
||||||
|
break
|
||||||
|
|
||||||
|
}
|
||||||
|
p, i = p+n, i+n
|
||||||
|
}
|
||||||
|
|
||||||
|
return sx
|
||||||
|
}
|
||||||
|
|
|
@ -197,7 +197,7 @@ func main() {
|
||||||
case st.Tag(i) == "":
|
case st.Tag(i) == "":
|
||||||
switch st.Field(i).Type().(*types.Basic).Kind() {
|
switch st.Field(i).Type().(*types.Basic).Kind() {
|
||||||
case types.Uint8:
|
case types.Uint8:
|
||||||
o("l += 1 // %s\n")
|
o("l++ // %s\n")
|
||||||
case types.Uint16:
|
case types.Uint16:
|
||||||
o("l += 2 // %s\n")
|
o("l += 2 // %s\n")
|
||||||
case types.Uint32:
|
case types.Uint32:
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
// +build !windows,!plan9
|
// +build !windows
|
||||||
|
|
||||||
package dns
|
package dns
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net"
|
"net"
|
||||||
"syscall"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// SessionUDP holds the remote address and the associated
|
// SessionUDP holds the remote address and the associated
|
||||||
|
@ -17,29 +16,6 @@ type SessionUDP struct {
|
||||||
// RemoteAddr returns the remote network address.
|
// RemoteAddr returns the remote network address.
|
||||||
func (s *SessionUDP) RemoteAddr() net.Addr { return s.raddr }
|
func (s *SessionUDP) RemoteAddr() net.Addr { return s.raddr }
|
||||||
|
|
||||||
// setUDPSocketOptions sets the UDP socket options.
|
|
||||||
// This function is implemented on a per platform basis. See udp_*.go for more details
|
|
||||||
func setUDPSocketOptions(conn *net.UDPConn) error {
|
|
||||||
sa, err := getUDPSocketName(conn)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
switch sa.(type) {
|
|
||||||
case *syscall.SockaddrInet6:
|
|
||||||
v6only, err := getUDPSocketOptions6Only(conn)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
setUDPSocketOptions6(conn)
|
|
||||||
if !v6only {
|
|
||||||
setUDPSocketOptions4(conn)
|
|
||||||
}
|
|
||||||
case *syscall.SockaddrInet4:
|
|
||||||
setUDPSocketOptions4(conn)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReadFromSessionUDP acts just like net.UDPConn.ReadFrom(), but returns a session object instead of a
|
// ReadFromSessionUDP acts just like net.UDPConn.ReadFrom(), but returns a session object instead of a
|
||||||
// net.UDPAddr.
|
// net.UDPAddr.
|
||||||
func ReadFromSessionUDP(conn *net.UDPConn, b []byte) (int, *SessionUDP, error) {
|
func ReadFromSessionUDP(conn *net.UDPConn, b []byte) (int, *SessionUDP, error) {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// +build linux
|
// +build linux,!appengine
|
||||||
|
|
||||||
package dns
|
package dns
|
||||||
|
|
||||||
|
@ -15,6 +15,29 @@ import (
|
||||||
"syscall"
|
"syscall"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// setUDPSocketOptions sets the UDP socket options.
|
||||||
|
// This function is implemented on a per platform basis. See udp_*.go for more details
|
||||||
|
func setUDPSocketOptions(conn *net.UDPConn) error {
|
||||||
|
sa, err := getUDPSocketName(conn)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
switch sa.(type) {
|
||||||
|
case *syscall.SockaddrInet6:
|
||||||
|
v6only, err := getUDPSocketOptions6Only(conn)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
setUDPSocketOptions6(conn)
|
||||||
|
if !v6only {
|
||||||
|
setUDPSocketOptions4(conn)
|
||||||
|
}
|
||||||
|
case *syscall.SockaddrInet4:
|
||||||
|
setUDPSocketOptions4(conn)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// setUDPSocketOptions4 prepares the v4 socket for sessions.
|
// setUDPSocketOptions4 prepares the v4 socket for sessions.
|
||||||
func setUDPSocketOptions4(conn *net.UDPConn) error {
|
func setUDPSocketOptions4(conn *net.UDPConn) error {
|
||||||
file, err := conn.File()
|
file, err := conn.File()
|
||||||
|
@ -22,14 +45,17 @@ func setUDPSocketOptions4(conn *net.UDPConn) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := syscall.SetsockoptInt(int(file.Fd()), syscall.IPPROTO_IP, syscall.IP_PKTINFO, 1); err != nil {
|
if err := syscall.SetsockoptInt(int(file.Fd()), syscall.IPPROTO_IP, syscall.IP_PKTINFO, 1); err != nil {
|
||||||
|
file.Close()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// Calling File() above results in the connection becoming blocking, we must fix that.
|
// Calling File() above results in the connection becoming blocking, we must fix that.
|
||||||
// See https://github.com/miekg/dns/issues/279
|
// See https://github.com/miekg/dns/issues/279
|
||||||
err = syscall.SetNonblock(int(file.Fd()), true)
|
err = syscall.SetNonblock(int(file.Fd()), true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
file.Close()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
file.Close()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,12 +66,15 @@ func setUDPSocketOptions6(conn *net.UDPConn) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := syscall.SetsockoptInt(int(file.Fd()), syscall.IPPROTO_IPV6, syscall.IPV6_RECVPKTINFO, 1); err != nil {
|
if err := syscall.SetsockoptInt(int(file.Fd()), syscall.IPPROTO_IPV6, syscall.IPV6_RECVPKTINFO, 1); err != nil {
|
||||||
|
file.Close()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = syscall.SetNonblock(int(file.Fd()), true)
|
err = syscall.SetNonblock(int(file.Fd()), true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
file.Close()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
file.Close()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,8 +88,10 @@ func getUDPSocketOptions6Only(conn *net.UDPConn) (bool, error) {
|
||||||
// dual stack. See http://stackoverflow.com/questions/1618240/how-to-support-both-ipv4-and-ipv6-connections
|
// dual stack. See http://stackoverflow.com/questions/1618240/how-to-support-both-ipv4-and-ipv6-connections
|
||||||
v6only, err := syscall.GetsockoptInt(int(file.Fd()), syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY)
|
v6only, err := syscall.GetsockoptInt(int(file.Fd()), syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
file.Close()
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
file.Close()
|
||||||
return v6only == 1, nil
|
return v6only == 1, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,5 +100,6 @@ func getUDPSocketName(conn *net.UDPConn) (syscall.Sockaddr, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
defer file.Close()
|
||||||
return syscall.Getsockname(int(file.Fd()))
|
return syscall.Getsockname(int(file.Fd()))
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +1,15 @@
|
||||||
// +build !linux,!plan9
|
// +build !linux appengine
|
||||||
|
|
||||||
package dns
|
package dns
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net"
|
"net"
|
||||||
"syscall"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// These do nothing. See udp_linux.go for an example of how to implement this.
|
// These do nothing. See udp_linux.go for an example of how to implement this.
|
||||||
|
|
||||||
// We tried to adhire to some kind of naming scheme.
|
// We tried to adhire to some kind of naming scheme.
|
||||||
|
func setUDPSocketOptions(conn *net.UDPConn) error { return nil }
|
||||||
func setUDPSocketOptions4(conn *net.UDPConn) error { return nil }
|
func setUDPSocketOptions4(conn *net.UDPConn) error { return nil }
|
||||||
func setUDPSocketOptions6(conn *net.UDPConn) error { return nil }
|
func setUDPSocketOptions6(conn *net.UDPConn) error { return nil }
|
||||||
func getUDPSocketOptions6Only(conn *net.UDPConn) (bool, error) { return false, nil }
|
func getUDPSocketOptions6Only(conn *net.UDPConn) (bool, error) { return false, nil }
|
||||||
func getUDPSocketName(conn *net.UDPConn) (syscall.Sockaddr, error) { return nil, nil }
|
|
||||||
|
|
|
@ -1,34 +0,0 @@
|
||||||
package dns
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net"
|
|
||||||
)
|
|
||||||
|
|
||||||
func setUDPSocketOptions(conn *net.UDPConn) error { return nil }
|
|
||||||
|
|
||||||
// SessionUDP holds the remote address and the associated
|
|
||||||
// out-of-band data.
|
|
||||||
type SessionUDP struct {
|
|
||||||
raddr *net.UDPAddr
|
|
||||||
context []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
// RemoteAddr returns the remote network address.
|
|
||||||
func (s *SessionUDP) RemoteAddr() net.Addr { return s.raddr }
|
|
||||||
|
|
||||||
// ReadFromSessionUDP acts just like net.UDPConn.ReadFrom(), but returns a session object instead of a
|
|
||||||
// net.UDPAddr.
|
|
||||||
func ReadFromSessionUDP(conn *net.UDPConn, b []byte) (int, *SessionUDP, error) {
|
|
||||||
oob := make([]byte, 40)
|
|
||||||
n, oobn, _, raddr, err := conn.ReadMsgUDP(b, oob)
|
|
||||||
if err != nil {
|
|
||||||
return n, nil, err
|
|
||||||
}
|
|
||||||
return n, &SessionUDP{raddr, oob[:oobn]}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// WriteToSessionUDP acts just like net.UDPConn.WritetTo(), but uses a *SessionUDP instead of a net.Addr.
|
|
||||||
func WriteToSessionUDP(conn *net.UDPConn, b []byte, session *SessionUDP) (int, error) {
|
|
||||||
n, _, err := conn.WriteMsgUDP(b, session.context, session.raddr)
|
|
||||||
return n, err
|
|
||||||
}
|
|
|
@ -8,6 +8,8 @@ type SessionUDP struct {
|
||||||
raddr *net.UDPAddr
|
raddr *net.UDPAddr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
@ -25,10 +27,3 @@ func WriteToSessionUDP(conn *net.UDPConn, b []byte, session *SessionUDP) (int, e
|
||||||
return n, err
|
return n, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SessionUDP) RemoteAddr() net.Addr { return s.raddr }
|
|
||||||
|
|
||||||
// setUDPSocketOptions sets the UDP socket options.
|
|
||||||
// This function is implemented on a per platform basis. See udp_*.go for more details
|
|
||||||
func setUDPSocketOptions(conn *net.UDPConn) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package dns
|
package dns
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -81,6 +82,10 @@ func (t *Transfer) inAxfr(id uint16, c chan *Envelope) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if first {
|
if first {
|
||||||
|
if in.Rcode != RcodeSuccess {
|
||||||
|
c <- &Envelope{in.Answer, &Error{err: fmt.Sprintf(errXFR, in.Rcode)}}
|
||||||
|
return
|
||||||
|
}
|
||||||
if !isSOAFirst(in) {
|
if !isSOAFirst(in) {
|
||||||
c <- &Envelope{in.Answer, ErrSoa}
|
c <- &Envelope{in.Answer, ErrSoa}
|
||||||
return
|
return
|
||||||
|
@ -126,6 +131,10 @@ func (t *Transfer) inIxfr(id uint16, c chan *Envelope) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if first {
|
if first {
|
||||||
|
if in.Rcode != RcodeSuccess {
|
||||||
|
c <- &Envelope{in.Answer, &Error{err: fmt.Sprintf(errXFR, in.Rcode)}}
|
||||||
|
return
|
||||||
|
}
|
||||||
// A single SOA RR signals "no changes"
|
// A single SOA RR signals "no changes"
|
||||||
if len(in.Answer) == 1 && isSOAFirst(in) {
|
if len(in.Answer) == 1 && isSOAFirst(in) {
|
||||||
c <- &Envelope{in.Answer, nil}
|
c <- &Envelope{in.Answer, nil}
|
||||||
|
@ -242,3 +251,5 @@ func isSOALast(in *Msg) bool {
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const errXFR = "bad xfr rcode: %d"
|
||||||
|
|
|
@ -0,0 +1,119 @@
|
||||||
|
// *** DO NOT MODIFY ***
|
||||||
|
// AUTOGENERATED BY go generate from compress_generate.go
|
||||||
|
|
||||||
|
package dns
|
||||||
|
|
||||||
|
func compressionLenHelperType(c map[string]int, r RR) {
|
||||||
|
switch x := r.(type) {
|
||||||
|
case *PTR:
|
||||||
|
compressionLenHelper(c, x.Ptr)
|
||||||
|
case *SOA:
|
||||||
|
compressionLenHelper(c, x.Ns)
|
||||||
|
compressionLenHelper(c, x.Mbox)
|
||||||
|
case *AFSDB:
|
||||||
|
compressionLenHelper(c, x.Hostname)
|
||||||
|
case *HIP:
|
||||||
|
for i := range x.RendezvousServers {
|
||||||
|
compressionLenHelper(c, x.RendezvousServers[i])
|
||||||
|
}
|
||||||
|
case *LP:
|
||||||
|
compressionLenHelper(c, x.Fqdn)
|
||||||
|
case *CNAME:
|
||||||
|
compressionLenHelper(c, x.Target)
|
||||||
|
case *MB:
|
||||||
|
compressionLenHelper(c, x.Mb)
|
||||||
|
case *RP:
|
||||||
|
compressionLenHelper(c, x.Mbox)
|
||||||
|
compressionLenHelper(c, x.Txt)
|
||||||
|
case *RRSIG:
|
||||||
|
compressionLenHelper(c, x.SignerName)
|
||||||
|
case *MF:
|
||||||
|
compressionLenHelper(c, x.Mf)
|
||||||
|
case *MINFO:
|
||||||
|
compressionLenHelper(c, x.Rmail)
|
||||||
|
compressionLenHelper(c, x.Email)
|
||||||
|
case *SIG:
|
||||||
|
compressionLenHelper(c, x.SignerName)
|
||||||
|
case *SRV:
|
||||||
|
compressionLenHelper(c, x.Target)
|
||||||
|
case *TSIG:
|
||||||
|
compressionLenHelper(c, x.Algorithm)
|
||||||
|
case *KX:
|
||||||
|
compressionLenHelper(c, x.Exchanger)
|
||||||
|
case *MG:
|
||||||
|
compressionLenHelper(c, x.Mg)
|
||||||
|
case *NSAPPTR:
|
||||||
|
compressionLenHelper(c, x.Ptr)
|
||||||
|
case *PX:
|
||||||
|
compressionLenHelper(c, x.Map822)
|
||||||
|
compressionLenHelper(c, x.Mapx400)
|
||||||
|
case *DNAME:
|
||||||
|
compressionLenHelper(c, x.Target)
|
||||||
|
case *MR:
|
||||||
|
compressionLenHelper(c, x.Mr)
|
||||||
|
case *MX:
|
||||||
|
compressionLenHelper(c, x.Mx)
|
||||||
|
case *TKEY:
|
||||||
|
compressionLenHelper(c, x.Algorithm)
|
||||||
|
case *NSEC:
|
||||||
|
compressionLenHelper(c, x.NextDomain)
|
||||||
|
case *TALINK:
|
||||||
|
compressionLenHelper(c, x.PreviousName)
|
||||||
|
compressionLenHelper(c, x.NextName)
|
||||||
|
case *MD:
|
||||||
|
compressionLenHelper(c, x.Md)
|
||||||
|
case *NAPTR:
|
||||||
|
compressionLenHelper(c, x.Replacement)
|
||||||
|
case *NS:
|
||||||
|
compressionLenHelper(c, x.Ns)
|
||||||
|
case *RT:
|
||||||
|
compressionLenHelper(c, x.Host)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func compressionLenSearchType(c map[string]int, r RR) (int, bool) {
|
||||||
|
switch x := r.(type) {
|
||||||
|
case *MG:
|
||||||
|
k1, ok1 := compressionLenSearch(c, x.Mg)
|
||||||
|
return k1, ok1
|
||||||
|
case *PTR:
|
||||||
|
k1, ok1 := compressionLenSearch(c, x.Ptr)
|
||||||
|
return k1, ok1
|
||||||
|
case *AFSDB:
|
||||||
|
k1, ok1 := compressionLenSearch(c, x.Hostname)
|
||||||
|
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 *NS:
|
||||||
|
k1, ok1 := compressionLenSearch(c, x.Ns)
|
||||||
|
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
|
||||||
|
case *CNAME:
|
||||||
|
k1, ok1 := compressionLenSearch(c, x.Target)
|
||||||
|
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
|
||||||
|
}
|
||||||
|
return 0, false
|
||||||
|
}
|
|
@ -61,6 +61,20 @@ func (rr *ANY) pack(msg []byte, off int, compression map[string]int, compress bo
|
||||||
return off, nil
|
return off, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (rr *AVC) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
|
||||||
|
off, err := rr.Hdr.pack(msg, off, compression, compress)
|
||||||
|
if err != nil {
|
||||||
|
return off, err
|
||||||
|
}
|
||||||
|
headerEnd := off
|
||||||
|
off, err = packStringTxt(rr.Txt, msg, off)
|
||||||
|
if err != nil {
|
||||||
|
return off, err
|
||||||
|
}
|
||||||
|
rr.Header().Rdlength = uint16(off - headerEnd)
|
||||||
|
return off, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (rr *CAA) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
|
func (rr *CAA) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
|
||||||
off, err := rr.Hdr.pack(msg, off, compression, compress)
|
off, err := rr.Hdr.pack(msg, off, compression, compress)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -221,7 +235,7 @@ func (rr *DNAME) pack(msg []byte, off int, compression map[string]int, compress
|
||||||
return off, err
|
return off, err
|
||||||
}
|
}
|
||||||
headerEnd := off
|
headerEnd := off
|
||||||
off, err = PackDomainName(rr.Target, msg, off, compression, compress)
|
off, err = PackDomainName(rr.Target, msg, off, compression, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return off, err
|
return off, err
|
||||||
}
|
}
|
||||||
|
@ -447,7 +461,7 @@ func (rr *KX) pack(msg []byte, off int, compression map[string]int, compress boo
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return off, err
|
return off, err
|
||||||
}
|
}
|
||||||
off, err = PackDomainName(rr.Exchanger, msg, off, compression, compress)
|
off, err = PackDomainName(rr.Exchanger, msg, off, compression, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return off, err
|
return off, err
|
||||||
}
|
}
|
||||||
|
@ -539,7 +553,7 @@ func (rr *LP) pack(msg []byte, off int, compression map[string]int, compress boo
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return off, err
|
return off, err
|
||||||
}
|
}
|
||||||
off, err = PackDomainName(rr.Fqdn, msg, off, compression, compress)
|
off, err = PackDomainName(rr.Fqdn, msg, off, compression, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return off, err
|
return off, err
|
||||||
}
|
}
|
||||||
|
@ -679,7 +693,7 @@ func (rr *NAPTR) pack(msg []byte, off int, compression map[string]int, compress
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return off, err
|
return off, err
|
||||||
}
|
}
|
||||||
off, err = PackDomainName(rr.Replacement, msg, off, compression, compress)
|
off, err = PackDomainName(rr.Replacement, msg, off, compression, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return off, err
|
return off, err
|
||||||
}
|
}
|
||||||
|
@ -753,7 +767,7 @@ func (rr *NSAPPTR) pack(msg []byte, off int, compression map[string]int, compres
|
||||||
return off, err
|
return off, err
|
||||||
}
|
}
|
||||||
headerEnd := off
|
headerEnd := off
|
||||||
off, err = PackDomainName(rr.Ptr, msg, off, compression, compress)
|
off, err = PackDomainName(rr.Ptr, msg, off, compression, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return off, err
|
return off, err
|
||||||
}
|
}
|
||||||
|
@ -767,7 +781,7 @@ func (rr *NSEC) pack(msg []byte, off int, compression map[string]int, compress b
|
||||||
return off, err
|
return off, err
|
||||||
}
|
}
|
||||||
headerEnd := off
|
headerEnd := off
|
||||||
off, err = PackDomainName(rr.NextDomain, msg, off, compression, compress)
|
off, err = PackDomainName(rr.NextDomain, msg, off, compression, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return off, err
|
return off, err
|
||||||
}
|
}
|
||||||
|
@ -801,10 +815,12 @@ func (rr *NSEC3) pack(msg []byte, off int, compression map[string]int, compress
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return off, err
|
return off, err
|
||||||
}
|
}
|
||||||
if rr.Salt == "-" { /* do nothing, empty salt */
|
// Only pack salt if value is not "-", i.e. empty
|
||||||
}
|
if rr.Salt != "-" {
|
||||||
if err != nil {
|
off, err = packStringHex(rr.Salt, msg, off)
|
||||||
return off, err
|
if err != nil {
|
||||||
|
return off, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
off, err = packUint8(rr.HashLength, msg, off)
|
off, err = packUint8(rr.HashLength, msg, off)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -844,10 +860,12 @@ func (rr *NSEC3PARAM) pack(msg []byte, off int, compression map[string]int, comp
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return off, err
|
return off, err
|
||||||
}
|
}
|
||||||
if rr.Salt == "-" { /* do nothing, empty salt */
|
// Only pack salt if value is not "-", i.e. empty
|
||||||
}
|
if rr.Salt != "-" {
|
||||||
if err != nil {
|
off, err = packStringHex(rr.Salt, msg, off)
|
||||||
return off, err
|
if err != nil {
|
||||||
|
return off, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
rr.Header().Rdlength = uint16(off - headerEnd)
|
rr.Header().Rdlength = uint16(off - headerEnd)
|
||||||
return off, nil
|
return off, nil
|
||||||
|
@ -905,11 +923,11 @@ func (rr *PX) pack(msg []byte, off int, compression map[string]int, compress boo
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return off, err
|
return off, err
|
||||||
}
|
}
|
||||||
off, err = PackDomainName(rr.Map822, msg, off, compression, compress)
|
off, err = PackDomainName(rr.Map822, msg, off, compression, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return off, err
|
return off, err
|
||||||
}
|
}
|
||||||
off, err = PackDomainName(rr.Mapx400, msg, off, compression, compress)
|
off, err = PackDomainName(rr.Mapx400, msg, off, compression, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return off, err
|
return off, err
|
||||||
}
|
}
|
||||||
|
@ -963,11 +981,11 @@ func (rr *RP) pack(msg []byte, off int, compression map[string]int, compress boo
|
||||||
return off, err
|
return off, err
|
||||||
}
|
}
|
||||||
headerEnd := off
|
headerEnd := off
|
||||||
off, err = PackDomainName(rr.Mbox, msg, off, compression, compress)
|
off, err = PackDomainName(rr.Mbox, msg, off, compression, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return off, err
|
return off, err
|
||||||
}
|
}
|
||||||
off, err = PackDomainName(rr.Txt, msg, off, compression, compress)
|
off, err = PackDomainName(rr.Txt, msg, off, compression, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return off, err
|
return off, err
|
||||||
}
|
}
|
||||||
|
@ -1009,7 +1027,7 @@ func (rr *RRSIG) pack(msg []byte, off int, compression map[string]int, compress
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return off, err
|
return off, err
|
||||||
}
|
}
|
||||||
off, err = PackDomainName(rr.SignerName, msg, off, compression, compress)
|
off, err = PackDomainName(rr.SignerName, msg, off, compression, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return off, err
|
return off, err
|
||||||
}
|
}
|
||||||
|
@ -1073,7 +1091,7 @@ func (rr *SIG) pack(msg []byte, off int, compression map[string]int, compress bo
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return off, err
|
return off, err
|
||||||
}
|
}
|
||||||
off, err = PackDomainName(rr.SignerName, msg, off, compression, compress)
|
off, err = PackDomainName(rr.SignerName, msg, off, compression, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return off, err
|
return off, err
|
||||||
}
|
}
|
||||||
|
@ -1085,6 +1103,32 @@ func (rr *SIG) pack(msg []byte, off int, compression map[string]int, compress bo
|
||||||
return off, nil
|
return off, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (rr *SMIMEA) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
|
||||||
|
off, err := rr.Hdr.pack(msg, off, compression, compress)
|
||||||
|
if err != nil {
|
||||||
|
return off, err
|
||||||
|
}
|
||||||
|
headerEnd := off
|
||||||
|
off, err = packUint8(rr.Usage, msg, off)
|
||||||
|
if err != nil {
|
||||||
|
return off, err
|
||||||
|
}
|
||||||
|
off, err = packUint8(rr.Selector, msg, off)
|
||||||
|
if err != nil {
|
||||||
|
return off, err
|
||||||
|
}
|
||||||
|
off, err = packUint8(rr.MatchingType, msg, off)
|
||||||
|
if err != nil {
|
||||||
|
return off, err
|
||||||
|
}
|
||||||
|
off, err = packStringHex(rr.Certificate, msg, off)
|
||||||
|
if err != nil {
|
||||||
|
return off, err
|
||||||
|
}
|
||||||
|
rr.Header().Rdlength = uint16(off - headerEnd)
|
||||||
|
return off, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (rr *SOA) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
|
func (rr *SOA) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
|
||||||
off, err := rr.Hdr.pack(msg, off, compression, compress)
|
off, err := rr.Hdr.pack(msg, off, compression, compress)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -1155,7 +1199,7 @@ func (rr *SRV) pack(msg []byte, off int, compression map[string]int, compress bo
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return off, err
|
return off, err
|
||||||
}
|
}
|
||||||
off, err = PackDomainName(rr.Target, msg, off, compression, compress)
|
off, err = PackDomainName(rr.Target, msg, off, compression, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return off, err
|
return off, err
|
||||||
}
|
}
|
||||||
|
@ -1217,11 +1261,11 @@ func (rr *TALINK) pack(msg []byte, off int, compression map[string]int, compress
|
||||||
return off, err
|
return off, err
|
||||||
}
|
}
|
||||||
headerEnd := off
|
headerEnd := off
|
||||||
off, err = PackDomainName(rr.PreviousName, msg, off, compression, compress)
|
off, err = PackDomainName(rr.PreviousName, msg, off, compression, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return off, err
|
return off, err
|
||||||
}
|
}
|
||||||
off, err = PackDomainName(rr.NextName, msg, off, compression, compress)
|
off, err = PackDomainName(rr.NextName, msg, off, compression, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return off, err
|
return off, err
|
||||||
}
|
}
|
||||||
|
@ -1235,7 +1279,7 @@ func (rr *TKEY) pack(msg []byte, off int, compression map[string]int, compress b
|
||||||
return off, err
|
return off, err
|
||||||
}
|
}
|
||||||
headerEnd := off
|
headerEnd := off
|
||||||
off, err = PackDomainName(rr.Algorithm, msg, off, compression, compress)
|
off, err = PackDomainName(rr.Algorithm, msg, off, compression, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return off, err
|
return off, err
|
||||||
}
|
}
|
||||||
|
@ -1307,7 +1351,7 @@ func (rr *TSIG) pack(msg []byte, off int, compression map[string]int, compress b
|
||||||
return off, err
|
return off, err
|
||||||
}
|
}
|
||||||
headerEnd := off
|
headerEnd := off
|
||||||
off, err = PackDomainName(rr.Algorithm, msg, off, compression, compress)
|
off, err = PackDomainName(rr.Algorithm, msg, off, compression, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return off, err
|
return off, err
|
||||||
}
|
}
|
||||||
|
@ -1498,6 +1542,23 @@ func unpackANY(h RR_Header, msg []byte, off int) (RR, int, error) {
|
||||||
return rr, off, err
|
return rr, off, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func unpackAVC(h RR_Header, msg []byte, off int) (RR, int, error) {
|
||||||
|
rr := new(AVC)
|
||||||
|
rr.Hdr = h
|
||||||
|
if noRdata(h) {
|
||||||
|
return rr, off, nil
|
||||||
|
}
|
||||||
|
var err error
|
||||||
|
rdStart := off
|
||||||
|
_ = rdStart
|
||||||
|
|
||||||
|
rr.Txt, off, err = unpackStringTxt(msg, off)
|
||||||
|
if err != nil {
|
||||||
|
return rr, off, err
|
||||||
|
}
|
||||||
|
return rr, off, err
|
||||||
|
}
|
||||||
|
|
||||||
func unpackCAA(h RR_Header, msg []byte, off int) (RR, int, error) {
|
func unpackCAA(h RR_Header, msg []byte, off int) (RR, int, error) {
|
||||||
rr := new(CAA)
|
rr := new(CAA)
|
||||||
rr.Hdr = h
|
rr.Hdr = h
|
||||||
|
@ -2907,6 +2968,44 @@ func unpackSIG(h RR_Header, msg []byte, off int) (RR, int, error) {
|
||||||
return rr, off, err
|
return rr, off, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func unpackSMIMEA(h RR_Header, msg []byte, off int) (RR, int, error) {
|
||||||
|
rr := new(SMIMEA)
|
||||||
|
rr.Hdr = h
|
||||||
|
if noRdata(h) {
|
||||||
|
return rr, off, nil
|
||||||
|
}
|
||||||
|
var err error
|
||||||
|
rdStart := off
|
||||||
|
_ = rdStart
|
||||||
|
|
||||||
|
rr.Usage, off, err = unpackUint8(msg, off)
|
||||||
|
if err != nil {
|
||||||
|
return rr, off, err
|
||||||
|
}
|
||||||
|
if off == len(msg) {
|
||||||
|
return rr, off, nil
|
||||||
|
}
|
||||||
|
rr.Selector, off, err = unpackUint8(msg, off)
|
||||||
|
if err != nil {
|
||||||
|
return rr, off, err
|
||||||
|
}
|
||||||
|
if off == len(msg) {
|
||||||
|
return rr, off, nil
|
||||||
|
}
|
||||||
|
rr.MatchingType, off, err = unpackUint8(msg, off)
|
||||||
|
if err != nil {
|
||||||
|
return rr, off, err
|
||||||
|
}
|
||||||
|
if off == len(msg) {
|
||||||
|
return rr, off, nil
|
||||||
|
}
|
||||||
|
rr.Certificate, off, err = unpackStringHex(msg, off, rdStart+int(rr.Hdr.Rdlength))
|
||||||
|
if err != nil {
|
||||||
|
return rr, off, err
|
||||||
|
}
|
||||||
|
return rr, off, err
|
||||||
|
}
|
||||||
|
|
||||||
func unpackSOA(h RR_Header, msg []byte, off int) (RR, int, error) {
|
func unpackSOA(h RR_Header, msg []byte, off int) (RR, int, error) {
|
||||||
rr := new(SOA)
|
rr := new(SOA)
|
||||||
rr.Hdr = h
|
rr.Hdr = h
|
||||||
|
@ -3399,6 +3498,7 @@ var typeToUnpack = map[uint16]func(RR_Header, []byte, int) (RR, int, error){
|
||||||
TypeAAAA: unpackAAAA,
|
TypeAAAA: unpackAAAA,
|
||||||
TypeAFSDB: unpackAFSDB,
|
TypeAFSDB: unpackAFSDB,
|
||||||
TypeANY: unpackANY,
|
TypeANY: unpackANY,
|
||||||
|
TypeAVC: unpackAVC,
|
||||||
TypeCAA: unpackCAA,
|
TypeCAA: unpackCAA,
|
||||||
TypeCDNSKEY: unpackCDNSKEY,
|
TypeCDNSKEY: unpackCDNSKEY,
|
||||||
TypeCDS: unpackCDS,
|
TypeCDS: unpackCDS,
|
||||||
|
@ -3447,6 +3547,7 @@ var typeToUnpack = map[uint16]func(RR_Header, []byte, int) (RR, int, error){
|
||||||
TypeRRSIG: unpackRRSIG,
|
TypeRRSIG: unpackRRSIG,
|
||||||
TypeRT: unpackRT,
|
TypeRT: unpackRT,
|
||||||
TypeSIG: unpackSIG,
|
TypeSIG: unpackSIG,
|
||||||
|
TypeSMIMEA: unpackSMIMEA,
|
||||||
TypeSOA: unpackSOA,
|
TypeSOA: unpackSOA,
|
||||||
TypeSPF: unpackSPF,
|
TypeSPF: unpackSPF,
|
||||||
TypeSRV: unpackSRV,
|
TypeSRV: unpackSRV,
|
||||||
|
|
|
@ -14,6 +14,7 @@ var TypeToRR = map[uint16]func() RR{
|
||||||
TypeAAAA: func() RR { return new(AAAA) },
|
TypeAAAA: func() RR { return new(AAAA) },
|
||||||
TypeAFSDB: func() RR { return new(AFSDB) },
|
TypeAFSDB: func() RR { return new(AFSDB) },
|
||||||
TypeANY: func() RR { return new(ANY) },
|
TypeANY: func() RR { return new(ANY) },
|
||||||
|
TypeAVC: func() RR { return new(AVC) },
|
||||||
TypeCAA: func() RR { return new(CAA) },
|
TypeCAA: func() RR { return new(CAA) },
|
||||||
TypeCDNSKEY: func() RR { return new(CDNSKEY) },
|
TypeCDNSKEY: func() RR { return new(CDNSKEY) },
|
||||||
TypeCDS: func() RR { return new(CDS) },
|
TypeCDS: func() RR { return new(CDS) },
|
||||||
|
@ -62,6 +63,7 @@ var TypeToRR = map[uint16]func() RR{
|
||||||
TypeRRSIG: func() RR { return new(RRSIG) },
|
TypeRRSIG: func() RR { return new(RRSIG) },
|
||||||
TypeRT: func() RR { return new(RT) },
|
TypeRT: func() RR { return new(RT) },
|
||||||
TypeSIG: func() RR { return new(SIG) },
|
TypeSIG: func() RR { return new(SIG) },
|
||||||
|
TypeSMIMEA: func() RR { return new(SMIMEA) },
|
||||||
TypeSOA: func() RR { return new(SOA) },
|
TypeSOA: func() RR { return new(SOA) },
|
||||||
TypeSPF: func() RR { return new(SPF) },
|
TypeSPF: func() RR { return new(SPF) },
|
||||||
TypeSRV: func() RR { return new(SRV) },
|
TypeSRV: func() RR { return new(SRV) },
|
||||||
|
@ -85,6 +87,7 @@ var TypeToString = map[uint16]string{
|
||||||
TypeAFSDB: "AFSDB",
|
TypeAFSDB: "AFSDB",
|
||||||
TypeANY: "ANY",
|
TypeANY: "ANY",
|
||||||
TypeATMA: "ATMA",
|
TypeATMA: "ATMA",
|
||||||
|
TypeAVC: "AVC",
|
||||||
TypeAXFR: "AXFR",
|
TypeAXFR: "AXFR",
|
||||||
TypeCAA: "CAA",
|
TypeCAA: "CAA",
|
||||||
TypeCDNSKEY: "CDNSKEY",
|
TypeCDNSKEY: "CDNSKEY",
|
||||||
|
@ -141,6 +144,7 @@ var TypeToString = map[uint16]string{
|
||||||
TypeRT: "RT",
|
TypeRT: "RT",
|
||||||
TypeReserved: "Reserved",
|
TypeReserved: "Reserved",
|
||||||
TypeSIG: "SIG",
|
TypeSIG: "SIG",
|
||||||
|
TypeSMIMEA: "SMIMEA",
|
||||||
TypeSOA: "SOA",
|
TypeSOA: "SOA",
|
||||||
TypeSPF: "SPF",
|
TypeSPF: "SPF",
|
||||||
TypeSRV: "SRV",
|
TypeSRV: "SRV",
|
||||||
|
@ -164,6 +168,7 @@ func (rr *A) Header() *RR_Header { return &rr.Hdr }
|
||||||
func (rr *AAAA) Header() *RR_Header { return &rr.Hdr }
|
func (rr *AAAA) Header() *RR_Header { return &rr.Hdr }
|
||||||
func (rr *AFSDB) Header() *RR_Header { return &rr.Hdr }
|
func (rr *AFSDB) Header() *RR_Header { return &rr.Hdr }
|
||||||
func (rr *ANY) Header() *RR_Header { return &rr.Hdr }
|
func (rr *ANY) Header() *RR_Header { return &rr.Hdr }
|
||||||
|
func (rr *AVC) Header() *RR_Header { return &rr.Hdr }
|
||||||
func (rr *CAA) Header() *RR_Header { return &rr.Hdr }
|
func (rr *CAA) Header() *RR_Header { return &rr.Hdr }
|
||||||
func (rr *CDNSKEY) Header() *RR_Header { return &rr.Hdr }
|
func (rr *CDNSKEY) Header() *RR_Header { return &rr.Hdr }
|
||||||
func (rr *CDS) Header() *RR_Header { return &rr.Hdr }
|
func (rr *CDS) Header() *RR_Header { return &rr.Hdr }
|
||||||
|
@ -213,6 +218,7 @@ func (rr *RP) Header() *RR_Header { return &rr.Hdr }
|
||||||
func (rr *RRSIG) Header() *RR_Header { return &rr.Hdr }
|
func (rr *RRSIG) Header() *RR_Header { return &rr.Hdr }
|
||||||
func (rr *RT) Header() *RR_Header { return &rr.Hdr }
|
func (rr *RT) Header() *RR_Header { return &rr.Hdr }
|
||||||
func (rr *SIG) Header() *RR_Header { return &rr.Hdr }
|
func (rr *SIG) Header() *RR_Header { return &rr.Hdr }
|
||||||
|
func (rr *SMIMEA) Header() *RR_Header { return &rr.Hdr }
|
||||||
func (rr *SOA) Header() *RR_Header { return &rr.Hdr }
|
func (rr *SOA) Header() *RR_Header { return &rr.Hdr }
|
||||||
func (rr *SPF) Header() *RR_Header { return &rr.Hdr }
|
func (rr *SPF) Header() *RR_Header { return &rr.Hdr }
|
||||||
func (rr *SRV) Header() *RR_Header { return &rr.Hdr }
|
func (rr *SRV) Header() *RR_Header { return &rr.Hdr }
|
||||||
|
@ -249,9 +255,16 @@ func (rr *ANY) len() int {
|
||||||
l := rr.Hdr.len()
|
l := rr.Hdr.len()
|
||||||
return l
|
return l
|
||||||
}
|
}
|
||||||
|
func (rr *AVC) len() int {
|
||||||
|
l := rr.Hdr.len()
|
||||||
|
for _, x := range rr.Txt {
|
||||||
|
l += len(x) + 1
|
||||||
|
}
|
||||||
|
return l
|
||||||
|
}
|
||||||
func (rr *CAA) len() int {
|
func (rr *CAA) len() int {
|
||||||
l := rr.Hdr.len()
|
l := rr.Hdr.len()
|
||||||
l += 1 // 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
|
||||||
|
@ -260,7 +273,7 @@ func (rr *CERT) len() int {
|
||||||
l := rr.Hdr.len()
|
l := rr.Hdr.len()
|
||||||
l += 2 // Type
|
l += 2 // Type
|
||||||
l += 2 // KeyTag
|
l += 2 // KeyTag
|
||||||
l += 1 // Algorithm
|
l++ // Algorithm
|
||||||
l += base64.StdEncoding.DecodedLen(len(rr.Certificate))
|
l += base64.StdEncoding.DecodedLen(len(rr.Certificate))
|
||||||
return l
|
return l
|
||||||
}
|
}
|
||||||
|
@ -282,16 +295,16 @@ func (rr *DNAME) len() int {
|
||||||
func (rr *DNSKEY) len() int {
|
func (rr *DNSKEY) len() int {
|
||||||
l := rr.Hdr.len()
|
l := rr.Hdr.len()
|
||||||
l += 2 // Flags
|
l += 2 // Flags
|
||||||
l += 1 // Protocol
|
l++ // Protocol
|
||||||
l += 1 // 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() int {
|
||||||
l := rr.Hdr.len()
|
l := rr.Hdr.len()
|
||||||
l += 2 // KeyTag
|
l += 2 // KeyTag
|
||||||
l += 1 // Algorithm
|
l++ // Algorithm
|
||||||
l += 1 // DigestType
|
l++ // DigestType
|
||||||
l += len(rr.Digest)/2 + 1
|
l += len(rr.Digest)/2 + 1
|
||||||
return l
|
return l
|
||||||
}
|
}
|
||||||
|
@ -330,8 +343,8 @@ func (rr *HINFO) len() int {
|
||||||
}
|
}
|
||||||
func (rr *HIP) len() int {
|
func (rr *HIP) len() int {
|
||||||
l := rr.Hdr.len()
|
l := rr.Hdr.len()
|
||||||
l += 1 // HitLength
|
l++ // HitLength
|
||||||
l += 1 // PublicKeyAlgorithm
|
l++ // PublicKeyAlgorithm
|
||||||
l += 2 // PublicKeyLength
|
l += 2 // PublicKeyLength
|
||||||
l += len(rr.Hit)/2 + 1
|
l += len(rr.Hit)/2 + 1
|
||||||
l += base64.StdEncoding.DecodedLen(len(rr.PublicKey))
|
l += base64.StdEncoding.DecodedLen(len(rr.PublicKey))
|
||||||
|
@ -360,10 +373,10 @@ func (rr *L64) len() int {
|
||||||
}
|
}
|
||||||
func (rr *LOC) len() int {
|
func (rr *LOC) len() int {
|
||||||
l := rr.Hdr.len()
|
l := rr.Hdr.len()
|
||||||
l += 1 // Version
|
l++ // Version
|
||||||
l += 1 // Size
|
l++ // Size
|
||||||
l += 1 // HorizPre
|
l++ // HorizPre
|
||||||
l += 1 // VertPre
|
l++ // VertPre
|
||||||
l += 4 // Latitude
|
l += 4 // Latitude
|
||||||
l += 4 // Longitude
|
l += 4 // Longitude
|
||||||
l += 4 // Altitude
|
l += 4 // Altitude
|
||||||
|
@ -452,10 +465,10 @@ func (rr *NSAPPTR) len() int {
|
||||||
}
|
}
|
||||||
func (rr *NSEC3PARAM) len() int {
|
func (rr *NSEC3PARAM) len() int {
|
||||||
l := rr.Hdr.len()
|
l := rr.Hdr.len()
|
||||||
l += 1 // Hash
|
l++ // Hash
|
||||||
l += 1 // Flags
|
l++ // Flags
|
||||||
l += 2 // Iterations
|
l += 2 // Iterations
|
||||||
l += 1 // SaltLength
|
l++ // SaltLength
|
||||||
l += len(rr.Salt)/2 + 1
|
l += len(rr.Salt)/2 + 1
|
||||||
return l
|
return l
|
||||||
}
|
}
|
||||||
|
@ -484,8 +497,8 @@ func (rr *RFC3597) len() int {
|
||||||
func (rr *RKEY) len() int {
|
func (rr *RKEY) len() int {
|
||||||
l := rr.Hdr.len()
|
l := rr.Hdr.len()
|
||||||
l += 2 // Flags
|
l += 2 // Flags
|
||||||
l += 1 // Protocol
|
l++ // Protocol
|
||||||
l += 1 // Algorithm
|
l++ // Algorithm
|
||||||
l += base64.StdEncoding.DecodedLen(len(rr.PublicKey))
|
l += base64.StdEncoding.DecodedLen(len(rr.PublicKey))
|
||||||
return l
|
return l
|
||||||
}
|
}
|
||||||
|
@ -498,8 +511,8 @@ func (rr *RP) len() int {
|
||||||
func (rr *RRSIG) len() int {
|
func (rr *RRSIG) len() int {
|
||||||
l := rr.Hdr.len()
|
l := rr.Hdr.len()
|
||||||
l += 2 // TypeCovered
|
l += 2 // TypeCovered
|
||||||
l += 1 // Algorithm
|
l++ // Algorithm
|
||||||
l += 1 // Labels
|
l++ // Labels
|
||||||
l += 4 // OrigTtl
|
l += 4 // OrigTtl
|
||||||
l += 4 // Expiration
|
l += 4 // Expiration
|
||||||
l += 4 // Inception
|
l += 4 // Inception
|
||||||
|
@ -514,6 +527,14 @@ func (rr *RT) len() int {
|
||||||
l += len(rr.Host) + 1
|
l += len(rr.Host) + 1
|
||||||
return l
|
return l
|
||||||
}
|
}
|
||||||
|
func (rr *SMIMEA) len() int {
|
||||||
|
l := rr.Hdr.len()
|
||||||
|
l++ // Usage
|
||||||
|
l++ // Selector
|
||||||
|
l++ // MatchingType
|
||||||
|
l += len(rr.Certificate)/2 + 1
|
||||||
|
return l
|
||||||
|
}
|
||||||
func (rr *SOA) len() int {
|
func (rr *SOA) len() int {
|
||||||
l := rr.Hdr.len()
|
l := rr.Hdr.len()
|
||||||
l += len(rr.Ns) + 1
|
l += len(rr.Ns) + 1
|
||||||
|
@ -542,16 +563,16 @@ func (rr *SRV) len() int {
|
||||||
}
|
}
|
||||||
func (rr *SSHFP) len() int {
|
func (rr *SSHFP) len() int {
|
||||||
l := rr.Hdr.len()
|
l := rr.Hdr.len()
|
||||||
l += 1 // Algorithm
|
l++ // Algorithm
|
||||||
l += 1 // 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() int {
|
||||||
l := rr.Hdr.len()
|
l := rr.Hdr.len()
|
||||||
l += 2 // KeyTag
|
l += 2 // KeyTag
|
||||||
l += 1 // Algorithm
|
l++ // Algorithm
|
||||||
l += 1 // DigestType
|
l++ // DigestType
|
||||||
l += len(rr.Digest)/2 + 1
|
l += len(rr.Digest)/2 + 1
|
||||||
return l
|
return l
|
||||||
}
|
}
|
||||||
|
@ -576,9 +597,9 @@ func (rr *TKEY) len() int {
|
||||||
}
|
}
|
||||||
func (rr *TLSA) len() int {
|
func (rr *TLSA) len() int {
|
||||||
l := rr.Hdr.len()
|
l := rr.Hdr.len()
|
||||||
l += 1 // Usage
|
l++ // Usage
|
||||||
l += 1 // Selector
|
l++ // Selector
|
||||||
l += 1 // MatchingType
|
l++ // MatchingType
|
||||||
l += len(rr.Certificate)/2 + 1
|
l += len(rr.Certificate)/2 + 1
|
||||||
return l
|
return l
|
||||||
}
|
}
|
||||||
|
@ -638,6 +659,11 @@ func (rr *AFSDB) copy() RR {
|
||||||
func (rr *ANY) copy() RR {
|
func (rr *ANY) copy() RR {
|
||||||
return &ANY{*rr.Hdr.copyHeader()}
|
return &ANY{*rr.Hdr.copyHeader()}
|
||||||
}
|
}
|
||||||
|
func (rr *AVC) copy() RR {
|
||||||
|
Txt := make([]string, len(rr.Txt))
|
||||||
|
copy(Txt, rr.Txt)
|
||||||
|
return &AVC{*rr.Hdr.copyHeader(), 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.copyHeader(), rr.Flag, rr.Tag, rr.Value}
|
||||||
}
|
}
|
||||||
|
@ -780,6 +806,9 @@ func (rr *RRSIG) copy() RR {
|
||||||
func (rr *RT) copy() RR {
|
func (rr *RT) copy() RR {
|
||||||
return &RT{*rr.Hdr.copyHeader(), rr.Preference, rr.Host}
|
return &RT{*rr.Hdr.copyHeader(), rr.Preference, rr.Host}
|
||||||
}
|
}
|
||||||
|
func (rr *SMIMEA) copy() RR {
|
||||||
|
return &SMIMEA{*rr.Hdr.copyHeader(), 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.copyHeader(), rr.Ns, rr.Mbox, rr.Serial, rr.Refresh, rr.Retry, rr.Expire, rr.Minttl}
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,7 +63,7 @@
|
||||||
{"path":"github.com/hashicorp/serf/serf","checksumSHA1":"3WPnGSL9ZK6EmkAE6tEW5SCxrd8=","comment":"v0.7.0-66-g6c4672d","revision":"b84a66cc5575994cb672940d244a2404141688c0","revisionTime":"2017-08-17T21:22:02Z"},
|
{"path":"github.com/hashicorp/serf/serf","checksumSHA1":"3WPnGSL9ZK6EmkAE6tEW5SCxrd8=","comment":"v0.7.0-66-g6c4672d","revision":"b84a66cc5575994cb672940d244a2404141688c0","revisionTime":"2017-08-17T21:22:02Z"},
|
||||||
{"path":"github.com/hashicorp/yamux","checksumSHA1":"ZhK6IO2XN81Y+3RAjTcVm1Ic7oU=","revision":"d1caa6c97c9fc1cc9e83bbe34d0603f9ff0ce8bd","revisionTime":"2016-07-20T23:31:40Z"},
|
{"path":"github.com/hashicorp/yamux","checksumSHA1":"ZhK6IO2XN81Y+3RAjTcVm1Ic7oU=","revision":"d1caa6c97c9fc1cc9e83bbe34d0603f9ff0ce8bd","revisionTime":"2016-07-20T23:31:40Z"},
|
||||||
{"path":"github.com/mattn/go-isatty","checksumSHA1":"xZuhljnmBysJPta/lMyYmJdujCg=","revision":"66b8e73f3f5cda9f96b69efd03dd3d7fc4a5cdb8","revisionTime":"2016-08-06T12:27:52Z"},
|
{"path":"github.com/mattn/go-isatty","checksumSHA1":"xZuhljnmBysJPta/lMyYmJdujCg=","revision":"66b8e73f3f5cda9f96b69efd03dd3d7fc4a5cdb8","revisionTime":"2016-08-06T12:27:52Z"},
|
||||||
{"path":"github.com/miekg/dns","checksumSHA1":"OUZ1FFXyKs+Cfg9M9rmXqqweQck=","revision":"db96a2b759cdef4f11a34506a42eb8d1290c598e","revisionTime":"2016-07-26T03:20:27Z"},
|
{"path":"github.com/miekg/dns","checksumSHA1":"Jo+pItYOocIRdoFL0fc4nHhUEJY=","revision":"bbca4873b326f5dc54bfe31148446d4ed79a5a02","revisionTime":"2017-08-08T22:19:10Z"},
|
||||||
{"path":"github.com/mitchellh/cli","checksumSHA1":"GzfpPGtV2UJH9hFsKwzGjKrhp/A=","revision":"dff723fff508858a44c1f4bd0911f00d73b0202f","revisionTime":"2017-09-05T22:10:09Z"},
|
{"path":"github.com/mitchellh/cli","checksumSHA1":"GzfpPGtV2UJH9hFsKwzGjKrhp/A=","revision":"dff723fff508858a44c1f4bd0911f00d73b0202f","revisionTime":"2017-09-05T22:10:09Z"},
|
||||||
{"path":"github.com/mitchellh/copystructure","checksumSHA1":"86nE93o1VIND0Doe8PuhCXnhUx0=","revision":"cdac8253d00f2ecf0a0b19fbff173a9a72de4f82","revisionTime":"2016-08-04T03:23:30Z"},
|
{"path":"github.com/mitchellh/copystructure","checksumSHA1":"86nE93o1VIND0Doe8PuhCXnhUx0=","revision":"cdac8253d00f2ecf0a0b19fbff173a9a72de4f82","revisionTime":"2016-08-04T03:23:30Z"},
|
||||||
{"path":"github.com/mitchellh/go-homedir","checksumSHA1":"V/quM7+em2ByJbWBLOsEwnY3j/Q=","revision":"b8bc1bf767474819792c23f32d8286a45736f1c6","revisionTime":"2016-12-03T19:45:07Z"},
|
{"path":"github.com/mitchellh/go-homedir","checksumSHA1":"V/quM7+em2ByJbWBLOsEwnY3j/Q=","revision":"b8bc1bf767474819792c23f32d8286a45736f1c6","revisionTime":"2016-12-03T19:45:07Z"},
|
||||||
|
|
Loading…
Reference in New Issue