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