sm_gethost.c revision 261363
1/*
2 *  Copyright (c) 1999-2001, 2004, 2010, 2013 Proofpoint, Inc. and its suppliers.
3 *	All rights reserved.
4 *
5 * By using this file, you agree to the terms and conditions set
6 * forth in the LICENSE file which can be found at the top level of
7 * the sendmail distribution.
8 *
9 */
10
11#include <sm/gen.h>
12SM_RCSID("@(#)$Id: sm_gethost.c,v 8.32 2013/11/22 20:51:36 ca Exp $")
13
14#include <sendmail.h>
15#if NETINET || NETINET6
16# include <arpa/inet.h>
17#endif /* NETINET || NETINET6 */
18#include "libmilter.h"
19
20/*
21**  MI_GETHOSTBY{NAME,ADDR} -- compatibility routines for gethostbyXXX
22**
23**	Some operating systems have wierd problems with the gethostbyXXX
24**	routines.  For example, Solaris versions at least through 2.3
25**	don't properly deliver a canonical h_name field.  This tries to
26**	work around these problems.
27**
28**	Support IPv6 as well as IPv4.
29*/
30
31#if NETINET6 && NEEDSGETIPNODE
32
33static struct hostent *sm_getipnodebyname __P((const char *, int, int, int *));
34
35# ifndef AI_ADDRCONFIG
36#  define AI_ADDRCONFIG	0	/* dummy */
37# endif /* ! AI_ADDRCONFIG */
38# ifndef AI_ALL
39#  define AI_ALL	0	/* dummy */
40# endif /* ! AI_ALL */
41# ifndef AI_DEFAULT
42#  define AI_DEFAULT	0	/* dummy */
43# endif /* ! AI_DEFAULT */
44
45static struct hostent *
46sm_getipnodebyname(name, family, flags, err)
47	const char *name;
48	int family;
49	int flags;
50	int *err;
51{
52	bool resv6 = true;
53	struct hostent *h;
54
55	if (family == AF_INET6)
56	{
57		/* From RFC2133, section 6.1 */
58		resv6 = bitset(RES_USE_INET6, _res.options);
59		_res.options |= RES_USE_INET6;
60	}
61	SM_SET_H_ERRNO(0);
62	h = gethostbyname(name);
63	if (family == AF_INET6 && !resv6)
64		_res.options &= ~RES_USE_INET6;
65
66	/* the function is supposed to return only the requested family */
67	if (h != NULL && h->h_addrtype != family)
68	{
69# if NETINET6
70		freehostent(h);
71# endif /* NETINET6 */
72		h = NULL;
73		*err = NO_DATA;
74	}
75	else
76		*err = h_errno;
77	return h;
78}
79
80void
81freehostent(h)
82	struct hostent *h;
83{
84	/*
85	**  Stub routine -- if they don't have getipnodeby*(),
86	**  they probably don't have the free routine either.
87	*/
88
89	return;
90}
91#else /* NEEDSGETIPNODE && NETINET6 */
92#define sm_getipnodebyname getipnodebyname
93#endif /* NEEDSGETIPNODE && NETINET6 */
94
95struct hostent *
96mi_gethostbyname(name, family)
97	char *name;
98	int family;
99{
100	struct hostent *h = NULL;
101#if (SOLARIS > 10000 && SOLARIS < 20400) || (defined(SOLARIS) && SOLARIS < 204) || (defined(sony_news) && defined(__svr4))
102# if SOLARIS == 20300 || SOLARIS == 203
103	static struct hostent hp;
104	static char buf[1000];
105	extern struct hostent *_switch_gethostbyname_r();
106
107	h = _switch_gethostbyname_r(name, &hp, buf, sizeof(buf), &h_errno);
108# else /* SOLARIS == 20300 || SOLARIS == 203 */
109	extern struct hostent *__switch_gethostbyname();
110
111	h = __switch_gethostbyname(name);
112# endif /* SOLARIS == 20300 || SOLARIS == 203 */
113#else /* (SOLARIS > 10000 && SOLARIS < 20400) || (defined(SOLARIS) && SOLARIS < 204) || (defined(sony_news) && defined(__svr4)) */
114# if NETINET6
115#  ifndef SM_IPNODEBYNAME_FLAGS
116    /* For IPv4-mapped addresses, use: AI_DEFAULT|AI_ALL */
117#   define SM_IPNODEBYNAME_FLAGS	AI_ADDRCONFIG
118#  endif /* SM_IPNODEBYNAME_FLAGS */
119
120	int flags = SM_IPNODEBYNAME_FLAGS;
121	int err;
122# endif /* NETINET6 */
123
124# if NETINET6
125#  if ADDRCONFIG_IS_BROKEN
126	flags &= ~AI_ADDRCONFIG;
127#  endif /* ADDRCONFIG_IS_BROKEN */
128	h = sm_getipnodebyname(name, family, flags, &err);
129	SM_SET_H_ERRNO(err);
130# else /* NETINET6 */
131	h = gethostbyname(name);
132# endif /* NETINET6 */
133
134#endif /* (SOLARIS > 10000 && SOLARIS < 20400) || (defined(SOLARIS) && SOLARIS < 204) || (defined(sony_news) && defined(__svr4)) */
135
136	/* the function is supposed to return only the requested family */
137	if (h != NULL && h->h_addrtype != family)
138	{
139# if NETINET6
140		freehostent(h);
141# endif /* NETINET6 */
142		h = NULL;
143		SM_SET_H_ERRNO(NO_DATA);
144	}
145	return h;
146}
147
148#if NETINET6
149/*
150**  MI_INET_PTON -- convert printed form to network address.
151**
152**	Wrapper for inet_pton() which handles IPv6: labels.
153**
154**	Parameters:
155**		family -- address family
156**		src -- string
157**		dst -- destination address structure
158**
159**	Returns:
160**		1 if the address was valid
161**		0 if the address wasn't parseable
162**		-1 if error
163*/
164
165int
166mi_inet_pton(family, src, dst)
167	int family;
168	const char *src;
169	void *dst;
170{
171	if (family == AF_INET6 &&
172	    strncasecmp(src, "IPv6:", 5) == 0)
173		src += 5;
174	return inet_pton(family, src, dst);
175}
176#endif /* NETINET6 */
177