1 /*
2  * Copyright (C) 2010 Bernhard Reutner-Fischer <uclibc@uclibc.org>
3  *
4  * Licensed under LGPL v2.1 or later, see the file COPYING.LIB in this tarball.
5  */
6 
7 /* /etc/networks
8 #   network-name  number     [aliases ...]
9 loopback          127.0.0.0  # optional aliases
10 
11 network-name: symbolic name of the netwkork
12 number: official number of the network in dotted quad
13 aliases: case sensitive optional space or tab separated list of other names
14 */
15 
16 #include <features.h>
17 #include <netdb.h>
18 #include <string.h>
19 #include <stdlib.h>
20 #include <netinet/in.h>
21 #include <arpa/inet.h>
22 #include <errno.h>
23 #include <unistd.h>
24 #include "internal/parse_config.h"
25 
26 #include <bits/uClibc_mutex.h>
27 __UCLIBC_MUTEX_STATIC(mylock, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP);
28 
29 #define MINTOKENS	2
30 #define	MAXALIASES	8
31 #define MAXTOKENS	(MINTOKENS + MAXALIASES + 1)
32 #define BUFSZ		(255) /* one line */
33 #define SBUFSIZE	(BUFSZ + 1 + (sizeof(char *) * MAXTOKENS))
34 
35 static parser_t *netp = NULL;
36 static struct netent nete;
37 static char *netbuf = NULL;
38 static smallint net_stayopen;
39 
setnetent(int stayopen)40 void setnetent(int stayopen)
41 {
42 	__UCLIBC_MUTEX_LOCK(mylock);
43 	if (netp)
44 		config_close(netp);
45 	netp = config_open(_PATH_NETWORKS);
46 	if (stayopen)
47 		net_stayopen = 1;
48 	__UCLIBC_MUTEX_UNLOCK(mylock);
49 }
libc_hidden_def(setnetent)50 libc_hidden_def(setnetent)
51 
52 void endnetent(void)
53 {
54 	__UCLIBC_MUTEX_LOCK(mylock);
55 	if (netp) {
56 		config_close(netp);
57 		netp = NULL;
58 	}
59 	net_stayopen = 0;
60 	__UCLIBC_MUTEX_UNLOCK(mylock);
61 }
libc_hidden_def(endnetent)62 libc_hidden_def(endnetent)
63 
64 int getnetent_r(struct netent *result_buf,
65 				char *buf, size_t buflen, struct netent **result,
66 				int *h_errnop
67 				 )
68 {
69 	char **tok = NULL;
70 	const size_t aliaslen = sizeof(char *) * MAXTOKENS;
71 	int ret = ERANGE;
72 	(void)h_errnop;
73 
74 	*result = NULL;
75 	if (buflen < aliaslen
76 		|| (buflen - aliaslen) < BUFSZ + 1)
77 		goto DONE_NOUNLOCK;
78 
79 	__UCLIBC_MUTEX_LOCK(mylock);
80 	ret = ENOENT;
81 	if (netp == NULL)
82 		setnetent(net_stayopen);
83 	if (netp == NULL)
84 		goto DONE;
85 	netp->data = buf;
86 	netp->data_len = aliaslen;
87 	netp->line_len = buflen - aliaslen;
88 	/* <name>[[:space:]]<netnumber>[[:space:]][<aliases>] */
89 	if (!config_read(netp, &tok, MAXTOKENS-1, MINTOKENS, "# \t/", PARSE_NORMAL)) {
90 		goto DONE;
91 	}
92 	result_buf->n_name = *(tok++);
93 	{
94 		struct addrinfo hints, *addri;
95 # define sa4_to_uint32(sa) \
96 	(ntohl(((struct sockaddr_in*)sa)->sin_addr.s_addr))
97 #ifdef __UCLIBC_HAS_IPV6__
98 # define sa6_to_uint8(sa) \
99 	(ntohl(((struct sockaddr_in6*)sa)->sin6_addr.s6_addr))
100 #endif
101 		memset(&hints, 0, sizeof(struct addrinfo));
102 		hints.ai_family = AF_UNSPEC;
103 		hints.ai_flags = AI_NUMERICHOST;
104 		getaddrinfo(*(tok++), NULL, &hints, &addri);
105 		result_buf->n_addrtype = addri->ai_family;
106 		result_buf->n_net =
107 #if 0 /*FIXME: implement me! def __UCLIBC_HAS_IPV6__ */
108 			addri->ai_family == AF_INET6 ? sa6_to_uint8(addri->ai_addr) :
109 #endif
110 			sa4_to_uint32(addri->ai_addr);
111 		freeaddrinfo(addri);
112 	}
113 	result_buf->n_aliases = tok;
114 	*result = result_buf;
115 	ret = 0;
116  DONE:
117 	__UCLIBC_MUTEX_UNLOCK(mylock);
118  DONE_NOUNLOCK:
119 	errno = ret;
120 	return errno;
121 }
libc_hidden_def(getnetent_r)122 libc_hidden_def(getnetent_r)
123 
124 static void __initbuf(void)
125 {
126 	if (!netbuf) {
127 		netbuf = malloc(SBUFSIZE);
128 		if (!netbuf)
129 			abort();
130 	}
131 }
132 
getnetent(void)133 struct netent *getnetent(void)
134 {
135 	struct netent *result;
136 	int herrnop;
137 
138 	__initbuf();
139 	getnetent_r(&nete, netbuf, SBUFSIZE, &result, &herrnop);
140 	return result;
141 }
142 
getnetbyname_r(const char * name,struct netent * result_buf,char * buf,size_t buflen,struct netent ** result,int * h_errnop)143 int getnetbyname_r(const char *name,
144 					struct netent *result_buf, char *buf, size_t buflen,
145 					struct netent **result,
146 					int *h_errnop
147 					)
148 {
149 	register char **cp;
150 	int ret, herrnop;
151 	(void)h_errnop;
152 
153 	__UCLIBC_MUTEX_LOCK(mylock);
154 	setnetent(net_stayopen);
155 	while (!(ret = getnetent_r(result_buf, buf, buflen, result, &herrnop))) {
156 		if (strcmp(name, result_buf->n_name) == 0)
157 			break;
158 		for (cp = result_buf->n_aliases; *cp; cp++)
159 			if (strcmp(name, *cp) == 0)
160 				goto gotname;
161 	}
162  gotname:
163 	if (!net_stayopen)
164 		endnetent();
165 	__UCLIBC_MUTEX_UNLOCK(mylock);
166 	return *result ? 0 : ret;
167 }
libc_hidden_def(getnetbyname_r)168 libc_hidden_def(getnetbyname_r)
169 
170 struct netent *getnetbyname(const char *name)
171 {
172 	struct netent *result;
173 	int herrnop;
174 
175 	__initbuf();
176 	getnetbyname_r(name, &nete, netbuf, SBUFSIZE, &result, &herrnop);
177 	return result;
178 }
179 
getnetbyaddr_r(uint32_t net,int type,struct netent * result_buf,char * buf,size_t buflen,struct netent ** result,int * h_errnop)180 int getnetbyaddr_r(uint32_t net, int type,
181 					struct netent *result_buf, char *buf,
182 					size_t buflen, struct netent **result,
183 					int *h_errnop)
184 {
185 	int ret, herrnop;
186 	(void)h_errnop;
187 
188 	__UCLIBC_MUTEX_LOCK(mylock);
189 	setnetent(net_stayopen);
190 	while (!(ret = getnetent_r(result_buf, buf, buflen, result, &herrnop))) {
191 		if (net == result_buf->n_net && type == result_buf->n_addrtype)
192 			break;
193 	}
194 	if (!net_stayopen)
195 		endnetent();
196 	__UCLIBC_MUTEX_UNLOCK(mylock);
197 	return *result ? 0 : ret;
198 }
libc_hidden_def(getnetbyaddr_r)199 libc_hidden_def(getnetbyaddr_r)
200 
201 struct netent *getnetbyaddr(uint32_t net, int type)
202 {
203 	struct netent *result;
204 	int herrnop;
205 
206 	__initbuf();
207 	getnetbyaddr_r(net, type, &nete, netbuf, SBUFSIZE, &result, &herrnop);
208 	return result;
209 }
210 
211