Skip to content

Instantly share code, notes, and snippets.

@zengxs
Last active February 27, 2017 07:26
Show Gist options
  • Save zengxs/a4df5cb4455e3a8aaec32ed0f0a37039 to your computer and use it in GitHub Desktop.
Save zengxs/a4df5cb4455e3a8aaec32ed0f0a37039 to your computer and use it in GitHub Desktop.
Sample dns server written in C with libuv
/*
* Licensed under the MIT License <https://opensource.org/licenses/MIT>.
* Copyright (c) 2017 Matsuz <[email protected]>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include "uv.h"
static uint8_t DNSRsp[] = {
0x00, 0x00, // Transaction ID
0x80, 0x00, // flags |QR:1|Opcode:0|AA:0|TC:0|RD:0|RA:0|Z:0|Rcode:0|
0, 1, // Number of Questions
0, 1, // Number of Answer RRs
0, 0, // Number of Authority RRs
0, 0, // Number of Additional RRs
};
static uint8_t qrecord[] = {
1, 'g', 2, 'c', 'n', 0, // query name ("g.cn")
0x00, 0x01, // query type (A)
0x00, 0x01, // query class (IN)
};
static uint8_t arecord[] = {
0xc0, 0x0c, // query name
0x00, 0x01, // query type (A)
0x00, 0x01, // query class (IN)
0, 0, 0, 0, // ttl
0, 4, // data length
203, 208, 51, 81, // data (ipv4 address)
};
static uv_loop_t *loop;
static uv_udp_t server;
static struct sockaddr_in addr;
static void alloc_buffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf);
static void on_recv(uv_udp_t *handle, ssize_t nread, const uv_buf_t *buf, const struct sockaddr *addr, unsigned flags);
static void on_send(uv_udp_send_t *req, int status);
int main()
{
loop = uv_default_loop();
uv_udp_init(loop, &server);
/* Bind the UDP handle to an IP address and port. */
uv_ip4_addr("127.0.0.1", 53, &addr);
uv_udp_bind(&server, (const struct sockaddr *)&addr, UV_UDP_REUSEADDR);
/* Prepare for receiving data. */
uv_udp_recv_start(&server, alloc_buffer, on_recv);
uv_run(loop, UV_RUN_DEFAULT);
return 0;
}
static void
alloc_buffer(uv_handle_t *handle,
size_t suggested_size,
uv_buf_t *buf)
{
buf->base = malloc(suggested_size);
buf->len = suggested_size;
}
static void
on_recv(uv_udp_t *handle,
ssize_t nread,
const uv_buf_t *rcvbuf,
const struct sockaddr *addr,
unsigned flags)
{
if (nread <= 0)
return;
// fprintf(stderr, "Size: %lu, Addr: %p\n", nread, rcvbuf->base);
uv_udp_send_t *req = malloc(sizeof(*req));
uv_buf_t sndbuf; /* Buffer for send data. */
/* #### construct response data start #### */
sndbuf.len = sizeof(DNSRsp) + sizeof(qrecord) + sizeof(arecord);
sndbuf.base = malloc(sndbuf.len);
memset(sndbuf.base, 0, sndbuf.len); // fill 0 to buf
memcpy(sndbuf.base, DNSRsp, sizeof(DNSRsp)); // DNS Header
memcpy(sndbuf.base + sizeof(DNSRsp), qrecord, sizeof(qrecord)); // Query Record
memcpy(sndbuf.base + sizeof(DNSRsp) + sizeof(qrecord), arecord, sizeof(arecord)); // Answer Record
memcpy(sndbuf.base, rcvbuf->base, 2); // Transaction ID
/* #### construct response data end #### */
fprintf(stderr, "UV_UDP_SEND_STATUS: %d\n", uv_udp_send(req, handle, &sndbuf, 1, addr, on_send));
// printf("free :%lu %p\n", rcvbuf->len, rcvbuf->base);
free(rcvbuf->base);
free(sndbuf.base);
}
static void
on_send(uv_udp_send_t *req, int status)
{
// assert(status == 0);
fprintf(stderr, "Status: %d\n", status);
free(req);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment