Age Owner TLA Line data Source code
1 : /*
2 : * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
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 ISC DISCLAIMS ALL WARRANTIES
10 : * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 : * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
12 : * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 : * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 : * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
15 : * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 : *
17 : * src/backend/utils/adt/inet_cidr_ntop.c
18 : */
19 :
20 : #if defined(LIBC_SCCS) && !defined(lint)
21 : static const char rcsid[] = "Id: inet_net_ntop.c,v 1.1.2.2 2004/03/09 09:17:27 marka Exp $";
22 : #endif
23 :
24 : #include "postgres.h"
25 :
26 : #include <sys/socket.h>
27 : #include <netinet/in.h>
28 : #include <arpa/inet.h>
29 :
30 : #include "utils/builtins.h"
31 : #include "utils/inet.h"
32 :
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_cidr_ntop_ipv4(const u_char *src, int bits,
41 : char *dst, size_t size);
42 : static char *inet_cidr_ntop_ipv6(const u_char *src, int bits,
43 : char *dst, size_t size);
44 :
45 : /*
46 : * char *
47 : * pg_inet_cidr_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 *
1330 tgl 56 CBC 51 : pg_inet_cidr_ntop(int af, const void *src, int bits, char *dst, size_t size)
57 : {
8954 bruce 58 51 : switch (af)
59 : {
7229 60 42 : case PGSQL_AF_INET:
2061 peter_e 61 42 : return inet_cidr_ntop_ipv4(src, bits, dst, size);
7229 bruce 62 9 : case PGSQL_AF_INET6:
2061 peter_e 63 9 : return inet_cidr_ntop_ipv6(src, bits, dst, size);
8954 bruce 64 UBC 0 : default:
65 0 : errno = EAFNOSUPPORT;
2061 peter_e 66 0 : return NULL;
67 : }
68 : }
69 :
70 :
71 : /*
72 : * static char *
73 : * inet_cidr_ntop_ipv4(src, bits, dst, size)
74 : * convert IPv4 network number from network to presentation format.
75 : * generates CIDR style result always.
76 : * return:
77 : * pointer to dst, or NULL if an error occurred (check errno).
78 : * note:
79 : * network byte order assumed. this means 192.5.5.240/28 has
80 : * 0b11110000 in its fourth octet.
81 : * author:
82 : * Paul Vixie (ISC), July 1996
83 : */
84 : static char *
8935 bruce 85 CBC 42 : inet_cidr_ntop_ipv4(const u_char *src, int bits, char *dst, size_t size)
86 : {
8954 87 42 : char *odst = dst;
88 : char *t;
89 : u_int m;
90 : int b;
91 :
92 42 : if (bits < 0 || bits > 32)
93 : {
8954 bruce 94 UBC 0 : errno = EINVAL;
2061 peter_e 95 0 : return NULL;
96 : }
97 :
8954 bruce 98 CBC 42 : if (bits == 0)
99 : {
8954 bruce 100 UBC 0 : if (size < sizeof "0")
101 0 : goto emsgsize;
102 0 : *dst++ = '0';
6641 tgl 103 0 : size--;
8954 bruce 104 0 : *dst = '\0';
105 : }
106 :
107 : /* Format whole octets. */
8954 bruce 108 CBC 147 : for (b = bits / 8; b > 0; b--)
109 : {
6641 tgl 110 105 : if (size <= sizeof "255.")
8954 bruce 111 UBC 0 : goto emsgsize;
8954 bruce 112 CBC 105 : t = dst;
8185 tgl 113 105 : dst += SPRINTF((dst, "%u", *src++));
6641 114 105 : if (b > 1)
115 : {
116 63 : *dst++ = '.';
117 63 : *dst = '\0';
118 : }
8954 bruce 119 105 : size -= (size_t) (dst - t);
120 : }
121 :
122 : /* Format partial octet. */
123 42 : b = bits % 8;
124 42 : if (b > 0)
125 : {
6641 tgl 126 3 : if (size <= sizeof ".255")
8954 bruce 127 UBC 0 : goto emsgsize;
8954 bruce 128 CBC 3 : t = dst;
129 3 : if (dst != odst)
130 3 : *dst++ = '.';
131 3 : m = ((1 << b) - 1) << (8 - b);
132 3 : dst += SPRINTF((dst, "%u", *src & m));
133 3 : size -= (size_t) (dst - t);
134 : }
135 :
136 : /* Format CIDR /width. */
6641 tgl 137 42 : if (size <= sizeof "/32")
8954 bruce 138 UBC 0 : goto emsgsize;
8954 bruce 139 CBC 42 : dst += SPRINTF((dst, "/%u", bits));
2061 peter_e 140 42 : return odst;
141 :
8954 bruce 142 UBC 0 : emsgsize:
143 0 : errno = EMSGSIZE;
2061 peter_e 144 0 : return NULL;
145 : }
146 :
147 : /*
148 : * static char *
149 : * inet_cidr_ntop_ipv6(src, bits, dst, size)
150 : * convert IPv6 network number from network to presentation format.
151 : * generates CIDR style result always. Picks the shortest representation
152 : * unless the IP is really IPv4.
153 : * always prints specified number of bits (bits).
154 : * return:
155 : * pointer to dst, or NULL if an error occurred (check errno).
156 : * note:
157 : * network byte order assumed. this means 192.5.5.240/28 has
158 : * 0x11110000 in its fourth octet.
159 : * author:
160 : * Vadim Kogan (UCB), June 2001
161 : * Original version (IPv4) by Paul Vixie (ISC), July 1996
162 : */
163 :
164 : static char *
7229 bruce 165 CBC 9 : inet_cidr_ntop_ipv6(const u_char *src, int bits, char *dst, size_t size)
166 : {
167 : u_int m;
168 : int b;
169 : int p;
170 : int zero_s,
171 : zero_l,
172 : tmp_zero_s,
173 : tmp_zero_l;
174 : int i;
7188 175 9 : int is_ipv4 = 0;
176 : unsigned char inbuf[16];
177 : char outbuf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")];
178 : char *cp;
179 : int words;
180 : u_char *s;
181 :
182 9 : if (bits < 0 || bits > 128)
183 : {
7229 bruce 184 UBC 0 : errno = EINVAL;
2061 peter_e 185 0 : return NULL;
186 : }
187 :
7229 bruce 188 CBC 9 : cp = outbuf;
189 :
7188 190 9 : if (bits == 0)
191 : {
7229 bruce 192 UBC 0 : *cp++ = ':';
193 0 : *cp++ = ':';
194 0 : *cp = '\0';
195 : }
196 : else
197 : {
198 : /* Copy src to private buffer. Zero host part. */
7229 bruce 199 CBC 9 : p = (bits + 7) / 8;
200 9 : memcpy(inbuf, src, p);
201 9 : memset(inbuf + p, 0, 16 - p);
202 9 : b = bits % 8;
7188 203 9 : if (b != 0)
204 : {
1757 tgl 205 3 : m = ((u_int) ~0) << (8 - b);
7188 bruce 206 3 : inbuf[p - 1] &= m;
207 : }
208 :
7229 209 9 : s = inbuf;
210 :
211 : /* how many words need to be displayed in output */
212 9 : words = (bits + 15) / 16;
213 9 : if (words == 1)
7229 bruce 214 UBC 0 : words = 2;
215 :
216 : /* Find the longest substring of zero's */
7229 bruce 217 CBC 9 : zero_s = zero_l = tmp_zero_s = tmp_zero_l = 0;
7188 218 81 : for (i = 0; i < (words * 2); i += 2)
219 : {
220 72 : if ((s[i] | s[i + 1]) == 0)
221 : {
7229 222 45 : if (tmp_zero_l == 0)
223 9 : tmp_zero_s = i / 2;
224 45 : tmp_zero_l++;
225 : }
226 : else
227 : {
7188 228 27 : if (tmp_zero_l && zero_l < tmp_zero_l)
229 : {
7229 230 9 : zero_s = tmp_zero_s;
231 9 : zero_l = tmp_zero_l;
232 9 : tmp_zero_l = 0;
233 : }
234 : }
235 : }
236 :
7188 237 9 : if (tmp_zero_l && zero_l < tmp_zero_l)
238 : {
7229 bruce 239 UBC 0 : zero_s = tmp_zero_s;
240 0 : zero_l = tmp_zero_l;
241 : }
242 :
7229 bruce 243 CBC 9 : if (zero_l != words && zero_s == 0 && ((zero_l == 6) ||
2118 tgl 244 3 : ((zero_l == 5 && s[10] == 0xff && s[11] == 0xff) ||
2118 tgl 245 UBC 0 : ((zero_l == 7 && s[14] != 0 && s[15] != 1)))))
7229 bruce 246 CBC 3 : is_ipv4 = 1;
247 :
248 : /* Format whole words. */
7188 249 81 : for (p = 0; p < words; p++)
250 : {
251 72 : if (zero_l != 0 && p >= zero_s && p < zero_s + zero_l)
252 : {
253 : /* Time to skip some zeros */
7229 254 45 : if (p == zero_s)
255 9 : *cp++ = ':';
7188 256 45 : if (p == words - 1)
7229 bruce 257 UBC 0 : *cp++ = ':';
7229 bruce 258 CBC 45 : s++;
259 45 : s++;
260 45 : continue;
261 : }
262 :
7188 263 27 : if (is_ipv4 && p > 5)
264 : {
7229 265 6 : *cp++ = (p == 6) ? ':' : '.';
266 6 : cp += SPRINTF((cp, "%u", *s++));
267 : /* we can potentially drop the last octet */
7188 268 6 : if (p != 7 || bits > 120)
269 : {
7229 270 6 : *cp++ = '.';
271 6 : cp += SPRINTF((cp, "%u", *s++));
272 : }
273 : }
274 : else
275 : {
276 21 : if (cp != outbuf)
277 15 : *cp++ = ':';
278 21 : cp += SPRINTF((cp, "%x", *s * 256 + s[1]));
279 21 : s += 2;
280 : }
281 : }
282 : }
283 : /* Format CIDR /width. */
6194 284 9 : (void) SPRINTF((cp, "/%u", bits));
7229 285 9 : if (strlen(outbuf) + 1 > size)
7229 bruce 286 UBC 0 : goto emsgsize;
7229 bruce 287 CBC 9 : strcpy(dst, outbuf);
288 :
2061 peter_e 289 9 : return dst;
290 :
7229 bruce 291 UBC 0 : emsgsize:
292 0 : errno = EMSGSIZE;
2061 peter_e 293 0 : return NULL;
294 : }
|