1 /* $OpenBSD: inet_net_pton.c,v 1.6 2008/09/01 09:40:43 markus 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 #include <sys/types.h> 21 #include <sys/socket.h> 22 #include <netinet/in.h> 23 #include <arpa/inet.h> 24 25 #include <assert.h> 26 #include <ctype.h> 27 #include <errno.h> 28 #include <stdio.h> 29 #include <string.h> 30 #include <stdlib.h> 31 32 static int inet_net_pton_ipv4(const char *, u_char *, size_t); 33 34 /* 35 * static int 36 * inet_net_pton(af, src, dst, size) 37 * convert network number from presentation to network format. 38 * accepts hex octets, hex strings, decimal octets, and /CIDR. 39 * "size" is in bytes and describes "dst". 40 * return: 41 * number of bits, either imputed classfully or specified with /CIDR, 42 * or -1 if some failure occurred (check errno). ENOENT means it was 43 * not a valid network specification. 44 * author: 45 * Paul Vixie (ISC), June 1996 46 */ 47 int 48 inet_net_pton(int af, const char *src, void *dst, size_t size) 49 { 50 switch (af) { 51 case AF_INET: 52 return (inet_net_pton_ipv4(src, dst, size)); 53 default: 54 errno = EAFNOSUPPORT; 55 return (-1); 56 } 57 } 58 59 /* 60 * static int 61 * inet_net_pton_ipv4(src, dst, size) 62 * convert IPv4 network number from presentation to network format. 63 * accepts hex octets, hex strings, decimal octets, and /CIDR. 64 * "size" is in bytes and describes "dst". 65 * return: 66 * number of bits, either imputed classfully or specified with /CIDR, 67 * or -1 if some failure occurred (check errno). ENOENT means it was 68 * not an IPv4 network specification. 69 * note: 70 * network byte order assumed. this means 192.5.5.240/28 has 71 * 0x11110000 in its fourth octet. 72 * author: 73 * Paul Vixie (ISC), June 1996 74 */ 75 static int 76 inet_net_pton_ipv4(const char *src, u_char *dst, size_t size) 77 { 78 static const char 79 xdigits[] = "0123456789abcdef", 80 digits[] = "0123456789"; 81 int n, ch, tmp, dirty, bits; 82 const u_char *odst = dst; 83 84 ch = *src++; 85 if (ch == '0' && (src[0] == 'x' || src[0] == 'X') 86 && isascii(src[1]) && isxdigit(src[1])) { 87 /* Hexadecimal: Eat nybble string. */ 88 if (size <= 0) 89 goto emsgsize; 90 *dst = 0, dirty = 0; 91 src++; /* skip x or X. */ 92 while ((ch = *src++) != '\0' && 93 isascii(ch) && isxdigit(ch)) { 94 if (isupper(ch)) 95 ch = tolower(ch); 96 n = strchr(xdigits, ch) - xdigits; 97 assert(n >= 0 && n <= 15); 98 *dst |= n; 99 if (!dirty++) 100 *dst <<= 4; 101 else if (size-- > 0) 102 *++dst = 0, dirty = 0; 103 else 104 goto emsgsize; 105 } 106 if (dirty) 107 size--; 108 } else if (isascii(ch) && isdigit(ch)) { 109 /* Decimal: eat dotted digit string. */ 110 for (;;) { 111 tmp = 0; 112 do { 113 n = strchr(digits, ch) - digits; 114 assert(n >= 0 && n <= 9); 115 tmp *= 10; 116 tmp += n; 117 if (tmp > 255) 118 goto enoent; 119 } while ((ch = *src++) != '\0' && 120 isascii(ch) && isdigit(ch)); 121 if (size-- <= 0) 122 goto emsgsize; 123 *dst++ = (u_char) tmp; 124 if (ch == '\0' || ch == '/') 125 break; 126 if (ch != '.') 127 goto enoent; 128 ch = *src++; 129 if (!isascii(ch) || !isdigit(ch)) 130 goto enoent; 131 } 132 } else 133 goto enoent; 134 135 bits = -1; 136 if (ch == '/' && isascii(src[0]) && isdigit(src[0]) && dst > odst) { 137 /* CIDR width specifier. Nothing can follow it. */ 138 ch = *src++; /* Skip over the /. */ 139 bits = 0; 140 do { 141 n = strchr(digits, ch) - digits; 142 assert(n >= 0 && n <= 9); 143 bits *= 10; 144 bits += n; 145 if (bits > 32) 146 goto emsgsize; 147 } while ((ch = *src++) != '\0' && 148 isascii(ch) && isdigit(ch)); 149 if (ch != '\0') 150 goto enoent; 151 } 152 153 /* Firey death and destruction unless we prefetched EOS. */ 154 if (ch != '\0') 155 goto enoent; 156 157 /* If nothing was written to the destination, we found no address. */ 158 if (dst == odst) 159 goto enoent; 160 /* If no CIDR spec was given, infer width from net class. */ 161 if (bits == -1) { 162 if (*odst >= 240) /* Class E */ 163 bits = 32; 164 else if (*odst >= 224) /* Class D */ 165 bits = 4; 166 else if (*odst >= 192) /* Class C */ 167 bits = 24; 168 else if (*odst >= 128) /* Class B */ 169 bits = 16; 170 else /* Class A */ 171 bits = 8; 172 /* If imputed mask is narrower than specified octets, widen. */ 173 if (bits < ((dst - odst) * 8)) 174 bits = (dst - odst) * 8; 175 } 176 /* Extend network to cover the actual mask. */ 177 while (bits > ((dst - odst) * 8)) { 178 if (size-- <= 0) 179 goto emsgsize; 180 *dst++ = '\0'; 181 } 182 return (bits); 183 184 enoent: 185 errno = ENOENT; 186 return (-1); 187 188 emsgsize: 189 errno = EMSGSIZE; 190 return (-1); 191 } 192