dns

package
v0.55.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 21, 2024 License: BSD-3-Clause Imports: 29 Imported by: 0

Documentation

Overview

Package dns implement DNS client and server.

This library implemented in reference to,

  • RFC1034 DOMAIN NAMES - CONCEPTS AND FACILITIES
  • RFC1035 DOMAIN NAMES - IMPLEMENTATION AND SPECIFICATION
  • RFC1886 DNS Extensions to support IP version 6.
  • RFC2782 A DNS RR for specifying the location of services (DNS SRV)
  • RFC6891 Extension Mechanisms for DNS (EDNS(0))
  • RFC8484 DNS Queries over HTTPS (DoH)
  • RFC9460 Service Binding and Parameter Specification via the DNS (SVCB and HTTPS Resource Records)

Index

Examples

Constants

View Source
const (
	// DefaultPort define default DNS remote or listen port for UDP and
	// TCP connection.
	DefaultPort uint16 = 53

	// DefaultTLSPort define default remote and listen port for DNS over
	// TLS.
	DefaultTLSPort uint16 = 853

	// DefaultHTTPPort define default port for DNS over HTTPS.
	DefaultHTTPPort uint16 = 443
)
View Source
const (
	HostsFilePOSIX   = "/etc/hosts"
	HostsFileWindows = "C:\\Windows\\System32\\Drivers\\etc\\hosts"
)

List of known hosts file by OS.

View Source
const (
	DefaultSoaRName   string = `root`
	DefaultSoaRefresh int32  = 1 * 24 * 60 * 60 // 1 Day.
	DefaultSoaRetry   int32  = 1 * 60 * 60      // 1 Hour.

	DefaultSoaMinimumTTL uint32 = 1 * 60 * 60 // 1 Hour.
)

Default SOA record value.

View Source
const (
	// Log error on DNS level, in example EMPTY answer, ERR_NAME,
	// ERR_NOT_IMPLEMENTED, ERR_REFUSED.
	DebugLevelDNS = 1

	// Log cache operations, including new record, updating records,
	// and pruning record in caches.
	DebugLevelCache = 2

	// Log low level DNS connection and packet, including request and
	// response.
	DebugLevelConnPacket = 4
)

List of ServerOptions Debug mode. For example, to log DNS error and cache operations, set the Debug value to 3 or (DebugLevelDNS|DebugLevelCache).

Variables

View Source
var (
	ErrNewConnection  = errors.New("lookup: can't create new connection")
	ErrLabelSizeLimit = errors.New("labels should be 63 octet or less")
	ErrInvalidAddress = errors.New("invalid address")
	ErrIPv4Length     = errors.New("invalid length of A RDATA format")
	ErrIPv6Length     = errors.New("invalid length of AAAA RDATA format")
)

List of error messages.

View Source
var RecordClassName = map[RecordClass]string{
	RecordClassCH: "CH",
	RecordClassHS: "HS",
	RecordClassIN: "IN",
}

RecordClassName contains a mapping between the record class value and its string representation, ordered by key alphabetically.

View Source
var RecordClasses = map[string]RecordClass{
	"CH": RecordClassCH,
	"HS": RecordClassHS,
	"IN": RecordClassIN,
}

RecordClasses contains a mapping between string representation of record class to their numeric value, ordered by key alphabetically.

View Source
var RecordTypeNames = map[RecordType]string{
	RecordTypeA:     "A",
	RecordTypeAAAA:  "AAAA",
	RecordTypeANY:   `ANY`,
	RecordTypeAXFR:  "AXFR",
	RecordTypeCNAME: "CNAME",
	RecordTypeHINFO: "HINFO",
	RecordTypeHTTPS: `HTTPS`,
	RecordTypeMAILA: "MAILA",
	RecordTypeMAILB: "MAILB",
	RecordTypeMB:    "MB",
	RecordTypeMD:    "MD",
	RecordTypeMF:    "MF",
	RecordTypeMG:    "MG",
	RecordTypeMINFO: "MINFO",
	RecordTypeMR:    "MR",
	RecordTypeMX:    "MX",
	RecordTypeNS:    "NS",
	RecordTypeNULL:  "NULL",
	RecordTypeOPT:   "OPT",
	RecordTypePTR:   "PTR",
	RecordTypeSOA:   "SOA",
	RecordTypeSVCB:  `SVCB`,
	RecordTypeSRV:   "SRV",
	RecordTypeTXT:   "TXT",
	RecordTypeWKS:   "WKS",
}

RecordTypeNames contains mapping between record type and and their string representation, ordered alphabetically.

View Source
var RecordTypes = map[string]RecordType{
	"A":     RecordTypeA,
	"AAAA":  RecordTypeAAAA,
	`ANY`:   RecordTypeANY,
	"AXFR":  RecordTypeAXFR,
	"CNAME": RecordTypeCNAME,
	"HINFO": RecordTypeHINFO,
	`HTTPS`: RecordTypeHTTPS,
	"MAILA": RecordTypeMAILA,
	"MAILB": RecordTypeMAILB,
	"MB":    RecordTypeMB,
	"MD":    RecordTypeMD,
	"MF":    RecordTypeMF,
	"MG":    RecordTypeMG,
	"MINFO": RecordTypeMINFO,
	"MR":    RecordTypeMR,
	"MX":    RecordTypeMX,
	"NS":    RecordTypeNS,
	"NULL":  RecordTypeNULL,
	"OPT":   RecordTypeOPT,
	"PTR":   RecordTypePTR,
	"SOA":   RecordTypeSOA,
	`SVCB`:  RecordTypeSVCB,
	"SRV":   RecordTypeSRV,
	"TXT":   RecordTypeTXT,
	"WKS":   RecordTypeWKS,
}

RecordTypes contains a mapping between string representation of DNS record type with their numeric value, ordered by key alphabetically.

Functions

func GetSystemHosts

func GetSystemHosts() string

GetSystemHosts return path to system hosts file.

func GetSystemNameServers

func GetSystemNameServers(path string) []string

GetSystemNameServers return list of system name servers by reading resolv.conf formatted file in path.

Default path is "/etc/resolv.conf".

func LoadHostsDir

func LoadHostsDir(dir string) (hostsFiles map[string]*HostsFile, err error)

LoadHostsDir load all of hosts formatted files inside a directory. On success, it will return map of filename and the content of hosts file as list of Message. On fail, it will return partial loadeded hosts files and an error.

func LoadZoneDir

func LoadZoneDir(dir string) (zoneFiles map[string]*Zone, err error)

LoadZoneDir load DNS record from zone formatted files in directory "dir". On success, it will return map of zone Origin and its content as list of Message. On fail, it will return possible partially parse zone file and an error.

func LookupPTR

func LookupPTR(client Client, ip net.IP) (answer string, err error)

LookupPTR accept an IP address (either IPv4 or IPv6) and return a single answer as domain name on success or an error on failed. If IP address does not contains PTR record it will return an empty string without error.

func ParseNameServers

func ParseNameServers(nameservers []string) (udpAddrs []*net.UDPAddr, err error)

ParseNameServers parse list of nameserver into UDP addresses. If one of nameserver is invalid it will stop parsing and return only valid nameserver addresses with error.

Types

type Answer

