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