1 |
/* |
2 |
* inet_ntop.c -- provides inet_ntop() if necessary |
3 |
* |
4 |
* $Id: inet_ntop.c,v 1.3 2010/10/06 19:07:47 pseudo Exp $ |
5 |
*/ |
6 |
/* |
7 |
* Portions Copyright (C) 2010 Eggheads Development Team |
8 |
* |
9 |
* This program is free software; you can redistribute it and/or |
10 |
* modify it under the terms of the GNU General Public License |
11 |
* as published by the Free Software Foundation; either version 2 |
12 |
* of the License, or (at your option) any later version. |
13 |
* |
14 |
* This program is distributed in the hope that it will be useful, |
15 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
17 |
* GNU General Public License for more details. |
18 |
* |
19 |
* You should have received a copy of the GNU General Public License |
20 |
* along with this program; if not, write to the Free Software |
21 |
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
22 |
*/ |
23 |
|
24 |
#include "inet_ntop.h" |
25 |
|
26 |
#ifndef HAVE_INET_NTOP |
27 |
/* |
28 |
* Copyright (c) 1996-1999 by Internet Software Consortium. |
29 |
* |
30 |
* Permission to use, copy, modify, and distribute this software for any |
31 |
* purpose with or without fee is hereby granted, provided that the above |
32 |
* copyright notice and this permission notice appear in all copies. |
33 |
* |
34 |
* THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS |
35 |
* ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES |
36 |
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE |
37 |
* CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL |
38 |
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR |
39 |
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS |
40 |
* ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS |
41 |
* SOFTWARE. |
42 |
*/ |
43 |
|
44 |
#include <sys/param.h> |
45 |
#include <sys/types.h> |
46 |
#include <arpa/inet.h> |
47 |
|
48 |
#include <stdio.h> |
49 |
#include <string.h> |
50 |
|
51 |
#ifdef SPRINTF_CHAR |
52 |
# define SPRINTF(x) strlen(sprintf/**/x) |
53 |
#else |
54 |
# define SPRINTF(x) ((size_t)sprintf x) |
55 |
#endif |
56 |
|
57 |
#define NS_INADDRSZ 4 /* IPv4 T_A */ |
58 |
#define NS_IN6ADDRSZ 16 /* IPv6 T_AAAA */ |
59 |
#define NS_INT16SZ 2 /* #/bytes of data in a u_int16_t */ |
60 |
|
61 |
/* |
62 |
* WARNING: Don't even consider trying to compile this on a system where |
63 |
* sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX. |
64 |
*/ |
65 |
|
66 |
static const char *inet_ntop4 (const u_char *src, char *dst, socklen_t size); |
67 |
#ifdef IPV6 |
68 |
static const char *inet_ntop6 (const u_char *src, char *dst, socklen_t size); |
69 |
#endif |
70 |
|
71 |
/* char * |
72 |
* inet_ntop(af, src, dst, size) |
73 |
* convert a network format address to presentation format. |
74 |
* return: |
75 |
* pointer to presentation format address (`dst'), or NULL (see errno). |
76 |
* author: |
77 |
* Paul Vixie, 1996. |
78 |
*/ |
79 |
const char * |
80 |
inet_ntop(af, src, dst, size) |
81 |
int af; |
82 |
const void *src; |
83 |
char *dst; |
84 |
socklen_t size; |
85 |
{ |
86 |
switch (af) { |
87 |
case AF_INET: |
88 |
return (inet_ntop4(src, dst, size)); |
89 |
#ifdef IPV6 |
90 |
case AF_INET6: |
91 |
return (inet_ntop6(src, dst, size)); |
92 |
#endif |
93 |
default: |
94 |
return NULL; |
95 |
} |
96 |
/* NOTREACHED */ |
97 |
} |
98 |
|
99 |
/* const char * |
100 |
* inet_ntop4(src, dst, size) |
101 |
* format an IPv4 address |
102 |
* return: |
103 |
* `dst' (as a const) |
104 |
* notes: |
105 |
* (1) uses no statics |
106 |
* (2) takes a u_char* not an in_addr as input |
107 |
* author: |
108 |
* Paul Vixie, 1996. |
109 |
*/ |
110 |
static const char *inet_ntop4(src, dst, size) |
111 |
const u_char *src; |
112 |
char *dst; |
113 |
socklen_t size; |
114 |
{ |
115 |
static const char fmt[] = "%u.%u.%u.%u"; |
116 |
char tmp[sizeof "255.255.255.255"]; |
117 |
|
118 |
if (SPRINTF((tmp, fmt, src[0], src[1], src[2], src[3])) > size) { |
119 |
/* __set_errno (ENOSPC); */ |
120 |
return (NULL); |
121 |
} |
122 |
return strcpy(dst, tmp); |
123 |
} |
124 |
|
125 |
/* const char * |
126 |
* inet_ntop6(src, dst, size) |
127 |
* convert IPv6 binary address into presentation (printable) format |
128 |
* author: |
129 |
* Paul Vixie, 1996. |
130 |
*/ |
131 |
#ifdef IPV6 |
132 |
static const char * |
133 |
inet_ntop6(src, dst, size) |
134 |
const u_char *src; |
135 |
char *dst; |
136 |
socklen_t size; |
137 |
{ |
138 |
/* |
139 |
* Note that int32_t and int16_t need only be "at least" large enough |
140 |
* to contain a value of the specified size. On some systems, like |
141 |
* Crays, there is no such thing as an integer variable with 16 bits. |
142 |
* Keep this in mind if you think this function should have been coded |
143 |
* to use pointer overlays. All the world's not a VAX. |
144 |
*/ |
145 |
char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp; |
146 |
struct { int base, len; } best, cur; |
147 |
u_int words[NS_IN6ADDRSZ / NS_INT16SZ]; |
148 |
int i; |
149 |
|
150 |
/* |
151 |
* Preprocess: |
152 |
* Copy the input (bytewise) array into a wordwise array. |
153 |
* Find the longest run of 0x00's in src[] for :: shorthanding. |
154 |
*/ |
155 |
memset(words, '\0', sizeof words); |
156 |
best.len = cur.len = 0; |
157 |
for (i = 0; i < NS_IN6ADDRSZ; i += 2) |
158 |
words[i / 2] = (src[i] << 8) | src[i + 1]; |
159 |
best.base = -1; |
160 |
cur.base = -1; |
161 |
for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) { |
162 |
if (words[i] == 0) { |
163 |
if (cur.base == -1) |
164 |
cur.base = i, cur.len = 1; |
165 |
else |
166 |
cur.len++; |
167 |
} else { |
168 |
if (cur.base != -1) { |
169 |
if (best.base == -1 || cur.len > best.len) |
170 |
best = cur; |
171 |
cur.base = -1; |
172 |
} |
173 |
} |
174 |
} |
175 |
if (cur.base != -1) { |
176 |
if (best.base == -1 || cur.len > best.len) |
177 |
best = cur; |
178 |
} |
179 |
if (best.base != -1 && best.len < 2) |
180 |
best.base = -1; |
181 |
|
182 |
/* |
183 |
* Format the result. |
184 |
*/ |
185 |
tp = tmp; |
186 |
for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) { |
187 |
/* Are we inside the best run of 0x00's? */ |
188 |
if (best.base != -1 && i >= best.base && |
189 |
i < (best.base + best.len)) { |
190 |
if (i == best.base) |
191 |
*tp++ = ':'; |
192 |
continue; |
193 |
} |
194 |
/* Are we following an initial run of 0x00s or any real hex? */ |
195 |
if (i != 0) |
196 |
*tp++ = ':'; |
197 |
/* Is this address an encapsulated IPv4? */ |
198 |
if (i == 6 && best.base == 0 && |
199 |
(best.len == 6 || (best.len == 5 && words[5] == 0xffff))) { |
200 |
if (!inet_ntop4(src+12, tp, sizeof tmp - (tp - tmp))) |
201 |
return (NULL); |
202 |
tp += strlen(tp); |
203 |
break; |
204 |
} |
205 |
tp += SPRINTF((tp, "%x", words[i])); |
206 |
} |
207 |
/* Was it a trailing run of 0x00's? */ |
208 |
if (best.base != -1 && (best.base + best.len) == |
209 |
(NS_IN6ADDRSZ / NS_INT16SZ)) |
210 |
*tp++ = ':'; |
211 |
*tp++ = '\0'; |
212 |
|
213 |
/* |
214 |
* Check for overflow, copy, and we're done. |
215 |
*/ |
216 |
if ((socklen_t)(tp - tmp) > size) { |
217 |
/* __set_errno (ENOSPC); */ |
218 |
return (NULL); |
219 |
} |
220 |
return strcpy(dst, tmp); |
221 |
} |
222 |
#endif /* IPV6 */ |
223 |
|
224 |
#endif /* HAVE_INET_NTOP */ |