dn_comp.c raw

   1  #include <string.h>
   2  #include <resolv.h>
   3  
   4  /* RFC 1035 message compression */
   5  
   6  /* label start offsets of a compressed domain name s */
   7  static int getoffs(short *offs, const unsigned char *base, const unsigned char *s)
   8  {
   9  	int i=0;
  10  	for (;;) {
  11  		while (*s & 0xc0) {
  12  			if ((*s & 0xc0) != 0xc0) return 0;
  13  			s = base + ((s[0]&0x3f)<<8 | s[1]);
  14  		}
  15  		if (!*s) return i;
  16  		if (s-base >= 0x4000) return 0;
  17  		offs[i++] = s-base;
  18  		s += *s + 1;
  19  	}
  20  }
  21  
  22  /* label lengths of an ascii domain name s */
  23  static int getlens(unsigned char *lens, const char *s, int l)
  24  {
  25  	int i=0,j=0,k=0;
  26  	for (;;) {
  27  		for (; j<l && s[j]!='.'; j++);
  28  		if (j-k-1u > 62) return 0;
  29  		lens[i++] = j-k;
  30  		if (j==l) return i;
  31  		k = ++j;
  32  	}
  33  }
  34  
  35  /* longest suffix match of an ascii domain with a compressed domain name dn */
  36  static int match(int *offset, const unsigned char *base, const unsigned char *dn,
  37  	const char *end, const unsigned char *lens, int nlen)
  38  {
  39  	int l, o, m=0;
  40  	short offs[128];
  41  	int noff = getoffs(offs, base, dn);
  42  	if (!noff) return 0;
  43  	for (;;) {
  44  		l = lens[--nlen];
  45  		o = offs[--noff];
  46  		end -= l;
  47  		if (l != base[o] || memcmp(base+o+1, end, l))
  48  			return m;
  49  		*offset = o;
  50  		m += l;
  51  		if (nlen) m++;
  52  		if (!nlen || !noff) return m;
  53  		end--;
  54  	}
  55  }
  56  
  57  int dn_comp(const char *src, unsigned char *dst, int space, unsigned char **dnptrs, unsigned char **lastdnptr)
  58  {
  59  	int i, j, n, m=0, offset, bestlen=0, bestoff;
  60  	unsigned char lens[127];
  61  	unsigned char **p;
  62  	const char *end;
  63  	size_t l = strnlen(src, 255);
  64  	if (l && src[l-1] == '.') l--;
  65  	if (l>253 || space<=0) return -1;
  66  	if (!l) {
  67  		*dst = 0;
  68  		return 1;
  69  	}
  70  	end = src+l;
  71  	n = getlens(lens, src, l);
  72  	if (!n) return -1;
  73  
  74  	p = dnptrs;
  75  	if (p && *p) for (p++; *p; p++) {
  76  		m = match(&offset, *dnptrs, *p, end, lens, n);
  77  		if (m > bestlen) {
  78  			bestlen = m;
  79  			bestoff = offset;
  80  			if (m == l)
  81  				break;
  82  		}
  83  	}
  84  
  85  	/* encode unmatched part */
  86  	if (space < l-bestlen+2+(bestlen-1 < l-1)) return -1;
  87  	memcpy(dst+1, src, l-bestlen);
  88  	for (i=j=0; i<l-bestlen; i+=lens[j++]+1)
  89  		dst[i] = lens[j];
  90  
  91  	/* add tail */
  92  	if (bestlen) {
  93  		dst[i++] = 0xc0 | bestoff>>8;
  94  		dst[i++] = bestoff;
  95  	} else
  96  		dst[i++] = 0;
  97  
  98  	/* save dst pointer */
  99  	if (i>2 && lastdnptr && dnptrs && *dnptrs) {
 100  		while (*p) p++;
 101  		if (p+1 < lastdnptr) {
 102  			*p++ = dst;
 103  			*p=0;
 104  		}
 105  	}
 106  	return i;
 107  }
 108