type Answer struct {

	// QName contains DNS question name, a copy of msg.Question.Name.
	QName string

	// ReceivedAt contains time when message is received.
	// A zero value indicated local answer (loaded from hosts or zone
	// files).
	ReceivedAt int64

	// AccessedAt contains time when message last accessed.
	// This field is used to prune old answer from caches.
	AccessedAt int64

	// RType contains record type, a copy of msg.Question.Type.
	RType RecordType

	// RClass contains record class, a copy of msg.Question.Class.
	RClass RecordClass
	// contains filtered or unexported fields
}

Answer maintain the record of DNS response for cache.

type Caches

type Caches struct {
	sync.Mutex
	// contains filtered or unexported fields
}

Caches of DNS answers.

There are two type of answer: internal and external. Internal answer is a DNS record that is loaded from hosts or zone files. Internal answer never get pruned. External answer is a DNS record that is received from parent name servers.

func (*Caches) ExternalClear

func (c *Caches) ExternalClear() (listAnswer []*Answer)

ExternalClear remove all external answers.

func (*Caches) ExternalLRU

func (c *Caches) ExternalLRU() (answers []*Answer)

ExternalLRU return list of external caches ordered by the least recently used.

func (*Caches) ExternalLoad

func (c *Caches) ExternalLoad(r io.Reader) (answers []*Answer, err error)

ExternalLoad the gob encoded external answers from r.

func (*Caches) ExternalRemoveNames

func (c *Caches) ExternalRemoveNames(names []string) (listAnswer []*Answer)

ExternalRemoveNames remove external caches by domain names.

func (*Caches) ExternalSave

func (c *Caches) ExternalSave(w io.Writer) (n int, err error)

ExternalSave write all external answers into w, encoded with gob. On success, it returns the number of answers written to w.

func (*Caches) ExternalSearch

func (c *Caches) ExternalSearch(re *regexp.Regexp) (listMsg []*Message)

ExternalSearch search external answers where domain name match with regular expression.

func (*Caches) InternalPopulate

func (c *Caches) InternalPopulate(msgs []*Message, from string)

InternalPopulate add list of message to internal caches.

func (*Caches) InternalPopulateRecords

func (c *Caches) InternalPopulateRecords(listRR []*ResourceRecord, from string) (err error)

InternalPopulateRecords update or insert new ResourceRecord into internal caches.

func (*Caches) InternalPopulateZone

func (c *Caches) InternalPopulateZone(zone *Zone)

InternalPopulateZone populate the internal caches from Zone.

func (*Caches) InternalRemoveNames

func (c *Caches) InternalRemoveNames(names []string)

InternalRemoveNames remove internal caches by domain names.

func (*Caches) InternalRemoveRecord

func (c *Caches) InternalRemoveRecord(rr *ResourceRecord) (rrOut *ResourceRecord, err error)

InternalRemoveRecord remove the answer from caches by ResourceRecord name, type, class, and value.

type Client

type Client interface {
	Close() error
	Lookup(q MessageQuestion, allowRecursion bool) (*Message, error)
	Query(req *Message) (*Message, error)
	RemoteAddr() string
	SetRemoteAddr(addr string) error
	SetTimeout(t time.Duration)
}

Client is interface that implement sending and receiving DNS message.

func NewClient

func NewClient(nsURL string, isInsecure bool) (cl Client, err error)

NewClient create new DNS client using the name server URL. The name server URL is defined in the same format as ServerOptions.NameServers. The isInsecure parameter only usable for DNS over TLS (DoT) and DNS over HTTPS (DoH).

For example,

type DoHClient

type DoHClient struct {
	// contains filtered or unexported fields
}

DoHClient client for DNS over HTTPS.

func NewDoHClient

func NewDoHClient(nameserver string, allowInsecure bool) (cl *DoHClient, err error)

NewDoHClient will create new DNS client with HTTP connection.

func (*DoHClient) Close

func (cl *DoHClient) Close() error

Close all idle connections.

func (*DoHClient) Get

func (cl *DoHClient) Get(msg *Message) (res *Message, err error)

Get send query to name server using HTTP GET and return the response as unpacked message.

func (*DoHClient) Lookup

func (cl *DoHClient) Lookup(q MessageQuestion, allowRecursion bool) (res *Message, err error)

Lookup DNS records based on MessageQuestion Name and Type, in synchronous mode. The MessageQuestion Class default to IN.

It will return an error if the Name is empty.

func (*DoHClient) Post

func (cl *DoHClient) Post(msg *Message) (res *Message, err error)

Post send query to name server using HTTP POST and return the response as unpacked message.

func (*DoHClient) Query

func (cl *DoHClient) Query(msg *Message) (*Message, error)

Query send DNS query to name server. This is an alias to Get method, to make it consistent with other DNS clients.

func (*DoHClient) RemoteAddr

func (cl *DoHClient) RemoteAddr() string

RemoteAddr return client remote nameserver address.

func (*DoHClient) SetRemoteAddr

func (cl *DoHClient) SetRemoteAddr(addr string) (err error)

SetRemoteAddr set the remote address for sending the packet.

func (*DoHClient) SetTimeout

func (cl *DoHClient) SetTimeout(t time.Duration)

SetTimeout set the timeout for sending and receiving packet.

func (*DoHClient) Write

func (cl *DoHClient) Write(packet []byte) (n int, err error)

Write the raw DNS response message to active connection. This method is only used by server to write the response of query to client.

type DoTClient

type DoTClient struct {
	// contains filtered or unexported fields
}

DoTClient client for DNS over TLS.

func NewDoTClient

func NewDoTClient(nameserver string, allowInsecure bool) (cl *DoTClient, err error)

NewDoTClient will create new DNS client over TLS connection.

The nameserver contains the IP address, not host name, of parent DNS server. Default port is 853, if not set.

func (*DoTClient) Close

func (cl *DoTClient) Close() error

Close the client connection.

func (*DoTClient) Lookup

func (cl *DoTClient) Lookup(q MessageQuestion, allowRecursion bool) (res *Message, err error)

Lookup DNS records based on MessageQuestion Name and Type, in synchronous mode. The MessageQuestion Class default to IN.

It will return an error if the Name is empty.

func (*DoTClient) Query

func (cl *DoTClient) Query(msg *Message) (res *Message, err error)

Query send DNS Message to name server.

func (*DoTClient) RemoteAddr

func (cl *DoTClient) RemoteAddr() string

RemoteAddr return client remote nameserver address.

func (*DoTClient) SetRemoteAddr

func (cl *DoTClient) SetRemoteAddr(_ string) (err error)

SetRemoteAddr no-op.

func (*DoTClient) SetTimeout

func (cl *DoTClient) SetTimeout(t time.Duration)

SetTimeout for sending and receiving packet.

func (*DoTClient) Write

func (cl *DoTClient) Write(msg []byte) (n int, err error)

Write raw DNS message on active connection.

type HostsFile

type HostsFile struct {
	Path    string `json:"-"`
	Name    string
	Records []*ResourceRecord `json:"-"`
	// contains filtered or unexported fields
}

HostsFile represent content of single hosts file.

func NewHostsFile

func NewHostsFile(path string, records []*ResourceRecord) (
	hfile *HostsFile, err error,
)

NewHostsFile create and store the host records in file defined by "path".

func ParseHostsFile

func ParseHostsFile(path string) (hfile *HostsFile, err error)

ParseHostsFile parse the content of hosts file as packed DNS message. If path is empty, it will load from the system hosts file.

func (*HostsFile) AppendAndSaveRecord

