mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-10 13:13:44 +01:00
r9099@Kushana: nickm | 2006-10-05 17:42:55 -0400
start fleshing out some logic to build server support into eventdns. Still needs work and testing. svn:r9068
This commit is contained in:
parent
8cf8b8087a
commit
e9d67b1162
17
doc/TODO
17
doc/TODO
@ -92,9 +92,20 @@ N - DNS improvements
|
||||
. Asynchronous DNS
|
||||
o Document and rename SearchDomains, ResolvConf options
|
||||
D Make API closer to getaddrinfo()
|
||||
- Teach it to be able to listen for A and PTR requests to be processed.
|
||||
Interface should be set_request_listener(sock, cb); [ cb(request) ]
|
||||
send_reply(request, answer);
|
||||
- Teach it to be able to listen for requests to be processed.
|
||||
. Design interface.
|
||||
- Rename stuff; current names suck.
|
||||
. Design backend.
|
||||
- Implement
|
||||
. Listen for questions
|
||||
o Parse questions, tell user code
|
||||
. Let user code tell us the answer
|
||||
- Generate responses
|
||||
o Send responses to client
|
||||
o Queue responses when we see EAGAIN
|
||||
- Retry responses after a while
|
||||
- Add some kind of general question/response API so libevent can be
|
||||
flexible here.
|
||||
d - Add option to use /etc/hosts?
|
||||
d - Special-case localhost?
|
||||
- Verify that it works on windows
|
||||
|
@ -8,7 +8,8 @@
|
||||
*
|
||||
* TODO:
|
||||
* - Have a way to query for AAAA and A records simultaneously.
|
||||
* - Improve request API.
|
||||
* - Improve request API: At the very least, add the ability to construct
|
||||
* a more-or-less arbitrary request and get a response.
|
||||
* - (Can we suppress cnames? Should we?)
|
||||
* - Replace all externally visible magic numbers with #defined constants.
|
||||
* - Write documentation for APIs of all external functions.
|
||||
@ -382,6 +383,44 @@ struct nameserver {
|
||||
static struct request *req_head = NULL, *req_waiting_head = NULL;
|
||||
static struct nameserver *server_head = NULL;
|
||||
|
||||
struct server_port {
|
||||
int socket;
|
||||
int refcnt;
|
||||
char choaked;
|
||||
evdns_request_callback_type user_callback;
|
||||
void *user_data;
|
||||
struct server_request *pending_replies;
|
||||
};
|
||||
|
||||
struct server_request_section {
|
||||
int n_items;
|
||||
int j;
|
||||
char buf[512];
|
||||
};
|
||||
|
||||
struct server_request {
|
||||
struct server_request *next_pending;
|
||||
struct server_request *prev_pending;
|
||||
|
||||
u16 trans_id;
|
||||
struct server_port *port;
|
||||
struct sockaddr_storage addr;
|
||||
socklen_t addrlen;
|
||||
|
||||
struct server_request_section *answer;
|
||||
struct server_request_section *authority;
|
||||
struct server_request_section *additional;
|
||||
|
||||
struct evdns_request base;
|
||||
};
|
||||
#define OFFSET_OF(st, member) ((off_t) (((char*)&((st*)0)->member)-(char*)0))
|
||||
|
||||
#define TO_SERVER_REQUEST(base_ptr) \
|
||||
((struct server_request*) \
|
||||
(((char*)(base_ptr) - OFFSET_OF(struct server_request, base))))
|
||||
|
||||
static void evdns_request_free(struct evdns_request *_req);
|
||||
|
||||
// The number of good nameservers that we have
|
||||
static int global_good_nameservers = 0;
|
||||
|
||||
@ -868,9 +907,10 @@ name_parse(u8 *packet, int length, int *idx, char *name_out, int name_out_len) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// parses a raw packet from the wire
|
||||
// parses a raw request from the wire
|
||||
static int
|
||||
reply_parse(u8 *packet, int length) {
|
||||
reply_parse(u8 *packet, int length)
|
||||
{
|
||||
int j = 0; // index into packet
|
||||
u16 _t; // used by the macros
|
||||
u32 _t32; // used by the macros
|
||||
@ -879,7 +919,7 @@ reply_parse(u8 *packet, int length) {
|
||||
u16 trans_id, flags, questions, answers, authority, additional, datalength;
|
||||
u32 ttl, ttl_r = 0xffffffff;
|
||||
struct reply reply;
|
||||
struct request *req;
|
||||
struct request *req = NULL;
|
||||
unsigned int i;
|
||||
|
||||
GET16(trans_id);
|
||||
@ -891,8 +931,16 @@ reply_parse(u8 *packet, int length) {
|
||||
(void) authority;
|
||||
(void) additional;
|
||||
|
||||
// This macro skips a name in the DNS reply.
|
||||
#define SKIP_NAME \
|
||||
do { tmp_name[0] = '\0'; \
|
||||
if (name_parse(packet, length, &j, tmp_name, sizeof(tmp_name))<0) \
|
||||
return -1; \
|
||||
} while(0);
|
||||
|
||||
req = request_find_from_trans_id(trans_id);
|
||||
if (!req) return -1;
|
||||
|
||||
// XXXX should the other return points also call reply_handle? -NM
|
||||
// log("reqparse: trans was %d\n", (int)trans_id);
|
||||
|
||||
@ -906,23 +954,16 @@ reply_parse(u8 *packet, int length) {
|
||||
}
|
||||
// if (!answers) return; // must have an answer of some form
|
||||
|
||||
// This macro skips a name in the DNS reply.
|
||||
#define SKIP_NAME \
|
||||
do { tmp_name[0] = '\0'; \
|
||||
if (name_parse(packet, length, &j, tmp_name, sizeof(tmp_name))<0) \
|
||||
return -1; \
|
||||
} while(0);
|
||||
|
||||
reply.type = req->request_type;
|
||||
|
||||
// skip over each question in the reply
|
||||
// skip over each question in the reply
|
||||
for (i = 0; i < questions; ++i) {
|
||||
// the question looks like
|
||||
// <label:name><u16:type><u16:class>
|
||||
SKIP_NAME;
|
||||
j += 4;
|
||||
if (j >= length) return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// now we have the answer section which looks like
|
||||
// <label:name><u16:type><u16:class><u32:ttl><u16:len><data...>
|
||||
@ -940,7 +981,7 @@ reply_parse(u8 *packet, int length) {
|
||||
|
||||
// log("@%d, Name %s, type %d, class %d, j=%d", pre, tmp_name, (int)type, (int)class, j);
|
||||
|
||||
if (type == TYPE_A && class == CLASS_INET) {
|
||||
if (type == TYPE_A && class == CLASS_INET) {
|
||||
int addrcount, addrtocopy;
|
||||
if (req->request_type != TYPE_A) {
|
||||
j += datalength; continue;
|
||||
@ -981,11 +1022,88 @@ reply_parse(u8 *packet, int length) {
|
||||
|
||||
reply_handle(req, flags, ttl_r, &reply);
|
||||
return 0;
|
||||
}
|
||||
#undef SKIP_NAME
|
||||
#undef GET32
|
||||
#undef GET16
|
||||
#undef GET8
|
||||
|
||||
static int
|
||||
request_parse(u8 *packet, int length, struct 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
|
||||
|
||||
#define GET16(x) do { if (j + 2 > length) goto err; memcpy(&_t, packet + j, 2); j += 2; x = ntohs(_t); } while(0);
|
||||
#define GET8(x) do { if (j >= length) goto err; x = packet[j++]; } while(0);
|
||||
|
||||
int i;
|
||||
u16 trans_id, flags, questions, answers, authority, additional;
|
||||
struct server_request *server_req = NULL;
|
||||
|
||||
GET16(trans_id);
|
||||
GET16(flags);
|
||||
GET16(questions);
|
||||
GET16(answers);
|
||||
GET16(authority);
|
||||
GET16(additional);
|
||||
|
||||
if (flags & 0x8000) return -1; // Must not be an answer.
|
||||
|
||||
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_question *) * questions);
|
||||
if (server_req->base.questions == NULL)
|
||||
goto err;
|
||||
|
||||
for (i = 0; i < questions; ++i) {
|
||||
u16 type, class;
|
||||
struct evdns_question *q;
|
||||
int namelen;
|
||||
if (name_parse(packet, length, &j, tmp_name, sizeof(tmp_name))<0)
|
||||
goto err;
|
||||
GET16(type);
|
||||
GET16(class);
|
||||
namelen = strlen(tmp_name);
|
||||
q = malloc(sizeof(struct evdns_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;
|
||||
}
|
||||
|
||||
// Do nothing with rest of packet -- safe?
|
||||
|
||||
server_req->port = port;
|
||||
port->refcnt++;
|
||||
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);
|
||||
}
|
||||
free(server_req);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
#undef GET16
|
||||
#undef GET8
|
||||
|
||||
|
||||
// Try to choose a strong transaction id which isn't already in flight
|
||||
static u16
|
||||
@ -1086,6 +1204,27 @@ nameserver_read(struct nameserver *ns) {
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
server_port_read(struct server_port *s) {
|
||||
u8 packet[1500];
|
||||
struct sockaddr_storage addr;
|
||||
socklen_t addrlen;
|
||||
int r;
|
||||
|
||||
for (;;) {
|
||||
addrlen = 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;
|
||||
// XXXX log error; not much else to do. -NM
|
||||
return;
|
||||
}
|
||||
request_parse(packet, r, s, (struct sockaddr*) &addr, addrlen);
|
||||
}
|
||||
}
|
||||
|
||||
// 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.
|
||||
@ -1200,6 +1339,14 @@ evdns_request_data_build(const char *const name, const int name_len, const u16 t
|
||||
memcpy(buf + j, &_t, 2); \
|
||||
j += 2; \
|
||||
} while (0)
|
||||
#define APPEND32(x) do { \
|
||||
if (j + 4 > buf_len) \
|
||||
return (-1); \
|
||||
_t32 = htonl(x); \
|
||||
memcpy(buf + j, &_t32, 4); \
|
||||
j += 4; \
|
||||
} while (0)
|
||||
|
||||
|
||||
APPEND16(trans_id);
|
||||
APPEND16(0x0100); // standard query, recusion needed
|
||||
@ -1226,11 +1373,164 @@ evdns_request_data_build(const char *const name, const int name_len, const u16 t
|
||||
|
||||
APPEND16(type);
|
||||
APPEND16(class);
|
||||
#undef APPEND16
|
||||
|
||||
return (int)j;
|
||||
}
|
||||
|
||||
// exported function
|
||||
int
|
||||
evdns_request_add_reply(struct evdns_request *_req, int section, const char *name, int type, int class, int ttl, int datalen, const char *data)
|
||||
{
|
||||
struct server_request *req = TO_SERVER_REQUEST(_req);
|
||||
struct server_request_section **secp;
|
||||
int j;
|
||||
char *buf;
|
||||
int buf_len;
|
||||
u16 _t; // used by the macros
|
||||
u32 _t32; // used by the macros
|
||||
u8 *labels;
|
||||
int labels_len, name_len;
|
||||
|
||||
switch (section) {
|
||||
case EVDNS_ANSWER_SECTION:
|
||||
secp = &req->answer;
|
||||
break;
|
||||
case EVDNS_AUTHORITY_SECTION:
|
||||
secp = &req->authority;
|
||||
break;
|
||||
case EVDNS_ADDITIONAL_SECTION:
|
||||
secp = &req->additional;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
if (!*secp) {
|
||||
if (!(*secp = malloc(sizeof(struct server_request_section))))
|
||||
return -1;
|
||||
memset(*secp, 0, sizeof(struct server_request_section));
|
||||
}
|
||||
buf = (*secp)->buf;
|
||||
buf_len = sizeof((*secp)->buf);
|
||||
j = (*secp)->j;
|
||||
|
||||
// format is <label:name><u16:type><u16:class><u32:ttl><u16:len><data...>
|
||||
name_len = strlen(name);
|
||||
|
||||
labels = (u8 *) malloc(name_len + 2);
|
||||
if (labels == NULL)
|
||||
return -1;
|
||||
labels_len = dnsname_to_labels(labels, name, name_len);
|
||||
if (labels_len < 0) {
|
||||
free(labels);
|
||||
return labels_len;
|
||||
}
|
||||
if ((size_t)(j + labels_len) > buf_len) {
|
||||
free(labels);
|
||||
return (-1);
|
||||
}
|
||||
memcpy(buf + j, labels, labels_len);
|
||||
j += labels_len;
|
||||
free(labels);
|
||||
|
||||
APPEND16(type);
|
||||
APPEND16(class);
|
||||
APPEND32(ttl);
|
||||
APPEND16(datalen);
|
||||
if ((size_t)(j + datalen) > buf_len)
|
||||
return -1;
|
||||
memcpy(buf + j, data, datalen);
|
||||
j += datalen;
|
||||
|
||||
(*secp)->j = j;
|
||||
(*secp)->n_items++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// exported function
|
||||
int
|
||||
evdns_request_add_a_reply(struct evdns_request *req, const char *name, int n, void *addrs, int ttl)
|
||||
{
|
||||
return evdns_request_add_reply(
|
||||
req, EVDNS_ANSWER_SECTION, name, TYPE_A, CLASS_INET,
|
||||
ttl, n*4, addrs);
|
||||
}
|
||||
|
||||
// exported function
|
||||
int
|
||||
eventdns_request_respond(struct evdns_request *_req, int err, int flags)
|
||||
{
|
||||
struct server_request *req = TO_SERVER_REQUEST(_req);
|
||||
int r;
|
||||
char response[1500];
|
||||
size_t responselen = 10;
|
||||
|
||||
// XXXX make a response and store it somewhere. Where? Oops; structs
|
||||
// may be wrong.
|
||||
|
||||
r = sendto(req->port->socket, response, responselen, 0,
|
||||
(struct sockaddr*) &req->addr, req->addrlen);
|
||||
if (r<0) {
|
||||
int err = last_error(req->port->socket);
|
||||
if (! error_is_eagain(err))
|
||||
return -1;
|
||||
|
||||
if (req->port->pending_replies) {
|
||||
req->prev_pending = req->port->pending_replies->prev_pending;
|
||||
req->next_pending = req->port->pending_replies;
|
||||
req->prev_pending->next_pending =
|
||||
req->next_pending->prev_pending = req;
|
||||
} else {
|
||||
req->prev_pending = req->next_pending = req;
|
||||
req->port->pending_replies = req;
|
||||
req->port->choaked = 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
// XXXX process pending replies.
|
||||
|
||||
evdns_request_free(_req);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
evdns_request_free(struct evdns_request *_req)
|
||||
{
|
||||
struct server_request *req = TO_SERVER_REQUEST(_req);
|
||||
int i;
|
||||
if (req->base.questions) {
|
||||
for (i = 0; i < req->base.nquestions; ++i)
|
||||
free(req->base.questions[i]);
|
||||
}
|
||||
|
||||
if (req->answer)
|
||||
free(req->answer);
|
||||
if (req->answer)
|
||||
free(req->authority);
|
||||
if (req->answer)
|
||||
free(req->additional);
|
||||
|
||||
if (req->port) {
|
||||
if (req->port->pending_replies == req) {
|
||||
if (req->next_pending)
|
||||
req->port->pending_replies = req->next_pending;
|
||||
else
|
||||
req->port->pending_replies = NULL;
|
||||
}
|
||||
--req->port->refcnt; /* release? XXXX NM*/
|
||||
}
|
||||
|
||||
if (req->next_pending && req->next_pending != req) {
|
||||
req->next_pending->prev_pending = req->prev_pending;
|
||||
req->prev_pending->next_pending = req->next_pending;
|
||||
}
|
||||
|
||||
free(req);
|
||||
}
|
||||
|
||||
#undef APPEND16
|
||||
#undef APPEND32
|
||||
|
||||
|
||||
// this is a libevent callback function which is called when a request
|
||||
// has timed out.
|
||||
static void
|
||||
@ -2243,71 +2543,6 @@ evdns_config_windows_nameservers(void) {
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef EVDNS_MAIN
|
||||
void
|
||||
main_callback(int result, char type, int count, int ttl,
|
||||
void *addrs, void *orig) {
|
||||
char *n = (char*)orig;
|
||||
int i;
|
||||
for (i = 0; i < count; ++i) {
|
||||
if (type == DNS_IPv4_A) {
|
||||
printf("%s: %s\n", n, debug_ntoa(((u32*)addrs)[i]));
|
||||
} else if (type == DNS_PTR) {
|
||||
printf("%s: %s\n", n, ((char**)addrs)[i]);
|
||||
}
|
||||
}
|
||||
if (!count) {
|
||||
printf("%s: No answer (%d)\n", n, result);
|
||||
}
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
void
|
||||
logfn(const char *msg) {
|
||||
fprintf(stderr, "%s\n", msg);
|
||||
}
|
||||
int
|
||||
main(int c, char **v) {
|
||||
int idx;
|
||||
int reverse = 0, verbose = 1;
|
||||
if (c<2) {
|
||||
fprintf(stderr, "syntax: %s [-x] [-v] hostname\n", v[0]);
|
||||
return 1;
|
||||
}
|
||||
idx = 1;
|
||||
while (idx < c && v[idx][0] == '-') {
|
||||
if (!strcmp(v[idx], "-x"))
|
||||
reverse = 1;
|
||||
else if (!strcmp(v[idx], "-v"))
|
||||
verbose = 1;
|
||||
else
|
||||
fprintf(stderr, "Unknown option %s\n", v[idx]);
|
||||
++idx;
|
||||
}
|
||||
event_init();
|
||||
if (verbose)
|
||||
evdns_set_log_fn(logfn);
|
||||
evdns_resolv_conf_parse(DNS_OPTION_NAMESERVERS, "/etc/resolv.conf");
|
||||
for (; idx < c; ++idx) {
|
||||
if (reverse) {
|
||||
struct in_addr addr;
|
||||
if (!inet_aton(v[idx], &addr)) {
|
||||
fprintf(stderr, "Skipping non-IP %s\n", v[idx]);
|
||||
continue;
|
||||
}
|
||||
fprintf(stderr, "resolving %s...\n",v[idx]);
|
||||
evdns_resolve_reverse(&addr, 0, main_callback, v[idx]);
|
||||
} else {
|
||||
fprintf(stderr, "resolving (fwd) %s...\n",v[idx]);
|
||||
evdns_resolve_ipv4(v[idx], 0, main_callback, v[idx]);
|
||||
}
|
||||
}
|
||||
fflush(stdout);
|
||||
event_dispatch();
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
evdns_init(void)
|
||||
{
|
||||
@ -2381,6 +2616,71 @@ evdns_shutdown(int fail_requests)
|
||||
evdns_log_fn = NULL;
|
||||
}
|
||||
|
||||
#ifdef EVDNS_MAIN
|
||||
void
|
||||
main_callback(int result, char type, int count, int ttl,
|
||||
void *addrs, void *orig) {
|
||||
char *n = (char*)orig;
|
||||
int i;
|
||||
for (i = 0; i < count; ++i) {
|
||||
if (type == DNS_IPv4_A) {
|
||||
printf("%s: %s\n", n, debug_ntoa(((u32*)addrs)[i]));
|
||||
} else if (type == DNS_PTR) {
|
||||
printf("%s: %s\n", n, ((char**)addrs)[i]);
|
||||
}
|
||||
}
|
||||
if (!count) {
|
||||
printf("%s: No answer (%d)\n", n, result);
|
||||
}
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
void
|
||||
logfn(const char *msg) {
|
||||
fprintf(stderr, "%s\n", msg);
|
||||
}
|
||||
int
|
||||
main(int c, char **v) {
|
||||
int idx;
|
||||
int reverse = 0, verbose = 1;
|
||||
if (c<2) {
|
||||
fprintf(stderr, "syntax: %s [-x] [-v] hostname\n", v[0]);
|
||||
return 1;
|
||||
}
|
||||
idx = 1;
|
||||
while (idx < c && v[idx][0] == '-') {
|
||||
if (!strcmp(v[idx], "-x"))
|
||||
reverse = 1;
|
||||
else if (!strcmp(v[idx], "-v"))
|
||||
verbose = 1;
|
||||
else
|
||||
fprintf(stderr, "Unknown option %s\n", v[idx]);
|
||||
++idx;
|
||||
}
|
||||
event_init();
|
||||
if (verbose)
|
||||
evdns_set_log_fn(logfn);
|
||||
evdns_resolv_conf_parse(DNS_OPTION_NAMESERVERS, "/etc/resolv.conf");
|
||||
for (; idx < c; ++idx) {
|
||||
if (reverse) {
|
||||
struct in_addr addr;
|
||||
if (!inet_aton(v[idx], &addr)) {
|
||||
fprintf(stderr, "Skipping non-IP %s\n", v[idx]);
|
||||
continue;
|
||||
}
|
||||
fprintf(stderr, "resolving %s...\n",v[idx]);
|
||||
evdns_resolve_reverse(&addr, 0, main_callback, v[idx]);
|
||||
} else {
|
||||
fprintf(stderr, "resolving (fwd) %s...\n",v[idx]);
|
||||
evdns_resolve_ipv4(v[idx], 0, main_callback, v[idx]);
|
||||
}
|
||||
}
|
||||
fflush(stdout);
|
||||
event_dispatch();
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Local Variables:
|
||||
// tab-width: 4
|
||||
// c-basic-offset: 4
|
||||
|
@ -75,4 +75,25 @@ void evdns_set_log_fn(evdns_debug_log_fn_type fn);
|
||||
|
||||
#define DNS_NO_SEARCH 1
|
||||
|
||||
struct evdns_request {
|
||||
int flags;
|
||||
int nquestions;
|
||||
struct evdns_question **questions;
|
||||
};
|
||||
struct evdns_question {
|
||||
int type;
|
||||
int class;
|
||||
char name[1];
|
||||
};
|
||||
typedef void (*evdns_request_callback_type)(struct evdns_request *, void *);
|
||||
#define EVDNS_ANSWER_SECTION 0
|
||||
#define EVDNS_AUTHORITY_SECTION 1
|
||||
#define EVDNS_ADDITIONAL_SECTION 2
|
||||
int evdns_request_add_reply(struct evdns_request *req, int section, const char *name, int type, int class, int ttl, int datalen, const char *data);
|
||||
int evdns_request_add_a_reply(struct evdns_request *req, const char *name, int n, void *addrs, int ttl);
|
||||
int evdns_request_add_ptr_reply(struct evdns_request *req, struct in_addr *in, const char *name, int ttl);
|
||||
int evdns_request_add_cname_reply(struct evdns_request *req, const char *name, const char *cname, int ttl);
|
||||
int evdns_request_respond(struct evdns_request *req, int err, int flags);
|
||||
int evdns_request_drop(struct evdns_request *req);
|
||||
|
||||
#endif // !EVENTDNS_H
|
||||
|
Loading…
Reference in New Issue
Block a user