Added new feature (rfc2671)
This commit is contained in:
parent
e447bc5c60
commit
90364defb0
|
@ -20,6 +20,7 @@ CSOURCES = ares__close_sockets.c \
|
||||||
ares_library_init.c \
|
ares_library_init.c \
|
||||||
ares_llist.c \
|
ares_llist.c \
|
||||||
ares_mkquery.c \
|
ares_mkquery.c \
|
||||||
|
ares_create_query.c \
|
||||||
ares_nowarn.c \
|
ares_nowarn.c \
|
||||||
ares_options.c \
|
ares_options.c \
|
||||||
ares_parse_a_reply.c \
|
ares_parse_a_reply.c \
|
||||||
|
@ -92,6 +93,7 @@ MANPAGES = ares_cancel.3 \
|
||||||
ares_library_cleanup.3 \
|
ares_library_cleanup.3 \
|
||||||
ares_library_init.3 \
|
ares_library_init.3 \
|
||||||
ares_mkquery.3 \
|
ares_mkquery.3 \
|
||||||
|
ares_create_query.3 \
|
||||||
ares_parse_a_reply.3 \
|
ares_parse_a_reply.3 \
|
||||||
ares_parse_aaaa_reply.3 \
|
ares_parse_aaaa_reply.3 \
|
||||||
ares_parse_mx_reply.3 \
|
ares_parse_mx_reply.3 \
|
||||||
|
@ -133,6 +135,7 @@ HTMLPAGES = ares_cancel.html \
|
||||||
ares_library_cleanup.html \
|
ares_library_cleanup.html \
|
||||||
ares_library_init.html \
|
ares_library_init.html \
|
||||||
ares_mkquery.html \
|
ares_mkquery.html \
|
||||||
|
ares_create_query.html \
|
||||||
ares_parse_a_reply.html \
|
ares_parse_a_reply.html \
|
||||||
ares_parse_aaaa_reply.html \
|
ares_parse_aaaa_reply.html \
|
||||||
ares_parse_mx_reply.html \
|
ares_parse_mx_reply.html \
|
||||||
|
@ -173,6 +176,7 @@ PDFPAGES = ares_cancel.pdf \
|
||||||
ares_library_cleanup.pdf \
|
ares_library_cleanup.pdf \
|
||||||
ares_library_init.pdf \
|
ares_library_init.pdf \
|
||||||
ares_mkquery.pdf \
|
ares_mkquery.pdf \
|
||||||
|
ares_create_query.pdf \
|
||||||
ares_parse_a_reply.pdf \
|
ares_parse_a_reply.pdf \
|
||||||
ares_parse_aaaa_reply.pdf \
|
ares_parse_aaaa_reply.pdf \
|
||||||
ares_parse_mx_reply.pdf \
|
ares_parse_mx_reply.pdf \
|
||||||
|
|
12
ares.h
12
ares.h
|
@ -143,6 +143,7 @@ extern "C" {
|
||||||
#define ARES_FLAG_NOSEARCH (1 << 5)
|
#define ARES_FLAG_NOSEARCH (1 << 5)
|
||||||
#define ARES_FLAG_NOALIASES (1 << 6)
|
#define ARES_FLAG_NOALIASES (1 << 6)
|
||||||
#define ARES_FLAG_NOCHECKRESP (1 << 7)
|
#define ARES_FLAG_NOCHECKRESP (1 << 7)
|
||||||
|
#define ARES_FLAG_EDNS (1 << 8)
|
||||||
|
|
||||||
/* Option mask values */
|
/* Option mask values */
|
||||||
#define ARES_OPT_FLAGS (1 << 0)
|
#define ARES_OPT_FLAGS (1 << 0)
|
||||||
|
@ -160,6 +161,7 @@ extern "C" {
|
||||||
#define ARES_OPT_SOCK_RCVBUF (1 << 12)
|
#define ARES_OPT_SOCK_RCVBUF (1 << 12)
|
||||||
#define ARES_OPT_TIMEOUTMS (1 << 13)
|
#define ARES_OPT_TIMEOUTMS (1 << 13)
|
||||||
#define ARES_OPT_ROTATE (1 << 14)
|
#define ARES_OPT_ROTATE (1 << 14)
|
||||||
|
#define ARES_OPT_EDNSPSZ (1 << 15)
|
||||||
|
|
||||||
/* Nameinfo flag values */
|
/* Nameinfo flag values */
|
||||||
#define ARES_NI_NOFQDN (1 << 0)
|
#define ARES_NI_NOFQDN (1 << 0)
|
||||||
|
@ -265,6 +267,7 @@ struct ares_options {
|
||||||
void *sock_state_cb_data;
|
void *sock_state_cb_data;
|
||||||
struct apattern *sortlist;
|
struct apattern *sortlist;
|
||||||
int nsort;
|
int nsort;
|
||||||
|
int ednspsz;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct hostent;
|
struct hostent;
|
||||||
|
@ -403,6 +406,15 @@ CARES_EXTERN void ares_process_fd(ares_channel channel,
|
||||||
ares_socket_t read_fd,
|
ares_socket_t read_fd,
|
||||||
ares_socket_t write_fd);
|
ares_socket_t write_fd);
|
||||||
|
|
||||||
|
CARES_EXTERN int ares_create_query(const char *name,
|
||||||
|
int dnsclass,
|
||||||
|
int type,
|
||||||
|
unsigned short id,
|
||||||
|
int rd,
|
||||||
|
unsigned char **buf,
|
||||||
|
int *buflen,
|
||||||
|
int max_udp_size);
|
||||||
|
|
||||||
CARES_EXTERN int ares_mkquery(const char *name,
|
CARES_EXTERN int ares_mkquery(const char *name,
|
||||||
int dnsclass,
|
int dnsclass,
|
||||||
int type,
|
int type,
|
||||||
|
|
|
@ -0,0 +1,79 @@
|
||||||
|
.\"
|
||||||
|
.\" Copyright 1998, 2000 by the Massachusetts Institute of Technology.
|
||||||
|
.\"
|
||||||
|
.\" Permission to use, copy, modify, and distribute this
|
||||||
|
.\" software and its documentation for any purpose and without
|
||||||
|
.\" fee is hereby granted, provided that the above copyright
|
||||||
|
.\" notice appear in all copies and that both that copyright
|
||||||
|
.\" notice and this permission notice appear in supporting
|
||||||
|
.\" documentation, and that the name of M.I.T. not be used in
|
||||||
|
.\" advertising or publicity pertaining to distribution of the
|
||||||
|
.\" software without specific, written prior permission.
|
||||||
|
.\" M.I.T. makes no representations about the suitability of
|
||||||
|
.\" this software for any purpose. It is provided "as is"
|
||||||
|
.\" without express or implied warranty.
|
||||||
|
.\"
|
||||||
|
.TH ARES_CREATE_QUERY 3 "20 Nov 2009"
|
||||||
|
.SH NAME
|
||||||
|
ares_create_query \- Compose a single-question DNS query buffer
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.nf
|
||||||
|
.B #include <ares.h>
|
||||||
|
.PP
|
||||||
|
.B int ares_create_query(const char *\fIname\fP, int \fIdnsclass\fP,\
|
||||||
|
int \fItype\fP,
|
||||||
|
.B unsigned short \fIid\fP, int \fIrd\fP,\
|
||||||
|
unsigned char **\fIbuf\fP,
|
||||||
|
.B int *\fIbuflen\fP, int \fImax_udp_size\fP)
|
||||||
|
.fi
|
||||||
|
.SH DESCRIPTION
|
||||||
|
The
|
||||||
|
.B ares_create_query
|
||||||
|
function composes a DNS query with a single question.
|
||||||
|
The parameter
|
||||||
|
.I name
|
||||||
|
gives the query name as a NUL-terminated C string of period-separated
|
||||||
|
labels optionally ending with a period; periods and backslashes within
|
||||||
|
a label must be escaped with a backlash. The parameters
|
||||||
|
.I dnsclass
|
||||||
|
and
|
||||||
|
.I type
|
||||||
|
give the class and type of the query using the values defined in
|
||||||
|
.BR <arpa/nameser.h> .
|
||||||
|
The parameter
|
||||||
|
.I id
|
||||||
|
gives a 16-bit identifier for the query. The parameter
|
||||||
|
.I rd
|
||||||
|
should be nonzero if recursion is desired, zero if not. The query
|
||||||
|
will be placed in an allocated buffer, a pointer to which will be
|
||||||
|
stored in the variable pointed to by
|
||||||
|
.IR buf ,
|
||||||
|
and the length of which will be stored in the variable pointed to by
|
||||||
|
.IR buflen .
|
||||||
|
It is the caller's responsibility to free this buffer using
|
||||||
|
\fIares_free_string(3)\fP when it is no longer needed.
|
||||||
|
The parameter
|
||||||
|
.I max_udp_size
|
||||||
|
should be nonzero to activate EDNS. Usage of \fIares_create_query(3)\fP\ with
|
||||||
|
.I max_udp_size
|
||||||
|
set to zero is equivalent to \fIares_mkquery(3)\fP.
|
||||||
|
.SH RETURN VALUES
|
||||||
|
.B ares_create_query
|
||||||
|
can return any of the following values:
|
||||||
|
.TP 15
|
||||||
|
.B ARES_SUCCESS
|
||||||
|
Construction of the DNS query succeeded.
|
||||||
|
.TP 15
|
||||||
|
.B ARES_EBADNAME
|
||||||
|
The query name
|
||||||
|
.I name
|
||||||
|
could not be encoded as a domain name, either because it contained a
|
||||||
|
zero-length label or because it contained a label of more than 63
|
||||||
|
characters.
|
||||||
|
.TP 15
|
||||||
|
.B ARES_ENOMEM
|
||||||
|
Memory was exhausted.
|
||||||
|
.SH SEE ALSO
|
||||||
|
.BR ares_expand_name (3),
|
||||||
|
.BR ares_free_string (3)
|
||||||
|
.SH AUTHOR
|
|
@ -0,0 +1,209 @@
|
||||||
|
|
||||||
|
/* Copyright 1998 by the Massachusetts Institute of Technology.
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this
|
||||||
|
* software and its documentation for any purpose and without
|
||||||
|
* fee is hereby granted, provided that the above copyright
|
||||||
|
* notice appear in all copies and that both that copyright
|
||||||
|
* notice and this permission notice appear in supporting
|
||||||
|
* documentation, and that the name of M.I.T. not be used in
|
||||||
|
* advertising or publicity pertaining to distribution of the
|
||||||
|
* software without specific, written prior permission.
|
||||||
|
* M.I.T. makes no representations about the suitability of
|
||||||
|
* this software for any purpose. It is provided "as is"
|
||||||
|
* without express or implied warranty.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ares_setup.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_SYS_SOCKET_H
|
||||||
|
# include <sys/socket.h>
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_NETINET_IN_H
|
||||||
|
# include <netinet/in.h>
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_ARPA_NAMESER_H
|
||||||
|
# include <arpa/nameser.h>
|
||||||
|
#else
|
||||||
|
# include "nameser.h"
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_ARPA_NAMESER_COMPAT_H
|
||||||
|
# include <arpa/nameser_compat.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "ares.h"
|
||||||
|
#include "ares_dns.h"
|
||||||
|
#include "ares_private.h"
|
||||||
|
|
||||||
|
/* Header format, from RFC 1035:
|
||||||
|
* 1 1 1 1 1 1
|
||||||
|
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
|
||||||
|
* +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||||
|
* | ID |
|
||||||
|
* +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||||
|
* |QR| Opcode |AA|TC|RD|RA| Z | RCODE |
|
||||||
|
* +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||||
|
* | QDCOUNT |
|
||||||
|
* +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||||
|
* | ANCOUNT |
|
||||||
|
* +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||||
|
* | NSCOUNT |
|
||||||
|
* +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||||
|
* | ARCOUNT |
|
||||||
|
* +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||||
|
*
|
||||||
|
* AA, TC, RA, and RCODE are only set in responses. Brief description
|
||||||
|
* of the remaining fields:
|
||||||
|
* ID Identifier to match responses with queries
|
||||||
|
* QR Query (0) or response (1)
|
||||||
|
* Opcode For our purposes, always QUERY
|
||||||
|
* RD Recursion desired
|
||||||
|
* Z Reserved (zero)
|
||||||
|
* QDCOUNT Number of queries
|
||||||
|
* ANCOUNT Number of answers
|
||||||
|
* NSCOUNT Number of name server records
|
||||||
|
* ARCOUNT Number of additional records
|
||||||
|
*
|
||||||
|
* Question format, from RFC 1035:
|
||||||
|
* 1 1 1 1 1 1
|
||||||
|
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
|
||||||
|
* +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||||
|
* | |
|
||||||
|
* / QNAME /
|
||||||
|
* / /
|
||||||
|
* +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||||
|
* | QTYPE |
|
||||||
|
* +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||||
|
* | QCLASS |
|
||||||
|
* +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||||
|
*
|
||||||
|
* The query name is encoded as a series of labels, each represented
|
||||||
|
* as a one-byte length (maximum 63) followed by the text of the
|
||||||
|
* label. The list is terminated by a label of length zero (which can
|
||||||
|
* be thought of as the root domain).
|
||||||
|
*/
|
||||||
|
|
||||||
|
int ares_create_query(const char *name, int dnsclass, int type,
|
||||||
|
unsigned short id, int rd, unsigned char **buf,
|
||||||
|
int *buflen, int max_udp_size)
|
||||||
|
{
|
||||||
|
int len;
|
||||||
|
unsigned char *q;
|
||||||
|
const char *p;
|
||||||
|
|
||||||
|
/* Set our results early, in case we bail out early with an error. */
|
||||||
|
*buflen = 0;
|
||||||
|
*buf = NULL;
|
||||||
|
|
||||||
|
/* Compute the length of the encoded name so we can check buflen.
|
||||||
|
* Start counting at 1 for the zero-length label at the end. */
|
||||||
|
len = 1;
|
||||||
|
for (p = name; *p; p++)
|
||||||
|
{
|
||||||
|
if (*p == '\\' && *(p + 1) != 0)
|
||||||
|
p++;
|
||||||
|
len++;
|
||||||
|
}
|
||||||
|
/* If there are n periods in the name, there are n + 1 labels, and
|
||||||
|
* thus n + 1 length fields, unless the name is empty or ends with a
|
||||||
|
* period. So add 1 unless name is empty or ends with a period.
|
||||||
|
*/
|
||||||
|
if (*name && *(p - 1) != '.')
|
||||||
|
len++;
|
||||||
|
|
||||||
|
/* Immediately reject names that are longer than the maximum of 255
|
||||||
|
* bytes that's specified in RFC 1035 ("To simplify implementations,
|
||||||
|
* the total length of a domain name (i.e., label octets and label
|
||||||
|
* length octets) is restricted to 255 octets or less."). We aren't
|
||||||
|
* doing this just to be a stickler about RFCs. For names that are
|
||||||
|
* too long, 'dnscache' closes its TCP connection to us immediately
|
||||||
|
* (when using TCP) and ignores the request when using UDP, and
|
||||||
|
* BIND's named returns ServFail (TCP or UDP). Sending a request
|
||||||
|
* that we know will cause 'dnscache' to close the TCP connection is
|
||||||
|
* painful, since that makes any other outstanding requests on that
|
||||||
|
* connection fail. And sending a UDP request that we know
|
||||||
|
* 'dnscache' will ignore is bad because resources will be tied up
|
||||||
|
* until we time-out the request.
|
||||||
|
*/
|
||||||
|
if (len > MAXCDNAME)
|
||||||
|
return ARES_EBADNAME;
|
||||||
|
|
||||||
|
*buflen = len + HFIXEDSZ + QFIXEDSZ + (max_udp_size ? EDNSFIXEDSZ : 0);
|
||||||
|
*buf = malloc(*buflen);
|
||||||
|
if (!*buf)
|
||||||
|
return ARES_ENOMEM;
|
||||||
|
|
||||||
|
/* Set up the header. */
|
||||||
|
q = *buf;
|
||||||
|
memset(q, 0, HFIXEDSZ);
|
||||||
|
DNS_HEADER_SET_QID(q, id);
|
||||||
|
DNS_HEADER_SET_OPCODE(q, QUERY);
|
||||||
|
if (rd) {
|
||||||
|
DNS_HEADER_SET_RD(q, 1);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
DNS_HEADER_SET_RD(q, 0);
|
||||||
|
}
|
||||||
|
DNS_HEADER_SET_QDCOUNT(q, 1);
|
||||||
|
|
||||||
|
if (max_udp_size) {
|
||||||
|
DNS_HEADER_SET_ARCOUNT(q, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* A name of "." is a screw case for the loop below, so adjust it. */
|
||||||
|
if (strcmp(name, ".") == 0)
|
||||||
|
name++;
|
||||||
|
|
||||||
|
/* Start writing out the name after the header. */
|
||||||
|
q += HFIXEDSZ;
|
||||||
|
while (*name)
|
||||||
|
{
|
||||||
|
if (*name == '.')
|
||||||
|
return ARES_EBADNAME;
|
||||||
|
|
||||||
|
/* Count the number of bytes in this label. */
|
||||||
|
len = 0;
|
||||||
|
for (p = name; *p && *p != '.'; p++)
|
||||||
|
{
|
||||||
|
if (*p == '\\' && *(p + 1) != 0)
|
||||||
|
p++;
|
||||||
|
len++;
|
||||||
|
}
|
||||||
|
if (len > MAXLABEL)
|
||||||
|
return ARES_EBADNAME;
|
||||||
|
|
||||||
|
/* Encode the length and copy the data. */
|
||||||
|
*q++ = (unsigned char)len;
|
||||||
|
for (p = name; *p && *p != '.'; p++)
|
||||||
|
{
|
||||||
|
if (*p == '\\' && *(p + 1) != 0)
|
||||||
|
p++;
|
||||||
|
*q++ = *p;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Go to the next label and repeat, unless we hit the end. */
|
||||||
|
if (!*p)
|
||||||
|
break;
|
||||||
|
name = p + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add the zero-length label at the end. */
|
||||||
|
*q++ = 0;
|
||||||
|
|
||||||
|
/* Finish off the question with the type and class. */
|
||||||
|
DNS_QUESTION_SET_TYPE(q, type);
|
||||||
|
DNS_QUESTION_SET_CLASS(q, dnsclass);
|
||||||
|
|
||||||
|
if (max_udp_size)
|
||||||
|
{
|
||||||
|
q += QFIXEDSZ;
|
||||||
|
memset(q, 0, EDNSFIXEDSZ);
|
||||||
|
q++;
|
||||||
|
DNS_RR_SET_TYPE(q, ns_t_opt);
|
||||||
|
DNS_RR_SET_CLASS(q, max_udp_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ARES_SUCCESS;
|
||||||
|
}
|
|
@ -95,9 +95,9 @@
|
||||||
#define DNS_RR_LEN(r) DNS__16BIT((r) + 8)
|
#define DNS_RR_LEN(r) DNS__16BIT((r) + 8)
|
||||||
|
|
||||||
/* Macros for constructing the fixed part of a DNS resource record */
|
/* Macros for constructing the fixed part of a DNS resource record */
|
||||||
#define DNS_RR_SET_TYPE(r) DNS__SET16BIT(r, v)
|
#define DNS_RR_SET_TYPE(r, v) DNS__SET16BIT(r, v)
|
||||||
#define DNS_RR_SET_CLASS(r) DNS__SET16BIT((r) + 2, v)
|
#define DNS_RR_SET_CLASS(r, v) DNS__SET16BIT((r) + 2, v)
|
||||||
#define DNS_RR_SET_TTL(r) DNS__SET32BIT((r) + 4, v)
|
#define DNS_RR_SET_TTL(r, v) DNS__SET32BIT((r) + 4, v)
|
||||||
#define DNS_RR_SET_LEN(r) DNS__SET16BIT((r) + 8, v)
|
#define DNS_RR_SET_LEN(r, v) DNS__SET16BIT((r) + 8, v)
|
||||||
|
|
||||||
#endif /* HEADER_CARES_DNS_H */
|
#endif /* HEADER_CARES_DNS_H */
|
||||||
|
|
|
@ -163,6 +163,7 @@ int ares_init_options(ares_channel *channelptr, struct ares_options *options,
|
||||||
channel->rotate = -1;
|
channel->rotate = -1;
|
||||||
channel->udp_port = -1;
|
channel->udp_port = -1;
|
||||||
channel->tcp_port = -1;
|
channel->tcp_port = -1;
|
||||||
|
channel->ednspsz = -1;
|
||||||
channel->socket_send_buffer_size = -1;
|
channel->socket_send_buffer_size = -1;
|
||||||
channel->socket_receive_buffer_size = -1;
|
channel->socket_receive_buffer_size = -1;
|
||||||
channel->nservers = -1;
|
channel->nservers = -1;
|
||||||
|
@ -453,6 +454,9 @@ static int init_by_options(ares_channel channel,
|
||||||
&& channel->socket_receive_buffer_size == -1)
|
&& channel->socket_receive_buffer_size == -1)
|
||||||
channel->socket_receive_buffer_size = options->socket_receive_buffer_size;
|
channel->socket_receive_buffer_size = options->socket_receive_buffer_size;
|
||||||
|
|
||||||
|
if ((optmask & ARES_OPT_EDNSPSZ) && channel->ednspsz == -1)
|
||||||
|
channel->ednspsz = options->ednspsz;
|
||||||
|
|
||||||
/* Copy the IPv4 servers, if given. */
|
/* Copy the IPv4 servers, if given. */
|
||||||
if ((optmask & ARES_OPT_SERVERS) && channel->nservers == -1)
|
if ((optmask & ARES_OPT_SERVERS) && channel->nservers == -1)
|
||||||
{
|
{
|
||||||
|
@ -1358,6 +1362,9 @@ static int init_by_defaults(ares_channel channel)
|
||||||
if (channel->tcp_port == -1)
|
if (channel->tcp_port == -1)
|
||||||
channel->tcp_port = htons(NAMESERVER_PORT);
|
channel->tcp_port = htons(NAMESERVER_PORT);
|
||||||
|
|
||||||
|
if (channel->ednspsz == -1)
|
||||||
|
channel->ednspsz = EDNSPACKETSZ;
|
||||||
|
|
||||||
if (channel->nservers == -1) {
|
if (channel->nservers == -1) {
|
||||||
/* If nobody specified servers, try a local named. */
|
/* If nobody specified servers, try a local named. */
|
||||||
channel->servers = malloc(sizeof(struct server_state));
|
channel->servers = malloc(sizeof(struct server_state));
|
||||||
|
|
|
@ -25,6 +25,8 @@ ares_mkquery \- Compose a single-question DNS query buffer
|
||||||
.B int *\fIbuflen\fP)
|
.B int *\fIbuflen\fP)
|
||||||
.fi
|
.fi
|
||||||
.SH DESCRIPTION
|
.SH DESCRIPTION
|
||||||
|
Deprecated function. See \fIares_create_query(3)\fP instead!
|
||||||
|
|
||||||
The
|
The
|
||||||
.B ares_mkquery
|
.B ares_mkquery
|
||||||
function composes a DNS query with a single question.
|
function composes a DNS query with a single question.
|
||||||
|
@ -50,6 +52,11 @@ and the length of which will be stored in the variable pointed to by
|
||||||
.IR buflen .
|
.IR buflen .
|
||||||
It is the caller's responsibility to free this buffer using
|
It is the caller's responsibility to free this buffer using
|
||||||
\fIares_free_string(3)\fP when it is no longer needed.
|
\fIares_free_string(3)\fP when it is no longer needed.
|
||||||
|
|
||||||
|
Usage of \fIares_mkquery(3)\fP is deprecated, whereas the function is
|
||||||
|
equivalent to \fIares_create_query(3)\fP with \fBmax_udp_size\fP set to
|
||||||
|
0.
|
||||||
|
|
||||||
.SH RETURN VALUES
|
.SH RETURN VALUES
|
||||||
.B ares_mkquery
|
.B ares_mkquery
|
||||||
can return any of the following values:
|
can return any of the following values:
|
||||||
|
|
173
ares_mkquery.c
173
ares_mkquery.c
|
@ -15,181 +15,10 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "ares_setup.h"
|
#include "ares_setup.h"
|
||||||
|
|
||||||
#ifdef HAVE_SYS_SOCKET_H
|
|
||||||
# include <sys/socket.h>
|
|
||||||
#endif
|
|
||||||
#ifdef HAVE_NETINET_IN_H
|
|
||||||
# include <netinet/in.h>
|
|
||||||
#endif
|
|
||||||
#ifdef HAVE_ARPA_NAMESER_H
|
|
||||||
# include <arpa/nameser.h>
|
|
||||||
#else
|
|
||||||
# include "nameser.h"
|
|
||||||
#endif
|
|
||||||
#ifdef HAVE_ARPA_NAMESER_COMPAT_H
|
|
||||||
# include <arpa/nameser_compat.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "ares.h"
|
#include "ares.h"
|
||||||
#include "ares_dns.h"
|
|
||||||
#include "ares_private.h"
|
|
||||||
|
|
||||||
/* Header format, from RFC 1035:
|
|
||||||
* 1 1 1 1 1 1
|
|
||||||
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
|
|
||||||
* +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
|
||||||
* | ID |
|
|
||||||
* +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
|
||||||
* |QR| Opcode |AA|TC|RD|RA| Z | RCODE |
|
|
||||||
* +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
|
||||||
* | QDCOUNT |
|
|
||||||
* +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
|
||||||
* | ANCOUNT |
|
|
||||||
* +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
|
||||||
* | NSCOUNT |
|
|
||||||
* +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
|
||||||
* | ARCOUNT |
|
|
||||||
* +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
|
||||||
*
|
|
||||||
* AA, TC, RA, and RCODE are only set in responses. Brief description
|
|
||||||
* of the remaining fields:
|
|
||||||
* ID Identifier to match responses with queries
|
|
||||||
* QR Query (0) or response (1)
|
|
||||||
* Opcode For our purposes, always QUERY
|
|
||||||
* RD Recursion desired
|
|
||||||
* Z Reserved (zero)
|
|
||||||
* QDCOUNT Number of queries
|
|
||||||
* ANCOUNT Number of answers
|
|
||||||
* NSCOUNT Number of name server records
|
|
||||||
* ARCOUNT Number of additional records
|
|
||||||
*
|
|
||||||
* Question format, from RFC 1035:
|
|
||||||
* 1 1 1 1 1 1
|
|
||||||
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
|
|
||||||
* +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
|
||||||
* | |
|
|
||||||
* / QNAME /
|
|
||||||
* / /
|
|
||||||
* +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
|
||||||
* | QTYPE |
|
|
||||||
* +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
|
||||||
* | QCLASS |
|
|
||||||
* +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
|
||||||
*
|
|
||||||
* The query name is encoded as a series of labels, each represented
|
|
||||||
* as a one-byte length (maximum 63) followed by the text of the
|
|
||||||
* label. The list is terminated by a label of length zero (which can
|
|
||||||
* be thought of as the root domain).
|
|
||||||
*/
|
|
||||||
|
|
||||||
int ares_mkquery(const char *name, int dnsclass, int type, unsigned short id,
|
int ares_mkquery(const char *name, int dnsclass, int type, unsigned short id,
|
||||||
int rd, unsigned char **buf, int *buflen)
|
int rd, unsigned char **buf, int *buflen)
|
||||||
{
|
{
|
||||||
int len;
|
return ares_create_query(name, dnsclass, type, id, rd, buf, buflen, 0);
|
||||||
unsigned char *q;
|
|
||||||
const char *p;
|
|
||||||
|
|
||||||
/* Set our results early, in case we bail out early with an error. */
|
|
||||||
*buflen = 0;
|
|
||||||
*buf = NULL;
|
|
||||||
|
|
||||||
/* Compute the length of the encoded name so we can check buflen.
|
|
||||||
* Start counting at 1 for the zero-length label at the end. */
|
|
||||||
len = 1;
|
|
||||||
for (p = name; *p; p++)
|
|
||||||
{
|
|
||||||
if (*p == '\\' && *(p + 1) != 0)
|
|
||||||
p++;
|
|
||||||
len++;
|
|
||||||
}
|
|
||||||
/* If there are n periods in the name, there are n + 1 labels, and
|
|
||||||
* thus n + 1 length fields, unless the name is empty or ends with a
|
|
||||||
* period. So add 1 unless name is empty or ends with a period.
|
|
||||||
*/
|
|
||||||
if (*name && *(p - 1) != '.')
|
|
||||||
len++;
|
|
||||||
|
|
||||||
/* Immediately reject names that are longer than the maximum of 255
|
|
||||||
* bytes that's specified in RFC 1035 ("To simplify implementations,
|
|
||||||
* the total length of a domain name (i.e., label octets and label
|
|
||||||
* length octets) is restricted to 255 octets or less."). We aren't
|
|
||||||
* doing this just to be a stickler about RFCs. For names that are
|
|
||||||
* too long, 'dnscache' closes its TCP connection to us immediately
|
|
||||||
* (when using TCP) and ignores the request when using UDP, and
|
|
||||||
* BIND's named returns ServFail (TCP or UDP). Sending a request
|
|
||||||
* that we know will cause 'dnscache' to close the TCP connection is
|
|
||||||
* painful, since that makes any other outstanding requests on that
|
|
||||||
* connection fail. And sending a UDP request that we know
|
|
||||||
* 'dnscache' will ignore is bad because resources will be tied up
|
|
||||||
* until we time-out the request.
|
|
||||||
*/
|
|
||||||
if (len > MAXCDNAME)
|
|
||||||
return ARES_EBADNAME;
|
|
||||||
|
|
||||||
*buflen = len + HFIXEDSZ + QFIXEDSZ;
|
|
||||||
*buf = malloc(*buflen);
|
|
||||||
if (!*buf)
|
|
||||||
return ARES_ENOMEM;
|
|
||||||
|
|
||||||
/* Set up the header. */
|
|
||||||
q = *buf;
|
|
||||||
memset(q, 0, HFIXEDSZ);
|
|
||||||
DNS_HEADER_SET_QID(q, id);
|
|
||||||
DNS_HEADER_SET_OPCODE(q, QUERY);
|
|
||||||
if (rd) {
|
|
||||||
DNS_HEADER_SET_RD(q, 1);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
DNS_HEADER_SET_RD(q, 0);
|
|
||||||
}
|
|
||||||
DNS_HEADER_SET_QDCOUNT(q, 1);
|
|
||||||
|
|
||||||
/* A name of "." is a screw case for the loop below, so adjust it. */
|
|
||||||
if (strcmp(name, ".") == 0)
|
|
||||||
name++;
|
|
||||||
|
|
||||||
/* Start writing out the name after the header. */
|
|
||||||
q += HFIXEDSZ;
|
|
||||||
while (*name)
|
|
||||||
{
|
|
||||||
if (*name == '.')
|
|
||||||
return ARES_EBADNAME;
|
|
||||||
|
|
||||||
/* Count the number of bytes in this label. */
|
|
||||||
len = 0;
|
|
||||||
for (p = name; *p && *p != '.'; p++)
|
|
||||||
{
|
|
||||||
if (*p == '\\' && *(p + 1) != 0)
|
|
||||||
p++;
|
|
||||||
len++;
|
|
||||||
}
|
|
||||||
if (len > MAXLABEL)
|
|
||||||
return ARES_EBADNAME;
|
|
||||||
|
|
||||||
/* Encode the length and copy the data. */
|
|
||||||
*q++ = (unsigned char)len;
|
|
||||||
for (p = name; *p && *p != '.'; p++)
|
|
||||||
{
|
|
||||||
if (*p == '\\' && *(p + 1) != 0)
|
|
||||||
p++;
|
|
||||||
*q++ = *p;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Go to the next label and repeat, unless we hit the end. */
|
|
||||||
if (!*p)
|
|
||||||
break;
|
|
||||||
name = p + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Add the zero-length label at the end. */
|
|
||||||
*q++ = 0;
|
|
||||||
|
|
||||||
/* Finish off the question with the type and class. */
|
|
||||||
DNS_QUESTION_SET_TYPE(q, type);
|
|
||||||
DNS_QUESTION_SET_CLASS(q, dnsclass);
|
|
||||||
|
|
||||||
return ARES_SUCCESS;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,6 +113,13 @@
|
||||||
# define writev(s,ptr,cnt) ares_writev(s,ptr,cnt)
|
# define writev(s,ptr,cnt) ares_writev(s,ptr,cnt)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/********* EDNS defines section ******/
|
||||||
|
#define EDNSPACKETSZ 1280 /* Reasonable UDP payload size, as suggested
|
||||||
|
in RFC2671 */
|
||||||
|
#define MAXENDSSZ 4096 /* Maximum (local) limit for edns packet size */
|
||||||
|
#define EDNSFIXEDSZ 11 /* Size of EDNS header */
|
||||||
|
/********* EDNS defines section ******/
|
||||||
|
|
||||||
struct ares_addr {
|
struct ares_addr {
|
||||||
int family;
|
int family;
|
||||||
union {
|
union {
|
||||||
|
@ -260,6 +267,7 @@ struct ares_channeldata {
|
||||||
struct apattern *sortlist;
|
struct apattern *sortlist;
|
||||||
int nsort;
|
int nsort;
|
||||||
char *lookups;
|
char *lookups;
|
||||||
|
int ednspsz;
|
||||||
|
|
||||||
/* For binding to local devices and/or IP addresses. Leave
|
/* For binding to local devices and/or IP addresses. Leave
|
||||||
* them null/zero for no binding.
|
* them null/zero for no binding.
|
||||||
|
|
|
@ -430,7 +430,7 @@ static void read_udp_packets(ares_channel channel, fd_set *read_fds,
|
||||||
struct server_state *server;
|
struct server_state *server;
|
||||||
int i;
|
int i;
|
||||||
ssize_t count;
|
ssize_t count;
|
||||||
unsigned char buf[PACKETSZ + 1];
|
unsigned char buf[MAXENDSSZ + 1];
|
||||||
#ifdef HAVE_RECVFROM
|
#ifdef HAVE_RECVFROM
|
||||||
ares_socklen_t fromlen;
|
ares_socklen_t fromlen;
|
||||||
union {
|
union {
|
||||||
|
@ -541,7 +541,7 @@ static void process_answer(ares_channel channel, unsigned char *abuf,
|
||||||
int alen, int whichserver, int tcp,
|
int alen, int whichserver, int tcp,
|
||||||
struct timeval *now)
|
struct timeval *now)
|
||||||
{
|
{
|
||||||
int tc, rcode;
|
int tc, rcode, packetsz;
|
||||||
unsigned short id;
|
unsigned short id;
|
||||||
struct query *query;
|
struct query *query;
|
||||||
struct list_node* list_head;
|
struct list_node* list_head;
|
||||||
|
@ -578,11 +578,34 @@ static void process_answer(ares_channel channel, unsigned char *abuf,
|
||||||
if (!query)
|
if (!query)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
packetsz = PACKETSZ;
|
||||||
|
/* If we use EDNS and server answers with one of these RCODES, the protocol
|
||||||
|
* extension is not understood by the responder. We must retry the query
|
||||||
|
* without EDNS enabled.
|
||||||
|
*/
|
||||||
|
if (channel->flags & ARES_FLAG_EDNS)
|
||||||
|
{
|
||||||
|
packetsz = channel->ednspsz;
|
||||||
|
if (rcode == NOTIMP || rcode == FORMERR || rcode == SERVFAIL)
|
||||||
|
{
|
||||||
|
int qlen = alen - EDNSFIXEDSZ;
|
||||||
|
channel->flags ^= ARES_FLAG_EDNS;
|
||||||
|
query->tcplen -= EDNSFIXEDSZ;
|
||||||
|
query->qlen -= EDNSFIXEDSZ;
|
||||||
|
query->tcpbuf[0] = (unsigned char)((qlen >> 8) & 0xff);
|
||||||
|
query->tcpbuf[1] = (unsigned char)(qlen & 0xff);
|
||||||
|
DNS_HEADER_SET_ARCOUNT(query->tcpbuf + 2, 0);
|
||||||
|
query->tcpbuf = realloc(query->tcpbuf, query->tcplen);
|
||||||
|
ares__send_query(channel, query, now);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* If we got a truncated UDP packet and are not ignoring truncation,
|
/* If we got a truncated UDP packet and are not ignoring truncation,
|
||||||
* don't accept the packet, and switch the query to TCP if we hadn't
|
* don't accept the packet, and switch the query to TCP if we hadn't
|
||||||
* done so already.
|
* done so already.
|
||||||
*/
|
*/
|
||||||
if ((tc || alen > PACKETSZ) && !tcp && !(channel->flags & ARES_FLAG_IGNTC))
|
if ((tc || alen > packetsz) && !tcp && !(channel->flags & ARES_FLAG_IGNTC))
|
||||||
{
|
{
|
||||||
if (!query->using_tcp)
|
if (!query->using_tcp)
|
||||||
{
|
{
|
||||||
|
@ -595,8 +618,8 @@ static void process_answer(ares_channel channel, unsigned char *abuf,
|
||||||
/* Limit alen to PACKETSZ if we aren't using TCP (only relevant if we
|
/* Limit alen to PACKETSZ if we aren't using TCP (only relevant if we
|
||||||
* are ignoring truncation.
|
* are ignoring truncation.
|
||||||
*/
|
*/
|
||||||
if (alen > PACKETSZ && !tcp)
|
if (alen > packetsz && !tcp)
|
||||||
alen = PACKETSZ;
|
alen = packetsz;
|
||||||
|
|
||||||
/* If we aren't passing through all error packets, discard packets
|
/* If we aren't passing through all error packets, discard packets
|
||||||
* with SERVFAIL, NOTIMP, or REFUSED response codes.
|
* with SERVFAIL, NOTIMP, or REFUSED response codes.
|
||||||
|
|
|
@ -114,8 +114,8 @@ void ares_query(ares_channel channel, const char *name, int dnsclass,
|
||||||
|
|
||||||
/* Compose the query. */
|
/* Compose the query. */
|
||||||
rd = !(channel->flags & ARES_FLAG_NORECURSE);
|
rd = !(channel->flags & ARES_FLAG_NORECURSE);
|
||||||
status = ares_mkquery(name, dnsclass, type, channel->next_id, rd, &qbuf,
|
status = ares_create_query(name, dnsclass, type, channel->next_id, rd, &qbuf,
|
||||||
&qlen);
|
&qlen, (channel->flags & ARES_FLAG_EDNS) ? channel->ednspsz : 0);
|
||||||
if (status != ARES_SUCCESS)
|
if (status != ARES_SUCCESS)
|
||||||
{
|
{
|
||||||
if (qbuf != NULL) free(qbuf);
|
if (qbuf != NULL) free(qbuf);
|
||||||
|
|
|
@ -42,7 +42,7 @@ void ares_send(ares_channel channel, const unsigned char *qbuf, int qlen,
|
||||||
ares_callback callback, void *arg)
|
ares_callback callback, void *arg)
|
||||||
{
|
{
|
||||||
struct query *query;
|
struct query *query;
|
||||||
int i;
|
int i, packetsz;
|
||||||
struct timeval now;
|
struct timeval now;
|
||||||
|
|
||||||
/* Verify that the query is at least long enough to hold the header. */
|
/* Verify that the query is at least long enough to hold the header. */
|
||||||
|
@ -109,7 +109,10 @@ void ares_send(ares_channel channel, const unsigned char *qbuf, int qlen,
|
||||||
query->server_info[i].skip_server = 0;
|
query->server_info[i].skip_server = 0;
|
||||||
query->server_info[i].tcp_connection_generation = 0;
|
query->server_info[i].tcp_connection_generation = 0;
|
||||||
}
|
}
|
||||||
query->using_tcp = (channel->flags & ARES_FLAG_USEVC) || qlen > PACKETSZ;
|
|
||||||
|
packetsz = (channel->flags & ARES_FLAG_EDNS) ? channel->ednspsz : PACKETSZ;
|
||||||
|
query->using_tcp = (channel->flags & ARES_FLAG_USEVC) || qlen > packetsz;
|
||||||
|
|
||||||
query->error_status = ARES_ECONNREFUSED;
|
query->error_status = ARES_ECONNREFUSED;
|
||||||
query->timeouts = 0;
|
query->timeouts = 0;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue