xref: /netbsd-src/sbin/ifconfig/af_inet.c (revision bdc22b2e01993381dcefeff2bc9b56ca75a4235c)
1 /*	$NetBSD: af_inet.c,v 1.25 2018/06/11 17:45:50 kamil Exp $	*/
2 
3 /*
4  * Copyright (c) 1983, 1993
5  *      The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the University nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 #include <sys/cdefs.h>
33 #ifndef lint
34 __RCSID("$NetBSD: af_inet.c,v 1.25 2018/06/11 17:45:50 kamil Exp $");
35 #endif /* not lint */
36 
37 #include <sys/param.h>
38 #include <sys/ioctl.h>
39 #include <sys/socket.h>
40 
41 #include <net/if.h>
42 #include <netinet/in.h>
43 #include <netinet/in_var.h>
44 
45 #include <arpa/inet.h>
46 
47 #include <assert.h>
48 #include <err.h>
49 #include <errno.h>
50 #include <ifaddrs.h>
51 #include <netdb.h>
52 #include <string.h>
53 #include <stdlib.h>
54 #include <stdio.h>
55 #include <util.h>
56 
57 #include "env.h"
58 #include "extern.h"
59 #include "af_inetany.h"
60 #include "prog_ops.h"
61 
62 static void in_constructor(void) __attribute__((constructor));
63 static void in_status(prop_dictionary_t, prop_dictionary_t, bool);
64 static void in_commit_address(prop_dictionary_t, prop_dictionary_t);
65 static bool in_addr_tentative(struct ifaddrs *);
66 static bool in_addr_tentative_or_detached(struct ifaddrs *);
67 static in_addr_t in_netmask(struct sockaddr *);;
68 static int  in_prefixlen(struct sockaddr *);
69 static void in_alias(struct ifaddrs *, prop_dictionary_t, prop_dictionary_t);
70 
71 static struct afswtch af = {
72 	.af_name = "inet", .af_af = AF_INET, .af_status = in_status,
73 	.af_addr_commit = in_commit_address,
74 	.af_addr_tentative = in_addr_tentative,
75 	.af_addr_tentative_or_detached = in_addr_tentative_or_detached
76 };
77 
78 static in_addr_t
79 in_netmask(struct sockaddr *sa)
80 {
81 	struct sockaddr_in sin;
82 
83 	memset(&sin, 0, sizeof(sin));
84 	memcpy(&sin, sa, sa->sa_len);
85 	return ntohl(sin.sin_addr.s_addr);
86 }
87 
88 static int
89 in_prefixlen(struct sockaddr *sa)
90 {
91 	in_addr_t mask;
92 	int cidr;
93 
94 	mask = in_netmask(sa);
95 	if (mask == 0)			/* mask 0 ==> /0 */
96 		return 0;
97 
98 	cidr = 33 - ffs(mask);		/* 33 - (1 .. 32) -> 32 .. 1 */
99 
100 	if (cidr < 32) {		/* more than 1 bit in mask */
101 		/* check for non-contig netmask */
102 		if ((mask ^ (((1U << cidr) - 1) << (32 - cidr))) != 0)
103 			return -1;	/* noncontig, no pfxlen */
104 	}
105 
106 	return cidr;
107 }
108 
109 static void
110 in_alias(struct ifaddrs *ifa, prop_dictionary_t env, prop_dictionary_t oenv)
111 {
112 	char hbuf[NI_MAXHOST];
113 	const int niflag = Nflag ? 0 : NI_NUMERICHOST;
114 	int pfxlen;
115 	char fbuf[1024];
116 
117 	if (lflag)
118 		return;
119 
120 	if (getnameinfo(ifa->ifa_addr, ifa->ifa_addr->sa_len,
121 			hbuf, sizeof(hbuf), NULL, 0, niflag))
122 		strlcpy(hbuf, "", sizeof(hbuf));	/* some message? */
123 	printf("\tinet %s", hbuf);
124 	pfxlen = in_prefixlen(ifa->ifa_netmask);
125 	if (pfxlen >= 0)
126 		printf("/%d", pfxlen);
127 
128 	if (ifa->ifa_flags & IFF_POINTOPOINT) {
129 		if (getnameinfo(ifa->ifa_dstaddr, ifa->ifa_dstaddr->sa_len,
130 				hbuf, sizeof(hbuf), NULL, 0, niflag))
131 			strlcpy(hbuf, "", sizeof(hbuf)); /* some message? */
132 		printf(" -> %s", hbuf);
133 	}
134 
135 	if (pfxlen < 0)
136 		printf(" netmask %#x", in_netmask(ifa->ifa_netmask));
137 
138 	if (ifa->ifa_flags & IFF_BROADCAST) {
139 		if (getnameinfo(ifa->ifa_broadaddr, ifa->ifa_broadaddr->sa_len,
140 				hbuf, sizeof(hbuf), NULL, 0, niflag))
141 			strlcpy(hbuf, "", sizeof(hbuf)); /* some message? */
142 		printf(" broadcast %s", hbuf);
143 	}
144 
145 	(void)snprintb(fbuf, sizeof(fbuf), IN_IFFBITS, ifa->ifa_addrflags);
146 	printf(" flags %s", fbuf);
147 }
148 
149 static void
150 in_status(prop_dictionary_t env, prop_dictionary_t oenv, bool force)
151 {
152 	struct ifaddrs *ifap, *ifa;
153 	bool printprefs = false;
154 	const char *ifname;
155 
156 	if ((ifname = getifname(env)) == NULL)
157 		err(EXIT_FAILURE, "%s: getifname", __func__);
158 
159 	if (getifaddrs(&ifap) != 0)
160 		err(EXIT_FAILURE, "getifaddrs");
161 
162 	printprefs = ifa_any_preferences(ifname, ifap, AF_INET);
163 
164 	for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
165 		if (strcmp(ifname, ifa->ifa_name) != 0)
166 			continue;
167 		if (ifa->ifa_addr->sa_family != AF_INET)
168 			continue;
169 		/* The first address is not an alias. */
170 		in_alias(ifa, env, oenv);
171 		if (printprefs)
172 			ifa_print_preference(ifa->ifa_name, ifa->ifa_addr);
173 		printf("\n");
174 	}
175 	freeifaddrs(ifap);
176 }
177 
178 static void
179 in_commit_address(prop_dictionary_t env, prop_dictionary_t oenv)
180 {
181 	struct ifreq in_ifr;
182 	struct in_aliasreq in_ifra;
183 	struct afparam inparam = {
184 		  .req = BUFPARAM(in_ifra)
185 		, .dgreq = BUFPARAM(in_ifr)
186 		, .name = {
187 			  {.buf = in_ifr.ifr_name,
188 			   .buflen = sizeof(in_ifr.ifr_name)}
189 			, {.buf = in_ifra.ifra_name,
190 			   .buflen = sizeof(in_ifra.ifra_name)}
191 		  }
192 		, .dgaddr = BUFPARAM(in_ifr.ifr_addr)
193 		, .addr = BUFPARAM(in_ifra.ifra_addr)
194 		, .dst = BUFPARAM(in_ifra.ifra_dstaddr)
195 		, .brd = BUFPARAM(in_ifra.ifra_broadaddr)
196 		, .mask = BUFPARAM(in_ifra.ifra_mask)
197 		, .aifaddr = IFADDR_PARAM(SIOCAIFADDR)
198 		, .difaddr = IFADDR_PARAM(SIOCDIFADDR)
199 		, .gifaddr = IFADDR_PARAM(SIOCGIFADDR)
200 		, .defmask = {.buf = NULL, .buflen = 0}
201 	};
202 	memset(&in_ifr, 0, sizeof(in_ifr));
203 	memset(&in_ifra, 0, sizeof(in_ifra));
204 	commit_address(env, oenv, &inparam);
205 }
206 
207 #ifdef SIOCGIFAFLAG_IN
208 static bool
209 in_addr_flags(struct ifaddrs *ifa, int flags)
210 {
211 	int s;
212 	struct ifreq ifr;
213 
214 	memset(&ifr, 0, sizeof(ifr));
215 	estrlcpy(ifr.ifr_name, ifa->ifa_name, sizeof(ifr.ifr_name));
216 	ifr.ifr_addr = *ifa->ifa_addr;
217 	if ((s = getsock(AF_INET)) == -1)
218 		err(EXIT_FAILURE, "%s: getsock", __func__);
219 	if (prog_ioctl(s, SIOCGIFAFLAG_IN, &ifr) == -1)
220 		err(EXIT_FAILURE, "SIOCGIFAFLAG_IN");
221 	return ifr.ifr_addrflags & flags ? true : false;
222 	return false;
223 }
224 #endif
225 
226 static bool
227 in_addr_tentative(struct ifaddrs *ifa)
228 {
229 
230 #ifdef SIOCGIFAFLAG_IN
231 	return in_addr_flags(ifa, IN_IFF_TENTATIVE);
232 #else
233 	return false;
234 #endif
235 }
236 
237 static bool
238 in_addr_tentative_or_detached(struct ifaddrs *ifa)
239 {
240 
241 #ifdef SIOCGIFAFLAG_IN
242 	return in_addr_flags(ifa, IN_IFF_TENTATIVE | IN_IFF_DETACHED);
243 #else
244 	return false;
245 #endif
246 }
247 
248 static void
249 in_constructor(void)
250 {
251 	register_family(&af);
252 }
253