]> git.ipfire.org Git - thirdparty/cups.git/blame - cups/http-addr.c
Fix domain socket handling (STR #1277)
[thirdparty/cups.git] / cups / http-addr.c
CommitLineData
e92958ad 1/*
c9d3f842 2 * "$Id$"
e92958ad 3 *
4 * HTTP address routines for the Common UNIX Printing System (CUPS).
5 *
c9d3f842 6 * Copyright 1997-2005 by Easy Software Products, all rights reserved.
e92958ad 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
c9d3f842 18 * Hollywood, Maryland 20636 USA
e92958ad 19 *
c4dcf3cc 20 * Voice: (301) 373-9600
e92958ad 21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
23 *
24 * Contents:
25 *
0f71c41e 26 * httpAddrAny() - Check for the "any" address.
e92958ad 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.
365cfbcc 32 * httpGetHostByName() - Lookup a hostname or IP address, and return
33 * address records for the specified name.
e92958ad 34 */
35
36/*
37 * Include necessary headers...
38 */
39
03f61bf3 40#include "globals.h"
e92958ad 41#include "debug.h"
7c298ddc 42#include <stdlib.h>
e92958ad 43
44
0f71c41e 45/*
46 * 'httpAddrAny()' - Check for the "any" address.
47 */
48
49int /* O - 1 if "any", 0 otherwise */
50httpAddrAny(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
e92958ad 66/*
67 * 'httpAddrEqual()' - Compare two addresses.
68 */
69
70int /* O - 1 if equal, 0 if != */
71httpAddrEqual(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
928c0377 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
e92958ad 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
a36f3f3d 91/*
92 * 'httpAddrLength()' - Return the length of the address in bytes.
93 */
94
95int /* O - Length in bytes */
96httpAddrLength(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
e92958ad 116/*
117 * 'httpAddrLoad()' - Load a host entry address into an HTTP address.
118 */
119
120void
121httpAddrLoad(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);
ed093015 137 addr->ipv6.sin6_family = AF_INET6;
e92958ad 138 }
139 else
140#endif /* AF_INET6 */
1fcc120e 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)
e92958ad 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);
ed093015 159 addr->ipv4.sin_family = AF_INET;
e92958ad 160 }
161}
162
163
164/*
165 * 'httpAddrLocalhost()' - Check for the local loopback address.
166 */
167
0f71c41e 168int /* O - 1 if local host, 0 otherwise */
169httpAddrLocalhost(const http_addr_t *addr)
170 /* I - Address to check */
e92958ad 171{
172#ifdef AF_INET6
173 if (addr->addr.sa_family == AF_INET6 &&
7c298ddc 174 (IN6_IS_ADDR_LOOPBACK(&(addr->ipv6.sin6_addr)) ||
175 IN6_IS_ADDR_UNSPECIFIED(&(addr->ipv6.sin6_addr))))
e92958ad 176 return (1);
177#endif /* AF_INET6 */
178
8eba4f2f 179#ifdef AF_LOCAL
c6075312 180 if (addr->addr.sa_family == AF_LOCAL)
181 return (1);
8eba4f2f 182#endif /* AF_LOCAL */
c6075312 183
e92958ad 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
203char * /* O - Host name */
204httpAddrLookup(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
8eba4f2f 211 DEBUG_printf(("httpAddrLookup(addr=%p, name=%p, namelen=%d)\n",
212 addr, name, namelen));
213
e92958ad 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 */
1fcc120e 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 */
e92958ad 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
1fcc120e 240 strlcpy(name, host->h_name, namelen);
e92958ad 241
242 return (name);
243}
244
245
246/*
247 * 'httpAddrString()' - Convert an IP address to a dotted string.
248 */
249
250char * /* O - IP string */
251httpAddrString(const http_addr_t *addr, /* I - Address to convert */
252 char *s, /* I - String buffer */
253 int slen) /* I - Length of string */
254{
8eba4f2f 255 DEBUG_printf(("httpAddrString(addr=%p, s=%p, slen=%d)\n",
256 addr, s, slen));
257
e92958ad 258#ifdef AF_INET6
259 if (addr->addr.sa_family == AF_INET6)
7c298ddc 260 snprintf(s, slen, "[%x:%x:%x:%x]",
e92958ad 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 */
c6075312 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 */
e92958ad 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
c6075312 283 strlcpy(s, "UNKNOWN", slen);
e92958ad 284
8eba4f2f 285 DEBUG_printf(("httpAddrString: returning \"%s\"...\n", s));
286
e92958ad 287 return (s);
288}
289
290
291/*
365cfbcc 292 * 'httpGetHostByName()' - Lookup a hostname or IP address, and return
293 * address records for the specified name.
294 */
295
296struct hostent * /* O - Host entry */
297httpGetHostByName(const char *name) /* I - Hostname or IP address */
298{
7c298ddc 299 int i; /* Looping var */
365cfbcc 300 const char *nameptr; /* Pointer into name */
301 unsigned ip[4]; /* IP address components */
2625096f 302 _cups_globals_t *cg = _cupsGlobals();
03f61bf3 303 /* Pointer to library globals */
365cfbcc 304
6db7190f 305
8eba4f2f 306 DEBUG_printf(("httpGetHostByName(name=\"%s\")\n", name));
307
03f61bf3 308 /*
309 * Avoid lookup delays and configuration problems when connecting
310 * to the localhost address...
311 */
312
7c298ddc 313 if (!strcmp(name, "localhost"))
03f61bf3 314 name = "127.0.0.1";
365cfbcc 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.
1fcc120e 324 *
325 * We also support domain sockets when supported by the underlying
326 * OS...
365cfbcc 327 */
328
1fcc120e 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
03f61bf3 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;
1fcc120e 343
8eba4f2f 344 DEBUG_puts("httpGetHostByName: returning domain socket address...");
345
03f61bf3 346 return (&cg->hostent);
1fcc120e 347 }
348#endif /* AF_LOCAL */
7c298ddc 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
03f61bf3 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;
7c298ddc 363
364 for (i = 0, nameptr = name + 1; *nameptr && i < 4; i ++)
365 {
366 if (*nameptr == ']')
367 break;
368 else if (*nameptr == ':')
03f61bf3 369 cg->ip_addrs[0][i] = 0;
7c298ddc 370 else
03f61bf3 371 cg->ip_addrs[0][i] = htonl(strtoul(nameptr, (char **)&nameptr, 16));
7c298ddc 372
373 if (*nameptr == ':' || *nameptr == ']')
374 nameptr ++;
375 }
376
377 while (i < 4)
378 {
03f61bf3 379 cg->ip_addrs[0][i] = 0;
7c298ddc 380 i ++;
381 }
382
383 if (*nameptr)
384 return (NULL);
385
386 DEBUG_puts("httpGetHostByName: returning IPv6 address...");
387
03f61bf3 388 return (&cg->hostent);
7c298ddc 389 }
390#endif /* AF_INET6 */
1fcc120e 391
64bbab09 392 for (nameptr = name; isdigit(*nameptr & 255) || *nameptr == '.'; nameptr ++);
365cfbcc 393
394 if (!*nameptr)
395 {
396 /*
7c298ddc 397 * We have an IPv4 address; break it up and provide the host entry
398 * to the caller.
365cfbcc 399 */
400
401 if (sscanf(name, "%u.%u.%u.%u", ip, ip + 1, ip + 2, ip + 3) != 4)
c5b73e9f 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! */
365cfbcc 406
03f61bf3 407 cg->ip_addrs[0][0] = htonl(((((((ip[0] << 8) | ip[1]) << 8) | ip[2]) << 8) |
7c298ddc 408 ip[3]));
365cfbcc 409
410 /*
411 * Fill in the host entry and return it...
412 */
413
03f61bf3 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;
365cfbcc 421
8eba4f2f 422 DEBUG_puts("httpGetHostByName: returning IPv4 address...");
423
03f61bf3 424 return (&cg->hostent);
365cfbcc 425 }
426 else
7c298ddc 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
03f61bf3 480 strlcpy(cg->hostname, current->ai_canonname, sizeof(cg->hostname));
7c298ddc 481
03f61bf3 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;
7c298ddc 486
f5f4dd62 487 if (current->ai_family == AF_INET6)
03f61bf3 488 cg->hostent.h_length = 16;
f5f4dd62 489 else
03f61bf3 490 cg->hostent.h_length = 4;
f5f4dd62 491
7c298ddc 492 /*
493 * Convert the address info to a hostent structure...
494 */
495
03f61bf3 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)
7c298ddc 500 {
501 /*
502 * Copy this address...
503 */
504
505 address = (http_addr_t *)(current->ai_addr);
506
507 if (current->ai_family == AF_INET)
03f61bf3 508 memcpy((char *)cg->ip_addrs[i], (char *)&(address->ipv4.sin_addr), 4);
7c298ddc 509 else
03f61bf3 510 memcpy((char *)cg->ip_addrs[i], (char *)&(address->ipv6.sin6_addr), 16);
7c298ddc 511
03f61bf3 512 cg->ip_ptrs[i] = (char *)cg->ip_addrs[i];
7c298ddc 513 i ++;
514 }
515
03f61bf3 516 cg->ip_ptrs[i] = NULL;
7c298ddc 517
518 /*
519 * Free the getaddrinfo() results and return the hostent structure...
520 */
521
522 freeaddrinfo(results);
523
03f61bf3 524 return (&cg->hostent);
7c298ddc 525 }
526#else
365cfbcc 527 {
528 /*
529 * Use the gethostbyname() function to get the IP address for
530 * the name...
531 */
532
8eba4f2f 533 DEBUG_puts("httpGetHostByName: returning domain lookup address(es)...");
534
365cfbcc 535 return (gethostbyname(name));
536 }
7c298ddc 537#endif /* HAVE_GETADDRINFO */
365cfbcc 538}
539
540
0a283777 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
548const char * /* O - FQDN for this system */
549httpGetHostname(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
365cfbcc 579/*
c9d3f842 580 * End of "$Id$".
e92958ad 581 */