Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/lib/libc/inet/inet_net_ntop.c
39530 views
1
/*-
2
* SPDX-License-Identifier: ISC
3
*
4
* Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
5
* Copyright (c) 1996,1999 by Internet Software Consortium.
6
*
7
* Permission to use, copy, modify, and distribute this software for any
8
* purpose with or without fee is hereby granted, provided that the above
9
* copyright notice and this permission notice appear in all copies.
10
*
11
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
12
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
14
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
17
* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18
*/
19
20
#include "port_before.h"
21
22
#include <sys/types.h>
23
#include <sys/socket.h>
24
#include <netinet/in.h>
25
#include <arpa/inet.h>
26
27
#include <errno.h>
28
#include <stdio.h>
29
#include <string.h>
30
#include <stdlib.h>
31
32
#include "port_after.h"
33
34
#ifdef SPRINTF_CHAR
35
# define SPRINTF(x) strlen(sprintf/**/x)
36
#else
37
# define SPRINTF(x) ((size_t)sprintf x)
38
#endif
39
40
static char * inet_net_ntop_ipv4(const u_char *src, int bits, char *dst,
41
size_t size);
42
static char * inet_net_ntop_ipv6(const u_char *src, int bits, char *dst,
43
size_t size);
44
45
/*%
46
* char *
47
* inet_net_ntop(af, src, bits, dst, size)
48
* convert network number from network to presentation format.
49
* generates CIDR style result always.
50
* return:
51
* pointer to dst, or NULL if an error occurred (check errno).
52
* author:
53
* Paul Vixie (ISC), July 1996
54
*/
55
char *
56
inet_net_ntop(int af, const void *src, int bits, char *dst, size_t size)
57
{
58
switch (af) {
59
case AF_INET:
60
return (inet_net_ntop_ipv4(src, bits, dst, size));
61
case AF_INET6:
62
return (inet_net_ntop_ipv6(src, bits, dst, size));
63
default:
64
errno = EAFNOSUPPORT;
65
return (NULL);
66
}
67
}
68
69
/*%
70
* static char *
71
* inet_net_ntop_ipv4(src, bits, dst, size)
72
* convert IPv4 network number from network to presentation format.
73
* generates CIDR style result always.
74
* return:
75
* pointer to dst, or NULL if an error occurred (check errno).
76
* note:
77
* network byte order assumed. this means 192.5.5.240/28 has
78
* 0b11110000 in its fourth octet.
79
* author:
80
* Paul Vixie (ISC), July 1996
81
*/
82
static char *
83
inet_net_ntop_ipv4(const u_char *src, int bits, char *dst, size_t size)
84
{
85
char *odst = dst;
86
char *t;
87
u_int m;
88
int b;
89
90
if (bits < 0 || bits > 32) {
91
errno = EINVAL;
92
return (NULL);
93
}
94
95
if (bits == 0) {
96
if (size < sizeof "0")
97
goto emsgsize;
98
*dst++ = '0';
99
size--;
100
*dst = '\0';
101
}
102
103
/* Format whole octets. */
104
for (b = bits / 8; b > 0; b--) {
105
if (size <= sizeof "255.")
106
goto emsgsize;
107
t = dst;
108
dst += SPRINTF((dst, "%u", *src++));
109
if (b > 1) {
110
*dst++ = '.';
111
*dst = '\0';
112
}
113
size -= (size_t)(dst - t);
114
}
115
116
/* Format partial octet. */
117
b = bits % 8;
118
if (b > 0) {
119
if (size <= sizeof ".255")
120
goto emsgsize;
121
t = dst;
122
if (dst != odst)
123
*dst++ = '.';
124
m = ((1 << b) - 1) << (8 - b);
125
dst += SPRINTF((dst, "%u", *src & m));
126
size -= (size_t)(dst - t);
127
}
128
129
/* Format CIDR /width. */
130
if (size <= sizeof "/32")
131
goto emsgsize;
132
dst += SPRINTF((dst, "/%u", bits));
133
return (odst);
134
135
emsgsize:
136
errno = EMSGSIZE;
137
return (NULL);
138
}
139
140
/*%
141
* static char *
142
* inet_net_ntop_ipv6(src, bits, fakebits, dst, size)
143
* convert IPv6 network number from network to presentation format.
144
* generates CIDR style result always. Picks the shortest representation
145
* unless the IP is really IPv4.
146
* always prints specified number of bits (bits).
147
* return:
148
* pointer to dst, or NULL if an error occurred (check errno).
149
* note:
150
* network byte order assumed. this means 192.5.5.240/28 has
151
* 0b11110000 in its fourth octet.
152
* author:
153
* Vadim Kogan (UCB), June 2001
154
* Original version (IPv4) by Paul Vixie (ISC), July 1996
155
*/
156
157
static char *
158
inet_net_ntop_ipv6(const u_char *src, int bits, char *dst, size_t size) {
159
u_int m;
160
int b;
161
int p;
162
int zero_s, zero_l, tmp_zero_s, tmp_zero_l;
163
int i;
164
int is_ipv4 = 0;
165
unsigned char inbuf[16];
166
char outbuf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")];
167
char *cp;
168
int words;
169
u_char *s;
170
171
if (bits < 0 || bits > 128) {
172
errno = EINVAL;
173
return (NULL);
174
}
175
176
cp = outbuf;
177
178
if (bits == 0) {
179
*cp++ = ':';
180
*cp++ = ':';
181
*cp = '\0';
182
} else {
183
/* Copy src to private buffer. Zero host part. */
184
p = (bits + 7) / 8;
185
memcpy(inbuf, src, p);
186
memset(inbuf + p, 0, 16 - p);
187
b = bits % 8;
188
if (b != 0) {
189
m = ~0 << (8 - b);
190
inbuf[p-1] &= m;
191
}
192
193
s = inbuf;
194
195
/* how many words need to be displayed in output */
196
words = (bits + 15) / 16;
197
if (words == 1)
198
words = 2;
199
200
/* Find the longest substring of zero's */
201
zero_s = zero_l = tmp_zero_s = tmp_zero_l = 0;
202
for (i = 0; i < (words * 2); i += 2) {
203
if ((s[i] | s[i+1]) == 0) {
204
if (tmp_zero_l == 0)
205
tmp_zero_s = i / 2;
206
tmp_zero_l++;
207
} else {
208
if (tmp_zero_l && zero_l < tmp_zero_l) {
209
zero_s = tmp_zero_s;
210
zero_l = tmp_zero_l;
211
tmp_zero_l = 0;
212
}
213
}
214
}
215
216
if (tmp_zero_l && zero_l < tmp_zero_l) {
217
zero_s = tmp_zero_s;
218
zero_l = tmp_zero_l;
219
}
220
221
if (zero_l != words && zero_s == 0 && ((zero_l == 6) ||
222
((zero_l == 5 && s[10] == 0xff && s[11] == 0xff) ||
223
((zero_l == 7 && s[14] != 0 && s[15] != 1)))))
224
is_ipv4 = 1;
225
226
/* Format whole words. */
227
for (p = 0; p < words; p++) {
228
if (zero_l != 0 && p >= zero_s && p < zero_s + zero_l) {
229
/* Time to skip some zeros */
230
if (p == zero_s)
231
*cp++ = ':';
232
if (p == words - 1)
233
*cp++ = ':';
234
s++;
235
s++;
236
continue;
237
}
238
239
if (is_ipv4 && p > 5 ) {
240
*cp++ = (p == 6) ? ':' : '.';
241
cp += SPRINTF((cp, "%u", *s++));
242
/* we can potentially drop the last octet */
243
if (p != 7 || bits > 120) {
244
*cp++ = '.';
245
cp += SPRINTF((cp, "%u", *s++));
246
}
247
} else {
248
if (cp != outbuf)
249
*cp++ = ':';
250
cp += SPRINTF((cp, "%x", *s * 256 + s[1]));
251
s += 2;
252
}
253
}
254
}
255
/* Format CIDR /width. */
256
sprintf(cp, "/%u", bits);
257
if (strlen(outbuf) + 1 > size)
258
goto emsgsize;
259
strcpy(dst, outbuf);
260
261
return (dst);
262
263
emsgsize:
264
errno = EMSGSIZE;
265
return (NULL);
266
}
267
268
/*
269
* Weak aliases for applications that use certain private entry points,
270
* and fail to include <arpa/inet.h>.
271
*/
272
#undef inet_net_ntop
273
__weak_reference(__inet_net_ntop, inet_net_ntop);
274
275
/*! \file */
276
277