1
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
3
* Permission is hereby granted, free of charge, to any person obtaining a copy
4
* of this software and associated documentation files (the "Software"), to
5
* deal in the Software without restriction, including without limitation the
6
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7
* sell copies of the Software, and to permit persons to whom the Software is
8
* furnished to do so, subject to the following conditions:
10
* The above copyright notice and this permission notice shall be included in
11
* all copies or substantial portions of the Software.
13
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
35
/* used to track multiple DNS requests received */
43
/* modify handle to append dnsstate */
50
static uv_loop_t* loop;
53
static int server_closed;
54
static uv_tcp_t server;
57
static void after_write(uv_write_t* req, int status);
58
static void after_read(uv_stream_t*, ssize_t nread, uv_buf_t buf);
59
static void on_close(uv_handle_t* peer);
60
static void on_server_close(uv_handle_t* handle);
61
static void on_connection(uv_stream_t*, int status);
63
#define WRITE_BUF_LEN (64*1024)
64
#define DNSREC_LEN (4)
67
#define QUERYID_OFFSET 2
68
unsigned char DNSRsp[] = {0, 43, 0, 0, 0x81, 0x80, 0, 1, 0, 1, 0, 0, 0, 0 };
69
unsigned char qrecord[] = {5, 'e', 'c', 'h', 'o', 's', 3, 's', 'r', 'v', 0, 0, 1, 0, 1};
70
unsigned char arecord[] = {0xc0, 0x0c, 0, 1, 0, 1, 0, 0, 5, 0xbd, 0, 4, 10, 0, 1, 1 };
73
static void after_write(uv_write_t* req, int status) {
77
uv_err_t err = uv_last_error(loop);
78
fprintf(stderr, "uv_write error: %s\n", uv_strerror(err));
82
wr = (write_req_t*) req;
84
/* Free the read/write buffer and the request */
90
static void after_shutdown(uv_shutdown_t* req, int status) {
91
uv_close((uv_handle_t*) req->handle, on_close);
96
static void addrsp(write_req_t* wr, char* hdr) {
101
rsplen = sizeof(DNSRsp) + sizeof(qrecord) + sizeof(arecord);
103
ASSERT (rsplen + wr->buf.len < WRITE_BUF_LEN);
105
dnsrsp = wr->buf.base + wr->buf.len;
107
/* copy stock response */
108
memcpy(dnsrsp, DNSRsp, sizeof(DNSRsp));
109
memcpy(dnsrsp + sizeof(DNSRsp), qrecord, sizeof(qrecord));
110
memcpy(dnsrsp + sizeof(DNSRsp) + sizeof(qrecord), arecord, sizeof(arecord));
112
/* overwrite with network order length and id from request header */
113
reclen = (short int*)dnsrsp;
114
*reclen = htons(rsplen-2);
115
dnsrsp[QUERYID_OFFSET] = hdr[QUERYID_OFFSET];
116
dnsrsp[QUERYID_OFFSET+1] = hdr[QUERYID_OFFSET+1];
118
wr->buf.len += rsplen;
121
static void process_req(uv_stream_t* handle, ssize_t nread, uv_buf_t buf) {
123
dnshandle* dns = (dnshandle*)handle;
124
char hdrbuf[DNSREC_LEN];
125
int hdrbuf_remaining = DNSREC_LEN;
126
int rec_remaining = 0;
127
int readbuf_remaining;
132
wr = (write_req_t*) malloc(sizeof *wr);
133
wr->buf.base = (char*)malloc(WRITE_BUF_LEN);
136
if (dns->state.prevbuf_ptr != NULL) {
137
dnsreq = dns->state.prevbuf_ptr + dns->state.prevbuf_pos;
138
readbuf_remaining = dns->state.prevbuf_rem;
142
readbuf_remaining = nread;
146
while (dnsreq != NULL) {
147
/* something to process */
148
while (readbuf_remaining > 0) {
149
/* something to process in current buffer */
150
if (hdrbuf_remaining > 0) {
151
/* process len and id */
152
if (readbuf_remaining < hdrbuf_remaining) {
153
/* too little to get request header. save for next buffer */
154
memcpy(&hdrbuf[DNSREC_LEN - hdrbuf_remaining], dnsreq, readbuf_remaining);
155
hdrbuf_remaining = DNSREC_LEN - readbuf_remaining;
160
memcpy(&hdrbuf[DNSREC_LEN - hdrbuf_remaining], dnsreq, hdrbuf_remaining);
161
dnsreq += hdrbuf_remaining;
162
readbuf_remaining -= hdrbuf_remaining;
163
hdrbuf_remaining = 0;
165
/* get record length */
166
reclen_n = *((short int*)hdrbuf);
167
rec_remaining = ntohs(reclen_n) - (DNSREC_LEN - 2);
171
if (rec_remaining <= readbuf_remaining) {
175
/* move to next record */
176
dnsreq += rec_remaining;
178
readbuf_remaining -= rec_remaining;
180
hdrbuf_remaining = DNSREC_LEN;
182
/* otherwise this buffer is done. */
183
rec_remaining -= readbuf_remaining;
188
/* if we had to use bytes from prev buffer, start processing the current one */
189
if (usingprev == 1) {
190
/* free previous buffer */
191
free(dns->state.prevbuf_ptr);
193
readbuf_remaining = nread;
200
/* send write buffer */
201
if (wr->buf.len > 0) {
202
if (uv_write((uv_write_t*) &wr->req, handle, &wr->buf, 1, after_write)) {
203
FATAL("uv_write failed");
207
if (readbuf_remaining > 0) {
208
/* save start of record position, so we can continue on next read */
209
dns->state.prevbuf_ptr = buf.base;
210
dns->state.prevbuf_pos = hdrstart - buf.base;
211
dns->state.prevbuf_rem = nread - dns->state.prevbuf_pos;
213
/* nothing left in this buffer */
214
dns->state.prevbuf_ptr = NULL;
215
dns->state.prevbuf_pos = 0;
216
dns->state.prevbuf_rem = 0;
221
static void after_read(uv_stream_t* handle, ssize_t nread, uv_buf_t buf) {
226
ASSERT (uv_last_error(loop).code == UV_EOF);
232
req = malloc(sizeof *req);
233
uv_shutdown(req, handle, after_shutdown);
239
/* Everything OK, but nothing read. */
243
/* process requests and send responses */
244
process_req(handle, nread, buf);
248
static void on_close(uv_handle_t* peer) {
253
static uv_buf_t buf_alloc(uv_handle_t* handle, size_t suggested_size) {
255
buf.base = (char*) malloc(suggested_size);
256
buf.len = suggested_size;
261
static void on_connection(uv_stream_t* server, int status) {
267
handle = (dnshandle*) malloc(sizeof *handle);
268
ASSERT(handle != NULL);
270
/* initialize read buffer state */
271
handle->state.prevbuf_ptr = 0;
272
handle->state.prevbuf_pos = 0;
273
handle->state.prevbuf_rem = 0;
275
r = uv_tcp_init(loop, (uv_tcp_t*)handle);
278
r = uv_accept(server, (uv_stream_t*)handle);
281
r = uv_read_start((uv_stream_t*)handle, buf_alloc, after_read);
286
static void on_server_close(uv_handle_t* handle) {
287
ASSERT(handle == (uv_handle_t*)&server);
291
static int dns_start(int port) {
292
struct sockaddr_in addr = uv_ip4_addr("0.0.0.0", port);
295
r = uv_tcp_init(loop, &server);
297
/* TODO: Error codes */
298
fprintf(stderr, "Socket creation error\n");
302
r = uv_tcp_bind(&server, addr);
304
/* TODO: Error codes */
305
fprintf(stderr, "Bind error\n");
309
r = uv_listen((uv_stream_t*)&server, 128, on_connection);
311
/* TODO: Error codes */
312
fprintf(stderr, "Listen error\n");
320
HELPER_IMPL(dns_server) {
321
loop = uv_default_loop();
323
if (dns_start(TEST_PORT_2))