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