11676Sjpk /* 21676Sjpk * CDDL HEADER START 31676Sjpk * 41676Sjpk * The contents of this file are subject to the terms of the 51676Sjpk * Common Development and Distribution License (the "License"). 61676Sjpk * You may not use this file except in compliance with the License. 71676Sjpk * 81676Sjpk * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 91676Sjpk * or http://www.opensolaris.org/os/licensing. 101676Sjpk * See the License for the specific language governing permissions 111676Sjpk * and limitations under the License. 121676Sjpk * 131676Sjpk * When distributing Covered Code, include this CDDL HEADER in each 141676Sjpk * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 151676Sjpk * If applicable, add the following below this CDDL HEADER, with the 161676Sjpk * fields enclosed by brackets "[]" replaced with your own identifying 171676Sjpk * information: Portions Copyright [yyyy] [name of copyright owner] 181676Sjpk * 191676Sjpk * CDDL HEADER END 201676Sjpk */ 211676Sjpk /* 221676Sjpk * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 231676Sjpk * Use is subject to license terms. 241676Sjpk */ 251676Sjpk 261676Sjpk #pragma ident "%Z%%M% %I% %E% SMI" 271676Sjpk 281676Sjpk #include <sys/types.h> 291676Sjpk #include <sys/stream.h> 301676Sjpk #include <sys/strsubr.h> 311676Sjpk #include <sys/stropts.h> 321676Sjpk #include <sys/sunddi.h> 331676Sjpk #include <sys/cred.h> 341676Sjpk #include <sys/debug.h> 351676Sjpk #include <sys/kmem.h> 361676Sjpk #include <sys/errno.h> 371676Sjpk #include <sys/disp.h> 381676Sjpk #include <netinet/in.h> 391676Sjpk #include <netinet/in_systm.h> 401676Sjpk #include <netinet/ip.h> 411676Sjpk #include <netinet/ip_icmp.h> 421676Sjpk #include <netinet/tcp.h> 431676Sjpk #include <inet/common.h> 441676Sjpk #include <inet/ipclassifier.h> 451676Sjpk #include <inet/ip.h> 461676Sjpk #include <inet/mib2.h> 471676Sjpk #include <inet/nd.h> 481676Sjpk #include <inet/tcp.h> 491676Sjpk #include <inet/ip_rts.h> 501676Sjpk #include <inet/ip_ire.h> 511676Sjpk #include <inet/ip_if.h> 521676Sjpk #include <sys/modhash.h> 531676Sjpk 541676Sjpk #include <sys/tsol/label.h> 551676Sjpk #include <sys/tsol/label_macro.h> 561676Sjpk #include <sys/tsol/tnet.h> 571676Sjpk #include <sys/tsol/tndb.h> 581676Sjpk #include <sys/strsun.h> 591676Sjpk 601676Sjpk /* tunable for strict error-reply behavior (TCP RST and ICMP Unreachable) */ 611676Sjpk int tsol_strict_error; 621676Sjpk 631676Sjpk /* 641676Sjpk * Some notes on the Trusted Solaris IRE gateway security attributes: 651676Sjpk * 661676Sjpk * When running in Trusted mode, the routing subsystem determines whether or 671676Sjpk * not a packet can be delivered to an off-link host (not directly reachable 681676Sjpk * through an interface) based on the accreditation checks of the packet's 691676Sjpk * security attributes against those associated with the next-hop gateway. 701676Sjpk * 711676Sjpk * The next-hop gateway's security attributes can be derived from two sources 721676Sjpk * (in order of preference): route-related and the host database. A Trusted 731676Sjpk * system must be configured with at least the host database containing an 741676Sjpk * entry for the next-hop gateway, or otherwise no accreditation checks can 751676Sjpk * be performed, which may result in the inability to send packets to any 761676Sjpk * off-link destination host. 771676Sjpk * 781676Sjpk * The major differences between the two sources are the number and type of 791676Sjpk * security attributes used for accreditation checks. A host database entry 801676Sjpk * can contain at most one set of security attributes, specific only to the 811676Sjpk * next-hop gateway. On contrast, route-related security attributes are made 821676Sjpk * up of a collection of security attributes for the distant networks, and 831676Sjpk * are grouped together per next-hop gateway used to reach those networks. 841676Sjpk * This is the preferred method, and the routing subsystem will fallback to 851676Sjpk * the host database entry only if there are no route-related attributes 861676Sjpk * associated with the next-hop gateway. 871676Sjpk * 881676Sjpk * In Trusted mode, all of the IRE entries (except LOCAL/LOOPBACK/BROADCAST/ 891676Sjpk * INTERFACE type) are initialized to contain a placeholder to store this 901676Sjpk * information. The ire_gw_secattr structure gets allocated, initialized 911676Sjpk * and associated with the IRE during the time of the IRE creation. The 921676Sjpk * initialization process also includes resolving the host database entry 931676Sjpk * of the next-hop gateway for fallback purposes. It does not include any 941676Sjpk * route-related attribute setup, as that process comes separately as part 951676Sjpk * of the route requests (add/change) made to the routing subsystem. 961676Sjpk * 971676Sjpk * The underlying logic which involves associating IREs with the gateway 981676Sjpk * security attributes are represented by the following data structures: 991676Sjpk * 1001676Sjpk * tsol_gcdb_t, or "gcdb" 1011676Sjpk * 1021676Sjpk * - This is a system-wide collection of records containing the 1031676Sjpk * currently used route-related security attributes, which are fed 1041676Sjpk * through the routing socket interface, e.g. "route add/change". 1051676Sjpk * 1061676Sjpk * tsol_gc_t, or "gc" 1071676Sjpk * 1081676Sjpk * - This is the gateway credential structure, and it provides for the 1091676Sjpk * only mechanism to access the contents of gcdb. More than one gc 1101676Sjpk * entries may refer to the same gcdb record. gc's in the system are 1111676Sjpk * grouped according to the next-hop gateway address. 1121676Sjpk * 1131676Sjpk * tsol_gcgrp_t, or "gcgrp" 1141676Sjpk * 1151676Sjpk * - Group of gateway credentials, and is unique per next-hop gateway 1161676Sjpk * address. When the group is not empty, i.e. when gcgrp_count is 1171676Sjpk * greater than zero, it contains one or more gc's, each pointing to 1181676Sjpk * a gcdb record which indicates the gateway security attributes 1191676Sjpk * associated with the next-hop gateway. 1201676Sjpk * 1211676Sjpk * The fields of the tsol_ire_gw_secattr_t used from within the IRE are: 1221676Sjpk * 1231676Sjpk * igsa_lock 1241676Sjpk * 1251676Sjpk * - Lock that protects all fields within tsol_ire_gw_secattr_t. 1261676Sjpk * 1271676Sjpk * igsa_rhc 1281676Sjpk * 1291676Sjpk * - Remote host cache database entry of next-hop gateway. This is 1301676Sjpk * used in the case when there are no route-related attributes 1311676Sjpk * configured for the IRE. 1321676Sjpk * 1331676Sjpk * igsa_gc 1341676Sjpk * 1351676Sjpk * - A set of route-related attributes that only get set for prefix 1361676Sjpk * IREs. If this is non-NULL, the prefix IRE has been associated 1371676Sjpk * with a set of gateway security attributes by way of route add/ 1381676Sjpk * change functionality. This field stays NULL for IRE_CACHEs. 1391676Sjpk * 1401676Sjpk * igsa_gcgrp 1411676Sjpk * 1421676Sjpk * - Group of gc's which only gets set for IRE_CACHEs. Each of the gc 1431676Sjpk * points to a gcdb record that contains the security attributes 1441676Sjpk * used to perform the credential checks of the packet which uses 1451676Sjpk * the IRE. If the group is not empty, the list of gc's can be 1461676Sjpk * traversed starting at gcgrp_head. This field stays NULL for 1471676Sjpk * prefix IREs. 1481676Sjpk */ 1491676Sjpk 1501676Sjpk static kmem_cache_t *ire_gw_secattr_cache; 1511676Sjpk 1521676Sjpk #define GCDB_HASH_SIZE 101 1531676Sjpk #define GCGRP_HASH_SIZE 101 1541676Sjpk 1551676Sjpk #define GCDB_REFRELE(p) { \ 1561676Sjpk mutex_enter(&gcdb_lock); \ 1571676Sjpk ASSERT((p)->gcdb_refcnt > 0); \ 1581676Sjpk if (--((p)->gcdb_refcnt) == 0) \ 1591676Sjpk gcdb_inactive(p); \ 1601676Sjpk ASSERT(MUTEX_HELD(&gcdb_lock)); \ 1611676Sjpk mutex_exit(&gcdb_lock); \ 1621676Sjpk } 1631676Sjpk 1641676Sjpk static int gcdb_hash_size = GCDB_HASH_SIZE; 1651676Sjpk static int gcgrp_hash_size = GCGRP_HASH_SIZE; 1661676Sjpk static mod_hash_t *gcdb_hash; 1671676Sjpk static mod_hash_t *gcgrp4_hash; 1681676Sjpk static mod_hash_t *gcgrp6_hash; 1691676Sjpk 1701676Sjpk static kmutex_t gcdb_lock; 1711676Sjpk kmutex_t gcgrp_lock; 1721676Sjpk 1731676Sjpk static uint_t gcdb_hash_by_secattr(void *, mod_hash_key_t); 1741676Sjpk static int gcdb_hash_cmp(mod_hash_key_t, mod_hash_key_t); 1751676Sjpk static tsol_gcdb_t *gcdb_lookup(struct rtsa_s *, boolean_t); 1761676Sjpk static void gcdb_inactive(tsol_gcdb_t *); 1771676Sjpk 1781676Sjpk static uint_t gcgrp_hash_by_addr(void *, mod_hash_key_t); 1791676Sjpk static int gcgrp_hash_cmp(mod_hash_key_t, mod_hash_key_t); 1801676Sjpk 1811676Sjpk static int ire_gw_secattr_constructor(void *, void *, int); 1821676Sjpk static void ire_gw_secattr_destructor(void *, void *); 1831676Sjpk 1841676Sjpk void 1851676Sjpk tnet_init(void) 1861676Sjpk { 1871676Sjpk ire_gw_secattr_cache = kmem_cache_create("ire_gw_secattr_cache", 1881676Sjpk sizeof (tsol_ire_gw_secattr_t), 64, ire_gw_secattr_constructor, 1891676Sjpk ire_gw_secattr_destructor, NULL, NULL, NULL, 0); 1901676Sjpk 1911676Sjpk gcdb_hash = mod_hash_create_extended("gcdb_hash", 1921676Sjpk gcdb_hash_size, mod_hash_null_keydtor, mod_hash_null_valdtor, 1931676Sjpk gcdb_hash_by_secattr, NULL, gcdb_hash_cmp, KM_SLEEP); 1941676Sjpk 1951676Sjpk gcgrp4_hash = mod_hash_create_extended("gcgrp4_hash", 1961676Sjpk gcgrp_hash_size, mod_hash_null_keydtor, mod_hash_null_valdtor, 1971676Sjpk gcgrp_hash_by_addr, NULL, gcgrp_hash_cmp, KM_SLEEP); 1981676Sjpk 1991676Sjpk gcgrp6_hash = mod_hash_create_extended("gcgrp6_hash", 2001676Sjpk gcgrp_hash_size, mod_hash_null_keydtor, mod_hash_null_valdtor, 2011676Sjpk gcgrp_hash_by_addr, NULL, gcgrp_hash_cmp, KM_SLEEP); 2021676Sjpk 2031676Sjpk mutex_init(&gcdb_lock, NULL, MUTEX_DEFAULT, NULL); 2041676Sjpk mutex_init(&gcgrp_lock, NULL, MUTEX_DEFAULT, NULL); 2051676Sjpk } 2061676Sjpk 2071676Sjpk void 2081676Sjpk tnet_fini(void) 2091676Sjpk { 2101676Sjpk kmem_cache_destroy(ire_gw_secattr_cache); 2111676Sjpk mod_hash_destroy_hash(gcdb_hash); 2121676Sjpk mod_hash_destroy_hash(gcgrp4_hash); 2131676Sjpk mod_hash_destroy_hash(gcgrp6_hash); 2141676Sjpk mutex_destroy(&gcdb_lock); 2151676Sjpk mutex_destroy(&gcgrp_lock); 2161676Sjpk } 2171676Sjpk 2181676Sjpk /* ARGSUSED */ 2191676Sjpk static int 2201676Sjpk ire_gw_secattr_constructor(void *buf, void *cdrarg, int kmflags) 2211676Sjpk { 2221676Sjpk tsol_ire_gw_secattr_t *attrp = buf; 2231676Sjpk 2241676Sjpk mutex_init(&attrp->igsa_lock, NULL, MUTEX_DEFAULT, NULL); 2251676Sjpk 2261676Sjpk attrp->igsa_rhc = NULL; 2271676Sjpk attrp->igsa_gc = NULL; 2281676Sjpk attrp->igsa_gcgrp = NULL; 2291676Sjpk 2301676Sjpk return (0); 2311676Sjpk } 2321676Sjpk 2331676Sjpk /* ARGSUSED */ 2341676Sjpk static void 2351676Sjpk ire_gw_secattr_destructor(void *buf, void *cdrarg) 2361676Sjpk { 2371676Sjpk tsol_ire_gw_secattr_t *attrp = (tsol_ire_gw_secattr_t *)buf; 2381676Sjpk 2391676Sjpk mutex_destroy(&attrp->igsa_lock); 2401676Sjpk } 2411676Sjpk 2421676Sjpk tsol_ire_gw_secattr_t * 2431676Sjpk ire_gw_secattr_alloc(int kmflags) 2441676Sjpk { 2451676Sjpk return (kmem_cache_alloc(ire_gw_secattr_cache, kmflags)); 2461676Sjpk } 2471676Sjpk 2481676Sjpk void 2491676Sjpk ire_gw_secattr_free(tsol_ire_gw_secattr_t *attrp) 2501676Sjpk { 2511676Sjpk ASSERT(MUTEX_NOT_HELD(&attrp->igsa_lock)); 2521676Sjpk 2531676Sjpk if (attrp->igsa_rhc != NULL) { 2541676Sjpk TNRHC_RELE(attrp->igsa_rhc); 2551676Sjpk attrp->igsa_rhc = NULL; 2561676Sjpk } 2571676Sjpk 2581676Sjpk if (attrp->igsa_gc != NULL) { 2591676Sjpk GC_REFRELE(attrp->igsa_gc); 2601676Sjpk attrp->igsa_gc = NULL; 2611676Sjpk } 2621676Sjpk if (attrp->igsa_gcgrp != NULL) { 2631676Sjpk GCGRP_REFRELE(attrp->igsa_gcgrp); 2641676Sjpk attrp->igsa_gcgrp = NULL; 2651676Sjpk } 2661676Sjpk 2671676Sjpk ASSERT(attrp->igsa_rhc == NULL); 2681676Sjpk ASSERT(attrp->igsa_gc == NULL); 2691676Sjpk ASSERT(attrp->igsa_gcgrp == NULL); 2701676Sjpk 2711676Sjpk kmem_cache_free(ire_gw_secattr_cache, attrp); 2721676Sjpk } 2731676Sjpk 2741676Sjpk /* ARGSUSED */ 2751676Sjpk static uint_t 2761676Sjpk gcdb_hash_by_secattr(void *hash_data, mod_hash_key_t key) 2771676Sjpk { 2781676Sjpk const struct rtsa_s *rp = (struct rtsa_s *)key; 2791676Sjpk const uint32_t *up, *ue; 2801676Sjpk uint_t hash; 2811676Sjpk int i; 2821676Sjpk 2831676Sjpk ASSERT(rp != NULL); 2841676Sjpk 2851676Sjpk /* See comments in hash_bylabel in zone.c for details */ 2861676Sjpk hash = rp->rtsa_doi + (rp->rtsa_doi << 1); 2871676Sjpk up = (const uint32_t *)&rp->rtsa_slrange; 2881676Sjpk ue = up + sizeof (rp->rtsa_slrange) / sizeof (*up); 2891676Sjpk i = 1; 2901676Sjpk while (up < ue) { 2911676Sjpk /* using 2^n + 1, 1 <= n <= 16 as source of many primes */ 2921676Sjpk hash += *up + (*up << ((i % 16) + 1)); 2931676Sjpk up++; 2941676Sjpk i++; 2951676Sjpk } 2961676Sjpk return (hash); 2971676Sjpk } 2981676Sjpk 2991676Sjpk static int 3001676Sjpk gcdb_hash_cmp(mod_hash_key_t key1, mod_hash_key_t key2) 3011676Sjpk { 3021676Sjpk struct rtsa_s *rp1 = (struct rtsa_s *)key1; 3031676Sjpk struct rtsa_s *rp2 = (struct rtsa_s *)key2; 3041676Sjpk 3051676Sjpk ASSERT(rp1 != NULL && rp2 != NULL); 3061676Sjpk 3071676Sjpk if (blequal(&rp1->rtsa_slrange.lower_bound, 3081676Sjpk &rp2->rtsa_slrange.lower_bound) && 3091676Sjpk blequal(&rp1->rtsa_slrange.upper_bound, 3101676Sjpk &rp2->rtsa_slrange.upper_bound) && 3111676Sjpk rp1->rtsa_doi == rp2->rtsa_doi) 3121676Sjpk return (0); 3131676Sjpk 3141676Sjpk /* No match; not found */ 3151676Sjpk return (-1); 3161676Sjpk } 3171676Sjpk 3181676Sjpk /* ARGSUSED */ 3191676Sjpk static uint_t 3201676Sjpk gcgrp_hash_by_addr(void *hash_data, mod_hash_key_t key) 3211676Sjpk { 3221676Sjpk tsol_gcgrp_addr_t *ga = (tsol_gcgrp_addr_t *)key; 3231676Sjpk uint_t idx = 0; 3241676Sjpk uint32_t *ap; 3251676Sjpk 3261676Sjpk ASSERT(ga != NULL); 3271676Sjpk ASSERT(ga->ga_af == AF_INET || ga->ga_af == AF_INET6); 3281676Sjpk 3291676Sjpk ap = (uint32_t *)&ga->ga_addr.s6_addr32[0]; 3301676Sjpk idx ^= *ap++; 3311676Sjpk idx ^= *ap++; 3321676Sjpk idx ^= *ap++; 3331676Sjpk idx ^= *ap; 3341676Sjpk 3351676Sjpk return (idx); 3361676Sjpk } 3371676Sjpk 3381676Sjpk static int 3391676Sjpk gcgrp_hash_cmp(mod_hash_key_t key1, mod_hash_key_t key2) 3401676Sjpk { 3411676Sjpk tsol_gcgrp_addr_t *ga1 = (tsol_gcgrp_addr_t *)key1; 3421676Sjpk tsol_gcgrp_addr_t *ga2 = (tsol_gcgrp_addr_t *)key2; 3431676Sjpk 3441676Sjpk ASSERT(ga1 != NULL && ga2 != NULL); 3451676Sjpk 3461676Sjpk /* Address family must match */ 3471676Sjpk if (ga1->ga_af != ga2->ga_af) 3481676Sjpk return (-1); 3491676Sjpk 3501676Sjpk if (ga1->ga_addr.s6_addr32[0] == ga2->ga_addr.s6_addr32[0] && 3511676Sjpk ga1->ga_addr.s6_addr32[1] == ga2->ga_addr.s6_addr32[1] && 3521676Sjpk ga1->ga_addr.s6_addr32[2] == ga2->ga_addr.s6_addr32[2] && 3531676Sjpk ga1->ga_addr.s6_addr32[3] == ga2->ga_addr.s6_addr32[3]) 3541676Sjpk return (0); 3551676Sjpk 3561676Sjpk /* No match; not found */ 3571676Sjpk return (-1); 3581676Sjpk } 3591676Sjpk 3601676Sjpk #define RTSAFLAGS "\20\11cipso\3doi\2max_sl\1min_sl" 3611676Sjpk 3621676Sjpk int 3631676Sjpk rtsa_validate(const struct rtsa_s *rp) 3641676Sjpk { 3651676Sjpk uint32_t mask = rp->rtsa_mask; 3661676Sjpk 3671676Sjpk /* RTSA_CIPSO must be set, and DOI must not be zero */ 3681676Sjpk if ((mask & RTSA_CIPSO) == 0 || rp->rtsa_doi == 0) { 3691676Sjpk DTRACE_PROBE2(tx__gcdb__log__error__rtsa__validate, char *, 3701676Sjpk "rtsa(1) lacks flag or has 0 doi.", 3711676Sjpk rtsa_s *, rp); 3721676Sjpk return (EINVAL); 3731676Sjpk } 3741676Sjpk /* 3751676Sjpk * SL range must be specified, and it must have its 3761676Sjpk * upper bound dominating its lower bound. 3771676Sjpk */ 3781676Sjpk if ((mask & RTSA_SLRANGE) != RTSA_SLRANGE || 3791676Sjpk !bldominates(&rp->rtsa_slrange.upper_bound, 3801676Sjpk &rp->rtsa_slrange.lower_bound)) { 3811676Sjpk DTRACE_PROBE2(tx__gcdb__log__error__rtsa__validate, char *, 3821676Sjpk "rtsa(1) min_sl and max_sl not set or max_sl is " 3831676Sjpk "not dominating.", rtsa_s *, rp); 3841676Sjpk return (EINVAL); 3851676Sjpk } 3861676Sjpk return (0); 3871676Sjpk } 3881676Sjpk 3891676Sjpk /* 3901676Sjpk * A brief explanation of the reference counting scheme: 3911676Sjpk * 3921676Sjpk * Prefix IREs have a non-NULL igsa_gc and a NULL igsa_gcgrp; 3931676Sjpk * IRE_CACHEs have it vice-versa. 3941676Sjpk * 3951676Sjpk * Apart from dynamic references due to to reference holds done 3961676Sjpk * actively by threads, we have the following references: 3971676Sjpk * 3981676Sjpk * gcdb_refcnt: 3991676Sjpk * - Every tsol_gc_t pointing to a tsol_gcdb_t contributes a reference 4001676Sjpk * to the gcdb_refcnt. 4011676Sjpk * 4021676Sjpk * gc_refcnt: 4031676Sjpk * - A prefix IRE that points to an igsa_gc contributes a reference 4041676Sjpk * to the gc_refcnt. 4051676Sjpk * 4061676Sjpk * gcgrp_refcnt: 4071676Sjpk * - An IRE_CACHE that points to an igsa_gcgrp contributes a reference 4081676Sjpk * to the gcgrp_refcnt of the associated tsol_gcgrp_t. 4091676Sjpk * - Every tsol_gc_t in the chain headed by tsol_gcgrp_t contributes 4101676Sjpk * a reference to the gcgrp_refcnt. 4111676Sjpk */ 4121676Sjpk static tsol_gcdb_t * 4131676Sjpk gcdb_lookup(struct rtsa_s *rp, boolean_t alloc) 4141676Sjpk { 4151676Sjpk tsol_gcdb_t *gcdb = NULL; 4161676Sjpk 4171676Sjpk if (rtsa_validate(rp) != 0) 4181676Sjpk return (NULL); 4191676Sjpk 4201676Sjpk mutex_enter(&gcdb_lock); 4211676Sjpk /* Find a copy in the cache; otherwise, create one and cache it */ 4221676Sjpk if (mod_hash_find(gcdb_hash, (mod_hash_key_t)rp, 4231676Sjpk (mod_hash_val_t *)&gcdb) == 0) { 4241676Sjpk gcdb->gcdb_refcnt++; 4251676Sjpk ASSERT(gcdb->gcdb_refcnt != 0); 4261676Sjpk 4271676Sjpk DTRACE_PROBE2(tx__gcdb__log__info__gcdb__lookup, char *, 4281676Sjpk "gcdb(1) is in gcdb_hash(global)", tsol_gcdb_t *, gcdb); 4291676Sjpk } else if (alloc) { 4301676Sjpk gcdb = kmem_zalloc(sizeof (*gcdb), KM_NOSLEEP); 4311676Sjpk if (gcdb != NULL) { 4321676Sjpk gcdb->gcdb_refcnt = 1; 4331676Sjpk gcdb->gcdb_mask = rp->rtsa_mask; 4341676Sjpk gcdb->gcdb_doi = rp->rtsa_doi; 4351676Sjpk gcdb->gcdb_slrange = rp->rtsa_slrange; 4361676Sjpk 4371676Sjpk if (mod_hash_insert(gcdb_hash, 4381676Sjpk (mod_hash_key_t)&gcdb->gcdb_attr, 4391676Sjpk (mod_hash_val_t)gcdb) != 0) { 4401676Sjpk mutex_exit(&gcdb_lock); 4411676Sjpk kmem_free(gcdb, sizeof (*gcdb)); 4421676Sjpk return (NULL); 4431676Sjpk } 4441676Sjpk 4451676Sjpk DTRACE_PROBE2(tx__gcdb__log__info__gcdb__insert, char *, 4461676Sjpk "gcdb(1) inserted in gcdb_hash(global)", 4471676Sjpk tsol_gcdb_t *, gcdb); 4481676Sjpk } 4491676Sjpk } 4501676Sjpk mutex_exit(&gcdb_lock); 4511676Sjpk return (gcdb); 4521676Sjpk } 4531676Sjpk 4541676Sjpk static void 4551676Sjpk gcdb_inactive(tsol_gcdb_t *gcdb) 4561676Sjpk { 4571676Sjpk ASSERT(MUTEX_HELD(&gcdb_lock)); 4581676Sjpk ASSERT(gcdb != NULL && gcdb->gcdb_refcnt == 0); 4591676Sjpk 4601676Sjpk (void) mod_hash_remove(gcdb_hash, (mod_hash_key_t)&gcdb->gcdb_attr, 4611676Sjpk (mod_hash_val_t *)&gcdb); 4621676Sjpk 4631676Sjpk DTRACE_PROBE2(tx__gcdb__log__info__gcdb__remove, char *, 4641676Sjpk "gcdb(1) removed from gcdb_hash(global)", 4651676Sjpk tsol_gcdb_t *, gcdb); 4661676Sjpk kmem_free(gcdb, sizeof (*gcdb)); 4671676Sjpk } 4681676Sjpk 4691676Sjpk tsol_gc_t * 4701676Sjpk gc_create(struct rtsa_s *rp, tsol_gcgrp_t *gcgrp, boolean_t *gcgrp_xtrarefp) 4711676Sjpk { 4721676Sjpk tsol_gc_t *gc; 4731676Sjpk tsol_gcdb_t *gcdb; 4741676Sjpk 4751676Sjpk *gcgrp_xtrarefp = B_TRUE; 4761676Sjpk 4771676Sjpk rw_enter(&gcgrp->gcgrp_rwlock, RW_WRITER); 4781676Sjpk if ((gcdb = gcdb_lookup(rp, B_TRUE)) == NULL) { 4791676Sjpk rw_exit(&gcgrp->gcgrp_rwlock); 4801676Sjpk return (NULL); 4811676Sjpk } 4821676Sjpk 4831676Sjpk for (gc = gcgrp->gcgrp_head; gc != NULL; gc = gc->gc_next) { 4841676Sjpk if (gc->gc_db == gcdb) { 4851676Sjpk ASSERT(gc->gc_grp == gcgrp); 4861676Sjpk 4871676Sjpk gc->gc_refcnt++; 4881676Sjpk ASSERT(gc->gc_refcnt != 0); 4891676Sjpk 4901676Sjpk GCDB_REFRELE(gcdb); 4911676Sjpk 4921676Sjpk DTRACE_PROBE3(tx__gcdb__log__info__gc__create, 4931676Sjpk char *, "found gc(1) in gcgrp(2)", 4941676Sjpk tsol_gc_t *, gc, tsol_gcgrp_t *, gcgrp); 4951676Sjpk rw_exit(&gcgrp->gcgrp_rwlock); 4961676Sjpk return (gc); 4971676Sjpk } 4981676Sjpk } 4991676Sjpk 5001676Sjpk gc = kmem_zalloc(sizeof (*gc), KM_NOSLEEP); 5011676Sjpk if (gc != NULL) { 5021676Sjpk if (gcgrp->gcgrp_head == NULL) { 5031676Sjpk gcgrp->gcgrp_head = gcgrp->gcgrp_tail = gc; 5041676Sjpk } else { 5051676Sjpk gcgrp->gcgrp_tail->gc_next = gc; 5061676Sjpk gc->gc_prev = gcgrp->gcgrp_tail; 5071676Sjpk gcgrp->gcgrp_tail = gc; 5081676Sjpk } 5091676Sjpk gcgrp->gcgrp_count++; 5101676Sjpk ASSERT(gcgrp->gcgrp_count != 0); 5111676Sjpk 5121676Sjpk /* caller has incremented gcgrp reference for us */ 5131676Sjpk gc->gc_grp = gcgrp; 5141676Sjpk 5151676Sjpk gc->gc_db = gcdb; 5161676Sjpk gc->gc_refcnt = 1; 5171676Sjpk 5181676Sjpk DTRACE_PROBE3(tx__gcdb__log__info__gc__create, char *, 5191676Sjpk "added gc(1) to gcgrp(2)", tsol_gc_t *, gc, 5201676Sjpk tsol_gcgrp_t *, gcgrp); 5211676Sjpk 5221676Sjpk *gcgrp_xtrarefp = B_FALSE; 5231676Sjpk } 5241676Sjpk rw_exit(&gcgrp->gcgrp_rwlock); 5251676Sjpk 5261676Sjpk return (gc); 5271676Sjpk } 5281676Sjpk 5291676Sjpk void 5301676Sjpk gc_inactive(tsol_gc_t *gc) 5311676Sjpk { 5321676Sjpk tsol_gcgrp_t *gcgrp = gc->gc_grp; 5331676Sjpk 5341676Sjpk ASSERT(gcgrp != NULL); 5351676Sjpk ASSERT(RW_WRITE_HELD(&gcgrp->gcgrp_rwlock)); 5361676Sjpk ASSERT(gc->gc_refcnt == 0); 5371676Sjpk 5381676Sjpk if (gc->gc_prev != NULL) 5391676Sjpk gc->gc_prev->gc_next = gc->gc_next; 5401676Sjpk else 5411676Sjpk gcgrp->gcgrp_head = gc->gc_next; 5421676Sjpk if (gc->gc_next != NULL) 5431676Sjpk gc->gc_next->gc_prev = gc->gc_prev; 5441676Sjpk else 5451676Sjpk gcgrp->gcgrp_tail = gc->gc_prev; 5461676Sjpk ASSERT(gcgrp->gcgrp_count > 0); 5471676Sjpk gcgrp->gcgrp_count--; 5481676Sjpk 5491676Sjpk /* drop lock before it's destroyed */ 5501676Sjpk rw_exit(&gcgrp->gcgrp_rwlock); 5511676Sjpk 5521676Sjpk DTRACE_PROBE3(tx__gcdb__log__info__gc__remove, char *, 5531676Sjpk "removed inactive gc(1) from gcgrp(2)", 5541676Sjpk tsol_gc_t *, gc, tsol_gcgrp_t *, gcgrp); 5551676Sjpk 5561676Sjpk GCGRP_REFRELE(gcgrp); 5571676Sjpk 5581676Sjpk gc->gc_grp = NULL; 5591676Sjpk gc->gc_prev = gc->gc_next = NULL; 5601676Sjpk 5611676Sjpk if (gc->gc_db != NULL) 5621676Sjpk GCDB_REFRELE(gc->gc_db); 5631676Sjpk 5641676Sjpk kmem_free(gc, sizeof (*gc)); 5651676Sjpk } 5661676Sjpk 5671676Sjpk tsol_gcgrp_t * 5681676Sjpk gcgrp_lookup(tsol_gcgrp_addr_t *ga, boolean_t alloc) 5691676Sjpk { 5701676Sjpk tsol_gcgrp_t *gcgrp = NULL; 5711676Sjpk mod_hash_t *hashp; 5721676Sjpk 5731676Sjpk ASSERT(ga->ga_af == AF_INET || ga->ga_af == AF_INET6); 5741676Sjpk 5751676Sjpk hashp = (ga->ga_af == AF_INET) ? gcgrp4_hash : gcgrp6_hash; 5761676Sjpk 5771676Sjpk mutex_enter(&gcgrp_lock); 5781676Sjpk if (mod_hash_find(hashp, (mod_hash_key_t)ga, 5791676Sjpk (mod_hash_val_t *)&gcgrp) == 0) { 5801676Sjpk gcgrp->gcgrp_refcnt++; 5811676Sjpk ASSERT(gcgrp->gcgrp_refcnt != 0); 5821676Sjpk 5831676Sjpk DTRACE_PROBE3(tx__gcdb__log__info__gcgrp__lookup, char *, 5841676Sjpk "found gcgrp(1) in hash(2)", tsol_gcgrp_t *, gcgrp, 5851676Sjpk mod_hash_t *, hashp); 5861676Sjpk 5871676Sjpk } else if (alloc) { 5881676Sjpk gcgrp = kmem_zalloc(sizeof (*gcgrp), KM_NOSLEEP); 5891676Sjpk if (gcgrp != NULL) { 5901676Sjpk gcgrp->gcgrp_refcnt = 1; 5911676Sjpk rw_init(&gcgrp->gcgrp_rwlock, NULL, RW_DEFAULT, NULL); 5921676Sjpk bcopy(ga, &gcgrp->gcgrp_addr, sizeof (*ga)); 5931676Sjpk 5941676Sjpk if (mod_hash_insert(hashp, 5951676Sjpk (mod_hash_key_t)&gcgrp->gcgrp_addr, 5961676Sjpk (mod_hash_val_t)gcgrp) != 0) { 5971676Sjpk mutex_exit(&gcgrp_lock); 5981676Sjpk kmem_free(gcgrp, sizeof (*gcgrp)); 5991676Sjpk return (NULL); 6001676Sjpk } 6011676Sjpk 6021676Sjpk DTRACE_PROBE3(tx__gcdb__log__info__gcgrp__insert, 6031676Sjpk char *, "inserted gcgrp(1) in hash(2)", 6041676Sjpk tsol_gcgrp_t *, gcgrp, mod_hash_t *, hashp); 6051676Sjpk } 6061676Sjpk } 6071676Sjpk mutex_exit(&gcgrp_lock); 6081676Sjpk return (gcgrp); 6091676Sjpk } 6101676Sjpk 6111676Sjpk void 6121676Sjpk gcgrp_inactive(tsol_gcgrp_t *gcgrp) 6131676Sjpk { 6141676Sjpk tsol_gcgrp_addr_t *ga; 6151676Sjpk mod_hash_t *hashp; 6161676Sjpk 6171676Sjpk ASSERT(MUTEX_HELD(&gcgrp_lock)); 6181676Sjpk ASSERT(!RW_LOCK_HELD(&gcgrp->gcgrp_rwlock)); 6191676Sjpk ASSERT(gcgrp != NULL && gcgrp->gcgrp_refcnt == 0); 6201676Sjpk ASSERT(gcgrp->gcgrp_head == NULL && gcgrp->gcgrp_count == 0); 6211676Sjpk 6221676Sjpk ga = &gcgrp->gcgrp_addr; 6231676Sjpk ASSERT(ga->ga_af == AF_INET || ga->ga_af == AF_INET6); 6241676Sjpk 6251676Sjpk hashp = (ga->ga_af == AF_INET) ? gcgrp4_hash : gcgrp6_hash; 6261676Sjpk (void) mod_hash_remove(hashp, (mod_hash_key_t)ga, 6271676Sjpk (mod_hash_val_t *)&gcgrp); 6281676Sjpk rw_destroy(&gcgrp->gcgrp_rwlock); 6291676Sjpk 6301676Sjpk DTRACE_PROBE3(tx__gcdb__log__info__gcgrp__remove, char *, 6311676Sjpk "removed inactive gcgrp(1) from hash(2)", 6321676Sjpk tsol_gcgrp_t *, gcgrp, mod_hash_t *, hashp); 6331676Sjpk 6341676Sjpk kmem_free(gcgrp, sizeof (*gcgrp)); 6351676Sjpk } 6361676Sjpk 6371676Sjpk /* 6381676Sjpk * Converts CIPSO option to sensitivity label. 6391676Sjpk * Validity checks based on restrictions defined in 6401676Sjpk * COMMERCIAL IP SECURITY OPTION (CIPSO 2.2) (draft-ietf-cipso-ipsecurity) 6411676Sjpk */ 6421676Sjpk static boolean_t 6431676Sjpk cipso_to_sl(const uchar_t *option, bslabel_t *sl) 6441676Sjpk { 6451676Sjpk const struct cipso_option *co = (const struct cipso_option *)option; 6461676Sjpk const struct cipso_tag_type_1 *tt1; 6471676Sjpk 6481676Sjpk tt1 = (struct cipso_tag_type_1 *)&co->cipso_tag_type[0]; 6491676Sjpk if (tt1->tag_type != 1 || 6501676Sjpk tt1->tag_length < TSOL_TT1_MIN_LENGTH || 6511676Sjpk tt1->tag_length > TSOL_TT1_MAX_LENGTH || 6521676Sjpk tt1->tag_length + TSOL_CIPSO_TAG_OFFSET > co->cipso_length) 6531676Sjpk return (B_FALSE); 6541676Sjpk 6551676Sjpk bsllow(sl); /* assumed: sets compartments to all zeroes */ 6561676Sjpk LCLASS_SET((_bslabel_impl_t *)sl, tt1->tag_sl); 6571676Sjpk bcopy(tt1->tag_cat, &((_bslabel_impl_t *)sl)->compartments, 6581676Sjpk tt1->tag_length - TSOL_TT1_MIN_LENGTH); 6591676Sjpk return (B_TRUE); 6601676Sjpk } 6611676Sjpk 6621676Sjpk /* 6631676Sjpk * Parse the CIPSO label in the incoming packet and construct a ts_label_t 6641676Sjpk * that reflects the CIPSO label and attach it to the dblk cred. Later as 6651676Sjpk * the mblk flows up through the stack any code that needs to examine the 6661676Sjpk * packet label can inspect the label from the dblk cred. This function is 6671676Sjpk * called right in ip_rput for all packets, i.e. locally destined and 6681676Sjpk * to be forwarded packets. The forwarding path needs to examine the label 6691676Sjpk * to determine how to forward the packet. 6701676Sjpk * 6711676Sjpk * For IPv4, IP header options have been pulled up, but other headers might not 6721676Sjpk * have been. For IPv6, any hop-by-hop options have been pulled up, but any 6731676Sjpk * other headers might not be present. 6741676Sjpk */ 6751676Sjpk boolean_t 6761676Sjpk tsol_get_pkt_label(mblk_t *mp, int version) 6771676Sjpk { 6781676Sjpk tsol_tpc_t *src_rhtp; 6791676Sjpk uchar_t *opt_ptr = NULL; 6801676Sjpk const ipha_t *ipha; 6811676Sjpk bslabel_t sl; 6821676Sjpk uint32_t doi; 6831676Sjpk tsol_ip_label_t label_type; 6841676Sjpk const cipso_option_t *co; 6851676Sjpk const void *src; 6861676Sjpk const ip6_t *ip6h; 6871676Sjpk 6881676Sjpk ASSERT(DB_TYPE(mp) == M_DATA); 6891676Sjpk 6901676Sjpk if (version == IPV4_VERSION) { 6911676Sjpk ipha = (const ipha_t *)mp->b_rptr; 6921676Sjpk src = &ipha->ipha_src; 6931676Sjpk label_type = tsol_get_option(mp, &opt_ptr); 6941676Sjpk } else { 6951676Sjpk uchar_t *after_secopt; 6961676Sjpk boolean_t hbh_needed; 6971676Sjpk const uchar_t *ip6hbh; 6981676Sjpk size_t optlen; 6991676Sjpk 7001676Sjpk label_type = OPT_NONE; 7011676Sjpk ip6h = (const ip6_t *)mp->b_rptr; 7021676Sjpk src = &ip6h->ip6_src; 7031676Sjpk if (ip6h->ip6_nxt == IPPROTO_HOPOPTS) { 7041676Sjpk ip6hbh = (const uchar_t *)&ip6h[1]; 7051676Sjpk optlen = (ip6hbh[1] + 1) << 3; 7061676Sjpk ASSERT(ip6hbh + optlen <= mp->b_wptr); 7071676Sjpk opt_ptr = tsol_find_secopt_v6(ip6hbh, optlen, 7081676Sjpk &after_secopt, &hbh_needed); 7091676Sjpk /* tsol_find_secopt_v6 guarantees some sanity */ 7101676Sjpk if (opt_ptr != NULL && 7111676Sjpk (optlen = opt_ptr[1]) >= 8) { 7121676Sjpk opt_ptr += 2; 7131676Sjpk bcopy(opt_ptr, &doi, sizeof (doi)); 7141676Sjpk doi = ntohl(doi); 7151676Sjpk if (doi == IP6LS_DOI_V4 && 7161676Sjpk opt_ptr[4] == IP6LS_TT_V4 && 7171676Sjpk opt_ptr[5] <= optlen - 4 && 7181676Sjpk opt_ptr[7] <= optlen - 6) { 7191676Sjpk opt_ptr += sizeof (doi) + 2; 7201676Sjpk label_type = OPT_CIPSO; 7211676Sjpk } 7221676Sjpk } 7231676Sjpk } 7241676Sjpk } 7251676Sjpk 7261676Sjpk switch (label_type) { 7271676Sjpk case OPT_CIPSO: 7281676Sjpk /* 7291676Sjpk * Convert the CIPSO label to the internal format 7301676Sjpk * and attach it to the dblk cred. 7311676Sjpk * Validity checks based on restrictions defined in 7321676Sjpk * COMMERCIAL IP SECURITY OPTION (CIPSO 2.2) 7331676Sjpk * (draft-ietf-cipso-ipsecurity) 7341676Sjpk */ 7351676Sjpk if (version == IPV6_VERSION && ip6opt_ls == 0) 7361676Sjpk return (B_FALSE); 7371676Sjpk co = (const struct cipso_option *)opt_ptr; 7381676Sjpk if ((co->cipso_length < 7391676Sjpk TSOL_CIPSO_TAG_OFFSET + TSOL_TT1_MIN_LENGTH) || 7401676Sjpk (co->cipso_length > IP_MAX_OPT_LENGTH)) 7411676Sjpk return (B_FALSE); 7421676Sjpk bcopy(co->cipso_doi, &doi, sizeof (doi)); 7431676Sjpk doi = ntohl(doi); 7441676Sjpk if (!cipso_to_sl(opt_ptr, &sl)) 7451676Sjpk return (B_FALSE); 7461676Sjpk setbltype(&sl, SUN_SL_ID); 7471676Sjpk break; 7481676Sjpk 7491676Sjpk case OPT_NONE: 7501676Sjpk /* 7511676Sjpk * Handle special cases that are not currently labeled, even 7521676Sjpk * though the sending system may otherwise be configured as 7531676Sjpk * labeled. 7541676Sjpk * - IGMP 7551676Sjpk * - IPv4 ICMP Router Discovery 7561676Sjpk * - IPv6 Neighbor Discovery 7571676Sjpk */ 7581676Sjpk if (version == IPV4_VERSION) { 7591676Sjpk if (ipha->ipha_protocol == IPPROTO_IGMP) 7601676Sjpk return (B_TRUE); 7611676Sjpk if (ipha->ipha_protocol == IPPROTO_ICMP) { 7621676Sjpk const struct icmp *icmp = (const struct icmp *) 7631676Sjpk (mp->b_rptr + IPH_HDR_LENGTH(ipha)); 7641676Sjpk 7651676Sjpk if ((uchar_t *)icmp > mp->b_wptr) { 7661676Sjpk if (!pullupmsg(mp, 7671676Sjpk (uchar_t *)icmp - mp->b_rptr + 1)) 7681676Sjpk return (B_FALSE); 7691676Sjpk icmp = (const struct icmp *) 7701676Sjpk (mp->b_rptr + 7711676Sjpk IPH_HDR_LENGTH(ipha)); 7721676Sjpk } 7731676Sjpk if (icmp->icmp_type == ICMP_ROUTERADVERT || 7741676Sjpk icmp->icmp_type == ICMP_ROUTERSOLICIT) 7751676Sjpk return (B_TRUE); 7761676Sjpk } 7771676Sjpk src = &ipha->ipha_src; 7781676Sjpk } else { 7791676Sjpk if (ip6h->ip6_nxt == IPPROTO_ICMPV6) { 7801676Sjpk const icmp6_t *icmp6 = (const icmp6_t *) 7811676Sjpk (mp->b_rptr + IPV6_HDR_LEN); 7821676Sjpk 7831676Sjpk if ((uchar_t *)icmp6 + ICMP6_MINLEN > 7841676Sjpk mp->b_wptr) { 7851676Sjpk if (!pullupmsg(mp, 7861676Sjpk (uchar_t *)icmp6 - mp->b_rptr + 7871676Sjpk ICMP6_MINLEN)) 7881676Sjpk return (B_FALSE); 7891676Sjpk icmp6 = (const icmp6_t *) 7901676Sjpk (mp->b_rptr + IPV6_HDR_LEN); 7911676Sjpk } 7921676Sjpk if (icmp6->icmp6_type >= MLD_LISTENER_QUERY && 7931676Sjpk icmp6->icmp6_type <= ICMP6_MAX_INFO_TYPE) 7941676Sjpk return (B_TRUE); 7951676Sjpk } 7961676Sjpk src = &ip6h->ip6_src; 7971676Sjpk } 7981676Sjpk 7991676Sjpk /* 8001676Sjpk * Look up the tnrhtp database and get the implicit label 8011676Sjpk * that is associated with this unlabeled host and attach 8021676Sjpk * it to the packet. 8031676Sjpk */ 8041676Sjpk if ((src_rhtp = find_tpc(src, version, B_FALSE)) == NULL) 8051676Sjpk return (B_FALSE); 8061676Sjpk 8071676Sjpk /* If the sender is labeled, drop the unlabeled packet. */ 8081676Sjpk if (src_rhtp->tpc_tp.host_type != UNLABELED) { 8091676Sjpk TPC_RELE(src_rhtp); 8101676Sjpk pr_addr_dbg("unlabeled packet forged from %s\n", 8111676Sjpk version == IPV4_VERSION ? AF_INET : AF_INET6, src); 8121676Sjpk return (B_FALSE); 8131676Sjpk } 8141676Sjpk 8151676Sjpk sl = src_rhtp->tpc_tp.tp_def_label; 8161676Sjpk setbltype(&sl, SUN_SL_ID); 8171676Sjpk doi = src_rhtp->tpc_tp.tp_doi; 8181676Sjpk TPC_RELE(src_rhtp); 8191676Sjpk break; 8201676Sjpk 8211676Sjpk default: 8221676Sjpk return (B_FALSE); 8231676Sjpk } 8241676Sjpk 8251676Sjpk /* Make sure no other thread is messing with this mblk */ 8261676Sjpk ASSERT(DB_REF(mp) == 1); 8271676Sjpk if (DB_CRED(mp) == NULL) { 8281676Sjpk DB_CRED(mp) = newcred_from_bslabel(&sl, doi, KM_NOSLEEP); 8291676Sjpk if (DB_CRED(mp) == NULL) 8301676Sjpk return (B_FALSE); 8311676Sjpk } else { 8321676Sjpk cred_t *newcr; 8331676Sjpk 8341676Sjpk newcr = copycred_from_bslabel(DB_CRED(mp), &sl, doi, 8351676Sjpk KM_NOSLEEP); 8361676Sjpk if (newcr == NULL) 8371676Sjpk return (B_FALSE); 8381676Sjpk crfree(DB_CRED(mp)); 8391676Sjpk DB_CRED(mp) = newcr; 8401676Sjpk } 8411676Sjpk 8421676Sjpk /* 8431676Sjpk * If the source was unlabeled, then flag as such, 8441676Sjpk * while remembering that CIPSO routers add headers. 8451676Sjpk */ 8461676Sjpk if (label_type == OPT_NONE) 8471676Sjpk crgetlabel(DB_CRED(mp))->tsl_flags |= TSLF_UNLABELED; 8481676Sjpk else if (label_type == OPT_CIPSO) { 8491676Sjpk if ((src_rhtp = find_tpc(src, version, B_FALSE)) == NULL) 8501676Sjpk return (B_FALSE); 8511676Sjpk if (src_rhtp->tpc_tp.host_type == UNLABELED) 8521676Sjpk crgetlabel(DB_CRED(mp))->tsl_flags |= 8531676Sjpk TSLF_UNLABELED; 8541676Sjpk TPC_RELE(src_rhtp); 8551676Sjpk } 8561676Sjpk 8571676Sjpk return (B_TRUE); 8581676Sjpk } 8591676Sjpk 8601676Sjpk /* 8611676Sjpk * This routine determines whether the given packet should be accepted locally. 8621676Sjpk * It does a range/set check on the packet's label by looking up the given 8631676Sjpk * address in the remote host database. 8641676Sjpk */ 8651676Sjpk boolean_t 8661676Sjpk tsol_receive_local(const mblk_t *mp, const void *addr, uchar_t version, 8671676Sjpk boolean_t shared_addr, const conn_t *connp) 8681676Sjpk { 8691676Sjpk const cred_t *credp; 8701676Sjpk ts_label_t *plabel, *conn_plabel; 8711676Sjpk tsol_tpc_t *tp; 8721676Sjpk boolean_t retv; 8731676Sjpk const bslabel_t *label, *conn_label; 8741676Sjpk 8751676Sjpk /* 8761676Sjpk * The cases in which this can happen are: 8771676Sjpk * - IPv6 Router Alert, where ip_rput_data_v6 deliberately skips 8781676Sjpk * over the label attachment process. 8791676Sjpk * - MLD output looped-back to ourselves. 8801676Sjpk * - IPv4 Router Discovery, where tsol_get_pkt_label intentionally 8811676Sjpk * avoids the labeling process. 8821676Sjpk * We trust that all valid paths in the code set the cred pointer when 8831676Sjpk * needed. 8841676Sjpk */ 8851676Sjpk if ((credp = DB_CRED(mp)) == NULL) 8861676Sjpk return (B_TRUE); 8871676Sjpk 8881676Sjpk /* 8891676Sjpk * If this packet is from the inside (not a remote host) and has the 8901676Sjpk * same zoneid as the selected destination, then no checks are 8911676Sjpk * necessary. Membership in the zone is enough proof. This is 8921676Sjpk * intended to be a hot path through this function. 8931676Sjpk */ 8941676Sjpk if (!crisremote(credp) && 8951676Sjpk crgetzone(credp) == crgetzone(connp->conn_cred)) 8961676Sjpk return (B_TRUE); 8971676Sjpk 8981676Sjpk plabel = crgetlabel(credp); 8991676Sjpk conn_plabel = crgetlabel(connp->conn_cred); 9001676Sjpk ASSERT(plabel != NULL && conn_plabel != NULL); 9011676Sjpk 9021676Sjpk label = label2bslabel(plabel); 9031676Sjpk conn_label = label2bslabel(crgetlabel(connp->conn_cred)); 9041676Sjpk 9051676Sjpk /* 9061676Sjpk * MLPs are always validated using the range and set of the local 9071676Sjpk * address, even when the remote host is unlabeled. 9081676Sjpk */ 9091676Sjpk if (connp->conn_mlp_type == mlptBoth || 9101676Sjpk /* LINTED: no consequent */ 9111676Sjpk connp->conn_mlp_type == (shared_addr ? mlptShared : mlptPrivate)) { 9121676Sjpk ; 9131676Sjpk 9141676Sjpk /* 9151676Sjpk * If this is a packet from an unlabeled sender, then we must apply 9161676Sjpk * different rules. If the label is equal to the zone's label, then 9171676Sjpk * it's allowed. If it's not equal, but the zone is either the global 9181676Sjpk * zone or the label is dominated by the zone's label, then allow it 9191676Sjpk * as long as it's in the range configured for the destination. 9201676Sjpk */ 9211676Sjpk } else if (plabel->tsl_flags & TSLF_UNLABELED) { 9221676Sjpk if (plabel->tsl_doi == conn_plabel->tsl_doi && 9231676Sjpk blequal(label, conn_label)) 9241676Sjpk return (B_TRUE); 9251676Sjpk 9261676Sjpk if (!connp->conn_mac_exempt || 9271676Sjpk (connp->conn_zoneid != GLOBAL_ZONEID && 9281676Sjpk (plabel->tsl_doi != conn_plabel->tsl_doi || 9291676Sjpk !bldominates(conn_label, label)))) { 9301676Sjpk DTRACE_PROBE3( 9311676Sjpk tx__ip__log__drop__receivelocal__mac_unl, 9321676Sjpk char *, 9331676Sjpk "unlabeled packet mp(1) fails mac for conn(2)", 9341676Sjpk mblk_t *, mp, conn_t *, connp); 9351676Sjpk return (B_FALSE); 9361676Sjpk } 9371676Sjpk 9381676Sjpk /* 9391676Sjpk * If this is a private address and the connection is SLP for private 9401676Sjpk * addresses, then the only thing that matters is the label on the 9411676Sjpk * zone, which is the same as the label on the connection. We don't 9421676Sjpk * care (and don't have to care) about the tnrhdb. 9431676Sjpk */ 9441676Sjpk } else if (!shared_addr) { 9451676Sjpk /* 9461676Sjpk * Since this is a zone-specific address, we know that any MLP 9471676Sjpk * case should have been handled up above. That means this 9481676Sjpk * connection must not be MLP for zone-specific addresses. We 9491676Sjpk * assert that to be true. 9501676Sjpk */ 9511676Sjpk ASSERT(connp->conn_mlp_type == mlptSingle || 9521676Sjpk connp->conn_mlp_type == mlptShared); 9531676Sjpk if (plabel->tsl_doi == conn_plabel->tsl_doi && 9541676Sjpk blequal(label, conn_label)) 9551676Sjpk return (B_TRUE); 9561676Sjpk DTRACE_PROBE3(tx__ip__log__drop__receivelocal__mac__slp, 9571676Sjpk char *, "packet mp(1) fails exactly SLP match conn(2)", 9581676Sjpk mblk_t *, mp, conn_t *, connp); 9591676Sjpk return (B_FALSE); 9601676Sjpk } 9611676Sjpk 9621676Sjpk tp = find_tpc(addr, version, B_FALSE); 9631676Sjpk if (tp == NULL) { 9641676Sjpk DTRACE_PROBE3(tx__ip__log__drop__receivelocal__no__tnr, 9651676Sjpk char *, "dropping mp(1), host(2) lacks entry", 9661676Sjpk mblk_t *, mp, void *, addr); 9671676Sjpk return (B_FALSE); 9681676Sjpk } 9691676Sjpk 9701676Sjpk /* 9711676Sjpk * The local host address should not be unlabeled at this point. The 9721676Sjpk * only way this can happen is that the destination isn't unicast. We 9731676Sjpk * assume that the packet should not have had a label, and thus should 9741676Sjpk * have been handled by the TSLF_UNLABELED logic above. 9751676Sjpk */ 9761676Sjpk if (tp->tpc_tp.host_type == UNLABELED) { 9771676Sjpk retv = B_FALSE; 9781676Sjpk DTRACE_PROBE3(tx__ip__log__drop__receivelocal__flag, char *, 9791676Sjpk "mp(1) unlabeled source, but tp is not unlabeled.", 9801676Sjpk mblk_t *, mp, tsol_tpc_t *, tp); 9811676Sjpk 9821676Sjpk } else if (tp->tpc_tp.host_type != SUN_CIPSO) { 9831676Sjpk retv = B_FALSE; 9841676Sjpk DTRACE_PROBE3(tx__ip__log__drop__receivelocal__tptype, char *, 9851676Sjpk "delivering mp(1), found unrecognized tpc(2) type.", 9861676Sjpk mblk_t *, mp, tsol_tpc_t *, tp); 9871676Sjpk 9881676Sjpk } else if (plabel->tsl_doi != tp->tpc_tp.tp_doi) { 9891676Sjpk retv = B_FALSE; 9901676Sjpk DTRACE_PROBE3(tx__ip__log__drop__receivelocal__mac, char *, 9911676Sjpk "mp(1) could not be delievered to tp(2), doi mismatch", 9921676Sjpk mblk_t *, mp, tsol_tpc_t *, tp); 9931676Sjpk 9941676Sjpk } else if (!_blinrange(label, &tp->tpc_tp.tp_sl_range_cipso) && 9951676Sjpk !blinlset(label, tp->tpc_tp.tp_sl_set_cipso)) { 9961676Sjpk retv = B_FALSE; 9971676Sjpk DTRACE_PROBE3(tx__ip__log__drop__receivelocal__mac, char *, 9981676Sjpk "mp(1) could not be delievered to tp(2), bad mac", 9991676Sjpk mblk_t *, mp, tsol_tpc_t *, tp); 10001676Sjpk } else { 10011676Sjpk retv = B_TRUE; 10021676Sjpk } 10031676Sjpk 10041676Sjpk TPC_RELE(tp); 10051676Sjpk 10061676Sjpk return (retv); 10071676Sjpk } 10081676Sjpk 10091676Sjpk boolean_t 10101676Sjpk tsol_can_accept_raw(mblk_t *mp, boolean_t check_host) 10111676Sjpk { 10121676Sjpk ts_label_t *plabel = NULL; 10131676Sjpk tsol_tpc_t *src_rhtp, *dst_rhtp; 10141676Sjpk boolean_t retv; 10151676Sjpk 10161676Sjpk if (DB_CRED(mp) != NULL) 10171676Sjpk plabel = crgetlabel(DB_CRED(mp)); 10181676Sjpk 10191676Sjpk /* We are bootstrapping or the internal template was never deleted */ 10201676Sjpk if (plabel == NULL) 10211676Sjpk return (B_TRUE); 10221676Sjpk 10231676Sjpk if (IPH_HDR_VERSION(mp->b_rptr) == IPV4_VERSION) { 10241676Sjpk ipha_t *ipha = (ipha_t *)mp->b_rptr; 10251676Sjpk 10261676Sjpk src_rhtp = find_tpc(&ipha->ipha_src, IPV4_VERSION, 10271676Sjpk B_FALSE); 10281676Sjpk if (src_rhtp == NULL) 10291676Sjpk return (B_FALSE); 10301676Sjpk dst_rhtp = find_tpc(&ipha->ipha_dst, IPV4_VERSION, 10311676Sjpk B_FALSE); 10321676Sjpk } else { 10331676Sjpk ip6_t *ip6h = (ip6_t *)mp->b_rptr; 10341676Sjpk 10351676Sjpk src_rhtp = find_tpc(&ip6h->ip6_src, IPV6_VERSION, 10361676Sjpk B_FALSE); 10371676Sjpk if (src_rhtp == NULL) 10381676Sjpk return (B_FALSE); 10391676Sjpk dst_rhtp = find_tpc(&ip6h->ip6_dst, IPV6_VERSION, 10401676Sjpk B_FALSE); 10411676Sjpk } 10421676Sjpk if (dst_rhtp == NULL) { 10431676Sjpk TPC_RELE(src_rhtp); 10441676Sjpk return (B_FALSE); 10451676Sjpk } 10461676Sjpk 10471676Sjpk if (label2doi(plabel) != src_rhtp->tpc_tp.tp_doi) { 10481676Sjpk retv = B_FALSE; 10491676Sjpk 10501676Sjpk /* 10511676Sjpk * Check that the packet's label is in the correct range for labeled 10521676Sjpk * sender, or is equal to the default label for unlabeled sender. 10531676Sjpk */ 10541676Sjpk } else if ((src_rhtp->tpc_tp.host_type != UNLABELED && 10551676Sjpk !_blinrange(label2bslabel(plabel), 10561676Sjpk &src_rhtp->tpc_tp.tp_sl_range_cipso) && 10571676Sjpk !blinlset(label2bslabel(plabel), 10581676Sjpk src_rhtp->tpc_tp.tp_sl_set_cipso)) || 10591676Sjpk (src_rhtp->tpc_tp.host_type == UNLABELED && 10601676Sjpk !blequal(&plabel->tsl_label, &src_rhtp->tpc_tp.tp_def_label))) { 10611676Sjpk retv = B_FALSE; 10621676Sjpk 10631676Sjpk } else if (check_host) { 10641676Sjpk retv = B_TRUE; 10651676Sjpk 10661676Sjpk /* 10671676Sjpk * Until we have SL range in the Zone structure, pass it 10681676Sjpk * when our own address lookup returned an internal entry. 10691676Sjpk */ 10701676Sjpk } else switch (dst_rhtp->tpc_tp.host_type) { 10711676Sjpk case UNLABELED: 10721676Sjpk retv = B_TRUE; 10731676Sjpk break; 10741676Sjpk 10751676Sjpk case SUN_CIPSO: 10761676Sjpk retv = _blinrange(label2bslabel(plabel), 10771676Sjpk &dst_rhtp->tpc_tp.tp_sl_range_cipso) || 10781676Sjpk blinlset(label2bslabel(plabel), 10791676Sjpk dst_rhtp->tpc_tp.tp_sl_set_cipso); 10801676Sjpk break; 10811676Sjpk 10821676Sjpk default: 10831676Sjpk retv = B_FALSE; 10841676Sjpk } 10851676Sjpk TPC_RELE(src_rhtp); 10861676Sjpk TPC_RELE(dst_rhtp); 10871676Sjpk return (retv); 10881676Sjpk } 10891676Sjpk 10901676Sjpk /* 10911676Sjpk * This routine determines whether a response to a failed packet delivery or 10921676Sjpk * connection should be sent back. By default, the policy is to allow such 10931676Sjpk * messages to be sent at all times, as these messages reveal little useful 10941676Sjpk * information and are healthy parts of TCP/IP networking. 10951676Sjpk * 10961676Sjpk * If tsol_strict_error is set, then we do strict tests: if the packet label is 10971676Sjpk * within the label range/set of this host/zone, return B_TRUE; otherwise 10981676Sjpk * return B_FALSE, which causes the packet to be dropped silently. 10991676Sjpk * 11001676Sjpk * Note that tsol_get_pkt_label will cause the packet to drop if the sender is 11011676Sjpk * marked as labeled in the remote host database, but the packet lacks a label. 11021676Sjpk * This means that we don't need to do a lookup on the source; the 11031676Sjpk * TSLF_UNLABELED flag is sufficient. 11041676Sjpk */ 11051676Sjpk boolean_t 11061676Sjpk tsol_can_reply_error(const mblk_t *mp) 11071676Sjpk { 11081676Sjpk ts_label_t *plabel = NULL; 11091676Sjpk tsol_tpc_t *rhtp; 11101676Sjpk const ipha_t *ipha; 11111676Sjpk const ip6_t *ip6h; 11121676Sjpk boolean_t retv; 11131676Sjpk bslabel_t *pktbs; 11141676Sjpk 11151676Sjpk /* Caller must pull up at least the IP header */ 11161676Sjpk ASSERT(MBLKL(mp) >= (IPH_HDR_VERSION(mp->b_rptr) == IPV4_VERSION ? 11171676Sjpk sizeof (*ipha) : sizeof (*ip6h))); 11181676Sjpk 11191676Sjpk if (!tsol_strict_error) 11201676Sjpk return (B_TRUE); 11211676Sjpk 11221676Sjpk if (DB_CRED(mp) != NULL) 11231676Sjpk plabel = crgetlabel(DB_CRED(mp)); 11241676Sjpk 11251676Sjpk /* We are bootstrapping or the internal template was never deleted */ 11261676Sjpk if (plabel == NULL) 11271676Sjpk return (B_TRUE); 11281676Sjpk 11291676Sjpk if (IPH_HDR_VERSION(mp->b_rptr) == IPV4_VERSION) { 11301676Sjpk ipha = (const ipha_t *)mp->b_rptr; 11311676Sjpk rhtp = find_tpc(&ipha->ipha_dst, IPV4_VERSION, B_FALSE); 11321676Sjpk } else { 11331676Sjpk ip6h = (const ip6_t *)mp->b_rptr; 11341676Sjpk rhtp = find_tpc(&ip6h->ip6_dst, IPV6_VERSION, B_FALSE); 11351676Sjpk } 11361676Sjpk 11371676Sjpk if (rhtp == NULL || label2doi(plabel) != rhtp->tpc_tp.tp_doi) { 11381676Sjpk retv = B_FALSE; 11391676Sjpk } else { 11401676Sjpk /* 11411676Sjpk * If we're in the midst of forwarding, then the destination 11421676Sjpk * address might not be labeled. In that case, allow unlabeled 11431676Sjpk * packets through only if the default label is the same, and 11441676Sjpk * labeled ones if they dominate. 11451676Sjpk */ 11461676Sjpk pktbs = label2bslabel(plabel); 11471676Sjpk switch (rhtp->tpc_tp.host_type) { 11481676Sjpk case UNLABELED: 11491676Sjpk if (plabel->tsl_flags & TSLF_UNLABELED) { 11501676Sjpk retv = blequal(pktbs, 11511676Sjpk &rhtp->tpc_tp.tp_def_label); 11521676Sjpk } else { 11531676Sjpk retv = bldominates(pktbs, 11541676Sjpk &rhtp->tpc_tp.tp_def_label); 11551676Sjpk } 11561676Sjpk break; 11571676Sjpk 11581676Sjpk case SUN_CIPSO: 11591676Sjpk retv = _blinrange(pktbs, 11601676Sjpk &rhtp->tpc_tp.tp_sl_range_cipso) || 11611676Sjpk blinlset(pktbs, rhtp->tpc_tp.tp_sl_set_cipso); 11621676Sjpk break; 11631676Sjpk 11641676Sjpk default: 11651676Sjpk retv = B_FALSE; 11661676Sjpk break; 11671676Sjpk } 11681676Sjpk } 11691676Sjpk 11701676Sjpk if (rhtp != NULL) 11711676Sjpk TPC_RELE(rhtp); 11721676Sjpk 11731676Sjpk return (retv); 11741676Sjpk } 11751676Sjpk 11761676Sjpk /* 11771676Sjpk * Finds the zone associated with the given packet. Returns GLOBAL_ZONEID if 11781676Sjpk * the zone cannot be located. 11791676Sjpk * 11801676Sjpk * This is used by the classifier when the packet matches an ALL_ZONES IRE, and 11811676Sjpk * there's no MLP defined. 11821676Sjpk */ 11831676Sjpk zoneid_t 11841676Sjpk tsol_packet_to_zoneid(const mblk_t *mp) 11851676Sjpk { 11861676Sjpk cred_t *cr = DB_CRED(mp); 11871676Sjpk zone_t *zone; 11881676Sjpk ts_label_t *label; 11891676Sjpk 11901676Sjpk if (cr != NULL) { 11911676Sjpk if ((label = crgetlabel(cr)) != NULL) { 11921676Sjpk zone = zone_find_by_label(label); 11931676Sjpk if (zone != NULL) { 11941676Sjpk zoneid_t zoneid = zone->zone_id; 11951676Sjpk 11961676Sjpk zone_rele(zone); 11971676Sjpk return (zoneid); 11981676Sjpk } 11991676Sjpk } 12001676Sjpk } 12011676Sjpk return (GLOBAL_ZONEID); 12021676Sjpk } 12031676Sjpk 12041676Sjpk int 12051676Sjpk tsol_ire_match_gwattr(ire_t *ire, const ts_label_t *tsl) 12061676Sjpk { 12071676Sjpk int error = 0; 12081676Sjpk tsol_ire_gw_secattr_t *attrp = NULL; 12091676Sjpk tsol_tnrhc_t *gw_rhc = NULL; 12101676Sjpk tsol_gcgrp_t *gcgrp = NULL; 12111676Sjpk tsol_gc_t *gc = NULL; 12121676Sjpk in_addr_t ga_addr4; 12131676Sjpk void *paddr = NULL; 12141676Sjpk 12151676Sjpk /* Not in Trusted mode or IRE is local/loopback/broadcast/interface */ 12161676Sjpk if (!is_system_labeled() || 12171676Sjpk (ire->ire_type & (IRE_LOCAL | IRE_LOOPBACK | IRE_BROADCAST | 12181676Sjpk IRE_INTERFACE))) 12191676Sjpk goto done; 12201676Sjpk 12211676Sjpk /* 12221676Sjpk * If we don't have a label to compare with, or the IRE does not 12231676Sjpk * contain any gateway security attributes, there's not much that 12241676Sjpk * we can do. We let the former case pass, and the latter fail, 12251676Sjpk * since the IRE doesn't qualify for a match due to the lack of 12261676Sjpk * security attributes. 12271676Sjpk */ 12281676Sjpk if (tsl == NULL || ire->ire_gw_secattr == NULL) { 12291676Sjpk if (tsl != NULL) { 12301676Sjpk DTRACE_PROBE3( 12311676Sjpk tx__ip__log__drop__irematch__nogwsec, char *, 12321676Sjpk "ire(1) lacks ire_gw_secattr when matching label(2)", 12331676Sjpk ire_t *, ire, ts_label_t *, tsl); 12341676Sjpk error = EACCES; 12351676Sjpk } 12361676Sjpk goto done; 12371676Sjpk } 12381676Sjpk 12391676Sjpk attrp = ire->ire_gw_secattr; 12401676Sjpk 12411676Sjpk /* 12421676Sjpk * The possible lock order scenarios related to the tsol gateway 12431676Sjpk * attribute locks are documented at the beginning of ip.c in the 12441676Sjpk * lock order scenario section. 12451676Sjpk */ 12461676Sjpk mutex_enter(&attrp->igsa_lock); 12471676Sjpk 12481676Sjpk /* 12491676Sjpk * Depending on the IRE type (prefix vs. cache), we seek the group 12501676Sjpk * structure which contains all security credentials of the gateway. 12511676Sjpk * A prefix IRE is associated with at most one gateway credential, 12521676Sjpk * while a cache IRE is associated with every credentials that the 12531676Sjpk * gateway has. 12541676Sjpk */ 12551676Sjpk if ((gc = attrp->igsa_gc) != NULL) { /* prefix */ 12561676Sjpk gcgrp = gc->gc_grp; 12571676Sjpk ASSERT(gcgrp != NULL); 12581676Sjpk rw_enter(&gcgrp->gcgrp_rwlock, RW_READER); 12591676Sjpk } else if ((gcgrp = attrp->igsa_gcgrp) != NULL) { /* cache */ 12601676Sjpk rw_enter(&gcgrp->gcgrp_rwlock, RW_READER); 12611676Sjpk gc = gcgrp->gcgrp_head; 12621676Sjpk if (gc == NULL) { 12631676Sjpk /* gc group is empty, so the drop lock now */ 12641676Sjpk ASSERT(gcgrp->gcgrp_count == 0); 12651676Sjpk rw_exit(&gcgrp->gcgrp_rwlock); 12661676Sjpk gcgrp = NULL; 12671676Sjpk } 12681676Sjpk } 12691676Sjpk 12701676Sjpk if (gcgrp != NULL) 12711676Sjpk GCGRP_REFHOLD(gcgrp); 12721676Sjpk 12731676Sjpk if ((gw_rhc = attrp->igsa_rhc) != NULL) { 12741676Sjpk /* 12751676Sjpk * If our cached entry has grown stale, then discard it so we 12761676Sjpk * can get a new one. 12771676Sjpk */ 12781676Sjpk if (gw_rhc->rhc_invalid || gw_rhc->rhc_tpc->tpc_invalid) { 12791676Sjpk TNRHC_RELE(gw_rhc); 12801676Sjpk attrp->igsa_rhc = gw_rhc = NULL; 12811676Sjpk } else { 12821676Sjpk TNRHC_HOLD(gw_rhc) 12831676Sjpk } 12841676Sjpk } 12851676Sjpk 12861676Sjpk /* Last attempt at loading the template had failed; try again */ 12871676Sjpk if (gw_rhc == NULL) { 12881676Sjpk if (gcgrp != NULL) { 12891676Sjpk tsol_gcgrp_addr_t *ga = &gcgrp->gcgrp_addr; 12901676Sjpk 12911676Sjpk if (ire->ire_ipversion == IPV4_VERSION) { 12921676Sjpk ASSERT(ga->ga_af == AF_INET); 12931676Sjpk IN6_V4MAPPED_TO_IPADDR(&ga->ga_addr, ga_addr4); 12941676Sjpk paddr = &ga_addr4; 12951676Sjpk } else { 12961676Sjpk ASSERT(ga->ga_af == AF_INET6); 12971676Sjpk paddr = &ga->ga_addr; 12981676Sjpk } 12991676Sjpk } else if (ire->ire_ipversion == IPV6_VERSION && 13001676Sjpk !IN6_IS_ADDR_UNSPECIFIED(&ire->ire_gateway_addr_v6)) { 13011676Sjpk paddr = &ire->ire_gateway_addr_v6; 13021676Sjpk } else if (ire->ire_ipversion == IPV4_VERSION && 13031676Sjpk ire->ire_gateway_addr != INADDR_ANY) { 13041676Sjpk paddr = &ire->ire_gateway_addr; 13051676Sjpk } 13061676Sjpk 13071676Sjpk /* We've found a gateway address to do the template lookup */ 13081676Sjpk if (paddr != NULL) { 13091676Sjpk ASSERT(gw_rhc == NULL); 13101676Sjpk if (ire->ire_ipversion == IPV4_VERSION) 13111676Sjpk gw_rhc = find_rhc_v4(paddr); 13121676Sjpk else 13131676Sjpk gw_rhc = find_rhc_v6(paddr); 13141676Sjpk if (gw_rhc != NULL) { 13151676Sjpk /* 13161676Sjpk * Note that if the lookup above returned an 13171676Sjpk * internal template, we'll use it for the 13181676Sjpk * time being, and do another lookup next 13191676Sjpk * time around. 13201676Sjpk */ 13211676Sjpk /* Another thread has loaded the template? */ 13221676Sjpk if (attrp->igsa_rhc != NULL) { 13231676Sjpk TNRHC_RELE(gw_rhc) 13241676Sjpk /* reload, it could be different */ 13251676Sjpk gw_rhc = attrp->igsa_rhc; 13261676Sjpk } else { 13271676Sjpk attrp->igsa_rhc = gw_rhc; 13281676Sjpk } 13291676Sjpk /* 13301676Sjpk * Hold an extra reference just like we did 13311676Sjpk * above prior to dropping the igsa_lock. 13321676Sjpk */ 13331676Sjpk TNRHC_HOLD(gw_rhc) 13341676Sjpk } 13351676Sjpk } 13361676Sjpk } 13371676Sjpk 13381676Sjpk mutex_exit(&attrp->igsa_lock); 13391676Sjpk /* Gateway template not found */ 13401676Sjpk if (gw_rhc == NULL) { 13411676Sjpk /* 13421676Sjpk * If destination address is directly reachable through an 13431676Sjpk * interface rather than through a learned route, pass it. 13441676Sjpk */ 13451676Sjpk if (paddr != NULL) { 13461676Sjpk DTRACE_PROBE3( 13471676Sjpk tx__ip__log__drop__irematch__nogwtmpl, char *, 13481676Sjpk "ire(1), label(2) off-link with no gw_rhc", 13491676Sjpk ire_t *, ire, ts_label_t *, tsl); 13501676Sjpk error = EINVAL; 13511676Sjpk } 13521676Sjpk goto done; 13531676Sjpk } 13541676Sjpk 13551676Sjpk if (gc != NULL) { 13561676Sjpk tsol_gcdb_t *gcdb; 13571676Sjpk /* 13581676Sjpk * In the case of IRE_CACHE we've got one or more gateway 13591676Sjpk * security credentials to compare against the passed in label. 13601676Sjpk * Perform label range comparison against each security 13611676Sjpk * credential of the gateway. In the case of a prefix ire 13621676Sjpk * we need to match against the security attributes of 13631676Sjpk * just the route itself, so the loop is executed only once. 13641676Sjpk */ 13651676Sjpk ASSERT(gcgrp != NULL); 13661676Sjpk do { 13671676Sjpk gcdb = gc->gc_db; 13681676Sjpk if (tsl->tsl_doi == gcdb->gcdb_doi && 13691676Sjpk _blinrange(&tsl->tsl_label, &gcdb->gcdb_slrange)) 13701676Sjpk break; 13711676Sjpk if (ire->ire_type == IRE_CACHE) 13721676Sjpk gc = gc->gc_next; 13731676Sjpk else 13741676Sjpk gc = NULL; 13751676Sjpk } while (gc != NULL); 13761676Sjpk 13771676Sjpk if (gc == NULL) { 13781676Sjpk DTRACE_PROBE3( 13791676Sjpk tx__ip__log__drop__irematch__nogcmatched, 13801676Sjpk char *, "ire(1), tsl(2): all gc failed match", 13811676Sjpk ire_t *, ire, ts_label_t *, tsl); 13821676Sjpk error = EACCES; 13831676Sjpk } 13841676Sjpk } else { 13851676Sjpk /* 13861676Sjpk * We didn't find any gateway credentials in the IRE 13871676Sjpk * attributes; fall back to the gateway's template for 13881676Sjpk * label range checks, if we are required to do so. 13891676Sjpk */ 13901676Sjpk ASSERT(gw_rhc != NULL); 13911676Sjpk switch (gw_rhc->rhc_tpc->tpc_tp.host_type) { 13921676Sjpk case SUN_CIPSO: 13931676Sjpk if (tsl->tsl_doi != 13941676Sjpk gw_rhc->rhc_tpc->tpc_tp.tp_doi || 13951676Sjpk (!_blinrange(&tsl->tsl_label, 13961676Sjpk &gw_rhc->rhc_tpc->tpc_tp. 13971676Sjpk tp_sl_range_cipso) && 13981676Sjpk !blinlset(&tsl->tsl_label, 13991676Sjpk gw_rhc->rhc_tpc->tpc_tp.tp_sl_set_cipso))) { 14001676Sjpk error = EACCES; 14011676Sjpk DTRACE_PROBE4( 14021676Sjpk tx__ip__log__drop__irematch__deftmpl, 14031676Sjpk char *, "ire(1), tsl(2), gw_rhc(3) " 14041676Sjpk "failed match (cipso gw)", 14051676Sjpk ire_t *, ire, ts_label_t *, tsl, 14061676Sjpk tsol_tnrhc_t *, gw_rhc); 14071676Sjpk } 14081676Sjpk break; 14091676Sjpk 14101676Sjpk case UNLABELED: 14111676Sjpk if (tsl->tsl_doi != 14121676Sjpk gw_rhc->rhc_tpc->tpc_tp.tp_doi || 14131676Sjpk (!_blinrange(&tsl->tsl_label, 14141676Sjpk &gw_rhc->rhc_tpc->tpc_tp.tp_gw_sl_range) && 14151676Sjpk !blinlset(&tsl->tsl_label, 14161676Sjpk gw_rhc->rhc_tpc->tpc_tp.tp_gw_sl_set))) { 14171676Sjpk error = EACCES; 14181676Sjpk DTRACE_PROBE4( 14191676Sjpk tx__ip__log__drop__irematch__deftmpl, 14201676Sjpk char *, "ire(1), tsl(2), gw_rhc(3) " 14211676Sjpk "failed match (unlabeled gw)", 14221676Sjpk ire_t *, ire, ts_label_t *, tsl, 14231676Sjpk tsol_tnrhc_t *, gw_rhc); 14241676Sjpk } 14251676Sjpk break; 14261676Sjpk } 14271676Sjpk } 14281676Sjpk 14291676Sjpk done: 14301676Sjpk 14311676Sjpk if (gcgrp != NULL) { 14321676Sjpk rw_exit(&gcgrp->gcgrp_rwlock); 14331676Sjpk GCGRP_REFRELE(gcgrp); 14341676Sjpk } 14351676Sjpk 14361676Sjpk if (gw_rhc != NULL) 14371676Sjpk TNRHC_RELE(gw_rhc) 14381676Sjpk 14391676Sjpk return (error); 14401676Sjpk } 14411676Sjpk 14421676Sjpk /* 14431676Sjpk * Performs label accreditation checks for packet forwarding. 14441676Sjpk * 14451676Sjpk * Returns a pointer to the modified mblk if allowed for forwarding, 14461676Sjpk * or NULL if the packet must be dropped. 14471676Sjpk */ 14481676Sjpk mblk_t * 14491676Sjpk tsol_ip_forward(ire_t *ire, mblk_t *mp) 14501676Sjpk { 14511676Sjpk tsol_ire_gw_secattr_t *attrp = NULL; 14521676Sjpk ipha_t *ipha; 14531676Sjpk ip6_t *ip6h; 14541676Sjpk const void *pdst; 14551676Sjpk const void *psrc; 14561676Sjpk boolean_t off_link; 14571676Sjpk tsol_tpc_t *dst_rhtp, *gw_rhtp; 14581676Sjpk tsol_ip_label_t label_type; 14591676Sjpk uchar_t *opt_ptr = NULL; 14601676Sjpk ts_label_t *tsl; 14611676Sjpk uint8_t proto; 14621676Sjpk int af, adjust; 14631676Sjpk uint16_t iplen; 1464*2535Ssangeeta boolean_t need_tpc_rele = B_FALSE; 1465*2535Ssangeeta ipaddr_t *gw; 14661676Sjpk 14671676Sjpk ASSERT(ire != NULL && mp != NULL); 14681676Sjpk ASSERT(ire->ire_stq != NULL); 14691676Sjpk 14701676Sjpk af = (ire->ire_ipversion == IPV4_VERSION) ? AF_INET : AF_INET6; 14711676Sjpk 14721676Sjpk if (IPH_HDR_VERSION(mp->b_rptr) == IPV4_VERSION) { 14731676Sjpk ASSERT(ire->ire_ipversion == IPV4_VERSION); 14741676Sjpk ipha = (ipha_t *)mp->b_rptr; 14751676Sjpk psrc = &ipha->ipha_src; 14761676Sjpk pdst = &ipha->ipha_dst; 14771676Sjpk proto = ipha->ipha_protocol; 14781676Sjpk 1479*2535Ssangeeta /* 1480*2535Ssangeeta * off_link is TRUE if destination not directly reachable. 1481*2535Ssangeeta * Surya note: we avoid creation of per-dst IRE_CACHE entries 1482*2535Ssangeeta * for forwarded packets, so we set off_link to be TRUE 1483*2535Ssangeeta * if the packet dst is different from the ire_addr of 1484*2535Ssangeeta * the ire for the nexthop. 1485*2535Ssangeeta */ 1486*2535Ssangeeta off_link = ((ipha->ipha_dst != ire->ire_addr) || 1487*2535Ssangeeta (ire->ire_gateway_addr != INADDR_ANY)); 14881676Sjpk } else { 14891676Sjpk ASSERT(ire->ire_ipversion == IPV6_VERSION); 14901676Sjpk ip6h = (ip6_t *)mp->b_rptr; 14911676Sjpk psrc = &ip6h->ip6_src; 14921676Sjpk pdst = &ip6h->ip6_dst; 14931676Sjpk proto = ip6h->ip6_nxt; 14941676Sjpk 14951676Sjpk if (proto != IPPROTO_TCP && proto != IPPROTO_UDP && 14961676Sjpk proto != IPPROTO_ICMPV6) { 14971676Sjpk uint8_t *nexthdrp; 14981676Sjpk uint16_t hdr_len; 14991676Sjpk 15001676Sjpk if (!ip_hdr_length_nexthdr_v6(mp, ip6h, &hdr_len, 15011676Sjpk &nexthdrp)) { 15021676Sjpk /* malformed packet; drop it */ 15031676Sjpk return (NULL); 15041676Sjpk } 15051676Sjpk proto = *nexthdrp; 15061676Sjpk } 15071676Sjpk 15081676Sjpk /* destination not directly reachable? */ 15091676Sjpk off_link = !IN6_IS_ADDR_UNSPECIFIED(&ire->ire_gateway_addr_v6); 15101676Sjpk } 15111676Sjpk 15121676Sjpk if ((tsl = MBLK_GETLABEL(mp)) == NULL) 15131676Sjpk return (mp); 15141676Sjpk 15151676Sjpk label_type = tsol_get_option(mp, &opt_ptr); 15161676Sjpk 15171676Sjpk ASSERT(psrc != NULL && pdst != NULL); 15181676Sjpk dst_rhtp = find_tpc(pdst, ire->ire_ipversion, B_FALSE); 15191676Sjpk 15201676Sjpk if (dst_rhtp == NULL) { 15211676Sjpk /* 15221676Sjpk * Without a template we do not know if forwarding 15231676Sjpk * violates MAC 15241676Sjpk */ 15251676Sjpk DTRACE_PROBE3(tx__ip__log__drop__forward__nodst, char *, 15261676Sjpk "mp(1) dropped, no template for destination ip4|6(2)", 15271676Sjpk mblk_t *, mp, void *, pdst); 15281676Sjpk return (NULL); 15291676Sjpk } 15301676Sjpk 15311676Sjpk /* 15321676Sjpk * Gateway template must have existed for off-link destinations, 15331676Sjpk * since tsol_ire_match_gwattr has ensured such condition. 15341676Sjpk */ 1535*2535Ssangeeta if (ire->ire_ipversion == IPV4_VERSION && off_link) { 1536*2535Ssangeeta /* 1537*2535Ssangeeta * Surya note: first check if we can get the gw_rhtp from 1538*2535Ssangeeta * the ire_gw_secattr->igsa_rhc; if this is null, then 1539*2535Ssangeeta * do a lookup based on the ire_addr (address of gw) 1540*2535Ssangeeta */ 1541*2535Ssangeeta if (ire->ire_gw_secattr != NULL && 1542*2535Ssangeeta ire->ire_gw_secattr->igsa_rhc != NULL) { 1543*2535Ssangeeta attrp = ire->ire_gw_secattr; 1544*2535Ssangeeta gw_rhtp = attrp->igsa_rhc->rhc_tpc; 1545*2535Ssangeeta } else { 1546*2535Ssangeeta /* 1547*2535Ssangeeta * use the ire_addr if this is the IRE_CACHE of nexthop 1548*2535Ssangeeta */ 1549*2535Ssangeeta gw = (ire->ire_gateway_addr == NULL? &ire->ire_addr : 1550*2535Ssangeeta &ire->ire_gateway_addr); 1551*2535Ssangeeta gw_rhtp = find_tpc(gw, ire->ire_ipversion, B_FALSE); 1552*2535Ssangeeta need_tpc_rele = B_TRUE; 1553*2535Ssangeeta } 1554*2535Ssangeeta if (gw_rhtp == NULL) { 1555*2535Ssangeeta DTRACE_PROBE3(tx__ip__log__drop__forward__nogw, char *, 1556*2535Ssangeeta "mp(1) dropped, no gateway in ire attributes(2)", 1557*2535Ssangeeta mblk_t *, mp, tsol_ire_gw_secattr_t *, attrp); 1558*2535Ssangeeta mp = NULL; 1559*2535Ssangeeta goto keep_label; 1560*2535Ssangeeta } 1561*2535Ssangeeta } 1562*2535Ssangeeta if (ire->ire_ipversion == IPV6_VERSION && 1563*2535Ssangeeta ((attrp = ire->ire_gw_secattr) == NULL || attrp->igsa_rhc == NULL || 15641676Sjpk (gw_rhtp = attrp->igsa_rhc->rhc_tpc) == NULL) && off_link) { 15651676Sjpk DTRACE_PROBE3(tx__ip__log__drop__forward__nogw, char *, 15661676Sjpk "mp(1) dropped, no gateway in ire attributes(2)", 15671676Sjpk mblk_t *, mp, tsol_ire_gw_secattr_t *, attrp); 15681676Sjpk mp = NULL; 15691676Sjpk goto keep_label; 15701676Sjpk } 15711676Sjpk 15721676Sjpk /* 15731676Sjpk * Check that the label for the packet is acceptable 15741676Sjpk * by destination host; otherwise, drop it. 15751676Sjpk */ 15761676Sjpk switch (dst_rhtp->tpc_tp.host_type) { 15771676Sjpk case SUN_CIPSO: 15781676Sjpk if (tsl->tsl_doi != dst_rhtp->tpc_tp.tp_doi || 15791676Sjpk (!_blinrange(&tsl->tsl_label, 15801676Sjpk &dst_rhtp->tpc_tp.tp_sl_range_cipso) && 15811676Sjpk !blinlset(&tsl->tsl_label, 15821676Sjpk dst_rhtp->tpc_tp.tp_sl_set_cipso))) { 15831676Sjpk DTRACE_PROBE4(tx__ip__log__drop__forward__mac, char *, 15841676Sjpk "labeled packet mp(1) dropped, label(2) fails " 15851676Sjpk "destination(3) accredation check", 15861676Sjpk mblk_t *, mp, ts_label_t *, tsl, 15871676Sjpk tsol_tpc_t *, dst_rhtp); 15881676Sjpk mp = NULL; 15891676Sjpk goto keep_label; 15901676Sjpk } 15911676Sjpk break; 15921676Sjpk 15931676Sjpk 15941676Sjpk case UNLABELED: 15951676Sjpk if (tsl->tsl_doi != dst_rhtp->tpc_tp.tp_doi || 15961676Sjpk !blequal(&dst_rhtp->tpc_tp.tp_def_label, 15971676Sjpk &tsl->tsl_label)) { 15981676Sjpk DTRACE_PROBE4(tx__ip__log__drop__forward__mac, char *, 15991676Sjpk "unlabeled packet mp(1) dropped, label(2) fails " 16001676Sjpk "destination(3) accredation check", 16011676Sjpk mblk_t *, mp, ts_label_t *, tsl, 16021676Sjpk tsol_tpc_t *, dst_rhtp); 16031676Sjpk mp = NULL; 16041676Sjpk goto keep_label; 16051676Sjpk } 16061676Sjpk break; 16071676Sjpk } 16081676Sjpk if (label_type == OPT_CIPSO) { 16091676Sjpk /* 16101676Sjpk * We keep the label on any of the following cases: 16111676Sjpk * 16121676Sjpk * 1. The destination is labeled (on/off-link). 16131676Sjpk * 2. The unlabeled destination is off-link, 16141676Sjpk * and the next hop gateway is labeled. 16151676Sjpk */ 16161676Sjpk if (dst_rhtp->tpc_tp.host_type != UNLABELED || 16171676Sjpk (off_link && 16181676Sjpk gw_rhtp->tpc_tp.host_type != UNLABELED)) 16191676Sjpk goto keep_label; 16201676Sjpk 16211676Sjpk /* 16221676Sjpk * Strip off the CIPSO option from the packet because: the 16231676Sjpk * unlabeled destination host is directly reachable through 16241676Sjpk * an interface (on-link); or, the unlabeled destination host 16251676Sjpk * is not directly reachable (off-link), and the next hop 16261676Sjpk * gateway is unlabeled. 16271676Sjpk */ 16281676Sjpk adjust = (af == AF_INET) ? tsol_remove_secopt(ipha, MBLKL(mp)) : 16291676Sjpk tsol_remove_secopt_v6(ip6h, MBLKL(mp)); 16301676Sjpk 16311676Sjpk ASSERT(adjust <= 0); 16321676Sjpk if (adjust != 0) { 16331676Sjpk 16341676Sjpk /* adjust is negative */ 16351676Sjpk ASSERT((mp->b_wptr + adjust) >= mp->b_rptr); 16361676Sjpk mp->b_wptr += adjust; 16371676Sjpk 16381676Sjpk if (af == AF_INET) { 16391676Sjpk ipha = (ipha_t *)mp->b_rptr; 16401676Sjpk iplen = ntohs(ipha->ipha_length) + adjust; 16411676Sjpk ipha->ipha_length = htons(iplen); 16421676Sjpk ipha->ipha_hdr_checksum = 0; 16431676Sjpk ipha->ipha_hdr_checksum = ip_csum_hdr(ipha); 16441676Sjpk } 16451676Sjpk DTRACE_PROBE3(tx__ip__log__info__forward__adjust, 16461676Sjpk char *, 16471676Sjpk "mp(1) adjusted(2) for CIPSO option removal", 16481676Sjpk mblk_t *, mp, int, adjust); 16491676Sjpk } 16501676Sjpk goto keep_label; 16511676Sjpk } 16521676Sjpk 16531676Sjpk ASSERT(label_type == OPT_NONE); 16541676Sjpk ASSERT(dst_rhtp != NULL); 16551676Sjpk 16561676Sjpk /* 16571676Sjpk * We need to add CIPSO option if the destination or the next hop 16581676Sjpk * gateway is labeled. Otherwise, pass the packet as is. 16591676Sjpk */ 16601676Sjpk if (dst_rhtp->tpc_tp.host_type == UNLABELED && 16611676Sjpk (!off_link || gw_rhtp->tpc_tp.host_type == UNLABELED)) 16621676Sjpk goto keep_label; 16631676Sjpk 16641676Sjpk if ((af == AF_INET && 16651676Sjpk tsol_check_label(DB_CRED(mp), &mp, &adjust, B_FALSE) != 0) || 16661676Sjpk (af == AF_INET6 && 16671676Sjpk tsol_check_label_v6(DB_CRED(mp), &mp, &adjust, B_FALSE) != 0)) { 16681676Sjpk mp = NULL; 16691676Sjpk goto keep_label; 16701676Sjpk } 16711676Sjpk 16721676Sjpk ASSERT(adjust != -1); 16731676Sjpk if (adjust != 0) { 16741676Sjpk if (af == AF_INET) { 16751676Sjpk ipha = (ipha_t *)mp->b_rptr; 16761676Sjpk iplen = ntohs(ipha->ipha_length) + adjust; 16771676Sjpk ipha->ipha_length = htons(iplen); 16781676Sjpk ipha->ipha_hdr_checksum = 0; 16791676Sjpk ipha->ipha_hdr_checksum = ip_csum_hdr(ipha); 16801676Sjpk } 16811676Sjpk 16821676Sjpk DTRACE_PROBE3(tx__ip__log__info__forward__adjust, char *, 16831676Sjpk "mp(1) adjusted(2) for CIPSO option removal", 16841676Sjpk mblk_t *, mp, int, adjust); 16851676Sjpk } 16861676Sjpk 16871676Sjpk keep_label: 16881676Sjpk TPC_RELE(dst_rhtp); 1689*2535Ssangeeta if (need_tpc_rele && gw_rhtp != NULL) 1690*2535Ssangeeta TPC_RELE(gw_rhtp); 16911676Sjpk return (mp); 16921676Sjpk } 16931676Sjpk 16941676Sjpk /* 16951676Sjpk * Name: tsol_rtsa_init() 16961676Sjpk * 16971676Sjpk * Normal: Sanity checks on the route security attributes provided by 16981676Sjpk * user. Convert it into a route security parameter list to 16991676Sjpk * be returned to caller. 17001676Sjpk * 17011676Sjpk * Output: EINVAL if bad security attributes in the routing message 17021676Sjpk * ENOMEM if unable to allocate data structures 17031676Sjpk * 0 otherwise. 17041676Sjpk * 17051676Sjpk * Note: On input, cp must point to the end of any addresses in 17061676Sjpk * the rt_msghdr_t structure. 17071676Sjpk */ 17081676Sjpk int 17091676Sjpk tsol_rtsa_init(rt_msghdr_t *rtm, tsol_rtsecattr_t *sp, caddr_t cp) 17101676Sjpk { 17111676Sjpk uint_t sacnt; 17121676Sjpk int err; 17131676Sjpk caddr_t lim; 17141676Sjpk tsol_rtsecattr_t *tp; 17151676Sjpk 17161676Sjpk ASSERT((cp >= (caddr_t)&rtm[1]) && sp != NULL); 17171676Sjpk 17181676Sjpk /* 17191676Sjpk * In theory, we could accept as many security attributes configured 17201676Sjpk * per route destination. However, the current design is limited 17211676Sjpk * such that at most only one set security attributes is allowed to 17221676Sjpk * be associated with a prefix IRE. We therefore assert for now. 17231676Sjpk */ 17241676Sjpk /* LINTED */ 17251676Sjpk ASSERT(TSOL_RTSA_REQUEST_MAX == 1); 17261676Sjpk 17271676Sjpk sp->rtsa_cnt = 0; 17281676Sjpk lim = (caddr_t)rtm + rtm->rtm_msglen; 17291676Sjpk ASSERT(cp <= lim); 17301676Sjpk 17311676Sjpk if ((lim - cp) < sizeof (rtm_ext_t) || 17321676Sjpk ((rtm_ext_t *)cp)->rtmex_type != RTMEX_GATEWAY_SECATTR) 17331676Sjpk return (0); 17341676Sjpk 17351676Sjpk if (((rtm_ext_t *)cp)->rtmex_len < sizeof (tsol_rtsecattr_t)) 17361676Sjpk return (EINVAL); 17371676Sjpk 17381676Sjpk cp += sizeof (rtm_ext_t); 17391676Sjpk 17401676Sjpk if ((lim - cp) < sizeof (*tp) || 17411676Sjpk (tp = (tsol_rtsecattr_t *)cp, (sacnt = tp->rtsa_cnt) == 0) || 17421676Sjpk (lim - cp) < TSOL_RTSECATTR_SIZE(sacnt)) 17431676Sjpk return (EINVAL); 17441676Sjpk 17451676Sjpk /* 17461676Sjpk * Trying to add route security attributes when system 17471676Sjpk * labeling service is not available, or when user supllies 17481676Sjpk * more than the maximum number of security attributes 17491676Sjpk * allowed per request. 17501676Sjpk */ 17511676Sjpk if ((sacnt > 0 && !is_system_labeled()) || 17521676Sjpk sacnt > TSOL_RTSA_REQUEST_MAX) 17531676Sjpk return (EINVAL); 17541676Sjpk 17551676Sjpk /* Ensure valid credentials */ 17561676Sjpk if ((err = rtsa_validate(&((tsol_rtsecattr_t *)cp)-> 17571676Sjpk rtsa_attr[0])) != 0) { 17581676Sjpk cp += sizeof (*sp); 17591676Sjpk return (err); 17601676Sjpk } 17611676Sjpk 17621676Sjpk bcopy(cp, sp, sizeof (*sp)); 17631676Sjpk cp += sizeof (*sp); 17641676Sjpk return (0); 17651676Sjpk } 17661676Sjpk 17671676Sjpk int 17681676Sjpk tsol_ire_init_gwattr(ire_t *ire, uchar_t ipversion, tsol_gc_t *gc, 17691676Sjpk tsol_gcgrp_t *gcgrp) 17701676Sjpk { 17711676Sjpk tsol_ire_gw_secattr_t *attrp; 17721676Sjpk boolean_t exists = B_FALSE; 17731676Sjpk in_addr_t ga_addr4; 17741676Sjpk void *paddr = NULL; 17751676Sjpk 17761676Sjpk ASSERT(ire != NULL); 17771676Sjpk 17781676Sjpk /* 17791676Sjpk * The only time that attrp can be NULL is when this routine is 17801676Sjpk * called for the first time during the creation/initialization 17811676Sjpk * of the corresponding IRE. It will only get cleared when the 17821676Sjpk * IRE is deleted. 17831676Sjpk */ 17841676Sjpk if ((attrp = ire->ire_gw_secattr) == NULL) { 17851676Sjpk attrp = ire_gw_secattr_alloc(KM_NOSLEEP); 17861676Sjpk if (attrp == NULL) 17871676Sjpk return (ENOMEM); 17881676Sjpk ire->ire_gw_secattr = attrp; 17891676Sjpk } else { 17901676Sjpk exists = B_TRUE; 17911676Sjpk mutex_enter(&attrp->igsa_lock); 17921676Sjpk 17931676Sjpk if (attrp->igsa_rhc != NULL) { 17941676Sjpk TNRHC_RELE(attrp->igsa_rhc); 17951676Sjpk attrp->igsa_rhc = NULL; 17961676Sjpk } 17971676Sjpk 17981676Sjpk if (attrp->igsa_gc != NULL) 17991676Sjpk GC_REFRELE(attrp->igsa_gc); 18001676Sjpk if (attrp->igsa_gcgrp != NULL) 18011676Sjpk GCGRP_REFRELE(attrp->igsa_gcgrp); 18021676Sjpk } 18031676Sjpk ASSERT(!exists || MUTEX_HELD(&attrp->igsa_lock)); 18041676Sjpk 18051676Sjpk /* 18061676Sjpk * References already held by caller and we keep them; 18071676Sjpk * note that both gc and gcgrp may be set to NULL to 18081676Sjpk * clear out igsa_gc and igsa_gcgrp, respectively. 18091676Sjpk */ 18101676Sjpk attrp->igsa_gc = gc; 18111676Sjpk attrp->igsa_gcgrp = gcgrp; 18121676Sjpk 18131676Sjpk if (gcgrp == NULL && gc != NULL) { 18141676Sjpk gcgrp = gc->gc_grp; 18151676Sjpk ASSERT(gcgrp != NULL); 18161676Sjpk } 18171676Sjpk 18181676Sjpk /* 18191676Sjpk * Intialize the template for gateway; we use the gateway's 18201676Sjpk * address found in either the passed in gateway credential 18211676Sjpk * or group pointer, or the ire_gateway_addr{_v6} field. 18221676Sjpk */ 18231676Sjpk if (gcgrp != NULL) { 18241676Sjpk tsol_gcgrp_addr_t *ga = &gcgrp->gcgrp_addr; 18251676Sjpk 18261676Sjpk /* 18271676Sjpk * Caller is holding a reference, and that we don't 18281676Sjpk * need to hold any lock to access the address. 18291676Sjpk */ 18301676Sjpk if (ipversion == IPV4_VERSION) { 18311676Sjpk ASSERT(ga->ga_af == AF_INET); 18321676Sjpk IN6_V4MAPPED_TO_IPADDR(&ga->ga_addr, ga_addr4); 18331676Sjpk paddr = &ga_addr4; 18341676Sjpk } else { 18351676Sjpk ASSERT(ga->ga_af == AF_INET6); 18361676Sjpk paddr = &ga->ga_addr; 18371676Sjpk } 18381676Sjpk } else if (ipversion == IPV6_VERSION && 18391676Sjpk !IN6_IS_ADDR_UNSPECIFIED(&ire->ire_gateway_addr_v6)) { 18401676Sjpk paddr = &ire->ire_gateway_addr_v6; 18411676Sjpk } else if (ipversion == IPV4_VERSION && 18421676Sjpk ire->ire_gateway_addr != INADDR_ANY) { 18431676Sjpk paddr = &ire->ire_gateway_addr; 18441676Sjpk } 18451676Sjpk 18461676Sjpk /* 18471676Sjpk * Lookup the gateway template; note that we could get an internal 18481676Sjpk * template here, which we cache anyway. During IRE matching, we'll 18491676Sjpk * try to update this gateway template cache and hopefully get a 18501676Sjpk * real one. 18511676Sjpk */ 18521676Sjpk if (paddr != NULL) { 18531676Sjpk attrp->igsa_rhc = (ipversion == IPV4_VERSION) ? 18541676Sjpk find_rhc_v4(paddr) : find_rhc_v6(paddr); 18551676Sjpk } 18561676Sjpk 18571676Sjpk if (exists) 18581676Sjpk mutex_exit(&attrp->igsa_lock); 18591676Sjpk 18601676Sjpk return (0); 18611676Sjpk } 18621676Sjpk 18631676Sjpk /* 18641676Sjpk * This function figures the type of MLP that we'll be using based on the 18651676Sjpk * address that the user is binding and the zone. If the address is 18661676Sjpk * unspecified, then we're looking at both private and shared. If it's one 18671676Sjpk * of the zone's private addresses, then it's private only. If it's one 18681676Sjpk * of the global addresses, then it's shared only. 18691676Sjpk * 18701676Sjpk * If we can't figure out what it is, then return mlptSingle. That's actually 18711676Sjpk * an error case. 18721676Sjpk */ 18731676Sjpk mlp_type_t 18741676Sjpk tsol_mlp_addr_type(zoneid_t zoneid, uchar_t version, const void *addr) 18751676Sjpk { 18761676Sjpk in_addr_t in4; 18771676Sjpk ire_t *ire; 18781676Sjpk ipif_t *ipif; 18791676Sjpk zoneid_t addrzone; 18801676Sjpk 18811676Sjpk ASSERT(addr != NULL); 18821676Sjpk 18831676Sjpk if (version == IPV6_VERSION && 18841676Sjpk IN6_IS_ADDR_V4MAPPED((const in6_addr_t *)addr)) { 18851676Sjpk IN6_V4MAPPED_TO_IPADDR((const in6_addr_t *)addr, in4); 18861676Sjpk addr = &in4; 18871676Sjpk version = IPV4_VERSION; 18881676Sjpk } 18891676Sjpk 18901676Sjpk if (version == IPV4_VERSION) { 18911676Sjpk in4 = *(const in_addr_t *)addr; 18921676Sjpk if (in4 == INADDR_ANY) 18931676Sjpk return (mlptBoth); 18941676Sjpk ire = ire_cache_lookup(in4, zoneid, NULL); 18951676Sjpk } else { 18961676Sjpk if (IN6_IS_ADDR_UNSPECIFIED((const in6_addr_t *)addr)) 18971676Sjpk return (mlptBoth); 18981676Sjpk ire = ire_cache_lookup_v6(addr, zoneid, NULL); 18991676Sjpk } 19001676Sjpk /* 19011676Sjpk * If we can't find the IRE, then we have to behave exactly like 19021676Sjpk * ip_bind_laddr{,_v6}. That means looking up the IPIF so that users 19031676Sjpk * can bind to addresses on "down" interfaces. 19041676Sjpk * 19051676Sjpk * If we can't find that either, then the bind is going to fail, so 19061676Sjpk * just give up. Note that there's a miniscule chance that the address 19071676Sjpk * is in transition, but we don't bother handling that. 19081676Sjpk */ 19091676Sjpk if (ire == NULL) { 19101676Sjpk if (version == IPV4_VERSION) 19111676Sjpk ipif = ipif_lookup_addr(*(const in_addr_t *)addr, NULL, 19121676Sjpk zoneid, NULL, NULL, NULL, NULL); 19131676Sjpk else 19141676Sjpk ipif = ipif_lookup_addr_v6((const in6_addr_t *)addr, 19151676Sjpk NULL, zoneid, NULL, NULL, NULL, NULL); 19161676Sjpk if (ipif == NULL) 19171676Sjpk return (mlptSingle); 19181676Sjpk addrzone = ipif->ipif_zoneid; 19191676Sjpk ipif_refrele(ipif); 19201676Sjpk } else { 19211676Sjpk addrzone = ire->ire_zoneid; 19221676Sjpk ire_refrele(ire); 19231676Sjpk } 19241676Sjpk return (addrzone == ALL_ZONES ? mlptShared : mlptPrivate); 19251676Sjpk } 19261676Sjpk 19271676Sjpk /* 19281676Sjpk * Since we are configuring local interfaces, and we know trusted 19291676Sjpk * extension CDE requires local interfaces to be cipso host type in 19301676Sjpk * order to function correctly, we'll associate a cipso template 19311676Sjpk * to each local interface and let the interface come up. Configuring 19321676Sjpk * a local interface to be "unlabeled" host type is a configuration error. 19331676Sjpk * We'll override that error and make the interface host type to be cipso 19341676Sjpk * here. 19351676Sjpk * 19361676Sjpk * The code is optimized for the usual "success" case and unwinds things on 19371676Sjpk * error. We don't want to go to the trouble and expense of formatting the 19381676Sjpk * interface name for the usual case where everything is configured correctly. 19391676Sjpk */ 19401676Sjpk boolean_t 19411676Sjpk tsol_check_interface_address(const ipif_t *ipif) 19421676Sjpk { 19431676Sjpk tsol_tpc_t *tp; 19441676Sjpk char addrbuf[INET6_ADDRSTRLEN]; 19451676Sjpk int af; 19461676Sjpk const void *addr; 19471676Sjpk zone_t *zone; 19481676Sjpk ts_label_t *plabel; 19491676Sjpk const bslabel_t *label; 19501676Sjpk char ifbuf[LIFNAMSIZ + 10]; 19511676Sjpk const char *ifname; 19521676Sjpk boolean_t retval; 19531676Sjpk tsol_rhent_t rhent; 19541676Sjpk 19551676Sjpk if (IN6_IS_ADDR_V4MAPPED(&ipif->ipif_v6lcl_addr)) { 19561676Sjpk af = AF_INET; 19571676Sjpk addr = &V4_PART_OF_V6(ipif->ipif_v6lcl_addr); 19581676Sjpk } else { 19591676Sjpk af = AF_INET6; 19601676Sjpk addr = &ipif->ipif_v6lcl_addr; 19611676Sjpk } 19621676Sjpk 19631676Sjpk tp = find_tpc(&ipif->ipif_v6lcl_addr, IPV6_VERSION, B_FALSE); 19641676Sjpk zone = ipif->ipif_zoneid == ALL_ZONES ? NULL : 19651676Sjpk zone_find_by_id(ipif->ipif_zoneid); 19661676Sjpk if (zone != NULL) { 19671676Sjpk plabel = zone->zone_slabel; 19681676Sjpk ASSERT(plabel != NULL); 19691676Sjpk label = label2bslabel(plabel); 19701676Sjpk } 19711676Sjpk 19721676Sjpk /* 19731676Sjpk * If it's CIPSO and an all-zones address, then we're done. 19741676Sjpk * If it's a CIPSO zone specific address, the zone's label 19751676Sjpk * must be in the range or set specified in the template. 19761676Sjpk * When the remote host entry is missing or the template 19771676Sjpk * type is incorrect for this interface, we create a 19781676Sjpk * CIPSO host entry in kernel and allow the interface to be 19791676Sjpk * brought up as CIPSO type. 19801676Sjpk */ 19811676Sjpk if (tp != NULL && ( 19821676Sjpk /* The all-zones case */ 19831676Sjpk (tp->tpc_tp.host_type == SUN_CIPSO && 19841676Sjpk tp->tpc_tp.tp_doi == default_doi && 19851676Sjpk ipif->ipif_zoneid == ALL_ZONES) || 19861676Sjpk /* The local-zone case */ 19871676Sjpk (zone != NULL && plabel->tsl_doi == tp->tpc_tp.tp_doi && 19881676Sjpk ((tp->tpc_tp.host_type == SUN_CIPSO && 19891676Sjpk (_blinrange(label, &tp->tpc_tp.tp_sl_range_cipso) || 19901676Sjpk blinlset(label, tp->tpc_tp.tp_sl_set_cipso))))))) { 19911676Sjpk if (zone != NULL) 19921676Sjpk zone_rele(zone); 19931676Sjpk TPC_RELE(tp); 19941676Sjpk return (B_TRUE); 19951676Sjpk } 19961676Sjpk 19971676Sjpk ifname = ipif->ipif_ill->ill_name; 19981676Sjpk if (ipif->ipif_id != 0) { 19991676Sjpk (void) snprintf(ifbuf, sizeof (ifbuf), "%s:%u", ifname, 20001676Sjpk ipif->ipif_id); 20011676Sjpk ifname = ifbuf; 20021676Sjpk } 20031676Sjpk (void) inet_ntop(af, addr, addrbuf, sizeof (addrbuf)); 20041676Sjpk 20051676Sjpk if (tp == NULL) { 20061676Sjpk cmn_err(CE_NOTE, "template entry for %s missing. Default to " 20071676Sjpk "CIPSO type for %s", ifname, addrbuf); 20081676Sjpk retval = B_TRUE; 20091676Sjpk } else if (tp->tpc_tp.host_type == UNLABELED) { 20101676Sjpk cmn_err(CE_NOTE, "template type for %s incorrectly configured. " 20111676Sjpk "Change to CIPSO type for %s", ifname, addrbuf); 20121676Sjpk retval = B_TRUE; 20131676Sjpk } else if (ipif->ipif_zoneid == ALL_ZONES) { 20141676Sjpk if (tp->tpc_tp.host_type != SUN_CIPSO) { 20151676Sjpk cmn_err(CE_NOTE, "%s failed: %s isn't set to CIPSO for " 20161676Sjpk "all-zones. Converted to CIPSO.", ifname, addrbuf); 20171676Sjpk retval = B_TRUE; 20181676Sjpk } else { 20191676Sjpk cmn_err(CE_NOTE, "%s failed: %s has wrong DOI %d " 20201676Sjpk "instead of %d", ifname, addrbuf, 20211676Sjpk tp->tpc_tp.tp_doi, default_doi); 20221676Sjpk retval = B_FALSE; 20231676Sjpk } 20241676Sjpk } else if (zone == NULL) { 20251676Sjpk cmn_err(CE_NOTE, "%s failed: zoneid %d unknown", 20261676Sjpk ifname, ipif->ipif_zoneid); 20271676Sjpk retval = B_FALSE; 20281676Sjpk } else if (plabel->tsl_doi != tp->tpc_tp.tp_doi) { 20291676Sjpk cmn_err(CE_NOTE, "%s failed: zone %s has DOI %d but %s has " 20301676Sjpk "DOI %d", ifname, zone->zone_name, plabel->tsl_doi, 20311676Sjpk addrbuf, tp->tpc_tp.tp_doi); 20321676Sjpk retval = B_FALSE; 20331676Sjpk } else { 20341676Sjpk cmn_err(CE_NOTE, "%s failed: zone %s label incompatible with " 20351676Sjpk "%s", ifname, zone->zone_name, addrbuf); 20361676Sjpk tsol_print_label(label, "zone label"); 20371676Sjpk retval = B_FALSE; 20381676Sjpk } 20391676Sjpk 20401676Sjpk if (zone != NULL) 20411676Sjpk zone_rele(zone); 20421676Sjpk if (tp != NULL) 20431676Sjpk TPC_RELE(tp); 20441676Sjpk if (retval) { 20451676Sjpk /* 20461676Sjpk * we've corrected a config error and let the interface 20471676Sjpk * come up as cipso. Need to insert an rhent. 20481676Sjpk */ 20491676Sjpk if ((rhent.rh_address.ta_family = af) == AF_INET) { 20501676Sjpk rhent.rh_prefix = 32; 20511676Sjpk rhent.rh_address.ta_addr_v4 = *(struct in_addr *)addr; 20521676Sjpk } else { 20531676Sjpk rhent.rh_prefix = 128; 20541676Sjpk rhent.rh_address.ta_addr_v6 = *(in6_addr_t *)addr; 20551676Sjpk } 20561676Sjpk (void) strcpy(rhent.rh_template, "cipso"); 20571676Sjpk if (tnrh_load(&rhent) != 0) { 20581676Sjpk cmn_err(CE_NOTE, "%s failed: Cannot insert CIPSO " 20591676Sjpk "template for local addr %s", ifname, addrbuf); 20601676Sjpk retval = B_FALSE; 20611676Sjpk } 20621676Sjpk } 20631676Sjpk return (retval); 20641676Sjpk } 2065