]>
git.ipfire.org Git - people/ms/strongswan.git/blob - src/libfreeswan/libfreeswan/ttoaddr.c
2 * conversion from text forms of addresses to internal ones
3 * Copyright (C) 2000 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: ttoaddr.c,v 1.1 2004/03/15 20:35:26 as Exp $
21 * Legal ASCII characters in a domain name. Underscore technically is not,
22 * but is a common misunderstanding. Non-ASCII characters are simply
23 * exempted from checking at the moment, to allow for UTF-8 encoded stuff;
24 * the purpose of this check is merely to catch blatant errors.
26 static const char namechars
[] = "abcdefghijklmnopqrstuvwxyz0123456789"
27 "ABCDEFGHIJKLMNOPQRSTUVWXYZ-_.";
28 #define ISASCII(c) (((c) & 0x80) == 0)
30 static err_t
tryname(const char *, size_t, int, int, ip_address
*);
31 static err_t
tryhex(const char *, size_t, int, ip_address
*);
32 static err_t
trydotted(const char *, size_t, ip_address
*);
33 static err_t
getbyte(const char **, const char *, int *);
34 static err_t
colon(const char *, size_t, ip_address
*);
35 static err_t
getpiece(const char **, const char *, unsigned *);
38 - ttoaddr - convert text name or dotted-decimal address to binary address
40 err_t
/* NULL for success, else string literal */
41 ttoaddr(src
, srclen
, af
, dst
)
43 size_t srclen
; /* 0 means "apply strlen" */
44 int af
; /* address family */
48 # define HEXLEN 10 /* strlen("0x11223344") */
54 return "empty string";
57 nultermd
= 0; /* at least, not *known* to be terminated */
66 return "invalid address family";
69 if (af
== AF_INET
&& srclen
== HEXLEN
&& *src
== '0') {
70 if (*(src
+1) == 'x' || *(src
+1) == 'X')
71 return tryhex(src
+2, srclen
-2, 'x', dst
);
72 if (*(src
+1) == 'h' || *(src
+1) == 'H')
73 return tryhex(src
+2, srclen
-2, 'h', dst
);
76 if (memchr(src
, ':', srclen
) != NULL
) {
83 return "non-ipv6 address may not contain `:'";
84 return colon(src
, srclen
, dst
);
87 if (af
== 0 || af
== AF_INET
) {
88 oops
= trydotted(src
, srclen
, dst
);
90 return NULL
; /* it worked */
92 return oops
; /* probably meant as d-d */
95 return tryname(src
, srclen
, nultermd
, af
, dst
);
99 - tnatoaddr - convert text numeric address (only) to binary address
101 err_t
/* NULL for success, else string literal */
102 tnatoaddr(src
, srclen
, af
, dst
)
104 size_t srclen
; /* 0 means "apply strlen" */
105 int af
; /* address family */
111 srclen
= strlen(src
);
113 return "empty string";
118 oops
= colon(src
, srclen
, dst
);
123 oops
= trydotted(src
, srclen
, dst
);
128 return "does not appear to be either IPv4 or IPv6 numeric address";
132 return colon(src
, srclen
, dst
);
135 oops
= trydotted(src
, srclen
, dst
);
137 return NULL
; /* it worked */
139 return oops
; /* probably meant as d-d */
140 return "does not appear to be numeric address";
143 return "unknown address family in tnatoaddr";
149 - tryname - try it as a name
150 * Slightly complicated by lack of reliable NUL termination in source.
153 tryname(src
, srclen
, nultermd
, af
, dst
)
156 int nultermd
; /* is it known to be NUL-terminated? */
161 struct netent
*ne
= NULL
;
162 char namebuf
[100]; /* enough for most DNS names */
167 for (cp
= src
, n
= srclen
; n
> 0; cp
++, n
--)
168 if (ISASCII(*cp
) && strchr(namechars
, *cp
) == NULL
)
169 return "illegal (non-DNS-name) character in name";
174 if (srclen
+1 > sizeof(namebuf
)) {
175 p
= (char *) MALLOC(srclen
+1);
177 return "unable to get temporary space for name";
179 p
[0] = '\0'; /* strncpy semantics are wrong */
180 strncat(p
, src
, srclen
);
181 cp
= (const char *)p
;
184 h
= gethostbyname2(cp
, af
);
185 if (h
== NULL
&& af
== AF_INET
)
186 ne
= getnetbyname(cp
);
189 if (h
== NULL
&& ne
== NULL
)
190 return "does not look numeric and name lookup failed";
193 if (h
->h_addrtype
!= af
)
194 return "address-type mismatch from gethostbyname2!!!";
195 return initaddr((unsigned char *)h
->h_addr
, h
->h_length
, af
, dst
);
197 if (ne
->n_addrtype
!= af
)
198 return "address-type mismatch from getnetbyname!!!";
199 ne
->n_net
= htonl(ne
->n_net
);
200 return initaddr((unsigned char *)&ne
->n_net
, sizeof(ne
->n_net
),
206 - tryhex - try conversion as an eight-digit hex number (AF_INET only)
209 tryhex(src
, srclen
, flavor
, dst
)
211 size_t srclen
; /* should be 8 */
212 int flavor
; /* 'x' for network order, 'h' for host order */
219 unsigned char buf
[4];
223 return "internal error, tryhex called with bad length";
225 oops
= ttoul(src
, srclen
, 16, &ul
);
229 u
.addr
= (flavor
== 'h') ? ul
: htonl(ul
);
230 return initaddr(u
.buf
, sizeof(u
.buf
), AF_INET
, dst
);
234 - trydotted - try conversion as dotted decimal (AF_INET only)
236 * If the first char of a complaint is '?', that means "didn't look like
237 * dotted decimal at all".
240 trydotted(src
, srclen
, dst
)
245 const char *stop
= src
+ srclen
; /* just past end */
249 unsigned char buf
[NBYTES
];
252 memset(buf
, 0, sizeof(buf
));
253 for (i
= 0; i
< NBYTES
&& src
< stop
; i
++) {
254 oops
= getbyte(&src
, stop
, &byte
);
257 return oops
; /* bad number */
259 return oops
+1; /* failed number */
260 return oops
; /* with leading '?' */
263 if (i
< 3 && src
< stop
&& *src
++ != '.') {
265 return "?syntax error in dotted-decimal address";
267 return "syntax error in dotted-decimal address";
271 return "extra garbage on end of dotted-decimal address";
273 return initaddr(buf
, sizeof(buf
), AF_INET
, dst
);
277 - getbyte - try to scan a byte in dotted decimal
278 * A subtlety here is that all this arithmetic on ASCII digits really is
279 * highly portable -- ANSI C guarantees that digits 0-9 are contiguous.
280 * It's easier to just do it ourselves than set up for a call to ttoul().
282 * If the first char of a complaint is '?', that means "didn't look like a
286 getbyte(srcp
, stop
, retp
)
287 const char **srcp
; /* *srcp is updated */
288 const char *stop
; /* first untouchable char */
289 int *retp
; /* return-value pointer */
296 return "?empty number in dotted-decimal address";
300 while (p
< stop
&& no
<= 255 && (c
= *p
) >= '0' && c
<= '9') {
301 no
= no
*10 + (c
- '0');
305 return "?non-numeric component in dotted-decimal address";
308 return "byte overflow in dotted-decimal address";
314 - colon - convert IPv6 "numeric" address
317 colon(src
, srclen
, dst
)
319 size_t srclen
; /* known to be >0 */
322 const char *stop
= src
+ srclen
; /* just past end */
324 int gapat
; /* where was empty piece seen */
327 unsigned char buf
[NPIECES
*2]; /* short may have wrong byte order */
330 # define IT "IPv6 numeric address"
333 /* leading or trailing :: becomes single empty field */
334 if (*src
== ':') { /* legal only if leading :: */
335 if (srclen
== 1 || *(src
+1) != ':')
336 return "illegal leading `:' in " IT
;
338 unspecaddr(AF_INET6
, dst
);
341 src
++; /* past first but not second */
344 if (*(stop
-1) == ':') { /* legal only if trailing :: */
345 if (srclen
== 1 || *(stop
-2) != ':')
346 return "illegal trailing `:' in " IT
;
347 srclen
--; /* leave one */
351 for (i
= 0; i
< NPIECES
&& src
< stop
; i
++) {
352 oops
= getpiece(&src
, stop
, &piece
);
353 if (oops
!= NULL
&& *oops
== ':') { /* empty field */
355 return "more than one :: in " IT
;
357 } else if (oops
!= NULL
)
359 buf
[2*i
] = piece
>> 8;
360 buf
[2*i
+ 1] = piece
& 0xff;
361 if (i
< NPIECES
-1) { /* there should be more input */
362 if (src
== stop
&& gapat
< 0)
363 return IT
" ends prematurely";
364 if (src
!= stop
&& *src
++ != ':')
365 return "syntax error in " IT
;
369 return "extra garbage on end of " IT
;
371 if (gapat
< 0 && i
< NPIECES
) /* should have been caught earlier */
372 return "incomplete " IT
" (internal error)";
373 if (gapat
>= 0 && i
== NPIECES
)
374 return "non-abbreviating empty field in " IT
;
376 naftergap
= i
- (gapat
+ 1);
377 for (i
--, j
= NPIECES
-1; naftergap
> 0; i
--, j
--, naftergap
--) {
379 buf
[2*j
+ 1] = buf
[2*i
+ 1];
381 for (; j
>= gapat
; j
--)
382 buf
[2*j
] = buf
[2*j
+ 1] = 0;
385 return initaddr(buf
, sizeof(buf
), AF_INET6
, dst
);
389 - getpiece - try to scan one 16-bit piece of an IPv6 address
391 err_t
/* ":" means "empty field seen" */
392 getpiece(srcp
, stop
, retp
)
393 const char **srcp
; /* *srcp is updated */
394 const char *stop
; /* first untouchable char */
395 unsigned *retp
; /* return-value pointer */
403 if (*srcp
>= stop
|| **srcp
== ':') { /* empty field */
410 while (p
< stop
&& d
< NDIG
&& isxdigit(*p
)) {
415 return "non-hex field in IPv6 numeric address";
416 if (p
< stop
&& d
== NDIG
&& isxdigit(*p
))
417 return "field in IPv6 numeric address longer than 4 hex digits";
419 oops
= ttoul(*srcp
, d
, 16, &ret
);
420 if (oops
!= NULL
) /* shouldn't happen, really... */