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.14 (Berkeley) 06/27/88"; 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 - 1; 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 return (-1); 161 *cp++ = c; 162 } while ((c = *dn++) != '\0'); 163 /* catch trailing '.'s but not '..' */ 164 if ((l = cp - sp - 1) == 0 && c == '\0') { 165 cp--; 166 break; 167 } 168 if (l <= 0 || l > MAXLABEL) 169 return (-1); 170 *sp = l; 171 } 172 if (cp >= eob) 173 return (-1); 174 *cp++ = '\0'; 175 return (cp - comp_dn); 176 } 177 178 /* 179 * Skip over a compressed domain name. Return the size or -1. 180 */ 181 dn_skipname(comp_dn, eom) 182 u_char *comp_dn, *eom; 183 { 184 register u_char *cp; 185 register int n; 186 187 cp = comp_dn; 188 while (cp < eom && (n = *cp++)) { 189 /* 190 * check for indirection 191 */ 192 switch (n & INDIR_MASK) { 193 case 0: /* normal case, n == len */ 194 cp += n; 195 continue; 196 default: /* illegal type */ 197 return (-1); 198 case INDIR_MASK: /* indirection */ 199 cp++; 200 } 201 break; 202 } 203 return (cp - comp_dn); 204 } 205 206 /* 207 * Search for expanded name from a list of previously compressed names. 208 * Return the offset from msg if found or -1. 209 * dnptrs is the pointer to the first name on the list, 210 * not the pointer to the start of the message. 211 */ 212 static 213 dn_find(exp_dn, msg, dnptrs, lastdnptr) 214 u_char *exp_dn, *msg; 215 u_char **dnptrs, **lastdnptr; 216 { 217 register u_char *dn, *cp, **cpp; 218 register int n; 219 u_char *sp; 220 221 for (cpp = dnptrs; cpp < lastdnptr; cpp++) { 222 dn = exp_dn; 223 sp = cp = *cpp; 224 while (n = *cp++) { 225 /* 226 * check for indirection 227 */ 228 switch (n & INDIR_MASK) { 229 case 0: /* normal case, n == len */ 230 while (--n >= 0) { 231 if (*dn == '\\') 232 dn++; 233 if (*dn++ != *cp++) 234 goto next; 235 } 236 if ((n = *dn++) == '\0' && *cp == '\0') 237 return (sp - msg); 238 if (n == '.') 239 continue; 240 goto next; 241 242 default: /* illegal type */ 243 return (-1); 244 245 case INDIR_MASK: /* indirection */ 246 cp = msg + (((n & 0x3f) << 8) | *cp); 247 } 248 } 249 if (*dn == '\0') 250 return (sp - msg); 251 next: ; 252 } 253 return (-1); 254 } 255 256 /* 257 * Routines to insert/extract short/long's. Must account for byte 258 * order and non-alignment problems. This code at least has the 259 * advantage of being portable. 260 * 261 * used by sendmail. 262 */ 263 264 u_short 265 _getshort(msgp) 266 u_char *msgp; 267 { 268 register u_char *p = (u_char *) msgp; 269 #ifdef vax 270 /* 271 * vax compiler doesn't put shorts in registers 272 */ 273 register u_long u; 274 #else 275 register u_short u; 276 #endif 277 278 u = *p++ << 8; 279 return ((u_short)(u | *p)); 280 } 281 282 u_long 283 _getlong(msgp) 284 u_char *msgp; 285 { 286 register u_char *p = (u_char *) msgp; 287 register u_long u; 288 289 u = *p++; u <<= 8; 290 u |= *p++; u <<= 8; 291 u |= *p++; u <<= 8; 292 return (u | *p); 293 } 294 295 296 putshort(s, msgp) 297 register u_short s; 298 register u_char *msgp; 299 { 300 301 msgp[1] = s; 302 msgp[0] = s >> 8; 303 } 304 305 putlong(l, msgp) 306 register u_long l; 307 register u_char *msgp; 308 { 309 310 msgp[3] = l; 311 msgp[2] = (l >>= 8); 312 msgp[1] = (l >>= 8); 313 msgp[0] = l >> 8; 314 } 315