fix blank ai_canonname from getaddrinfo for non-CNAMEs
[musl] / src / network / getaddrinfo.c
index c0f135f..3d7b9ec 100644 (file)
@@ -47,7 +47,7 @@ struct aibuf {
 /* Extra slots needed for storing canonical name */
 #define EXTRA ((256+sizeof(struct aibuf)-1)/sizeof(struct aibuf))
 
-int getaddrinfo(const char *host, const char *serv, const struct addrinfo *hint, struct addrinfo **res)
+int getaddrinfo(const char *restrict host, const char *restrict serv, const struct addrinfo *restrict hint, struct addrinfo **restrict res)
 {
        int flags = hint ? hint->ai_flags : 0;
        int family = hint ? hint->ai_family : AF_UNSPEC;
@@ -58,10 +58,9 @@ int getaddrinfo(const char *host, const char *serv, const struct addrinfo *hint,
        union sa sa = {{0}};
        unsigned char reply[1024];
        int i, j;
-       //char hostbuf[256];
        char line[512];
        FILE *f, _f;
-       unsigned char _buf[64];
+       unsigned char _buf[1024];
        char *z;
        int result;
        int cnt;
@@ -75,14 +74,28 @@ int getaddrinfo(const char *host, const char *serv, const struct addrinfo *hint,
                type = proto==IPPROTO_UDP ? SOCK_DGRAM : SOCK_STREAM;
 
        if (serv) {
-               port = strtoul(serv, &z, 0);
-               if (!*z && port > 65535) return EAI_SERVICE;
-               if (!port) {
+               if (!*serv) return EAI_SERVICE;
+               port = strtoul(serv, &z, 10);
+               if (*z) {
+                       size_t servlen = strlen(serv);
+                       char *end = line;
+
                        if (flags & AI_NUMERICSERV) return EAI_SERVICE;
 
-                       //f = fopen("/etc/services", "rb");
-                       return EAI_SERVICE;
+                       f = __fopen_rb_ca("/etc/services", &_f, _buf, sizeof _buf);
+                       if (!f) return EAI_SERVICE;
+                       while (fgets(line, sizeof line, f)) {
+                               if (strncmp(line, serv, servlen) || !isspace(line[servlen]))
+                                       continue;
+                               port = strtoul(line+servlen, &end, 10);
+                               if (strncmp(end, proto==IPPROTO_UDP ? "/udp" : "/tcp", 4))
+                                       continue;
+                               break;
+                       }
+                       __fclose_ca(f);
+                       if (feof(f)) return EAI_SERVICE;
                }
+               if (port > 65535) return EAI_SERVICE;
                port = htons(port);
        }
 
@@ -107,6 +120,8 @@ int getaddrinfo(const char *host, const char *serv, const struct addrinfo *hint,
                return 0;
        }
 
+       if (!*host) return EAI_NONAME;
+
        /* Try as a numeric address */
        if (__ipparse(&sa, family, host) >= 0) {
                buf = calloc(sizeof *buf, 1+EXTRA);
@@ -204,7 +219,7 @@ int getaddrinfo(const char *host, const char *serv, const struct addrinfo *hint,
                while (j--) buf[i++].sa.sin.sin_family = AF_INET6;
        }
 
-       if (__dns_get_rr((void *)&buf[cnt], 0, 256, 1, reply, RR_CNAME, 1) < 0)
+       if (__dns_get_rr((void *)&buf[cnt], 0, 256, 1, reply, RR_CNAME, 1) <= 0)
                strcpy((void *)&buf[cnt], host);
 
        for (i=0; i<cnt; i++) {