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