1
2#include <sys/types.h>
3#include <netinet/in.h>
4#include <arpa/inet.h>
5#include <stdio.h>
6#include <stdint.h>
7#include <string.h>
8#include <errno.h>
9#include <sys/socket.h>
10
11#define MAX_V4_ADDR_LEN 16
12#define MAX_V6_ADDR_LEN 64
13
14static const char *hexchars = "0123456789abcdef";
15
16const char *
17inet_ntop6(const struct in6_addr *addr, char *dst, socklen_t size)
18{
19	char hexa[8][5], tmp[MAX_V6_ADDR_LEN];
20	int zr[8];
21	socklen_t len;
22	int32_t i, j, k, skip;
23	uint8_t x8, hx8;
24	uint16_t x16;
25	struct in_addr a4;
26
27	if (addr == NULL)
28	{
29		errno = EAFNOSUPPORT;
30		return NULL;
31	}
32
33	if (dst == NULL)
34	{
35		errno = ENOSPC;
36		return NULL;
37	}
38
39	memset(tmp, 0, MAX_V6_ADDR_LEN);
40
41	/*  check for mapped or compat addresses */
42	i = IN6_IS_ADDR_V4MAPPED(addr);
43	j = IN6_IS_ADDR_V4COMPAT(addr);
44	if ((i != 0) || (j != 0))
45	{
46		a4.s_addr = addr->__u6_addr.__u6_addr32[3];
47		sprintf(tmp, "::%s%s", (i != 0) ? "ffff:" : "", inet_ntoa(a4));
48		len = strlen(tmp) + 1;
49		if (len > size)
50		{
51			errno = ENOSPC;
52			return NULL;
53		}
54
55		memcpy(dst, tmp, len);
56		return dst;
57	}
58
59	k = 0;
60	for (i = 0; i < 16; i += 2)
61	{
62		j = 0;
63		skip = 1;
64
65		memset(hexa[k], 0, 5);
66
67		x8 = addr->__u6_addr.__u6_addr8[i];
68
69		hx8 = x8 >> 4;
70		if (hx8 != 0)
71		{
72			skip = 0;
73			hexa[k][j++] = hexchars[hx8];
74		}
75
76		hx8 = x8 & 0x0f;
77		if ((skip == 0) || ((skip == 1) && (hx8 != 0)))
78		{
79			skip = 0;
80			hexa[k][j++] = hexchars[hx8];
81		}
82
83		x8 = addr->__u6_addr.__u6_addr8[i + 1];
84
85		hx8 = x8 >> 4;
86		if ((skip == 0) || ((skip == 1) && (hx8 != 0)))
87		{
88			hexa[k][j++] = hexchars[hx8];
89		}
90
91		hx8 = x8 & 0x0f;
92		hexa[k][j++] = hexchars[hx8];
93
94		k++;
95	}
96
97	/* find runs of zeros for :: convention */
98	j = 0;
99	for (i = 7; i >= 0; i--)
100	{
101		zr[i] = j;
102		x16 = addr->__u6_addr.__u6_addr16[i];
103		if (x16 == 0) j++;
104		else j = 0;
105		zr[i] = j;
106	}
107
108	/* find longest run of zeros */
109	k = -1;
110	j = 0;
111	for(i = 0; i < 8; i++)
112	{
113		if (zr[i] > j)
114		{
115			k = i;
116			j = zr[i];
117		}
118	}
119
120	for(i = 0; i < 8; i++)
121	{
122		if (i != k) zr[i] = 0;
123	}
124
125	len = 0;
126	for (i = 0; i < 8; i++)
127	{
128		if (zr[i] != 0)
129		{
130			/* check for leading zero */
131			if (i == 0) tmp[len++] = ':';
132			tmp[len++] = ':';
133			i += (zr[i] - 1);
134			continue;
135		}
136		for (j = 0; hexa[i][j] != '\0'; j++) tmp[len++] = hexa[i][j];
137		if (i != 7) tmp[len++] = ':';
138	}
139
140	/* trailing NULL */
141	len++;
142
143	if (len > size)
144	{
145		errno = ENOSPC;
146		return NULL;
147	}
148
149	memcpy(dst, tmp, len);
150	return dst;
151}
152
153const char *
154inet_ntop4(const struct in_addr *addr, char *dst, socklen_t size)
155{
156	char tmp[MAX_V4_ADDR_LEN], *p;
157	const u_int8_t *ap = (u_int8_t *)&addr->s_addr;
158	int i, ql, len;
159
160	if (addr == NULL)
161	{
162		errno = EAFNOSUPPORT;
163		return NULL;
164	}
165
166	if (dst == NULL)
167	{
168		errno = ENOSPC;
169		return NULL;
170	}
171
172	memset(tmp, 0, MAX_V4_ADDR_LEN);
173
174	/* 3 dots, trailing nul */
175	len = 4;
176
177	p = tmp;
178
179	for (i = 0; i < 4; i++, ap++)
180	{
181		snprintf(p, 4, "%d", *ap);
182		ql = strlen(p);
183		len += ql;
184		p += ql;
185		if (i < 3) *p++ = '.';
186	}
187
188	if (len > size)
189	{
190		errno = ENOSPC;
191		return NULL;
192	}
193
194	memcpy(dst, tmp, len);
195	return dst;
196}
197
198const char *
199inet_ntop(int af, const void *addr, char *buf, socklen_t len)
200{
201	if (af == AF_INET6) return inet_ntop6(addr, buf, len);
202	if (af == AF_INET) return inet_ntop4(addr, buf, len);
203
204	errno = EAFNOSUPPORT;
205	return NULL;
206}
207