|
|
# dns-packet
[](https://www.npmjs.org/package/dns-packet) [](https://www.npmjs.org/package/dns-packet) [](https://github.com/github/mafintosh/dns-packet/workflows/ci.yml) [](https://coveralls.io/github/mafintosh/dns-packet?branch=master)
An [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.
```npm install dns-packet```
## UDP Usage
``` jsconst dnsPacket = require('dns-packet')const dgram = require('dgram')
const socket = dgram.createSocket('udp4')
const buf = dnsPacket.encode({ type: 'query', id: 1, flags: dnsPacket.RECURSION_DESIRED, questions: [{ type: 'A', name: 'google.com' }]})
socket.on('message', message => { console.log(dnsPacket.decode(message)) // prints out a response from google dns})
socket.send(buf, 0, buf.length, 53, '8.8.8.8')```
Also see [the UDP example](examples/udp.js).
## TCP, TLS, HTTPS
While 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:
- [TCP](examples/tcp.js)- [DNS over TLS](examples/tls.js)- [DNS over HTTPS](examples/doh.js)
## API
#### `var buf = packets.encode(packet, [buf], [offset])`
Encodes a DNS packet into a buffer containing a UDP payload.
#### `var packet = packets.decode(buf, [offset])`
Decode a DNS packet from a buffer containing a UDP payload.
#### `var buf = packets.streamEncode(packet, [buf], [offset])`
Encodes a DNS packet into a buffer containing a TCP payload.
#### `var packet = packets.streamDecode(buf, [offset])`
Decode a DNS packet from a buffer containing a TCP payload.
#### `var len = packets.encodingLength(packet)`
Returns how many bytes are needed to encode the DNS packet
## Packets
Packets look like this
``` js{ type: 'query|response', id: optionalIdNumber, flags: optionalBitFlags, questions: [...], answers: [...], additionals: [...], authorities: [...]}```
The bit flags available are
``` jspacket.RECURSION_DESIREDpacket.RECURSION_AVAILABLEpacket.TRUNCATED_RESPONSEpacket.AUTHORITATIVE_ANSWERpacket.AUTHENTIC_DATApacket.CHECKING_DISABLED```
To use more than one flag bitwise-or them together
``` jsvar flags = packet.RECURSION_DESIRED | packet.RECURSION_AVAILABLE```
And to check for a flag use bitwise-and
``` jsvar isRecursive = message.flags & packet.RECURSION_DESIRED```
A question looks like this
``` js{ type: 'A', // or SRV, AAAA, etc class: 'IN', // one of IN, CS, CH, HS, ANY. Default: IN name: 'google.com' // which record are you looking for}```
And an answer, additional, or authority looks like this
``` js{ type: 'A', // or SRV, AAAA, etc class: 'IN', // one of IN, CS, CH, HS name: 'google.com', // which name is this record for ttl: optionalTimeToLiveInSeconds, (record specific data, see below)}```
## Supported record types
#### `A`
``` js{ data: 'IPv4 address' // fx 127.0.0.1}```
#### `AAAA`
``` js{ data: 'IPv6 address' // fx fe80::1}```
#### `CAA`
``` js{ flags: 128, // octet tag: 'issue|issuewild|iodef', value: 'ca.example.net', issuerCritical: false}```
#### `CNAME`
``` js{ data: 'cname.to.another.record'}```
#### `DNAME`
``` js{ data: 'dname.to.another.record'}```
#### `DNSKEY`
``` js{ flags: 257, // 16 bits algorithm: 1, // octet key: Buffer}```
#### `DS`
``` js{ keyTag: 12345, algorithm: 8, digestType: 1, digest: Buffer}```
#### `HINFO`
``` js{ data: { cpu: 'cpu info', os: 'os info' }}```
#### `MX`
``` js{ preference: 10, exchange: 'mail.example.net'}```
#### `NAPTR`
``` js{ data: { order: 100, preference: 10, flags: 's', services: 'SIP+D2U', regexp: '!^.*$!sip:customer-service@example.com!', replacement: '_sip._udp.example.com' }}```
#### `NS`
``` js{ data: nameServer}```
#### `NSEC`
``` js{ nextDomain: 'a.domain', rrtypes: ['A', 'TXT', 'RRSIG']}```
#### `NSEC3`
``` js{ algorithm: 1, flags: 0, iterations: 2, salt: Buffer, nextDomain: Buffer, // Hashed per RFC5155 rrtypes: ['A', 'TXT', 'RRSIG']}```
#### `NULL`
``` js{ data: Buffer('any binary data')}```
#### `OPT`
[EDNS0](https://tools.ietf.org/html/rfc6891) options.
``` js{ type: 'OPT', name: '.', udpPayloadSize: 4096, flags: packet.DNSSEC_OK, options: [{ // pass in any code/data for generic EDNS0 options code: 12, data: Buffer.alloc(31) }, { // Several EDNS0 options have enhanced support code: 'PADDING', length: 31, }, { code: 'CLIENT_SUBNET', family: 2, // 1 for IPv4, 2 for IPv6 sourcePrefixLength: 64, // used to truncate IP address scopePrefixLength: 0, ip: 'fe80::', }, { code: 'TCP_KEEPALIVE', timeout: 150 // increments of 100ms. This means 15s. }, { code: 'KEY_TAG', tags: [1, 2, 3], }]}```
The 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.
#### `PTR`
``` js{ data: 'points.to.another.record'}```
#### `RP`
``` js{ mbox: 'admin.example.com', txt: 'txt.example.com'}```
#### `SSHFP`
``` js{ algorithm: 1, hash: 1, fingerprint: 'A108C9F834354D5B37AF988141C9294822F5BC00'}````
#### `RRSIG`
``` js{ typeCovered: 'A', algorithm: 8, labels: 1, originalTTL: 3600, expiration: timestamp, inception: timestamp, keyTag: 12345, signersName: 'a.name', signature: Buffer}```
#### `SOA`
``` js{ data: { mname: domainName, rname: mailbox, serial: zoneSerial, refresh: refreshInterval, retry: retryInterval, expire: expireInterval, minimum: minimumTTL }}```
#### `SRV`
``` js{ data: { port: servicePort, target: serviceHostName, priority: optionalServicePriority, weight: optionalServiceWeight }}```
#### `TLSA`
``` js{ usage: 3, selector: 1, matchingType: 1, certificate: Buffer}```
#### `TXT`
``` js{ data: 'text' || Buffer || [ Buffer || 'text' ]}```
When 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.
If you need another record type, open an issue and we'll try to add it.
## License
MIT
|