1 /*- 2 * SPDX-License-Identifier: BSD-3-Clause 3 * 4 * Copyright (C) 2000 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 * $KAME: scope6.c,v 1.10 2000/07/24 13:29:31 itojun Exp $ 32 */ 33 34 #include <sys/cdefs.h> 35 __FBSDID("$FreeBSD$"); 36 37 #include <sys/param.h> 38 #include <sys/malloc.h> 39 #include <sys/mbuf.h> 40 #include <sys/socket.h> 41 #include <sys/sockio.h> 42 #include <sys/systm.h> 43 #include <sys/queue.h> 44 #include <sys/sysctl.h> 45 #include <sys/syslog.h> 46 47 #include <net/if.h> 48 #include <net/if_var.h> 49 #include <net/vnet.h> 50 51 #include <netinet/in.h> 52 53 #include <netinet/ip6.h> 54 #include <netinet6/in6_var.h> 55 #include <netinet6/ip6_var.h> 56 #include <netinet6/scope6_var.h> 57 58 #ifdef ENABLE_DEFAULT_SCOPE 59 VNET_DEFINE(int, ip6_use_defzone) = 1; 60 #else 61 VNET_DEFINE(int, ip6_use_defzone) = 0; 62 #endif 63 VNET_DEFINE(int, deembed_scopeid) = 1; 64 SYSCTL_DECL(_net_inet6_ip6); 65 SYSCTL_INT(_net_inet6_ip6, OID_AUTO, deembed_scopeid, CTLFLAG_VNET | CTLFLAG_RW, 66 &VNET_NAME(deembed_scopeid), 0, 67 "Extract embedded zone ID and set it to sin6_scope_id in sockaddr_in6."); 68 69 /* 70 * The scope6_lock protects the global sid default stored in 71 * sid_default below. 72 */ 73 static struct mtx scope6_lock; 74 #define SCOPE6_LOCK_INIT() mtx_init(&scope6_lock, "scope6_lock", NULL, MTX_DEF) 75 #define SCOPE6_LOCK() mtx_lock(&scope6_lock) 76 #define SCOPE6_UNLOCK() mtx_unlock(&scope6_lock) 77 #define SCOPE6_LOCK_ASSERT() mtx_assert(&scope6_lock, MA_OWNED) 78 79 static VNET_DEFINE(struct scope6_id, sid_default); 80 #define V_sid_default VNET(sid_default) 81 82 #define SID(ifp) \ 83 (((struct in6_ifextra *)(ifp)->if_afdata[AF_INET6])->scope6_id) 84 85 static int scope6_get(struct ifnet *, struct scope6_id *); 86 static int scope6_set(struct ifnet *, struct scope6_id *); 87 88 void 89 scope6_init(void) 90 { 91 92 bzero(&V_sid_default, sizeof(V_sid_default)); 93 94 if (!IS_DEFAULT_VNET(curvnet)) 95 return; 96 97 SCOPE6_LOCK_INIT(); 98 } 99 100 struct scope6_id * 101 scope6_ifattach(struct ifnet *ifp) 102 { 103 struct scope6_id *sid; 104 105 sid = malloc(sizeof(*sid), M_IFADDR, M_WAITOK | M_ZERO); 106 /* 107 * XXX: IPV6_ADDR_SCOPE_xxx macros are not standard. 108 * Should we rather hardcode here? 109 */ 110 sid->s6id_list[IPV6_ADDR_SCOPE_INTFACELOCAL] = ifp->if_index; 111 sid->s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL] = ifp->if_index; 112 return (sid); 113 } 114 115 void 116 scope6_ifdetach(struct scope6_id *sid) 117 { 118 119 free(sid, M_IFADDR); 120 } 121 122 int 123 scope6_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp) 124 { 125 struct in6_ifreq *ifr; 126 127 if (ifp->if_afdata[AF_INET6] == NULL) 128 return (EPFNOSUPPORT); 129 130 ifr = (struct in6_ifreq *)data; 131 switch (cmd) { 132 case SIOCSSCOPE6: 133 return (scope6_set(ifp, 134 (struct scope6_id *)ifr->ifr_ifru.ifru_scope_id)); 135 case SIOCGSCOPE6: 136 return (scope6_get(ifp, 137 (struct scope6_id *)ifr->ifr_ifru.ifru_scope_id)); 138 case SIOCGSCOPE6DEF: 139 return (scope6_get_default( 140 (struct scope6_id *)ifr->ifr_ifru.ifru_scope_id)); 141 default: 142 return (EOPNOTSUPP); 143 } 144 } 145 146 static int 147 scope6_set(struct ifnet *ifp, struct scope6_id *idlist) 148 { 149 int i; 150 int error = 0; 151 struct scope6_id *sid = NULL; 152 153 IF_AFDATA_WLOCK(ifp); 154 sid = SID(ifp); 155 156 if (!sid) { /* paranoid? */ 157 IF_AFDATA_WUNLOCK(ifp); 158 return (EINVAL); 159 } 160 161 /* 162 * XXX: We need more consistency checks of the relationship among 163 * scopes (e.g. an organization should be larger than a site). 164 */ 165 166 /* 167 * TODO(XXX): after setting, we should reflect the changes to 168 * interface addresses, routing table entries, PCB entries... 169 */ 170 171 for (i = 0; i < 16; i++) { 172 if (idlist->s6id_list[i] && 173 idlist->s6id_list[i] != sid->s6id_list[i]) { 174 /* 175 * An interface zone ID must be the corresponding 176 * interface index by definition. 177 */ 178 if (i == IPV6_ADDR_SCOPE_INTFACELOCAL && 179 idlist->s6id_list[i] != ifp->if_index) { 180 IF_AFDATA_WUNLOCK(ifp); 181 return (EINVAL); 182 } 183 184 if (i == IPV6_ADDR_SCOPE_LINKLOCAL && 185 idlist->s6id_list[i] > V_if_index) { 186 /* 187 * XXX: theoretically, there should be no 188 * relationship between link IDs and interface 189 * IDs, but we check the consistency for 190 * safety in later use. 191 */ 192 IF_AFDATA_WUNLOCK(ifp); 193 return (EINVAL); 194 } 195 196 /* 197 * XXX: we must need lots of work in this case, 198 * but we simply set the new value in this initial 199 * implementation. 200 */ 201 sid->s6id_list[i] = idlist->s6id_list[i]; 202 } 203 } 204 IF_AFDATA_WUNLOCK(ifp); 205 206 return (error); 207 } 208 209 static int 210 scope6_get(struct ifnet *ifp, struct scope6_id *idlist) 211 { 212 struct scope6_id *sid; 213 214 /* We only need to lock the interface's afdata for SID() to work. */ 215 IF_AFDATA_RLOCK(ifp); 216 sid = SID(ifp); 217 if (sid == NULL) { /* paranoid? */ 218 IF_AFDATA_RUNLOCK(ifp); 219 return (EINVAL); 220 } 221 222 *idlist = *sid; 223 224 IF_AFDATA_RUNLOCK(ifp); 225 return (0); 226 } 227 228 /* 229 * Get a scope of the address. Node-local, link-local, site-local or global. 230 */ 231 int 232 in6_addrscope(const struct in6_addr *addr) 233 { 234 235 if (IN6_IS_ADDR_MULTICAST(addr)) { 236 /* 237 * Addresses with reserved value F must be treated as 238 * global multicast addresses. 239 */ 240 if (IPV6_ADDR_MC_SCOPE(addr) == 0x0f) 241 return (IPV6_ADDR_SCOPE_GLOBAL); 242 return (IPV6_ADDR_MC_SCOPE(addr)); 243 } 244 if (IN6_IS_ADDR_LINKLOCAL(addr) || 245 IN6_IS_ADDR_LOOPBACK(addr)) 246 return (IPV6_ADDR_SCOPE_LINKLOCAL); 247 if (IN6_IS_ADDR_SITELOCAL(addr)) 248 return (IPV6_ADDR_SCOPE_SITELOCAL); 249 return (IPV6_ADDR_SCOPE_GLOBAL); 250 } 251 252 /* 253 * ifp - note that this might be NULL 254 */ 255 256 void 257 scope6_setdefault(struct ifnet *ifp) 258 { 259 260 /* 261 * Currently, this function just sets the default "interfaces" 262 * and "links" according to the given interface. 263 * We might eventually have to separate the notion of "link" from 264 * "interface" and provide a user interface to set the default. 265 */ 266 SCOPE6_LOCK(); 267 if (ifp) { 268 V_sid_default.s6id_list[IPV6_ADDR_SCOPE_INTFACELOCAL] = 269 ifp->if_index; 270 V_sid_default.s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL] = 271 ifp->if_index; 272 } else { 273 V_sid_default.s6id_list[IPV6_ADDR_SCOPE_INTFACELOCAL] = 0; 274 V_sid_default.s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL] = 0; 275 } 276 SCOPE6_UNLOCK(); 277 } 278 279 int 280 scope6_get_default(struct scope6_id *idlist) 281 { 282 283 SCOPE6_LOCK(); 284 *idlist = V_sid_default; 285 SCOPE6_UNLOCK(); 286 287 return (0); 288 } 289 290 u_int32_t 291 scope6_addr2default(struct in6_addr *addr) 292 { 293 u_int32_t id; 294 295 /* 296 * special case: The loopback address should be considered as 297 * link-local, but there's no ambiguity in the syntax. 298 */ 299 if (IN6_IS_ADDR_LOOPBACK(addr)) 300 return (0); 301 302 /* 303 * XXX: 32-bit read is atomic on all our platforms, is it OK 304 * not to lock here? 305 */ 306 SCOPE6_LOCK(); 307 id = V_sid_default.s6id_list[in6_addrscope(addr)]; 308 SCOPE6_UNLOCK(); 309 return (id); 310 } 311 312 /* 313 * Validate the specified scope zone ID in the sin6_scope_id field. If the ID 314 * is unspecified (=0), needs to be specified, and the default zone ID can be 315 * used, the default value will be used. 316 * This routine then generates the kernel-internal form: if the address scope 317 * of is interface-local or link-local, embed the interface index in the 318 * address. 319 */ 320 int 321 sa6_embedscope(struct sockaddr_in6 *sin6, int defaultok) 322 { 323 u_int32_t zoneid; 324 325 if ((zoneid = sin6->sin6_scope_id) == 0 && defaultok) 326 zoneid = scope6_addr2default(&sin6->sin6_addr); 327 328 if (zoneid != 0 && 329 (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr) || 330 IN6_IS_ADDR_MC_INTFACELOCAL(&sin6->sin6_addr))) { 331 /* 332 * At this moment, we only check interface-local and 333 * link-local scope IDs, and use interface indices as the 334 * zone IDs assuming a one-to-one mapping between interfaces 335 * and links. 336 */ 337 if (V_if_index < zoneid || ifnet_byindex(zoneid) == NULL) 338 return (ENXIO); 339 340 /* XXX assignment to 16bit from 32bit variable */ 341 sin6->sin6_addr.s6_addr16[1] = htons(zoneid & 0xffff); 342 sin6->sin6_scope_id = 0; 343 } 344 345 return 0; 346 } 347 348 /* 349 * generate standard sockaddr_in6 from embedded form. 350 */ 351 int 352 sa6_recoverscope(struct sockaddr_in6 *sin6) 353 { 354 char ip6buf[INET6_ADDRSTRLEN]; 355 u_int32_t zoneid; 356 357 if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr) || 358 IN6_IS_ADDR_MC_INTFACELOCAL(&sin6->sin6_addr)) { 359 /* 360 * KAME assumption: link id == interface id 361 */ 362 zoneid = ntohs(sin6->sin6_addr.s6_addr16[1]); 363 if (zoneid) { 364 /* sanity check */ 365 if (V_if_index < zoneid) 366 return (ENXIO); 367 #if 0 368 /* XXX: Disabled due to possible deadlock. */ 369 if (!ifnet_byindex(zoneid)) 370 return (ENXIO); 371 #endif 372 if (sin6->sin6_scope_id != 0 && 373 zoneid != sin6->sin6_scope_id) { 374 log(LOG_NOTICE, 375 "%s: embedded scope mismatch: %s%%%d. " 376 "sin6_scope_id was overridden\n", __func__, 377 ip6_sprintf(ip6buf, &sin6->sin6_addr), 378 sin6->sin6_scope_id); 379 } 380 sin6->sin6_addr.s6_addr16[1] = 0; 381 sin6->sin6_scope_id = zoneid; 382 } 383 } 384 385 return 0; 386 } 387 388 /* 389 * Determine the appropriate scope zone ID for in6 and ifp. If ret_id is 390 * non NULL, it is set to the zone ID. If the zone ID needs to be embedded 391 * in the in6_addr structure, in6 will be modified. 392 * 393 * ret_id - unnecessary? 394 */ 395 int 396 in6_setscope(struct in6_addr *in6, struct ifnet *ifp, u_int32_t *ret_id) 397 { 398 int scope; 399 u_int32_t zoneid = 0; 400 struct scope6_id *sid; 401 402 /* 403 * special case: the loopback address can only belong to a loopback 404 * interface. 405 */ 406 if (IN6_IS_ADDR_LOOPBACK(in6)) { 407 if (!(ifp->if_flags & IFF_LOOPBACK)) 408 return (EINVAL); 409 } else { 410 scope = in6_addrscope(in6); 411 if (scope == IPV6_ADDR_SCOPE_INTFACELOCAL || 412 scope == IPV6_ADDR_SCOPE_LINKLOCAL) { 413 /* 414 * Currently we use interface indices as the 415 * zone IDs for interface-local and link-local 416 * scopes. 417 */ 418 zoneid = ifp->if_index; 419 in6->s6_addr16[1] = htons(zoneid & 0xffff); /* XXX */ 420 } else if (scope != IPV6_ADDR_SCOPE_GLOBAL) { 421 IF_AFDATA_RLOCK(ifp); 422 sid = SID(ifp); 423 zoneid = sid->s6id_list[scope]; 424 IF_AFDATA_RUNLOCK(ifp); 425 } 426 } 427 428 if (ret_id != NULL) 429 *ret_id = zoneid; 430 431 return (0); 432 } 433 434 /* 435 * Just clear the embedded scope identifier. Return 0 if the original address 436 * is intact; return non 0 if the address is modified. 437 */ 438 int 439 in6_clearscope(struct in6_addr *in6) 440 { 441 int modified = 0; 442 443 if (IN6_IS_SCOPE_LINKLOCAL(in6) || IN6_IS_ADDR_MC_INTFACELOCAL(in6)) { 444 if (in6->s6_addr16[1] != 0) 445 modified = 1; 446 in6->s6_addr16[1] = 0; 447 } 448 449 return (modified); 450 } 451 452 /* 453 * Return the scope identifier or zero. 454 */ 455 uint16_t 456 in6_getscope(struct in6_addr *in6) 457 { 458 459 if (IN6_IS_SCOPE_LINKLOCAL(in6) || IN6_IS_ADDR_MC_INTFACELOCAL(in6)) 460 return (in6->s6_addr16[1]); 461 462 return (0); 463 } 464 465 /* 466 * Return pointer to ifnet structure, corresponding to the zone id of 467 * link-local scope. 468 */ 469 struct ifnet* 470 in6_getlinkifnet(uint32_t zoneid) 471 { 472 473 return (ifnet_byindex((u_short)zoneid)); 474 } 475 476 /* 477 * Return zone id for the specified scope. 478 */ 479 uint32_t 480 in6_getscopezone(const struct ifnet *ifp, int scope) 481 { 482 483 if (scope == IPV6_ADDR_SCOPE_INTFACELOCAL || 484 scope == IPV6_ADDR_SCOPE_LINKLOCAL) 485 return (ifp->if_index); 486 if (scope >= 0 && scope < IPV6_ADDR_SCOPES_COUNT) 487 return (SID(ifp)->s6id_list[scope]); 488 return (0); 489 } 490 491 /* 492 * Extracts scope from adddress @dst, stores cleared address 493 * inside @dst and zone inside @scopeid 494 */ 495 void 496 in6_splitscope(const struct in6_addr *src, struct in6_addr *dst, 497 uint32_t *scopeid) 498 { 499 uint32_t zoneid; 500 501 *dst = *src; 502 zoneid = ntohs(in6_getscope(dst)); 503 in6_clearscope(dst); 504 *scopeid = zoneid; 505 } 506 507 /* 508 * This function is for checking sockaddr_in6 structure passed 509 * from the application level (usually). 510 * 511 * sin6_scope_id should be set for link-local unicast, link-local and 512 * interface-local multicast addresses. 513 * 514 * If it is zero, then look into default zone ids. If default zone id is 515 * not set or disabled, then return error. 516 */ 517 int 518 sa6_checkzone(struct sockaddr_in6 *sa6) 519 { 520 int scope; 521 522 scope = in6_addrscope(&sa6->sin6_addr); 523 if (scope == IPV6_ADDR_SCOPE_GLOBAL) 524 return (sa6->sin6_scope_id ? EINVAL: 0); 525 if (IN6_IS_ADDR_MULTICAST(&sa6->sin6_addr) && 526 scope != IPV6_ADDR_SCOPE_LINKLOCAL && 527 scope != IPV6_ADDR_SCOPE_INTFACELOCAL) { 528 if (sa6->sin6_scope_id == 0 && V_ip6_use_defzone != 0) 529 sa6->sin6_scope_id = V_sid_default.s6id_list[scope]; 530 return (0); 531 } 532 /* 533 * Since ::1 address always configured on the lo0, we can 534 * automatically set its zone id, when it is not specified. 535 * Return error, when specified zone id doesn't match with 536 * actual value. 537 */ 538 if (IN6_IS_ADDR_LOOPBACK(&sa6->sin6_addr)) { 539 if (sa6->sin6_scope_id == 0) 540 sa6->sin6_scope_id = in6_getscopezone(V_loif, scope); 541 else if (sa6->sin6_scope_id != in6_getscopezone(V_loif, scope)) 542 return (EADDRNOTAVAIL); 543 } 544 /* XXX: we can validate sin6_scope_id here */ 545 if (sa6->sin6_scope_id != 0) 546 return (0); 547 if (V_ip6_use_defzone != 0) 548 sa6->sin6_scope_id = V_sid_default.s6id_list[scope]; 549 /* Return error if we can't determine zone id */ 550 return (sa6->sin6_scope_id ? 0: EADDRNOTAVAIL); 551 } 552 553 /* 554 * This function is similar to sa6_checkzone, but it uses given ifp 555 * to initialize sin6_scope_id. 556 */ 557 int 558 sa6_checkzone_ifp(struct ifnet *ifp, struct sockaddr_in6 *sa6) 559 { 560 int scope; 561 562 scope = in6_addrscope(&sa6->sin6_addr); 563 if (scope == IPV6_ADDR_SCOPE_LINKLOCAL || 564 scope == IPV6_ADDR_SCOPE_INTFACELOCAL) { 565 if (sa6->sin6_scope_id == 0) { 566 sa6->sin6_scope_id = in6_getscopezone(ifp, scope); 567 return (0); 568 } else if (sa6->sin6_scope_id != in6_getscopezone(ifp, scope)) 569 return (EADDRNOTAVAIL); 570 } 571 return (sa6_checkzone(sa6)); 572 } 573 574 575