1 /*
2  * "$Id: http-addr.c 148 2006-04-25 16:54:17Z njacobs $"
3  *
4  *   HTTP address routines for the Common UNIX Printing System (CUPS).
5  *
6  *   Copyright 1997-2005 by Easy Software Products, all rights reserved.
7  *
8  *   These coded instructions, statements, and computer programs are the
9  *   property of Easy Software Products and are protected by Federal
10  *   copyright law.  Distribution and use rights are outlined in the file
11  *   "LICENSE.txt" which should have been included with this file.  If this
12  *   file is missing or damaged please contact Easy Software Products
13  *   at:
14  *
15  *       Attn: CUPS Licensing Information
16  *       Easy Software Products
17  *       44141 Airport View Drive, Suite 204
18  *       Hollywood, Maryland 20636 USA
19  *
20  *       Voice: (301) 373-9600
21  *       EMail: cups-info@cups.org
22  *         WWW: http://www.cups.org
23  *
24  * Contents:
25  *
26  *   httpAddrAny()       - Check for the "any" address.
27  *   httpAddrEqual()     - Compare two addresses.
28  *   httpAddrLoad()      - Load a host entry address into an HTTP address.
29  *   httpAddrLocalhost() - Check for the local loopback address.
30  *   httpAddrLookup()    - Lookup the hostname associated with the address.
31  *   httpAddrString()    - Convert an IP address to a dotted string.
32  *   httpGetHostByName() - Lookup a hostname or IP address, and return
33  *                         address records for the specified name.
34  */
35 
36 /*
37  * Include necessary headers...
38  */
39 
40 #pragma ident	"%Z%%M%	%I%	%E% SMI"
41 
42 #include "http.h"
43 #include "debug.h"
44 #include "string.h"
45 #include <ctype.h>
46 
47 
48 /*
49  * 'httpAddrAny()' - Check for the "any" address.
50  */
51 
52 int					/* O - 1 if "any", 0 otherwise */
53 httpAddrAny(const http_addr_t *addr)	/* I - Address to check */
54 {
55 #ifdef AF_INET6
56   if (addr->addr.sa_family == AF_INET6 &&
57       IN6_IS_ADDR_UNSPECIFIED(&(addr->ipv6.sin6_addr)))
58     return (1);
59 #endif /* AF_INET6 */
60 
61   if (addr->addr.sa_family == AF_INET &&
62       ntohl(addr->ipv4.sin_addr.s_addr) == 0x00000000)
63     return (1);
64 
65   return (0);
66 }
67 
68 
69 /*
70  * 'httpAddrEqual()' - Compare two addresses.
71  */
72 
73 int						/* O - 1 if equal, 0 if != */
74 httpAddrEqual(const http_addr_t *addr1,		/* I - First address */
75               const http_addr_t *addr2)		/* I - Second address */
76 {
77   if (addr1->addr.sa_family != addr2->addr.sa_family)
78     return (0);
79 
80 #ifdef AF_INET6
81   if (addr1->addr.sa_family == AF_INET6)
82     return (memcmp(&(addr1->ipv6.sin6_addr), &(addr2->ipv6.sin6_addr), 16) == 0);
83 #endif /* AF_INET6 */
84 
85   return (addr1->ipv4.sin_addr.s_addr == addr2->ipv4.sin_addr.s_addr);
86 }
87 
88 
89 /*
90  * 'httpAddrLoad()' - Load a host entry address into an HTTP address.
91  */
92 
93 void
94 httpAddrLoad(const struct hostent *host,	/* I - Host entry */
95              int                  port,		/* I - Port number */
96              int                  n,		/* I - Index into host entry */
97 	     http_addr_t          *addr)	/* O - Address to load */
98 {
99 #ifdef AF_INET6
100   if (host->h_addrtype == AF_INET6)
101   {
102 #  ifdef WIN32
103     addr->ipv6.sin6_port = htons((u_short)port);
104 #  else
105     addr->ipv6.sin6_port = htons(port);
106 #  endif /* WIN32 */
107 
108     memcpy((char *)&(addr->ipv6.sin6_addr), host->h_addr_list[n],
109            host->h_length);
110     addr->ipv6.sin6_family = AF_INET6;
111   }
112   else
113 #endif /* AF_INET6 */
114 #ifdef AF_LOCAL
115   if (host->h_addrtype == AF_LOCAL)
116   {
117     addr->un.sun_family = AF_LOCAL;
118     strlcpy(addr->un.sun_path, host->h_addr_list[n], sizeof(addr->un.sun_path));
119   }
120   else
121 #endif /* AF_LOCAL */
122   if (host->h_addrtype == AF_INET)
123   {
124 #  ifdef WIN32
125     addr->ipv4.sin_port = htons((u_short)port);
126 #  else
127     addr->ipv4.sin_port = htons(port);
128 #  endif /* WIN32 */
129 
130     memcpy((char *)&(addr->ipv4.sin_addr), host->h_addr_list[n],
131            host->h_length);
132     addr->ipv4.sin_family = AF_INET;
133   }
134 }
135 
136 
137 /*
138  * 'httpAddrLocalhost()' - Check for the local loopback address.
139  */
140 
141 int					/* O - 1 if local host, 0 otherwise */
142 httpAddrLocalhost(const http_addr_t *addr)
143 					/* I - Address to check */
144 {
145 #ifdef AF_INET6
146   if (addr->addr.sa_family == AF_INET6 &&
147       IN6_IS_ADDR_LOOPBACK(&(addr->ipv6.sin6_addr)))
148     return (1);
149 #endif /* AF_INET6 */
150 
151 #ifdef AF_LOCAL
152   if (addr->addr.sa_family == AF_LOCAL)
153     return (1);
154 #endif /* AF_LOCAL */
155 
156   if (addr->addr.sa_family == AF_INET &&
157       ntohl(addr->ipv4.sin_addr.s_addr) == 0x7f000001)
158     return (1);
159 
160   return (0);
161 }
162 
163 
164 #ifdef __sgi
165 #  define ADDR_CAST (struct sockaddr *)
166 #else
167 #  define ADDR_CAST (char *)
168 #endif /* __sgi */
169 
170 
171 /*
172  * 'httpAddrLookup()' - Lookup the hostname associated with the address.
173  */
174 
175 char *						/* O - Host name */
176 httpAddrLookup(const http_addr_t *addr,		/* I - Address to lookup */
177                char              *name,		/* I - Host name buffer */
178 	       int               namelen)	/* I - Size of name buffer */
179 {
180   struct hostent	*host;			/* Host from name service */
181 
182 
183   DEBUG_printf(("httpAddrLookup(addr=%p, name=%p, namelen=%d)\n",
184                 addr, name, namelen));
185 
186 #ifdef AF_INET6
187   if (addr->addr.sa_family == AF_INET6)
188     host = gethostbyaddr(ADDR_CAST &(addr->ipv6.sin6_addr),
189                          sizeof(struct in6_addr), AF_INET6);
190   else
191 #endif /* AF_INET6 */
192 #ifdef AF_LOCAL
193   if (addr->addr.sa_family == AF_LOCAL)
194   {
195     strlcpy(name, addr->un.sun_path, namelen);
196     return (name);
197   }
198   else
199 #endif /* AF_LOCAL */
200   if (addr->addr.sa_family == AF_INET)
201     host = gethostbyaddr(ADDR_CAST &(addr->ipv4.sin_addr),
202                          sizeof(struct in_addr), AF_INET);
203   else
204     host = NULL;
205 
206   if (host == NULL)
207   {
208     httpAddrString(addr, name, namelen);
209     return (NULL);
210   }
211 
212   strlcpy(name, host->h_name, namelen);
213 
214   return (name);
215 }
216 
217 
218 /*
219  * 'httpAddrString()' - Convert an IP address to a dotted string.
220  */
221 
222 char *						/* O - IP string */
223 httpAddrString(const http_addr_t *addr,		/* I - Address to convert */
224                char              *s,		/* I - String buffer */
225 	       int               slen)		/* I - Length of string */
226 {
227   DEBUG_printf(("httpAddrString(addr=%p, s=%p, slen=%d)\n",
228                 addr, s, slen));
229 
230 #ifdef AF_INET6
231   if (addr->addr.sa_family == AF_INET6)
232     snprintf(s, slen, "%u.%u.%u.%u",
233              ntohl(addr->ipv6.sin6_addr.s6_addr32[0]),
234              ntohl(addr->ipv6.sin6_addr.s6_addr32[1]),
235              ntohl(addr->ipv6.sin6_addr.s6_addr32[2]),
236              ntohl(addr->ipv6.sin6_addr.s6_addr32[3]));
237   else
238 #endif /* AF_INET6 */
239 #ifdef AF_LOCAL
240   if (addr->addr.sa_family == AF_LOCAL)
241     strlcpy(s, addr->un.sun_path, slen);
242   else
243 #endif /* AF_LOCAL */
244   if (addr->addr.sa_family == AF_INET)
245   {
246     unsigned temp;				/* Temporary address */
247 
248 
249     temp = ntohl(addr->ipv4.sin_addr.s_addr);
250 
251     snprintf(s, slen, "%d.%d.%d.%d", (temp >> 24) & 255,
252              (temp >> 16) & 255, (temp >> 8) & 255, temp & 255);
253   }
254   else
255     strlcpy(s, "UNKNOWN", slen);
256 
257   DEBUG_printf(("httpAddrString: returning \"%s\"...\n", s));
258 
259   return (s);
260 }
261 
262 
263 /*
264  * 'httpGetHostByName()' - Lookup a hostname or IP address, and return
265  *                         address records for the specified name.
266  */
267 
268 struct hostent *			/* O - Host entry */
269 httpGetHostByName(const char *name)	/* I - Hostname or IP address */
270 {
271   const char		*nameptr;	/* Pointer into name */
272   unsigned		ip[4];		/* IP address components */
273   static unsigned	packed_ip;	/* Packed IPv4 address */
274   static char		*packed_ptr[2];	/* Pointer to packed address */
275   static struct hostent	host_ip;	/* Host entry for IP/domain address */
276 
277 
278   DEBUG_printf(("httpGetHostByName(name=\"%s\")\n", name));
279 
280 #if defined(__APPLE__)
281   /* OS X hack to avoid it's ocassional long delay in lookupd */
282   static const char sLoopback[] = "127.0.0.1";
283   if (strcmp(name, "localhost") == 0)
284     name = sLoopback;
285 #endif /* __APPLE__ */
286 
287  /*
288   * This function is needed because some operating systems have a
289   * buggy implementation of gethostbyname() that does not support
290   * IP addresses.  If the first character of the name string is a
291   * number, then sscanf() is used to extract the IP components.
292   * We then pack the components into an IPv4 address manually,
293   * since the inet_aton() function is deprecated.  We use the
294   * htonl() macro to get the right byte order for the address.
295   *
296   * We also support domain sockets when supported by the underlying
297   * OS...
298   */
299 
300 #ifdef AF_LOCAL
301   if (name[0] == '/')
302   {
303    /*
304     * A domain socket address, so make an AF_LOCAL entry and return it...
305     */
306 
307     host_ip.h_name      = (char *)name;
308     host_ip.h_aliases   = NULL;
309     host_ip.h_addrtype  = AF_LOCAL;
310     host_ip.h_length    = strlen(name) + 1;
311     host_ip.h_addr_list = packed_ptr;
312     packed_ptr[0]       = (char *)name;
313     packed_ptr[1]       = NULL;
314 
315     DEBUG_puts("httpGetHostByName: returning domain socket address...");
316 
317     return (&host_ip);
318   }
319 #endif /* AF_LOCAL */
320 
321   for (nameptr = name; isdigit(*nameptr & 255) || *nameptr == '.'; nameptr ++);
322 
323   if (!*nameptr)
324   {
325    /*
326     * We have an IP address; break it up and provide the host entry
327     * to the caller.  Currently only supports IPv4 addresses, although
328     * it should be trivial to support IPv6 in CUPS 1.2.
329     */
330 
331     if (sscanf(name, "%u.%u.%u.%u", ip, ip + 1, ip + 2, ip + 3) != 4)
332       return (NULL);			/* Must have 4 numbers */
333 
334     if (ip[0] > 255 || ip[1] > 255 || ip[2] > 255 || ip[3] > 255)
335       return (NULL);			/* Invalid byte ranges! */
336 
337     packed_ip = htonl(((((((ip[0] << 8) | ip[1]) << 8) | ip[2]) << 8) | ip[3]));
338 
339    /*
340     * Fill in the host entry and return it...
341     */
342 
343     host_ip.h_name      = (char *)name;
344     host_ip.h_aliases   = NULL;
345     host_ip.h_addrtype  = AF_INET;
346     host_ip.h_length    = 4;
347     host_ip.h_addr_list = packed_ptr;
348     packed_ptr[0]       = (char *)(&packed_ip);
349     packed_ptr[1]       = NULL;
350 
351     DEBUG_puts("httpGetHostByName: returning IPv4 address...");
352 
353     return (&host_ip);
354   }
355   else
356   {
357    /*
358     * Use the gethostbyname() function to get the IP address for
359     * the name...
360     */
361 
362     DEBUG_puts("httpGetHostByName: returning domain lookup address(es)...");
363 
364     return (gethostbyname(name));
365   }
366 }
367 
368 
369 /*
370  * End of "$Id: http-addr.c 148 2006-04-25 16:54:17Z njacobs $".
371  */
372