~ubuntu-branches/ubuntu/oneiric/postgresql-9.1/oneiric-security

« back to all changes in this revision

Viewing changes to src/backend/utils/adt/inet_cidr_ntop.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2011-05-11 10:41:53 UTC
  • Revision ID: james.westby@ubuntu.com-20110511104153-psbh2o58553fv1m0
Tags: upstream-9.1~beta1
ImportĀ upstreamĀ versionĀ 9.1~beta1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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_net_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/types.h>
 
27
#include <sys/socket.h>
 
28
#include <netinet/in.h>
 
29
#include <arpa/inet.h>
 
30
 
 
31
#include "utils/builtins.h"
 
32
#include "utils/inet.h"
 
33
 
 
34
 
 
35
#ifdef SPRINTF_CHAR
 
36
#define SPRINTF(x) strlen(sprintf/**/x)
 
37
#else
 
38
#define SPRINTF(x) ((size_t)sprintf x)
 
39
#endif
 
40
 
 
41
static char *inet_cidr_ntop_ipv4(const u_char *src, int bits,
 
42
                                        char *dst, size_t size);
 
43
static char *inet_cidr_ntop_ipv6(const u_char *src, int bits,
 
44
                                        char *dst, size_t size);
 
45
 
 
46
/*
 
47
 * char *
 
48
 * inet_cidr_ntop(af, src, bits, dst, size)
 
49
 *      convert network number from network to presentation format.
 
50
 *      generates CIDR style result always.
 
51
 * return:
 
52
 *      pointer to dst, or NULL if an error occurred (check errno).
 
53
 * author:
 
54
 *      Paul Vixie (ISC), July 1996
 
55
 */
 
56
char *
 
57
inet_cidr_ntop(int af, const void *src, int bits, char *dst, size_t size)
 
58
{
 
59
        switch (af)
 
60
        {
 
61
                case PGSQL_AF_INET:
 
62
                        return (inet_cidr_ntop_ipv4(src, bits, dst, size));
 
63
                case PGSQL_AF_INET6:
 
64
                        return (inet_cidr_ntop_ipv6(src, bits, dst, size));
 
65
                default:
 
66
                        errno = EAFNOSUPPORT;
 
67
                        return (NULL);
 
68
        }
 
69
}
 
70
 
 
71
 
 
72
/*
 
73
 * static char *
 
74
 * inet_cidr_ntop_ipv4(src, bits, dst, size)
 
75
 *      convert IPv4 network number from network to presentation format.
 
76
 *      generates CIDR style result always.
 
77
 * return:
 
78
 *      pointer to dst, or NULL if an error occurred (check errno).
 
79
 * note:
 
80
 *      network byte order assumed.  this means 192.5.5.240/28 has
 
81
 *      0b11110000 in its fourth octet.
 
82
 * author:
 
83
 *      Paul Vixie (ISC), July 1996
 
84
 */
 
85
static char *
 
86
inet_cidr_ntop_ipv4(const u_char *src, int bits, char *dst, size_t size)
 
87
{
 
88
        char       *odst = dst;
 
89
        char       *t;
 
90
        u_int           m;
 
91
        int                     b;
 
92
 
 
93
        if (bits < 0 || bits > 32)
 
94
        {
 
95
                errno = EINVAL;
 
96
                return (NULL);
 
97
        }
 
98
 
 
99
        if (bits == 0)
 
100
        {
 
101
                if (size < sizeof "0")
 
102
                        goto emsgsize;
 
103
                *dst++ = '0';
 
104
                size--;
 
105
                *dst = '\0';
 
106
        }
 
107
 
 
108
        /* Format whole octets. */
 
109
        for (b = bits / 8; b > 0; b--)
 
110
        {
 
111
                if (size <= sizeof "255.")
 
112
                        goto emsgsize;
 
113
                t = dst;
 
114
                dst += SPRINTF((dst, "%u", *src++));
 
115
                if (b > 1)
 
116
                {
 
117
                        *dst++ = '.';
 
118
                        *dst = '\0';
 
119
                }
 
120
                size -= (size_t) (dst - t);
 
121
        }
 
122
 
 
123
        /* Format partial octet. */
 
124
        b = bits % 8;
 
125
        if (b > 0)
 
126
        {
 
127
                if (size <= sizeof ".255")
 
128
                        goto emsgsize;
 
129
                t = dst;
 
130
                if (dst != odst)
 
131
                        *dst++ = '.';
 
132
                m = ((1 << b) - 1) << (8 - b);
 
133
                dst += SPRINTF((dst, "%u", *src & m));
 
134
                size -= (size_t) (dst - t);
 
135
        }
 
136
 
 
137
        /* Format CIDR /width. */
 
138
        if (size <= sizeof "/32")
 
139
                goto emsgsize;
 
140
        dst += SPRINTF((dst, "/%u", bits));
 
141
        return (odst);
 
142
 
 
143
emsgsize:
 
144
        errno = EMSGSIZE;
 
145
        return (NULL);
 
146
}
 
