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