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