File indexing completed on 2023-09-24 04:04:59
0001 /* 0002 * This file is part of the KDE libraries 0003 * Copyright (C) 2000,2001 Thiago Macieira <thiago.macieira@kdemail.net> 0004 * 0005 * This library is free software; you can redistribute it and/or 0006 * modify it under the terms of the GNU Library General Public 0007 * License as published by the Free Software Foundation; either 0008 * version 2 of the License, or (at your option) any later version. 0009 * 0010 * This library is distributed in the hope that it will be useful, 0011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0013 * Library General Public License for more details. 0014 * 0015 * You should have received a copy of the GNU Library General Public License 0016 * along with this library; see the file COPYING.LIB. If not, write to 0017 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0018 * Boston, MA 02110-1301, USA. 0019 **/ 0020 0021 #include <sys/types.h> 0022 #include <sys/un.h> 0023 #include <netinet/in.h> 0024 #include <stdlib.h> 0025 #include <stdio.h> 0026 #include <errno.h> 0027 #include <unistd.h> 0028 #include <arpa/inet.h> 0029 0030 #include <kdebug.h> 0031 0032 // This is so that, if addrinfo is defined, it doesn't clobber our definition 0033 // It might be defined in the few cases in which we are replacing the system's 0034 // broken getaddrinfo 0035 0036 #include "klocalizedstring.h" 0037 0038 #ifndef IN6_IS_ADDR_V4MAPPED 0039 #define NEED_IN6_TESTS 0040 #endif 0041 #undef CLOBBER_IN6 0042 #include "netsupp.h" //krazy:exclude=includes (netsupp.h not installed; KDE3 compat code) 0043 0044 #if defined(__hpux) || defined(_HPUX_SOURCE) 0045 extern int h_errno; 0046 #endif 0047 0048 #if !defined(kde_sockaddr_in6) 0049 /* 0050 * kde_sockaddr_in6 might have got defined even though we #undef'ed 0051 * CLOBBER_IN6. This happens when we are compiling under --enable-final. 0052 * However, in that case, if it was defined, that's because ksockaddr.cpp 0053 * had it defined because sockaddr_in6 didn't exist, and so sockaddr_in6 0054 * exists and is our kde_sockaddr_in6 0055 */ 0056 # define sockaddr_in6 kde_sockaddr_in6 0057 # define in6_addr kde_in6_addr 0058 #endif 0059 0060 #ifdef offsetof 0061 #undef offsetof 0062 #endif 0063 #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) 0064 0065 /* 0066 * These constants tell the flags in KDE::resolverFlags 0067 * The user could (but shouldn't) test the variable to know what kind of 0068 * resolution is supported 0069 */ 0070 #define KRF_KNOWS_AF_INET6 0x01 /* if present, the code knows about AF_INET6 */ 0071 #define KRF_USING_OWN_GETADDRINFO 0x02 /* if present, we are using our own getaddrinfo */ 0072 #define KRF_USING_OWN_INET_NTOP 0x04 /* if present, we are using our own inet_ntop */ 0073 #define KRF_USING_OWN_INET_PTON 0x08 /* if present, we are using our own inet_pton */ 0074 #define KRF_CAN_RESOLVE_UNIX 0x100 /* if present, the resolver can resolve Unix sockets */ 0075 #define KRF_CAN_RESOLVE_IPV4 0x200 /* if present, the resolver can resolve to IPv4 */ 0076 #define KRF_CAN_RESOLVE_IPV6 0x400 /* if present, the resolver can resolve to IPv6 */ 0077 0078 static void dofreeaddrinfo(struct addrinfo *ai) 0079 { 0080 while (ai) { 0081 struct addrinfo *ai2 = ai; 0082 if (ai->ai_canonname != nullptr) { 0083 free(ai->ai_canonname); 0084 } 0085 0086 if (ai->ai_addr != nullptr) { 0087 free(ai->ai_addr); 0088 } 0089 0090 ai = ai->ai_next; 0091 free(ai2); 0092 } 0093 } 0094 0095 void kde_freeaddrinfo(struct kde_addrinfo *ai) 0096 { 0097 if (ai->origin == KAI_LOCALUNIX) { 0098 struct addrinfo *p, *last = nullptr; 0099 /* We've added one AF_UNIX socket in here, to the 0100 * tail of the linked list. We have to find it */ 0101 for (p = ai->data; p; p = p->ai_next) { 0102 if (p->ai_family == AF_UNIX) { 0103 if (last) { 0104 last->ai_next = nullptr; 0105 freeaddrinfo(ai->data); 0106 } 0107 dofreeaddrinfo(p); 0108 break; 0109 } 0110 last = p; 0111 } 0112 } else { 0113 freeaddrinfo(ai->data); 0114 } 0115 0116 free(ai); 0117 } 0118 0119 static struct addrinfo * 0120 make_unix(const char *name, const char *serv) 0121 { 0122 const char *buf; 0123 struct addrinfo *p; 0124 struct sockaddr_un *_sun; 0125 int len; 0126 0127 p = (addrinfo *)malloc(sizeof(*p)); 0128 if (p == nullptr) { 0129 return nullptr; 0130 } 0131 memset(p, 0, sizeof(*p)); 0132 0133 if (name != nullptr) { 0134 buf = name; 0135 } else { 0136 buf = serv; 0137 } 0138 0139 // Calculate length of the binary representation 0140 len = strlen(buf) + offsetof(struct sockaddr_un, sun_path) + 1; 0141 if (*buf != '/') { 0142 len += 5; // strlen("/tmp/"); 0143 } 0144 0145 _sun = (sockaddr_un *)malloc(len); 0146 if (_sun == nullptr) { 0147 // Oops 0148 free(p); 0149 return nullptr; 0150 } 0151 0152 _sun->sun_family = AF_UNIX; 0153 # if HAVE_STRUCT_SOCKADDR_SA_LEN 0154 _sun->sun_len = len; 0155 # endif 0156 if (*buf == '/') { 0157 *_sun->sun_path = '\0'; // empty it 0158 } else { 0159 strcpy(_sun->sun_path, "/tmp/"); 0160 } 0161 strcat(_sun->sun_path, buf); 0162 0163 // Set the addrinfo 0164 p->ai_family = AF_UNIX; 0165 p->ai_addrlen = len; 0166 p->ai_addr = (sockaddr *)_sun; 0167 p->ai_canonname = qstrdup(buf); 0168 0169 return p; 0170 } 0171 0172 // Ugh. I hate #ifdefs 0173 // Anyways, here's what this does: 0174 // KDE_IPV6_LOOKUP_MODE != 1, this function doesn't exist 0175 // AF_INET6 not defined, we say there is no IPv6 stack 0176 // otherwise, we try to create a socket. 0177 // returns: 1 for IPv6 stack available, 2 for not available 0178 #if defined(KDE_IPV6_LOOKUP_MODE) && KDE_IPV6_LOOKUP_MODE == 1 0179 static int check_ipv6_stack() 0180 { 0181 # ifndef AF_INET6 0182 return 2; // how can we check? 0183 # else 0184 if (!qgetenv("KDE_NO_IPV6").isEmpty()) { 0185 return 2; 0186 } 0187 int fd = ::socket(AF_INET6, SOCK_STREAM, 0); 0188 if (fd == -1) { 0189 return 2; 0190 } 0191 0192 ::close(fd); 0193 return 1; 0194 # endif 0195 } 0196 #endif 0197 0198 /* 0199 * Reason for using this function: kde_getaddrinfo 0200 * 0201 * I decided to add this wrapper function for getaddrinfo 0202 * and have this be called by KExtendedSocket instead of 0203 * the real getaddrinfo so that we can make sure that the 0204 * behavior is the desired one. 0205 * 0206 * Currently, the only "undesired" behavior is getaddrinfo 0207 * not returning PF_UNIX sockets in some implementations. 0208 * 0209 * getaddrinfo and family are defined in POSIX 1003.1g 0210 * (Protocol Independent Interfaces) and in RFC 2553 0211 * (Basic Socket Interface for IPv6). Whereas the RFC is ambiguosly 0212 * vague whether this family of functions should return Internet 0213 * sockets only or not, the name of the POSIX draft says 0214 * otherwise: it should be independent of protocol. 0215 * 0216 * So, my interpretation is that they should return every 0217 * kind of socket available and known and that's how I 0218 * designed KExtendedSocket on top of it. 0219 * 0220 * That's why there's this wrapper, to make sure PF_UNIX 0221 * sockets are returned when expected. 0222 */ 0223 0224 int kde_getaddrinfo(const char *name, const char *service, 0225 const struct addrinfo *hint, 0226 struct kde_addrinfo **result) 0227 { 0228 struct kde_addrinfo *res; 0229 struct addrinfo *p; 0230 int err = EAI_SERVICE; 0231 #if defined(KDE_IPV6_LOOKUP_MODE) && KDE_IPV6_LOOKUP_MODE == 1 0232 // mode 1: do a check on whether we have an IPv6 stack 0233 static int ipv6_stack = 0; // 0: unknown, 1: yes, 2: no 0234 #endif 0235 0236 // allocate memory for results 0237 res = (kde_addrinfo *)malloc(sizeof(*res)); 0238 if (res == nullptr) { 0239 return EAI_MEMORY; 0240 } 0241 res->data = nullptr; 0242 res->origin = KAI_SYSTEM; // at first, it'll be only system data 0243 0244 struct addrinfo *last = nullptr; 0245 0246 // Skip the getaddrinfo call and the ipv6 check for a UNIX socket. 0247 if (hint && (hint->ai_family == PF_UNIX)) { 0248 if (service == nullptr || *service == '\0') { 0249 goto out; // can't be Unix if no service was requested 0250 } 0251 0252 // Unix sockets must be localhost 0253 // That is, either name is NULL or, if it's not, it must be empty, 0254 // "*" or "localhost" 0255 if (name != nullptr && !(name[0] == '\0' || (name[0] == '*' && name[1] == '\0') || 0256 strcmp("localhost", name) == 0)) { 0257 goto out; // isn't localhost 0258 } 0259 0260 goto do_unix; 0261 } 0262 0263 #if defined(KDE_IPV6_LOOKUP_MODE) && KDE_IPV6_LOOKUP_MODE != 0 0264 # if KDE_IPV6_LOOKUP_MODE == 1 0265 // mode 1: do a check on whether we have an IPv6 stack 0266 if (ipv6_stack == 0) { 0267 ipv6_stack = check_ipv6_stack(); 0268 } 0269 0270 if (ipv6_stack == 2) { 0271 # endif 0272 // here we have modes 1 and 2 (no lookups) 0273 // this is shared code 0274 struct addrinfo our_hint; 0275 if (hint != NULL) { 0276 memcpy(&our_hint, hint, sizeof(our_hint)); 0277 if (our_hint.ai_family == AF_UNSPEC) { 0278 our_hint.ai_family = AF_INET; 0279 } 0280 } else { 0281 memset(&our_hint, 0, sizeof(our_hint)); 0282 our_hint.ai_family = AF_INET; 0283 } 0284 0285 // do the actual resolution 0286 err = getaddrinfo(name, service, &our_hint, &res->data); 0287 # if KDE_IPV6_LOOKUP_MODE == 1 0288 } else 0289 # endif 0290 #endif 0291 #if defined(KDE_IPV6_LOOKUP_MODE) && KDE_IPV6_LOOKUP_MODE != 2 0292 // do the IPV6 resolution 0293 err = getaddrinfo(name, service, hint, &res->data); 0294 #endif 0295 0296 // Now we have to check whether the user could want a Unix socket 0297 0298 if (service == nullptr || *service == '\0') { 0299 goto out; // can't be Unix if no service was requested 0300 } 0301 0302 // Unix sockets must be localhost 0303 // That is, either name is NULL or, if it's not, it must be empty, 0304 // "*" or "localhost" 0305 if (name != nullptr && !(name[0] == '\0' || (name[0] == '*' && name[1] == '\0') || 0306 strcmp("localhost", name) == 0)) { 0307 goto out; // isn't localhost 0308 } 0309 0310 // Unix sockets can only be returned if the user asked for a PF_UNSPEC 0311 // or PF_UNIX socket type or gave us a NULL hint 0312 if (hint != nullptr && (hint->ai_family != PF_UNSPEC && hint->ai_family != PF_UNIX)) { 0313 goto out; // user doesn't want Unix 0314 } 0315 0316 // If we got here, then it means that the user might be expecting Unix 0317 // sockets. The user wants a local socket, with a non-null service and 0318 // has told us that they accept PF_UNIX sockets 0319 // Check whether the system implementation returned Unix 0320 if (err == 0) 0321 for (p = res->data; p; p = p->ai_next) { 0322 last = p; // we have to find out which one is last anyways 0323 if (p->ai_family == AF_UNIX) 0324 // there is an Unix node 0325 { 0326 goto out; 0327 } 0328 } 0329 0330 do_unix: 0331 // So, give the user a PF_UNIX socket 0332 p = make_unix(nullptr, service); 0333 if (p == nullptr) { 0334 err = EAI_MEMORY; 0335 goto out; 0336 } 0337 if (hint != nullptr) { 0338 p->ai_socktype = hint->ai_socktype; 0339 } 0340 if (p->ai_socktype == 0) { 0341 p->ai_socktype = SOCK_STREAM; // default 0342 } 0343 0344 if (last) { 0345 last->ai_next = p; 0346 } else { 0347 res->data = p; 0348 } 0349 res->origin = KAI_LOCALUNIX; 0350 *result = res; 0351 return 0; 0352 0353 out: 0354 if (res->data != nullptr) { 0355 freeaddrinfo(res->data); 0356 } 0357 free(res); 0358 return err; 0359 } 0360 0361 #if HAVE_GETADDRINFO && !HAVE_BROKEN_GETADDRINFO 0362 0363 #define KRF_getaddrinfo 0 0364 #define KRF_resolver 0 0365 0366 #else // !HAVE_GETADDRINFO || HAVE_BROKEN_GETADDRINFO 0367 0368 #define KRF_getaddrinfo KRF_USING_OWN_GETADDRINFO 0369 #define KRF_resolver KRF_CAN_RESOLVE_UNIX | KRF_CAN_RESOLVE_IPV4 0370 0371 /* 0372 * No getaddrinfo() in this system. 0373 * We shall provide our own 0374 */ 0375 0376 /** TODO 0377 * Try and use gethostbyname2_r before gethostbyname2 and gethostbyname 0378 */ 0379 static int inet_lookup(const char *name, int portnum, int protonum, 0380 struct addrinfo *p, const struct addrinfo *hint, 0381 struct addrinfo **result) 0382 { 0383 struct addrinfo *q; 0384 struct hostent *h; 0385 struct sockaddr **psa = NULL; 0386 int len; 0387 0388 // TODO 0389 // Currently, this never resolves IPv6 (need gethostbyname2, etc.) 0390 # ifdef AF_INET6 0391 if (hint->ai_family == AF_INET6) { 0392 if (p != NULL) { 0393 *result = p; 0394 return 0; 0395 } 0396 return EAI_FAIL; 0397 } 0398 # endif 0399 0400 h = gethostbyname(name); 0401 if (h == NULL) { 0402 if (p != NULL) { 0403 // There already is a suitable result 0404 *result = p; 0405 return 0; 0406 } 0407 0408 switch (h_errno) { 0409 case HOST_NOT_FOUND: 0410 return EAI_NONAME; 0411 case TRY_AGAIN: 0412 return EAI_AGAIN; 0413 case NO_RECOVERY: 0414 return EAI_FAIL; 0415 case NO_ADDRESS: 0416 return EAI_NODATA; 0417 default: 0418 // EH!? 0419 return EAI_FAIL; 0420 } 0421 } 0422 0423 q = (addrinfo *)malloc(sizeof(*q)); 0424 if (q == NULL) { 0425 freeaddrinfo(p); 0426 return EAI_MEMORY; 0427 } 0428 0429 // convert the hostent to addrinfo 0430 if (h->h_addrtype == AF_INET && (hint->ai_family == AF_INET || hint->ai_family == AF_UNSPEC)) { 0431 len = sizeof(struct sockaddr_in); 0432 } 0433 # ifdef AF_INET6 0434 else if (h->h_addrtype == AF_INET6 && (hint->ai_family == AF_INET6 || 0435 hint->ai_family == AF_UNSPEC)) { 0436 len = sizeof(struct sockaddr_in6); 0437 } 0438 # endif 0439 else { 0440 free(q); 0441 // We don't know what to do with these addresses 0442 // Or gethostbyname returned information we don't want 0443 if (p != NULL) { 0444 *result = p; 0445 return 0; 0446 } 0447 return EAI_NODATA; 0448 } 0449 0450 q->ai_flags = 0; 0451 q->ai_family = h->h_addrtype; 0452 q->ai_socktype = hint->ai_socktype; 0453 q->ai_protocol = protonum; 0454 q->ai_addrlen = len; 0455 0456 q->ai_addr = (sockaddr *)malloc(len); 0457 if (q->ai_addr == NULL) { 0458 free(q); 0459 freeaddrinfo(p); 0460 return EAI_MEMORY; 0461 } 0462 if (h->h_addrtype == AF_INET) { 0463 struct sockaddr_in *sin = (sockaddr_in *)q->ai_addr; 0464 sin->sin_family = AF_INET; 0465 # if HAVE_STRUCT_SOCKADDR_SA_LEN 0466 sin->sin_len = sizeof(*sin); 0467 # endif 0468 sin->sin_port = portnum; 0469 memcpy(&sin->sin_addr, h->h_addr, h->h_length); 0470 } 0471 # ifdef AF_INET6 0472 else if (h->h_addrtype == AF_INET6) { 0473 struct sockaddr_in6 *sin6 = (sockaddr_in6 *)q->ai_addr; 0474 sin6->sin6_family = AF_INET6; 0475 # if HAVE_STRUCT_SOCKADDR_SA_LEN 0476 sin6->sin6_len = sizeof(*sin6); 0477 # endif 0478 sin6->sin6_port = portnum; 0479 sin6->sin6_flowinfo = 0; 0480 memcpy(&sin6->sin6_addr, h->h_addr, h->h_length); 0481 sin6->sin6_scope_id = 0; 0482 } 0483 # endif 0484 0485 if (hint->ai_flags & AI_CANONNAME) { 0486 q->ai_canonname = qstrdup(h->h_name); 0487 } else { 0488 q->ai_canonname = NULL; 0489 } 0490 0491 q->ai_next = p; 0492 p = q; 0493 0494 // cycle through the rest of the hosts; 0495 for (psa = (sockaddr **)h->h_addr_list + 1; *psa; psa++) { 0496 q = (addrinfo *)malloc(sizeof(*q)); 0497 if (q == NULL) { 0498 freeaddrinfo(p); 0499 return EAI_MEMORY; 0500 } 0501 memcpy(q, p, sizeof(*q)); 0502 0503 q->ai_addr = (sockaddr *)malloc(h->h_length); 0504 if (q->ai_addr == NULL) { 0505 freeaddrinfo(p); 0506 free(q); 0507 return EAI_MEMORY; 0508 } 0509 if (h->h_addrtype == AF_INET) { 0510 struct sockaddr_in *sin = (sockaddr_in *)q->ai_addr; 0511 sin->sin_family = AF_INET; 0512 # if HAVE_STRUCT_SOCKADDR_SA_LEN 0513 sin->sin_len = sizeof(*sin); 0514 # endif 0515 sin->sin_port = portnum; 0516 memcpy(&sin->sin_addr, *psa, h->h_length); 0517 } 0518 # ifdef AF_INET6 0519 else if (h->h_addrtype == AF_INET6) { 0520 struct sockaddr_in6 *sin6 = (sockaddr_in6 *)q->ai_addr; 0521 sin6->sin6_family = AF_INET6; 0522 # if HAVE_STRUCT_SOCKADDR_SA_LEN 0523 sin6->sin6_len = sizeof(*sin6); 0524 # endif 0525 sin6->sin6_port = portnum; 0526 sin6->sin6_flowinfo = 0; 0527 memcpy(&sin6->sin6_addr, *psa, h->h_length); 0528 sin6->sin6_scope_id = 0; 0529 } 0530 # endif 0531 0532 if (q->ai_canonname != NULL) { 0533 q->ai_canonname = qstrdup(q->ai_canonname); 0534 } 0535 0536 q->ai_next = p; 0537 p = q; 0538 } 0539 0540 *result = p; 0541 return 0; // Whew! Success! 0542 } 0543 0544 static int make_inet(const char *name, int portnum, int protonum, struct addrinfo *p, 0545 const struct addrinfo *hint, struct addrinfo **result) 0546 { 0547 struct addrinfo *q; 0548 0549 do { 0550 // This 'do' is here just so that we can 'break' out of it 0551 0552 if (name != NULL) { 0553 // first, try to use inet_pton before resolving 0554 // it will catch IP addresses given without having to go to lookup 0555 struct sockaddr_in *sin; 0556 struct in_addr in; 0557 # ifdef AF_INET6 0558 struct sockaddr_in6 *sin6; 0559 struct in6_addr in6; 0560 0561 if (hint->ai_family == AF_INET6 || (hint->ai_family == AF_UNSPEC && 0562 strchr(name, ':') != NULL)) { 0563 // yes, this is IPv6 0564 if (inet_pton(AF_INET6, name, &in6) != 1) { 0565 if (hint->ai_flags & AI_NUMERICHOST) { 0566 freeaddrinfo(p); 0567 return EAI_FAIL; 0568 } 0569 break; // not a numeric host 0570 } 0571 0572 sin6 = (sockaddr_in6 *)malloc(sizeof(*sin6)); 0573 if (sin6 == NULL) { 0574 freeaddrinfo(p); 0575 return EAI_MEMORY; 0576 } 0577 memcpy(&sin6->sin6_addr, &in6, sizeof(in6)); 0578 0579 if (strchr(name, '%') != NULL) { 0580 errno = 0; 0581 sin6->sin6_scope_id = strtoul(strchr(name, '%') + 1, NULL, 10); 0582 if (errno != 0) { 0583 sin6->sin6_scope_id = 0; // no interface 0584 } 0585 } 0586 0587 q = (addrinfo *)malloc(sizeof(*q)); 0588 if (q == NULL) { 0589 freeaddrinfo(p); 0590 free(sin6); 0591 return EAI_MEMORY; 0592 } 0593 0594 sin6->sin6_family = AF_INET6; 0595 # if HAVE_STRUCT_SOCKADDR_SA_LEN 0596 sin6->sin6_len = sizeof(*sin6); 0597 # endif 0598 sin6->sin6_port = portnum; 0599 sin6->sin6_flowinfo = 0; 0600 0601 q->ai_flags = 0; 0602 q->ai_family = AF_INET6; 0603 q->ai_socktype = hint->ai_socktype; 0604 q->ai_protocol = protonum; 0605 q->ai_addrlen = sizeof(*sin6); 0606 q->ai_canonname = NULL; 0607 q->ai_addr = (sockaddr *)sin6; 0608 q->ai_next = p; 0609 0610 *result = q; 0611 return 0; // success! 0612 } 0613 # endif // AF_INET6 0614 0615 if (hint->ai_family == AF_INET || hint->ai_family == AF_UNSPEC) { 0616 // This has to be IPv4 0617 if (inet_pton(AF_INET, name, &in) != 1) { 0618 if (hint->ai_flags & AI_NUMERICHOST) { 0619 freeaddrinfo(p); 0620 return EAI_FAIL; // invalid, I guess 0621 } 0622 break; // not a numeric host, do lookup 0623 } 0624 0625 sin = (sockaddr_in *)malloc(sizeof(*sin)); 0626 if (sin == NULL) { 0627 freeaddrinfo(p); 0628 return EAI_MEMORY; 0629 } 0630 0631 q = (addrinfo *)malloc(sizeof(*q)); 0632 if (q == NULL) { 0633 freeaddrinfo(p); 0634 free(sin); 0635 return EAI_MEMORY; 0636 } 0637 0638 sin->sin_family = AF_INET; 0639 # if HAVE_STRUCT_SOCKADDR_SA_LEN 0640 sin->sin_len = sizeof(*sin); 0641 # endif 0642 sin->sin_port = portnum; 0643 sin->sin_addr = in; 0644 0645 q->ai_flags = 0; 0646 q->ai_family = AF_INET; 0647 q->ai_socktype = hint->ai_socktype; 0648 q->ai_protocol = protonum; 0649 q->ai_addrlen = sizeof(*sin); 0650 q->ai_canonname = NULL; 0651 q->ai_addr = (sockaddr *)sin; 0652 q->ai_next = p; 0653 *result = q; 0654 return 0; 0655 } 0656 0657 // Eh, what!? 0658 // One of the two above has to have matched 0659 kError() << "I wasn't supposed to get here!"; 0660 } 0661 } while (false); 0662 0663 // This means localhost 0664 if (name == NULL) { 0665 struct sockaddr_in *sin = (sockaddr_in *)malloc(sizeof(*sin)); 0666 # ifdef AF_INET6 0667 struct sockaddr_in6 *sin6; 0668 # endif 0669 0670 if (hint->ai_family == AF_INET || hint->ai_family == AF_UNSPEC) { 0671 if (sin == NULL) { 0672 free(sin); 0673 freeaddrinfo(p); 0674 return EAI_MEMORY; 0675 } 0676 0677 // Do IPv4 first 0678 q = (addrinfo *)malloc(sizeof(*q)); 0679 if (q == NULL) { 0680 free(sin); 0681 freeaddrinfo(p); 0682 return EAI_MEMORY; 0683 } 0684 0685 sin->sin_family = AF_INET; 0686 # if HAVE_STRUCT_SOCKADDR_SA_LEN 0687 sin->sin_len = sizeof(*sin); 0688 # endif 0689 sin->sin_port = portnum; 0690 if (hint->ai_flags & AI_PASSIVE) { 0691 *(quint32 *)&sin->sin_addr = INADDR_ANY; 0692 } else { 0693 *(quint32 *)&sin->sin_addr = htonl(INADDR_LOOPBACK); 0694 } 0695 q->ai_flags = 0; 0696 q->ai_family = AF_INET; 0697 q->ai_socktype = hint->ai_socktype; 0698 q->ai_protocol = protonum; 0699 q->ai_addrlen = sizeof(*sin); 0700 q->ai_canonname = NULL; 0701 q->ai_addr = (sockaddr *)sin; 0702 q->ai_next = p; 0703 p = q; 0704 } 0705 0706 # ifdef AF_INET6 0707 // Try now IPv6 0708 0709 if (hint->ai_family == AF_INET6 || hint->ai_family == AF_UNSPEC) { 0710 sin6 = (sockaddr_in6 *)malloc(sizeof(*sin6)); 0711 q = (addrinfo *)malloc(sizeof(*q)); 0712 if (q == NULL || sin6 == NULL) { 0713 free(sin); 0714 free(sin6); 0715 free(q); 0716 freeaddrinfo(p); 0717 return EAI_MEMORY; 0718 } 0719 0720 sin6->sin6_family = AF_INET6; 0721 # if HAVE_STRUCT_SOCKADDR_SA_LEN 0722 sin6->sin6_len = sizeof(*sin6); 0723 # endif 0724 sin6->sin6_port = portnum; 0725 sin6->sin6_flowinfo = 0; 0726 sin6->sin6_scope_id = 0; 0727 0728 // We don't want to use in6addr_loopback and in6addr_any 0729 memset(&sin6->sin6_addr, 0, sizeof(sin6->sin6_addr)); 0730 if ((hint->ai_flags & AI_PASSIVE) == 0) { 0731 ((char *)&sin6->sin6_addr)[15] = 1; 0732 } 0733 0734 q->ai_flags = 0; 0735 q->ai_family = AF_INET6; 0736 q->ai_socktype = hint->ai_socktype; 0737 q->ai_protocol = protonum; 0738 q->ai_addrlen = sizeof(*sin6); 0739 q->ai_canonname = NULL; 0740 q->ai_addr = (sockaddr *)sin6; 0741 q->ai_next = p; 0742 p = q; 0743 } 0744 0745 # endif // AF_INET6 0746 0747 *result = p; 0748 free(sin); 0749 return 0; // success! 0750 } 0751 0752 return inet_lookup(name, portnum, protonum, p, hint, result); 0753 } 0754 0755 int getaddrinfo(const char *name, const char *serv, 0756 const struct addrinfo *hint, 0757 struct addrinfo **result) 0758 { 0759 unsigned short portnum; // remember to store in network byte order 0760 int protonum = IPPROTO_TCP; 0761 const char *proto = "tcp"; 0762 struct addrinfo *p = NULL; 0763 0764 // Sanity checks: 0765 if (hint == NULL || result == NULL) { 0766 return EAI_BADFLAGS; 0767 } 0768 if (hint->ai_family != AF_UNSPEC && hint->ai_family != AF_UNIX && 0769 hint->ai_family != AF_INET 0770 # ifdef AF_INET6 0771 && hint->ai_family != AF_INET6 0772 # endif 0773 ) { 0774 return EAI_FAMILY; 0775 } 0776 if (hint->ai_socktype != 0 && hint->ai_socktype != SOCK_STREAM && 0777 hint->ai_socktype != SOCK_DGRAM) { 0778 return EAI_SOCKTYPE; 0779 } 0780 0781 // Treat hostname of "*" as NULL, which means localhost 0782 if (name != NULL && ((*name == '*' && name[1] == '\0') || *name == '\0')) { 0783 name = NULL; 0784 } 0785 // Treat service of "*" as NULL, which I guess means no port (0) 0786 if (serv != NULL && ((*serv == '*' && serv[1] == '\0') || *serv == '\0')) { 0787 serv = NULL; 0788 } 0789 0790 if (name == NULL && serv == NULL) { // what the hell do you want? 0791 return EAI_NONAME; 0792 } 0793 0794 // This is just to make it easier 0795 if (name != NULL && strcmp(name, "localhost") == 0) { 0796 name = NULL; 0797 } 0798 0799 // First, check for a Unix socket 0800 // family must be either AF_UNIX or AF_UNSPEC 0801 // either of name or serv must be set, the other must be NULL or empty 0802 if (hint->ai_family == AF_UNIX || hint->ai_family == AF_UNSPEC) { 0803 if (name != NULL && serv != NULL) { 0804 // This is not allowed 0805 if (hint->ai_family == AF_UNIX) { 0806 return EAI_BADFLAGS; 0807 } 0808 } else { 0809 p = make_unix(name, serv); 0810 if (p == NULL) { 0811 return EAI_MEMORY; 0812 } 0813 0814 p->ai_socktype = hint->ai_socktype; 0815 // If the name/service started with a slash, then this *IS* 0816 // only a Unix socket. Return. 0817 if (hint->ai_family == AF_UNIX || ((name != NULL && *name == '/') || 0818 (serv != NULL && *serv == '/'))) { 0819 *result = p; 0820 return 0; // successful lookup 0821 } 0822 } 0823 } 0824 0825 // Lookup the service name, if required 0826 if (serv != NULL) { 0827 char *tail; 0828 struct servent *sent; 0829 0830 portnum = htons((unsigned)strtoul(serv, &tail, 10)); 0831 if (*tail != '\0') { 0832 // not a number. We have to do the lookup 0833 if (hint->ai_socktype == SOCK_DGRAM) { 0834 proto = "udp"; 0835 protonum = IPPROTO_UDP; 0836 } 0837 0838 sent = getservbyname(serv, proto); 0839 if (sent == NULL) { // no service? 0840 if (p == NULL) { 0841 return EAI_NONAME; 0842 } else { 0843 return 0; // a Unix socket available 0844 } 0845 } 0846 0847 portnum = sent->s_port; 0848 } 0849 } else { 0850 portnum = 0; // no port number 0851 } 0852 0853 return make_inet(name, portnum, protonum, p, hint, result); 0854 } 0855 0856 void freeaddrinfo(struct addrinfo *p) 0857 { 0858 dofreeaddrinfo(p); 0859 } 0860 0861 #if !HAVE_GAI_STRERROR_PROTO 0862 char *gai_strerror(int errorcode) 0863 { 0864 static const char messages[] = { 0865 I18N_NOOP("no error")"\0" // 0 0866 I18N_NOOP("address family for nodename not supported")"\0" // EAI_ADDRFAMILY 0867 I18N_NOOP("temporary failure in name resolution")"\0" // EAI_AGAIN 0868 I18N_NOOP("invalid value for 'ai_flags'")"\0" // EAI_BADFLAGS 0869 I18N_NOOP("non-recoverable failure in name resolution")"\0" // EAI_FAIL 0870 I18N_NOOP("'ai_family' not supported")"\0" // EAI_FAMILY 0871 I18N_NOOP("memory allocation failure")"\0" // EAI_MEMORY 0872 I18N_NOOP("no address associated with nodename")"\0" // EAI_NODATA 0873 I18N_NOOP("name or service not known")"\0" // EAI_NONAME 0874 I18N_NOOP("servname not supported for ai_socktype")"\0" // EAI_SERVICE 0875 I18N_NOOP("'ai_socktype' not supported")"\0" // EAI_SOCKTYPE 0876 I18N_NOOP("system error")"\0" // EAI_SYSTEM 0877 "\0" 0878 }; 0879 0880 static const int messages_indices[] = { 0881 0, 9, 51, 88, 117, 160, 186, 212, 0882 248, 274, 313, 341, 0 0883 }; 0884 0885 Q_ASSERT(sizeof(messages_indices) / sizeof(messages_indices[0]) >= EAI_SYSTEM); 0886 if (errorcode > EAI_SYSTEM || errorcode < 0) { 0887 return NULL; 0888 } 0889 0890 static char buffer[200]; 0891 strcpy(buffer, i18n(messages + messages_indices[errorcode]).toLocal8Bit()); 0892 return buffer; 0893 } 0894 #endif 0895 0896 static void findport(unsigned short port, char *serv, size_t servlen, int flags) 0897 { 0898 if (serv == NULL) { 0899 return; 0900 } 0901 0902 if ((flags & NI_NUMERICSERV) == 0) { 0903 struct servent *sent; 0904 sent = getservbyport(ntohs(port), flags & NI_DGRAM ? "udp" : "tcp"); 0905 if (sent != NULL && servlen > strlen(sent->s_name)) { 0906 strcpy(serv, sent->s_name); 0907 return; 0908 } 0909 } 0910 0911 qsnprintf(serv, servlen, "%u", ntohs(port)); 0912 } 0913 0914 int getnameinfo(const struct sockaddr *sa, kde_socklen_t salen, 0915 char *host, size_t hostlen, char *serv, size_t servlen, 0916 int flags) 0917 { 0918 union { 0919 const sockaddr *sa; 0920 const sockaddr_un *_sun; 0921 const sockaddr_in *sin; 0922 const sockaddr_in6 *sin6; 0923 } s; 0924 0925 if ((host == NULL || hostlen == 0) && (serv == NULL || servlen == 0)) { 0926 return 1; 0927 } 0928 0929 s.sa = sa; 0930 if (s.sa->sa_family == AF_UNIX) { 0931 if (salen < offsetof(struct sockaddr_un, sun_path) + strlen(s._sun->sun_path) + 1) { 0932 return 1; // invalid socket 0933 } 0934 0935 if (servlen && serv != NULL) { 0936 *serv = '\0'; 0937 } 0938 if (host != NULL && hostlen > strlen(s._sun->sun_path)) { 0939 strcpy(host, s._sun->sun_path); 0940 } 0941 0942 return 0; 0943 } else if (s.sa->sa_family == AF_INET) { 0944 if (salen < offsetof(struct sockaddr_in, sin_addr) + sizeof(s.sin->sin_addr)) { 0945 return 1; // invalid socket 0946 } 0947 0948 if (flags & NI_NUMERICHOST) { 0949 inet_ntop(AF_INET, &s.sin->sin_addr, host, hostlen); 0950 } else { 0951 // have to do lookup 0952 struct hostent *h = gethostbyaddr((const char *)&s.sin->sin_addr, sizeof(s.sin->sin_addr), 0953 AF_INET); 0954 if (h == NULL && flags & NI_NAMEREQD) { 0955 return 1; 0956 } else if (h == NULL) { 0957 inet_ntop(AF_INET, &s.sin->sin_addr, host, hostlen); 0958 } else if (host != NULL && hostlen > strlen(h->h_name)) { 0959 strcpy(host, h->h_name); 0960 } else { 0961 return 1; // error 0962 } 0963 } 0964 0965 findport(s.sin->sin_port, serv, servlen, flags); 0966 } 0967 # ifdef AF_INET6 0968 else if (s.sa->sa_family == AF_INET6) { 0969 if (salen < offsetof(struct sockaddr_in6, sin6_addr) + sizeof(s.sin6->sin6_addr)) { 0970 return 1; // invalid socket 0971 } 0972 0973 if (flags & NI_NUMERICHOST) { 0974 inet_ntop(AF_INET6, &s.sin6->sin6_addr, host, hostlen); 0975 } else { 0976 // have to do lookup 0977 struct hostent *h = gethostbyaddr((const char *)&s.sin->sin_addr, sizeof(s.sin->sin_addr), 0978 AF_INET6); 0979 if (h == NULL && flags & NI_NAMEREQD) { 0980 return 1; 0981 } else if (h == NULL) { 0982 inet_ntop(AF_INET6, &s.sin6->sin6_addr, host, hostlen); 0983 } else if (host != NULL && hostlen > strlen(h->h_name)) { 0984 strcpy(host, h->h_name); 0985 } else { 0986 return 1; // error 0987 } 0988 } 0989 0990 findport(s.sin6->sin6_port, serv, servlen, flags); 0991 } 0992 # endif // AF_INET6 0993 0994 return 1; // invalid family 0995 } 0996 0997 #endif // HAVE_GETADDRINFO 0998 0999 #if !HAVE_INET_NTOP && !defined(inet_ntop) 1000 1001 #define KRF_inet_ntop KRF_USING_OWN_INET_NTOP 1002 1003 static void add_dwords(char *buf, quint16 *dw, int count) 1004 { 1005 int i = 1; 1006 sprintf(buf + strlen(buf), "%x", ntohs(dw[0])); 1007 while (--count) { 1008 sprintf(buf + strlen(buf), ":%x", ntohs(dw[i++])); 1009 } 1010 } 1011 1012 const char *inet_ntop(int af, const void *cp, char *buf, size_t len) 1013 { 1014 char buf2[sizeof "1234:5678:9abc:def0:1234:5678:255.255.255.255" + 1]; 1015 quint8 *data = (quint8 *)cp; 1016 1017 if (af == AF_INET) { 1018 sprintf(buf2, "%u.%u.%u.%u", data[0], data[1], data[2], data[3]); 1019 1020 if (len > strlen(buf2)) { 1021 strcpy(buf, buf2); 1022 return buf; 1023 } 1024 1025 errno = ENOSPC; 1026 return NULL; // failed 1027 } 1028 1029 # ifdef AF_INET6 1030 if (af == AF_INET6) { 1031 quint16 *p = (quint16 *)data; 1032 quint16 *longest = NULL, *cur = NULL; 1033 int longest_length = 0, cur_length; 1034 int i; 1035 1036 if (KDE_IN6_IS_ADDR_V4MAPPED(p) || KDE_IN6_IS_ADDR_V4COMPAT(p)) 1037 sprintf(buf2, "::%s%u.%u.%u.%u", 1038 KDE_IN6_IS_ADDR_V4MAPPED(p) ? "ffff:" : "", 1039 buf[12], buf[13], buf[14], buf[15]); 1040 else { 1041 // find the longest sequence of zeroes 1042 for (i = 0; i < 8; --i) 1043 if (cur == NULL && p[i] == 0) { 1044 // a zero, start the sequence 1045 cur = p + i; 1046 cur_length = 1; 1047 } else if (cur != NULL && p[i] == 0) 1048 // part of the sequence 1049 { 1050 cur_length++; 1051 } else if (cur != NULL && p[i] != 0) { 1052 // end of the sequence 1053 if (cur_length > longest_length) { 1054 longest_length = cur_length; 1055 longest = cur; 1056 } 1057 cur = NULL; // restart sequence 1058 } 1059 if (cur != NULL && cur_length > longest_length) { 1060 longest_length = cur_length; 1061 longest = cur; 1062 } 1063 1064 if (longest_length > 1) { 1065 // We have a candidate 1066 buf2[0] = '\0'; 1067 if (longest != p) { 1068 add_dwords(buf2, p, longest - p); 1069 } 1070 strcat(buf2, "::"); 1071 if (longest + longest_length < p + 8) { 1072 add_dwords(buf2, longest + longest_length, 8 - (longest - p) - longest_length); 1073 } 1074 } else { 1075 // Nope, no candidate 1076 buf2[0] = '\0'; 1077 add_dwords(buf2, p, 8); 1078 } 1079 } 1080 1081 if (strlen(buf2) < len) { 1082 strcpy(buf, buf2); 1083 return buf; 1084 } 1085 1086 errno = ENOSPC; 1087 return NULL; 1088 } 1089 # endif 1090 1091 errno = EAFNOSUPPORT; 1092 return NULL; // a family we don't know about 1093 } 1094 1095 #else // HAVE_INET_NTOP 1096 1097 #define KRF_inet_ntop 0 1098 1099 #endif // HAVE_INET_NTOP 1100 1101 #if !HAVE_INET_PTON && !defined(inet_pton) 1102 1103 #define KRF_inet_pton KRF_USING_OWN_INET_PTON 1104 int inet_pton(int af, const char *cp, void *buf) 1105 { 1106 if (af == AF_INET) { 1107 // Piece of cake 1108 unsigned p[4]; 1109 unsigned char *q = (unsigned char *)buf; 1110 if (sscanf(cp, "%u.%u.%u.%u", p, p + 1, p + 2, p + 3) != 4) { 1111 return 0; 1112 } 1113 1114 if (p[0] > 0xff || p[1] > 0xff || p[2] > 0xff || p[3] > 0xff) { 1115 return 0; 1116 } 1117 1118 q[0] = p[0]; 1119 q[1] = p[1]; 1120 q[2] = p[2]; 1121 q[3] = p[3]; 1122 1123 return 1; 1124 } 1125 1126 # ifdef AF_INET6 1127 else if (af == AF_INET6) { 1128 quint16 addr[8]; 1129 const char *p = cp; 1130 int n = 0, start = 8; 1131 bool has_v4 = strchr(p, '.') != NULL; 1132 1133 memset(addr, 0, sizeof(addr)); 1134 1135 if (*p == '\0' || p[1] == '\0') { 1136 return 0; // less than 2 chars is not valid 1137 } 1138 1139 if (*p == ':' && p[1] == ':') { 1140 start = 0; 1141 p += 2; 1142 } 1143 while (*p) { 1144 if (has_v4 && inet_pton(AF_INET, p, addr + n) != 0) { 1145 // successful v4 convertion 1146 addr[n] = ntohs(addr[n]); 1147 n++; 1148 addr[n] = ntohs(addr[n]); 1149 n++; 1150 break; 1151 } 1152 if (sscanf(p, "%hx", addr + n++) != 1) { 1153 return 0; 1154 } 1155 1156 while (*p && *p != ':') { 1157 p++; 1158 } 1159 if (!*p) { 1160 break; 1161 } 1162 p++; 1163 1164 if (*p == ':') { // another ':'? 1165 if (start != 8) { 1166 return 0; // two :: were found 1167 } 1168 start = n; 1169 p++; 1170 } 1171 } 1172 1173 // if start is not 8, then a "::" was found at word 'start' 1174 // n is the number of converted words 1175 // n == 8 means everything was converted and no moving is necessary 1176 // n < 8 means that we have to move n - start words 8 - n words to the right 1177 if (start == 8 && n != 8) { 1178 return 0; // bad conversion 1179 } 1180 memmove(addr + start + (8 - n), addr + start, (n - start) * sizeof(quint16)); 1181 memset(addr + start, 0, (8 - n) * sizeof(quint16)); 1182 1183 // check the byte order 1184 // The compiler should optimize this out in big endian machines 1185 if (htons(0x1234) != 0x1234) 1186 for (n = 0; n < 8; ++n) { 1187 addr[n] = htons(addr[n]); 1188 } 1189 1190 memcpy(buf, addr, sizeof(addr)); 1191 return 1; 1192 } 1193 # endif 1194 1195 errno = EAFNOSUPPORT; 1196 return -1; // unknown family 1197 } 1198 1199 #else // HAVE_INET_PTON 1200 1201 #define KRF_inet_pton 0 1202 1203 #endif // HAVE_INET_PTON 1204 1205 #ifdef AF_INET6 1206 # define KRF_afinet6 KRF_KNOWS_AF_INET6 1207 #else 1208 # define KRF_afinet6 0 1209 #endif 1210 1211 namespace KDE 1212 { 1213 /** @internal */ 1214 extern const int resolverFlags = KRF_getaddrinfo | KRF_resolver | KRF_afinet6 | KRF_inet_ntop | KRF_inet_pton; 1215 }