]> git.ipfire.org Git - thirdparty/cups.git/blob - cups/http-addr.c
121b47ddbbd15915ffb34fa1ca0e579b11f0433a
[thirdparty/cups.git] / cups / http-addr.c
1 /*
2 * "$Id$"
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 "globals.h"
41 #include "debug.h"
42 #include <stdlib.h>
43
44
45 /*
46 * 'httpAddrAny()' - Check for the "any" address.
47 */
48
49 int /* O - 1 if "any", 0 otherwise */
50 httpAddrAny(const http_addr_t *addr) /* I - Address to check */
51 {
52 #ifdef AF_INET6
53 if (addr->addr.sa_family == AF_INET6 &&
54 IN6_IS_ADDR_UNSPECIFIED(&(addr->ipv6.sin6_addr)))
55 return (1);
56 #endif /* AF_INET6 */
57
58 if (addr->addr.sa_family == AF_INET &&
59 ntohl(addr->ipv4.sin_addr.s_addr) == 0x00000000)
60 return (1);
61
62 return (0);
63 }
64
65
66 /*
67 * 'httpAddrEqual()' - Compare two addresses.
68 */
69
70 int /* O - 1 if equal, 0 if != */
71 httpAddrEqual(const http_addr_t *addr1, /* I - First address */
72 const http_addr_t *addr2) /* I - Second address */
73 {
74 if (addr1->addr.sa_family != addr2->addr.sa_family)
75 return (0);
76
77 #ifdef AF_LOCAL
78 if (addr1->addr.sa_family == AF_LOCAL)
79 return (!strcmp(addr1->un.sun_path, addr2->un.sun_path));
80 #endif /* AF_LOCAL */
81
82 #ifdef AF_INET6
83 if (addr1->addr.sa_family == AF_INET6)
84 return (memcmp(&(addr1->ipv6.sin6_addr), &(addr2->ipv6.sin6_addr), 16) == 0);
85 #endif /* AF_INET6 */
86
87 return (addr1->ipv4.sin_addr.s_addr == addr2->ipv4.sin_addr.s_addr);
88 }
89
90
91 /*
92 * 'httpAddrLength()' - Return the length of the address in bytes.
93 */
94
95 int /* O - Length in bytes */
96 httpAddrLength(const http_addr_t *addr) /* I - Address */
97 {
98 #ifdef AF_INET6
99 if (addr->addr.sa_family == AF_INET6)
100 return (sizeof(addr->ipv6));
101 else
102 #endif /* AF_INET6 */
103 #ifdef AF_LOCAL
104 if (addr->addr.sa_family == AF_LOCAL)
105 return (sizeof(addr->un.sun_family) + strlen(addr->un.sun_path));
106 else
107 #endif /* AF_LOCAL */
108 if (addr->addr.sa_family == AF_INET)
109 return (sizeof(addr->ipv4));
110 else
111 return (0);
112
113 }
114
115
116 /*
117 * 'httpAddrLoad()' - Load a host entry address into an HTTP address.
118 */
119
120 void
121 httpAddrLoad(const struct hostent *host, /* I - Host entry */
122 int port, /* I - Port number */
123 int n, /* I - Index into host entry */
124 http_addr_t *addr) /* O - Address to load */
125 {
126 #ifdef AF_INET6
127 if (host->h_addrtype == AF_INET6)
128 {
129 # ifdef WIN32
130 addr->ipv6.sin6_port = htons((u_short)port);
131 # else
132 addr->ipv6.sin6_port = htons(port);
133 # endif /* WIN32 */
134
135 memcpy((char *)&(addr->ipv6.sin6_addr), host->h_addr_list[n],
136 host->h_length);
137 addr->ipv6.sin6_family = AF_INET6;
138 }
139 else
140 #endif /* AF_INET6 */
141 #ifdef AF_LOCAL
142 if (host->h_addrtype == AF_LOCAL)
143 {
144 addr->un.sun_family = AF_LOCAL;
145 strlcpy(addr->un.sun_path, host->h_addr_list[n], sizeof(addr->un.sun_path));
146 }
147 else
148 #endif /* AF_LOCAL */
149 if (host->h_addrtype == AF_INET)
150 {
151 # ifdef WIN32
152 addr->ipv4.sin_port = htons((u_short)port);
153 # else
154 addr->ipv4.sin_port = htons(port);
155 # endif /* WIN32 */
156
157 memcpy((char *)&(addr->ipv4.sin_addr), host->h_addr_list[n],
158 host->h_length);
159 addr->ipv4.sin_family = AF_INET;
160 }
161 }
162
163
164 /*
165 * 'httpAddrLocalhost()' - Check for the local loopback address.
166 */
167
168 int /* O - 1 if local host, 0 otherwise */
169 httpAddrLocalhost(const http_addr_t *addr)
170 /* I - Address to check */
171 {
172 #ifdef AF_INET6
173 if (addr->addr.sa_family == AF_INET6 &&
174 (IN6_IS_ADDR_LOOPBACK(&(addr->ipv6.sin6_addr)) ||
175 IN6_IS_ADDR_UNSPECIFIED(&(addr->ipv6.sin6_addr))))
176 return (1);
177 #endif /* AF_INET6 */
178
179 #ifdef AF_LOCAL
180 if (addr->addr.sa_family == AF_LOCAL)
181 return (1);
182 #endif /* AF_LOCAL */
183
184 if (addr->addr.sa_family == AF_INET &&
185 ntohl(addr->ipv4.sin_addr.s_addr) == 0x7f000001)
186 return (1);
187
188 return (0);
189 }
190
191
192 #ifdef __sgi
193 # define ADDR_CAST (struct sockaddr *)
194 #else
195 # define ADDR_CAST (char *)
196 #endif /* __sgi */
197
198
199 /*
200 * 'httpAddrLookup()' - Lookup the hostname associated with the address.
201 */
202
203 char * /* O - Host name */
204 httpAddrLookup(const http_addr_t *addr, /* I - Address to lookup */
205 char *name, /* I - Host name buffer */
206 int namelen) /* I - Size of name buffer */
207 {
208 struct hostent *host; /* Host from name service */
209
210
211 DEBUG_printf(("httpAddrLookup(addr=%p, name=%p, namelen=%d)\n",
212 addr, name, namelen));
213
214 #ifdef AF_INET6
215 if (addr->addr.sa_family == AF_INET6)
216 host = gethostbyaddr(ADDR_CAST &(addr->ipv6.sin6_addr),
217 sizeof(struct in6_addr), AF_INET6);
218 else
219 #endif /* AF_INET6 */
220 #ifdef AF_LOCAL
221 if (addr->addr.sa_family == AF_LOCAL)
222 {
223 strlcpy(name, addr->un.sun_path, namelen);
224 return (name);
225 }
226 else
227 #endif /* AF_LOCAL */
228 if (addr->addr.sa_family == AF_INET)
229 host = gethostbyaddr(ADDR_CAST &(addr->ipv4.sin_addr),
230 sizeof(struct in_addr), AF_INET);
231 else
232 host = NULL;
233
234 if (host == NULL)
235 {
236 httpAddrString(addr, name, namelen);
237 return (NULL);
238 }
239
240 strlcpy(name, host->h_name, namelen);
241
242 return (name);
243 }
244
245
246 /*
247 * 'httpAddrString()' - Convert an IP address to a dotted string.
248 */
249
250 char * /* O - IP string */
251 httpAddrString(const http_addr_t *addr, /* I - Address to convert */
252 char *s, /* I - String buffer */
253 int slen) /* I - Length of string */
254 {
255 DEBUG_printf(("httpAddrString(addr=%p, s=%p, slen=%d)\n",
256 addr, s, slen));
257
258 #ifdef AF_INET6
259 if (addr->addr.sa_family == AF_INET6)
260 snprintf(s, slen, "[%x:%x:%x:%x]",
261 ntohl(addr->ipv6.sin6_addr.s6_addr32[0]),
262 ntohl(addr->ipv6.sin6_addr.s6_addr32[1]),
263 ntohl(addr->ipv6.sin6_addr.s6_addr32[2]),
264 ntohl(addr->ipv6.sin6_addr.s6_addr32[3]));
265 else
266 #endif /* AF_INET6 */
267 #ifdef AF_LOCAL
268 if (addr->addr.sa_family == AF_LOCAL)
269 strlcpy(s, addr->un.sun_path, slen);
270 else
271 #endif /* AF_LOCAL */
272 if (addr->addr.sa_family == AF_INET)
273 {
274 unsigned temp; /* Temporary address */
275
276
277 temp = ntohl(addr->ipv4.sin_addr.s_addr);
278
279 snprintf(s, slen, "%d.%d.%d.%d", (temp >> 24) & 255,
280 (temp >> 16) & 255, (temp >> 8) & 255, temp & 255);
281 }
282 else
283 strlcpy(s, "UNKNOWN", slen);
284
285 DEBUG_printf(("httpAddrString: returning \"%s\"...\n", s));
286
287 return (s);
288 }
289
290
291 /*
292 * 'httpGetHostByName()' - Lookup a hostname or IP address, and return
293 * address records for the specified name.
294 */
295
296 struct hostent * /* O - Host entry */
297 httpGetHostByName(const char *name) /* I - Hostname or IP address */
298 {
299 int i; /* Looping var */
300 const char *nameptr; /* Pointer into name */
301 unsigned ip[4]; /* IP address components */
302 _cups_globals_t *cg = _cupsGlobals();
303 /* Pointer to library globals */
304
305
306 DEBUG_printf(("httpGetHostByName(name=\"%s\")\n", name));
307
308 /*
309 * Avoid lookup delays and configuration problems when connecting
310 * to the localhost address...
311 */
312
313 if (!strcmp(name, "localhost"))
314 name = "127.0.0.1";
315
316 /*
317 * This function is needed because some operating systems have a
318 * buggy implementation of gethostbyname() that does not support
319 * IP addresses. If the first character of the name string is a
320 * number, then sscanf() is used to extract the IP components.
321 * We then pack the components into an IPv4 address manually,
322 * since the inet_aton() function is deprecated. We use the
323 * htonl() macro to get the right byte order for the address.
324 *
325 * We also support domain sockets when supported by the underlying
326 * OS...
327 */
328
329 #ifdef AF_LOCAL
330 if (name[0] == '/')
331 {
332 /*
333 * A domain socket address, so make an AF_LOCAL entry and return it...
334 */
335
336 cg->hostent.h_name = (char *)name;
337 cg->hostent.h_aliases = NULL;
338 cg->hostent.h_addrtype = AF_LOCAL;
339 cg->hostent.h_length = strlen(name) + 1;
340 cg->hostent.h_addr_list = cg->ip_ptrs;
341 cg->ip_ptrs[0] = (char *)name;
342 cg->ip_ptrs[1] = NULL;
343
344 DEBUG_puts("httpGetHostByName: returning domain socket address...");
345
346 return (&cg->hostent);
347 }
348 #endif /* AF_LOCAL */
349 #ifdef AF_INET6
350 if (name[0] == '[')
351 {
352 /*
353 * A raw 128-bit IPv6 address of the form "[xxxx:xxxx:xxxx:xxxx]"
354 */
355
356 cg->hostent.h_name = (char *)name;
357 cg->hostent.h_aliases = NULL;
358 cg->hostent.h_addrtype = AF_INET6;
359 cg->hostent.h_length = 16;
360 cg->hostent.h_addr_list = cg->ip_ptrs;
361 cg->ip_ptrs[0] = (char *)(cg->ip_addrs[0]);
362 cg->ip_ptrs[1] = NULL;
363
364 for (i = 0, nameptr = name + 1; *nameptr && i < 4; i ++)
365 {
366 if (*nameptr == ']')
367 break;
368 else if (*nameptr == ':')
369 cg->ip_addrs[0][i] = 0;
370 else
371 cg->ip_addrs[0][i] = htonl(strtoul(nameptr, (char **)&nameptr, 16));
372
373 if (*nameptr == ':' || *nameptr == ']')
374 nameptr ++;
375 }
376
377 while (i < 4)
378 {
379 cg->ip_addrs[0][i] = 0;
380 i ++;
381 }
382
383 if (*nameptr)
384 return (NULL);
385
386 DEBUG_puts("httpGetHostByName: returning IPv6 address...");
387
388 return (&cg->hostent);
389 }
390 #endif /* AF_INET6 */
391
392 for (nameptr = name; isdigit(*nameptr & 255) || *nameptr == '.'; nameptr ++);
393
394 if (!*nameptr)
395 {
396 /*
397 * We have an IPv4 address; break it up and provide the host entry
398 * to the caller.
399 */
400
401 if (sscanf(name, "%u.%u.%u.%u", ip, ip + 1, ip + 2, ip + 3) != 4)
402 return (NULL); /* Must have 4 numbers */
403
404 if (ip[0] > 255 || ip[1] > 255 || ip[2] > 255 || ip[3] > 255)
405 return (NULL); /* Invalid byte ranges! */
406
407 cg->ip_addrs[0][0] = htonl(((((((ip[0] << 8) | ip[1]) << 8) | ip[2]) << 8) |
408 ip[3]));
409
410 /*
411 * Fill in the host entry and return it...
412 */
413
414 cg->hostent.h_name = (char *)name;
415 cg->hostent.h_aliases = NULL;
416 cg->hostent.h_addrtype = AF_INET;
417 cg->hostent.h_length = 4;
418 cg->hostent.h_addr_list = cg->ip_ptrs;
419 cg->ip_ptrs[0] = (char *)cg->ip_addrs[0];
420 cg->ip_ptrs[1] = NULL;
421
422 DEBUG_puts("httpGetHostByName: returning IPv4 address...");
423
424 return (&cg->hostent);
425 }
426 else
427 #ifdef HAVE_GETADDRINFO
428 {
429 /*
430 * Use the getaddrinfo() function to get the IP address for the
431 * name...
432 */
433
434 struct addrinfo hints, /* Address lookup hints */
435 *results, /* Address lookup results */
436 *current; /* Current result */
437 http_addr_t *address; /* Current address */
438
439
440 memset(&hints, 0, sizeof(hints));
441 hints.ai_family = PF_UNSPEC;
442 hints.ai_socktype = SOCK_STREAM;
443 hints.ai_flags = AI_CANONNAME;
444
445 if (getaddrinfo(name, NULL, &hints, &results))
446 {
447 /*
448 * If getaddrinfo() fails, try gethostbyname()...
449 */
450
451 return (gethostbyname(name));
452 }
453
454 /*
455 * Initialize hostent structure, preferring the IPv6 address...
456 */
457
458 for (current = results; current; current = current->ai_next)
459 if (current->ai_family == AF_INET6)
460 break;
461
462 if (!current)
463 {
464 for (current = results; current; current = current->ai_next)
465 if (current->ai_family == AF_INET)
466 break;
467
468 if (!current)
469 {
470 /*
471 * No IPv4 or IPv6 addresses, try gethostbyname()...
472 */
473
474 freeaddrinfo(results);
475
476 return (gethostbyname(name));
477 }
478 }
479
480 strlcpy(cg->hostname, current->ai_canonname, sizeof(cg->hostname));
481
482 cg->hostent.h_name = cg->hostname;
483 cg->hostent.h_aliases = NULL;
484 cg->hostent.h_addrtype = current->ai_family;
485 cg->hostent.h_addr_list = cg->ip_ptrs;
486
487 if (current->ai_family == AF_INET6)
488 cg->hostent.h_length = 16;
489 else
490 cg->hostent.h_length = 4;
491
492 /*
493 * Convert the address info to a hostent structure...
494 */
495
496 for (i = 0, current = results;
497 i < CUPS_MAX_ADDRS && current;
498 current = current->ai_next)
499 if (current->ai_family == cg->hostent.h_addrtype)
500 {
501 /*
502 * Copy this address...
503 */
504
505 address = (http_addr_t *)(current->ai_addr);
506
507 if (current->ai_family == AF_INET)
508 memcpy((char *)cg->ip_addrs[i], (char *)&(address->ipv4.sin_addr), 4);
509 else
510 memcpy((char *)cg->ip_addrs[i], (char *)&(address->ipv6.sin6_addr), 16);
511
512 cg->ip_ptrs[i] = (char *)cg->ip_addrs[i];
513 i ++;
514 }
515
516 cg->ip_ptrs[i] = NULL;
517
518 /*
519 * Free the getaddrinfo() results and return the hostent structure...
520 */
521
522 freeaddrinfo(results);
523
524 return (&cg->hostent);
525 }
526 #else
527 {
528 /*
529 * Use the gethostbyname() function to get the IP address for
530 * the name...
531 */
532
533 DEBUG_puts("httpGetHostByName: returning domain lookup address(es)...");
534
535 return (gethostbyname(name));
536 }
537 #endif /* HAVE_GETADDRINFO */
538 }
539
540
541 /*
542 * 'httpGetHostname()' - Get the FQDN for the local system.
543 *
544 * This function uses both gethostname() and gethostbyname() to
545 * get the local hostname with domain.
546 */
547
548 const char * /* O - FQDN for this system */
549 httpGetHostname(char *s, /* I - String buffer for name */
550 int slen) /* I - Size of buffer */
551 {
552 struct hostent *host; /* Host entry to get FQDN */
553
554
555 /*
556 * Get the hostname...
557 */
558
559 gethostname(s, slen);
560
561 if (!strchr(s, '.'))
562 {
563 /*
564 * The hostname is not a FQDN, so look it up...
565 */
566
567 if ((host = gethostbyname(s)) != NULL)
568 strlcpy(s, host->h_name, slen);
569 }
570
571 /*
572 * Return the hostname with as much domain info as we have...
573 */
574
575 return (s);
576 }
577
578
579 /*
580 * End of "$Id$".
581 */