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