#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
+#include <net/if.h>
#include <arpa/inet.h>
#include <ctype.h>
#include <stdlib.h>
#include "lookup.h"
#include "stdio_impl.h"
#include "syscall.h"
-#include "__dns.h"
static int is_valid_hostname(const char *host)
{
const unsigned char *s;
- if (strnlen(host, 256)-1 > 254 || mbstowcs(0, host, 0) > 255) return 0;
+ if (strnlen(host, 255)-1 >= 254 || mbstowcs(0, host, 0) == -1) return 0;
for (s=(void *)host; *s>=0x80 || *s=='.' || *s=='-' || isalnum(*s); s++);
return !*s;
}
static int name_from_numeric(struct address buf[static 1], const char *name, int family)
{
- struct in_addr a4;
- struct in6_addr a6;
- if (family != AF_INET6 && inet_aton(name, &a4)>0) {
- memcpy(&buf[0].addr, &a4, sizeof a4);
- buf[0].family = AF_INET;
- return 1;
- }
- if (family != AF_INET && inet_pton(AF_INET6, name, &a6)>0) {
- memcpy(&buf[0].addr, &a6, sizeof a6);
- buf[0].family = AF_INET6;
- return 1;
- }
- return 0;
+ return __lookup_ipliteral(buf, name, family);
}
static int name_from_hosts(struct address buf[static MAXADDRS], char canon[static 256], const char *name, int family)
return cnt;
}
-static int name_from_dns(struct address buf[static MAXADDRS], char canon[static 256], const char *name, int family)
+struct dpc_ctx {
+ struct address *addrs;
+ char *canon;
+ int cnt;
+};
+
+int __dns_parse(const unsigned char *, int, int (*)(void *, int, const void *, int, const void *), void *);
+int __dn_expand(const unsigned char *, const unsigned char *, const unsigned char *, char *, int);
+int __res_mkquery(int, const char *, int, int, const unsigned char *, int, const unsigned char*, unsigned char *, int);
+int __res_msend(int, const unsigned char *const *, const int *, unsigned char *const *, int *, int);
+
+#define RR_A 1
+#define RR_CNAME 5
+#define RR_AAAA 28
+
+static int dns_parse_callback(void *c, int rr, const void *data, int len, const void *packet)
{
- unsigned char reply[1024] = { 0 }, *p = reply;
char tmp[256];
- int i, cnt = 0;
-
- /* Perform one or more DNS queries for host */
- int result = __dns_query(reply, name, family, 0);
- if (result < 0) return result;
+ struct dpc_ctx *ctx = c;
+ switch (rr) {
+ case RR_A:
+ if (len != 4) return -1;
+ ctx->addrs[ctx->cnt].family = AF_INET;
+ ctx->addrs[ctx->cnt].scopeid = 0;
+ memcpy(ctx->addrs[ctx->cnt++].addr, data, 4);
+ break;
+ case RR_AAAA:
+ if (len != 16) return -1;
+ ctx->addrs[ctx->cnt].family = AF_INET6;
+ ctx->addrs[ctx->cnt].scopeid = 0;
+ memcpy(ctx->addrs[ctx->cnt++].addr, data, 16);
+ break;
+ case RR_CNAME:
+ if (__dn_expand(packet, (const unsigned char *)packet + 512,
+ data, tmp, sizeof tmp) > 0 && is_valid_hostname(tmp))
+ strcpy(ctx->canon, tmp);
+ break;
+ }
+ return 0;
+}
- for (i=0; i<result; i++) {
- if (family != AF_INET6) {
- int j = __dns_get_rr(&buf[cnt].addr, sizeof *buf, 4, MAXADDRS-cnt, p, RR_A, 0);
- while (j--) buf[cnt++].family = AF_INET;
- }
- if (family != AF_INET) {
- int j = __dns_get_rr(&buf[cnt].addr, sizeof *buf, 16, MAXADDRS-cnt, p, RR_AAAA, 0);
- while (j--) buf[cnt++].family = AF_INET6;
- }
- p += 512;
+static int name_from_dns(struct address buf[static MAXADDRS], char canon[static 256], const char *name, int family)
+{
+ unsigned char qbuf[2][280], abuf[2][512];
+ const unsigned char *qp[2] = { qbuf[0], qbuf[1] };
+ unsigned char *ap[2] = { abuf[0], abuf[1] };
+ int qlens[2], alens[2];
+ int i, nq = 0;
+ struct dpc_ctx ctx = { .addrs = buf, .canon = canon };
+
+ if (family != AF_INET6) {
+ qlens[nq] = __res_mkquery(0, name, 1, RR_A, 0, 0, 0,
+ qbuf[nq], sizeof *qbuf);
+ nq++;
}
- __dns_get_rr(tmp, 0, 256, 1, reply, RR_CNAME, 1);
- if (is_valid_hostname(tmp)) strcpy(canon, tmp);
- return cnt;
+ if (family != AF_INET) {
+ qlens[nq] = __res_mkquery(0, name, 1, RR_AAAA, 0, 0, 0,
+ qbuf[nq], sizeof *qbuf);
+ nq++;
+ }
+
+ if (__res_msend(nq, qp, qlens, ap, alens, sizeof *abuf) < 0) return EAI_SYSTEM;
+
+ for (i=0; i<nq; i++)
+ __dns_parse(abuf[i], alens[i], dns_parse_callback, &ctx);
+
+ if (ctx.cnt) return ctx.cnt;
+ if (alens[0] < 4 || (abuf[0][3] & 15) == 2) return EAI_AGAIN;
+ if ((abuf[0][3] & 15) == 3) return EAI_NONAME;
+ return EAI_FAIL;
}
int __lookup_name(struct address buf[static MAXADDRS], char canon[static 256], const char *name, int family, int flags)
*canon = 0;
if (name) {
- size_t l;
- if ((l = strnlen(name, 256))-1 > 254)
+ /* reject empty name and check len so it fits into temp bufs */
+ size_t l = strnlen(name, 255);
+ if (l-1 >= 254)
return EAI_NONAME;
memcpy(canon, name, l+1);
}
/* Try each backend until there's at least one result. */
cnt = name_from_null(buf, name, family, flags);
- if (cnt<=0) cnt = name_from_numeric(buf, name, family);
- if (cnt<=0 && !(flags & AI_NUMERICHOST)) {
+ if (!cnt) cnt = name_from_numeric(buf, name, family);
+ if (!cnt && !(flags & AI_NUMERICHOST)) {
cnt = name_from_hosts(buf, canon, name, family);
- if (cnt<=0) cnt = name_from_dns(buf, canon, name, family);
+ if (!cnt) cnt = name_from_dns(buf, canon, name, family);
}
if (cnt<=0) return cnt ? cnt : EAI_NONAME;
if (buf[i].family != AF_INET) continue;
memcpy(buf[i].addr+12, buf[i].addr, 4);
memcpy(buf[i].addr, "\0\0\0\0\0\0\0\0\0\0\xff\xff", 12);
- buf[i].scopeid = 0;
buf[i].family = AF_INET6;
}
}