1 /* 2 * Copyright (c) 1985 Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #if defined(LIBC_SCCS) && !defined(lint) 9 static char sccsid[] = "@(#)res_comp.c 6.17 (Berkeley) 06/01/90"; 10 #endif /* LIBC_SCCS and not lint */ 11 12 #include <sys/types.h> 13 #include <stdio.h> 14 #include <arpa/nameser.h> 15 16 static dn_find(); 17 18 /* 19 * Expand compressed domain name 'comp_dn' to full domain name. 20 * 'msg' is a pointer to the begining of the message, 21 * 'eomorig' points to the first location after the message, 22 * 'exp_dn' is a pointer to a buffer of size 'length' for the result. 23 * Return size of compressed name or -1 if there was an error. 24 */ 25 dn_expand(msg, eomorig, comp_dn, exp_dn, length) 26 u_char *msg, *eomorig, *comp_dn, *exp_dn; 27 int length; 28 { 29 register u_char *cp, *dn; 30 register int n, c; 31 u_char *eom; 32 int len = -1, checked = 0; 33 34 dn = exp_dn; 35 cp = comp_dn; 36 eom = exp_dn + length; 37 /* 38 * fetch next label in domain name 39 */ 40 while (n = *cp++) { 41 /* 42 * Check for indirection 43 */ 44 switch (n & INDIR_MASK) { 45 case 0: 46 if (dn != exp_dn) { 47 if (dn >= eom) 48 return (-1); 49 *dn++ = '.'; 50 } 51 if (dn+n >= eom) 52 return (-1); 53 checked += n + 1; 54 while (--n >= 0) { 55 if ((c = *cp++) == '.') { 56 if (dn+n+1 >= eom) 57 return (-1); 58 *dn++ = '\\'; 59 } 60 *dn++ = c; 61 if (cp >= eomorig) /* out of range */ 62 return(-1); 63 } 64 break; 65 66 case INDIR_MASK: 67 if (len < 0) 68 len = cp - comp_dn + 1; 69 cp = msg + (((n & 0x3f) << 8) | (*cp & 0xff)); 70 if (cp < msg || cp >= eomorig) /* out of range */ 71 return(-1); 72 checked += 2; 73 /* 74 * Check for loops in the compressed name; 75 * if we've looked at the whole message, 76 * there must be a loop. 77 */ 78 if (checked >= eomorig - msg) 79 return (-1); 80 break; 81 82 default: 83 return (-1); /* flag error */ 84 } 85 } 86 *dn = '\0'; 87 if (len < 0) 88 len = cp - comp_dn; 89 return (len); 90 } 91 92 /* 93 * Compress domain name 'exp_dn' into 'comp_dn'. 94 * Return the size of the compressed name or -1. 95 * 'length' is the size of the array pointed to by 'comp_dn'. 96 * 'dnptrs' is a list of pointers to previous compressed names. dnptrs[0] 97 * is a pointer to the beginning of the message. The list ends with NULL. 98 * 'lastdnptr' is a pointer to the end of the arrary pointed to 99 * by 'dnptrs'. Side effect is to update the list of pointers for 100 * labels inserted into the message as we compress the name. 101 * If 'dnptr' is NULL, we don't try to compress names. If 'lastdnptr' 102 * is NULL, we don't update the list. 103 */ 104 dn_comp(exp_dn, comp_dn, length, dnptrs, lastdnptr) 105 u_char *exp_dn, *comp_dn; 106 int length; 107 u_char **dnptrs, **lastdnptr; 108 { 109 register u_char *cp, *dn; 110 register int c, l; 111 u_char **cpp, **lpp, *sp, *eob; 112 u_char *msg; 113 114 dn = exp_dn; 115 cp = comp_dn; 116 eob = cp + length; 117 if (dnptrs != NULL) { 118 if ((msg = *dnptrs++) != NULL) { 119 for (cpp = dnptrs; *cpp != NULL; cpp++) 120 ; 121 lpp = cpp; /* end of list to search */ 122 } 123 } else 124 msg = NULL; 125 for (c = *dn++; c != '\0'; ) { 126 /* look to see if we can use pointers */ 127 if (msg != NULL) { 128 if ((l = dn_find(dn-1, msg, dnptrs, lpp)) >= 0) { 129 if (cp+1 >= eob) 130 return (-1); 131 *cp++ = (l >> 8) | INDIR_MASK; 132 *cp++ = l % 256; 133 return (cp - comp_dn); 134 } 135 /* not found, save it */ 136 if (lastdnptr != NULL && cpp < lastdnptr-1) { 137 *cpp++ = cp; 138 *cpp = NULL; 139 } 140 } 141 sp = cp++; /* save ptr to length byte */ 142 do { 143 if (c == '.') { 144 c = *dn++; 145 break; 146 } 147 if (c == '\\') { 148 if ((c = *dn++) == '\0') 149 break; 150 } 151 if (cp >= eob) { 152 if (msg != NULL) 153 *lpp = NULL; 154 return (-1); 155 } 156 *cp++ = c; 157 } while ((c = *dn++) != '\0'); 158 /* catch trailing '.'s but not '..' */ 159 if ((l = cp - sp - 1) == 0 && c == '\0') { 160 cp--; 161 break; 162 } 163 if (l <= 0 || l > MAXLABEL) { 164 if (msg != NULL) 165 *lpp = NULL; 166 return (-1); 167 } 168 *sp = l; 169 } 170 if (cp >= eob) { 171 if (msg != NULL) 172 *lpp = NULL; 173 return (-1); 174 } 175 *cp++ = '\0'; 176 return (cp - comp_dn); 177 } 178 179 /* 180 * Skip over a compressed domain name. Return the size or -1. 181 */ 182 dn_skipname(comp_dn, eom) 183 u_char *comp_dn, *eom; 184 { 185 register u_char *cp; 186 register int n; 187 188 cp = comp_dn; 189 while (cp < eom && (n = *cp++)) { 190 /* 191 * check for indirection 192 */ 193 switch (n & INDIR_MASK) { 194 case 0: /* normal case, n == len */ 195 cp += n; 196 continue; 197 default: /* illegal type */ 198 return (-1); 199 case INDIR_MASK: /* indirection */ 200 cp++; 201 } 202 break; 203 } 204 return (cp - comp_dn); 205 } 206 207 /* 208 * Search for expanded name from a list of previously compressed names. 209 * Return the offset from msg if found or -1. 210 * dnptrs is the pointer to the first name on the list, 211 * not the pointer to the start of the message. 212 */ 213 static 214 dn_find(exp_dn, msg, dnptrs, lastdnptr) 215 u_char *exp_dn, *msg; 216 u_char **dnptrs, **lastdnptr; 217 { 218 register u_char *dn, *cp, **cpp; 219 register int n; 220 u_char *sp; 221 222 for (cpp = dnptrs; cpp < lastdnptr; cpp++) { 223 dn = exp_dn; 224 sp = cp = *cpp; 225 while (n = *cp++) { 226 /* 227 * check for indirection 228 */ 229 switch (n & INDIR_MASK) { 230 case 0: /* normal case, n == len */ 231 while (--n >= 0) { 232 if (*dn == '.') 233 goto next; 234 if (*dn == '\\') 235 dn++; 236 if (*dn++ != *cp++) 237 goto next; 238 } 239 if ((n = *dn++) == '\0' && *cp == '\0') 240 return (sp - msg); 241 if (n == '.') 242 continue; 243 goto next; 244 245 default: /* illegal type */ 246 return (-1); 247 248 case INDIR_MASK: /* indirection */ 249 cp = msg + (((n & 0x3f) << 8) | *cp); 250 } 251 } 252 if (*dn == '\0') 253 return (sp - msg); 254 next: ; 255 } 256 return (-1); 257 } 258 259 /* 260 * Routines to insert/extract short/long's. Must account for byte 261 * order and non-alignment problems. This code at least has the 262 * advantage of being portable. 263 * 264 * used by sendmail. 265 */ 266 267 u_short 268 _getshort(msgp) 269 u_char *msgp; 270 { 271 register u_char *p = (u_char *) msgp; 272 #ifdef vax 273 /* 274 * vax compiler doesn't put shorts in registers 275 */ 276 register u_long u; 277 #else 278 register u_short u; 279 #endif 280 281 u = *p++ << 8; 282 return ((u_short)(u | *p)); 283 } 284 285 u_long 286 _getlong(msgp) 287 u_char *msgp; 288 { 289 register u_char *p = (u_char *) msgp; 290 register u_long u; 291 292 u = *p++; u <<= 8; 293 u |= *p++; u <<= 8; 294 u |= *p++; u <<= 8; 295 return (u | *p); 296 } 297 298 299 putshort(s, msgp) 300 register u_short s; 301 register u_char *msgp; 302 { 303 304 msgp[1] = s; 305 msgp[0] = s >> 8; 306 } 307 308 putlong(l, msgp) 309 register u_long l; 310 register u_char *msgp; 311 { 312 313 msgp[3] = l; 314 msgp[2] = (l >>= 8); 315 msgp[1] = (l >>= 8); 316 msgp[0] = l >> 8; 317 } 318