func (hfile *HostsFile) AppendAndSaveRecord(rr *ResourceRecord) (err error)

AppendAndSaveRecord append new record and save it to hosts file.

func (*HostsFile) Delete

func (hfile *HostsFile) Delete() (err error)

Delete the hosts file from the storage.

func (*HostsFile) Get

func (hfile *HostsFile) Get(dname, value string) (rr *ResourceRecord)

Get the first resource record that match with domain name and/or value. The value parameter is optional, if its empty, then only the first record that match with domain name that will be returned.

If no record matched, it will return nil.

Example
var (
	hostsFile = &HostsFile{
		Records: []*ResourceRecord{{
			Name:  "my.local",
			Type:  RecordTypeA,
			Value: "127.0.0.1",
		}, {
			Name:  "my.local",
			Type:  RecordTypeA,
			Value: "127.0.0.2",
		}},
	}
)

fmt.Println(hostsFile.Get("my.local", ""))
fmt.Println(hostsFile.Get("my.local", "127.0.0.2"))
fmt.Println(hostsFile.Get("my.my", ""))
Output:

{Name:my.local Type:1 Class:0 TTL:0 Value:127.0.0.1}
{Name:my.local Type:1 Class:0 TTL:0 Value:127.0.0.2}
<nil>

func (*HostsFile) Names

func (hfile *HostsFile) Names() (names []string)

Names return all hosts domain names.

func (*HostsFile) RemoveRecord

func (hfile *HostsFile) RemoveRecord(dname string) (rr *ResourceRecord)

RemoveRecord remove single record from hosts file by domain name. It will return true if record found and removed.

func (*HostsFile) Save

func (hfile *HostsFile) Save() (err error)

Save the hosts records into the file defined by field "Path".

type Message

type Message struct {
	Answer     []ResourceRecord
	Authority  []ResourceRecord
	Additional []ResourceRecord

	Question MessageQuestion
	Header   MessageHeader
	// contains filtered or unexported fields
}

Message represent a DNS message.

All communications inside of the domain protocol are carried in a single format called a message. The top level format of message is divided into 5 sections (some of which are empty in certain cases) shown below:

+---------------------+
|        Header       |
+---------------------+
|       Question      | the question for the name server
+---------------------+
|        Answer       | RRs answering the question
+---------------------+
|      Authority      | RRs pointing toward an authority
+---------------------+
|      Additional     | RRs holding additional information
+---------------------+

The names of the sections after the header are derived from their use in standard queries. The question section contains fields that describe a question to a name server. These fields are a query type (QTYPE), a query class (QCLASS), and a query domain name (QNAME). The last three sections have the same format: a possibly empty list of concatenated resource records (RRs). The answer section contains RRs that answer the question; the authority section contains RRs that point toward an authoritative name server; the additional records section contains RRs which relate to the query, but are not strictly answers for the question. [1]

[1] RFC 1035 - 4.1. Format

func NewMessage

func NewMessage() *Message

NewMessage create, initialize, and return new message.

func NewMessageAddress

func NewMessageAddress(hname []byte, addresses [][]byte) (msg *Message)

NewMessageAddress create new DNS message for hostname that contains one or more A or AAAA addresses. The addresses must be all IPv4 or IPv6, the first address define the query type. If hname is not valid hostname or one of the address is not valid IP address it will return nil.

func NewMessageFromRR

func NewMessageFromRR(rr *ResourceRecord) (msg *Message, err error)

NewMessageFromRR create new message with one RR as an answer.

func UnpackMessage

func UnpackMessage(packet []byte) (msg *Message, err error)

Unpack the raw DNS packet into a Message.

func (*Message) AddAnswer

func (msg *Message) AddAnswer(rr *ResourceRecord) (err error)

AddAnswer to the Answer field and re-pack it again.

func (*Message) AddAuthority

func (msg *Message) AddAuthority(rr *ResourceRecord) (err error)

AddAuthority add the rr to list of Authority. Calling this method mark the message as answer, instead of query.

If the rr is SOA, it will replace the existing record if exist and set the flag authoritative answer (IsAA) in header to true. If the rr is NS, it will be added only if its not exist.

It will return an error if the rr type is not SOA or NS or the size of records in Authority is full, maximum four records.

func (*Message) FilterAnswers

func (msg *Message) FilterAnswers(t RecordType) (answers []ResourceRecord)

FilterAnswers return resource record in Answer that match only with specific query type.

func (*Message) IsExpired

func (msg *Message) IsExpired() bool

IsExpired will return true if at least one resource record in answers is expired, where their TTL value is equal to 0. As long as the answers RR exist and no TTL is 0, it will return false.

If RR answers is empty, then the TTL on authority RR will be checked for zero.

There is no check to be done on additional RR, since its may contain EDNS with zero TTL.

func (*Message) Pack

func (msg *Message) Pack() ([]byte, error)

Pack convert message into datagram packet. The result of packing a message will be saved in Packet field and returned.

func (*Message) RemoveAnswer

func (msg *Message) RemoveAnswer(rrIn *ResourceRecord) (*ResourceRecord, error)

RemoveAnswer remove the RR from list of answer.

func (*Message) Reset

func (msg *Message) Reset()

Reset the message fields.

func (*Message) ResetRR

func (msg *Message) ResetRR()

ResetRR free allocated resource records in message. This function can be used to release some memory after message has been packed, but the raw packet may still be in use.

func (*Message) SetAuthorativeAnswer

func (msg *Message) SetAuthorativeAnswer(isAA bool)

SetAuthorativeAnswer set the header authoritative answer to true (1) or false (0).

func (*Message) SetID

func (msg *Message) SetID(id uint16)

SetID in section header and in packet.

func (*Message) SetQuery

func (msg *Message) SetQuery(isQuery bool)

SetQuery set the message as query (0) or as response (1) in header and in packet. Setting the message as query will also turning off AA, TC, and RA flags.

func (*Message) SetRecursionDesired

func (msg *Message) SetRecursionDesired(isRD bool)

SetRecursionDesired set the message to allow recursion (true=1) or not (false=0) in header and packet.

func (*Message) SetResponseCode

func (msg *Message) SetResponseCode(code ResponseCode)

SetResponseCode in message header and in packet.

func (*Message) String

func (msg *Message) String() string

String return the message representation as string.

func (*Message) SubTTL

func (msg *Message) SubTTL(n uint32)

SubTTL subtract TTL in each resource records and in packet by n seconds. If TTL is less than n, it will set to 0.

func (*Message) UnpackHeaderQuestion

func (msg *Message) UnpackHeaderQuestion() (err error)

UnpackHeaderQuestion extract only DNS header and question from message packet. This method assume that message.packet already set to DNS raw message.

type MessageHeader

