1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License").  You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22/*
23 * Copyright 2002-2003 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27#pragma ident	"%Z%%M%	%I%	%E% SMI"
28
29#include <sys/salib.h>
30#include <sys/types.h>
31#include <sys/socket.h>
32#include <sys/bootvfs.h>
33#include <netinet/in.h>
34
35/*
36 * This structure defines the static area where gethostbyname()
37 * stores the hostent data that it returns to the caller.
38 */
39static struct {
40	struct hostent	he;
41	in_addr_t	*ha_list[2];
42	in_addr_t	ha_addr;
43	char		ha_name[MAXHOSTNAMELEN+1];
44} hostinfo;
45
46int h_errno;
47
48static in_addr_t inet_addr(const char *);
49static in_addr_t nam2addr(const char *);
50
51/* Very stripped-down gethostbyname() */
52struct hostent *
53gethostbyname(const char *nam)
54{
55	bzero(&hostinfo, sizeof (hostinfo));
56
57	hostinfo.ha_addr = inet_addr(nam);
58	if ((int32_t)hostinfo.ha_addr == -1) {
59		if (get_default_fs() == NULL) {
60			h_errno = HOST_NOT_FOUND;
61			return (NULL);
62		}
63		hostinfo.ha_addr = nam2addr(nam);
64		if ((int32_t)hostinfo.ha_addr == -1) {
65			h_errno = HOST_NOT_FOUND;
66			return (NULL);
67		}
68	}
69
70	hostinfo.he.h_addrtype = AF_INET;
71	(void) strlcpy(hostinfo.ha_name, nam, MAXHOSTNAMELEN);
72	hostinfo.he.h_name = hostinfo.ha_name;
73	hostinfo.he.h_length = sizeof (struct in_addr);
74	hostinfo.ha_list[0] = &hostinfo.ha_addr;
75	hostinfo.he.h_addr_list = (char **)&hostinfo.ha_list;
76	return (&hostinfo.he);
77}
78
79#define	SKIP_SPACE(_p)							\
80	{								\
81		char	_c;						\
82		while ((_c = *(_p)) != '\0' && isspace(_c))		\
83			p++;						\
84		if (_c == '\0')						\
85			goto next_line;					\
86	}
87
88#define	SKIP_TOKEN(_p)							\
89	{								\
90		char	_c;						\
91		while ((_c = *(_p)) != '\0' && !isspace(_c))		\
92			p++;						\
93		if (_c == '\0')						\
94			goto next_line;					\
95	}
96
97#define	TRIM_LINE(_l)							\
98	{								\
99		char	_c, *_p = (_l);					\
100		while ((_c = *_p) != '#' && _c != '\n' && _c != '\0')	\
101			_p++;						\
102		*_p = '\0';						\
103	}
104
105#define	BUFSZ	1024
106#define	HOSTDB	"/etc/inet/hosts"
107
108static in_addr_t
109nam2addr(const char *nam)
110{
111	FILE *h;
112	char c, buf[BUFSZ];
113	char *l, *p, *s;
114	boolean_t first_token;
115
116	if ((h = fopen(HOSTDB, "r")) == NULL) {
117		return ((in_addr_t)-1);
118	}
119
120next_line:
121	if ((l = fgets(buf, BUFSZ, h)) == NULL) {
122		(void) fclose(h);
123		return ((in_addr_t)-1);
124	}
125	TRIM_LINE(l);
126
127	p = l;
128	first_token = B_TRUE;
129next_token:
130	SKIP_SPACE(p);
131
132	if (first_token) {
133		first_token = B_FALSE;
134		SKIP_TOKEN(p);
135
136		*p++ = '\0';
137		goto next_token;
138	}
139
140	s = (char *)nam;
141	if (*p++ == *s++) {
142		while ((c = *s++) == *p && c != '\0')
143			p++;
144		if (c == '\0' && (isspace(*p) || *p == '\0'))
145			goto match;
146	}
147
148	SKIP_TOKEN(p);
149	goto next_token;
150match:
151	(void) fclose(h);
152	return (inet_addr((const char *)l));
153}
154
155static in_addr_t
156inet_addr(const char *cp)
157{
158	in_addr_t val;
159	uint_t base, n;
160	char c;
161	in_addr_t parts[4], *pp = parts;
162
163again:
164	/*
165	 * Collect number up to ``.''.
166	 * Values are specified as for C:
167	 * 0x=hex, 0=octal, other=decimal.
168	 */
169	val = 0; base = 10;
170	if (*cp == '0') {
171		if (*++cp == 'x' || *cp == 'X')
172			base = 16, cp++;
173		else
174			base = 8;
175	}
176
177	while ((c = *cp) != 0) {
178		if (isdigit(c)) {
179			if ((c - '0') >= base)
180				break;
181			val = (val * base) + (c - '0');
182			cp++;
183			continue;
184		}
185		if (base == 16 && isxdigit(c)) {
186			val = (val << 4) + (c + 10 - (islower(c) ? 'a' : 'A'));
187			cp++;
188			continue;
189		}
190		break;
191	}
192	if (*cp == '.') {
193		/*
194		 * Internet format:
195		 *	a.b.c.d
196		 *	a.b.c	(with c treated as 16-bits)
197		 *	a.b	(with b treated as 24 bits)
198		 */
199		if (pp >= parts + 4)
200			return ((in_addr_t)-1);
201		*pp++ = val, cp++;
202		goto again;
203	}
204	/*
205	 * Check for trailing characters.
206	 */
207	if (*cp && !isspace(*cp))
208		return ((in_addr_t)-1);
209	*pp++ = val;
210	/*
211	 * Concoct the address according to
212	 * the number of parts specified.
213	 */
214	n = pp - parts;
215	switch (n) {
216
217	case 1:			 /* a -- 32 bits */
218		val = parts[0];
219		break;
220
221	case 2:			 /* a.b -- 8.24 bits */
222		val = (parts[0] << 24) | (parts[1] & 0xffffff);
223		break;
224
225	case 3:			 /* a.b.c -- 8.8.16 bits */
226		val = (parts[0] << 24) | ((parts[1] & 0xff) << 16) |
227			(parts[2] & 0xffff);
228		break;
229
230	case 4:			 /* a.b.c.d -- 8.8.8.8 bits */
231		val = (parts[0] << 24) | ((parts[1] & 0xff) << 16) |
232			((parts[2] & 0xff) << 8) | (parts[3] & 0xff);
233		break;
234
235	default:
236		return ((in_addr_t)-1);
237	}
238	val = htonl(val);
239	return (val);
240}
241