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