diff options
Diffstat (limited to 'vendor/github.com/miekg')
26 files changed, 1286 insertions, 707 deletions
diff --git a/vendor/github.com/miekg/dns/CONTRIBUTORS b/vendor/github.com/miekg/dns/CONTRIBUTORS index f77e8a895..5903779d8 100644 --- a/vendor/github.com/miekg/dns/CONTRIBUTORS +++ b/vendor/github.com/miekg/dns/CONTRIBUTORS @@ -7,3 +7,4 @@ Marek Majkowski Peter van Dijk Omri Bahumi Alex Sergeyev +James Hartig diff --git a/vendor/github.com/miekg/dns/client.go b/vendor/github.com/miekg/dns/client.go index 1c14a19d8..359a0ab8f 100644 --- a/vendor/github.com/miekg/dns/client.go +++ b/vendor/github.com/miekg/dns/client.go @@ -9,6 +9,7 @@ import ( "encoding/binary" "io" "net" + "strings" "time" ) @@ -27,11 +28,15 @@ type Conn struct { // A Client defines parameters for a DNS client. type Client struct { - Net string // if "tcp" or "tcp-tls" (DNS over TLS) a TCP query will be initiated, otherwise an UDP one (default is "" for UDP) - UDPSize uint16 // minimum receive buffer for UDP messages - TLSConfig *tls.Config // TLS connection configuration - Timeout time.Duration // a cumulative timeout for dial, write and read, defaults to 0 (disabled) - overrides DialTimeout, ReadTimeout and WriteTimeout when non-zero - DialTimeout time.Duration // net.DialTimeout, defaults to 2 seconds - overridden by Timeout when that value is non-zero + Net string // if "tcp" or "tcp-tls" (DNS over TLS) a TCP query will be initiated, otherwise an UDP one (default is "" for UDP) + UDPSize uint16 // minimum receive buffer for UDP messages + TLSConfig *tls.Config // TLS connection configuration + Dialer *net.Dialer // a net.Dialer used to set local address, timeouts and more + // Timeout is a cumulative timeout for dial, write and read, defaults to 0 (disabled) - overrides DialTimeout, ReadTimeout, + // WriteTimeout when non-zero. Can be overridden with net.Dialer.Timeout (see Client.ExchangeWithDialer and + // Client.Dialer) or context.Context.Deadline (see the deprecated ExchangeContext) + Timeout time.Duration + DialTimeout time.Duration // net.DialTimeout, defaults to 2 seconds, or net.Dialer.Timeout if expiring earlier - overridden by Timeout when that value is non-zero ReadTimeout time.Duration // net.Conn.SetReadTimeout value for connections, defaults to 2 seconds - overridden by Timeout when that value is non-zero WriteTimeout time.Duration // net.Conn.SetWriteTimeout value for connections, defaults to 2 seconds - overridden by Timeout when that value is non-zero TsigSecret map[string]string // secret(s) for Tsig map[<zonename>]<base64 secret>, zonename must be fully qualified @@ -44,91 +49,74 @@ type Client struct { // will it fall back to TCP in case of truncation. // See client.Exchange for more information on setting larger buffer sizes. func Exchange(m *Msg, a string) (r *Msg, err error) { - var co *Conn - co, err = DialTimeout("udp", a, dnsTimeout) - if err != nil { - return nil, err - } - - defer co.Close() + client := Client{Net: "udp"} + r, _, err = client.Exchange(m, a) + return r, err +} - opt := m.IsEdns0() - // If EDNS0 is used use that for size. - if opt != nil && opt.UDPSize() >= MinMsgSize { - co.UDPSize = opt.UDPSize() +func (c *Client) dialTimeout() time.Duration { + if c.Timeout != 0 { + return c.Timeout } - - co.SetWriteDeadline(time.Now().Add(dnsTimeout)) - if err = co.WriteMsg(m); err != nil { - return nil, err + if c.DialTimeout != 0 { + return c.DialTimeout } + return dnsTimeout +} - co.SetReadDeadline(time.Now().Add(dnsTimeout)) - r, err = co.ReadMsg() - if err == nil && r.Id != m.Id { - err = ErrId +func (c *Client) readTimeout() time.Duration { + if c.ReadTimeout != 0 { + return c.ReadTimeout } - return r, err + return dnsTimeout } -// 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 +func (c *Client) writeTimeout() time.Duration { + if c.WriteTimeout != 0 { + return c.WriteTimeout } + return dnsTimeout +} - 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() +func (c *Client) Dial(address string) (conn *Conn, err error) { + // create a new dialer with the appropriate timeout + var d net.Dialer + if c.Dialer == nil { + d = net.Dialer{} + } else { + d = net.Dialer(*c.Dialer) } + d.Timeout = c.getTimeoutForRequest(c.writeTimeout()) - co.SetWriteDeadline(deadline) - if err = co.WriteMsg(m); err != nil { - return nil, err - } + network := "udp" + useTLS := false - co.SetReadDeadline(deadline) - r, err = co.ReadMsg() - if err == nil && r.Id != m.Id { - err = ErrId + switch c.Net { + case "tcp-tls": + network = "tcp" + useTLS = true + case "tcp4-tls": + network = "tcp4" + useTLS = true + case "tcp6-tls": + network = "tcp6" + useTLS = true + default: + if c.Net != "" { + network = c.Net + } } - return r, err -} -// 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. -// This function is going away, but can easily be mimicked: -// -// co := &dns.Conn{Conn: c} // c is your net.Conn -// co.WriteMsg(m) -// in, _ := co.ReadMsg() -// co.Close() -// -func ExchangeConn(c net.Conn, m *Msg) (r *Msg, err error) { - println("dns: this function is deprecated") - co := new(Conn) - co.Conn = c - if err = co.WriteMsg(m); err != nil { - return nil, err + conn = new(Conn) + if useTLS { + conn.Conn, err = tls.DialWithDialer(&d, network, address, c.TLSConfig) + } else { + conn.Conn, err = d.Dial(network, address) } - r, err = co.ReadMsg() - if err == nil && r.Id != m.Id { - err = ErrId + if err != nil { + return nil, err } - return r, err + return conn, nil } // Exchange performs a synchronous query. It sends the message m to the address @@ -142,22 +130,14 @@ func ExchangeConn(c net.Conn, m *Msg) (r *Msg, err error) { // It is up to the caller to create a message that allows for larger responses to be // returned. Specifically this means adding an EDNS0 OPT RR that will advertise a larger // buffer, see SetEdns0. Messages without an OPT RR will fallback to the historic limit -// of 512 bytes. -func (c *Client) Exchange(m *Msg, a string) (r *Msg, rtt time.Duration, err error) { - 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) { +// of 512 bytes +// To specify a local address or a timeout, the caller has to set the `Client.Dialer` +// attribute appropriately +func (c *Client) Exchange(m *Msg, address string) (r *Msg, rtt time.Duration, err error) { if !c.SingleInflight { - return c.exchange(ctx, m, a) + return c.exchange(m, address) } - // This adds a bunch of garbage, TODO(miek). + t := "nop" if t1, ok := TypeToString[m.Question[0].Qtype]; ok { t = t1 @@ -167,75 +147,18 @@ func (c *Client) ExchangeContext(ctx context.Context, m *Msg, a string) ( cl = cl1 } r, rtt, err, shared := c.group.Do(m.Question[0].Name+t+cl, func() (*Msg, time.Duration, error) { - return c.exchange(ctx, m, a) + return c.exchange(m, address) }) if r != nil && shared { r = r.Copy() } - if err != nil { - return r, rtt, err - } - return r, rtt, nil -} - -func (c *Client) dialTimeout() time.Duration { - if c.Timeout != 0 { - return c.Timeout - } - if c.DialTimeout != 0 { - return c.DialTimeout - } - return dnsTimeout + return r, rtt, err } -func (c *Client) readTimeout() time.Duration { - if c.ReadTimeout != 0 { - return c.ReadTimeout - } - return dnsTimeout -} - -func (c *Client) writeTimeout() time.Duration { - if c.WriteTimeout != 0 { - return c.WriteTimeout - } - return dnsTimeout -} - -func (c *Client) exchange(ctx context.Context, 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) { var co *Conn - network := "udp" - tls := false - - switch c.Net { - case "tcp-tls": - network = "tcp" - tls = true - case "tcp4-tls": - network = "tcp4" - tls = true - case "tcp6-tls": - network = "tcp6" - tls = true - default: - if c.Net != "" { - network = c.Net - } - } - - var deadline time.Time - if c.Timeout != 0 { - deadline = time.Now().Add(c.Timeout) - } - - dialDeadline := deadlineOrTimeoutOrCtx(ctx, deadline, c.dialTimeout()) - dialTimeout := dialDeadline.Sub(time.Now()) - if tls { - co, err = DialTimeoutWithTLS(network, a, c.TLSConfig, dialTimeout) - } else { - co, err = DialTimeout(network, a, dialTimeout) - } + co, err = c.Dial(a) if err != nil { return nil, 0, err @@ -253,12 +176,13 @@ func (c *Client) exchange(ctx context.Context, m *Msg, a string) (r *Msg, rtt ti } co.TsigSecret = c.TsigSecret - co.SetWriteDeadline(deadlineOrTimeoutOrCtx(ctx, deadline, c.writeTimeout())) + // write with the appropriate write timeout + co.SetWriteDeadline(time.Now().Add(c.getTimeoutForRequest(c.writeTimeout()))) if err = co.WriteMsg(m); err != nil { return nil, 0, err } - co.SetReadDeadline(deadlineOrTimeoutOrCtx(ctx, deadline, c.readTimeout())) + co.SetReadDeadline(time.Now().Add(c.getTimeoutForRequest(c.readTimeout()))) r, err = co.ReadMsg() if err == nil && r.Id != m.Id { err = ErrId @@ -352,7 +276,7 @@ func tcpMsgLen(t io.Reader) (int, error) { return 0, err } - // As seen with my local router/switch, retursn 1 byte on the above read, + // As seen with my local router/switch, returns 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 { @@ -467,6 +391,24 @@ func (co *Conn) Write(p []byte) (n int, err error) { return n, err } +// Return the appropriate timeout for a specific request +func (c *Client) getTimeoutForRequest(timeout time.Duration) time.Duration { + var requestTimeout time.Duration + if c.Timeout != 0 { + requestTimeout = c.Timeout + } else { + requestTimeout = timeout + } + // net.Dialer.Timeout has priority if smaller than the timeouts computed so + // far + if c.Dialer != nil && c.Dialer.Timeout != 0 { + if c.Dialer.Timeout < requestTimeout { + requestTimeout = c.Dialer.Timeout + } + } + return requestTimeout +} + // Dial connects to the address on the named network. func Dial(network, address string) (conn *Conn, err error) { conn = new(Conn) @@ -477,10 +419,44 @@ func Dial(network, address string) (conn *Conn, err error) { return conn, nil } +// 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) { + client := Client{Net: "udp"} + r, _, err = client.ExchangeContext(ctx, m, a) + // ignorint rtt to leave the original ExchangeContext API unchanged, but + // this function will go away + return r, err +} + +// 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. +// This function is going away, but can easily be mimicked: +// +// co := &dns.Conn{Conn: c} // c is your net.Conn +// co.WriteMsg(m) +// in, _ := co.ReadMsg() +// co.Close() +// +func ExchangeConn(c net.Conn, m *Msg) (r *Msg, err error) { + println("dns: ExchangeConn: this function is deprecated") + co := new(Conn) + co.Conn = c + if err = co.WriteMsg(m); err != nil { + return nil, err + } + r, err = co.ReadMsg() + if err == nil && r.Id != m.Id { + err = ErrId + } + return r, err +} + // DialTimeout acts like Dial but takes a timeout. func DialTimeout(network, address string, timeout time.Duration) (conn *Conn, err error) { - conn = new(Conn) - conn.Conn, err = net.DialTimeout(network, address, timeout) + + client := Client{Net: "udp", Dialer: &net.Dialer{Timeout: timeout}} + conn, err = client.Dial(address) if err != nil { return nil, err } @@ -489,8 +465,12 @@ func DialTimeout(network, address string, timeout time.Duration) (conn *Conn, er // DialWithTLS connects to the address on the named network with TLS. func DialWithTLS(network, address string, tlsConfig *tls.Config) (conn *Conn, err error) { - conn = new(Conn) - conn.Conn, err = tls.Dial(network, address, tlsConfig) + if !strings.HasSuffix(network, "-tls") { + network += "-tls" + } + client := Client{Net: network, TLSConfig: tlsConfig} + conn, err = client.Dial(address) + if err != nil { return nil, err } @@ -499,33 +479,29 @@ func DialWithTLS(network, address string, tlsConfig *tls.Config) (conn *Conn, er // DialTimeoutWithTLS acts like DialWithTLS but takes a timeout. func DialTimeoutWithTLS(network, address string, tlsConfig *tls.Config, timeout time.Duration) (conn *Conn, err error) { - var dialer net.Dialer - dialer.Timeout = timeout - - conn = new(Conn) - conn.Conn, err = tls.DialWithDialer(&dialer, network, address, tlsConfig) + if !strings.HasSuffix(network, "-tls") { + network += "-tls" + } + client := Client{Net: network, Dialer: &net.Dialer{Timeout: timeout}, TLSConfig: tlsConfig} + conn, err = client.Dial(address) if err != nil { return nil, err } 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 { - if deadline.IsZero() { - return time.Now().Add(timeout) - } - 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 +// 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) { + var timeout time.Duration + if deadline, ok := ctx.Deadline(); !ok { + timeout = 0 + } else { + timeout = deadline.Sub(time.Now()) } - return result + // not passing the context to the underlying calls, as the API does not support + // context. For timeouts you should set up Client.Dialer and call Client.Exchange. + c.Dialer = &net.Dialer{Timeout: timeout} + return c.Exchange(m, a) } diff --git a/vendor/github.com/miekg/dns/client_test.go b/vendor/github.com/miekg/dns/client_test.go index 73083dbaf..3ff619cfa 100644 --- a/vendor/github.com/miekg/dns/client_test.go +++ b/vendor/github.com/miekg/dns/client_test.go @@ -11,6 +11,29 @@ import ( "time" ) +func TestDialUDP(t *testing.T) { + HandleFunc("miek.nl.", HelloServer) + defer HandleRemove("miek.nl.") + + s, addrstr, err := RunLocalUDPServer("[::1]:0") + if err != nil { + t.Fatalf("unable to run test server: %v", err) + } + defer s.Shutdown() + + m := new(Msg) + m.SetQuestion("miek.nl.", TypeSOA) + + c := new(Client) + conn, err := c.Dial(addrstr) + if err != nil { + t.Fatalf("failed to dial: %v", err) + } + if conn == nil { + t.Fatalf("conn is nil") + } +} + func TestClientSync(t *testing.T) { HandleFunc("miek.nl.", HelloServer) defer HandleRemove("miek.nl.") @@ -27,9 +50,12 @@ func TestClientSync(t *testing.T) { c := new(Client) r, _, err := c.Exchange(m, addrstr) if err != nil { - t.Errorf("failed to exchange: %v", err) + t.Fatalf("failed to exchange: %v", err) } - if r != nil && r.Rcode != RcodeSuccess { + if r == nil { + t.Fatal("response is nil") + } + if r.Rcode != RcodeSuccess { t.Errorf("failed to get an valid answer\n%v", r) } // And now with plain Exchange(). @@ -42,7 +68,42 @@ func TestClientSync(t *testing.T) { } } -func TestClientTLSSync(t *testing.T) { +func TestClientLocalAddress(t *testing.T) { + HandleFunc("miek.nl.", HelloServerEchoAddrPort) + defer HandleRemove("miek.nl.") + + s, addrstr, err := RunLocalUDPServer("127.0.0.1:0") + if err != nil { + t.Fatalf("unable to run test server: %v", err) + } + defer s.Shutdown() + + m := new(Msg) + m.SetQuestion("miek.nl.", TypeSOA) + + c := new(Client) + laddr := net.UDPAddr{IP: net.ParseIP("127.0.0.1"), Port: 12345, Zone: ""} + c.Dialer = &net.Dialer{LocalAddr: &laddr} + r, _, err := c.Exchange(m, addrstr) + if err != nil { + t.Errorf("failed to exchange: %v", err) + } + if r != nil && r.Rcode != RcodeSuccess { + t.Errorf("failed to get an valid answer\n%v", r) + } + if len(r.Extra) != 1 { + t.Errorf("failed to get additional answers\n%v", r) + } + txt := r.Extra[0].(*TXT) + if txt == nil { + t.Errorf("invalid TXT response\n%v", txt) + } + if len(txt.Txt) != 1 || txt.Txt[0] != "127.0.0.1:12345" { + t.Errorf("invalid TXT response\n%v", txt.Txt) + } +} + +func TestClientTLSSyncV4(t *testing.T) { HandleFunc("miek.nl.", HelloServer) defer HandleRemove("miek.nl.") @@ -65,6 +126,8 @@ func TestClientTLSSync(t *testing.T) { m.SetQuestion("miek.nl.", TypeSOA) c := new(Client) + + // test tcp-tls c.Net = "tcp-tls" c.TLSConfig = &tls.Config{ InsecureSkipVerify: true, @@ -72,9 +135,88 @@ func TestClientTLSSync(t *testing.T) { r, _, err := c.Exchange(m, addrstr) if err != nil { - t.Errorf("failed to exchange: %v", err) + t.Fatalf("failed to exchange: %v", err) } - if r != nil && r.Rcode != RcodeSuccess { + if r == nil { + t.Fatal("response is nil") + } + if r.Rcode != RcodeSuccess { + t.Errorf("failed to get an valid answer\n%v", r) + } + + // test tcp4-tls + c.Net = "tcp4-tls" + c.TLSConfig = &tls.Config{ + InsecureSkipVerify: true, + } + + r, _, err = c.Exchange(m, addrstr) + if err != nil { + t.Fatalf("failed to exchange: %v", err) + } + if r == nil { + t.Fatal("response is nil") + } + if r.Rcode != RcodeSuccess { + t.Errorf("failed to get an valid answer\n%v", r) + } +} + +func TestClientTLSSyncV6(t *testing.T) { + HandleFunc("miek.nl.", HelloServer) + defer HandleRemove("miek.nl.") + + cert, err := tls.X509KeyPair(CertPEMBlock, KeyPEMBlock) + if err != nil { + t.Fatalf("unable to build certificate: %v", err) + } + + config := tls.Config{ + Certificates: []tls.Certificate{cert}, + } + + s, addrstr, err := RunLocalTLSServer("[::1]:0", &config) + if err != nil { + t.Fatalf("unable to run test server: %v", err) + } + defer s.Shutdown() + + m := new(Msg) + m.SetQuestion("miek.nl.", TypeSOA) + + c := new(Client) + + // test tcp-tls + c.Net = "tcp-tls" + c.TLSConfig = &tls.Config{ + InsecureSkipVerify: true, + } + + r, _, err := c.Exchange(m, addrstr) + if err != nil { + t.Fatalf("failed to exchange: %v", err) + } + if r == nil { + t.Fatal("response is nil") + } + if r.Rcode != RcodeSuccess { + t.Errorf("failed to get an valid answer\n%v", r) + } + + // test tcp6-tls + c.Net = "tcp6-tls" + c.TLSConfig = &tls.Config{ + InsecureSkipVerify: true, + } + + r, _, err = c.Exchange(m, addrstr) + if err != nil { + t.Fatalf("failed to exchange: %v", err) + } + if r == nil { + t.Fatal("response is nil") + } + if r.Rcode != RcodeSuccess { t.Errorf("failed to get an valid answer\n%v", r) } } @@ -120,11 +262,11 @@ func TestClientEDNS0(t *testing.T) { c := new(Client) r, _, err := c.Exchange(m, addrstr) if err != nil { - t.Errorf("failed to exchange: %v", err) + t.Fatalf("failed to exchange: %v", err) } if r != nil && r.Rcode != RcodeSuccess { - t.Errorf("failed to get an valid answer\n%v", r) + t.Errorf("failed to get a valid answer\n%v", r) } } @@ -171,11 +313,14 @@ func TestClientEDNS0Local(t *testing.T) { c := new(Client) r, _, err := c.Exchange(m, addrstr) if err != nil { - t.Errorf("failed to exchange: %s", err) + t.Fatalf("failed to exchange: %s", err) } - if r != nil && r.Rcode != RcodeSuccess { - t.Error("failed to get a valid answer") + if r == nil { + t.Fatal("response is nil") + } + if r.Rcode != RcodeSuccess { + t.Fatal("failed to get a valid answer") t.Logf("%v\n", r) } @@ -513,6 +658,9 @@ func TestConcurrentExchanges(t *testing.T) { for i := 0; i < len(r); i++ { go func(i int) { r[i], _, _ = c.Exchange(m.Copy(), addrstr) + if r[i] == nil { + t.Fatalf("response %d is nil", i) + } wg.Done() }(i) } diff --git a/vendor/github.com/miekg/dns/dnsutil/util.go b/vendor/github.com/miekg/dns/dnsutil/util.go index 9ed03f296..c8c6af7b3 100644 --- a/vendor/github.com/miekg/dns/dnsutil/util.go +++ b/vendor/github.com/miekg/dns/dnsutil/util.go @@ -11,7 +11,7 @@ import ( "github.com/miekg/dns" ) -// AddDomain adds origin to s if s is not already a FQDN. +// AddOrigin adds origin to s if s is not already a FQDN. // Note that the result may not be a FQDN. If origin does not end // with a ".", the result won't either. // This implements the zonefile convention (specified in RFC 1035, diff --git a/vendor/github.com/miekg/dns/doc.go b/vendor/github.com/miekg/dns/doc.go index e38753d7d..ceabd24c1 100644 --- a/vendor/github.com/miekg/dns/doc.go +++ b/vendor/github.com/miekg/dns/doc.go @@ -1,7 +1,7 @@ /* Package dns implements a full featured interface to the Domain Name System. Server- and client-side programming is supported. -The package allows complete control over what is send out to the DNS. The package +The package allows complete control over what is sent out to the DNS. The package API follows the less-is-more principle, by presenting a small, clean interface. The package dns supports (asynchronous) querying/replying, incoming/outgoing zone transfers, @@ -14,7 +14,7 @@ Basic usage pattern for creating a new resource record: r := new(dns.MX) r.Hdr = dns.RR_Header{Name: "miek.nl.", Rrtype: dns.TypeMX, - Class: dns.ClassINET, Ttl: 3600} + Class: dns.ClassINET, Ttl: 3600} r.Preference = 10 r.Mx = "mx.miek.nl." @@ -22,16 +22,16 @@ Or directly from a string: mx, err := dns.NewRR("miek.nl. 3600 IN MX 10 mx.miek.nl.") -Or when the default TTL (3600) and class (IN) suit you: +Or when the default origin (.) and TTL (3600) and class (IN) suit you: - mx, err := dns.NewRR("miek.nl. MX 10 mx.miek.nl.") + mx, err := dns.NewRR("miek.nl MX 10 mx.miek.nl") Or even: mx, err := dns.NewRR("$ORIGIN nl.\nmiek 1H IN MX 10 mx.miek") In the DNS messages are exchanged, these messages contain resource -records (sets). Use pattern for creating a message: +records (sets). Use pattern for creating a message: m := new(dns.Msg) m.SetQuestion("miek.nl.", dns.TypeMX) @@ -51,7 +51,7 @@ The following is slightly more verbose, but more flexible: m1.Question = make([]dns.Question, 1) m1.Question[0] = dns.Question{"miek.nl.", dns.TypeMX, dns.ClassINET} -After creating a message it can be send. +After creating a message it can be sent. Basic use pattern for synchronous querying the DNS at a server configured on 127.0.0.1 and port 53: @@ -63,7 +63,23 @@ class) is as easy as setting: c.SingleInflight = true -If these "advanced" features are not needed, a simple UDP query can be send, +More advanced options are availabe using a net.Dialer and the corresponding API. +For example it is possible to set a timeout, or to specify a source IP address +and port to use for the connection: + + c := new(dns.Client) + laddr := net.UDPAddr{ + IP: net.ParseIP("[::1]"), + Port: 12345, + Zone: "", + } + d := net.Dialer{ + Timeout: 200 * time.Millisecond, + LocalAddr: &laddr, + } + in, rtt, err := c.ExchangeWithDialer(&d, m1, "8.8.8.8:53") + +If these "advanced" features are not needed, a simple UDP query can be sent, with: in, err := dns.Exchange(m1, "127.0.0.1:53") diff --git a/vendor/github.com/miekg/dns/edns.go b/vendor/github.com/miekg/dns/edns.go index dbff3714c..718842f28 100644 --- a/vendor/github.com/miekg/dns/edns.go +++ b/vendor/github.com/miekg/dns/edns.go @@ -21,6 +21,7 @@ const ( EDNS0EXPIRE = 0x9 // EDNS0 expire EDNS0COOKIE = 0xa // EDNS0 Cookie EDNS0TCPKEEPALIVE = 0xb // EDNS0 tcp keep alive (RFC7828) + EDNS0PADDING = 0xc // EDNS0 padding (RFC7830) EDNS0SUBNETDRAFT = 0x50fa // Don't use! Use EDNS0SUBNET EDNS0LOCALSTART = 0xFDE9 // Beginning of range reserved for local/experimental use (RFC6891) EDNS0LOCALEND = 0xFFFE // End of range reserved for local/experimental use (RFC6891) @@ -74,6 +75,8 @@ func (rr *OPT) String() string { s += "\n; NSEC3 HASH UNDERSTOOD: " + o.String() case *EDNS0_LOCAL: s += "\n; LOCAL OPT: " + o.String() + case *EDNS0_PADDING: + s += "\n; PADDING: " + o.String() } } return s @@ -595,3 +598,15 @@ func (e *EDNS0_TCP_KEEPALIVE) String() (s string) { } return } + +// EDNS0_PADDING option is used to add padding to a request/response. The default +// value of padding SHOULD be 0x0 but other values MAY be used, for instance if +// compression is applied before encryption which may break signatures. +type EDNS0_PADDING struct { + Padding []byte +} + +func (e *EDNS0_PADDING) pack() ([]byte, error) { return e.Padding, nil } +func (e *EDNS0_PADDING) Option() uint16 { return EDNS0PADDING } +func (e *EDNS0_PADDING) unpack(b []byte) error { e.Padding = b; return nil } +func (e *EDNS0_PADDING) String() string { return fmt.Sprintf("%0X", e.Padding) } diff --git a/vendor/github.com/miekg/dns/internal/socket/cmsghdr.go b/vendor/github.com/miekg/dns/internal/socket/cmsghdr.go new file mode 100644 index 000000000..62f2d2f74 --- /dev/null +++ b/vendor/github.com/miekg/dns/internal/socket/cmsghdr.go @@ -0,0 +1,7 @@ +// +build linux + +package socket + +func (h *cmsghdr) len() int { return int(h.Len) } +func (h *cmsghdr) lvl() int { return int(h.Level) } +func (h *cmsghdr) typ() int { return int(h.Type) } diff --git a/vendor/github.com/miekg/dns/internal/socket/cmsghdr_linux_32bit.go b/vendor/github.com/miekg/dns/internal/socket/cmsghdr_linux_32bit.go new file mode 100644 index 000000000..e92e85800 --- /dev/null +++ b/vendor/github.com/miekg/dns/internal/socket/cmsghdr_linux_32bit.go @@ -0,0 +1,20 @@ +// +build arm mips mipsle 386 +// +build linux + +package socket + +type cmsghdr struct { + Len uint32 + Level int32 + Type int32 +} + +const ( + sizeofCmsghdr = 0xc +) + +func (h *cmsghdr) set(l, lvl, typ int) { + h.Len = uint32(l) + h.Level = int32(lvl) + h.Type = int32(typ) +} diff --git a/vendor/github.com/miekg/dns/internal/socket/cmsghdr_linux_64bit.go b/vendor/github.com/miekg/dns/internal/socket/cmsghdr_linux_64bit.go new file mode 100644 index 000000000..ddfc9e09a --- /dev/null +++ b/vendor/github.com/miekg/dns/internal/socket/cmsghdr_linux_64bit.go @@ -0,0 +1,20 @@ +// +build arm64 amd64 ppc64 ppc64le mips64 mips64le s390x +// +build linux + +package socket + +type cmsghdr struct { + Len uint64 + Level int32 + Type int32 +} + +const ( + sizeofCmsghdr = 0x10 +) + +func (h *cmsghdr) set(l, lvl, typ int) { + h.Len = uint64(l) + h.Level = int32(lvl) + h.Type = int32(typ) +} diff --git a/vendor/github.com/miekg/dns/internal/socket/cmsghdr_other.go b/vendor/github.com/miekg/dns/internal/socket/cmsghdr_other.go new file mode 100644 index 000000000..8078487c8 --- /dev/null +++ b/vendor/github.com/miekg/dns/internal/socket/cmsghdr_other.go @@ -0,0 +1,13 @@ +// +build !linux + +package socket + +type cmsghdr struct{} + +const sizeofCmsghdr = 0 + +func (h *cmsghdr) len() int { return 0 } +func (h *cmsghdr) lvl() int { return 0 } +func (h *cmsghdr) typ() int { return 0 } + +func (h *cmsghdr) set(l, lvl, typ int) {} diff --git a/vendor/github.com/miekg/dns/internal/socket/controlmessage.go b/vendor/github.com/miekg/dns/internal/socket/controlmessage.go new file mode 100644 index 000000000..3176e9602 --- /dev/null +++ b/vendor/github.com/miekg/dns/internal/socket/controlmessage.go @@ -0,0 +1,118 @@ +package socket + +import ( + "errors" + "unsafe" +) + +func controlHeaderLen() int { + return roundup(sizeofCmsghdr) +} + +func controlMessageLen(dataLen int) int { + return roundup(sizeofCmsghdr) + dataLen +} + +// returns the whole length of control message. +func ControlMessageSpace(dataLen int) int { + return roundup(sizeofCmsghdr) + roundup(dataLen) +} + +// A ControlMessage represents the head message in a stream of control +// messages. +// +// A control message comprises of a header, data and a few padding +// fields to conform to the interface to the kernel. +// +// See RFC 3542 for further information. +type ControlMessage []byte + +// Data returns the data field of the control message at the head. +func (m ControlMessage) Data(dataLen int) []byte { + l := controlHeaderLen() + if len(m) < l || len(m) < l+dataLen { + return nil + } + return m[l : l+dataLen] +} + +// ParseHeader parses and returns the header fields of the control +// message at the head. +func (m ControlMessage) ParseHeader() (lvl, typ, dataLen int, err error) { + l := controlHeaderLen() + if len(m) < l { + return 0, 0, 0, errors.New("short message") + } + h := (*cmsghdr)(unsafe.Pointer(&m[0])) + return h.lvl(), h.typ(), int(uint64(h.len()) - uint64(l)), nil +} + +// Next returns the control message at the next. +func (m ControlMessage) Next(dataLen int) ControlMessage { + l := ControlMessageSpace(dataLen) + if len(m) < l { + return nil + } + return m[l:] +} + +// MarshalHeader marshals the header fields of the control message at +// the head. +func (m ControlMessage) MarshalHeader(lvl, typ, dataLen int) error { + if len(m) < controlHeaderLen() { + return errors.New("short message") + } + h := (*cmsghdr)(unsafe.Pointer(&m[0])) + h.set(controlMessageLen(dataLen), lvl, typ) + return nil +} + +// Marshal marshals the control message at the head, and returns the next +// control message. +func (m ControlMessage) Marshal(lvl, typ int, data []byte) (ControlMessage, error) { + l := len(data) + if len(m) < ControlMessageSpace(l) { + return nil, errors.New("short message") + } + h := (*cmsghdr)(unsafe.Pointer(&m[0])) + h.set(controlMessageLen(l), lvl, typ) + if l > 0 { + copy(m.Data(l), data) + } + return m.Next(l), nil +} + +// Parse parses as a single or multiple control messages. +func (m ControlMessage) Parse() ([]ControlMessage, error) { + var ms []ControlMessage + for len(m) >= controlHeaderLen() { + h := (*cmsghdr)(unsafe.Pointer(&m[0])) + l := h.len() + if l <= 0 { + return nil, errors.New("invalid header length") + } + if uint64(l) < uint64(controlHeaderLen()) { + return nil, errors.New("invalid message length") + } + if uint64(l) > uint64(len(m)) { + return nil, errors.New("short buffer") + } + ms = append(ms, ControlMessage(m[:l])) + ll := l - controlHeaderLen() + if len(m) >= ControlMessageSpace(ll) { + m = m[ControlMessageSpace(ll):] + } else { + m = m[controlMessageLen(ll):] + } + } + return ms, nil +} + +// NewControlMessage returns a new stream of control messages. +func NewControlMessage(dataLen []int) ControlMessage { + var l int + for i := range dataLen { + l += ControlMessageSpace(dataLen[i]) + } + return make([]byte, l) +} diff --git a/vendor/github.com/miekg/dns/internal/socket/controlmessage_test.go b/vendor/github.com/miekg/dns/internal/socket/controlmessage_test.go new file mode 100644 index 000000000..e9fff4d45 --- /dev/null +++ b/vendor/github.com/miekg/dns/internal/socket/controlmessage_test.go @@ -0,0 +1,103 @@ +// +build linux + +package socket + +import ( + "bytes" + "testing" +) + +type mockControl struct { + Level int + Type int + Data []byte +} + +func TestControlMessage(t *testing.T) { + for _, tt := range []struct { + cs []mockControl + }{ + { + []mockControl{ + {Level: 1, Type: 1}, + }, + }, + { + []mockControl{ + {Level: 2, Type: 2, Data: []byte{0xfe}}, + }, + }, + { + []mockControl{ + {Level: 3, Type: 3, Data: []byte{0xfe, 0xff, 0xff, 0xfe}}, + }, + }, + { + []mockControl{ + {Level: 4, Type: 4, Data: []byte{0xfe, 0xff, 0xff, 0xfe, 0xfe, 0xff, 0xff, 0xfe}}, + }, + }, + { + []mockControl{ + {Level: 4, Type: 4, Data: []byte{0xfe, 0xff, 0xff, 0xfe, 0xfe, 0xff, 0xff, 0xfe}}, + {Level: 2, Type: 2, Data: []byte{0xfe}}, + }, + }, + } { + var w []byte + var tailPadLen int + mm := NewControlMessage([]int{0}) + for i, c := range tt.cs { + m := NewControlMessage([]int{len(c.Data)}) + l := len(m) - len(mm) + if i == len(tt.cs)-1 && l > len(c.Data) { + tailPadLen = l - len(c.Data) + } + w = append(w, m...) + } + + var err error + ww := make([]byte, len(w)) + copy(ww, w) + m := ControlMessage(ww) + for _, c := range tt.cs { + if err = m.MarshalHeader(c.Level, c.Type, len(c.Data)); err != nil { + t.Fatalf("(%v).MarshalHeader() = %v", tt.cs, err) + } + copy(m.Data(len(c.Data)), c.Data) + m = m.Next(len(c.Data)) + } + m = ControlMessage(w) + for _, c := range tt.cs { + m, err = m.Marshal(c.Level, c.Type, c.Data) + if err != nil { + t.Fatalf("(%v).Marshal() = %v", tt.cs, err) + } + } + if !bytes.Equal(ww, w) { + t.Fatalf("got %#v; want %#v", ww, w) + } + + ws := [][]byte{w} + if tailPadLen > 0 { + // Test a message with no tail padding. + nopad := w[:len(w)-tailPadLen] + ws = append(ws, [][]byte{nopad}...) + } + for _, w := range ws { + ms, err := ControlMessage(w).Parse() + if err != nil { + t.Fatalf("(%v).Parse() = %v", tt.cs, err) + } + for i, m := range ms { + lvl, typ, dataLen, err := m.ParseHeader() + if err != nil { + t.Fatalf("(%v).ParseHeader() = %v", tt.cs, err) + } + if lvl != tt.cs[i].Level || typ != tt.cs[i].Type || dataLen != len(tt.cs[i].Data) { + t.Fatalf("%v: got %d, %d, %d; want %d, %d, %d", tt.cs[i], lvl, typ, dataLen, tt.cs[i].Level, tt.cs[i].Type, len(tt.cs[i].Data)) + } + } + } + } +} diff --git a/vendor/github.com/miekg/dns/internal/socket/socket.go b/vendor/github.com/miekg/dns/internal/socket/socket.go new file mode 100644 index 000000000..edb58e29a --- /dev/null +++ b/vendor/github.com/miekg/dns/internal/socket/socket.go @@ -0,0 +1,4 @@ +// Package socket contains ControlMessage parsing code from +// golang.org/x/net/internal/socket. Instead of supporting all possible +// architectures, we're only supporting linux 32/64 bit. +package socket diff --git a/vendor/github.com/miekg/dns/internal/socket/sys.go b/vendor/github.com/miekg/dns/internal/socket/sys.go new file mode 100644 index 000000000..2f3f5cfed --- /dev/null +++ b/vendor/github.com/miekg/dns/internal/socket/sys.go @@ -0,0 +1,14 @@ +package socket + +import "unsafe" + +var ( + kernelAlign = func() int { + var p uintptr + return int(unsafe.Sizeof(p)) + }() +) + +func roundup(l int) int { + return (l + kernelAlign - 1) & ^(kernelAlign - 1) +} diff --git a/vendor/github.com/miekg/dns/msg_helpers.go b/vendor/github.com/miekg/dns/msg_helpers.go index 8d415c92a..0ca12b048 100644 --- a/vendor/github.com/miekg/dns/msg_helpers.go +++ b/vendor/github.com/miekg/dns/msg_helpers.go @@ -458,6 +458,13 @@ Option: } edns = append(edns, e) off += int(optlen) + case EDNS0PADDING: + e := new(EDNS0_PADDING) + if err := e.unpack(msg[off : off+int(optlen)]); err != nil { + return nil, len(msg), err + } + edns = append(edns, e) + off += int(optlen) default: e := new(EDNS0_LOCAL) e.Code = code diff --git a/vendor/github.com/miekg/dns/parse_test.go b/vendor/github.com/miekg/dns/parse_test.go index fc5bdaf5d..c7ecb499d 100644 --- a/vendor/github.com/miekg/dns/parse_test.go +++ b/vendor/github.com/miekg/dns/parse_test.go @@ -8,6 +8,7 @@ import ( "math/rand" "net" "reflect" + "regexp" "strconv" "strings" "testing" @@ -571,81 +572,88 @@ test IN CNAME test.a.example.com. t.Logf("%d RRs parsed in %.2f s (%.2f RR/s)", i, float32(delta)/1e9, float32(i)/(float32(delta)/1e9)) } -func ExampleParseZone() { - zone := `$ORIGIN . -$TTL 3600 ; 1 hour -name IN SOA a6.nstld.com. hostmaster.nic.name. ( - 203362132 ; serial - 300 ; refresh (5 minutes) - 300 ; retry (5 minutes) - 1209600 ; expire (2 weeks) - 300 ; minimum (5 minutes) - ) -$TTL 10800 ; 3 hours -name. 10800 IN NS name. - IN NS g6.nstld.com. - 7200 NS h6.nstld.com. - 3600 IN NS j6.nstld.com. - IN 3600 NS k6.nstld.com. - NS l6.nstld.com. - NS a6.nstld.com. - NS c6.nstld.com. - NS d6.nstld.com. - NS f6.nstld.com. - NS m6.nstld.com. -( - NS m7.nstld.com. -) -$ORIGIN name. -0-0onlus NS ns7.ehiweb.it. - NS ns8.ehiweb.it. -0-g MX 10 mx01.nic - MX 10 mx02.nic - MX 10 mx03.nic - MX 10 mx04.nic -$ORIGIN 0-g.name -moutamassey NS ns01.yahoodomains.jp. - NS ns02.yahoodomains.jp. +func TestOmittedTTL(t *testing.T) { + zone := ` +$ORIGIN example.com. +example.com. 42 IN SOA ns1.example.com. hostmaster.example.com. 1 86400 60 86400 3600 ; TTL=42 SOA +example.com. NS 2 ; TTL=42 absolute owner name +@ MD 3 ; TTL=42 current-origin owner name + MF 4 ; TTL=42 leading-space implied owner name + 43 TYPE65280 \# 1 05 ; TTL=43 implied owner name explicit TTL + MB 6 ; TTL=43 leading-tab implied owner name +$TTL 1337 +example.com. 88 MG 7 ; TTL=88 explicit TTL +example.com. MR 8 ; TTL=1337 after first $TTL +$TTL 314 + 1 TXT 9 ; TTL=1 implied owner name explicit TTL +example.com. DNAME 10 ; TTL=314 after second $TTL ` - to := ParseZone(strings.NewReader(zone), "", "testzone") - for x := range to { - fmt.Println(x.RR) - } - // Output: - // name. 3600 IN SOA a6.nstld.com. hostmaster.nic.name. 203362132 300 300 1209600 300 - // name. 10800 IN NS name. - // name. 10800 IN NS g6.nstld.com. - // name. 7200 IN NS h6.nstld.com. - // name. 3600 IN NS j6.nstld.com. - // name. 3600 IN NS k6.nstld.com. - // name. 10800 IN NS l6.nstld.com. - // name. 10800 IN NS a6.nstld.com. - // name. 10800 IN NS c6.nstld.com. - // name. 10800 IN NS d6.nstld.com. - // name. 10800 IN NS f6.nstld.com. - // name. 10800 IN NS m6.nstld.com. - // name. 10800 IN NS m7.nstld.com. - // 0-0onlus.name. 10800 IN NS ns7.ehiweb.it. - // 0-0onlus.name. 10800 IN NS ns8.ehiweb.it. - // 0-g.name. 10800 IN MX 10 mx01.nic.name. - // 0-g.name. 10800 IN MX 10 mx02.nic.name. - // 0-g.name. 10800 IN MX 10 mx03.nic.name. - // 0-g.name. 10800 IN MX 10 mx04.nic.name. - // moutamassey.0-g.name.name. 10800 IN NS ns01.yahoodomains.jp. - // moutamassey.0-g.name.name. 10800 IN NS ns02.yahoodomains.jp. + reCaseFromComment := regexp.MustCompile(`TTL=(\d+)\s+(.*)`) + records := ParseZone(strings.NewReader(zone), "", "") + var i int + for record := range records { + i++ + if record.Error != nil { + t.Error(record.Error) + continue + } + expected := reCaseFromComment.FindStringSubmatch(record.Comment) + expectedTTL, _ := strconv.ParseUint(expected[1], 10, 32) + ttl := record.RR.Header().Ttl + if ttl != uint32(expectedTTL) { + t.Errorf("%s: expected TTL %d, got %d", expected[2], expectedTTL, ttl) + } + } + if i != 10 { + t.Errorf("expected %d records, got %d", 5, i) + } } -func ExampleHIP() { - h := `www.example.com IN HIP ( 2 200100107B1A74DF365639CC39F1D578 - AwEAAbdxyhNuSutc5EMzxTs9LBPCIkOFH8cIvM4p -9+LrV4e19WzK00+CI6zBCQTdtWsuxKbWIy87UOoJTwkUs7lBu+Upr1gsNrut79ryra+bSRGQ -b1slImA8YVJyuIDsj7kwzG7jnERNqnWxZ48AWkskmdHaVDP4BcelrTI3rMXdXF5D - rvs.example.com. )` - if hip, err := NewRR(h); err == nil { - fmt.Println(hip.String()) +func TestRelativeNameErrors(t *testing.T) { + var badZones = []struct { + label string + zoneContents string + expectedErr string + }{ + { + "relative owner name without origin", + "example.com 3600 IN SOA ns.example.com. hostmaster.example.com. 1 86400 60 86400 3600", + "bad owner name", + }, + { + "relative owner name in RDATA", + "example.com. 3600 IN SOA ns hostmaster 1 86400 60 86400 3600", + "bad SOA Ns", + }, + { + "origin reference without origin", + "@ 3600 IN SOA ns.example.com. hostmaster.example.com. 1 86400 60 86400 3600", + "bad owner name", + }, + { + "relative owner name in $INCLUDE", + "$INCLUDE file.db example.com", + "bad origin name", + }, + { + "relative owner name in $ORIGIN", + "$ORIGIN example.com", + "bad origin name", + }, + } + for _, errorCase := range badZones { + entries := ParseZone(strings.NewReader(errorCase.zoneContents), "", "") + for entry := range entries { + if entry.Error == nil { + t.Errorf("%s: expected error, got nil", errorCase.label) + continue + } + err := entry.Error.err + if err != errorCase.expectedErr { + t.Errorf("%s: expected error `%s`, got `%s`", errorCase.label, errorCase.expectedErr, err) + } + } } - // Output: - // www.example.com. 3600 IN HIP 2 200100107B1A74DF365639CC39F1D578 AwEAAbdxyhNuSutc5EMzxTs9LBPCIkOFH8cIvM4p9+LrV4e19WzK00+CI6zBCQTdtWsuxKbWIy87UOoJTwkUs7lBu+Upr1gsNrut79ryra+bSRGQb1slImA8YVJyuIDsj7kwzG7jnERNqnWxZ48AWkskmdHaVDP4BcelrTI3rMXdXF5D rvs.example.com. } func TestHIP(t *testing.T) { @@ -686,24 +694,6 @@ b1slImA8YVJyuIDsj7kwzG7jnERNqnWxZ48AWkskmdHaVDP4BcelrTI3rMXdXF5D } } -func ExampleSOA() { - s := "example.com. 1000 SOA master.example.com. admin.example.com. 1 4294967294 4294967293 4294967295 100" - if soa, err := NewRR(s); err == nil { - fmt.Println(soa.String()) - } - // Output: - // example.com. 1000 IN SOA master.example.com. admin.example.com. 1 4294967294 4294967293 4294967295 100 -} - -func TestLineNumberError(t *testing.T) { - s := "example.com. 1000 SOA master.example.com. admin.example.com. monkey 4294967294 4294967293 4294967295 100" - if _, err := NewRR(s); err != nil { - if err.Error() != "dns: bad SOA zone parameter: \"monkey\" at line: 1:68" { - t.Error("not expecting this error: ", err) - } - } -} - // Test with no known RR on the line func TestLineNumberError2(t *testing.T) { tests := map[string]string{ @@ -801,28 +791,6 @@ func TestLowercaseTokens(t *testing.T) { } } -func ExampleParseZone_generate() { - // From the manual: http://www.bind9.net/manual/bind/9.3.2/Bv9ARM.ch06.html#id2566761 - zone := "$GENERATE 1-2 0 NS SERVER$.EXAMPLE.\n$GENERATE 1-8 $ CNAME $.0" - to := ParseZone(strings.NewReader(zone), "0.0.192.IN-ADDR.ARPA.", "") - for x := range to { - if x.Error == nil { - fmt.Println(x.RR.String()) - } - } - // Output: - // 0.0.0.192.IN-ADDR.ARPA. 3600 IN NS SERVER1.EXAMPLE. - // 0.0.0.192.IN-ADDR.ARPA. 3600 IN NS SERVER2.EXAMPLE. - // 1.0.0.192.IN-ADDR.ARPA. 3600 IN CNAME 1.0.0.0.192.IN-ADDR.ARPA. - // 2.0.0.192.IN-ADDR.ARPA. 3600 IN CNAME 2.0.0.0.192.IN-ADDR.ARPA. - // 3.0.0.192.IN-ADDR.ARPA. 3600 IN CNAME 3.0.0.0.192.IN-ADDR.ARPA. - // 4.0.0.192.IN-ADDR.ARPA. 3600 IN CNAME 4.0.0.0.192.IN-ADDR.ARPA. - // 5.0.0.192.IN-ADDR.ARPA. 3600 IN CNAME 5.0.0.0.192.IN-ADDR.ARPA. - // 6.0.0.192.IN-ADDR.ARPA. 3600 IN CNAME 6.0.0.0.192.IN-ADDR.ARPA. - // 7.0.0.192.IN-ADDR.ARPA. 3600 IN CNAME 7.0.0.0.192.IN-ADDR.ARPA. - // 8.0.0.192.IN-ADDR.ARPA. 3600 IN CNAME 8.0.0.0.192.IN-ADDR.ARPA. -} - func TestSRVPacking(t *testing.T) { msg := Msg{} diff --git a/vendor/github.com/miekg/dns/privaterr_test.go b/vendor/github.com/miekg/dns/privaterr_test.go index 72ec8f5c0..f50d0f48c 100644 --- a/vendor/github.com/miekg/dns/privaterr_test.go +++ b/vendor/github.com/miekg/dns/privaterr_test.go @@ -143,7 +143,7 @@ func (rd *VERSION) Len() int { } var smallzone = `$ORIGIN example.org. -@ SOA sns.dns.icann.org. noc.dns.icann.org. ( +@ 3600 IN SOA sns.dns.icann.org. noc.dns.icann.org. ( 2014091518 7200 3600 1209600 3600 ) A 1.2.3.4 diff --git a/vendor/github.com/miekg/dns/scan.go b/vendor/github.com/miekg/dns/scan.go index 5f7f64423..c7b1eb19a 100644 --- a/vendor/github.com/miekg/dns/scan.go +++ b/vendor/github.com/miekg/dns/scan.go @@ -105,6 +105,12 @@ type Token struct { Comment string } +// ttlState describes the state necessary to fill in an omitted RR TTL +type ttlState struct { + ttl uint32 // ttl is the current default TTL + isByDirective bool // isByDirective indicates whether ttl was set by a $TTL directive +} + // NewRR reads the RR contained in the string s. Only the first RR is // returned. If s contains no RR, return nil with no error. The class // defaults to IN and TTL defaults to 3600. The full zone file syntax @@ -120,7 +126,8 @@ func NewRR(s string) (RR, error) { // ReadRR reads the RR contained in q. // See NewRR for more documentation. func ReadRR(q io.Reader, filename string) (RR, error) { - r := <-parseZoneHelper(q, ".", filename, 1) + defttl := &ttlState{defaultTtl, false} + r := <-parseZoneHelper(q, ".", defttl, filename, 1) if r == nil { return nil, nil } @@ -132,10 +139,10 @@ func ReadRR(q io.Reader, filename string) (RR, error) { } // ParseZone reads a RFC 1035 style zonefile from r. It returns *Tokens on the -// returned channel, which consist out the parsed RR, a potential comment or an error. -// If there is an error the RR is nil. The string file is only used +// returned channel, each consisting of either a parsed RR and optional comment +// or a nil RR and an error. The string file is only used // in error reporting. The string origin is used as the initial origin, as -// if the file would start with: $ORIGIN origin . +// if the file would start with an $ORIGIN directive. // The directives $INCLUDE, $ORIGIN, $TTL and $GENERATE are supported. // The channel t is closed by ParseZone when the end of r is reached. // @@ -157,16 +164,16 @@ func ReadRR(q io.Reader, filename string) (RR, error) { // The text "; this is comment" is returned in Token.Comment. Comments inside the // RR are discarded. Comments on a line by themselves are discarded too. func ParseZone(r io.Reader, origin, file string) chan *Token { - return parseZoneHelper(r, origin, file, 10000) + return parseZoneHelper(r, origin, nil, file, 10000) } -func parseZoneHelper(r io.Reader, origin, file string, chansize int) chan *Token { +func parseZoneHelper(r io.Reader, origin string, defttl *ttlState, file string, chansize int) chan *Token { t := make(chan *Token, chansize) - go parseZone(r, origin, file, t, 0) + go parseZone(r, origin, defttl, file, t, 0) return t } -func parseZone(r io.Reader, origin, f string, t chan *Token, include int) { +func parseZone(r io.Reader, origin string, defttl *ttlState, f string, t chan *Token, include int) { defer func() { if include == 0 { close(t) @@ -186,18 +193,16 @@ func parseZone(r io.Reader, origin, f string, t chan *Token, include int) { // After detecting these, we know the zRrtype so we can jump to functions // handling the rdata for each of these types. - if origin == "" { - origin = "." - } - origin = Fqdn(origin) - if _, ok := IsDomainName(origin); !ok { - t <- &Token{Error: &ParseError{f, "bad initial origin name", lex{}}} - return + if origin != "" { + origin = Fqdn(origin) + if _, ok := IsDomainName(origin); !ok { + t <- &Token{Error: &ParseError{f, "bad initial origin name", lex{}}} + return + } } st := zExpectOwnerDir // initial state var h RR_Header - var defttl uint32 = defaultTtl var prevName string for l := range c { // Lexer spotted an error already @@ -209,27 +214,21 @@ func parseZone(r io.Reader, origin, f string, t chan *Token, include int) { switch st { case zExpectOwnerDir: // We can also expect a directive, like $TTL or $ORIGIN - h.Ttl = defttl + if defttl != nil { + h.Ttl = defttl.ttl + } h.Class = ClassINET switch l.value { case zNewline: st = zExpectOwnerDir case zOwner: h.Name = l.token - if l.token[0] == '@' { - h.Name = origin - prevName = h.Name - st = zExpectOwnerBl - break - } - if h.Name[l.length-1] != '.' { - h.Name = appendOrigin(h.Name, origin) - } - _, ok := IsDomainName(l.token) + name, ok := toAbsoluteName(l.token, origin) if !ok { t <- &Token{Error: &ParseError{f, "bad owner name", l}} return } + h.Name = name prevName = h.Name st = zExpectOwnerBl case zDirTtl: @@ -258,8 +257,9 @@ func parseZone(r io.Reader, origin, f string, t chan *Token, include int) { return } h.Ttl = ttl - // Don't about the defttl, we should take the $TTL value - // defttl = ttl + if defttl == nil || !defttl.isByDirective { + defttl = &ttlState{ttl, false} + } st = zExpectAnyNoTtlBl default: @@ -282,20 +282,12 @@ func parseZone(r io.Reader, origin, f string, t chan *Token, include int) { case zBlank: l := <-c if l.value == zString { - if _, ok := IsDomainName(l.token); !ok || l.length == 0 || l.err { + name, ok := toAbsoluteName(l.token, origin) + if !ok { t <- &Token{Error: &ParseError{f, "bad origin name", l}} return } - // a new origin is specified. - if l.token[l.length-1] != '.' { - if origin != "." { // Prevent .. endings - neworigin = l.token + "." + origin - } else { - neworigin = l.token + origin - } - } else { - neworigin = l.token - } + neworigin = name } case zNewline, zEOF: // Ok @@ -313,7 +305,7 @@ func parseZone(r io.Reader, origin, f string, t chan *Token, include int) { t <- &Token{Error: &ParseError{f, "too deeply nested $INCLUDE", l}} return } - parseZone(r1, l.token, neworigin, t, include+1) + parseZone(r1, neworigin, defttl, l.token, t, include+1) st = zExpectOwnerDir case zExpectDirTtlBl: if l.value != zBlank { @@ -335,7 +327,7 @@ func parseZone(r io.Reader, origin, f string, t chan *Token, include int) { t <- &Token{Error: &ParseError{f, "expecting $TTL value, not this...", l}} return } - defttl = ttl + defttl = &ttlState{ttl, true} st = zExpectOwnerDir case zExpectDirOriginBl: if l.value != zBlank { @@ -351,19 +343,12 @@ func parseZone(r io.Reader, origin, f string, t chan *Token, include int) { if e, _ := slurpRemainder(c, f); e != nil { t <- &Token{Error: e} } - if _, ok := IsDomainName(l.token); !ok { + name, ok := toAbsoluteName(l.token, origin) + if !ok { t <- &Token{Error: &ParseError{f, "bad origin name", l}} return } - if l.token[l.length-1] != '.' { - if origin != "." { // Prevent .. endings - origin = l.token + "." + origin - } else { - origin = l.token + origin - } - } else { - origin = l.token - } + origin = name st = zExpectOwnerDir case zExpectDirGenerateBl: if l.value != zBlank { @@ -390,6 +375,10 @@ func parseZone(r io.Reader, origin, f string, t chan *Token, include int) { case zExpectAny: switch l.value { case zRrtpe: + if defttl == nil { + t <- &Token{Error: &ParseError{f, "missing TTL with no previous value", l}} + return + } h.Rrtype = l.torc st = zExpectRdata case zClass: @@ -402,7 +391,9 @@ func parseZone(r io.Reader, origin, f string, t chan *Token, include int) { return } h.Ttl = ttl - // defttl = ttl // don't set the defttl here + if defttl == nil || !defttl.isByDirective { + defttl = &ttlState{ttl, false} + } st = zExpectAnyNoTtlBl default: t <- &Token{Error: &ParseError{f, "expecting RR type, TTL or class, not this...", l}} @@ -441,7 +432,9 @@ func parseZone(r io.Reader, origin, f string, t chan *Token, include int) { return } h.Ttl = ttl - // defttl = ttl // don't set the def ttl anymore + if defttl == nil || !defttl.isByDirective { + defttl = &ttlState{ttl, false} + } st = zExpectRrtypeBl case zRrtpe: h.Rrtype = l.torc @@ -918,6 +911,34 @@ func stringToCm(token string) (e, m uint8, ok bool) { return } +func toAbsoluteName(name, origin string) (absolute string, ok bool) { + // check for an explicit origin reference + if name == "@" { + // require a nonempty origin + if origin == "" { + return "", false + } + return origin, true + } + + // require a valid domain name + _, ok = IsDomainName(name) + if !ok || name == "" { + return "", false + } + + // check if name is already absolute + if name[len(name)-1] == '.' { + return name, true + } + + // require a nonempty origin + if origin == "" { + return "", false + } + return appendOrigin(name, origin), true +} + func appendOrigin(name, origin string) string { if origin == "." { return name + origin diff --git a/vendor/github.com/miekg/dns/scan_rr.go b/vendor/github.com/miekg/dns/scan_rr.go index b8b18fd77..824b9c949 100644 --- a/vendor/github.com/miekg/dns/scan_rr.go +++ b/vendor/github.com/miekg/dns/scan_rr.go @@ -130,9 +130,10 @@ func setA(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { rr.Hdr = h l := <-c - if l.length == 0 { // Dynamic updates. + if l.length == 0 { // dynamic update rr. return rr, nil, "" } + rr.A = net.ParseIP(l.token) if rr.A == nil || l.err { return nil, &ParseError{f, "bad A A", l}, "" @@ -145,9 +146,10 @@ func setAAAA(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { rr.Hdr = h l := <-c - if l.length == 0 { + if l.length == 0 { // dynamic update rr. return rr, nil, "" } + rr.AAAA = net.ParseIP(l.token) if rr.AAAA == nil || l.err { return nil, &ParseError{f, "bad AAAA AAAA", l}, "" @@ -161,20 +163,15 @@ func setNS(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { l := <-c rr.Ns = l.token - if l.length == 0 { - return rr, nil, "" - } - if l.token == "@" { - rr.Ns = o + if l.length == 0 { // dynamic update rr. return rr, nil, "" } - _, ok := IsDomainName(l.token) - if !ok || l.length == 0 || l.err { + + name, nameOk := toAbsoluteName(l.token, o) + if l.err || !nameOk { return nil, &ParseError{f, "bad NS Ns", l}, "" } - if rr.Ns[l.length-1] != '.' { - rr.Ns = appendOrigin(rr.Ns, o) - } + rr.Ns = name return rr, nil, "" } @@ -187,17 +184,12 @@ func setPTR(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { if l.length == 0 { // dynamic update rr. return rr, nil, "" } - if l.token == "@" { - rr.Ptr = o - return rr, nil, "" - } - _, ok := IsDomainName(l.token) - if !ok || l.length == 0 || l.err { + + name, nameOk := toAbsoluteName(l.token, o) + if l.err || !nameOk { return nil, &ParseError{f, "bad PTR Ptr", l}, "" } - if rr.Ptr[l.length-1] != '.' { - rr.Ptr = appendOrigin(rr.Ptr, o) - } + rr.Ptr = name return rr, nil, "" } @@ -207,20 +199,15 @@ func setNSAPPTR(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) l := <-c rr.Ptr = l.token - if l.length == 0 { - return rr, nil, "" - } - if l.token == "@" { - rr.Ptr = o + if l.length == 0 { // dynamic update rr. return rr, nil, "" } - _, ok := IsDomainName(l.token) - if !ok || l.length == 0 || l.err { + + name, nameOk := toAbsoluteName(l.token, o) + if l.err || !nameOk { return nil, &ParseError{f, "bad NSAP-PTR Ptr", l}, "" } - if rr.Ptr[l.length-1] != '.' { - rr.Ptr = appendOrigin(rr.Ptr, o) - } + rr.Ptr = name return rr, nil, "" } @@ -230,34 +217,26 @@ func setRP(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { l := <-c rr.Mbox = l.token - if l.length == 0 { + if l.length == 0 { // dynamic update rr. return rr, nil, "" } - if l.token == "@" { - rr.Mbox = o - } else { - _, ok := IsDomainName(l.token) - if !ok || l.length == 0 || l.err { - return nil, &ParseError{f, "bad RP Mbox", l}, "" - } - if rr.Mbox[l.length-1] != '.' { - rr.Mbox = appendOrigin(rr.Mbox, o) - } + + mbox, mboxOk := toAbsoluteName(l.token, o) + if l.err || !mboxOk { + return nil, &ParseError{f, "bad RP Mbox", l}, "" } + rr.Mbox = mbox + <-c // zBlank l = <-c rr.Txt = l.token - if l.token == "@" { - rr.Txt = o - return rr, nil, "" - } - _, ok := IsDomainName(l.token) - if !ok || l.length == 0 || l.err { + + txt, txtOk := toAbsoluteName(l.token, o) + if l.err || !txtOk { return nil, &ParseError{f, "bad RP Txt", l}, "" } - if rr.Txt[l.length-1] != '.' { - rr.Txt = appendOrigin(rr.Txt, o) - } + rr.Txt = txt + return rr, nil, "" } @@ -267,20 +246,15 @@ func setMR(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { l := <-c rr.Mr = l.token - if l.length == 0 { - return rr, nil, "" - } - if l.token == "@" { - rr.Mr = o + if l.length == 0 { // dynamic update rr. return rr, nil, "" } - _, ok := IsDomainName(l.token) - if !ok || l.length == 0 || l.err { + + name, nameOk := toAbsoluteName(l.token, o) + if l.err || !nameOk { return nil, &ParseError{f, "bad MR Mr", l}, "" } - if rr.Mr[l.length-1] != '.' { - rr.Mr = appendOrigin(rr.Mr, o) - } + rr.Mr = name return rr, nil, "" } @@ -290,20 +264,15 @@ func setMB(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { l := <-c rr.Mb = l.token - if l.length == 0 { - return rr, nil, "" - } - if l.token == "@" { - rr.Mb = o + if l.length == 0 { // dynamic update rr. return rr, nil, "" } - _, ok := IsDomainName(l.token) - if !ok || l.length == 0 || l.err { + + name, nameOk := toAbsoluteName(l.token, o) + if l.err || !nameOk { return nil, &ParseError{f, "bad MB Mb", l}, "" } - if rr.Mb[l.length-1] != '.' { - rr.Mb = appendOrigin(rr.Mb, o) - } + rr.Mb = name return rr, nil, "" } @@ -313,20 +282,15 @@ func setMG(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { l := <-c rr.Mg = l.token - if l.length == 0 { - return rr, nil, "" - } - if l.token == "@" { - rr.Mg = o + if l.length == 0 { // dynamic update rr. return rr, nil, "" } - _, ok := IsDomainName(l.token) - if !ok || l.length == 0 || l.err { + + name, nameOk := toAbsoluteName(l.token, o) + if l.err || !nameOk { return nil, &ParseError{f, "bad MG Mg", l}, "" } - if rr.Mg[l.length-1] != '.' { - rr.Mg = appendOrigin(rr.Mg, o) - } + rr.Mg = name return rr, nil, "" } @@ -362,34 +326,26 @@ func setMINFO(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { l := <-c rr.Rmail = l.token - if l.length == 0 { + if l.length == 0 { // dynamic update rr. return rr, nil, "" } - if l.token == "@" { - rr.Rmail = o - } else { - _, ok := IsDomainName(l.token) - if !ok || l.length == 0 || l.err { - return nil, &ParseError{f, "bad MINFO Rmail", l}, "" - } - if rr.Rmail[l.length-1] != '.' { - rr.Rmail = appendOrigin(rr.Rmail, o) - } + + rmail, rmailOk := toAbsoluteName(l.token, o) + if l.err || !rmailOk { + return nil, &ParseError{f, "bad MINFO Rmail", l}, "" } + rr.Rmail = rmail + <-c // zBlank l = <-c rr.Email = l.token - if l.token == "@" { - rr.Email = o - return rr, nil, "" - } - _, ok := IsDomainName(l.token) - if !ok || l.length == 0 || l.err { + + email, emailOk := toAbsoluteName(l.token, o) + if l.err || !emailOk { return nil, &ParseError{f, "bad MINFO Email", l}, "" } - if rr.Email[l.length-1] != '.' { - rr.Email = appendOrigin(rr.Email, o) - } + rr.Email = email + return rr, nil, "" } @@ -399,20 +355,15 @@ func setMF(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { l := <-c rr.Mf = l.token - if l.length == 0 { - return rr, nil, "" - } - if l.token == "@" { - rr.Mf = o + if l.length == 0 { // dynamic update rr. return rr, nil, "" } - _, ok := IsDomainName(l.token) - if !ok || l.length == 0 || l.err { + + name, nameOk := toAbsoluteName(l.token, o) + if l.err || !nameOk { return nil, &ParseError{f, "bad MF Mf", l}, "" } - if rr.Mf[l.length-1] != '.' { - rr.Mf = appendOrigin(rr.Mf, o) - } + rr.Mf = name return rr, nil, "" } @@ -422,20 +373,15 @@ func setMD(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { l := <-c rr.Md = l.token - if l.length == 0 { - return rr, nil, "" - } - if l.token == "@" { - rr.Md = o + if l.length == 0 { // dynamic update rr. return rr, nil, "" } - _, ok := IsDomainName(l.token) - if !ok || l.length == 0 || l.err { + + name, nameOk := toAbsoluteName(l.token, o) + if l.err || !nameOk { return nil, &ParseError{f, "bad MD Md", l}, "" } - if rr.Md[l.length-1] != '.' { - rr.Md = appendOrigin(rr.Md, o) - } + rr.Md = name return rr, nil, "" } @@ -444,57 +390,54 @@ func setMX(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { rr.Hdr = h l := <-c - if l.length == 0 { + if l.length == 0 { // dynamic update rr. return rr, nil, "" } + i, e := strconv.ParseUint(l.token, 10, 16) if e != nil || l.err { return nil, &ParseError{f, "bad MX Pref", l}, "" } rr.Preference = uint16(i) + <-c // zBlank l = <-c // zString rr.Mx = l.token - if l.token == "@" { - rr.Mx = o - return rr, nil, "" - } - _, ok := IsDomainName(l.token) - if !ok || l.length == 0 || l.err { + + name, nameOk := toAbsoluteName(l.token, o) + if l.err || !nameOk { return nil, &ParseError{f, "bad MX Mx", l}, "" } - if rr.Mx[l.length-1] != '.' { - rr.Mx = appendOrigin(rr.Mx, o) - } + rr.Mx = name + return rr, nil, "" } func setRT(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { rr := new(RT) rr.Hdr = h + l := <-c - if l.length == 0 { + if l.length == 0 { // dynamic update rr. return rr, nil, "" } + i, e := strconv.ParseUint(l.token, 10, 16) if e != nil { return nil, &ParseError{f, "bad RT Preference", l}, "" } rr.Preference = uint16(i) + <-c // zBlank l = <-c // zString rr.Host = l.token - if l.token == "@" { - rr.Host = o - return rr, nil, "" - } - _, ok := IsDomainName(l.token) - if !ok || l.length == 0 || l.err { + + name, nameOk := toAbsoluteName(l.token, o) + if l.err || !nameOk { return nil, &ParseError{f, "bad RT Host", l}, "" } - if rr.Host[l.length-1] != '.' { - rr.Host = appendOrigin(rr.Host, o) - } + rr.Host = name + return rr, nil, "" } @@ -503,28 +446,25 @@ func setAFSDB(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { rr.Hdr = h l := <-c - if l.length == 0 { + if l.length == 0 { // dynamic update rr. return rr, nil, "" } + i, e := strconv.ParseUint(l.token, 10, 16) if e != nil || l.err { return nil, &ParseError{f, "bad AFSDB Subtype", l}, "" } rr.Subtype = uint16(i) + <-c // zBlank l = <-c // zString rr.Hostname = l.token - if l.token == "@" { - rr.Hostname = o - return rr, nil, "" - } - _, ok := IsDomainName(l.token) - if !ok || l.length == 0 || l.err { + + name, nameOk := toAbsoluteName(l.token, o) + if l.err || !nameOk { return nil, &ParseError{f, "bad AFSDB Hostname", l}, "" } - if rr.Hostname[l.length-1] != '.' { - rr.Hostname = appendOrigin(rr.Hostname, o) - } + rr.Hostname = name return rr, nil, "" } @@ -533,9 +473,10 @@ func setX25(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { rr.Hdr = h l := <-c - if l.length == 0 { + if l.length == 0 { // dynamic update rr. return rr, nil, "" } + if l.err { return nil, &ParseError{f, "bad X25 PSDNAddress", l}, "" } @@ -548,28 +489,25 @@ func setKX(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { rr.Hdr = h l := <-c - if l.length == 0 { + if l.length == 0 { // dynamic update rr. return rr, nil, "" } + i, e := strconv.ParseUint(l.token, 10, 16) if e != nil || l.err { return nil, &ParseError{f, "bad KX Pref", l}, "" } rr.Preference = uint16(i) + <-c // zBlank l = <-c // zString rr.Exchanger = l.token - if l.token == "@" { - rr.Exchanger = o - return rr, nil, "" - } - _, ok := IsDomainName(l.token) - if !ok || l.length == 0 || l.err { + + name, nameOk := toAbsoluteName(l.token, o) + if l.err || !nameOk { return nil, &ParseError{f, "bad KX Exchanger", l}, "" } - if rr.Exchanger[l.length-1] != '.' { - rr.Exchanger = appendOrigin(rr.Exchanger, o) - } + rr.Exchanger = name return rr, nil, "" } @@ -579,20 +517,15 @@ func setCNAME(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { l := <-c rr.Target = l.token - if l.length == 0 { - return rr, nil, "" - } - if l.token == "@" { - rr.Target = o + if l.length == 0 { // dynamic update rr. return rr, nil, "" } - _, ok := IsDomainName(l.token) - if !ok || l.length == 0 || l.err { + + name, nameOk := toAbsoluteName(l.token, o) + if l.err || !nameOk { return nil, &ParseError{f, "bad CNAME Target", l}, "" } - if rr.Target[l.length-1] != '.' { - rr.Target = appendOrigin(rr.Target, o) - } + rr.Target = name return rr, nil, "" } @@ -602,20 +535,15 @@ func setDNAME(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { l := <-c rr.Target = l.token - if l.length == 0 { - return rr, nil, "" - } - if l.token == "@" { - rr.Target = o + if l.length == 0 { // dynamic update rr. return rr, nil, "" } - _, ok := IsDomainName(l.token) - if !ok || l.length == 0 || l.err { - return nil, &ParseError{f, "bad CNAME Target", l}, "" - } - if rr.Target[l.length-1] != '.' { - rr.Target = appendOrigin(rr.Target, o) + + name, nameOk := toAbsoluteName(l.token, o) + if l.err || !nameOk { + return nil, &ParseError{f, "bad DNAME Target", l}, "" } + rr.Target = name return rr, nil, "" } @@ -625,35 +553,26 @@ func setSOA(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { l := <-c rr.Ns = l.token - if l.length == 0 { + if l.length == 0 { // dynamic update rr. return rr, nil, "" } - <-c // zBlank - if l.token == "@" { - rr.Ns = o - } else { - _, ok := IsDomainName(l.token) - if !ok || l.length == 0 || l.err { - return nil, &ParseError{f, "bad SOA Ns", l}, "" - } - if rr.Ns[l.length-1] != '.' { - rr.Ns = appendOrigin(rr.Ns, o) - } + + ns, nsOk := toAbsoluteName(l.token, o) + if l.err || !nsOk { + return nil, &ParseError{f, "bad SOA Ns", l}, "" } + rr.Ns = ns + <-c // zBlank l = <-c rr.Mbox = l.token - if l.token == "@" { - rr.Mbox = o - } else { - _, ok := IsDomainName(l.token) - if !ok || l.length == 0 || l.err { - return nil, &ParseError{f, "bad SOA Mbox", l}, "" - } - if rr.Mbox[l.length-1] != '.' { - rr.Mbox = appendOrigin(rr.Mbox, o) - } + + mbox, mboxOk := toAbsoluteName(l.token, o) + if l.err || !mboxOk { + return nil, &ParseError{f, "bad SOA Mbox", l}, "" } + rr.Mbox = mbox + <-c // zBlank var ( @@ -667,9 +586,10 @@ func setSOA(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { } if j, e := strconv.ParseUint(l.token, 10, 32); e != nil { if i == 0 { - // Serial should be a number + // Serial must be a number return nil, &ParseError{f, "bad SOA zone parameter", l}, "" } + // We allow other fields to be unitful duration strings if v, ok = stringToTtl(l.token); !ok { return nil, &ParseError{f, "bad SOA zone parameter", l}, "" @@ -702,14 +622,16 @@ func setSRV(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { rr.Hdr = h l := <-c - if l.length == 0 { + if l.length == 0 { // dynamic update rr. return rr, nil, "" } + i, e := strconv.ParseUint(l.token, 10, 16) if e != nil || l.err { return nil, &ParseError{f, "bad SRV Priority", l}, "" } rr.Priority = uint16(i) + <-c // zBlank l = <-c // zString i, e = strconv.ParseUint(l.token, 10, 16) @@ -717,6 +639,7 @@ func setSRV(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { return nil, &ParseError{f, "bad SRV Weight", l}, "" } rr.Weight = uint16(i) + <-c // zBlank l = <-c // zString i, e = strconv.ParseUint(l.token, 10, 16) @@ -724,20 +647,16 @@ func setSRV(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { return nil, &ParseError{f, "bad SRV Port", l}, "" } rr.Port = uint16(i) + <-c // zBlank l = <-c // zString rr.Target = l.token - if l.token == "@" { - rr.Target = o - return rr, nil, "" - } - _, ok := IsDomainName(l.token) - if !ok || l.length == 0 || l.err { + + name, nameOk := toAbsoluteName(l.token, o) + if l.err || !nameOk { return nil, &ParseError{f, "bad SRV Target", l}, "" } - if rr.Target[l.length-1] != '.' { - rr.Target = appendOrigin(rr.Target, o) - } + rr.Target = name return rr, nil, "" } @@ -746,14 +665,16 @@ func setNAPTR(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { rr.Hdr = h l := <-c - if l.length == 0 { + if l.length == 0 { // dynamic update rr. return rr, nil, "" } + i, e := strconv.ParseUint(l.token, 10, 16) if e != nil || l.err { return nil, &ParseError{f, "bad NAPTR Order", l}, "" } rr.Order = uint16(i) + <-c // zBlank l = <-c // zString i, e = strconv.ParseUint(l.token, 10, 16) @@ -761,6 +682,7 @@ func setNAPTR(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { return nil, &ParseError{f, "bad NAPTR Preference", l}, "" } rr.Preference = uint16(i) + // Flags <-c // zBlank l = <-c // _QUOTE @@ -817,21 +739,17 @@ func setNAPTR(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { } else { return nil, &ParseError{f, "bad NAPTR Regexp", l}, "" } + // After quote no space?? <-c // zBlank l = <-c // zString rr.Replacement = l.token - if l.token == "@" { - rr.Replacement = o - return rr, nil, "" - } - _, ok := IsDomainName(l.token) - if !ok || l.length == 0 || l.err { + + name, nameOk := toAbsoluteName(l.token, o) + if l.err || !nameOk { return nil, &ParseError{f, "bad NAPTR Replacement", l}, "" } - if rr.Replacement[l.length-1] != '.' { - rr.Replacement = appendOrigin(rr.Replacement, o) - } + rr.Replacement = name return rr, nil, "" } @@ -841,34 +759,26 @@ func setTALINK(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { l := <-c rr.PreviousName = l.token - if l.length == 0 { + if l.length == 0 { // dynamic update rr. return rr, nil, "" } - if l.token == "@" { - rr.PreviousName = o - } else { - _, ok := IsDomainName(l.token) - if !ok || l.length == 0 || l.err { - return nil, &ParseError{f, "bad TALINK PreviousName", l}, "" - } - if rr.PreviousName[l.length-1] != '.' { - rr.PreviousName = appendOrigin(rr.PreviousName, o) - } + + previousName, previousNameOk := toAbsoluteName(l.token, o) + if l.err || !previousNameOk { + return nil, &ParseError{f, "bad TALINK PreviousName", l}, "" } + rr.PreviousName = previousName + <-c // zBlank l = <-c rr.NextName = l.token - if l.token == "@" { - rr.NextName = o - return rr, nil, "" - } - _, ok := IsDomainName(l.token) - if !ok || l.length == 0 || l.err { + + nextName, nextNameOk := toAbsoluteName(l.token, o) + if l.err || !nextNameOk { return nil, &ParseError{f, "bad TALINK NextName", l}, "" } - if rr.NextName[l.length-1] != '.' { - rr.NextName = appendOrigin(rr.NextName, o) - } + rr.NextName = nextName + return rr, nil, "" } @@ -880,9 +790,10 @@ func setLOC(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { rr.VertPre = 162 // 10 rr.Size = 18 // 1 ok := false + // North l := <-c - if l.length == 0 { + if l.length == 0 { // dynamic update rr. return rr, nil, "" } i, e := strconv.ParseUint(l.token, 10, 32) @@ -1013,14 +924,16 @@ func setHIP(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { // HitLength is not represented l := <-c - if l.length == 0 { + if l.length == 0 { // dynamic update rr. return rr, nil, l.comment } + i, e := strconv.ParseUint(l.token, 10, 8) if e != nil || l.err { return nil, &ParseError{f, "bad HIP PublicKeyAlgorithm", l}, "" } rr.PublicKeyAlgorithm = uint8(i) + <-c // zBlank l = <-c // zString if l.length == 0 || l.err { @@ -1043,19 +956,11 @@ func setHIP(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { for l.value != zNewline && l.value != zEOF { switch l.value { case zString: - if l.token == "@" { - xs = append(xs, o) - l = <-c - continue - } - _, ok := IsDomainName(l.token) - if !ok || l.length == 0 || l.err { + name, nameOk := toAbsoluteName(l.token, o) + if l.err || !nameOk { return nil, &ParseError{f, "bad HIP RendezvousServers", l}, "" } - if l.token[l.length-1] != '.' { - l.token = appendOrigin(l.token, o) - } - xs = append(xs, l.token) + xs = append(xs, name) case zBlank: // Ok default: @@ -1072,9 +977,10 @@ func setCERT(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { rr.Hdr = h l := <-c - if l.length == 0 { + if l.length == 0 { // dynamic update rr. return rr, nil, l.comment } + if v, ok := StringToCertType[l.token]; ok { rr.Type = v } else if i, e := strconv.ParseUint(l.token, 10, 16); e != nil { @@ -1129,10 +1035,12 @@ func setSIG(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { func setRRSIG(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { rr := new(RRSIG) rr.Hdr = h + l := <-c - if l.length == 0 { + if l.length == 0 { // dynamic update rr. return rr, nil, l.comment } + if t, ok := StringToType[l.tokenUpper]; !ok { if strings.HasPrefix(l.tokenUpper, "TYPE") { t, ok = typeToInt(l.tokenUpper) @@ -1146,6 +1054,7 @@ func setRRSIG(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { } else { rr.TypeCovered = t } + <-c // zBlank l = <-c i, err := strconv.ParseUint(l.token, 10, 8) @@ -1153,6 +1062,7 @@ func setRRSIG(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { return nil, &ParseError{f, "bad RRSIG Algorithm", l}, "" } rr.Algorithm = uint8(i) + <-c // zBlank l = <-c i, err = strconv.ParseUint(l.token, 10, 8) @@ -1160,6 +1070,7 @@ func setRRSIG(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { return nil, &ParseError{f, "bad RRSIG Labels", l}, "" } rr.Labels = uint8(i) + <-c // zBlank l = <-c i, err = strconv.ParseUint(l.token, 10, 32) @@ -1167,6 +1078,7 @@ func setRRSIG(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { return nil, &ParseError{f, "bad RRSIG OrigTtl", l}, "" } rr.OrigTtl = uint32(i) + <-c // zBlank l = <-c if i, err := StringToTime(l.token); err != nil { @@ -1180,6 +1092,7 @@ func setRRSIG(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { } else { rr.Expiration = i } + <-c // zBlank l = <-c if i, err := StringToTime(l.token); err != nil { @@ -1191,6 +1104,7 @@ func setRRSIG(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { } else { rr.Inception = i } + <-c // zBlank l = <-c i, err = strconv.ParseUint(l.token, 10, 16) @@ -1198,25 +1112,22 @@ func setRRSIG(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { return nil, &ParseError{f, "bad RRSIG KeyTag", l}, "" } rr.KeyTag = uint16(i) + <-c // zBlank l = <-c rr.SignerName = l.token - if l.token == "@" { - rr.SignerName = o - } else { - _, ok := IsDomainName(l.token) - if !ok || l.length == 0 || l.err { - return nil, &ParseError{f, "bad RRSIG SignerName", l}, "" - } - if rr.SignerName[l.length-1] != '.' { - rr.SignerName = appendOrigin(rr.SignerName, o) - } + name, nameOk := toAbsoluteName(l.token, o) + if l.err || !nameOk { + return nil, &ParseError{f, "bad RRSIG SignerName", l}, "" } + rr.SignerName = name + s, e, c1 := endingToString(c, "bad RRSIG Signature", f) if e != nil { return nil, e, c1 } rr.Signature = s + return rr, nil, c1 } @@ -1226,20 +1137,15 @@ func setNSEC(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { l := <-c rr.NextDomain = l.token - if l.length == 0 { + if l.length == 0 { // dynamic update rr. return rr, nil, l.comment } - if l.token == "@" { - rr.NextDomain = o - } else { - _, ok := IsDomainName(l.token) - if !ok || l.length == 0 || l.err { - return nil, &ParseError{f, "bad NSEC NextDomain", l}, "" - } - if rr.NextDomain[l.length-1] != '.' { - rr.NextDomain = appendOrigin(rr.NextDomain, o) - } + + name, nameOk := toAbsoluteName(l.token, o) + if l.err || !nameOk { + return nil, &ParseError{f, "bad NSEC NextDomain", l}, "" } + rr.NextDomain = name rr.TypeBitMap = make([]uint16, 0) var ( @@ -1271,9 +1177,10 @@ func setNSEC3(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { rr.Hdr = h l := <-c - if l.length == 0 { + if l.length == 0 { // dynamic update rr. return rr, nil, l.comment } + i, e := strconv.ParseUint(l.token, 10, 8) if e != nil || l.err { return nil, &ParseError{f, "bad NSEC3 Hash", l}, "" @@ -1339,9 +1246,10 @@ func setNSEC3PARAM(h RR_Header, c chan lex, o, f string) (RR, *ParseError, strin rr.Hdr = h l := <-c - if l.length == 0 { + if l.length == 0 { // dynamic update rr. return rr, nil, "" } + i, e := strconv.ParseUint(l.token, 10, 8) if e != nil || l.err { return nil, &ParseError{f, "bad NSEC3PARAM Hash", l}, "" @@ -1373,9 +1281,10 @@ func setEUI48(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { rr.Hdr = h l := <-c - if l.length == 0 { + if l.length == 0 { // dynamic update rr. return rr, nil, "" } + if l.length != 17 || l.err { return nil, &ParseError{f, "bad EUI48 Address", l}, "" } @@ -1405,9 +1314,10 @@ func setEUI64(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { rr.Hdr = h l := <-c - if l.length == 0 { + if l.length == 0 { // dynamic update rr. return rr, nil, "" } + if l.length != 23 || l.err { return nil, &ParseError{f, "bad EUI64 Address", l}, "" } @@ -1437,9 +1347,10 @@ func setSSHFP(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { rr.Hdr = h l := <-c - if l.length == 0 { + if l.length == 0 { // dynamic update rr. return rr, nil, "" } + i, e := strconv.ParseUint(l.token, 10, 8) if e != nil || l.err { return nil, &ParseError{f, "bad SSHFP Algorithm", l}, "" @@ -1466,9 +1377,10 @@ func setDNSKEYs(h RR_Header, c chan lex, o, f, typ string) (RR, *ParseError, str rr.Hdr = h l := <-c - if l.length == 0 { + if l.length == 0 { // dynamic update rr. return rr, nil, l.comment } + i, e := strconv.ParseUint(l.token, 10, 16) if e != nil || l.err { return nil, &ParseError{f, "bad " + typ + " Flags", l}, "" @@ -1522,9 +1434,10 @@ func setRKEY(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { rr.Hdr = h l := <-c - if l.length == 0 { + if l.length == 0 { // dynamic update rr. return rr, nil, l.comment } + i, e := strconv.ParseUint(l.token, 10, 16) if e != nil || l.err { return nil, &ParseError{f, "bad RKEY Flags", l}, "" @@ -1577,10 +1490,12 @@ func setNIMLOC(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { func setGPOS(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { rr := new(GPOS) rr.Hdr = h + l := <-c - if l.length == 0 { + if l.length == 0 { // dynamic update rr. return rr, nil, "" } + _, e := strconv.ParseFloat(l.token, 64) if e != nil || l.err { return nil, &ParseError{f, "bad GPOS Longitude", l}, "" @@ -1606,10 +1521,12 @@ func setGPOS(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { func setDSs(h RR_Header, c chan lex, o, f, typ string) (RR, *ParseError, string) { rr := new(DS) rr.Hdr = h + l := <-c - if l.length == 0 { + if l.length == 0 { // dynamic update rr. return rr, nil, l.comment } + i, e := strconv.ParseUint(l.token, 10, 16) if e != nil || l.err { return nil, &ParseError{f, "bad " + typ + " KeyTag", l}, "" @@ -1665,10 +1582,12 @@ func setCDS(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { func setTA(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { rr := new(TA) rr.Hdr = h + l := <-c - if l.length == 0 { + if l.length == 0 { // dynamic update rr. return rr, nil, l.comment } + i, e := strconv.ParseUint(l.token, 10, 16) if e != nil || l.err { return nil, &ParseError{f, "bad TA KeyTag", l}, "" @@ -1703,10 +1622,12 @@ func setTA(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { func setTLSA(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { rr := new(TLSA) rr.Hdr = h + l := <-c - if l.length == 0 { + if l.length == 0 { // dynamic update rr. return rr, nil, l.comment } + i, e := strconv.ParseUint(l.token, 10, 8) if e != nil || l.err { return nil, &ParseError{f, "bad TLSA Usage", l}, "" @@ -1738,10 +1659,12 @@ func setTLSA(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { 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 { + if l.length == 0 { // dynamic update rr. 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}, "" @@ -1773,10 +1696,12 @@ func setSMIMEA(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.Hdr = h + l := <-c if l.token != "\\#" { return nil, &ParseError{f, "bad RFC3597 Rdata", l}, "" } + <-c // zBlank l = <-c rdlength, e := strconv.Atoi(l.token) @@ -1850,7 +1775,7 @@ func setURI(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { rr.Hdr = h l := <-c - if l.length == 0 { // Dynamic updates. + if l.length == 0 { // dynamic update rr. return rr, nil, "" } @@ -1897,9 +1822,10 @@ func setNID(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { rr.Hdr = h l := <-c - if l.length == 0 { + if l.length == 0 { // dynamic update rr. return rr, nil, "" } + i, e := strconv.ParseUint(l.token, 10, 16) if e != nil || l.err { return nil, &ParseError{f, "bad NID Preference", l}, "" @@ -1920,9 +1846,10 @@ func setL32(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { rr.Hdr = h l := <-c - if l.length == 0 { + if l.length == 0 { // dynamic update rr. return rr, nil, "" } + i, e := strconv.ParseUint(l.token, 10, 16) if e != nil || l.err { return nil, &ParseError{f, "bad L32 Preference", l}, "" @@ -1942,31 +1869,25 @@ func setLP(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { rr.Hdr = h l := <-c - if l.length == 0 { + if l.length == 0 { // dynamic update rr. return rr, nil, "" } + i, e := strconv.ParseUint(l.token, 10, 16) if e != nil || l.err { return nil, &ParseError{f, "bad LP Preference", l}, "" } rr.Preference = uint16(i) + <-c // zBlank l = <-c // zString rr.Fqdn = l.token - if l.length == 0 { - return rr, nil, "" - } - if l.token == "@" { - rr.Fqdn = o - return rr, nil, "" - } - _, ok := IsDomainName(l.token) - if !ok || l.length == 0 || l.err { + name, nameOk := toAbsoluteName(l.token, o) + if l.err || !nameOk { return nil, &ParseError{f, "bad LP Fqdn", l}, "" } - if rr.Fqdn[l.length-1] != '.' { - rr.Fqdn = appendOrigin(rr.Fqdn, o) - } + rr.Fqdn = name + return rr, nil, "" } @@ -1975,9 +1896,10 @@ func setL64(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { rr.Hdr = h l := <-c - if l.length == 0 { + if l.length == 0 { // dynamic update rr. return rr, nil, "" } + i, e := strconv.ParseUint(l.token, 10, 16) if e != nil || l.err { return nil, &ParseError{f, "bad L64 Preference", l}, "" @@ -1996,10 +1918,12 @@ func setL64(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { func setUID(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { rr := new(UID) rr.Hdr = h + l := <-c - if l.length == 0 { + if l.length == 0 { // dynamic update rr. return rr, nil, "" } + i, e := strconv.ParseUint(l.token, 10, 32) if e != nil || l.err { return nil, &ParseError{f, "bad UID Uid", l}, "" @@ -2011,10 +1935,12 @@ func setUID(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { func setGID(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { rr := new(GID) rr.Hdr = h + l := <-c - if l.length == 0 { + if l.length == 0 { // dynamic update rr. return rr, nil, "" } + i, e := strconv.ParseUint(l.token, 10, 32) if e != nil || l.err { return nil, &ParseError{f, "bad GID Gid", l}, "" @@ -2026,6 +1952,7 @@ func setGID(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { func setUINFO(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { rr := new(UINFO) rr.Hdr = h + s, e, c1 := endingToTxtSlice(c, "bad UINFO Uinfo", f) if e != nil { return nil, e, c1 @@ -2042,55 +1969,46 @@ func setPX(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { rr.Hdr = h l := <-c - if l.length == 0 { + if l.length == 0 { // dynamic update rr. return rr, nil, "" } + i, e := strconv.ParseUint(l.token, 10, 16) if e != nil || l.err { return nil, &ParseError{f, "bad PX Preference", l}, "" } rr.Preference = uint16(i) + <-c // zBlank l = <-c // zString rr.Map822 = l.token - if l.length == 0 { - return rr, nil, "" - } - if l.token == "@" { - rr.Map822 = o - return rr, nil, "" - } - _, ok := IsDomainName(l.token) - if !ok || l.length == 0 || l.err { + map822, map822Ok := toAbsoluteName(l.token, o) + if l.err || !map822Ok { return nil, &ParseError{f, "bad PX Map822", l}, "" } - if rr.Map822[l.length-1] != '.' { - rr.Map822 = appendOrigin(rr.Map822, o) - } + rr.Map822 = map822 + <-c // zBlank l = <-c // zString rr.Mapx400 = l.token - if l.token == "@" { - rr.Mapx400 = o - return rr, nil, "" - } - _, ok = IsDomainName(l.token) - if !ok || l.length == 0 || l.err { + mapx400, mapx400Ok := toAbsoluteName(l.token, o) + if l.err || !mapx400Ok { return nil, &ParseError{f, "bad PX Mapx400", l}, "" } - if rr.Mapx400[l.length-1] != '.' { - rr.Mapx400 = appendOrigin(rr.Mapx400, o) - } + rr.Mapx400 = mapx400 + return rr, nil, "" } func setCAA(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { rr := new(CAA) rr.Hdr = h + l := <-c - if l.length == 0 { + if l.length == 0 { // dynamic update rr. return rr, nil, l.comment } + i, err := strconv.ParseUint(l.token, 10, 8) if err != nil || l.err { return nil, &ParseError{f, "bad CAA Flag", l}, "" diff --git a/vendor/github.com/miekg/dns/scan_test.go b/vendor/github.com/miekg/dns/scan_test.go index b31c4c779..e43ad4478 100644 --- a/vendor/github.com/miekg/dns/scan_test.go +++ b/vendor/github.com/miekg/dns/scan_test.go @@ -21,13 +21,16 @@ func TestParseZoneInclude(t *testing.T) { t.Fatalf("could not close tmpfile %q: %s", tmpfile.Name(), err) } - zone := "$INCLUDE " + tmpfile.Name() + zone := "$ORIGIN example.org.\n$INCLUDE " + tmpfile.Name() tok := ParseZone(strings.NewReader(zone), "", "") for x := range tok { if x.Error != nil { t.Fatalf("expected no error, but got %s", x.Error) } + if x.RR.Header().Name != "foo.example.org." { + t.Fatalf("expected %s, but got %s", "foo.example.org.", x.RR.Header().Name) + } } os.Remove(tmpfile.Name()) diff --git a/vendor/github.com/miekg/dns/server_test.go b/vendor/github.com/miekg/dns/server_test.go index f17a2f90f..b74f2f1a8 100644 --- a/vendor/github.com/miekg/dns/server_test.go +++ b/vendor/github.com/miekg/dns/server_test.go @@ -30,6 +30,16 @@ func HelloServerBadID(w ResponseWriter, req *Msg) { w.WriteMsg(m) } +func HelloServerEchoAddrPort(w ResponseWriter, req *Msg) { + m := new(Msg) + m.SetReply(req) + + remoteAddr := w.RemoteAddr().String() + m.Extra = make([]RR, 1) + m.Extra[0] = &TXT{Hdr: RR_Header{Name: m.Question[0].Name, Rrtype: TypeTXT, Class: ClassINET, Ttl: 0}, Txt: []string{remoteAddr}} + w.WriteMsg(m) +} + func AnotherHelloServer(w ResponseWriter, req *Msg) { m := new(Msg) m.SetReply(req) diff --git a/vendor/github.com/miekg/dns/udp.go b/vendor/github.com/miekg/dns/udp.go index af111b9a8..12a209678 100644 --- a/vendor/github.com/miekg/dns/udp.go +++ b/vendor/github.com/miekg/dns/udp.go @@ -27,8 +27,19 @@ func ReadFromSessionUDP(conn *net.UDPConn, b []byte) (int, *SessionUDP, error) { return n, &SessionUDP{raddr, oob[:oobn]}, err } -// WriteToSessionUDP acts just like net.UDPConn.WritetTo(), but uses a *SessionUDP instead of a net.Addr. +// WriteToSessionUDP acts just like net.UDPConn.WriteTo(), 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) + oob := correctSource(session.context) + n, _, err := conn.WriteMsgUDP(b, oob, session.raddr) return n, err } + +// correctSource takes oob data and returns new oob data with the Src equal to the Dst +func correctSource(oob []byte) []byte { + dst, err := parseUDPSocketDst(oob) + // If the destination could not be determined, ignore. + if err != nil || dst == nil { + return nil + } + return marshalUDPSocketSrc(dst) +} diff --git a/vendor/github.com/miekg/dns/udp_linux.go b/vendor/github.com/miekg/dns/udp_linux.go index 033df4239..13747ed34 100644 --- a/vendor/github.com/miekg/dns/udp_linux.go +++ b/vendor/github.com/miekg/dns/udp_linux.go @@ -13,8 +13,34 @@ package dns import ( "net" "syscall" + "unsafe" + + "github.com/miekg/dns/internal/socket" +) + +const ( + sizeofInet6Pktinfo = 0x14 + sizeofInetPktinfo = 0xc + protocolIP = 0 + protocolIPv6 = 41 ) +type inetPktinfo struct { + Ifindex int32 + Spec_dst [4]byte /* in_addr */ + Addr [4]byte /* in_addr */ +} + +type inet6Pktinfo struct { + Addr [16]byte /* in6_addr */ + Ifindex int32 +} + +type inetControlMessage struct { + Src net.IP // source address, specifying only + Dst net.IP // destination address, receiving only +} + // 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 { @@ -103,3 +129,92 @@ func getUDPSocketName(conn *net.UDPConn) (syscall.Sockaddr, error) { defer file.Close() return syscall.Getsockname(int(file.Fd())) } + +// marshalInetPacketInfo marshals a ipv4 control message, returning +// the byte slice for the next marshal, if any +func marshalInetPacketInfo(b []byte, cm *inetControlMessage) []byte { + m := socket.ControlMessage(b) + m.MarshalHeader(protocolIP, syscall.IP_PKTINFO, sizeofInetPktinfo) + if cm != nil { + pi := (*inetPktinfo)(unsafe.Pointer(&m.Data(sizeofInetPktinfo)[0])) + if ip := cm.Src.To4(); ip != nil { + copy(pi.Spec_dst[:], ip) + } + } + return m.Next(sizeofInetPktinfo) +} + +// marshalInet6PacketInfo marshals a ipv6 control message, returning +// the byte slice for the next marshal, if any +func marshalInet6PacketInfo(b []byte, cm *inetControlMessage) []byte { + m := socket.ControlMessage(b) + m.MarshalHeader(protocolIPv6, syscall.IPV6_PKTINFO, sizeofInet6Pktinfo) + if cm != nil { + pi := (*inet6Pktinfo)(unsafe.Pointer(&m.Data(sizeofInet6Pktinfo)[0])) + if ip := cm.Src.To16(); ip != nil && ip.To4() == nil { + copy(pi.Addr[:], ip) + } + } + return m.Next(sizeofInet6Pktinfo) +} + +func parseInetPacketInfo(cm *inetControlMessage, b []byte) { + pi := (*inetPktinfo)(unsafe.Pointer(&b[0])) + if len(cm.Dst) < net.IPv4len { + cm.Dst = make(net.IP, net.IPv4len) + } + copy(cm.Dst, pi.Addr[:]) +} + +func parseInet6PacketInfo(cm *inetControlMessage, b []byte) { + pi := (*inet6Pktinfo)(unsafe.Pointer(&b[0])) + if len(cm.Dst) < net.IPv6len { + cm.Dst = make(net.IP, net.IPv6len) + } + copy(cm.Dst, pi.Addr[:]) +} + +// parseUDPSocketDst takes out-of-band data from ReadMsgUDP and parses it for +// the Dst address +func parseUDPSocketDst(oob []byte) (net.IP, error) { + cm := new(inetControlMessage) + ms, err := socket.ControlMessage(oob).Parse() + if err != nil { + return nil, err + } + for _, m := range ms { + lvl, typ, l, err := m.ParseHeader() + if err != nil { + return nil, err + } + if lvl == protocolIPv6 { // IPv6 + if typ == syscall.IPV6_PKTINFO && l >= sizeofInet6Pktinfo { + parseInet6PacketInfo(cm, m.Data(l)) + } + } else if lvl == protocolIP { // IPv4 + if typ == syscall.IP_PKTINFO && l >= sizeofInetPktinfo { + parseInetPacketInfo(cm, m.Data(l)) + } + } + } + return cm.Dst, nil +} + +// marshalUDPSocketSrc takes the given src address and returns out-of-band data +// to give to WriteMsgUDP +func marshalUDPSocketSrc(src net.IP) []byte { + var oob []byte + // If the dst is definitely an ipv6, then use ipv6 control to respond + // otherwise use ipv4 because the ipv6 marshal ignores ipv4 messages. + // See marshalInet6PacketInfo + cm := new(inetControlMessage) + cm.Src = src + if src.To4() == nil { + oob = make([]byte, socket.ControlMessageSpace(sizeofInet6Pktinfo)) + marshalInet6PacketInfo(oob, cm) + } else { + oob = make([]byte, socket.ControlMessageSpace(sizeofInetPktinfo)) + marshalInetPacketInfo(oob, cm) + } + return oob +} diff --git a/vendor/github.com/miekg/dns/udp_linux_test.go b/vendor/github.com/miekg/dns/udp_linux_test.go new file mode 100644 index 000000000..14a8acefd --- /dev/null +++ b/vendor/github.com/miekg/dns/udp_linux_test.go @@ -0,0 +1,68 @@ +// +build linux,!appengine + +package dns + +import ( + "bytes" + "net" + "testing" +) + +func TestParseUDPSocketDst(t *testing.T) { + // dst is :ffff:100.100.100.100 + oob := []byte{36, 0, 0, 0, 0, 0, 0, 0, 41, 0, 0, 0, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 100, 100, 100, 100, 2, 0, 0, 0} + dst, err := parseUDPSocketDst(oob) + if err != nil { + t.Fatalf("error parsing ipv6 oob: %v", err) + } + dst4 := dst.To4() + if dst4 == nil { + t.Errorf("failed to parse ipv4: %v", dst) + } else if dst4.String() != "100.100.100.100" { + t.Errorf("unexpected ipv4: %v", dst4) + } + + // dst is 2001:db8::1 + oob = []byte{36, 0, 0, 0, 0, 0, 0, 0, 41, 0, 0, 0, 50, 0, 0, 0, 32, 1, 13, 184, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0} + dst, err = parseUDPSocketDst(oob) + if err != nil { + t.Fatalf("error parsing ipv6 oob: %v", err) + } + dst6 := dst.To16() + if dst6 == nil { + t.Errorf("failed to parse ipv6: %v", dst) + } else if dst6.String() != "2001:db8::1" { + t.Errorf("unexpected ipv6: %v", dst4) + } + + // dst is 100.100.100.100 but was received on 10.10.10.10 + oob = []byte{28, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 2, 0, 0, 0, 10, 10, 10, 10, 100, 100, 100, 100, 0, 0, 0, 0} + dst, err = parseUDPSocketDst(oob) + if err != nil { + t.Fatalf("error parsing ipv4 oob: %v", err) + } + dst4 = dst.To4() + if dst4 == nil { + t.Errorf("failed to parse ipv4: %v", dst) + } else if dst4.String() != "100.100.100.100" { + t.Errorf("unexpected ipv4: %v", dst4) + } +} + +func TestMarshalUDPSocketSrc(t *testing.T) { + // src is 100.100.100.100 + exoob := []byte{28, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 100, 100, 100, 100, 0, 0, 0, 0, 0, 0, 0, 0} + oob := marshalUDPSocketSrc(net.ParseIP("100.100.100.100")) + if !bytes.Equal(exoob, oob) { + t.Errorf("expected ipv4 oob:\n%v", exoob) + t.Errorf("actual ipv4 oob:\n%v", oob) + } + + // src is 2001:db8::1 + exoob = []byte{36, 0, 0, 0, 0, 0, 0, 0, 41, 0, 0, 0, 50, 0, 0, 0, 32, 1, 13, 184, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0} + oob = marshalUDPSocketSrc(net.ParseIP("2001:db8::1")) + if !bytes.Equal(exoob, oob) { + t.Errorf("expected ipv6 oob:\n%v", exoob) + t.Errorf("actual ipv6 oob:\n%v", oob) + } +} diff --git a/vendor/github.com/miekg/dns/udp_other.go b/vendor/github.com/miekg/dns/udp_other.go index 488a282b2..531f4ebcc 100644 --- a/vendor/github.com/miekg/dns/udp_other.go +++ b/vendor/github.com/miekg/dns/udp_other.go @@ -9,7 +9,9 @@ import ( // 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. -func setUDPSocketOptions(conn *net.UDPConn) error { return nil } -func setUDPSocketOptions4(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 setUDPSocketOptions(conn *net.UDPConn) error { return nil } +func setUDPSocketOptions4(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 parseUDPSocketDst(oob []byte) (net.IP, error) { return nil, nil } +func marshalUDPSocketSrc(src net.IP) []byte { return nil } diff --git a/vendor/github.com/miekg/dns/udp_windows.go b/vendor/github.com/miekg/dns/udp_windows.go index 51e532ac2..2ad4ede7f 100644 --- a/vendor/github.com/miekg/dns/udp_windows.go +++ b/vendor/github.com/miekg/dns/udp_windows.go @@ -4,10 +4,12 @@ package dns import "net" +// SessionUDP holds the remote address type SessionUDP struct { raddr *net.UDPAddr } +// 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 @@ -21,9 +23,8 @@ func ReadFromSessionUDP(conn *net.UDPConn, b []byte) (int, *SessionUDP, error) { return n, session, err } -// WriteToSessionUDP acts just like net.UDPConn.WritetTo(), but uses a *SessionUDP instead of a net.Addr. +// WriteToSessionUDP acts just like net.UDPConn.WriteTo(), but uses a *SessionUDP instead of a net.Addr. func WriteToSessionUDP(conn *net.UDPConn, b []byte, session *SessionUDP) (int, error) { n, err := conn.WriteTo(b, session.raddr) return n, err } - |