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