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