inet_ntop
Network address to representation format.
See https://man7.org/linux/man-pages/man3/inet_ntop.3.html
./code/inet_ntop.c
1#include <arpa/inet.h>
2#include <stdio.h>
3
4int main() {
5 struct in_addr addr;
6 uint8_t *p = (uint8_t *)&addr.s_addr;
7 p[0] = 192;
8 p[1] = 168;
9 p[2] = 1;
10 p[3] = 2;
11 char buf[INET_ADDRSTRLEN];
12 const char *ret = inet_ntop(AF_INET, &addr.s_addr, buf, sizeof(buf));
13 printf("%s\n", buf);
14 printf("%p, %p\n", buf, ret);
15 return 0;
16}
17#if 0
18192.168.1.2
190x7ffc808b5e80, 0x7ffc808b5e80
20#endif
Its implementation can be found at https://github.com/bminor/glibc/blob/master/resolv/inet_ntop.c
./code/inet_ntop_impl.c
1// https://github.com/bminor/glibc/blob/master/resolv/inet_ntop.c
2/*
3 * Copyright (c) 1996-1999 by Internet Software Consortium.
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
10 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
11 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
12 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
13 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
14 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
15 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
16 * SOFTWARE.
17 */
18
19#include <sys/param.h>
20#include <sys/types.h>
21#include <sys/socket.h>
22
23#include <netinet/in.h>
24#include <arpa/inet.h>
25#include <arpa/nameser.h>
26
27#include <errno.h>
28#include <stdio.h>
29#include <string.h>
30
31#ifdef SPRINTF_CHAR
32# define SPRINTF(x) strlen(sprintf/**/x)
33#else
34# define SPRINTF(x) ((size_t)sprintf x)
35#endif
36
37/*
38 * WARNING: Don't even consider trying to compile this on a system where
39 * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
40 */
41
42static const char *inet_ntop4 (const u_char *src, char *dst, socklen_t size);
43static const char *inet_ntop6 (const u_char *src, char *dst, socklen_t size);
44
45/* char *
46 * inet_ntop(af, src, dst, size)
47 * convert a network format address to presentation format.
48 * return:
49 * pointer to presentation format address (`dst'), or NULL (see errno).
50 * author:
51 * Paul Vixie, 1996.
52 */
53const char *
54inet_ntop (int af, const void *src, char *dst, socklen_t size)
55{
56 switch (af) {
57 case AF_INET:
58 return (inet_ntop4(src, dst, size));
59 case AF_INET6:
60 return (inet_ntop6(src, dst, size));
61 default:
62 __set_errno (EAFNOSUPPORT);
63 return (NULL);
64 }
65 /* NOTREACHED */
66}
67libc_hidden_def (inet_ntop)
68
69/* const char *
70 * inet_ntop4(src, dst, size)
71 * format an IPv4 address
72 * return:
73 * `dst' (as a const)
74 * notes:
75 * (1) uses no statics
76 * (2) takes a u_char* not an in_addr as input
77 * author:
78 * Paul Vixie, 1996.
79 */
80static const char *
81inet_ntop4 (const u_char *src, char *dst, socklen_t size)
82{
83 static const char fmt[] = "%u.%u.%u.%u";
84 char tmp[sizeof "255.255.255.255"];
85
86 if (SPRINTF((tmp, fmt, src[0], src[1], src[2], src[3])) >= size) {
87 __set_errno (ENOSPC);
88 return (NULL);
89 }
90 return strcpy(dst, tmp);
91}
92
93/* const char *
94 * inet_ntop6(src, dst, size)
95 * convert IPv6 binary address into presentation (printable) format
96 * author:
97 * Paul Vixie, 1996.
98 */
99static const char *
100inet_ntop6 (const u_char *src, char *dst, socklen_t size)
101{
102 /*
103 * Note that int32_t and int16_t need only be "at least" large enough
104 * to contain a value of the specified size. On some systems, like
105 * Crays, there is no such thing as an integer variable with 16 bits.
106 * Keep this in mind if you think this function should have been coded
107 * to use pointer overlays. All the world's not a VAX.
108 */
109 char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp;
110 struct { int base, len; } best, cur;
111 u_int words[NS_IN6ADDRSZ / NS_INT16SZ];
112 int i;
113
114 /*
115 * Preprocess:
116 * Copy the input (bytewise) array into a wordwise array.
117 * Find the longest run of 0x00's in src[] for :: shorthanding.
118 */
119 memset(words, '\0', sizeof words);
120 for (i = 0; i < NS_IN6ADDRSZ; i += 2)
121 words[i / 2] = (src[i] << 8) | src[i + 1];
122 best.base = -1;
123 cur.base = -1;
124 best.len = 0;
125 cur.len = 0;
126 for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
127 if (words[i] == 0) {
128 if (cur.base == -1)
129 cur.base = i, cur.len = 1;
130 else
131 cur.len++;
132 } else {
133 if (cur.base != -1) {
134 if (best.base == -1 || cur.len > best.len)
135 best = cur;
136 cur.base = -1;
137 }
138 }
139 }
140 if (cur.base != -1) {
141 if (best.base == -1 || cur.len > best.len)
142 best = cur;
143 }
144 if (best.base != -1 && best.len < 2)
145 best.base = -1;
146
147 /*
148 * Format the result.
149 */
150 tp = tmp;
151 for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
152 /* Are we inside the best run of 0x00's? */
153 if (best.base != -1 && i >= best.base &&
154 i < (best.base + best.len)) {
155 if (i == best.base)
156 *tp++ = ':';
157 continue;
158 }
159 /* Are we following an initial run of 0x00s or any real hex? */
160 if (i != 0)
161 *tp++ = ':';
162 /* Is this address an encapsulated IPv4? */
163 if (i == 6 && best.base == 0 &&
164 (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) {
165 if (!inet_ntop4(src+12, tp, sizeof tmp - (tp - tmp)))
166 return (NULL);
167 tp += strlen(tp);
168 break;
169 }
170 tp += SPRINTF((tp, "%x", words[i]));
171 }
172 /* Was it a trailing run of 0x00's? */
173 if (best.base != -1 && (best.base + best.len) ==
174 (NS_IN6ADDRSZ / NS_INT16SZ))
175 *tp++ = ':';
176 *tp++ = '\0';
177
178 /*
179 * Check for overflow, copy, and we're done.
180 */
181 if ((socklen_t)(tp - tmp) > size) {
182 __set_errno (ENOSPC);
183 return (NULL);
184 }
185 return strcpy(dst, tmp);
186}