forked from aarond10/https_dns_proxy
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathdns_server.c
116 lines (95 loc) · 3.58 KB
/
dns_server.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#include <ares.h> // NOLINT(llvmlibc-restrict-system-libc-headers)
#include <errno.h> // NOLINT(llvmlibc-restrict-system-libc-headers)
#include <netdb.h> // NOLINT(llvmlibc-restrict-system-libc-headers)
#include <netinet/in.h> // NOLINT(llvmlibc-restrict-system-libc-headers)
#include <stdint.h>
#include <string.h> // NOLINT(llvmlibc-restrict-system-libc-headers)
#include <sys/socket.h> // NOLINT(llvmlibc-restrict-system-libc-headers)
#include <unistd.h> // NOLINT(llvmlibc-restrict-system-libc-headers)
#include "dns_server.h"
#include "logging.h"
enum {
REQUEST_MAX = 1500 // A default MTU. We don't do TCP so any bigger is likely a waste
};
// Creates and bind a listening UDP socket for incoming requests.
static int get_listen_sock(const char *listen_addr, int listen_port,
unsigned int *addrlen) {
struct addrinfo *ai = NULL;
struct addrinfo hints;
// NOLINTNEXTLINE(clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling)
memset(&hints, 0, sizeof(struct addrinfo));
/* prevent DNS lookups if leakage is our worry */
hints.ai_flags = AI_NUMERICHOST;
int res = getaddrinfo(listen_addr, NULL, &hints, &ai);
if(res != 0) {
FLOG("Error parsing listen address %s:%d (getaddrinfo): %s", listen_addr, listen_port,
gai_strerror(res));
if(ai) {
freeaddrinfo(ai);
}
return -1;
}
struct sockaddr_in *saddr = (struct sockaddr_in*) ai->ai_addr;
*addrlen = ai->ai_addrlen;
saddr->sin_port = htons(listen_port);
int sock = socket(ai->ai_family, SOCK_DGRAM, 0);
if (sock < 0) {
FLOG("Error creating socket");
}
res = bind(sock, ai->ai_addr, ai->ai_addrlen);
if (res < 0) {
FLOG("Error binding %s:%d: %s (%d)", listen_addr, listen_port,
strerror(errno), res);
}
freeaddrinfo(ai);
ILOG("Listening on %s:%d", listen_addr, listen_port);
return sock;
}
static void watcher_cb(struct ev_loop __attribute__((unused)) *loop,
ev_io *w, int __attribute__((unused)) revents) {
dns_server_t *d = (dns_server_t *)w->data;
char *buf = (char *)calloc(1, REQUEST_MAX + 1);
if (buf == NULL) {
FLOG("Out of mem");
}
struct sockaddr_storage raddr;
/* recvfrom can write to addrlen */
socklen_t tmp_addrlen = d->addrlen;
ssize_t len = recvfrom(w->fd, buf, REQUEST_MAX, 0, (struct sockaddr*)&raddr,
&tmp_addrlen);
if (len < 0) {
ELOG("recvfrom failed: %s", strerror(errno));
return;
}
if (len < (int)sizeof(uint16_t)) {
WLOG("Malformed request received (too short).");
return;
}
uint16_t tx_id = ntohs(*((uint16_t*)buf));
d->cb(d, d->cb_data, (struct sockaddr*)&raddr, tx_id, buf, len);
}
void dns_server_init(dns_server_t *d, struct ev_loop *loop,
const char *listen_addr, int listen_port,
dns_req_received_cb cb, void *data) {
d->loop = loop;
d->sock = get_listen_sock(listen_addr, listen_port, &d->addrlen);
d->cb = cb;
d->cb_data = data;
// NOLINTNEXTLINE(clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling)
ev_io_init(&d->watcher, watcher_cb, d->sock, EV_READ);
d->watcher.data = d;
ev_io_start(d->loop, &d->watcher);
}
void dns_server_respond(dns_server_t *d, struct sockaddr *raddr, char *buf,
size_t blen) {
ssize_t len = sendto(d->sock, buf, blen, 0, raddr, d->addrlen);
if(len == -1) {
DLOG("sendto failed: %s", strerror(errno));
}
}
void dns_server_stop(dns_server_t *d) {
ev_io_stop(d->loop, &d->watcher);
}
void dns_server_cleanup(dns_server_t *d) {
close(d->sock);
}