int mesg_dname_cmp (u_char *msg, u_char *dname_mesg, u_char *dname) { /* * compare dname_mesg and dname label by label, while doing * decompression of the dname_mesg of the message msg. */ dname_mesg = dname_redirect (dname_mesg, msg); while (*dname_mesg != '\0' && (*dname == *dname_mesg)) { int len; len = labellen(dname_mesg); if (len != labellen(dname)) return -1; if (*dname == EDNS0_ELT_BITLABEL) { if (memcmp (dname_mesg + 1, dname + 1, len)) return -1; } else if (strncasecmp (dname_mesg + 1, dname + 1, len)) return -1; dname += len + 1; dname_mesg += len + 1; dname_mesg = dname_redirect (dname_mesg, msg); } if (*dname != *dname_mesg) return -1; else return 0; }
u_char *mesg_skip_dname (u_char *dname, u_char *end) { int l; if (dname >= end) return NULL; while(*dname) { if ((*dname & DNCMP_MASK) == DNCMP_MASK) { dname += 2; /* redirection */ return dname; } if (dname + 2 > end) /* we need at least 2 bytes */ return NULL; l = labellen(dname); if (l < 0) return NULL; dname += l + 1; if (dname >= end) return NULL; } dname++; /* push away null terminator */ return dname; }
/* * ns_name_skip(ptrptr, eom) * Advance *ptrptr to skip over the compressed name it points at. * return: * 0 on success, -1 (with errno set) on failure. */ static int irc_ns_name_skip(const unsigned char **ptrptr, const unsigned char *eom) { const unsigned char *cp; unsigned int n; int l; cp = *ptrptr; while (cp < eom && (n = *cp++) != 0) { /* Check for indirection. */ switch (n & NS_CMPRSFLGS) { case 0: /* normal case, n == len */ cp += n; continue; case NS_TYPE_ELT: /* EDNS0 extended label */ if ((l = labellen(cp - 1)) < 0) { errno = EMSGSIZE; /* XXX */ return (-1); } cp += l; continue; case NS_CMPRSFLGS: /* indirection */ cp++; break; default: /* illegal type */ errno = EMSGSIZE; return (-1); } break; } if (cp > eom) { errno = EMSGSIZE; return (-1); } *ptrptr = cp; return (0); } /*2*/
int ns_name_ntol(const u_char *src, u_char *dst, size_t dstsiz) { const u_char *cp; u_char *dn, *eom; u_char c; u_int n; int l; cp = src; dn = dst; eom = dst + dstsiz; if (dn >= eom) { errno = EMSGSIZE; return (-1); } while ((n = *cp++) != 0) { if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) { /* Some kind of compression pointer. */ errno = EMSGSIZE; return (-1); } *dn++ = n; if ((l = labellen(cp - 1)) < 0) { errno = EMSGSIZE; return (-1); } if (dn + l >= eom) { errno = EMSGSIZE; return (-1); } for ((void)NULL; l > 0; l--) { c = *cp++; if (isupper(c)) *dn++ = tolower(c); else *dn++ = c; } } *dn++ = '\0'; return (dn - dst); }
/* * irc_ns_name_ntop(src, dst, dstsiz) * Convert an encoded domain name to printable ascii as per RFC1035. * return: * Number of bytes written to buffer, or -1 (with errno set) * notes: * The root is returned as "." * All other domains are returned in non absolute form */ static int irc_ns_name_ntop(const char *src, char *dst, size_t dstsiz) { const char *cp; char *dn, *eom; unsigned char c; unsigned int n; int l; cp = src; dn = dst; eom = dst + dstsiz; while ((n = *cp++) != 0) { if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) { /* Some kind of compression pointer. */ errno = EMSGSIZE; return (-1); } if (dn != dst) { if (dn >= eom) { errno = EMSGSIZE; return (-1); } *dn++ = '.'; } if ((l = labellen((const unsigned char*)(cp - 1))) < 0) { errno = EMSGSIZE; /* XXX */ return(-1); } if (dn + l >= eom) { errno = EMSGSIZE; return (-1); } if ((n & NS_CMPRSFLGS) == NS_TYPE_ELT) { int m; if (n != DNS_LABELTYPE_BITSTRING) { /* XXX: labellen should reject this case */ errno = EINVAL; return(-1); } if ((m = irc_decode_bitstring(&cp, dn, eom)) < 0) { errno = EMSGSIZE; return(-1); } dn += m; continue; } for ((void)NULL; l > 0; l--) { c = *cp++; if (special(c)) { if (dn + 1 >= eom) { errno = EMSGSIZE; return (-1); } *dn++ = '\\'; *dn++ = (char)c; } else if (!printable(c)) { if (dn + 3 >= eom) { errno = EMSGSIZE; return (-1); } *dn++ = '\\'; *dn++ = digits[c / 100]; *dn++ = digits[(c % 100) / 10]; *dn++ = digits[c % 10]; } else { if (dn >= eom) { errno = EMSGSIZE; return (-1); } *dn++ = (char)c; } } } if (dn == dst) { if (dn >= eom) { errno = EMSGSIZE; return (-1); } *dn++ = '.'; } if (dn >= eom) { errno = EMSGSIZE; return (-1); } *dn++ = '\0'; return (dn - dst); }
/* * irc_ns_name_unpack(rmsg, eom, src, dst, dstsiz) * Unpack a domain name from a message, source may be compressed. * return: * -1 if it fails, or consumed octets if it succeeds. */ static int irc_ns_name_unpack(const unsigned char *rmsg, const unsigned char *eom, const unsigned char *src, unsigned char *dst, size_t dstsiz) { const unsigned char *srcp, *dstlim; unsigned char *dstp; int n, len, checked, l; len = -1; checked = 0; dstp = dst; srcp = src; dstlim = dst + dstsiz; if (srcp < rmsg || srcp >= eom) { errno = EMSGSIZE; return (-1); } /* Fetch next label in domain name. */ while ((n = *srcp++) != 0) { /* Check for indirection. */ switch (n & NS_CMPRSFLGS) { case 0: case NS_TYPE_ELT: /* Limit checks. */ if ((l = labellen(srcp - 1)) < 0) { errno = EMSGSIZE; return(-1); } if (dstp + l + 1 >= dstlim || srcp + l >= eom) { errno = EMSGSIZE; return (-1); } checked += l + 1; *dstp++ = n; memcpy(dstp, srcp, l); dstp += l; srcp += l; break; case NS_CMPRSFLGS: if (srcp >= eom) { errno = EMSGSIZE; return (-1); } if (len < 0) len = srcp - src + 1; srcp = rmsg + (((n & 0x3f) << 8) | (*srcp & 0xff)); if (srcp < rmsg || srcp >= eom) { /* Out of range. */ errno = EMSGSIZE; return (-1); } checked += 2; /* * Check for loops in the compressed name; * if we've looked at the whole message, * there must be a loop. */ if (checked >= eom - rmsg) { errno = EMSGSIZE; return (-1); } break; default: errno = EMSGSIZE; return (-1); /* flag error */ } } *dstp = '\0'; if (len < 0) len = srcp - src; return (len); }
u_char *dname_decompress (u_char *buf, int buflen, u_char *dname, u_char *m_head, u_char *m_tail, int *written) { int token_len, written_len, iter; u_char *cp, *next; int pktsiz = m_tail - m_head; next = NULL; written_len = token_len = 0; for (cp = dname; *cp; cp += token_len) { iter = 0; top: if ((*cp & DNCMP_MASK) == DNCMP_MASK) { uint16_t ui; if (iter++ >= pktsiz) /* we're probably in a loop. */ return NULL; if (!m_head || !m_tail) /* irregular redirect */ return NULL; /* redirect */ next = cp + 2; GETSHORT (ui, cp); ui = ui & ~DNCMP_MASK_INT16T; cp = m_head + ui; if (cp < m_head || m_tail < cp) return NULL; goto top; } token_len = labellen(cp); if (token_len < 0) return NULL; else token_len++; if (T.debug > 4) syslog (LOG_DEBUG, "token_len: %d", token_len); if (written_len + token_len >= buflen) return NULL; /* buffer overrun */ if (cp + token_len > m_tail) return NULL; /* out of bounds */ if (written) { /* non-printable dname string */ memcpy (buf, cp, token_len); written_len += token_len; buf += token_len; } else { /* write printable string */ if ((*cp & DNCMP_MASK) != EDNS0_MASK) { memcpy (buf, cp + 1, token_len - 1); *(buf + (token_len - 1)) = DNAME_DELIM; written_len += token_len; buf += token_len; } else if (*cp == EDNS0_ELT_BITLABEL) { int bitlength, i; u_char *wp; /* a bit conservative test, but simple */ if (written_len + token_len*2 + 7 >= buflen) return NULL; /* buffer overrun */ wp = buf; wp += sprintf(wp, "\\[x"); for (i = 1; i < token_len-1; i++) { u_char d1, d2; uint b; b = (int) *(cp + 1 + i); d1 = hex[(b >> 4) & 0x0f]; d2 = hex[b & 0x0f]; wp += sprintf(wp, "%c%c", d1, d2); } bitlength = *(cp + 1) ? *(cp + 1) : 256; wp += sprintf(wp, "/%u].", bitlength); written_len += (wp - buf); buf += written_len; } } }
/*% * Pack domain name 'domain' into 'comp_dn'. * * return: *\li Size of the compressed name, or -1. * * notes: *\li 'dnptrs' is an array of pointers to previous compressed names. *\li dnptrs[0] is a pointer to the beginning of the message. The array * ends with NULL. *\li 'lastdnptr' is a pointer to the end of the array pointed to * by 'dnptrs'. * * Side effects: *\li The list of pointers in dnptrs is updated for labels inserted into * the message as we compress the name. If 'dnptr' is NULL, we don't * try to compress names. If 'lastdnptr' is NULL, we don't update the * list. */ 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 { int l0; n = *srcp; if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) { errno = EMSGSIZE; return (-1); } if ((l0 = labellen(srcp)) < 0) { errno = EINVAL; return(-1); } l += l0 + 1; if (l > MAXCDNAME) { errno = EMSGSIZE; return (-1); } srcp += l0 + 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 && 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) == NS_CMPRSFLGS) { /* Should not happen. */ goto cleanup; } n = labellen(srcp); if (dstp + 1 + n >= eob) { goto cleanup; } memcpy(dstp, srcp, n + 1); srcp += n + 1; dstp += n + 1; } while (n != 0);