125723Stegge/*	$KAME: probe.c,v 1.17 2003/10/05 00:09:36 itojun Exp $	*/
225723Stegge
3139823Simp/*
425723Stegge * Copyright (C) 1998 WIDE Project.
525723Stegge * All rights reserved.
625723Stegge *
725723Stegge * Redistribution and use in source and binary forms, with or without
825723Stegge * modification, are permitted provided that the following conditions
925723Stegge * are met:
1025723Stegge * 1. Redistributions of source code must retain the above copyright
1125723Stegge *    notice, this list of conditions and the following disclaimer.
1225723Stegge * 2. Redistributions in binary form must reproduce the above copyright
1325723Stegge *    notice, this list of conditions and the following disclaimer in the
1425723Stegge *    documentation and/or other materials provided with the distribution.
1525723Stegge * 3. Neither the name of the project nor the names of its contributors
1625723Stegge *    may be used to endorse or promote products derived from this software
1725723Stegge *    without specific prior written permission.
1825723Stegge *
1925723Stegge * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
2025723Stegge * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2125723Stegge * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2225723Stegge * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
2325723Stegge * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2425723Stegge * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2525723Stegge * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2625723Stegge * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2725723Stegge * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2825723Stegge * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2925723Stegge * SUCH DAMAGE.
3025723Stegge *
3125723Stegge * $FreeBSD$
3225723Stegge */
3325723Stegge
3425723Stegge#include <sys/param.h>
3525723Stegge#include <sys/types.h>
3625723Stegge#include <sys/ioctl.h>
3725723Stegge#include <sys/socket.h>
3825723Stegge#include <sys/sysctl.h>
3925723Stegge#include <sys/uio.h>
4025723Stegge#include <sys/queue.h>
4125723Stegge
4225723Stegge#include <net/if.h>
4325723Stegge#include <net/if_var.h>
4425723Stegge#include <net/if_dl.h>
4583651Speter
4683651Speter#include <netinet/in.h>
4783651Speter#include <netinet6/in6_var.h>
4825723Stegge#include <netinet/icmp6.h>
4925723Stegge#include <netinet6/nd6.h>
50201044Sbz
5130354Sphk#include <arpa/inet.h>
5225723Stegge
5388743Srwatson#include <errno.h>
5425723Stegge#include <unistd.h>
5525723Stegge#include <string.h>
5634924Sbde#include <syslog.h>
5725723Stegge#include <stdlib.h>
5825723Stegge
59200471Sbz#include "rtsold.h"
60200471Sbz
6125723Steggestatic struct msghdr sndmhdr;
6225723Steggestatic struct iovec sndiov[2];
63195202Sdfrstatic int probesock;
64195202Sdfrstatic void sendprobe(struct in6_addr *, struct ifinfo *);
65195202Sdfr
6683651Speterint
6725723Steggeprobe_init(void)
6825723Stegge{
6925723Stegge	int scmsglen = CMSG_SPACE(sizeof(struct in6_pktinfo)) +
7025723Stegge	    CMSG_SPACE(sizeof(int));
7125723Stegge	static u_char *sndcmsgbuf = NULL;
7225723Stegge
7325723Stegge	if (sndcmsgbuf == NULL &&
7425723Stegge	    (sndcmsgbuf = (u_char *)malloc(scmsglen)) == NULL) {
7525723Stegge		warnmsg(LOG_ERR, __func__, "malloc failed");
7625723Stegge		return (-1);
7725723Stegge	}
7825723Stegge
7925723Stegge	if ((probesock = socket(AF_INET6, SOCK_RAW, IPPROTO_NONE)) < 0) {
8025723Stegge		warnmsg(LOG_ERR, __func__, "socket: %s", strerror(errno));
8125723Stegge		return (-1);
8225723Stegge	}
8325723Stegge
8425723Stegge	/* make the socket send-only */
8525723Stegge	if (shutdown(probesock, 0)) {
8625723Stegge		warnmsg(LOG_ERR, __func__, "shutdown: %s", strerror(errno));
8725723Stegge		return (-1);
8825723Stegge	}
8925723Stegge
9025723Stegge	/* initialize msghdr for sending packets */
9125723Stegge	sndmhdr.msg_namelen = sizeof(struct sockaddr_in6);
92122719Salfred	sndmhdr.msg_iov = sndiov;
9325723Stegge	sndmhdr.msg_iovlen = 1;
9425723Stegge	sndmhdr.msg_control = (caddr_t)sndcmsgbuf;
9525723Stegge	sndmhdr.msg_controllen = scmsglen;
9625723Stegge
9725723Stegge	return (0);
9825723Stegge}
9925723Stegge
10025723Stegge/*
10125723Stegge * Probe if each router in the default router list is still alive.
10225723Stegge */
10325723Steggevoid
104122719Salfreddefrouter_probe(struct ifinfo *ifinfo)
10525723Stegge{
10625723Stegge	struct in6_defrouter *p, *ep;
10725723Stegge	int ifindex, mib[4];
10825723Stegge	char *buf, ntopbuf[INET6_ADDRSTRLEN];
10925723Stegge	size_t l;
11025723Stegge
11125723Stegge	ifindex = ifinfo->sdl->sdl_index;
11225723Stegge	if (ifindex == 0)
11325723Stegge		return;
11425723Stegge	mib[0] = CTL_NET;
11525723Stegge	mib[1] = PF_INET6;
11625723Stegge	mib[2] = IPPROTO_ICMPV6;
11725723Stegge	mib[3] = ICMPV6CTL_ND6_DRLIST;
11825723Stegge	if (sysctl(mib, nitems(mib), NULL, &l, NULL, 0) < 0) {
11925723Stegge		warnmsg(LOG_ERR, __func__, "sysctl(ICMPV6CTL_ND6_DRLIST): %s",
12025723Stegge		    strerror(errno));
12125723Stegge		return;
12225723Stegge	}
12325723Stegge	if (l == 0)
12425723Stegge		return;
12525723Stegge	buf = malloc(l);
12625723Stegge	if (buf == NULL) {
12725723Stegge		warnmsg(LOG_ERR, __func__, "malloc(): %s", strerror(errno));
12825723Stegge		return;
12925723Stegge	}
13025723Stegge	if (sysctl(mib, nitems(mib), buf, &l, NULL, 0) < 0) {
13125723Stegge		warnmsg(LOG_ERR, __func__, "sysctl(ICMPV6CTL_ND6_DRLIST): %s",
13225723Stegge		    strerror(errno));
13325723Stegge		free(buf);
13425723Stegge		return;
13583651Speter	}
13683651Speter	ep = (struct in6_defrouter *)(void *)(buf + l);
13725723Stegge	for (p = (struct in6_defrouter *)(void *)buf; p < ep; p++) {
13825723Stegge		if (ifindex != p->if_index)
13925723Stegge			continue;
14025723Stegge		if (!IN6_IS_ADDR_LINKLOCAL(&p->rtaddr.sin6_addr)) {
14125723Stegge			warnmsg(LOG_ERR, __func__,
14225723Stegge			    "default router list contains a "
14325723Stegge			    "non-link-local address(%s)",
14425723Stegge			    inet_ntop(AF_INET6, &p->rtaddr.sin6_addr, ntopbuf,
14525723Stegge			    INET6_ADDRSTRLEN));
14625723Stegge			continue; /* ignore the address */
14725723Stegge		}
14825723Stegge		sendprobe(&p->rtaddr.sin6_addr, ifinfo);
14925723Stegge	}
15025723Stegge	free(buf);
15125723Stegge}
15225723Stegge
15325723Steggestatic void
15425723Steggesendprobe(struct in6_addr *addr, struct ifinfo *ifinfo)
15525723Stegge{
15625723Stegge	u_char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ];
157177599Sru	struct sockaddr_in6 sa6_probe;
15825723Stegge	struct in6_pktinfo *pi;
15925723Stegge	struct cmsghdr *cm;
16025723Stegge	u_int32_t ifindex = ifinfo->sdl->sdl_index;
16125723Stegge	int hoplimit = 1;
16225723Stegge
16325723Stegge	memset(&sa6_probe, 0, sizeof(sa6_probe));
16425723Stegge	sa6_probe.sin6_family = AF_INET6;
16525723Stegge	sa6_probe.sin6_len = sizeof(sa6_probe);
16625723Stegge	sa6_probe.sin6_addr = *addr;
16725723Stegge	sa6_probe.sin6_scope_id = ifinfo->linkid;
16825723Stegge
16983366Sjulian	sndmhdr.msg_name = (caddr_t)&sa6_probe;
17083651Speter	sndmhdr.msg_iov[0].iov_base = NULL;
17125723Stegge	sndmhdr.msg_iov[0].iov_len = 0;
17225723Stegge
17325723Stegge	cm = CMSG_FIRSTHDR(&sndmhdr);
17425723Stegge	/* specify the outgoing interface */
17525723Stegge	cm->cmsg_level = IPPROTO_IPV6;
17625723Stegge	cm->cmsg_type = IPV6_PKTINFO;
17725723Stegge	cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
17825723Stegge	pi = (struct in6_pktinfo *)(void *)CMSG_DATA(cm);
17925723Stegge	memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr));	/*XXX*/
18025723Stegge	pi->ipi6_ifindex = ifindex;
18125723Stegge
18225723Stegge	/* specify the hop limit of the packet for safety */
18325723Stegge	cm = CMSG_NXTHDR(&sndmhdr, cm);
18425723Stegge	cm->cmsg_level = IPPROTO_IPV6;
18525723Stegge	cm->cmsg_type = IPV6_HOPLIMIT;
18625723Stegge	cm->cmsg_len = CMSG_LEN(sizeof(int));
18725723Stegge	memcpy(CMSG_DATA(cm), &hoplimit, sizeof(int));
18825723Stegge
18925723Stegge	warnmsg(LOG_DEBUG, __func__, "probe a router %s on %s",
19025723Stegge	    inet_ntop(AF_INET6, addr, ntopbuf, INET6_ADDRSTRLEN),
19183651Speter	    if_indextoname(ifindex, ifnamebuf));
19283651Speter
19325723Stegge	if (sendmsg(probesock, &sndmhdr, 0))
19425723Stegge		warnmsg(LOG_ERR, __func__, "sendmsg on %s: %s",
19528270Swollman		    if_indextoname(ifindex, ifnamebuf), strerror(errno));
19628270Swollman}
19728270Swollman