[comp.mail.sendmail] sendmail-5.61 + IDA-1.2.8; proper host name resolution with BIND

salzman@randvax.UUCP (Isaac Salzman) (02/08/89)

The following patches will make sendmail 5.61+IDA handle host name
resolution with BIND in a reasonable manner (at least in my opinion :-).

The problem is with maphostname(). IDA likes to use gethostbyname() to do
the job, which is insufficient for hosts that only have MX records. You'll
end up getting a pathalias path for those hosts (assuming you're using IDA
with it's sendmail.cf and a pathalias database) instead of using the MX
record, which defeats to purpose of MX records all together.

Lennart noted the following problem with using the supplied getcanonname()
instead of gethostbyname():

/* from domain.c */
/*
**	Getcanonname() below is broken in the sense that it won't return
**	unqualified local host names with their full domain extension,
**	unless the argument is an alias.
**
**	Since gethostbyname() calls the name server with bind 4.8,
**	I don't see why this function would be needed at all.  I've
**	therefore restored the old code in maphostname() of daemon.c
**	that uses gethostbyname().  If there's something I've missed,
**	feel free to change maphostname() to again call getcanonname(),
**	but also make sure that the latter will qualify the host with
**	its full domain AND return a status code indicating if the host
**	was found.
**
**	Lennart Lovstrand, Rank Xerox EuroPARC, 24-Aug-88
*/

As he's suggested, I've modified maphostname() and getcanonname(). I did not
get rid of the call to gethostbyname(). Instead, I look at h_errno after
calling gethostbyname() to determine whether or not to bother calling
getcanonname(). This solves the problem of returning FQDN's for local host
names. If gethostbyname() fails and h_errno contains NO_DATA/NO_ADDRESS (the
same), it will try getcanonname(), which will work for MX only sites (since
it does a T_ANY query).

For this to work you need the following in conf.h:

#define NO_WILDCARD_MX 1	/* to use T_ANY instead of T_CNAME in 
				   getcanonname()
				*/

#define GETHOSTBYNAME_ISNT_ENOUGH 1 /* to call getcanonname() in addition
				       to gethostbyname() in maphostname()
				    */

These patches were made to the port of IDA 1.2.8 to sendmail 5.61 that's
available for ftp on gatekeeper.dec.com (sendmail.5.61.ida.tar.Z).

If there's a better (or more proper) way to handle this, I'd really
like to hear about it. Likewise if there are any problems. It would be
nice to see these patches find their way into future releases of IDA
(I once sent them to Lennart, but I think they ended up in /dev/null :-).
Enjoy!

[ Apply patches in src directory. Files effected: domain.c, daemon.c. Watch
  out for the .signature at the end of the message. ]

*** domain.c.ORIG	Thu Jan 26 07:50:59 1989
--- domain.c	Tue Feb  7 13:42:34 1989
***************
*** 215,221 ****
  		if (tTd(8, 1))
  			printf("getcanonname:  res_search failed (errno=%d, h_errno=%d)\n",
  			    errno, h_errno);
! 		return;
  	}
  
  	/* find first satisfactory answer */
--- 215,221 ----
  		if (tTd(8, 1))
  			printf("getcanonname:  res_search failed (errno=%d, h_errno=%d)\n",
  			    errno, h_errno);
! 		return FALSE;
  	}
  
  	/* find first satisfactory answer */
***************
*** 226,238 ****
  	if (ancount == 0) {
  		if (tTd(8, 1))
  			printf("rcode = %d, ancount=%d\n", hp->rcode, ancount);
! 		return;
  	}
  	cp = (u_char *)&answer + sizeof(HEADER);
  	eom = (u_char *)&answer + n;
  	for (qdcount = ntohs(hp->qdcount); qdcount--; cp += n + QFIXEDSZ)
  		if ((n = dn_skipname(cp, eom)) < 0)
! 			return;
  
  	/*
  	 * just in case someone puts a CNAME record after another record,
--- 226,238 ----
  	if (ancount == 0) {
  		if (tTd(8, 1))
  			printf("rcode = %d, ancount=%d\n", hp->rcode, ancount);
! 		return FALSE;
  	}
  	cp = (u_char *)&answer + sizeof(HEADER);
  	eom = (u_char *)&answer + n;
  	for (qdcount = ntohs(hp->qdcount); qdcount--; cp += n + QFIXEDSZ)
  		if ((n = dn_skipname(cp, eom)) < 0)
! 			return FALSE;
  
  	/*
  	 * just in case someone puts a CNAME record after another record,
***************
*** 264,275 ****
  			(void)strncpy(host, nbuf, hbsize); /* XXX */
  			host[hbsize - 1] = '\0';
  			if (++loopcnt > 8)	/* never be more than 1 */
! 				return;
  			goto loop;
  		}
! 	}
  }
- #endif GETHOSTBYNAME_ISNT_ENOUGH
  
  #else /* not NAMED_BIND */
  
--- 264,276 ----
  			(void)strncpy(host, nbuf, hbsize); /* XXX */
  			host[hbsize - 1] = '\0';
  			if (++loopcnt > 8)	/* never be more than 1 */
