diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2008-11-01 23:24:00 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2008-11-01 23:24:00 +0000 |
commit | f09a1461fe8f3511750ad91f164b2769225858f5 (patch) | |
tree | 6d05d5b6ca6bcd3cba1f4e2f13d9a555572e8388 /libc/inet/resolv.c | |
parent | c040a39eb5c792434b9c539dc3f0616222406721 (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.c | 27 |
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; |