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