dns-server.c
Go to the documentation of this file.
1 /* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
2  *
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:
9  *
10  * The above copyright notice and this permission notice shall be included in
11  * all copies or substantial portions of the Software.
12  *
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
19  * IN THE SOFTWARE.
20  */
21 
22 #include "uv.h"
23 #include "task.h"
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 
28 
29 typedef struct {
31  uv_buf_t buf;
32 } write_req_t;
33 
34 
35 /* used to track multiple DNS requests received */
36 typedef struct {
37  char* prevbuf_ptr;
40 } dnsstate;
41 
42 
43 /* modify handle to append dnsstate */
44 typedef struct {
47 } dnshandle;
48 
49 
50 static uv_loop_t* loop;
51 
52 
54 
55 
56 static void after_write(uv_write_t* req, int status);
57 static void after_read(uv_stream_t*, ssize_t nread, const uv_buf_t* buf);
58 static void on_close(uv_handle_t* peer);
59 static void on_connection(uv_stream_t*, int status);
60 
61 #define WRITE_BUF_LEN (64*1024)
62 #define DNSREC_LEN (4)
63 
64 #define LEN_OFFSET 0
65 #define QUERYID_OFFSET 2
66 
67 static unsigned char DNSRsp[] = {
68  0, 43, 0, 0, 0x81, 0x80, 0, 1, 0, 1, 0, 0, 0, 0
69 };
70 
71 static unsigned char qrecord[] = {
72  5, 'e', 'c', 'h', 'o', 's', 3, 's', 'r', 'v', 0, 0, 1, 0, 1
73 };
74 
75 static unsigned char arecord[] = {
76  0xc0, 0x0c, 0, 1, 0, 1, 0, 0, 5, 0xbd, 0, 4, 10, 0, 1, 1
77 };
78 
79 
80 static void after_write(uv_write_t* req, int status) {
81  write_req_t* wr;
82 
83  if (status) {
84  fprintf(stderr, "uv_write error: %s\n", uv_strerror(status));
85  ASSERT(0);
86  }
87 
88  wr = (write_req_t*) req;
89 
90  /* Free the read/write buffer and the request */
91  free(wr->buf.base);
92  free(wr);
93 }
94 
95 
96 static void after_shutdown(uv_shutdown_t* req, int status) {
98  free(req);
99 }
100 
101 
102 static void addrsp(write_req_t* wr, char* hdr) {
103  char * dnsrsp;
104  short int rsplen;
105  short int* reclen;
106 
107  rsplen = sizeof(DNSRsp) + sizeof(qrecord) + sizeof(arecord);
108 
109  ASSERT (rsplen + wr->buf.len < WRITE_BUF_LEN);
110 
111  dnsrsp = wr->buf.base + wr->buf.len;
112 
113  /* copy stock response */
114  memcpy(dnsrsp, DNSRsp, sizeof(DNSRsp));
115  memcpy(dnsrsp + sizeof(DNSRsp), qrecord, sizeof(qrecord));
116  memcpy(dnsrsp + sizeof(DNSRsp) + sizeof(qrecord), arecord, sizeof(arecord));
117 
118  /* overwrite with network order length and id from request header */
119  reclen = (short int*)dnsrsp;
120  *reclen = htons(rsplen-2);
121  dnsrsp[QUERYID_OFFSET] = hdr[QUERYID_OFFSET];
122  dnsrsp[QUERYID_OFFSET+1] = hdr[QUERYID_OFFSET+1];
123 
124  wr->buf.len += rsplen;
125 }
126 
128  ssize_t nread,
129  const uv_buf_t* buf) {
130  write_req_t* wr;
131  dnshandle* dns = (dnshandle*)handle;
132  char hdrbuf[DNSREC_LEN];
133  int hdrbuf_remaining = DNSREC_LEN;
134  int rec_remaining = 0;
135  int readbuf_remaining;
136  char* dnsreq;
137  char* hdrstart;
138  int usingprev = 0;
139 
140  wr = (write_req_t*) malloc(sizeof *wr);
141  wr->buf.base = (char*)malloc(WRITE_BUF_LEN);
142  wr->buf.len = 0;
143 
144  if (dns->state.prevbuf_ptr != NULL) {
145  dnsreq = dns->state.prevbuf_ptr + dns->state.prevbuf_pos;
146  readbuf_remaining = dns->state.prevbuf_rem;
147  usingprev = 1;
148  } else {
149  dnsreq = buf->base;
150  readbuf_remaining = nread;
151  }
152  hdrstart = dnsreq;
153 
154  while (dnsreq != NULL) {
155  /* something to process */
156  while (readbuf_remaining > 0) {
157  /* something to process in current buffer */
158  if (hdrbuf_remaining > 0) {
159  /* process len and id */
160  if (readbuf_remaining < hdrbuf_remaining) {
161  /* too little to get request header. save for next buffer */
162  memcpy(&hdrbuf[DNSREC_LEN - hdrbuf_remaining],
163  dnsreq,
164  readbuf_remaining);
165  hdrbuf_remaining = DNSREC_LEN - readbuf_remaining;
166  break;
167  } else {
168  /* save header */
169  memcpy(&hdrbuf[DNSREC_LEN - hdrbuf_remaining],
170  dnsreq,
171  hdrbuf_remaining);
172  dnsreq += hdrbuf_remaining;
173  readbuf_remaining -= hdrbuf_remaining;
174  hdrbuf_remaining = 0;
175 
176  /* get record length */
177  rec_remaining = (unsigned) hdrbuf[0] * 256 + (unsigned) hdrbuf[1];
178  rec_remaining -= (DNSREC_LEN - 2);
179  }
180  }
181 
182  if (rec_remaining <= readbuf_remaining) {
183  /* prepare reply */
184  addrsp(wr, hdrbuf);
185 
186  /* move to next record */
187  dnsreq += rec_remaining;
188  hdrstart = dnsreq;
189  readbuf_remaining -= rec_remaining;
190  rec_remaining = 0;
191  hdrbuf_remaining = DNSREC_LEN;
192  } else {
193  /* otherwise this buffer is done. */
194  rec_remaining -= readbuf_remaining;
195  break;
196  }
197  }
198 
199  /* If we had to use bytes from prev buffer, start processing the current
200  * one.
201  */
202  if (usingprev == 1) {
203  /* free previous buffer */
204  free(dns->state.prevbuf_ptr);
205  dnsreq = buf->base;
206  readbuf_remaining = nread;
207  usingprev = 0;
208  } else {
209  dnsreq = NULL;
210  }
211  }
212 
213  /* send write buffer */
214  if (wr->buf.len > 0) {
215  if (uv_write((uv_write_t*) &wr->req, handle, &wr->buf, 1, after_write)) {
216  FATAL("uv_write failed");
217  }
218  }
219 
220  if (readbuf_remaining > 0) {
221  /* save start of record position, so we can continue on next read */
222  dns->state.prevbuf_ptr = buf->base;
223  dns->state.prevbuf_pos = hdrstart - buf->base;
224  dns->state.prevbuf_rem = nread - dns->state.prevbuf_pos;
225  } else {
226  /* nothing left in this buffer */
227  dns->state.prevbuf_ptr = NULL;
228  dns->state.prevbuf_pos = 0;
229  dns->state.prevbuf_rem = 0;
230  free(buf->base);
231  }
232 }
233 
235  ssize_t nread,
236  const uv_buf_t* buf) {
238 
239  if (nread < 0) {
240  /* Error or EOF */
241  ASSERT(nread == UV_EOF);
242 
243  if (buf->base) {
244  free(buf->base);
245  }
246 
247  req = malloc(sizeof *req);
249 
250  return;
251  }
252 
253  if (nread == 0) {
254  /* Everything OK, but nothing read. */
255  free(buf->base);
256  return;
257  }
258  /* process requests and send responses */
259  process_req(handle, nread, buf);
260 }
261 
262 
263 static void on_close(uv_handle_t* peer) {
264  free(peer);
265 }
266 
267 
269  size_t suggested_size,
270  uv_buf_t* buf) {
271  buf->base = malloc(suggested_size);
272  buf->len = suggested_size;
273 }
274 
275 
277  dnshandle* handle;
278  int r;
279 
280  ASSERT(status == 0);
281 
282  handle = (dnshandle*) malloc(sizeof *handle);
283  ASSERT(handle != NULL);
284 
285  /* initialize read buffer state */
286  handle->state.prevbuf_ptr = 0;
287  handle->state.prevbuf_pos = 0;
288  handle->state.prevbuf_rem = 0;
289 
291  ASSERT(r == 0);
292 
294  ASSERT(r == 0);
295 
297  ASSERT(r == 0);
298 }
299 
300 
301 static int dns_start(int port) {
302  struct sockaddr_in addr;
303  int r;
304 
305  ASSERT(0 == uv_ip4_addr("0.0.0.0", port, &addr));
306 
307  r = uv_tcp_init(loop, &server);
308  if (r) {
309  /* TODO: Error codes */
310  fprintf(stderr, "Socket creation error\n");
311  return 1;
312  }
313 
314  r = uv_tcp_bind(&server, (const struct sockaddr*) &addr, 0);
315  if (r) {
316  /* TODO: Error codes */
317  fprintf(stderr, "Bind error\n");
318  return 1;
319  }
320 
322  if (r) {
323  /* TODO: Error codes */
324  fprintf(stderr, "Listen error\n");
325  return 1;
326  }
327 
328  return 0;
329 }
330 
331 
333  loop = uv_default_loop();
334 
335  if (dns_start(TEST_PORT_2))
336  return 1;
337 
339  return 0;
340 }
qrecord
static unsigned char qrecord[]
Definition: dns-server.c:71
loop
static uv_loop_t * loop
Definition: dns-server.c:50
dnsstate::prevbuf_pos
int prevbuf_pos
Definition: dns-server.c:38
buf_alloc
static void buf_alloc(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf)
Definition: dns-server.c:268
task.h
write_req_t::req
uv_write_t req
Definition: worker.c:12
dns_server
Definition: dns_server.py:1
on_connection
static void on_connection(uv_stream_t *, int status)
Definition: dns-server.c:276
uv_shutdown_s
Definition: uv.h:417
server
static uv_tcp_t server
Definition: dns-server.c:53
string.h
buf
voidpf void * buf
Definition: bloaty/third_party/zlib/contrib/minizip/ioapi.h:136
uv_listen
UV_EXTERN int uv_listen(uv_stream_t *stream, int backlog, uv_connection_cb cb)
Definition: unix/stream.c:656
uv_connect_s::handle
uv_stream_t * handle
Definition: uv.h:583
ASSERT
#define ASSERT(expr)
Definition: task.h:102
write_req_t
Definition: worker.c:11
status
absl::Status status
Definition: rls.cc:251
uv_strerror
const UV_EXTERN char * uv_strerror(int err)
Definition: uv-common.c:212
process_req
static void process_req(uv_stream_t *handle, ssize_t nread, const uv_buf_t *buf)
Definition: dns-server.c:127
addrsp
static void addrsp(write_req_t *wr, char *hdr)
Definition: dns-server.c:102
uv_run
UV_EXTERN int uv_run(uv_loop_t *, uv_run_mode mode)
Definition: unix/core.c:361
uv_tcp_bind
UV_EXTERN int uv_tcp_bind(uv_tcp_t *handle, const struct sockaddr *addr, unsigned int flags)
Definition: uv-common.c:277
python_utils.port_server.stderr
stderr
Definition: port_server.py:51
uv_close
UV_EXTERN void uv_close(uv_handle_t *handle, uv_close_cb close_cb)
Definition: unix/core.c:112
uv_stream_s
Definition: uv.h:491
dnsstate
Definition: dns-server.c:36
dnshandle::handle
uv_tcp_t handle
Definition: dns-server.c:45
uv_ip4_addr
UV_EXTERN int uv_ip4_addr(const char *ip, int port, struct sockaddr_in *addr)
Definition: uv-common.c:221
memcpy
memcpy(mem, inblock.get(), min(CONTAINING_RECORD(inblock.get(), MEMBLOCK, data) ->size, size))
uv_default_loop
UV_EXTERN uv_loop_t * uv_default_loop(void)
Definition: uv-common.c:733
ssize_t
intptr_t ssize_t
Definition: win.h:27
arecord
static unsigned char arecord[]
Definition: dns-server.c:75
uv_write
UV_EXTERN int uv_write(uv_write_t *req, uv_stream_t *handle, const uv_buf_t bufs[], unsigned int nbufs, uv_write_cb cb)
Definition: unix/stream.c:1492
req
static uv_connect_t req
Definition: test-connection-fail.c:30
UV_RUN_DEFAULT
@ UV_RUN_DEFAULT
Definition: uv.h:254
uv_shutdown
UV_PRIVATE_REQ_TYPES UV_EXTERN int uv_shutdown(uv_shutdown_t *req, uv_stream_t *handle, uv_shutdown_cb cb)
Definition: unix/stream.c:1259
HELPER_IMPL
HELPER_IMPL(dns_server)
Definition: dns-server.c:332
uv_read_start
UV_EXTERN int uv_read_start(uv_stream_t *, uv_alloc_cb alloc_cb, uv_read_cb read_cb)
Definition: unix/stream.c:1555
uv_tcp_init
UV_EXTERN int uv_tcp_init(uv_loop_t *, uv_tcp_t *handle)
Definition: unix/tcp.c:143
uv_accept
UV_EXTERN int uv_accept(uv_stream_t *server, uv_stream_t *client)
Definition: unix/stream.c:591
uv_tcp_s
Definition: uv.h:544
uv_buf_t::base
char * base
Definition: unix.h:122
tests.unit._exit_scenarios.port
port
Definition: _exit_scenarios.py:179
uv.h
FATAL
#define FATAL(msg)
Definition: task.h:88
uv_buf_t
Definition: unix.h:121
after_write
static void after_write(uv_write_t *req, int status)
Definition: dns-server.c:80
QUERYID_OFFSET
#define QUERYID_OFFSET
Definition: dns-server.c:65
server
Definition: examples/python/async_streaming/server.py:1
dnsstate::prevbuf_ptr
char * prevbuf_ptr
Definition: dns-server.c:37
fix_build_deps.r
r
Definition: fix_build_deps.py:491
write_req_t::buf
uv_buf_t buf
Definition: worker.c:13
dnsstate::prevbuf_rem
int prevbuf_rem
Definition: dns-server.c:39
dnshandle
Definition: dns-server.c:44
uv_buf_t::len
size_t len
Definition: unix.h:123
dnshandle::state
dnsstate state
Definition: dns-server.c:46
uv_write_s
Definition: uv.h:522
TEST_PORT_2
#define TEST_PORT_2
Definition: task.h:54
DNSREC_LEN
#define DNSREC_LEN
Definition: dns-server.c:62
handle
static csh handle
Definition: test_arm_regression.c:16
WRITE_BUF_LEN
#define WRITE_BUF_LEN
Definition: dns-server.c:61
after_read
static void after_read(uv_stream_t *, ssize_t nread, const uv_buf_t *buf)
Definition: dns-server.c:234
uv_handle_s
Definition: uv.h:441
uv_loop_s
Definition: uv.h:1767
after_shutdown
static void after_shutdown(uv_shutdown_t *req, int status)
Definition: dns-server.c:96
addr
struct sockaddr_in addr
Definition: libuv/docs/code/tcp-echo-server/main.c:10
DNSRsp
static unsigned char DNSRsp[]
Definition: dns-server.c:67
on_close
static void on_close(uv_handle_t *peer)
Definition: dns-server.c:263
dns_start
static int dns_start(int port)
Definition: dns-server.c:301


grpc
Author(s):
autogenerated on Fri May 16 2025 02:58:17