probe.c revision 119026
1119026Sume/* $KAME: probe.c,v 1.16 2002/06/10 20:00: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: head/usr.sbin/rtsold/probe.c 119026 2003-08-17 11:11:32Z ume $ 3255163Sshin */ 3355163Sshin 3455163Sshin#include <sys/param.h> 3555163Sshin#include <sys/types.h> 3655163Sshin#include <sys/ioctl.h> 3755163Sshin#include <sys/socket.h> 3855163Sshin#include <sys/uio.h> 3966776Skris#include <sys/queue.h> 4055163Sshin 4155163Sshin#include <net/if.h> 4255163Sshin#include <net/if_var.h> 43119026Sume#include <net/if_dl.h> 4455163Sshin 4555163Sshin#include <netinet/in.h> 4655163Sshin#include <netinet6/in6_var.h> 4755163Sshin#include <netinet/icmp6.h> 4855163Sshin#include <netinet6/nd6.h> 4955163Sshin 5055163Sshin#include <arpa/inet.h> 5155163Sshin 5255163Sshin#include <errno.h> 5355163Sshin#include <unistd.h> 5455163Sshin#include <string.h> 5555163Sshin#include <syslog.h> 5662632Skris#include <stdlib.h> 5755163Sshin 5855163Sshin#include "rtsold.h" 5955163Sshin 6055163Sshinstatic struct msghdr sndmhdr; 6155163Sshinstatic struct iovec sndiov[2]; 6255163Sshinstatic int probesock; 63119026Sumestatic void sendprobe __P((struct in6_addr *, struct ifinfo *)); 6455163Sshin 6555163Sshinint 6655163Sshinprobe_init() 6755163Sshin{ 6862632Skris int scmsglen = CMSG_SPACE(sizeof(struct in6_pktinfo)) + 69118664Sume CMSG_SPACE(sizeof(int)); 7062632Skris static u_char *sndcmsgbuf = NULL; 71118664Sume 7262632Skris if (sndcmsgbuf == NULL && 7362632Skris (sndcmsgbuf = (u_char *)malloc(scmsglen)) == NULL) { 74118660Sume warnmsg(LOG_ERR, __func__, "malloc failed"); 7562632Skris return(-1); 7662632Skris } 7755163Sshin 7855163Sshin if ((probesock = socket(AF_INET6, SOCK_RAW, IPPROTO_NONE)) < 0) { 79118660Sume warnmsg(LOG_ERR, __func__, "socket: %s", strerror(errno)); 8055163Sshin return(-1); 8155163Sshin } 8255163Sshin 8355163Sshin /* make the socket send-only */ 8455163Sshin if (shutdown(probesock, 0)) { 85118660Sume warnmsg(LOG_ERR, __func__, "shutdown: %s", strerror(errno)); 8655163Sshin return(-1); 8755163Sshin } 8855163Sshin 8955163Sshin /* initialize msghdr for sending packets */ 9055163Sshin sndmhdr.msg_namelen = sizeof(struct sockaddr_in6); 9155163Sshin sndmhdr.msg_iov = sndiov; 9255163Sshin sndmhdr.msg_iovlen = 1; 9355163Sshin sndmhdr.msg_control = (caddr_t)sndcmsgbuf; 9462632Skris sndmhdr.msg_controllen = scmsglen; 9555163Sshin return(0); 9655163Sshin} 9755163Sshin 9855163Sshin/* 99118664Sume * Probe if each router in the default router list is still alive. 10055163Sshin */ 10155163Sshinvoid 102119026Sumedefrouter_probe(struct ifinfo *ifinfo) 10355163Sshin{ 104119026Sume u_char ntopbuf[INET6_ADDRSTRLEN]; 10555163Sshin struct in6_drlist dr; 10655163Sshin int s, i; 107119026Sume int ifindex = ifinfo->sdl->sdl_index; 10855163Sshin 10955163Sshin if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 110118660Sume warnmsg(LOG_ERR, __func__, "socket: %s", strerror(errno)); 11155163Sshin return; 11255163Sshin } 113118786Sume memset(&dr, 0, sizeof(dr)); 114118786Sume strlcpy(dr.ifname, "lo0", sizeof dr.ifname); /* dummy interface */ 11555163Sshin if (ioctl(s, SIOCGDRLST_IN6, (caddr_t)&dr) < 0) { 116118660Sume warnmsg(LOG_ERR, __func__, "ioctl(SIOCGDRLST_IN6): %s", 117118664Sume strerror(errno)); 11855163Sshin goto closeandend; 11955163Sshin } 12055163Sshin 121118664Sume for (i = 0; dr.defrouter[i].if_index && i < PRLSTSIZ; i++) { 12255163Sshin if (ifindex && dr.defrouter[i].if_index == ifindex) { 12355163Sshin /* sanity check */ 12455163Sshin if (!IN6_IS_ADDR_LINKLOCAL(&dr.defrouter[i].rtaddr)) { 125118660Sume warnmsg(LOG_ERR, __func__, 126118664Sume "default router list contains a " 127118664Sume "non-link-local address(%s)", 128118664Sume inet_ntop(AF_INET6, 129118664Sume &dr.defrouter[i].rtaddr, 130118664Sume ntopbuf, INET6_ADDRSTRLEN)); 13155163Sshin continue; /* ignore the address */ 13255163Sshin } 133119026Sume sendprobe(&dr.defrouter[i].rtaddr, ifinfo); 13455163Sshin } 13555163Sshin } 13655163Sshin 137118664Sumecloseandend: 13855163Sshin close(s); 13955163Sshin} 14055163Sshin 14155163Sshinstatic void 142119026Sumesendprobe(struct in6_addr *addr, struct ifinfo *ifinfo) 14355163Sshin{ 144119026Sume u_char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ]; 14555163Sshin struct sockaddr_in6 sa6_probe; 14655163Sshin struct in6_pktinfo *pi; 14755163Sshin struct cmsghdr *cm; 148119026Sume u_int32_t ifindex = ifinfo->sdl->sdl_index; 149118664Sume int hoplimit = 1; 15055163Sshin 151118786Sume memset(&sa6_probe, 0, sizeof(sa6_probe)); 15255163Sshin sa6_probe.sin6_family = AF_INET6; 15355163Sshin sa6_probe.sin6_len = sizeof(sa6_probe); 15455163Sshin sa6_probe.sin6_addr = *addr; 155119026Sume sa6_probe.sin6_scope_id = ifinfo->linkid; 15655163Sshin 15755163Sshin sndmhdr.msg_name = (caddr_t)&sa6_probe; 15855163Sshin sndmhdr.msg_iov[0].iov_base = NULL; 15955163Sshin sndmhdr.msg_iov[0].iov_len = 0; 16055163Sshin 16155163Sshin cm = CMSG_FIRSTHDR(&sndmhdr); 16255163Sshin /* specify the outgoing interface */ 16355163Sshin cm->cmsg_level = IPPROTO_IPV6; 16455163Sshin cm->cmsg_type = IPV6_PKTINFO; 16555163Sshin cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); 16655163Sshin pi = (struct in6_pktinfo *)CMSG_DATA(cm); 16755163Sshin memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr)); /*XXX*/ 16855163Sshin pi->ipi6_ifindex = ifindex; 16955163Sshin 17055163Sshin /* specify the hop limit of the packet for safety */ 171118664Sume cm = CMSG_NXTHDR(&sndmhdr, cm); 172118664Sume cm->cmsg_level = IPPROTO_IPV6; 173118664Sume cm->cmsg_type = IPV6_HOPLIMIT; 174118664Sume cm->cmsg_len = CMSG_LEN(sizeof(int)); 175118664Sume memcpy(CMSG_DATA(cm), &hoplimit, sizeof(int)); 17655163Sshin 177118660Sume warnmsg(LOG_DEBUG, __func__, "probe a router %s on %s", 178118664Sume inet_ntop(AF_INET6, addr, ntopbuf, INET6_ADDRSTRLEN), 179118664Sume if_indextoname(ifindex, ifnamebuf)); 18055163Sshin 18155163Sshin if (sendmsg(probesock, &sndmhdr, 0)) 182118660Sume warnmsg(LOG_ERR, __func__, "sendmsg on %s: %s", 183118664Sume if_indextoname(ifindex, ifnamebuf), strerror(errno)); 18455163Sshin} 185