forked from aarond10/https_dns_proxy
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdns_server.c
More file actions
143 lines (121 loc) · 3.75 KB
/
dns_server.c
File metadata and controls
143 lines (121 loc) · 3.75 KB
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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
#include <sys/socket.h>
#include <sys/types.h>
#include <ares.h>
#include <arpa/inet.h>
#include <curl/curl.h>
#include <errno.h>
#include <ev.h>
#include <grp.h>
#include <netdb.h>
#include <netinet/in.h>
#include <pwd.h>
#include <signal.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include "dns_server.h"
#include "logging.h"
// 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;
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");
}
if ((res = bind(sock, ai->ai_addr, ai->ai_addrlen)) < 0) {
FLOG("Error binding %s:%d: %s", listen_addr, listen_port, strerror(res));
}
freeaddrinfo(ai);
ILOG("Listening on %s:%d", listen_addr, listen_port);
return sock;
}
static uint16_t next_uint16(unsigned char **const p) {
uint16_t u;
memcpy(&u, *p, sizeof(u));
*p += sizeof(u);
return u;
}
static void watcher_cb(struct ev_loop *loop, ev_io *w, int revents) {
dns_server_t *d = (dns_server_t *)w->data;
// A default MTU. We don't do TCP so any bigger is likely a waste.
unsigned char buf[1500];
struct sockaddr_storage raddr;
/* recvfrom can write to addrlen */
socklen_t tmp_addrlen = d->addrlen;
int len = recvfrom(w->fd, buf, sizeof(buf), 0, (struct sockaddr*)&raddr,
&tmp_addrlen);
if (len < 0) {
WLOG("recvfrom failed: %s", strerror(errno));
return;
}
if (len < sizeof(uint16_t) * 3) {
DLOG("Malformed request received (too short).");
return;
}
unsigned char *p = buf;
uint16_t tx_id = ntohs(next_uint16(&p));
uint16_t flags = ntohs(next_uint16(&p));
uint16_t num_q = ntohs(next_uint16(&p));
//uint16_t num_rr = ntohs(next_uint16(&p));
next_uint16(&p);
//uint16_t num_arr = ntohs(next_uint16(&p));
next_uint16(&p);
//uint16_t num_xrr = ntohs(next_uint16(&p));
next_uint16(&p);
if (num_q != 1) {
DLOG("Malformed request received.");
return;
};
char *domain_name;
long enc_len;
if (ares_expand_name(p, buf, len, &domain_name, &enc_len) != ARES_SUCCESS) {
DLOG("Malformed request received.");
return;
}
p += enc_len;
uint16_t type = ntohs(next_uint16(&p));
d->cb(d, d->cb_data, (struct sockaddr*)&raddr, tx_id, flags, domain_name, type);
ares_free_string(domain_name);
}
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;
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,
int blen) {
size_t len = sendto(d->sock, buf, blen, 0, raddr, d->addrlen);
if(len == -1) {
DLOG("sendto failed: %s", strerror(errno));
}
}
void dns_server_cleanup(dns_server_t *d) {
ev_io_stop(d->loop, &d->watcher);
close(d->sock);
}