type MessageHeader struct {
	//
	// A 16 bit identifier assigned by the program that generates
	// any kind of query.  This identifier is copied the corresponding
	// reply and can be used by the requester to match up replies to
	// outstanding queries.
	//
	ID uint16

	//
	// A one bit field that specifies whether this message is a query (0),
	// or a response (1).
	//
	IsQuery bool

	//
	// A four bit field that specifies kind of query in this message.
	// This value is set by the originator of a query and copied into the
	// response.
	//
	Op OpCode

	//
	// Authoritative Answer - this bit is valid in responses, and
	// specifies that the responding name server is an authority for the
	// domain name in question section.  Note that the contents of the
	// answer section may have multiple owner names because of aliases.
	// The AA bit corresponds to the name which matches the query name, or
	// the first owner name in the answer section.
	//
	IsAA bool

	//
	// TrunCation - specifies that this message was truncated due to
	// length greater than that permitted on the transmission channel.
	//
	IsTC bool

	//
	// Recursion Desired - this bit may be set in a query and is copied
	// into the response.  If RD is set, it directs the name server to
	// pursue the query recursively.  Recursive query support is optional.
	//
	IsRD bool

	//
	// Recursion Available - this bit is set or cleared in a response, and
	// denotes whether recursive query support is available in the name
	// server.
	//
	IsRA bool

	//
	// Response code - this 4 bit field is set as part of responses.
	//
	RCode ResponseCode

	// The number of entries in the question section.
	QDCount uint16

	// The number of resource records in the answer section.
	ANCount uint16

	// The number of name server resource records in the authority records
	// section.
	NSCount uint16

	// The number of resource records in the additional records section.
	ARCount uint16
}

MessageHeader the header includes fields that specify which of the remaining sections are present, and also specify whether the message is a query or a response, a standard query or some other opcode, etc. [1]

The header section is always present.

[1] RFC 1035 P-25 - 4.1. Format

func (*MessageHeader) Reset

func (hdr *MessageHeader) Reset()

Reset the header to default (query) values, which mean the IsQuery is true, the Op code is 0, with recursion enabled, and query count set tot 1.

type MessageQuestion

type MessageQuestion struct {
	// The domain name to be queried.
	Name string

	// The Type of query.
	Type RecordType

	// The Class of the query.
	Class RecordClass
}

MessageQuestion contains the "question" in most queries.

func (*MessageQuestion) Reset

func (qst *MessageQuestion) Reset()

Reset the message question field to it's default values for query.

func (*MessageQuestion) String

func (qst *MessageQuestion) String() string

type OpCode

type OpCode byte

OpCode define a custom type for DNS header operation code.

const (
	OpCodeQuery  OpCode = iota // A standard query (QUERY)
	OpCodeIQuery               // An inverse query (IQUERY), obsolete by RFC3425
	OpCodeStatus               // A server status request (STATUS)
)

List of valid operation code.

type RDataHINFO

type RDataHINFO struct {
	CPU []byte
	OS  []byte
}

RDataHINFO HINFO records are used to acquire general information about a host. The main use is for protocols such as FTP that can use special procedures when talking between machines or operating systems of the same type.

func (*RDataHINFO) String

func (hinfo *RDataHINFO) String() string

String return readable representation of HINFO record.

type RDataHTTPS

type RDataHTTPS struct {
	RDataSVCB
}

RDataHTTPS the resource record for type 65 HTTPS RR.

func (*RDataHTTPS) WriteTo

func (https *RDataHTTPS) WriteTo(out io.Writer) (_ int64, err error)

WriteTo write the SVCB record as zone format to out.

type RDataMINFO

type RDataMINFO struct {
	// A <domain-name> which specifies a mailbox which is responsible for
	// the mailing list or mailbox.  If this domain name names the root,
	// the owner of the MINFO RR is responsible for itself.  Note that
	// many existing mailing lists use a mailbox X-request for the RMAILBX
	// field of mailing list X, e.g., Msgroup-request for Msgroup.  This
	// field provides a more general mechanism.
	RMailBox string

	// A <domain-name> which specifies a mailbox which is to receive error
	// messages related to the mailing list or mailbox specified by the
	// owner of the MINFO RR (similar to the ERRORS-TO: field which has
	// been proposed).  If this domain name names the root, errors should
	// be returned to the sender of the message.
	EmailBox string
}

RDataMINFO define a resource record for type MINFO.

func (*RDataMINFO) String

func (minfo *RDataMINFO) String() string

String return readable representation of MINFO record.

type RDataMX

type RDataMX struct {
	// A <domain-name> which specifies a host willing to act as a mail
	// exchange for the owner name.
	Exchange string

	// A 16 bit integer which specifies the preference given to this RR
	// among others at the same owner.  Lower values are preferred.
	Preference int16
}

RDataMX MX records cause type A additional section processing for the host specified by EXCHANGE. The use of MX RRs is explained in detail in [RFC-974].

type RDataOPT

type RDataOPT struct {
	// ListVar list of pair of code-value inside the RDATA.
	ListVar []RDataOPTVar

	// Forms the upper 8 bits of extended 12-bit RCODE (together with
	// the 4 bits defined message header).
	// Note that the value of 0 indicates that the RCODE in message
	// header is in use (values 0 through 15).
	ExtRCode byte

	// Indicates the implementation level of the setter.
	// Full conformance with this specification is indicated by version
	// '0'.
	// Requestors are encouraged to set this to the lowest implemented
	// level capable of expressing a transaction, to minimise the
	// responder and network load of discovering the greatest common
	// implementation level between requestor and responder.
	// A requestor's version numbering strategy MAY ideally be a
	// run-time configuration option.
	Version byte

	// DNSSEC OK bit as defined by [RFC3225].
	DO bool
}

RDataOPT define format of RDATA for OPT.

The extended RCODE and flags, which OPT stores in the RR Time to Live (TTL) field, contains ExtRCode, Version, and DNSSEC OK flag.

func (*RDataOPT) String

func (opt *RDataOPT) String() string

String return readable representation of OPT record.

type RDataOPTVar added in v0.55.0

type RDataOPTVar struct {
	// Varies per Code.
	// MUST be treated as a bit field.
	Data []byte

	// Assigned by the Expert Review process as defined by the DNSEXT
	// working group and the IESG.
	Code uint16
}

RDataOPTVar contains the option in OPT RDATA.

type RDataSOA

type RDataSOA struct {
	// The primary name server for the zone.
	MName string

	// The mailbox of the person responsible for the name server.
	// For example, "root@localhost", but with '@' is replaced with dot
	// '.', its become "root.localhost".
	// If its empty, default to "root".
	RName string

	// The version number of the original copy of the zone.
	// If its empty, default to current epoch.
	Serial uint32

	// A time interval before the zone should be refreshed.
	// If its empty, default to 1 days.
	Refresh int32

	// A time interval that should elapse before a failed refresh should
	// be retried.
	// If its empty, default to 1 hour.
	Retry int32

	// A time value that specifies the upper limit on the time interval
	// that can elapse before the zone is no longer authoritative.
	Expire int32

	// The minimum TTL field that should be exported with any RR from this
	// zone.
	// If its empty, default to 1 hour.
	Minimum uint32
}

RDataSOA contains the authority of zone.

All times are in units of seconds.

func NewRDataSOA

func NewRDataSOA(mname, rname string) (soa *RDataSOA)

NewRDataSOA create and initialize the new SOA record using default values for Serial, Refresh, Retry, Expiry, and Minimum.

type RDataSRV

