probe.c revision 55543
1/*
2 * Copyright (C) 1998 WIDE Project.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the project nor the names of its contributors
14 *    may be used to endorse or promote products derived from this software
15 *    without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * $FreeBSD: head/usr.sbin/rtsold/probe.c 55543 2000-01-07 10:02:43Z shin $
30 */
31
32#include <sys/param.h>
33#include <sys/types.h>
34#include <sys/ioctl.h>
35#include <sys/socket.h>
36#include <sys/uio.h>
37
38#include <net/if.h>
39#include <net/if_var.h>
40
41#include <netinet/in.h>
42#include <netinet6/in6_var.h>
43#include <netinet/icmp6.h>
44#include <netinet6/nd6.h>
45
46#include <arpa/inet.h>
47
48#include <errno.h>
49#include <unistd.h>
50#include <string.h>
51#include <syslog.h>
52
53#include "rtsold.h"
54
55static struct msghdr sndmhdr;
56static struct iovec sndiov[2];
57static int probesock;
58static void sendprobe __P((struct in6_addr *addr, int ifindex));
59
60int
61probe_init()
62{
63	static u_char sndcmsgbuf[CMSG_SPACE(sizeof(struct in6_pktinfo)) +
64				CMSG_SPACE(sizeof(int))];
65
66	if ((probesock = socket(AF_INET6, SOCK_RAW, IPPROTO_NONE)) < 0) {
67		warnmsg(LOG_ERR, __FUNCTION__, "socket: %s", strerror(errno));
68		return(-1);
69	}
70
71	/* make the socket send-only */
72	if (shutdown(probesock, 0)) {
73		warnmsg(LOG_ERR, __FUNCTION__, "shutdown: %s", strerror(errno));
74		return(-1);
75	}
76
77	/* initialize msghdr for sending packets */
78	sndmhdr.msg_namelen = sizeof(struct sockaddr_in6);
79	sndmhdr.msg_iov = sndiov;
80	sndmhdr.msg_iovlen = 1;
81	sndmhdr.msg_control = (caddr_t)sndcmsgbuf;
82	sndmhdr.msg_controllen = sizeof(sndcmsgbuf);
83
84	return(0);
85}
86
87/*
88 * Probe if each router in the default router list is still alive.
89 */
90void
91defrouter_probe(int ifindex)
92{
93	struct in6_drlist dr;
94	int s, i;
95	u_char ntopbuf[INET6_ADDRSTRLEN];
96
97	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
98		warnmsg(LOG_ERR, __FUNCTION__, "socket: %s", strerror(errno));
99		return;
100	}
101	bzero(&dr, sizeof(dr));
102	strcpy(dr.ifname, "lo0"); /* dummy interface */
103	if (ioctl(s, SIOCGDRLST_IN6, (caddr_t)&dr) < 0) {
104		warnmsg(LOG_ERR, __FUNCTION__, "ioctl(SIOCGDRLST_IN6): %s",
105		       strerror(errno));
106		goto closeandend;
107	}
108
109	for(i = 0; dr.defrouter[i].if_index && i < PRLSTSIZ; i++) {
110		if (ifindex && dr.defrouter[i].if_index == ifindex) {
111			/* sanity check */
112			if (!IN6_IS_ADDR_LINKLOCAL(&dr.defrouter[i].rtaddr)) {
113				warnmsg(LOG_ERR, __FUNCTION__,
114					"default router list contains a "
115					"non-linklocal address(%s)",
116				       inet_ntop(AF_INET6,
117						 &dr.defrouter[i].rtaddr,
118						 ntopbuf, INET6_ADDRSTRLEN));
119				continue; /* ignore the address */
120			}
121			sendprobe(&dr.defrouter[i].rtaddr,
122				  dr.defrouter[i].if_index);
123		}
124	}
125
126  closeandend:
127	close(s);
128	return;
129}
130
131static void
132sendprobe(struct in6_addr *addr, int ifindex)
133{
134	struct sockaddr_in6 sa6_probe;
135	struct in6_pktinfo *pi;
136	struct cmsghdr *cm;
137	u_char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ];;
138
139	bzero(&sa6_probe, sizeof(sa6_probe));
140	sa6_probe.sin6_family = AF_INET6;
141	sa6_probe.sin6_len = sizeof(sa6_probe);
142	sa6_probe.sin6_addr = *addr;
143
144	sndmhdr.msg_name = (caddr_t)&sa6_probe;
145	sndmhdr.msg_iov[0].iov_base = NULL;
146	sndmhdr.msg_iov[0].iov_len = 0;
147
148	cm = CMSG_FIRSTHDR(&sndmhdr);
149	/* specify the outgoing interface */
150	cm->cmsg_level = IPPROTO_IPV6;
151	cm->cmsg_type = IPV6_PKTINFO;
152	cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
153	pi = (struct in6_pktinfo *)CMSG_DATA(cm);
154	memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr));	/*XXX*/
155	pi->ipi6_ifindex = ifindex;
156
157	/* specify the hop limit of the packet for safety */
158	{
159		int hoplimit = 1;
160
161		cm = CMSG_NXTHDR(&sndmhdr, cm);
162		cm->cmsg_level = IPPROTO_IPV6;
163		cm->cmsg_type = IPV6_HOPLIMIT;
164		cm->cmsg_len = CMSG_LEN(sizeof(int));
165		memcpy(CMSG_DATA(cm), &hoplimit, sizeof(int));
166	}
167
168	warnmsg(LOG_DEBUG, __FUNCTION__, "probe a router %s on %s",
169	       inet_ntop(AF_INET6, addr, ntopbuf, INET6_ADDRSTRLEN),
170	       if_indextoname(ifindex, ifnamebuf));
171
172	if (sendmsg(probesock, &sndmhdr, 0))
173		warnmsg(LOG_ERR, __FUNCTION__, "sendmsg on %s: %s",
174			if_indextoname(ifindex, ifnamebuf), strerror(errno));
175
176	return;
177}
178