"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "src/lib/ares_expand_name.c" between
c-ares-1.17.1.tar.gz and c-ares-1.17.2.tar.gz

About: c-ares is a C library for asynchronous DNS requests (including name resolves).

ares_expand_name.c  (c-ares-1.17.1):ares_expand_name.c  (c-ares-1.17.2)
skipping to change at line 22 skipping to change at line 22
* M.I.T. makes no representations about the suitability of * M.I.T. makes no representations about the suitability of
* this software for any purpose. It is provided "as is" * this software for any purpose. It is provided "as is"
* without express or implied warranty. * without express or implied warranty.
*/ */
#include "ares_setup.h" #include "ares_setup.h"
#ifdef HAVE_NETINET_IN_H #ifdef HAVE_NETINET_IN_H
# include <netinet/in.h> # include <netinet/in.h>
#endif #endif
#ifdef HAVE_ARPA_NAMESER_H
# include <arpa/nameser.h> #include "ares_nameser.h"
#else
# include "nameser.h"
#endif
#ifdef HAVE_ARPA_NAMESER_COMPAT_H
# include <arpa/nameser_compat.h>
#endif
#include "ares.h" #include "ares.h"
#include "ares_nowarn.h" #include "ares_nowarn.h"
#include "ares_private.h" /* for the memdebug */ #include "ares_private.h" /* for the memdebug */
/* Maximum number of indirections allowed for a name */ /* Maximum number of indirections allowed for a name */
#define MAX_INDIRS 50 #define MAX_INDIRS 50
static int name_length(const unsigned char *encoded, const unsigned char *abuf, static int name_length(const unsigned char *encoded, const unsigned char *abuf,
int alen); int alen, int is_hostname);
/* Reserved characters for names that need to be escaped */
static int is_reservedch(int ch)
{
switch (ch) {
case '"':
case '.':
case ';':
case '\\':
case '(':
case ')':
case '@':
case '$':
return 1;
default:
break;
}
return 0;
}
static int ares__isprint(int ch)
{
if (ch >= 0x20 && ch <= 0x7E)
return 1;
return 0;
}
/* Character set allowed by hostnames */
static int is_hostnamech(int ch)
{
/* [A-Za-z0-9-.]
* Don't use isalnum() as it is locale-specific
*/
if (ch >= 'A' && ch <= 'Z')
return 1;
if (ch >= 'a' && ch <= 'z')
return 1;
if (ch >= '0' && ch <= '9')
return 1;
if (ch == '-' || ch == '.')
return 1;
return 0;
}
/* Expand an RFC1035-encoded domain name given by encoded. The /* Expand an RFC1035-encoded domain name given by encoded. The
* containing message is given by abuf and alen. The result given by * containing message is given by abuf and alen. The result given by
* *s, which is set to a NUL-terminated allocated buffer. *enclen is * *s, which is set to a NUL-terminated allocated buffer. *enclen is
* set to the length of the encoded name (not the length of the * set to the length of the encoded name (not the length of the
* expanded name; the goal is to tell the caller how many bytes to * expanded name; the goal is to tell the caller how many bytes to
* move forward to get past the encoded name). * move forward to get past the encoded name).
* *
* In the simple case, an encoded name is a series of labels, each * In the simple case, an encoded name is a series of labels, each
* composed of a one-byte length (limited to values between 0 and 63 * composed of a one-byte length (limited to values between 0 and 63
skipping to change at line 63 skipping to change at line 102
* In the more complicated case, a label may be terminated by an * In the more complicated case, a label may be terminated by an
* indirection pointer, specified by two bytes with the high bits of * indirection pointer, specified by two bytes with the high bits of
* the first byte (corresponding to INDIR_MASK) set to 11. With the * the first byte (corresponding to INDIR_MASK) set to 11. With the
* two high bits of the first byte stripped off, the indirection * two high bits of the first byte stripped off, the indirection
* pointer gives an offset from the beginning of the containing * pointer gives an offset from the beginning of the containing
* message with more labels to decode. Indirection can happen an * message with more labels to decode. Indirection can happen an
* arbitrary number of times, so we have to detect loops. * arbitrary number of times, so we have to detect loops.
* *
* Since the expanded name uses '.' as a label separator, we use * Since the expanded name uses '.' as a label separator, we use
* backslashes to escape periods or backslashes in the expanded name. * backslashes to escape periods or backslashes in the expanded name.
*
* If the result is expected to be a hostname, then no escaped data is allowed
* and will return error.
*/ */
int ares_expand_name(const unsigned char *encoded, const unsigned char *abuf, int ares__expand_name_validated(const unsigned char *encoded,
int alen, char **s, long *enclen) const unsigned char *abuf,
int alen, char **s, long *enclen,
int is_hostname)
{ {
int len, indir = 0; int len, indir = 0;
char *q; char *q;
const unsigned char *p; const unsigned char *p;
union { union {
ares_ssize_t sig; ares_ssize_t sig;
size_t uns; size_t uns;
} nlen; } nlen;
nlen.sig = name_length(encoded, abuf, alen); nlen.sig = name_length(encoded, abuf, alen, is_hostname);
if (nlen.sig < 0) if (nlen.sig < 0)
return ARES_EBADNAME; return ARES_EBADNAME;
*s = ares_malloc(nlen.uns + 1); *s = ares_malloc(nlen.uns + 1);
if (!*s) if (!*s)
return ARES_ENOMEM; return ARES_ENOMEM;
q = *s; q = *s;
if (nlen.uns == 0) { if (nlen.uns == 0) {
/* RFC2181 says this should be ".": the root of the DNS tree. /* RFC2181 says this should be ".": the root of the DNS tree.
skipping to change at line 116 skipping to change at line 160
{ {
if (!indir) if (!indir)
{ {
*enclen = aresx_uztosl(p + 2U - encoded); *enclen = aresx_uztosl(p + 2U - encoded);
indir = 1; indir = 1;
} }
p = abuf + ((*p & ~INDIR_MASK) << 8 | *(p + 1)); p = abuf + ((*p & ~INDIR_MASK) << 8 | *(p + 1));
} }
else else
{ {
len = *p; int name_len = *p;
len = name_len;
p++; p++;
while (len--) while (len--)
{ {
if (*p == '.' || *p == '\\') /* Output as \DDD for consistency with RFC1035 5.1, except
*q++ = '\\'; * for the special case of a root name response */
*q++ = *p; if (!ares__isprint(*p) && !(name_len == 1 && *p == 0))
{
*q++ = '\\';
*q++ = '0' + *p / 100;
*q++ = '0' + (*p % 100) / 10;
*q++ = '0' + (*p % 10);
}
else if (is_reservedch(*p))
{
*q++ = '\\';
*q++ = *p;
}
else
{
*q++ = *p;
}
p++; p++;
} }
*q++ = '.'; *q++ = '.';
} }
} }
if (!indir) if (!indir)
*enclen = aresx_uztosl(p + 1U - encoded); *enclen = aresx_uztosl(p + 1U - encoded);
/* Nuke the trailing period if we wrote one. */ /* Nuke the trailing period if we wrote one. */
if (q > *s) if (q > *s)
*(q - 1) = 0; *(q - 1) = 0;
else else
*q = 0; /* zero terminate; LCOV_EXCL_LINE: empty names exit above */ *q = 0; /* zero terminate; LCOV_EXCL_LINE: empty names exit above */
return ARES_SUCCESS; return ARES_SUCCESS;
} }
int ares_expand_name(const unsigned char *encoded, const unsigned char *abuf,
int alen, char **s, long *enclen)
{
return ares__expand_name_validated(encoded, abuf, alen, s, enclen, 0);
}
/* Return the length of the expansion of an encoded domain name, or /* Return the length of the expansion of an encoded domain name, or
* -1 if the encoding is invalid. * -1 if the encoding is invalid.
*/ */
static int name_length(const unsigned char *encoded, const unsigned char *abuf, static int name_length(const unsigned char *encoded, const unsigned char *abuf,
int alen) int alen, int is_hostname)
{ {
int n = 0, offset, indir = 0, top; int n = 0, offset, indir = 0, top;
/* Allow the caller to pass us abuf + alen and have us check for it. */ /* Allow the caller to pass us abuf + alen and have us check for it. */
if (encoded >= abuf + alen) if (encoded >= abuf + alen)
return -1; return -1;
while (*encoded) while (*encoded)
{ {
top = (*encoded & INDIR_MASK); top = (*encoded & INDIR_MASK);
skipping to change at line 174 skipping to change at line 242
/* If we've seen more indirects than the message length, /* If we've seen more indirects than the message length,
* then there's a loop. * then there's a loop.
*/ */
++indir; ++indir;
if (indir > alen || indir > MAX_INDIRS) if (indir > alen || indir > MAX_INDIRS)
return -1; return -1;
} }
else if (top == 0x00) else if (top == 0x00)
{ {
offset = *encoded; int name_len = *encoded;
offset = name_len;
if (encoded + offset + 1 >= abuf + alen) if (encoded + offset + 1 >= abuf + alen)
return -1; return -1;
encoded++; encoded++;
while (offset--) while (offset--)
{ {
n += (*encoded == '.' || *encoded == '\\') ? 2 : 1; if (!ares__isprint(*encoded) && !(name_len == 1 && *encoded == 0))
{
if (is_hostname)
return -1;
n += 4;
}
else if (is_reservedch(*encoded))
{
if (is_hostname)
return -1;
n += 2;
}
else
{
if (is_hostname && !is_hostnamech(*encoded))
return -1;
n += 1;
}
encoded++; encoded++;
} }
n++; n++;
} }
else else
{ {
/* RFC 1035 4.1.4 says other options (01, 10) for top 2 /* RFC 1035 4.1.4 says other options (01, 10) for top 2
* bits are reserved. * bits are reserved.
*/ */
return -1; return -1;
} }
} }
/* If there were any labels at all, then the number of dots is one /* If there were any labels at all, then the number of dots is one
* less than the number of labels, so subtract one. * less than the number of labels, so subtract one.
*/ */
return (n) ? n - 1 : n; return (n) ? n - 1 : n;
} }
/* Like ares_expand_name but returns EBADRESP in case of invalid input. */ /* Like ares_expand_name_validated but returns EBADRESP in case of invalid
* input. */
int ares__expand_name_for_response(const unsigned char *encoded, int ares__expand_name_for_response(const unsigned char *encoded,
const unsigned char *abuf, int alen, const unsigned char *abuf, int alen,
char **s, long *enclen) char **s, long *enclen, int is_hostname)
{ {
int status = ares_expand_name(encoded, abuf, alen, s, enclen); int status = ares__expand_name_validated(encoded, abuf, alen, s, enclen,
is_hostname);
if (status == ARES_EBADNAME) if (status == ARES_EBADNAME)
status = ARES_EBADRESP; status = ARES_EBADRESP;
return status; return status;
} }
 End of changes. 18 change blocks. 
23 lines changed or deleted 113 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)