type RDataSRV struct {
	// The symbolic name of the desired service, as defined in Assigned
	// Numbers [STD 2] or locally.  An underscore (_) is prepended to
	// the service identifier to avoid collisions with DNS labels that
	// occur in nature.
	//
	// Some widely used services, notably POP, don't have a single
	// universal name.  If Assigned Numbers names the service
	// indicated, that name is the only name which is legal for SRV
	// lookups.  The Service is case insensitive.
	Service string

	// The symbolic name of the desired protocol, with an underscore
	// (_) prepended to prevent collisions with DNS labels that occur
	// in nature.  _TCP and _UDP are at present the most useful values
	// for this field, though any name defined by Assigned Numbers or
	// locally may be used (as for Service).  The Proto is case
	// insensitive.
	Proto string

	// The domain this RR refers to.  The SRV RR is unique in that the
	// name one searches for is not this name; the example near the end
	// shows this clearly.
	Name string

	// The domain name of the target host.  There MUST be one or more
	// address records for this name, the name MUST NOT be an alias (in
	// the sense of RFC 1034 or RFC 2181).  Implementors are urged, but
	// not required, to return the address record(s) in the Additional
	// Data section.  Unless and until permitted by future standards
	// action, name compression is not to be used for this field.
	//
	// A Target of "." means that the service is decidedly not
	// available at this domain.
	Target string

	// The priority of this target host.  A client MUST attempt to
	// contact the target host with the lowest-numbered priority it can
	// reach; target hosts with the same priority SHOULD be tried in an
	// order defined by the weight field.  The range is 0-65535.  This
	// is a 16 bit unsigned integer in network byte order.
	Priority uint16

	// A server selection mechanism.  The weight field specifies a
	// relative weight for entries with the same priority. Larger
	// weights SHOULD be given a proportionately higher probability of
	// being selected. The range of this number is 0-65535.  This is a
	// 16 bit unsigned integer in network byte order.  Domain
	// administrators SHOULD use Weight 0 when there isn't any server
	// selection to do, to make the RR easier to read for humans (less
	// noisy).  In the presence of records containing weights greater
	// than 0, records with weight 0 should have a very small chance of
	// being selected.
	//
	// In the absence of a protocol whose specification calls for the
	// use of other weighting information, a client arranges the SRV
	// RRs of the same Priority in the order in which target hosts,
	// specified by the SRV RRs, will be contacted. The following
	// algorithm SHOULD be used to order the SRV RRs of the same
	// priority:
	//
	// To select a target to be contacted next, arrange all SRV RRs
	// (that have not been ordered yet) in any order, except that all
	// those with weight 0 are placed at the beginning of the list.
	//
	// Compute the sum of the weights of those RRs, and with each RR
	// associate the running sum in the selected order. Then choose a
	// uniform random number between 0 and the sum computed
	// (inclusive), and select the RR whose running sum value is the
	// first in the selected order which is greater than or equal to
	// the random number selected. The target host specified in the
	// selected SRV RR is the next one to be contacted by the client.
	// Remove this SRV RR from the set of the unordered SRV RRs and
	// apply the described algorithm to the unordered SRV RRs to select
	// the next target host.  Continue the ordering process until there
	// are no unordered SRV RRs.  This process is repeated for each
	// Priority.
	Weight uint16

	// The port on this target host of this service.  The range is 0-
	// 65535.  This is a 16 bit unsigned integer in network byte order.
	// This is often as specified in Assigned Numbers but need not be.
	Port uint16
}

RDataSRV define a resource record for type SRV.

func (*RDataSRV) String

func (srv *RDataSRV) String() string

String return readable representation of SRV record.

type RDataSVCB

type RDataSVCB struct {
	// Params contains service parameters indexed by key's ID.
	Params map[int][]string

	TargetName string
	Priority   uint16
}

RDataSVCB the resource record for type 64 SVCB RR. Format of SVCB RDATA,

+-------------+
| SvcPriority | 2-octets.
+-------------+
/ TargetName  / A <domain-name>.
/             /
+-------------+
/ SvcParams   / A <character-string>.
/             /
+-------------+

SVCB RR has two modes: AliasMode and ServiceMode. SvcPriority with value 0 indicates SVCB RR as AliasMode. SvcParams SHALL be used only for ServiceMode.

The SvcParams contains the SVCB parameter key and value. Format of SvcParams,

+-------------------+
| SvcParamKey       | ; 2-octets.
+-------------------+
| SvcParamKeyLength | ; 2-octets, indicates the length of SvcParamValue.
+-------------------+
/ SvcParamValue     / ; Dynamic value based on the key.
/                   /
+-------------------+

The RDATA considered malformed if:

  • RDATA end at SvcParamKeyLength with non-zero value.
  • SvcParamKey are not in increasing numeric order, for example: 1, 3, 2.
  • Contains duplicate SvcParamKey.
  • Contains invalid SvcParamValue format.

Currently, there are six known keys,

  • mandatory (0): define list of keys that must be exists on TargetName. Each value is stored as 2-octets of its numeric ID.
  • alpn (1): define list of Application-Layer Protocol Negotiation (ALPN) supported by TargetName. Each alpn is stored as combination of 2-octets length and its value.
  • no-default-alpn (2): indicates that no default ALPN exists on TargetName. This key does not have value.
  • port (3): define TCP or UDP port of TargetName. The port value is encoded in 2-octets.
  • ipv4hint (4): contains list of IPv4 addresses of TargetName. Each IPv4 address is encoded in 4-octets.
  • ech (5): Reserved.
  • ipv6hint (6): contains list of IPv6 addresses of TargetName. Each IPv6 address is encoded in 8-octets.

A generic key can be defined in zone file by prefixing the number with string "key". For example,

key123="hello"

will be encoded in RDATA as 123 (2-octets), followed by 5 (length of value, 2-octets), and followed by "hello" (5-octets).

Example

The domain "example.com" provides a service "foo.example.org" with priority 16 and with two mandatory parameters: "alpn" and "ipv4hint".

example.com.   SVCB   16 foo.example.org. (
                           alpn=h2,h3-19 mandatory=ipv4hint,alpn
                           ipv4hint=192.0.2.1
                         )

The above zone record when encoded to RDATA (displayed in decimal for readability),

+----+-----------------+
| 16 / foo.example.org /
+----+-----------------+
; SvcPriority=16               (2 octets)
; TargetName="foo.example.org" (domain-name, max 255 octects)
+---+---+---+---+
| 0 | 4 | 1 | 4 |
+---+---+---+---+
; SvcParamKey=0 (mandatory)  (2 octets)
; length=4                   (2 octets)
; value[0]: 1 (alpn)         (2 octets)
; value[1]: 4 (ipv4hint)     (2 octets)
+---+---+---+----+---+-------+
| 1 | 9 | 2 | h2 | 5 | h3-19 |
+---+---+---+----+---+-------+
; SvcParamKey=1 (alpn)              (2 octets)
; length=9                          (2 octets)
; value[0]: length=2, value="h2"    (1 + 2 octets)
; value[1]: length=5, value="h3-19" (1 + 5 octets)
+---+---+-----------+
| 4 | 4 | 192.0.2.1 |
+---+---+-----------+
; SvcParamKey=4 (ipv4hint)  (2 octets)
; length=4                  (2 octets)
; value="192.0.2.1"         (4 octets)

func (*RDataSVCB) AddParam

func (svcb *RDataSVCB) AddParam(key string, listValue []string) (err error)

AddParam add parameter to service binding. It will return an error if key already exist or contains invalid value.

func (*RDataSVCB) WriteTo

func (svcb *RDataSVCB) WriteTo(out io.Writer) (_ int64, err error)

WriteTo write the SVCB record as zone format to out.

type RDataWKS

type RDataWKS struct {
	Address  []byte
	BitMap   []byte
	Protocol byte
}

