]>
git.saurik.com Git - apple/libc.git/blob - net/FreeBSD/inet_net_pton.c
   2  * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") 
   3  * Copyright (c) 1996,1999 by Internet Software Consortium. 
   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. 
   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. 
  18 #if defined(LIBC_SCCS) && !defined(lint) 
  19 static const char rcsid
[] = "$Id: inet_net_pton.c,v 1.7.18.2 2008/08/26 04:42:43 marka Exp $"; 
  22 /* the algorithms only can deal with ASCII, so we optimize for it */ 
  25 #include <sys/cdefs.h> 
  26 __FBSDID("$FreeBSD: src/lib/libc/inet/inet_net_pton.c,v 1.4 2008/12/14 19:39:53 ume Exp $"); 
  28 #include "port_before.h" 
  30 #include <sys/types.h> 
  31 #include <sys/socket.h> 
  32 #include <netinet/in.h> 
  33 #include <arpa/nameser.h> 
  34 #include <arpa/inet.h> 
  43 #include "port_after.h" 
  46 # define SPRINTF(x) strlen(sprintf/**/x) 
  48 # define SPRINTF(x) ((size_t)sprintf x) 
  53  * inet_net_pton_ipv4(src, dst, size) 
  54  *      convert IPv4 network number from presentation to network format. 
  55  *      accepts hex octets, hex strings, decimal octets, and /CIDR. 
  56  *      "size" is in bytes and describes "dst". 
  58  *      number of bits, either imputed classfully or specified with /CIDR, 
  59  *      or -1 if some failure occurred (check errno).  ENOENT means it was 
  60  *      not an IPv4 network specification. 
  62  *      network byte order assumed.  this means 192.5.5.240/28 has 
  63  *      0b11110000 in its fourth octet. 
  65  *      Paul Vixie (ISC), June 1996 
  68 inet_net_pton_ipv4(const char *src
, u_char 
*dst
, size_t size
) { 
  69         static const char xdigits
[] = "0123456789abcdef"; 
  70         static const char digits
[] = "0123456789"; 
  71         int n
, ch
, tmp 
= 0, dirty
, bits
; 
  72         const u_char 
*odst 
= dst
; 
  75         if (ch 
== '0' && (src
[0] == 'x' || src
[0] == 'X') 
  76             && isascii((unsigned char)(src
[1])) 
  77             && isxdigit((unsigned char)(src
[1]))) { 
  78                 /* Hexadecimal: Eat nybble string. */ 
  82                 src
++;  /*%< skip x or X. */ 
  83                 while ((ch 
= *src
++) != '\0' && isascii(ch
) && isxdigit(ch
)) { 
  86                         n 
= strchr(xdigits
, ch
) - xdigits
; 
  87                         assert(n 
>= 0 && n 
<= 15); 
  95                                 *dst
++ = (u_char
) tmp
; 
  99                 if (dirty
) {  /*%< Odd trailing nybble? */ 
 102                         *dst
++ = (u_char
) (tmp 
<< 4); 
 104         } else if (isascii(ch
) && isdigit(ch
)) { 
 105                 /* Decimal: eat dotted digit string. */ 
 109                                 n 
= strchr(digits
, ch
) - digits
; 
 110                                 assert(n 
>= 0 && n 
<= 9); 
 115                         } while ((ch 
= *src
++) != '\0' && 
 116                                  isascii(ch
) && isdigit(ch
)); 
 119                         *dst
++ = (u_char
) tmp
; 
 120                         if (ch 
== '\0' || ch 
== '/') 
 125                         if (!isascii(ch
) || !isdigit(ch
)) 
 132         if (ch 
== '/' && isascii((unsigned char)(src
[0])) && 
 133             isdigit((unsigned char)(src
[0])) && dst 
> odst
) { 
 134                 /* CIDR width specifier.  Nothing can follow it. */ 
 135                 ch 
= *src
++;    /*%< Skip over the /. */ 
 138                         n 
= strchr(digits
, ch
) - digits
; 
 139                         assert(n 
>= 0 && n 
<= 9); 
 144                 } while ((ch 
= *src
++) != '\0' && isascii(ch
) && isdigit(ch
)); 
 149         /* Firey death and destruction unless we prefetched EOS. */ 
 153         /* If nothing was written to the destination, we found no address. */ 
 156         /* If no CIDR spec was given, infer width from net class. */ 
 158                 if (*odst 
>= 240)       /*%< Class E */ 
 160                 else if (*odst 
>= 224)  /*%< Class D */ 
 162                 else if (*odst 
>= 192)  /*%< Class C */ 
 164                 else if (*odst 
>= 128)  /*%< Class B */ 
 168                 /* If imputed mask is narrower than specified octets, widen. */ 
 169                 if (bits 
< ((dst 
- odst
) * 8)) 
 170                         bits 
= (dst 
- odst
) * 8; 
 172                  * If there are no additional bits specified for a class D 
 173                  * address adjust bits to 4. 
 175                 if (bits 
== 8 && *odst 
== 224) 
 178         /* Extend network to cover the actual mask. */ 
 179         while (bits 
> ((dst 
- odst
) * 8)) { 
 196 getbits(const char *src
, int *bitsp
) { 
 197         static const char digits
[] = "0123456789"; 
 204         while ((ch 
= *src
++) != '\0') { 
 207                 pch 
= strchr(digits
, ch
); 
 209                         if (n
++ != 0 && val 
== 0)       /*%< no leading zeros */ 
 212                         val 
+= (pch 
- digits
); 
 213                         if (val 
> 128)                  /*%< range */ 
 226 getv4(const char *src
, u_char 
*dst
, int *bitsp
) { 
 227         static const char digits
[] = "0123456789"; 
 235         while ((ch 
= *src
++) != '\0') { 
 238                 pch 
= strchr(digits
, ch
); 
 240                         if (n
++ != 0 && val 
== 0)       /*%< no leading zeros */ 
 243                         val 
+= (pch 
- digits
); 
 244                         if (val 
> 255)                  /*%< range */ 
 248                 if (ch 
== '.' || ch 
== '/') { 
 249                         if (dst 
- odst 
> 3)             /*%< too many octets? */ 
 253                                 return (getbits(src
, bitsp
)); 
 262         if (dst 
- odst 
> 3)             /*%< too many octets? */ 
 269 inet_net_pton_ipv6(const char *src
, u_char 
*dst
, size_t size
) { 
 270         static const char xdigits_l
[] = "0123456789abcdef", 
 271                           xdigits_u
[] = "0123456789ABCDEF"; 
 272         u_char tmp
[NS_IN6ADDRSZ
], *tp
, *endp
, *colonp
; 
 273         const char *xdigits
, *curtok
; 
 282         memset((tp 
= tmp
), '\0', NS_IN6ADDRSZ
); 
 283         endp 
= tp 
+ NS_IN6ADDRSZ
; 
 285         /* Leading :: requires some special handling. */ 
 295         while ((ch 
= *src
++) != '\0') { 
 298                 if ((pch 
= strchr((xdigits 
= xdigits_l
), ch
)) == NULL
) 
 299                         pch 
= strchr((xdigits 
= xdigits_u
), ch
); 
 302                         val 
|= (pch 
- xdigits
); 
 315                         } else if (*src 
== '\0') 
 317                         if (tp 
+ NS_INT16SZ 
> endp
) 
 319                         *tp
++ = (u_char
) (val 
>> 8) & 0xff; 
 320                         *tp
++ = (u_char
) val 
& 0xff; 
 326                 if (ch 
== '.' && ((tp 
+ NS_INADDRSZ
) <= endp
) && 
 327                      getv4(curtok
, tp
, &bits
) > 0) { 
 331                         break;  /*%< '\\0' was seen by inet_pton4(). */ 
 333                 if (ch 
== '/' && getbits(src
, &bits
) > 0) 
 338                 if (tp 
+ NS_INT16SZ 
> endp
) 
 340                 *tp
++ = (u_char
) (val 
>> 8) & 0xff; 
 341                 *tp
++ = (u_char
) val 
& 0xff; 
 346         words 
= (bits 
+ 15) / 16; 
 351         endp 
=  tmp 
+ 2 * words
; 
 353         if (colonp 
!= NULL
) { 
 355                  * Since some memmove()'s erroneously fail to handle 
 356                  * overlapping regions, we'll do the shift by hand. 
 358                 const int n 
= tp 
- colonp
; 
 363                 for (i 
= 1; i 
<= n
; i
++) { 
 364                         endp
[- i
] = colonp
[n 
- i
]; 
 372         bytes 
= (bits 
+ 7) / 8; 
 375         memcpy(dst
, tmp
, bytes
); 
 389  * inet_net_pton(af, src, dst, size) 
 390  *      convert network number from presentation to network format. 
 391  *      accepts hex octets, hex strings, decimal octets, and /CIDR. 
 392  *      "size" is in bytes and describes "dst". 
 394  *      number of bits, either imputed classfully or specified with /CIDR, 
 395  *      or -1 if some failure occurred (check errno).  ENOENT means it was 
 396  *      not a valid network specification. 
 398  *      Paul Vixie (ISC), June 1996 
 401 inet_net_pton(int af
, const char *src
, void *dst
, size_t size
) { 
 404                 return (inet_net_pton_ipv4(src
, dst
, size
)); 
 406                 return (inet_net_pton_ipv6(src
, dst
, size
)); 
 408                 errno 
= EAFNOSUPPORT
; 
 414  * Weak aliases for applications that use certain private entry points, 
 415  * and fail to include <arpa/inet.h>. 
 418 __weak_reference(__inet_net_pton
, inet_net_pton
);