From 6f409bff008a83fa6bc640c10366765874de35e2 Mon Sep 17 00:00:00 2001 From: Rich Felker Date: Sat, 31 May 2014 20:57:54 -0400 Subject: refactor getaddrinfo and add support for most remaining features this is the first phase of the "resolver overhaul" project. conceptually, the results of getaddrinfo are a direct product of a list of address results and a list of service results. the new code makes this explicit by computing these lists separately and combining the results. this adds support for services that have both tcp and udp versions, where the caller has not specified which it wants, and eliminates a number of duplicate code paths which were all producing the final output addrinfo structures, but in subtly different ways, making it difficult to implement any of the features which were missing. in addition to the above benefits, the refactoring allows for legacy functions like gethostbyname to be implemented without using the getaddrinfo function itself. such changes to the legacy functions have not yet been made, however. further improvements include matching of service alias names from /etc/services (previously only the primary name was supported), returning multiple results from /etc/hosts (previously only the first matching line was honored), and support for the AI_V4MAPPED and AI_ALL flags. features which remain unimplemented are IDN translations (encoding non-ASCII hostnames for DNS lookup) and the AI_ADDRCONFIG flag. at this point, the DNS-based name resolving code is still based on the old interfaces in __dns.c, albeit somewhat simpler in its use of them. there may be some dead code which could already be removed, but changes to this layer will be a later phase of the resolver overhaul. --- src/network/lookup_serv.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 src/network/lookup_serv.c (limited to 'src/network/lookup_serv.c') diff --git a/src/network/lookup_serv.c b/src/network/lookup_serv.c new file mode 100644 index 00000000..bf4cba09 --- /dev/null +++ b/src/network/lookup_serv.c @@ -0,0 +1,72 @@ +#include +#include +#include +#include +#include +#include +#include "lookup.h" +#include "stdio_impl.h" + +int __lookup_serv(struct service buf[static MAXSERVS], const char *name, int proto, int flags) +{ + char line[128]; + int cnt = 0; + char *p, *z = ""; + unsigned long port = 0; + + if (name) { + if (!*name) return EAI_SERVICE; + port = strtoul(name, &z, 10); + } + if (!*z) { + if (port > 65535) return EAI_SERVICE; + if (proto != IPPROTO_UDP) { + buf[cnt].port = port; + buf[cnt++].proto = IPPROTO_TCP; + } + if (proto != IPPROTO_TCP) { + buf[cnt].port = port; + buf[cnt++].proto = IPPROTO_UDP; + } + return cnt; + } + + if (flags & AI_NUMERICSERV) return EAI_SERVICE; + + size_t l = strlen(name); + + unsigned char _buf[1032]; + FILE _f, *f = __fopen_rb_ca("/etc/services", &_f, _buf, sizeof _buf); + if (!f) return EAI_SERVICE; + + while (fgets(line, sizeof line, f) && cnt < MAXSERVS) { + if ((p=strchr(line, '#'))) *p++='\n', *p=0; + + /* Find service name */ + for(p=line; (p=strstr(p, name)); p++) { + if (p>line && !isspace(p[-1])) continue; + if (p[l] && !isspace(p[l])) continue; + break; + } + if (!p) continue; + + /* Skip past canonical name at beginning of line */ + for (p=line; *p && !isspace(*p); p++); + if (!p) continue; + + port = strtoul(p, &z, 10); + if (port > 65535 || z==p) continue; + if (!strncmp(z, "/udp", 4)) { + if (proto == IPPROTO_TCP) continue; + buf[cnt].port = port; + buf[cnt++].proto = IPPROTO_UDP; + } + if (!strncmp(z, "/tcp", 4)) { + if (proto == IPPROTO_UDP) continue; + buf[cnt].port = port; + buf[cnt++].proto = IPPROTO_TCP; + } + } + __fclose_ca(f); + return cnt > 0 ? cnt : EAI_SERVICE; +} -- cgit v1.2.1