1124524Sume/* $KAME: probe.c,v 1.17 2003/10/05 00:09:36 itojun Exp $ */ 266776Skris 355163Sshin/* 455163Sshin * Copyright (C) 1998 WIDE Project. 555163Sshin * All rights reserved. 662632Skris * 755163Sshin * Redistribution and use in source and binary forms, with or without 855163Sshin * modification, are permitted provided that the following conditions 955163Sshin * are met: 1055163Sshin * 1. Redistributions of source code must retain the above copyright 1155163Sshin * notice, this list of conditions and the following disclaimer. 1255163Sshin * 2. Redistributions in binary form must reproduce the above copyright 1355163Sshin * notice, this list of conditions and the following disclaimer in the 1455163Sshin * documentation and/or other materials provided with the distribution. 1555163Sshin * 3. Neither the name of the project nor the names of its contributors 1655163Sshin * may be used to endorse or promote products derived from this software 1755163Sshin * without specific prior written permission. 1862632Skris * 1955163Sshin * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 2055163Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2155163Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2255163Sshin * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 2355163Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2455163Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2555163Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2655163Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2755163Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2855163Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2955163Sshin * SUCH DAMAGE. 3055163Sshin * 3155163Sshin * $FreeBSD$ 3255163Sshin */ 3355163Sshin 3455163Sshin#include <sys/param.h> 3555163Sshin#include <sys/types.h> 3655163Sshin#include <sys/ioctl.h> 3755163Sshin#include <sys/socket.h> 38254470Shrs#include <sys/sysctl.h> 3955163Sshin#include <sys/uio.h> 4066776Skris#include <sys/queue.h> 4155163Sshin 4255163Sshin#include <net/if.h> 4355163Sshin#include <net/if_var.h> 44119026Sume#include <net/if_dl.h> 4555163Sshin 4655163Sshin#include <netinet/in.h> 4755163Sshin#include <netinet6/in6_var.h> 4855163Sshin#include <netinet/icmp6.h> 4955163Sshin#include <netinet6/nd6.h> 5055163Sshin 5155163Sshin#include <arpa/inet.h> 5255163Sshin 5355163Sshin#include <errno.h> 5455163Sshin#include <unistd.h> 5555163Sshin#include <string.h> 5655163Sshin#include <syslog.h> 5762632Skris#include <stdlib.h> 5855163Sshin 5955163Sshin#include "rtsold.h" 6055163Sshin 6155163Sshinstatic struct msghdr sndmhdr; 6255163Sshinstatic struct iovec sndiov[2]; 6355163Sshinstatic int probesock; 64173412Skevlostatic void sendprobe(struct in6_addr *, struct ifinfo *); 6555163Sshin 6655163Sshinint 67124524Sumeprobe_init(void) 6855163Sshin{ 6962632Skris int scmsglen = CMSG_SPACE(sizeof(struct in6_pktinfo)) + 70118664Sume CMSG_SPACE(sizeof(int)); 7162632Skris static u_char *sndcmsgbuf = NULL; 72118664Sume 7362632Skris if (sndcmsgbuf == NULL && 7462632Skris (sndcmsgbuf = (u_char *)malloc(scmsglen)) == NULL) { 75118660Sume warnmsg(LOG_ERR, __func__, "malloc failed"); 76222732Shrs return (-1); 7762632Skris } 7855163Sshin 7955163Sshin if ((probesock = socket(AF_INET6, SOCK_RAW, IPPROTO_NONE)) < 0) { 80118660Sume warnmsg(LOG_ERR, __func__, "socket: %s", strerror(errno)); 81222732Shrs return (-1); 8255163Sshin } 8355163Sshin 8455163Sshin /* make the socket send-only */ 8555163Sshin if (shutdown(probesock, 0)) { 86118660Sume warnmsg(LOG_ERR, __func__, "shutdown: %s", strerror(errno)); 87222732Shrs return (-1); 8855163Sshin } 8955163Sshin 9055163Sshin /* initialize msghdr for sending packets */ 9155163Sshin sndmhdr.msg_namelen = sizeof(struct sockaddr_in6); 9255163Sshin sndmhdr.msg_iov = sndiov; 9355163Sshin sndmhdr.msg_iovlen = 1; 9455163Sshin sndmhdr.msg_control = (caddr_t)sndcmsgbuf; 9562632Skris sndmhdr.msg_controllen = scmsglen; 96222732Shrs 97222732Shrs return (0); 9855163Sshin} 9955163Sshin 10055163Sshin/* 101118664Sume * Probe if each router in the default router list is still alive. 10255163Sshin */ 10355163Sshinvoid 104119026Sumedefrouter_probe(struct ifinfo *ifinfo) 10555163Sshin{ 106254470Shrs struct in6_defrouter *p, *ep; 107254470Shrs int ifindex, mib[4]; 108254470Shrs char *buf, ntopbuf[INET6_ADDRSTRLEN]; 109254470Shrs size_t l; 11055163Sshin 111254470Shrs ifindex = ifinfo->sdl->sdl_index; 112254470Shrs if (ifindex == 0) 11355163Sshin return; 114254470Shrs mib[0] = CTL_NET; 115254470Shrs mib[1] = PF_INET6; 116254470Shrs mib[2] = IPPROTO_ICMPV6; 117254470Shrs mib[3] = ICMPV6CTL_ND6_DRLIST; 118254470Shrs if (sysctl(mib, nitems(mib), NULL, &l, NULL, 0) < 0) { 119254470Shrs warnmsg(LOG_ERR, __func__, "sysctl(ICMPV6CTL_ND6_DRLIST): %s", 120254470Shrs strerror(errno)); 121254470Shrs return; 12255163Sshin } 123254470Shrs if (l == 0) 124254470Shrs return; 125254470Shrs buf = malloc(l); 126254470Shrs if (buf == NULL) { 127254470Shrs warnmsg(LOG_ERR, __func__, "malloc(): %s", strerror(errno)); 128254470Shrs return; 129254470Shrs } 130254470Shrs if (sysctl(mib, nitems(mib), buf, &l, NULL, 0) < 0) { 131254470Shrs warnmsg(LOG_ERR, __func__, "sysctl(ICMPV6CTL_ND6_DRLIST): %s", 132118664Sume strerror(errno)); 133254470Shrs free(buf); 134254470Shrs return; 13555163Sshin } 136254470Shrs ep = (struct in6_defrouter *)(void *)(buf + l); 137254470Shrs for (p = (struct in6_defrouter *)(void *)buf; p < ep; p++) { 138254470Shrs if (ifindex != p->if_index) 139254470Shrs continue; 140254470Shrs if (!IN6_IS_ADDR_LINKLOCAL(&p->rtaddr.sin6_addr)) { 141254470Shrs warnmsg(LOG_ERR, __func__, 142254470Shrs "default router list contains a " 143254470Shrs "non-link-local address(%s)", 144254470Shrs inet_ntop(AF_INET6, &p->rtaddr.sin6_addr, ntopbuf, 145254470Shrs INET6_ADDRSTRLEN)); 146254470Shrs continue; /* ignore the address */ 14755163Sshin } 148254470Shrs sendprobe(&p->rtaddr.sin6_addr, ifinfo); 14955163Sshin } 150254470Shrs free(buf); 15155163Sshin} 15255163Sshin 15355163Sshinstatic void 154119026Sumesendprobe(struct in6_addr *addr, struct ifinfo *ifinfo) 15555163Sshin{ 156119026Sume u_char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ]; 15755163Sshin struct sockaddr_in6 sa6_probe; 15855163Sshin struct in6_pktinfo *pi; 15955163Sshin struct cmsghdr *cm; 160119026Sume u_int32_t ifindex = ifinfo->sdl->sdl_index; 161118664Sume int hoplimit = 1; 16255163Sshin 163118786Sume memset(&sa6_probe, 0, sizeof(sa6_probe)); 16455163Sshin sa6_probe.sin6_family = AF_INET6; 16555163Sshin sa6_probe.sin6_len = sizeof(sa6_probe); 16655163Sshin sa6_probe.sin6_addr = *addr; 167119026Sume sa6_probe.sin6_scope_id = ifinfo->linkid; 16855163Sshin 16955163Sshin sndmhdr.msg_name = (caddr_t)&sa6_probe; 17055163Sshin sndmhdr.msg_iov[0].iov_base = NULL; 17155163Sshin sndmhdr.msg_iov[0].iov_len = 0; 17255163Sshin 17355163Sshin cm = CMSG_FIRSTHDR(&sndmhdr); 17455163Sshin /* specify the outgoing interface */ 17555163Sshin cm->cmsg_level = IPPROTO_IPV6; 17655163Sshin cm->cmsg_type = IPV6_PKTINFO; 17755163Sshin cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); 178254462Shrs pi = (struct in6_pktinfo *)(void *)CMSG_DATA(cm); 17955163Sshin memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr)); /*XXX*/ 18055163Sshin pi->ipi6_ifindex = ifindex; 18155163Sshin 18255163Sshin /* specify the hop limit of the packet for safety */ 183118664Sume cm = CMSG_NXTHDR(&sndmhdr, cm); 184118664Sume cm->cmsg_level = IPPROTO_IPV6; 185118664Sume cm->cmsg_type = IPV6_HOPLIMIT; 186118664Sume cm->cmsg_len = CMSG_LEN(sizeof(int)); 187118664Sume memcpy(CMSG_DATA(cm), &hoplimit, sizeof(int)); 18855163Sshin 189118660Sume warnmsg(LOG_DEBUG, __func__, "probe a router %s on %s", 190118664Sume inet_ntop(AF_INET6, addr, ntopbuf, INET6_ADDRSTRLEN), 191118664Sume if_indextoname(ifindex, ifnamebuf)); 19255163Sshin 19355163Sshin if (sendmsg(probesock, &sndmhdr, 0)) 194118660Sume warnmsg(LOG_ERR, __func__, "sendmsg on %s: %s", 195118664Sume if_indextoname(ifindex, ifnamebuf), strerror(errno)); 19655163Sshin} 197