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