~ubuntu-branches/ubuntu/hardy/postgresql-8.4/hardy-backports

« back to all changes in this revision

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

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2009-03-20 12:00:13 UTC
  • Revision ID: james.westby@ubuntu.com-20090320120013-hogj7egc5mjncc5g
Tags: upstream-8.4~0cvs20090328
ImportĀ upstreamĀ versionĀ 8.4~0cvs20090328

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
 *        $PostgreSQL$
 
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
#define NS_IN6ADDRSZ 16
 
36
#define NS_INT16SZ 2
 
37
 
 
38
#ifdef SPRINTF_CHAR
 
39
#define SPRINTF(x) strlen(sprintf/**/x)
 
40
#else
 
41
#define SPRINTF(x) ((size_t)sprintf x)
 
42
#endif
 
43
 
 
44
static char *inet_net_ntop_ipv4(const u_char *src, int bits,
 
45
                                   char *dst, size_t size);
 
46
static char *inet_cidr_ntop_ipv4(const u_char *src, int bits,
 
47
                                        char *dst, size_t size);
 
48
static char *inet_net_ntop_ipv6(const u_char *src, int bits,
 
49
                                   char *dst, size_t size);
 
50
static char *inet_cidr_ntop_ipv6(const u_char *src, int bits,
 
51
                                        char *dst, size_t size);
 
52
 
 
53
/*
 
54
 * char *
 
55
 * inet_cidr_ntop(af, src, bits, dst, size)
 
56
 *      convert network number from network to presentation format.
 
57
 *      generates CIDR style result always.
 
58
 * return:
 
59
 *      pointer to dst, or NULL if an error occurred (check errno).
 
60
 * author:
 
61
 *      Paul Vixie (ISC), July 1996
 
62
 */
 
63
char *
 
64
inet_cidr_ntop(int af, const void *src, int bits, char *dst, size_t size)
 
65
{
 
66
        switch (af)
 
67
        {
 
68
                case PGSQL_AF_INET:
 
69
                        return (inet_cidr_ntop_ipv4(src, bits, dst, size));
 
70
                case PGSQL_AF_INET6:
 
71
                        return (inet_cidr_ntop_ipv6(src, bits, dst, size));
 
72
                default:
 
73
                        errno = EAFNOSUPPORT;
 
74
                        return (NULL);
 
75
        }
 
76
}
 
77
 
 
78
 
 
79
/*
 
80
 * static char *
 
81
 * inet_cidr_ntop_ipv4(src, bits, dst, size)
 
82
 *      convert IPv4 network number from network to presentation format.
 
83
 *      generates CIDR style result always.
 
84
 * return:
 
85
 *      pointer to dst, or NULL if an error occurred (check errno).
 
86
 * note:
 
87
 *      network byte order assumed.  this means 192.5.5.240/28 has
 
88
 *      0b11110000 in its fourth octet.
 
89
 * author:
 
90
 *      Paul Vixie (ISC), July 1996
 
91
 */
 
92
static char *
 
93
inet_cidr_ntop_ipv4(const u_char *src, int bits, char *dst, size_t size)
 
94
{
 
95
        char       *odst = dst;
 
96
        char       *t;
 
97
        u_int           m;
 
98
        int                     b;
 
99
 
 
100
        if (bits < 0 || bits > 32)
 
101
        {
 
102
                errno = EINVAL;
 
103
                return (NULL);
 
104
        }
 
105
 
 
106
        if (bits == 0)
 
107
        {
 
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
        {
 
118
                if (size <= sizeof "255.")
 
119
                        goto emsgsize;
 
120
                t = dst;
 
121
                dst += SPRINTF((dst, "%u", *src++));
 
122
                if (b > 1)
 
123
                {
 
124
                        *dst++ = '.';
 
125
                        *dst = '\0';
 
126
                }
 
127
                size -= (size_t) (dst - t);
 
128
        }
 
129
 
 
130
        /* Format partial octet. */
 
131
        b = bits % 8;
 
132
        if (b > 0)
 
133
        {
 
134
                if (size <= sizeof ".255")
 
135
                        goto emsgsize;
 
136
                t = dst;
 
137
                if (dst != odst)
 
138
                        *dst++ = '.';
 
139
                m = ((1 << b) - 1) << (8 - b);
 
140
                dst += SPRINTF((dst, "%u", *src & m));
 
141
                size -= (size_t) (dst - t);
 
142
        }
 
143
 
 
144
        /* Format CIDR /width. */
 
145
        if (size <= sizeof "/32")
 
146
                goto emsgsize;
 
147
        dst += SPRINTF((dst, "/%u", bits));
 
148
        return (odst);
 
149
 
 
150
emsgsize:
 
151
        errno = EMSGSIZE;
 
152
        return (NULL);
 
153
}
 
154
 
 
155
/*
 
156
 * static char *
 
157
 * inet_cidr_ntop_ipv6(src, bits, fakebits, dst, size)
 
158
 *      convert IPv6 network number from network to presentation format.
 
159
 *      generates CIDR style result always. Picks the shortest representation
 
160
 *      unless the IP is really IPv4.
 
161
 *      always prints specified number of bits (bits).
 
162
 * return:
 
163
 *      pointer to dst, or NULL if an error occurred (check errno).
 
164
 * note:
 
165
 *      network byte order assumed.  this means 192.5.5.240/28 has
 
166
 *      0x11110000 in its fourth octet.
 
167
 * author:
 
168
 *      Vadim Kogan (UCB), June 2001
 
169
 *      Original version (IPv4) by Paul Vixie (ISC), July 1996
 
170
 */
 
171
 
 
172
static char *
 
173
inet_cidr_ntop_ipv6(const u_char *src, int bits, char *dst, size_t size)
 
174
{
 
175
        u_int           m;
 
176
        int                     b;
 
177
        int                     p;
 
178
        int                     zero_s,
 
179
                                zero_l,
 
180
                                tmp_zero_s,
 
181
                                tmp_zero_l;
 
182
        int                     i;
 
183
        int                     is_ipv4 = 0;
 
184
        unsigned char inbuf[16];
 
185
        char            outbuf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")];
 
186
        char       *cp;
 
187
        int                     words;
 
188
        u_char     *s;
 
189
 
 
190
        if (bits < 0 || bits > 128)
 
191
        {
 
192
                errno = EINVAL;
 
193
                return (NULL);
 
194
        }
 
195
 
 
196
        cp = outbuf;
 
197
 
 
198
        if (bits == 0)
 
199
        {
 
200
                *cp++ = ':';
 
201
                *cp++ = ':';
 
202
                *cp = '\0';
 
203
        }
 
204
        else
 
205
        {
 
206
                /* Copy src to private buffer.  Zero host part. */
 
207
                p = (bits + 7) / 8;
 
208
                memcpy(inbuf, src, p);
 
209
                memset(inbuf + p, 0, 16 - p);
 
210
                b = bits % 8;
 
211
                if (b != 0)
 
212
                {
 
213
                        m = ~0 << (8 - b);
 
214
                        inbuf[p - 1] &= m;
 
215
                }
 
216
 
 
217
                s = inbuf;
 
218
 
 
219
                /* how many words need to be displayed in output */
 
220
                words = (bits + 15) / 16;
 
221
                if (words == 1)
 
222
                        words = 2;
 
223
 
 
224
                /* Find the longest substring of zero's */
 
225
                zero_s = zero_l = tmp_zero_s = tmp_zero_l = 0;
 
226
                for (i = 0; i < (words * 2); i += 2)
 
227
                {
 
228
                        if ((s[i] | s[i + 1]) == 0)
 
229
                        {
 
230
                                if (tmp_zero_l == 0)
 
231
                                        tmp_zero_s = i / 2;
 
232
                                tmp_zero_l++;
 
233
                        }
 
234
                        else
 
235
                        {
 
236
                                if (tmp_zero_l && zero_l < tmp_zero_l)
 
237
                                {
 
238
                                        zero_s = tmp_zero_s;
 
239
                                        zero_l = tmp_zero_l;
 
240
                                        tmp_zero_l = 0;
 
241
                                }
 
242
                        }
 
243
                }
 
244
 
 
245
                if (tmp_zero_l && zero_l < tmp_zero_l)
 
246
                {
 
247
                        zero_s = tmp_zero_s;
 
248
                        zero_l = tmp_zero_l;
 
249
                }
 
250
 
 
251
                if (zero_l != words && zero_s == 0 && ((zero_l == 6) ||
 
252
                                                  ((zero_l == 5 && s[10] == 0xff && s[11] == 0xff) ||
 
253
                                                   ((zero_l == 7 && s[14] != 0 && s[15] != 1)))))
 
254
                        is_ipv4 = 1;
 
255
 
 
256
                /* Format whole words. */
 
257
                for (p = 0; p < words; p++)
 
258
                {
 
259
                        if (zero_l != 0 && p >= zero_s && p < zero_s + zero_l)
 
260
                        {
 
261
                                /* Time to skip some zeros */
 
262
                                if (p == zero_s)
 
263
                                        *cp++ = ':';
 
264
                                if (p == words - 1)
 
265
                                        *cp++ = ':';
 
266
                                s++;
 
267
                                s++;
 
268
                                continue;
 
269
                        }
 
270
 
 
271
                        if (is_ipv4 && p > 5)
 
272
                        {
 
273
                                *cp++ = (p == 6) ? ':' : '.';
 
274
                                cp += SPRINTF((cp, "%u", *s++));
 
275
                                /* we can potentially drop the last octet */
 
276
                                if (p != 7 || bits > 120)
 
277
                                {
 
278
                                        *cp++ = '.';
 
279
                                        cp += SPRINTF((cp, "%u", *s++));
 
280
                                }
 
281
                        }
 
282
                        else
 
283
                        {
 
284
                                if (cp != outbuf)
 
285
                                        *cp++ = ':';
 
286
                                cp += SPRINTF((cp, "%x", *s * 256 + s[1]));
 
287
                                s += 2;
 
288
                        }
 
289
                }
 
290
        }
 
291
        /* Format CIDR /width. */
 
292
        (void) SPRINTF((cp, "/%u", bits));
 
293
        if (strlen(outbuf) + 1 > size)
 
294
                goto emsgsize;
 
295
        strcpy(dst, outbuf);
 
296
 
 
297
        return (dst);
 
298
 
 
299
emsgsize:
 
300
        errno = EMSGSIZE;
 
301
        return (NULL);
 
302
}
 
303
 
 
304
 
 
305
/*
 
306
 * char *
 
307
 * inet_net_ntop(af, src, bits, dst, size)
 
308
 *      convert host/network address from network to presentation format.
 
309
 *      "src"'s size is determined from its "af".
 
310
 * return:
 
311
 *      pointer to dst, or NULL if an error occurred (check errno).
 
312
 * note:
 
313
 *      192.5.5.1/28 has a nonzero host part, which means it isn't a network
 
314
 *      as called for by inet_net_pton() but it can be a host address with
 
315
 *      an included netmask.
 
316
 * author:
 
317
 *      Paul Vixie (ISC), October 1998
 
318
 */
 
319
char *
 
320
inet_net_ntop(int af, const void *src, int bits, char *dst, size_t size)
 
321
{
 
322
        switch (af)
 
323
        {
 
324
                case PGSQL_AF_INET:
 
325
                        return (inet_net_ntop_ipv4(src, bits, dst, size));
 
326
                case PGSQL_AF_INET6:
 
327
                        return (inet_net_ntop_ipv6(src, bits, dst, size));
 
328
                default:
 
329
                        errno = EAFNOSUPPORT;
 
330
                        return (NULL);
 
331
        }
 
332
}
 
333
 
 
334
/*
 
335
 * static char *
 
336
 * inet_net_ntop_ipv4(src, bits, dst, size)
 
337
 *      convert IPv4 network address from network to presentation format.
 
338
 *      "src"'s size is determined from its "af".
 
339
 * return:
 
340
 *      pointer to dst, or NULL if an error occurred (check errno).
 
341
 * note:
 
342
 *      network byte order assumed.  this means 192.5.5.240/28 has
 
343
 *      0b11110000 in its fourth octet.
 
344
 * author:
 
345
 *      Paul Vixie (ISC), October 1998
 
346
 */
 
347
static char *
 
348
inet_net_ntop_ipv4(const u_char *src, int bits, char *dst, size_t size)
 
349
{
 
350
        char       *odst = dst;
 
351
        char       *t;
 
352
        int                     len = 4;
 
353
        int                     b;
 
354
 
 
355
        if (bits < 0 || bits > 32)
 
356
        {
 
357
                errno = EINVAL;
 
358
                return (NULL);
 
359
        }
 
360
 
 
361
        /* Always format all four octets, regardless of mask length. */
 
362
        for (b = len; b > 0; b--)
 
363
        {
 
364
                if (size <= sizeof ".255")
 
365
                        goto emsgsize;
 
366
                t = dst;
 
367
                if (dst != odst)
 
368
                        *dst++ = '.';
 
369
                dst += SPRINTF((dst, "%u", *src++));
 
370
                size -= (size_t) (dst - t);
 
371
        }
 
372
 
 
373
        /* don't print masklen if 32 bits */
 
374
        if (bits != 32)
 
375
        {
 
376
                if (size <= sizeof "/32")
 
377
                        goto emsgsize;
 
378
                dst += SPRINTF((dst, "/%u", bits));
 
379
        }
 
380
 
 
381
        return (odst);
 
382
 
 
383
emsgsize:
 
384
        errno = EMSGSIZE;
 
385
        return (NULL);
 
386
}
 
387
 
 
388
static int
 
389
decoct(const u_char *src, int bytes, char *dst, size_t size)
 
390
{
 
391
        char       *odst = dst;
 
392
        char       *t;
 
393
        int                     b;
 
394
 
 
395
        for (b = 1; b <= bytes; b++)
 
396
        {
 
397
                if (size <= sizeof "255.")
 
398
                        return (0);
 
399
                t = dst;
 
400
                dst += SPRINTF((dst, "%u", *src++));
 
401
                if (b != bytes)
 
402
                {
 
403
                        *dst++ = '.';
 
404
                        *dst = '\0';
 
405
                }
 
406
                size -= (size_t) (dst - t);
 
407
        }
 
408
        return (dst - odst);
 
409
}
 
410
 
 
411
static char *
 
412
inet_net_ntop_ipv6(const u_char *src, int bits, char *dst, size_t size)
 
413
{
 
414
        /*
 
415
         * Note that int32_t and int16_t need only be "at least" large enough to
 
416
         * contain a value of the specified size.  On some systems, like Crays,
 
417
         * there is no such thing as an integer variable with 16 bits. Keep this
 
418
         * in mind if you think this function should have been coded to use
 
419
         * pointer overlays.  All the world's not a VAX.
 
420
         */
 
421
        char            tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255/128"];
 
422
        char       *tp;
 
423
        struct
 
424
        {
 
425
                int                     base,
 
426
                                        len;
 
427
        }                       best, cur;
 
428
        u_int           words[NS_IN6ADDRSZ / NS_INT16SZ];
 
429
        int                     i;
 
430
 
 
431
        if ((bits < -1) || (bits > 128))
 
432
        {
 
433
                errno = EINVAL;
 
434
                return (NULL);
 
435
        }
 
436
 
 
437
        /*
 
438
         * Preprocess: Copy the input (bytewise) array into a wordwise array. Find
 
439
         * the longest run of 0x00's in src[] for :: shorthanding.
 
440
         */
 
441
        memset(words, '\0', sizeof words);
 
442
        for (i = 0; i < NS_IN6ADDRSZ; i++)
 
443
                words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));
 
