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.10 (Berkeley) 11/19/87"; 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 */ 200 dn_find(exp_dn, msg, dnptrs, lastdnptr) 201 u_char *exp_dn, *msg; 202 u_char **dnptrs, **lastdnptr; 203 { 204 register u_char *dn, *cp, **cpp; 205 register int n; 206 u_char *sp; 207 208 for (cpp = dnptrs + 1; cpp < lastdnptr; cpp++) { 209 dn = exp_dn; 210 sp = cp = *cpp; 211 while (n = *cp++) { 212 /* 213 * check for indirection 214 */ 215 switch (n & INDIR_MASK) { 216 case 0: /* normal case, n == len */ 217 while (--n >= 0) { 218 if (*dn == '\\') 219 dn++; 220 if (*dn++ != *cp++) 221 goto next; 222 } 223 if ((n = *dn++) == '\0' && *cp == '\0') 224 return (sp - msg); 225 if (n == '.') 226 continue; 227 goto next; 228 229 default: /* illegal type */ 230 return (-1); 231 232 case INDIR_MASK: /* indirection */ 233 cp = msg + (((n & 0x3f) << 8) | *cp); 234 } 235 } 236 if (*dn == '\0') 237 return (sp - msg); 238 next: ; 239 } 240 return (-1); 241 } 242 243 /* 244 * Routines to insert/extract short/long's. Must account for byte 245 * order and non-alignment problems. This code at least has the 246 * advantage of being portable. 247 */ 248 249 u_short 250 _getshort(msgp) 251 u_char *msgp; 252 { 253 register u_char *p = (u_char *) msgp; 254 #ifdef vax 255 /* 256 * vax compiler doesn't put shorts in registers 257 */ 258 register u_long u; 259 #else 260 register u_short u; 261 #endif 262 263 u = *p++ << 8; 264 return ((u_short)(u | *p)); 265 } 266 267 u_long 268 _getlong(msgp) 269 u_char *msgp; 270 { 271 register u_char *p = (u_char *) msgp; 272 register u_long u; 273 274 u = *p++; u <<= 8; 275 u |= *p++; u <<= 8; 276 u |= *p++; u <<= 8; 277 return (u | *p); 278 } 279 280 281 putshort(s, msgp) 282 register u_short s; 283 register u_char *msgp; 284 { 285 286 msgp[1] = s; 287 msgp[0] = s >> 8; 288 } 289 290 putlong(l, msgp) 291 register u_long l; 292 register u_char *msgp; 293 { 294 295 msgp[3] = l; 296 msgp[2] = (l >>= 8); 297 msgp[1] = (l >>= 8); 298 msgp[0] = l >> 8; 299 } 300