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