147
 
 
148
/*
 
149
 * static char *
 
150
 * inet_cidr_ntop_ipv6(src, bits, fakebits, dst, size)
 
151
 *      convert IPv6 network number from network to presentation format.
 
152
 *      generates CIDR style result always. Picks the shortest representation
 
153
 *      unless the IP is really IPv4.
 
154
 *      always prints specified number of bits (bits).
 
155
 * return:
 
156
 *      pointer to dst, or NULL if an error occurred (check errno).
 
157
 * note:
 
158
 *      network byte order assumed.  this means 192.5.5.240/28 has
 
159
 *      0x11110000 in its fourth octet.
 
160
 * author:
 
161
 *      Vadim Kogan (UCB), June 2001
 
162
 *      Original version (IPv4) by Paul Vixie (ISC), July 1996
 
163
 */
 
164
 
 
165
static char *
 
166
inet_cidr_ntop_ipv6(const u_char *src, int bits, char *dst, size_t size)
 
167
{
 
168
        u_int           m;
 
169
        int                     b;
 
170
        int                     p;
 
171
        int                     zero_s,
 
172
                                zero_l,
 
173
                                tmp_zero_s,
 
174
                                tmp_zero_l;
 
175
        int                     i;
 
176
        int                     is_ipv4 = 0;
 
177
        unsigned char inbuf[16];
 
178
        char            outbuf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")];
 
179
        char       *cp;
 
180
        int                     words;
 
181
        u_char     *s;
 
182
 
 
183
        if (bits < 0 || bits > 128)
 
184
        {
 
185
                errno = EINVAL;
 
186
                return (NULL);
 
187
        }
 
188
 
 
189
        cp = outbuf;
 
190
 
 
191
        if (bits == 0)
 
192
        {
 
193
                *cp++ = ':';
 
194
                *cp++ = ':';
 
195
                *cp = '\0';
 
196
        }
 
197
        else
 
198
        {
 
199
                /* Copy src to private buffer.  Zero host part. */
 
200
                p = (bits + 7) / 8;
 
201
                memcpy(inbuf, src, p);
 
202
                memset(inbuf + p, 0, 16 - p);
 
203
                b = bits % 8;
 
204
                if (b != 0)
 
205
                {
 
206
                        m = ~0 << (8 - b);
 
207
                        inbuf[p - 1] &= m;
 
208
                }
 
209
 
 
210
                s = inbuf;
 
211
 
 
212
                /* how many words need to be displayed in output */
 
213
                words = (bits + 15) / 16;
 
214
                if (words == 1)
 
215
                        words = 2;
 
216
 
 
217
                /* Find the longest substring of zero's */
 
218
                zero_s = zero_l = tmp_zero_s = tmp_zero_l = 0;
 
219
                for (i = 0; i < (words * 2); i += 2)
 
220
                {
 
221
                        if ((s[i] | s[i + 1]) == 0)
 
222
                        {
 
223
                                if (tmp_zero_l == 0)
 
224
                                        tmp_zero_s = i / 2;
 
225
                                tmp_zero_l++;
 
226
                        }
 
227
                        else
 
228
                        {
 
229
                                if (tmp_zero_l && zero_l < tmp_zero_l)
 
230
                                {
 
231
                                        zero_s = tmp_zero_s;
 
232
                                        zero_l = tmp_zero_l;
 
233
                                        tmp_zero_l = 0;
 
234
                                }
 
235
                        }
 
236
                }
 
237
 
 
238
                if (tmp_zero_l && zero_l < tmp_zero_l)
 
239
                {
 
240
                        zero_s = tmp_zero_s;
 
241
                        zero_l = tmp_zero_l;
 
242
                }
 
243
 
 
244
                if (zero_l != words && zero_s == 0 && ((zero_l == 6) ||
 
245
                                                  ((zero_l == 5 && s[10] == 0xff && s[11] == 0xff) ||
 
246
                                                   ((zero_l == 7 && s[14] != 0 && s[15] != 1)))))
 
247
                        is_ipv4 = 1;
 
248
 
 
249
                /* Format whole words. */
 
250
                for (p = 0; p < words; p++)
 
251
                {
 
252
                        if (zero_l != 0 && p >= zero_s && p < zero_s + zero_l)
 
253
                        {
 
254
                                /* Time to skip some zeros */
 
255
                                if (p == zero_s)
 
256
                                        *cp++ = ':';
 
257
                                if (p == words - 1)
 
258
                                        *cp++ = ':';
 
259
                                s++;
 
260
                                s++;
 
261
                                continue;
 
262
                        }
 
263
 
 
264
                        if (is_ipv4 && p > 5)
 
265
                        {
 
266
                                *cp++ = (p == 6) ? ':' : '.';
 
267
                                cp += SPRINTF((cp, "%u", *s++));
 
268
                                /* we can potentially drop the last octet */
 
269
                                if (p != 7 || bits > 120)
 
270
                                {
 
271
                                        *cp++ = '.';
 
272
                                        cp += SPRINTF((cp, "%u", *s++));
 
273
                                }
 
274
                        }
 
275
                        else
 
276
                        {
 
277
                                if (cp != outbuf)
 
278
                                        *cp++ = ':';
 
279
                                cp += SPRINTF((cp, "%x", *s * 256 + s[1]));
 
280
                                s += 2;
 
281
                        }
 
282
                }
 
283
        }
 
284
        /* Format CIDR /width. */
 
285
        (void) SPRINTF((cp, "/%u", bits));
 
286
        if (strlen(outbuf) + 1 > size)
 
287
                goto emsgsize;
 
288
        strcpy(dst, outbuf);
 
289
 
 
290
        return (dst);
 
291
 
 
292
emsgsize:
 
293
        errno = EMSGSIZE;
 
294
        return (NULL);
 
295
}