[BACK]Return to inet_net_ntop.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / lib / libc / inet

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>