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