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