1/* 2Package dns implements a full featured interface to the Domain Name System. 3Both server- and client-side programming is supported. The package allows 4complete control over what is sent out to the DNS. The API follows the 5less-is-more principle, by presenting a small, clean interface. 6 7It supports (asynchronous) querying/replying, incoming/outgoing zone transfers, 8TSIG, EDNS0, dynamic updates, notifies and DNSSEC validation/signing. 9 10Note that domain names MUST be fully qualified before sending them, unqualified 11names in a message will result in a packing failure. 12 13Resource records are native types. They are not stored in wire format. Basic 14usage pattern for creating a new resource record: 15 16 r := new(dns.MX) 17 r.Hdr = dns.RR_Header{Name: "miek.nl.", Rrtype: dns.TypeMX, Class: dns.ClassINET, Ttl: 3600} 18 r.Preference = 10 19 r.Mx = "mx.miek.nl." 20 21Or directly from a string: 22 23 mx, err := dns.NewRR("miek.nl. 3600 IN MX 10 mx.miek.nl.") 24 25Or when the default origin (.) and TTL (3600) and class (IN) suit you: 26 27 mx, err := dns.NewRR("miek.nl MX 10 mx.miek.nl") 28 29Or even: 30 31 mx, err := dns.NewRR("$ORIGIN nl.\nmiek 1H IN MX 10 mx.miek") 32 33In the DNS messages are exchanged, these messages contain resource records 34(sets). Use pattern for creating a message: 35 36 m := new(dns.Msg) 37 m.SetQuestion("miek.nl.", dns.TypeMX) 38 39Or when not certain if the domain name is fully qualified: 40 41 m.SetQuestion(dns.Fqdn("miek.nl"), dns.TypeMX) 42 43The message m is now a message with the question section set to ask the MX 44records for the miek.nl. zone. 45 46The following is slightly more verbose, but more flexible: 47 48 m1 := new(dns.Msg) 49 m1.Id = dns.Id() 50 m1.RecursionDesired = true 51 m1.Question = make([]dns.Question, 1) 52 m1.Question[0] = dns.Question{"miek.nl.", dns.TypeMX, dns.ClassINET} 53 54After creating a message it can be sent. Basic use pattern for synchronous 55querying the DNS at a server configured on 127.0.0.1 and port 53: 56 57 c := new(dns.Client) 58 in, rtt, err := c.Exchange(m1, "127.0.0.1:53") 59 60Suppressing multiple outstanding queries (with the same question, type and 61class) is as easy as setting: 62 63 c.SingleInflight = true 64 65More advanced options are available using a net.Dialer and the corresponding API. 66For example it is possible to set a timeout, or to specify a source IP address 67and port to use for the connection: 68 69 c := new(dns.Client) 70 laddr := net.UDPAddr{ 71 IP: net.ParseIP("[::1]"), 72 Port: 12345, 73 Zone: "", 74 } 75 c.Dialer := &net.Dialer{ 76 Timeout: 200 * time.Millisecond, 77 LocalAddr: &laddr, 78 } 79 in, rtt, err := c.Exchange(m1, "8.8.8.8:53") 80 81If these "advanced" features are not needed, a simple UDP query can be sent, 82with: 83 84 in, err := dns.Exchange(m1, "127.0.0.1:53") 85 86When this functions returns you will get DNS message. A DNS message consists 87out of four sections. 88The question section: in.Question, the answer section: in.Answer, 89the authority section: in.Ns and the additional section: in.Extra. 90 91Each of these sections (except the Question section) contain a []RR. Basic 92use pattern for accessing the rdata of a TXT RR as the first RR in 93the Answer section: 94 95 if t, ok := in.Answer[0].(*dns.TXT); ok { 96 // do something with t.Txt 97 } 98 99Domain Name and TXT Character String Representations 100 101Both domain names and TXT character strings are converted to presentation form 102both when unpacked and when converted to strings. 103 104For TXT character strings, tabs, carriage returns and line feeds will be 105converted to \t, \r and \n respectively. Back slashes and quotations marks will 106be escaped. Bytes below 32 and above 127 will be converted to \DDD form. 107 108For domain names, in addition to the above rules brackets, periods, spaces, 109semicolons and the at symbol are escaped. 110 111DNSSEC 112 113DNSSEC (DNS Security Extension) adds a layer of security to the DNS. It uses 114public key cryptography to sign resource records. The public keys are stored in 115DNSKEY records and the signatures in RRSIG records. 116 117Requesting DNSSEC information for a zone is done by adding the DO (DNSSEC OK) 118bit to a request. 119 120 m := new(dns.Msg) 121 m.SetEdns0(4096, true) 122 123Signature generation, signature verification and key generation are all supported. 124 125DYNAMIC UPDATES 126 127Dynamic updates reuses the DNS message format, but renames three of the 128sections. Question is Zone, Answer is Prerequisite, Authority is Update, only 129the Additional is not renamed. See RFC 2136 for the gory details. 130 131You can set a rather complex set of rules for the existence of absence of 132certain resource records or names in a zone to specify if resource records 133should be added or removed. The table from RFC 2136 supplemented with the Go 134DNS function shows which functions exist to specify the prerequisites. 135 136 3.2.4 - Table Of Metavalues Used In Prerequisite Section 137 138 CLASS TYPE RDATA Meaning Function 139 -------------------------------------------------------------- 140 ANY ANY empty Name is in use dns.NameUsed 141 ANY rrset empty RRset exists (value indep) dns.RRsetUsed 142 NONE ANY empty Name is not in use dns.NameNotUsed 143 NONE rrset empty RRset does not exist dns.RRsetNotUsed 144 zone rrset rr RRset exists (value dep) dns.Used 145 146The prerequisite section can also be left empty. If you have decided on the 147prerequisites you can tell what RRs should be added or deleted. The next table 148shows the options you have and what functions to call. 149 150 3.4.2.6 - Table Of Metavalues Used In Update Section 151 152 CLASS TYPE RDATA Meaning Function 153 --------------------------------------------------------------- 154 ANY ANY empty Delete all RRsets from name dns.RemoveName 155 ANY rrset empty Delete an RRset dns.RemoveRRset 156 NONE rrset rr Delete an RR from RRset dns.Remove 157 zone rrset rr Add to an RRset dns.Insert 158 159TRANSACTION SIGNATURE 160 161An TSIG or transaction signature adds a HMAC TSIG record to each message sent. 162The supported algorithms include: HmacSHA1, HmacSHA256 and HmacSHA512. 163 164Basic use pattern when querying with a TSIG name "axfr." (note that these key names 165must be fully qualified - as they are domain names) and the base64 secret 166"so6ZGir4GPAqINNh9U5c3A==": 167 168If an incoming message contains a TSIG record it MUST be the last record in 169the additional section (RFC2845 3.2). This means that you should make the 170call to SetTsig last, right before executing the query. If you make any 171changes to the RRset after calling SetTsig() the signature will be incorrect. 172 173 c := new(dns.Client) 174 c.TsigSecret = map[string]string{"axfr.": "so6ZGir4GPAqINNh9U5c3A=="} 175 m := new(dns.Msg) 176 m.SetQuestion("miek.nl.", dns.TypeMX) 177 m.SetTsig("axfr.", dns.HmacSHA256, 300, time.Now().Unix()) 178 ... 179 // When sending the TSIG RR is calculated and filled in before sending 180 181When requesting an zone transfer (almost all TSIG usage is when requesting zone 182transfers), with TSIG, this is the basic use pattern. In this example we 183request an AXFR for miek.nl. with TSIG key named "axfr." and secret 184"so6ZGir4GPAqINNh9U5c3A==" and using the server 176.58.119.54: 185 186 t := new(dns.Transfer) 187 m := new(dns.Msg) 188 t.TsigSecret = map[string]string{"axfr.": "so6ZGir4GPAqINNh9U5c3A=="} 189 m.SetAxfr("miek.nl.") 190 m.SetTsig("axfr.", dns.HmacSHA256, 300, time.Now().Unix()) 191 c, err := t.In(m, "176.58.119.54:53") 192 for r := range c { ... } 193 194You can now read the records from the transfer as they come in. Each envelope 195is checked with TSIG. If something is not correct an error is returned. 196 197A custom TSIG implementation can be used. This requires additional code to 198perform any session establishment and signature generation/verification. The 199client must be configured with an implementation of the TsigProvider interface: 200 201 type Provider struct{} 202 203 func (*Provider) Generate(msg []byte, tsig *dns.TSIG) ([]byte, error) { 204 // Use tsig.Hdr.Name and tsig.Algorithm in your code to 205 // generate the MAC using msg as the payload. 206 } 207 208 func (*Provider) Verify(msg []byte, tsig *dns.TSIG) error { 209 // Use tsig.Hdr.Name and tsig.Algorithm in your code to verify 210 // that msg matches the value in tsig.MAC. 211 } 212 213 c := new(dns.Client) 214 c.TsigProvider = new(Provider) 215 m := new(dns.Msg) 216 m.SetQuestion("miek.nl.", dns.TypeMX) 217 m.SetTsig(keyname, dns.HmacSHA256, 300, time.Now().Unix()) 218 ... 219 // TSIG RR is calculated by calling your Generate method 220 221Basic use pattern validating and replying to a message that has TSIG set. 222 223 server := &dns.Server{Addr: ":53", Net: "udp"} 224 server.TsigSecret = map[string]string{"axfr.": "so6ZGir4GPAqINNh9U5c3A=="} 225 go server.ListenAndServe() 226 dns.HandleFunc(".", handleRequest) 227 228 func handleRequest(w dns.ResponseWriter, r *dns.Msg) { 229 m := new(dns.Msg) 230 m.SetReply(r) 231 if r.IsTsig() != nil { 232 if w.TsigStatus() == nil { 233 // *Msg r has an TSIG record and it was validated 234 m.SetTsig("axfr.", dns.HmacSHA256, 300, time.Now().Unix()) 235 } else { 236 // *Msg r has an TSIG records and it was not validated 237 } 238 } 239 w.WriteMsg(m) 240 } 241 242PRIVATE RRS 243 244RFC 6895 sets aside a range of type codes for private use. This range is 65,280 245- 65,534 (0xFF00 - 0xFFFE). When experimenting with new Resource Records these 246can be used, before requesting an official type code from IANA. 247 248See https://miek.nl/2014/september/21/idn-and-private-rr-in-go-dns/ for more 249information. 250 251EDNS0 252 253EDNS0 is an extension mechanism for the DNS defined in RFC 2671 and updated by 254RFC 6891. It defines an new RR type, the OPT RR, which is then completely 255abused. 256 257Basic use pattern for creating an (empty) OPT RR: 258 259 o := new(dns.OPT) 260 o.Hdr.Name = "." // MUST be the root zone, per definition. 261 o.Hdr.Rrtype = dns.TypeOPT 262 263The rdata of an OPT RR consists out of a slice of EDNS0 (RFC 6891) interfaces. 264Currently only a few have been standardized: EDNS0_NSID (RFC 5001) and 265EDNS0_SUBNET (RFC 7871). Note that these options may be combined in an OPT RR. 266Basic use pattern for a server to check if (and which) options are set: 267 268 // o is a dns.OPT 269 for _, s := range o.Option { 270 switch e := s.(type) { 271 case *dns.EDNS0_NSID: 272 // do stuff with e.Nsid 273 case *dns.EDNS0_SUBNET: 274 // access e.Family, e.Address, etc. 275 } 276 } 277 278SIG(0) 279 280From RFC 2931: 281 282 SIG(0) provides protection for DNS transactions and requests .... 283 ... protection for glue records, DNS requests, protection for message headers 284 on requests and responses, and protection of the overall integrity of a response. 285 286It works like TSIG, except that SIG(0) uses public key cryptography, instead of 287the shared secret approach in TSIG. Supported algorithms: ECDSAP256SHA256, 288ECDSAP384SHA384, RSASHA1, RSASHA256 and RSASHA512. 289 290Signing subsequent messages in multi-message sessions is not implemented. 291*/ 292package dns 293