RDataWKS The WKS record is used to describe the well known services supported by a particular protocol on a particular internet address. The PROTOCOL field specifies an IP protocol number, and the bit map has one bit per port of the specified protocol. The first bit corresponds to port 0, the second to port 1, etc. If the bit map does not include a bit for a protocol of interest, that bit is assumed zero. The appropriate values and mnemonics for ports and protocols are specified in [RFC-1010].

For example, if PROTOCOL=TCP (6), the 26th bit corresponds to TCP port 25 (SMTP). If this bit is set, a SMTP server should be listening on TCP port 25; if zero, SMTP service is not supported on the specified address.

The purpose of WKS RRs is to provide availability information for servers for TCP and UDP. If a server supports both TCP and UDP, or has multiple Internet addresses, then multiple WKS RRs are used.

func (*RDataWKS) String

func (wks *RDataWKS) String() string

String return readable representation of WKS record.

type RecordClass

type RecordClass uint16

RecordClass represent the class for resource record.

const (
	RecordClassZERO RecordClass = iota // Empty query class.
	RecordClassIN                      // The Internet
	RecordClassCH                      // The CHAOS class
	RecordClassHS                      // Hesiod [Dyer 87]

	RecordClassANY RecordClass = 255 // Any class
)

List of known record class, ordered by value.

type RecordType

type RecordType uint16

RecordType A two octet code which specifies the type of the record.

Example
fmt.Println(RecordType(1))  // Known record type.
fmt.Println(RecordType(17)) // Unregistered record type.
Output:

1
17
const (
	RecordTypeZERO  RecordType = iota // Empty record type.
	RecordTypeA                       //  1 - A host address
	RecordTypeNS                      //  2 - An authoritative name server
	RecordTypeMD                      //  3 - A mail destination (Obsolete - use MX)
	RecordTypeMF                      //  4 - A mail forwarder (Obsolete - use MX)
	RecordTypeCNAME                   //  5 - The canonical name for an alias
	RecordTypeSOA                     //  6 - Marks the start of a zone of authority
	RecordTypeMB                      //  7 - A mailbox domain name (EXPERIMENTAL)
	RecordTypeMG                      //  8 - A mail group member (EXPERIMENTAL)
	RecordTypeMR                      //  9 - A mail rename domain name (EXPERIMENTAL)
	RecordTypeNULL                    // 10 - A null RR (EXPERIMENTAL)
	RecordTypeWKS                     // 11 - A well known service description
	RecordTypePTR                     // 12 - A domain name pointer
	RecordTypeHINFO                   // 13 - Host information
	RecordTypeMINFO                   // 14 - Mailbox or mail list information
	RecordTypeMX                      // 15 - Mail exchange
	RecordTypeTXT                     // 16 - Text strings

	RecordTypeAAAA RecordType = 28 // IPv6 address
	RecordTypeSRV  RecordType = 33 // A SRV RR for locating service.
	RecordTypeOPT  RecordType = 41 // An OPT pseudo-RR (sometimes called a meta-RR)

	RecordTypeSVCB  RecordType = 64 // RFC 9460.
	RecordTypeHTTPS RecordType = 65 // RFC 9460.

	RecordTypeAXFR  RecordType = 252 // A request for a transfer of an entire zone
	RecordTypeMAILB RecordType = 253 // A request for mailbox-related records (MB, MG or MR)
	RecordTypeMAILA RecordType = 254 // A request for mail agent RRs (Obsolete - see MX)
	RecordTypeANY   RecordType = 255 // A request for all records.
)

List of code for known DNS record types, ordered by value.

func RecordTypeFromAddress

func RecordTypeFromAddress(addr []byte) (rtype RecordType)

RecordTypeFromAddress return RecordTypeA or RecordTypeAAAA if addr is valid IPv4 or IPv6 address, respectively, otherwise it will return 0.

Example
fmt.Println(RecordTypeFromAddress([]byte("127.0.0.1")))
fmt.Println(RecordTypeFromAddress([]byte("fc00::")))
fmt.Println(RecordTypeFromAddress([]byte("127")))
Output:

1
28
0

type ResourceRecord

type ResourceRecord struct {
	// Value hold the generic, unpacked rdata based on Type.
	Value interface{}

	// A domain name to which this resource record pertains.
	Name string

	// This field specifies the meaning of the data in the rdata field.
	Type RecordType

	// The class of the data in the rdata field.
	Class RecordClass

	// A time interval (in seconds) that the resource record may be cached
	// before it should be discarded.
	// Zero values are interpreted to mean that the RR can only be used
	// for the transaction in progress, and should not be cached.
	TTL uint32
	// contains filtered or unexported fields
}

ResourceRecord The answer, authority, and additional sections all share the same format: a variable number of resource records, where the number of records is specified in the corresponding count field in the header. Each resource record has the following format:

func (*ResourceRecord) String

func (rr *ResourceRecord) String() string

String return the text representation of ResourceRecord for human.

type ResponseCode

type ResponseCode byte

ResponseCode define response code in message header.

const (
	RCodeOK ResponseCode = iota //  No error condition

	// Format error - The name server was unable to interpret the query.
	RCodeErrFormat

	// Server failure - The name server was unable to process this query
	// due to a problem with the name server.
	RCodeErrServer

	// Name Error - Meaningful only for responses from an authoritative
	// name server, this code signifies that the domain name referenced in
	// the query does not exist.
	RCodeErrName

	// Not Implemented - The name server does not support the requested
	// kind of query.
	RCodeNotImplemented

	// Refused - The name server refuses to perform the specified
	// operation for policy reasons.  For example, a name server may not
	// wish to provide the information to the particular requester, or a
	// name server may not wish to perform a particular operation (e.g.,
	// zone transfer) for particular data.
	RCodeRefused
)

List of response codes.

type Server

type Server struct {
	HostsFiles map[string]*HostsFile
	Caches     Caches
	// contains filtered or unexported fields
}

Server defines DNS server.

Services

The server will listening for DNS over TLS only if certificates file is exist and valid.

Caches

There are two type of answer: internal and external. Internal answers is DNS records that are loaded from hosts or zone files. Internal answers never get pruned. External answers is DNS records that are received from parent name servers.

Server caches the DNS answers in two storages: map and list.List. The map caches store internal and external answers, using domain name as a key and list of answers as value,

domain-name -> [{A,IN,...},{AAAA,IN,...}]

The list.List store external answers, ordered by accessed time, it is used to prune least frequently accessed answers.

Debugging

If [ServerOptions.Debug] is set to value DebugLevelCache, server will print each processed request, forward, and response. The debug information prefixed with single character to differentiate single action,

> : incoming request from client
< : the answer is sent to client
! : no answer found on cache and the query is not recursive, or
    response contains error code
^ : request is forwarded to parent name server
* : request is dropped from queue
~ : answer exist on cache but its expired
- : answer is pruned from caches
+ : new answer is added to caches
# : the expired answer is renewed and updated on caches

Following the prefix is connection type, parent name server address, message ID, and question.

Example
package main

import (
	"fmt"
	"log"
	"time"
)

func clientLookup(nameserver string) {
	var (
		q = MessageQuestion{
			Name: "kilabit.info",
		}

		cl  *UDPClient
		msg *Message
		rr  ResourceRecord
		err error
		x   int
	)

	cl, err = NewUDPClient(nameserver)
	if err != nil {
		log.Println(err)
		return
	}

	msg, err = cl.Lookup(q, false)
	if err != nil {
		log.Println(err)
		return
	}

	fmt.Printf("Receiving DNS message: %s\n", msg)
	for x, rr = range msg.Answer {
		fmt.Printf("Answer %d: %s\n", x, rr.Value)
	}
	for x, rr = range msg.Authority {
		fmt.Printf("Authority %d: %s\n", x, rr.Value)
	}
	for x, rr = range msg.Additional {
		fmt.Printf("Additional %d: %s\n", x, rr.Value)
	}
}

