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