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.7 (Berkeley) 3/11/86"; 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: }