func main() {
	var (
		serverAddress = "127.0.0.1:5300"
		serverOptions = &ServerOptions{
			ListenAddress:    "127.0.0.1:5300",
			HTTPPort:         8443,
			TLSCertFile:      "testdata/domain.crt",
			TLSPrivateKey:    "testdata/domain.key",
			TLSAllowInsecure: true,
		}

		server   *Server
		zoneFile *Zone
		err      error
	)

	server, err = NewServer(serverOptions)
	if err != nil {
		log.Fatal(err)
	}

	// Load records to be served from zone file.
	zoneFile, err = ParseZoneFile("testdata/kilabit.info", "", 0)
	if err != nil {
		log.Fatal(err)
	}

	server.Caches.InternalPopulate(zoneFile.Messages(), zoneFile.Path)

	go func() {
		err = server.ListenAndServe()
		if err != nil {
			log.Fatal(err)
		}
	}()

	// Wait for all listeners running.
	time.Sleep(500 * time.Millisecond)

	clientLookup(serverAddress)

	server.Stop()
}
Output:

func NewServer

func NewServer(opts *ServerOptions) (srv *Server, err error)

NewServer create and initialize DNS server.

func (*Server) ListenAndServe

func (srv *Server) ListenAndServe() (err error)

ListenAndServe start listening and serve queries from clients.

func (*Server) RestartForwarders

func (srv *Server) RestartForwarders(nameServers []string)

RestartForwarders stop and start new forwarders with new nameserver address and protocol. Empty nameservers means server will run without forwarding request.

func (*Server) ServeHTTP

func (srv *Server) ServeHTTP(w http.ResponseWriter, r *http.Request)

func (*Server) Stop

func (srv *Server) Stop()

Stop the forwarders and close all listeners.

type ServerOptions

type ServerOptions struct {

	// ListenAddress ip address and port number to serve query.
	// This field is optional, default to "0.0.0.0:53".
	ListenAddress string `ini:"dns:server:listen"`

	// TLSCertFile contains path to certificate for serving DNS over TLS
	// and HTTPS.
	// This field is optional, if its empty, server will listening on
	// unsecure HTTP connection only.
	TLSCertFile string `ini:"dns:server:tls.certificate"`

	// TLSPrivateKey contains path to certificate private key file.
	TLSPrivateKey string `ini:"dns:server:tls.private_key"`

	// NameServers contains list of parent name servers.
	//
	// Answer that does not exist on local will be forwarded to parent
	// name servers.  If this field is empty, any query that does not have
	// an answer in local caches, will be returned with response code
	// RCodeErrName (3).
	//
	// The name server use the URI format,
	//
	//	nameserver  = [ scheme "://" ] ( ip-address / domain-name ) [:port]
	//	scheme      = ( "udp" / "https" )
	//	ip-address  = ( ip4 / ip6 )
	//	domain-name = ; fully qualified domain name
	//
	// If no scheme is given, it will default to "udp".
	// The domain-name MUST only used if scheme is "https".
	//
	// Example,
	//
	//	udp://35.240.172.103
	//	https://35.240.172.103:853 (DNS over TLS)
	//	https://kilabit.info/dns-query (DNS over HTTPS)
	//
	NameServers []string `ini:"dns:server:parent"`

	// The root authority for all zones and records under this server.
	SOA RDataSOA

	// HTTPIdleTimeout number of seconds before considering the client of
	// HTTP connection to be closed.
	// This field is optional, default to 120 seconds.
	HTTPIdleTimeout time.Duration `ini:"dns:server:http.idle_timeout"`

	// PruneDelay define a delay where caches will be pruned.
	// This field is optional, minimum value is 1 minute, and default
	// value is 1 hour.
	// For example, if its set to 1 hour, every 1 hour the caches will be
	// inspected to remove answers that has not been accessed more than or
	// equal to PruneThreshold.
	PruneDelay time.Duration `ini:"dns:server:cache.prune_delay"`

	// PruneThreshold define negative duration where answers will be
	// pruned from caches.
	// This field is optional, minimum value is -1 minute, and default
	// value is -1 hour,
	// For example, if its set to -1 minute, any answers that has not been
	// accessed in the last 1 minute will be removed from cache.
	PruneThreshold time.Duration `ini:"dns:server:cache.prune_threshold"`

	// Debug level for server, accept value [DebugLevelDNS],
	// [DebugLevelCache], [DebugLevelConnPacket], or any combination of
	// it.
	Debug int `ini:"dns:server:debug"`

	// HTTPPort port for listening DNS over HTTP (DoH), default to 0.
	// If its zero, the server will not serve DNS over HTTP.
	HTTPPort uint16 `ini:"dns:server:http.port"`

	// TLSPort port for listening DNS over TLS, default to 0.
	// If its zero, the server will not serve DNS over TLS.
	TLSPort uint16 `ini:"dns:server:tls.port"`

	// TLSAllowInsecure option to allow to serve DoH with self-signed
	// certificate.
	// This field is optional.
	TLSAllowInsecure bool `ini:"dns:server:tls.allow_insecure"`

	// DoHBehindProxy allow serving DNS over insecure HTTP, even if
	// certificate file is defined.
	// This option allow serving DNS request forwarded by another proxy
	// server.
	DoHBehindProxy bool `ini:"dns:server:doh.behind_proxy"`
	// contains filtered or unexported fields
}

ServerOptions describes options for running a DNS server.

type TCPClient

type TCPClient struct {
	// contains filtered or unexported fields
}

TCPClient for DNS with TCP connection and list of remote addresses.

func NewTCPClient

func NewTCPClient(nameserver string) (cl *TCPClient, err error)

NewTCPClient will create new DNS client with TCP network connection.

The nameserver contains the IP address, not host name, of parent DNS server. Default port is 53, if not set.

func (*TCPClient) Close

func (cl *TCPClient) Close() error

Close client connection.

func (*TCPClient) Connect

func (cl *TCPClient) Connect(raddr *net.TCPAddr) (err error)

Connect to remote address.

func (*TCPClient) Lookup

func (cl *TCPClient) Lookup(q MessageQuestion, allowRecursion bool) (msg *Message, err error)

Lookup DNS records based on MessageQuestion Name and Type, in synchronous mode. The MessageQuestion Class default to IN.

It will return an error if the client does not set the name server address, or no connection, or Name is empty.

Example
var (
	q = MessageQuestion{
		Name: "kilabit.info",
	}

	cl  *TCPClient
	msg *Message
	rr  ResourceRecord
	err error
	x   int
)

cl, err = NewTCPClient("127.0.0.1:53")
if err != nil {
	log.Println(err)
	return
}

msg, err = cl.Lookup(q, false)
if err != nil {
	log.Println(err)
	return
}

fmt.Printf("Receiving DNS message: %s\n", msg)
for x, rr = range msg.Answer {
	fmt.Printf("Answer %d: %s\n", x, rr.Value)
}
for x, rr = range msg.Authority {
	fmt.Printf("Authority %d: %s\n", x, rr.Value)
}
for x, rr = range msg.Additional {
	fmt.Printf("Additional %d: %s\n", x, rr.Value)
}
Output:

