UNPKG

6.63 kBMarkdownView Raw
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