xref: /illumos-gate/usr/src/cmd/cmd-inet/lib/nwamd/routing_events.c (revision e4d060fb4c00d44cd578713eb9a921f594b733b8)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #include <arpa/inet.h>
28 #include <assert.h>
29 #include <errno.h>
30 #include <fcntl.h>
31 #include <net/if.h>
32 #include <net/route.h>
33 #include <pthread.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <strings.h>
38 #include <sys/fcntl.h>
39 #include <unistd.h>
40 
41 #include <inetcfg.h>
42 #include <libnwam.h>
43 #include "events.h"
44 #include "ncp.h"
45 #include "ncu.h"
46 #include "util.h"
47 
48 /*
49  * routing_events.c - this file contains routines to retrieve routing socket
50  * events and package them for high level processing.
51  */
52 
53 #define	RTMBUFSZ	sizeof (struct rt_msghdr) + \
54 			(RTAX_MAX * sizeof (struct sockaddr_storage))
55 
56 static void printaddrs(int, void *);
57 static char *printaddr(void **);
58 static void *getaddr(int, int, void *);
59 static void setaddr(int, int *, void *, struct sockaddr *);
60 
61 union rtm_buf
62 {
63 	/* Routing information. */
64 	struct
65 	{
66 		struct rt_msghdr rtm;
67 		struct sockaddr_storage addr[RTAX_MAX];
68 	} r;
69 
70 	/* Interface information. */
71 	struct
72 	{
73 		struct if_msghdr ifm;
74 		struct sockaddr_storage addr[RTAX_MAX];
75 	} im;
76 
77 	/* Interface address information. */
78 	struct
79 	{
80 		struct ifa_msghdr ifa;
81 		struct sockaddr_storage addr[RTAX_MAX];
82 	} ia;
83 };
84 
85 static int v4_sock = -1;
86 static int v6_sock = -1;
87 static pthread_t v4_routing, v6_routing;
88 static int seq = 0;
89 
90 static const char *
91 rtmtype_str(int type)
92 {
93 	static char typestr[12]; /* strlen("type ") + enough for an int */
94 
95 	switch (type) {
96 	case RTM_NEWADDR:
97 		return ("NEWADDR");
98 	case RTM_DELADDR:
99 		return ("DELADDR");
100 	case RTM_CHGADDR:
101 		return ("CHGADDR");
102 	case RTM_FREEADDR:
103 		return ("FREEADDR");
104 	case RTM_IFINFO:
105 		return ("IFINFO");
106 	default:
107 		(void) snprintf(typestr, sizeof (typestr), "type %d", type);
108 		return (typestr);
109 	}
110 }
111 
112 /* ARGSUSED0 */
113 static void *
114 routing_events_v4(void *arg)
115 {
116 	int n;
117 	union rtm_buf buffer;
118 	struct rt_msghdr *rtm;
119 	struct ifa_msghdr *ifa;
120 	struct if_msghdr *ifm;
121 	char *addrs, *if_name;
122 	struct sockaddr_dl *addr_dl;
123 	struct sockaddr *addr;
124 	nwamd_event_t ip_event;
125 
126 	nlog(LOG_DEBUG, "v4 routing socket %d", v4_sock);
127 
128 	for (;;) {
129 		rtm = &buffer.r.rtm;
130 		n = read(v4_sock, &buffer, sizeof (buffer));
131 		if (n == -1 && errno == EAGAIN) {
132 			continue;
133 		} else if (n == -1) {
134 			nlog(LOG_ERR, "error reading routing socket "
135 			    "%d: %m", v4_sock);
136 			/* Low likelihood.  What's recovery path?  */
137 			continue;
138 		}
139 
140 		if (rtm->rtm_msglen < n) {
141 			nlog(LOG_ERR, "only read %d bytes from "
142 			    "routing socket but message claims to be "
143 			    "of length %d", rtm->rtm_msglen);
144 			continue;
145 		}
146 
147 		if (rtm->rtm_version != RTM_VERSION) {
148 			nlog(LOG_ERR, "tossing routing message of "
149 			    "version %d type %d", rtm->rtm_version,
150 			    rtm->rtm_type);
151 			continue;
152 		}
153 
154 		if (rtm->rtm_msglen != n) {
155 			nlog(LOG_DEBUG, "routing message of %d size came from "
156 			    "read of %d on socket %d", rtm->rtm_msglen,
157 			    n, v4_sock);
158 		}
159 
160 		switch (rtm->rtm_type) {
161 		case RTM_NEWADDR:
162 		case RTM_DELADDR:
163 		case RTM_CHGADDR:
164 		case RTM_FREEADDR:
165 
166 			ifa = (void *)rtm;
167 			addrs = (char *)ifa + sizeof (*ifa);
168 
169 			nlog(LOG_DEBUG, "v4 routing message %s: "
170 			    "index %d flags %x", rtmtype_str(rtm->rtm_type),
171 			    ifa->ifam_index, ifa->ifam_flags);
172 			printaddrs(ifa->ifam_addrs, addrs);
173 
174 			if ((addr = (struct sockaddr *)getaddr(RTA_IFA,
175 			    ifa->ifam_addrs, addrs)) == NULL)
176 				break;
177 
178 			/* Ignore routing socket messages for 0.0.0.0 */
179 			/*LINTED*/
180 			if (((struct sockaddr_in *)addr)->sin_addr.s_addr
181 			    == INADDR_ANY) {
182 				nlog(LOG_DEBUG, "routing_events_v4: "
183 				    "tossing message for 0.0.0.0");
184 				break;
185 			}
186 
187 			if ((addr_dl = (struct sockaddr_dl *)getaddr
188 			    (RTA_IFP, ifa->ifam_addrs, addrs)) == NULL)
189 				break;
190 			/*
191 			 * We don't use the lladdr in this structure so we can
192 			 * run over it.
193 			 */
194 			addr_dl->sdl_data[addr_dl->sdl_nlen] = 0;
195 			if_name = addr_dl->sdl_data; /* no lifnum */
196 
197 			if (ifa->ifam_index == 0) {
198 				nlog(LOG_DEBUG, "tossing index 0 message");
199 				break;
200 			}
201 			if (ifa->ifam_type != rtm->rtm_type) {
202 				nlog(LOG_INFO,
203 				    "routing_events_v4: unhandled type %d",
204 				    ifa->ifam_type);
205 				break;
206 			}
207 
208 			/* Create and enqueue IF_STATE event */
209 			ip_event = nwamd_event_init_if_state(if_name,
210 			    ifa->ifam_flags,
211 			    (rtm->rtm_type == RTM_NEWADDR ||
212 			    rtm->rtm_type == RTM_CHGADDR ? B_TRUE : B_FALSE),
213 			    ifa->ifam_index, addr);
214 			if (ip_event != NULL)
215 				nwamd_event_enqueue(ip_event);
216 			break;
217 
218 		case RTM_IFINFO:
219 
220 			ifm = (void *)rtm;
221 			addrs = (char *)ifm + sizeof (*ifm);
222 			nlog(LOG_DEBUG, "v4 routing message %s: "
223 			    "index %d flags %x", rtmtype_str(rtm->rtm_type),
224 			    ifm->ifm_index, ifm->ifm_flags);
225 			printaddrs(ifm->ifm_addrs, addrs);
226 
227 			if ((addr_dl = (struct sockaddr_dl *)getaddr(RTA_IFP,
228 			    ifm->ifm_addrs, addrs)) == NULL)
229 				break;
230 			/*
231 			 * We don't use the lladdr in this structure so we can
232 			 * run over it.
233 			 */
234 			addr_dl->sdl_data[addr_dl->sdl_nlen] = 0;
235 			if_name = addr_dl->sdl_data; /* no lifnum */
236 
237 			if (ifm->ifm_index == 0) {
238 				nlog(LOG_DEBUG, "tossing index 0 message");
239 				break;
240 			}
241 			if (ifm->ifm_type != RTM_IFINFO) {
242 				nlog(LOG_DEBUG,
243 				    "routing_events_v4: unhandled type %d",
244 				    ifm->ifm_type);
245 				break;
246 			}
247 
248 			/* Create and enqueue IF_STATE event */
249 			ip_event = nwamd_event_init_if_state(if_name,
250 			    ifm->ifm_flags, B_FALSE, ifm->ifm_index, NULL);
251 			if (ip_event != NULL)
252 				nwamd_event_enqueue(ip_event);
253 			break;
254 
255 		default:
256 			nlog(LOG_DEBUG, "v4 routing message %s discarded",
257 			    rtmtype_str(rtm->rtm_type));
258 			break;
259 		}
260 	}
261 	/* NOTREACHED */
262 	return (NULL);
263 }
264 
265 /* ARGSUSED0 */
266 static void *
267 routing_events_v6(void *arg)
268 {
269 	int n;
270 	union rtm_buf buffer;
271 	struct rt_msghdr *rtm;
272 	struct ifa_msghdr *ifa;
273 	struct if_msghdr *ifm;
274 	char *addrs, *if_name;
275 	struct sockaddr_dl *addr_dl;
276 	struct sockaddr *addr;
277 	nwamd_event_t ip_event;
278 
279 	nlog(LOG_DEBUG, "v6 routing socket %d", v6_sock);
280 
281 	for (;;) {
282 
283 		rtm = &buffer.r.rtm;
284 		n = read(v6_sock, &buffer, sizeof (buffer));
285 		if (n == -1 && errno == EAGAIN) {
286 			continue;
287 		} else if (n == -1) {
288 			nlog(LOG_ERR, "error reading routing socket "
289 			    "%d: %m", v6_sock);
290 			/* Low likelihood.  What's recovery path?  */
291 			continue;
292 		}
293 
294 		if (rtm->rtm_msglen < n) {
295 			nlog(LOG_ERR, "only read %d bytes from "
296 			    "routing socket but message claims to be "
297 			    "of length %d", rtm->rtm_msglen);
298 			continue;
299 		}
300 
301 		if (rtm->rtm_version != RTM_VERSION) {
302 			nlog(LOG_ERR, "tossing routing message of "
303 			    "version %d type %d", rtm->rtm_version,
304 			    rtm->rtm_type);
305 			continue;
306 		}
307 
308 		if (rtm->rtm_msglen != n) {
309 			nlog(LOG_DEBUG, "routing message of %d size came from "
310 			    "read of %d on socket %d", rtm->rtm_msglen,
311 			    n, v6_sock);
312 		}
313 
314 		switch (rtm->rtm_type) {
315 		case RTM_NEWADDR:
316 		case RTM_DELADDR:
317 		case RTM_CHGADDR:
318 		case RTM_FREEADDR:
319 
320 			ifa = (void *)rtm;
321 			addrs = (char *)ifa + sizeof (*ifa);
322 
323 			nlog(LOG_DEBUG, "v6 routing message %s: "
324 			    "index %d flags %x", rtmtype_str(rtm->rtm_type),
325 			    ifa->ifam_index, ifa->ifam_flags);
326 			printaddrs(ifa->ifam_addrs, addrs);
327 
328 			if ((addr = (struct sockaddr *)getaddr(RTA_IFA,
329 			    ifa->ifam_addrs, addrs)) == NULL)
330 				break;
331 
332 			/* Ignore messages for link local address */
333 			/*LINTED*/
334 			if (IN6_IS_ADDR_LINKLOCAL(
335 			    &((struct sockaddr_in6 *)addr)->sin6_addr)) {
336 				nlog(LOG_INFO, "routing_events_v6: "
337 				    "tossing message for link local address");
338 				break;
339 			}
340 
341 			if ((addr_dl = (struct sockaddr_dl *)getaddr
342 			    (RTA_IFP, ifa->ifam_addrs, addrs)) == NULL)
343 				break;
344 			/*
345 			 * We don't use the lladdr in this structure so we can
346 			 * run over it.
347 			 */
348 			addr_dl->sdl_data[addr_dl->sdl_nlen] = 0;
349 			if_name = addr_dl->sdl_data; /* no lifnum */
350 
351 			if (ifa->ifam_index == 0) {
352 				nlog(LOG_DEBUG, "tossing index 0 message");
353 				break;
354 			}
355 			if (ifa->ifam_type != rtm->rtm_type) {
356 				nlog(LOG_DEBUG,
357 				    "routing_events_v6: unhandled type %d",
358 				    ifa->ifam_type);
359 				break;
360 			}
361 
362 			/* Create and enqueue IF_STATE event */
363 			ip_event = nwamd_event_init_if_state(if_name,
364 			    ifa->ifam_flags,
365 			    (rtm->rtm_type == RTM_NEWADDR ||
366 			    rtm->rtm_type == RTM_CHGADDR ? B_TRUE : B_FALSE),
367 			    ifa->ifam_index, addr);
368 			if (ip_event != NULL)
369 				nwamd_event_enqueue(ip_event);
370 			break;
371 
372 		case RTM_IFINFO:
373 
374 			ifm = (void *)rtm;
375 			addrs = (char *)ifm + sizeof (*ifm);
376 			nlog(LOG_DEBUG, "v6 routing message %s: "
377 			    "index %d flags %x", rtmtype_str(rtm->rtm_type),
378 			    ifm->ifm_index, ifm->ifm_flags);
379 			printaddrs(ifm->ifm_addrs, addrs);
380 
381 			if ((addr_dl = (struct sockaddr_dl *)getaddr(RTA_IFP,
382 			    ifm->ifm_addrs, addrs)) == NULL)
383 				break;
384 			/*
385 			 * We don't use the lladdr in this structure so we can
386 			 * run over it.
387 			 */
388 			addr_dl->sdl_data[addr_dl->sdl_nlen] = 0;
389 			if_name = addr_dl->sdl_data; /* no lifnum */
390 
391 			if (ifm->ifm_index == 0) {
392 				nlog(LOG_DEBUG, "tossing index 0 message");
393 				break;
394 			}
395 			if (ifm->ifm_type != RTM_IFINFO) {
396 				nlog(LOG_DEBUG,
397 				    "routing_events_v6: unhandled type %d",
398 				    ifm->ifm_type);
399 				break;
400 			}
401 
402 			/* Create and enqueue IF_STATE event */
403 			ip_event = nwamd_event_init_if_state(if_name,
404 			    ifm->ifm_flags, B_FALSE, ifm->ifm_index, NULL);
405 			if (ip_event != NULL)
406 				nwamd_event_enqueue(ip_event);
407 			break;
408 
409 		default:
410 			nlog(LOG_DEBUG, "v6 routing message %s discarded",
411 			    rtmtype_str(rtm->rtm_type));
412 			break;
413 		}
414 	}
415 	/* NOTREACHED */
416 	return (NULL);
417 }
418 
419 void
420 nwamd_routing_events_init(void)
421 {
422 	pthread_attr_t attr;
423 
424 	/*
425 	 * Initialize routing sockets here so that we know the routing threads
426 	 * (and any requests to add a route) will be working with a valid socket
427 	 * by the time we start handling events.
428 	 */
429 	v4_sock = socket(AF_ROUTE, SOCK_RAW, AF_INET);
430 	if (v4_sock == -1)
431 		pfail("failed to open v4 routing socket: %m");
432 
433 	v6_sock = socket(AF_ROUTE, SOCK_RAW, AF_INET6);
434 	if (v6_sock == -1)
435 		pfail("failed to open v6 routing socket: %m");
436 
437 	(void) pthread_attr_init(&attr);
438 	(void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
439 	if (pthread_create(&v4_routing, &attr, routing_events_v4, NULL) != 0 ||
440 	    pthread_create(&v6_routing, &attr, routing_events_v6, NULL) != 0)
441 		pfail("routing thread creation failed");
442 	(void) pthread_attr_destroy(&attr);
443 }
444 
445 void
446 nwamd_routing_events_fini(void)
447 {
448 	(void) pthread_cancel(v4_routing);
449 	(void) pthread_cancel(v6_routing);
450 }
451 
452 void
453 nwamd_add_route(struct sockaddr *dest, struct sockaddr *mask,
454     struct sockaddr *gateway, const char *ifname)
455 {
456 	char rtbuf[RTMBUFSZ];
457 	/* LINTED E_BAD_PTR_CAST_ALIGN */
458 	struct rt_msghdr *rtm = (struct rt_msghdr *)rtbuf;
459 	void *addrs = rtbuf + sizeof (struct rt_msghdr);
460 	struct sockaddr_dl sdl;
461 	icfg_if_t intf;
462 	icfg_handle_t h;
463 	int rlen, index;
464 	int af;
465 
466 	af = gateway->sa_family;
467 
468 	/* set interface for default route to be associated with */
469 	(void) strlcpy(intf.if_name, ifname, sizeof (intf.if_name));
470 	intf.if_protocol = af;
471 	if (icfg_open(&h, &intf) != ICFG_SUCCESS) {
472 		nlog(LOG_ERR, "nwamd_add_route: "
473 		    "icfg_open failed on %s", ifname);
474 		return;
475 	}
476 	if (icfg_get_index(h, &index) != ICFG_SUCCESS) {
477 		nlog(LOG_ERR, "nwamd_add_route: "
478 		    "icfg_get_index failed on %s", ifname);
479 	}
480 	icfg_close(h);
481 	(void) bzero(&sdl, sizeof (struct sockaddr_dl));
482 	sdl.sdl_family = AF_LINK;
483 	sdl.sdl_index = index;
484 
485 	(void) bzero(rtm, RTMBUFSZ);
486 	rtm->rtm_pid = getpid();
487 	rtm->rtm_type = RTM_ADD;
488 	rtm->rtm_flags = RTF_UP | RTF_STATIC | RTF_GATEWAY;
489 	rtm->rtm_version = RTM_VERSION;
490 	rtm->rtm_seq = ++seq;
491 	rtm->rtm_msglen = sizeof (rtbuf);
492 	setaddr(RTA_DST, &rtm->rtm_addrs, &addrs, dest);
493 	setaddr(RTA_GATEWAY, &rtm->rtm_addrs, &addrs, gateway);
494 	setaddr(RTA_NETMASK, &rtm->rtm_addrs, &addrs, mask);
495 	setaddr(RTA_IFP, &rtm->rtm_addrs, &addrs, (struct sockaddr *)&sdl);
496 
497 	if ((rlen = write(af == AF_INET ? v4_sock : v6_sock,
498 	    rtbuf, rtm->rtm_msglen)) < 0) {
499 		nlog(LOG_ERR, "nwamd_add_route: "
500 		    "got error %s writing to routing socket", strerror(errno));
501 	} else if (rlen < rtm->rtm_msglen) {
502 		nlog(LOG_ERR, "nwamd_add_route: "
503 		    "only wrote %d bytes of %d to routing socket\n",
504 		    rlen, rtm->rtm_msglen);
505 	}
506 }
507 
508 static char *
509 printaddr(void **address)
510 {
511 	static char buffer[80];
512 	sa_family_t family = *(sa_family_t *)*address;
513 	struct sockaddr_in *s4 = *address;
514 	struct sockaddr_in6 *s6 = *address;
515 	struct sockaddr_dl *dl = *address;
516 
517 	switch (family) {
518 	case AF_UNSPEC:
519 		(void) inet_ntop(AF_UNSPEC, &s4->sin_addr, buffer,
520 		    sizeof (buffer));
521 		*address = (char *)*address + sizeof (*s4);
522 		break;
523 	case AF_INET:
524 		(void) inet_ntop(AF_INET, &s4->sin_addr, buffer,
525 		    sizeof (buffer));
526 		*address = (char *)*address + sizeof (*s4);
527 		break;
528 	case AF_INET6:
529 		(void) inet_ntop(AF_INET6, &s6->sin6_addr, buffer,
530 		    sizeof (buffer));
531 		*address = (char *)*address + sizeof (*s6);
532 		break;
533 	case AF_LINK:
534 		(void) snprintf(buffer, sizeof (buffer), "link %.*s",
535 		    dl->sdl_nlen, dl->sdl_data);
536 		*address = (char *)*address + sizeof (*dl);
537 		break;
538 	default:
539 		/*
540 		 * We can't reliably update the size of this thing
541 		 * because we don't know what its type is.  So bump
542 		 * it by a sockaddr_in and see what happens.  The
543 		 * caller should really make sure this never happens.
544 		 */
545 		*address = (char *)*address + sizeof (*s4);
546 		(void) snprintf(buffer, sizeof (buffer),
547 		    "unknown address family %d", family);
548 		break;
549 	}
550 	return (buffer);
551 }
552 
553 static void
554 printaddrs(int mask, void *address)
555 {
556 	if (mask == 0)
557 		return;
558 	if (mask & RTA_DST)
559 		nlog(LOG_DEBUG, "destination address: %s", printaddr(&address));
560 	if (mask & RTA_GATEWAY)
561 		nlog(LOG_DEBUG, "gateway address: %s", printaddr(&address));
562 	if (mask & RTA_NETMASK)
563 		nlog(LOG_DEBUG, "netmask: %s", printaddr(&address));
564 	if (mask & RTA_GENMASK)
565 		nlog(LOG_DEBUG, "cloning mask: %s", printaddr(&address));
566 	if (mask & RTA_IFP)
567 		nlog(LOG_DEBUG, "interface name: %s", printaddr(&address));
568 	if (mask & RTA_IFA)
569 		nlog(LOG_DEBUG, "interface address: %s", printaddr(&address));
570 	if (mask & RTA_AUTHOR)
571 		nlog(LOG_DEBUG, "author: %s", printaddr(&address));
572 	if (mask & RTA_BRD)
573 		nlog(LOG_DEBUG, "broadcast address: %s", printaddr(&address));
574 }
575 
576 static void
577 nextaddr(void **address)
578 {
579 	sa_family_t family = *(sa_family_t *)*address;
580 
581 	switch (family) {
582 	case AF_UNSPEC:
583 	case AF_INET:
584 		*address = (char *)*address + sizeof (struct sockaddr_in);
585 		break;
586 	case AF_INET6:
587 		*address = (char *)*address + sizeof (struct sockaddr_in6);
588 		break;
589 	case AF_LINK:
590 		*address = (char *)*address + sizeof (struct sockaddr_dl);
591 		break;
592 	default:
593 		nlog(LOG_ERR, "unknown af (%d) while parsing rtm", family);
594 		break;
595 	}
596 }
597 
598 static void *
599 getaddr(int addrid, int mask, void *addresses)
600 {
601 	int i;
602 	void *p = addresses;
603 
604 	if ((mask & addrid) == 0)
605 		return (NULL);
606 
607 	for (i = 1; i < addrid; i <<= 1) {
608 		if (i & mask)
609 			nextaddr(&p);
610 	}
611 	return (p);
612 }
613 
614 static void
615 setaddr(int addrid, int *maskp, void *addressesp, struct sockaddr *address)
616 {
617 	struct sockaddr *p = *((struct sockaddr **)addressesp);
618 
619 	*maskp |= addrid;
620 
621 	switch (address->sa_family) {
622 	case AF_INET:
623 		(void) memcpy(p, address, sizeof (struct sockaddr_in));
624 		break;
625 	case AF_INET6:
626 		(void) memcpy(p, address, sizeof (struct sockaddr_in6));
627 		break;
628 	case AF_LINK:
629 		(void) memcpy(p, address, sizeof (struct sockaddr_dl));
630 		break;
631 	default:
632 		nlog(LOG_ERR, "setaddr: unknown af (%d) while setting addr",
633 		    address->sa_family);
634 		break;
635 	}
636 	nextaddr(addressesp);
637 }
638