Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sudo-project
GitHub Repository: sudo-project/sudo
Path: blob/main/lib/util/inet_ntop.c
1532 views
1
/* $OpenBSD: inet_ntop.c,v 1.9 2014/02/05 14:20:43 millert Exp $ */
2
3
/*
4
* SPDX-License-Identifier: ISC
5
*
6
* Copyright (c) 1996 by Internet Software Consortium.
7
*
8
* Permission to use, copy, modify, and distribute this software for any
9
* purpose with or without fee is hereby granted, provided that the above
10
* copyright notice and this permission notice appear in all copies.
11
*
12
* THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
13
* ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
14
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
15
* CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
16
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
17
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
18
* ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
19
* SOFTWARE.
20
*/
21
22
#include <config.h>
23
24
#if !defined(HAVE_INET_NTOP)
25
26
#include <sys/types.h>
27
#include <sys/socket.h>
28
#include <netinet/in.h>
29
#include <arpa/inet.h>
30
#include <arpa/nameser.h>
31
#include <string.h>
32
#include <errno.h>
33
#include <stdio.h>
34
35
#include <sudo_compat.h>
36
37
#ifndef EAFNOSUPPORT
38
# define EAFNOSUPPORT EINVAL
39
#endif
40
41
#ifndef NS_IN6ADDRSZ
42
# ifdef IN6ADDRSZ
43
# define NS_IN6ADDRSZ IN6ADDRSZ
44
# else
45
# define NS_IN6ADDRSZ 16
46
# endif
47
#endif
48
#ifndef NS_INT16SZ
49
# ifdef INT16SZ
50
# define NS_INT16SZ INT16SZ
51
# else
52
# define NS_INT16SZ 2
53
# endif
54
#endif
55
56
/*
57
* WARNING: Don't even consider trying to compile this on a system where
58
* sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
59
*/
60
61
/* const char *
62
* inet_ntop4(src, dst, size)
63
* format an IPv4 address, more or less like inet_ntoa()
64
* return:
65
* `dst' (as a const)
66
* notes:
67
* (1) uses no statics
68
* (2) takes a unsigned char* not an in_addr as input
69
* author:
70
* Paul Vixie, 1996.
71
*/
72
static const char *
73
inet_ntop4(const unsigned char * restrict src, char * restrict dst, socklen_t size)
74
{
75
const char fmt[] = "%u.%u.%u.%u";
76
int len;
77
78
len = snprintf(dst, size, fmt, src[0], src[1], src[2], src[3]);
79
if (len < 0 || (socklen_t)len >= size) {
80
errno = ENOSPC;
81
return (NULL);
82
}
83
return (dst);
84
}
85
86
#ifdef HAVE_STRUCT_IN6_ADDR
87
/* const char *
88
* inet_ntop6(src, dst, size)
89
* convert IPv6 binary address into presentation (printable) format
90
* author:
91
* Paul Vixie, 1996.
92
*/
93
static const char *
94
inet_ntop6(const unsigned char * restrict src, char * restrict dst, socklen_t size)
95
{
96
/*
97
* Note that int32_t and int16_t need only be "at least" large enough
98
* to contain a value of the specified size. On some systems, like
99
* Crays, there is no such thing as an integer variable with 16 bits.
100
* Keep this in mind if you think this function should have been coded
101
* to use pointer overlays. All the world's not a VAX.
102
*/
103
char *cp, *ep;
104
struct { int base, len; } best, cur;
105
unsigned int words[NS_IN6ADDRSZ / NS_INT16SZ];
106
int i;
107
int advance;
108
109
/*
110
* Preprocess:
111
* Copy the input (bytewise) array into a wordwise array.
112
* Find the longest run of 0x00's in src[] for :: shorthanding.
113
*/
114
memset(words, 0, sizeof(words));
115
for (i = 0; i < NS_IN6ADDRSZ; i++)
116
words[i / 2] |= (src[i] << ((1 - (i & 1)) << 3));
117
best.base = -1;
118
best.len = 0;
119
cur.base = -1;
120
cur.len = 0;
121
for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
122
if (words[i] == 0) {
123
if (cur.base == -1)
124
cur.base = i, cur.len = 1;
125
else
126
cur.len++;
127
} else {
128
if (cur.base != -1) {
129
if (best.base == -1 || cur.len > best.len)
130
best = cur;
131
cur.base = -1;
132
}
133
}
134
}
135
if (cur.base != -1) {
136
if (best.base == -1 || cur.len > best.len)
137
best = cur;
138
}
139
if (best.base != -1 && best.len < 2)
140
best.base = -1;
141
142
/*
143
* Format the result.
144
*/
145
cp = dst;
146
ep = dst + size;
147
for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ) && cp < ep; i++) {
148
/* Are we inside the best run of 0x00's? */
149
if (best.base != -1 && i >= best.base &&
150
i < (best.base + best.len)) {
151
if (i == best.base) {
152
if (cp + 1 >= ep) {
153
errno = ENOSPC;
154
return (NULL);
155
}
156
*cp++ = ':';
157
}
158
continue;
159
}
160
/* Are we following an initial run of 0x00s or any real hex? */
161
if (i != 0) {
162
if (cp + 1 >= ep) {
163
errno = ENOSPC;
164
return (NULL);
165
}
166
*cp++ = ':';
167
}
168
/* Is this address an encapsulated IPv4? */
169
if (i == 6 && best.base == 0 &&
170
(best.len == 6 ||
171
(best.len == 7 && words[7] != 0x0001) ||
172
(best.len == 5 && words[5] == 0xffff))) {
173
if (!inet_ntop4(src + 12, cp, (socklen_t)(ep - cp)))
174
return (NULL);
175
cp += strlen(cp);
176
break;
177
}
178
advance = snprintf(cp, (size_t)(ep - cp), "%x", words[i]);
179
if (advance <= 0 || advance >= ep - cp) {
180
errno = ENOSPC;
181
return (NULL);
182
}
183
cp += advance;
184
}
185
/* Was it a trailing run of 0x00's? */
186
if (best.base != -1 &&
187
(best.base + best.len) == (NS_IN6ADDRSZ / NS_INT16SZ)) {
188
if (cp + 1 >= ep) {
189
errno = ENOSPC;
190
return (NULL);
191
}
192
*cp++ = ':';
193
}
194
if (cp + 1 >= ep) {
195
errno = ENOSPC;
196
return (NULL);
197
}
198
*cp++ = '\0';
199
200
return (dst);
201
}
202
#endif /* HAVE_STRUCT_IN6_ADDR */
203
204
/* const char *
205
* inet_ntop(af, src, dst, size)
206
* convert a network format address to presentation format.
207
* return:
208
* pointer to presentation format address (`dst'), or NULL (see errno).
209
* author:
210
* Paul Vixie, 1996.
211
*/
212
const char *
213
sudo_inet_ntop(int af, const void * restrict src, char * restrict dst, socklen_t size)
214
{
215
switch (af) {
216
case AF_INET:
217
return (inet_ntop4(src, dst, size));
218
#ifdef HAVE_STRUCT_IN6_ADDR
219
case AF_INET6:
220
return (inet_ntop6(src, dst, size));
221
#endif
222
default:
223
errno = EAFNOSUPPORT;
224
return (NULL);
225
}
226
/* NOTREACHED */
227
}
228
229
#endif /* !HAVE_INET_NTOP */
230
231