func (*TCPClient) Query

func (cl *TCPClient) Query(msg *Message) (res *Message, err error)

Query send DNS query to name server. The addr parameter is unused.

func (*TCPClient) RemoteAddr

func (cl *TCPClient) RemoteAddr() string

RemoteAddr return client remote nameserver address.

func (*TCPClient) SetRemoteAddr

func (cl *TCPClient) SetRemoteAddr(addr string) (err error)

SetRemoteAddr set the remote address for sending the packet.

func (*TCPClient) SetTimeout

func (cl *TCPClient) SetTimeout(t time.Duration)

SetTimeout for sending and receiving packet.

func (*TCPClient) Write

func (cl *TCPClient) Write(msg []byte) (n int, err error)

Write raw DNS response message on active connection. This method is only used by server to write the response of query to client.

type UDPClient

type UDPClient struct {
	sync.Mutex
	// contains filtered or unexported fields
}

UDPClient for DNS with UDP connection.

Any implementation that need to query DNS message in multiple Go routines should create one client per routine.

Example

The following example show how to use send and Recv to query domain name address.

var (
	req = &Message{
		Header: MessageHeader{},
		Question: MessageQuestion{
			Name:  "kilabit.info",
			Type:  RecordTypeA,
			Class: RecordClassIN,
		},
	}

	cl  *UDPClient
	err error
	res *Message
	rr  ResourceRecord
	x   int
)

cl, err = NewUDPClient("127.0.0.1:53")
if err != nil {
	log.Println(err)
	return
}

_, err = req.Pack()
if err != nil {
	log.Fatal(err)
	return
}

res, err = cl.Query(req)
if err != nil {
	log.Fatal(err)
	return
}

fmt.Printf("Receiving DNS message: %s\n", res)
for x, rr = range res.Answer {
	fmt.Printf("Answer %d: %s\n", x, rr.Value)
}
for x, rr = range res.Authority {
	fmt.Printf("Authority %d: %s\n", x, rr.Value)
}
for x, rr = range res.Additional {
	fmt.Printf("Additional %d: %s\n", x, rr.Value)
}
Output:

func NewUDPClient

func NewUDPClient(nameserver string) (cl *UDPClient, err error)

NewUDPClient will create new DNS client with UDP network connection.

The nameserver contains the IP address, not host name, of parent DNS server. Default port is 53, if not set.

func (*UDPClient) Close

func (cl *UDPClient) Close() error

Close client connection.

func (*UDPClient) Lookup

func (cl *UDPClient) Lookup(q MessageQuestion, allowRecursion bool) (msg *Message, err error)

Lookup DNS records based on MessageQuestion Name and Type, in synchronous mode. The MessageQuestion Class default to IN.

It will return an error if the client does not set the name server address, or no connection, or Name is empty.

Example
var (
	q = MessageQuestion{
		Name: "kilabit.info",
	}

	cl  *UDPClient
	msg *Message
	rr  ResourceRecord
	err error
	x   int
)

cl, err = NewUDPClient("127.0.0.1:53")
if err != nil {
	log.Println(err)
	return
}

msg, err = cl.Lookup(q, false)
if err != nil {
	log.Println(err)
	return
}

fmt.Printf("Receiving DNS message: %s\n", msg)
for x, rr = range msg.Answer {
	fmt.Printf("Answer %d: %s\n", x, rr.Value)
}
for x, rr = range msg.Authority {
	fmt.Printf("Authority %d: %s\n", x, rr.Value)
}
for x, rr = range msg.Additional {
	fmt.Printf("Additional %d: %s\n", x, rr.Value)
}
Output:

func (*UDPClient) Query

func (cl *UDPClient) Query(req *Message) (res *Message, err error)

Query send DNS query to name server "ns" and return the unpacked response.

func (*UDPClient) RemoteAddr

func (cl *UDPClient) RemoteAddr() string

RemoteAddr return client remote nameserver address.

func (*UDPClient) SetRemoteAddr

func (cl *UDPClient) SetRemoteAddr(addr string) (err error)

SetRemoteAddr set the remote address for sending the packet.

func (*UDPClient) SetTimeout

func (cl *UDPClient) SetTimeout(t time.Duration)

SetTimeout for sending and receiving packet.

func (*UDPClient) Write

func (cl *UDPClient) Write(msg []byte) (n int, err error)

Write raw DNS response message on active connection. This method is only used by server to write the response of query to client.

type UDPClientPool

type UDPClientPool struct {
	sync.Mutex
	// contains filtered or unexported fields
}

UDPClientPool contains a pool of UDP client connections.

Any implementation that access UDPClient in multiple Go routines should create one client per Go routine; instead of using a single UDP client. The reason for this is because UDP packet is asynchronous.

WARNING: using pooling is only works if client only call Lookup or Query. If implementation call Send() n client connection, make sure, it also call Recv on the same routine before putting the client back to pool.

func NewUDPClientPool

func NewUDPClientPool(nameServers []string) (ucp *UDPClientPool, err error)

NewUDPClientPool create pool for UDP connection using list of name servers. If no name servers is defined it will return nil.

func (*UDPClientPool) Get

func (ucp *UDPClientPool) Get() *UDPClient

Get return UDP client.

func (*UDPClientPool) Put

func (ucp *UDPClientPool) Put(cl interface{})

Put the UDP client into pool.

WARNING: any client connection that call Send(), MUST call Recv() before putting client back to pool. You have been warned.

type Zone

type Zone struct {
	// Records contains mapping between domain name and its resource
	// records.
	Records map[string][]*ResourceRecord `json:"-"`

	SOA *RDataSOA

	Path string `json:"-"`

	// The base domain of zone.
	// It must be absolute domain, end with period.
	Origin string
	// contains filtered or unexported fields
}

Zone represent a group of domain names shared a single root domain. A Zone contains at least one SOA record.

func NewZone

func NewZone(file, origin string) (zone *Zone)

NewZone create and initialize new zone.

func ParseZone

func ParseZone(content []byte, origin string, ttl uint32) (zone *Zone, err error)

ParseZone parse zone from raw bytes.

func ParseZoneFile

func ParseZoneFile(file, origin string, ttl uint32) (zone *Zone, err error)

ParseZoneFile parse zone file. The file name will be assumed as origin if parameter origin or $ORIGIN is not set.

func (*Zone) Add

func (zone *Zone) Add(rr *ResourceRecord) (err error)

Add add new ResourceRecord to Zone.

func (*Zone) Delete

func (zone *Zone) Delete() (err error)

Delete the zone file from storage.

func (*Zone) Messages

func (zone *Zone) Messages() []*Message

Messages return all pre-generated DNS messages.

func (*Zone) Remove

func (zone *Zone) Remove(rr *ResourceRecord) (err error)

Remove a ResourceRecord from zone file. If the RR is SOA it will reset the value back to default.

func (*Zone) Save

func (zone *Zone) Save() (err error)

Save the content of zone records to file defined by Zone.Path. The zone content will be different with original file, since it does not preserve comment and indentation.

func (*Zone) WriteTo

func (zone *Zone) WriteTo(out io.Writer) (total int64, err error)

WriteTo write the zone as text into w. The result of WriteTo will be different with original content of zone file, since it does not preserve comment and indentation.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL