1/* 2 * Copyright (c) 2009 Apple Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28 29/* $KAME: probe.c,v 1.10 2000/08/13 06:14:59 itojun Exp $ */ 30 31/* 32 * Copyright (C) 1998 WIDE Project. 33 * All rights reserved. 34 * 35 * Redistribution and use in source and binary forms, with or without 36 * modification, are permitted provided that the following conditions 37 * are met: 38 * 1. Redistributions of source code must retain the above copyright 39 * notice, this list of conditions and the following disclaimer. 40 * 2. Redistributions in binary form must reproduce the above copyright 41 * notice, this list of conditions and the following disclaimer in the 42 * documentation and/or other materials provided with the distribution. 43 * 3. Neither the name of the project nor the names of its contributors 44 * may be used to endorse or promote products derived from this software 45 * without specific prior written permission. 46 * 47 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 48 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 49 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 50 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 51 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 52 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 53 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 54 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 55 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 56 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 57 * SUCH DAMAGE. 58 * 59 * $FreeBSD: src/usr.sbin/rtsold/probe.c,v 1.2.2.3 2001/07/03 11:02:16 ume Exp $ 60 */ 61 62#include <sys/param.h> 63#include <sys/types.h> 64#include <sys/ioctl.h> 65#include <sys/socket.h> 66#include <sys/uio.h> 67#include <sys/queue.h> 68 69#include <net/if.h> 70#if defined(__FreeBSD__) && __FreeBSD__ >= 3 71#include <net/if_var.h> 72#endif /* __FreeBSD__ >= 3 */ 73 74#include <netinet/in.h> 75#include <netinet6/in6_var.h> 76#include <netinet/icmp6.h> 77#include <netinet6/nd6.h> 78 79#include <arpa/inet.h> 80 81#include <errno.h> 82#include <unistd.h> 83#include <string.h> 84#include <syslog.h> 85#include <stdlib.h> 86 87#include "rtsold.h" 88 89static struct msghdr sndmhdr; 90static struct iovec sndiov[2]; 91static int probesock; 92static void sendprobe __P((struct in6_addr *addr, int ifindex)); 93 94 95int 96probe_init() 97{ 98 int scmsglen = CMSG_SPACE(sizeof(struct in6_pktinfo)) + 99 CMSG_SPACE(sizeof(int)); 100 static u_char *sndcmsgbuf = NULL; 101 102 if (sndcmsgbuf == NULL && 103 (sndcmsgbuf = (u_char *)malloc(scmsglen)) == NULL) { 104 warnmsg(LOG_ERR, __FUNCTION__, "malloc failed"); 105 return(-1); 106 } 107 108 if ((probesock = socket(AF_INET6, SOCK_RAW, IPPROTO_NONE)) < 0) { 109 warnmsg(LOG_ERR, __FUNCTION__, "socket: %s", strerror(errno)); 110 return(-1); 111 } 112 113#ifndef __APPLE__ 114 /* make the socket send-only */ 115 if (shutdown(probesock, 0)) { 116 warnmsg(LOG_ERR, __FUNCTION__, "shutdown: %s", strerror(errno)); 117 return(-1); 118 } 119#endif /* __APPLE__ */ 120 121 /* initialize msghdr for sending packets */ 122 sndmhdr.msg_namelen = sizeof(struct sockaddr_in6); 123 sndmhdr.msg_iov = sndiov; 124 sndmhdr.msg_iovlen = 1; 125 sndmhdr.msg_control = (caddr_t)sndcmsgbuf; 126 sndmhdr.msg_controllen = scmsglen; 127 128 return(0); 129} 130 131/* 132 * Probe if each router in the default router list is still alive. 133 */ 134void 135defrouter_probe(int ifindex) 136{ 137 struct in6_drlist dr; 138 int s, i; 139 u_char ntopbuf[INET6_ADDRSTRLEN]; 140 141 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 142 warnmsg(LOG_ERR, __FUNCTION__, "socket: %s", strerror(errno)); 143 return; 144 } 145 bzero(&dr, sizeof(dr)); 146 strlcpy(dr.ifname, "lo0", sizeof(dr.ifname)); /* dummy interface */ 147 if (ioctl(s, SIOCGDRLST_IN6, (caddr_t)&dr) < 0) { 148 warnmsg(LOG_ERR, __FUNCTION__, "ioctl(SIOCGDRLST_IN6): %s", 149 strerror(errno)); 150 goto closeandend; 151 } 152 153 for(i = 0; dr.defrouter[i].if_index && i < PRLSTSIZ; i++) { 154 if (ifindex && dr.defrouter[i].if_index == ifindex) { 155 /* sanity check */ 156 if (!IN6_IS_ADDR_LINKLOCAL(&dr.defrouter[i].rtaddr)) { 157 warnmsg(LOG_ERR, __FUNCTION__, 158 "default router list contains a " 159 "non-linklocal address(%s)", 160 inet_ntop(AF_INET6, 161 &dr.defrouter[i].rtaddr, 162 (char *)ntopbuf, INET6_ADDRSTRLEN)); 163 continue; /* ignore the address */ 164 } 165 sendprobe(&dr.defrouter[i].rtaddr, 166 dr.defrouter[i].if_index); 167 } 168 } 169 170 closeandend: 171 close(s); 172 return; 173} 174 175static void 176sendprobe(struct in6_addr *addr, int ifindex) 177{ 178 struct sockaddr_in6 sa6_probe; 179 struct in6_pktinfo *pi; 180 struct cmsghdr *cm; 181 u_char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ];; 182 183 bzero(&sa6_probe, sizeof(sa6_probe)); 184 sa6_probe.sin6_family = AF_INET6; 185 sa6_probe.sin6_len = sizeof(sa6_probe); 186 sa6_probe.sin6_addr = *addr; 187 188 sndmhdr.msg_name = (caddr_t)&sa6_probe; 189 sndmhdr.msg_iov[0].iov_base = NULL; 190 sndmhdr.msg_iov[0].iov_len = 0; 191 192 cm = CMSG_FIRSTHDR(&sndmhdr); 193 /* specify the outgoing interface */ 194 cm->cmsg_level = IPPROTO_IPV6; 195 cm->cmsg_type = IPV6_PKTINFO; 196 cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); 197 pi = (struct in6_pktinfo *)CMSG_DATA(cm); 198 memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr)); /*XXX*/ 199 pi->ipi6_ifindex = ifindex; 200 201 /* specify the hop limit of the packet for safety */ 202 { 203 int hoplimit = 1; 204 205 cm = CMSG_NXTHDR(&sndmhdr, cm); 206 cm->cmsg_level = IPPROTO_IPV6; 207 cm->cmsg_type = IPV6_HOPLIMIT; 208 cm->cmsg_len = CMSG_LEN(sizeof(int)); 209 memcpy(CMSG_DATA(cm), &hoplimit, sizeof(int)); 210 } 211 212 warnmsg(LOG_DEBUG, __FUNCTION__, "probe a router %s on %s", 213 inet_ntop(AF_INET6, addr, (char *)ntopbuf, INET6_ADDRSTRLEN), 214 if_indextoname(ifindex, (char *)ifnamebuf)); 215 216 if (sendmsg(probesock, &sndmhdr, 0)) 217 warnmsg(LOG_ERR, __FUNCTION__, "sendmsg on %s: %s", 218 if_indextoname(ifindex, (char *)ifnamebuf), strerror(errno)); 219 220 return; 221} 222