1 #ifndef lint 2 static char sccsid[] = "@(#)res_comp.c 4.1 (Berkeley) 03/01/85"; 3 #endif 4 5 #include <sys/types.h> 6 #include <stdio.h> 7 #include <ctype.h> 8 #include <nameser.h> 9 10 11 /* 12 * Expand compressed domain name format to full domain name. 13 * Return size of compressed name or -1 if there was an error. 14 */ 15 dn_expand(msg, comp_dn, exp_dn, length) 16 char *msg, *comp_dn, *exp_dn; 17 int length; 18 { 19 register char *cp, *dn; 20 register int n, c; 21 char *eom; 22 int len = 0; 23 24 dn = exp_dn; 25 cp = comp_dn; 26 eom = exp_dn + length - 1; 27 /* 28 * fetch next label in domain name 29 */ 30 while (n = *cp++) { 31 /* 32 * Check for indirection 33 */ 34 switch (n & INDIR_MASK) { 35 case 0: 36 if (dn != exp_dn) 37 *dn++ = '.'; 38 if (dn+n >= eom) 39 return (-1); 40 while (--n >= 0) 41 if (islower(c = *cp++)) 42 *dn++ = toupper(c); 43 else 44 *dn++ = c; 45 break; 46 47 case INDIR_MASK: 48 if (len == 0) 49 len = cp - comp_dn + 1; 50 cp = msg + (((n & 0x3f) << 8) | (*cp & 0xff)); 51 break; 52 53 default: 54 return (-1); /* flag error */ 55 } 56 } 57 *dn = '\0'; 58 if (len == 0) 59 len = cp - comp_dn; 60 return (len); 61 } 62 63 /* 64 * Compress domain name. Return the size of the compressed name or -1. 65 * Dnptrs is a list of pointers to previous compressed names. dnptrs[0] 66 * is a pointer to the beginning of the message. The list ends with NULL. 67 */ 68 dn_comp(exp_dn, comp_dn, length, dnptrs, lastdnptr) 69 char *exp_dn, *comp_dn; 70 int length; 71 char **dnptrs, **lastdnptr; 72 { 73 register char *cp, *dn; 74 register int c, l; 75 char **cpp, **lpp, *sp, *eob; 76 char *msg; 77 78 dn = exp_dn; 79 cp = comp_dn; 80 eob = comp_dn + length; 81 if (dnptrs != NULL) { 82 if ((msg = *dnptrs++) != NULL) { 83 for (cpp = dnptrs; *cpp != NULL; cpp++) 84 ; 85 lpp = cpp; /* end of list to search */ 86 } 87 } else 88 msg = NULL; 89 for (c = *dn++; c != '\0'; ) { 90 /* look to see if we can use pointers */ 91 if (msg != NULL) { 92 if ((l = dn_find(dn-1, msg, dnptrs, lpp)) >= 0) { 93 if (cp+1 >= eob) 94 return (-1); 95 *cp++ = (l >> 8) | INDIR_MASK; 96 *cp++ = l; 97 return (cp - comp_dn); 98 } 99 /* not found, save it */ 100 if (lastdnptr != NULL && cpp < lastdnptr-1) { 101 *cpp++ = cp; 102 *cpp = NULL; 103 } 104 } 105 sp = cp++; /* save ptr to length byte */ 106 do { 107 if (c == '.') { 108 c = *dn++; 109 break; 110 } 111 if (cp >= eob) 112 return (-1); 113 *cp++ = c; 114 } while ((c = *dn++) != '\0'); 115 if ((l = cp - sp - 1) <= 0 || l > MAXLABEL) 116 return (-1); 117 *sp = l; 118 } 119 if (cp >= eob) 120 return (-1); 121 *cp++ = '\0'; 122 return (cp - comp_dn); 123 } 124 125 /* 126 * Skip over a compressed domain name. Return the size. 127 */ 128 dn_skip(buf) 129 char *buf; 130 { 131 register char *cp; 132 register int n; 133 134 cp = buf; 135 while (n = *cp++) { 136 /* 137 * check for indirection 138 */ 139 switch (n & INDIR_MASK) { 140 case 0: /* normal case, n == len */ 141 cp += n; 142 continue; 143 default: /* illegal type */ 144 return (-1); 145 case INDIR_MASK: /* indirection */ 146 cp++; 147 } 148 break; 149 } 150 return (cp - buf); 151 } 152 153 /* 154 * Search for expanded name from a list of previously compressed names. 155 * Return the offset from msg if found or -1. 156 */ 157 dn_find(exp_dn, msg, dnptrs, lastdnptr) 158 char *exp_dn, *msg; 159 char **dnptrs, **lastdnptr; 160 { 161 register char *dn, *cp, **cpp; 162 register int n; 163 char *sp; 164 165 for (cpp = dnptrs; cpp < lastdnptr; cpp++) { 166 dn = exp_dn; 167 sp = cp = *cpp; 168 while (n = *cp++) { 169 /* 170 * check for indirection 171 */ 172 switch (n & INDIR_MASK) { 173 case 0: /* normal case, n == len */ 174 while (--n >= 0) 175 if (*dn++ != *cp++) 176 goto next; 177 if ((n = *dn++) == '\0' && *cp == '\0') 178 return (sp - msg); 179 if (n == '.') 180 continue; 181 goto next; 182 183 default: /* illegal type */ 184 return (-1); 185 186 case INDIR_MASK: /* indirection */ 187 cp = msg + (((n & 0x3f) << 8) | (*cp & 0xff)); 188 } 189 } 190 if (*dn == '\0') 191 return (sp - msg); 192 next: ; 193 } 194 return (-1); 195 } 196