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