1# dns-packet 2[![](https://img.shields.io/npm/v/dns-packet.svg?style=flat)](https://www.npmjs.org/package/dns-packet) [![](https://img.shields.io/npm/dm/dns-packet.svg)](https://www.npmjs.org/package/dns-packet) [![](https://api.travis-ci.org/mafintosh/dns-packet.svg?style=flat)](https://travis-ci.org/mafintosh/dns-packet) [![Coverage Status](https://coveralls.io/repos/github/mafintosh/dns-packet/badge.svg?branch=master)](https://coveralls.io/github/mafintosh/dns-packet?branch=master) 3 4An [abstract-encoding](https://github.com/mafintosh/abstract-encoding) compliant module for encoding / decoding DNS packets. Lifted out of [multicast-dns](https://github.com/mafintosh/multicast-dns) as a separate module. 5 6``` 7npm install dns-packet 8``` 9 10## UDP Usage 11 12``` js 13const dnsPacket = require('dns-packet') 14const dgram = require('dgram') 15 16const socket = dgram.createSocket('udp4') 17 18const buf = dnsPacket.encode({ 19 type: 'query', 20 id: 1, 21 flags: dnsPacket.RECURSION_DESIRED, 22 questions: [{ 23 type: 'A', 24 name: 'google.com' 25 }] 26}) 27 28socket.on('message', message => { 29 console.log(dnsPacket.decode(message)) // prints out a response from google dns 30}) 31 32socket.send(buf, 0, buf.length, 53, '8.8.8.8') 33``` 34 35Also see [the UDP example](examples/udp.js). 36 37## TCP, TLS, HTTPS 38 39While DNS has traditionally been used over a datagram transport, it is increasingly being carried over TCP for larger responses commonly including DNSSEC responses and TLS or HTTPS for enhanced security. See below examples on how to use `dns-packet` to wrap DNS packets in these protocols: 40 41- [TCP](examples/tcp.js) 42- [DNS over TLS](examples/tls.js) 43- [DNS over HTTPS](examples/doh.js) 44 45## API 46 47#### `var buf = packets.encode(packet, [buf], [offset])` 48 49Encodes a DNS packet into a buffer containing a UDP payload. 50 51#### `var packet = packets.decode(buf, [offset])` 52 53Decode a DNS packet from a buffer containing a UDP payload. 54 55#### `var buf = packets.streamEncode(packet, [buf], [offset])` 56 57Encodes a DNS packet into a buffer containing a TCP payload. 58 59#### `var packet = packets.streamDecode(buf, [offset])` 60 61Decode a DNS packet from a buffer containing a TCP payload. 62 63#### `var len = packets.encodingLength(packet)` 64 65Returns how many bytes are needed to encode the DNS packet 66 67## Packets 68 69Packets look like this 70 71``` js 72{ 73 type: 'query|response', 74 id: optionalIdNumber, 75 flags: optionalBitFlags, 76 questions: [...], 77 answers: [...], 78 additionals: [...], 79 authorities: [...] 80} 81``` 82 83The bit flags available are 84 85``` js 86packet.RECURSION_DESIRED 87packet.RECURSION_AVAILABLE 88packet.TRUNCATED_RESPONSE 89packet.AUTHORITATIVE_ANSWER 90packet.AUTHENTIC_DATA 91packet.CHECKING_DISABLED 92``` 93 94To use more than one flag bitwise-or them together 95 96``` js 97var flags = packet.RECURSION_DESIRED | packet.RECURSION_AVAILABLE 98``` 99 100And to check for a flag use bitwise-and 101 102``` js 103var isRecursive = message.flags & packet.RECURSION_DESIRED 104``` 105 106A question looks like this 107 108``` js 109{ 110 type: 'A', // or SRV, AAAA, etc 111 class: 'IN', // one of IN, CS, CH, HS, ANY. Default: IN 112 name: 'google.com' // which record are you looking for 113} 114``` 115 116And an answer, additional, or authority looks like this 117 118``` js 119{ 120 type: 'A', // or SRV, AAAA, etc 121 class: 'IN', // one of IN, CS, CH, HS 122 name: 'google.com', // which name is this record for 123 ttl: optionalTimeToLiveInSeconds, 124 (record specific data, see below) 125} 126``` 127 128## Supported record types 129 130#### `A` 131 132``` js 133{ 134 data: 'IPv4 address' // fx 127.0.0.1 135} 136``` 137 138#### `AAAA` 139 140``` js 141{ 142 data: 'IPv6 address' // fx fe80::1 143} 144``` 145 146#### `CAA` 147 148``` js 149{ 150 flags: 128, // octet 151 tag: 'issue|issuewild|iodef', 152 value: 'ca.example.net', 153 issuerCritical: false 154} 155``` 156 157#### `CNAME` 158 159``` js 160{ 161 data: 'cname.to.another.record' 162} 163``` 164 165#### `DNAME` 166 167``` js 168{ 169 data: 'dname.to.another.record' 170} 171``` 172 173#### `DNSKEY` 174 175``` js 176{ 177 flags: 257, // 16 bits 178 algorithm: 1, // octet 179 key: Buffer 180} 181``` 182 183#### `DS` 184 185``` js 186{ 187 keyTag: 12345, 188 algorithm: 8, 189 digestType: 1, 190 digest: Buffer 191} 192``` 193 194#### `HINFO` 195 196``` js 197{ 198 data: { 199 cpu: 'cpu info', 200 os: 'os info' 201 } 202} 203``` 204 205#### `MX` 206 207``` js 208{ 209 preference: 10, 210 exchange: 'mail.example.net' 211} 212``` 213 214#### `NS` 215 216``` js 217{ 218 data: nameServer 219} 220``` 221 222#### `NSEC` 223 224``` js 225{ 226 nextDomain: 'a.domain', 227 rrtypes: ['A', 'TXT', 'RRSIG'] 228} 229``` 230 231#### `NSEC3` 232 233``` js 234{ 235 algorithm: 1, 236 flags: 0, 237 iterations: 2, 238 salt: Buffer, 239 nextDomain: Buffer, // Hashed per RFC5155 240 rrtypes: ['A', 'TXT', 'RRSIG'] 241} 242``` 243 244#### `NULL` 245 246``` js 247{ 248 data: Buffer('any binary data') 249} 250``` 251 252#### `OPT` 253 254[EDNS0](https://tools.ietf.org/html/rfc6891) options. 255 256``` js 257{ 258 type: 'OPT', 259 name: '.', 260 udpPayloadSize: 4096, 261 flags: packet.DNSSEC_OK, 262 options: [{ 263 // pass in any code/data for generic EDNS0 options 264 code: 12, 265 data: Buffer.alloc(31) 266 }, { 267 // Several EDNS0 options have enhanced support 268 code: 'PADDING', 269 length: 31, 270 }, { 271 code: 'CLIENT_SUBNET', 272 family: 2, // 1 for IPv4, 2 for IPv6 273 sourcePrefixLength: 64, // used to truncate IP address 274 scopePrefixLength: 0, 275 ip: 'fe80::', 276 }, { 277 code: 'TCP_KEEPALIVE', 278 timeout: 150 // increments of 100ms. This means 15s. 279 }, { 280 code: 'KEY_TAG', 281 tags: [1, 2, 3], 282 }] 283} 284``` 285 286The options `PADDING`, `CLIENT_SUBNET`, `TCP_KEEPALIVE` and `KEY_TAG` support enhanced de/encoding. See [optionscodes.js](https://github.com/mafintosh/dns-packet/blob/master/optioncodes.js) for all supported option codes. If the `data` property is present on a option, it takes precedence. On decoding, `data` will always be defined. 287 288#### `PTR` 289 290``` js 291{ 292 data: 'points.to.another.record' 293} 294``` 295 296#### `RP` 297 298``` js 299{ 300 mbox: 'admin.example.com', 301 txt: 'txt.example.com' 302} 303``` 304 305#### `RRSIG` 306 307``` js 308{ 309 typeCovered: 'A', 310 algorithm: 8, 311 labels: 1, 312 originalTTL: 3600, 313 expiration: timestamp, 314 inception: timestamp, 315 keyTag: 12345, 316 signersName: 'a.name', 317 signature: Buffer 318} 319``` 320 321#### `SOA` 322 323``` js 324{ 325 data: 326 { 327 mname: domainName, 328 rname: mailbox, 329 serial: zoneSerial, 330 refresh: refreshInterval, 331 retry: retryInterval, 332 expire: expireInterval, 333 minimum: minimumTTL 334 } 335} 336``` 337 338#### `SRV` 339 340``` js 341{ 342 data: { 343 port: servicePort, 344 target: serviceHostName, 345 priority: optionalServicePriority, 346 weight: optionalServiceWeight 347 } 348} 349``` 350 351#### `TXT` 352 353``` js 354{ 355 data: 'text' || Buffer || [ Buffer || 'text' ] 356} 357``` 358 359When encoding, scalar values are converted to an array and strings are converted to UTF-8 encoded Buffers. When decoding, the return value will always be an array of Buffer. 360 361If you need another record type, open an issue and we'll try to add it. 362 363## License 364 365MIT 366