diff -Naur mtr-0.69.old/dns.c mtr-0.69.new/dns.c --- mtr-0.69.old/dns.c 2005-01-11 09:32:42.000000000 +0100 +++ mtr-0.69.new/dns.c 2005-10-03 21:31:27.000000000 +0200 @@ -853,6 +853,507 @@ fputs("\r",stderr); } +#ifdef __UCLIBC__ + +static const char digits[] = "0123456789"; +#define __set_errno(e) (errno = (e)) + +#define NS_PUT16(s, cp) do { \ + register u_int16_t t_s = (u_int16_t)(s); \ + register u_char *t_cp = (u_char *)(cp); \ + *t_cp++ = t_s >> 8; \ + *t_cp = t_s; \ + (cp) += NS_INT16SZ; \ +} while (0) + + + +#define NS_PUT32(l, cp) do { \ + register u_int32_t t_l = (u_int32_t)(l); \ + register u_char *t_cp = (u_char *)(cp); \ + *t_cp++ = t_l >> 24; \ + *t_cp++ = t_l >> 16; \ + *t_cp++ = t_l >> 8; \ + *t_cp = t_l; \ + (cp) += NS_INT32SZ; \ +} while (0) + + +void +ns_put16(u_int src, u_char *dst) { + NS_PUT16(src, dst); +} + +void +ns_put32(u_long src, u_char *dst) { + NS_PUT32(src, dst); +} + +void __putshort(u_int16_t src, u_char *dst) { ns_put16(src, dst); } +void __putlong(u_int32_t src, u_char *dst) { ns_put32(src, dst); } + +int +mklower(int ch) { + if (ch >= 0x41 && ch <= 0x5A) + return (ch + 0x20); + return (ch); +} + + +static int +dn_find(const u_char *domain, const u_char *msg, + const u_char * const *dnptrs, + const u_char * const *lastdnptr) +{ + const u_char *dn, *cp, *sp; + const u_char * const *cpp; + u_int n; + + for (cpp = dnptrs; cpp < lastdnptr; cpp++) { + sp = *cpp; + /* + * terminate search on: + * root label + * compression pointer + * unusable offset + */ + while (*sp != 0 && (*sp & NS_CMPRSFLGS) == 0 && + (sp - msg) < 0x4000) { + dn = domain; + cp = sp; + while ((n = *cp++) != 0) { + /* + * check for indirection + */ + switch (n & NS_CMPRSFLGS) { + case 0: /* normal case, n == len */ + if (n != *dn++) + goto next; + for ((void)NULL; n > 0; n--) + if (mklower(*dn++) != + mklower(*cp++)) + goto next; + /* Is next root for both ? */ + if (*dn == '\0' && *cp == '\0') + return (sp - msg); + if (*dn) + continue; + goto next; + + case NS_CMPRSFLGS: /* indirection */ + cp = msg + (((n & 0x3f) << 8) | *cp); + break; + + default: /* illegal type */ + __set_errno (EMSGSIZE); + return (-1); + } + } + next: + sp += *sp + 1; + } + } + __set_errno (ENOENT); + return (-1); +} + + +int +ns_name_pack(const u_char *src, u_char *dst, int dstsiz, + const u_char **dnptrs, const u_char **lastdnptr) +{ + u_char *dstp; + const u_char **cpp, **lpp, *eob, *msg; + const u_char *srcp; + int n, l, first = 1; + + srcp = src; + dstp = dst; + eob = dstp + dstsiz; + lpp = cpp = NULL; + if (dnptrs != NULL) { + if ((msg = *dnptrs++) != NULL) { + for (cpp = dnptrs; *cpp != NULL; cpp++) + (void)NULL; + lpp = cpp; /* end of list to search */ + } + } else + msg = NULL; + + /* make sure the domain we are about to add is legal */ + l = 0; + do { + n = *srcp; + if ((n & NS_CMPRSFLGS) != 0 && n != 0x41) { + __set_errno (EMSGSIZE); + return (-1); + } + if (n == 0x41) + n = *++srcp / 8; + l += n + 1; + if (l > MAXCDNAME) { + __set_errno (EMSGSIZE); + return (-1); + } + srcp += n + 1; + } while (n != 0); + + /* from here on we need to reset compression pointer array on error */ + srcp = src; + do { + /* Look to see if we can use pointers. */ + n = *srcp; + if (n != 0 && n != 0x41 && msg != NULL) { + l = dn_find(srcp, msg, (const u_char * const *)dnptrs, + (const u_char * const *)lpp); + if (l >= 0) { + if (dstp + 1 >= eob) { + goto cleanup; + } + *dstp++ = (l >> 8) | NS_CMPRSFLGS; + *dstp++ = l % 256; + return (dstp - dst); + } + /* Not found, save it. */ + if (lastdnptr != NULL && cpp < lastdnptr - 1 && + (dstp - msg) < 0x4000 && first) { + *cpp++ = dstp; + *cpp = NULL; + first = 0; + } + } + /* copy label to buffer */ + if ((n & NS_CMPRSFLGS) != 0 && n != 0x41) { /* Should not happen. */ + goto cleanup; + } + if (n == 0x41) { + n = *++srcp / 8; + if (dstp + 1 >= eob) + goto cleanup; + *dstp++ = 0x41; + } + if (dstp + 1 + n >= eob) { + goto cleanup; + } + memcpy(dstp, srcp, n + 1); + srcp += n + 1; + dstp += n + 1; + } while (n != 0); + + if (dstp > eob) { +cleanup: + if (msg != NULL) + *lpp = NULL; + __set_errno (EMSGSIZE); + return (-1); + } + return (dstp - dst); +} + + +int +ns_name_pton(const char *src, u_char *dst, size_t dstsiz) { + u_char *label, *bp, *eom; + int c, n, escaped; + char *cp; + + escaped = 0; + bp = dst; + eom = dst + dstsiz; + label = bp++; + + while ((c = *src++) != 0) { + if (escaped) { + if ((cp = strchr(digits, c)) != NULL) { + n = (cp - digits) * 100; + if ((c = *src++) == 0 || + (cp = strchr(digits, c)) == NULL) { + __set_errno (EMSGSIZE); + return (-1); + } + n += (cp - digits) * 10; + if ((c = *src++) == 0 || + (cp = strchr(digits, c)) == NULL) { + __set_errno (EMSGSIZE); + return (-1); + } + n += (cp - digits); + if (n > 255) { + __set_errno (EMSGSIZE); + return (-1); + } + c = n; + } else if (c == '[' && label == bp - 1 && *src == 'x') { + /* Theoretically we would have to handle \[o + as well but we do not since we do not need + it internally. */ + *label = 0x41; + label = bp++; + ++src; + while (isxdigit (*src)) { + n = *src > '9' ? *src - 'a' + 10 : *src - '0'; + ++src; + if (! isxdigit(*src)) { + __set_errno (EMSGSIZE); + return (-1); + } + n <<= 4; + n += *src > '9' ? *src - 'a' + 10 : *src - '0'; + if (bp + 1 >= eom) { + __set_errno (EMSGSIZE); + return (-1); + } + *bp++ = n; + ++src; + } + *label = (bp - label - 1) * 8; + if (*src++ != ']' || *src++ != '.') { + __set_errno (EMSGSIZE); + return (-1); + } + escaped = 0; + label = bp++; + if (bp >= eom) { + __set_errno (EMSGSIZE); + return (-1); + } + continue; + } + escaped = 0; + } else if (c == '\\') { + escaped = 1; + continue; + } else if (c == '.') { + c = (bp - label - 1); + if ((c & NS_CMPRSFLGS) != 0) { /* Label too big. */ + __set_errno (EMSGSIZE); + return (-1); + } + if (label >= eom) { + __set_errno (EMSGSIZE); + return (-1); + } + *label = c; + /* Fully qualified ? */ + if (*src == '\0') { + if (c != 0) { + if (bp >= eom) { + __set_errno (EMSGSIZE); + return (-1); + } + *bp++ = '\0'; + } + if ((bp - dst) > MAXCDNAME) { + __set_errno (EMSGSIZE); + return (-1); + } + return (1); + } + if (c == 0 || *src == '.') { + __set_errno (EMSGSIZE); + return (-1); + } + label = bp++; + continue; + } + if (bp >= eom) { + __set_errno (EMSGSIZE); + return (-1); + } + *bp++ = (u_char)c; + } + c = (bp - label - 1); + if ((c & NS_CMPRSFLGS) != 0) { /* Label too big. */ + __set_errno (EMSGSIZE); + return (-1); + } + if (label >= eom) { + __set_errno (EMSGSIZE); + return (-1); + } + *label = c; + if (c != 0) { + if (bp >= eom) { + __set_errno (EMSGSIZE); + return (-1); + } + *bp++ = 0; + } + if ((bp - dst) > MAXCDNAME) { /* src too big */ + __set_errno (EMSGSIZE); + return (-1); + } + return (0); +} + + + +int +ns_name_compress(const char *src, u_char *dst, size_t dstsiz, + const u_char **dnptrs, const u_char **lastdnptr) +{ + u_char tmp[NS_MAXCDNAME]; + + if (ns_name_pton(src, tmp, sizeof tmp) == -1) + return (-1); + return (ns_name_pack(tmp, dst, dstsiz, dnptrs, lastdnptr)); +} + + +int +dn_comp(const char *src, u_char *dst, int dstsiz, + u_char **dnptrs, u_char **lastdnptr) +{ + return (ns_name_compress(src, dst, (size_t)dstsiz, + (const u_char **)dnptrs, + (const u_char **)lastdnptr)); +} + + + + +int +res_nmkquery(res_state statp, + int op, /* opcode of query */ + const char *dname, /* domain name */ + int class, int type, /* class and type of query */ + const u_char *data, /* resource record data */ + int datalen, /* length of data */ + const u_char *newrr_in, /* new rr for modify or append */ + u_char *buf, /* buffer to put query */ + int buflen) /* size of buffer */ +{ + register HEADER *hp; + register u_char *cp; + register int n; + u_char *dnptrs[20], **dpp, **lastdnptr; + +#ifdef DEBUG + if (statp->options & RES_DEBUG) + printf(";; res_nmkquery(%s, %s, %s, %s)\n", + _res_opcodes[op], dname, p_class(class), p_type(type)); +#endif + /* + * Initialize header fields. + */ + if ((buf == NULL) || (buflen < HFIXEDSZ)) + return (-1); + memset(buf, 0, HFIXEDSZ); + hp = (HEADER *) buf; + /* We randomize the IDs every time. The old code just + incremented by one after the initial randomization which + still predictable if the application does multiple + requests. */ +#if 0 + hp->id = htons(++statp->id); +#else + hp->id = htons(statp->id); + int randombits; + do + { +#ifdef RANDOM_BITS + RANDOM_BITS (randombits); +#else + struct timeval tv; + gettimeofday (&tv, NULL); + randombits = (tv.tv_sec << 8) ^ tv.tv_usec; +#endif + } + while ((randombits & 0xffff) == 0); + statp->id = (statp->id + randombits) & 0xffff; +#endif + hp->opcode = op; + hp->rd = (statp->options & RES_RECURSE) != 0; + hp->rcode = NOERROR; + cp = buf + HFIXEDSZ; + buflen -= HFIXEDSZ; + dpp = dnptrs; + *dpp++ = buf; + *dpp++ = NULL; + lastdnptr = dnptrs + sizeof dnptrs / sizeof dnptrs[0]; + /* + * perform opcode specific processing + */ + switch (op) { + case QUERY: /*FALLTHROUGH*/ + case NS_NOTIFY_OP: + if ((buflen -= QFIXEDSZ) < 0) + return (-1); + if ((n = dn_comp(dname, cp, buflen, dnptrs, lastdnptr)) < 0) + return (-1); + cp += n; + buflen -= n; + __putshort(type, cp); + cp += INT16SZ; + __putshort(class, cp); + cp += INT16SZ; + hp->qdcount = htons(1); + if (op == QUERY || data == NULL) + break; + /* + * Make an additional record for completion domain. + */ + buflen -= RRFIXEDSZ; + n = dn_comp((char *)data, cp, buflen, dnptrs, lastdnptr); + if (n < 0) + return (-1); + cp += n; + buflen -= n; + __putshort(T_NULL, cp); + cp += INT16SZ; + __putshort(class, cp); + cp += INT16SZ; + __putlong(0, cp); + cp += INT32SZ; + __putshort(0, cp); + cp += INT16SZ; + hp->arcount = htons(1); + break; + + case IQUERY: + /* + * Initialize answer section + */ + if (buflen < 1 + RRFIXEDSZ + datalen) + return (-1); + *cp++ = '\0'; /* no domain name */ + __putshort(type, cp); + cp += INT16SZ; + __putshort(class, cp); + cp += INT16SZ; + __putlong(0, cp); + cp += INT32SZ; + __putshort(datalen, cp); + cp += INT16SZ; + if (datalen) { + memcpy(cp, data, datalen); + cp += datalen; + } + hp->ancount = htons(1); + break; + + default: + return (-1); + } + return (cp - buf); +} + +int +res_mkquery(int op, /* opcode of query */ + const char *dname, /* domain name */ + int class, int type, /* class and type of query */ + const u_char *data, /* resource record data */ + int datalen, /* length of data */ + const u_char *newrr_in, /* new rr for modify or append */ + u_char *buf, /* buffer to put query */ + int buflen) /* size of buffer */ +{ + return (res_nmkquery(&_res, op, dname, class, type, + data, datalen, + newrr_in, buf, buflen)); +} + +#endif void dorequest(char *s,int type,word id) {