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