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