1a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt/* 2a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt * dhcpcd - DHCP client daemon 3a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt * Copyright (c) 2006-2012 Roy Marples <roy@marples.name> 4a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt * All rights reserved 5a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt 6a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt * Redistribution and use in source and binary forms, with or without 7a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt * modification, are permitted provided that the following conditions 8a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt * are met: 9a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt * 1. Redistributions of source code must retain the above copyright 10a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt * notice, this list of conditions and the following disclaimer. 11a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt * 2. Redistributions in binary form must reproduce the above copyright 12a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt * notice, this list of conditions and the following disclaimer in the 13a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt * documentation and/or other materials provided with the distribution. 14a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt * 15a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt * SUCH DAMAGE. 26a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt */ 27a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt 28a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt#include <sys/param.h> 29a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt#include <sys/socket.h> 30a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt#include <net/if.h> 31a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt#include <netinet/in.h> 32a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt#include <netinet/ip6.h> 33a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt#include <netinet/icmp6.h> 34a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt 35a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt#include <errno.h> 36a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt#include <stddef.h> 37a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt#include <stdlib.h> 38a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt#include <string.h> 39a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt#include <syslog.h> 40a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt 41a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt#ifdef __linux__ 42a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt# define _LINUX_IN6_H 43a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt# include <linux/ipv6.h> 44a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt#endif 45a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt 46a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt#define ELOOP_QUEUE 1 47a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt#include "bind.h" 48a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt#include "common.h" 49a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt#include "configure.h" 50a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt#include "dhcpcd.h" 51a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt#include "eloop.h" 52a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt#include "ipv6rs.h" 53a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt 54a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt#define ALLROUTERS "ff02::2" 55a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt#define HOPLIMIT 255 56a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt 57a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt#define ROUNDUP8(a) (1 + (((a) - 1) | 7)) 58a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt 59a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt#define RTR_SOLICITATION_INTERVAL 4 /* seconds */ 60a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt#define MAX_RTR_SOLICITATIONS 3 /* times */ 61a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt 62a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt#ifndef ND_OPT_RDNSS 63a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt#define ND_OPT_RDNSS 25 64a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidtstruct nd_opt_rdnss { /* RDNSS option RFC 6106 */ 65a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt uint8_t nd_opt_rdnss_type; 66a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt uint8_t nd_opt_rdnss_len; 67a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt uint16_t nd_opt_rdnss_reserved; 68a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt uint32_t nd_opt_rdnss_lifetime; 69a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt /* followed by list of IP prefixes */ 70a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt} _packed; 71a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt#endif 72a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt 73a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt#ifndef ND_OPT_DNSSL 74a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt#define ND_OPT_DNSSL 31 75a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidtstruct nd_opt_dnssl { /* DNSSL option RFC 6106 */ 76a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt uint8_t nd_opt_dnssl_type; 77a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt uint8_t nd_opt_dnssl_len; 78a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt uint16_t nd_opt_dnssl_reserved; 79a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt uint32_t nd_opt_dnssl_lifetime; 80a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt /* followed by list of DNS servers */ 81a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt} _packed; 82a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt#endif 83a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt 84a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidtstatic int sock; 85a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidtstatic struct sockaddr_in6 allrouters, from; 86a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidtstatic struct msghdr sndhdr; 87a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidtstatic struct iovec sndiov[2]; 88a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidtstatic unsigned char *sndbuf; 89a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidtstatic struct msghdr rcvhdr; 90a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidtstatic struct iovec rcviov[2]; 91a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidtstatic unsigned char *rcvbuf; 92a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidtstatic unsigned char ansbuf[1500]; 93a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidtstatic char ntopbuf[INET6_ADDRSTRLEN]; 94a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt 95a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt#if DEBUG_MEMORY 96a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidtstatic void 97a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidtipv6rs_cleanup(void) 98a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt{ 99a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt 100a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt free(sndbuf); 101a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt free(rcvbuf); 102a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt} 103a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt#endif 104a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt 105a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidtint 106a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidtipv6rs_open(void) 107a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt{ 108a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt int on; 109a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt int len; 110a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt struct icmp6_filter filt; 111a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt 112a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt memset(&allrouters, 0, sizeof(allrouters)); 113a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt allrouters.sin6_family = AF_INET6; 114a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt#ifdef SIN6_LEN 115a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt allrouters.sin6_len = sizeof(allrouters); 116a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt#endif 117a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt if (inet_pton(AF_INET6, ALLROUTERS, &allrouters.sin6_addr.s6_addr) != 1) 118a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt return -1; 119a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); 120a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt if (sock == -1) 121a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt return -1; 122a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt on = 1; 123a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, 124a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt &on, sizeof(on)) == -1) 125a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt return -1; 126a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt 127a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt on = 1; 128a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, 129a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt &on, sizeof(on)) == -1) 130a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt return -1; 131a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt 132a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt ICMP6_FILTER_SETBLOCKALL(&filt); 133a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filt); 134a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt if (setsockopt(sock, IPPROTO_ICMPV6, ICMP6_FILTER, 135a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt &filt, sizeof(filt)) == -1) 136a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt return -1; 137a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt 138a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt#if DEBUG_MEMORY 139a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt atexit(ipv6rs_cleanup); 140a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt#endif 141a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt 142a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt len = CMSG_SPACE(sizeof(struct in6_pktinfo)) + CMSG_SPACE(sizeof(int)); 143a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt sndbuf = xzalloc(len); 144a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt if (sndbuf == NULL) 145a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt return -1; 146a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt sndhdr.msg_namelen = sizeof(struct sockaddr_in6); 147a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt sndhdr.msg_iov = sndiov; 148a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt sndhdr.msg_iovlen = 1; 149a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt sndhdr.msg_control = sndbuf; 150a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt sndhdr.msg_controllen = len; 151a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt rcvbuf = xzalloc(len); 152a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt if (rcvbuf == NULL) 153a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt return -1; 154a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt rcvhdr.msg_name = &from; 155a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt rcvhdr.msg_namelen = sizeof(from); 156a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt rcvhdr.msg_iov = rcviov; 157a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt rcvhdr.msg_iovlen = 1; 158a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt rcvhdr.msg_control = rcvbuf; 159a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt rcvhdr.msg_controllen = len; 160a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt rcviov[0].iov_base = ansbuf; 161a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt rcviov[0].iov_len = sizeof(ansbuf); 162a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt return sock; 163a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt} 164a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt 165a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidtstatic int 166a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidtipv6rs_makeprobe(struct interface *ifp) 167a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt{ 168a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt struct nd_router_solicit *rs; 169a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt struct nd_opt_hdr *nd; 170a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt 171a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt free(ifp->rs); 172a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt ifp->rslen = sizeof(*rs) + ROUNDUP8(ifp->hwlen + 2); 173a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt ifp->rs = xzalloc(ifp->rslen); 174a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt if (ifp->rs == NULL) 175a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt return -1; 176a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt rs = (struct nd_router_solicit *)ifp->rs; 177a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt rs->nd_rs_type = ND_ROUTER_SOLICIT; 178a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt rs->nd_rs_code = 0; 179a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt rs->nd_rs_cksum = 0; 180a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt rs->nd_rs_reserved = 0; 181a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt nd = (struct nd_opt_hdr *)(ifp->rs + sizeof(*rs)); 182a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt nd->nd_opt_type = ND_OPT_SOURCE_LINKADDR; 183a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt nd->nd_opt_len = (ROUNDUP8(ifp->hwlen + 2)) >> 3; 184a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt memcpy(nd + 1, ifp->hwaddr, ifp->hwlen); 185a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt return 0; 186a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt} 187a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt 188a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidtstatic void 189a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidtipv6rs_sendprobe(void *arg) 190a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt{ 191a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt struct interface *ifp = arg; 192a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt struct sockaddr_in6 dst; 193a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt struct cmsghdr *cm; 194a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt struct in6_pktinfo pi; 195a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt int hoplimit = HOPLIMIT; 196a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt 197a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt dst = allrouters; 198a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt //dst.sin6_scope_id = ifp->linkid; 199a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt 200a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt ipv6rs_makeprobe(ifp); 201a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt sndhdr.msg_name = (caddr_t)&dst; 202a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt sndhdr.msg_iov[0].iov_base = ifp->rs; 203a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt sndhdr.msg_iov[0].iov_len = ifp->rslen; 204a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt 205a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt /* Set the outbound interface */ 206a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt cm = CMSG_FIRSTHDR(&sndhdr); 207a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt cm->cmsg_level = IPPROTO_IPV6; 208a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt cm->cmsg_type = IPV6_PKTINFO; 209a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt cm->cmsg_len = CMSG_LEN(sizeof(pi)); 210a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt memset(&pi, 0, sizeof(pi)); 211a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt pi.ipi6_ifindex = if_nametoindex(ifp->name); 212a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt memcpy(CMSG_DATA(cm), &pi, sizeof(pi)); 213a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt 214a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt /* Hop limit */ 215a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt cm = CMSG_NXTHDR(&sndhdr, cm); 216a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt cm->cmsg_level = IPPROTO_IPV6; 217a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt cm->cmsg_type = IPV6_HOPLIMIT; 218a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt cm->cmsg_len = CMSG_LEN(sizeof(hoplimit)); 219a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt memcpy(CMSG_DATA(cm), &hoplimit, sizeof(hoplimit)); 220a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt 221a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt syslog(LOG_INFO, "%s: sending IPv6 Router Solicitation", ifp->name); 222a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt if (sendmsg(sock, &sndhdr, 0) == -1) 223a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt syslog(LOG_ERR, "%s: sendmsg: %m", ifp->name); 224a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt 225a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt if (ifp->rsprobes++ < MAX_RTR_SOLICITATIONS) 226a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt add_timeout_sec(RTR_SOLICITATION_INTERVAL, 227a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt ipv6rs_sendprobe, ifp); 228a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt else 229a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt syslog(LOG_INFO, "%s: no IPv6 Routers available", ifp->name); 230a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt} 231a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt 232a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidtstatic void 233a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidtipv6rs_sort(struct interface *ifp) 234a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt{ 235a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt struct ra *rap, *sorted, *ran, *rat; 236a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt 237a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt if (ifp->ras == NULL || ifp->ras->next == NULL) 238a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt return; 239a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt 240a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt /* Sort our RA's - most recent first */ 241a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt sorted = ifp->ras; 242a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt ifp->ras = ifp->ras->next; 243a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt sorted->next = NULL; 244a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt for (rap = ifp->ras; rap && (ran = rap->next, 1); rap = ran) { 245a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt /* Are we the new head? */ 246a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt if (timercmp(&rap->received, &sorted->received, <)) { 247a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt rap->next = sorted; 248a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt sorted = rap; 249a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt continue; 250a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt } 251a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt /* Do we fit in the middle? */ 252a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt for (rat = sorted; rat->next; rat = rat->next) { 253a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt if (timercmp(&rap->received, &rat->next->received, <)) { 254a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt rap->next = rat->next; 255a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt rat->next = rap; 256a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt break; 257a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt } 258a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt } 259a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt /* We must be at the end */ 260a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt if (!rat->next) { 261a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt rat->next = rap; 262a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt rap->next = NULL; 263a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt } 264a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt } 265a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt} 266a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt 267a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidtvoid 268a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidtipv6rs_handledata(_unused void *arg) 269a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt{ 270a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt ssize_t len, l, n, olen; 271a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt struct cmsghdr *cm; 272a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt int hoplimit; 273a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt struct in6_pktinfo pkt; 274a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt struct icmp6_hdr *icp; 275a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt struct interface *ifp; 276a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt const char *sfrom; 277a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt struct nd_router_advert *nd_ra; 278a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt struct nd_opt_prefix_info *pi; 279a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt struct nd_opt_mtu *mtu; 280a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt struct nd_opt_rdnss *rdnss; 281a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt struct nd_opt_dnssl *dnssl; 282a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt uint32_t lifetime; 283a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt uint8_t *p, *op; 284a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt struct in6_addr addr; 285a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt char buf[INET6_ADDRSTRLEN]; 286a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt const char *cbp; 287a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt struct ra *rap; 288a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt struct nd_opt_hdr *ndo; 289a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt struct ra_opt *rao, *raol; 290a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt char *opt; 291a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt struct timeval expire; 292a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt int has_dns; 293a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt 294a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt len = recvmsg(sock, &rcvhdr, 0); 295a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt if (len == -1) { 296a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt syslog(LOG_ERR, "recvmsg: %m"); 297a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt return; 298a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt } 299a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt sfrom = inet_ntop(AF_INET6, &from.sin6_addr, 300a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt ntopbuf, INET6_ADDRSTRLEN); 301a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt if ((size_t)len < sizeof(struct nd_router_advert)) { 302a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt syslog(LOG_ERR, "IPv6 RA packet too short from %s", sfrom); 303a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt return; 304a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt } 305a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt 306a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt pkt.ipi6_ifindex = hoplimit = 0; 307a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&rcvhdr); 308a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt cm; 309a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt cm = (struct cmsghdr *)CMSG_NXTHDR(&rcvhdr, cm)) 310a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt { 311a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt if (cm->cmsg_level != IPPROTO_IPV6) 312a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt continue; 313a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt switch(cm->cmsg_type) { 314a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt case IPV6_PKTINFO: 315a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt if (cm->cmsg_len == CMSG_LEN(sizeof(pkt))) 316a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt memcpy(&pkt, CMSG_DATA(cm), sizeof(pkt)); 317a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt break; 318a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt case IPV6_HOPLIMIT: 319a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt if (cm->cmsg_len == CMSG_LEN(sizeof(int))) 320a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt memcpy(&hoplimit, CMSG_DATA(cm), sizeof(int)); 321a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt break; 322a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt } 323a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt } 324a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt 325a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt if (pkt.ipi6_ifindex == 0 || hoplimit == 0) { 326a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt syslog(LOG_ERR, 327a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt "IPv6 RA did not contain index or hop limit from %s", 328a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt sfrom); 329a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt return; 330a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt } 331a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt 332a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt icp = (struct icmp6_hdr *)rcvhdr.msg_iov[0].iov_base; 333a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt if (icp->icmp6_type != ND_ROUTER_ADVERT || 334a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt icp->icmp6_code != 0) 335a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt { 336a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt syslog(LOG_ERR, "invalid IPv6 type or code from %s", sfrom); 337a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt return; 338a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt } 339a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt 340a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt if (!IN6_IS_ADDR_LINKLOCAL(&from.sin6_addr)) { 341a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt syslog(LOG_ERR, "RA recieved from non local IPv6 address %s", 342a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt sfrom); 343a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt return; 344a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt } 345a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt 346a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt for (ifp = ifaces; ifp; ifp = ifp->next) 347a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt if (if_nametoindex(ifp->name) == (unsigned int)pkt.ipi6_ifindex) 348a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt break; 349a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt if (ifp == NULL) { 350a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt syslog(LOG_ERR,"received RA for unexpected interface from %s", 351a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt sfrom); 352a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt return; 353a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt } 354a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt for (rap = ifp->ras; rap; rap = rap->next) { 355a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt if (memcmp(rap->from.s6_addr, from.sin6_addr.s6_addr, 356a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt sizeof(rap->from.s6_addr)) == 0) 357a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt break; 358a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt } 359a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt 360a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt /* We don't want to spam the log with the fact we got an RA every 361a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt * 30 seconds or so, so only spam the log if it's different. */ 362a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt if (options & DHCPCD_DEBUG || rap == NULL || 363a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt (rap->expired || rap->data_len != len || 364a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt memcmp(rap->data, (unsigned char *)icp, rap->data_len) != 0)) 365a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt { 366a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt if (rap) { 367a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt free(rap->data); 368a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt rap->data_len = 0; 369a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt } 370a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt syslog(LOG_INFO, "%s: Router Advertisement from %s", 371a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt ifp->name, sfrom); 372a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt } 373a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt 374a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt if (rap == NULL) { 375a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt rap = xmalloc(sizeof(*rap)); 376a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt rap->next = ifp->ras; 377a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt rap->options = NULL; 378a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt ifp->ras = rap; 379a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt memcpy(rap->from.s6_addr, from.sin6_addr.s6_addr, 380a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt sizeof(rap->from.s6_addr)); 381a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt strlcpy(rap->sfrom, sfrom, sizeof(rap->sfrom)); 382a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt rap->data_len = 0; 383a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt } 384a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt if (rap->data_len == 0) { 385a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt rap->data = xmalloc(len); 386a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt memcpy(rap->data, icp, len); 387a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt rap->data_len = len; 388a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt } 389a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt 390a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt get_monotonic(&rap->received); 391a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt nd_ra = (struct nd_router_advert *)icp; 392a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt rap->lifetime = ntohs(nd_ra->nd_ra_router_lifetime); 393a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt rap->expired = 0; 394a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt 395a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt len -= sizeof(struct nd_router_advert); 396a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt p = ((uint8_t *)icp) + sizeof(struct nd_router_advert); 397a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt olen = 0; 398a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt lifetime = ~0U; 399a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt has_dns = 0; 400a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt for (olen = 0; len > 0; p += olen, len -= olen) { 401a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt if ((size_t)len < sizeof(struct nd_opt_hdr)) { 402a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt syslog(LOG_ERR, "%s: Short option", ifp->name); 403a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt break; 404a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt } 405a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt ndo = (struct nd_opt_hdr *)p; 406a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt olen = ndo->nd_opt_len * 8 ; 407a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt if (olen == 0) { 408a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt syslog(LOG_ERR, "%s: zero length option", ifp->name); 409a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt break; 410a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt } 411a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt if (olen > len) { 412a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt syslog(LOG_ERR, 413a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt "%s: Option length exceeds message", ifp->name); 414a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt break; 415a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt } 416a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt 417a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt opt = NULL; 418a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt switch (ndo->nd_opt_type) { 419a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt case ND_OPT_PREFIX_INFORMATION: 420a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt pi = (struct nd_opt_prefix_info *)ndo; 421a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt if (pi->nd_opt_pi_len != 4) { 422a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt syslog(LOG_ERR, 423a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt "%s: invalid option len for prefix", 424a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt ifp->name); 425a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt break; 426a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt } 427a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt if (pi->nd_opt_pi_prefix_len > 128) { 428a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt syslog(LOG_ERR, "%s: invalid prefix len", 429a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt ifp->name); 430a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt break; 431a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt } 432a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt if (IN6_IS_ADDR_MULTICAST(&pi->nd_opt_pi_prefix) || 433a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt IN6_IS_ADDR_LINKLOCAL(&pi->nd_opt_pi_prefix)) 434a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt { 435a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt syslog(LOG_ERR, 436a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt "%s: invalid prefix in RA", ifp->name); 437a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt break; 438a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt } 439a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt opt = xstrdup(inet_ntop(AF_INET6, 440a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt pi->nd_opt_pi_prefix.s6_addr, 441a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt ntopbuf, INET6_ADDRSTRLEN)); 442a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt if (opt) { 443a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt rap->prefix_len = pi->nd_opt_pi_prefix_len; 444a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt rap->prefix_vltime = 445a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt ntohl(pi->nd_opt_pi_valid_time); 446a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt rap->prefix_pltime = 447a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt ntohl(pi->nd_opt_pi_preferred_time); 448a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt } 449a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt break; 450a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt 451a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt case ND_OPT_MTU: 452a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt mtu = (struct nd_opt_mtu *)p; 453a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt snprintf(buf, sizeof(buf), "%d", 454a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt ntohl(mtu->nd_opt_mtu_mtu)); 455a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt opt = xstrdup(buf); 456a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt break; 457a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt 458a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt case ND_OPT_RDNSS: 459a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt rdnss = (struct nd_opt_rdnss *)p; 460a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt lifetime = ntohl(rdnss->nd_opt_rdnss_lifetime); 461a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt op = (uint8_t *)ndo; 462a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt op += offsetof(struct nd_opt_rdnss, 463a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt nd_opt_rdnss_lifetime); 464a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt op += sizeof(rdnss->nd_opt_rdnss_lifetime); 465a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt l = 0; 466a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt for (n = ndo->nd_opt_len - 1; n > 1; n -= 2) { 467a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt memcpy(&addr.s6_addr, op, sizeof(addr.s6_addr)); 468a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt cbp = inet_ntop(AF_INET6, &addr, 469a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt ntopbuf, INET6_ADDRSTRLEN); 470a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt if (cbp == NULL) { 471a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt syslog(LOG_ERR, 472a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt "%s: invalid RDNSS address", 473a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt ifp->name); 474a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt } else { 475a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt if (opt) { 476a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt l = strlen(opt); 477a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt opt = xrealloc(opt, 478a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt l + strlen(cbp) + 2); 479a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt opt[l] = ' '; 480a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt strcpy(opt + l + 1, cbp); 481a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt } else 482a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt opt = xstrdup(cbp); 483a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt if (lifetime > 0) 484a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt has_dns = 1; 485a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt } 486a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt op += sizeof(addr.s6_addr); 487a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt } 488a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt break; 489a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt 490a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt case ND_OPT_DNSSL: 491a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt dnssl = (struct nd_opt_dnssl *)p; 492a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt lifetime = ntohl(dnssl->nd_opt_dnssl_lifetime); 493a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt op = p + offsetof(struct nd_opt_dnssl, 494a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt nd_opt_dnssl_lifetime); 495a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt op += sizeof(dnssl->nd_opt_dnssl_lifetime); 496a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt n = (dnssl->nd_opt_dnssl_len - 1) * 8; 497a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt l = decode_rfc3397(NULL, 0, n, op); 498a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt if (l < 1) { 499a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt syslog(LOG_ERR, "%s: invalid DNSSL option", 500a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt ifp->name); 501a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt } else { 502a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt opt = xmalloc(l); 503a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt decode_rfc3397(opt, l, n, op); 504a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt } 505a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt break; 506a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt } 507a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt 508a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt if (opt == NULL) 509a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt continue; 510a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt for (raol = NULL, rao = rap->options; 511a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt rao; 512a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt raol = rao, rao = rao->next) 513a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt { 514a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt if (rao->type == ndo->nd_opt_type && 515a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt strcmp(rao->option, opt) == 0) 516a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt break; 517a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt } 518a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt if (lifetime == 0) { 519a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt if (rao) { 520a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt if (raol) 521a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt raol->next = rao->next; 522a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt else 523a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt rap->options = rao->next; 524a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt free(rao->option); 525a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt free(rao); 526a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt } 527a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt continue; 528a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt } 529a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt 530a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt if (rao == NULL) { 531a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt rao = xmalloc(sizeof(*rao)); 532a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt rao->next = rap->options; 533a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt rap->options = rao; 534a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt rao->type = ndo->nd_opt_type; 535a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt rao->option = opt; 536a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt } else 537a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt free(opt); 538a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt if (lifetime == ~0U) 539a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt timerclear(&rao->expire); 540a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt else { 541a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt expire.tv_sec = lifetime; 542a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt expire.tv_usec = 0; 543a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt timeradd(&rap->received, &expire, &rao->expire); 544a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt } 545a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt } 546a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt 547a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt ipv6rs_sort(ifp); 548a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt run_script_reason(ifp, options & DHCPCD_TEST ? "TEST" : "ROUTERADVERT"); 549a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt if (options & DHCPCD_TEST) 550a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt exit(EXIT_SUCCESS); 551a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt 552a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt /* If we don't require RDNSS then set has_dns = 1 so we fork */ 553a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt if (!(ifp->state->options->options & DHCPCD_IPV6RA_REQRDNSS)) 554a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt has_dns = 1; 555a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt 556a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt if (has_dns) 557a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt delete_q_timeout(0, handle_exit_timeout, NULL); 558a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt delete_timeout(NULL, ifp); 559a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt ipv6rs_expire(ifp); 560a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt if (has_dns) 561a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt daemonise(); 562a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt else if (options & DHCPCD_DAEMONISE && !(options & DHCPCD_DAEMONISED)) 563a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt syslog(LOG_WARNING, 564a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt "%s: did not fork due to an absent RDNSS option in the RA", 565a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt ifp->name); 566a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt} 567a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt 568a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidtssize_t 569a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidtipv6rs_env(char **env, const char *prefix, const struct interface *ifp) 570a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt{ 571a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt ssize_t l; 572a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt struct timeval now; 573a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt const struct ra *rap; 574a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt const struct ra_opt *rao; 575a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt int i; 576a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt char buffer[32], buffer2[32]; 577a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt const char *optn; 578a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt 579a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt l = 0; 580a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt get_monotonic(&now); 581a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt for (rap = ifp->ras, i = 1; rap; rap = rap->next, i++) { 582a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt if (env) { 583a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt snprintf(buffer, sizeof(buffer), 584a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt "ra%d_from", i); 585a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt setvar(&env, prefix, buffer, rap->sfrom); 586a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt } 587a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt l++; 588a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt 589a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt for (rao = rap->options; rao; rao = rao->next) { 590a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt if (rao->option == NULL) 591a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt continue; 592a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt if (env == NULL) { 593a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt switch (rao->type) { 594a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt case ND_OPT_PREFIX_INFORMATION: 595a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt l += 4; 596a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt break; 597a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt default: 598a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt l++; 599a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt } 600a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt continue; 601a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt } 602a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt switch (rao->type) { 603a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt case ND_OPT_PREFIX_INFORMATION: 604a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt optn = "prefix"; 605a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt break; 606a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt case ND_OPT_MTU: 607a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt optn = "mtu"; 608a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt break; 609a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt case ND_OPT_RDNSS: 610a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt optn = "rdnss"; 611a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt break; 612a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt case ND_OPT_DNSSL: 613a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt optn = "dnssl"; 614a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt break; 615a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt default: 616a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt continue; 617a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt } 618a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt snprintf(buffer, sizeof(buffer), "ra%d_%s", i, optn); 619a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt setvar(&env, prefix, buffer, rao->option); 620a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt l++; 621a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt switch (rao->type) { 622a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt case ND_OPT_PREFIX_INFORMATION: 623a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt snprintf(buffer, sizeof(buffer), 624a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt "ra%d_prefix_len", i); 625a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt snprintf(buffer2, sizeof(buffer2), 626a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt "%d", rap->prefix_len); 627a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt setvar(&env, prefix, buffer, buffer2); 628a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt 629a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt snprintf(buffer, sizeof(buffer), 630a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt "ra%d_prefix_vltime", i); 631a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt snprintf(buffer2, sizeof(buffer2), 632a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt "%d", rap->prefix_vltime); 633a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt setvar(&env, prefix, buffer, buffer2); 634a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt 635a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt snprintf(buffer, sizeof(buffer), 636a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt "ra%d_prefix_pltime", i); 637a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt snprintf(buffer2, sizeof(buffer2), 638a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt "%d", rap->prefix_pltime); 639a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt setvar(&env, prefix, buffer, buffer2); 640a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt l += 3; 641a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt break; 642a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt } 643a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt 644a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt } 645a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt } 646a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt 647a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt if (env) 648a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt setvard(&env, prefix, "ra_count", i - 1); 649a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt l++; 650a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt return l; 651a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt} 652a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt 653a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidtstatic void 654a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidtipv6rs_free_opts(struct ra *rap) 655a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt{ 656a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt struct ra_opt *rao, *raon; 657a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt 658a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt for (rao = rap->options; rao && (raon = rao->next, 1); rao = raon) { 659a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt free(rao->option); 660a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt free(rao); 661a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt } 662a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt} 663a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt 664a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidtvoid 665a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidtipv6rs_free(struct interface *ifp) 666a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt{ 667a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt struct ra *rap, *ran; 668a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt 669a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt free(ifp->rs); 670a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt ifp->rs = NULL; 671a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt for (rap = ifp->ras; rap && (ran = rap->next, 1); rap = ran) { 672a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt ipv6rs_free_opts(rap); 673a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt free(rap->data); 674a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt free(rap); 675a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt } 676a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt ifp->ras = NULL; 677a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt} 678a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt 679a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidtvoid 680a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidtipv6rs_expire(void *arg) 681a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt{ 682a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt struct interface *ifp; 683a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt struct ra *rap, *ran, *ral; 684a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt struct ra_opt *rao, *raol, *raon; 685a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt struct timeval now, lt, expire, next; 686a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt int expired; 687a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt uint32_t expire_secs; 688a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt 689a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt ifp = arg; 690a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt get_monotonic(&now); 691a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt expired = 0; 692a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt expire_secs = ~0U; 693a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt timerclear(&next); 694a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt 695a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt for (rap = ifp->ras, ral = NULL; 696a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt rap && (ran = rap->next, 1); 697a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt ral = rap, rap = ran) 698a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt { 699a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt lt.tv_sec = rap->lifetime; 700a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt lt.tv_usec = 0; 701a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt timeradd(&rap->received, <, &expire); 702a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt if (timercmp(&now, &expire, >)) { 703a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt syslog(LOG_INFO, "%s: %s: expired Router Advertisement", 704a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt ifp->name, rap->sfrom); 705a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt rap->expired = expired = 1; 706a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt if (ral) 707a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt ral->next = ran; 708a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt else 709a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt ifp->ras = ran; 710a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt ipv6rs_free_opts(rap); 711a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt free(rap); 712a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt continue; 713a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt } 714a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt timersub(&expire, &now, <); 715a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt if (!timerisset(&next) || timercmp(&next, <, >)) 716a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt next = lt; 717a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt 718a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt for (rao = rap->options, raol = NULL; 719a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt rao && (raon = rao->next); 720a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt raol = rao, rao = raon) 721a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt { 722a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt if (!timerisset(&rao->expire)) 723a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt continue; 724a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt if (timercmp(&now, &rao->expire, >)) { 725a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt syslog(LOG_INFO, 726a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt "%s: %s: expired option %d", 727a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt ifp->name, rap->sfrom, rao->type); 728a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt rap->expired = expired = 1; 729a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt if (raol) 730a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt raol = raon; 731a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt else 732a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt rap->options = raon; 733a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt continue; 734a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt } 735a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt timersub(&rao->expire, &now, <); 736a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt if (!timerisset(&next) || timercmp(&next, <, >)) 737a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt next = lt; 738a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt } 739a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt } 740a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt 741a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt if (timerisset(&next)) 742a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt add_timeout_tv(&next, ipv6rs_expire, ifp); 743a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt if (expired) 744a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt run_script_reason(ifp, "ROUTERADVERT"); 745a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt} 746a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt 747a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidtint 748a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidtipv6rs_start(struct interface *ifp) 749a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt{ 750a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt 751a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt delete_timeout(NULL, ifp); 752a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt 753a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt /* Always make a new probe as the underlying hardware 754a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt * address could have changed. */ 755a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt ipv6rs_makeprobe(ifp); 756a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt if (ifp->rs == NULL) 757a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt return -1; 758a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt 759a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt ifp->rsprobes = 0; 760a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt ipv6rs_sendprobe(ifp); 761a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt return 0; 762a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt} 763