1 /* $OpenBSD: inet_net_ntop.c,v 1.9 2019/07/03 03:24:04 deraadt Exp $ */ 2 3 /* 4 * Copyright (c) 2012 by Gilles Chehade <gilles@openbsd.org> 5 * Copyright (c) 1996 by Internet Software Consortium. 6 * 7 * SPDX-License-Identifier: ISC 8 * 9 * Permission to use, copy, modify, and distribute this software for any 10 * purpose with or without fee is hereby granted, provided that the above 11 * copyright notice and this permission notice appear in all copies. 12 * 13 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS 14 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES 15 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE 16 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 17 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 18 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS 19 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 20 * SOFTWARE. 21 */ 22 23 #include "port_before.h" 24 25 #include <sys/types.h> 26 #include <sys/socket.h> 27 #include <netinet/in.h> 28 #include <arpa/inet.h> 29 30 #include <errno.h> 31 #include <stdio.h> 32 #include <string.h> 33 #include <stdlib.h> 34 35 #include "port_after.h" 36 37 static char *inet_net_ntop_ipv4(const u_char *, int, char *, size_t); 38 static char *inet_net_ntop_ipv6(const u_char *, int, char *, size_t); 39 40 /* 41 * char * 42 * inet_net_ntop(af, src, bits, dst, size) 43 * convert network number from network to presentation format. 44 * generates CIDR style result always. 45 * return: 46 * pointer to dst, or NULL if an error occurred (check errno). 47 * author: 48 * Paul Vixie (ISC), July 1996 49 */ 50 char * 51 inet_net_ntop(int af, const void *src, int bits, char *dst, size_t size) 52 { 53 switch (af) { 54 case AF_INET: 55 return (inet_net_ntop_ipv4(src, bits, dst, size)); 56 case AF_INET6: 57 return (inet_net_ntop_ipv6(src, bits, dst, size)); 58 default: 59 errno = EAFNOSUPPORT; 60 return (NULL); 61 } 62 } 63 64 /* 65 * static char * 66 * inet_net_ntop_ipv4(src, bits, dst, size) 67 * convert IPv4 network number from network to presentation format. 68 * generates CIDR style result always. 69 * return: 70 * pointer to dst, or NULL if an error occurred (check errno). 71 * note: 72 * network byte order assumed. this means 192.5.5.240/28 has 73 * 0b11110000 in its fourth octet. 74 * author: 75 * Paul Vixie (ISC), July 1996 76 */ 77 static char * 78 inet_net_ntop_ipv4(const u_char *src, int bits, char *dst, size_t size) 79 { 80 char *odst = dst; 81 u_int m; 82 int b; 83 char *ep; 84 int advance; 85 86 ep = dst + size; 87 if (ep <= dst) 88 goto emsgsize; 89 90 if (bits < 0 || bits > 32) { 91 errno = EINVAL; 92 return (NULL); 93 } 94 if (bits == 0) { 95 if (ep - dst < sizeof "0") 96 goto emsgsize; 97 *dst++ = '0'; 98 *dst = '\0'; 99 } 100 101 /* Format whole octets. */ 102 for (b = bits / 8; b > 0; b--) { 103 if (ep - dst < sizeof "255.") 104 goto emsgsize; 105 advance = snprintf(dst, ep - dst, "%u", *src++); 106 if (advance <= 0 || advance >= ep - dst) 107 goto emsgsize; 108 dst += advance; 109 if (b > 1) { 110 if (dst + 1 >= ep) 111 goto emsgsize; 112 *dst++ = '.'; 113 *dst = '\0'; 114 } 115 } 116 117 /* Format partial octet. */ 118 b = bits % 8; 119 if (b > 0) { 120 if (ep - dst < sizeof ".255") 121 goto emsgsize; 122 if (dst != odst) 123 *dst++ = '.'; 124 m = ((1 << b) - 1) << (8 - b); 125 advance = snprintf(dst, ep - dst, "%u", *src & m); 126 if (advance <= 0 || advance >= ep - dst) 127 goto emsgsize; 128 dst += advance; 129 } 130 131 /* Format CIDR /width. */ 132 if (ep - dst < sizeof "/32") 133 goto emsgsize; 134 advance = snprintf(dst, ep - dst, "/%u", bits); 135 if (advance <= 0 || advance >= ep - dst) 136 goto emsgsize; 137 dst += advance; 138 return (odst); 139 140 emsgsize: 141 errno = EMSGSIZE; 142 return (NULL); 143 } 144 145 static char * 146 inet_net_ntop_ipv6(const u_char *src, int bits, char *dst, size_t size) 147 { 148 int ret; 149 char buf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255:255:255:255/128")]; 150 151 if (bits < 0 || bits > 128) { 152 errno = EINVAL; 153 return (NULL); 154 } 155 156 if (inet_ntop(AF_INET6, src, buf, size) == NULL) 157 return (NULL); 158 159 ret = snprintf(dst, size, "%s/%d", buf, bits); 160 if (ret < 0 || ret >= size) { 161 errno = EMSGSIZE; 162 return (NULL); 163 } 164 165 return (dst); 166 } 167 168 /* 169 * Weak aliases for applications that use certain private entry points, 170 * and fail to include <arpa/inet.h>. 171 */ 172 #undef inet_net_ntop 173 __weak_reference(__inet_net_ntop, inet_net_ntop); 174