📄 eventdns.c
字号:
/* Parse a raw request (packet,length) sent to a nameserver port (port) from */
/* a DNS client (addr,addrlen), and if it's well-formed, call the corresponding */
/* callback. */
static int
request_parse(u8 *packet, ssize_t length, struct evdns_server_port *port, struct sockaddr *addr, socklen_t addrlen)
{
int j = 0; /* index into packet */
u16 _t; /* used by the macros */
char tmp_name[256]; /* used by the macros */
int i;
u16 trans_id, flags, questions, answers, authority, additional;
struct server_request *server_req = NULL;
/* Get the header fields */
GET16(trans_id);
GET16(flags);
GET16(questions);
GET16(answers);
GET16(authority);
GET16(additional);
if (flags & 0x8000) return -1; /* Must not be an answer. */
flags &= 0x0110; /* Only RD and CD get preserved. */
if (length > INT_MAX)
return -1;
server_req = malloc(sizeof(struct server_request));
if (server_req == NULL) return -1;
memset(server_req, 0, sizeof(struct server_request));
server_req->trans_id = trans_id;
memcpy(&server_req->addr, addr, addrlen);
server_req->addrlen = addrlen;
server_req->base.flags = flags;
server_req->base.nquestions = 0;
server_req->base.questions = malloc(sizeof(struct evdns_server_question *) * questions);
if (server_req->base.questions == NULL)
goto err;
for (i = 0; i < questions; ++i) {
u16 type, class;
struct evdns_server_question *q;
size_t namelen;
if (name_parse(packet, (int)length, &j, tmp_name, sizeof(tmp_name))<0)
goto err;
GET16(type);
GET16(class);
namelen = strlen(tmp_name);
q = malloc(sizeof(struct evdns_server_question) + namelen);
if (!q)
goto err;
q->type = type;
q->class = class;
memcpy(q->name, tmp_name, namelen+1);
server_req->base.questions[server_req->base.nquestions++] = q;
}
/* Ignore answers, authority, and additional. */
server_req->port = port;
port->refcnt++;
/* Only standard queries are supported. */
if (flags & 0x7800) {
evdns_server_request_respond(&(server_req->base), DNS_ERR_NOTIMPL);
return -1;
}
port->user_callback(&(server_req->base), port->user_data);
return 0;
err:
if (server_req) {
if (server_req->base.questions) {
for (i = 0; i < server_req->base.nquestions; ++i)
free(server_req->base.questions[i]);
free(server_req->base.questions);
}
CLEAR(server_req);
free(server_req);
}
return -1;
#undef SKIP_NAME
#undef GET32
#undef GET16
#undef GET8
}
static uint16_t
default_transaction_id_fn(void)
{
u16 trans_id;
#ifdef DNS_USE_CPU_CLOCK_FOR_ID
struct timespec ts;
#ifdef CLOCK_MONOTONIC
if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1)
#else
if (clock_gettime(CLOCK_REALTIME, &ts) == -1)
#endif
event_err(1, "clock_gettime");
trans_id = ts.tv_nsec & 0xffff;
#endif
#ifdef DNS_USE_GETTIMEOFDAY_FOR_ID
struct timeval tv;
gettimeofday(&tv, NULL);
trans_id = tv.tv_usec & 0xffff;
#endif
#ifdef DNS_USE_OPENSSL_FOR_ID
if (RAND_pseudo_bytes((u8 *) &trans_id, 2) == -1) {
/* in the case that the RAND call fails we back */
/* down to using gettimeofday. */
/*
struct timeval tv;
gettimeofday(&tv, NULL);
trans_id = tv.tv_usec & 0xffff;
*/
abort();
}
#endif
return (unsigned short) trans_id;
}
static uint16_t (*trans_id_function)(void) = default_transaction_id_fn;
void
evdns_set_transaction_id_fn(uint16_t (*fn)(void))
{
if (fn)
trans_id_function = fn;
else
trans_id_function = default_transaction_id_fn;
}
/* Try to choose a strong transaction id which isn't already in flight */
static u16
transaction_id_pick(void) {
for (;;) {
const struct request *req = req_head, *started_at;
u16 trans_id = trans_id_function();
if (trans_id == 0xffff) continue;
/* now check to see if that id is already inflight */
req = started_at = req_head;
if (req) {
do {
if (req->trans_id == trans_id) break;
req = req->next;
} while (req != started_at);
}
/* we didn't find it, so this is a good id */
if (req == started_at) return trans_id;
}
}
/* choose a namesever to use. This function will try to ignore */
/* nameservers which we think are down and load balance across the rest */
/* by updating the server_head global each time. */
static struct nameserver *
nameserver_pick(void) {
struct nameserver *started_at = server_head, *picked;
if (!server_head) return NULL;
/* if we don't have any good nameservers then there's no */
/* point in trying to find one. */
if (!global_good_nameservers) {
server_head = server_head->next;
return server_head;
}
/* remember that nameservers are in a circular list */
for (;;) {
if (server_head->state) {
/* we think this server is currently good */
picked = server_head;
server_head = server_head->next;
return picked;
}
server_head = server_head->next;
if (server_head == started_at) {
/* all the nameservers seem to be down */
/* so we just return this one and hope for the */
/* best */
assert(global_good_nameservers == 0);
picked = server_head;
server_head = server_head->next;
return picked;
}
}
}
/* this is called when a namesever socket is ready for reading */
static void
nameserver_read(struct nameserver *ns) {
u8 packet[1500];
for (;;) {
const int r =
(int)recv(ns->socket, packet,(socklen_t)sizeof(packet), 0);
if (r < 0) {
int err = last_error(ns->socket);
if (error_is_eagain(err)) return;
nameserver_failed(ns, strerror(err));
return;
}
ns->timedout = 0;
reply_parse(packet, r);
}
}
/* Read a packet from a DNS client on a server port s, parse it, and */
/* act accordingly. */
static void
server_port_read(struct evdns_server_port *s) {
u8 packet[1500];
struct sockaddr_storage addr;
socklen_t addrlen;
ssize_t r;
for (;;) {
addrlen = (socklen_t)sizeof(struct sockaddr_storage);
r = recvfrom(s->socket, packet, sizeof(packet), 0,
(struct sockaddr*) &addr, &addrlen);
if (r < 0) {
int err = last_error(s->socket);
if (error_is_eagain(err)) return;
log(EVDNS_LOG_WARN, "Error %s (%d) while reading request.",
strerror(err), err);
return;
}
request_parse(packet, r, s, (struct sockaddr*) &addr, addrlen);
}
}
/* Try to write all pending replies on a given DNS server port. */
static void
server_port_flush(struct evdns_server_port *port)
{
while (port->pending_replies) {
struct server_request *req = port->pending_replies;
ssize_t r = sendto(port->socket, req->response, req->response_len, 0,
(struct sockaddr*) &req->addr, (socklen_t)req->addrlen);
if (r < 0) {
int err = last_error(port->socket);
if (error_is_eagain(err))
return;
log(EVDNS_LOG_WARN, "Error %s (%d) while writing response to port; dropping", strerror(err), err);
}
if (server_request_free(req)) {
/* we released the last reference to req->port. */
return;
}
}
/* We have no more pending requests; stop listening for 'writeable' events. */
(void) event_del(&port->event);
CLEAR(&port->event);
event_set(&port->event, port->socket, EV_READ | EV_PERSIST,
server_port_ready_callback, port);
if (event_add(&port->event, NULL) < 0) {
log(EVDNS_LOG_WARN, "Error from libevent when adding event for DNS server.");
/* ???? Do more? */
}
}
/* set if we are waiting for the ability to write to this server. */
/* if waiting is true then we ask libevent for EV_WRITE events, otherwise */
/* we stop these events. */
static void
nameserver_write_waiting(struct nameserver *ns, char waiting) {
if (ns->write_waiting == waiting) return;
ns->write_waiting = waiting;
(void) event_del(&ns->event);
CLEAR(&ns->event);
event_set(&ns->event, ns->socket, EV_READ | (waiting ? EV_WRITE : 0) | EV_PERSIST,
nameserver_ready_callback, ns);
if (event_add(&ns->event, NULL) < 0) {
log(EVDNS_LOG_WARN, "Error from libevent when adding event for %s",
debug_ntoa(ns->address));
/* ???? Do more? */
}
}
/* a callback function. Called by libevent when the kernel says that */
/* a nameserver socket is ready for writing or reading */
static void
nameserver_ready_callback(int fd, short events, void *arg) {
struct nameserver *ns = (struct nameserver *) arg;
(void)fd;
if (events & EV_WRITE) {
ns->choked = 0;
if (!evdns_transmit()) {
nameserver_write_waiting(ns, 0);
}
}
if (events & EV_READ) {
nameserver_read(ns);
}
}
/* a callback function. Called by libevent when the kernel says that */
/* a server socket is ready for writing or reading. */
static void
server_port_ready_callback(int fd, short events, void *arg) {
struct evdns_server_port *port = (struct evdns_server_port *) arg;
(void) fd;
if (events & EV_WRITE) {
port->choked = 0;
server_port_flush(port);
}
if (events & EV_READ) {
server_port_read(port);
}
}
/* This is an inefficient representation; only use it via the dnslabel_table_*
* functions, so that is can be safely replaced with something smarter later. */
#define MAX_LABELS 128
/* Structures used to implement name compression */
struct dnslabel_entry { char *v; off_t pos; };
struct dnslabel_table {
int n_labels; /* number of current entries */
/* map from name to position in message */
struct dnslabel_entry labels[MAX_LABELS];
};
/* Initialize dnslabel_table. */
static void
dnslabel_table_init(struct dnslabel_table *table)
{
table->n_labels = 0;
}
/* Free all storage held by table, but not the table itself. */
static void
dnslabel_clear(struct dnslabel_table *table)
{
int i;
for (i = 0; i < table->n_labels; ++i)
free(table->labels[i].v);
table->n_labels = 0;
}
/* return the position of the label in the current message, or -1 if the label */
/* hasn't been used yet. */
static int
dnslabel_table_get_pos(const struct dnslabel_table *table, const char *label)
{
int i;
for (i = 0; i < table->n_labels; ++i) {
if (!strcmp(label, table->labels[i].v)) {
off_t pos = table->labels[i].pos;
if (pos > 65535)
return -1;
return (int)pos;
}
}
return -1;
}
/* remember that we've used the label at position pos */
static int
dnslabel_table_add(struct dnslabel_table *table, const char *label, off_t pos)
{
char *v;
int p;
if (table->n_labels == MAX_LABELS)
return (-1);
v = strdup(label);
if (v == NULL)
return (-1);
p = table->n_labels++;
table->labels[p].v = v;
table->labels[p].pos = pos;
return (0);
}
/* Converts a string to a length-prefixed set of DNS labels, starting */
/* at buf[j]. name and buf must not overlap. name_len should be the length */
/* of name. table is optional, and is used for compression. */
/* */
/* Input: abc.def */
/* Output: <3>abc<3>def<0> */
/* */
/* Returns the first index after the encoded name, or negative on error. */
/* -1 label was > 63 bytes */
/* -2 name too long to fit in buffer. */
/* */
static off_t
dnsname_to_labels(u8 *const buf, size_t buf_len, off_t j,
const char *name, const size_t name_len,
struct dnslabel_table *table) {
const char *end = name + name_len;
int ref = 0;
u16 _t;
#define APPEND16(x) do { \
if (j + 2 > (off_t)buf_len) \
goto overflow; \
_t = htons(x); \
memcpy(buf + j, &_t, 2); \
j += 2; \
} while (0)
#define APPEND32(x) do { \
if (j + 4 > (off_t)buf_len) \
goto overflow; \
_t32 = htonl(x); \
memcpy(buf + j, &_t32, 4); \
j += 4; \
} while (0)
if (name_len > 255) return -2;
for (;;) {
const char *const start = name;
if (table && (ref = dnslabel_table_get_pos(table, name)) >= 0) {
APPEND16(ref | 0xc000);
return j;
}
name = strchr(name, '.');
if (!name) {
const size_t label_len = end - start;
if (label_len > 63) return -1;
if ((size_t)(j+label_len+1) > buf_len) return -2;
if (table) dnslabel_table_add(table, start, j);
buf[j++] = (uint8_t)label_len;
memcpy(buf + j, start, label_len);
j += end - start;
break;
} else {
/* append length of the label. */
const size_t label_len = name - start;
if (label_len > 63) return -1;
if ((size_t)(j+label_len+1) > buf_len) return -2;
if (table) dnslabel_table_add(table, start, j);
buf[j++] = (uint8_t)label_len;
memcpy(buf + j, start, name - start);
j += name - start;
/* hop over the '.' */
name++;
}
}
/* the labels must be terminated by a 0. */
/* It's possible that the name ended in a . */
/* in which case the zero is already there */
if (!j || buf[j-1]) buf[j++] = 0;
return j;
overflow:
return (-2);
}
/* Finds the length of a dns request for a DNS name of the given */
/* length. The actual request may be smaller than the value returned */
/* here */
static size_t
evdns_request_len(const size_t name_len) {
return 96 + /* length of the DNS standard header */
name_len + 2 +
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -