1 /* $OpenBSD: inet_net_pton.c,v 1.1 1997/03/13 19:07:30 downsj Exp $ */ 2 3 /* 4 * Copyright (c) 1996 by Internet Software Consortium. 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS 11 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES 12 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE 13 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 14 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 15 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS 16 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 17 * SOFTWARE. 18 */ 19 20 #if defined(LIBC_SCCS) && !defined(lint) 21 #if 0 22 static const char rcsid[] = "$From: inet_net_pton.c,v 8.3 1996/11/11 06:36:52 vixie Exp $"; 23 #else 24 static const char rcsid[] = "$OpenBSD: inet_net_pton.c,v 1.1 1997/03/13 19:07:30 downsj Exp $"; 25 #endif 26 #endif 27 28 #include <sys/types.h> 29 #include <sys/socket.h> 30 #include <netinet/in.h> 31 #include <arpa/inet.h> 32 33 #include <assert.h> 34 #include <ctype.h> 35 #include <errno.h> 36 #include <stdio.h> 37 #include <string.h> 38 #include <stdlib.h> 39 40 static int inet_net_pton_ipv4 __P((const char *src, u_char *dst, 41 size_t size)); 42 43 /* 44 * static int 45 * inet_net_pton(af, src, dst, size) 46 * convert network number from presentation to network format. 47 * accepts hex octets, hex strings, decimal octets, and /CIDR. 48 * "size" is in bytes and describes "dst". 49 * return: 50 * number of bits, either imputed classfully or specified with /CIDR, 51 * or -1 if some failure occurred (check errno). ENOENT means it was 52 * not a valid network specification. 53 * author: 54 * Paul Vixie (ISC), June 1996 55 */ 56 int 57 inet_net_pton(af, src, dst, size) 58 int af; 59 const char *src; 60 void *dst; 61 size_t size; 62 { 63 switch (af) { 64 case AF_INET: 65 return (inet_net_pton_ipv4(src, dst, size)); 66 default: 67 errno = EAFNOSUPPORT; 68 return (-1); 69 } 70 } 71 72 /* 73 * static int 74 * inet_net_pton_ipv4(src, dst, size) 75 * convert IPv4 network number from presentation to network format. 76 * accepts hex octets, hex strings, decimal octets, and /CIDR. 77 * "size" is in bytes and describes "dst". 78 * return: 79 * number of bits, either imputed classfully or specified with /CIDR, 80 * or -1 if some failure occurred (check errno). ENOENT means it was 81 * not an IPv4 network specification. 82 * note: 83 * network byte order assumed. this means 192.5.5.240/28 has 84 * 0x11110000 in its fourth octet. 85 * author: 86 * Paul Vixie (ISC), June 1996 87 */ 88 static int 89 inet_net_pton_ipv4(src, dst, size) 90 const char *src; 91 u_char *dst; 92 size_t size; 93 { 94 static const char 95 xdigits[] = "0123456789abcdef", 96 digits[] = "0123456789"; 97 int n, ch, tmp, dirty, bits; 98 const u_char *odst = dst; 99 100 ch = *src++; 101 if (ch == '0' && (src[0] == 'x' || src[0] == 'X') 102 && isascii(src[1]) && isxdigit(src[1])) { 103 /* Hexadecimal: Eat nybble string. */ 104 if (size <= 0) 105 goto emsgsize; 106 *dst = 0, dirty = 0; 107 src++; /* skip x or X. */ 108 while ((ch = *src++) != '\0' && 109 isascii(ch) && isxdigit(ch)) { 110 if (isupper(ch)) 111 ch = tolower(ch); 112 n = strchr(xdigits, ch) - xdigits; 113 assert(n >= 0 && n <= 15); 114 *dst |= n; 115 if (!dirty++) 116 *dst <<= 4; 117 else if (size-- > 0) 118 *++dst = 0, dirty = 0; 119 else 120 goto emsgsize; 121 } 122 if (dirty) 123 size--; 124 } else if (isascii(ch) && isdigit(ch)) { 125 /* Decimal: eat dotted digit string. */ 126 for (;;) { 127 tmp = 0; 128 do { 129 n = strchr(digits, ch) - digits; 130 assert(n >= 0 && n <= 9); 131 tmp *= 10; 132 tmp += n; 133 if (tmp > 255) 134 goto enoent; 135 } while ((ch = *src++) != '\0' && 136 isascii(ch) && isdigit(ch)); 137 if (size-- <= 0) 138 goto emsgsize; 139 *dst++ = (u_char) tmp; 140 if (ch == '\0' || ch == '/') 141 break; 142 if (ch != '.') 143 goto enoent; 144 ch = *src++; 145 if (!isascii(ch) || !isdigit(ch)) 146 goto enoent; 147 } 148 } else 149 goto enoent; 150 151 bits = -1; 152 if (ch == '/' && isascii(src[0]) && isdigit(src[0]) && dst > odst) { 153 /* CIDR width specifier. Nothing can follow it. */ 154 ch = *src++; /* Skip over the /. */ 155 bits = 0; 156 do { 157 n = strchr(digits, ch) - digits; 158 assert(n >= 0 && n <= 9); 159 bits *= 10; 160 bits += n; 161 } while ((ch = *src++) != '\0' && 162 isascii(ch) && isdigit(ch)); 163 if (ch != '\0') 164 goto enoent; 165 if (bits > 32) 166 goto emsgsize; 167 } 168 169 /* Firey death and destruction unless we prefetched EOS. */ 170 if (ch != '\0') 171 goto enoent; 172 173 /* If nothing was written to the destination, we found no address. */ 174 if (dst == odst) 175 goto enoent; 176 /* If no CIDR spec was given, infer width from net class. */ 177 if (bits == -1) { 178 if (*odst >= 240) /* Class E */ 179 bits = 32; 180 else if (*odst >= 224) /* Class D */ 181 bits = 4; 182 else if (*odst >= 192) /* Class C */ 183 bits = 24; 184 else if (*odst >= 128) /* Class B */ 185 bits = 16; 186 else /* Class A */ 187 bits = 8; 188 /* If imputed mask is narrower than specified octets, widen. */ 189 if (bits >= 8 && bits < ((dst - odst) * 8)) 190 bits = (dst - odst) * 8; 191 } 192 /* Extend network to cover the actual mask. */ 193 while (bits > ((dst - odst) * 8)) { 194 if (size-- <= 0) 195 goto emsgsize; 196 *dst++ = '\0'; 197 } 198 return (bits); 199 200 enoent: 201 errno = ENOENT; 202 return (-1); 203 204 emsgsize: 205 errno = EMSGSIZE; 206 return (-1); 207 } 208