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