njord-ns-server 1.0.1 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Makefile +2 -6
- package/README.md +82 -6
- package/RELEASE.md +177 -0
- package/docs/index.md +113 -4
- package/examples/app.js +11 -9
- package/examples/axfr.js +74 -0
- package/examples/cluster.js +46 -63
- package/examples/noanswer.js +18 -16
- package/examples/recursor.js +43 -0
- package/examples/reflect.js +34 -43
- package/lib/errors.js +50 -60
- package/lib/index.js +53 -64
- package/lib/protocol.js +476 -391
- package/lib/query.js +187 -146
- package/lib/records/a.js +17 -14
- package/lib/records/aaaa.js +17 -13
- package/lib/records/cname.js +15 -14
- package/lib/records/mx.js +20 -29
- package/lib/records/ns.js +15 -14
- package/lib/records/ptr.js +22 -0
- package/lib/records/record.js +19 -0
- package/lib/records/soa.js +29 -42
- package/lib/records/srv.js +24 -32
- package/lib/records/txt.js +17 -14
- package/lib/recursor.js +189 -0
- package/lib/server.js +298 -150
- package/lib/validators.js +89 -62
- package/package.json +7 -7
- package/test/dnsbuffer.js +29 -56
- package/test/named.test.js +270 -199
- package/test/protocol.test.js +222 -26
- package/test/query.test.js +111 -43
- package/test/records.test.js +84 -45
- package/test/recursor.test.js +226 -0
- package/test/tcp.test.js +247 -0
- package/test/validator.test.js +118 -73
- package/TODO.md +0 -5
- package/test/dig.js +0 -113
- package/test/helper.js +0 -50
package/Makefile
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
NODEUNIT := ./node_modules/.bin/nodeunit
|
|
2
|
-
BUNYAN := ./node_modules/.bin/bunyan
|
|
3
1
|
NPM := $(shell which npm)
|
|
4
2
|
|
|
5
3
|
.PHONY: setup
|
|
@@ -7,7 +5,5 @@ setup: $(NPM)
|
|
|
7
5
|
$(NPM) install
|
|
8
6
|
|
|
9
7
|
.PHONY: test
|
|
10
|
-
test: $(
|
|
11
|
-
$(
|
|
12
|
-
|
|
13
|
-
|
|
8
|
+
test: $(NPM)
|
|
9
|
+
$(NPM) test
|
package/README.md
CHANGED
|
@@ -8,6 +8,20 @@ functionality that is in use today.
|
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
|
|
11
|
+
## Requirements
|
|
12
|
+
|
|
13
|
+
Node.js 20 or newer.
|
|
14
|
+
|
|
15
|
+
## Testing
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
npm install
|
|
19
|
+
npm test
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
The tests use the test runner that is built into Node.js, and query a running
|
|
23
|
+
server with the `dns` resolver of Node.js, so no other tools are needed.
|
|
24
|
+
|
|
11
25
|
## Creating a DNS Server
|
|
12
26
|
```javascript
|
|
13
27
|
var named = require('./lib/index');
|
|
@@ -30,7 +44,7 @@ server.on('query', function(query) {
|
|
|
30
44
|
|
|
31
45
|
node-named provides helper functions for creating DNS records.
|
|
32
46
|
The records are available under 'named.record.NAME' where NAME is one
|
|
33
|
-
of ['A', 'AAAA', 'CNAME', 'SOA', 'MX', 'NS', 'TXT, 'SRV']. It is important to
|
|
47
|
+
of ['A', 'AAAA', 'CNAME', 'SOA', 'MX', 'NS', 'PTR', 'TXT, 'SRV']. It is important to
|
|
34
48
|
remember that these DNS records are not permanently added to the server.
|
|
35
49
|
They only exist for the length of the particular request. After that, they are
|
|
36
50
|
destroyed. This means you have to create your own lookup mechanism.
|
|
@@ -50,6 +64,7 @@ The following record types are supported
|
|
|
50
64
|
* SOA (start of authority)
|
|
51
65
|
* MX (mail server records)
|
|
52
66
|
* NS (nameserver entries)
|
|
67
|
+
* PTR (reverse entries)
|
|
53
68
|
* TXT (arbitrary text entries)
|
|
54
69
|
* SRV (service discovery)
|
|
55
70
|
|
|
@@ -65,12 +80,69 @@ You can pass in an alternate logger if you wish. If you do not, then it will use
|
|
|
65
80
|
bunyan by default. Your logger must expose the functions 'info', 'debug',
|
|
66
81
|
'warn', 'trace', 'error', and 'notice'.
|
|
67
82
|
|
|
68
|
-
###
|
|
83
|
+
### Validating records
|
|
84
|
+
|
|
85
|
+
`record.valid()` tells you whether a record can be sent to a client, and
|
|
86
|
+
`record.invalid()` which of its properties can not:
|
|
87
|
+
```javascript
|
|
88
|
+
var srv = new named.SRVRecord('sip example', 70000);
|
|
89
|
+
srv.valid(); // false
|
|
90
|
+
srv.invalid(); // [ 'target', 'port' ]
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## TCP and zone transfers (AXFR)
|
|
94
|
+
|
|
95
|
+
A server listens on UDP with `listen`, and on TCP with `listenTcp`. Queries
|
|
96
|
+
that arrive over TCP are emitted and answered in the same way as the ones that
|
|
97
|
+
arrive over UDP, and `query.transport()` tells them apart.
|
|
98
|
+
|
|
99
|
+
A zone transfer is a query of the type `AXFR`, that is answered with all of
|
|
100
|
+
the records of the zone, between two copies of its SOA record. A transfer that
|
|
101
|
+
is too large for one DNS message is split over as many messages as it takes.
|
|
102
|
+
```javascript
|
|
103
|
+
server.listen(9999, '127.0.0.1');
|
|
104
|
+
server.listenTcp(9999, '127.0.0.1');
|
|
105
|
+
|
|
106
|
+
server.on('query', function(query) {
|
|
107
|
+
if (query.type() === 'AXFR') {
|
|
108
|
+
if (query.transport() !== 'tcp' || query.name() !== 'example.com') {
|
|
109
|
+
query.setError('erefuse');
|
|
110
|
+
} else {
|
|
111
|
+
query.addAnswer('example.com', soa, 300);
|
|
112
|
+
// ... one addAnswer for each record of the zone ...
|
|
113
|
+
query.addAnswer('example.com', soa, 300);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
server.send(query);
|
|
117
|
+
});
|
|
118
|
+
```
|
|
119
|
+
See `examples/axfr.js` for a complete server. Anyone who can reach the TCP
|
|
120
|
+
port can ask for a transfer, so check `query._client.address` before you
|
|
121
|
+
answer one.
|
|
69
122
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
123
|
+
## Recursor
|
|
124
|
+
|
|
125
|
+
A recursor is a DNS client that answers a query by asking other DNS servers,
|
|
126
|
+
which are the ones of the system unless you name them. A lookup that fails
|
|
127
|
+
sets the response code of the query (`query.setError`), so the query can be
|
|
128
|
+
sent either way.
|
|
129
|
+
```javascript
|
|
130
|
+
var recursor = named.createRecursor({servers: ['1.1.1.1', '8.8.8.8']});
|
|
131
|
+
|
|
132
|
+
server.on('query', function(query) {
|
|
133
|
+
recursor.resolve(query, function() {
|
|
134
|
+
server.send(query);
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
```
|
|
138
|
+
The client can be used by itself as well:
|
|
139
|
+
```javascript
|
|
140
|
+
recursor.lookup('example.com', 'MX').then(function(answers) {
|
|
141
|
+
// [ { record: MX { exchange: ..., priority: ... }, ttl: 60 }, ... ]
|
|
142
|
+
});
|
|
143
|
+
```
|
|
144
|
+
The A, AAAA, CNAME, MX, NS, PTR, SOA, SRV and TXT records can be looked up.
|
|
145
|
+
See `examples/recursor.js`.
|
|
74
146
|
|
|
75
147
|
## Tell me even more...
|
|
76
148
|
|
|
@@ -85,3 +157,7 @@ basis).
|
|
|
85
157
|
|
|
86
158
|
There are a few handy ways to lookup DNS records in node.
|
|
87
159
|
https://github.com/LCMApps/dns-lookup-cache
|
|
160
|
+
|
|
161
|
+
## Release notes
|
|
162
|
+
|
|
163
|
+
See [RELEASE.md](RELEASE.md) for what changed in each release.
|
package/RELEASE.md
ADDED
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
# Njord NS Server 2.1.0
|
|
2
|
+
|
|
3
|
+
This release completes the TODO list of the project: PTR records, better
|
|
4
|
+
validation of records, queries over TCP including zone transfers (AXFR), and a
|
|
5
|
+
recursor that answers queries by asking other DNS servers.
|
|
6
|
+
|
|
7
|
+
Everything is an addition to 2.0.0. Existing servers keep working without
|
|
8
|
+
changes, with the exceptions listed under "Behaviour changes".
|
|
9
|
+
|
|
10
|
+
## New features
|
|
11
|
+
|
|
12
|
+
### PTR records
|
|
13
|
+
|
|
14
|
+
`named.PTRRecord(target)` is the answer to a reverse lookup, such as a query
|
|
15
|
+
for `1.2.0.192.in-addr.arpa`.
|
|
16
|
+
|
|
17
|
+
### Record validation
|
|
18
|
+
|
|
19
|
+
- `record.valid()` checks that names are valid host or domain names, that
|
|
20
|
+
addresses are valid addresses, and that numbers are integers within the
|
|
21
|
+
range of their field.
|
|
22
|
+
- `record.invalid()` returns the names of the properties that hold invalid
|
|
23
|
+
data, for example `['target', 'port']`.
|
|
24
|
+
- `query.addAnswer` throws a `RangeError` for a TTL that is not an integer
|
|
25
|
+
from 0 to 2147483647.
|
|
26
|
+
|
|
27
|
+
### TCP and zone transfers (AXFR)
|
|
28
|
+
|
|
29
|
+
- `server.listenTcp(port, [host], [onListen])` accepts queries over TCP, next
|
|
30
|
+
to or instead of the UDP socket of `server.listen`. `server.close()` closes
|
|
31
|
+
both.
|
|
32
|
+
- Queries that arrive over TCP are emitted with the same `query` event and
|
|
33
|
+
answered with the same `server.send`. `query.transport()` returns `'udp'` or
|
|
34
|
+
`'tcp'`.
|
|
35
|
+
- A zone transfer is a query of the type `AXFR`, answered with the SOA record
|
|
36
|
+
of the zone, its records, and the SOA record again. A response of more than
|
|
37
|
+
65535 bytes is split over several DNS messages.
|
|
38
|
+
- Idle connections are closed after 30 seconds, which the `tcpTimeout` option
|
|
39
|
+
of `createServer` changes.
|
|
40
|
+
|
|
41
|
+
There is no access control for zone transfers: check `query._client.address`
|
|
42
|
+
before you answer one. See `examples/axfr.js`.
|
|
43
|
+
|
|
44
|
+
### Recursor
|
|
45
|
+
|
|
46
|
+
- `named.createRecursor({servers, timeout, tries, ttl})` creates a DNS client
|
|
47
|
+
on top of the resolver of Node.js (c-ares). Without `servers` it asks the
|
|
48
|
+
DNS servers of the system.
|
|
49
|
+
- `recursor.resolve(query, [callback])` adds the answers that are found to a
|
|
50
|
+
query, or sets its response code when the lookup fails, so that the query
|
|
51
|
+
can be sent either way.
|
|
52
|
+
- `recursor.lookup(name, type)` is the client by itself, and returns a promise
|
|
53
|
+
for a list of records with their TTL.
|
|
54
|
+
- The A, AAAA, CNAME, MX, NS, PTR, SOA, SRV and TXT records can be looked up.
|
|
55
|
+
|
|
56
|
+
The resolver only reports the TTL of A and AAAA records. The other records get
|
|
57
|
+
the `ttl` of the recursor, which is 60 seconds by default. See
|
|
58
|
+
`examples/recursor.js`.
|
|
59
|
+
|
|
60
|
+
### Response codes
|
|
61
|
+
|
|
62
|
+
`query.setError(name)` sets the response code of a query, with `'enoerr'`,
|
|
63
|
+
`'eformat'`, `'eserver'`, `'enoname'`, `'enotimp'` or `'erefuse'`.
|
|
64
|
+
|
|
65
|
+
## Behaviour changes
|
|
66
|
+
|
|
67
|
+
- The target of a SRV record must be a domain name to be valid. It used to be
|
|
68
|
+
any text of up to 255 characters.
|
|
69
|
+
- The port of a SRV record must be from 1 to 65535 to be valid.
|
|
70
|
+
- An IPv6 address with a zone (`fe80::1%eth0`) is not valid.
|
|
71
|
+
- The TTL of a MX record must be at most 2147483647 to be valid.
|
|
72
|
+
- A TXT record of more than 255 bytes is valid, as it is sent as several
|
|
73
|
+
strings.
|
|
74
|
+
- Host names may end with a dot, and may be the root (`.`), which is what a
|
|
75
|
+
null MX record and a SRV record of an unavailable service use.
|
|
76
|
+
- `query.addAnswer` rejects a TTL that is negative, fractional or too large
|
|
77
|
+
when the answer is added. It used to fail when the response was sent.
|
|
78
|
+
|
|
79
|
+
## Known limitations
|
|
80
|
+
|
|
81
|
+
- A response that is too large for UDP is sent as it is. It is not truncated
|
|
82
|
+
to make the client retry over TCP.
|
|
83
|
+
- `examples/cluster.js` does not run on Windows.
|
|
84
|
+
|
|
85
|
+
## Testing
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
npm install
|
|
89
|
+
npm test
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
The 105 tests cover the new features with a live server: queries over TCP, a
|
|
93
|
+
zone transfer of 6000 records, and a recursor that asks a second server.
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
# Njord NS Server 2.0.0
|
|
98
|
+
|
|
99
|
+
This release modernizes the codebase, updates every dependency, and makes
|
|
100
|
+
encoding a response several times faster. The exported API is unchanged, but
|
|
101
|
+
the minimum Node.js version is raised and a number of bugs are fixed in ways
|
|
102
|
+
that callers can observe, hence the new major version.
|
|
103
|
+
|
|
104
|
+
## Requirements
|
|
105
|
+
|
|
106
|
+
Node.js 20 or newer (was 0.6).
|
|
107
|
+
|
|
108
|
+
## Upgrading from 1.x
|
|
109
|
+
|
|
110
|
+
No code changes are needed for most users: the exports, method signatures and
|
|
111
|
+
events are the same, and `error.message()` is still a function. Check the list
|
|
112
|
+
of behaviour changes below if you relied on any of the old behaviour.
|
|
113
|
+
|
|
114
|
+
## Dependencies
|
|
115
|
+
|
|
116
|
+
| Package | 1.0.1 | 2.0.0 |
|
|
117
|
+
|-----------|-------|---------|
|
|
118
|
+
| bunyan | 0.7.0 | 1.8.15 |
|
|
119
|
+
| ipaddr.js | 0.1.1 | 2.5.0 |
|
|
120
|
+
| nodeunit | 0.9.0 | removed |
|
|
121
|
+
|
|
122
|
+
The tests now use the test runner that is built into Node.js, so there are no
|
|
123
|
+
development dependencies, and `dig` is no longer needed to run them.
|
|
124
|
+
|
|
125
|
+
## Performance
|
|
126
|
+
|
|
127
|
+
A response is written in a single pass into one buffer, instead of one small
|
|
128
|
+
buffer per field. Names are compressed with DNS pointers (RFC 1035 4.1.4), so
|
|
129
|
+
responses are smaller as well.
|
|
130
|
+
|
|
131
|
+
Parsing a query and encoding its response, measured on one machine:
|
|
132
|
+
|
|
133
|
+
| Response | 1.0.1 (ops/s) | 2.0.0 (ops/s) | Size (bytes) |
|
|
134
|
+
|----------|---------------|---------------|--------------|
|
|
135
|
+
| A | 53k | 236k | 62 → 48 |
|
|
136
|
+
| AAAA | 41k | 144k | 74 → 60 |
|
|
137
|
+
| SOA | 44k | 234k | 113 → 79 |
|
|
138
|
+
| 4 × MX | 21k | 118k | 208 → 112 |
|
|
139
|
+
|
|
140
|
+
This is a micro-benchmark of the protocol code, not of network throughput.
|
|
141
|
+
|
|
142
|
+
## Behaviour changes
|
|
143
|
+
|
|
144
|
+
- `record.valid()` validates the record. It used to return `true` for
|
|
145
|
+
everything.
|
|
146
|
+
- `query.addAnswer(name, record, 0)` sends a TTL of 0. It used to be replaced
|
|
147
|
+
by the default of 5.
|
|
148
|
+
- `server.listen(port, '::1')` listens on IPv6. A UDP4 socket used to be
|
|
149
|
+
opened whatever the address was.
|
|
150
|
+
- The address family of the client of a query is the real one. It used to be
|
|
151
|
+
reported as `udp6` for every client.
|
|
152
|
+
- The counts in the header of a response describe what is sent. A query with
|
|
153
|
+
EDNS options used to get a response that announced an additional record
|
|
154
|
+
which was not there.
|
|
155
|
+
- The opcode of a query is decoded correctly, so `query.operation()` works for
|
|
156
|
+
status, notify and update messages.
|
|
157
|
+
- Names with a trailing dot, and the root name, are encoded correctly.
|
|
158
|
+
- TXT records longer than 255 bytes are split into several strings.
|
|
159
|
+
- The constructors of the records leave the options that are passed to them
|
|
160
|
+
alone.
|
|
161
|
+
- Invalid addresses and names are rejected when the response is encoded, which
|
|
162
|
+
is reported with the `uncaughtException` event of the server.
|
|
163
|
+
|
|
164
|
+
## Other changes
|
|
165
|
+
|
|
166
|
+
- `lib/` is written with classes and in strict mode, and no longer leaks
|
|
167
|
+
global variables.
|
|
168
|
+
- The examples listen on port 9999, as their output always claimed.
|
|
169
|
+
- `examples/cluster.js` documents that it does not run on Windows, where
|
|
170
|
+
Node.js can not share a UDP socket between the workers of a cluster.
|
|
171
|
+
|
|
172
|
+
## Testing
|
|
173
|
+
|
|
174
|
+
```
|
|
175
|
+
npm install
|
|
176
|
+
npm test
|
|
177
|
+
```
|
package/docs/index.md
CHANGED
|
@@ -77,6 +77,8 @@ options is an object which may specify:
|
|
|
77
77
|
|
|
78
78
|
- log: an optional bunyan logger
|
|
79
79
|
- name: an optional name used to identify the server
|
|
80
|
+
- tcpTimeout: the number of milliseconds after which an idle TCP connection is
|
|
81
|
+
closed. Defaults to 30000, and 0 disables the timeout.
|
|
80
82
|
|
|
81
83
|
Here is an example a named server listening on port 53
|
|
82
84
|
|
|
@@ -99,6 +101,17 @@ This function is asyncronous. Whenever the server is litening a `listen` event
|
|
|
99
101
|
will be emitted. The last parameter `onListen` will be executed but not attached
|
|
100
102
|
to the listen event, when the server is listening.
|
|
101
103
|
|
|
104
|
+
### server.listenTcp(port, [host], [onListen])
|
|
105
|
+
|
|
106
|
+
Start accepting TCP connections on the specified `port` and `host`, next to
|
|
107
|
+
or instead of the UDP socket of `server.listen`. TCP is what clients use for
|
|
108
|
+
zone transfers (AXFR), and for answers that are too large for UDP.
|
|
109
|
+
|
|
110
|
+
Queries that arrive over TCP are emitted with the same `query` event, and are
|
|
111
|
+
answered with the same `server.send`. A client may send several queries over
|
|
112
|
+
one connection. A response of more than 65535 bytes is sent as several DNS
|
|
113
|
+
messages, which is how a large zone is transferred.
|
|
114
|
+
|
|
102
115
|
### server.send(queryResponse)
|
|
103
116
|
|
|
104
117
|
Sends a `queryResponse` message. The queryResponse includes information about
|
|
@@ -111,8 +124,8 @@ will send a 'null-response' DNS message. This is the equivalent of an HTTP 404.
|
|
|
111
124
|
|
|
112
125
|
### server.close(onClose)
|
|
113
126
|
|
|
114
|
-
Stops listening
|
|
115
|
-
|
|
127
|
+
Stops listening, on UDP as well as on TCP, and closes the open TCP connections.
|
|
128
|
+
`onClose` is an optional callback that is called once everything is closed.
|
|
116
129
|
|
|
117
130
|
### Event: 'listening'
|
|
118
131
|
|
|
@@ -190,6 +203,22 @@ are responding with. In most cases this will be what the query.type() returns,
|
|
|
190
203
|
but for instances like an 'A' or 'AAAA' request you may elect to respond with a
|
|
191
204
|
CNAME record.
|
|
192
205
|
|
|
206
|
+
### query.transport()
|
|
207
|
+
|
|
208
|
+
Returns `'udp'` or `'tcp'`, depending on how the query was received. A zone
|
|
209
|
+
transfer (a query of the type 'AXFR') should only be answered over TCP.
|
|
210
|
+
|
|
211
|
+
### query.setError(name)
|
|
212
|
+
|
|
213
|
+
Sets the response code of the query. `name` is one of:
|
|
214
|
+
|
|
215
|
+
- `'enoerr'`: no error, which is the default
|
|
216
|
+
- `'eformat'`: the query could not be interpreted
|
|
217
|
+
- `'eserver'`: the server failed to process the query
|
|
218
|
+
- `'enoname'`: the name does not exist
|
|
219
|
+
- `'enotimp'`: the kind of query is not implemented
|
|
220
|
+
- `'erefuse'`: the server refuses to answer, for policy reasons
|
|
221
|
+
|
|
193
222
|
### query.operation()
|
|
194
223
|
|
|
195
224
|
Returns the type of operation that the client is requesting. In almost all cases
|
|
@@ -202,6 +231,68 @@ Encodes the query and stores the results as a `buffer` in the query itself.
|
|
|
202
231
|
This function should never need to be invoked, as the `server.send` function
|
|
203
232
|
will automatically encode a query prior to being sent to the client.
|
|
204
233
|
|
|
234
|
+
### query.encodeMessages(maxSize)
|
|
235
|
+
|
|
236
|
+
Encodes the query as an array of buffers, each of which is a DNS message of at
|
|
237
|
+
most `maxSize` bytes with as many of the answers as fit. This is what
|
|
238
|
+
`server.send` uses for a query that was received over TCP.
|
|
239
|
+
|
|
240
|
+
## Class: named.Recursor
|
|
241
|
+
|
|
242
|
+
A DNS client that answers queries by asking other DNS servers. The lookups are
|
|
243
|
+
made with the resolver of Node.js, which is built on c-ares.
|
|
244
|
+
|
|
245
|
+
### named.createRecursor([options])
|
|
246
|
+
|
|
247
|
+
options is an object which may specify:
|
|
248
|
+
|
|
249
|
+
- servers: an array with the addresses of the servers to ask, each with an
|
|
250
|
+
optional port (`'192.0.2.1'`, `'192.0.2.1:5353'`, `'[2001:db8::1]:53'`).
|
|
251
|
+
Defaults to the DNS servers of the system.
|
|
252
|
+
- timeout: the number of milliseconds to wait for an answer to each attempt
|
|
253
|
+
- tries: the number of attempts that are made for each lookup
|
|
254
|
+
- ttl: the ttl of the answers for which the server that was asked does not
|
|
255
|
+
report one, which it only does for A and AAAA records. Defaults to 60.
|
|
256
|
+
|
|
257
|
+
### recursor.resolve(query, [callback])
|
|
258
|
+
|
|
259
|
+
Looks up the question of a `query`, and adds what is found to it as answers.
|
|
260
|
+
When the lookup fails the response code of the query is set instead: to
|
|
261
|
+
'enoname' for a name that does not exist, to 'enotimp' for a type that can not
|
|
262
|
+
be looked up, to 'erefuse' when the other server refuses, and to 'eserver' for
|
|
263
|
+
everything else. In either case the query is ready to be sent.
|
|
264
|
+
|
|
265
|
+
server.on('query', function(query) {
|
|
266
|
+
recursor.resolve(query, function() {
|
|
267
|
+
server.send(query);
|
|
268
|
+
});
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
`callback` is called with an error (which is `null`, as failed lookups are
|
|
272
|
+
reported to the client) and the query. Without a callback a promise for the
|
|
273
|
+
query is returned.
|
|
274
|
+
|
|
275
|
+
### recursor.lookup(name, type)
|
|
276
|
+
|
|
277
|
+
Looks up the records of a `type` for a `name`. Returns a promise for an array
|
|
278
|
+
of objects with a `record` (an instance of `named.Record`) and its `ttl`.
|
|
279
|
+
The promise is rejected with the error of the resolver, of which the `code` is
|
|
280
|
+
one of the error codes of the `dns` module of Node.js, such as 'ENOTFOUND' and
|
|
281
|
+
'ENODATA'.
|
|
282
|
+
|
|
283
|
+
### recursor.types()
|
|
284
|
+
|
|
285
|
+
Returns the types of record that can be looked up: A, AAAA, CNAME, MX, NS, PTR,
|
|
286
|
+
SOA, SRV and TXT.
|
|
287
|
+
|
|
288
|
+
### recursor.servers()
|
|
289
|
+
|
|
290
|
+
Returns the addresses of the servers that are asked.
|
|
291
|
+
|
|
292
|
+
### recursor.cancel()
|
|
293
|
+
|
|
294
|
+
Cancels the lookups that are in progress, which then fail.
|
|
295
|
+
|
|
205
296
|
|
|
206
297
|
## Records
|
|
207
298
|
|
|
@@ -243,6 +334,17 @@ Create an IPv6 resource record.
|
|
|
243
334
|
Create an Alias record. When these records are sent to the client, the client
|
|
244
335
|
will often make an additional request for the alias itself.
|
|
245
336
|
|
|
337
|
+
### named.NSRecord(target)
|
|
338
|
+
|
|
339
|
+
Create a Name Server record. `target` is the name of a server that is
|
|
340
|
+
authoritative for the domain.
|
|
341
|
+
|
|
342
|
+
### named.PTRRecord(target)
|
|
343
|
+
|
|
344
|
+
Create a Pointer record, which is the answer to a reverse lookup: a query for a
|
|
345
|
+
name such as `1.2.0.192.in-addr.arpa`. `target` is the name of the host that
|
|
346
|
+
has the address.
|
|
347
|
+
|
|
246
348
|
### named.MXRecord(exchange, options)
|
|
247
349
|
|
|
248
350
|
Create a Mail Server record. A client making this request will often make an
|
|
@@ -269,14 +371,21 @@ Options:
|
|
|
269
371
|
### named.TXTRecord(target)
|
|
270
372
|
|
|
271
373
|
Create a text resource record.
|
|
272
|
-
`target` can be any text
|
|
374
|
+
`target` can be any text. Text of more than 255 bytes is sent as several
|
|
375
|
+
strings, which clients join again.
|
|
273
376
|
|
|
274
377
|
## Class: named.Record
|
|
275
378
|
|
|
276
379
|
### record.valid()
|
|
277
380
|
|
|
278
381
|
This function will ensure that the data you used to create the record is in fact
|
|
279
|
-
valid.
|
|
382
|
+
valid. Names must be valid host or domain names, addresses must be valid
|
|
383
|
+
addresses, and numbers must be integers within the range of their field.
|
|
384
|
+
|
|
385
|
+
### record.invalid()
|
|
386
|
+
|
|
387
|
+
Returns an array with the names of the properties of the record that hold
|
|
388
|
+
invalid data, which is empty for a valid record.
|
|
280
389
|
|
|
281
390
|
## DnsError
|
|
282
391
|
|
package/examples/app.js
CHANGED
|
@@ -1,15 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
var server = named.createServer();
|
|
1
|
+
'use strict';
|
|
3
2
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
const named = require('../lib');
|
|
4
|
+
|
|
5
|
+
const PORT = 9999;
|
|
6
|
+
const server = named.createServer();
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
server.listen(PORT, '127.0.0.1', () => {
|
|
9
|
+
console.log('DNS server started on port %d', PORT);
|
|
10
|
+
});
|
|
9
11
|
|
|
10
|
-
server.on('query',
|
|
11
|
-
|
|
12
|
-
|
|
12
|
+
server.on('query', (query) => {
|
|
13
|
+
const domain = query.name();
|
|
14
|
+
const record = new named.SOARecord(domain, {serial: 12345, ttl: 300});
|
|
13
15
|
query.addAnswer(domain, record, 300);
|
|
14
16
|
server.send(query);
|
|
15
17
|
});
|
package/examples/axfr.js
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* A server that listens on UDP as well as on TCP, and that transfers its zone
|
|
5
|
+
* to the clients that ask for it (AXFR).
|
|
6
|
+
*
|
|
7
|
+
* You can test it like this:
|
|
8
|
+
*
|
|
9
|
+
* $ dig @127.0.0.1 -p 9999 www.example.com
|
|
10
|
+
* $ dig @127.0.0.1 -p 9999 example.com AXFR
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
const named = require('../lib');
|
|
14
|
+
|
|
15
|
+
const PORT = 9999;
|
|
16
|
+
const ZONE = 'example.com';
|
|
17
|
+
const TTL = 300;
|
|
18
|
+
|
|
19
|
+
const soa = new named.SOARecord('ns.' + ZONE, {serial: 2024010101});
|
|
20
|
+
|
|
21
|
+
// name -> records
|
|
22
|
+
const records = {
|
|
23
|
+
'example.com': [
|
|
24
|
+
new named.NSRecord('ns.example.com'),
|
|
25
|
+
new named.MXRecord('smtp.example.com', {priority: 10})
|
|
26
|
+
],
|
|
27
|
+
'ns.example.com': [new named.ARecord('192.0.2.1')],
|
|
28
|
+
'smtp.example.com': [new named.ARecord('192.0.2.2')],
|
|
29
|
+
'www.example.com': [new named.CNAMERecord('example.com')],
|
|
30
|
+
'_sip._tcp.example.com': [new named.SRVRecord('sip.example.com', 5060)]
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const server = named.createServer();
|
|
34
|
+
|
|
35
|
+
server.on('query', (query) => {
|
|
36
|
+
const domain = query.name();
|
|
37
|
+
const type = query.type();
|
|
38
|
+
console.log('DNS Query: (%s) %s over %s', type, domain, query.transport());
|
|
39
|
+
|
|
40
|
+
if (type === 'AXFR') {
|
|
41
|
+
// Zone transfers are only possible over TCP. This is also the place to
|
|
42
|
+
// check query._client.address: a zone should not be given to everyone.
|
|
43
|
+
if (query.transport() !== 'tcp' || domain !== ZONE) {
|
|
44
|
+
query.setError('erefuse');
|
|
45
|
+
} else {
|
|
46
|
+
// a transfer starts and ends with the SOA record of the zone
|
|
47
|
+
query.addAnswer(ZONE, soa, TTL);
|
|
48
|
+
for (const name of Object.keys(records)) {
|
|
49
|
+
for (const record of records[name])
|
|
50
|
+
query.addAnswer(name, record, TTL);
|
|
51
|
+
}
|
|
52
|
+
query.addAnswer(ZONE, soa, TTL);
|
|
53
|
+
}
|
|
54
|
+
} else if (type === 'SOA' && domain === ZONE) {
|
|
55
|
+
query.addAnswer(ZONE, soa, TTL);
|
|
56
|
+
} else if (records[domain] === undefined) {
|
|
57
|
+
query.setError('enoname');
|
|
58
|
+
} else {
|
|
59
|
+
for (const record of records[domain]) {
|
|
60
|
+
if (record._type === type)
|
|
61
|
+
query.addAnswer(domain, record, TTL);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
server.send(query);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
server.listen(PORT, '127.0.0.1', () => {
|
|
69
|
+
console.log('DNS server started on udp port %d', PORT);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
server.listenTcp(PORT, '127.0.0.1', () => {
|
|
73
|
+
console.log('DNS server started on tcp port %d', PORT);
|
|
74
|
+
});
|