1 /* $KAME: rrenum.c,v 1.3 2000/05/16 13:34:14 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$ 32 */ 33 34 #include <sys/param.h> 35 #include <sys/ioctl.h> 36 #include <sys/socket.h> 37 #include <sys/sysctl.h> 38 39 #include <net/if.h> 40 #if defined(__FreeBSD__) && __FreeBSD__ >= 3 41 #include <net/if_var.h> 42 #endif /* __FreeBSD__ >= 3 */ 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 <string.h> 52 #include <stdlib.h> 53 #include <syslog.h> 54 #include "rrenum.h" 55 #include "if.h" 56 57 #define RR_ISSET_SEGNUM(segnum_bits, segnum) \ 58 ((((segnum_bits)[(segnum) >> 5]) & (1 << ((segnum) & 31))) != 0) 59 #define RR_SET_SEGNUM(segnum_bits, segnum) \ 60 (((segnum_bits)[(segnum) >> 5]) |= (1 << ((segnum) & 31))) 61 62 struct rr_operation { 63 u_long rro_seqnum; 64 u_long rro_segnum_bits[8]; 65 }; 66 67 static struct rr_operation rro; 68 static int rr_rcvifindex; 69 static int rrcmd2pco[RPM_PCO_MAX] = { 70 0, 71 SIOCAIFPREFIX_IN6, 72 SIOCCIFPREFIX_IN6, 73 SIOCSGIFPREFIX_IN6 74 }; 75 static int s = -1; 76 77 /* 78 * Check validity of a Prefix Control Operation(PCO). 79 * Return 0 on success, 1 on failure. 80 */ 81 static int 82 rr_pco_check(int len, struct rr_pco_match *rpm) 83 { 84 struct rr_pco_use *rpu, *rpulim; 85 int checklen; 86 87 /* rpm->rpm_len must be (4N * 3) as router-renum-05.txt */ 88 if ((rpm->rpm_len - 3) < 0 || /* must be at least 3 */ 89 (rpm->rpm_len - 3) & 0x3) { /* must be multiple of 4 */ 90 syslog(LOG_WARNING, "<%s> rpm_len %d is not 4N * 3", 91 __FUNCTION__, rpm->rpm_len); 92 return 1; 93 } 94 /* rpm->rpm_code must be valid value */ 95 switch(rpm->rpm_code) { 96 case RPM_PCO_ADD: 97 case RPM_PCO_CHANGE: 98 case RPM_PCO_SETGLOBAL: 99 break; 100 default: 101 syslog(LOG_WARNING, "<%s> unknown rpm_code %d", __FUNCTION__, 102 rpm->rpm_code); 103 return 1; 104 } 105 /* rpm->rpm_matchlen must be 0 to 128 inclusive */ 106 if (rpm->rpm_matchlen > 128) { 107 syslog(LOG_WARNING, "<%s> rpm_matchlen %d is over 128", 108 __FUNCTION__, rpm->rpm_matchlen); 109 return 1; 110 } 111 112 /* 113 * rpu->rpu_uselen, rpu->rpu_keeplen, and sum of them must be 114 * between 0 and 128 inclusive 115 */ 116 for (rpu = (struct rr_pco_use *)(rpm + 1), 117 rpulim = (struct rr_pco_use *)((char *)rpm + len); 118 rpu < rpulim; 119 rpu += 1) { 120 checklen = rpu->rpu_uselen; 121 checklen += rpu->rpu_keeplen; 122 /* 123 * omit these check, because either of rpu_uselen 124 * and rpu_keeplen is unsigned char 125 * (128 > rpu_uselen > 0) 126 * (128 > rpu_keeplen > 0) 127 * (rpu_uselen + rpu_keeplen > 0) 128 */ 129 if (checklen > 128) { 130 syslog(LOG_WARNING, "<%s> sum of rpu_uselen %d and" 131 " rpu_keeplen %d is %d(over 128)", 132 __FUNCTION__, rpu->rpu_uselen, 133 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, struct in6_rrenumreq *irr) { 143 struct rr_pco_use *rpu, *rpulim; 144 145 rpu = (struct rr_pco_use *)(rpm + 1); 146 rpulim = (struct rr_pco_use *)((char *)rpm + len); 147 148 if (rpu == rpulim) { 149 if (rpm->rpm_code == RPM_PCO_ADD) 150 return; 151 152 irr->irr_u_uselen = 0; 153 irr->irr_u_keeplen = 0; 154 irr->irr_raf_mask_onlink = 0; 155 irr->irr_raf_mask_auto = 0; 156 irr->irr_vltime = 0; 157 irr->irr_pltime = 0; 158 memset(&irr->irr_flags, 0, sizeof(irr->irr_flags)); 159 irr->irr_useprefix.sin6_len = 0; /* let it mean, no addition */ 160 irr->irr_useprefix.sin6_family = 0; 161 irr->irr_useprefix.sin6_addr = in6addr_any; 162 if (ioctl(s, rrcmd2pco[rpm->rpm_code], (caddr_t)irr) < 0 && 163 errno != EADDRNOTAVAIL) 164 syslog(LOG_ERR, "<%s> ioctl: %s", __FUNCTION__, 165 strerror(errno)); 166 return; 167 } 168 169 for (rpu = (struct rr_pco_use *)(rpm + 1), 170 rpulim = (struct rr_pco_use *)((char *)rpm + len); 171 rpu < rpulim; 172 rpu += 1) { 173 /* init in6_rrenumreq fields */ 174 irr->irr_u_uselen = rpu->rpu_uselen; 175 irr->irr_u_keeplen = rpu->rpu_keeplen; 176 irr->irr_raf_mask_onlink = 177 (rpu->rpu_ramask & ICMP6_RR_PCOUSE_RAFLAGS_ONLINK); 178 irr->irr_raf_mask_auto = 179 (rpu->rpu_ramask & ICMP6_RR_PCOUSE_RAFLAGS_AUTO); 180 irr->irr_vltime = rpu->rpu_vltime; 181 irr->irr_pltime = rpu->rpu_pltime; 182 irr->irr_raf_onlink = 183 (rpu->rpu_raflags & ICMP6_RR_PCOUSE_RAFLAGS_ONLINK); 184 irr->irr_raf_auto = 185 (rpu->rpu_raflags & ICMP6_RR_PCOUSE_RAFLAGS_AUTO); 186 irr->irr_rrf_decrvalid = 187 (rpu->rpu_flags & ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME); 188 irr->irr_rrf_decrprefd = 189 (rpu->rpu_flags & ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME); 190 irr->irr_useprefix.sin6_len = sizeof(irr->irr_useprefix); 191 irr->irr_useprefix.sin6_family = AF_INET6; 192 irr->irr_useprefix.sin6_addr = rpu->rpu_prefix; 193 194 if (ioctl(s, rrcmd2pco[rpm->rpm_code], (caddr_t)irr) < 0 && 195 errno != EADDRNOTAVAIL) 196 syslog(LOG_ERR, "<%s> ioctl: %s", __FUNCTION__, 197 strerror(errno)); 198 } 199 } 200 201 /* 202 * process a Prefix Control Operation(PCO). 203 * return 0 on success, 1 on failure 204 */ 205 static int 206 do_pco(struct icmp6_router_renum *rr, int len, struct rr_pco_match *rpm) 207 { 208 int ifindex = 0; 209 struct in6_rrenumreq irr; 210 211 if ((rr_pco_check(len, rpm) != NULL)) 212 return 1; 213 214 if (s == -1 && (s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 215 syslog(LOG_ERR, "<%s> socket: %s", __FUNCTION__, 216 strerror(errno)); 217 exit(1); 218 } 219 220 memset(&irr, 0, sizeof(irr)); 221 irr.irr_origin = PR_ORIG_RR; 222 irr.irr_m_len = rpm->rpm_matchlen; 223 irr.irr_m_minlen = rpm->rpm_minlen; 224 irr.irr_m_maxlen = rpm->rpm_maxlen; 225 irr.irr_matchprefix.sin6_len = sizeof(irr.irr_matchprefix); 226 irr.irr_matchprefix.sin6_family = AF_INET6; 227 irr.irr_matchprefix.sin6_addr = rpm->rpm_prefix; 228 229 while (if_indextoname(++ifindex, irr.irr_name)) { 230 /* 231 * if ICMP6_RR_FLAGS_FORCEAPPLY(A flag) is 0 and IFF_UP is off, 232 * the interface is not applied 233 */ 234 if ((rr->rr_flags & ICMP6_RR_FLAGS_FORCEAPPLY) == 0 && 235 (iflist[ifindex]->ifm_flags & IFF_UP) == 0) 236 continue; 237 /* TODO: interface scope check */ 238 do_use_prefix(len, rpm, &irr); 239 } 240 if (errno == ENXIO) 241 return 0; 242 else if (errno) { 243 syslog(LOG_ERR, "<%s> if_indextoname: %s", __FUNCTION__, 244 strerror(errno)); 245 return 1; 246 } 247 return 0; 248 } 249 250 /* 251 * call do_pco() for each Prefix Control Operations(PCOs) in a received 252 * Router Renumbering Command packet. 253 * return 0 on success, 1 on failure 254 */ 255 static int 256 do_rr(int len, struct icmp6_router_renum *rr) 257 { 258 struct rr_pco_match *rpm; 259 char *cp, *lim; 260 261 lim = (char *)rr + len; 262 cp = (char *)(rr + 1); 263 len -= sizeof(struct icmp6_router_renum); 264 265 /* get iflist block from kernel again, to get up-to-date information */ 266 init_iflist(); 267 268 while (cp < lim) { 269 int rpmlen; 270 271 rpm = (struct rr_pco_match *)cp; 272 if (len < sizeof(struct rr_pco_match)) { 273 tooshort: 274 syslog(LOG_ERR, "<%s> pkt too short. left len = %d. " 275 "gabage at end of pkt?", __FUNCTION__, len); 276 return 1; 277 } 278 rpmlen = rpm->rpm_len << 3; 279 if (len < rpmlen) 280 goto tooshort; 281 282 if (do_pco(rr, rpmlen, rpm)) { 283 syslog(LOG_WARNING, "<%s> invalid PCO", __FUNCTION__); 284 goto next; 285 } 286 287 next: 288 cp += rpmlen; 289 len -= rpmlen; 290 } 291 292 return 0; 293 } 294 295 /* 296 * check validity of a router renumbering command packet 297 * return 0 on success, 1 on failure 298 */ 299 static int 300 rr_command_check(int len, struct icmp6_router_renum *rr, struct in6_addr *from, 301 struct in6_addr *dst) 302 { 303 u_char ntopbuf[INET6_ADDRSTRLEN]; 304 305 /* omit rr minimal length check. hope kernel have done it. */ 306 /* rr_command length check */ 307 if (len < (sizeof(struct icmp6_router_renum) + 308 sizeof(struct rr_pco_match))) { 309 syslog(LOG_ERR, "<%s> rr_command len %d is too short", 310 __FUNCTION__, len); 311 return 1; 312 } 313 314 /* destination check. only for multicast. omit unicast check. */ 315 if (IN6_IS_ADDR_MULTICAST(dst) && !IN6_IS_ADDR_MC_LINKLOCAL(dst) && 316 !IN6_IS_ADDR_MC_SITELOCAL(dst)) { 317 syslog(LOG_ERR, "<%s> dst mcast addr %s is illegal", 318 __FUNCTION__, 319 inet_ntop(AF_INET6, dst, ntopbuf, INET6_ADDRSTRLEN)); 320 return 1; 321 } 322 323 /* seqnum and segnum check */ 324 if (rro.rro_seqnum > rr->rr_seqnum) { 325 syslog(LOG_WARNING, 326 "<%s> rcvd old seqnum %d from %s", 327 __FUNCTION__, (u_int32_t)ntohl(rr->rr_seqnum), 328 inet_ntop(AF_INET6, from, ntopbuf, INET6_ADDRSTRLEN)); 329 return 1; 330 } 331 if (rro.rro_seqnum == rr->rr_seqnum && 332 (rr->rr_flags & ICMP6_RR_FLAGS_TEST) == 0 && 333 RR_ISSET_SEGNUM(rro.rro_segnum_bits, rr->rr_segnum)) { 334 if ((rr->rr_flags & ICMP6_RR_FLAGS_REQRESULT) != 0) 335 syslog(LOG_WARNING, 336 "<%s> rcvd duped segnum %d from %s", 337 __FUNCTION__, rr->rr_segnum, 338 inet_ntop(AF_INET6, from, ntopbuf, 339 INET6_ADDRSTRLEN)); 340 return 0; 341 } 342 343 /* update seqnum */ 344 if (rro.rro_seqnum != rr->rr_seqnum) { 345 /* then must be "<" */ 346 347 /* init rro_segnum_bits */ 348 memset(rro.rro_segnum_bits, 0, 349 sizeof(rro.rro_segnum_bits)); 350 } 351 rro.rro_seqnum = rr->rr_seqnum; 352 353 return 0; 354 } 355 356 static void 357 rr_command_input(int len, struct icmp6_router_renum *rr, 358 struct in6_addr *from, struct in6_addr *dst) 359 { 360 /* rr_command validity check */ 361 if (rr_command_check(len, rr, from, dst)) 362 goto failed; 363 if ((rr->rr_flags & (ICMP6_RR_FLAGS_TEST|ICMP6_RR_FLAGS_REQRESULT)) == 364 ICMP6_RR_FLAGS_TEST) 365 return; 366 367 /* do router renumbering */ 368 if (do_rr(len, rr)) { 369 goto failed; 370 } 371 372 /* update segnum */ 373 RR_SET_SEGNUM(rro.rro_segnum_bits, rr->rr_segnum); 374 375 return; 376 377 failed: 378 syslog(LOG_ERR, "<%s> received RR was invalid", __FUNCTION__); 379 return; 380 } 381 382 void 383 rr_input(int len, struct icmp6_router_renum *rr, struct in6_pktinfo *pi, 384 struct sockaddr_in6 *from, struct in6_addr *dst) 385 { 386 u_char ntopbuf[2][INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ]; 387 388 syslog(LOG_DEBUG, 389 "<%s> RR received from %s to %s on %s", 390 __FUNCTION__, 391 inet_ntop(AF_INET6, &from->sin6_addr, 392 ntopbuf[0], INET6_ADDRSTRLEN), 393 inet_ntop(AF_INET6, &dst, ntopbuf[1], INET6_ADDRSTRLEN), 394 if_indextoname(pi->ipi6_ifindex, ifnamebuf)); 395 396 rr_rcvifindex = pi->ipi6_ifindex; 397 398 /* TODO: some consistency check. */ 399 400 switch (rr->rr_code) { 401 case ICMP6_ROUTER_RENUMBERING_COMMAND: 402 rr_command_input(len, rr, &from->sin6_addr, dst); 403 /* TODO: send reply msg */ 404 break; 405 case ICMP6_ROUTER_RENUMBERING_RESULT: 406 /* RESULT will be processed by rrenumd */ 407 break; 408 case ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET: 409 /* TODO: sequence number reset */ 410 break; 411 default: 412 syslog(LOG_ERR, "<%s> received unknown code %d", 413 __FUNCTION__, rr->rr_code); 414 break; 415 416 } 417 418 return; 419 } 420