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