1 1.13 christos /* $NetBSD: sockaddr.c,v 1.13 2025/01/26 16:25:38 christos Exp $ */ 2 1.1 christos 3 1.1 christos /* 4 1.1 christos * Copyright (C) Internet Systems Consortium, Inc. ("ISC") 5 1.1 christos * 6 1.10 christos * SPDX-License-Identifier: MPL-2.0 7 1.10 christos * 8 1.1 christos * This Source Code Form is subject to the terms of the Mozilla Public 9 1.1 christos * License, v. 2.0. If a copy of the MPL was not distributed with this 10 1.9 christos * file, you can obtain one at https://mozilla.org/MPL/2.0/. 11 1.1 christos * 12 1.1 christos * See the COPYRIGHT file distributed with this work for additional 13 1.1 christos * information regarding copyright ownership. 14 1.1 christos */ 15 1.1 christos 16 1.1 christos /*! \file */ 17 1.1 christos 18 1.13 christos #include <netdb.h> 19 1.3 christos #include <stdbool.h> 20 1.1 christos #include <stdio.h> 21 1.1 christos 22 1.1 christos #include <isc/buffer.h> 23 1.1 christos #include <isc/hash.h> 24 1.1 christos #include <isc/netaddr.h> 25 1.1 christos #include <isc/region.h> 26 1.1 christos #include <isc/sockaddr.h> 27 1.1 christos #include <isc/string.h> 28 1.1 christos #include <isc/util.h> 29 1.1 christos 30 1.3 christos bool 31 1.1 christos isc_sockaddr_equal(const isc_sockaddr_t *a, const isc_sockaddr_t *b) { 32 1.13 christos return isc_sockaddr_compare(a, b, 33 1.13 christos ISC_SOCKADDR_CMPADDR | 34 1.13 christos ISC_SOCKADDR_CMPPORT | 35 1.13 christos ISC_SOCKADDR_CMPSCOPE); 36 1.1 christos } 37 1.1 christos 38 1.3 christos bool 39 1.1 christos isc_sockaddr_eqaddr(const isc_sockaddr_t *a, const isc_sockaddr_t *b) { 40 1.13 christos return isc_sockaddr_compare( 41 1.13 christos a, b, ISC_SOCKADDR_CMPADDR | ISC_SOCKADDR_CMPSCOPE); 42 1.1 christos } 43 1.1 christos 44 1.3 christos bool 45 1.1 christos isc_sockaddr_compare(const isc_sockaddr_t *a, const isc_sockaddr_t *b, 46 1.8 christos unsigned int flags) { 47 1.1 christos REQUIRE(a != NULL && b != NULL); 48 1.1 christos 49 1.8 christos if (a->length != b->length) { 50 1.13 christos return false; 51 1.8 christos } 52 1.1 christos 53 1.1 christos /* 54 1.1 christos * We don't just memcmp because the sin_zero field isn't always 55 1.1 christos * zero. 56 1.1 christos */ 57 1.1 christos 58 1.8 christos if (a->type.sa.sa_family != b->type.sa.sa_family) { 59 1.13 christos return false; 60 1.8 christos } 61 1.1 christos switch (a->type.sa.sa_family) { 62 1.1 christos case AF_INET: 63 1.1 christos if ((flags & ISC_SOCKADDR_CMPADDR) != 0 && 64 1.1 christos memcmp(&a->type.sin.sin_addr, &b->type.sin.sin_addr, 65 1.1 christos sizeof(a->type.sin.sin_addr)) != 0) 66 1.8 christos { 67 1.13 christos return false; 68 1.8 christos } 69 1.1 christos if ((flags & ISC_SOCKADDR_CMPPORT) != 0 && 70 1.1 christos a->type.sin.sin_port != b->type.sin.sin_port) 71 1.8 christos { 72 1.13 christos return false; 73 1.8 christos } 74 1.1 christos break; 75 1.1 christos case AF_INET6: 76 1.1 christos if ((flags & ISC_SOCKADDR_CMPADDR) != 0 && 77 1.1 christos memcmp(&a->type.sin6.sin6_addr, &b->type.sin6.sin6_addr, 78 1.1 christos sizeof(a->type.sin6.sin6_addr)) != 0) 79 1.8 christos { 80 1.13 christos return false; 81 1.8 christos } 82 1.1 christos /* 83 1.1 christos * If ISC_SOCKADDR_CMPSCOPEZERO is set then don't return 84 1.3 christos * false if one of the scopes in zero. 85 1.1 christos */ 86 1.1 christos if ((flags & ISC_SOCKADDR_CMPSCOPE) != 0 && 87 1.1 christos a->type.sin6.sin6_scope_id != b->type.sin6.sin6_scope_id && 88 1.1 christos ((flags & ISC_SOCKADDR_CMPSCOPEZERO) == 0 || 89 1.8 christos (a->type.sin6.sin6_scope_id != 0 && 90 1.8 christos b->type.sin6.sin6_scope_id != 0))) 91 1.8 christos { 92 1.13 christos return false; 93 1.8 christos } 94 1.1 christos if ((flags & ISC_SOCKADDR_CMPPORT) != 0 && 95 1.1 christos a->type.sin6.sin6_port != b->type.sin6.sin6_port) 96 1.8 christos { 97 1.13 christos return false; 98 1.8 christos } 99 1.1 christos break; 100 1.1 christos default: 101 1.8 christos if (memcmp(&a->type, &b->type, a->length) != 0) { 102 1.13 christos return false; 103 1.8 christos } 104 1.1 christos } 105 1.13 christos return true; 106 1.1 christos } 107 1.1 christos 108 1.3 christos bool 109 1.1 christos isc_sockaddr_eqaddrprefix(const isc_sockaddr_t *a, const isc_sockaddr_t *b, 110 1.8 christos unsigned int prefixlen) { 111 1.1 christos isc_netaddr_t na, nb; 112 1.1 christos isc_netaddr_fromsockaddr(&na, a); 113 1.1 christos isc_netaddr_fromsockaddr(&nb, b); 114 1.13 christos return isc_netaddr_eqprefix(&na, &nb, prefixlen); 115 1.1 christos } 116 1.1 christos 117 1.1 christos isc_result_t 118 1.1 christos isc_sockaddr_totext(const isc_sockaddr_t *sockaddr, isc_buffer_t *target) { 119 1.1 christos isc_result_t result; 120 1.1 christos isc_netaddr_t netaddr; 121 1.1 christos char pbuf[sizeof("65000")]; 122 1.1 christos unsigned int plen; 123 1.1 christos isc_region_t avail; 124 1.1 christos 125 1.1 christos REQUIRE(sockaddr != NULL); 126 1.1 christos 127 1.1 christos /* 128 1.1 christos * Do the port first, giving us the opportunity to check for 129 1.1 christos * unsupported address families before calling 130 1.1 christos * isc_netaddr_fromsockaddr(). 131 1.1 christos */ 132 1.1 christos switch (sockaddr->type.sa.sa_family) { 133 1.1 christos case AF_INET: 134 1.8 christos snprintf(pbuf, sizeof(pbuf), "%u", 135 1.8 christos ntohs(sockaddr->type.sin.sin_port)); 136 1.1 christos break; 137 1.1 christos case AF_INET6: 138 1.8 christos snprintf(pbuf, sizeof(pbuf), "%u", 139 1.8 christos ntohs(sockaddr->type.sin6.sin6_port)); 140 1.1 christos break; 141 1.1 christos default: 142 1.13 christos return ISC_R_FAILURE; 143 1.1 christos } 144 1.1 christos 145 1.1 christos plen = strlen(pbuf); 146 1.1 christos INSIST(plen < sizeof(pbuf)); 147 1.1 christos 148 1.1 christos isc_netaddr_fromsockaddr(&netaddr, sockaddr); 149 1.1 christos result = isc_netaddr_totext(&netaddr, target); 150 1.8 christos if (result != ISC_R_SUCCESS) { 151 1.13 christos return result; 152 1.8 christos } 153 1.1 christos 154 1.8 christos if (1 + plen + 1 > isc_buffer_availablelength(target)) { 155 1.13 christos return ISC_R_NOSPACE; 156 1.8 christos } 157 1.1 christos 158 1.1 christos isc_buffer_putmem(target, (const unsigned char *)"#", 1); 159 1.1 christos isc_buffer_putmem(target, (const unsigned char *)pbuf, plen); 160 1.1 christos 161 1.1 christos /* 162 1.1 christos * Null terminate after used region. 163 1.1 christos */ 164 1.1 christos isc_buffer_availableregion(target, &avail); 165 1.1 christos INSIST(avail.length >= 1); 166 1.1 christos avail.base[0] = '\0'; 167 1.1 christos 168 1.13 christos return ISC_R_SUCCESS; 169 1.1 christos } 170 1.1 christos 171 1.1 christos void 172 1.1 christos isc_sockaddr_format(const isc_sockaddr_t *sa, char *array, unsigned int size) { 173 1.1 christos isc_result_t result; 174 1.1 christos isc_buffer_t buf; 175 1.1 christos 176 1.8 christos if (size == 0U) { 177 1.1 christos return; 178 1.8 christos } 179 1.1 christos 180 1.1 christos isc_buffer_init(&buf, array, size); 181 1.1 christos result = isc_sockaddr_totext(sa, &buf); 182 1.1 christos if (result != ISC_R_SUCCESS) { 183 1.1 christos /* 184 1.1 christos * The message is the same as in netaddr.c. 185 1.1 christos */ 186 1.8 christos snprintf(array, size, "<unknown address, family %u>", 187 1.1 christos sa->type.sa.sa_family); 188 1.1 christos array[size - 1] = '\0'; 189 1.1 christos } 190 1.1 christos } 191 1.1 christos 192 1.13 christos void 193 1.13 christos isc_sockaddr_hash_ex(isc_hash32_t *hash, const isc_sockaddr_t *sockaddr, 194 1.13 christos bool address_only) { 195 1.13 christos REQUIRE(sockaddr != NULL); 196 1.13 christos 197 1.13 christos size_t len = 0; 198 1.13 christos const uint8_t *s = NULL; 199 1.1 christos unsigned int p = 0; 200 1.1 christos const struct in6_addr *in6; 201 1.1 christos 202 1.1 christos switch (sockaddr->type.sa.sa_family) { 203 1.1 christos case AF_INET: 204 1.13 christos s = (const uint8_t *)&sockaddr->type.sin.sin_addr; 205 1.13 christos len = sizeof(sockaddr->type.sin.sin_addr.s_addr); 206 1.13 christos if (!address_only) { 207 1.13 christos p = ntohs(sockaddr->type.sin.sin_port); 208 1.13 christos } 209 1.1 christos break; 210 1.1 christos case AF_INET6: 211 1.1 christos in6 = &sockaddr->type.sin6.sin6_addr; 212 1.13 christos s = (const uint8_t *)in6; 213 1.1 christos if (IN6_IS_ADDR_V4MAPPED(in6)) { 214 1.1 christos s += 12; 215 1.13 christos len = sizeof(sockaddr->type.sin.sin_addr.s_addr); 216 1.8 christos } else { 217 1.13 christos len = sizeof(sockaddr->type.sin6.sin6_addr); 218 1.13 christos } 219 1.13 christos if (!address_only) { 220 1.13 christos p = ntohs(sockaddr->type.sin6.sin6_port); 221 1.8 christos } 222 1.1 christos break; 223 1.1 christos default: 224 1.13 christos UNREACHABLE(); 225 1.1 christos } 226 1.1 christos 227 1.13 christos isc_hash32_hash(hash, s, len, true); 228 1.5 christos if (!address_only) { 229 1.13 christos isc_hash32_hash(hash, &p, sizeof(p), true); 230 1.5 christos } 231 1.13 christos } 232 1.13 christos 233 1.13 christos uint32_t 234 1.13 christos isc_sockaddr_hash(const isc_sockaddr_t *sockaddr, bool address_only) { 235 1.13 christos isc_hash32_t hash; 236 1.13 christos 237 1.13 christos isc_hash32_init(&hash); 238 1.13 christos 239 1.13 christos isc_sockaddr_hash_ex(&hash, sockaddr, address_only); 240 1.1 christos 241 1.13 christos return isc_hash32_finalize(&hash); 242 1.1 christos } 243 1.1 christos 244 1.1 christos void 245 1.8 christos isc_sockaddr_any(isc_sockaddr_t *sockaddr) { 246 1.1 christos memset(sockaddr, 0, sizeof(*sockaddr)); 247 1.1 christos sockaddr->type.sin.sin_family = AF_INET; 248 1.1 christos sockaddr->type.sin.sin_addr.s_addr = INADDR_ANY; 249 1.1 christos sockaddr->type.sin.sin_port = 0; 250 1.1 christos sockaddr->length = sizeof(sockaddr->type.sin); 251 1.1 christos ISC_LINK_INIT(sockaddr, link); 252 1.1 christos } 253 1.1 christos 254 1.1 christos void 255 1.8 christos isc_sockaddr_any6(isc_sockaddr_t *sockaddr) { 256 1.1 christos memset(sockaddr, 0, sizeof(*sockaddr)); 257 1.1 christos sockaddr->type.sin6.sin6_family = AF_INET6; 258 1.1 christos sockaddr->type.sin6.sin6_addr = in6addr_any; 259 1.1 christos sockaddr->type.sin6.sin6_port = 0; 260 1.1 christos sockaddr->length = sizeof(sockaddr->type.sin6); 261 1.1 christos ISC_LINK_INIT(sockaddr, link); 262 1.1 christos } 263 1.1 christos 264 1.1 christos void 265 1.1 christos isc_sockaddr_fromin(isc_sockaddr_t *sockaddr, const struct in_addr *ina, 266 1.8 christos in_port_t port) { 267 1.1 christos memset(sockaddr, 0, sizeof(*sockaddr)); 268 1.1 christos sockaddr->type.sin.sin_family = AF_INET; 269 1.1 christos sockaddr->type.sin.sin_addr = *ina; 270 1.1 christos sockaddr->type.sin.sin_port = htons(port); 271 1.1 christos sockaddr->length = sizeof(sockaddr->type.sin); 272 1.1 christos ISC_LINK_INIT(sockaddr, link); 273 1.1 christos } 274 1.1 christos 275 1.1 christos void 276 1.1 christos isc_sockaddr_anyofpf(isc_sockaddr_t *sockaddr, int pf) { 277 1.8 christos switch (pf) { 278 1.8 christos case AF_INET: 279 1.8 christos isc_sockaddr_any(sockaddr); 280 1.8 christos break; 281 1.8 christos case AF_INET6: 282 1.8 christos isc_sockaddr_any6(sockaddr); 283 1.8 christos break; 284 1.8 christos default: 285 1.10 christos UNREACHABLE(); 286 1.8 christos } 287 1.1 christos } 288 1.1 christos 289 1.1 christos void 290 1.1 christos isc_sockaddr_fromin6(isc_sockaddr_t *sockaddr, const struct in6_addr *ina6, 291 1.8 christos in_port_t port) { 292 1.1 christos memset(sockaddr, 0, sizeof(*sockaddr)); 293 1.1 christos sockaddr->type.sin6.sin6_family = AF_INET6; 294 1.1 christos sockaddr->type.sin6.sin6_addr = *ina6; 295 1.1 christos sockaddr->type.sin6.sin6_port = htons(port); 296 1.1 christos sockaddr->length = sizeof(sockaddr->type.sin6); 297 1.1 christos ISC_LINK_INIT(sockaddr, link); 298 1.1 christos } 299 1.1 christos 300 1.1 christos void 301 1.1 christos isc_sockaddr_v6fromin(isc_sockaddr_t *sockaddr, const struct in_addr *ina, 302 1.8 christos in_port_t port) { 303 1.1 christos memset(sockaddr, 0, sizeof(*sockaddr)); 304 1.1 christos sockaddr->type.sin6.sin6_family = AF_INET6; 305 1.1 christos sockaddr->type.sin6.sin6_addr.s6_addr[10] = 0xff; 306 1.1 christos sockaddr->type.sin6.sin6_addr.s6_addr[11] = 0xff; 307 1.1 christos memmove(&sockaddr->type.sin6.sin6_addr.s6_addr[12], ina, 4); 308 1.1 christos sockaddr->type.sin6.sin6_port = htons(port); 309 1.1 christos sockaddr->length = sizeof(sockaddr->type.sin6); 310 1.1 christos ISC_LINK_INIT(sockaddr, link); 311 1.1 christos } 312 1.1 christos 313 1.1 christos int 314 1.1 christos isc_sockaddr_pf(const isc_sockaddr_t *sockaddr) { 315 1.1 christos /* 316 1.1 christos * Get the protocol family of 'sockaddr'. 317 1.1 christos */ 318 1.1 christos 319 1.1 christos #if (AF_INET == PF_INET && AF_INET6 == PF_INET6) 320 1.1 christos /* 321 1.1 christos * Assume that PF_xxx == AF_xxx for all AF and PF. 322 1.1 christos */ 323 1.13 christos return sockaddr->type.sa.sa_family; 324 1.8 christos #else /* if (AF_INET == PF_INET && AF_INET6 == PF_INET6) */ 325 1.1 christos switch (sockaddr->type.sa.sa_family) { 326 1.1 christos case AF_INET: 327 1.13 christos return PF_INET; 328 1.1 christos case AF_INET6: 329 1.13 christos return PF_INET6; 330 1.1 christos default: 331 1.11 christos FATAL_ERROR("unknown address family: %d", 332 1.1 christos (int)sockaddr->type.sa.sa_family); 333 1.1 christos } 334 1.8 christos #endif /* if (AF_INET == PF_INET && AF_INET6 == PF_INET6) */ 335 1.1 christos } 336 1.1 christos 337 1.1 christos void 338 1.1 christos isc_sockaddr_fromnetaddr(isc_sockaddr_t *sockaddr, const isc_netaddr_t *na, 339 1.8 christos in_port_t port) { 340 1.1 christos memset(sockaddr, 0, sizeof(*sockaddr)); 341 1.1 christos sockaddr->type.sin.sin_family = na->family; 342 1.1 christos switch (na->family) { 343 1.1 christos case AF_INET: 344 1.1 christos sockaddr->length = sizeof(sockaddr->type.sin); 345 1.1 christos sockaddr->type.sin.sin_addr = na->type.in; 346 1.1 christos sockaddr->type.sin.sin_port = htons(port); 347 1.1 christos break; 348 1.1 christos case AF_INET6: 349 1.1 christos sockaddr->length = sizeof(sockaddr->type.sin6); 350 1.1 christos memmove(&sockaddr->type.sin6.sin6_addr, &na->type.in6, 16); 351 1.1 christos sockaddr->type.sin6.sin6_scope_id = isc_netaddr_getzone(na); 352 1.1 christos sockaddr->type.sin6.sin6_port = htons(port); 353 1.1 christos break; 354 1.1 christos default: 355 1.10 christos UNREACHABLE(); 356 1.1 christos } 357 1.1 christos ISC_LINK_INIT(sockaddr, link); 358 1.1 christos } 359 1.1 christos 360 1.1 christos void 361 1.1 christos isc_sockaddr_setport(isc_sockaddr_t *sockaddr, in_port_t port) { 362 1.1 christos switch (sockaddr->type.sa.sa_family) { 363 1.1 christos case AF_INET: 364 1.1 christos sockaddr->type.sin.sin_port = htons(port); 365 1.1 christos break; 366 1.1 christos case AF_INET6: 367 1.1 christos sockaddr->type.sin6.sin6_port = htons(port); 368 1.1 christos break; 369 1.1 christos default: 370 1.11 christos FATAL_ERROR("unknown address family: %d", 371 1.1 christos (int)sockaddr->type.sa.sa_family); 372 1.1 christos } 373 1.1 christos } 374 1.1 christos 375 1.1 christos in_port_t 376 1.1 christos isc_sockaddr_getport(const isc_sockaddr_t *sockaddr) { 377 1.1 christos in_port_t port = 0; 378 1.1 christos 379 1.1 christos switch (sockaddr->type.sa.sa_family) { 380 1.1 christos case AF_INET: 381 1.1 christos port = ntohs(sockaddr->type.sin.sin_port); 382 1.1 christos break; 383 1.1 christos case AF_INET6: 384 1.1 christos port = ntohs(sockaddr->type.sin6.sin6_port); 385 1.1 christos break; 386 1.1 christos default: 387 1.11 christos FATAL_ERROR("unknown address family: %d", 388 1.1 christos (int)sockaddr->type.sa.sa_family); 389 1.1 christos } 390 1.1 christos 391 1.13 christos return port; 392 1.1 christos } 393 1.1 christos 394 1.3 christos bool 395 1.1 christos isc_sockaddr_ismulticast(const isc_sockaddr_t *sockaddr) { 396 1.1 christos isc_netaddr_t netaddr; 397 1.1 christos 398 1.1 christos if (sockaddr->type.sa.sa_family == AF_INET || 399 1.8 christos sockaddr->type.sa.sa_family == AF_INET6) 400 1.8 christos { 401 1.1 christos isc_netaddr_fromsockaddr(&netaddr, sockaddr); 402 1.13 christos return isc_netaddr_ismulticast(&netaddr); 403 1.1 christos } 404 1.13 christos return false; 405 1.1 christos } 406 1.1 christos 407 1.3 christos bool 408 1.1 christos isc_sockaddr_isexperimental(const isc_sockaddr_t *sockaddr) { 409 1.1 christos isc_netaddr_t netaddr; 410 1.1 christos 411 1.1 christos if (sockaddr->type.sa.sa_family == AF_INET) { 412 1.1 christos isc_netaddr_fromsockaddr(&netaddr, sockaddr); 413 1.13 christos return isc_netaddr_isexperimental(&netaddr); 414 1.1 christos } 415 1.13 christos return false; 416 1.1 christos } 417 1.1 christos 418 1.3 christos bool 419 1.1 christos isc_sockaddr_issitelocal(const isc_sockaddr_t *sockaddr) { 420 1.1 christos isc_netaddr_t netaddr; 421 1.1 christos 422 1.1 christos if (sockaddr->type.sa.sa_family == AF_INET6) { 423 1.1 christos isc_netaddr_fromsockaddr(&netaddr, sockaddr); 424 1.13 christos return isc_netaddr_issitelocal(&netaddr); 425 1.1 christos } 426 1.13 christos return false; 427 1.1 christos } 428 1.1 christos 429 1.3 christos bool 430 1.1 christos isc_sockaddr_islinklocal(const isc_sockaddr_t *sockaddr) { 431 1.1 christos isc_netaddr_t netaddr; 432 1.1 christos 433 1.1 christos if (sockaddr->type.sa.sa_family == AF_INET6) { 434 1.1 christos isc_netaddr_fromsockaddr(&netaddr, sockaddr); 435 1.13 christos return isc_netaddr_islinklocal(&netaddr); 436 1.1 christos } 437 1.13 christos return false; 438 1.1 christos } 439 1.1 christos 440 1.3 christos bool 441 1.1 christos isc_sockaddr_isnetzero(const isc_sockaddr_t *sockaddr) { 442 1.1 christos isc_netaddr_t netaddr; 443 1.1 christos 444 1.1 christos if (sockaddr->type.sa.sa_family == AF_INET) { 445 1.1 christos isc_netaddr_fromsockaddr(&netaddr, sockaddr); 446 1.13 christos return isc_netaddr_isnetzero(&netaddr); 447 1.1 christos } 448 1.13 christos return false; 449 1.8 christos } 450 1.8 christos 451 1.8 christos isc_result_t 452 1.8 christos isc_sockaddr_fromsockaddr(isc_sockaddr_t *isa, const struct sockaddr *sa) { 453 1.8 christos unsigned int length = 0; 454 1.8 christos 455 1.8 christos switch (sa->sa_family) { 456 1.8 christos case AF_INET: 457 1.8 christos length = sizeof(isa->type.sin); 458 1.8 christos break; 459 1.8 christos case AF_INET6: 460 1.8 christos length = sizeof(isa->type.sin6); 461 1.8 christos break; 462 1.8 christos default: 463 1.13 christos return ISC_R_NOTIMPLEMENTED; 464 1.8 christos } 465 1.8 christos 466 1.13 christos *isa = (isc_sockaddr_t){ .length = length, 467 1.13 christos .link = ISC_LINK_INITIALIZER }; 468 1.9 christos memmove(isa, sa, length); 469 1.8 christos 470 1.13 christos return ISC_R_SUCCESS; 471 1.1 christos } 472 1.12 christos 473 1.12 christos bool 474 1.12 christos isc_sockaddr_disabled(const isc_sockaddr_t *sockaddr) { 475 1.12 christos if ((sockaddr->type.sa.sa_family == AF_INET && 476 1.12 christos isc_net_probeipv4() == ISC_R_DISABLED) || 477 1.12 christos (sockaddr->type.sa.sa_family == AF_INET6 && 478 1.12 christos isc_net_probeipv6() == ISC_R_DISABLED)) 479 1.12 christos { 480 1.13 christos return true; 481 1.12 christos } 482 1.13 christos return false; 483 1.12 christos } 484