OSDN Git Service

2013.10.24
[uclinux-h8/uClinux-dist.git] / freeswan / lib / 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  * RCSID $Id: atoaddr.c,v 1.12 2000/01/22 02:17:22 henry Exp $
16  */
17 #include "internal.h"
18 #include "freeswan.h"
19
20 /*
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).
23  */
24
25 /*
26  * Legal characters in a domain name.  Underscore technically is not,
27  * but is a common misunderstanding.
28  */
29 static const char namechars[] = "abcdefghijklmnopqrstuvwxyz0123456789"
30                                 "ABCDEFGHIJKLMNOPQRSTUVWXYZ-_.";
31
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 *);
36
37 /*
38  - atoaddr - convert ASCII name or dotted-decimal address to binary address
39  */
40 const char *                    /* NULL for success, else string literal */
41 atoaddr(src, srclen, addrp)
42 const char *src;
43 size_t srclen;                  /* 0 means "apply strlen" */
44 struct in_addr *addrp;
45 {
46         struct hostent *h;
47         struct netent *ne = NULL;
48         const char *oops;
49 #       define  HEXLEN  10      /* strlen("0x11223344") */
50 #       ifndef ATOADDRBUF
51 #       define  ATOADDRBUF      100
52 #       endif
53         char namebuf[ATOADDRBUF];
54         char *p = namebuf;
55         char *q;
56
57         if (srclen == 0)
58                 srclen = strlen(src);
59         if (srclen == 0)
60                 return "empty string";
61
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);
67
68         /* try it as dotted decimal */
69         oops = trydotted(src, srclen, addrp);
70         if (oops == NULL)
71                 return NULL;            /* it worked */
72         if (*oops != '?')
73                 return oops;            /* it *was* probably meant as a d.q. */
74
75         /* try it as a name -- first, NUL-terminate it */
76         if (srclen > sizeof(namebuf)-1) {
77                 p = (char *) MALLOC(srclen+1);
78                 if (p == NULL)
79                         return "unable to allocate temporary space for name";
80         }
81         p[0] = '\0';
82         strncat(p, src, srclen);
83
84         /* next, check that it's a vaguely legal name */
85         for (q = p; *q != '\0'; q++)
86                 if (!isprint(*q))
87                         return "unprintable character in name";
88         if (strspn(p, namechars) != srclen)
89                 return "illegal (non-DNS-name) character in name";
90
91         /* try as host name, failing that as /etc/networks network name */
92         h = gethostbyname(p);
93         if (h == NULL)
94                 ne = getnetbyname(p);
95         if (p != namebuf)
96                 FREE(p);
97         if (h == NULL && ne == NULL)
98                 return "name lookup failed";
99
100         if (h != NULL)
101                 memcpy(&addrp->s_addr, h->h_addr, sizeof(addrp->s_addr));
102         else
103                 addrp->s_addr = htonl(ne->n_net);
104         return NULL;
105 }
106
107 /*
108  - try8hosthex - try conversion as an eight-digit host-order hex number
109  */
110 const char *                    /* NULL for success, else string literal */
111 try8hosthex(src, srclen, addrp)
112 const char *src;
113 size_t srclen;                  /* should be 8 */
114 struct in_addr *addrp;
115 {
116         const char *oops;
117         unsigned long addr;
118
119         if (srclen != 8)
120                 return "internal error, try8hex called with bad length";
121
122         oops = atoul(src, srclen, 16, &addr);
123         if (oops != NULL)
124                 return oops;
125
126         addrp->s_addr = addr;
127         return NULL;
128 }
129
130 /*
131  - try8hex - try conversion as an eight-digit network-order hex number
132  */
133 const char *                    /* NULL for success, else string literal */
134 try8hex(src, srclen, addrp)
135 const char *src;
136 size_t srclen;                  /* should be 8 */
137 struct in_addr *addrp;
138 {
139         const char *oops;
140
141         oops = try8hosthex(src, srclen, addrp);
142         if (oops != NULL)
143                 return oops;
144
145         addrp->s_addr = htonl(addrp->s_addr);
146         return NULL;
147 }
148
149 /*
150  - trydotted - try conversion as dotted decimal
151  *
152  * If the first char of a complaint is '?', that means "didn't look like
153  * dotted decimal at all".
154  */
155 const char *                    /* NULL for success, else string literal */
156 trydotted(src, srclen, addrp)
157 const char *src;
158 size_t srclen;
159 struct in_addr *addrp;
160 {
161         const char *stop = src + srclen;        /* just past end */
162         int byte;
163         const char *oops;
164         unsigned long addr;
165         int i;
166 #       define  NBYTES  4
167 #       define  BYTE    8
168
169         addr = 0;
170         for (i = 0; i < NBYTES && src < stop; i++) {
171                 oops = getbyte(&src, stop, &byte);
172                 if (oops != NULL) {
173                         if (*oops != '?')
174                                 return oops;    /* bad number */
175                         if (i > 1)
176                                 return oops+1;  /* failed number */
177                         return oops;            /* with leading '?' */
178                 }
179                 addr = (addr << BYTE) | byte;
180                 if (i < 3 && src < stop && *src++ != '.') {
181                         if (i == 0)
182                                 return "?syntax error in dotted-decimal address";
183                         else
184                                 return "syntax error in dotted-decimal address";
185                 }
186         }
187         addr <<= (NBYTES - i) * BYTE;
188         if (src != stop)
189                 return "extra garbage on end of dotted-decimal address";
190
191         addrp->s_addr = htonl(addr);
192         return NULL;
193 }
194
195 /*
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().
200  *
201  * If the first char of a complaint is '?', that means "didn't look like a
202  * number at all".
203  */
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 */
209 {
210         char c;
211         const char *p;
212         int no;
213
214         if (*srcp >= stop)
215                 return "?empty number in dotted-decimal address";
216
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 */
223
224         /* must be decimal, if it's numeric at all */
225         no = 0;
226         p = *srcp;
227         while (p < stop && no <= 255 && (c = *p) >= '0' && c <= '9') {
228                 no = no*10 + (c - '0');
229                 p++;
230         }
231         if (p == *srcp)
232                 return "?non-numeric component in dotted-decimal address";
233         *srcp = p;
234         if (no > 255)
235                 return "byte overflow in dotted-decimal address";
236         *retp = no;
237         return NULL;
238 }