probe.c revision 55163
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 55163 1999-12-28 02:37:14Z 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#if defined(__FreeBSD__) && __FreeBSD__ >= 3
40#include <net/if_var.h>
41#endif /* __FreeBSD__ >= 3 */
42
43#include <netinet/in.h>
44#include <netinet6/in6_var.h>
45#include <netinet/icmp6.h>
46#include <netinet6/nd6.h>
47
48#include <arpa/inet.h>
49
50#include <errno.h>
51#include <unistd.h>
52#include <string.h>
53#include <syslog.h>
54
55#include "rtsold.h"
56
57static struct msghdr sndmhdr;
58static struct iovec sndiov[2];
59static int probesock;
60static void sendprobe __P((struct in6_addr *addr, int ifindex));
61
62int
63probe_init()
64{
65	static u_char sndcmsgbuf[CMSG_SPACE(sizeof(struct in6_pktinfo)) +
66				CMSG_SPACE(sizeof(int))];
67
68	if ((probesock = socket(AF_INET6, SOCK_RAW, IPPROTO_NONE)) < 0) {
69		warnmsg(LOG_ERR, __FUNCTION__, "socket: %s", strerror(errno));
70		return(-1);
71	}
72
73	/* make the socket send-only */
74	if (shutdown(probesock, 0)) {
75		warnmsg(LOG_ERR, __FUNCTION__, "shutdown: %s", strerror(errno));
76		return(-1);
77	}
78
79	/* initialize msghdr for sending packets */
80	sndmhdr.msg_namelen = sizeof(struct sockaddr_in6);
81	sndmhdr.msg_iov = sndiov;
82	sndmhdr.msg_iovlen = 1;
83	sndmhdr.msg_control = (caddr_t)sndcmsgbuf;
84	sndmhdr.msg_controllen = sizeof(sndcmsgbuf);
85
86	return(0);
87}
88
89/*
90 * Probe if each router in the default router list is still alive.
91 */
92void
93defrouter_probe(int ifindex)
94{
95	struct in6_drlist dr;
96	int s, i;
97	u_char ntopbuf[INET6_ADDRSTRLEN];
98
99	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
100		warnmsg(LOG_ERR, __FUNCTION__, "socket: %s", strerror(errno));
101		return;
102	}
103	bzero(&dr, sizeof(dr));
104	strcpy(dr.ifname, "lo0"); /* dummy interface */
105	if (ioctl(s, SIOCGDRLST_IN6, (caddr_t)&dr) < 0) {
106		warnmsg(LOG_ERR, __FUNCTION__, "ioctl(SIOCGDRLST_IN6): %s",
107		       strerror(errno));
108		goto closeandend;
109	}
110
111	for(i = 0; dr.defrouter[i].if_index && i < PRLSTSIZ; i++) {
112		if (ifindex && dr.defrouter[i].if_index == ifindex) {
113			/* sanity check */
114			if (!IN6_IS_ADDR_LINKLOCAL(&dr.defrouter[i].rtaddr)) {
115				warnmsg(LOG_ERR, __FUNCTION__,
116					"default router list contains a "
117					"non-linklocal address(%s)",
118				       inet_ntop(AF_INET6,
119						 &dr.defrouter[i].rtaddr,
120						 ntopbuf, INET6_ADDRSTRLEN));
121				continue; /* ignore the address */
122			}
123			sendprobe(&dr.defrouter[i].rtaddr,
124				  dr.defrouter[i].if_index);
125		}
126	}
127
128  closeandend:
129	close(s);
130	return;
131}
132
133static void
134sendprobe(struct in6_addr *addr, int ifindex)
135{
136	struct sockaddr_in6 sa6_probe;
137	struct in6_pktinfo *pi;
138	struct cmsghdr *cm;
139	u_char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ];;
140
141	bzero(&sa6_probe, sizeof(sa6_probe));
142	sa6_probe.sin6_family = AF_INET6;
143	sa6_probe.sin6_len = sizeof(sa6_probe);
144	sa6_probe.sin6_addr = *addr;
145
146	sndmhdr.msg_name = (caddr_t)&sa6_probe;
147	sndmhdr.msg_iov[0].iov_base = NULL;
148	sndmhdr.msg_iov[0].iov_len = 0;
149
150	cm = CMSG_FIRSTHDR(&sndmhdr);
151	/* specify the outgoing interface */
152	cm->cmsg_level = IPPROTO_IPV6;
153	cm->cmsg_type = IPV6_PKTINFO;
154	cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
155	pi = (struct in6_pktinfo *)CMSG_DATA(cm);
156	memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr));	/*XXX*/
157	pi->ipi6_ifindex = ifindex;
158
159	/* specify the hop limit of the packet for safety */
160	{
161		int hoplimit = 1;
162
163		cm = CMSG_NXTHDR(&sndmhdr, cm);
164		cm->cmsg_level = IPPROTO_IPV6;
165		cm->cmsg_type = IPV6_HOPLIMIT;
166		cm->cmsg_len = CMSG_LEN(sizeof(int));
167		memcpy(CMSG_DATA(cm), &hoplimit, sizeof(int));
168	}
169
170	warnmsg(LOG_DEBUG, __FUNCTION__, "probe a router %s on %s",
171	       inet_ntop(AF_INET6, addr, ntopbuf, INET6_ADDRSTRLEN),
172	       if_indextoname(ifindex, ifnamebuf));
173
174	if (sendmsg(probesock, &sndmhdr, 0))
175		warnmsg(LOG_ERR, __FUNCTION__, "sendmsg on %s: %s",
176			if_indextoname(ifindex, ifnamebuf), strerror(errno));
177
178	return;
179}
180