Tue Apr 21 12:16:47 2020 UTC ()
rtadvd: Remove disabled use of SIOCGIFPREFIX_IN6

It's not been enabled since the functionality was added to ifconfig(8)
many many years ago.


(roy)
diff -r1.43 -r1.44 src/usr.sbin/rtadvd/config.c
diff -r1.10 -r1.11 src/usr.sbin/rtadvd/config.h
diff -r1.72 -r1.73 src/usr.sbin/rtadvd/rtadvd.c

cvs diff -r1.43 -r1.44 src/usr.sbin/rtadvd/config.c (switch to unified diff)

--- src/usr.sbin/rtadvd/config.c 2019/11/11 13:42:49 1.43
+++ src/usr.sbin/rtadvd/config.c 2020/04/21 12:16:47 1.44
@@ -1,1308 +1,1237 @@ @@ -1,1308 +1,1237 @@
1/* $NetBSD: config.c,v 1.43 2019/11/11 13:42:49 roy Exp $ */ 1/* $NetBSD: config.c,v 1.44 2020/04/21 12:16:47 roy Exp $ */
2/* $KAME: config.c,v 1.93 2005/10/17 14:40:02 suz Exp $ */ 2/* $KAME: config.c,v 1.93 2005/10/17 14:40:02 suz Exp $ */
3 3
4/* 4/*
5 * Copyright (C) 1998 WIDE Project. 5 * Copyright (C) 1998 WIDE Project.
6 * All rights reserved. 6 * All rights reserved.
7 * 7 *
8 * Redistribution and use in source and binary forms, with or without 8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions 9 * modification, are permitted provided that the following conditions
10 * are met: 10 * are met:
11 * 1. Redistributions of source code must retain the above copyright 11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer. 12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright 13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the 14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution. 15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the project nor the names of its contributors 16 * 3. Neither the name of the project nor the names of its contributors
17 * may be used to endorse or promote products derived from this software 17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission. 18 * without specific prior written permission.
19 * 19 *
20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE. 30 * SUCH DAMAGE.
31 */ 31 */
32 32
33#include <sys/param.h> 33#include <sys/param.h>
34#include <sys/ioctl.h> 34#include <sys/ioctl.h>
35#include <sys/socket.h> 35#include <sys/socket.h>
36#include <sys/time.h> 36#include <sys/time.h>
37#include <sys/sysctl.h> 37#include <sys/sysctl.h>
38 38
39#include <net/if.h> 39#include <net/if.h>
40#include <net/route.h> 40#include <net/route.h>
41#include <net/if_dl.h> 41#include <net/if_dl.h>
42#ifdef __FreeBSD__ 42#ifdef __FreeBSD__
43#include <net/if_var.h> 43#include <net/if_var.h>
44#endif 44#endif
45 45
46#include <netinet/in.h> 46#include <netinet/in.h>
47#include <netinet/in_var.h> 47#include <netinet/in_var.h>
48#include <netinet/ip6.h> 48#include <netinet/ip6.h>
49#include <netinet6/ip6_var.h> 49#include <netinet6/ip6_var.h>
50#include <netinet/icmp6.h> 50#include <netinet/icmp6.h>
51#include <netinet6/nd6.h> 51#include <netinet6/nd6.h>
52 52
53#include <arpa/inet.h> 53#include <arpa/inet.h>
54 54
55#include <stdio.h> 55#include <stdio.h>
56#include <syslog.h> 56#include <syslog.h>
57#include <errno.h> 57#include <errno.h>
58#include <string.h> 58#include <string.h>
59#include <stdlib.h> 59#include <stdlib.h>
60#include <search.h> 60#include <search.h>
61#include <unistd.h> 61#include <unistd.h>
62#include <ifaddrs.h> 62#include <ifaddrs.h>
63#include <inttypes.h> 63#include <inttypes.h>
64 64
65#include "rtadvd.h" 65#include "rtadvd.h"
66#include "advcap.h" 66#include "advcap.h"
67#include "timer.h" 67#include "timer.h"
68#include "if.h" 68#include "if.h"
69#include "config.h" 69#include "config.h"
70#include "logit.h" 70#include "logit.h"
71#include "prog_ops.h" 71#include "prog_ops.h"
72 72
73#ifndef __arraycount 73#ifndef __arraycount
74#define __arraycount(__x) (sizeof(__x) / sizeof(__x[0])) 74#define __arraycount(__x) (sizeof(__x) / sizeof(__x[0]))
75#endif 75#endif
76 76
77static time_t prefix_timo = (60 * 120); /* 2 hours. 77static time_t prefix_timo = (60 * 120); /* 2 hours.
78 * XXX: should be configurable. */ 78 * XXX: should be configurable. */
79static struct rtadvd_timer *prefix_timeout(void *); 79static struct rtadvd_timer *prefix_timeout(void *);
80static void makeentry(char *, size_t, int, const char *); 80static void makeentry(char *, size_t, int, const char *);
81static int getinet6sysctl(int); 81static int getinet6sysctl(int);
82 82
83static size_t 83static size_t
84encode_domain(char *dst, const char *src) 84encode_domain(char *dst, const char *src)
85{ 85{
86 ssize_t len; 86 ssize_t len;
87 char *odst, *p; 87 char *odst, *p;
88 88
89 odst = dst; 89 odst = dst;
90 while (src && (len = strlen(src)) != 0) { 90 while (src && (len = strlen(src)) != 0) {
91 p = strchr(src, '.'); 91 p = strchr(src, '.');
92 *dst++ = len = MIN(63, p == NULL ? len : p - src); 92 *dst++ = len = MIN(63, p == NULL ? len : p - src);
93 memcpy(dst, src, len); 93 memcpy(dst, src, len);
94 dst += len; 94 dst += len;
95 if (p == NULL) 95 if (p == NULL)
96 break; 96 break;
97 src = p + 1; 97 src = p + 1;
98 } 98 }
99 *dst++ = '\0'; 99 *dst++ = '\0';
100 100
101 return dst - odst; 101 return dst - odst;
102} 102}
103 103
104void 104void
105free_rainfo(struct rainfo *rai) 105free_rainfo(struct rainfo *rai)
106{ 106{
107 struct soliciter *sol; 107 struct soliciter *sol;
108 struct prefix *pfx; 108 struct prefix *pfx;
109 struct rtinfo *rti; 109 struct rtinfo *rti;
110 struct rdnss *rdnss; 110 struct rdnss *rdnss;
111 struct rdnss_addr *rdnsa; 111 struct rdnss_addr *rdnsa;
112 struct dnssl *dnssl; 112 struct dnssl *dnssl;
113 struct dnssl_domain *dnsd; 113 struct dnssl_domain *dnsd;
114 114
115 rtadvd_remove_timer(&rai->timer); 115 rtadvd_remove_timer(&rai->timer);
116 rtadvd_remove_timer(&rai->timer_sol); 116 rtadvd_remove_timer(&rai->timer_sol);
117 117
118 while ((sol = TAILQ_FIRST(&rai->soliciter))) { 118 while ((sol = TAILQ_FIRST(&rai->soliciter))) {
119 TAILQ_REMOVE(&rai->soliciter, sol, next); 119 TAILQ_REMOVE(&rai->soliciter, sol, next);
120 free(sol); 120 free(sol);
121 } 121 }
122 122
123 while ((pfx = TAILQ_FIRST(&rai->prefix))) { 123 while ((pfx = TAILQ_FIRST(&rai->prefix))) {
124 TAILQ_REMOVE(&rai->prefix, pfx, next); 124 TAILQ_REMOVE(&rai->prefix, pfx, next);
125 free(pfx); 125 free(pfx);
126 } 126 }
127 127
128 while ((rti = TAILQ_FIRST(&rai->route))) { 128 while ((rti = TAILQ_FIRST(&rai->route))) {
129 TAILQ_REMOVE(&rai->route, rti, next); 129 TAILQ_REMOVE(&rai->route, rti, next);
130 free(rti); 130 free(rti);
131 } 131 }
132 132
133 while ((rdnss = TAILQ_FIRST(&rai->rdnss))) { 133 while ((rdnss = TAILQ_FIRST(&rai->rdnss))) {
134 TAILQ_REMOVE(&rai->rdnss, rdnss, next); 134 TAILQ_REMOVE(&rai->rdnss, rdnss, next);
135 while ((rdnsa = TAILQ_FIRST(&rdnss->list))) { 135 while ((rdnsa = TAILQ_FIRST(&rdnss->list))) {
136 TAILQ_REMOVE(&rdnss->list, rdnsa, next); 136 TAILQ_REMOVE(&rdnss->list, rdnsa, next);
137 free(rdnsa); 137 free(rdnsa);
138 } 138 }
139 free(rdnss); 139 free(rdnss);
140 } 140 }
141 141
142 while ((dnssl = TAILQ_FIRST(&rai->dnssl))) { 142 while ((dnssl = TAILQ_FIRST(&rai->dnssl))) {
143 TAILQ_REMOVE(&rai->dnssl, dnssl, next); 143 TAILQ_REMOVE(&rai->dnssl, dnssl, next);
144 while ((dnsd = TAILQ_FIRST(&dnssl->list))) { 144 while ((dnsd = TAILQ_FIRST(&dnssl->list))) {
145 TAILQ_REMOVE(&dnssl->list, dnsd, next); 145 TAILQ_REMOVE(&dnssl->list, dnsd, next);
146 free(dnsd); 146 free(dnsd);
147 } 147 }
148 free(dnssl); 148 free(dnssl);
149 } 149 }
150 150
151 free(rai->sdl); 151 free(rai->sdl);
152 free(rai->ra_data); 152 free(rai->ra_data);
153 free(rai); 153 free(rai);
154} 154}
155 155
156void 156void
157getconfig(const char *intface, int exithard) 157getconfig(const char *intface, int exithard)
158{ 158{
159 int stat, c, i; 159 int stat, c, i;
160 char tbuf[BUFSIZ]; 160 char tbuf[BUFSIZ];
161 struct rainfo *tmp, *rai; 161 struct rainfo *tmp, *rai;
162 int32_t val; 162 int32_t val;
163 int64_t val64; 163 int64_t val64;
164 char buf[BUFSIZ]; 164 char buf[BUFSIZ];
165 char *bp = buf; 165 char *bp = buf;
166 char *addr, *flagstr, *ap; 166 char *addr, *flagstr, *ap;
167 static int forwarding = -1; 167 static int forwarding = -1;
168 char entbuf[256], abuf[256]; 168 char entbuf[256], abuf[256];
169 struct rdnss *rdnss; 169 struct rdnss *rdnss;
170 struct dnssl *dnssl; 170 struct dnssl *dnssl;
171 171
172#define MUSTHAVE(var, cap) \ 172#define MUSTHAVE(var, cap) \
173 do { \ 173 do { \
174 int64_t t; \ 174 int64_t t; \
175 if ((t = agetnum(cap)) < 0) { \ 175 if ((t = agetnum(cap)) < 0) { \
176 fprintf(stderr, "rtadvd: need %s for interface %s\n", \ 176 fprintf(stderr, "rtadvd: need %s for interface %s\n", \
177 cap, intface); \ 177 cap, intface); \
178 goto errexit; \ 178 goto errexit; \
179 } \ 179 } \
180 var = t; \ 180 var = t; \
181 } while (0) 181 } while (0)
182#define MAYHAVE(var, cap, def) \ 182#define MAYHAVE(var, cap, def) \
183 do { \ 183 do { \
184 if ((var = agetnum(cap)) < 0) \ 184 if ((var = agetnum(cap)) < 0) \
185 var = def; \ 185 var = def; \
186 } while (0) 186 } while (0)
187#define ELM_MALLOC(p) \ 187#define ELM_MALLOC(p) \
188 do { \ 188 do { \
189 p = calloc(1, sizeof(*p)); \ 189 p = calloc(1, sizeof(*p)); \
190 if (p == NULL) { \ 190 if (p == NULL) { \
191 logit(LOG_ERR, "<%s> calloc failed: %m", \ 191 logit(LOG_ERR, "<%s> calloc failed: %m", \
192 __func__); \ 192 __func__); \
193 goto errexit; \ 193 goto errexit; \
194 } \ 194 } \
195 } while(/*CONSTCOND*/0) 195 } while(/*CONSTCOND*/0)
196 196
197 if (if_nametoindex(intface) == 0) { 197 if (if_nametoindex(intface) == 0) {
198 logit(LOG_INFO, "<%s> interface %s not found, ignoring", 198 logit(LOG_INFO, "<%s> interface %s not found, ignoring",
199 __func__, intface); 199 __func__, intface);
200 return; 200 return;
201 } 201 }
202 202
203 logit(LOG_DEBUG, "<%s> loading configuration for interface %s", 203 logit(LOG_DEBUG, "<%s> loading configuration for interface %s",
204 __func__, intface); 204 __func__, intface);
205 205
206 if ((stat = agetent(tbuf, intface)) <= 0) { 206 if ((stat = agetent(tbuf, intface)) <= 0) {
207 memset(tbuf, 0, sizeof(tbuf)); 207 memset(tbuf, 0, sizeof(tbuf));
208 logit(LOG_INFO, 208 logit(LOG_INFO,
209 "<%s> %s isn't defined in the configuration file" 209 "<%s> %s isn't defined in the configuration file"
210 " or the configuration file doesn't exist." 210 " or the configuration file doesn't exist."
211 " Treat it as default", 211 " Treat it as default",
212 __func__, intface); 212 __func__, intface);
213 } 213 }
214 214
215 ELM_MALLOC(tmp); 215 ELM_MALLOC(tmp);
216 TAILQ_INIT(&tmp->soliciter); 216 TAILQ_INIT(&tmp->soliciter);
217 TAILQ_INIT(&tmp->prefix); 217 TAILQ_INIT(&tmp->prefix);
218 TAILQ_INIT(&tmp->route); 218 TAILQ_INIT(&tmp->route);
219 TAILQ_INIT(&tmp->rdnss); 219 TAILQ_INIT(&tmp->rdnss);
220 TAILQ_INIT(&tmp->dnssl); 220 TAILQ_INIT(&tmp->dnssl);
221 221
222 /* check if we are allowed to forward packets (if not determined) */ 222 /* check if we are allowed to forward packets (if not determined) */
223 if (forwarding < 0) { 223 if (forwarding < 0) {
224 if ((forwarding = getinet6sysctl(IPV6CTL_FORWARDING)) < 0) 224 if ((forwarding = getinet6sysctl(IPV6CTL_FORWARDING)) < 0)
225 exit(1); 225 exit(1);
226 } 226 }
227 227
228 /* get interface information */ 228 /* get interface information */
229 if (agetflag("nolladdr")) 229 if (agetflag("nolladdr"))
230 tmp->advlinkopt = 0; 230 tmp->advlinkopt = 0;
231 else 231 else
232 tmp->advlinkopt = 1; 232 tmp->advlinkopt = 1;
233 if (tmp->advlinkopt) { 233 if (tmp->advlinkopt) {
234 if ((tmp->sdl = if_nametosdl(intface)) == NULL) { 234 if ((tmp->sdl = if_nametosdl(intface)) == NULL) {
235 logit(LOG_ERR, 235 logit(LOG_ERR,
236 "<%s> can't get information of %s", 236 "<%s> can't get information of %s",
237 __func__, intface); 237 __func__, intface);
238 goto errexit; 238 goto errexit;
239 } 239 }
240 tmp->ifindex = tmp->sdl->sdl_index; 240 tmp->ifindex = tmp->sdl->sdl_index;
241 } else { 241 } else {
242 tmp->ifindex = if_nametoindex(intface); 242 tmp->ifindex = if_nametoindex(intface);
243 if (tmp->ifindex == 0) { 243 if (tmp->ifindex == 0) {
244 logit(LOG_ERR, 244 logit(LOG_ERR,
245 "<%s> can't get information of %s", 245 "<%s> can't get information of %s",
246 __func__, intface); 246 __func__, intface);
247 goto errexit; 247 goto errexit;
248 } 248 }
249 } 249 }
250 tmp->ifflags = if_getflags(tmp->ifindex, 0); 250 tmp->ifflags = if_getflags(tmp->ifindex, 0);
251 strlcpy(tmp->ifname, intface, sizeof(tmp->ifname)); 251 strlcpy(tmp->ifname, intface, sizeof(tmp->ifname));
252 if ((tmp->phymtu = if_getmtu(intface)) == 0) { 252 if ((tmp->phymtu = if_getmtu(intface)) == 0) {
253 tmp->phymtu = IPV6_MMTU; 253 tmp->phymtu = IPV6_MMTU;
254 logit(LOG_WARNING, 254 logit(LOG_WARNING,
255 "<%s> can't get interface mtu of %s. Treat as %d", 255 "<%s> can't get interface mtu of %s. Treat as %d",
256 __func__, intface, IPV6_MMTU); 256 __func__, intface, IPV6_MMTU);
257 } 257 }
258 258
259 /* 259 /*
260 * set router configuration variables. 260 * set router configuration variables.
261 */ 261 */
262 MAYHAVE(val, "maxinterval", DEF_MAXRTRADVINTERVAL); 262 MAYHAVE(val, "maxinterval", DEF_MAXRTRADVINTERVAL);
263 if (val < MIN_MAXINTERVAL || val > MAX_MAXINTERVAL) { 263 if (val < MIN_MAXINTERVAL || val > MAX_MAXINTERVAL) {
264 logit(LOG_ERR, 264 logit(LOG_ERR,
265 "<%s> maxinterval (%d) on %s is invalid " 265 "<%s> maxinterval (%d) on %s is invalid "
266 "(must be between %u and %u)", __func__, val, 266 "(must be between %u and %u)", __func__, val,
267 intface, MIN_MAXINTERVAL, MAX_MAXINTERVAL); 267 intface, MIN_MAXINTERVAL, MAX_MAXINTERVAL);
268 goto errexit; 268 goto errexit;
269 } 269 }
270 tmp->maxinterval = val; 270 tmp->maxinterval = val;
271 MAYHAVE(val, "mininterval", tmp->maxinterval/3); 271 MAYHAVE(val, "mininterval", tmp->maxinterval/3);
272 if (val < MIN_MININTERVAL || val > (tmp->maxinterval * 3) / 4) { 272 if (val < MIN_MININTERVAL || val > (tmp->maxinterval * 3) / 4) {
273 logit(LOG_ERR, 273 logit(LOG_ERR,
274 "<%s> mininterval (%d) on %s is invalid " 274 "<%s> mininterval (%d) on %s is invalid "
275 "(must be between %u and %d)", 275 "(must be between %u and %d)",
276 __func__, val, intface, MIN_MININTERVAL, 276 __func__, val, intface, MIN_MININTERVAL,
277 (tmp->maxinterval * 3) / 4); 277 (tmp->maxinterval * 3) / 4);
278 goto errexit; 278 goto errexit;
279 } 279 }
280 tmp->mininterval = val; 280 tmp->mininterval = val;
281 281
282 MAYHAVE(val, "chlim", DEF_ADVCURHOPLIMIT); 282 MAYHAVE(val, "chlim", DEF_ADVCURHOPLIMIT);
283 tmp->hoplimit = val & 0xff; 283 tmp->hoplimit = val & 0xff;
284 284
285 if ((flagstr = (char *)agetstr("raflags", &bp))) { 285 if ((flagstr = (char *)agetstr("raflags", &bp))) {
286 val = 0; 286 val = 0;
287 if (strchr(flagstr, 'm')) 287 if (strchr(flagstr, 'm'))
288 val |= ND_RA_FLAG_MANAGED; 288 val |= ND_RA_FLAG_MANAGED;
289 if (strchr(flagstr, 'o')) 289 if (strchr(flagstr, 'o'))
290 val |= ND_RA_FLAG_OTHER; 290 val |= ND_RA_FLAG_OTHER;
291 if (strchr(flagstr, 'h')) 291 if (strchr(flagstr, 'h'))
292 val |= ND_RA_FLAG_RTPREF_HIGH; 292 val |= ND_RA_FLAG_RTPREF_HIGH;
293 if (strchr(flagstr, 'l')) { 293 if (strchr(flagstr, 'l')) {
294 if ((val & ND_RA_FLAG_RTPREF_HIGH)) { 294 if ((val & ND_RA_FLAG_RTPREF_HIGH)) {
295 logit(LOG_ERR, "<%s> the \'h\' and \'l\'" 295 logit(LOG_ERR, "<%s> the \'h\' and \'l\'"
296 " router flags are exclusive", __func__); 296 " router flags are exclusive", __func__);
297 goto errexit; 297 goto errexit;
298 } 298 }
299 val |= ND_RA_FLAG_RTPREF_LOW; 299 val |= ND_RA_FLAG_RTPREF_LOW;
300 } 300 }
301 } else { 301 } else {
302 MAYHAVE(val, "raflags", 0); 302 MAYHAVE(val, "raflags", 0);
303 } 303 }
304 tmp->managedflg = val & ND_RA_FLAG_MANAGED; 304 tmp->managedflg = val & ND_RA_FLAG_MANAGED;
305 tmp->otherflg = val & ND_RA_FLAG_OTHER; 305 tmp->otherflg = val & ND_RA_FLAG_OTHER;
306#ifndef ND_RA_FLAG_RTPREF_MASK 306#ifndef ND_RA_FLAG_RTPREF_MASK
307#define ND_RA_FLAG_RTPREF_MASK 0x18 /* 00011000 */ 307#define ND_RA_FLAG_RTPREF_MASK 0x18 /* 00011000 */
308#define ND_RA_FLAG_RTPREF_RSV 0x10 /* 00010000 */ 308#define ND_RA_FLAG_RTPREF_RSV 0x10 /* 00010000 */
309#endif 309#endif
310 tmp->rtpref = val & ND_RA_FLAG_RTPREF_MASK; 310 tmp->rtpref = val & ND_RA_FLAG_RTPREF_MASK;
311 if (tmp->rtpref == ND_RA_FLAG_RTPREF_RSV) { 311 if (tmp->rtpref == ND_RA_FLAG_RTPREF_RSV) {
312 logit(LOG_ERR, "<%s> invalid router preference (%02x) on %s", 312 logit(LOG_ERR, "<%s> invalid router preference (%02x) on %s",
313 __func__, tmp->rtpref, intface); 313 __func__, tmp->rtpref, intface);
314 goto errexit; 314 goto errexit;
315 } 315 }
316 316
317 MAYHAVE(val, "rltime", DEF_ADVROUTERLIFETIME); 317 MAYHAVE(val, "rltime", DEF_ADVROUTERLIFETIME);
318 if (val && (val < tmp->maxinterval || val > MAXROUTERLIFETIME)) { 318 if (val && (val < tmp->maxinterval || val > MAXROUTERLIFETIME)) {
319 logit(LOG_ERR, 319 logit(LOG_ERR,
320 "<%s> router lifetime (%d) on %s is invalid " 320 "<%s> router lifetime (%d) on %s is invalid "
321 "(must be 0 or between %d and %d)", 321 "(must be 0 or between %d and %d)",
322 __func__, val, intface, 322 __func__, val, intface,
323 tmp->maxinterval, MAXROUTERLIFETIME); 323 tmp->maxinterval, MAXROUTERLIFETIME);
324 goto errexit; 324 goto errexit;
325 } 325 }
326 /* 326 /*
327 * Basically, hosts MUST NOT send Router Advertisement messages at any 327 * Basically, hosts MUST NOT send Router Advertisement messages at any
328 * time (RFC 2461, Section 6.2.3). However, it would sometimes be 328 * time (RFC 2461, Section 6.2.3). However, it would sometimes be
329 * useful to allow hosts to advertise some parameters such as prefix 329 * useful to allow hosts to advertise some parameters such as prefix
330 * information and link MTU. Thus, we allow hosts to invoke rtadvd 330 * information and link MTU. Thus, we allow hosts to invoke rtadvd
331 * only when router lifetime (on every advertising interface) is 331 * only when router lifetime (on every advertising interface) is
332 * explicitly set zero. (see also the above section) 332 * explicitly set zero. (see also the above section)
333 */ 333 */
334 if (val && forwarding == 0) { 334 if (val && forwarding == 0) {
335 logit(LOG_ERR, 335 logit(LOG_ERR,
336 "<%s> non zero router lifetime is specified for %s, " 336 "<%s> non zero router lifetime is specified for %s, "
337 "which must not be allowed for hosts. you must " 337 "which must not be allowed for hosts. you must "
338 "change router lifetime or enable IPv6 forwarding.", 338 "change router lifetime or enable IPv6 forwarding.",
339 __func__, intface); 339 __func__, intface);
340 goto errexit; 340 goto errexit;
341 } 341 }
342 tmp->lifetime = val & 0xffff; 342 tmp->lifetime = val & 0xffff;
343 343
344 MAYHAVE(val, "rtime", DEF_ADVREACHABLETIME); 344 MAYHAVE(val, "rtime", DEF_ADVREACHABLETIME);
345 if (val < 0 || val > MAXREACHABLETIME) { 345 if (val < 0 || val > MAXREACHABLETIME) {
346 logit(LOG_ERR, 346 logit(LOG_ERR,
347 "<%s> reachable time (%d) on %s is invalid " 347 "<%s> reachable time (%d) on %s is invalid "
348 "(must be no greater than %d)", 348 "(must be no greater than %d)",
349 __func__, val, intface, MAXREACHABLETIME); 349 __func__, val, intface, MAXREACHABLETIME);
350 goto errexit; 350 goto errexit;
351 } 351 }
352 tmp->reachabletime = (uint32_t)val; 352 tmp->reachabletime = (uint32_t)val;
353 353
354 MAYHAVE(val64, "retrans", DEF_ADVRETRANSTIMER); 354 MAYHAVE(val64, "retrans", DEF_ADVRETRANSTIMER);
355 if (val64 < 0 || val64 > 0xffffffff) { 355 if (val64 < 0 || val64 > 0xffffffff) {
356 logit(LOG_ERR, "<%s> retrans time (%lld) on %s out of range", 356 logit(LOG_ERR, "<%s> retrans time (%lld) on %s out of range",
357 __func__, (long long)val64, intface); 357 __func__, (long long)val64, intface);
358 goto errexit; 358 goto errexit;
359 } 359 }
360 tmp->retranstimer = (uint32_t)val64; 360 tmp->retranstimer = (uint32_t)val64;
361 361
362 if (agetnum("hapref") != -1 || agetnum("hatime") != -1) { 362 if (agetnum("hapref") != -1 || agetnum("hatime") != -1) {
363 logit(LOG_ERR, 363 logit(LOG_ERR,
364 "<%s> mobile-ip6 configuration not supported", 364 "<%s> mobile-ip6 configuration not supported",
365 __func__); 365 __func__);
366 goto errexit; 366 goto errexit;
367 } 367 }
368 /* prefix information */ 368 /* prefix information */
369 369
370 /* 370 /*
371 * This is an implementation specific parameter to consider 371 * This is an implementation specific parameter to consider
372 * link propagation delays and poorly synchronized clocks when 372 * link propagation delays and poorly synchronized clocks when
373 * checking consistency of advertised lifetimes. 373 * checking consistency of advertised lifetimes.
374 */ 374 */
375 MAYHAVE(val, "clockskew", 0); 375 MAYHAVE(val, "clockskew", 0);
376 tmp->clockskew = val; 376 tmp->clockskew = val;
377 377
378 tmp->pfxs = 0; 378 tmp->pfxs = 0;
379 for (i = -1; i < MAXPREFIX; i++) { 379 for (i = -1; i < MAXPREFIX; i++) {
380 struct prefix *pfx; 380 struct prefix *pfx;
381 381
382 makeentry(entbuf, sizeof(entbuf), i, "addr"); 382 makeentry(entbuf, sizeof(entbuf), i, "addr");
383 addr = (char *)agetstr(entbuf, &bp); 383 addr = (char *)agetstr(entbuf, &bp);
384 if (addr == NULL) 384 if (addr == NULL)
385 continue; 385 continue;
386 386
387 /* allocate memory to store prefix information */ 387 /* allocate memory to store prefix information */
388 if ((pfx = calloc(1, sizeof(*pfx))) == NULL) { 388 if ((pfx = calloc(1, sizeof(*pfx))) == NULL) {
389 logit(LOG_ERR, 389 logit(LOG_ERR,
390 "<%s> can't allocate memory: %m", 390 "<%s> can't allocate memory: %m",
391 __func__); 391 __func__);
392 goto errexit; 392 goto errexit;
393 } 393 }
394 394
395 TAILQ_INSERT_TAIL(&tmp->prefix, pfx, next); 395 TAILQ_INSERT_TAIL(&tmp->prefix, pfx, next);
396 tmp->pfxs++; 396 tmp->pfxs++;
397 pfx->rainfo = tmp; 397 pfx->rainfo = tmp;
398 398
399 pfx->origin = PREFIX_FROM_CONFIG; 399 pfx->origin = PREFIX_FROM_CONFIG;
400 400
401 if (inet_pton(AF_INET6, addr, &pfx->prefix) != 1) { 401 if (inet_pton(AF_INET6, addr, &pfx->prefix) != 1) {
402 logit(LOG_ERR, 402 logit(LOG_ERR,
403 "<%s> inet_pton failed for %s", 403 "<%s> inet_pton failed for %s",
404 __func__, addr); 404 __func__, addr);
405 goto errexit; 405 goto errexit;
406 } 406 }
407 if (IN6_IS_ADDR_MULTICAST(&pfx->prefix)) { 407 if (IN6_IS_ADDR_MULTICAST(&pfx->prefix)) {
408 logit(LOG_ERR, 408 logit(LOG_ERR,
409 "<%s> multicast prefix (%s) must " 409 "<%s> multicast prefix (%s) must "
410 "not be advertised on %s", 410 "not be advertised on %s",
411 __func__, addr, intface); 411 __func__, addr, intface);
412 goto errexit; 412 goto errexit;
413 } 413 }
414 if (IN6_IS_ADDR_LINKLOCAL(&pfx->prefix)) 414 if (IN6_IS_ADDR_LINKLOCAL(&pfx->prefix))
415 logit(LOG_NOTICE, 415 logit(LOG_NOTICE,
416 "<%s> link-local prefix (%s) will be" 416 "<%s> link-local prefix (%s) will be"
417 " advertised on %s", 417 " advertised on %s",
418 __func__, addr, intface); 418 __func__, addr, intface);
419 419
420 makeentry(entbuf, sizeof(entbuf), i, "prefixlen"); 420 makeentry(entbuf, sizeof(entbuf), i, "prefixlen");
421 MAYHAVE(val, entbuf, 64); 421 MAYHAVE(val, entbuf, 64);
422 if (val < 0 || val > 128) { 422 if (val < 0 || val > 128) {
423 logit(LOG_ERR, "<%s> prefixlen (%d) for %s " 423 logit(LOG_ERR, "<%s> prefixlen (%d) for %s "
424 "on %s out of range", 424 "on %s out of range",
425 __func__, val, addr, intface); 425 __func__, val, addr, intface);
426 goto errexit; 426 goto errexit;
427 } 427 }
428 pfx->prefixlen = (int)val; 428 pfx->prefixlen = (int)val;
429 429
430 makeentry(entbuf, sizeof(entbuf), i, "pinfoflags"); 430 makeentry(entbuf, sizeof(entbuf), i, "pinfoflags");
431 if ((flagstr = (char *)agetstr(entbuf, &bp))) { 431 if ((flagstr = (char *)agetstr(entbuf, &bp))) {
432 val = 0; 432 val = 0;
433 if (strchr(flagstr, 'l')) 433 if (strchr(flagstr, 'l'))
434 val |= ND_OPT_PI_FLAG_ONLINK; 434 val |= ND_OPT_PI_FLAG_ONLINK;
435 if (strchr(flagstr, 'a')) 435 if (strchr(flagstr, 'a'))
436 val |= ND_OPT_PI_FLAG_AUTO; 436 val |= ND_OPT_PI_FLAG_AUTO;
437 } else { 437 } else {
438 MAYHAVE(val, entbuf, 438 MAYHAVE(val, entbuf,
439 (ND_OPT_PI_FLAG_ONLINK|ND_OPT_PI_FLAG_AUTO)); 439 (ND_OPT_PI_FLAG_ONLINK|ND_OPT_PI_FLAG_AUTO));
440 } 440 }
441 pfx->onlinkflg = val & ND_OPT_PI_FLAG_ONLINK; 441 pfx->onlinkflg = val & ND_OPT_PI_FLAG_ONLINK;
442 pfx->autoconfflg = val & ND_OPT_PI_FLAG_AUTO; 442 pfx->autoconfflg = val & ND_OPT_PI_FLAG_AUTO;
443 443
444 makeentry(entbuf, sizeof(entbuf), i, "vltime"); 444 makeentry(entbuf, sizeof(entbuf), i, "vltime");
445 MAYHAVE(val64, entbuf, DEF_ADVVALIDLIFETIME); 445 MAYHAVE(val64, entbuf, DEF_ADVVALIDLIFETIME);
446 if (val64 < 0 || val64 > 0xffffffff) { 446 if (val64 < 0 || val64 > 0xffffffff) {
447 logit(LOG_ERR, "<%s> vltime (%lld) for " 447 logit(LOG_ERR, "<%s> vltime (%lld) for "
448 "%s/%d on %s is out of range", 448 "%s/%d on %s is out of range",
449 __func__, (long long)val64, 449 __func__, (long long)val64,
450 addr, pfx->prefixlen, intface); 450 addr, pfx->prefixlen, intface);
451 goto errexit; 451 goto errexit;
452 } 452 }
453 pfx->validlifetime = (uint32_t)val64; 453 pfx->validlifetime = (uint32_t)val64;
454 454
455 makeentry(entbuf, sizeof(entbuf), i, "vltimedecr"); 455 makeentry(entbuf, sizeof(entbuf), i, "vltimedecr");
456 if (agetflag(entbuf)) { 456 if (agetflag(entbuf)) {
457 struct timespec now; 457 struct timespec now;
458 prog_clock_gettime(CLOCK_MONOTONIC, &now); 458 prog_clock_gettime(CLOCK_MONOTONIC, &now);
459 pfx->vltimeexpire = 459 pfx->vltimeexpire =
460 now.tv_sec + pfx->validlifetime; 460 now.tv_sec + pfx->validlifetime;
461 } 461 }
462 462
463 makeentry(entbuf, sizeof(entbuf), i, "pltime"); 463 makeentry(entbuf, sizeof(entbuf), i, "pltime");
464 MAYHAVE(val64, entbuf, DEF_ADVPREFERREDLIFETIME); 464 MAYHAVE(val64, entbuf, DEF_ADVPREFERREDLIFETIME);
465 if (val64 < 0 || val64 > 0xffffffff) { 465 if (val64 < 0 || val64 > 0xffffffff) {
466 logit(LOG_ERR, 466 logit(LOG_ERR,
467 "<%s> pltime (%lld) for %s/%d on %s " 467 "<%s> pltime (%lld) for %s/%d on %s "
468 "is out of range", 468 "is out of range",
469 __func__, (long long)val64, 469 __func__, (long long)val64,
470 addr, pfx->prefixlen, intface); 470 addr, pfx->prefixlen, intface);
471 goto errexit; 471 goto errexit;
472 } 472 }
473 pfx->preflifetime = (uint32_t)val64; 473 pfx->preflifetime = (uint32_t)val64;
474 474
475 makeentry(entbuf, sizeof(entbuf), i, "pltimedecr"); 475 makeentry(entbuf, sizeof(entbuf), i, "pltimedecr");
476 if (agetflag(entbuf)) { 476 if (agetflag(entbuf)) {
477 struct timespec now; 477 struct timespec now;
478 prog_clock_gettime(CLOCK_MONOTONIC, &now); 478 prog_clock_gettime(CLOCK_MONOTONIC, &now);
479 pfx->pltimeexpire = 479 pfx->pltimeexpire =
480 now.tv_sec + pfx->preflifetime; 480 now.tv_sec + pfx->preflifetime;
481 } 481 }
482 } 482 }
483 if (TAILQ_FIRST(&tmp->prefix) == NULL && !agetflag("noifprefix")) 483 if (TAILQ_FIRST(&tmp->prefix) == NULL && !agetflag("noifprefix"))
484 get_prefix(tmp); 484 get_prefix(tmp);
485 485
486 MAYHAVE(val64, "mtu", 0); 486 MAYHAVE(val64, "mtu", 0);
487 if (val64 < 0 || val64 > 0xffffffff) { 487 if (val64 < 0 || val64 > 0xffffffff) {
488 logit(LOG_ERR, 488 logit(LOG_ERR,
489 "<%s> mtu (%" PRIi64 ") on %s out of range", 489 "<%s> mtu (%" PRIi64 ") on %s out of range",
490 __func__, val64, intface); 490 __func__, val64, intface);
491 goto errexit; 491 goto errexit;
492 } 492 }
493 tmp->linkmtu = (uint32_t)val64; 493 tmp->linkmtu = (uint32_t)val64;
494 if (tmp->linkmtu == 0) { 494 if (tmp->linkmtu == 0) {
495 char *mtustr; 495 char *mtustr;
496 496
497 if ((mtustr = (char *)agetstr("mtu", &bp)) && 497 if ((mtustr = (char *)agetstr("mtu", &bp)) &&
498 strcmp(mtustr, "auto") == 0) 498 strcmp(mtustr, "auto") == 0)
499 tmp->linkmtu = tmp->phymtu; 499 tmp->linkmtu = tmp->phymtu;
500 } 500 }
501 else if (tmp->linkmtu < IPV6_MMTU || tmp->linkmtu > tmp->phymtu) { 501 else if (tmp->linkmtu < IPV6_MMTU || tmp->linkmtu > tmp->phymtu) {
502 logit(LOG_ERR, 502 logit(LOG_ERR,
503 "<%s> advertised link mtu (%d) on %s is invalid (must " 503 "<%s> advertised link mtu (%d) on %s is invalid (must "
504 "be between least MTU (%d) and physical link MTU (%d)", 504 "be between least MTU (%d) and physical link MTU (%d)",
505 __func__, tmp->linkmtu, intface, 505 __func__, tmp->linkmtu, intface,
506 IPV6_MMTU, tmp->phymtu); 506 IPV6_MMTU, tmp->phymtu);
507 goto errexit; 507 goto errexit;
508 } 508 }
509 509
510 /* route information */ 510 /* route information */
511 for (i = -1; i < MAXROUTE; i++) { 511 for (i = -1; i < MAXROUTE; i++) {
512 struct rtinfo *rti; 512 struct rtinfo *rti;
513 char oentbuf[256]; 513 char oentbuf[256];
514 514
515 makeentry(entbuf, sizeof(entbuf), i, "rtprefix"); 515 makeentry(entbuf, sizeof(entbuf), i, "rtprefix");
516 addr = (char *)agetstr(entbuf, &bp); 516 addr = (char *)agetstr(entbuf, &bp);
517 if (addr == NULL) { 517 if (addr == NULL) {
518 makeentry(oentbuf, sizeof(oentbuf), i, "rtrprefix"); 518 makeentry(oentbuf, sizeof(oentbuf), i, "rtrprefix");
519 addr = (char *)agetstr(oentbuf, &bp); 519 addr = (char *)agetstr(oentbuf, &bp);
520 if (addr) { 520 if (addr) {
521 fprintf(stderr, "%s was obsoleted. Use %s.\n", 521 fprintf(stderr, "%s was obsoleted. Use %s.\n",
522 oentbuf, entbuf); 522 oentbuf, entbuf);
523 } 523 }
524 } 524 }
525 if (addr == NULL) 525 if (addr == NULL)
526 continue; 526 continue;
527 527
528 ELM_MALLOC(rti); 528 ELM_MALLOC(rti);
529 memset(rti, 0, sizeof(*rti)); 529 memset(rti, 0, sizeof(*rti));
530 530
531 /* link into chain */ 531 /* link into chain */
532 TAILQ_INSERT_TAIL(&tmp->route, rti, next); 532 TAILQ_INSERT_TAIL(&tmp->route, rti, next);
533 533
534 if (inet_pton(AF_INET6, addr, &rti->prefix) != 1) { 534 if (inet_pton(AF_INET6, addr, &rti->prefix) != 1) {
535 logit(LOG_ERR, "<%s> inet_pton failed for %s", 535 logit(LOG_ERR, "<%s> inet_pton failed for %s",
536 __func__, addr); 536 __func__, addr);
537 goto errexit; 537 goto errexit;
538 } 538 }
539#if 0 539#if 0
540 /* 540 /*
541 * XXX: currently there's no restriction in route information 541 * XXX: currently there's no restriction in route information
542 * prefix according to 542 * prefix according to
543 * draft-ietf-ipngwg-router-selection-00.txt. 543 * draft-ietf-ipngwg-router-selection-00.txt.
544 * However, I think the similar restriction be necessary. 544 * However, I think the similar restriction be necessary.
545 */ 545 */
546 MAYHAVE(val64, entbuf, DEF_ADVVALIDLIFETIME); 546 MAYHAVE(val64, entbuf, DEF_ADVVALIDLIFETIME);
547 if (IN6_IS_ADDR_MULTICAST(&rti->prefix)) { 547 if (IN6_IS_ADDR_MULTICAST(&rti->prefix)) {
548 logit(LOG_ERR, 548 logit(LOG_ERR,
549 "<%s> multicast route (%s) must " 549 "<%s> multicast route (%s) must "
550 "not be advertised on %s", 550 "not be advertised on %s",
551 __func__, addr, intface); 551 __func__, addr, intface);
552 goto errexit; 552 goto errexit;
553 } 553 }
554 if (IN6_IS_ADDR_LINKLOCAL(&rti->prefix)) { 554 if (IN6_IS_ADDR_LINKLOCAL(&rti->prefix)) {
555 logit(LOG_NOTICE, 555 logit(LOG_NOTICE,
556 "<%s> link-local route (%s) will " 556 "<%s> link-local route (%s) will "
557 "be advertised on %s", 557 "be advertised on %s",
558 __func__, addr, intface); 558 __func__, addr, intface);
559 goto errexit; 559 goto errexit;
560 } 560 }
561#endif 561#endif
562 562
563 makeentry(entbuf, sizeof(entbuf), i, "rtplen"); 563 makeentry(entbuf, sizeof(entbuf), i, "rtplen");
564 /* XXX: 256 is a magic number for compatibility check. */ 564 /* XXX: 256 is a magic number for compatibility check. */
565 MAYHAVE(val, entbuf, 256); 565 MAYHAVE(val, entbuf, 256);
566 if (val == 256) { 566 if (val == 256) {
567 makeentry(oentbuf, sizeof(oentbuf), i, "rtrplen"); 567 makeentry(oentbuf, sizeof(oentbuf), i, "rtrplen");
568 MAYHAVE(val, oentbuf, 256); 568 MAYHAVE(val, oentbuf, 256);
569 if (val != 256) { 569 if (val != 256) {
570 fprintf(stderr, "%s was obsoleted. Use %s.\n", 570 fprintf(stderr, "%s was obsoleted. Use %s.\n",
571 oentbuf, entbuf); 571 oentbuf, entbuf);
572 } else 572 } else
573 val = 64; 573 val = 64;
574 } 574 }
575 if (val < 0 || val > 128) { 575 if (val < 0 || val > 128) {
576 logit(LOG_ERR, "<%s> prefixlen (%d) for %s on %s " 576 logit(LOG_ERR, "<%s> prefixlen (%d) for %s on %s "
577 "out of range", 577 "out of range",
578 __func__, val, addr, intface); 578 __func__, val, addr, intface);
579 goto errexit; 579 goto errexit;
580 } 580 }
581 rti->prefixlen = (int)val; 581 rti->prefixlen = (int)val;
582 582
583 makeentry(entbuf, sizeof(entbuf), i, "rtflags"); 583 makeentry(entbuf, sizeof(entbuf), i, "rtflags");
584 if ((flagstr = (char *)agetstr(entbuf, &bp))) { 584 if ((flagstr = (char *)agetstr(entbuf, &bp))) {
585 val = 0; 585 val = 0;
586 if (strchr(flagstr, 'h')) 586 if (strchr(flagstr, 'h'))
587 val |= ND_RA_FLAG_RTPREF_HIGH; 587 val |= ND_RA_FLAG_RTPREF_HIGH;
588 if (strchr(flagstr, 'l')) { 588 if (strchr(flagstr, 'l')) {
589 if ((val & ND_RA_FLAG_RTPREF_HIGH)) { 589 if ((val & ND_RA_FLAG_RTPREF_HIGH)) {
590 logit(LOG_ERR, 590 logit(LOG_ERR,
591 "<%s> the \'h\' and \'l\' route" 591 "<%s> the \'h\' and \'l\' route"
592 " preferences are exclusive", 592 " preferences are exclusive",
593 __func__); 593 __func__);
594 goto errexit; 594 goto errexit;
595 } 595 }
596 val |= ND_RA_FLAG_RTPREF_LOW; 596 val |= ND_RA_FLAG_RTPREF_LOW;
597 } 597 }
598 } else 598 } else
599 MAYHAVE(val, entbuf, 256); /* XXX */ 599 MAYHAVE(val, entbuf, 256); /* XXX */
600 if (val == 256) { 600 if (val == 256) {
601 makeentry(oentbuf, sizeof(oentbuf), i, "rtrflags"); 601 makeentry(oentbuf, sizeof(oentbuf), i, "rtrflags");
602 MAYHAVE(val, oentbuf, 256); 602 MAYHAVE(val, oentbuf, 256);
603 if (val != 256) { 603 if (val != 256) {
604 fprintf(stderr, "%s was obsoleted. Use %s.\n", 604 fprintf(stderr, "%s was obsoleted. Use %s.\n",
605 oentbuf, entbuf); 605 oentbuf, entbuf);
606 } else 606 } else
607 val = 0; 607 val = 0;
608 } 608 }
609 rti->rtpref = val & ND_RA_FLAG_RTPREF_MASK; 609 rti->rtpref = val & ND_RA_FLAG_RTPREF_MASK;
610 if (rti->rtpref == ND_RA_FLAG_RTPREF_RSV) { 610 if (rti->rtpref == ND_RA_FLAG_RTPREF_RSV) {
611 logit(LOG_ERR, "<%s> invalid route preference (%02x) " 611 logit(LOG_ERR, "<%s> invalid route preference (%02x) "
612 "for %s/%d on %s", 612 "for %s/%d on %s",
613 __func__, rti->rtpref, addr, 613 __func__, rti->rtpref, addr,
614 rti->prefixlen, intface); 614 rti->prefixlen, intface);
615 goto errexit; 615 goto errexit;
616 } 616 }
617 617
618 /* 618 /*
619 * Since the spec does not a default value, we should make 619 * Since the spec does not a default value, we should make
620 * this entry mandatory. However, FreeBSD 4.4 has shipped 620 * this entry mandatory. However, FreeBSD 4.4 has shipped
621 * with this field being optional, we use the router lifetime 621 * with this field being optional, we use the router lifetime
622 * as an ad-hoc default value with a warning message. 622 * as an ad-hoc default value with a warning message.
623 */ 623 */
624 makeentry(entbuf, sizeof(entbuf), i, "rtltime"); 624 makeentry(entbuf, sizeof(entbuf), i, "rtltime");
625 MAYHAVE(val64, entbuf, -1); 625 MAYHAVE(val64, entbuf, -1);
626 if (val64 == -1) { 626 if (val64 == -1) {
627 makeentry(oentbuf, sizeof(oentbuf), i, "rtrltime"); 627 makeentry(oentbuf, sizeof(oentbuf), i, "rtrltime");
628 MAYHAVE(val64, oentbuf, -1); 628 MAYHAVE(val64, oentbuf, -1);
629 if (val64 != -1) { 629 if (val64 != -1) {
630 fprintf(stderr, "%s was obsoleted. Use %s.\n", 630 fprintf(stderr, "%s was obsoleted. Use %s.\n",
631 oentbuf, entbuf); 631 oentbuf, entbuf);
632 } else { 632 } else {
633 fprintf(stderr, "%s should be specified " 633 fprintf(stderr, "%s should be specified "
634 "for interface %s.\n", 634 "for interface %s.\n",
635 entbuf, intface); 635 entbuf, intface);
636 val64 = tmp->lifetime; 636 val64 = tmp->lifetime;
637 } 637 }
638 } 638 }
639 if (val64 < 0 || val64 > 0xffffffff) { 639 if (val64 < 0 || val64 > 0xffffffff) {
640 logit(LOG_ERR, "<%s> route lifetime (%lld) for " 640 logit(LOG_ERR, "<%s> route lifetime (%lld) for "
641 "%s/%d on %s out of range", __func__, 641 "%s/%d on %s out of range", __func__,
642 (long long)val64, addr, rti->prefixlen, intface); 642 (long long)val64, addr, rti->prefixlen, intface);
643 goto errexit; 643 goto errexit;
644 } 644 }
645 rti->ltime = (uint32_t)val64; 645 rti->ltime = (uint32_t)val64;
646 } 646 }
647 647
648 /* RDNSS */ 648 /* RDNSS */
649 for (i = -1; i < MAXRDNSS; i++) { 649 for (i = -1; i < MAXRDNSS; i++) {
650 struct rdnss_addr *rdnsa; 650 struct rdnss_addr *rdnsa;
651 651
652 makeentry(entbuf, sizeof(entbuf), i, "rdnss"); 652 makeentry(entbuf, sizeof(entbuf), i, "rdnss");
653 addr = (char *)agetstr(entbuf, &bp); 653 addr = (char *)agetstr(entbuf, &bp);
654 if (addr == NULL) 654 if (addr == NULL)
655 continue; 655 continue;
656 656
657 ELM_MALLOC(rdnss); 657 ELM_MALLOC(rdnss);
658 TAILQ_INSERT_TAIL(&tmp->rdnss, rdnss, next); 658 TAILQ_INSERT_TAIL(&tmp->rdnss, rdnss, next);
659 TAILQ_INIT(&rdnss->list); 659 TAILQ_INIT(&rdnss->list);
660 660
661 for (ap = addr; ap - addr < (ssize_t)strlen(addr); ap += c+1) { 661 for (ap = addr; ap - addr < (ssize_t)strlen(addr); ap += c+1) {
662 c = strcspn(ap, ","); 662 c = strcspn(ap, ",");
663 strncpy(abuf, ap, c); 663 strncpy(abuf, ap, c);
664 abuf[c] = '\0'; 664 abuf[c] = '\0';
665 ELM_MALLOC(rdnsa); 665 ELM_MALLOC(rdnsa);
666 TAILQ_INSERT_TAIL(&rdnss->list, rdnsa, next); 666 TAILQ_INSERT_TAIL(&rdnss->list, rdnsa, next);
667 if (inet_pton(AF_INET6, abuf, &rdnsa->addr) != 1) { 667 if (inet_pton(AF_INET6, abuf, &rdnsa->addr) != 1) {
668 logit(LOG_ERR, "<%s> inet_pton failed for %s", 668 logit(LOG_ERR, "<%s> inet_pton failed for %s",
669 __func__, addr); 669 __func__, addr);
670 goto errexit; 670 goto errexit;
671 } 671 }
672 } 672 }
673 673
674 makeentry(entbuf, sizeof(entbuf), i, "rdnssltime"); 674 makeentry(entbuf, sizeof(entbuf), i, "rdnssltime");
675 MAYHAVE(val64, entbuf, tmp->maxinterval * 3 / 2); 675 MAYHAVE(val64, entbuf, tmp->maxinterval * 3 / 2);
676 if (val64 < 0 || val64 > 0xffffffff) { 676 if (val64 < 0 || val64 > 0xffffffff) {
677 logit(LOG_ERR, "<%s> %s (%lld) on %s is invalid", 677 logit(LOG_ERR, "<%s> %s (%lld) on %s is invalid",
678 __func__, entbuf, (long long)val64, intface); 678 __func__, entbuf, (long long)val64, intface);
679 goto errexit; 679 goto errexit;
680 } 680 }
681 rdnss->lifetime = (uint32_t)val64; 681 rdnss->lifetime = (uint32_t)val64;
682 682
683 } 683 }
684 684
685 /* DNSSL */ 685 /* DNSSL */
686 TAILQ_INIT(&tmp->dnssl); 686 TAILQ_INIT(&tmp->dnssl);
687 for (i = -1; i < MAXDNSSL; i++) { 687 for (i = -1; i < MAXDNSSL; i++) {
688 struct dnssl_domain *dnsd; 688 struct dnssl_domain *dnsd;
689 689
690 makeentry(entbuf, sizeof(entbuf), i, "dnssl"); 690 makeentry(entbuf, sizeof(entbuf), i, "dnssl");
691 addr = (char *)agetstr(entbuf, &bp); 691 addr = (char *)agetstr(entbuf, &bp);
692 if (addr == NULL) 692 if (addr == NULL)
693 continue; 693 continue;
694 694
695 ELM_MALLOC(dnssl); 695 ELM_MALLOC(dnssl);
696 TAILQ_INSERT_TAIL(&tmp->dnssl, dnssl, next); 696 TAILQ_INSERT_TAIL(&tmp->dnssl, dnssl, next);
697 TAILQ_INIT(&dnssl->list); 697 TAILQ_INIT(&dnssl->list);
698 698
699 for (ap = addr; ap - addr < (ssize_t)strlen(addr); ap += c+1) { 699 for (ap = addr; ap - addr < (ssize_t)strlen(addr); ap += c+1) {
700 c = strcspn(ap, ","); 700 c = strcspn(ap, ",");
701 strncpy(abuf, ap, c); 701 strncpy(abuf, ap, c);
702 abuf[c] = '\0'; 702 abuf[c] = '\0';
703 ELM_MALLOC(dnsd); 703 ELM_MALLOC(dnsd);
704 TAILQ_INSERT_TAIL(&dnssl->list, dnsd, next); 704 TAILQ_INSERT_TAIL(&dnssl->list, dnsd, next);
705 dnsd->len = encode_domain(dnsd->domain, abuf); 705 dnsd->len = encode_domain(dnsd->domain, abuf);
706 } 706 }
707 707
708 makeentry(entbuf, sizeof(entbuf), i, "dnsslltime"); 708 makeentry(entbuf, sizeof(entbuf), i, "dnsslltime");
709 MAYHAVE(val64, entbuf, tmp->maxinterval * 3 / 2); 709 MAYHAVE(val64, entbuf, tmp->maxinterval * 3 / 2);
710 if (val64 < 0 || val64 > 0xffffffff) { 710 if (val64 < 0 || val64 > 0xffffffff) {
711 logit(LOG_ERR, "<%s> %s (%lld) on %s is invalid", 711 logit(LOG_ERR, "<%s> %s (%lld) on %s is invalid",
712 __func__, entbuf, (long long)val64, intface); 712 __func__, entbuf, (long long)val64, intface);
713 goto errexit; 713 goto errexit;
714 } 714 }
715 dnssl->lifetime = (uint32_t)val64; 715 dnssl->lifetime = (uint32_t)val64;
716 716
717 } 717 }
718 718
719 TAILQ_FOREACH(rai, &ralist, next) { 719 TAILQ_FOREACH(rai, &ralist, next) {
720 if (rai->ifindex == tmp->ifindex) { 720 if (rai->ifindex == tmp->ifindex) {
721 TAILQ_REMOVE(&ralist, rai, next); 721 TAILQ_REMOVE(&ralist, rai, next);
722 if (Cflag) { 722 if (Cflag) {
723 free_rainfo(rai); 723 free_rainfo(rai);
724 rai = NULL; 724 rai = NULL;
725 break; 725 break;
726 } 726 }
727 /* If we already have a leaving RA use that 727 /* If we already have a leaving RA use that
728 * as this config hasn't been advertised */ 728 * as this config hasn't been advertised */
729 if (rai->leaving) { 729 if (rai->leaving) {
730 tmp->leaving = rai->leaving; 730 tmp->leaving = rai->leaving;
731 free_rainfo(rai); 731 free_rainfo(rai);
732 rai = tmp->leaving; 732 rai = tmp->leaving;
733 rai->leaving_for = tmp; 733 rai->leaving_for = tmp;
734 break; 734 break;
735 } 735 }
736 rai->lifetime = 0; 736 rai->lifetime = 0;
737 TAILQ_FOREACH(rdnss, &rai->rdnss, next) 737 TAILQ_FOREACH(rdnss, &rai->rdnss, next)
738 rdnss->lifetime = 0; 738 rdnss->lifetime = 0;
739 TAILQ_FOREACH(dnssl, &rai->dnssl, next) 739 TAILQ_FOREACH(dnssl, &rai->dnssl, next)
740 dnssl->lifetime = 0; 740 dnssl->lifetime = 0;
741 rai->leaving_for = tmp; 741 rai->leaving_for = tmp;
742 tmp->leaving = rai; 742 tmp->leaving = rai;
743 rai->initcounter = MAX_INITIAL_RTR_ADVERTISEMENTS; 743 rai->initcounter = MAX_INITIAL_RTR_ADVERTISEMENTS;
744 rai->mininterval = MIN_DELAY_BETWEEN_RAS; 744 rai->mininterval = MIN_DELAY_BETWEEN_RAS;
745 rai->maxinterval = MIN_DELAY_BETWEEN_RAS; 745 rai->maxinterval = MIN_DELAY_BETWEEN_RAS;
746 rai->leaving_adv = MAX_FINAL_RTR_ADVERTISEMENTS; 746 rai->leaving_adv = MAX_FINAL_RTR_ADVERTISEMENTS;
747 if (rai->timer == NULL) 747 if (rai->timer == NULL)
748 rai->timer = rtadvd_add_timer(ra_timeout, 748 rai->timer = rtadvd_add_timer(ra_timeout,
749 ra_timer_update, 749 ra_timer_update,
750 rai, rai); 750 rai, rai);
751 ra_timer_update((void *)rai, &rai->timer->tm); 751 ra_timer_update((void *)rai, &rai->timer->tm);
752 rtadvd_set_timer(&rai->timer->tm, rai->timer); 752 rtadvd_set_timer(&rai->timer->tm, rai->timer);
753 break; 753 break;
754 } 754 }
755 } 755 }
756 756
757 /* okey */ 757 /* okey */
758 TAILQ_INSERT_TAIL(&ralist, tmp, next); 758 TAILQ_INSERT_TAIL(&ralist, tmp, next);
759 759
760 /* construct the sending packet */ 760 /* construct the sending packet */
761 make_packet(tmp); 761 make_packet(tmp);
762 762
763 /* set timer */ 763 /* set timer */
764 if (rai) 764 if (rai)
765 return; 765 return;
766 tmp->timer = rtadvd_add_timer(ra_timeout, ra_timer_update, 766 tmp->timer = rtadvd_add_timer(ra_timeout, ra_timer_update,
767 tmp, tmp); 767 tmp, tmp);
768 ra_timer_set_short_delay(tmp, tmp->timer); 768 ra_timer_set_short_delay(tmp, tmp->timer);
769 tmp->timer_sol = rtadvd_add_timer(ra_timeout_sol, NULL, tmp, NULL); 769 tmp->timer_sol = rtadvd_add_timer(ra_timeout_sol, NULL, tmp, NULL);
770 770
771 return; 771 return;
772 772
773errexit: 773errexit:
774 if (exithard) 774 if (exithard)
775 exit(1); 775 exit(1);
776 free_rainfo(tmp); 776 free_rainfo(tmp);
777} 777}
778 778
779void 779void
780get_prefix(struct rainfo *rai) 780get_prefix(struct rainfo *rai)
781{ 781{
782 struct ifaddrs *ifap, *ifa; 782 struct ifaddrs *ifap, *ifa;
783 struct prefix *pp; 783 struct prefix *pp;
784 struct in6_addr *a; 784 struct in6_addr *a;
785 unsigned char *p, *ep, *m, *lim; 785 unsigned char *p, *ep, *m, *lim;
786 char ntopbuf[INET6_ADDRSTRLEN]; 786 char ntopbuf[INET6_ADDRSTRLEN];
787 787
788 if (getifaddrs(&ifap) < 0) { 788 if (getifaddrs(&ifap) < 0) {
789 logit(LOG_ERR, 789 logit(LOG_ERR,
790 "<%s> can't get interface addresses", 790 "<%s> can't get interface addresses",
791 __func__); 791 __func__);
792 exit(1); 792 exit(1);
793 } 793 }
794 794
795 for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 795 for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
796 int plen; 796 int plen;
797 797
798 if (strcmp(ifa->ifa_name, rai->ifname) != 0) 798 if (strcmp(ifa->ifa_name, rai->ifname) != 0)
799 continue; 799 continue;
800 if (ifa->ifa_addr->sa_family != AF_INET6) 800 if (ifa->ifa_addr->sa_family != AF_INET6)
801 continue; 801 continue;
802 a = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr; 802 a = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
803 if (IN6_IS_ADDR_LINKLOCAL(a)) 803 if (IN6_IS_ADDR_LINKLOCAL(a))
804 continue; 804 continue;
805 /* get prefix length */ 805 /* get prefix length */
806 m = (unsigned char *)&((struct sockaddr_in6 *)ifa->ifa_netmask)->sin6_addr; 806 m = (unsigned char *)&((struct sockaddr_in6 *)ifa->ifa_netmask)->sin6_addr;
807 lim = (unsigned char *)(ifa->ifa_netmask) + ifa->ifa_netmask->sa_len; 807 lim = (unsigned char *)(ifa->ifa_netmask) + ifa->ifa_netmask->sa_len;
808 plen = prefixlen(m, lim); 808 plen = prefixlen(m, lim);
809 if (plen <= 0 || plen > 128) { 809 if (plen <= 0 || plen > 128) {
810 logit(LOG_ERR, "<%s> failed to get prefixlen " 810 logit(LOG_ERR, "<%s> failed to get prefixlen "
811 "or prefix is invalid", 811 "or prefix is invalid",
812 __func__); 812 __func__);
813 exit(1); 813 exit(1);
814 } 814 }
815 if (plen == 128) /* XXX */ 815 if (plen == 128) /* XXX */
816 continue; 816 continue;
817 if (find_prefix(rai, a, plen)) { 817 if (find_prefix(rai, a, plen)) {
818 /* ignore a duplicated prefix. */ 818 /* ignore a duplicated prefix. */
819 continue; 819 continue;
820 } 820 }
821 821
822 /* allocate memory to store prefix info. */ 822 /* allocate memory to store prefix info. */
823 if ((pp = calloc(1, sizeof(*pp))) == NULL) { 823 if ((pp = calloc(1, sizeof(*pp))) == NULL) {
824 logit(LOG_ERR, 824 logit(LOG_ERR,
825 "<%s> can't get allocate buffer for prefix", 825 "<%s> can't get allocate buffer for prefix",
826 __func__); 826 __func__);
827 exit(1); 827 exit(1);
828 } 828 }
829 829
830 /* set prefix, sweep bits outside of prefixlen */ 830 /* set prefix, sweep bits outside of prefixlen */
831 pp->prefixlen = plen; 831 pp->prefixlen = plen;
832 memcpy(&pp->prefix, a, sizeof(*a)); 832 memcpy(&pp->prefix, a, sizeof(*a));
833 if (1) 833 if (1)
834 { 834 {
835 p = (unsigned char *)&pp->prefix; 835 p = (unsigned char *)&pp->prefix;
836 ep = (unsigned char *)(&pp->prefix + 1); 836 ep = (unsigned char *)(&pp->prefix + 1);
837 while (m < lim && p < ep) 837 while (m < lim && p < ep)
838 *p++ &= *m++; 838 *p++ &= *m++;
839 while (p < ep) 839 while (p < ep)
840 *p++ = 0x00; 840 *p++ = 0x00;
841 } 841 }
842 if (!inet_ntop(AF_INET6, &pp->prefix, ntopbuf, 842 if (!inet_ntop(AF_INET6, &pp->prefix, ntopbuf,
843 sizeof(ntopbuf))) { 843 sizeof(ntopbuf))) {
844 logit(LOG_ERR, "<%s> inet_ntop failed", __func__); 844 logit(LOG_ERR, "<%s> inet_ntop failed", __func__);
845 exit(1); 845 exit(1);
846 } 846 }
847 logit(LOG_DEBUG, 847 logit(LOG_DEBUG,
848 "<%s> add %s/%d to prefix list on %s", 848 "<%s> add %s/%d to prefix list on %s",
849 __func__, ntopbuf, pp->prefixlen, rai->ifname); 849 __func__, ntopbuf, pp->prefixlen, rai->ifname);
850 850
851 /* set other fields with protocol defaults */ 851 /* set other fields with protocol defaults */
852 pp->validlifetime = DEF_ADVVALIDLIFETIME; 852 pp->validlifetime = DEF_ADVVALIDLIFETIME;
853 pp->preflifetime = DEF_ADVPREFERREDLIFETIME; 853 pp->preflifetime = DEF_ADVPREFERREDLIFETIME;
854 pp->onlinkflg = 1; 854 pp->onlinkflg = 1;
855 pp->autoconfflg = 1; 855 pp->autoconfflg = 1;
856 pp->origin = PREFIX_FROM_KERNEL; 856 pp->origin = PREFIX_FROM_KERNEL;
857 pp->rainfo = rai; 857 pp->rainfo = rai;
858 858
859 /* link into chain */ 859 /* link into chain */
860 TAILQ_INSERT_TAIL(&rai->prefix, pp, next); 860 TAILQ_INSERT_TAIL(&rai->prefix, pp, next);
861 rai->pfxs++; 861 rai->pfxs++;
862 } 862 }
863 863
864 freeifaddrs(ifap); 864 freeifaddrs(ifap);
865} 865}
866 866
867static void 867static void
868makeentry(char *buf, size_t len, int id, const char *string) 868makeentry(char *buf, size_t len, int id, const char *string)
869{ 869{
870 870
871 if (id < 0) 871 if (id < 0)
872 strlcpy(buf, string, len); 872 strlcpy(buf, string, len);
873 else 873 else
874 snprintf(buf, len, "%s%d", string, id); 874 snprintf(buf, len, "%s%d", string, id);
875} 875}
876 876
877/* 877/*
878 * Add a prefix to the list of specified interface and reconstruct 
879 * the outgoing packet. 
880 * The prefix must not be in the list. 
881 * XXX: other parameters of the prefix(e.g. lifetime) should be 
882 * able to be specified. 
883 */ 
884static void 
885add_prefix(struct rainfo *rai, struct in6_prefixreq *ipr) 
886{ 
887 struct prefix *prefix; 
888 char ntopbuf[INET6_ADDRSTRLEN]; 
889 
890 if ((prefix = calloc(1, sizeof(*prefix))) == NULL) { 
891 logit(LOG_ERR, "<%s> memory allocation failed", 
892 __func__); 
893 return; /* XXX: error or exit? */ 
894 } 
895 prefix->prefix = ipr->ipr_prefix.sin6_addr; 
896 prefix->prefixlen = ipr->ipr_plen; 
897 prefix->validlifetime = ipr->ipr_vltime; 
898 prefix->preflifetime = ipr->ipr_pltime; 
899 prefix->onlinkflg = ipr->ipr_raf_onlink; 
900 prefix->autoconfflg = ipr->ipr_raf_auto; 
901 prefix->origin = PREFIX_FROM_DYNAMIC; 
902 
903 prefix->rainfo = rai; 
904 TAILQ_INSERT_TAIL(&rai->prefix, prefix, next); 
905 rai->pfxs++; 
906 
907 logit(LOG_DEBUG, "<%s> new prefix %s/%d was added on %s", 
908 __func__, inet_ntop(AF_INET6, &ipr->ipr_prefix.sin6_addr, 
909 ntopbuf, INET6_ADDRSTRLEN), 
910 ipr->ipr_plen, rai->ifname); 
911 
912 /* free the previous packet */ 
913 free(rai->ra_data); 
914 rai->ra_data = NULL; 
915 
916 /* reconstruct the packet */ 
917 make_packet(rai); 
918} 
919 
920/* 
921 * Delete a prefix to the list of specified interface and reconstruct 878 * Delete a prefix to the list of specified interface and reconstruct
922 * the outgoing packet. 879 * the outgoing packet.
923 * The prefix must be in the list. 880 * The prefix must be in the list.
924 */ 881 */
925void 882void
926delete_prefix(struct prefix *prefix) 883delete_prefix(struct prefix *prefix)
927{ 884{
928 char ntopbuf[INET6_ADDRSTRLEN]; 885 char ntopbuf[INET6_ADDRSTRLEN];
929 struct rainfo *rai = prefix->rainfo; 886 struct rainfo *rai = prefix->rainfo;
930 887
931 TAILQ_REMOVE(&rai->prefix, prefix, next); 888 TAILQ_REMOVE(&rai->prefix, prefix, next);
932 rai->pfxs--; 889 rai->pfxs--;
933 logit(LOG_DEBUG, "<%s> prefix %s/%d was deleted on %s", 890 logit(LOG_DEBUG, "<%s> prefix %s/%d was deleted on %s",
934 __func__, inet_ntop(AF_INET6, &prefix->prefix, 891 __func__, inet_ntop(AF_INET6, &prefix->prefix,
935 ntopbuf, INET6_ADDRSTRLEN), 892 ntopbuf, INET6_ADDRSTRLEN),
936 prefix->prefixlen, rai->ifname); 893 prefix->prefixlen, rai->ifname);
937 rtadvd_remove_timer(&prefix->timer); 894 rtadvd_remove_timer(&prefix->timer);
938 free(prefix); 895 free(prefix);
939} 896}
940 897
941void 898void
942invalidate_prefix(struct prefix *prefix) 899invalidate_prefix(struct prefix *prefix)
943{ 900{
944 char ntopbuf[INET6_ADDRSTRLEN]; 901 char ntopbuf[INET6_ADDRSTRLEN];
945 struct timespec timo; 902 struct timespec timo;
946 struct rainfo *rai = prefix->rainfo; 903 struct rainfo *rai = prefix->rainfo;
947 904
948 if (prefix->timer) { /* sanity check */ 905 if (prefix->timer) { /* sanity check */
949 logit(LOG_ERR, 906 logit(LOG_ERR,
950 "<%s> assumption failure: timer already exists", 907 "<%s> assumption failure: timer already exists",
951 __func__); 908 __func__);
952 exit(1); 909 exit(1);
953 } 910 }
954 911
955 logit(LOG_DEBUG, "<%s> prefix %s/%d was invalidated on %s, " 912 logit(LOG_DEBUG, "<%s> prefix %s/%d was invalidated on %s, "
956 "will expire in %ld seconds", __func__, 913 "will expire in %ld seconds", __func__,
957 inet_ntop(AF_INET6, &prefix->prefix, ntopbuf, INET6_ADDRSTRLEN), 914 inet_ntop(AF_INET6, &prefix->prefix, ntopbuf, INET6_ADDRSTRLEN),
958 prefix->prefixlen, rai->ifname, (long)prefix_timo); 915 prefix->prefixlen, rai->ifname, (long)prefix_timo);
959 916
960 /* set the expiration timer */ 917 /* set the expiration timer */
961 prefix->timer = rtadvd_add_timer(prefix_timeout, NULL, prefix, NULL); 918 prefix->timer = rtadvd_add_timer(prefix_timeout, NULL, prefix, NULL);
962 if (prefix->timer == NULL) { 919 if (prefix->timer == NULL) {
963 logit(LOG_ERR, "<%s> failed to add a timer for a prefix. " 920 logit(LOG_ERR, "<%s> failed to add a timer for a prefix. "
964 "remove the prefix", __func__); 921 "remove the prefix", __func__);
965 delete_prefix(prefix); 922 delete_prefix(prefix);
966 } 923 }
967 timo.tv_sec = prefix_timo; 924 timo.tv_sec = prefix_timo;
968 timo.tv_nsec = 0; 925 timo.tv_nsec = 0;
969 rtadvd_set_timer(&timo, prefix->timer); 926 rtadvd_set_timer(&timo, prefix->timer);
970} 927}
971 928
972static struct rtadvd_timer * 929static struct rtadvd_timer *
973prefix_timeout(void *arg) 930prefix_timeout(void *arg)
974{ 931{
975 struct prefix *prefix = (struct prefix *)arg; 932 struct prefix *prefix = (struct prefix *)arg;
976 933
977 delete_prefix(prefix); 934 delete_prefix(prefix);
978 935
979 return(NULL); 936 return(NULL);
980} 937}
981 938
982void 939void
983update_prefix(struct prefix * prefix) 940update_prefix(struct prefix * prefix)
984{ 941{
985 char ntopbuf[INET6_ADDRSTRLEN]; 942 char ntopbuf[INET6_ADDRSTRLEN];
986 struct rainfo *rai = prefix->rainfo; 943 struct rainfo *rai = prefix->rainfo;
987 944
988 if (prefix->timer == NULL) { /* sanity check */ 945 if (prefix->timer == NULL) { /* sanity check */
989 logit(LOG_ERR, 946 logit(LOG_ERR,
990 "<%s> assumption failure: timer does not exist", 947 "<%s> assumption failure: timer does not exist",
991 __func__); 948 __func__);
992 exit(1); 949 exit(1);
993 } 950 }
994 951
995 logit(LOG_DEBUG, "<%s> prefix %s/%d was re-enabled on %s", 952 logit(LOG_DEBUG, "<%s> prefix %s/%d was re-enabled on %s",
996 __func__, inet_ntop(AF_INET6, &prefix->prefix, ntopbuf, 953 __func__, inet_ntop(AF_INET6, &prefix->prefix, ntopbuf,
997 INET6_ADDRSTRLEN), prefix->prefixlen, rai->ifname); 954 INET6_ADDRSTRLEN), prefix->prefixlen, rai->ifname);
998 955
999 /* stop the expiration timer */ 956 /* stop the expiration timer */
1000 rtadvd_remove_timer(&prefix->timer); 957 rtadvd_remove_timer(&prefix->timer);
1001} 958}
1002 959
1003/* 960/*
1004 * Try to get an in6_prefixreq contents for a prefix which matches 961 * Add a prefix to the list of specified interface and reconstruct
1005 * ipr->ipr_prefix and ipr->ipr_plen and belongs to 962 * the outgoing packet.
1006 * the interface whose name is ipr->ipr_name[]. 963 * The prefix must not be in the list.
 964 * XXX: other parameters of the prefix(e.g. lifetime) should be
 965 * able to be specified.
1007 */ 966 */
1008static int 967void
1009init_prefix(struct in6_prefixreq *ipr) 968add_prefix(struct rainfo *rai, int ifindex, struct in6_addr *addr, int plen)
1010{ 969{
1011#if 0 970 struct prefix *prefix;
1012 int s; 971 char ntopbuf[INET6_ADDRSTRLEN];
1013 972
1014 if ((s = prog_socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 973 if ((prefix = calloc(1, sizeof(*prefix))) == NULL) {
1015 logit(LOG_ERR, "<%s> socket: %m", __func__); 974 logit(LOG_ERR, "<%s> memory allocation failed",
1016 exit(1); 975 __func__);
 976 return; /* XXX: error or exit? */
1017 } 977 }
 978 prefix->prefix = *addr;
 979 prefix->prefixlen = plen;
 980 prefix->validlifetime = DEF_ADVVALIDLIFETIME;
 981 prefix->preflifetime = DEF_ADVPREFERREDLIFETIME;
 982 prefix->onlinkflg = 1;
 983 prefix->autoconfflg = 0;
 984 prefix->origin = PREFIX_FROM_DYNAMIC;
1018 985
1019 if (prog_ioctl(s, SIOCGIFPREFIX_IN6, ipr) < 0) { 986 prefix->rainfo = rai;
1020 logit(LOG_INFO, "<%s> ioctl:SIOCGIFPREFIX: %m", __func__); 987 TAILQ_INSERT_TAIL(&rai->prefix, prefix, next);
 988 rai->pfxs++;
1021 989
1022 ipr->ipr_vltime = DEF_ADVVALIDLIFETIME; 990 logit(LOG_DEBUG, "<%s> new prefix %s/%d was added on %s",
1023 ipr->ipr_pltime = DEF_ADVPREFERREDLIFETIME; 991 __func__, inet_ntop(AF_INET6, addr, ntopbuf, INET6_ADDRSTRLEN),
1024 ipr->ipr_raf_onlink = 1; 992 plen, rai->ifname);
1025 ipr->ipr_raf_auto = 1; 
1026 /* omit other field initialization */ 
1027 } 
1028 else if (ipr->ipr_origin < PR_ORIG_RR) { 
1029 char ntopbuf[INET6_ADDRSTRLEN]; 
1030 
1031 logit(LOG_WARNING, "<%s> Added prefix(%s)'s origin %d is" 
1032 "lower than PR_ORIG_RR(router renumbering)." 
1033 "This should not happen if I am router", __func__, 
1034 inet_ntop(AF_INET6, &ipr->ipr_prefix.sin6_addr, ntopbuf, 
1035 sizeof(ntopbuf)), ipr->ipr_origin); 
1036 prog_close(s); 
1037 return 1; 
1038 } 
1039 
1040 prog_close(s); 
1041 return 0; 
1042#else 
1043 ipr->ipr_vltime = DEF_ADVVALIDLIFETIME; 
1044 ipr->ipr_pltime = DEF_ADVPREFERREDLIFETIME; 
1045 ipr->ipr_raf_onlink = 1; 
1046 ipr->ipr_raf_auto = 1; 
1047 return 0; 
1048#endif 
1049} 
1050 993
1051void 994 /* free the previous packet */
1052make_prefix(struct rainfo *rai, int ifindex, struct in6_addr *addr, int plen) 995 free(rai->ra_data);
1053{ 996 rai->ra_data = NULL;
1054 struct in6_prefixreq ipr; 
1055 997
1056 memset(&ipr, 0, sizeof(ipr)); 998 /* reconstruct the packet */
1057 if (if_indextoname(ifindex, ipr.ipr_name) == NULL) { 999 make_packet(rai);
1058 logit(LOG_ERR, "<%s> Prefix added interface No.%d doesn't" 
1059 "exist. This should not happen: %m", __func__, 
1060 ifindex); 
1061 exit(1); 
1062 } 
1063 ipr.ipr_prefix.sin6_len = sizeof(ipr.ipr_prefix); 
1064 ipr.ipr_prefix.sin6_family = AF_INET6; 
1065 ipr.ipr_prefix.sin6_addr = *addr; 
1066 ipr.ipr_plen = plen; 
1067 
1068 if (init_prefix(&ipr)) 
1069 return; /* init failed by some error */ 
1070 add_prefix(rai, &ipr); 
1071} 1000}
1072 1001
1073void 1002void
1074make_packet(struct rainfo *rainfo) 1003make_packet(struct rainfo *rainfo)
1075{ 1004{
1076 size_t packlen, lladdroptlen = 0; 1005 size_t packlen, lladdroptlen = 0;
1077 char *buf; 1006 char *buf;
1078 struct nd_router_advert *ra; 1007 struct nd_router_advert *ra;
1079 struct nd_opt_prefix_info *ndopt_pi; 1008 struct nd_opt_prefix_info *ndopt_pi;
1080 struct nd_opt_mtu *ndopt_mtu; 1009 struct nd_opt_mtu *ndopt_mtu;
1081 struct prefix *pfx; 1010 struct prefix *pfx;
1082 struct nd_opt_route_info *ndopt_rti; 1011 struct nd_opt_route_info *ndopt_rti;
1083 struct rtinfo *rti; 1012 struct rtinfo *rti;
1084 struct nd_opt_rdnss *ndopt_rdnss; 1013 struct nd_opt_rdnss *ndopt_rdnss;
1085 struct rdnss *rdns; 1014 struct rdnss *rdns;
1086 struct rdnss_addr *rdnsa; 1015 struct rdnss_addr *rdnsa;
1087 struct nd_opt_dnssl *ndopt_dnssl; 1016 struct nd_opt_dnssl *ndopt_dnssl;
1088 struct dnssl *dnsl; 1017 struct dnssl *dnsl;
1089 struct dnssl_domain *dnsd; 1018 struct dnssl_domain *dnsd;
1090 size_t len, plen; 1019 size_t len, plen;
1091 1020
1092 /* calculate total length */ 1021 /* calculate total length */
1093 packlen = sizeof(struct nd_router_advert); 1022 packlen = sizeof(struct nd_router_advert);
1094 if (rainfo->advlinkopt) { 1023 if (rainfo->advlinkopt) {
1095 if ((lladdroptlen = lladdropt_length(rainfo->sdl)) == 0) { 1024 if ((lladdroptlen = lladdropt_length(rainfo->sdl)) == 0) {
1096 logit(LOG_INFO, 1025 logit(LOG_INFO,
1097 "<%s> link-layer address option has" 1026 "<%s> link-layer address option has"
1098 " null length on %s. Treat as not included.", 1027 " null length on %s. Treat as not included.",
1099 __func__, rainfo->ifname); 1028 __func__, rainfo->ifname);
1100 rainfo->advlinkopt = 0; 1029 rainfo->advlinkopt = 0;
1101 } 1030 }
1102 packlen += lladdroptlen; 1031 packlen += lladdroptlen;
1103 } 1032 }
1104 if (TAILQ_FIRST(&rainfo->prefix) != NULL) 1033 if (TAILQ_FIRST(&rainfo->prefix) != NULL)
1105 packlen += sizeof(struct nd_opt_prefix_info) * rainfo->pfxs; 1034 packlen += sizeof(struct nd_opt_prefix_info) * rainfo->pfxs;
1106 if (rainfo->linkmtu) 1035 if (rainfo->linkmtu)
1107 packlen += sizeof(struct nd_opt_mtu); 1036 packlen += sizeof(struct nd_opt_mtu);
1108 TAILQ_FOREACH(rti, &rainfo->route, next) 1037 TAILQ_FOREACH(rti, &rainfo->route, next)
1109 packlen += sizeof(struct nd_opt_route_info) + 1038 packlen += sizeof(struct nd_opt_route_info) +
1110 ((rti->prefixlen + 0x3f) >> 6) * 8; 1039 ((rti->prefixlen + 0x3f) >> 6) * 8;
1111 1040
1112 TAILQ_FOREACH(rdns, &rainfo->rdnss, next) { 1041 TAILQ_FOREACH(rdns, &rainfo->rdnss, next) {
1113 packlen += sizeof(struct nd_opt_rdnss); 1042 packlen += sizeof(struct nd_opt_rdnss);
1114 TAILQ_FOREACH(rdnsa, &rdns->list, next) 1043 TAILQ_FOREACH(rdnsa, &rdns->list, next)
1115 packlen += sizeof(rdnsa->addr); 1044 packlen += sizeof(rdnsa->addr);
1116 } 1045 }
1117 TAILQ_FOREACH(dnsl, &rainfo->dnssl, next) { 1046 TAILQ_FOREACH(dnsl, &rainfo->dnssl, next) {
1118 packlen += sizeof(struct nd_opt_dnssl); 1047 packlen += sizeof(struct nd_opt_dnssl);
1119 len = 0; 1048 len = 0;
1120 TAILQ_FOREACH(dnsd, &dnsl->list, next) 1049 TAILQ_FOREACH(dnsd, &dnsl->list, next)
1121 len += dnsd->len; 1050 len += dnsd->len;
1122 len += len % 8 ? 8 - len % 8 : 0; 1051 len += len % 8 ? 8 - len % 8 : 0;
1123 packlen += len; 1052 packlen += len;
1124 } 1053 }
1125 1054
1126 /* allocate memory for the packet */ 1055 /* allocate memory for the packet */
1127 if ((buf = realloc(rainfo->ra_data, packlen)) == NULL) { 1056 if ((buf = realloc(rainfo->ra_data, packlen)) == NULL) {
1128 logit(LOG_ERR, 1057 logit(LOG_ERR,
1129 "<%s> can't get enough memory for an RA packet %m", 1058 "<%s> can't get enough memory for an RA packet %m",
1130 __func__); 1059 __func__);
1131 exit(1); 1060 exit(1);
1132 } 1061 }
1133 rainfo->ra_data = buf; 1062 rainfo->ra_data = buf;
1134 /* XXX: what if packlen > 576? */ 1063 /* XXX: what if packlen > 576? */
1135 rainfo->ra_datalen = packlen; 1064 rainfo->ra_datalen = packlen;
1136#define CHECKLEN(size) \ 1065#define CHECKLEN(size) \
1137 do { \ 1066 do { \
1138 if (buf + size > rainfo->ra_data + packlen) { \ 1067 if (buf + size > rainfo->ra_data + packlen) { \
1139 logit(LOG_ERR, \ 1068 logit(LOG_ERR, \
1140 "<%s, %d> RA packet does not fit in %zu",\ 1069 "<%s, %d> RA packet does not fit in %zu",\
1141 __func__, __LINE__, packlen); \ 1070 __func__, __LINE__, packlen); \
1142 exit(1); \ 1071 exit(1); \
1143 } \ 1072 } \
1144 } while (/*CONSTCOND*/0) 1073 } while (/*CONSTCOND*/0)
1145 /* 1074 /*
1146 * construct the packet 1075 * construct the packet
1147 */ 1076 */
1148 CHECKLEN(sizeof(*ra)); 1077 CHECKLEN(sizeof(*ra));
1149 ra = (struct nd_router_advert *)buf; 1078 ra = (struct nd_router_advert *)buf;
1150 ra->nd_ra_type = ND_ROUTER_ADVERT; 1079 ra->nd_ra_type = ND_ROUTER_ADVERT;
1151 ra->nd_ra_code = 0; 1080 ra->nd_ra_code = 0;
1152 ra->nd_ra_cksum = 0; 1081 ra->nd_ra_cksum = 0;
1153 ra->nd_ra_curhoplimit = (uint8_t)(0xff & rainfo->hoplimit); 1082 ra->nd_ra_curhoplimit = (uint8_t)(0xff & rainfo->hoplimit);
1154 ra->nd_ra_flags_reserved = 0; /* just in case */ 1083 ra->nd_ra_flags_reserved = 0; /* just in case */
1155 /* 1084 /*
1156 * XXX: the router preference field, which is a 2-bit field, should be 1085 * XXX: the router preference field, which is a 2-bit field, should be
1157 * initialized before other fields. 1086 * initialized before other fields.
1158 */ 1087 */
1159 ra->nd_ra_flags_reserved = 0xff & rainfo->rtpref; 1088 ra->nd_ra_flags_reserved = 0xff & rainfo->rtpref;
1160 ra->nd_ra_flags_reserved |= 1089 ra->nd_ra_flags_reserved |=
1161 rainfo->managedflg ? ND_RA_FLAG_MANAGED : 0; 1090 rainfo->managedflg ? ND_RA_FLAG_MANAGED : 0;
1162 ra->nd_ra_flags_reserved |= 1091 ra->nd_ra_flags_reserved |=
1163 rainfo->otherflg ? ND_RA_FLAG_OTHER : 0; 1092 rainfo->otherflg ? ND_RA_FLAG_OTHER : 0;
1164 ra->nd_ra_router_lifetime = htons(rainfo->lifetime); 1093 ra->nd_ra_router_lifetime = htons(rainfo->lifetime);
1165 ra->nd_ra_reachable = htonl(rainfo->reachabletime); 1094 ra->nd_ra_reachable = htonl(rainfo->reachabletime);
1166 ra->nd_ra_retransmit = htonl(rainfo->retranstimer); 1095 ra->nd_ra_retransmit = htonl(rainfo->retranstimer);
1167 buf += sizeof(*ra); 1096 buf += sizeof(*ra);
1168 1097
1169 if (rainfo->advlinkopt) { 1098 if (rainfo->advlinkopt) {
1170 CHECKLEN(sizeof(struct nd_opt_hdr)); 1099 CHECKLEN(sizeof(struct nd_opt_hdr));
1171 lladdropt_fill(rainfo->sdl, (struct nd_opt_hdr *)buf); 1100 lladdropt_fill(rainfo->sdl, (struct nd_opt_hdr *)buf);
1172 buf += lladdroptlen; 1101 buf += lladdroptlen;
1173 } 1102 }
1174 1103
1175 if (rainfo->linkmtu) { 1104 if (rainfo->linkmtu) {
1176 CHECKLEN(sizeof(*ndopt_mtu)); 1105 CHECKLEN(sizeof(*ndopt_mtu));
1177 ndopt_mtu = (struct nd_opt_mtu *)buf; 1106 ndopt_mtu = (struct nd_opt_mtu *)buf;
1178 ndopt_mtu->nd_opt_mtu_type = ND_OPT_MTU; 1107 ndopt_mtu->nd_opt_mtu_type = ND_OPT_MTU;
1179 ndopt_mtu->nd_opt_mtu_len = 1; 1108 ndopt_mtu->nd_opt_mtu_len = 1;
1180 ndopt_mtu->nd_opt_mtu_reserved = 0; 1109 ndopt_mtu->nd_opt_mtu_reserved = 0;
1181 ndopt_mtu->nd_opt_mtu_mtu = htonl(rainfo->linkmtu); 1110 ndopt_mtu->nd_opt_mtu_mtu = htonl(rainfo->linkmtu);
1182 buf += sizeof(struct nd_opt_mtu); 1111 buf += sizeof(struct nd_opt_mtu);
1183 } 1112 }
1184 1113
1185 TAILQ_FOREACH(pfx, &rainfo->prefix, next) { 1114 TAILQ_FOREACH(pfx, &rainfo->prefix, next) {
1186 uint32_t vltime, pltime; 1115 uint32_t vltime, pltime;
1187 struct timespec now; 1116 struct timespec now;
1188 1117
1189 CHECKLEN(sizeof(*ndopt_pi)); 1118 CHECKLEN(sizeof(*ndopt_pi));
1190 ndopt_pi = (struct nd_opt_prefix_info *)buf; 1119 ndopt_pi = (struct nd_opt_prefix_info *)buf;
1191 ndopt_pi->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION; 1120 ndopt_pi->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION;
1192 ndopt_pi->nd_opt_pi_len = 4; 1121 ndopt_pi->nd_opt_pi_len = 4;
1193 ndopt_pi->nd_opt_pi_prefix_len = pfx->prefixlen; 1122 ndopt_pi->nd_opt_pi_prefix_len = pfx->prefixlen;
1194 ndopt_pi->nd_opt_pi_flags_reserved = 0; 1123 ndopt_pi->nd_opt_pi_flags_reserved = 0;
1195 if (pfx->onlinkflg) 1124 if (pfx->onlinkflg)
1196 ndopt_pi->nd_opt_pi_flags_reserved |= 1125 ndopt_pi->nd_opt_pi_flags_reserved |=
1197 ND_OPT_PI_FLAG_ONLINK; 1126 ND_OPT_PI_FLAG_ONLINK;
1198 if (pfx->autoconfflg) 1127 if (pfx->autoconfflg)
1199 ndopt_pi->nd_opt_pi_flags_reserved |= 1128 ndopt_pi->nd_opt_pi_flags_reserved |=
1200 ND_OPT_PI_FLAG_AUTO; 1129 ND_OPT_PI_FLAG_AUTO;
1201 if (pfx->timer) 1130 if (pfx->timer)
1202 vltime = 0; 1131 vltime = 0;
1203 else { 1132 else {
1204 if (pfx->vltimeexpire || pfx->pltimeexpire) 1133 if (pfx->vltimeexpire || pfx->pltimeexpire)
1205 prog_clock_gettime(CLOCK_MONOTONIC, &now); 1134 prog_clock_gettime(CLOCK_MONOTONIC, &now);
1206 if (pfx->vltimeexpire == 0) 1135 if (pfx->vltimeexpire == 0)
1207 vltime = pfx->validlifetime; 1136 vltime = pfx->validlifetime;
1208 else 1137 else
1209 vltime = (pfx->vltimeexpire > now.tv_sec) ? 1138 vltime = (pfx->vltimeexpire > now.tv_sec) ?
1210 pfx->vltimeexpire - now.tv_sec : 0; 1139 pfx->vltimeexpire - now.tv_sec : 0;
1211 } 1140 }
1212 if (pfx->timer) 1141 if (pfx->timer)
1213 pltime = 0; 1142 pltime = 0;
1214 else { 1143 else {
1215 if (pfx->pltimeexpire == 0) 1144 if (pfx->pltimeexpire == 0)
1216 pltime = pfx->preflifetime; 1145 pltime = pfx->preflifetime;
1217 else 1146 else
1218 pltime = (pfx->pltimeexpire > now.tv_sec) ?  1147 pltime = (pfx->pltimeexpire > now.tv_sec) ?
1219 pfx->pltimeexpire - now.tv_sec : 0; 1148 pfx->pltimeexpire - now.tv_sec : 0;
1220 } 1149 }
1221 if (vltime < pltime) { 1150 if (vltime < pltime) {
1222 /* 1151 /*
1223 * this can happen if vltime is decrement but pltime 1152 * this can happen if vltime is decrement but pltime
1224 * is not. 1153 * is not.
1225 */ 1154 */
1226 pltime = vltime; 1155 pltime = vltime;
1227 } 1156 }
1228 ndopt_pi->nd_opt_pi_valid_time = htonl(vltime); 1157 ndopt_pi->nd_opt_pi_valid_time = htonl(vltime);
1229 ndopt_pi->nd_opt_pi_preferred_time = htonl(pltime); 1158 ndopt_pi->nd_opt_pi_preferred_time = htonl(pltime);
1230 ndopt_pi->nd_opt_pi_reserved2 = 0; 1159 ndopt_pi->nd_opt_pi_reserved2 = 0;
1231 ndopt_pi->nd_opt_pi_prefix = pfx->prefix; 1160 ndopt_pi->nd_opt_pi_prefix = pfx->prefix;
1232 1161
1233 buf += sizeof(struct nd_opt_prefix_info); 1162 buf += sizeof(struct nd_opt_prefix_info);
1234 } 1163 }
1235 1164
1236 TAILQ_FOREACH(rti, &rainfo->route, next) { 1165 TAILQ_FOREACH(rti, &rainfo->route, next) {
1237 uint8_t psize = (rti->prefixlen + 0x3f) >> 6; 1166 uint8_t psize = (rti->prefixlen + 0x3f) >> 6;
1238 1167
1239 CHECKLEN(sizeof(*ndopt_rti)); 1168 CHECKLEN(sizeof(*ndopt_rti));
1240 ndopt_rti = (struct nd_opt_route_info *)buf; 1169 ndopt_rti = (struct nd_opt_route_info *)buf;
1241 ndopt_rti->nd_opt_rti_type = ND_OPT_ROUTE_INFO; 1170 ndopt_rti->nd_opt_rti_type = ND_OPT_ROUTE_INFO;
1242 ndopt_rti->nd_opt_rti_len = 1 + psize; 1171 ndopt_rti->nd_opt_rti_len = 1 + psize;
1243 ndopt_rti->nd_opt_rti_prefixlen = rti->prefixlen; 1172 ndopt_rti->nd_opt_rti_prefixlen = rti->prefixlen;
1244 ndopt_rti->nd_opt_rti_flags = 0xff & rti->rtpref; 1173 ndopt_rti->nd_opt_rti_flags = 0xff & rti->rtpref;
1245 ndopt_rti->nd_opt_rti_lifetime = htonl(rti->ltime); 1174 ndopt_rti->nd_opt_rti_lifetime = htonl(rti->ltime);
1246 memcpy(ndopt_rti + 1, &rti->prefix, psize * 8); 1175 memcpy(ndopt_rti + 1, &rti->prefix, psize * 8);
1247 buf += sizeof(struct nd_opt_route_info) + psize * 8; 1176 buf += sizeof(struct nd_opt_route_info) + psize * 8;
1248 } 1177 }
1249 1178
1250 TAILQ_FOREACH(rdns, &rainfo->rdnss, next) { 1179 TAILQ_FOREACH(rdns, &rainfo->rdnss, next) {
1251 CHECKLEN(sizeof(*ndopt_rdnss)); 1180 CHECKLEN(sizeof(*ndopt_rdnss));
1252 ndopt_rdnss = (struct nd_opt_rdnss *)buf; 1181 ndopt_rdnss = (struct nd_opt_rdnss *)buf;
1253 ndopt_rdnss->nd_opt_rdnss_type = ND_OPT_RDNSS; 1182 ndopt_rdnss->nd_opt_rdnss_type = ND_OPT_RDNSS;
1254 ndopt_rdnss->nd_opt_rdnss_len = 1; 1183 ndopt_rdnss->nd_opt_rdnss_len = 1;
1255 ndopt_rdnss->nd_opt_rdnss_reserved = 0; 1184 ndopt_rdnss->nd_opt_rdnss_reserved = 0;
1256 ndopt_rdnss->nd_opt_rdnss_lifetime = htonl(rdns->lifetime); 1185 ndopt_rdnss->nd_opt_rdnss_lifetime = htonl(rdns->lifetime);
1257 buf += sizeof(*ndopt_rdnss); 1186 buf += sizeof(*ndopt_rdnss);
1258 1187
1259 TAILQ_FOREACH(rdnsa, &rdns->list, next) { 1188 TAILQ_FOREACH(rdnsa, &rdns->list, next) {
1260 CHECKLEN(sizeof(rdnsa->addr)); 1189 CHECKLEN(sizeof(rdnsa->addr));
1261 memcpy(buf, &rdnsa->addr, sizeof(rdnsa->addr)); 1190 memcpy(buf, &rdnsa->addr, sizeof(rdnsa->addr));
1262 ndopt_rdnss->nd_opt_rdnss_len += 2; 1191 ndopt_rdnss->nd_opt_rdnss_len += 2;
1263 buf += sizeof(rdnsa->addr); 1192 buf += sizeof(rdnsa->addr);
1264 } 1193 }
1265 } 1194 }
1266 1195
1267 TAILQ_FOREACH(dnsl, &rainfo->dnssl, next) { 1196 TAILQ_FOREACH(dnsl, &rainfo->dnssl, next) {
1268 CHECKLEN(sizeof(*ndopt_dnssl)); 1197 CHECKLEN(sizeof(*ndopt_dnssl));
1269 ndopt_dnssl = (struct nd_opt_dnssl *)buf; 1198 ndopt_dnssl = (struct nd_opt_dnssl *)buf;
1270 ndopt_dnssl->nd_opt_dnssl_type = ND_OPT_DNSSL; 1199 ndopt_dnssl->nd_opt_dnssl_type = ND_OPT_DNSSL;
1271 ndopt_dnssl->nd_opt_dnssl_len = 0; 1200 ndopt_dnssl->nd_opt_dnssl_len = 0;
1272 ndopt_dnssl->nd_opt_dnssl_reserved = 0; 1201 ndopt_dnssl->nd_opt_dnssl_reserved = 0;
1273 ndopt_dnssl->nd_opt_dnssl_lifetime = htonl(dnsl->lifetime); 1202 ndopt_dnssl->nd_opt_dnssl_lifetime = htonl(dnsl->lifetime);
1274 buf += sizeof(*ndopt_dnssl); 1203 buf += sizeof(*ndopt_dnssl);
1275 1204
1276 TAILQ_FOREACH(dnsd, &dnsl->list, next) { 1205 TAILQ_FOREACH(dnsd, &dnsl->list, next) {
1277 CHECKLEN(dnsd->len); 1206 CHECKLEN(dnsd->len);
1278 memcpy(buf, dnsd->domain, dnsd->len); 1207 memcpy(buf, dnsd->domain, dnsd->len);
1279 buf += dnsd->len; 1208 buf += dnsd->len;
1280 } 1209 }
1281 /* Ensure our length is padded correctly */ 1210 /* Ensure our length is padded correctly */
1282 len = buf - (char *)ndopt_dnssl; 1211 len = buf - (char *)ndopt_dnssl;
1283 plen = len % 8 ? 8 - len % 8 : 0; 1212 plen = len % 8 ? 8 - len % 8 : 0;
1284 CHECKLEN(plen); 1213 CHECKLEN(plen);
1285 memset(buf, 0, plen); 1214 memset(buf, 0, plen);
1286 buf += plen; 1215 buf += plen;
1287 ndopt_dnssl->nd_opt_dnssl_len = (len + plen) / 8; 1216 ndopt_dnssl->nd_opt_dnssl_len = (len + plen) / 8;
1288 } 1217 }
1289 memset(buf, 0, packlen - (buf - rainfo->ra_data)); 1218 memset(buf, 0, packlen - (buf - rainfo->ra_data));
1290} 1219}
1291 1220
1292static int 1221static int
1293getinet6sysctl(int code) 1222getinet6sysctl(int code)
1294{ 1223{
1295 const int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, code }; 1224 const int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, code };
1296 int value; 1225 int value;
1297 size_t size; 1226 size_t size;
1298 1227
1299 size = sizeof(value); 1228 size = sizeof(value);
1300 if (prog_sysctl(mib, __arraycount(mib), &value, &size, NULL, 0) 1229 if (prog_sysctl(mib, __arraycount(mib), &value, &size, NULL, 0)
1301 < 0) { 1230 < 0) {
1302 logit(LOG_ERR, "<%s>: failed to get ip6 sysctl(%d): %m", 1231 logit(LOG_ERR, "<%s>: failed to get ip6 sysctl(%d): %m",
1303 __func__, code); 1232 __func__, code);
1304 return -1; 1233 return -1;
1305 } 1234 }
1306 else 1235 else
1307 return value; 1236 return value;
1308} 1237}

