static int write_dname (u_char *msg, u_char *msg_tail, uint16_t *dnames,
		      int dnames_len, u_char *dname, u_char *wp) {
	char *fn = "write_dname()";
	u_char *bestmatch_rpd = NULL;
	u_char *bestmatch_rpm = NULL;
	int bestmatch_len;
	u_char *rpd, *rpm;
	int written_len;

	if (T.debug > 4)
		syslog (LOG_DEBUG, "%s: start", fn);

	/*
	 * Check if some (part of) dname has already appeared in message
	 * 
	 * Start with full name, and chop first name label off for each
	 * iteration.
	 */
	bestmatch_len = 0;
	for (rpd = dname; *rpd && !bestmatch_len; rpd += labellen(rpd) + 1) {
		int i;

		/*
		 * The dnames array contains a list of pointers to domainnames
		 * in the message that we will try to match our name against.
		 */
		for (i = 0; dnames[i] != 0 && i < dnames_len; i++) {
			/*
	 		 * Again, start with full name, and chop first name label
			 * off for each iteration. Meanwhile, we follow
			 * redirections.
			 */
			for (rpm = dname_redirect (msg + dnames[i], msg); *rpm;
			     rpm = dname_redirect (labellen(rpm)+rpm+1, msg)) {
				u_char *cpd, *cpm;
				int match_len;

				if (rpm < msg || msg_tail < rpm)
					return -1; /* out of bounds */

				/* comparison pointers */
				cpd = rpd;
				cpm = rpm;

				match_len = 0;
				while (*cpm && *cpm == *cpd) {
					int mlen;

					mlen = labellen(cpm);
					if (mlen != labellen(cpd))
						break;

					/* binary comparison */
					if (*cpm == EDNS0_ELT_BITLABEL &&
					    memcmp (cpm+1, cpd+1, mlen))
							break;

					/* case-insensitive comparison */
					if (*cpm != EDNS0_ELT_BITLABEL &&
					    strncasecmp ((const char *)cpm+1, 
                                                         (const char *)cpd+1, 
                                                         *cpm))
						break;
					
					/* a label matched, move to next one */
					cpm += mlen + 1;
					cpd += mlen + 1;

					/* check redirection */
					cpm = dname_redirect (cpm, msg);
					if (cpm < msg || msg_tail < cpm)
						return -1; /* out of bounds */

					match_len++;
				}

				/*
				 * matched parts have to be postfixes, i.e.
				 * both need to be NULL terminated. We record
				 * the match if it is better than the best one
				 * we found so far.
				 */
				if (*cpm == '\0' && *cpd == '\0' &&
				    match_len > bestmatch_len) {
					bestmatch_rpd = rpd;
					bestmatch_rpm = rpm;
					bestmatch_len = match_len;
				}
			}
		}
	}

	/* register this name if not complete match */
	if (bestmatch_rpd != dname) {
		int i;
		/* we didn't find ourselves */
		for (i = 0; dnames[i] != 0; i++);

		if (i + 1 < dnames_len) {
			/* we still have room for one more in the table */
			if (((uint16_t) (bestmatch_rpm - msg)
			    < DNCMP_REDIRECT_LIMIT)) {
				/* It is within range */

				dnames[i] = (uint16_t) (wp - msg);
				dnames[i + 1] = 0;
			}
		}
	}

	/* write dname */
	written_len = 0;
	rpd = dname;

	/* write first unique part */
	while (*rpd && rpd != bestmatch_rpd) {
		int i;

		i = labellen(rpd) + 1;
		if (wp + i > msg_tail)
			return -1; /* overflow! */

		memcpy (wp, rpd, i);
		written_len += i;
		rpd += i;
		wp += i;
	}

	/* write second redirected part, if any found, or terminate */
	if (rpd == bestmatch_rpd) {
		uint16_t us;

		/* write redirection pointer */
		if (wp + sizeof (uint16_t) > msg_tail)
			return -1; /* overflow */

		us = (uint16_t) (bestmatch_rpm - msg) | DNCMP_MASK_INT16T;
		PUTSHORT (us, wp);
		written_len += sizeof (uint16_t);
	} else {
		*wp = '\0';
		written_len++;
	}

	if (T.debug > 4)
		syslog (LOG_DEBUG, "%s: return (written_len = %d)",
			fn, written_len);

	return written_len;
}
static int write_dname (u_char *msg, u_char *msg_tail, uint16_t *dnames,
		      int dnames_len, u_char *dname, u_char *wp) {
	char *fn = "write_dname()";
	u_char *bestmatch_rpd = NULL;
	u_char *bestmatch_rpm = NULL;
	int bestmatch_len;
	u_char *rpd, *rpm;
	int written_len;

	if (T.debug > 4)
		syslog (LOG_DEBUG, "%s: start", fn);

	 
	bestmatch_len = 0;
	for (rpd = dname; *rpd && !bestmatch_len; rpd += labellen(rpd) + 1) {
		int i;

		 
		for (i = 0; dnames[i] != 0 && i < dnames_len; i++) {
			 
			for (rpm = dname_redirect (msg + dnames[i], msg); *rpm;
			     rpm = dname_redirect (labellen(rpm)+rpm+1, msg)) {
				u_char *cpd, *cpm;
				int match_len;

				if (rpm < msg || msg_tail < rpm)
					return -1;  

				 
				cpd = rpd;
				cpm = rpm;

				match_len = 0;
				while (*cpm && *cpm == *cpd) {
					int mlen;

					mlen = labellen(cpm);
					if (mlen != labellen(cpd))
						break;

					 
					if (*cpm == EDNS0_ELT_BITLABEL &&
					    memcmp (cpm+1, cpd+1, mlen))
							break;

					 
					if (*cpm != EDNS0_ELT_BITLABEL &&
					    strncasecmp ((const char *)cpm+1, 
                                                         (const char *)cpd+1, 
                                                         *cpm))
						break;
					
					 
					cpm += mlen + 1;
					cpd += mlen + 1;

					 
					cpm = dname_redirect (cpm, msg);
					if (cpm < msg || msg_tail < cpm)
						return -1;  

					match_len++;
				}

				 
				if (*cpm == '\0' && *cpd == '\0' &&
				    match_len > bestmatch_len) {
					bestmatch_rpd = rpd;
					bestmatch_rpm = rpm;
					bestmatch_len = match_len;
				}
			}
		}
	}

	 
	if (bestmatch_rpd != dname) {
		int i;
		 
		for (i = 0; dnames[i] != 0; i++);

		if (i + 1 < dnames_len) {
			 
			if (((uint16_t) (bestmatch_rpm - msg)
			    < DNCMP_REDIRECT_LIMIT)) {
				 

				dnames[i] = (uint16_t) (wp - msg);
				dnames[i + 1] = 0;
			}
		}
	}

	 
	written_len = 0;
	rpd = dname;

	 
	while (*rpd && rpd != bestmatch_rpd) {
		int i;

		i = labellen(rpd) + 1;
		if (wp + i > msg_tail)
			return -1;  

		memcpy (wp, rpd, i);
		written_len += i;
		rpd += i;
		wp += i;
	}

	 
	if (rpd == bestmatch_rpd) {
		uint16_t us;

		 
		if (wp + sizeof (uint16_t) > msg_tail)
			return -1;  

		us = (uint16_t) (bestmatch_rpm - msg) | DNCMP_MASK_INT16T;
		PUTSHORT (us, wp);
		written_len += sizeof (uint16_t);
	} else {
		*wp = '\0';
		written_len++;
	}

	if (T.debug > 4)
		syslog (LOG_DEBUG, "%s: return (written_len = %d)",
			fn, written_len);

	return written_len;
}