File indexing completed on 2024-03-24 15:27:31

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 }