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