1238106Sdes/* $KAME: inet_pton.c,v 1.5 2001/08/20 02:32:40 itojun Exp $ */ 2238106Sdes 3238106Sdes/* Copyright (c) 1996 by Internet Software Consortium. 4238106Sdes * 5238106Sdes * Permission to use, copy, modify, and distribute this software for any 6238106Sdes * purpose with or without fee is hereby granted, provided that the above 7238106Sdes * copyright notice and this permission notice appear in all copies. 8238106Sdes * 9238106Sdes * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS 10238106Sdes * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES 11238106Sdes * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE 12238106Sdes * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 13238106Sdes * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 14238106Sdes * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS 15238106Sdes * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 16238106Sdes * SOFTWARE. 17238106Sdes */ 18238106Sdes 19238106Sdes#include <config.h> 20238106Sdes 21238106Sdes#include <string.h> 22238106Sdes#include <stdio.h> 23238106Sdes#include <errno.h> 24238106Sdes 25238106Sdes/* 26238106Sdes * WARNING: Don't even consider trying to compile this on a system where 27238106Sdes * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX. 28238106Sdes */ 29238106Sdes 30238106Sdesstatic int inet_pton4 (const char *src, uint8_t *dst); 31238106Sdesstatic int inet_pton6 (const char *src, uint8_t *dst); 32238106Sdes 33238106Sdes/* 34238106Sdes * 35238106Sdes * The definitions we might miss. 36238106Sdes * 37238106Sdes */ 38238106Sdes#ifndef NS_INT16SZ 39238106Sdes#define NS_INT16SZ 2 40238106Sdes#endif 41238106Sdes 42238106Sdes#ifndef NS_IN6ADDRSZ 43238106Sdes#define NS_IN6ADDRSZ 16 44238106Sdes#endif 45238106Sdes 46238106Sdes#ifndef NS_INADDRSZ 47238106Sdes#define NS_INADDRSZ 4 48238106Sdes#endif 49238106Sdes 50238106Sdes/* int 51238106Sdes * inet_pton(af, src, dst) 52238106Sdes * convert from presentation format (which usually means ASCII printable) 53238106Sdes * to network format (which is usually some kind of binary format). 54238106Sdes * return: 55238106Sdes * 1 if the address was valid for the specified address family 56238106Sdes * 0 if the address wasn't valid (`dst' is untouched in this case) 57238106Sdes * -1 if some other error occurred (`dst' is untouched in this case, too) 58238106Sdes * author: 59238106Sdes * Paul Vixie, 1996. 60238106Sdes */ 61238106Sdesint 62238106Sdesinet_pton(af, src, dst) 63238106Sdes int af; 64238106Sdes const char *src; 65238106Sdes void *dst; 66238106Sdes{ 67238106Sdes switch (af) { 68238106Sdes case AF_INET: 69238106Sdes return (inet_pton4(src, dst)); 70238106Sdes case AF_INET6: 71238106Sdes return (inet_pton6(src, dst)); 72238106Sdes default: 73238106Sdes#ifdef EAFNOSUPPORT 74238106Sdes errno = EAFNOSUPPORT; 75238106Sdes#else 76238106Sdes errno = ENOSYS; 77238106Sdes#endif 78238106Sdes return (-1); 79238106Sdes } 80238106Sdes /* NOTREACHED */ 81238106Sdes} 82238106Sdes 83238106Sdes/* int 84238106Sdes * inet_pton4(src, dst) 85238106Sdes * like inet_aton() but without all the hexadecimal and shorthand. 86238106Sdes * return: 87238106Sdes * 1 if `src' is a valid dotted quad, else 0. 88238106Sdes * notice: 89238106Sdes * does not touch `dst' unless it's returning 1. 90238106Sdes * author: 91238106Sdes * Paul Vixie, 1996. 92238106Sdes */ 93238106Sdesstatic int 94238106Sdesinet_pton4(src, dst) 95238106Sdes const char *src; 96238106Sdes uint8_t *dst; 97238106Sdes{ 98238106Sdes static const char digits[] = "0123456789"; 99238106Sdes int saw_digit, octets, ch; 100238106Sdes uint8_t tmp[NS_INADDRSZ], *tp; 101238106Sdes 102238106Sdes saw_digit = 0; 103238106Sdes octets = 0; 104238106Sdes *(tp = tmp) = 0; 105238106Sdes while ((ch = *src++) != '\0') { 106238106Sdes const char *pch; 107238106Sdes 108238106Sdes if ((pch = strchr(digits, ch)) != NULL) { 109238106Sdes uint32_t new = *tp * 10 + (pch - digits); 110238106Sdes 111238106Sdes if (new > 255) 112238106Sdes return (0); 113238106Sdes *tp = new; 114238106Sdes if (! saw_digit) { 115238106Sdes if (++octets > 4) 116238106Sdes return (0); 117238106Sdes saw_digit = 1; 118238106Sdes } 119238106Sdes } else if (ch == '.' && saw_digit) { 120238106Sdes if (octets == 4) 121238106Sdes return (0); 122238106Sdes *++tp = 0; 123238106Sdes saw_digit = 0; 124238106Sdes } else 125238106Sdes return (0); 126238106Sdes } 127238106Sdes if (octets < 4) 128238106Sdes return (0); 129238106Sdes 130238106Sdes memcpy(dst, tmp, NS_INADDRSZ); 131238106Sdes return (1); 132238106Sdes} 133238106Sdes 134238106Sdes/* int 135238106Sdes * inet_pton6(src, dst) 136238106Sdes * convert presentation level address to network order binary form. 137238106Sdes * return: 138238106Sdes * 1 if `src' is a valid [RFC1884 2.2] address, else 0. 139238106Sdes * notice: 140238106Sdes * (1) does not touch `dst' unless it's returning 1. 141238106Sdes * (2) :: in a full address is silently ignored. 142238106Sdes * credit: 143238106Sdes * inspired by Mark Andrews. 144238106Sdes * author: 145238106Sdes * Paul Vixie, 1996. 146238106Sdes */ 147238106Sdesstatic int 148238106Sdesinet_pton6(src, dst) 149238106Sdes const char *src; 150238106Sdes uint8_t *dst; 151238106Sdes{ 152238106Sdes static const char xdigits_l[] = "0123456789abcdef", 153238106Sdes xdigits_u[] = "0123456789ABCDEF"; 154238106Sdes uint8_t tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp; 155238106Sdes const char *xdigits, *curtok; 156238106Sdes int ch, saw_xdigit; 157238106Sdes uint32_t val; 158238106Sdes 159238106Sdes memset((tp = tmp), '\0', NS_IN6ADDRSZ); 160238106Sdes endp = tp + NS_IN6ADDRSZ; 161238106Sdes colonp = NULL; 162238106Sdes /* Leading :: requires some special handling. */ 163238106Sdes if (*src == ':') 164238106Sdes if (*++src != ':') 165238106Sdes return (0); 166238106Sdes curtok = src; 167238106Sdes saw_xdigit = 0; 168238106Sdes val = 0; 169238106Sdes while ((ch = *src++) != '\0') { 170238106Sdes const char *pch; 171238106Sdes 172238106Sdes if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL) 173238106Sdes pch = strchr((xdigits = xdigits_u), ch); 174238106Sdes if (pch != NULL) { 175238106Sdes val <<= 4; 176238106Sdes val |= (pch - xdigits); 177238106Sdes if (val > 0xffff) 178238106Sdes return (0); 179238106Sdes saw_xdigit = 1; 180238106Sdes continue; 181238106Sdes } 182238106Sdes if (ch == ':') { 183238106Sdes curtok = src; 184238106Sdes if (!saw_xdigit) { 185238106Sdes if (colonp) 186238106Sdes return (0); 187238106Sdes colonp = tp; 188238106Sdes continue; 189238106Sdes } 190238106Sdes if (tp + NS_INT16SZ > endp) 191238106Sdes return (0); 192238106Sdes *tp++ = (uint8_t) (val >> 8) & 0xff; 193238106Sdes *tp++ = (uint8_t) val & 0xff; 194238106Sdes saw_xdigit = 0; 195238106Sdes val = 0; 196238106Sdes continue; 197238106Sdes } 198238106Sdes if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) && 199238106Sdes inet_pton4(curtok, tp) > 0) { 200238106Sdes tp += NS_INADDRSZ; 201238106Sdes saw_xdigit = 0; 202238106Sdes break; /* '\0' was seen by inet_pton4(). */ 203238106Sdes } 204238106Sdes return (0); 205238106Sdes } 206238106Sdes if (saw_xdigit) { 207238106Sdes if (tp + NS_INT16SZ > endp) 208238106Sdes return (0); 209238106Sdes *tp++ = (uint8_t) (val >> 8) & 0xff; 210238106Sdes *tp++ = (uint8_t) val & 0xff; 211238106Sdes } 212238106Sdes if (colonp != NULL) { 213238106Sdes /* 214238106Sdes * Since some memmove()'s erroneously fail to handle 215238106Sdes * overlapping regions, we'll do the shift by hand. 216238106Sdes */ 217238106Sdes const int n = tp - colonp; 218238106Sdes int i; 219238106Sdes 220238106Sdes for (i = 1; i <= n; i++) { 221238106Sdes endp[- i] = colonp[n - i]; 222238106Sdes colonp[n - i] = 0; 223238106Sdes } 224238106Sdes tp = endp; 225238106Sdes } 226238106Sdes if (tp != endp) 227238106Sdes return (0); 228238106Sdes memcpy(dst, tmp, NS_IN6ADDRSZ); 229238106Sdes return (1); 230238106Sdes} 231