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