xref: /netbsd-src/sbin/ifconfig/util.c (revision 10ad5ffa714ce1a679dcc9dd8159648df2d67b5a)
1 /*	$NetBSD: util.c,v 1.11 2009/04/27 20:10:49 dyoung Exp $	*/
2 
3 /*-
4  * Copyright (c) 2008 David Young.  All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27 
28 #include <sys/cdefs.h>
29 #ifndef lint
30 __RCSID("$NetBSD: util.c,v 1.11 2009/04/27 20:10:49 dyoung Exp $");
31 #endif /* not lint */
32 
33 #include <ctype.h>
34 #include <err.h>
35 #include <errno.h>
36 #include <netdb.h>
37 #include <stddef.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <unistd.h>
42 #include <util.h>
43 
44 #include <sys/param.h>
45 #include <sys/types.h>
46 #include <sys/socket.h>
47 #include <ifaddrs.h>
48 
49 #include <sys/ioctl.h>
50 #include <net/if.h>
51 #include <net/if_dl.h>
52 #include <netinet/in.h>		/* XXX */
53 
54 #include "env.h"
55 #include "util.h"
56 
57 int
58 getsock(int naf)
59 {
60 	static int oaf = -1, s;
61 
62 	if (oaf == naf || (oaf != -1 && naf == AF_UNSPEC))
63 		return s;
64 
65 	if (oaf != -1)
66 		close(s);
67 
68 	if (naf == AF_UNSPEC)
69 		naf = AF_INET;
70 
71 	s = socket(naf, SOCK_DGRAM, 0);
72 	if (s == -1)
73 		oaf = -1;
74 	else
75 		oaf = naf;
76 	return s;
77 }
78 
79 const char *
80 get_string(const char *val, const char *sep, u_int8_t *buf, int *lenp)
81 {
82 	int len;
83 	bool hexstr;
84 	u_int8_t *p;
85 
86 	len = *lenp;
87 	p = buf;
88 	hexstr = (val[0] == '0' && tolower((u_char)val[1]) == 'x');
89 	if (hexstr)
90 		val += 2;
91 	for (;;) {
92 		if (*val == '\0')
93 			break;
94 		if (sep != NULL && strchr(sep, *val) != NULL) {
95 			val++;
96 			break;
97 		}
98 		if (hexstr) {
99 			if (!isxdigit((u_char)val[0]) ||
100 			    !isxdigit((u_char)val[1])) {
101 				warnx("bad hexadecimal digits");
102 				return NULL;
103 			}
104 		}
105 		if (p > buf + len) {
106 			if (hexstr)
107 				warnx("hexadecimal digits too long");
108 			else
109 				warnx("strings too long");
110 			return NULL;
111 		}
112 		if (hexstr) {
113 #define	tohex(x)	(isdigit(x) ? (x) - '0' : tolower(x) - 'a' + 10)
114 			*p++ = (tohex((u_char)val[0]) << 4) |
115 			    tohex((u_char)val[1]);
116 #undef tohex
117 			val += 2;
118 		} else
119 			*p++ = *val++;
120 	}
121 	len = p - buf;
122 	if (len < *lenp)
123 		memset(p, 0, *lenp - len);
124 	*lenp = len;
125 	return val;
126 }
127 
128 void
129 print_string(const u_int8_t *buf, int len)
130 {
131 	int i;
132 	bool hasspc;
133 
134 	i = 0;
135 	hasspc = false;
136 	if (len < 2 || buf[0] != '0' || tolower(buf[1]) != 'x') {
137 		for (; i < len; i++) {
138 			if (!isprint(buf[i]))
139 				break;
140 			if (isspace(buf[i]))
141 				hasspc = true;
142 		}
143 	}
144 	if (i == len) {
145 		if (hasspc || len == 0)
146 			printf("\"%.*s\"", len, buf);
147 		else
148 			printf("%.*s", len, buf);
149 	} else {
150 		printf("0x");
151 		for (i = 0; i < len; i++)
152 			printf("%02x", buf[i]);
153 	}
154 }
155 
156 struct paddr_prefix *
157 prefixlen_to_mask(int af, int plen)
158 {
159 	union {
160 		struct sockaddr sa;
161 		struct sockaddr_in sin;
162 		struct sockaddr_in6 sin6;
163 	} u;
164 	struct paddr_prefix *pfx;
165 	size_t addrlen;
166 	uint8_t *addr;
167 	int nbit;
168 
169 	memset(&u, 0, sizeof(u));
170 
171 	switch (af) {
172 	case AF_INET:
173 		addrlen = sizeof(u.sin.sin_addr);
174 		addr = (uint8_t *)&u.sin.sin_addr;
175 		u.sa.sa_len = sizeof(u.sin);
176 		break;
177 	case AF_INET6:
178 		addrlen = sizeof(u.sin6.sin6_addr);
179 		addr = (uint8_t *)&u.sin6.sin6_addr;
180 		u.sa.sa_len = sizeof(u.sin6);
181 		break;
182 	default:
183 		errno = EINVAL;
184 		return NULL;
185 	}
186 	u.sa.sa_family = af;
187 
188 	if (plen < 0 || (size_t)plen > addrlen * NBBY) {
189 		errno = EINVAL;
190 		return NULL;
191 	}
192 
193 	if (plen == 0)
194 		plen = addrlen * NBBY;
195 
196 	memset(addr, 0xff, (plen + NBBY - 1) / NBBY);
197 
198 	nbit = plen % NBBY;
199 	if (nbit != 0)
200 		addr[plen / NBBY] &= ~((uint8_t)0xff >> nbit);
201 	pfx = malloc(offsetof(struct paddr_prefix, pfx_addr) + u.sa.sa_len);
202 	if (pfx == NULL)
203 		return NULL;
204 	pfx->pfx_len = plen;
205 	memcpy(&pfx->pfx_addr, &u.sa, u.sa.sa_len);
206 
207 	return pfx;
208 }
209 
210 int
211 direct_ioctl(prop_dictionary_t env, unsigned long cmd, void *data)
212 {
213 	const char *ifname;
214 	int s;
215 
216 	if ((s = getsock(AF_UNSPEC)) == -1)
217 		err(EXIT_FAILURE, "getsock");
218 
219 	if ((ifname = getifname(env)) == NULL)
220 		err(EXIT_FAILURE, "getifname");
221 
222 	estrlcpy(data, ifname, IFNAMSIZ);
223 
224 	return ioctl(s, cmd, data);
225 }
226 
227 int
228 indirect_ioctl(prop_dictionary_t env, unsigned long cmd, void *data)
229 {
230 	struct ifreq ifr;
231 
232 	memset(&ifr, 0, sizeof(ifr));
233 
234 	ifr.ifr_data = data;
235 
236 	return direct_ioctl(env, cmd, &ifr);
237 }
238 
239 void
240 print_link_addresses(prop_dictionary_t env, bool print_active_only)
241 {
242 	char hbuf[NI_MAXHOST];
243 	const char *ifname;
244 	int s;
245 	struct ifaddrs *ifa, *ifap;
246 	const struct sockaddr_dl *sdl;
247 	struct if_laddrreq iflr;
248 
249 	if ((ifname = getifname(env)) == NULL)
250 		err(EXIT_FAILURE, "%s: getifname", __func__);
251 
252 	if ((s = getsock(AF_LINK)) == -1)
253 		err(EXIT_FAILURE, "%s: getsock", __func__);
254 
255 	if (getifaddrs(&ifap) == -1)
256 		err(EXIT_FAILURE, "%s: getifaddrs", __func__);
257 
258 	memset(&iflr, 0, sizeof(iflr));
259 
260 	strlcpy(iflr.iflr_name, ifname, sizeof(iflr.iflr_name));
261 
262 	for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
263 		if (strcmp(ifname, ifa->ifa_name) != 0)
264 			continue;
265 		if (ifa->ifa_addr->sa_family != AF_LINK)
266 			continue;
267 
268 		sdl = satocsdl(ifa->ifa_addr);
269 
270 		memcpy(&iflr.addr, ifa->ifa_addr, MIN(ifa->ifa_addr->sa_len,
271 		    sizeof(iflr.addr)));
272 		iflr.flags = IFLR_PREFIX;
273 		iflr.prefixlen = sdl->sdl_alen * NBBY;
274 
275 		if (ioctl(s, SIOCGLIFADDR, &iflr) == -1)
276 			err(EXIT_FAILURE, "%s: ioctl", __func__);
277 
278 		if (((iflr.flags & IFLR_ACTIVE) != 0) != print_active_only)
279 			continue;
280 
281 		if (getnameinfo(ifa->ifa_addr, ifa->ifa_addr->sa_len,
282 			hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) == 0 &&
283 		    hbuf[0] != '\0') {
284 			printf("\t%s %s\n",
285 			    print_active_only ? "address:" : "link", hbuf);
286 		}
287 	}
288 	freeifaddrs(ifap);
289 }
290 
291 #ifdef INET6
292 /* KAME idiosyncrasy */
293 void
294 in6_fillscopeid(struct sockaddr_in6 *sin6)
295 {
296 	if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
297 		sin6->sin6_scope_id =
298 			ntohs(*(u_int16_t *)&sin6->sin6_addr.s6_addr[2]);
299 		sin6->sin6_addr.s6_addr[2] = sin6->sin6_addr.s6_addr[3] = 0;
300 	}
301 }
302 #endif /* INET6	*/
303