cvs diff -r1.10 -r1.11 src/usr.sbin/rtadvd/config.h (switch to unified diff)

--- src/usr.sbin/rtadvd/config.h 2018/04/20 10:39:37 1.10
+++ src/usr.sbin/rtadvd/config.h 2020/04/21 12:16:47 1.11
@@ -1,49 +1,49 @@ @@ -1,49 +1,49 @@
1/* $NetBSD: config.h,v 1.10 2018/04/20 10:39:37 roy Exp $ */ 1/* $NetBSD: config.h,v 1.11 2020/04/21 12:16:47 roy Exp $ */
2/* $KAME: config.h,v 1.9 2003/08/06 04:19:40 ono Exp $ */ 2/* $KAME: config.h,v 1.9 2003/08/06 04:19:40 ono Exp $ */
3 3
4/* 4/*
5 * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. 5 * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
6 * All rights reserved. 6 * All rights reserved.
7 * 7 *
8 * Redistribution and use in source and binary forms, with or without 8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions 9 * modification, are permitted provided that the following conditions
10 * are met: 10 * are met:
11 * 1. Redistributions of source code must retain the above copyright 11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer. 12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright 13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the 14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution. 15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the project nor the names of its contributors 16 * 3. Neither the name of the project nor the names of its contributors
17 * may be used to endorse or promote products derived from this software 17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission. 18 * without specific prior written permission.
19 * 19 *
20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE. 30 * SUCH DAMAGE.
31 */ 31 */
32 32
33extern void free_rainfo(struct rainfo *); 33extern void free_rainfo(struct rainfo *);
34extern void getconfig(const char *, int); 34extern void getconfig(const char *, int);
35extern void delete_prefix(struct prefix *); 35extern void delete_prefix(struct prefix *);
36extern void invalidate_prefix(struct prefix *); 36extern void invalidate_prefix(struct prefix *);
37extern void update_prefix(struct prefix *); 37extern void update_prefix(struct prefix *);
38extern void make_prefix(struct rainfo *, int, struct in6_addr *, int); 38extern void add_prefix(struct rainfo *, int, struct in6_addr *, int);
39extern void make_packet(struct rainfo *); 39extern void make_packet(struct rainfo *);
40extern void get_prefix(struct rainfo *); 40extern void get_prefix(struct rainfo *);
41 41
42/* 42/*
43 * it is highly unlikely to have 100 information options, 43 * it is highly unlikely to have 100 information options,
44 * so it should be okay to limit it 44 * so it should be okay to limit it
45 */ 45 */
46#define MAXPREFIX 100 46#define MAXPREFIX 100
47#define MAXROUTE 100 47#define MAXROUTE 100
48#define MAXRDNSS 100 48#define MAXRDNSS 100
49#define MAXDNSSL 100 49#define MAXDNSSL 100

