probe.c revision 55163
155163Sshin/* 255163Sshin * Copyright (C) 1998 WIDE Project. 355163Sshin * All rights reserved. 455163Sshin * 555163Sshin * Redistribution and use in source and binary forms, with or without 655163Sshin * modification, are permitted provided that the following conditions 755163Sshin * are met: 855163Sshin * 1. Redistributions of source code must retain the above copyright 955163Sshin * notice, this list of conditions and the following disclaimer. 1055163Sshin * 2. Redistributions in binary form must reproduce the above copyright 1155163Sshin * notice, this list of conditions and the following disclaimer in the 1255163Sshin * documentation and/or other materials provided with the distribution. 1355163Sshin * 3. Neither the name of the project nor the names of its contributors 1455163Sshin * may be used to endorse or promote products derived from this software 1555163Sshin * without specific prior written permission. 1655163Sshin * 1755163Sshin * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 1855163Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1955163Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2055163Sshin * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 2155163Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2255163Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2355163Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2455163Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2555163Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2655163Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2755163Sshin * SUCH DAMAGE. 2855163Sshin * 2955163Sshin * $FreeBSD: head/usr.sbin/rtsold/probe.c 55163 1999-12-28 02:37:14Z shin $ 3055163Sshin */ 3155163Sshin 3255163Sshin#include <sys/param.h> 3355163Sshin#include <sys/types.h> 3455163Sshin#include <sys/ioctl.h> 3555163Sshin#include <sys/socket.h> 3655163Sshin#include <sys/uio.h> 3755163Sshin 3855163Sshin#include <net/if.h> 3955163Sshin#if defined(__FreeBSD__) && __FreeBSD__ >= 3 4055163Sshin#include <net/if_var.h> 4155163Sshin#endif /* __FreeBSD__ >= 3 */ 4255163Sshin 4355163Sshin#include <netinet/in.h> 4455163Sshin#include <netinet6/in6_var.h> 4555163Sshin#include <netinet/icmp6.h> 4655163Sshin#include <netinet6/nd6.h> 4755163Sshin 4855163Sshin#include <arpa/inet.h> 4955163Sshin 5055163Sshin#include <errno.h> 5155163Sshin#include <unistd.h> 5255163Sshin#include <string.h> 5355163Sshin#include <syslog.h> 5455163Sshin 5555163Sshin#include "rtsold.h" 5655163Sshin 5755163Sshinstatic struct msghdr sndmhdr; 5855163Sshinstatic struct iovec sndiov[2]; 5955163Sshinstatic int probesock; 6055163Sshinstatic void sendprobe __P((struct in6_addr *addr, int ifindex)); 6155163Sshin 6255163Sshinint 6355163Sshinprobe_init() 6455163Sshin{ 6555163Sshin static u_char sndcmsgbuf[CMSG_SPACE(sizeof(struct in6_pktinfo)) + 6655163Sshin CMSG_SPACE(sizeof(int))]; 6755163Sshin 6855163Sshin if ((probesock = socket(AF_INET6, SOCK_RAW, IPPROTO_NONE)) < 0) { 6955163Sshin warnmsg(LOG_ERR, __FUNCTION__, "socket: %s", strerror(errno)); 7055163Sshin return(-1); 7155163Sshin } 7255163Sshin 7355163Sshin /* make the socket send-only */ 7455163Sshin if (shutdown(probesock, 0)) { 7555163Sshin warnmsg(LOG_ERR, __FUNCTION__, "shutdown: %s", strerror(errno)); 7655163Sshin return(-1); 7755163Sshin } 7855163Sshin 7955163Sshin /* initialize msghdr for sending packets */ 8055163Sshin sndmhdr.msg_namelen = sizeof(struct sockaddr_in6); 8155163Sshin sndmhdr.msg_iov = sndiov; 8255163Sshin sndmhdr.msg_iovlen = 1; 8355163Sshin sndmhdr.msg_control = (caddr_t)sndcmsgbuf; 8455163Sshin sndmhdr.msg_controllen = sizeof(sndcmsgbuf); 8555163Sshin 8655163Sshin return(0); 8755163Sshin} 8855163Sshin 8955163Sshin/* 9055163Sshin * Probe if each router in the default router list is still alive. 9155163Sshin */ 9255163Sshinvoid 9355163Sshindefrouter_probe(int ifindex) 9455163Sshin{ 9555163Sshin struct in6_drlist dr; 9655163Sshin int s, i; 9755163Sshin u_char ntopbuf[INET6_ADDRSTRLEN]; 9855163Sshin 9955163Sshin if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 10055163Sshin warnmsg(LOG_ERR, __FUNCTION__, "socket: %s", strerror(errno)); 10155163Sshin return; 10255163Sshin } 10355163Sshin bzero(&dr, sizeof(dr)); 10455163Sshin strcpy(dr.ifname, "lo0"); /* dummy interface */ 10555163Sshin if (ioctl(s, SIOCGDRLST_IN6, (caddr_t)&dr) < 0) { 10655163Sshin warnmsg(LOG_ERR, __FUNCTION__, "ioctl(SIOCGDRLST_IN6): %s", 10755163Sshin strerror(errno)); 10855163Sshin goto closeandend; 10955163Sshin } 11055163Sshin 11155163Sshin for(i = 0; dr.defrouter[i].if_index && i < PRLSTSIZ; i++) { 11255163Sshin if (ifindex && dr.defrouter[i].if_index == ifindex) { 11355163Sshin /* sanity check */ 11455163Sshin if (!IN6_IS_ADDR_LINKLOCAL(&dr.defrouter[i].rtaddr)) { 11555163Sshin warnmsg(LOG_ERR, __FUNCTION__, 11655163Sshin "default router list contains a " 11755163Sshin "non-linklocal address(%s)", 11855163Sshin inet_ntop(AF_INET6, 11955163Sshin &dr.defrouter[i].rtaddr, 12055163Sshin ntopbuf, INET6_ADDRSTRLEN)); 12155163Sshin continue; /* ignore the address */ 12255163Sshin } 12355163Sshin sendprobe(&dr.defrouter[i].rtaddr, 12455163Sshin dr.defrouter[i].if_index); 12555163Sshin } 12655163Sshin } 12755163Sshin 12855163Sshin closeandend: 12955163Sshin close(s); 13055163Sshin return; 13155163Sshin} 13255163Sshin 13355163Sshinstatic void 13455163Sshinsendprobe(struct in6_addr *addr, int ifindex) 13555163Sshin{ 13655163Sshin struct sockaddr_in6 sa6_probe; 13755163Sshin struct in6_pktinfo *pi; 13855163Sshin struct cmsghdr *cm; 13955163Sshin u_char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ];; 14055163Sshin 14155163Sshin bzero(&sa6_probe, sizeof(sa6_probe)); 14255163Sshin sa6_probe.sin6_family = AF_INET6; 14355163Sshin sa6_probe.sin6_len = sizeof(sa6_probe); 14455163Sshin sa6_probe.sin6_addr = *addr; 14555163Sshin 14655163Sshin sndmhdr.msg_name = (caddr_t)&sa6_probe; 14755163Sshin sndmhdr.msg_iov[0].iov_base = NULL; 14855163Sshin sndmhdr.msg_iov[0].iov_len = 0; 14955163Sshin 15055163Sshin cm = CMSG_FIRSTHDR(&sndmhdr); 15155163Sshin /* specify the outgoing interface */ 15255163Sshin cm->cmsg_level = IPPROTO_IPV6; 15355163Sshin cm->cmsg_type = IPV6_PKTINFO; 15455163Sshin cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); 15555163Sshin pi = (struct in6_pktinfo *)CMSG_DATA(cm); 15655163Sshin memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr)); /*XXX*/ 15755163Sshin pi->ipi6_ifindex = ifindex; 15855163Sshin 15955163Sshin /* specify the hop limit of the packet for safety */ 16055163Sshin { 16155163Sshin int hoplimit = 1; 16255163Sshin 16355163Sshin cm = CMSG_NXTHDR(&sndmhdr, cm); 16455163Sshin cm->cmsg_level = IPPROTO_IPV6; 16555163Sshin cm->cmsg_type = IPV6_HOPLIMIT; 16655163Sshin cm->cmsg_len = CMSG_LEN(sizeof(int)); 16755163Sshin memcpy(CMSG_DATA(cm), &hoplimit, sizeof(int)); 16855163Sshin } 16955163Sshin 17055163Sshin warnmsg(LOG_DEBUG, __FUNCTION__, "probe a router %s on %s", 17155163Sshin inet_ntop(AF_INET6, addr, ntopbuf, INET6_ADDRSTRLEN), 17255163Sshin if_indextoname(ifindex, ifnamebuf)); 17355163Sshin 17455163Sshin if (sendmsg(probesock, &sndmhdr, 0)) 17555163Sshin warnmsg(LOG_ERR, __FUNCTION__, "sendmsg on %s: %s", 17655163Sshin if_indextoname(ifindex, ifnamebuf), strerror(errno)); 17755163Sshin 17855163Sshin return; 17955163Sshin} 180