Documentation ¶
Overview ¶
Package dns provides DNS client and server implementations.
A client can handle queries for a net.Dialer:
dialer := &net.Dialer{ Resolver: &net.Resolver{ PreferGo: true, Dial: new(dns.Client).Dial, }, } conn, err := dialer.DialContext(ctx, "tcp", "example.com:80")
It can also query a remote DNS server directly:
client := new(dns.Client) query := &dns.Query{ RemoteAddr: &net.TCPAddr{IP: net.IPv4(8, 8, 8, 8), Port: 53}, Message: &dns.Message{ Questions: []dns.Question{ { Name: "example.com.", Type: dns.TypeA, Class: dns.ClassIN, }, { Name: "example.com.", Type: dns.TypeAAAA, Class: dns.ClassIN, }, }, }, } msg, err := client.Do(ctx, query)
A handler answers queries for a server or a local resolver for a client:
zone := &dns.Zone{ Origin: "localhost.", TTL: 5 * time.Minute, RRs: map[string][]dns.Record{ "alpha": []dns.Record{ &dns.A{net.IPv4(127, 0, 0, 42).To4()}, &dns.AAAA{net.ParseIP("::42")}, }, }, } srv := &dns.Server{ Addr: ":53", Handler: zone, } go srv.ListenAndServe(ctx) mux := new(dns.ResolveMux) mux.Handle(dns.TypeANY, zone.Origin, zone) client := &dns.Client{ Resolver: mux, } net.DefaultResolver = &net.Resolver{ PreferGo: true, Dial: client.Dial, } addrs, err := net.LookupHost("alpha.localhost")
Index ¶
- Constants
- Variables
- func Recursor(ctx context.Context, w MessageWriter, r *Query)
- func Refuse(ctx context.Context, w MessageWriter, r *Query)
- type A
- type AAAA
- type AddrDialer
- type CNAME
- type Cache
- type Class
- type Client
- type Compressor
- type Conn
- type Decompressor
- type Handler
- type HandlerFunc
- type MX
- type Message
- type MessageWriter
- type NS
- type NameServers
- type OpCode
- type OverTLSAddr
- type PTR
- type PacketConn
- type ProxyFunc
- type Query
- type Question
- type RCode
- type Record
- type ResolveMux
- type Resource
- type RoundTripper
- type SOA
- type SRV
- type Server
- func (s *Server) ListenAndServe(ctx context.Context) error
- func (s *Server) ListenAndServeTLS(ctx context.Context) error
- func (s *Server) Serve(ctx context.Context, ln net.Listener) error
- func (s *Server) ServePacket(ctx context.Context, conn net.PacketConn) error
- func (s *Server) ServeTLS(ctx context.Context, ln net.Listener) error
- type StreamConn
- type TXT
- type Transport
- type Type
- type Zone
Examples ¶
Constants ¶
const ( // Resource Record (RR) TYPEs TypeA Type = 1 // [RFC1035] a host address TypeNS Type = 2 // [RFC1035] an authoritative name server TypeCNAME Type = 5 // [RFC1035] the canonical name for an alias TypeSOA Type = 6 // [RFC1035] marks the start of a zone of authority TypeWKS Type = 11 // [RFC1035] a well known service description TypePTR Type = 12 // [RFC1035] a domain name pointer TypeHINFO Type = 13 // [RFC1035] host information TypeMINFO Type = 14 // [RFC1035] mailbox or mail list information TypeMX Type = 15 // [RFC1035] mail exchange TypeTXT Type = 16 // [RFC1035] text strings TypeAAAA Type = 28 // [RFC3596] IP6 Address TypeSRV Type = 33 // [RFC2782] Server Selection TypeAXFR Type = 252 // [RFC1035][RFC5936] transfer of an entire zone TypeALL Type = 255 // [RFC1035][RFC6895] A request for all records the server/cache has available TypeANY Type = 0 // DNS CLASSes ClassIN Class = 1 // [RFC1035] Internet (IN) ClassCH Class = 3 // [] Chaos (CH) ClassHS Class = 4 // [] Hesiod (HS) ClassANY Class = 255 // [RFC1035] QCLASS * (ANY) // DNS RCODEs NoError RCode = 0 // [RFC1035] No Error FormErr RCode = 1 // [RFC1035] Format Error ServFail RCode = 2 // [RFC1035] Server Failure NXDomain RCode = 3 // [RFC1035] Non-Existent Domain NotImp RCode = 4 // [RFC1035] Not Implemented Refused RCode = 5 // [RFC1035] Query Refused )
Domain Name System (DNS) Parameters.
Taken from https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml
Variables ¶
var ( // ErrConflictingID is a pipelining error due to the same message ID being // used for more than one inflight query. ErrConflictingID = errors.New("conflicting message id") // ErrOversizedMessage is an error returned when attempting to send a // message that is longer than the maximum allowed number of bytes. ErrOversizedMessage = errors.New("oversized message") // ErrTruncatedMessage indicates the response message has been truncated. ErrTruncatedMessage = errors.New("truncated message") // ErrUnsupportedNetwork is returned when DialAddr is called with an // unknown network. ErrUnsupportedNetwork = errors.New("unsupported network") // ErrUnsupportedOp indicates the operation is not supported by callee. ErrUnsupportedOp = errors.New("unsupported operation") )
var ( // ErrNotStarted indicates that the prerequisite information isn't // available yet because the previous records haven't been appropriately // parsed or skipped. ErrNotStarted = errors.New("parsing of this type isn't available yet") // ErrSectionDone indicated that all records in the section have been // parsed. ErrSectionDone = errors.New("parsing of this section has completed") )
var NewRecordByType = map[Type]func() Record{ TypeA: func() Record { return new(A) }, TypeNS: func() Record { return new(NS) }, TypeCNAME: func() Record { return new(CNAME) }, TypeSOA: func() Record { return new(SOA) }, TypePTR: func() Record { return new(PTR) }, TypeMX: func() Record { return new(MX) }, TypeTXT: func() Record { return new(TXT) }, TypeAAAA: func() Record { return new(AAAA) }, TypeSRV: func() Record { return new(SRV) }, }
NewRecordByType returns a new instance of a Record for a Type.
Functions ¶
Types ¶
type AAAA ¶
AAAA is a DNS AAAA record.
type AddrDialer ¶
AddrDialer dials a net Addr.
type CNAME ¶
type CNAME struct {
CNAME string
}
CNAME is a DNS CNAME record.
func (CNAME) Length ¶
func (c CNAME) Length(com Compressor) int
Length returns the encoded RDATA size.
type Cache ¶
type Cache struct {
// contains filtered or unexported fields
}
Cache is a DNS query cache handler.
type Client ¶
type Client struct { // Transport manages connections to DNS servers. Transport AddrDialer // Resolver is a handler that may answer all or portions of a query. // Any questions answered by the handler are not sent to the upstream // server. Resolver Handler // contains filtered or unexported fields }
Client is a DNS client.
Example (DnsOverTLS) ¶
package main import ( "crypto/rand" "crypto/tls" "net" "github.com/benburkert/dns" ) func main() { dnsLocal := dns.OverTLSAddr{ Addr: &net.TCPAddr{ IP: net.IPv4(192, 168, 8, 8), Port: 853, }, } client := &dns.Client{ Transport: &dns.Transport{ Proxy: dns.NameServers{dnsLocal}.Random(rand.Reader), TLSConfig: &tls.Config{ ServerName: "dns.local", }, }, } net.DefaultResolver = &net.Resolver{ PreferGo: true, Dial: client.Dial, } }
Output:
Example (OverrideNameServers) ¶
package main import ( "fmt" "net" "github.com/benburkert/dns" ) func main() { net.DefaultResolver = &net.Resolver{ PreferGo: true, Dial: (&dns.Client{ Transport: &dns.Transport{ Proxy: dns.NameServers{ &net.UDPAddr{IP: net.IPv4(8, 8, 8, 8), Port: 53}, &net.UDPAddr{IP: net.IPv4(8, 8, 4, 4), Port: 53}, }.RoundRobin(), }, }).Dial, } addrs, err := net.LookupHost("127.0.0.1.xip.io") if err != nil { panic(err) } for _, addr := range addrs { fmt.Println(addr) } }
Output: 127.0.0.1
type Compressor ¶
Compressor encodes domain names.
type Conn ¶
type Conn interface { net.Conn // Recv reads a DNS message from the connection. Recv(msg *Message) error // Send writes a DNS message to the connection. Send(msg *Message) error }
Conn is a network connection to a DNS resolver.
type Decompressor ¶
Decompressor decodes domain names.
type Handler ¶
type Handler interface {
ServeDNS(context.Context, MessageWriter, *Query)
}
Handler responds to a DNS query.
ServeDNS should build the reply message using the MessageWriter, and may optionally call the Reply method. Returning signals that the request is finished and the response is ready to send.
A recursive handler may call the Recur method of the MessageWriter to send an query upstream. Only unanswered questions are included in the upstream query.
type HandlerFunc ¶
type HandlerFunc func(context.Context, MessageWriter, *Query)
The HandlerFunc type is an adapter to allow the use of ordinary functions as DNS handlers. If f is a function with the appropriate signature, HandlerFunc(f) is a Handler that calls f.
func (HandlerFunc) ServeDNS ¶
func (f HandlerFunc) ServeDNS(ctx context.Context, w MessageWriter, r *Query)
ServeDNS calls f(w, r).
type MX ¶
MX is a DNS MX record.
type Message ¶
type Message struct { ID int Response bool OpCode OpCode Authoritative bool Truncated bool RecursionDesired bool RecursionAvailable bool RCode RCode Questions []Question Answers []Resource Authorities []Resource Additionals []Resource }
Message is a DNS message.
type MessageWriter ¶
type MessageWriter interface { // Authoritative sets the Authoritative Answer (AA) bit of the header. Authoritative(bool) // Recursion sets the Recursion Available (RA) bit of the header. Recursion(bool) // Status sets the Response code (RCODE) bits of the header. Status(RCode) // Answer adds a record to the answers section. Answer(string, time.Duration, Record) // Authority adds a record to the authority section. Authority(string, time.Duration, Record) // Additional adds a record to the additional section Additional(string, time.Duration, Record) // Recur forwards the request query upstream, and returns the response // message or error. Recur(context.Context) (*Message, error) // Reply sends the response message. // // For large messages sent over a UDP connection, an ErrTruncatedMessage // error is returned if the message was truncated. Reply(context.Context) error }
MessageWriter is used by a DNS handler to serve a DNS query.
type NS ¶
type NS struct {
NS string
}
NS is a DNS MX record.
type NameServers ¶
NameServers is a slice of DNS nameserver addresses.
func (NameServers) Random ¶
func (s NameServers) Random(rand io.Reader) ProxyFunc
Random picks a random Addr from s every time.
func (NameServers) RoundRobin ¶
func (s NameServers) RoundRobin() ProxyFunc
RoundRobin picks the next Addr of s by index of the last pick.
type OverTLSAddr ¶
OverTLSAddr indicates the remote DNS service implements DNS-over-TLS as defined in RFC 7858.
func (OverTLSAddr) Network ¶
func (a OverTLSAddr) Network() string
Network returns the address's network name with a "-tls" suffix.
type PTR ¶
type PTR struct {
PTR string
}
PTR is a DNS PTR record.
type PacketConn ¶
PacketConn is a packet-oriented network connection to a DNS resolver that expects transmitted messages to adhere to RFC 1035 Section 4.2.1. "UDP usage".
func (*PacketConn) Recv ¶
func (c *PacketConn) Recv(msg *Message) error
Recv reads a DNS message from the underlying connection.
func (*PacketConn) Send ¶
func (c *PacketConn) Send(msg *Message) error
Send writes a DNS message to the underlying connection.
type Question ¶
A Question is a DNS query.
type Record ¶
type Record interface { Type() Type Length(Compressor) int Pack([]byte, Compressor) ([]byte, error) Unpack([]byte, Decompressor) ([]byte, error) }
Record is a DNS record.
type ResolveMux ¶
type ResolveMux struct {
// contains filtered or unexported fields
}
ResolveMux is a DNS query multiplexer. It matches a question type and name suffix to a Handler.
func (*ResolveMux) Handle ¶
func (m *ResolveMux) Handle(typ Type, suffix string, h Handler)
Handle registers the handler for the given question type and name suffix.
func (*ResolveMux) ServeDNS ¶
func (m *ResolveMux) ServeDNS(ctx context.Context, w MessageWriter, r *Query)
ServeDNS dispatches the query to the handler(s) whose pattern most closely matches each question.
type Resource ¶
Resource is a DNS resource record (RR).
type RoundTripper ¶
RoundTripper is an interface representing the ability to execute a single DNS transaction, obtaining a response Message for a given Query.
type SOA ¶
type SOA struct { NS string MBox string Serial int Refresh time.Duration Retry time.Duration Expire time.Duration MinTTL time.Duration }
SOA is a DNS SOA record.
type SRV ¶
type SRV struct { Priority int Weight int Port int Target string // Not compressed as per RFC 2782. }
SRV is a DNS SRV record.
type Server ¶
type Server struct { Addr string // TCP and UDP address to listen on, ":domain" if empty Handler Handler // handler to invoke TLSConfig *tls.Config // optional TLS config, used by ListenAndServeTLS // Forwarder relays a recursive query. If nil, recursive queries are // answered with a "Query Refused" message. Forwarder RoundTripper // ErrorLog specifies an optional logger for errors accepting connections, // reading data, and unpacking messages. // If nil, logging is done via the log package's standard logger. ErrorLog *log.Logger }
A Server defines parameters for running a DNS server. The zero value for Server is a valid configuration.
Example (Authoritative) ¶
package main import ( "context" "fmt" "log" "net" "time" "github.com/benburkert/dns" ) func main() { customTLD := &dns.Zone{ Origin: "tld.", TTL: time.Hour, SOA: &dns.SOA{ NS: "dns.tld.", MBox: "hostmaster.tld.", Serial: 1234, }, RRs: map[string][]dns.Record{ "1.app": { &dns.A{A: net.IPv4(10, 42, 0, 1).To4()}, &dns.AAAA{AAAA: net.ParseIP("dead:beef::1")}, }, "2.app": { &dns.A{A: net.IPv4(10, 42, 0, 2).To4()}, &dns.AAAA{AAAA: net.ParseIP("dead:beef::2")}, }, "3.app": { &dns.A{A: net.IPv4(10, 42, 0, 3).To4()}, &dns.AAAA{AAAA: net.ParseIP("dead:beef::3")}, }, "app": { &dns.A{A: net.IPv4(10, 42, 0, 1).To4()}, &dns.A{A: net.IPv4(10, 42, 0, 2).To4()}, &dns.A{A: net.IPv4(10, 42, 0, 3).To4()}, &dns.AAAA{AAAA: net.ParseIP("dead:beef::1")}, &dns.AAAA{AAAA: net.ParseIP("dead:beef::2")}, &dns.AAAA{AAAA: net.ParseIP("dead:beef::3")}, }, }, } srv := &dns.Server{ Addr: ":53351", Handler: customTLD, } go srv.ListenAndServe(context.Background()) time.Sleep(100 * time.Millisecond) // wait for bind() addr, err := net.ResolveTCPAddr("tcp", srv.Addr) if err != nil { log.Fatal(err) } query := &dns.Query{ RemoteAddr: addr, Message: &dns.Message{ Questions: []dns.Question{ { Name: "app.tld.", Type: dns.TypeA, Class: dns.ClassIN, }, { Name: "app.tld.", Type: dns.TypeAAAA, Class: dns.ClassIN, }, }, }, } res, err := new(dns.Client).Do(context.Background(), query) if err != nil { log.Fatal(err) } for _, answer := range res.Answers { switch rec := answer.Record.(type) { case *dns.A: fmt.Println(rec.A) case *dns.AAAA: fmt.Println(rec.AAAA) default: fmt.Println(rec) } } }
Output: 10.42.0.1 10.42.0.2 10.42.0.3 dead:beef::1 dead:beef::2 dead:beef::3
Example (Recursive) ¶
package main import ( "context" "fmt" "log" "net" "time" "github.com/benburkert/dns" ) func main() { srv := &dns.Server{ Addr: ":53352", Handler: dns.HandlerFunc(dns.Recursor), Forwarder: &dns.Client{ Transport: &dns.Transport{ Proxy: dns.NameServers{ &net.UDPAddr{IP: net.IPv4(8, 8, 8, 8), Port: 53}, &net.UDPAddr{IP: net.IPv4(8, 8, 4, 4), Port: 53}, }.RoundRobin(), }, Resolver: new(dns.Cache), }, } go srv.ListenAndServe(context.Background()) time.Sleep(100 * time.Millisecond) // wait for bind() addr, err := net.ResolveTCPAddr("tcp", srv.Addr) if err != nil { log.Fatal(err) } query := &dns.Query{ RemoteAddr: addr, Message: &dns.Message{ RecursionDesired: true, Questions: []dns.Question{ { Name: "127.1.2.3.xip.io.", Type: dns.TypeA, Class: dns.ClassIN, }, }, }, } res, err := new(dns.Client).Do(context.Background(), query) if err != nil { log.Fatal(err) } for _, answer := range res.Answers { switch rec := answer.Record.(type) { case *dns.A: fmt.Println(rec.A) default: fmt.Println(rec) } } }
Output: 127.1.2.3
Example (RecursiveWithZone) ¶
package main import ( "context" "fmt" "log" "net" "time" "github.com/benburkert/dns" ) func main() { customTLD := &dns.Zone{ Origin: "tld.", RRs: map[string][]dns.Record{ "foo": { &dns.A{A: net.IPv4(127, 0, 0, 1).To4()}, }, }, } mux := new(dns.ResolveMux) mux.Handle(dns.TypeANY, "tld.", customTLD) srv := &dns.Server{ Addr: ":53353", Handler: mux, Forwarder: &dns.Client{ Transport: &dns.Transport{ Proxy: dns.NameServers{ &net.UDPAddr{IP: net.IPv4(8, 8, 8, 8), Port: 53}, &net.UDPAddr{IP: net.IPv4(8, 8, 4, 4), Port: 53}, }.RoundRobin(), }, Resolver: new(dns.Cache), }, } go srv.ListenAndServe(context.Background()) time.Sleep(100 * time.Millisecond) // wait for bind() addr, err := net.ResolveTCPAddr("tcp", srv.Addr) if err != nil { log.Fatal(err) } query := &dns.Query{ RemoteAddr: addr, Message: &dns.Message{ RecursionDesired: true, Questions: []dns.Question{ { Name: "127.0.0.127.xip.io.", Type: dns.TypeA, Class: dns.ClassIN, }, { Name: "foo.tld.", Type: dns.TypeA, Class: dns.ClassIN, }, }, }, } res, err := new(dns.Client).Do(context.Background(), query) if err != nil { log.Fatal(err) } for _, answer := range res.Answers { switch rec := answer.Record.(type) { case *dns.A: fmt.Println(rec.A) default: fmt.Println(rec) } } }
Output: 127.0.0.127 127.0.0.1
func (*Server) ListenAndServe ¶
ListenAndServe listens on both the TCP and UDP network address s.Addr and then calls Serve or ServePacket to handle queries on incoming connections. If srv.Addr is blank, ":domain" is used. ListenAndServe always returns a non-nil error.
func (*Server) ListenAndServeTLS ¶
ListenAndServeTLS listens on the TCP network address s.Addr and then calls Serve to handle requests on incoming TLS connections.
If s.Addr is blank, ":853" is used.
ListenAndServeTLS always returns a non-nil error.
func (*Server) Serve ¶
Serve accepts incoming connections on the Listener ln, creating a new service goroutine for each. The service goroutines read TCP encoded queries and then call s.Handler to reply to them.
See RFC 1035, section 4.2.2 "TCP usage" for transport encoding of messages.
Serve always returns a non-nil error.
func (*Server) ServePacket ¶
ServePacket reads UDP encoded queries from the PacketConn conn, creating a new service goroutine for each. The service goroutines call s.Handler to reply.
See RFC 1035, section 4.2.1 "UDP usage" for transport encoding of messages.
ServePacket always returns a non-nil error.
func (*Server) ServeTLS ¶
ServeTLS accepts incoming connections on the Listener ln, creating a new service goroutine for each. The service goroutines read TCP encoded queries over a TLS channel and then call s.Handler to reply to them, in another service goroutine.
See RFC 7858, section 3.3 for transport encoding of messages.
ServeTLS always returns a non-nil error.
type StreamConn ¶
StreamConn is a stream-oriented network connection to a DNS resolver that expects transmitted messages to adhere to RFC 1035 Section 4.2.2. "TCP usage".
func (*StreamConn) Recv ¶
func (c *StreamConn) Recv(msg *Message) error
Recv reads a DNS message from the underlying connection.
func (*StreamConn) Send ¶
func (c *StreamConn) Send(msg *Message) error
Send writes a DNS message to the underlying connection.
type TXT ¶
type TXT struct {
TXT []string
}
TXT is a DNS TXT record.
type Transport ¶
type Transport struct { TLSConfig *tls.Config // optional TLS config, used by DialAddr // DialContext func creates the underlying net connection. The DialContext // method of a new net.Dialer is used by default. DialContext func(context.Context, string, string) (net.Conn, error) // Proxy modifies the address of the DNS server to dial. Proxy ProxyFunc // DisablePipelining disables query pipelining for stream oriented // connections as defined in RFC 7766, section 6.2.1.1. DisablePipelining bool // contains filtered or unexported fields }
Transport is an implementation of AddrDialer that manages connections to DNS servers. Transport may modify the sending and receiving of messages but does not modify messages.