cvs diff -r1.72 -r1.73 src/usr.sbin/rtadvd/rtadvd.c (switch to unified diff)

--- src/usr.sbin/rtadvd/rtadvd.c 2020/04/21 12:05:54 1.72
+++ src/usr.sbin/rtadvd/rtadvd.c 2020/04/21 12:16:47 1.73
@@ -1,1617 +1,1617 @@ @@ -1,1617 +1,1617 @@
1/* $NetBSD: rtadvd.c,v 1.72 2020/04/21 12:05:54 roy Exp $ */ 1/* $NetBSD: rtadvd.c,v 1.73 2020/04/21 12:16:47 roy Exp $ */
2/* $KAME: rtadvd.c,v 1.92 2005/10/17 14:40:02 suz Exp $ */ 2/* $KAME: rtadvd.c,v 1.92 2005/10/17 14:40:02 suz Exp $ */
3 3
4/* 4/*
5 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 5 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
6 * All rights reserved. 6 * All rights reserved.
7 * 7 *
8 * Redistribution and use in source and binary forms, with or without 8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions 9 * modification, are permitted provided that the following conditions
10 * are met: 10 * are met:
11 * 1. Redistributions of source code must retain the above copyright 11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer. 12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright 13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the 14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution. 15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the project nor the names of its contributors 16 * 3. Neither the name of the project nor the names of its contributors
17 * may be used to endorse or promote products derived from this software 17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission. 18 * without specific prior written permission.
19 * 19 *
20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE. 30 * SUCH DAMAGE.
31 */ 31 */
32 32
33#include <sys/param.h> 33#include <sys/param.h>
34#include <sys/socket.h> 34#include <sys/socket.h>
35#include <sys/uio.h> 35#include <sys/uio.h>
36#include <sys/time.h> 36#include <sys/time.h>
37#include <sys/queue.h> 37#include <sys/queue.h>
38 38
39#include <net/if.h> 39#include <net/if.h>
40#include <net/route.h> 40#include <net/route.h>
41#include <net/if_dl.h> 41#include <net/if_dl.h>
42#include <netinet/in.h> 42#include <netinet/in.h>
43#include <netinet/ip6.h> 43#include <netinet/ip6.h>
44#include <netinet6/ip6_var.h> 44#include <netinet6/ip6_var.h>
45#include <netinet/icmp6.h> 45#include <netinet/icmp6.h>
46 46
47#include <arpa/inet.h> 47#include <arpa/inet.h>
48 48
49#include <time.h> 49#include <time.h>
50#include <unistd.h> 50#include <unistd.h>
51#include <stdio.h> 51#include <stdio.h>
52#include <err.h> 52#include <err.h>
53#include <errno.h> 53#include <errno.h>
54#include <string.h> 54#include <string.h>
55#include <stdlib.h> 55#include <stdlib.h>
56#include <syslog.h> 56#include <syslog.h>
57#include <stdarg.h> 57#include <stdarg.h>
58#ifdef __NetBSD__ 58#ifdef __NetBSD__
59#include <util.h> 59#include <util.h>
60#endif 60#endif
61#include <poll.h> 61#include <poll.h>
62#include <pwd.h> 62#include <pwd.h>
63 63
64#include "rtadvd.h" 64#include "rtadvd.h"
65#include "advcap.h" 65#include "advcap.h"
66#include "timer.h" 66#include "timer.h"
67#include "if.h" 67#include "if.h"
68#include "config.h" 68#include "config.h"
69#include "dump.h" 69#include "dump.h"
70#include "logit.h" 70#include "logit.h"
71#include "prog_ops.h" 71#include "prog_ops.h"
72#include "expandm.h" 72#include "expandm.h"
73 73
74struct msghdr rcvmhdr; 74struct msghdr rcvmhdr;
75static unsigned char *rcvcmsgbuf; 75static unsigned char *rcvcmsgbuf;
76static size_t rcvcmsgbuflen; 76static size_t rcvcmsgbuflen;
77static unsigned char *sndcmsgbuf; 77static unsigned char *sndcmsgbuf;
78static size_t sndcmsgbuflen; 78static size_t sndcmsgbuflen;
79volatile sig_atomic_t do_dump; 79volatile sig_atomic_t do_dump;
80volatile sig_atomic_t do_reconf; 80volatile sig_atomic_t do_reconf;
81volatile sig_atomic_t do_die; 81volatile sig_atomic_t do_die;
82struct msghdr sndmhdr; 82struct msghdr sndmhdr;
83struct iovec rcviov[2]; 83struct iovec rcviov[2];
84struct iovec sndiov[2]; 84struct iovec sndiov[2];
85struct sockaddr_in6 rcvfrom; 85struct sockaddr_in6 rcvfrom;
86static const char *dumpfilename = "/var/run/rtadvd.dump"; /* XXX configurable */ 86static const char *dumpfilename = "/var/run/rtadvd.dump"; /* XXX configurable */
87int sock; 87int sock;
88int rtsock = -1; 88int rtsock = -1;
89int Cflag = 0, dflag = 0, sflag = 0, Dflag; 89int Cflag = 0, dflag = 0, sflag = 0, Dflag;
90 90
91static char **if_argv; 91static char **if_argv;
92static int if_argc; 92static int if_argc;
93 93
94char *conffile = NULL; 94char *conffile = NULL;
95 95
96struct ralist_head_t ralist = TAILQ_HEAD_INITIALIZER(ralist); 96struct ralist_head_t ralist = TAILQ_HEAD_INITIALIZER(ralist);
97 97
98struct nd_optlist { 98struct nd_optlist {
99 TAILQ_ENTRY(nd_optlist) next; 99 TAILQ_ENTRY(nd_optlist) next;
100 struct nd_opt_hdr *opt; 100 struct nd_opt_hdr *opt;
101}; 101};
102union nd_opts { 102union nd_opts {
103 struct nd_opt_hdr *nd_opt_array[9]; 103 struct nd_opt_hdr *nd_opt_array[9];
104 struct { 104 struct {
105 struct nd_opt_hdr *zero; 105 struct nd_opt_hdr *zero;
106 struct nd_opt_hdr *src_lladdr; 106 struct nd_opt_hdr *src_lladdr;
107 struct nd_opt_hdr *tgt_lladdr; 107 struct nd_opt_hdr *tgt_lladdr;
108 struct nd_opt_prefix_info *pi; 108 struct nd_opt_prefix_info *pi;
109 struct nd_opt_rd_hdr *rh; 109 struct nd_opt_rd_hdr *rh;
110 struct nd_opt_mtu *mtu; 110 struct nd_opt_mtu *mtu;
111 TAILQ_HEAD(, nd_optlist) list; 111 TAILQ_HEAD(, nd_optlist) list;
112 } nd_opt_each; 112 } nd_opt_each;
113}; 113};
114#define nd_opts_src_lladdr nd_opt_each.src_lladdr 114#define nd_opts_src_lladdr nd_opt_each.src_lladdr
115#define nd_opts_tgt_lladdr nd_opt_each.tgt_lladdr 115#define nd_opts_tgt_lladdr nd_opt_each.tgt_lladdr
116#define nd_opts_pi nd_opt_each.pi 116#define nd_opts_pi nd_opt_each.pi
117#define nd_opts_rh nd_opt_each.rh 117#define nd_opts_rh nd_opt_each.rh
118#define nd_opts_mtu nd_opt_each.mtu 118#define nd_opts_mtu nd_opt_each.mtu
119#define nd_opts_list nd_opt_each.list 119#define nd_opts_list nd_opt_each.list
120 120
121#define NDOPT_FLAG_SRCLINKADDR (1 << 0) 121#define NDOPT_FLAG_SRCLINKADDR (1 << 0)
122#define NDOPT_FLAG_TGTLINKADDR (1 << 1) 122#define NDOPT_FLAG_TGTLINKADDR (1 << 1)
123#define NDOPT_FLAG_PREFIXINFO (1 << 2) 123#define NDOPT_FLAG_PREFIXINFO (1 << 2)
124#define NDOPT_FLAG_RDHDR (1 << 3) 124#define NDOPT_FLAG_RDHDR (1 << 3)
125#define NDOPT_FLAG_MTU (1 << 4) 125#define NDOPT_FLAG_MTU (1 << 4)
126#define NDOPT_FLAG_RDNSS (1 << 5) 126#define NDOPT_FLAG_RDNSS (1 << 5)
127#define NDOPT_FLAG_DNSSL (1 << 6) 127#define NDOPT_FLAG_DNSSL (1 << 6)
128 128
129uint32_t ndopt_flags[] = { 129uint32_t ndopt_flags[] = {
130 [ND_OPT_SOURCE_LINKADDR] = NDOPT_FLAG_SRCLINKADDR, 130 [ND_OPT_SOURCE_LINKADDR] = NDOPT_FLAG_SRCLINKADDR,
131 [ND_OPT_TARGET_LINKADDR] = NDOPT_FLAG_TGTLINKADDR, 131 [ND_OPT_TARGET_LINKADDR] = NDOPT_FLAG_TGTLINKADDR,
132 [ND_OPT_PREFIX_INFORMATION] = NDOPT_FLAG_PREFIXINFO, 132 [ND_OPT_PREFIX_INFORMATION] = NDOPT_FLAG_PREFIXINFO,
133 [ND_OPT_REDIRECTED_HEADER] = NDOPT_FLAG_RDHDR, 133 [ND_OPT_REDIRECTED_HEADER] = NDOPT_FLAG_RDHDR,
134 [ND_OPT_MTU] = NDOPT_FLAG_MTU, 134 [ND_OPT_MTU] = NDOPT_FLAG_MTU,
135 [ND_OPT_RDNSS] = NDOPT_FLAG_RDNSS, 135 [ND_OPT_RDNSS] = NDOPT_FLAG_RDNSS,
136 [ND_OPT_DNSSL] = NDOPT_FLAG_DNSSL, 136 [ND_OPT_DNSSL] = NDOPT_FLAG_DNSSL,
137}; 137};
138 138
139struct sockaddr_in6 sin6_linklocal_allnodes = { 139struct sockaddr_in6 sin6_linklocal_allnodes = {
140 .sin6_len = sizeof(sin6_linklocal_allnodes), 140 .sin6_len = sizeof(sin6_linklocal_allnodes),
141 .sin6_family = AF_INET6, 141 .sin6_family = AF_INET6,
142 .sin6_addr = IN6ADDR_LINKLOCAL_ALLNODES_INIT, 142 .sin6_addr = IN6ADDR_LINKLOCAL_ALLNODES_INIT,
143}; 143};
144#ifdef notdef 144#ifdef notdef
145struct sockaddr_in6 sin6_linklocal_allrouters = { 145struct sockaddr_in6 sin6_linklocal_allrouters = {
146 .sin6_len = sizeof(sin6_linklocal_allrouters), 146 .sin6_len = sizeof(sin6_linklocal_allrouters),
147 .sin6_family = AF_INET6, 147 .sin6_family = AF_INET6,
148 .sin6_addr = IN6ADDR_LINKLOCAL_ALLROUTERS_INIT, 148 .sin6_addr = IN6ADDR_LINKLOCAL_ALLROUTERS_INIT,
149}; 149};
150#endif 150#endif
151struct sockaddr_in6 sin6_sitelocal_allrouters = { 151struct sockaddr_in6 sin6_sitelocal_allrouters = {
152 .sin6_len = sizeof(sin6_sitelocal_allrouters), 152 .sin6_len = sizeof(sin6_sitelocal_allrouters),
153 .sin6_family = AF_INET6, 153 .sin6_family = AF_INET6,
154 .sin6_addr = IN6ADDR_SITELOCAL_ALLROUTERS_INIT, 154 .sin6_addr = IN6ADDR_SITELOCAL_ALLROUTERS_INIT,
155}; 155};
156 156
157static void set_die(int); 157static void set_die(int);
158static void die(void); 158static void die(void);
159static void set_reconf(int); 159static void set_reconf(int);
160static void sock_open(void); 160static void sock_open(void);
161static void rtsock_open(void); 161static void rtsock_open(void);
162static void rtadvd_input(void); 162static void rtadvd_input(void);
163static void rs_input(int, struct nd_router_solicit *, 163static void rs_input(int, struct nd_router_solicit *,
164 struct in6_pktinfo *, struct sockaddr_in6 *); 164 struct in6_pktinfo *, struct sockaddr_in6 *);
165static void ra_input(int, struct nd_router_advert *, 165static void ra_input(int, struct nd_router_advert *,
166 struct in6_pktinfo *, struct sockaddr_in6 *); 166 struct in6_pktinfo *, struct sockaddr_in6 *);
167static struct rainfo *ra_output(struct rainfo *, bool); 167static struct rainfo *ra_output(struct rainfo *, bool);
168static int prefix_check(struct nd_opt_prefix_info *, struct rainfo *, 168static int prefix_check(struct nd_opt_prefix_info *, struct rainfo *,
169 struct sockaddr_in6 *); 169 struct sockaddr_in6 *);
170static int nd6_options(struct nd_opt_hdr *, int, union nd_opts *, uint32_t); 170static int nd6_options(struct nd_opt_hdr *, int, union nd_opts *, uint32_t);
171static void free_ndopts(union nd_opts *); 171static void free_ndopts(union nd_opts *);
172static void rtmsg_input(void); 172static void rtmsg_input(void);
173static void rtadvd_set_dump_file(int); 173static void rtadvd_set_dump_file(int);
174 174
175int 175int
176main(int argc, char *argv[]) 176main(int argc, char *argv[])
177{ 177{
178 struct pollfd set[2]; 178 struct pollfd set[2];
179 struct timespec *timeout; 179 struct timespec *timeout;
180 int i, ch; 180 int i, ch;
181 int fflag = 0, logopt; 181 int fflag = 0, logopt;
182 struct passwd *pw; 182 struct passwd *pw;
183 const char *pidfilepath = NULL; 183 const char *pidfilepath = NULL;
184 pid_t pid; 184 pid_t pid;
185 185
186 /* get command line options and arguments */ 186 /* get command line options and arguments */
187#define OPTIONS "c:dDfM:p:s" 187#define OPTIONS "c:dDfM:p:s"
188 while ((ch = getopt(argc, argv, OPTIONS)) != -1) { 188 while ((ch = getopt(argc, argv, OPTIONS)) != -1) {
189#undef OPTIONS 189#undef OPTIONS
190 switch (ch) { 190 switch (ch) {
191 case 'c': 191 case 'c':
192 conffile = optarg; 192 conffile = optarg;
193 break; 193 break;
194 case 'C': 194 case 'C':
195 Cflag++; 195 Cflag++;
196 break; 196 break;
197 case 'd': 197 case 'd':
198 dflag++; 198 dflag++;
199 break; 199 break;
200 case 'D': 200 case 'D':
201 Dflag++; 201 Dflag++;
202 break; 202 break;
203 case 'f': 203 case 'f':
204 fflag = 1; 204 fflag = 1;
205 break; 205 break;
206 case 'p': 206 case 'p':
207 pidfilepath = optarg; 207 pidfilepath = optarg;
208 break; 208 break;
209 case 's': 209 case 's':
210 sflag = 1; 210 sflag = 1;
211 break; 211 break;
212 } 212 }
213 } 213 }
214 argc -= optind; 214 argc -= optind;
215 argv += optind; 215 argv += optind;
216 if (argc == 0) { 216 if (argc == 0) {
217 fprintf(stderr, "Ysage: %s [-DdfRs] [-c conffile]" 217 fprintf(stderr, "Ysage: %s [-DdfRs] [-c conffile]"
218 " [-M ifname] [-p pidfile] interface ...\n", getprogname()); 218 " [-M ifname] [-p pidfile] interface ...\n", getprogname());
219 return EXIT_FAILURE; 219 return EXIT_FAILURE;
220 } 220 }
221 221
222 if ((pid = pidfile_lock(pidfilepath)) != 0) { 222 if ((pid = pidfile_lock(pidfilepath)) != 0) {
223 if (pid == -1) 223 if (pid == -1)
224 logit(LOG_ERR, "pidfile_lock: %m"); 224 logit(LOG_ERR, "pidfile_lock: %m");
225 /* Continue */ 225 /* Continue */
226 else { 226 else {
227 logit(LOG_ERR, "Another instance of `%s' is running " 227 logit(LOG_ERR, "Another instance of `%s' is running "
228 "(pid %d); exiting.", getprogname(), pid); 228 "(pid %d); exiting.", getprogname(), pid);
229 return EXIT_FAILURE; 229 return EXIT_FAILURE;
230 } 230 }
231 } 231 }
232 232
233 if (prog_init && prog_init() == -1) 233 if (prog_init && prog_init() == -1)
234 err(EXIT_FAILURE, "init failed"); 234 err(EXIT_FAILURE, "init failed");
235 235
236 logopt = LOG_NDELAY | LOG_PID; 236 logopt = LOG_NDELAY | LOG_PID;
237 if (fflag) 237 if (fflag)
238 logopt |= LOG_PERROR; 238 logopt |= LOG_PERROR;
239 openlog("rtadvd", logopt, LOG_DAEMON); 239 openlog("rtadvd", logopt, LOG_DAEMON);
240 240
241 /* set log level */ 241 /* set log level */
242 if (dflag == 0) 242 if (dflag == 0)
243 (void)setlogmask(LOG_UPTO(LOG_ERR)); 243 (void)setlogmask(LOG_UPTO(LOG_ERR));
244 if (dflag == 1) 244 if (dflag == 1)
245 (void)setlogmask(LOG_UPTO(LOG_INFO)); 245 (void)setlogmask(LOG_UPTO(LOG_INFO));
246 246
247 errno = 0; /* Ensure errno is 0 so we know if getpwnam errors or not */ 247 errno = 0; /* Ensure errno is 0 so we know if getpwnam errors or not */
248 if ((pw = getpwnam(RTADVD_USER)) == NULL) { 248 if ((pw = getpwnam(RTADVD_USER)) == NULL) {
249 if (errno == 0) 249 if (errno == 0)
250 logit(LOG_ERR, 250 logit(LOG_ERR,
251 "user %s does not exist, aborting", 251 "user %s does not exist, aborting",
252 RTADVD_USER); 252 RTADVD_USER);
253 else 253 else
254 logit(LOG_ERR, "getpwnam: %s: %m", RTADVD_USER); 254 logit(LOG_ERR, "getpwnam: %s: %m", RTADVD_USER);
255 return EXIT_FAILURE; 255 return EXIT_FAILURE;
256 } 256 }
257 257
258 /* timer initialization */ 258 /* timer initialization */
259 rtadvd_timer_init(); 259 rtadvd_timer_init();
260 260
261 if_argc = argc; 261 if_argc = argc;
262 if_argv = argv; 262 if_argv = argv;
263 while (argc--) 263 while (argc--)
264 getconfig(*argv++, 1); 264 getconfig(*argv++, 1);
265 265
266 if (!fflag) { 266 if (!fflag) {
267 prog_daemon(1, 0); 267 prog_daemon(1, 0);
268 if (pidfile_lock(pidfilepath) != 0) 268 if (pidfile_lock(pidfilepath) != 0)
269 logit(LOG_ERR, " pidfile_lock: %m"); 269 logit(LOG_ERR, " pidfile_lock: %m");
270 } 270 }
271 271
272 sock_open(); 272 sock_open();
273 273
274 set[0].fd = sock; 274 set[0].fd = sock;
275 set[0].events = POLLIN; 275 set[0].events = POLLIN;
276 if (sflag == 0) { 276 if (sflag == 0) {
277 rtsock_open(); 277 rtsock_open();
278 set[1].fd = rtsock; 278 set[1].fd = rtsock;
279 set[1].events = POLLIN; 279 set[1].events = POLLIN;
280 } else 280 } else
281 set[1].fd = -1; 281 set[1].fd = -1;
282 282
283 logit(LOG_INFO, "dropping privileges to %s", RTADVD_USER); 283 logit(LOG_INFO, "dropping privileges to %s", RTADVD_USER);
284 if (prog_chroot(pw->pw_dir) == -1) { 284 if (prog_chroot(pw->pw_dir) == -1) {
285 logit(LOG_ERR, "chroot: %s: %m", pw->pw_dir); 285 logit(LOG_ERR, "chroot: %s: %m", pw->pw_dir);
286 return EXIT_FAILURE; 286 return EXIT_FAILURE;
287 } 287 }
288 if (prog_chdir("/") == -1) { 288 if (prog_chdir("/") == -1) {
289 logit(LOG_ERR, "chdir: /: %m"); 289 logit(LOG_ERR, "chdir: /: %m");
290 return EXIT_FAILURE; 290 return EXIT_FAILURE;
291 } 291 }
292 if (prog_setgroups(1, &pw->pw_gid) == -1 || 292 if (prog_setgroups(1, &pw->pw_gid) == -1 ||
293 prog_setgid(pw->pw_gid) == -1 || 293 prog_setgid(pw->pw_gid) == -1 ||
294 prog_setuid(pw->pw_uid) == -1) 294 prog_setuid(pw->pw_uid) == -1)
295 { 295 {
296 logit(LOG_ERR, "failed to drop privileges: %m"); 296 logit(LOG_ERR, "failed to drop privileges: %m");
297 return EXIT_FAILURE; 297 return EXIT_FAILURE;
298 } 298 }
299 299
300 signal(SIGINT, set_die); 300 signal(SIGINT, set_die);
301 signal(SIGTERM, set_die); 301 signal(SIGTERM, set_die);
302 signal(SIGHUP, set_reconf); 302 signal(SIGHUP, set_reconf);
303 signal(SIGUSR1, rtadvd_set_dump_file); 303 signal(SIGUSR1, rtadvd_set_dump_file);
304 304
305 for (;;) { 305 for (;;) {
306 if (do_dump) { /* SIGUSR1 */ 306 if (do_dump) { /* SIGUSR1 */
307 do_dump = 0; 307 do_dump = 0;
308 rtadvd_dump_file(dumpfilename); 308 rtadvd_dump_file(dumpfilename);
309 } 309 }
310 310
311 if (do_reconf) { /* SIGHUP */ 311 if (do_reconf) { /* SIGHUP */
312 do_reconf = 0; 312 do_reconf = 0;
313 logit(LOG_INFO, "%s: reloading config on SIGHUP", 313 logit(LOG_INFO, "%s: reloading config on SIGHUP",
314 __func__); 314 __func__);
315 argc = if_argc; 315 argc = if_argc;
316 argv = if_argv; 316 argv = if_argv;
317 while (argc--) 317 while (argc--)
318 getconfig(*argv++, 0); 318 getconfig(*argv++, 0);
319 } 319 }
320 320
321 /* timer expiration check and reset the timer */ 321 /* timer expiration check and reset the timer */
322 timeout = rtadvd_check_timer(); 322 timeout = rtadvd_check_timer();
323 323
324 if (do_die) { 324 if (do_die) {
325 die(); 325 die();
326 /*NOTREACHED*/ 326 /*NOTREACHED*/
327 } 327 }
328 328
329 if (timeout != NULL) { 329 if (timeout != NULL) {
330 logit(LOG_DEBUG, 330 logit(LOG_DEBUG,
331 "%s: set timer to %jd:%jd. waiting for " 331 "%s: set timer to %jd:%jd. waiting for "
332 "inputs or timeout", __func__, 332 "inputs or timeout", __func__,
333 (intmax_t)timeout->tv_sec, 333 (intmax_t)timeout->tv_sec,
334 (intmax_t)timeout->tv_nsec); 334 (intmax_t)timeout->tv_nsec);
335 } else { 335 } else {
336 logit(LOG_DEBUG, 336 logit(LOG_DEBUG,
337 "%s: there's no timer. waiting for inputs", 337 "%s: there's no timer. waiting for inputs",
338 __func__); 338 __func__);
339 } 339 }
340 340
341 if ((i = prog_poll(set, 2, timeout ? (timeout->tv_sec * 1000 + 341 if ((i = prog_poll(set, 2, timeout ? (timeout->tv_sec * 1000 +
342 (timeout->tv_nsec + 999999) / 1000000) : INFTIM)) == -1) 342 (timeout->tv_nsec + 999999) / 1000000) : INFTIM)) == -1)
343 { 343 {
344 /* EINTR would occur upon SIGUSR1 for status dump */ 344 /* EINTR would occur upon SIGUSR1 for status dump */
345 if (errno == EINTR) { 345 if (errno == EINTR) {
346 if (do_die) 346 if (do_die)
347 die(); 347 die();
348 continue; 348 continue;
349 } 349 }
350 350
351 logit(LOG_ERR, "%s: poll: %m", __func__); 351 logit(LOG_ERR, "%s: poll: %m", __func__);
352 if (Dflag) 352 if (Dflag)
353 exit(1); 353 exit(1);
354 } 354 }
355 if (i == 0) /* timeout */ 355 if (i == 0) /* timeout */
356 continue; 356 continue;
357 if (rtsock != -1 && set[1].revents & POLLIN) 357 if (rtsock != -1 && set[1].revents & POLLIN)
358 rtmsg_input(); 358 rtmsg_input();
359 if (set[0].revents & POLLIN) 359 if (set[0].revents & POLLIN)
360 rtadvd_input(); 360 rtadvd_input();
361 } 361 }
362 return EXIT_SUCCESS; /* NOTREACHED */ 362 return EXIT_SUCCESS; /* NOTREACHED */
363} 363}
364 364
365static void 365static void
366rtadvd_set_dump_file(__unused int sig) 366rtadvd_set_dump_file(__unused int sig)
367{ 367{
368 368
369 do_dump = 1; 369 do_dump = 1;
370} 370}
371 371
372static void 372static void
373set_reconf(__unused int sig) 373set_reconf(__unused int sig)
374{ 374{
375 375
376 do_reconf = 1; 376 do_reconf = 1;
377} 377}
378 378
379static void 379static void
380set_die(__unused int sig) 380set_die(__unused int sig)
381{ 381{
382 382
383 do_die = 1; 383 do_die = 1;
384} 384}
385 385
386static void 386static void
387die(void) 387die(void)
388{ 388{
389 static int waiting; 389 static int waiting;
390 struct rainfo *rai, *ran; 390 struct rainfo *rai, *ran;
391 struct rdnss *rdnss; 391 struct rdnss *rdnss;
392 struct dnssl *dnssl; 392 struct dnssl *dnssl;
393 393
394 if (waiting) { 394 if (waiting) {
395 if (TAILQ_FIRST(&ralist)) { 395 if (TAILQ_FIRST(&ralist)) {
396 logit(LOG_INFO, 396 logit(LOG_INFO,
397 "%s: waiting for expiration of all RA timers", 397 "%s: waiting for expiration of all RA timers",
398 __func__); 398 __func__);
399 return; 399 return;
400 } 400 }
401 logit(LOG_NOTICE, "%s: gracefully terminated", __func__); 401 logit(LOG_NOTICE, "%s: gracefully terminated", __func__);
402 free(rcvcmsgbuf); 402 free(rcvcmsgbuf);
403 free(sndcmsgbuf); 403 free(sndcmsgbuf);
404 exit(EXIT_SUCCESS); 404 exit(EXIT_SUCCESS);
405 /* NOT REACHED */ 405 /* NOT REACHED */
406 } 406 }
407 407
408 if (TAILQ_FIRST(&ralist) == NULL) { 408 if (TAILQ_FIRST(&ralist) == NULL) {
409 logit(LOG_NOTICE, "%s: gracefully terminated", __func__); 409 logit(LOG_NOTICE, "%s: gracefully terminated", __func__);
410 exit(EXIT_SUCCESS); 410 exit(EXIT_SUCCESS);
411 /* NOT REACHED */ 411 /* NOT REACHED */
412 } 412 }
413 413
414 waiting = 1; 414 waiting = 1;
415 logit(LOG_NOTICE, "%s: final RA transmission started", __func__); 415 logit(LOG_NOTICE, "%s: final RA transmission started", __func__);
416 416
417 TAILQ_FOREACH_SAFE(rai, &ralist, next, ran) { 417 TAILQ_FOREACH_SAFE(rai, &ralist, next, ran) {
418 if (rai->leaving) { 418 if (rai->leaving) {
419 TAILQ_REMOVE(&ralist, rai, next); 419 TAILQ_REMOVE(&ralist, rai, next);
420 TAILQ_INSERT_HEAD(&ralist, rai->leaving, next); 420 TAILQ_INSERT_HEAD(&ralist, rai->leaving, next);
421 rai->leaving->leaving = rai->leaving; 421 rai->leaving->leaving = rai->leaving;
422 rai->leaving->leaving_for = rai->leaving; 422 rai->leaving->leaving_for = rai->leaving;
423 free_rainfo(rai); 423 free_rainfo(rai);
424 continue; 424 continue;
425 } 425 }
426 rai->lifetime = 0; 426 rai->lifetime = 0;
427 TAILQ_FOREACH(rdnss, &rai->rdnss, next) 427 TAILQ_FOREACH(rdnss, &rai->rdnss, next)
428 rdnss->lifetime = 0; 428 rdnss->lifetime = 0;
429 TAILQ_FOREACH(dnssl, &rai->dnssl, next) 429 TAILQ_FOREACH(dnssl, &rai->dnssl, next)
430 dnssl->lifetime = 0; 430 dnssl->lifetime = 0;
431 make_packet(rai); 431 make_packet(rai);
432 rai->leaving = rai; 432 rai->leaving = rai;
433 rai->leaving_for = rai; 433 rai->leaving_for = rai;
434 rai->initcounter = MAX_INITIAL_RTR_ADVERTISEMENTS; 434 rai->initcounter = MAX_INITIAL_RTR_ADVERTISEMENTS;
435 rai->mininterval = MIN_DELAY_BETWEEN_RAS; 435 rai->mininterval = MIN_DELAY_BETWEEN_RAS;
436 rai->maxinterval = MIN_DELAY_BETWEEN_RAS; 436 rai->maxinterval = MIN_DELAY_BETWEEN_RAS;
437 rai->leaving_adv = MAX_FINAL_RTR_ADVERTISEMENTS; 437 rai->leaving_adv = MAX_FINAL_RTR_ADVERTISEMENTS;
438 ra_output(rai, false); 438 ra_output(rai, false);
439 ra_timer_update(rai, &rai->timer->tm); 439 ra_timer_update(rai, &rai->timer->tm);
440 rtadvd_set_timer(&rai->timer->tm, rai->timer); 440 rtadvd_set_timer(&rai->timer->tm, rai->timer);
441 } 441 }
442 exit(EXIT_SUCCESS); 442 exit(EXIT_SUCCESS);
443} 443}
444 444
445static void 445static void
446ra_timer_reset(struct rainfo *rai) 446ra_timer_reset(struct rainfo *rai)
447{ 447{
448 448
449 rtadvd_remove_timer(&rai->timer); 449 rtadvd_remove_timer(&rai->timer);
450 rai->timer = rtadvd_add_timer(ra_timeout, ra_timer_update, rai, rai); 450 rai->timer = rtadvd_add_timer(ra_timeout, ra_timer_update, rai, rai);
451 ra_timer_update(rai, &rai->timer->tm); 451 ra_timer_update(rai, &rai->timer->tm);
452 rtadvd_set_timer(&rai->timer->tm, rai->timer); 452 rtadvd_set_timer(&rai->timer->tm, rai->timer);
453 rtadvd_remove_timer(&rai->timer_sol); 453 rtadvd_remove_timer(&rai->timer_sol);
454 rai->timer_sol = rtadvd_add_timer(ra_timeout_sol, NULL, rai, NULL); 454 rai->timer_sol = rtadvd_add_timer(ra_timeout_sol, NULL, rai, NULL);
455} 455}
456 456
457static void 457static void
458rtmsg_input(void) 458rtmsg_input(void)
459{ 459{
460 int n, type, ifindex = 0, plen; 460 int n, type, ifindex = 0, plen;
461 size_t len; 461 size_t len;
462 union rt_msghdr_buf { 462 union rt_msghdr_buf {
463 struct rt_msghdr rt_msghdr; 463 struct rt_msghdr rt_msghdr;
464 char data[2048]; 464 char data[2048];
465 } buffer; 465 } buffer;
466 char *msg, *next, *lim, **argv; 466 char *msg, *next, *lim, **argv;
467 char ifname[IF_NAMESIZE]; 467 char ifname[IF_NAMESIZE];
468 struct prefix *prefix; 468 struct prefix *prefix;
469 struct rainfo *rai; 469 struct rainfo *rai;
470 struct in6_addr *addr; 470 struct in6_addr *addr;
471 char addrbuf[INET6_ADDRSTRLEN]; 471 char addrbuf[INET6_ADDRSTRLEN];
472 int prefixchange = 0, argc; 472 int prefixchange = 0, argc;
473 473
474 memset(&buffer, 0, sizeof(buffer)); 474 memset(&buffer, 0, sizeof(buffer));
475 n = prog_read(rtsock, &buffer, sizeof(buffer)); 475 n = prog_read(rtsock, &buffer, sizeof(buffer));
476 476
477 /* We read the buffer first to clear the FD */ 477 /* We read the buffer first to clear the FD */
478 if (do_die) 478 if (do_die)
479 return; 479 return;
480 480
481 msg = buffer.data; 481 msg = buffer.data;
482 if (dflag > 1) { 482 if (dflag > 1) {
483 logit(LOG_DEBUG, "%s: received a routing message " 483 logit(LOG_DEBUG, "%s: received a routing message "
484 "(type = %d, len = %d)", __func__, rtmsg_type(msg), 484 "(type = %d, len = %d)", __func__, rtmsg_type(msg),
485 rtmsg_len(msg)); 485 rtmsg_len(msg));
486 } 486 }
487 if (n > rtmsg_len(msg)) { 487 if (n > rtmsg_len(msg)) {
488 /* 488 /*
489 * This usually won't happen for messages received on  489 * This usually won't happen for messages received on
490 * a routing socket. 490 * a routing socket.
491 */ 491 */
492 if (dflag > 1) 492 if (dflag > 1)
493 logit(LOG_DEBUG, 493 logit(LOG_DEBUG,
494 "%s: received data length is larger than " 494 "%s: received data length is larger than "
495 "1st routing message len. multiple messages? " 495 "1st routing message len. multiple messages? "
496 "read %d bytes, but 1st msg len = %d", 496 "read %d bytes, but 1st msg len = %d",
497 __func__, n, rtmsg_len(msg)); 497 __func__, n, rtmsg_len(msg));
498#if 0 498#if 0
499 /* adjust length */ 499 /* adjust length */
500 n = rtmsg_len(msg); 500 n = rtmsg_len(msg);
501#endif 501#endif
502 } 502 }
503 503
504 lim = msg + n; 504 lim = msg + n;
505 for (next = msg; next < lim; next += len) { 505 for (next = msg; next < lim; next += len) {
506 int oldifflags; 506 int oldifflags;
507 507
508 next = get_next_msg(next, lim, 0, &len, 508 next = get_next_msg(next, lim, 0, &len,
509 RTADV_TYPE2BITMASK(RTM_ADD) | 509 RTADV_TYPE2BITMASK(RTM_ADD) |
510 RTADV_TYPE2BITMASK(RTM_DELETE) | 510 RTADV_TYPE2BITMASK(RTM_DELETE) |
511 RTADV_TYPE2BITMASK(RTM_NEWADDR) | 511 RTADV_TYPE2BITMASK(RTM_NEWADDR) |
512 RTADV_TYPE2BITMASK(RTM_DELADDR) | 512 RTADV_TYPE2BITMASK(RTM_DELADDR) |
513#ifdef RTM_IFANNOUNCE 513#ifdef RTM_IFANNOUNCE
514 RTADV_TYPE2BITMASK(RTM_IFANNOUNCE) | 514 RTADV_TYPE2BITMASK(RTM_IFANNOUNCE) |
515#endif 515#endif
516 RTADV_TYPE2BITMASK(RTM_IFINFO)); 516 RTADV_TYPE2BITMASK(RTM_IFINFO));
517 if (len == 0) 517 if (len == 0)
518 break; 518 break;
519 type = rtmsg_type(next); 519 type = rtmsg_type(next);
520 switch (type) { 520 switch (type) {
521 case RTM_ADD: 521 case RTM_ADD:
522 case RTM_DELETE: 522 case RTM_DELETE:
523 ifindex = get_rtm_ifindex(next); 523 ifindex = get_rtm_ifindex(next);
524 break; 524 break;
525 case RTM_NEWADDR: 525 case RTM_NEWADDR:
526 case RTM_DELADDR: 526 case RTM_DELADDR:
527 ifindex = get_ifam_ifindex(next); 527 ifindex = get_ifam_ifindex(next);
528 break; 528 break;
529#ifdef RTM_IFANNOUNCE 529#ifdef RTM_IFANNOUNCE
530 case RTM_IFANNOUNCE: 530 case RTM_IFANNOUNCE:
531 ifindex = get_ifan_ifindex(next); 531 ifindex = get_ifan_ifindex(next);
532 if (get_ifan_what(next) == IFAN_ARRIVAL) { 532 if (get_ifan_what(next) == IFAN_ARRIVAL) {
533 logit(LOG_DEBUG, 533 logit(LOG_DEBUG,
534 "%s: interface %s arrived", 534 "%s: interface %s arrived",
535 __func__, 535 __func__,
536 if_indextoname(ifindex, ifname)); 536 if_indextoname(ifindex, ifname));
537 if (if_argc == 0) { 537 if (if_argc == 0) {
538 getconfig(ifname, 0); 538 getconfig(ifname, 0);
539 continue; 539 continue;
540 } 540 }
541 argc = if_argc; 541 argc = if_argc;
542 argv = if_argv; 542 argv = if_argv;
543 while (argc--) { 543 while (argc--) {
544 if (strcmp(ifname, *argv++) == 0) { 544 if (strcmp(ifname, *argv++) == 0) {
545 getconfig(ifname, 0); 545 getconfig(ifname, 0);
546 break; 546 break;
547 } 547 }
548 } 548 }
549 continue; 549 continue;
550 } 550 }
551 break; 551 break;
552#endif 552#endif
553 case RTM_IFINFO: 553 case RTM_IFINFO:
554 ifindex = get_ifm_ifindex(next); 554 ifindex = get_ifm_ifindex(next);
555 break; 555 break;
556 default: 556 default:
557 /* should not reach here */ 557 /* should not reach here */
558 if (dflag > 1) { 558 if (dflag > 1) {
559 logit(LOG_DEBUG, "%s: unknown rtmsg %d on %s", 559 logit(LOG_DEBUG, "%s: unknown rtmsg %d on %s",
560 __func__, type, 560 __func__, type,
561 if_indextoname(ifindex, ifname)); 561 if_indextoname(ifindex, ifname));
562 } 562 }
563 continue; 563 continue;
564 } 564 }
565 565
566 if ((rai = if_indextorainfo(ifindex)) == NULL) { 566 if ((rai = if_indextorainfo(ifindex)) == NULL) {
567 if (dflag > 1) { 567 if (dflag > 1) {
568 logit(LOG_DEBUG, 568 logit(LOG_DEBUG,
569 "%s: route changed on " 569 "%s: route changed on "
570 "non advertising interface %s (%d)", 570 "non advertising interface %s (%d)",
571 __func__, 571 __func__,
572 if_indextoname(ifindex, ifname), 572 if_indextoname(ifindex, ifname),
573 ifindex); 573 ifindex);
574 } 574 }
575 continue; 575 continue;
576 } 576 }
577 oldifflags = rai->ifflags; 577 oldifflags = rai->ifflags;
578 578
579 switch (type) { 579 switch (type) {
580 case RTM_ADD: 580 case RTM_ADD:
581 /* init ifflags because it may have changed */ 581 /* init ifflags because it may have changed */
582 rai->ifflags = if_getflags(ifindex, rai->ifflags); 582 rai->ifflags = if_getflags(ifindex, rai->ifflags);
583 583
584 if (sflag) 584 if (sflag)
585 break; /* we aren't interested in prefixes */ 585 break; /* we aren't interested in prefixes */
586 586
587 addr = get_addr(msg); 587 addr = get_addr(msg);
588 plen = get_prefixlen(msg); 588 plen = get_prefixlen(msg);
589 /* sanity check for plen */ 589 /* sanity check for plen */
590 /* as RFC2373, prefixlen is at least 4 */ 590 /* as RFC2373, prefixlen is at least 4 */
591 if (plen < 4 || plen > 127) { 591 if (plen < 4 || plen > 127) {
592 logit(LOG_INFO, "%s: new interface route's" 592 logit(LOG_INFO, "%s: new interface route's"
593 "plen %d is invalid for a prefix", 593 "plen %d is invalid for a prefix",
594 __func__, plen); 594 __func__, plen);
595 break; 595 break;
596 } 596 }
597 prefix = find_prefix(rai, addr, plen); 597 prefix = find_prefix(rai, addr, plen);
598 if (prefix) { 598 if (prefix) {
599 if (prefix->timer) { 599 if (prefix->timer) {
600 /* 600 /*
601 * If the prefix has been invalidated, 601 * If the prefix has been invalidated,
602 * make it available again. 602 * make it available again.
603 */ 603 */
604 update_prefix(prefix); 604 update_prefix(prefix);
605 prefixchange = 1; 605 prefixchange = 1;
606 } else if (dflag > 1) { 606 } else if (dflag > 1) {
607 logit(LOG_DEBUG, 607 logit(LOG_DEBUG,
608 "%s: new prefix(%s/%d) " 608 "%s: new prefix(%s/%d) "
609 "added on %s, " 609 "added on %s, "
610 "but it was already in list", 610 "but it was already in list",
611 __func__, 611 __func__,
612 inet_ntop(AF_INET6, addr, 612 inet_ntop(AF_INET6, addr,
613 (char *)addrbuf, INET6_ADDRSTRLEN), 613 (char *)addrbuf, INET6_ADDRSTRLEN),
614 plen, rai->ifname); 614 plen, rai->ifname);
615 } 615 }
616 break; 616 break;
617 } 617 }
618 make_prefix(rai, ifindex, addr, plen); 618 add_prefix(rai, ifindex, addr, plen);
619 prefixchange = 1; 619 prefixchange = 1;
620 break; 620 break;
621 case RTM_DELETE: 621 case RTM_DELETE:
622 /* init ifflags because it may have changed */ 622 /* init ifflags because it may have changed */
623 rai->ifflags = if_getflags(ifindex, rai->ifflags); 623 rai->ifflags = if_getflags(ifindex, rai->ifflags);
624 624
625 if (sflag) 625 if (sflag)
626 break; 626 break;
627 627
628 addr = get_addr(msg); 628 addr = get_addr(msg);
629 plen = get_prefixlen(msg); 629 plen = get_prefixlen(msg);
630 /* sanity check for plen */ 630 /* sanity check for plen */
631 /* as RFC2373, prefixlen is at least 4 */ 631 /* as RFC2373, prefixlen is at least 4 */
632 if (plen < 4 || plen > 127) { 632 if (plen < 4 || plen > 127) {
633 logit(LOG_INFO, 633 logit(LOG_INFO,
634 "%s: deleted interface route's " 634 "%s: deleted interface route's "
635 "plen %d is invalid for a prefix", 635 "plen %d is invalid for a prefix",
636 __func__, plen); 636 __func__, plen);
637 break; 637 break;
638 } 638 }
639 prefix = find_prefix(rai, addr, plen); 639 prefix = find_prefix(rai, addr, plen);
640 if (prefix == NULL) { 640 if (prefix == NULL) {
641 if (dflag > 1) { 641 if (dflag > 1) {
642 logit(LOG_DEBUG, 642 logit(LOG_DEBUG,
643 "%s: prefix(%s/%d) was " 643 "%s: prefix(%s/%d) was "
644 "deleted on %s, " 644 "deleted on %s, "
645 "but it was not in list", 645 "but it was not in list",
646 __func__, 646 __func__,
647 inet_ntop(AF_INET6, addr, 647 inet_ntop(AF_INET6, addr,
648 (char *)addrbuf, INET6_ADDRSTRLEN), 648 (char *)addrbuf, INET6_ADDRSTRLEN),
649 plen, rai->ifname); 649 plen, rai->ifname);
650 } 650 }
651 break; 651 break;
652 } 652 }
653 invalidate_prefix(prefix); 653 invalidate_prefix(prefix);
654 prefixchange = 1; 654 prefixchange = 1;
655 break; 655 break;
656 case RTM_NEWADDR: 656 case RTM_NEWADDR:
657 case RTM_DELADDR: 657 case RTM_DELADDR:
658 /* init ifflags because it may have changed */ 658 /* init ifflags because it may have changed */
659 rai->ifflags = if_getflags(ifindex, rai->ifflags); 659 rai->ifflags = if_getflags(ifindex, rai->ifflags);
660 break; 660 break;
661 case RTM_IFINFO: 661 case RTM_IFINFO:
662 rai->ifflags = get_ifm_flags(next); 662 rai->ifflags = get_ifm_flags(next);
663 break; 663 break;
664#ifdef RTM_IFANNOUNCE 664#ifdef RTM_IFANNOUNCE
665 case RTM_IFANNOUNCE: 665 case RTM_IFANNOUNCE:
666 if (get_ifan_what(next) == IFAN_DEPARTURE) { 666 if (get_ifan_what(next) == IFAN_DEPARTURE) {
667 logit(LOG_DEBUG, 667 logit(LOG_DEBUG,
668 "%s: interface %s departed", 668 "%s: interface %s departed",
669 __func__, rai->ifname); 669 __func__, rai->ifname);
670 TAILQ_REMOVE(&ralist, rai, next); 670 TAILQ_REMOVE(&ralist, rai, next);
671 if (rai->leaving) 671 if (rai->leaving)
672 free_rainfo(rai->leaving); 672 free_rainfo(rai->leaving);
673 free_rainfo(rai); 673 free_rainfo(rai);
674 continue; 674 continue;
675 } 675 }
676 break; 676 break;
677#endif 677#endif
678 default: 678 default:
679 /* should not reach here */ 679 /* should not reach here */
680 if (dflag > 1) { 680 if (dflag > 1) {
681 logit(LOG_DEBUG, 681 logit(LOG_DEBUG,
682 "%s: unknown rtmsg %d on %s", 682 "%s: unknown rtmsg %d on %s",
683 __func__, type, 683 __func__, type,
684 if_indextoname(ifindex, ifname)); 684 if_indextoname(ifindex, ifname));
685 } 685 }
686 return; 686 return;
687 } 687 }
688 688
689 /* check if an interface flag is changed */ 689 /* check if an interface flag is changed */
690 if ((oldifflags & IFF_UP) != 0 && /* UP to DOWN */ 690 if ((oldifflags & IFF_UP) != 0 && /* UP to DOWN */
691 (rai->ifflags & IFF_UP) == 0) { 691 (rai->ifflags & IFF_UP) == 0) {
692 logit(LOG_INFO, 692 logit(LOG_INFO,
693 "%s: interface %s becomes down. stop timer.", 693 "%s: interface %s becomes down. stop timer.",
694 __func__, rai->ifname); 694 __func__, rai->ifname);
695 rtadvd_remove_timer(&rai->timer); 695 rtadvd_remove_timer(&rai->timer);
696 } else if ((oldifflags & IFF_UP) == 0 && /* DOWN to UP */ 696 } else if ((oldifflags & IFF_UP) == 0 && /* DOWN to UP */
697 (rai->ifflags & IFF_UP) != 0) { 697 (rai->ifflags & IFF_UP) != 0) {
698 logit(LOG_INFO, 698 logit(LOG_INFO,
699 "%s: interface %s becomes up. restart timer.", 699 "%s: interface %s becomes up. restart timer.",
700 __func__, rai->ifname); 700 __func__, rai->ifname);
701 701
702 rai->initcounter = 0; /* reset the counter */ 702 rai->initcounter = 0; /* reset the counter */
703 rai->waiting = 0; /* XXX */ 703 rai->waiting = 0; /* XXX */
704 ra_timer_reset(rai); 704 ra_timer_reset(rai);
705 } else if (prefixchange && rai->ifflags & IFF_UP) { 705 } else if (prefixchange && rai->ifflags & IFF_UP) {
706 /* 706 /*
707 * An advertised prefix has been added or invalidated. 707 * An advertised prefix has been added or invalidated.
708 * Will notice the change in a short delay. 708 * Will notice the change in a short delay.
709 */ 709 */
710 rai->initcounter = 0; 710 rai->initcounter = 0;
711 ra_timer_set_short_delay(rai, rai->timer); 711 ra_timer_set_short_delay(rai, rai->timer);
712 } 712 }
713 } 713 }
714 714
715 return; 715 return;
716} 716}
717 717
718void 718void
719rtadvd_input(void) 719rtadvd_input(void)
720{ 720{
721 ssize_t i; 721 ssize_t i;
722 int *hlimp = NULL; 722 int *hlimp = NULL;
723 struct icmp6_hdr *icp; 723 struct icmp6_hdr *icp;
724 int ifindex = 0; 724 int ifindex = 0;
725 struct cmsghdr *cm; 725 struct cmsghdr *cm;
726 struct in6_pktinfo *pi = NULL; 726 struct in6_pktinfo *pi = NULL;
727 char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ]; 727 char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ];
728 struct in6_addr dst = in6addr_any; 728 struct in6_addr dst = in6addr_any;
729 struct rainfo *rai; 729 struct rainfo *rai;
730 730
731 /* 731 /*
732 * Get message. We reset msg_controllen since the field could 732 * Get message. We reset msg_controllen since the field could
733 * be modified if we had received a message before setting 733 * be modified if we had received a message before setting
734 * receive options. 734 * receive options.
735 */ 735 */
736 rcvmhdr.msg_controllen = rcvcmsgbuflen; 736 rcvmhdr.msg_controllen = rcvcmsgbuflen;
737 if ((i = prog_recvmsg(sock, &rcvmhdr, 0)) == -1) 737 if ((i = prog_recvmsg(sock, &rcvmhdr, 0)) == -1)
738 return; 738 return;
739 739
740 /* We read the buffer first to clear the FD */ 740 /* We read the buffer first to clear the FD */
741 if (do_die) 741 if (do_die)
742 return; 742 return;
743 743
744 /* extract optional information via Advanced API */ 744 /* extract optional information via Advanced API */
745 for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&rcvmhdr); 745 for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&rcvmhdr);
746 cm; 746 cm;
747 cm = (struct cmsghdr *)CMSG_NXTHDR(&rcvmhdr, cm)) { 747 cm = (struct cmsghdr *)CMSG_NXTHDR(&rcvmhdr, cm)) {
748 if (cm->cmsg_level == IPPROTO_IPV6 && 748 if (cm->cmsg_level == IPPROTO_IPV6 &&
749 cm->cmsg_type == IPV6_PKTINFO && 749 cm->cmsg_type == IPV6_PKTINFO &&
750 cm->cmsg_len == CMSG_LEN(sizeof(struct in6_pktinfo))) { 750 cm->cmsg_len == CMSG_LEN(sizeof(struct in6_pktinfo))) {
751 pi = (struct in6_pktinfo *)(CMSG_DATA(cm)); 751 pi = (struct in6_pktinfo *)(CMSG_DATA(cm));
752 ifindex = pi->ipi6_ifindex; 752 ifindex = pi->ipi6_ifindex;
753 dst = pi->ipi6_addr; 753 dst = pi->ipi6_addr;
754 } 754 }
755 if (cm->cmsg_level == IPPROTO_IPV6 && 755 if (cm->cmsg_level == IPPROTO_IPV6 &&
756 cm->cmsg_type == IPV6_HOPLIMIT && 756 cm->cmsg_type == IPV6_HOPLIMIT &&
757 cm->cmsg_len == CMSG_LEN(sizeof(int))) 757 cm->cmsg_len == CMSG_LEN(sizeof(int)))
758 hlimp = (int *)CMSG_DATA(cm); 758 hlimp = (int *)CMSG_DATA(cm);
759 } 759 }
760 if (ifindex == 0) { 760 if (ifindex == 0) {
761 logit(LOG_ERR, 761 logit(LOG_ERR,
762 "%s: failed to get receiving interface", 762 "%s: failed to get receiving interface",
763 __func__); 763 __func__);
764 return; 764 return;
765 } 765 }
766 if (hlimp == NULL) { 766 if (hlimp == NULL) {
767 logit(LOG_ERR, 767 logit(LOG_ERR,
768 "%s: failed to get receiving hop limit", 768 "%s: failed to get receiving hop limit",
769 __func__); 769 __func__);
770 return; 770 return;
771 } 771 }
772 772
773 if ((rai = if_indextorainfo(pi->ipi6_ifindex)) == NULL) { 773 if ((rai = if_indextorainfo(pi->ipi6_ifindex)) == NULL) {
774 if (dflag > 1) { 774 if (dflag > 1) {
775 logit(LOG_DEBUG, 775 logit(LOG_DEBUG,
776 "%s: received data for non advertising " 776 "%s: received data for non advertising "
777 "interface (%s)", 777 "interface (%s)",
778 __func__, 778 __func__,
779 if_indextoname(pi->ipi6_ifindex, ifnamebuf)); 779 if_indextoname(pi->ipi6_ifindex, ifnamebuf));
780 } 780 }
781 return; 781 return;
782 } 782 }
783 /* 783 /*
784 * If we happen to receive data on an interface which is now down, 784 * If we happen to receive data on an interface which is now down,
785 * just discard the data. 785 * just discard the data.
786 */ 786 */
787 if ((rai->ifflags & IFF_UP) == 0) { 787 if ((rai->ifflags & IFF_UP) == 0) {
788 logit(LOG_INFO, 788 logit(LOG_INFO,
789 "%s: received data on a disabled interface (%s)", 789 "%s: received data on a disabled interface (%s)",
790 __func__, 790 __func__,
791 if_indextoname(pi->ipi6_ifindex, ifnamebuf)); 791 if_indextoname(pi->ipi6_ifindex, ifnamebuf));
792 return; 792 return;
793 } 793 }
794 794
795 if ((size_t)i < sizeof(struct icmp6_hdr)) { 795 if ((size_t)i < sizeof(struct icmp6_hdr)) {
796 logit(LOG_ERR, 796 logit(LOG_ERR,
797 "%s: packet size(%zd) is too short", 797 "%s: packet size(%zd) is too short",
798 __func__, i); 798 __func__, i);
799 return; 799 return;
800 } 800 }
801 801
802 icp = (struct icmp6_hdr *)rcvmhdr.msg_iov[0].iov_base; 802 icp = (struct icmp6_hdr *)rcvmhdr.msg_iov[0].iov_base;
803 803
804 switch (icp->icmp6_type) { 804 switch (icp->icmp6_type) {
805 case ND_ROUTER_SOLICIT: 805 case ND_ROUTER_SOLICIT:
806 /* 806 /*
807 * Message verification - RFC-2461 6.1.1 807 * Message verification - RFC-2461 6.1.1
808 * XXX: these checks must be done in the kernel as well, 808 * XXX: these checks must be done in the kernel as well,
809 * but we can't completely rely on them. 809 * but we can't completely rely on them.
810 */ 810 */
811 if (*hlimp != 255) { 811 if (*hlimp != 255) {
812 logit(LOG_NOTICE, 812 logit(LOG_NOTICE,
813 "%s: RS with invalid hop limit(%d) " 813 "%s: RS with invalid hop limit(%d) "
814 "received from %s on %s", 814 "received from %s on %s",
815 __func__, *hlimp, 815 __func__, *hlimp,
816 inet_ntop(AF_INET6, &rcvfrom.sin6_addr, ntopbuf, 816 inet_ntop(AF_INET6, &rcvfrom.sin6_addr, ntopbuf,
817 INET6_ADDRSTRLEN), 817 INET6_ADDRSTRLEN),
818 if_indextoname(pi->ipi6_ifindex, ifnamebuf)); 818 if_indextoname(pi->ipi6_ifindex, ifnamebuf));
819 return; 819 return;
820 } 820 }
821 if (icp->icmp6_code) { 821 if (icp->icmp6_code) {
822 logit(LOG_NOTICE, 822 logit(LOG_NOTICE,
823 "%s: RS with invalid ICMP6 code(%d) " 823 "%s: RS with invalid ICMP6 code(%d) "
824 "received from %s on %s", 824 "received from %s on %s",
825 __func__, icp->icmp6_code, 825 __func__, icp->icmp6_code,
826 inet_ntop(AF_INET6, &rcvfrom.sin6_addr, ntopbuf, 826 inet_ntop(AF_INET6, &rcvfrom.sin6_addr, ntopbuf,
827 INET6_ADDRSTRLEN), 827 INET6_ADDRSTRLEN),
828 if_indextoname(pi->ipi6_ifindex, ifnamebuf)); 828 if_indextoname(pi->ipi6_ifindex, ifnamebuf));
829 return; 829 return;
830 } 830 }
831 if ((size_t)i < sizeof(struct nd_router_solicit)) { 831 if ((size_t)i < sizeof(struct nd_router_solicit)) {
832 logit(LOG_NOTICE, 832 logit(LOG_NOTICE,
833 "%s: RS from %s on %s does not have enough " 833 "%s: RS from %s on %s does not have enough "
834 "length (len = %zd)", 834 "length (len = %zd)",
835 __func__, 835 __func__,
836 inet_ntop(AF_INET6, &rcvfrom.sin6_addr, ntopbuf, 836 inet_ntop(AF_INET6, &rcvfrom.sin6_addr, ntopbuf,
837 INET6_ADDRSTRLEN), 837 INET6_ADDRSTRLEN),
838 if_indextoname(pi->ipi6_ifindex, ifnamebuf), i); 838 if_indextoname(pi->ipi6_ifindex, ifnamebuf), i);
839 return; 839 return;
840 } 840 }
841 rs_input(i, (struct nd_router_solicit *)icp, pi, &rcvfrom); 841 rs_input(i, (struct nd_router_solicit *)icp, pi, &rcvfrom);
842 break; 842 break;
843 case ND_ROUTER_ADVERT: 843 case ND_ROUTER_ADVERT:
844 /* 844 /*
845 * Message verification - RFC-2461 6.1.2 845 * Message verification - RFC-2461 6.1.2
846 * XXX: there's a same dilemma as above...  846 * XXX: there's a same dilemma as above...
847 */ 847 */
848 if (*hlimp != 255) { 848 if (*hlimp != 255) {
849 logit(LOG_NOTICE, 849 logit(LOG_NOTICE,
850 "%s: RA with invalid hop limit(%d) " 850 "%s: RA with invalid hop limit(%d) "
851 "received from %s on %s", 851 "received from %s on %s",
852 __func__, *hlimp, 852 __func__, *hlimp,
853 inet_ntop(AF_INET6, &rcvfrom.sin6_addr, ntopbuf, 853 inet_ntop(AF_INET6, &rcvfrom.sin6_addr, ntopbuf,
854 INET6_ADDRSTRLEN), 854 INET6_ADDRSTRLEN),
855 if_indextoname(pi->ipi6_ifindex, ifnamebuf)); 855 if_indextoname(pi->ipi6_ifindex, ifnamebuf));
856 return; 856 return;
857 } 857 }
858 if (icp->icmp6_code) { 858 if (icp->icmp6_code) {
859 logit(LOG_NOTICE, 859 logit(LOG_NOTICE,
860 "%s: RA with invalid ICMP6 code(%d) " 860 "%s: RA with invalid ICMP6 code(%d) "
861 "received from %s on %s", 861 "received from %s on %s",
862 __func__, icp->icmp6_code, 862 __func__, icp->icmp6_code,
863 inet_ntop(AF_INET6, &rcvfrom.sin6_addr, ntopbuf, 863 inet_ntop(AF_INET6, &rcvfrom.sin6_addr, ntopbuf,
864 INET6_ADDRSTRLEN), 864 INET6_ADDRSTRLEN),
865 if_indextoname(pi->ipi6_ifindex, ifnamebuf)); 865 if_indextoname(pi->ipi6_ifindex, ifnamebuf));
866 return; 866 return;
867 } 867 }
868 if ((size_t)i < sizeof(struct nd_router_advert)) { 868 if ((size_t)i < sizeof(struct nd_router_advert)) {
869 logit(LOG_NOTICE, 869 logit(LOG_NOTICE,
870 "%s: RA from %s on %s does not have enough " 870 "%s: RA from %s on %s does not have enough "
871 "length (len = %zd)", 871 "length (len = %zd)",
872 __func__, 872 __func__,
873 inet_ntop(AF_INET6, &rcvfrom.sin6_addr, ntopbuf, 873 inet_ntop(AF_INET6, &rcvfrom.sin6_addr, ntopbuf,
874 INET6_ADDRSTRLEN), 874 INET6_ADDRSTRLEN),
875 if_indextoname(pi->ipi6_ifindex, ifnamebuf), i); 875 if_indextoname(pi->ipi6_ifindex, ifnamebuf), i);
876 return; 876 return;
877 } 877 }
878 ra_input(i, (struct nd_router_advert *)icp, pi, &rcvfrom); 878 ra_input(i, (struct nd_router_advert *)icp, pi, &rcvfrom);
879 break; 879 break;
880 default: 880 default:
881 /* 881 /*
882 * Note that this case is POSSIBLE, especially just 882 * Note that this case is POSSIBLE, especially just
883 * after invocation of the daemon. This is because we 883 * after invocation of the daemon. This is because we
884 * could receive message after opening the socket and 884 * could receive message after opening the socket and
885 * before setting ICMP6 type filter(see sock_open()). 885 * before setting ICMP6 type filter(see sock_open()).
886 */ 886 */
887 logit(LOG_ERR, "%s: invalid icmp type(%d)", 887 logit(LOG_ERR, "%s: invalid icmp type(%d)",
888 __func__, icp->icmp6_type); 888 __func__, icp->icmp6_type);
889 return; 889 return;
890 } 890 }
891} 891}
892 892
893static void 893static void
894rs_input(int len, struct nd_router_solicit *rs, 894rs_input(int len, struct nd_router_solicit *rs,
895 struct in6_pktinfo *pi, struct sockaddr_in6 *from) 895 struct in6_pktinfo *pi, struct sockaddr_in6 *from)
896{ 896{
897 char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ]; 897 char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ];
898 union nd_opts ndopts; 898 union nd_opts ndopts;
899 struct rainfo *rai; 899 struct rainfo *rai;
900 struct soliciter *sol; 900 struct soliciter *sol;
901 901
902 logit(LOG_DEBUG, 902 logit(LOG_DEBUG,
903 "%s: RS received from %s on %s", 903 "%s: RS received from %s on %s",
904 __func__, 904 __func__,
905 inet_ntop(AF_INET6, &from->sin6_addr, 905 inet_ntop(AF_INET6, &from->sin6_addr,
906 ntopbuf, INET6_ADDRSTRLEN), 906 ntopbuf, INET6_ADDRSTRLEN),
907 if_indextoname(pi->ipi6_ifindex, ifnamebuf)); 907 if_indextoname(pi->ipi6_ifindex, ifnamebuf));
908 908
909 /* ND option check */ 909 /* ND option check */
910 memset(&ndopts, 0, sizeof(ndopts)); 910 memset(&ndopts, 0, sizeof(ndopts));
911 TAILQ_INIT(&ndopts.nd_opts_list); 911 TAILQ_INIT(&ndopts.nd_opts_list);
912 if (nd6_options((struct nd_opt_hdr *)(rs + 1), 912 if (nd6_options((struct nd_opt_hdr *)(rs + 1),
913 len - sizeof(struct nd_router_solicit), 913 len - sizeof(struct nd_router_solicit),
914 &ndopts, NDOPT_FLAG_SRCLINKADDR)) { 914 &ndopts, NDOPT_FLAG_SRCLINKADDR)) {
915 logit(LOG_INFO, 915 logit(LOG_INFO,
916 "%s: ND option check failed for an RS from %s on %s", 916 "%s: ND option check failed for an RS from %s on %s",
917 __func__, 917 __func__,
918 inet_ntop(AF_INET6, &from->sin6_addr, 918 inet_ntop(AF_INET6, &from->sin6_addr,
919 ntopbuf, INET6_ADDRSTRLEN), 919 ntopbuf, INET6_ADDRSTRLEN),
920 if_indextoname(pi->ipi6_ifindex, ifnamebuf)); 920 if_indextoname(pi->ipi6_ifindex, ifnamebuf));
921 return; 921 return;
922 } 922 }
923 923
924 /* 924 /*
925 * If the IP source address is the unspecified address, there 925 * If the IP source address is the unspecified address, there
926 * must be no source link-layer address option in the message. 926 * must be no source link-layer address option in the message.
927 * (RFC-2461 6.1.1) 927 * (RFC-2461 6.1.1)
928 */ 928 */
929 if (IN6_IS_ADDR_UNSPECIFIED(&from->sin6_addr) && 929 if (IN6_IS_ADDR_UNSPECIFIED(&from->sin6_addr) &&
930 ndopts.nd_opts_src_lladdr) { 930 ndopts.nd_opts_src_lladdr) {
931 logit(LOG_INFO, 931 logit(LOG_INFO,
932 "%s: RS from unspecified src on %s has a link-layer" 932 "%s: RS from unspecified src on %s has a link-layer"
933 " address option", 933 " address option",
934 __func__, 934 __func__,
935 if_indextoname(pi->ipi6_ifindex, ifnamebuf)); 935 if_indextoname(pi->ipi6_ifindex, ifnamebuf));
936 goto done; 936 goto done;
937 } 937 }
938 938
939 if ((rai = if_indextorainfo(pi->ipi6_ifindex)) == NULL) { 939 if ((rai = if_indextorainfo(pi->ipi6_ifindex)) == NULL) {
940 logit(LOG_INFO, 940 logit(LOG_INFO,
941 "%s: RS received on non advertising interface(%s)", 941 "%s: RS received on non advertising interface(%s)",
942 __func__, 942 __func__,
943 if_indextoname(pi->ipi6_ifindex, ifnamebuf)); 943 if_indextoname(pi->ipi6_ifindex, ifnamebuf));
944 goto done; 944 goto done;
945 } 945 }
946 946
947 if (rai->leaving) { 947 if (rai->leaving) {
948 logit(LOG_INFO, 948 logit(LOG_INFO,
949 "%s: RS received on reconfiguring advertising interface(%s)", 949 "%s: RS received on reconfiguring advertising interface(%s)",
950 __func__, rai->ifname); 950 __func__, rai->ifname);
951 goto done; 951 goto done;
952 } 952 }
953 953
954 rai->rsinput++; /* increment statistics */ 954 rai->rsinput++; /* increment statistics */
955 955
956 /* 956 /*
957 * Decide whether to send RA according to the rate-limit 957 * Decide whether to send RA according to the rate-limit
958 * consideration. 958 * consideration.
959 */ 959 */
960 960
961 /* record sockaddr waiting for RA, if possible */ 961 /* record sockaddr waiting for RA, if possible */
962 TAILQ_FOREACH(sol, &rai->soliciter, next) { 962 TAILQ_FOREACH(sol, &rai->soliciter, next) {
963 if (IN6_ARE_ADDR_EQUAL(&sol->addr.sin6_addr, &from->sin6_addr)) 963 if (IN6_ARE_ADDR_EQUAL(&sol->addr.sin6_addr, &from->sin6_addr))
964 break; 964 break;
965 } 965 }
966 if (sol == NULL) { 966 if (sol == NULL) {
967 sol = malloc(sizeof(*sol)); 967 sol = malloc(sizeof(*sol));
968 if (sol == NULL) { 968 if (sol == NULL) {
969 logit(LOG_ERR, "%s: malloc: %m", __func__); 969 logit(LOG_ERR, "%s: malloc: %m", __func__);
970 } else { 970 } else {
971 sol->addr = *from; 971 sol->addr = *from;
972 /* XXX RFC2553 need clarification on flowinfo */ 972 /* XXX RFC2553 need clarification on flowinfo */
973 sol->addr.sin6_flowinfo = 0; 973 sol->addr.sin6_flowinfo = 0;
974 TAILQ_INSERT_TAIL(&rai->soliciter, sol, next); 974 TAILQ_INSERT_TAIL(&rai->soliciter, sol, next);
975 } 975 }
976 } 976 }
977 977
978 /* 978 /*
979 * If there is already a waiting RS packet, don't 979 * If there is already a waiting RS packet, don't
980 * update the timer. 980 * update the timer.
981 */ 981 */
982 if (rai->waiting++) 982 if (rai->waiting++)
983 goto done; 983 goto done;
984 984
985 ra_timer_set_short_delay(rai, rai->timer_sol); 985 ra_timer_set_short_delay(rai, rai->timer_sol);
986 986
987done: 987done:
988 free_ndopts(&ndopts); 988 free_ndopts(&ndopts);
989} 989}
990 990
991void 991void
992ra_timer_set_short_delay(struct rainfo *rai, struct rtadvd_timer *timer) 992ra_timer_set_short_delay(struct rainfo *rai, struct rtadvd_timer *timer)
993{ 993{
994 long delay; /* must not be greater than 1000000 */ 994 long delay; /* must not be greater than 1000000 */
995 struct timespec interval, now, min_delay, tm_tmp, *rest; 995 struct timespec interval, now, min_delay, tm_tmp, *rest;
996 996
997 /* 997 /*
998 * Compute a random delay. If the computed value 998 * Compute a random delay. If the computed value
999 * corresponds to a time later than the time the next 999 * corresponds to a time later than the time the next
1000 * multicast RA is scheduled to be sent, ignore the random 1000 * multicast RA is scheduled to be sent, ignore the random
1001 * delay and send the advertisement at the 1001 * delay and send the advertisement at the
1002 * already-scheduled time. RFC2461 6.2.6 1002 * already-scheduled time. RFC2461 6.2.6
1003 */ 1003 */
1004 delay = arc4random() % MAX_RA_DELAY_TIME; 1004 delay = arc4random() % MAX_RA_DELAY_TIME;
1005 interval.tv_sec = 0; 1005 interval.tv_sec = 0;
1006 interval.tv_nsec = delay; 1006 interval.tv_nsec = delay;
1007 rest = rtadvd_timer_rest(rai->timer); 1007 rest = rtadvd_timer_rest(rai->timer);
1008 if (timespeccmp(rest, &interval, <)) { 1008 if (timespeccmp(rest, &interval, <)) {
1009 logit(LOG_DEBUG, "%s: random delay is larger than " 1009 logit(LOG_DEBUG, "%s: random delay is larger than "
1010 "the rest of current timer", __func__); 1010 "the rest of current timer", __func__);
1011 interval = *rest; 1011 interval = *rest;
1012 } 1012 }
1013 1013
1014 /* 1014 /*
1015 * If we sent a multicast Router Advertisement within 1015 * If we sent a multicast Router Advertisement within
1016 * the last MIN_DELAY_BETWEEN_RAS seconds, schedule 1016 * the last MIN_DELAY_BETWEEN_RAS seconds, schedule
1017 * the advertisement to be sent at a time corresponding to 1017 * the advertisement to be sent at a time corresponding to
1018 * MIN_DELAY_BETWEEN_RAS plus the random value after the 1018 * MIN_DELAY_BETWEEN_RAS plus the random value after the
1019 * previous advertisement was sent. 1019 * previous advertisement was sent.
1020 */ 1020 */
1021 prog_clock_gettime(CLOCK_MONOTONIC, &now); 1021 prog_clock_gettime(CLOCK_MONOTONIC, &now);
1022 timespecsub(&now, &rai->lastsent, &tm_tmp); 1022 timespecsub(&now, &rai->lastsent, &tm_tmp);
1023 min_delay.tv_sec = MIN_DELAY_BETWEEN_RAS; 1023 min_delay.tv_sec = MIN_DELAY_BETWEEN_RAS;
1024 min_delay.tv_nsec = 0; 1024 min_delay.tv_nsec = 0;
1025 if (timespeccmp(&tm_tmp, &min_delay, <)) { 1025 if (timespeccmp(&tm_tmp, &min_delay, <)) {
1026 timespecsub(&min_delay, &tm_tmp, &min_delay); 1026 timespecsub(&min_delay, &tm_tmp, &min_delay);
1027 timespecadd(&min_delay, &interval, &interval); 1027 timespecadd(&min_delay, &interval, &interval);
1028 } 1028 }
1029 rtadvd_set_timer(&interval, timer); 1029 rtadvd_set_timer(&interval, timer);
1030} 1030}
1031 1031
1032static void 1032static void
1033ra_input(int len, struct nd_router_advert *ra, 1033ra_input(int len, struct nd_router_advert *ra,
1034 struct in6_pktinfo *pi, struct sockaddr_in6 *from) 1034 struct in6_pktinfo *pi, struct sockaddr_in6 *from)
1035{ 1035{
1036 struct rainfo *rai; 1036 struct rainfo *rai;
1037 char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ]; 1037 char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ];
1038 union nd_opts ndopts; 1038 union nd_opts ndopts;
1039 const char *on_off[] = {"OFF", "ON"}; 1039 const char *on_off[] = {"OFF", "ON"};
1040 uint32_t reachabletime, retranstimer, mtu; 1040 uint32_t reachabletime, retranstimer, mtu;
1041 struct nd_optlist *optp; 1041 struct nd_optlist *optp;
1042 int inconsistent = 0; 1042 int inconsistent = 0;
1043 1043
1044 logit(LOG_DEBUG, 1044 logit(LOG_DEBUG,
1045 "%s: RA received from %s on %s", 1045 "%s: RA received from %s on %s",
1046 __func__, 1046 __func__,
1047 inet_ntop(AF_INET6, &from->sin6_addr, 1047 inet_ntop(AF_INET6, &from->sin6_addr,
1048 ntopbuf, INET6_ADDRSTRLEN), 1048 ntopbuf, INET6_ADDRSTRLEN),
1049 if_indextoname(pi->ipi6_ifindex, ifnamebuf)); 1049 if_indextoname(pi->ipi6_ifindex, ifnamebuf));
1050 1050
1051 /* ND option check */ 1051 /* ND option check */
1052 memset(&ndopts, 0, sizeof(ndopts)); 1052 memset(&ndopts, 0, sizeof(ndopts));
1053 TAILQ_INIT(&ndopts.nd_opts_list); 1053 TAILQ_INIT(&ndopts.nd_opts_list);
1054 if (nd6_options((struct nd_opt_hdr *)(ra + 1), 1054 if (nd6_options((struct nd_opt_hdr *)(ra + 1),
1055 len - sizeof(struct nd_router_advert), 1055 len - sizeof(struct nd_router_advert),
1056 &ndopts, NDOPT_FLAG_SRCLINKADDR | 1056 &ndopts, NDOPT_FLAG_SRCLINKADDR |
1057 NDOPT_FLAG_PREFIXINFO | NDOPT_FLAG_MTU | 1057 NDOPT_FLAG_PREFIXINFO | NDOPT_FLAG_MTU |
1058 NDOPT_FLAG_RDNSS | NDOPT_FLAG_DNSSL)) 1058 NDOPT_FLAG_RDNSS | NDOPT_FLAG_DNSSL))
1059 { 1059 {
1060 logit(LOG_INFO, 1060 logit(LOG_INFO,
1061 "%s: ND option check failed for an RA from %s on %s", 1061 "%s: ND option check failed for an RA from %s on %s",
1062 __func__, 1062 __func__,
1063 inet_ntop(AF_INET6, &from->sin6_addr, 1063 inet_ntop(AF_INET6, &from->sin6_addr,
1064 ntopbuf, INET6_ADDRSTRLEN), 1064 ntopbuf, INET6_ADDRSTRLEN),
1065 if_indextoname(pi->ipi6_ifindex, ifnamebuf)); 1065 if_indextoname(pi->ipi6_ifindex, ifnamebuf));
1066 return; 1066 return;
1067 } 1067 }
1068 1068
1069 /* 1069 /*
1070 * RA consistency check according to RFC-2461 6.2.7 1070 * RA consistency check according to RFC-2461 6.2.7
1071 */ 1071 */
1072 if ((rai = if_indextorainfo(pi->ipi6_ifindex)) == 0) { 1072 if ((rai = if_indextorainfo(pi->ipi6_ifindex)) == 0) {
1073 logit(LOG_INFO, 1073 logit(LOG_INFO,
1074 "%s: received RA from %s on non-advertising" 1074 "%s: received RA from %s on non-advertising"
1075 " interface(%s)", 1075 " interface(%s)",
1076 __func__, 1076 __func__,
1077 inet_ntop(AF_INET6, &from->sin6_addr, 1077 inet_ntop(AF_INET6, &from->sin6_addr,
1078 ntopbuf, INET6_ADDRSTRLEN), 1078 ntopbuf, INET6_ADDRSTRLEN),
1079 if_indextoname(pi->ipi6_ifindex, ifnamebuf)); 1079 if_indextoname(pi->ipi6_ifindex, ifnamebuf));
1080 goto done; 1080 goto done;
1081 } 1081 }
1082 if (rai->leaving) { 1082 if (rai->leaving) {
1083 logit(LOG_DEBUG, 1083 logit(LOG_DEBUG,
1084 "%s: received RA on re-configuring interface (%s)", 1084 "%s: received RA on re-configuring interface (%s)",
1085 __func__, rai->ifname); 1085 __func__, rai->ifname);
1086 goto done; 1086 goto done;
1087 } 1087 }
1088 rai->rainput++; /* increment statistics */ 1088 rai->rainput++; /* increment statistics */
1089 1089
1090 /* Cur Hop Limit value */ 1090 /* Cur Hop Limit value */
1091 if (ra->nd_ra_curhoplimit && rai->hoplimit && 1091 if (ra->nd_ra_curhoplimit && rai->hoplimit &&
1092 ra->nd_ra_curhoplimit != rai->hoplimit) { 1092 ra->nd_ra_curhoplimit != rai->hoplimit) {
1093 logit(LOG_INFO, 1093 logit(LOG_INFO,
1094 "%s: CurHopLimit inconsistent on %s:" 1094 "%s: CurHopLimit inconsistent on %s:"
1095 " %d from %s, %d from us", 1095 " %d from %s, %d from us",
1096 __func__, 1096 __func__,
1097 rai->ifname, 1097 rai->ifname,
1098 ra->nd_ra_curhoplimit, 1098 ra->nd_ra_curhoplimit,
1099 inet_ntop(AF_INET6, &from->sin6_addr, 1099 inet_ntop(AF_INET6, &from->sin6_addr,
1100 ntopbuf, INET6_ADDRSTRLEN), 1100 ntopbuf, INET6_ADDRSTRLEN),
1101 rai->hoplimit); 1101 rai->hoplimit);
1102 inconsistent++; 1102 inconsistent++;
1103 } 1103 }
1104 /* M flag */ 1104 /* M flag */
1105 if ((ra->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED) != 1105 if ((ra->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED) !=
1106 rai->managedflg) { 1106 rai->managedflg) {
1107 logit(LOG_INFO, 1107 logit(LOG_INFO,
1108 "%s: M flag inconsistent on %s:" 1108 "%s: M flag inconsistent on %s:"
1109 " %s from %s, %s from us", 1109 " %s from %s, %s from us",
1110 __func__, 1110 __func__,
1111 rai->ifname, 1111 rai->ifname,
1112 on_off[!rai->managedflg], 1112 on_off[!rai->managedflg],
1113 inet_ntop(AF_INET6, &from->sin6_addr, 1113 inet_ntop(AF_INET6, &from->sin6_addr,
1114 ntopbuf, INET6_ADDRSTRLEN), 1114 ntopbuf, INET6_ADDRSTRLEN),
1115 on_off[rai->managedflg]); 1115 on_off[rai->managedflg]);
1116 inconsistent++; 1116 inconsistent++;
1117 } 1117 }
1118 /* O flag */ 1118 /* O flag */
1119 if ((ra->nd_ra_flags_reserved & ND_RA_FLAG_OTHER) != 1119 if ((ra->nd_ra_flags_reserved & ND_RA_FLAG_OTHER) !=
1120 rai->otherflg) { 1120 rai->otherflg) {
1121 logit(LOG_INFO, 1121 logit(LOG_INFO,
1122 "%s: O flag inconsistent on %s:" 1122 "%s: O flag inconsistent on %s:"
1123 " %s from %s, %s from us", 1123 " %s from %s, %s from us",
1124 __func__, 1124 __func__,
1125 rai->ifname, 1125 rai->ifname,
1126 on_off[!rai->otherflg], 1126 on_off[!rai->otherflg],
1127 inet_ntop(AF_INET6, &from->sin6_addr, 1127 inet_ntop(AF_INET6, &from->sin6_addr,
1128 ntopbuf, INET6_ADDRSTRLEN), 1128 ntopbuf, INET6_ADDRSTRLEN),
1129 on_off[rai->otherflg]); 1129 on_off[rai->otherflg]);
1130 inconsistent++; 1130 inconsistent++;
1131 } 1131 }
1132 /* Reachable Time */ 1132 /* Reachable Time */
1133 reachabletime = ntohl(ra->nd_ra_reachable); 1133 reachabletime = ntohl(ra->nd_ra_reachable);
1134 if (reachabletime && rai->reachabletime && 1134 if (reachabletime && rai->reachabletime &&
1135 reachabletime != rai->reachabletime) { 1135 reachabletime != rai->reachabletime) {
1136 logit(LOG_INFO, 1136 logit(LOG_INFO,
1137 "%s: ReachableTime inconsistent on %s:" 1137 "%s: ReachableTime inconsistent on %s:"
1138 " %d from %s, %d from us", 1138 " %d from %s, %d from us",
1139 __func__, 1139 __func__,
1140 rai->ifname, 1140 rai->ifname,
1141 reachabletime, 1141 reachabletime,
1142 inet_ntop(AF_INET6, &from->sin6_addr, 1142 inet_ntop(AF_INET6, &from->sin6_addr,
1143 ntopbuf, INET6_ADDRSTRLEN), 1143 ntopbuf, INET6_ADDRSTRLEN),
1144 rai->reachabletime); 1144 rai->reachabletime);
1145 inconsistent++; 1145 inconsistent++;
1146 } 1146 }
1147 /* Retrans Timer */ 1147 /* Retrans Timer */
1148 retranstimer = ntohl(ra->nd_ra_retransmit); 1148 retranstimer = ntohl(ra->nd_ra_retransmit);
1149 if (retranstimer && rai->retranstimer && 1149 if (retranstimer && rai->retranstimer &&
1150 retranstimer != rai->retranstimer) { 1150 retranstimer != rai->retranstimer) {
1151 logit(LOG_INFO, 1151 logit(LOG_INFO,
1152 "%s: RetranceTimer inconsistent on %s:" 1152 "%s: RetranceTimer inconsistent on %s:"
1153 " %d from %s, %d from us", 1153 " %d from %s, %d from us",
1154 __func__, 1154 __func__,
1155 rai->ifname, 1155 rai->ifname,
1156 retranstimer, 1156 retranstimer,
1157 inet_ntop(AF_INET6, &from->sin6_addr, 1157 inet_ntop(AF_INET6, &from->sin6_addr,
1158 ntopbuf, INET6_ADDRSTRLEN), 1158 ntopbuf, INET6_ADDRSTRLEN),
1159 rai->retranstimer); 1159 rai->retranstimer);
1160 inconsistent++; 1160 inconsistent++;
1161 } 1161 }
1162 /* Values in the MTU options */ 1162 /* Values in the MTU options */
1163 if (ndopts.nd_opts_mtu) { 1163 if (ndopts.nd_opts_mtu) {
1164 mtu = ntohl(ndopts.nd_opts_mtu->nd_opt_mtu_mtu); 1164 mtu = ntohl(ndopts.nd_opts_mtu->nd_opt_mtu_mtu);
1165 if (mtu && rai->linkmtu && mtu != rai->linkmtu) { 1165 if (mtu && rai->linkmtu && mtu != rai->linkmtu) {
1166 logit(LOG_INFO, 1166 logit(LOG_INFO,
1167 "%s: MTU option value inconsistent on %s:" 1167 "%s: MTU option value inconsistent on %s:"
1168 " %d from %s, %d from us", 1168 " %d from %s, %d from us",
1169 __func__, 1169 __func__,
1170 rai->ifname, mtu, 1170 rai->ifname, mtu,
1171 inet_ntop(AF_INET6, &from->sin6_addr, 1171 inet_ntop(AF_INET6, &from->sin6_addr,
1172 ntopbuf, INET6_ADDRSTRLEN), 1172 ntopbuf, INET6_ADDRSTRLEN),
1173 rai->linkmtu); 1173 rai->linkmtu);
1174 inconsistent++; 1174 inconsistent++;
1175 } 1175 }
1176 } 1176 }
1177 /* Preferred and Valid Lifetimes for prefixes */ 1177 /* Preferred and Valid Lifetimes for prefixes */
1178 if (ndopts.nd_opts_pi) 1178 if (ndopts.nd_opts_pi)
1179 if (prefix_check(ndopts.nd_opts_pi, rai, from)) 1179 if (prefix_check(ndopts.nd_opts_pi, rai, from))
1180 inconsistent++; 1180 inconsistent++;
1181 TAILQ_FOREACH(optp, &ndopts.nd_opts_list, next) 1181 TAILQ_FOREACH(optp, &ndopts.nd_opts_list, next)
1182 if (prefix_check((struct nd_opt_prefix_info *)optp->opt, 1182 if (prefix_check((struct nd_opt_prefix_info *)optp->opt,
1183 rai, from)) 1183 rai, from))
1184 inconsistent++; 1184 inconsistent++;
1185 1185
1186 if (inconsistent) 1186 if (inconsistent)
1187 rai->rainconsistent++; 1187 rai->rainconsistent++;
1188 1188
1189done: 1189done:
1190 free_ndopts(&ndopts); 1190 free_ndopts(&ndopts);
1191} 1191}
1192 1192
1193/* return a non-zero value if the received prefix is inconsitent with ours */ 1193/* return a non-zero value if the received prefix is inconsitent with ours */
1194static int 1194static int
1195prefix_check(struct nd_opt_prefix_info *pinfo, 1195prefix_check(struct nd_opt_prefix_info *pinfo,
1196 struct rainfo *rai, struct sockaddr_in6 *from) 1196 struct rainfo *rai, struct sockaddr_in6 *from)
1197{ 1197{
1198 uint32_t preferred_time, valid_time; 1198 uint32_t preferred_time, valid_time;
1199 struct prefix *pp; 1199 struct prefix *pp;
1200 int inconsistent = 0; 1200 int inconsistent = 0;
1201 char ntopbuf[INET6_ADDRSTRLEN], prefixbuf[INET6_ADDRSTRLEN]; 1201 char ntopbuf[INET6_ADDRSTRLEN], prefixbuf[INET6_ADDRSTRLEN];
1202 struct timespec now; 1202 struct timespec now;
1203 struct in6_addr prefix; 1203 struct in6_addr prefix;
1204 1204
1205#if 0 /* impossible */ 1205#if 0 /* impossible */
1206 if (pinfo->nd_opt_pi_type != ND_OPT_PREFIX_INFORMATION) 1206 if (pinfo->nd_opt_pi_type != ND_OPT_PREFIX_INFORMATION)
1207 return 0; 1207 return 0;
1208#endif 1208#endif
1209 1209
1210 memcpy(&prefix, &pinfo->nd_opt_pi_prefix, sizeof(prefix)); 1210 memcpy(&prefix, &pinfo->nd_opt_pi_prefix, sizeof(prefix));
1211 1211
1212 /* 1212 /*
1213 * log if the adveritsed prefix has link-local scope(sanity check?) 1213 * log if the adveritsed prefix has link-local scope(sanity check?)
1214 */ 1214 */
1215 if (IN6_IS_ADDR_LINKLOCAL(&prefix)) { 1215 if (IN6_IS_ADDR_LINKLOCAL(&prefix)) {
1216 logit(LOG_INFO, 1216 logit(LOG_INFO,
1217 "%s: link-local prefix %s/%d is advertised " 1217 "%s: link-local prefix %s/%d is advertised "
1218 "from %s on %s", 1218 "from %s on %s",
1219 __func__, 1219 __func__,
1220 inet_ntop(AF_INET6, &prefix, 1220 inet_ntop(AF_INET6, &prefix,
1221 prefixbuf, INET6_ADDRSTRLEN), 1221 prefixbuf, INET6_ADDRSTRLEN),
1222 pinfo->nd_opt_pi_prefix_len, 1222 pinfo->nd_opt_pi_prefix_len,
1223 inet_ntop(AF_INET6, &from->sin6_addr, 1223 inet_ntop(AF_INET6, &from->sin6_addr,
1224 ntopbuf, INET6_ADDRSTRLEN), 1224 ntopbuf, INET6_ADDRSTRLEN),
1225 rai->ifname); 1225 rai->ifname);
1226 } 1226 }
1227 1227
1228 if ((pp = find_prefix(rai, &prefix, 1228 if ((pp = find_prefix(rai, &prefix,
1229 pinfo->nd_opt_pi_prefix_len)) == NULL) { 1229 pinfo->nd_opt_pi_prefix_len)) == NULL) {
1230 logit(LOG_INFO, 1230 logit(LOG_INFO,
1231 "%s: prefix %s/%d from %s on %s is not in our list", 1231 "%s: prefix %s/%d from %s on %s is not in our list",
1232 __func__, 1232 __func__,
1233 inet_ntop(AF_INET6, &prefix, 1233 inet_ntop(AF_INET6, &prefix,
1234 prefixbuf, INET6_ADDRSTRLEN), 1234 prefixbuf, INET6_ADDRSTRLEN),
1235 pinfo->nd_opt_pi_prefix_len, 1235 pinfo->nd_opt_pi_prefix_len,
1236 inet_ntop(AF_INET6, &from->sin6_addr, 1236 inet_ntop(AF_INET6, &from->sin6_addr,
1237 ntopbuf, INET6_ADDRSTRLEN), 1237 ntopbuf, INET6_ADDRSTRLEN),
1238 rai->ifname); 1238 rai->ifname);
1239 return 0; 1239 return 0;
1240 } 1240 }
1241 1241
1242 preferred_time = ntohl(pinfo->nd_opt_pi_preferred_time); 1242 preferred_time = ntohl(pinfo->nd_opt_pi_preferred_time);
1243 if (pp->pltimeexpire) { 1243 if (pp->pltimeexpire) {
1244 /* 1244 /*
1245 * The lifetime is decremented in real time, so we should 1245 * The lifetime is decremented in real time, so we should
1246 * compare the expiration time. 1246 * compare the expiration time.
1247 * (RFC 2461 Section 6.2.7.) 1247 * (RFC 2461 Section 6.2.7.)
1248 * XXX: can we really expect that all routers on the link 1248 * XXX: can we really expect that all routers on the link
1249 * have synchronized clocks? 1249 * have synchronized clocks?
1250 */ 1250 */
1251 prog_clock_gettime(CLOCK_MONOTONIC, &now); 1251 prog_clock_gettime(CLOCK_MONOTONIC, &now);
1252 preferred_time += now.tv_sec; 1252 preferred_time += now.tv_sec;
1253 1253
1254 if (!pp->timer && rai->clockskew && 1254 if (!pp->timer && rai->clockskew &&
1255 llabs((long long)preferred_time - pp->pltimeexpire) > rai->clockskew) { 1255 llabs((long long)preferred_time - pp->pltimeexpire) > rai->clockskew) {
1256 logit(LOG_INFO, 1256 logit(LOG_INFO,
1257 "%s: preferred lifetime for %s/%d" 1257 "%s: preferred lifetime for %s/%d"
1258 " (decr. in real time) inconsistent on %s:" 1258 " (decr. in real time) inconsistent on %s:"
1259 " %d from %s, %ld from us", 1259 " %d from %s, %ld from us",
1260 __func__, 1260 __func__,
1261 inet_ntop(AF_INET6, &prefix, 1261 inet_ntop(AF_INET6, &prefix,
1262 prefixbuf, INET6_ADDRSTRLEN), 1262 prefixbuf, INET6_ADDRSTRLEN),
1263 pinfo->nd_opt_pi_prefix_len, 1263 pinfo->nd_opt_pi_prefix_len,
1264 rai->ifname, preferred_time, 1264 rai->ifname, preferred_time,
1265 inet_ntop(AF_INET6, &from->sin6_addr, 1265 inet_ntop(AF_INET6, &from->sin6_addr,
1266 ntopbuf, INET6_ADDRSTRLEN), 1266 ntopbuf, INET6_ADDRSTRLEN),
1267 pp->pltimeexpire); 1267 pp->pltimeexpire);
1268 inconsistent++; 1268 inconsistent++;
1269 } 1269 }
1270 } else if (!pp->timer && preferred_time != pp->preflifetime) { 1270 } else if (!pp->timer && preferred_time != pp->preflifetime) {
1271 logit(LOG_INFO, 1271 logit(LOG_INFO,
1272 "%s: preferred lifetime for %s/%d" 1272 "%s: preferred lifetime for %s/%d"
1273 " inconsistent on %s:" 1273 " inconsistent on %s:"
1274 " %d from %s, %d from us", 1274 " %d from %s, %d from us",
1275 __func__, 1275 __func__,
1276 inet_ntop(AF_INET6, &prefix, 1276 inet_ntop(AF_INET6, &prefix,
1277 prefixbuf, INET6_ADDRSTRLEN), 1277 prefixbuf, INET6_ADDRSTRLEN),
1278 pinfo->nd_opt_pi_prefix_len, 1278 pinfo->nd_opt_pi_prefix_len,
1279 rai->ifname, preferred_time, 1279 rai->ifname, preferred_time,
1280 inet_ntop(AF_INET6, &from->sin6_addr, 1280 inet_ntop(AF_INET6, &from->sin6_addr,
1281 ntopbuf, INET6_ADDRSTRLEN), 1281 ntopbuf, INET6_ADDRSTRLEN),
1282 pp->preflifetime); 1282 pp->preflifetime);
1283 } 1283 }
1284 1284
1285 valid_time = ntohl(pinfo->nd_opt_pi_valid_time); 1285 valid_time = ntohl(pinfo->nd_opt_pi_valid_time);
1286 if (pp->vltimeexpire) { 1286 if (pp->vltimeexpire) {
1287 prog_clock_gettime(CLOCK_MONOTONIC, &now); 1287 prog_clock_gettime(CLOCK_MONOTONIC, &now);
1288 valid_time += now.tv_sec; 1288 valid_time += now.tv_sec;
1289 1289
1290 if (!pp->timer && rai->clockskew && 1290 if (!pp->timer && rai->clockskew &&
1291 llabs((long long)valid_time - pp->vltimeexpire) > rai->clockskew) { 1291 llabs((long long)valid_time - pp->vltimeexpire) > rai->clockskew) {
1292 logit(LOG_INFO, 1292 logit(LOG_INFO,
1293 "%s: valid lifetime for %s/%d" 1293 "%s: valid lifetime for %s/%d"
1294 " (decr. in real time) inconsistent on %s:" 1294 " (decr. in real time) inconsistent on %s:"
1295 " %d from %s, %ld from us", 1295 " %d from %s, %ld from us",
1296 __func__, 1296 __func__,
1297 inet_ntop(AF_INET6, &prefix, 1297 inet_ntop(AF_INET6, &prefix,
1298 prefixbuf, INET6_ADDRSTRLEN), 1298 prefixbuf, INET6_ADDRSTRLEN),
1299 pinfo->nd_opt_pi_prefix_len, 1299 pinfo->nd_opt_pi_prefix_len,
1300 rai->ifname, preferred_time, 1300 rai->ifname, preferred_time,
1301 inet_ntop(AF_INET6, &from->sin6_addr, 1301 inet_ntop(AF_INET6, &from->sin6_addr,
1302 ntopbuf, INET6_ADDRSTRLEN), 1302 ntopbuf, INET6_ADDRSTRLEN),
1303 pp->vltimeexpire); 1303 pp->vltimeexpire);
1304 inconsistent++; 1304 inconsistent++;
1305 } 1305 }
1306 } else if (!pp->timer && valid_time != pp->validlifetime) { 1306 } else if (!pp->timer && valid_time != pp->validlifetime) {
1307 logit(LOG_INFO, 1307 logit(LOG_INFO,
1308 "%s: valid lifetime for %s/%d" 1308 "%s: valid lifetime for %s/%d"
1309 " inconsistent on %s:" 1309 " inconsistent on %s:"
1310 " %d from %s, %d from us", 1310 " %d from %s, %d from us",
1311 __func__, 1311 __func__,
1312 inet_ntop(AF_INET6, &prefix, 1312 inet_ntop(AF_INET6, &prefix,
1313 prefixbuf, INET6_ADDRSTRLEN), 1313 prefixbuf, INET6_ADDRSTRLEN),
1314 pinfo->nd_opt_pi_prefix_len, 1314 pinfo->nd_opt_pi_prefix_len,
1315 rai->ifname, valid_time, 1315 rai->ifname, valid_time,
1316 inet_ntop(AF_INET6, &from->sin6_addr, 1316 inet_ntop(AF_INET6, &from->sin6_addr,
1317 ntopbuf, INET6_ADDRSTRLEN), 1317 ntopbuf, INET6_ADDRSTRLEN),
1318 pp->validlifetime); 1318 pp->validlifetime);
1319 inconsistent++; 1319 inconsistent++;
1320 } 1320 }
1321 1321
1322 return inconsistent; 1322 return inconsistent;
1323} 1323}
1324 1324
1325struct prefix * 1325struct prefix *
1326find_prefix(struct rainfo *rai, struct in6_addr *prefix, int plen) 1326find_prefix(struct rainfo *rai, struct in6_addr *prefix, int plen)
1327{ 1327{
1328 struct prefix *pp; 1328 struct prefix *pp;
1329 int bytelen, bitlen; 1329 int bytelen, bitlen;
1330 unsigned char bitmask; 1330 unsigned char bitmask;
1331 1331
1332 TAILQ_FOREACH(pp, &rai->prefix, next) { 1332 TAILQ_FOREACH(pp, &rai->prefix, next) {
1333 if (plen != pp->prefixlen) 1333 if (plen != pp->prefixlen)
1334 continue; 1334 continue;
1335 bytelen = plen / 8; 1335 bytelen = plen / 8;
1336 bitlen = plen % 8; 1336 bitlen = plen % 8;
1337 bitmask = 0xff << (8 - bitlen); 1337 bitmask = 0xff << (8 - bitlen);
1338 if (memcmp(prefix, &pp->prefix, bytelen)) 1338 if (memcmp(prefix, &pp->prefix, bytelen))
1339 continue; 1339 continue;
1340 if (bitlen == 0 || 1340 if (bitlen == 0 ||
1341 ((prefix->s6_addr[bytelen] & bitmask) == 1341 ((prefix->s6_addr[bytelen] & bitmask) ==
1342 (pp->prefix.s6_addr[bytelen] & bitmask))) { 1342 (pp->prefix.s6_addr[bytelen] & bitmask))) {
1343 return pp; 1343 return pp;
1344 } 1344 }
1345 } 1345 }
1346 1346
1347 return NULL; 1347 return NULL;
1348} 1348}
1349 1349
1350/* check if p0/plen0 matches p1/plen1; return 1 if matches, otherwise 0. */ 1350/* check if p0/plen0 matches p1/plen1; return 1 if matches, otherwise 0. */
1351int 1351int
1352prefix_match(struct in6_addr *p0, int plen0, 1352prefix_match(struct in6_addr *p0, int plen0,
1353 struct in6_addr *p1, int plen1) 1353 struct in6_addr *p1, int plen1)
1354{ 1354{
1355 int bytelen, bitlen; 1355 int bytelen, bitlen;
1356 unsigned char bitmask; 1356 unsigned char bitmask;
1357 1357
1358 if (plen0 < plen1) 1358 if (plen0 < plen1)
1359 return 0; 1359 return 0;
1360 bytelen = plen1 / 8; 1360 bytelen = plen1 / 8;
1361 bitlen = plen1 % 8; 1361 bitlen = plen1 % 8;
1362 bitmask = 0xff << (8 - bitlen); 1362 bitmask = 0xff << (8 - bitlen);
1363 if (memcmp(p0, p1, bytelen)) 1363 if (memcmp(p0, p1, bytelen))
1364 return 0; 1364 return 0;
1365 if (bitlen == 0 || 1365 if (bitlen == 0 ||
1366 ((p0->s6_addr[bytelen] & bitmask) == 1366 ((p0->s6_addr[bytelen] & bitmask) ==
1367 (p1->s6_addr[bytelen] & bitmask))) { 1367 (p1->s6_addr[bytelen] & bitmask))) {
1368 return 1; 1368 return 1;
1369 } 1369 }
1370 1370
1371 return 0; 1371 return 0;
1372} 1372}
1373 1373
1374static int 1374static int
1375nd6_options(struct nd_opt_hdr *hdr, int limit, 1375nd6_options(struct nd_opt_hdr *hdr, int limit,
1376 union nd_opts *ndopts, uint32_t optflags) 1376 union nd_opts *ndopts, uint32_t optflags)
1377{ 1377{
1378 int optlen = 0; 1378 int optlen = 0;
1379 1379
1380 for (; limit > 0; limit -= optlen) { 1380 for (; limit > 0; limit -= optlen) {
1381 if ((size_t)limit < sizeof(struct nd_opt_hdr)) { 1381 if ((size_t)limit < sizeof(struct nd_opt_hdr)) {
1382 logit(LOG_INFO, "%s: short option header", __func__); 1382 logit(LOG_INFO, "%s: short option header", __func__);
1383 goto bad; 1383 goto bad;
1384 } 1384 }
1385 1385
1386 hdr = (struct nd_opt_hdr *)((char *)hdr + optlen); 1386 hdr = (struct nd_opt_hdr *)((char *)hdr + optlen);
1387 if (hdr->nd_opt_len == 0) { 1387 if (hdr->nd_opt_len == 0) {
1388 logit(LOG_INFO, 1388 logit(LOG_INFO,
1389 "%s: bad ND option length(0) (type = %d)", 1389 "%s: bad ND option length(0) (type = %d)",
1390 __func__, hdr->nd_opt_type); 1390 __func__, hdr->nd_opt_type);
1391 goto bad; 1391 goto bad;
1392 } 1392 }
1393 optlen = hdr->nd_opt_len << 3; 1393 optlen = hdr->nd_opt_len << 3;
1394 if (optlen > limit) { 1394 if (optlen > limit) {
1395 logit(LOG_INFO, "%s: short option", __func__); 1395 logit(LOG_INFO, "%s: short option", __func__);
1396 goto bad; 1396 goto bad;
1397 } 1397 }
1398 1398
1399 if (hdr->nd_opt_type > ND_OPT_MTU && 1399 if (hdr->nd_opt_type > ND_OPT_MTU &&
1400 hdr->nd_opt_type != ND_OPT_RDNSS && 1400 hdr->nd_opt_type != ND_OPT_RDNSS &&
1401 hdr->nd_opt_type != ND_OPT_DNSSL) 1401 hdr->nd_opt_type != ND_OPT_DNSSL)
1402 { 1402 {
1403 logit(LOG_INFO, "%s: unknown ND option(type %d)", 1403 logit(LOG_INFO, "%s: unknown ND option(type %d)",
1404 __func__, hdr->nd_opt_type); 1404 __func__, hdr->nd_opt_type);
1405 continue; 1405 continue;
1406 } 1406 }
1407 1407
1408 if ((ndopt_flags[hdr->nd_opt_type] & optflags) == 0) { 1408 if ((ndopt_flags[hdr->nd_opt_type] & optflags) == 0) {
1409 logit(LOG_INFO, "%s: unexpected ND option(type %d)", 1409 logit(LOG_INFO, "%s: unexpected ND option(type %d)",
1410 __func__, hdr->nd_opt_type); 1410 __func__, hdr->nd_opt_type);
1411 continue; 1411 continue;
1412 } 1412 }
1413 1413
1414 /* 1414 /*
1415 * Option length check. Do it here for all fixed-length 1415 * Option length check. Do it here for all fixed-length
1416 * options. 1416 * options.
1417 */ 1417 */
1418 if ((hdr->nd_opt_type == ND_OPT_MTU && 1418 if ((hdr->nd_opt_type == ND_OPT_MTU &&
1419 (optlen != sizeof(struct nd_opt_mtu))) || 1419 (optlen != sizeof(struct nd_opt_mtu))) ||
1420 ((hdr->nd_opt_type == ND_OPT_PREFIX_INFORMATION && 1420 ((hdr->nd_opt_type == ND_OPT_PREFIX_INFORMATION &&
1421 optlen != sizeof(struct nd_opt_prefix_info))) || 1421 optlen != sizeof(struct nd_opt_prefix_info))) ||
1422 (hdr->nd_opt_type == ND_OPT_RDNSS && 1422 (hdr->nd_opt_type == ND_OPT_RDNSS &&
1423 ((optlen < (int)sizeof(struct nd_opt_rdnss) || 1423 ((optlen < (int)sizeof(struct nd_opt_rdnss) ||
1424 (optlen - sizeof(struct nd_opt_rdnss)) % 16 != 0))) || 1424 (optlen - sizeof(struct nd_opt_rdnss)) % 16 != 0))) ||
1425 (hdr->nd_opt_type == ND_OPT_DNSSL && 1425 (hdr->nd_opt_type == ND_OPT_DNSSL &&
1426 optlen < (int)sizeof(struct nd_opt_dnssl))) 1426 optlen < (int)sizeof(struct nd_opt_dnssl)))
1427 { 1427 {
1428 logit(LOG_INFO, "%s: invalid option length", 1428 logit(LOG_INFO, "%s: invalid option length",
1429 __func__); 1429 __func__);
1430 continue; 1430 continue;
1431 } 1431 }
1432 1432
1433 switch (hdr->nd_opt_type) { 1433 switch (hdr->nd_opt_type) {
1434 case ND_OPT_TARGET_LINKADDR: 1434 case ND_OPT_TARGET_LINKADDR:
1435 case ND_OPT_REDIRECTED_HEADER: 1435 case ND_OPT_REDIRECTED_HEADER:
1436 case ND_OPT_RDNSS: 1436 case ND_OPT_RDNSS:
1437 case ND_OPT_DNSSL: 1437 case ND_OPT_DNSSL:
1438 break; /* we don't care about these options */ 1438 break; /* we don't care about these options */
1439 case ND_OPT_SOURCE_LINKADDR: 1439 case ND_OPT_SOURCE_LINKADDR:
1440 case ND_OPT_MTU: 1440 case ND_OPT_MTU:
1441 if (ndopts->nd_opt_array[hdr->nd_opt_type]) { 1441 if (ndopts->nd_opt_array[hdr->nd_opt_type]) {
1442 logit(LOG_INFO, 1442 logit(LOG_INFO,
1443 "%s: duplicated ND option (type = %d)", 1443 "%s: duplicated ND option (type = %d)",
1444 __func__, hdr->nd_opt_type); 1444 __func__, hdr->nd_opt_type);
1445 } 1445 }
1446 ndopts->nd_opt_array[hdr->nd_opt_type] = hdr; 1446 ndopts->nd_opt_array[hdr->nd_opt_type] = hdr;
1447 break; 1447 break;
1448 case ND_OPT_PREFIX_INFORMATION: 1448 case ND_OPT_PREFIX_INFORMATION:
1449 { 1449 {
1450 struct nd_optlist *pfxlist; 1450 struct nd_optlist *pfxlist;
1451 1451
1452 if (ndopts->nd_opts_pi == 0) { 1452 if (ndopts->nd_opts_pi == 0) {
1453 ndopts->nd_opts_pi = 1453 ndopts->nd_opts_pi =
1454 (struct nd_opt_prefix_info *)hdr; 1454 (struct nd_opt_prefix_info *)hdr;
1455 continue; 1455 continue;
1456 } 1456 }
1457 if ((pfxlist = malloc(sizeof(*pfxlist))) == NULL) { 1457 if ((pfxlist = malloc(sizeof(*pfxlist))) == NULL) {
1458 logit(LOG_ERR, "%s: can't allocate memory", 1458 logit(LOG_ERR, "%s: can't allocate memory",
1459 __func__); 1459 __func__);
1460 goto bad; 1460 goto bad;
1461 } 1461 }
1462 pfxlist->opt = hdr; 1462 pfxlist->opt = hdr;
1463 TAILQ_INSERT_TAIL(&ndopts->nd_opts_list, pfxlist, next); 1463 TAILQ_INSERT_TAIL(&ndopts->nd_opts_list, pfxlist, next);
1464 1464
1465 break; 1465 break;
1466 } 1466 }
1467 default: /* impossible */ 1467 default: /* impossible */
1468 break; 1468 break;
1469 } 1469 }
1470 } 1470 }
1471 1471
1472 return 0; 1472 return 0;
1473 1473
1474 bad: 1474 bad:
1475 free_ndopts(ndopts); 1475 free_ndopts(ndopts);
1476 return -1; 1476 return -1;
1477} 1477}
1478 1478
1479static void 1479static void
1480free_ndopts(union nd_opts *ndopts) 1480free_ndopts(union nd_opts *ndopts)
1481{ 1481{
1482 struct nd_optlist *opt; 1482 struct nd_optlist *opt;
1483 1483
1484 while ((opt = TAILQ_FIRST(&ndopts->nd_opts_list)) != NULL) { 1484 while ((opt = TAILQ_FIRST(&ndopts->nd_opts_list)) != NULL) {
1485 TAILQ_REMOVE(&ndopts->nd_opts_list, opt, next); 1485 TAILQ_REMOVE(&ndopts->nd_opts_list, opt, next);
1486 free(opt); 1486 free(opt);
1487 } 1487 }
1488} 1488}
1489 1489
1490void 1490void
1491sock_open(void) 1491sock_open(void)
1492{ 1492{
1493 struct icmp6_filter filt; 1493 struct icmp6_filter filt;
1494 struct ipv6_mreq mreq; 1494 struct ipv6_mreq mreq;
1495 struct rainfo *ra; 1495 struct rainfo *ra;
1496 int on; 1496 int on;
1497 /* XXX: should be max MTU attached to the node */ 1497 /* XXX: should be max MTU attached to the node */
1498 static unsigned char answer[1500]; 1498 static unsigned char answer[1500];
1499 1499
1500 rcvcmsgbuflen = CMSG_SPACE(sizeof(struct in6_pktinfo)) + 1500 rcvcmsgbuflen = CMSG_SPACE(sizeof(struct in6_pktinfo)) +
1501 CMSG_SPACE(sizeof(int)); 1501 CMSG_SPACE(sizeof(int));
1502 rcvcmsgbuf = malloc(rcvcmsgbuflen); 1502 rcvcmsgbuf = malloc(rcvcmsgbuflen);
1503 if (rcvcmsgbuf == NULL) { 1503 if (rcvcmsgbuf == NULL) {
1504 logit(LOG_ERR, "%s: malloc: %m", __func__); 1504 logit(LOG_ERR, "%s: malloc: %m", __func__);
1505 exit(EXIT_FAILURE); 1505 exit(EXIT_FAILURE);
1506 } 1506 }
1507 1507
1508 sndcmsgbuflen = CMSG_SPACE(sizeof(struct in6_pktinfo)); 1508 sndcmsgbuflen = CMSG_SPACE(sizeof(struct in6_pktinfo));
1509 sndcmsgbuf = malloc(sndcmsgbuflen); 1509 sndcmsgbuf = malloc(sndcmsgbuflen);
1510 if (sndcmsgbuf == NULL) { 1510 if (sndcmsgbuf == NULL) {
1511 logit(LOG_ERR, "%s: malloc: %m", __func__); 1511 logit(LOG_ERR, "%s: malloc: %m", __func__);
1512 exit(EXIT_FAILURE); 1512 exit(EXIT_FAILURE);
1513 } 1513 }
1514 1514
1515 if ((sock = prog_socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) == -1) { 1515 if ((sock = prog_socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) == -1) {
1516 logit(LOG_ERR, "%s: socket: %m", __func__); 1516 logit(LOG_ERR, "%s: socket: %m", __func__);
1517 exit(EXIT_FAILURE); 1517 exit(EXIT_FAILURE);
1518 } 1518 }
1519 1519
1520 /* RFC 4861 Section 4.2 */ 1520 /* RFC 4861 Section 4.2 */
1521 on = 255; 1521 on = 255;
1522 if (prog_setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &on, 1522 if (prog_setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &on,
1523 sizeof(on)) == -1) { 1523 sizeof(on)) == -1) {
1524 logit(LOG_ERR, "%s: IPV6_MULTICAST_HOPS: %m", __func__); 1524 logit(LOG_ERR, "%s: IPV6_MULTICAST_HOPS: %m", __func__);
1525 exit(EXIT_FAILURE); 1525 exit(EXIT_FAILURE);
1526 } 1526 }
1527 on = 255; 1527 on = 255;
1528 if (prog_setsockopt(sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &on, 1528 if (prog_setsockopt(sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &on,
1529 sizeof(on)) == -1) { 1529 sizeof(on)) == -1) {
1530 logit(LOG_ERR, "%s: IPV6_UNICAST_HOPS: %m", __func__); 1530 logit(LOG_ERR, "%s: IPV6_UNICAST_HOPS: %m", __func__);
1531 exit(EXIT_FAILURE); 1531 exit(EXIT_FAILURE);
1532 } 1532 }
1533 1533
1534 /* specify to tell receiving interface */ 1534 /* specify to tell receiving interface */
1535 on = 1; 1535 on = 1;
1536 if (prog_setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, 1536 if (prog_setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on,
1537 sizeof(on)) == -1) { 1537 sizeof(on)) == -1) {
1538 logit(LOG_ERR, "%s: IPV6_RECVPKTINFO: %m", __func__); 1538 logit(LOG_ERR, "%s: IPV6_RECVPKTINFO: %m", __func__);
1539 exit(EXIT_FAILURE); 1539 exit(EXIT_FAILURE);
1540 } 1540 }
1541 1541
1542 on = 1; 1542 on = 1;
1543 /* specify to tell value of hoplimit field of received IP6 hdr */ 1543 /* specify to tell value of hoplimit field of received IP6 hdr */
1544 if (prog_setsockopt(sock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on, 1544 if (prog_setsockopt(sock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on,
1545 sizeof(on)) == -1) { 1545 sizeof(on)) == -1) {
1546 logit(LOG_ERR, "%s: IPV6_RECVHOPLIMIT: %m", __func__); 1546 logit(LOG_ERR, "%s: IPV6_RECVHOPLIMIT: %m", __func__);
1547 exit(EXIT_FAILURE); 1547 exit(EXIT_FAILURE);
1548 } 1548 }
1549 1549
1550 ICMP6_FILTER_SETBLOCKALL(&filt); 1550 ICMP6_FILTER_SETBLOCKALL(&filt);
1551 ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &filt); 1551 ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &filt);
1552 ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filt); 1552 ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filt);
1553 if (prog_setsockopt(sock, IPPROTO_ICMPV6, ICMP6_FILTER, &filt, 1553 if (prog_setsockopt(sock, IPPROTO_ICMPV6, ICMP6_FILTER, &filt,
1554 sizeof(filt)) == -1) { 1554 sizeof(filt)) == -1) {
1555 logit(LOG_ERR, "%s: IICMP6_FILTER: %m", __func__); 1555 logit(LOG_ERR, "%s: IICMP6_FILTER: %m", __func__);
1556 exit(EXIT_FAILURE); 1556 exit(EXIT_FAILURE);
1557 } 1557 }
1558 1558
1559 /* 1559 /*
1560 * join all routers multicast address on each advertising interface. 1560 * join all routers multicast address on each advertising interface.
1561 */ 1561 */
1562 if (inet_pton(AF_INET6, ALLROUTERS_LINK, 1562 if (inet_pton(AF_INET6, ALLROUTERS_LINK,
1563 mreq.ipv6mr_multiaddr.s6_addr) != 1) 1563 mreq.ipv6mr_multiaddr.s6_addr) != 1)
1564 { 1564 {
1565 logit(LOG_ERR, "%s: inet_pton failed(library bug?)", 1565 logit(LOG_ERR, "%s: inet_pton failed(library bug?)",
1566 __func__); 1566 __func__);
1567 exit(EXIT_FAILURE); 1567 exit(EXIT_FAILURE);
1568 } 1568 }
1569 TAILQ_FOREACH(ra, &ralist, next) { 1569 TAILQ_FOREACH(ra, &ralist, next) {
1570 mreq.ipv6mr_interface = ra->ifindex; 1570 mreq.ipv6mr_interface = ra->ifindex;
1571 if (prog_setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, 1571 if (prog_setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq,
1572 sizeof(mreq)) == -1) { 1572 sizeof(mreq)) == -1) {
1573 logit(LOG_ERR, "%s: IPV6_JOIN_GROUP(link) on %s: %m", 1573 logit(LOG_ERR, "%s: IPV6_JOIN_GROUP(link) on %s: %m",
1574 __func__, ra->ifname); 1574 __func__, ra->ifname);
1575 continue; 1575 continue;
1576 } 1576 }
1577 } 1577 }
1578 1578
1579 /* initialize msghdr for receiving packets */ 1579 /* initialize msghdr for receiving packets */
1580 rcviov[0].iov_base = answer; 1580 rcviov[0].iov_base = answer;
1581 rcviov[0].iov_len = sizeof(answer); 1581 rcviov[0].iov_len = sizeof(answer);
1582 rcvmhdr.msg_name = &rcvfrom; 1582 rcvmhdr.msg_name = &rcvfrom;
1583 rcvmhdr.msg_namelen = sizeof(rcvfrom); 1583 rcvmhdr.msg_namelen = sizeof(rcvfrom);
1584 rcvmhdr.msg_iov = rcviov; 1584 rcvmhdr.msg_iov = rcviov;
1585 rcvmhdr.msg_iovlen = 1; 1585 rcvmhdr.msg_iovlen = 1;
1586 rcvmhdr.msg_control = rcvcmsgbuf; 1586 rcvmhdr.msg_control = rcvcmsgbuf;
1587 rcvmhdr.msg_controllen = rcvcmsgbuflen; 1587 rcvmhdr.msg_controllen = rcvcmsgbuflen;
1588 1588
1589 /* initialize msghdr for sending packets */ 1589 /* initialize msghdr for sending packets */
1590 sndmhdr.msg_namelen = sizeof(struct sockaddr_in6); 1590 sndmhdr.msg_namelen = sizeof(struct sockaddr_in6);
1591 sndmhdr.msg_iov = sndiov; 1591 sndmhdr.msg_iov = sndiov;
1592 sndmhdr.msg_iovlen = 1; 1592 sndmhdr.msg_iovlen = 1;
1593 sndmhdr.msg_control = sndcmsgbuf; 1593 sndmhdr.msg_control = sndcmsgbuf;
1594 sndmhdr.msg_controllen = sndcmsgbuflen; 1594 sndmhdr.msg_controllen = sndcmsgbuflen;
1595} 1595}
1596 1596
1597/* open a routing socket to watch the routing table */ 1597/* open a routing socket to watch the routing table */
1598static void 1598static void
1599rtsock_open(void) 1599rtsock_open(void)
1600{ 1600{
1601#ifdef RO_MSGFILTER 1601#ifdef RO_MSGFILTER
1602 unsigned char msgfilter[] = { 1602 unsigned char msgfilter[] = {
1603 RTM_ADD, RTM_DELETE, 1603 RTM_ADD, RTM_DELETE,
1604 RTM_NEWADDR, RTM_DELADDR, 1604 RTM_NEWADDR, RTM_DELADDR,
1605#ifdef RTM_IFANNOUNCE 1605#ifdef RTM_IFANNOUNCE
1606 RTM_IFANNOUNCE, 1606 RTM_IFANNOUNCE,
1607#endif 1607#endif
1608 RTM_IFINFO, 1608 RTM_IFINFO,
1609 }; 1609 };
1610#endif 1610#endif
1611 1611
1612 if ((rtsock = prog_socket(PF_ROUTE, SOCK_RAW, 0)) == -1) { 1612 if ((rtsock = prog_socket(PF_ROUTE, SOCK_RAW, 0)) == -1) {
1613 logit(LOG_ERR, "%s: socket: %m", __func__); 1613 logit(LOG_ERR, "%s: socket: %m", __func__);
1614 exit(EXIT_FAILURE); 1614 exit(EXIT_FAILURE);
1615 } 1615 }
1616#ifdef RO_MSGFILTER 1616#ifdef RO_MSGFILTER
1617 if (setsockopt(rtsock, PF_ROUTE, RO_MSGFILTER, 1617 if (setsockopt(rtsock, PF_ROUTE, RO_MSGFILTER,