1 /*-
2  * Copyright (c) 2013 Antti Kantee <pooka@iki.fi>
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
14  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23  * SUCH DAMAGE.
24  */
25 
26 #include <sys/param.h>
27 #include <sys/kernel.h>
28 #include <sys/socketvar.h>
29 
30 #include <net/if.h>
31 #include <net/if_dl.h>
32 #include <net/if_ether.h>
33 #include <net/if_bridgevar.h>
34 #include <net/if_types.h>
35 #include <net/route.h>
36 
37 #include <netinet/in.h>
38 #include <netinet/icmp6.h>
39 
40 #include <netinet6/in6.h>
41 #include <netinet6/in6_var.h>
42 #include <netinet6/ip6_var.h>
43 #include <netinet6/nd6.h>
44 #include <netinet6/scope6_var.h>
45 
46 #include "rump_private.h"
47 
48 #include "netconfig_if_priv.h"
49 #include "netconfig_private.h"
50 
51 static struct socket *in4so;
52 static struct socket *in6so;
53 static struct socket *rtso;
54 
55 #define CHECKDOMAIN(dom) if (!(dom)) return EAFNOSUPPORT
56 
57 static int
wrapifioctl(struct socket * so,u_long cmd,void * data)58 wrapifioctl(struct socket *so, u_long cmd, void *data)
59 {
60 	int rv;
61 
62 	KERNEL_LOCK(1, NULL);
63 	rv = ifioctl(so, cmd, data, curlwp);
64 	KERNEL_UNLOCK_ONE(NULL);
65 
66 	return rv;
67 }
68 
69 int
rump_netconfig_ifcreate(const char * ifname)70 rump_netconfig_ifcreate(const char *ifname)
71 {
72 	struct ifreq ifr;
73 
74 	memset(&ifr, 0, sizeof(ifr));
75 	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
76 	return wrapifioctl(in4so, SIOCIFCREATE, &ifr);
77 }
78 
79 static void
addup(short * fp)80 addup(short *fp)
81 {
82 
83 	*fp |= IFF_UP;
84 }
85 
86 static void
remup(short * fp)87 remup(short *fp)
88 {
89 
90 	*fp &= ~IFF_UP;
91 }
92 
93 static int
chflag(const char * ifname,void (* edflag)(short *))94 chflag(const char *ifname, void (*edflag)(short *))
95 {
96 	struct ifreq ifr;
97 	int rv;
98 
99 	memset(&ifr, 0, sizeof(ifr));
100 	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
101 	if ((rv = wrapifioctl(in4so, SIOCGIFFLAGS, &ifr)) != 0)
102 		return rv;
103 	edflag(&ifr.ifr_flags);
104 
105 	return wrapifioctl(in4so, SIOCSIFFLAGS, &ifr);
106 }
107 
108 int
rump_netconfig_ifup(const char * ifname)109 rump_netconfig_ifup(const char *ifname)
110 {
111 
112 	return chflag(ifname, addup);
113 }
114 
115 int
rump_netconfig_ifdown(const char * ifname)116 rump_netconfig_ifdown(const char *ifname)
117 {
118 
119 	return chflag(ifname, remup);
120 }
121 
122 int
rump_netconfig_ifsetlinkstr(const char * ifname,const char * linkstr)123 rump_netconfig_ifsetlinkstr(const char *ifname, const char *linkstr)
124 {
125 	struct ifdrv ifd;
126 
127 	memset(&ifd, 0, sizeof(ifd));
128 	strlcpy(ifd.ifd_name, ifname, sizeof(ifd.ifd_name));
129 	ifd.ifd_cmd = 0;
130 	ifd.ifd_data = __UNCONST(linkstr);
131 	ifd.ifd_len = strlen(linkstr)+1;
132 
133 	return wrapifioctl(in4so, SIOCSLINKSTR, &ifd);
134 }
135 
136 int
rump_netconfig_ifdestroy(const char * ifname)137 rump_netconfig_ifdestroy(const char *ifname)
138 {
139 	struct ifreq ifr;
140 
141 	memset(&ifr, 0, sizeof(ifr));
142 	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
143 	return wrapifioctl(in4so, SIOCIFDESTROY, &ifr);
144 }
145 
146 /*
147  * network bridge manipulation (bridge is created with ifbridge)
148  */
149 
150 static int
brioctl(const char * bridgename,const char * ifname,unsigned long op)151 brioctl(const char *bridgename, const char *ifname, unsigned long op)
152 {
153 	struct ifdrv ifd;
154 	struct ifbreq req;
155 
156 	memset(&req, 0, sizeof(req));
157 	strlcpy(req.ifbr_ifsname, ifname, sizeof(req.ifbr_ifsname));
158 
159 	memset(&ifd, 0, sizeof(ifd));
160 	strlcpy(ifd.ifd_name, bridgename, sizeof(ifd.ifd_name));
161 	ifd.ifd_cmd = op;
162 	ifd.ifd_len = sizeof(req);
163 	ifd.ifd_data = &req;
164 
165 
166 	return wrapifioctl(in4so, SIOCSDRVSPEC, &ifd);
167 }
168 
169 int
rump_netconfig_bradd(const char * bridgename,const char * ifname)170 rump_netconfig_bradd(const char *bridgename, const char *ifname)
171 {
172 
173 	return brioctl(bridgename, ifname, BRDGADD);
174 }
175 
176 int
rump_netconfig_brdel(const char * bridgename,const char * ifname)177 rump_netconfig_brdel(const char *bridgename, const char *ifname)
178 {
179 
180 	return brioctl(bridgename, ifname, BRDGDEL);
181 }
182 
183 static int
cfg_ipv4(const char * ifname,const char * addr,in_addr_t m_addr)184 cfg_ipv4(const char *ifname, const char *addr, in_addr_t m_addr)
185 {
186 	struct ifaliasreq ia;
187 	struct sockaddr_in *sin;
188 	int rv;
189 
190 	CHECKDOMAIN(in4so);
191 
192 	memset(&ia, 0, sizeof(ia));
193 	strlcpy(ia.ifra_name, ifname, sizeof(ia.ifra_name));
194 
195 	sin = (struct sockaddr_in *)&ia.ifra_addr;
196 	sin->sin_family = AF_INET;
197 	sin->sin_len = sizeof(*sin);
198 	sin->sin_addr.s_addr = inet_addr(addr);
199 
200 	sin = (struct sockaddr_in *)&ia.ifra_mask;
201 	sin->sin_family = AF_INET;
202 	sin->sin_len = sizeof(*sin);
203 	sin->sin_addr.s_addr = m_addr;
204 
205 	sin = (struct sockaddr_in *)&ia.ifra_broadaddr;
206 	sin->sin_family = AF_INET;
207 	sin->sin_len = sizeof(*sin);
208 	sin->sin_addr.s_addr = inet_addr(addr) | ~m_addr;
209 
210 	rv = wrapifioctl(in4so, SIOCAIFADDR, &ia);
211 	/*
212 	 * small pause so that we can assume interface is usable when
213 	 * we return (ARPs have trickled through, etc.)
214 	 */
215 	if (rv == 0)
216 		kpause("ramasee", false, mstohz(50), NULL);
217 	return rv;
218 }
219 
220 int
rump_netconfig_ipv4_ifaddr(const char * ifname,const char * addr,const char * mask)221 rump_netconfig_ipv4_ifaddr(const char *ifname, const char *addr,
222 	const char *mask)
223 {
224 
225 	return cfg_ipv4(ifname, addr, inet_addr(mask));
226 }
227 
228 int
rump_netconfig_ipv4_ifaddr_cidr(const char * ifname,const char * addr,int mask)229 rump_netconfig_ipv4_ifaddr_cidr(const char *ifname, const char *addr,
230 	int mask)
231 {
232 
233 	if (mask < 0 || mask > 32)
234 		return EINVAL;
235 	return cfg_ipv4(ifname, addr, htonl(~0U<<(32-mask)));
236 }
237 
238 int
rump_netconfig_ipv6_ifaddr(const char * ifname,const char * addr,int prefixlen)239 rump_netconfig_ipv6_ifaddr(const char *ifname, const char *addr, int prefixlen)
240 {
241 	struct sockaddr_in6 *sin6;
242 	struct in6_aliasreq ia;
243 	int rv;
244 
245 	CHECKDOMAIN(in6so);
246 
247 	/* pfft, you do the bitnibbling */
248 	if (prefixlen % 8)
249 		return EINVAL;
250 
251 	memset(&ia, 0, sizeof(ia));
252 	strlcpy(ia.ifra_name, ifname, sizeof(ia.ifra_name));
253 
254 	ia.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
255 	ia.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
256 
257 	sin6 = (struct sockaddr_in6 *)&ia.ifra_addr;
258 	sin6->sin6_family = AF_INET6;
259 	sin6->sin6_len = sizeof(*sin6);
260 	netconfig_inet_pton6(addr, &sin6->sin6_addr);
261 
262 	sin6 = (struct sockaddr_in6 *)&ia.ifra_prefixmask;
263 	sin6->sin6_family = AF_INET6;
264 	sin6->sin6_len = sizeof(*sin6);
265 	memset(&sin6->sin6_addr, 0, sizeof(sin6->sin6_addr));
266 	memset(&sin6->sin6_addr, 0xff, prefixlen / 8);
267 
268 	rv = wrapifioctl(in6so, SIOCAIFADDR_IN6, &ia);
269 	/*
270 	 * small pause so that we can assume interface is usable when
271 	 * we return (ARPs have trickled through, etc.)
272 	 */
273 	if (rv == 0)
274 		kpause("ramasee", false, mstohz(50), NULL);
275 	return rv;
276 }
277 
278 int
rump_netconfig_ipv4_gw(const char * gwaddr)279 rump_netconfig_ipv4_gw(const char *gwaddr)
280 {
281 	struct rt_msghdr rtm, *rtmp;
282 	struct sockaddr_in sin;
283 	struct mbuf *m;
284 	int off, rv;
285 
286 	CHECKDOMAIN(in4so);
287 
288 	memset(&rtm, 0, sizeof(rtm));
289 	rtm.rtm_type = RTM_ADD;
290 	rtm.rtm_flags = RTF_UP | RTF_STATIC | RTF_GATEWAY;
291 	rtm.rtm_version = RTM_VERSION;
292 	rtm.rtm_seq = 2;
293 	rtm.rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
294 
295 	m = m_gethdr(M_WAIT, MT_DATA);
296 	m->m_pkthdr.len = 0;
297 	m_copyback(m, 0, sizeof(rtm), &rtm);
298 	off = sizeof(rtm);
299 
300 	/* dest */
301 	memset(&sin, 0, sizeof(sin));
302 	sin.sin_family = AF_INET;
303 	sin.sin_len = sizeof(sin);
304 	m_copyback(m, off, sin.sin_len, &sin);
305 	RT_ADVANCE(off, (struct sockaddr *)&sin);
306 
307 	/* gw */
308 	sin.sin_addr.s_addr = inet_addr(gwaddr);
309 	m_copyback(m, off, sin.sin_len, &sin);
310 	RT_ADVANCE(off, (struct sockaddr *)&sin);
311 
312 	/* mask */
313 	sin.sin_addr.s_addr = 0;
314 	m_copyback(m, off, sin.sin_len, &sin);
315 	RT_ADVANCE(off, (struct sockaddr *)&sin);
316 
317 	m = m_pullup(m, sizeof(*rtmp));
318 	rtmp = mtod(m, struct rt_msghdr *);
319 	m->m_pkthdr.len = rtmp->rtm_msglen = off;
320 
321 	solock(rtso);
322 #if __NetBSD_Prereq__(7,99,26)
323 	rv = rtso->so_proto->pr_usrreqs->pr_send(rtso, m, NULL, NULL, curlwp);
324 #else
325 	rv = rtso->so_proto->pr_output(m, rtso);
326 #endif
327 	sounlock(rtso);
328 
329 	return rv;
330 }
331 
332 int
rump_netconfig_ipv6_gw(const char * gwaddr)333 rump_netconfig_ipv6_gw(const char *gwaddr)
334 {
335 	struct rt_msghdr rtm, *rtmp;
336 	struct sockaddr_in6 sin6;
337 	struct mbuf *m;
338 	int off, rv;
339 
340 	CHECKDOMAIN(in6so);
341 
342 	memset(&rtm, 0, sizeof(rtm));
343 	rtm.rtm_type = RTM_ADD;
344 	rtm.rtm_flags = RTF_UP | RTF_STATIC | RTF_GATEWAY;
345 	rtm.rtm_version = RTM_VERSION;
346 	rtm.rtm_seq = 2;
347 	rtm.rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
348 
349 	m = m_gethdr(M_WAIT, MT_DATA);
350 	m->m_pkthdr.len = 0;
351 	m_copyback(m, 0, sizeof(rtm), &rtm);
352 	off = sizeof(rtm);
353 
354 	/* dest */
355 	memset(&sin6, 0, sizeof(sin6));
356 	sin6.sin6_family = AF_INET6;
357 	sin6.sin6_len = sizeof(sin6);
358 	m_copyback(m, off, sin6.sin6_len, &sin6);
359 	RT_ADVANCE(off, (struct sockaddr *)&sin6);
360 
361 	/* gw */
362 	netconfig_inet_pton6(gwaddr, &sin6.sin6_addr);
363 	m_copyback(m, off, sin6.sin6_len, &sin6);
364 	RT_ADVANCE(off, (struct sockaddr *)&sin6);
365 
366 	/* mask */
367 	memset(&sin6.sin6_addr, 0, sizeof(sin6.sin6_addr));
368 	m_copyback(m, off, sin6.sin6_len, &sin6);
369 	off = m->m_pkthdr.len;
370 
371 	m = m_pullup(m, sizeof(*rtmp));
372 	rtmp = mtod(m, struct rt_msghdr *);
373 	rtmp->rtm_msglen = off;
374 
375 	solock(rtso);
376 #if __NetBSD_Prereq__(7,99,26)
377 	rv = rtso->so_proto->pr_usrreqs->pr_send(rtso, m, NULL, NULL, curlwp);
378 #else
379 	rv = rtso->so_proto->pr_output(m, rtso);
380 #endif
381 	sounlock(rtso);
382 
383 	return rv;
384 }
385 
386 /* Perform IPv6 autoconfiguration for the specified interface.
387  * This function sets the kernel to accept IPv6 RAs on all interfaces,
388  * brings the interface up and sends a single IPv6 RS packet to the
389  * all-routers multicast address from the specified interface. No attempt is
390  * made to check whether or not this actually provoked an RA in response.
391  */
392 
393 int
rump_netconfig_auto_ipv6(const char * ifname)394 rump_netconfig_auto_ipv6(const char *ifname)
395 {
396 	struct ifnet *ifp;
397 	int ifindex;
398 	struct socket *rsso = NULL;
399 	int rv = 0;
400 	int hoplimit = 255;
401 	struct mbuf *m_nam = NULL,
402 		    *m_outbuf = NULL;
403 	struct sockaddr_in6 *sin6;
404 	char *buf;
405 	struct nd_router_solicit rs;
406 	struct nd_opt_hdr opt;
407 
408 	ifp = ifunit(ifname);
409 	if (ifp == NULL) {
410 		rv = ENXIO;
411 		goto out;
412 	}
413 	if (ifp->if_sadl->sdl_type != IFT_ETHER) {
414 		rv = EINVAL;
415 		goto out;
416 	}
417 
418 	rv = socreate(PF_INET6, &rsso, SOCK_RAW, IPPROTO_ICMPV6, curlwp, NULL);
419 	if (rv != 0)
420 		goto out;
421 	ifindex = ifp->if_index;
422 	rv = so_setsockopt(curlwp, rsso, IPPROTO_IPV6, IPV6_MULTICAST_IF,
423 			&ifindex, sizeof ifindex);
424 	if (rv != 0)
425 		goto out;
426 	rv = so_setsockopt(curlwp, rsso, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
427 			&hoplimit, sizeof hoplimit);
428 	if (rv != 0)
429 		goto out;
430 
431 	m_nam = m_get(M_WAIT, MT_SONAME);
432 	sin6 = mtod(m_nam, struct sockaddr_in6 *);
433 	sin6->sin6_len = m_nam->m_len = sizeof (*sin6);
434 	sin6->sin6_family = AF_INET6;
435 	netconfig_inet_pton6("ff02::2", &sin6->sin6_addr);
436 
437 #define rslen (sizeof rs + sizeof opt + ETHER_ADDR_LEN)
438 	CTASSERT(rslen <= MCLBYTES);
439 	m_outbuf = m_gethdr(M_WAIT, MT_DATA);
440 	m_clget(m_outbuf, M_WAIT);
441 	m_outbuf->m_pkthdr.len = m_outbuf->m_len = rslen;
442 
443 
444 #if __NetBSD_Prereq__(7,99,31)
445 	m_set_rcvif(m_outbuf, NULL);
446 #else
447 	m_outbuf->m_pkthdr.rcvif = NULL;
448 #endif
449 
450 #undef rslen
451 	buf = mtod(m_outbuf, char *);
452 	memset(&rs, 0, sizeof rs);
453 	rs.nd_rs_type = ND_ROUTER_SOLICIT;
454 	memset(&opt, 0, sizeof opt);
455 	opt.nd_opt_type = ND_OPT_SOURCE_LINKADDR;
456 	opt.nd_opt_len = 1; /* units of 8 octets */
457 	memcpy(buf, &rs, sizeof rs);
458 	buf += sizeof rs;
459 	memcpy(buf, &opt, sizeof opt);
460 	buf += sizeof opt;
461 	memcpy(buf, CLLADDR(ifp->if_sadl), ETHER_ADDR_LEN);
462 
463 	ip6_accept_rtadv = 1;
464 	rv = rump_netconfig_ifup(ifname);
465 	if (rv != 0)
466 		goto out;
467 #if __NetBSD_Prereq__(7,99,12)
468 	rv = (*rsso->so_send)(rsso, (struct sockaddr *)sin6, NULL, m_outbuf,
469 			NULL, 0, curlwp);
470 #else
471 	rv = (*rsso->so_send)(rsso, m_nam, NULL, m_outbuf, NULL, 0, curlwp);
472 #endif
473 	if (rv == 0)
474 		/* *(so_send)() takes ownership of m_outbuf on success */
475 		m_outbuf = NULL;
476 	else
477 		goto out;
478 
479 	rv = 0;
480 out:
481 	if (m_nam)
482 		m_freem(m_nam);
483 	if (m_outbuf)
484 		m_freem(m_outbuf);
485 	if (rsso)
486 		soclose(rsso);
487 	return rv;
488 }
489 
RUMP_COMPONENT(RUMP_COMPONENT_NET_IFCFG)490 RUMP_COMPONENT(RUMP_COMPONENT_NET_IFCFG)
491 {
492 	int rv;
493 
494 	socreate(PF_INET, &in4so, SOCK_DGRAM, 0, curlwp, NULL);
495 	socreate(PF_INET6, &in6so, SOCK_DGRAM, 0, curlwp, NULL);
496 
497 	if (!in4so && !in6so)
498 		panic("netconfig: missing both inet and inet6");
499 	if ((rv = socreate(PF_ROUTE, &rtso, SOCK_RAW, 0, curlwp, NULL)) != 0)
500 		panic("netconfig socreate route: %d", rv);
501 }
502