1#include <stdlib.h> 2#include <sys/socket.h> 3#include <netinet/in.h> 4#include <netdb.h> 5#include <string.h> 6#include "lookup.h" 7 8int getaddrinfo(const char *restrict host, const char *restrict serv, const struct addrinfo *restrict hint, struct addrinfo **restrict res) 9{ 10 struct service ports[MAXSERVS]; 11 struct address addrs[MAXADDRS]; 12 char canon[256], *outcanon; 13 int nservs, naddrs, nais, canon_len, i, j, k; 14 int family = AF_UNSPEC, flags = 0, proto = 0, socktype = 0; 15 struct aibuf { 16 struct addrinfo ai; 17 union sa { 18 struct sockaddr_in sin; 19 struct sockaddr_in6 sin6; 20 } sa; 21 } *out; 22 23 if (!host && !serv) return EAI_NONAME; 24 25 if (hint) { 26 family = hint->ai_family; 27 flags = hint->ai_flags; 28 proto = hint->ai_protocol; 29 socktype = hint->ai_socktype; 30 31 const int mask = AI_PASSIVE | AI_CANONNAME | AI_NUMERICHOST | 32 AI_V4MAPPED | AI_ALL | AI_ADDRCONFIG | AI_NUMERICSERV; 33 if ((flags & mask) != flags) 34 return EAI_BADFLAGS; 35 36 switch (family) { 37 case AF_INET: 38 case AF_INET6: 39 case AF_UNSPEC: 40 break; 41 default: 42 return EAI_FAMILY; 43 } 44 } 45 46 nservs = __lookup_serv(ports, serv, proto, socktype, flags); 47 if (nservs < 0) return nservs; 48 49 naddrs = __lookup_name(addrs, canon, host, family, flags); 50 if (naddrs < 0) return naddrs; 51 52 nais = nservs * naddrs; 53 canon_len = strlen(canon); 54 out = calloc(1, nais * sizeof(*out) + canon_len + 1); 55 if (!out) return EAI_MEMORY; 56 57 if (canon_len) { 58 outcanon = (void *)&out[nais]; 59 memcpy(outcanon, canon, canon_len+1); 60 } else { 61 outcanon = 0; 62 } 63 64 for (k=i=0; i<naddrs; i++) for (j=0; j<nservs; j++, k++) { 65 out[k].ai = (struct addrinfo){ 66 .ai_family = addrs[i].family, 67 .ai_socktype = ports[j].socktype, 68 .ai_protocol = ports[j].proto, 69 .ai_addrlen = addrs[i].family == AF_INET 70 ? sizeof(struct sockaddr_in) 71 : sizeof(struct sockaddr_in6), 72 .ai_addr = (void *)&out[k].sa, 73 .ai_canonname = outcanon, 74 .ai_next = &out[k+1].ai }; 75 switch (addrs[i].family) { 76 case AF_INET: 77 out[k].sa.sin.sin_family = AF_INET; 78 out[k].sa.sin.sin_port = htons(ports[j].port); 79 memcpy(&out[k].sa.sin.sin_addr, &addrs[i].addr, 4); 80 break; 81 case AF_INET6: 82 out[k].sa.sin6.sin6_family = AF_INET6; 83 out[k].sa.sin6.sin6_port = htons(ports[j].port); 84 out[k].sa.sin6.sin6_scope_id = addrs[i].scopeid; 85 memcpy(&out[k].sa.sin6.sin6_addr, &addrs[i].addr, 16); 86 break; 87 } 88 } 89 out[nais-1].ai.ai_next = 0; 90 *res = &out->ai; 91 return 0; 92} 93