inet_pton.c revision 1219:f89f56c2d9ac
1238722Skargl/* 2238722Skargl * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 3238722Skargl * Use is subject to license terms. 4238722Skargl */ 5238722Skargl 6238722Skargl/* 7238722Skargl * Copyright (c) 1996 by Internet Software Consortium. 8238722Skargl * 9238722Skargl * Permission to use, copy, modify, and distribute this software for any 10238722Skargl * purpose with or without fee is hereby granted, provided that the above 11238722Skargl * copyright notice and this permission notice appear in all copies. 12238722Skargl * 13238722Skargl * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS 14238722Skargl * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES 15238722Skargl * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE 16238722Skargl * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 17238722Skargl * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 18238722Skargl * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS 19238722Skargl * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 20238722Skargl * SOFTWARE. 21238722Skargl */ 22238722Skargl 23238722Skargl#pragma ident "%Z%%M% %I% %E% SMI" 24238722Skargl 25238722Skargl#include "mt.h" 26238722Skargl#include <stdlib.h> 27238722Skargl#include <ctype.h> 28238722Skargl#include <string.h> 29238722Skargl#include <strings.h> 30238722Skargl#include <netdb.h> 31238722Skargl#include <stdio.h> 32240864Skargl#include <arpa/inet.h> 33238722Skargl#include <netinet/in.h> 34238722Skargl#include <sys/socket.h> 35238722Skargl#include <errno.h> 36238722Skargl 37238722Skarglstatic int inet_pton4(const char *src, uchar_t *dst); 38238722Skarglstatic int inet_pton6(const char *src, uchar_t *dst); 39238784Skargl 40238722Skargl/* 41238722Skargl * int 42238722Skargl * inet_pton(af, src, dst) 43238722Skargl * convert from presentation format (which usually means ASCII printable) 44238722Skargl * to network format (which is usually some kind of binary format). 45238722Skargl * return: 46238722Skargl * 1 if the address was valid for the specified address family 47238722Skargl * 0 if the address wasn't valid (`dst' is untouched in this case) 48238783Skargl * -1 if some other error occurred (`dst' is untouched in this case, too) 49238722Skargl * author: 50238722Skargl * Paul Vixie, 1996. Taken from on297-gate:dns stuff 51238722Skargl */ 52240861Skarglint 53238722Skarglinet_pton(int af, const char *src, void *dst) 54238722Skargl{ 55238722Skargl switch (af) { 56238722Skargl case AF_INET: 57238722Skargl return (inet_pton4(src, dst)); 58238722Skargl case AF_INET6: 59238722Skargl return (inet_pton6(src, dst)); 60238722Skargl default: 61238722Skargl errno = EAFNOSUPPORT; 62238722Skargl return (-1); 63241051Skargl } 64238722Skargl /* NOTREACHED */ 65241051Skargl} 66238722Skargl 67241516Skargl/* 68238722Skargl * int 69238784Skargl * inet_pton4(src, dst) 70238784Skargl * like inet_aton() but without all the hexadecimal and shorthand. 71238784Skargl * return: 72238722Skargl * 1 if `src' is a valid dotted quad, else 0. 73240864Skargl * notice: 74238722Skargl * does not touch `dst' unless it's returning 1. 75238722Skargl * 76238722Skargl */ 77238722Skargl#define INADDRSZ 4 78238722Skargl#define IN6ADDRSZ 16 79238784Skargl#define INT16SZ 2 80238722Skargl 81238722Skarglstatic int 82238722Skarglinet_pton4(const char *src, uchar_t *dst) 83238722Skargl{ 84238722Skargl static const char digits[] = "0123456789"; 85238722Skargl int saw_digit, octets, ch; 86238722Skargl uchar_t tmp[INADDRSZ], *tp; 87238722Skargl 88238784Skargl saw_digit = 0; 89241516Skargl octets = 0; 90241516Skargl *(tp = tmp) = 0; 91240861Skargl while ((ch = *src++) != '\0') { 92240861Skargl const char *pch; 93241516Skargl 94241516Skargl if ((pch = strchr(digits, ch)) != NULL) { 95238722Skargl uint_t new = *tp * 10 + (pch - digits); 96238722Skargl 97238722Skargl if (new > 255) 98238722Skargl return (0); 99241516Skargl *tp = new; 100241516Skargl if (!saw_digit) { 101238722Skargl if (++octets > 4) 102240861Skargl return (0); 103240861Skargl saw_digit = 1; 104240861Skargl } 105240861Skargl } else if (ch == '.' && saw_digit) { 106240861Skargl if (octets == 4) 107240861Skargl return (0); 108240861Skargl *++tp = 0; 109240861Skargl saw_digit = 0; 110240861Skargl } else 111240861Skargl return (0); 112240861Skargl } 113240861Skargl if (octets < 4) 114240861Skargl return (0); 115240861Skargl 116240861Skargl (void) memcpy(dst, tmp, INADDRSZ); 117240861Skargl return (1); 118240861Skargl} 119240861Skargl 120240861Skargl 121240861Skargl/* 122240861Skargl * int 123240861Skargl * inet_pton6(src, dst) 124240861Skargl * convert presentation level address to network order binary form. 125240861Skargl * return: 126240861Skargl * 1 if `src' is a valid [RFC1884 2.2] address, else 0. 127240861Skargl * notice: 128240861Skargl * (1) does not touch `dst' unless it's returning 1. 129240861Skargl * (2) :: in a full address is silently ignored. 130240861Skargl * credit: 131240861Skargl * inspired by Mark Andrews. 132240861Skargl * 133240861Skargl */ 134240861Skargl 135240861Skargl 136240861Skarglstatic int 137240861Skarglinet_pton6(const char *src, uchar_t *dst) 138240861Skargl{ 139240861Skargl static const char xdigits_l[] = "0123456789abcdef", 140240861Skargl xdigits_u[] = "0123456789ABCDEF"; 141240861Skargl uchar_t tmp[IN6ADDRSZ], *tp, *endp, *colonp; 142240861Skargl const char *xdigits, *curtok; 143240861Skargl int ch, saw_xdigit; 144240861Skargl uint_t val; 145240861Skargl 146240861Skargl (void) memset((tp = tmp), '\0', IN6ADDRSZ); 147240861Skargl endp = tp + IN6ADDRSZ; 148240861Skargl colonp = NULL; 149240861Skargl /* Leading :: requires some special handling. */ 150240861Skargl if (*src == ':') 151240861Skargl if (*++src != ':') 152240861Skargl return (0); 153240861Skargl curtok = src; 154240861Skargl saw_xdigit = 0; 155240861Skargl val = 0; 156240861Skargl while ((ch = *src++) != '\0') { 157240861Skargl const char *pch; 158240861Skargl 159240861Skargl if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL) 160240861Skargl pch = strchr((xdigits = xdigits_u), ch); 161240861Skargl if (pch != NULL) { 162240861Skargl val <<= 4; 163240861Skargl val |= (pch - xdigits); 164240861Skargl if (val > 0xffff) 165240861Skargl return (0); 166240861Skargl saw_xdigit = 1; 167240861Skargl continue; 168240861Skargl } 169240861Skargl if (ch == ':') { 170240861Skargl curtok = src; 171240861Skargl if (!saw_xdigit) { 172240861Skargl if (colonp) 173240861Skargl return (0); 174240861Skargl colonp = tp; 175240861Skargl continue; 176240861Skargl } else if (*src == '\0') { 177240861Skargl return (0); 178240861Skargl } 179240861Skargl if (tp + INT16SZ > endp) 180240861Skargl return (0); 181240861Skargl *tp++ = (uchar_t)(val >> 8) & 0xff; 182240861Skargl *tp++ = (uchar_t)val & 0xff; 183240861Skargl saw_xdigit = 0; 184240861Skargl val = 0; 185240861Skargl continue; 186240861Skargl } 187240861Skargl if (ch == '.' && ((tp + INADDRSZ) <= endp) && 188240861Skargl inet_pton4(curtok, tp) > 0) { 189240861Skargl tp += INADDRSZ; 190240861Skargl saw_xdigit = 0; 191240861Skargl break; /* '\0' was seen by inet_pton4(). */ 192240861Skargl } 193240861Skargl return (0); 194240861Skargl } 195240861Skargl if (saw_xdigit) { 196240861Skargl if (tp + INT16SZ > endp) 197240861Skargl return (0); 198240861Skargl *tp++ = (uchar_t)(val >> 8) & 0xff; 199240861Skargl *tp++ = (uchar_t)val & 0xff; 200240861Skargl } 201240861Skargl if (colonp != NULL) { 202240861Skargl /* 203240861Skargl * Since some memmove()'s erroneously fail to handle 204240861Skargl * overlapping regions, we'll do the shift by hand. 205240861Skargl */ 206240861Skargl const int n = tp - colonp; 207240861Skargl int i; 208240861Skargl 209240861Skargl if (tp == endp) 210240861Skargl return (0); 211240861Skargl for (i = 1; i <= n; i++) { 212240861Skargl endp[- i] = colonp[n - i]; 213240861Skargl colonp[n - i] = 0; 214240861Skargl } 215240861Skargl tp = endp; 216240861Skargl } 217240861Skargl if (tp != endp) 218240861Skargl return (0); 219240861Skargl (void) memcpy(dst, tmp, IN6ADDRSZ); 220240861Skargl return (1); 221240861Skargl} 222240861Skargl