444
        best.base = -1;
 
445
        cur.base = -1;
 
446
        best.len = 0;
 
447
        cur.len = 0;
 
448
        for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++)
 
449
        {
 
450
                if (words[i] == 0)
 
451
                {
 
452
                        if (cur.base == -1)
 
453
                                cur.base = i, cur.len = 1;
 
454
                        else
 
455
                                cur.len++;
 
456
                }
 
457
                else
 
458
                {
 
459
                        if (cur.base != -1)
 
460
                        {
 
461
                                if (best.base == -1 || cur.len > best.len)
 
462
                                        best = cur;
 
463
                                cur.base = -1;
 
464
                        }
 
465
                }
 
466
        }
 
467
        if (cur.base != -1)
 
468
        {
 
469
                if (best.base == -1 || cur.len > best.len)
 
470
                        best = cur;
 
471
        }
 
472
        if (best.base != -1 && best.len < 2)
 
473
                best.base = -1;
 
474
 
 
475
        /*
 
476
         * Format the result.
 
477
         */
 
478
        tp = tmp;
 
479
        for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++)
 
480
        {
 
481
                /* Are we inside the best run of 0x00's? */
 
482
                if (best.base != -1 && i >= best.base &&
 
483
                        i < (best.base + best.len))
 
484
                {
 
485
                        if (i == best.base)
 
486
                                *tp++ = ':';
 
487
                        continue;
 
488
                }
 
489
                /* Are we following an initial run of 0x00s or any real hex? */
 
490
                if (i != 0)
 
491
                        *tp++ = ':';
 
492
                /* Is this address an encapsulated IPv4? */
 
493
                if (i == 6 && best.base == 0 && (best.len == 6 ||
 
494
                                                                         (best.len == 7 && words[7] != 0x0001) ||
 
495
                                                                          (best.len == 5 && words[5] == 0xffff)))
 
496
                {
 
497
                        int                     n;
 
498
 
 
499
                        n = decoct(src + 12, 4, tp, sizeof tmp - (tp - tmp));
 
500
                        if (n == 0)
 
501
                        {
 
502
                                errno = EMSGSIZE;
 
503
                                return (NULL);
 
504
                        }
 
505
                        tp += strlen(tp);
 
506
                        break;
 
507
                }
 
508
                tp += SPRINTF((tp, "%x", words[i]));
 
509
        }
 
510
 
 
511
        /* Was it a trailing run of 0x00's? */
 
512
        if (best.base != -1 && (best.base + best.len) ==
 
513
                (NS_IN6ADDRSZ / NS_INT16SZ))
 
514
                *tp++ = ':';
 
515
        *tp = '\0';
 
516
 
 
517
        if (bits != -1 && bits != 128)
 
518
                tp += SPRINTF((tp, "/%u", bits));
 
519
 
 
520
        /*
 
521
         * Check for overflow, copy, and we're done.
 
522
         */
 
523
        if ((size_t) (tp - tmp) > size)
 
524
        {
 
525
                errno = EMSGSIZE;
 
526
                return (NULL);
 
527
        }
 
528
        strcpy(dst, tmp);
 
529
        return (dst);
 
530
}