xref: /netbsd-src/usr.sbin/mountd/get_net.c (revision 1ae5c388e8eeea72cde770bd5f8892b00c644ae2)
1*1ae5c388Sjoerg /* 	$NetBSD: get_net.c,v 1.3 2020/04/23 00:22:01 joerg Exp $	 */
2ce8e1195Schristos 
3ce8e1195Schristos /*
4ce8e1195Schristos  * Copyright (c) 1989, 1993
5ce8e1195Schristos  *	The Regents of the University of California.  All rights reserved.
6ce8e1195Schristos  *
7ce8e1195Schristos  * This code is derived from software contributed to Berkeley by
8ce8e1195Schristos  * Herb Hasler and Rick Macklem at The University of Guelph.
9ce8e1195Schristos  *
10ce8e1195Schristos  * Redistribution and use in source and binary forms, with or without
11ce8e1195Schristos  * modification, are permitted provided that the following conditions
12ce8e1195Schristos  * are met:
13ce8e1195Schristos  * 1. Redistributions of source code must retain the above copyright
14ce8e1195Schristos  *    notice, this list of conditions and the following disclaimer.
15ce8e1195Schristos  * 2. Redistributions in binary form must reproduce the above copyright
16ce8e1195Schristos  *    notice, this list of conditions and the following disclaimer in the
17ce8e1195Schristos  *    documentation and/or other materials provided with the distribution.
18ce8e1195Schristos  * 3. Neither the name of the University nor the names of its contributors
19ce8e1195Schristos  *    may be used to endorse or promote products derived from this software
20ce8e1195Schristos  *    without specific prior written permission.
21ce8e1195Schristos  *
22ce8e1195Schristos  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23ce8e1195Schristos  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24ce8e1195Schristos  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25ce8e1195Schristos  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26ce8e1195Schristos  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27ce8e1195Schristos  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28ce8e1195Schristos  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29ce8e1195Schristos  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30ce8e1195Schristos  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31ce8e1195Schristos  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32ce8e1195Schristos  * SUCH DAMAGE.
33ce8e1195Schristos  */
34ce8e1195Schristos 
35ce8e1195Schristos #include <sys/cdefs.h>
36*1ae5c388Sjoerg __RCSID("$NetBSD: get_net.c,v 1.3 2020/04/23 00:22:01 joerg Exp $");
37ce8e1195Schristos 
38ce8e1195Schristos #include <sys/types.h>
39ce8e1195Schristos #include <netdb.h>
40ce8e1195Schristos #include <stdio.h>
41ce8e1195Schristos #include <limits.h>
42ce8e1195Schristos #include <errno.h>
43ce8e1195Schristos #include <string.h>
44ce8e1195Schristos #include <stdlib.h>
45ce8e1195Schristos #include <unistd.h>
46ce8e1195Schristos #include <util.h>
47ce8e1195Schristos #include <arpa/inet.h>
48ce8e1195Schristos #include <netinet/in.h>
49ce8e1195Schristos 
50ce8e1195Schristos #include "mountd.h"
51ce8e1195Schristos 
52ce8e1195Schristos #ifdef TEST
53ce8e1195Schristos int      opt_flags;
54ce8e1195Schristos const int ninumeric = NI_NUMERICHOST;
55*1ae5c388Sjoerg int      mountd_debug = 1;
56ce8e1195Schristos #endif
57ce8e1195Schristos 
58ce8e1195Schristos static int
isdottedquad(const char * cp)59ce8e1195Schristos isdottedquad(const char *cp)
60ce8e1195Schristos {
61ce8e1195Schristos 	for (;;)
62ce8e1195Schristos 		switch (*cp++) {
63ce8e1195Schristos 		case '\0':
64ce8e1195Schristos 			return 1;
65ce8e1195Schristos 		case '.':
66ce8e1195Schristos 		case '0': case '1': case '2': case '3': case '4':
67ce8e1195Schristos 		case '5': case '6': case '7': case '8': case '9':
68ce8e1195Schristos 			continue;
69ce8e1195Schristos 		default:
70ce8e1195Schristos 			return 0;
71ce8e1195Schristos 		}
72ce8e1195Schristos }
73ce8e1195Schristos 
74ce8e1195Schristos static int
countones(struct sockaddr * sa)75ce8e1195Schristos countones(struct sockaddr *sa)
76ce8e1195Schristos {
77ce8e1195Schristos 	void *mask;
78ce8e1195Schristos 	int i, bits = 0, bytelen;
79ce8e1195Schristos 	u_int8_t *p;
80ce8e1195Schristos 
81ce8e1195Schristos 	switch (sa->sa_family) {
82ce8e1195Schristos 	case AF_INET:
83ce8e1195Schristos 		mask = (u_int8_t *)&((struct sockaddr_in *)sa)->sin_addr;
84ce8e1195Schristos 		bytelen = 4;
85ce8e1195Schristos 		break;
86ce8e1195Schristos 	case AF_INET6:
87ce8e1195Schristos 		mask = (u_int8_t *)&((struct sockaddr_in6 *)sa)->sin6_addr;
88ce8e1195Schristos 		bytelen = 16;
89ce8e1195Schristos 		break;
90ce8e1195Schristos 	default:
91ce8e1195Schristos 		return 0;
92ce8e1195Schristos 	}
93ce8e1195Schristos 
94ce8e1195Schristos 	p = mask;
95ce8e1195Schristos 
96ce8e1195Schristos 	for (i = 0; i < bytelen; i++, p++) {
97ce8e1195Schristos 		if (*p != 0xff) {
98ce8e1195Schristos 			for (bits = 0; bits < 8; bits++) {
99ce8e1195Schristos 				if (!(*p & (1 << (7 - bits))))
100ce8e1195Schristos 					break;
101ce8e1195Schristos 			}
102ce8e1195Schristos 			break;
103ce8e1195Schristos 		}
104ce8e1195Schristos 	}
105ce8e1195Schristos 
106ce8e1195Schristos 	return (i * 8 + bits);
107ce8e1195Schristos }
108ce8e1195Schristos 
109ce8e1195Schristos /*
110ce8e1195Schristos  * Translate a net address.
111ce8e1195Schristos  */
112ce8e1195Schristos int
get_net(char * cp,struct netmsk * net,int maskflg)113ce8e1195Schristos get_net(char *cp, struct netmsk *net, int maskflg)
114ce8e1195Schristos {
115ce8e1195Schristos 	struct netent *np;
116ce8e1195Schristos 	char *nname, *p, *prefp;
117ce8e1195Schristos 	struct sockaddr_in sin, *sinp;
118ce8e1195Schristos 	struct sockaddr *sa;
119ce8e1195Schristos 	struct addrinfo hints, *ai = NULL;
120ce8e1195Schristos 	char netname[NI_MAXHOST];
121ce8e1195Schristos 	long preflen;
122ce8e1195Schristos 	int ecode;
123ce8e1195Schristos 
124ce8e1195Schristos 	(void)memset(&sin, 0, sizeof(sin));
125ce8e1195Schristos 	if ((opt_flags & OP_MASKLEN) && !maskflg) {
126ce8e1195Schristos 		p = strchr(cp, '/');
127ce8e1195Schristos 		*p = '\0';
128ce8e1195Schristos 		prefp = p + 1;
129ce8e1195Schristos 	} else {
130ce8e1195Schristos 		p = NULL;	/* XXXGCC -Wuninitialized */
131ce8e1195Schristos 		prefp = NULL;	/* XXXGCC -Wuninitialized */
132ce8e1195Schristos 	}
133ce8e1195Schristos 
134ce8e1195Schristos 	if ((np = getnetbyname(cp)) != NULL) {
135ce8e1195Schristos 		sin.sin_family = AF_INET;
136ce8e1195Schristos 		sin.sin_len = sizeof sin;
137ce8e1195Schristos 		sin.sin_addr = inet_makeaddr(np->n_net, 0);
138ce8e1195Schristos 		sa = (struct sockaddr *)&sin;
139ce8e1195Schristos 	} else if (isdottedquad(cp)) {
140ce8e1195Schristos 		/*
141ce8e1195Schristos 		 * Handle dotted quad [or less than quad] notation specially
142ce8e1195Schristos 		 * because getaddrinfo() will parse them in the old style:
143ce8e1195Schristos 		 * i.e. 1.2.3 -> 1.2.0.3 not 1.2.3.0
144ce8e1195Schristos 		 */
145ce8e1195Schristos 		sin.sin_family = AF_INET;
146ce8e1195Schristos 		sin.sin_len = sizeof sin;
147ce8e1195Schristos 		sin.sin_addr = inet_makeaddr(inet_network(cp), 0);
148*1ae5c388Sjoerg 		if (mountd_debug)
149ce8e1195Schristos 			fprintf(stderr, "get_net: '%s' v4 addr %x\n",
150ce8e1195Schristos 			    cp, sin.sin_addr.s_addr);
151ce8e1195Schristos 		sa = (struct sockaddr *)&sin;
152ce8e1195Schristos 	} else {
153ce8e1195Schristos 		memset(&hints, 0, sizeof hints);
154ce8e1195Schristos 		hints.ai_family = AF_UNSPEC;
155ce8e1195Schristos 		hints.ai_flags = AI_NUMERICHOST;
156ce8e1195Schristos 		if (getaddrinfo(cp, NULL, &hints, &ai) == 0)
157ce8e1195Schristos 			sa = ai->ai_addr;
158ce8e1195Schristos 		else
159ce8e1195Schristos 			goto fail;
160ce8e1195Schristos 	}
161ce8e1195Schristos 
162ce8e1195Schristos 	/*
163e9e49674Schristos 	 * Disallow v6 addresses without a specific mask or masklen
164ce8e1195Schristos 	 */
165ce8e1195Schristos 	if (sa->sa_family == AF_INET6 && (!(opt_flags & OP_MASKLEN) || maskflg))
166ce8e1195Schristos 		return 1;
167ce8e1195Schristos 
168ce8e1195Schristos 	ecode = getnameinfo(sa, sa->sa_len, netname, sizeof netname,
169ce8e1195Schristos 	    NULL, 0, ninumeric);
170ce8e1195Schristos 	if (ecode != 0)
171ce8e1195Schristos 		goto fail;
172ce8e1195Schristos 
173ce8e1195Schristos 	if (maskflg)
174ce8e1195Schristos 		net->nt_len = countones(sa);
175ce8e1195Schristos 	else {
176ce8e1195Schristos 		if (opt_flags & OP_MASKLEN) {
177ce8e1195Schristos 			errno = 0;
178ce8e1195Schristos 			preflen = strtol(prefp, NULL, 10);
179ce8e1195Schristos 			if (preflen == LONG_MIN && errno == ERANGE)
180ce8e1195Schristos 				goto fail;
181ce8e1195Schristos 			net->nt_len = (int)preflen;
182ce8e1195Schristos 			*p = '/';
183ce8e1195Schristos 		}
184ce8e1195Schristos 
185ce8e1195Schristos 		if (np)
186ce8e1195Schristos 			nname = np->n_name;
187ce8e1195Schristos 		else {
188ce8e1195Schristos 			if (getnameinfo(sa, sa->sa_len, netname, sizeof netname,
189ce8e1195Schristos 			    NULL, 0, ninumeric) != 0)
190ce8e1195Schristos 				strlcpy(netname, "?", sizeof(netname));
191ce8e1195Schristos 			nname = netname;
192ce8e1195Schristos 		}
193ce8e1195Schristos 		net->nt_name = estrdup(nname);
194ce8e1195Schristos 		memcpy(&net->nt_net, sa, sa->sa_len);
195ce8e1195Schristos 	}
196ce8e1195Schristos 
197ce8e1195Schristos 	if (!maskflg && sa->sa_family == AF_INET &&
198ce8e1195Schristos 	    !(opt_flags & (OP_MASK|OP_MASKLEN))) {
199ce8e1195Schristos 		sinp = (struct sockaddr_in *)sa;
200ce8e1195Schristos 		if (IN_CLASSA(sinp->sin_addr.s_addr))
201ce8e1195Schristos 			net->nt_len = 8;
202ce8e1195Schristos 		else if (IN_CLASSB(sinp->sin_addr.s_addr))
203ce8e1195Schristos 			net->nt_len = 16;
204ce8e1195Schristos 		else if (IN_CLASSC(sinp->sin_addr.s_addr))
205ce8e1195Schristos 			net->nt_len = 24;
206ce8e1195Schristos 		else if (IN_CLASSD(sinp->sin_addr.s_addr))
207ce8e1195Schristos 			net->nt_len = 28;
208ce8e1195Schristos 		else
209ce8e1195Schristos 			net->nt_len = 32;	/* XXX */
210ce8e1195Schristos 	}
211ce8e1195Schristos 
212ce8e1195Schristos 	if (ai)
213ce8e1195Schristos 		freeaddrinfo(ai);
214ce8e1195Schristos 	return 0;
215ce8e1195Schristos 
216ce8e1195Schristos fail:
217ce8e1195Schristos 	if (ai)
218ce8e1195Schristos 		freeaddrinfo(ai);
219ce8e1195Schristos 	return 1;
220ce8e1195Schristos }
221ce8e1195Schristos 
222ce8e1195Schristos #ifdef TEST
223ce8e1195Schristos int
main(int argc,char * argv[])224ce8e1195Schristos main(int argc, char *argv[])
225ce8e1195Schristos {
226ce8e1195Schristos 	char buf[1024];
227ce8e1195Schristos 	struct netmsk nm;
228ce8e1195Schristos 
229ce8e1195Schristos 	if (get_net(argv[1], &nm, 0))
230ce8e1195Schristos 		errx(EXIT_FAILURE, "get_net failed");
231ce8e1195Schristos 
232ce8e1195Schristos 	sockaddr_snprintf(buf, sizeof(buf), "%a:%p", (void *)&nm.nt_net);
233ce8e1195Schristos 	printf("%s %d %s\n", buf, nm.nt_len, nm.nt_name);
234ce8e1195Schristos 	return 0;
235ce8e1195Schristos }
236ce8e1195Schristos #endif
237