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