probe.c revision 118664
11556Srgrimes/* $KAME: probe.c,v 1.10 2000/08/13 06:14:59 itojun Exp $ */ 21556Srgrimes 31556Srgrimes/* 41556Srgrimes * Copyright (C) 1998 WIDE Project. 51556Srgrimes * All rights reserved. 61556Srgrimes * 71556Srgrimes * Redistribution and use in source and binary forms, with or without 81556Srgrimes * modification, are permitted provided that the following conditions 91556Srgrimes * are met: 101556Srgrimes * 1. Redistributions of source code must retain the above copyright 111556Srgrimes * notice, this list of conditions and the following disclaimer. 121556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 131556Srgrimes * notice, this list of conditions and the following disclaimer in the 141556Srgrimes * documentation and/or other materials provided with the distribution. 151556Srgrimes * 3. Neither the name of the project nor the names of its contributors 161556Srgrimes * may be used to endorse or promote products derived from this software 171556Srgrimes * without specific prior written permission. 181556Srgrimes * 191556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 201556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 211556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 221556Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 231556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 241556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 251556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 261556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 271556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 281556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 291556Srgrimes * SUCH DAMAGE. 301556Srgrimes * 311556Srgrimes * $FreeBSD: head/usr.sbin/rtsold/probe.c 118664 2003-08-08 16:56:01Z ume $ 321556Srgrimes */ 331556Srgrimes 341556Srgrimes#include <sys/param.h> 351556Srgrimes#include <sys/types.h> 361556Srgrimes#include <sys/ioctl.h> 371556Srgrimes#include <sys/socket.h> 381556Srgrimes#include <sys/uio.h> 3936049Scharnier#include <sys/queue.h> 4036049Scharnier 4136049Scharnier#include <net/if.h> 421556Srgrimes#if defined(__FreeBSD__) && __FreeBSD__ >= 3 4399110Sobrien#include <net/if_var.h> 4499110Sobrien#endif /* __FreeBSD__ >= 3 */ 451556Srgrimes 461556Srgrimes#include <netinet/in.h> 471556Srgrimes#include <netinet6/in6_var.h> 481556Srgrimes#include <netinet/icmp6.h> 491556Srgrimes#include <netinet6/nd6.h> 501556Srgrimes 511556Srgrimes#include <arpa/inet.h> 521556Srgrimes 531556Srgrimes#include <errno.h> 541556Srgrimes#include <unistd.h> 551556Srgrimes#include <string.h> 561556Srgrimes#include <syslog.h> 571556Srgrimes#include <stdlib.h> 581556Srgrimes 591556Srgrimes#include "rtsold.h" 601556Srgrimes 611556Srgrimesstatic struct msghdr sndmhdr; 621556Srgrimesstatic struct iovec sndiov[2]; 631556Srgrimesstatic int probesock; 641556Srgrimesstatic void sendprobe __P((struct in6_addr *, int)); 651556Srgrimes 661556Srgrimesint 671556Srgrimesprobe_init() 681556Srgrimes{ 691556Srgrimes int scmsglen = CMSG_SPACE(sizeof(struct in6_pktinfo)) + 701556Srgrimes CMSG_SPACE(sizeof(int)); 711556Srgrimes static u_char *sndcmsgbuf = NULL; 721556Srgrimes 7346684Skris if (sndcmsgbuf == NULL && 741556Srgrimes (sndcmsgbuf = (u_char *)malloc(scmsglen)) == NULL) { 751556Srgrimes warnmsg(LOG_ERR, __func__, "malloc failed"); 761556Srgrimes return(-1); 771556Srgrimes } 781556Srgrimes 791556Srgrimes if ((probesock = socket(AF_INET6, SOCK_RAW, IPPROTO_NONE)) < 0) { 801556Srgrimes warnmsg(LOG_ERR, __func__, "socket: %s", strerror(errno)); 811556Srgrimes return(-1); 8290110Simp } 831556Srgrimes 841556Srgrimes /* make the socket send-only */ 851556Srgrimes if (shutdown(probesock, 0)) { 861556Srgrimes warnmsg(LOG_ERR, __func__, "shutdown: %s", strerror(errno)); 871556Srgrimes return(-1); 881556Srgrimes } 891556Srgrimes 901556Srgrimes /* initialize msghdr for sending packets */ 911556Srgrimes sndmhdr.msg_namelen = sizeof(struct sockaddr_in6); 921556Srgrimes sndmhdr.msg_iov = sndiov; 931556Srgrimes sndmhdr.msg_iovlen = 1; 941556Srgrimes sndmhdr.msg_control = (caddr_t)sndcmsgbuf; 951556Srgrimes sndmhdr.msg_controllen = scmsglen; 961556Srgrimes return(0); 971556Srgrimes} 98100012Skeramida 991556Srgrimes/* 1001556Srgrimes * Probe if each router in the default router list is still alive. 101100012Skeramida */ 1021556Srgrimesvoid 1031556Srgrimesdefrouter_probe(int ifindex) 1041556Srgrimes{ 1051556Srgrimes struct in6_drlist dr; 1061556Srgrimes int s, i; 1071556Srgrimes u_char ntopbuf[INET6_ADDRSTRLEN]; 1081556Srgrimes 1091556Srgrimes if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 1101556Srgrimes warnmsg(LOG_ERR, __func__, "socket: %s", strerror(errno)); 1111556Srgrimes return; 1121556Srgrimes } 1131556Srgrimes bzero(&dr, sizeof(dr)); 1141556Srgrimes strcpy(dr.ifname, "lo0"); /* dummy interface */ 1151556Srgrimes if (ioctl(s, SIOCGDRLST_IN6, (caddr_t)&dr) < 0) { 1161556Srgrimes warnmsg(LOG_ERR, __func__, "ioctl(SIOCGDRLST_IN6): %s", 1171556Srgrimes strerror(errno)); 1181556Srgrimes goto closeandend; 1191556Srgrimes } 1201556Srgrimes 12176017Skris for (i = 0; dr.defrouter[i].if_index && i < PRLSTSIZ; i++) { 1221556Srgrimes if (ifindex && dr.defrouter[i].if_index == ifindex) { 1231556Srgrimes /* sanity check */ 1241556Srgrimes if (!IN6_IS_ADDR_LINKLOCAL(&dr.defrouter[i].rtaddr)) { 1251556Srgrimes warnmsg(LOG_ERR, __func__, 1261556Srgrimes "default router list contains a " 1271556Srgrimes "non-link-local address(%s)", 1281556Srgrimes inet_ntop(AF_INET6, 12976017Skris &dr.defrouter[i].rtaddr, 1301556Srgrimes ntopbuf, INET6_ADDRSTRLEN)); 1311556Srgrimes continue; /* ignore the address */ 1321556Srgrimes } 1331556Srgrimes sendprobe(&dr.defrouter[i].rtaddr, 1341556Srgrimes dr.defrouter[i].if_index); 1351556Srgrimes } 1361556Srgrimes } 1371556Srgrimes 1381556Srgrimescloseandend: 1391556Srgrimes close(s); 1401556Srgrimes} 1411556Srgrimes 1421556Srgrimesstatic void 1431556Srgrimessendprobe(struct in6_addr *addr, int ifindex) 1441556Srgrimes{ 1451556Srgrimes struct sockaddr_in6 sa6_probe; 1461556Srgrimes struct in6_pktinfo *pi; 1471556Srgrimes struct cmsghdr *cm; 1481556Srgrimes u_char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ]; 14990113Simp int hoplimit = 1; 1501556Srgrimes 15190113Simp bzero(&sa6_probe, sizeof(sa6_probe)); 15290113Simp sa6_probe.sin6_family = AF_INET6; 1531556Srgrimes sa6_probe.sin6_len = sizeof(sa6_probe); 1541556Srgrimes sa6_probe.sin6_addr = *addr; 1551556Srgrimes 1561556Srgrimes sndmhdr.msg_name = (caddr_t)&sa6_probe; 1571556Srgrimes sndmhdr.msg_iov[0].iov_base = NULL; 15876017Skris sndmhdr.msg_iov[0].iov_len = 0; 1591556Srgrimes 1601556Srgrimes cm = CMSG_FIRSTHDR(&sndmhdr); 1611556Srgrimes /* specify the outgoing interface */ 1621556Srgrimes cm->cmsg_level = IPPROTO_IPV6; 1631556Srgrimes cm->cmsg_type = IPV6_PKTINFO; 1641556Srgrimes cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); 1651556Srgrimes pi = (struct in6_pktinfo *)CMSG_DATA(cm); 1661556Srgrimes memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr)); /*XXX*/ 1671556Srgrimes pi->ipi6_ifindex = ifindex; 16876017Skris 1691556Srgrimes /* specify the hop limit of the packet for safety */ 1701556Srgrimes cm = CMSG_NXTHDR(&sndmhdr, cm); 1711556Srgrimes cm->cmsg_level = IPPROTO_IPV6; 1721556Srgrimes cm->cmsg_type = IPV6_HOPLIMIT; 1731556Srgrimes cm->cmsg_len = CMSG_LEN(sizeof(int)); 1741556Srgrimes memcpy(CMSG_DATA(cm), &hoplimit, sizeof(int)); 1751556Srgrimes 17676351Skris warnmsg(LOG_DEBUG, __func__, "probe a router %s on %s", 1771556Srgrimes inet_ntop(AF_INET6, addr, ntopbuf, INET6_ADDRSTRLEN), 1781556Srgrimes if_indextoname(ifindex, ifnamebuf)); 1791556Srgrimes 1801556Srgrimes if (sendmsg(probesock, &sndmhdr, 0)) 1811556Srgrimes warnmsg(LOG_ERR, __func__, "sendmsg on %s: %s", 1821556Srgrimes if_indextoname(ifindex, ifnamebuf), strerror(errno)); 1831556Srgrimes} 1841556Srgrimes