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