1: /* 2: * Copyright (c) 1985 Regents of the University of California. 3: * All rights reserved. 4: * 5: * Redistribution and use in source and binary forms are permitted 6: * provided that this notice is preserved and that due credit is given 7: * to the University of California at Berkeley. The name of the University 8: * may not be used to endorse or promote products derived from this 9: * software without specific prior written permission. This software 10: * is provided ``as is'' without express or implied warranty. 11: */ 12: 13: #if defined(LIBC_SCCS) && !defined(lint) 14: static char sccsid[] = "@(#)res_comp.c 6.13 (Berkeley) 3/13/88"; 15: #endif /* LIBC_SCCS and not lint */ 16: 17: #include <sys/types.h> 18: #include <stdio.h> 19: #include <arpa/nameser.h> 20: 21: 22: /* 23: * Expand compressed domain name 'comp_dn' to full domain name. 24: * 'msg' is a pointer to the begining of the message, 25: * 'eomorig' points to the first location after the message, 26: * 'exp_dn' is a pointer to a buffer of size 'length' for the result. 27: * Return size of compressed name or -1 if there was an error. 28: */ 29: dn_expand(msg, eomorig, comp_dn, exp_dn, length) 30: u_char *msg, *eomorig, *comp_dn, *exp_dn; 31: int length; 32: { 33: register u_char *cp, *dn; 34: register int n, c; 35: u_char *eom; 36: int len = -1, checked = 0; 37: 38: dn = exp_dn; 39: cp = comp_dn; 40: eom = exp_dn + length - 1; 41: /* 42: * fetch next label in domain name 43: */ 44: while (n = *cp++) { 45: /* 46: * Check for indirection 47: */ 48: switch (n & INDIR_MASK) { 49: case 0: 50: if (dn != exp_dn) { 51: if (dn >= eom) 52: return (-1); 53: *dn++ = '.'; 54: } 55: if (dn+n >= eom) 56: return (-1); 57: checked += n + 1; 58: while (--n >= 0) { 59: if ((c = *cp++) == '.') { 60: if (dn+n+1 >= eom) 61: return (-1); 62: *dn++ = '\\'; 63: } 64: *dn++ = c; 65: if (cp >= eomorig) /* out of range */ 66: return(-1); 67: } 68: break; 69: 70: case INDIR_MASK: 71: if (len < 0) 72: len = cp - comp_dn + 1; 73: cp = msg + (((n & 0x3f) << 8) | (*cp & 0xff)); 74: if (cp < msg || cp >= eomorig) /* out of range */ 75: return(-1); 76: checked += 2; 77: /* 78: * Check for loops in the compressed name; 79: * if we've looked at the whole message, 80: * there must be a loop. 81: */ 82: if (checked >= eomorig - msg) 83: return (-1); 84: break; 85: 86: default: 87: return (-1); /* flag error */ 88: } 89: } 90: *dn = '\0'; 91: if (len < 0) 92: len = cp - comp_dn; 93: return (len); 94: } 95: 96: /* 97: * Compress domain name 'exp_dn' into 'comp_dn'. 98: * Return the size of the compressed name or -1. 99: * 'length' is the size of the array pointed to by 'comp_dn'. 100: * 'dnptrs' is a list of pointers to previous compressed names. dnptrs[0] 101: * is a pointer to the beginning of the message. The list ends with NULL. 102: * 'lastdnptr' is a pointer to the end of the arrary pointed to 103: * by 'dnptrs'. Side effect is to update the list of pointers for 104: * labels inserted into the message as we compress the name. 105: * If 'dnptr' is NULL, we don't try to compress names. If 'lastdnptr' 106: * is NULL, we don't update the list. 107: */ 108: dn_comp(exp_dn, comp_dn, length, dnptrs, lastdnptr) 109: u_char *exp_dn, *comp_dn; 110: int length; 111: u_char **dnptrs, **lastdnptr; 112: { 113: register u_char *cp, *dn; 114: register int c, l; 115: u_char **cpp, **lpp, *sp, *eob; 116: u_char *msg; 117: 118: dn = exp_dn; 119: cp = comp_dn; 120: eob = cp + length; 121: if (dnptrs != NULL) { 122: if ((msg = *dnptrs++) != NULL) { 123: for (cpp = dnptrs; *cpp != NULL; cpp++) 124: ; 125: lpp = cpp; /* end of list to search */ 126: } 127: } else 128: msg = NULL; 129: for (c = *dn++; c != '\0'; ) { 130: /* look to see if we can use pointers */ 131: if (msg != NULL) { 132: if ((l = dn_find(dn-1, msg, dnptrs, lpp)) >= 0) { 133: if (cp+1 >= eob) 134: return (-1); 135: *cp++ = (l >> 8) | INDIR_MASK; 136: *cp++ = l % 256; 137: return (cp - comp_dn); 138: } 139: /* not found, save it */ 140: if (lastdnptr != NULL && cpp < lastdnptr-1) { 141: *cpp++ = cp; 142: *cpp = NULL; 143: } 144: } 145: sp = cp++; /* save ptr to length byte */ 146: do { 147: if (c == '.') { 148: c = *dn++; 149: break; 150: } 151: if (c == '\\') { 152: if ((c = *dn++) == '\0') 153: break; 154: } 155: if (cp >= eob) 156: return (-1); 157: *cp++ = c; 158: } while ((c = *dn++) != '\0'); 159: /* catch trailing '.'s but not '..' */ 160: if ((l = cp - sp - 1) == 0 && c == '\0') { 161: cp--; 162: break; 163: } 164: if (l <= 0 || l > MAXLABEL) 165: return (-1); 166: *sp = l; 167: } 168: if (cp >= eob) 169: return (-1); 170: *cp++ = '\0'; 171: return (cp - comp_dn); 172: } 173: 174: /* 175: * Skip over a compressed domain name. Return the size or -1. 176: */ 177: dn_skipname(comp_dn, eom) 178: u_char *comp_dn, *eom; 179: { 180: register u_char *cp; 181: register int n; 182: 183: cp = comp_dn; 184: while (cp < eom && (n = *cp++)) { 185: /* 186: * check for indirection 187: */ 188: switch (n & INDIR_MASK) { 189: case 0: /* normal case, n == len */ 190: cp += n; 191: continue; 192: default: /* illegal type */ 193: return (-1); 194: case INDIR_MASK: /* indirection */ 195: cp++; 196: } 197: break; 198: } 199: return (cp - comp_dn); 200: } 201: 202: /* 203: * Search for expanded name from a list of previously compressed names. 204: * Return the offset from msg if found or -1. 205: * dnptrs is the pointer to the first name on the list, 206: * not the pointer to the start of the message. 207: */ 208: static 209: dn_find(exp_dn, msg, dnptrs, lastdnptr) 210: u_char *exp_dn, *msg; 211: u_char **dnptrs, **lastdnptr; 212: { 213: register u_char *dn, *cp, **cpp; 214: register int n; 215: u_char *sp; 216: 217: for (cpp = dnptrs; cpp < lastdnptr; cpp++) { 218: dn = exp_dn; 219: sp = cp = *cpp; 220: while (n = *cp++) { 221: /* 222: * check for indirection 223: */ 224: switch (n & INDIR_MASK) { 225: case 0: /* normal case, n == len */ 226: while (--n >= 0) { 227: if (*dn == '\\') 228: dn++; 229: if (*dn++ != *cp++) 230: goto next; 231: } 232: if ((n = *dn++) == '\0' && *cp == '\0') 233: return (sp - msg); 234: if (n == '.') 235: continue; 236: goto next; 237: 238: default: /* illegal type */ 239: return (-1); 240: 241: case INDIR_MASK: /* indirection */ 242: cp = msg + (((n & 0x3f) << 8) | *cp); 243: } 244: } 245: if (*dn == '\0') 246: return (sp - msg); 247: next: ; 248: } 249: return (-1); 250: } 251: 252: /* 253: * Routines to insert/extract short/long's. Must account for byte 254: * order and non-alignment problems. This code at least has the 255: * advantage of being portable. 256: * 257: * used by sendmail. 258: */ 259: 260: u_short 261: _getshort(msgp) 262: u_char *msgp; 263: { 264: register u_char *p = (u_char *) msgp; 265: #ifdef vax 266: /* 267: * vax compiler doesn't put shorts in registers 268: */ 269: register u_long u; 270: #else 271: register u_short u; 272: #endif 273: 274: u = *p++ << 8; 275: return ((u_short)(u | *p)); 276: } 277: 278: u_long 279: _getlong(msgp) 280: u_char *msgp; 281: { 282: register u_char *p = (u_char *) msgp; 283: register u_long u; 284: 285: u = *p++; u <<= 8; 286: u |= *p++; u <<= 8; 287: u |= *p++; u <<= 8; 288: return (u | *p); 289: } 290: 291: 292: putshort(s, msgp) 293: register u_short s; 294: register u_char *msgp; 295: { 296: 297: msgp[1] = s; 298: msgp[0] = s >> 8; 299: } 300: 301: putlong(l, msgp) 302: register u_long l; 303: register u_char *msgp; 304: { 305: 306: msgp[3] = l; 307: msgp[2] = (l >>= 8); 308: msgp[1] = (l >>= 8); 309: msgp[0] = l >> 8; 310: }