1 /* $FreeBSD$ */ 2 /* $KAME: rrenum.c,v 1.12 2002/06/10 19:59:47 itojun Exp $ */ 3 4 /*- 5 * SPDX-License-Identifier: BSD-3-Clause 6 * 7 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 8 * All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. Neither the name of the project nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 #include <sys/types.h> 35 #include <sys/param.h> 36 #include <sys/ioctl.h> 37 #include <sys/queue.h> 38 #include <sys/socket.h> 39 #include <sys/sysctl.h> 40 41 #include <net/if.h> 42 #include <net/if_dl.h> 43 #include <net/route.h> 44 #include <netinet/in.h> 45 #include <netinet/in_var.h> 46 #include <netinet/icmp6.h> 47 48 #include <arpa/inet.h> 49 50 #include <errno.h> 51 #include <netdb.h> 52 #include <string.h> 53 #include <stdlib.h> 54 #include <time.h> 55 #include <syslog.h> 56 #include "rtadvd.h" 57 #include "rrenum.h" 58 #include "if.h" 59 60 #define RR_ISSET_SEGNUM(segnum_bits, segnum) \ 61 ((((segnum_bits)[(segnum) >> 5]) & (1 << ((segnum) & 31))) != 0) 62 #define RR_SET_SEGNUM(segnum_bits, segnum) \ 63 (((segnum_bits)[(segnum) >> 5]) |= (1 << ((segnum) & 31))) 64 65 struct rr_operation { 66 u_long rro_seqnum; 67 u_long rro_segnum_bits[8]; 68 }; 69 70 static struct rr_operation rro; 71 static int rr_rcvifindex; 72 static int rrcmd2pco[RPM_PCO_MAX] = { 73 0, 74 SIOCAIFPREFIX_IN6, 75 SIOCCIFPREFIX_IN6, 76 SIOCSGIFPREFIX_IN6 77 }; 78 static int s = -1; 79 80 /* 81 * Check validity of a Prefix Control Operation(PCO). 82 * return 0 on success, 1 on failure. 83 */ 84 static int 85 rr_pco_check(int len, struct rr_pco_match *rpm) 86 { 87 struct rr_pco_use *rpu, *rpulim; 88 int checklen; 89 90 /* rpm->rpm_len must be (4N * 3) as router-renum-05.txt */ 91 if ((rpm->rpm_len - 3) < 0 || /* must be at least 3 */ 92 (rpm->rpm_len - 3) & 0x3) { /* must be multiple of 4 */ 93 syslog(LOG_WARNING, "<%s> rpm_len %d is not 4N * 3", 94 __func__, rpm->rpm_len); 95 return (1); 96 } 97 /* rpm->rpm_code must be valid value */ 98 switch (rpm->rpm_code) { 99 case RPM_PCO_ADD: 100 case RPM_PCO_CHANGE: 101 case RPM_PCO_SETGLOBAL: 102 break; 103 default: 104 syslog(LOG_WARNING, "<%s> unknown rpm_code %d", __func__, 105 rpm->rpm_code); 106 return (1); 107 } 108 /* rpm->rpm_matchlen must be 0 to 128 inclusive */ 109 if (rpm->rpm_matchlen > 128) { 110 syslog(LOG_WARNING, "<%s> rpm_matchlen %d is over 128", 111 __func__, rpm->rpm_matchlen); 112 return (1); 113 } 114 115 /* 116 * rpu->rpu_uselen, rpu->rpu_keeplen, and sum of them must be 117 * between 0 and 128 inclusive 118 */ 119 for (rpu = (struct rr_pco_use *)(rpm + 1), 120 rpulim = (struct rr_pco_use *)((char *)rpm + len); 121 rpu < rpulim; 122 rpu += 1) { 123 checklen = rpu->rpu_uselen; 124 checklen += rpu->rpu_keeplen; 125 /* 126 * omit these check, because either of rpu_uselen 127 * and rpu_keeplen is unsigned char 128 * (128 > rpu_uselen > 0) 129 * (128 > rpu_keeplen > 0) 130 * (rpu_uselen + rpu_keeplen > 0) 131 */ 132 if (checklen > 128) { 133 syslog(LOG_WARNING, "<%s> sum of rpu_uselen %d and" 134 " rpu_keeplen %d is %d(over 128)", 135 __func__, rpu->rpu_uselen, rpu->rpu_keeplen, 136 rpu->rpu_uselen + rpu->rpu_keeplen); 137 return (1); 138 } 139 } 140 return (0); 141 } 142 143 static void 144 do_use_prefix(int len, struct rr_pco_match *rpm, 145 struct in6_rrenumreq *irr, int ifindex) 146 { 147 struct rr_pco_use *rpu, *rpulim; 148 struct rainfo *rai; 149 struct ifinfo *ifi; 150 struct prefix *pfx; 151 152 rpu = (struct rr_pco_use *)(rpm + 1); 153 rpulim = (struct rr_pco_use *)((char *)rpm + len); 154 155 if (rpu == rpulim) { /* no use prefix */ 156 if (rpm->rpm_code == RPM_PCO_ADD) 157 return; 158 159 irr->irr_u_uselen = 0; 160 irr->irr_u_keeplen = 0; 161 irr->irr_raf_mask_onlink = 0; 162 irr->irr_raf_mask_auto = 0; 163 irr->irr_vltime = 0; 164 irr->irr_pltime = 0; 165 memset(&irr->irr_flags, 0, sizeof(irr->irr_flags)); 166 irr->irr_useprefix.sin6_len = 0; /* let it mean, no addition */ 167 irr->irr_useprefix.sin6_family = 0; 168 irr->irr_useprefix.sin6_addr = in6addr_any; 169 if (ioctl(s, rrcmd2pco[rpm->rpm_code], (caddr_t)irr) < 0 && 170 errno != EADDRNOTAVAIL) 171 syslog(LOG_ERR, "<%s> ioctl: %s", __func__, 172 strerror(errno)); 173 return; 174 } 175 176 for (rpu = (struct rr_pco_use *)(rpm + 1), 177 rpulim = (struct rr_pco_use *)((char *)rpm + len); 178 rpu < rpulim; 179 rpu += 1) { 180 /* init in6_rrenumreq fields */ 181 irr->irr_u_uselen = rpu->rpu_uselen; 182 irr->irr_u_keeplen = rpu->rpu_keeplen; 183 irr->irr_raf_mask_onlink = 184 !!(rpu->rpu_ramask & ICMP6_RR_PCOUSE_RAFLAGS_ONLINK); 185 irr->irr_raf_mask_auto = 186 !!(rpu->rpu_ramask & ICMP6_RR_PCOUSE_RAFLAGS_AUTO); 187 irr->irr_vltime = ntohl(rpu->rpu_vltime); 188 irr->irr_pltime = ntohl(rpu->rpu_pltime); 189 irr->irr_raf_onlink = 190 (rpu->rpu_raflags & ICMP6_RR_PCOUSE_RAFLAGS_ONLINK) == 0 ? 191 0 : 1; 192 irr->irr_raf_auto = 193 (rpu->rpu_raflags & ICMP6_RR_PCOUSE_RAFLAGS_AUTO) == 0 ? 194 0 : 1; 195 irr->irr_rrf_decrvalid = 196 (rpu->rpu_flags & ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME) == 0 ? 197 0 : 1; 198 irr->irr_rrf_decrprefd = 199 (rpu->rpu_flags & ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME) == 0 ? 200 0 : 1; 201 irr->irr_useprefix.sin6_len = sizeof(irr->irr_useprefix); 202 irr->irr_useprefix.sin6_family = AF_INET6; 203 irr->irr_useprefix.sin6_addr = rpu->rpu_prefix; 204 205 if (ioctl(s, rrcmd2pco[rpm->rpm_code], (caddr_t)irr) < 0 && 206 errno != EADDRNOTAVAIL) 207 syslog(LOG_ERR, "<%s> ioctl: %s", __func__, 208 strerror(errno)); 209 210 /* very adhoc: should be rewritten */ 211 if (rpm->rpm_code == RPM_PCO_CHANGE && 212 IN6_ARE_ADDR_EQUAL(&rpm->rpm_prefix, &rpu->rpu_prefix) && 213 rpm->rpm_matchlen == rpu->rpu_uselen && 214 rpu->rpu_uselen == rpu->rpu_keeplen) { 215 ifi = if_indextoifinfo(ifindex); 216 if (ifi == NULL || ifi->ifi_rainfo == NULL) 217 continue; /* non-advertising IF */ 218 rai = ifi->ifi_rainfo; 219 220 TAILQ_FOREACH(pfx, &rai->rai_prefix, pfx_next) { 221 struct timespec now; 222 223 if (prefix_match(&pfx->pfx_prefix, 224 pfx->pfx_prefixlen, &rpm->rpm_prefix, 225 rpm->rpm_matchlen)) { 226 /* change parameters */ 227 pfx->pfx_validlifetime = 228 ntohl(rpu->rpu_vltime); 229 pfx->pfx_preflifetime = 230 ntohl(rpu->rpu_pltime); 231 if (irr->irr_rrf_decrvalid) { 232 clock_gettime(CLOCK_MONOTONIC_FAST, 233 &now); 234 pfx->pfx_vltimeexpire = 235 now.tv_sec + 236 pfx->pfx_validlifetime; 237 } else 238 pfx->pfx_vltimeexpire = 0; 239 if (irr->irr_rrf_decrprefd) { 240 clock_gettime(CLOCK_MONOTONIC_FAST, 241 &now); 242 pfx->pfx_pltimeexpire = 243 now.tv_sec + 244 pfx->pfx_preflifetime; 245 } else 246 pfx->pfx_pltimeexpire = 0; 247 } 248 } 249 } 250 } 251 } 252 253 /* 254 * process a Prefix Control Operation(PCO). 255 * return 0 on success, 1 on failure 256 */ 257 static int 258 do_pco(struct icmp6_router_renum *rr, int len, struct rr_pco_match *rpm) 259 { 260 int ifindex = 0; 261 struct in6_rrenumreq irr; 262 struct ifinfo *ifi; 263 264 if ((rr_pco_check(len, rpm) != 0)) 265 return (1); 266 267 if (s == -1 && (s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 268 syslog(LOG_ERR, "<%s> socket: %s", __func__, 269 strerror(errno)); 270 exit(1); 271 } 272 273 memset(&irr, 0, sizeof(irr)); 274 irr.irr_origin = PR_ORIG_RR; 275 irr.irr_m_len = rpm->rpm_matchlen; 276 irr.irr_m_minlen = rpm->rpm_minlen; 277 irr.irr_m_maxlen = rpm->rpm_maxlen; 278 irr.irr_matchprefix.sin6_len = sizeof(irr.irr_matchprefix); 279 irr.irr_matchprefix.sin6_family = AF_INET6; 280 irr.irr_matchprefix.sin6_addr = rpm->rpm_prefix; 281 282 while (if_indextoname(++ifindex, irr.irr_name)) { 283 ifi = if_indextoifinfo(ifindex); 284 if (ifi == NULL) { 285 syslog(LOG_ERR, "<%s> ifindex not found.", 286 __func__); 287 return (1); 288 } 289 /* 290 * if ICMP6_RR_FLAGS_FORCEAPPLY(A flag) is 0 and 291 * IFF_UP is off, the interface is not applied 292 */ 293 if ((rr->rr_flags & ICMP6_RR_FLAGS_FORCEAPPLY) == 0 && 294 (ifi->ifi_flags & IFF_UP) == 0) 295 continue; 296 /* TODO: interface scope check */ 297 do_use_prefix(len, rpm, &irr, ifindex); 298 } 299 if (errno == ENXIO) 300 return (0); 301 else if (errno) { 302 syslog(LOG_ERR, "<%s> if_indextoname: %s", __func__, 303 strerror(errno)); 304 return (1); 305 } 306 return (0); 307 } 308 309 /* 310 * call do_pco() for each Prefix Control Operations(PCOs) in a received 311 * Router Renumbering Command packet. 312 * return 0 on success, 1 on failure 313 */ 314 static int 315 do_rr(int len, struct icmp6_router_renum *rr) 316 { 317 struct rr_pco_match *rpm; 318 char *cp, *lim; 319 320 lim = (char *)rr + len; 321 cp = (char *)(rr + 1); 322 len -= sizeof(struct icmp6_router_renum); 323 324 update_ifinfo(&ifilist, UPDATE_IFINFO_ALL); 325 326 while (cp < lim) { 327 int rpmlen; 328 329 rpm = (struct rr_pco_match *)cp; 330 if ((size_t)len < sizeof(struct rr_pco_match)) { 331 tooshort: 332 syslog(LOG_ERR, "<%s> pkt too short. left len = %d. " 333 "garbage at end of pkt?", __func__, len); 334 return (1); 335 } 336 rpmlen = rpm->rpm_len << 3; 337 if (len < rpmlen) 338 goto tooshort; 339 340 if (do_pco(rr, rpmlen, rpm)) { 341 syslog(LOG_WARNING, "<%s> invalid PCO", __func__); 342 goto next; 343 } 344 345 next: 346 cp += rpmlen; 347 len -= rpmlen; 348 } 349 350 return (0); 351 } 352 353 /* 354 * check validity of a router renumbering command packet 355 * return 0 on success, 1 on failure 356 */ 357 static int 358 rr_command_check(int len, struct icmp6_router_renum *rr, struct in6_addr *from, 359 struct in6_addr *dst) 360 { 361 u_char ntopbuf[INET6_ADDRSTRLEN]; 362 363 /* omit rr minimal length check. hope kernel have done it. */ 364 /* rr_command length check */ 365 if ((size_t)len < (sizeof(struct icmp6_router_renum) + 366 sizeof(struct rr_pco_match))) { 367 syslog(LOG_ERR, "<%s> rr_command len %d is too short", 368 __func__, len); 369 return (1); 370 } 371 372 /* destination check. only for multicast. omit unicast check. */ 373 if (IN6_IS_ADDR_MULTICAST(dst) && !IN6_IS_ADDR_MC_LINKLOCAL(dst) && 374 !IN6_IS_ADDR_MC_SITELOCAL(dst)) { 375 syslog(LOG_ERR, "<%s> dst mcast addr %s is illegal", 376 __func__, 377 inet_ntop(AF_INET6, dst, ntopbuf, sizeof(ntopbuf))); 378 return (1); 379 } 380 381 /* seqnum and segnum check */ 382 if (rro.rro_seqnum > rr->rr_seqnum) { 383 syslog(LOG_WARNING, 384 "<%s> rcvd old seqnum %d from %s", 385 __func__, (u_int32_t)ntohl(rr->rr_seqnum), 386 inet_ntop(AF_INET6, from, ntopbuf, sizeof(ntopbuf))); 387 return (1); 388 } 389 if (rro.rro_seqnum == rr->rr_seqnum && 390 (rr->rr_flags & ICMP6_RR_FLAGS_TEST) == 0 && 391 RR_ISSET_SEGNUM(rro.rro_segnum_bits, rr->rr_segnum)) { 392 if ((rr->rr_flags & ICMP6_RR_FLAGS_REQRESULT) != 0) 393 syslog(LOG_WARNING, 394 "<%s> rcvd duped segnum %d from %s", 395 __func__, rr->rr_segnum, inet_ntop(AF_INET6, from, 396 ntopbuf, sizeof(ntopbuf))); 397 return (0); 398 } 399 400 /* update seqnum */ 401 if (rro.rro_seqnum != rr->rr_seqnum) { 402 /* then must be "<" */ 403 404 /* init rro_segnum_bits */ 405 memset(rro.rro_segnum_bits, 0, 406 sizeof(rro.rro_segnum_bits)); 407 } 408 rro.rro_seqnum = rr->rr_seqnum; 409 410 return (0); 411 } 412 413 static void 414 rr_command_input(int len, struct icmp6_router_renum *rr, 415 struct in6_addr *from, struct in6_addr *dst) 416 { 417 /* rr_command validity check */ 418 if (rr_command_check(len, rr, from, dst)) 419 goto failed; 420 if ((rr->rr_flags & (ICMP6_RR_FLAGS_TEST|ICMP6_RR_FLAGS_REQRESULT)) == 421 ICMP6_RR_FLAGS_TEST) 422 return; 423 424 /* do router renumbering */ 425 if (do_rr(len, rr)) 426 goto failed; 427 428 /* update segnum */ 429 RR_SET_SEGNUM(rro.rro_segnum_bits, rr->rr_segnum); 430 431 return; 432 433 failed: 434 syslog(LOG_ERR, "<%s> received RR was invalid", __func__); 435 return; 436 } 437 438 void 439 rr_input(int len, struct icmp6_router_renum *rr, struct in6_pktinfo *pi, 440 struct sockaddr_in6 *from, struct in6_addr *dst) 441 { 442 u_char ntopbuf[2][INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ]; 443 444 syslog(LOG_DEBUG, 445 "<%s> RR received from %s to %s on %s", 446 __func__, 447 inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf[0] ,sizeof(ntopbuf[0])), 448 inet_ntop(AF_INET6, &dst, ntopbuf[1], sizeof(ntopbuf[1])), 449 if_indextoname(pi->ipi6_ifindex, ifnamebuf)); 450 451 /* packet validation based on Section 4.1 of RFC2894 */ 452 if ((size_t)len < sizeof(struct icmp6_router_renum)) { 453 syslog(LOG_NOTICE, 454 "<%s>: RR short message (size %d) from %s to %s on %s", 455 __func__, len, 456 inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf[0], 457 sizeof(ntopbuf[0])), 458 inet_ntop(AF_INET6, &dst, ntopbuf[1], sizeof(ntopbuf[1])), 459 if_indextoname(pi->ipi6_ifindex, ifnamebuf)); 460 return; 461 } 462 463 /* 464 * If the IPv6 destination address is neither an All Routers multicast 465 * address [AARCH] nor one of the receiving router's unicast addresses, 466 * the message MUST be discarded and SHOULD be logged to network 467 * management. 468 * We rely on the kernel input routine for unicast addresses, and thus 469 * check multicast destinations only. 470 */ 471 if (IN6_IS_ADDR_MULTICAST(&pi->ipi6_addr) && !IN6_ARE_ADDR_EQUAL( 472 &sin6_sitelocal_allrouters.sin6_addr, &pi->ipi6_addr)) { 473 syslog(LOG_NOTICE, 474 "<%s>: RR message with invalid destination (%s) " 475 "from %s on %s", 476 __func__, 477 inet_ntop(AF_INET6, &dst, ntopbuf[0], sizeof(ntopbuf[0])), 478 inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf[1], 479 sizeof(ntopbuf[1])), 480 if_indextoname(pi->ipi6_ifindex, ifnamebuf)); 481 return; 482 } 483 484 rr_rcvifindex = pi->ipi6_ifindex; 485 486 switch (rr->rr_code) { 487 case ICMP6_ROUTER_RENUMBERING_COMMAND: 488 rr_command_input(len, rr, &from->sin6_addr, dst); 489 /* TODO: send reply msg */ 490 break; 491 case ICMP6_ROUTER_RENUMBERING_RESULT: 492 /* RESULT will be processed by rrenumd */ 493 break; 494 case ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET: 495 /* TODO: sequence number reset */ 496 break; 497 default: 498 syslog(LOG_ERR, "<%s> received unknown code %d", 499 __func__, rr->rr_code); 500 break; 501 502 } 503 504 return; 505 } 506