dd73be7f320d2287ea96a7eb94c5cff7f1af9fe9
[strongswan.git] / src / libfreeswan / atoaddr.c
1 /*
2 * conversion from ASCII forms of addresses to internal ones
3 * Copyright (C) 1998, 1999 Henry Spencer.
4 *
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>.
9 *
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.
14 */
15 #include "internal.h"
16 #include "freeswan.h"
17
18 /*
19 * Define NOLEADINGZEROS to interpret 032 as an error, not as 32. There
20 * is deliberately no way to interpret it as 26 (i.e., as octal).
21 */
22
23 /*
24 * Legal characters in a domain name. Underscore technically is not,
25 * but is a common misunderstanding.
26 */
27 static const char namechars[] = "abcdefghijklmnopqrstuvwxyz0123456789"
28 "ABCDEFGHIJKLMNOPQRSTUVWXYZ-_.";
29
30 static const char *try8hex(const char *, size_t, struct in_addr *);
31 static const char *try8hosthex(const char *, size_t, struct in_addr *);
32 static const char *trydotted(const char *, size_t, struct in_addr *);
33 static const char *getbyte(const char **, const char *, int *);
34
35 /*
36 - atoaddr - convert ASCII name or dotted-decimal address to binary address
37 */
38 const char * /* NULL for success, else string literal */
39 atoaddr(src, srclen, addrp)
40 const char *src;
41 size_t srclen; /* 0 means "apply strlen" */
42 struct in_addr *addrp;
43 {
44 struct hostent *h;
45 struct netent *ne = NULL;
46 const char *oops;
47 # define HEXLEN 10 /* strlen("0x11223344") */
48 # ifndef ATOADDRBUF
49 # define ATOADDRBUF 100
50 # endif
51 char namebuf[ATOADDRBUF];
52 char *p = namebuf;
53 char *q;
54
55 if (srclen == 0)
56 srclen = strlen(src);
57 if (srclen == 0)
58 return "empty string";
59
60 /* might it be hex? */
61 if (srclen == HEXLEN && *src == '0' && CIEQ(*(src+1), 'x'))
62 return try8hex(src+2, srclen-2, addrp);
63 if (srclen == HEXLEN && *src == '0' && CIEQ(*(src+1), 'h'))
64 return try8hosthex(src+2, srclen-2, addrp);
65
66 /* try it as dotted decimal */
67 oops = trydotted(src, srclen, addrp);
68 if (oops == NULL)
69 return NULL; /* it worked */
70 if (*oops != '?')
71 return oops; /* it *was* probably meant as a d.q. */
72
73 /* try it as a name -- first, NUL-terminate it */
74 if (srclen > sizeof(namebuf)-1) {
75 p = (char *) MALLOC(srclen+1);
76 if (p == NULL)
77 return "unable to allocate temporary space for name";
78 }
79 p[0] = '\0';
80 strncat(p, src, srclen);
81
82 /* next, check that it's a vaguely legal name */
83 for (q = p; *q != '\0'; q++)
84 if (!isprint(*q))
85 return "unprintable character in name";
86 if (strspn(p, namechars) != srclen)
87 return "illegal (non-DNS-name) character in name";
88
89 /* try as host name, failing that as /etc/networks network name */
90 h = gethostbyname(p);
91 if (h == NULL)
92 ne = getnetbyname(p);
93 if (p != namebuf)
94 FREE(p);
95 if (h == NULL && ne == NULL)
96 return "name lookup failed";
97
98 if (h != NULL)
99 memcpy(&addrp->s_addr, h->h_addr, sizeof(addrp->s_addr));
100 else
101 addrp->s_addr = htonl(ne->n_net);
102 return NULL;
103 }
104
105 /*
106 - try8hosthex - try conversion as an eight-digit host-order hex number
107 */
108 const char * /* NULL for success, else string literal */
109 try8hosthex(src, srclen, addrp)
110 const char *src;
111 size_t srclen; /* should be 8 */
112 struct in_addr *addrp;
113 {
114 const char *oops;
115 unsigned long addr;
116
117 if (srclen != 8)
118 return "internal error, try8hex called with bad length";
119
120 oops = atoul(src, srclen, 16, &addr);
121 if (oops != NULL)
122 return oops;
123
124 addrp->s_addr = addr;
125 return NULL;
126 }
127
128 /*
129 - try8hex - try conversion as an eight-digit network-order hex number
130 */
131 const char * /* NULL for success, else string literal */
132 try8hex(src, srclen, addrp)
133 const char *src;
134 size_t srclen; /* should be 8 */
135 struct in_addr *addrp;
136 {
137 const char *oops;
138
139 oops = try8hosthex(src, srclen, addrp);
140 if (oops != NULL)
141 return oops;
142
143 addrp->s_addr = htonl(addrp->s_addr);
144 return NULL;
145 }
146
147 /*
148 - trydotted - try conversion as dotted decimal
149 *
150 * If the first char of a complaint is '?', that means "didn't look like
151 * dotted decimal at all".
152 */
153 const char * /* NULL for success, else string literal */
154 trydotted(src, srclen, addrp)
155 const char *src;
156 size_t srclen;
157 struct in_addr *addrp;
158 {
159 const char *stop = src + srclen; /* just past end */
160 int byte;
161 const char *oops;
162 unsigned long addr;
163 int i;
164 # define NBYTES 4
165 # define BYTE 8
166
167 addr = 0;
168 for (i = 0; i < NBYTES && src < stop; i++) {
169 oops = getbyte(&src, stop, &byte);
170 if (oops != NULL) {
171 if (*oops != '?')
172 return oops; /* bad number */
173 if (i > 1)
174 return oops+1; /* failed number */
175 return oops; /* with leading '?' */
176 }
177 addr = (addr << BYTE) | byte;
178 if (i < 3 && src < stop && *src++ != '.') {
179 if (i == 0)
180 return "?syntax error in dotted-decimal address";
181 else
182 return "syntax error in dotted-decimal address";
183 }
184 }
185 addr <<= (NBYTES - i) * BYTE;
186 if (src != stop)
187 return "extra garbage on end of dotted-decimal address";
188
189 addrp->s_addr = htonl(addr);
190 return NULL;
191 }
192
193 /*
194 - getbyte - try to scan a byte in dotted decimal
195 * A subtlety here is that all this arithmetic on ASCII digits really is
196 * highly portable -- ANSI C guarantees that digits 0-9 are contiguous.
197 * It's easier to just do it ourselves than set up for a call to atoul().
198 *
199 * If the first char of a complaint is '?', that means "didn't look like a
200 * number at all".
201 */
202 const char * /* NULL for success, else string literal */
203 getbyte(srcp, stop, retp)
204 const char **srcp; /* *srcp is updated */
205 const char *stop; /* first untouchable char */
206 int *retp; /* return-value pointer */
207 {
208 char c;
209 const char *p;
210 int no;
211
212 if (*srcp >= stop)
213 return "?empty number in dotted-decimal address";
214
215 if (stop - *srcp >= 3 && **srcp == '0' && CIEQ(*(*srcp+1), 'x'))
216 return "hex numbers not supported in dotted-decimal addresses";
217 #ifdef NOLEADINGZEROS
218 if (stop - *srcp >= 2 && **srcp == '0' && isdigit(*(*srcp+1)))
219 return "octal numbers not supported in dotted-decimal addresses";
220 #endif /* NOLEADINGZEROS */
221
222 /* must be decimal, if it's numeric at all */
223 no = 0;
224 p = *srcp;
225 while (p < stop && no <= 255 && (c = *p) >= '0' && c <= '9') {
226 no = no*10 + (c - '0');
227 p++;
228 }
229 if (p == *srcp)
230 return "?non-numeric component in dotted-decimal address";
231 *srcp = p;
232 if (no > 255)
233 return "byte overflow in dotted-decimal address";
234 *retp = no;
235 return NULL;
236 }