summaryrefslogtreecommitdiff
path: root/libc/inet/resolv.c
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2008-11-01 23:24:00 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2008-11-01 23:24:00 +0000
commitf09a1461fe8f3511750ad91f164b2769225858f5 (patch)
tree6d05d5b6ca6bcd3cba1f4e2f13d9a555572e8388 /libc/inet/resolv.c
parentc040a39eb5c792434b9c539dc3f0616222406721 (diff)
resolver: fix part of bug 1468:
"gethostbyname() fails if DNS server returns more than 23 addresses"
Diffstat (limited to 'libc/inet/resolv.c')
-rw-r--r--libc/inet/resolv.c27
1 files changed, 20 insertions, 7 deletions
diff --git a/libc/inet/resolv.c b/libc/inet/resolv.c
index 5b39e3ffa..d806a9dc9 100644
--- a/libc/inet/resolv.c
+++ b/libc/inet/resolv.c
@@ -328,7 +328,7 @@ extern int __decode_question(const unsigned char * const message, int offset,
extern int __encode_answer(struct resolv_answer * a,
unsigned char * dest, int maxlen) attribute_hidden;
extern int __decode_answer(const unsigned char * message, int offset,
- struct resolv_answer * a) attribute_hidden;
+ int len, struct resolv_answer * a) attribute_hidden;
extern int __length_question(const unsigned char * const message, int offset) attribute_hidden;
extern void __open_nameservers(void) attribute_hidden;
extern void __close_nameservers(void) attribute_hidden;
@@ -588,18 +588,25 @@ int attribute_hidden __encode_answer(struct resolv_answer *a, unsigned char *des
#ifdef L_decodea
int attribute_hidden __decode_answer(const unsigned char *message, int offset,
- struct resolv_answer *a)
+ int len, struct resolv_answer *a)
{
char temp[256];
int i;
+ DPRINTF("decode_answer(start): off %d, len %d\n", offset, len);
i = __decode_dotted(message, offset, temp, sizeof(temp));
if (i < 0)
return i;
message += offset + i;
+ len -= i + RRFIXEDSZ + offset;
+ if (len < 0) {
+ DPRINTF("decode_answer: off %d, len %d, i %d\n", offset, len, i);
+ return len;
+ }
- a->dotted = strdup(temp); /* TODO: what if this fails? */
+// TODO: what if strdup fails?
+ a->dotted = strdup(temp);
a->atype = (message[0] << 8) | message[1];
message += 2;
a->aclass = (message[0] << 8) | message[1];
@@ -614,6 +621,8 @@ int attribute_hidden __decode_answer(const unsigned char *message, int offset,
DPRINTF("i=%d,rdlength=%d\n", i, a->rdlength);
+ if (len < a->rdlength)
+ return -1;
return i + RRFIXEDSZ + a->rdlength;
}
#endif
@@ -940,11 +949,15 @@ int attribute_hidden __dns_lookup(const char *name, int type, int nscount, char
DPRINTF("Decoding answer at pos %d\n", pos);
first_answer = 1;
- for (j = 0; j < h.ancount; j++, pos += i) {
- i = __decode_answer(packet, pos, &ma);
+ for (j = 0; j < h.ancount && pos < len; j++, pos += i) {
+ i = __decode_answer(packet, pos, len, &ma);
if (i < 0) {
DPRINTF("failed decode %d\n", i);
+ /* if the message was truncated and we have
+ decoded some answers, pretend it's OK */
+ if (j && h.tc)
+ break;
goto again;
}
@@ -998,7 +1011,7 @@ int attribute_hidden __dns_lookup(const char *name, int type, int nscount, char
return len; /* success! */
- tryall:
+ tryall:
/* if there are other nameservers, give them a go,
otherwise return with error */
variant = -1;
@@ -1008,7 +1021,7 @@ int attribute_hidden __dns_lookup(const char *name, int type, int nscount, char
continue;
- again:
+ again:
/* if there are searchdomains, try them or fallback as passed */
if (!ends_with_dot) {
int sdomains;