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
52int					/* O - 1 if "any", 0 otherwise */
53httpAddrAny(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
73int						/* O - 1 if equal, 0 if != */
74httpAddrEqual(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
93void
94httpAddrLoad(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
141int					/* O - 1 if local host, 0 otherwise */
142httpAddrLocalhost(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
175char *						/* O - Host name */
176httpAddrLookup(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
222char *						/* O - IP string */
223httpAddrString(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
268struct hostent *			/* O - Host entry */
269httpGetHostByName(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