diff options
Diffstat (limited to 'libc/inet/resolv.c')
-rw-r--r-- | libc/inet/resolv.c | 195 |
1 files changed, 195 insertions, 0 deletions
diff --git a/libc/inet/resolv.c b/libc/inet/resolv.c index 6bfe52c79..011cd5e56 100644 --- a/libc/inet/resolv.c +++ b/libc/inet/resolv.c @@ -3886,6 +3886,201 @@ void ns_put32(unsigned long src, unsigned char *dst) } #endif /* L_ns_netint */ +#ifdef L_ns_parse +/* These need to be in the same order as the nres.h:ns_flag enum. */ +const struct _ns_flagdata _ns_flagdata[16] = { + { 0x8000, 15 }, /*%< qr. */ + { 0x7800, 11 }, /*%< opcode. */ + { 0x0400, 10 }, /*%< aa. */ + { 0x0200, 9 }, /*%< tc. */ + { 0x0100, 8 }, /*%< rd. */ + { 0x0080, 7 }, /*%< ra. */ + { 0x0040, 6 }, /*%< z. */ + { 0x0020, 5 }, /*%< ad. */ + { 0x0010, 4 }, /*%< cd. */ + { 0x000f, 0 }, /*%< rcode. */ + { 0x0000, 0 }, /*%< expansion (1/6). */ + { 0x0000, 0 }, /*%< expansion (2/6). */ + { 0x0000, 0 }, /*%< expansion (3/6). */ + { 0x0000, 0 }, /*%< expansion (4/6). */ + { 0x0000, 0 }, /*%< expansion (5/6). */ + { 0x0000, 0 }, /*%< expansion (6/6). */ +}; + +static void setsection(ns_msg *msg, ns_sect sect) +{ + msg->_sect = sect; + if (sect == ns_s_max) { + msg->_rrnum = -1; + msg->_ptr = NULL; + } else { + msg->_rrnum = 0; + msg->_ptr = msg->_sections[(int)sect]; + } +} + +int ns_skiprr(const unsigned char *ptr, + const unsigned char *eom, + ns_sect section, int count) +{ + const u_char *optr = ptr; + + for (; count > 0; count--) { + int b, rdlength; + + b = dn_skipname(ptr, eom); + if (b < 0) { + errno = EMSGSIZE; + return -1; + } + + ptr += b/*Name*/ + NS_INT16SZ/*Type*/ + NS_INT16SZ/*Class*/; + if (section != ns_s_qd) { + if (ptr + NS_INT32SZ + NS_INT16SZ > eom) { + errno = EMSGSIZE; + return -1; + } + + ptr += NS_INT32SZ/*TTL*/; + NS_GET16(rdlength, ptr); + ptr += rdlength/*RData*/; + } + } + + if (ptr > eom) { + errno = EMSGSIZE; + return -1; + } + + return ptr - optr; +} + +int +ns_initparse(const unsigned char *msg, int msglen, ns_msg *handle) +{ + const u_char *eom = msg + msglen; + int i; + + handle->_msg = msg; + handle->_eom = eom; + if (msg + NS_INT16SZ > eom) { + errno = EMSGSIZE; + return -1; + } + + NS_GET16(handle->_id, msg); + if (msg + NS_INT16SZ > eom) { + errno = EMSGSIZE; + return -1; + } + + NS_GET16(handle->_flags, msg); + for (i = 0; i < ns_s_max; i++) { + if (msg + NS_INT16SZ > eom) { + errno = EMSGSIZE; + return -1; + } + + NS_GET16(handle->_counts[i], msg); + } + for (i = 0; i < ns_s_max; i++) + if (handle->_counts[i] == 0) + handle->_sections[i] = NULL; + else { + int b = ns_skiprr(msg, eom, (ns_sect)i, + handle->_counts[i]); + + if (b < 0) + return -1; + handle->_sections[i] = msg; + msg += b; + } + + if (msg != eom) { + errno = EMSGSIZE; + return -1; + } + + setsection(handle, ns_s_max); + return 0; +} + +int +ns_parserr(ns_msg *handle, ns_sect section, int rrnum, ns_rr *rr) +{ + int b; + int tmp; + + /* Make section right. */ + tmp = section; + if (tmp < 0 || section >= ns_s_max) { + errno = ENODEV; + return -1; + } + + if (section != handle->_sect) + setsection(handle, section); + + /* Make rrnum right. */ + if (rrnum == -1) + rrnum = handle->_rrnum; + if (rrnum < 0 || rrnum >= handle->_counts[(int)section]) { + errno = ENODEV; + return -1; + } + if (rrnum < handle->_rrnum) + setsection(handle, section); + if (rrnum > handle->_rrnum) { + b = ns_skiprr(handle->_ptr, handle->_eom, section, + rrnum - handle->_rrnum); + + if (b < 0) + return (-1); + handle->_ptr += b; + handle->_rrnum = rrnum; + } + + /* Do the parse. */ + b = dn_expand(handle->_msg, handle->_eom, + handle->_ptr, rr->name, NS_MAXDNAME); + if (b < 0) + return (-1); + handle->_ptr += b; + if (handle->_ptr + NS_INT16SZ + NS_INT16SZ > handle->_eom) { + errno = EMSGSIZE; + return -1; + } + NS_GET16(rr->type, handle->_ptr); + NS_GET16(rr->rr_class, handle->_ptr); + if (section == ns_s_qd) { + rr->ttl = 0; + rr->rdlength = 0; + rr->rdata = NULL; + } else { + if (handle->_ptr + NS_INT32SZ + NS_INT16SZ > handle->_eom) { + errno = EMSGSIZE; + return -1; + } + NS_GET32(rr->ttl, handle->_ptr); + NS_GET16(rr->rdlength, handle->_ptr); + if (handle->_ptr + rr->rdlength > handle->_eom) { + errno = EMSGSIZE; + return -1; + } + rr->rdata = handle->_ptr; + handle->_ptr += rr->rdlength; + } + if (++handle->_rrnum > handle->_counts[(int)section]) + setsection(handle, (ns_sect)((int)section + 1)); + + return 0; +} + +int ns_msg_getflag(ns_msg handle, int flag) { + return ((handle)._flags & _ns_flagdata[flag].mask) >> _ns_flagdata[flag].shift; +} +#endif /* L_ns_parse */ + /* Unimplemented: */ /* res_mkquery */ /* res_send */ |