118546Sralph /* 221384Sdist * Copyright (c) 1985 Regents of the University of California. 333679Sbostic * All rights reserved. 433679Sbostic * 533679Sbostic * Redistribution and use in source and binary forms are permitted 634817Sbostic * provided that the above copyright notice and this paragraph are 734817Sbostic * duplicated in all such forms and that any documentation, 834817Sbostic * advertising materials, and other materials related to such 934817Sbostic * distribution and use acknowledge that the software was developed 1034817Sbostic * by the University of California, Berkeley. The name of the 1134817Sbostic * University may not be used to endorse or promote products derived 1234817Sbostic * from this software without specific prior written permission. 1334817Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1434817Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1534817Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1618546Sralph */ 1718546Sralph 1826631Sdonn #if defined(LIBC_SCCS) && !defined(lint) 19*41093Sleres static char sccsid[] = "@(#)res_comp.c 6.16 (Berkeley) 04/25/90"; 2033679Sbostic #endif /* LIBC_SCCS and not lint */ 2121384Sdist 2218140Sralph #include <sys/types.h> 2318140Sralph #include <stdio.h> 2424079Skjd #include <arpa/nameser.h> 2518140Sralph 26*41093Sleres static dn_find(); 27*41093Sleres 2818140Sralph /* 2918342Sralph * Expand compressed domain name 'comp_dn' to full domain name. 3018342Sralph * 'msg' is a pointer to the begining of the message, 3126112Skarels * 'eomorig' points to the first location after the message, 3218342Sralph * 'exp_dn' is a pointer to a buffer of size 'length' for the result. 3318140Sralph * Return size of compressed name or -1 if there was an error. 3418140Sralph */ 3526112Skarels dn_expand(msg, eomorig, comp_dn, exp_dn, length) 3632647Skarels u_char *msg, *eomorig, *comp_dn, *exp_dn; 3726112Skarels int length; 3818140Sralph { 3932647Skarels register u_char *cp, *dn; 4018140Sralph register int n, c; 4132647Skarels u_char *eom; 4231686Skarels int len = -1, checked = 0; 4318140Sralph 4418140Sralph dn = exp_dn; 4518140Sralph cp = comp_dn; 4639788Sbloom eom = exp_dn + length; 4718140Sralph /* 4818140Sralph * fetch next label in domain name 4918140Sralph */ 5018140Sralph while (n = *cp++) { 5118140Sralph /* 5218140Sralph * Check for indirection 5318140Sralph */ 5418140Sralph switch (n & INDIR_MASK) { 5518140Sralph case 0: 5618342Sralph if (dn != exp_dn) { 5718342Sralph if (dn >= eom) 5818342Sralph return (-1); 5918140Sralph *dn++ = '.'; 6018342Sralph } 6118140Sralph if (dn+n >= eom) 6218140Sralph return (-1); 6331686Skarels checked += n + 1; 6426064Skjd while (--n >= 0) { 6526812Sbloom if ((c = *cp++) == '.') { 6626812Sbloom if (dn+n+1 >= eom) 6726812Sbloom return (-1); 6826812Sbloom *dn++ = '\\'; 6918342Sralph } 7026812Sbloom *dn++ = c; 7126112Skarels if (cp >= eomorig) /* out of range */ 7226064Skjd return(-1); 7326064Skjd } 7418140Sralph break; 7518140Sralph 7618140Sralph case INDIR_MASK: 7718342Sralph if (len < 0) 7818140Sralph len = cp - comp_dn + 1; 7918140Sralph cp = msg + (((n & 0x3f) << 8) | (*cp & 0xff)); 8026112Skarels if (cp < msg || cp >= eomorig) /* out of range */ 8126064Skjd return(-1); 8231686Skarels checked += 2; 8331686Skarels /* 8431686Skarels * Check for loops in the compressed name; 8531686Skarels * if we've looked at the whole message, 8631686Skarels * there must be a loop. 8731686Skarels */ 8831686Skarels if (checked >= eomorig - msg) 8931686Skarels return (-1); 9018140Sralph break; 9118140Sralph 9218140Sralph default: 9318140Sralph return (-1); /* flag error */ 9418140Sralph } 9518140Sralph } 9618140Sralph *dn = '\0'; 9718342Sralph if (len < 0) 9818140Sralph len = cp - comp_dn; 9918140Sralph return (len); 10018140Sralph } 10118140Sralph 10218140Sralph /* 10318342Sralph * Compress domain name 'exp_dn' into 'comp_dn'. 10418342Sralph * Return the size of the compressed name or -1. 10518342Sralph * 'length' is the size of the array pointed to by 'comp_dn'. 10618342Sralph * 'dnptrs' is a list of pointers to previous compressed names. dnptrs[0] 10718140Sralph * is a pointer to the beginning of the message. The list ends with NULL. 10818342Sralph * 'lastdnptr' is a pointer to the end of the arrary pointed to 10918342Sralph * by 'dnptrs'. Side effect is to update the list of pointers for 11018342Sralph * labels inserted into the message as we compress the name. 11118342Sralph * If 'dnptr' is NULL, we don't try to compress names. If 'lastdnptr' 11218342Sralph * is NULL, we don't update the list. 11318140Sralph */ 11418140Sralph dn_comp(exp_dn, comp_dn, length, dnptrs, lastdnptr) 11532647Skarels u_char *exp_dn, *comp_dn; 11618140Sralph int length; 11732647Skarels u_char **dnptrs, **lastdnptr; 11818140Sralph { 11932647Skarels register u_char *cp, *dn; 12018140Sralph register int c, l; 12132647Skarels u_char **cpp, **lpp, *sp, *eob; 12232647Skarels u_char *msg; 12318140Sralph 12418140Sralph dn = exp_dn; 12518140Sralph cp = comp_dn; 12625360Sbloom eob = cp + length; 12718140Sralph if (dnptrs != NULL) { 12818140Sralph if ((msg = *dnptrs++) != NULL) { 12918140Sralph for (cpp = dnptrs; *cpp != NULL; cpp++) 13018140Sralph ; 13118140Sralph lpp = cpp; /* end of list to search */ 13218140Sralph } 13318140Sralph } else 13418140Sralph msg = NULL; 13518140Sralph for (c = *dn++; c != '\0'; ) { 13618140Sralph /* look to see if we can use pointers */ 13718140Sralph if (msg != NULL) { 13818140Sralph if ((l = dn_find(dn-1, msg, dnptrs, lpp)) >= 0) { 13918140Sralph if (cp+1 >= eob) 14018140Sralph return (-1); 14118140Sralph *cp++ = (l >> 8) | INDIR_MASK; 14226240Skjd *cp++ = l % 256; 14318140Sralph return (cp - comp_dn); 14418140Sralph } 14518140Sralph /* not found, save it */ 14618140Sralph if (lastdnptr != NULL && cpp < lastdnptr-1) { 14718140Sralph *cpp++ = cp; 14818140Sralph *cpp = NULL; 14918140Sralph } 15018140Sralph } 15118140Sralph sp = cp++; /* save ptr to length byte */ 15218140Sralph do { 15318140Sralph if (c == '.') { 15418140Sralph c = *dn++; 15518140Sralph break; 15618140Sralph } 15718342Sralph if (c == '\\') { 15818342Sralph if ((c = *dn++) == '\0') 15918342Sralph break; 16018342Sralph } 16139788Sbloom if (cp >= eob) { 16239788Sbloom if (msg != NULL) 16339788Sbloom *lpp = NULL; 16418140Sralph return (-1); 16539788Sbloom } 16618140Sralph *cp++ = c; 16718140Sralph } while ((c = *dn++) != '\0'); 16818342Sralph /* catch trailing '.'s but not '..' */ 16918342Sralph if ((l = cp - sp - 1) == 0 && c == '\0') { 17018342Sralph cp--; 17118342Sralph break; 17218342Sralph } 17339788Sbloom if (l <= 0 || l > MAXLABEL) { 17439788Sbloom if (msg != NULL) 17539788Sbloom *lpp = NULL; 17618140Sralph return (-1); 17739788Sbloom } 17818140Sralph *sp = l; 17918140Sralph } 18039788Sbloom if (cp >= eob) { 18139788Sbloom if (msg != NULL) 18239788Sbloom *lpp = NULL; 18318140Sralph return (-1); 18439788Sbloom } 18518140Sralph *cp++ = '\0'; 18618140Sralph return (cp - comp_dn); 18718140Sralph } 18818140Sralph 18918140Sralph /* 19018342Sralph * Skip over a compressed domain name. Return the size or -1. 19118140Sralph */ 19232647Skarels dn_skipname(comp_dn, eom) 19332647Skarels u_char *comp_dn, *eom; 19418140Sralph { 19532647Skarels register u_char *cp; 19618140Sralph register int n; 19718140Sralph 19818342Sralph cp = comp_dn; 19932647Skarels while (cp < eom && (n = *cp++)) { 20018140Sralph /* 20118140Sralph * check for indirection 20218140Sralph */ 20318140Sralph switch (n & INDIR_MASK) { 20418140Sralph case 0: /* normal case, n == len */ 20518140Sralph cp += n; 20618140Sralph continue; 20718140Sralph default: /* illegal type */ 20818140Sralph return (-1); 20918140Sralph case INDIR_MASK: /* indirection */ 21018140Sralph cp++; 21118140Sralph } 21218140Sralph break; 21318140Sralph } 21418342Sralph return (cp - comp_dn); 21518140Sralph } 21618140Sralph 21718140Sralph /* 21818140Sralph * Search for expanded name from a list of previously compressed names. 21918140Sralph * Return the offset from msg if found or -1. 22033617Skarels * dnptrs is the pointer to the first name on the list, 22133617Skarels * not the pointer to the start of the message. 22218140Sralph */ 22333617Skarels static 22418140Sralph dn_find(exp_dn, msg, dnptrs, lastdnptr) 22532647Skarels u_char *exp_dn, *msg; 22632647Skarels u_char **dnptrs, **lastdnptr; 22718140Sralph { 22832647Skarels register u_char *dn, *cp, **cpp; 22918140Sralph register int n; 23032647Skarels u_char *sp; 23118140Sralph 23233617Skarels for (cpp = dnptrs; cpp < lastdnptr; cpp++) { 23318140Sralph dn = exp_dn; 23418140Sralph sp = cp = *cpp; 23518140Sralph while (n = *cp++) { 23618140Sralph /* 23718140Sralph * check for indirection 23818140Sralph */ 23918140Sralph switch (n & INDIR_MASK) { 24018140Sralph case 0: /* normal case, n == len */ 24118342Sralph while (--n >= 0) { 24239788Sbloom if (*dn == '.') 24339788Sbloom goto next; 24418342Sralph if (*dn == '\\') 24518342Sralph dn++; 24618140Sralph if (*dn++ != *cp++) 24718140Sralph goto next; 24818342Sralph } 24918140Sralph if ((n = *dn++) == '\0' && *cp == '\0') 25018140Sralph return (sp - msg); 25118140Sralph if (n == '.') 25218140Sralph continue; 25318140Sralph goto next; 25418140Sralph 25518140Sralph default: /* illegal type */ 25618140Sralph return (-1); 25718140Sralph 25818140Sralph case INDIR_MASK: /* indirection */ 25932647Skarels cp = msg + (((n & 0x3f) << 8) | *cp); 26018140Sralph } 26118140Sralph } 26218140Sralph if (*dn == '\0') 26318140Sralph return (sp - msg); 26418140Sralph next: ; 26518140Sralph } 26618140Sralph return (-1); 26718140Sralph } 26818528Sralph 26918528Sralph /* 27018528Sralph * Routines to insert/extract short/long's. Must account for byte 27118528Sralph * order and non-alignment problems. This code at least has the 27218528Sralph * advantage of being portable. 27333727Sbostic * 27433727Sbostic * used by sendmail. 27518528Sralph */ 27618528Sralph 27718528Sralph u_short 27830441Skjd _getshort(msgp) 27932647Skarels u_char *msgp; 28018528Sralph { 28118528Sralph register u_char *p = (u_char *) msgp; 28225360Sbloom #ifdef vax 28325360Sbloom /* 28425360Sbloom * vax compiler doesn't put shorts in registers 28525360Sbloom */ 28625360Sbloom register u_long u; 28725360Sbloom #else 28824735Sbloom register u_short u; 28925360Sbloom #endif 29018528Sralph 29124735Sbloom u = *p++ << 8; 29225360Sbloom return ((u_short)(u | *p)); 29318528Sralph } 29418528Sralph 29518528Sralph u_long 29630441Skjd _getlong(msgp) 29732647Skarels u_char *msgp; 29818528Sralph { 29918528Sralph register u_char *p = (u_char *) msgp; 30023870Skjd register u_long u; 30118528Sralph 30223870Skjd u = *p++; u <<= 8; 30323870Skjd u |= *p++; u <<= 8; 30423870Skjd u |= *p++; u <<= 8; 30523870Skjd return (u | *p); 30618528Sralph } 30718528Sralph 30823870Skjd 30918528Sralph putshort(s, msgp) 31018528Sralph register u_short s; 31132647Skarels register u_char *msgp; 31218528Sralph { 31318528Sralph 31418528Sralph msgp[1] = s; 31518528Sralph msgp[0] = s >> 8; 31618528Sralph } 31718528Sralph 31818528Sralph putlong(l, msgp) 31918528Sralph register u_long l; 32032647Skarels register u_char *msgp; 32118528Sralph { 32218528Sralph 32318528Sralph msgp[3] = l; 32418528Sralph msgp[2] = (l >>= 8); 32518528Sralph msgp[1] = (l >>= 8); 32618528Sralph msgp[0] = l >> 8; 32718528Sralph } 328