1#include <sys/socket.h>
2#include <netinet/in.h>
3#include <netdb.h>
4#include <net/if.h>
5#include <arpa/inet.h>
6#include <limits.h>
7#include <stdlib.h>
8#include <string.h>
9#include <ctype.h>
10#include "lookup.h"
11
12int __inet_aton(const char *, struct in_addr *);
13
14int __lookup_ipliteral(struct address buf[static 1], const char *name, int family)
15{
16	struct in_addr a4;
17	struct in6_addr a6;
18	if (__inet_aton(name, &a4) > 0) {
19		if (family == AF_INET6) /* wrong family */
20			return EAI_NONAME;
21		memcpy(&buf[0].addr, &a4, sizeof a4);
22		buf[0].family = AF_INET;
23		buf[0].scopeid = 0;
24		return 1;
25	}
26
27	char tmp[64];
28	char *p = strchr(name, '%'), *z;
29	unsigned long long scopeid = 0;
30	if (p && p-name < 64) {
31		memcpy(tmp, name, p-name);
32		tmp[p-name] = 0;
33		name = tmp;
34	}
35
36	if (inet_pton(AF_INET6, name, &a6) <= 0)
37		return 0;
38	if (family == AF_INET) /* wrong family */
39		return EAI_NONAME;
40
41	memcpy(&buf[0].addr, &a6, sizeof a6);
42	buf[0].family = AF_INET6;
43	if (p) {
44		if (isdigit(*++p)) scopeid = strtoull(p, &z, 10);
45		else z = p-1;
46		if (*z) {
47			if (!IN6_IS_ADDR_LINKLOCAL(&a6) &&
48			    !IN6_IS_ADDR_MC_LINKLOCAL(&a6))
49				return EAI_NONAME;
50			scopeid = if_nametoindex(p);
51			if (!scopeid) return EAI_NONAME;
52		}
53		if (scopeid > UINT_MAX) return EAI_NONAME;
54	}
55	buf[0].scopeid = scopeid;
56	return 1;
57}
58