2 * conversion from ASCII forms of addresses to internal ones
3 * Copyright (C) 1998, 1999 Henry Spencer.
5 * This library is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU Library General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/lgpl.txt>.
10 * This library is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
13 * License for more details.
15 * RCSID $Id: atoaddr.c,v 1.12 2000/01/22 02:17:22 henry Exp $
21 * Define NOLEADINGZEROS to interpret 032 as an error, not as 32. There
22 * is deliberately no way to interpret it as 26 (i.e., as octal).
26 * Legal characters in a domain name. Underscore technically is not,
27 * but is a common misunderstanding.
29 static const char namechars[] = "abcdefghijklmnopqrstuvwxyz0123456789"
30 "ABCDEFGHIJKLMNOPQRSTUVWXYZ-_.";
32 static const char *try8hex(const char *, size_t, struct in_addr *);
33 static const char *try8hosthex(const char *, size_t, struct in_addr *);
34 static const char *trydotted(const char *, size_t, struct in_addr *);
35 static const char *getbyte(const char **, const char *, int *);
38 - atoaddr - convert ASCII name or dotted-decimal address to binary address
40 const char * /* NULL for success, else string literal */
41 atoaddr(src, srclen, addrp)
43 size_t srclen; /* 0 means "apply strlen" */
44 struct in_addr *addrp;
47 struct netent *ne = NULL;
49 # define HEXLEN 10 /* strlen("0x11223344") */
51 # define ATOADDRBUF 100
53 char namebuf[ATOADDRBUF];
60 return "empty string";
62 /* might it be hex? */
63 if (srclen == HEXLEN && *src == '0' && CIEQ(*(src+1), 'x'))
64 return try8hex(src+2, srclen-2, addrp);
65 if (srclen == HEXLEN && *src == '0' && CIEQ(*(src+1), 'h'))
66 return try8hosthex(src+2, srclen-2, addrp);
68 /* try it as dotted decimal */
69 oops = trydotted(src, srclen, addrp);
71 return NULL; /* it worked */
73 return oops; /* it *was* probably meant as a d.q. */
75 /* try it as a name -- first, NUL-terminate it */
76 if (srclen > sizeof(namebuf)-1) {
77 p = (char *) MALLOC(srclen+1);
79 return "unable to allocate temporary space for name";
82 strncat(p, src, srclen);
84 /* next, check that it's a vaguely legal name */
85 for (q = p; *q != '\0'; q++)
87 return "unprintable character in name";
88 if (strspn(p, namechars) != srclen)
89 return "illegal (non-DNS-name) character in name";
91 /* try as host name, failing that as /etc/networks network name */
97 if (h == NULL && ne == NULL)
98 return "name lookup failed";
101 memcpy(&addrp->s_addr, h->h_addr, sizeof(addrp->s_addr));
103 addrp->s_addr = htonl(ne->n_net);
108 - try8hosthex - try conversion as an eight-digit host-order hex number
110 const char * /* NULL for success, else string literal */
111 try8hosthex(src, srclen, addrp)
113 size_t srclen; /* should be 8 */
114 struct in_addr *addrp;
120 return "internal error, try8hex called with bad length";
122 oops = atoul(src, srclen, 16, &addr);
126 addrp->s_addr = addr;
131 - try8hex - try conversion as an eight-digit network-order hex number
133 const char * /* NULL for success, else string literal */
134 try8hex(src, srclen, addrp)
136 size_t srclen; /* should be 8 */
137 struct in_addr *addrp;
141 oops = try8hosthex(src, srclen, addrp);
145 addrp->s_addr = htonl(addrp->s_addr);
150 - trydotted - try conversion as dotted decimal
152 * If the first char of a complaint is '?', that means "didn't look like
153 * dotted decimal at all".
155 const char * /* NULL for success, else string literal */
156 trydotted(src, srclen, addrp)
159 struct in_addr *addrp;
161 const char *stop = src + srclen; /* just past end */
170 for (i = 0; i < NBYTES && src < stop; i++) {
171 oops = getbyte(&src, stop, &byte);
174 return oops; /* bad number */
176 return oops+1; /* failed number */
177 return oops; /* with leading '?' */
179 addr = (addr << BYTE) | byte;
180 if (i < 3 && src < stop && *src++ != '.') {
182 return "?syntax error in dotted-decimal address";
184 return "syntax error in dotted-decimal address";
187 addr <<= (NBYTES - i) * BYTE;
189 return "extra garbage on end of dotted-decimal address";
191 addrp->s_addr = htonl(addr);
196 - getbyte - try to scan a byte in dotted decimal
197 * A subtlety here is that all this arithmetic on ASCII digits really is
198 * highly portable -- ANSI C guarantees that digits 0-9 are contiguous.
199 * It's easier to just do it ourselves than set up for a call to atoul().
201 * If the first char of a complaint is '?', that means "didn't look like a
204 const char * /* NULL for success, else string literal */
205 getbyte(srcp, stop, retp)
206 const char **srcp; /* *srcp is updated */
207 const char *stop; /* first untouchable char */
208 int *retp; /* return-value pointer */
215 return "?empty number in dotted-decimal address";
217 if (stop - *srcp >= 3 && **srcp == '0' && CIEQ(*(*srcp+1), 'x'))
218 return "hex numbers not supported in dotted-decimal addresses";
219 #ifdef NOLEADINGZEROS
220 if (stop - *srcp >= 2 && **srcp == '0' && isdigit(*(*srcp+1)))
221 return "octal numbers not supported in dotted-decimal addresses";
222 #endif /* NOLEADINGZEROS */
224 /* must be decimal, if it's numeric at all */
227 while (p < stop && no <= 255 && (c = *p) >= '0' && c <= '9') {
228 no = no*10 + (c - '0');
232 return "?non-numeric component in dotted-decimal address";
235 return "byte overflow in dotted-decimal address";