! 				return FALSE;
  			goto loop;
  		}
! 	    }
!     return TRUE;
! 	
  }
  
  #else /* not NAMED_BIND */
  
***************
*** 283,294 ****
  
  	hp = gethostbyname(host);
  	if (hp == NULL)
! 		return;
  
  	if (strlen(hp->h_name) >= hbsize)
! 		return;
  
  	(void) strcpy(host, hp->h_name);
  }
  
  #endif /* not NAMED_BIND */
--- 284,298 ----
  
  	hp = gethostbyname(host);
  	if (hp == NULL)
! 		return FALSE;
  
  	if (strlen(hp->h_name) >= hbsize)
! 		return FALSE;
  
  	(void) strcpy(host, hp->h_name);
+ 	return TRUE;
  }
  
  #endif /* not NAMED_BIND */
+ 
+ #endif /* GETHOSTBYNAME_ISNT_ENOUGH */
*** daemon.c.ORIG	Tue Feb  7 11:09:29 1989
--- daemon.c	Tue Feb  7 14:06:14 1989
***************
*** 521,526 ****
--- 521,528 ----
  	register struct hostent *hp;
  	extern struct hostent *gethostbyname();
  	static char tmphbuf[MAXNAME];
+ 	extern int h_errno;
+ 	int status;
  
  	/*
  	 * If first character is a bracket, then it is an address
***************
*** 540,556 ****
  	else
  	{
  		hp = gethostbyname(hbuf);
! 		if (hp == NULL) {
! 			/* try lowercase version */
! 			(void) strcpy(tmphbuf, hbuf);
! 			(void) makelower(tmphbuf);
  		}
  	}
! 	if (tTd(9, 1))
! 		printf("maphostname(%s, %d) => %.*s\n",
! 			hbuf, hbsize, hbsize-1, hp ? hp->h_name : "NOT_FOUND");
  	if (hp == NULL)
! 		return FALSE;
  
  	if (strlen(hp->h_name) >= hbsize)
  		hp->h_name[hbsize - 1] = '\0';
--- 542,580 ----
  	else
  	{
  		hp = gethostbyname(hbuf);
! 		if (tTd(9, 1))
! 		    printf("maphostname [gethostbyname(%s)] => %.*s (%d)\n",
! 			   hbuf, hbsize-1,
! 			   hp ? hp->h_name : "NOT_FOUND", h_errno);
! 
! #if defined(GETHOSTBYNAME_ISNT_ENOUGH) && defined(NAMED_BIND)
! 		if (hp == NULL)
! 		{
! 		    switch(h_errno)
! 		      {
! 			case HOST_NOT_FOUND:
! 			case NO_RECOVERY:
! 			  return FALSE;
! 			case TRY_AGAIN:
! 			  /* could either return FALSE or fall through and try
! 			     getcanonname() for this case. I choose to return....
! 			  */
! 			  return FALSE;
! 			default: /* NO_DATA, NO_ADDRESS, try a T_CNAME or T_ANY query */
! 			  status = getcanonname(hbuf, hbsize);
! 			  if (tTd(9, 1))
! 			      printf("maphostname [getcanonname(%s,%d)] => %.*s\n",
! 				     hbuf, hbsize, hbsize-1,
! 				     (status == FALSE) ? "NOT_FOUND" : hbuf);
! 
! 			  return (status == FALSE) ? FALSE : TRUE;
! 		      }
  		}
+ #endif /* defined(GETHOSTBYNAME_ISNT_ENOUGH) && defined(NAMED_BIND) */
  	}
! 
  	if (hp == NULL)
! 	    return FALSE;
  
  	if (strlen(hp->h_name) >= hbsize)
  		hp->h_name[hbsize - 1] = '\0';

--
* Isaac J. Salzman                                            ----     
* The RAND Corporation - Information Sciences Dept.          /o o/  /  
* 1700 Main St., PO Box 2138, Santa Monica, CA 90406-2138    | v |  |  
* AT&T: +1 213-393-0411 x6421 or x7923 (ISL lab)            _|   |_/   
* ARPA: salzman@RAND.ORG or salzman@rand-unix.ARPA         / |   |
* UUCP: ...!{cbosgd,decvax,sdcrdcf}!randvax!salzman        | |   |     

vixie@decwrl.dec.com (Paul A Vixie) (02/12/89)

I've been hacking IDA sendmail to make it find MX records in maphostname()
since Len released his first version.  I now realize that for unconnected
sites (no SMTP or DNS) this is wrong and in fact, Len's method is better.

Rathewr than #ifdef'ing it, can someone add a config-file option?  And
preferrably convince Len to buy back the change so I don't have to maintain
hacked source?

More and more I am convinced that sendmail is a solution in search of a
problem.  This is all too complex.
--
Paul Vixie
Work:    vixie@decwrl.dec.com    decwrl!vixie    +1 415 853 6600
Play:    paul@vixie.sf.ca.us     vixie!paul      +1 415 864 7013