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 /* 228778SErik.Nordmark@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 231676Sjpk * Use is subject to license terms. 241676Sjpk */ 251676Sjpk 261676Sjpk #include <sys/types.h> 271676Sjpk #include <sys/stream.h> 281676Sjpk #include <sys/strsubr.h> 291676Sjpk #include <sys/stropts.h> 301676Sjpk #include <sys/sunddi.h> 311676Sjpk #include <sys/cred.h> 321676Sjpk #include <sys/debug.h> 331676Sjpk #include <sys/kmem.h> 341676Sjpk #include <sys/errno.h> 351676Sjpk #include <sys/disp.h> 361676Sjpk #include <netinet/in.h> 371676Sjpk #include <netinet/in_systm.h> 381676Sjpk #include <netinet/ip.h> 391676Sjpk #include <netinet/ip_icmp.h> 401676Sjpk #include <netinet/tcp.h> 411676Sjpk #include <inet/common.h> 421676Sjpk #include <inet/ipclassifier.h> 431676Sjpk #include <inet/ip.h> 441676Sjpk #include <inet/mib2.h> 451676Sjpk #include <inet/nd.h> 461676Sjpk #include <inet/tcp.h> 471676Sjpk #include <inet/ip_rts.h> 481676Sjpk #include <inet/ip_ire.h> 491676Sjpk #include <inet/ip_if.h> 501676Sjpk #include <sys/modhash.h> 511676Sjpk 521676Sjpk #include <sys/tsol/label.h> 531676Sjpk #include <sys/tsol/label_macro.h> 541676Sjpk #include <sys/tsol/tnet.h> 551676Sjpk #include <sys/tsol/tndb.h> 561676Sjpk #include <sys/strsun.h> 571676Sjpk 581676Sjpk /* tunable for strict error-reply behavior (TCP RST and ICMP Unreachable) */ 591676Sjpk int tsol_strict_error; 601676Sjpk 611676Sjpk /* 621676Sjpk * Some notes on the Trusted Solaris IRE gateway security attributes: 631676Sjpk * 641676Sjpk * When running in Trusted mode, the routing subsystem determines whether or 651676Sjpk * not a packet can be delivered to an off-link host (not directly reachable 661676Sjpk * through an interface) based on the accreditation checks of the packet's 671676Sjpk * security attributes against those associated with the next-hop gateway. 681676Sjpk * 691676Sjpk * The next-hop gateway's security attributes can be derived from two sources 701676Sjpk * (in order of preference): route-related and the host database. A Trusted 711676Sjpk * system must be configured with at least the host database containing an 721676Sjpk * entry for the next-hop gateway, or otherwise no accreditation checks can 731676Sjpk * be performed, which may result in the inability to send packets to any 741676Sjpk * off-link destination host. 751676Sjpk * 761676Sjpk * The major differences between the two sources are the number and type of 771676Sjpk * security attributes used for accreditation checks. A host database entry 781676Sjpk * can contain at most one set of security attributes, specific only to the 791676Sjpk * next-hop gateway. On contrast, route-related security attributes are made 801676Sjpk * up of a collection of security attributes for the distant networks, and 811676Sjpk * are grouped together per next-hop gateway used to reach those networks. 821676Sjpk * This is the preferred method, and the routing subsystem will fallback to 831676Sjpk * the host database entry only if there are no route-related attributes 841676Sjpk * associated with the next-hop gateway. 851676Sjpk * 861676Sjpk * In Trusted mode, all of the IRE entries (except LOCAL/LOOPBACK/BROADCAST/ 871676Sjpk * INTERFACE type) are initialized to contain a placeholder to store this 881676Sjpk * information. The ire_gw_secattr structure gets allocated, initialized 891676Sjpk * and associated with the IRE during the time of the IRE creation. The 901676Sjpk * initialization process also includes resolving the host database entry 911676Sjpk * of the next-hop gateway for fallback purposes. It does not include any 921676Sjpk * route-related attribute setup, as that process comes separately as part 931676Sjpk * of the route requests (add/change) made to the routing subsystem. 941676Sjpk * 951676Sjpk * The underlying logic which involves associating IREs with the gateway 961676Sjpk * security attributes are represented by the following data structures: 971676Sjpk * 981676Sjpk * tsol_gcdb_t, or "gcdb" 991676Sjpk * 1001676Sjpk * - This is a system-wide collection of records containing the 1011676Sjpk * currently used route-related security attributes, which are fed 1021676Sjpk * through the routing socket interface, e.g. "route add/change". 1031676Sjpk * 1041676Sjpk * tsol_gc_t, or "gc" 1051676Sjpk * 1061676Sjpk * - This is the gateway credential structure, and it provides for the 1071676Sjpk * only mechanism to access the contents of gcdb. More than one gc 1081676Sjpk * entries may refer to the same gcdb record. gc's in the system are 1091676Sjpk * grouped according to the next-hop gateway address. 1101676Sjpk * 1111676Sjpk * tsol_gcgrp_t, or "gcgrp" 1121676Sjpk * 1131676Sjpk * - Group of gateway credentials, and is unique per next-hop gateway 1141676Sjpk * address. When the group is not empty, i.e. when gcgrp_count is 1151676Sjpk * greater than zero, it contains one or more gc's, each pointing to 1161676Sjpk * a gcdb record which indicates the gateway security attributes 1171676Sjpk * associated with the next-hop gateway. 1181676Sjpk * 1191676Sjpk * The fields of the tsol_ire_gw_secattr_t used from within the IRE are: 1201676Sjpk * 1211676Sjpk * igsa_lock 1221676Sjpk * 1231676Sjpk * - Lock that protects all fields within tsol_ire_gw_secattr_t. 1241676Sjpk * 1251676Sjpk * igsa_rhc 1261676Sjpk * 1271676Sjpk * - Remote host cache database entry of next-hop gateway. This is 1281676Sjpk * used in the case when there are no route-related attributes 1291676Sjpk * configured for the IRE. 1301676Sjpk * 1311676Sjpk * igsa_gc 1321676Sjpk * 1331676Sjpk * - A set of route-related attributes that only get set for prefix 1341676Sjpk * IREs. If this is non-NULL, the prefix IRE has been associated 1351676Sjpk * with a set of gateway security attributes by way of route add/ 136*11042SErik.Nordmark@Sun.COM * change functionality. 1371676Sjpk */ 1381676Sjpk 1391676Sjpk static kmem_cache_t *ire_gw_secattr_cache; 1401676Sjpk 1411676Sjpk #define GCDB_HASH_SIZE 101 1421676Sjpk #define GCGRP_HASH_SIZE 101 1431676Sjpk 1441676Sjpk #define GCDB_REFRELE(p) { \ 1451676Sjpk mutex_enter(&gcdb_lock); \ 1461676Sjpk ASSERT((p)->gcdb_refcnt > 0); \ 1471676Sjpk if (--((p)->gcdb_refcnt) == 0) \ 1481676Sjpk gcdb_inactive(p); \ 1491676Sjpk ASSERT(MUTEX_HELD(&gcdb_lock)); \ 1501676Sjpk mutex_exit(&gcdb_lock); \ 1511676Sjpk } 1521676Sjpk 1531676Sjpk static int gcdb_hash_size = GCDB_HASH_SIZE; 1541676Sjpk static int gcgrp_hash_size = GCGRP_HASH_SIZE; 1551676Sjpk static mod_hash_t *gcdb_hash; 1561676Sjpk static mod_hash_t *gcgrp4_hash; 1571676Sjpk static mod_hash_t *gcgrp6_hash; 1581676Sjpk 1591676Sjpk static kmutex_t gcdb_lock; 1601676Sjpk kmutex_t gcgrp_lock; 1611676Sjpk 1621676Sjpk static uint_t gcdb_hash_by_secattr(void *, mod_hash_key_t); 1631676Sjpk static int gcdb_hash_cmp(mod_hash_key_t, mod_hash_key_t); 1641676Sjpk static tsol_gcdb_t *gcdb_lookup(struct rtsa_s *, boolean_t); 1651676Sjpk static void gcdb_inactive(tsol_gcdb_t *); 1661676Sjpk 1671676Sjpk static uint_t gcgrp_hash_by_addr(void *, mod_hash_key_t); 1681676Sjpk static int gcgrp_hash_cmp(mod_hash_key_t, mod_hash_key_t); 1691676Sjpk 1701676Sjpk static int ire_gw_secattr_constructor(void *, void *, int); 1711676Sjpk static void ire_gw_secattr_destructor(void *, void *); 1721676Sjpk 1731676Sjpk void 1741676Sjpk tnet_init(void) 1751676Sjpk { 1761676Sjpk ire_gw_secattr_cache = kmem_cache_create("ire_gw_secattr_cache", 1771676Sjpk sizeof (tsol_ire_gw_secattr_t), 64, ire_gw_secattr_constructor, 1781676Sjpk ire_gw_secattr_destructor, NULL, NULL, NULL, 0); 1791676Sjpk 1801676Sjpk gcdb_hash = mod_hash_create_extended("gcdb_hash", 1811676Sjpk gcdb_hash_size, mod_hash_null_keydtor, mod_hash_null_valdtor, 1821676Sjpk gcdb_hash_by_secattr, NULL, gcdb_hash_cmp, KM_SLEEP); 1831676Sjpk 1841676Sjpk gcgrp4_hash = mod_hash_create_extended("gcgrp4_hash", 1851676Sjpk gcgrp_hash_size, mod_hash_null_keydtor, mod_hash_null_valdtor, 1861676Sjpk gcgrp_hash_by_addr, NULL, gcgrp_hash_cmp, KM_SLEEP); 1871676Sjpk 1881676Sjpk gcgrp6_hash = mod_hash_create_extended("gcgrp6_hash", 1891676Sjpk gcgrp_hash_size, mod_hash_null_keydtor, mod_hash_null_valdtor, 1901676Sjpk gcgrp_hash_by_addr, NULL, gcgrp_hash_cmp, KM_SLEEP); 1911676Sjpk 1921676Sjpk mutex_init(&gcdb_lock, NULL, MUTEX_DEFAULT, NULL); 1931676Sjpk mutex_init(&gcgrp_lock, NULL, MUTEX_DEFAULT, NULL); 1941676Sjpk } 1951676Sjpk 1961676Sjpk void 1971676Sjpk tnet_fini(void) 1981676Sjpk { 1991676Sjpk kmem_cache_destroy(ire_gw_secattr_cache); 2001676Sjpk mod_hash_destroy_hash(gcdb_hash); 2011676Sjpk mod_hash_destroy_hash(gcgrp4_hash); 2021676Sjpk mod_hash_destroy_hash(gcgrp6_hash); 2031676Sjpk mutex_destroy(&gcdb_lock); 2041676Sjpk mutex_destroy(&gcgrp_lock); 2051676Sjpk } 2061676Sjpk 2071676Sjpk /* ARGSUSED */ 2081676Sjpk static int 2091676Sjpk ire_gw_secattr_constructor(void *buf, void *cdrarg, int kmflags) 2101676Sjpk { 2111676Sjpk tsol_ire_gw_secattr_t *attrp = buf; 2121676Sjpk 2131676Sjpk mutex_init(&attrp->igsa_lock, NULL, MUTEX_DEFAULT, NULL); 2141676Sjpk 2151676Sjpk attrp->igsa_rhc = NULL; 2161676Sjpk attrp->igsa_gc = NULL; 2171676Sjpk 2181676Sjpk return (0); 2191676Sjpk } 2201676Sjpk 2211676Sjpk /* ARGSUSED */ 2221676Sjpk static void 2231676Sjpk ire_gw_secattr_destructor(void *buf, void *cdrarg) 2241676Sjpk { 2251676Sjpk tsol_ire_gw_secattr_t *attrp = (tsol_ire_gw_secattr_t *)buf; 2261676Sjpk 2271676Sjpk mutex_destroy(&attrp->igsa_lock); 2281676Sjpk } 2291676Sjpk 2301676Sjpk tsol_ire_gw_secattr_t * 2311676Sjpk ire_gw_secattr_alloc(int kmflags) 2321676Sjpk { 2331676Sjpk return (kmem_cache_alloc(ire_gw_secattr_cache, kmflags)); 2341676Sjpk } 2351676Sjpk 2361676Sjpk void 2371676Sjpk ire_gw_secattr_free(tsol_ire_gw_secattr_t *attrp) 2381676Sjpk { 2391676Sjpk ASSERT(MUTEX_NOT_HELD(&attrp->igsa_lock)); 2401676Sjpk 2411676Sjpk if (attrp->igsa_rhc != NULL) { 2421676Sjpk TNRHC_RELE(attrp->igsa_rhc); 2431676Sjpk attrp->igsa_rhc = NULL; 2441676Sjpk } 2451676Sjpk 2461676Sjpk if (attrp->igsa_gc != NULL) { 2471676Sjpk GC_REFRELE(attrp->igsa_gc); 2481676Sjpk attrp->igsa_gc = NULL; 2491676Sjpk } 2501676Sjpk 2511676Sjpk ASSERT(attrp->igsa_rhc == NULL); 2521676Sjpk ASSERT(attrp->igsa_gc == NULL); 2531676Sjpk 2541676Sjpk kmem_cache_free(ire_gw_secattr_cache, attrp); 2551676Sjpk } 2561676Sjpk 2571676Sjpk /* ARGSUSED */ 2581676Sjpk static uint_t 2591676Sjpk gcdb_hash_by_secattr(void *hash_data, mod_hash_key_t key) 2601676Sjpk { 2611676Sjpk const struct rtsa_s *rp = (struct rtsa_s *)key; 2621676Sjpk const uint32_t *up, *ue; 2631676Sjpk uint_t hash; 2641676Sjpk int i; 2651676Sjpk 2661676Sjpk ASSERT(rp != NULL); 2671676Sjpk 2681676Sjpk /* See comments in hash_bylabel in zone.c for details */ 2691676Sjpk hash = rp->rtsa_doi + (rp->rtsa_doi << 1); 2701676Sjpk up = (const uint32_t *)&rp->rtsa_slrange; 2711676Sjpk ue = up + sizeof (rp->rtsa_slrange) / sizeof (*up); 2721676Sjpk i = 1; 2731676Sjpk while (up < ue) { 2741676Sjpk /* using 2^n + 1, 1 <= n <= 16 as source of many primes */ 2751676Sjpk hash += *up + (*up << ((i % 16) + 1)); 2761676Sjpk up++; 2771676Sjpk i++; 2781676Sjpk } 2791676Sjpk return (hash); 2801676Sjpk } 2811676Sjpk 2821676Sjpk static int 2831676Sjpk gcdb_hash_cmp(mod_hash_key_t key1, mod_hash_key_t key2) 2841676Sjpk { 2851676Sjpk struct rtsa_s *rp1 = (struct rtsa_s *)key1; 2861676Sjpk struct rtsa_s *rp2 = (struct rtsa_s *)key2; 2871676Sjpk 2881676Sjpk ASSERT(rp1 != NULL && rp2 != NULL); 2891676Sjpk 2901676Sjpk if (blequal(&rp1->rtsa_slrange.lower_bound, 2911676Sjpk &rp2->rtsa_slrange.lower_bound) && 2921676Sjpk blequal(&rp1->rtsa_slrange.upper_bound, 2931676Sjpk &rp2->rtsa_slrange.upper_bound) && 2941676Sjpk rp1->rtsa_doi == rp2->rtsa_doi) 2951676Sjpk return (0); 2961676Sjpk 2971676Sjpk /* No match; not found */ 2981676Sjpk return (-1); 2991676Sjpk } 3001676Sjpk 3011676Sjpk /* ARGSUSED */ 3021676Sjpk static uint_t 3031676Sjpk gcgrp_hash_by_addr(void *hash_data, mod_hash_key_t key) 3041676Sjpk { 3051676Sjpk tsol_gcgrp_addr_t *ga = (tsol_gcgrp_addr_t *)key; 3061676Sjpk uint_t idx = 0; 3071676Sjpk uint32_t *ap; 3081676Sjpk 3091676Sjpk ASSERT(ga != NULL); 3101676Sjpk ASSERT(ga->ga_af == AF_INET || ga->ga_af == AF_INET6); 3111676Sjpk 3121676Sjpk ap = (uint32_t *)&ga->ga_addr.s6_addr32[0]; 3131676Sjpk idx ^= *ap++; 3141676Sjpk idx ^= *ap++; 3151676Sjpk idx ^= *ap++; 3161676Sjpk idx ^= *ap; 3171676Sjpk 3181676Sjpk return (idx); 3191676Sjpk } 3201676Sjpk 3211676Sjpk static int 3221676Sjpk gcgrp_hash_cmp(mod_hash_key_t key1, mod_hash_key_t key2) 3231676Sjpk { 3241676Sjpk tsol_gcgrp_addr_t *ga1 = (tsol_gcgrp_addr_t *)key1; 3251676Sjpk tsol_gcgrp_addr_t *ga2 = (tsol_gcgrp_addr_t *)key2; 3261676Sjpk 3271676Sjpk ASSERT(ga1 != NULL && ga2 != NULL); 3281676Sjpk 3291676Sjpk /* Address family must match */ 3301676Sjpk if (ga1->ga_af != ga2->ga_af) 3311676Sjpk return (-1); 3321676Sjpk 3331676Sjpk if (ga1->ga_addr.s6_addr32[0] == ga2->ga_addr.s6_addr32[0] && 3341676Sjpk ga1->ga_addr.s6_addr32[1] == ga2->ga_addr.s6_addr32[1] && 3351676Sjpk ga1->ga_addr.s6_addr32[2] == ga2->ga_addr.s6_addr32[2] && 3361676Sjpk ga1->ga_addr.s6_addr32[3] == ga2->ga_addr.s6_addr32[3]) 3371676Sjpk return (0); 3381676Sjpk 3391676Sjpk /* No match; not found */ 3401676Sjpk return (-1); 3411676Sjpk } 3421676Sjpk 3431676Sjpk #define RTSAFLAGS "\20\11cipso\3doi\2max_sl\1min_sl" 3441676Sjpk 3451676Sjpk int 3461676Sjpk rtsa_validate(const struct rtsa_s *rp) 3471676Sjpk { 3481676Sjpk uint32_t mask = rp->rtsa_mask; 3491676Sjpk 3501676Sjpk /* RTSA_CIPSO must be set, and DOI must not be zero */ 3511676Sjpk if ((mask & RTSA_CIPSO) == 0 || rp->rtsa_doi == 0) { 3521676Sjpk DTRACE_PROBE2(tx__gcdb__log__error__rtsa__validate, char *, 3531676Sjpk "rtsa(1) lacks flag or has 0 doi.", 3541676Sjpk rtsa_s *, rp); 3551676Sjpk return (EINVAL); 3561676Sjpk } 3571676Sjpk /* 3581676Sjpk * SL range must be specified, and it must have its 3591676Sjpk * upper bound dominating its lower bound. 3601676Sjpk */ 3611676Sjpk if ((mask & RTSA_SLRANGE) != RTSA_SLRANGE || 3621676Sjpk !bldominates(&rp->rtsa_slrange.upper_bound, 3631676Sjpk &rp->rtsa_slrange.lower_bound)) { 3641676Sjpk DTRACE_PROBE2(tx__gcdb__log__error__rtsa__validate, char *, 3651676Sjpk "rtsa(1) min_sl and max_sl not set or max_sl is " 3661676Sjpk "not dominating.", rtsa_s *, rp); 3671676Sjpk return (EINVAL); 3681676Sjpk } 3691676Sjpk return (0); 3701676Sjpk } 3711676Sjpk 3721676Sjpk /* 3731676Sjpk * A brief explanation of the reference counting scheme: 3741676Sjpk * 3751676Sjpk * Apart from dynamic references due to to reference holds done 3761676Sjpk * actively by threads, we have the following references: 3771676Sjpk * 3781676Sjpk * gcdb_refcnt: 3791676Sjpk * - Every tsol_gc_t pointing to a tsol_gcdb_t contributes a reference 3801676Sjpk * to the gcdb_refcnt. 3811676Sjpk * 3821676Sjpk * gc_refcnt: 3831676Sjpk * - A prefix IRE that points to an igsa_gc contributes a reference 3841676Sjpk * to the gc_refcnt. 3851676Sjpk * 3861676Sjpk * gcgrp_refcnt: 3871676Sjpk * - Every tsol_gc_t in the chain headed by tsol_gcgrp_t contributes 3881676Sjpk * a reference to the gcgrp_refcnt. 3891676Sjpk */ 3901676Sjpk static tsol_gcdb_t * 3911676Sjpk gcdb_lookup(struct rtsa_s *rp, boolean_t alloc) 3921676Sjpk { 3931676Sjpk tsol_gcdb_t *gcdb = NULL; 3941676Sjpk 3951676Sjpk if (rtsa_validate(rp) != 0) 3961676Sjpk return (NULL); 3971676Sjpk 3981676Sjpk mutex_enter(&gcdb_lock); 3991676Sjpk /* Find a copy in the cache; otherwise, create one and cache it */ 4001676Sjpk if (mod_hash_find(gcdb_hash, (mod_hash_key_t)rp, 4011676Sjpk (mod_hash_val_t *)&gcdb) == 0) { 4021676Sjpk gcdb->gcdb_refcnt++; 4031676Sjpk ASSERT(gcdb->gcdb_refcnt != 0); 4041676Sjpk 4051676Sjpk DTRACE_PROBE2(tx__gcdb__log__info__gcdb__lookup, char *, 4061676Sjpk "gcdb(1) is in gcdb_hash(global)", tsol_gcdb_t *, gcdb); 4071676Sjpk } else if (alloc) { 4081676Sjpk gcdb = kmem_zalloc(sizeof (*gcdb), KM_NOSLEEP); 4091676Sjpk if (gcdb != NULL) { 4101676Sjpk gcdb->gcdb_refcnt = 1; 4111676Sjpk gcdb->gcdb_mask = rp->rtsa_mask; 4121676Sjpk gcdb->gcdb_doi = rp->rtsa_doi; 4131676Sjpk gcdb->gcdb_slrange = rp->rtsa_slrange; 4141676Sjpk 4151676Sjpk if (mod_hash_insert(gcdb_hash, 4161676Sjpk (mod_hash_key_t)&gcdb->gcdb_attr, 4171676Sjpk (mod_hash_val_t)gcdb) != 0) { 4181676Sjpk mutex_exit(&gcdb_lock); 4191676Sjpk kmem_free(gcdb, sizeof (*gcdb)); 4201676Sjpk return (NULL); 4211676Sjpk } 4221676Sjpk 4231676Sjpk DTRACE_PROBE2(tx__gcdb__log__info__gcdb__insert, char *, 4241676Sjpk "gcdb(1) inserted in gcdb_hash(global)", 4251676Sjpk tsol_gcdb_t *, gcdb); 4261676Sjpk } 4271676Sjpk } 4281676Sjpk mutex_exit(&gcdb_lock); 4291676Sjpk return (gcdb); 4301676Sjpk } 4311676Sjpk 4321676Sjpk static void 4331676Sjpk gcdb_inactive(tsol_gcdb_t *gcdb) 4341676Sjpk { 4351676Sjpk ASSERT(MUTEX_HELD(&gcdb_lock)); 4361676Sjpk ASSERT(gcdb != NULL && gcdb->gcdb_refcnt == 0); 4371676Sjpk 4381676Sjpk (void) mod_hash_remove(gcdb_hash, (mod_hash_key_t)&gcdb->gcdb_attr, 4391676Sjpk (mod_hash_val_t *)&gcdb); 4401676Sjpk 4411676Sjpk DTRACE_PROBE2(tx__gcdb__log__info__gcdb__remove, char *, 4421676Sjpk "gcdb(1) removed from gcdb_hash(global)", 4431676Sjpk tsol_gcdb_t *, gcdb); 4441676Sjpk kmem_free(gcdb, sizeof (*gcdb)); 4451676Sjpk } 4461676Sjpk 4471676Sjpk tsol_gc_t * 4481676Sjpk gc_create(struct rtsa_s *rp, tsol_gcgrp_t *gcgrp, boolean_t *gcgrp_xtrarefp) 4491676Sjpk { 4501676Sjpk tsol_gc_t *gc; 4511676Sjpk tsol_gcdb_t *gcdb; 4521676Sjpk 4531676Sjpk *gcgrp_xtrarefp = B_TRUE; 4541676Sjpk 4551676Sjpk rw_enter(&gcgrp->gcgrp_rwlock, RW_WRITER); 4561676Sjpk if ((gcdb = gcdb_lookup(rp, B_TRUE)) == NULL) { 4571676Sjpk rw_exit(&gcgrp->gcgrp_rwlock); 4581676Sjpk return (NULL); 4591676Sjpk } 4601676Sjpk 4611676Sjpk for (gc = gcgrp->gcgrp_head; gc != NULL; gc = gc->gc_next) { 4621676Sjpk if (gc->gc_db == gcdb) { 4631676Sjpk ASSERT(gc->gc_grp == gcgrp); 4641676Sjpk 4651676Sjpk gc->gc_refcnt++; 4661676Sjpk ASSERT(gc->gc_refcnt != 0); 4671676Sjpk 4681676Sjpk GCDB_REFRELE(gcdb); 4691676Sjpk 4701676Sjpk DTRACE_PROBE3(tx__gcdb__log__info__gc__create, 4711676Sjpk char *, "found gc(1) in gcgrp(2)", 4721676Sjpk tsol_gc_t *, gc, tsol_gcgrp_t *, gcgrp); 4731676Sjpk rw_exit(&gcgrp->gcgrp_rwlock); 4741676Sjpk return (gc); 4751676Sjpk } 4761676Sjpk } 4771676Sjpk 4781676Sjpk gc = kmem_zalloc(sizeof (*gc), KM_NOSLEEP); 4791676Sjpk if (gc != NULL) { 4801676Sjpk if (gcgrp->gcgrp_head == NULL) { 4811676Sjpk gcgrp->gcgrp_head = gcgrp->gcgrp_tail = gc; 4821676Sjpk } else { 4831676Sjpk gcgrp->gcgrp_tail->gc_next = gc; 4841676Sjpk gc->gc_prev = gcgrp->gcgrp_tail; 4851676Sjpk gcgrp->gcgrp_tail = gc; 4861676Sjpk } 4871676Sjpk gcgrp->gcgrp_count++; 4881676Sjpk ASSERT(gcgrp->gcgrp_count != 0); 4891676Sjpk 4901676Sjpk /* caller has incremented gcgrp reference for us */ 4911676Sjpk gc->gc_grp = gcgrp; 4921676Sjpk 4931676Sjpk gc->gc_db = gcdb; 4941676Sjpk gc->gc_refcnt = 1; 4951676Sjpk 4961676Sjpk DTRACE_PROBE3(tx__gcdb__log__info__gc__create, char *, 4971676Sjpk "added gc(1) to gcgrp(2)", tsol_gc_t *, gc, 4981676Sjpk tsol_gcgrp_t *, gcgrp); 4991676Sjpk 5001676Sjpk *gcgrp_xtrarefp = B_FALSE; 5011676Sjpk } 5021676Sjpk rw_exit(&gcgrp->gcgrp_rwlock); 5031676Sjpk 5041676Sjpk return (gc); 5051676Sjpk } 5061676Sjpk 5071676Sjpk void 5081676Sjpk gc_inactive(tsol_gc_t *gc) 5091676Sjpk { 5101676Sjpk tsol_gcgrp_t *gcgrp = gc->gc_grp; 5111676Sjpk 5121676Sjpk ASSERT(gcgrp != NULL); 5131676Sjpk ASSERT(RW_WRITE_HELD(&gcgrp->gcgrp_rwlock)); 5141676Sjpk ASSERT(gc->gc_refcnt == 0); 5151676Sjpk 5161676Sjpk if (gc->gc_prev != NULL) 5171676Sjpk gc->gc_prev->gc_next = gc->gc_next; 5181676Sjpk else 5191676Sjpk gcgrp->gcgrp_head = gc->gc_next; 5201676Sjpk if (gc->gc_next != NULL) 5211676Sjpk gc->gc_next->gc_prev = gc->gc_prev; 5221676Sjpk else 5231676Sjpk gcgrp->gcgrp_tail = gc->gc_prev; 5241676Sjpk ASSERT(gcgrp->gcgrp_count > 0); 5251676Sjpk gcgrp->gcgrp_count--; 5261676Sjpk 5271676Sjpk /* drop lock before it's destroyed */ 5281676Sjpk rw_exit(&gcgrp->gcgrp_rwlock); 5291676Sjpk 5301676Sjpk DTRACE_PROBE3(tx__gcdb__log__info__gc__remove, char *, 5311676Sjpk "removed inactive gc(1) from gcgrp(2)", 5321676Sjpk tsol_gc_t *, gc, tsol_gcgrp_t *, gcgrp); 5331676Sjpk 5341676Sjpk GCGRP_REFRELE(gcgrp); 5351676Sjpk 5361676Sjpk gc->gc_grp = NULL; 5371676Sjpk gc->gc_prev = gc->gc_next = NULL; 5381676Sjpk 5391676Sjpk if (gc->gc_db != NULL) 5401676Sjpk GCDB_REFRELE(gc->gc_db); 5411676Sjpk 5421676Sjpk kmem_free(gc, sizeof (*gc)); 5431676Sjpk } 5441676Sjpk 5451676Sjpk tsol_gcgrp_t * 5461676Sjpk gcgrp_lookup(tsol_gcgrp_addr_t *ga, boolean_t alloc) 5471676Sjpk { 5481676Sjpk tsol_gcgrp_t *gcgrp = NULL; 5491676Sjpk mod_hash_t *hashp; 5501676Sjpk 5511676Sjpk ASSERT(ga->ga_af == AF_INET || ga->ga_af == AF_INET6); 5521676Sjpk 5531676Sjpk hashp = (ga->ga_af == AF_INET) ? gcgrp4_hash : gcgrp6_hash; 5541676Sjpk 5551676Sjpk mutex_enter(&gcgrp_lock); 5561676Sjpk if (mod_hash_find(hashp, (mod_hash_key_t)ga, 5571676Sjpk (mod_hash_val_t *)&gcgrp) == 0) { 5581676Sjpk gcgrp->gcgrp_refcnt++; 5591676Sjpk ASSERT(gcgrp->gcgrp_refcnt != 0); 5601676Sjpk 5611676Sjpk DTRACE_PROBE3(tx__gcdb__log__info__gcgrp__lookup, char *, 5621676Sjpk "found gcgrp(1) in hash(2)", tsol_gcgrp_t *, gcgrp, 5631676Sjpk mod_hash_t *, hashp); 5641676Sjpk 5651676Sjpk } else if (alloc) { 5661676Sjpk gcgrp = kmem_zalloc(sizeof (*gcgrp), KM_NOSLEEP); 5671676Sjpk if (gcgrp != NULL) { 5681676Sjpk gcgrp->gcgrp_refcnt = 1; 5691676Sjpk rw_init(&gcgrp->gcgrp_rwlock, NULL, RW_DEFAULT, NULL); 5701676Sjpk bcopy(ga, &gcgrp->gcgrp_addr, sizeof (*ga)); 5711676Sjpk 5721676Sjpk if (mod_hash_insert(hashp, 5731676Sjpk (mod_hash_key_t)&gcgrp->gcgrp_addr, 5741676Sjpk (mod_hash_val_t)gcgrp) != 0) { 5751676Sjpk mutex_exit(&gcgrp_lock); 5761676Sjpk kmem_free(gcgrp, sizeof (*gcgrp)); 5771676Sjpk return (NULL); 5781676Sjpk } 5791676Sjpk 5801676Sjpk DTRACE_PROBE3(tx__gcdb__log__info__gcgrp__insert, 5811676Sjpk char *, "inserted gcgrp(1) in hash(2)", 5821676Sjpk tsol_gcgrp_t *, gcgrp, mod_hash_t *, hashp); 5831676Sjpk } 5841676Sjpk } 5851676Sjpk mutex_exit(&gcgrp_lock); 5861676Sjpk return (gcgrp); 5871676Sjpk } 5881676Sjpk 5891676Sjpk void 5901676Sjpk gcgrp_inactive(tsol_gcgrp_t *gcgrp) 5911676Sjpk { 5921676Sjpk tsol_gcgrp_addr_t *ga; 5931676Sjpk mod_hash_t *hashp; 5941676Sjpk 5951676Sjpk ASSERT(MUTEX_HELD(&gcgrp_lock)); 5961676Sjpk ASSERT(gcgrp != NULL && gcgrp->gcgrp_refcnt == 0); 5971676Sjpk ASSERT(gcgrp->gcgrp_head == NULL && gcgrp->gcgrp_count == 0); 5981676Sjpk 5991676Sjpk ga = &gcgrp->gcgrp_addr; 6001676Sjpk ASSERT(ga->ga_af == AF_INET || ga->ga_af == AF_INET6); 6011676Sjpk 6021676Sjpk hashp = (ga->ga_af == AF_INET) ? gcgrp4_hash : gcgrp6_hash; 6031676Sjpk (void) mod_hash_remove(hashp, (mod_hash_key_t)ga, 6041676Sjpk (mod_hash_val_t *)&gcgrp); 6051676Sjpk rw_destroy(&gcgrp->gcgrp_rwlock); 6061676Sjpk 6071676Sjpk DTRACE_PROBE3(tx__gcdb__log__info__gcgrp__remove, char *, 6081676Sjpk "removed inactive gcgrp(1) from hash(2)", 6091676Sjpk tsol_gcgrp_t *, gcgrp, mod_hash_t *, hashp); 6101676Sjpk 6111676Sjpk kmem_free(gcgrp, sizeof (*gcgrp)); 6121676Sjpk } 6131676Sjpk 61410934Ssommerfeld@sun.com 61510934Ssommerfeld@sun.com /* 61610934Ssommerfeld@sun.com * Assign a sensitivity label to inbound traffic which arrived without 61710934Ssommerfeld@sun.com * an explicit on-the-wire label. 61810934Ssommerfeld@sun.com * 61910934Ssommerfeld@sun.com * In the case of CIPSO-type hosts, we assume packets arriving without 62010934Ssommerfeld@sun.com * a label are at the most sensitive label known for the host, most 62110934Ssommerfeld@sun.com * likely involving out-of-band key management traffic (such as IKE, 62210934Ssommerfeld@sun.com * etc.,) 62310934Ssommerfeld@sun.com */ 62410934Ssommerfeld@sun.com static boolean_t 62510934Ssommerfeld@sun.com tsol_find_unlabeled_label(tsol_tpc_t *rhtp, bslabel_t *sl, uint32_t *doi) 62610934Ssommerfeld@sun.com { 62710934Ssommerfeld@sun.com *doi = rhtp->tpc_tp.tp_doi; 62810934Ssommerfeld@sun.com switch (rhtp->tpc_tp.host_type) { 62910934Ssommerfeld@sun.com case UNLABELED: 63010934Ssommerfeld@sun.com *sl = rhtp->tpc_tp.tp_def_label; 63110934Ssommerfeld@sun.com break; 63210934Ssommerfeld@sun.com case SUN_CIPSO: 63310934Ssommerfeld@sun.com *sl = rhtp->tpc_tp.tp_sl_range_cipso.upper_bound; 63410934Ssommerfeld@sun.com break; 63510934Ssommerfeld@sun.com default: 63610934Ssommerfeld@sun.com return (B_FALSE); 63710934Ssommerfeld@sun.com } 63810934Ssommerfeld@sun.com setbltype(sl, SUN_SL_ID); 63910934Ssommerfeld@sun.com return (B_TRUE); 64010934Ssommerfeld@sun.com } 64110934Ssommerfeld@sun.com 6421676Sjpk /* 6431676Sjpk * Converts CIPSO option to sensitivity label. 6441676Sjpk * Validity checks based on restrictions defined in 6451676Sjpk * COMMERCIAL IP SECURITY OPTION (CIPSO 2.2) (draft-ietf-cipso-ipsecurity) 6461676Sjpk */ 6471676Sjpk static boolean_t 6481676Sjpk cipso_to_sl(const uchar_t *option, bslabel_t *sl) 6491676Sjpk { 6501676Sjpk const struct cipso_option *co = (const struct cipso_option *)option; 6511676Sjpk const struct cipso_tag_type_1 *tt1; 6521676Sjpk 6531676Sjpk tt1 = (struct cipso_tag_type_1 *)&co->cipso_tag_type[0]; 6541676Sjpk if (tt1->tag_type != 1 || 6551676Sjpk tt1->tag_length < TSOL_TT1_MIN_LENGTH || 6561676Sjpk tt1->tag_length > TSOL_TT1_MAX_LENGTH || 6571676Sjpk tt1->tag_length + TSOL_CIPSO_TAG_OFFSET > co->cipso_length) 6581676Sjpk return (B_FALSE); 6591676Sjpk 6601676Sjpk bsllow(sl); /* assumed: sets compartments to all zeroes */ 6611676Sjpk LCLASS_SET((_bslabel_impl_t *)sl, tt1->tag_sl); 6621676Sjpk bcopy(tt1->tag_cat, &((_bslabel_impl_t *)sl)->compartments, 6631676Sjpk tt1->tag_length - TSOL_TT1_MIN_LENGTH); 6641676Sjpk return (B_TRUE); 6651676Sjpk } 6661676Sjpk 6671676Sjpk /* 668*11042SErik.Nordmark@Sun.COM * If present, parse the CIPSO label in the incoming packet and 669*11042SErik.Nordmark@Sun.COM * construct a ts_label_t that reflects the CIPSO label and put it in 670*11042SErik.Nordmark@Sun.COM * the ip_recv_attr_t. Later as the packet flows up through the stack any 67110934Ssommerfeld@sun.com * code that needs to examine the packet label can inspect the label 672*11042SErik.Nordmark@Sun.COM * from the ira_tsl. This function is 673*11042SErik.Nordmark@Sun.COM * called right in ip_input for all packets, i.e. locally destined and 674*11042SErik.Nordmark@Sun.COM * to be forwarded packets. The forwarding path needs to examine the label 675*11042SErik.Nordmark@Sun.COM * to determine how to forward the packet. 6761676Sjpk * 67710181SKen.Powell@Sun.COM * This routine pulls all message text up into the first mblk. 67810181SKen.Powell@Sun.COM * For IPv4, only the first 20 bytes of the IP header are guaranteed 67910181SKen.Powell@Sun.COM * to exist. For IPv6, only the IPv6 header is guaranteed to exist. 6801676Sjpk */ 6811676Sjpk boolean_t 682*11042SErik.Nordmark@Sun.COM tsol_get_pkt_label(mblk_t *mp, int version, ip_recv_attr_t *ira) 6831676Sjpk { 68410934Ssommerfeld@sun.com tsol_tpc_t *src_rhtp = NULL; 6851676Sjpk uchar_t *opt_ptr = NULL; 6861676Sjpk const ipha_t *ipha; 6871676Sjpk bslabel_t sl; 6881676Sjpk uint32_t doi; 6891676Sjpk tsol_ip_label_t label_type; 69010934Ssommerfeld@sun.com uint32_t label_flags = 0; /* flags to set in label */ 6911676Sjpk const cipso_option_t *co; 6921676Sjpk const void *src; 6931676Sjpk const ip6_t *ip6h; 6948778SErik.Nordmark@Sun.COM cred_t *credp; 69510934Ssommerfeld@sun.com int proto; 6961676Sjpk 6971676Sjpk ASSERT(DB_TYPE(mp) == M_DATA); 6981676Sjpk 6999710SKen.Powell@Sun.COM if (mp->b_cont != NULL && !pullupmsg(mp, -1)) 7009710SKen.Powell@Sun.COM return (B_FALSE); 7019710SKen.Powell@Sun.COM 7021676Sjpk if (version == IPV4_VERSION) { 70310181SKen.Powell@Sun.COM ASSERT(MBLKL(mp) >= IP_SIMPLE_HDR_LENGTH); 7041676Sjpk ipha = (const ipha_t *)mp->b_rptr; 7051676Sjpk src = &ipha->ipha_src; 70610181SKen.Powell@Sun.COM if (!tsol_get_option_v4(mp, &label_type, &opt_ptr)) 70710181SKen.Powell@Sun.COM return (B_FALSE); 7081676Sjpk } else { 70910181SKen.Powell@Sun.COM ASSERT(MBLKL(mp) >= IPV6_HDR_LEN); 7101676Sjpk ip6h = (const ip6_t *)mp->b_rptr; 7111676Sjpk src = &ip6h->ip6_src; 71210181SKen.Powell@Sun.COM if (!tsol_get_option_v6(mp, &label_type, &opt_ptr)) 71310181SKen.Powell@Sun.COM return (B_FALSE); 7141676Sjpk } 7151676Sjpk 7161676Sjpk switch (label_type) { 7171676Sjpk case OPT_CIPSO: 7181676Sjpk /* 7191676Sjpk * Convert the CIPSO label to the internal format 7201676Sjpk * and attach it to the dblk cred. 7211676Sjpk * Validity checks based on restrictions defined in 7221676Sjpk * COMMERCIAL IP SECURITY OPTION (CIPSO 2.2) 7231676Sjpk * (draft-ietf-cipso-ipsecurity) 7241676Sjpk */ 7251676Sjpk if (version == IPV6_VERSION && ip6opt_ls == 0) 7261676Sjpk return (B_FALSE); 7271676Sjpk co = (const struct cipso_option *)opt_ptr; 7281676Sjpk if ((co->cipso_length < 7291676Sjpk TSOL_CIPSO_TAG_OFFSET + TSOL_TT1_MIN_LENGTH) || 7301676Sjpk (co->cipso_length > IP_MAX_OPT_LENGTH)) 7311676Sjpk return (B_FALSE); 7321676Sjpk bcopy(co->cipso_doi, &doi, sizeof (doi)); 7331676Sjpk doi = ntohl(doi); 7341676Sjpk if (!cipso_to_sl(opt_ptr, &sl)) 7351676Sjpk return (B_FALSE); 7361676Sjpk setbltype(&sl, SUN_SL_ID); 73710934Ssommerfeld@sun.com 73810934Ssommerfeld@sun.com /* 73910934Ssommerfeld@sun.com * If the source was unlabeled, then flag as such, 74010934Ssommerfeld@sun.com * (since CIPSO routers may add headers) 74110934Ssommerfeld@sun.com */ 74210934Ssommerfeld@sun.com 74310934Ssommerfeld@sun.com if ((src_rhtp = find_tpc(src, version, B_FALSE)) == NULL) 74410934Ssommerfeld@sun.com return (B_FALSE); 74510934Ssommerfeld@sun.com 74610934Ssommerfeld@sun.com if (src_rhtp->tpc_tp.host_type == UNLABELED) 74710934Ssommerfeld@sun.com label_flags = TSLF_UNLABELED; 74810934Ssommerfeld@sun.com 74910934Ssommerfeld@sun.com TPC_RELE(src_rhtp); 75010934Ssommerfeld@sun.com 7511676Sjpk break; 7521676Sjpk 7531676Sjpk case OPT_NONE: 7541676Sjpk /* 75510934Ssommerfeld@sun.com * Handle special cases that may not be labeled, even 7561676Sjpk * though the sending system may otherwise be configured as 7571676Sjpk * labeled. 7581676Sjpk * - IGMP 7591676Sjpk * - IPv4 ICMP Router Discovery 7601676Sjpk * - IPv6 Neighbor Discovery 76110934Ssommerfeld@sun.com * - IPsec ESP 7621676Sjpk */ 7631676Sjpk if (version == IPV4_VERSION) { 76410934Ssommerfeld@sun.com proto = ipha->ipha_protocol; 76510934Ssommerfeld@sun.com if (proto == IPPROTO_IGMP) 7661676Sjpk return (B_TRUE); 76710934Ssommerfeld@sun.com if (proto == IPPROTO_ICMP) { 7681676Sjpk const struct icmp *icmp = (const struct icmp *) 7691676Sjpk (mp->b_rptr + IPH_HDR_LENGTH(ipha)); 7701676Sjpk 77110181SKen.Powell@Sun.COM if ((uchar_t *)icmp + ICMP_MINLEN > mp->b_wptr) 77210181SKen.Powell@Sun.COM return (B_FALSE); 7731676Sjpk if (icmp->icmp_type == ICMP_ROUTERADVERT || 7741676Sjpk icmp->icmp_type == ICMP_ROUTERSOLICIT) 7751676Sjpk return (B_TRUE); 7761676Sjpk } 7771676Sjpk } else { 77810934Ssommerfeld@sun.com proto = ip6h->ip6_nxt; 77910934Ssommerfeld@sun.com if (proto == 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 > 78410181SKen.Powell@Sun.COM mp->b_wptr) 78510181SKen.Powell@Sun.COM return (B_FALSE); 7861676Sjpk if (icmp6->icmp6_type >= MLD_LISTENER_QUERY && 7871676Sjpk icmp6->icmp6_type <= ICMP6_MAX_INFO_TYPE) 7881676Sjpk return (B_TRUE); 7891676Sjpk } 7901676Sjpk } 7911676Sjpk 7921676Sjpk /* 7931676Sjpk * Look up the tnrhtp database and get the implicit label 79410934Ssommerfeld@sun.com * that is associated with the sending host and attach 7951676Sjpk * it to the packet. 7961676Sjpk */ 7971676Sjpk if ((src_rhtp = find_tpc(src, version, B_FALSE)) == NULL) 7981676Sjpk return (B_FALSE); 7991676Sjpk 80010934Ssommerfeld@sun.com /* 80110934Ssommerfeld@sun.com * If peer is label-aware, mark as "implicit" rather than 80210934Ssommerfeld@sun.com * "unlabeled" to cause appropriate mac-exempt processing 80310934Ssommerfeld@sun.com * to happen. 80410934Ssommerfeld@sun.com */ 80510934Ssommerfeld@sun.com if (src_rhtp->tpc_tp.host_type == SUN_CIPSO) 80610934Ssommerfeld@sun.com label_flags = TSLF_IMPLICIT_IN; 80710934Ssommerfeld@sun.com else if (src_rhtp->tpc_tp.host_type == UNLABELED) 80810934Ssommerfeld@sun.com label_flags = TSLF_UNLABELED; 80910934Ssommerfeld@sun.com else { 81010934Ssommerfeld@sun.com DTRACE_PROBE2(tx__get__pkt__label, char *, 81110934Ssommerfeld@sun.com "template(1) has unknown hosttype", 81210934Ssommerfeld@sun.com tsol_tpc_t *, src_rhtp); 81310934Ssommerfeld@sun.com } 81410934Ssommerfeld@sun.com 81510934Ssommerfeld@sun.com 81610934Ssommerfeld@sun.com if (!tsol_find_unlabeled_label(src_rhtp, &sl, &doi)) { 8171676Sjpk TPC_RELE(src_rhtp); 8181676Sjpk return (B_FALSE); 8191676Sjpk } 8201676Sjpk TPC_RELE(src_rhtp); 8211676Sjpk break; 8221676Sjpk 8231676Sjpk default: 8241676Sjpk return (B_FALSE); 8251676Sjpk } 8261676Sjpk 827*11042SErik.Nordmark@Sun.COM if (ira->ira_cred == NULL) { 8288778SErik.Nordmark@Sun.COM credp = newcred_from_bslabel(&sl, doi, KM_NOSLEEP); 829*11042SErik.Nordmark@Sun.COM if (credp == NULL) 830*11042SErik.Nordmark@Sun.COM return (B_FALSE); 8311676Sjpk } else { 8321676Sjpk cred_t *newcr; 8331676Sjpk 834*11042SErik.Nordmark@Sun.COM newcr = copycred_from_bslabel(ira->ira_cred, &sl, doi, 8351676Sjpk KM_NOSLEEP); 836*11042SErik.Nordmark@Sun.COM if (newcr == NULL) 837*11042SErik.Nordmark@Sun.COM return (B_FALSE); 838*11042SErik.Nordmark@Sun.COM if (ira->ira_free_flags & IRA_FREE_CRED) { 839*11042SErik.Nordmark@Sun.COM crfree(ira->ira_cred); 840*11042SErik.Nordmark@Sun.COM ira->ira_free_flags &= ~IRA_FREE_CRED; 841*11042SErik.Nordmark@Sun.COM ira->ira_cred = NULL; 842*11042SErik.Nordmark@Sun.COM } 8438778SErik.Nordmark@Sun.COM credp = newcr; 8441676Sjpk } 84510934Ssommerfeld@sun.com 846*11042SErik.Nordmark@Sun.COM /* 847*11042SErik.Nordmark@Sun.COM * Put the label in ira_tsl for convinience, while keeping 848*11042SErik.Nordmark@Sun.COM * the cred in ira_cred for getpeerucred which is used to get 849*11042SErik.Nordmark@Sun.COM * labels with TX. 850*11042SErik.Nordmark@Sun.COM * Note: no explicit refcnt/free_flag for ira_tsl. The free_flag 851*11042SErik.Nordmark@Sun.COM * for IRA_FREE_CRED is sufficient for both. 852*11042SErik.Nordmark@Sun.COM */ 853*11042SErik.Nordmark@Sun.COM ira->ira_tsl = crgetlabel(credp); 854*11042SErik.Nordmark@Sun.COM ira->ira_cred = credp; 855*11042SErik.Nordmark@Sun.COM ira->ira_free_flags |= IRA_FREE_CRED; 85610934Ssommerfeld@sun.com 857*11042SErik.Nordmark@Sun.COM ira->ira_tsl->tsl_flags |= label_flags; 8581676Sjpk return (B_TRUE); 8591676Sjpk } 8601676Sjpk 8611676Sjpk /* 8621676Sjpk * This routine determines whether the given packet should be accepted locally. 8631676Sjpk * It does a range/set check on the packet's label by looking up the given 8641676Sjpk * address in the remote host database. 8651676Sjpk */ 8661676Sjpk boolean_t 8671676Sjpk tsol_receive_local(const mblk_t *mp, const void *addr, uchar_t version, 868*11042SErik.Nordmark@Sun.COM ip_recv_attr_t *ira, const conn_t *connp) 8691676Sjpk { 8701676Sjpk const cred_t *credp; 8711676Sjpk ts_label_t *plabel, *conn_plabel; 8721676Sjpk tsol_tpc_t *tp; 8731676Sjpk boolean_t retv; 8741676Sjpk const bslabel_t *label, *conn_label; 875*11042SErik.Nordmark@Sun.COM boolean_t shared_addr = (ira->ira_flags & IRAF_TX_SHARED_ADDR); 8761676Sjpk 8771676Sjpk /* 878*11042SErik.Nordmark@Sun.COM * tsol_get_pkt_label intentionally avoids the labeling process for: 879*11042SErik.Nordmark@Sun.COM * - IPv6 router and neighbor discovery as well as redirects. 880*11042SErik.Nordmark@Sun.COM * - MLD packets. (Anything between ICMPv6 code 130 and 138.) 881*11042SErik.Nordmark@Sun.COM * - IGMP packets. 882*11042SErik.Nordmark@Sun.COM * - IPv4 router discovery. 883*11042SErik.Nordmark@Sun.COM * In those cases ire_cred is NULL. 8841676Sjpk */ 885*11042SErik.Nordmark@Sun.COM credp = ira->ira_cred; 886*11042SErik.Nordmark@Sun.COM if (credp == NULL) 8871676Sjpk return (B_TRUE); 8881676Sjpk 8891676Sjpk /* 8901676Sjpk * If this packet is from the inside (not a remote host) and has the 8911676Sjpk * same zoneid as the selected destination, then no checks are 8921676Sjpk * necessary. Membership in the zone is enough proof. This is 8931676Sjpk * intended to be a hot path through this function. 894*11042SErik.Nordmark@Sun.COM * Note: Using crgetzone here is ok since the peer is local. 8951676Sjpk */ 8961676Sjpk if (!crisremote(credp) && 8971676Sjpk crgetzone(credp) == crgetzone(connp->conn_cred)) 8981676Sjpk return (B_TRUE); 8991676Sjpk 900*11042SErik.Nordmark@Sun.COM plabel = ira->ira_tsl; 9011676Sjpk conn_plabel = crgetlabel(connp->conn_cred); 9021676Sjpk ASSERT(plabel != NULL && conn_plabel != NULL); 9031676Sjpk 9041676Sjpk label = label2bslabel(plabel); 905*11042SErik.Nordmark@Sun.COM conn_label = label2bslabel(conn_plabel); 9061676Sjpk 90710934Ssommerfeld@sun.com 90810934Ssommerfeld@sun.com /* 90910934Ssommerfeld@sun.com * Implicitly labeled packets from label-aware sources 91010934Ssommerfeld@sun.com * go only to privileged receivers 91110934Ssommerfeld@sun.com */ 91210934Ssommerfeld@sun.com if ((plabel->tsl_flags & TSLF_IMPLICIT_IN) && 91310934Ssommerfeld@sun.com (connp->conn_mac_mode != CONN_MAC_IMPLICIT)) { 91410934Ssommerfeld@sun.com DTRACE_PROBE3(tx__ip__log__drop__receivelocal__mac_impl, 91510934Ssommerfeld@sun.com char *, 91610934Ssommerfeld@sun.com "implicitly labeled packet mp(1) for conn(2) " 91710934Ssommerfeld@sun.com "which isn't in implicit mac mode", 91810934Ssommerfeld@sun.com mblk_t *, mp, conn_t *, connp); 91910934Ssommerfeld@sun.com 92010934Ssommerfeld@sun.com return (B_FALSE); 92110934Ssommerfeld@sun.com } 92210934Ssommerfeld@sun.com 92310934Ssommerfeld@sun.com 9241676Sjpk /* 9251676Sjpk * MLPs are always validated using the range and set of the local 9261676Sjpk * address, even when the remote host is unlabeled. 9271676Sjpk */ 9281676Sjpk if (connp->conn_mlp_type == mlptBoth || 9291676Sjpk /* LINTED: no consequent */ 9301676Sjpk connp->conn_mlp_type == (shared_addr ? mlptShared : mlptPrivate)) { 9311676Sjpk ; 9321676Sjpk 9331676Sjpk /* 9341676Sjpk * If this is a packet from an unlabeled sender, then we must apply 9351676Sjpk * different rules. If the label is equal to the zone's label, then 9361676Sjpk * it's allowed. If it's not equal, but the zone is either the global 9371676Sjpk * zone or the label is dominated by the zone's label, then allow it 9381676Sjpk * as long as it's in the range configured for the destination. 9391676Sjpk */ 9401676Sjpk } else if (plabel->tsl_flags & TSLF_UNLABELED) { 9411676Sjpk if (plabel->tsl_doi == conn_plabel->tsl_doi && 9421676Sjpk blequal(label, conn_label)) 9431676Sjpk return (B_TRUE); 9441676Sjpk 94510934Ssommerfeld@sun.com if ((connp->conn_mac_mode == CONN_MAC_DEFAULT) || 946*11042SErik.Nordmark@Sun.COM (!connp->conn_zone_is_global && 9471676Sjpk (plabel->tsl_doi != conn_plabel->tsl_doi || 9481676Sjpk !bldominates(conn_label, label)))) { 9491676Sjpk DTRACE_PROBE3( 9501676Sjpk tx__ip__log__drop__receivelocal__mac_unl, 9511676Sjpk char *, 9521676Sjpk "unlabeled packet mp(1) fails mac for conn(2)", 9531676Sjpk mblk_t *, mp, conn_t *, connp); 9541676Sjpk return (B_FALSE); 9551676Sjpk } 9561676Sjpk 9571676Sjpk /* 9584448Skp158701 * If this is a packet from a labeled sender, verify the 9594448Skp158701 * label on the packet matches the connection label. 9601676Sjpk */ 9614448Skp158701 } else { 9624448Skp158701 if (plabel->tsl_doi != conn_plabel->tsl_doi || 9634448Skp158701 !blequal(label, conn_label)) { 9644448Skp158701 DTRACE_PROBE3(tx__ip__log__drop__receivelocal__mac__slp, 9654448Skp158701 char *, 9664448Skp158701 "packet mp(1) failed label match to SLP conn(2)", 9674448Skp158701 mblk_t *, mp, conn_t *, connp); 9684448Skp158701 return (B_FALSE); 9694448Skp158701 } 9701676Sjpk /* 9714448Skp158701 * No further checks will be needed if this is a zone- 9724448Skp158701 * specific address because (1) The process for bringing up 9734448Skp158701 * the interface ensures the zone's label is within the zone- 9744448Skp158701 * specific address's valid label range; (2) For cases where 9754448Skp158701 * the conn is bound to the unspecified addresses, ip fanout 9764448Skp158701 * logic ensures conn's zoneid equals the dest addr's zoneid; 9774448Skp158701 * (3) Mac-exempt and mlp logic above already handle all 9784448Skp158701 * cases where the zone label may not be the same as the 9794448Skp158701 * conn label. 9801676Sjpk */ 9814448Skp158701 if (!shared_addr) 9821676Sjpk return (B_TRUE); 9831676Sjpk } 9841676Sjpk 9851676Sjpk tp = find_tpc(addr, version, B_FALSE); 9861676Sjpk if (tp == NULL) { 9871676Sjpk DTRACE_PROBE3(tx__ip__log__drop__receivelocal__no__tnr, 9881676Sjpk char *, "dropping mp(1), host(2) lacks entry", 9891676Sjpk mblk_t *, mp, void *, addr); 9901676Sjpk return (B_FALSE); 9911676Sjpk } 9921676Sjpk 9931676Sjpk /* 9941676Sjpk * The local host address should not be unlabeled at this point. The 9951676Sjpk * only way this can happen is that the destination isn't unicast. We 9961676Sjpk * assume that the packet should not have had a label, and thus should 9971676Sjpk * have been handled by the TSLF_UNLABELED logic above. 9981676Sjpk */ 9991676Sjpk if (tp->tpc_tp.host_type == UNLABELED) { 10001676Sjpk retv = B_FALSE; 10011676Sjpk DTRACE_PROBE3(tx__ip__log__drop__receivelocal__flag, char *, 10021676Sjpk "mp(1) unlabeled source, but tp is not unlabeled.", 10031676Sjpk mblk_t *, mp, tsol_tpc_t *, tp); 10041676Sjpk 10051676Sjpk } else if (tp->tpc_tp.host_type != SUN_CIPSO) { 10061676Sjpk retv = B_FALSE; 10071676Sjpk DTRACE_PROBE3(tx__ip__log__drop__receivelocal__tptype, char *, 10081676Sjpk "delivering mp(1), found unrecognized tpc(2) type.", 10091676Sjpk mblk_t *, mp, tsol_tpc_t *, tp); 10101676Sjpk 10111676Sjpk } else if (plabel->tsl_doi != tp->tpc_tp.tp_doi) { 10121676Sjpk retv = B_FALSE; 10131676Sjpk DTRACE_PROBE3(tx__ip__log__drop__receivelocal__mac, char *, 10141676Sjpk "mp(1) could not be delievered to tp(2), doi mismatch", 10151676Sjpk mblk_t *, mp, tsol_tpc_t *, tp); 10161676Sjpk 10171676Sjpk } else if (!_blinrange(label, &tp->tpc_tp.tp_sl_range_cipso) && 10181676Sjpk !blinlset(label, tp->tpc_tp.tp_sl_set_cipso)) { 10191676Sjpk retv = B_FALSE; 10201676Sjpk DTRACE_PROBE3(tx__ip__log__drop__receivelocal__mac, char *, 10211676Sjpk "mp(1) could not be delievered to tp(2), bad mac", 10221676Sjpk mblk_t *, mp, tsol_tpc_t *, tp); 10231676Sjpk } else { 10241676Sjpk retv = B_TRUE; 10251676Sjpk } 10261676Sjpk 10271676Sjpk TPC_RELE(tp); 10281676Sjpk 10291676Sjpk return (retv); 10301676Sjpk } 10311676Sjpk 10321676Sjpk boolean_t 1033*11042SErik.Nordmark@Sun.COM tsol_can_accept_raw(mblk_t *mp, ip_recv_attr_t *ira, boolean_t check_host) 10341676Sjpk { 10351676Sjpk ts_label_t *plabel = NULL; 10361676Sjpk tsol_tpc_t *src_rhtp, *dst_rhtp; 10371676Sjpk boolean_t retv; 10381676Sjpk 1039*11042SErik.Nordmark@Sun.COM plabel = ira->ira_tsl; 10401676Sjpk 10411676Sjpk /* We are bootstrapping or the internal template was never deleted */ 10421676Sjpk if (plabel == NULL) 10431676Sjpk return (B_TRUE); 10441676Sjpk 10451676Sjpk if (IPH_HDR_VERSION(mp->b_rptr) == IPV4_VERSION) { 10461676Sjpk ipha_t *ipha = (ipha_t *)mp->b_rptr; 10471676Sjpk 10481676Sjpk src_rhtp = find_tpc(&ipha->ipha_src, IPV4_VERSION, 10491676Sjpk B_FALSE); 10501676Sjpk if (src_rhtp == NULL) 10511676Sjpk return (B_FALSE); 10521676Sjpk dst_rhtp = find_tpc(&ipha->ipha_dst, IPV4_VERSION, 10531676Sjpk B_FALSE); 10541676Sjpk } else { 10551676Sjpk ip6_t *ip6h = (ip6_t *)mp->b_rptr; 10561676Sjpk 10571676Sjpk src_rhtp = find_tpc(&ip6h->ip6_src, IPV6_VERSION, 10581676Sjpk B_FALSE); 10591676Sjpk if (src_rhtp == NULL) 10601676Sjpk return (B_FALSE); 10611676Sjpk dst_rhtp = find_tpc(&ip6h->ip6_dst, IPV6_VERSION, 10621676Sjpk B_FALSE); 10631676Sjpk } 10641676Sjpk if (dst_rhtp == NULL) { 10651676Sjpk TPC_RELE(src_rhtp); 10661676Sjpk return (B_FALSE); 10671676Sjpk } 10681676Sjpk 10691676Sjpk if (label2doi(plabel) != src_rhtp->tpc_tp.tp_doi) { 10701676Sjpk retv = B_FALSE; 10711676Sjpk 10721676Sjpk /* 10731676Sjpk * Check that the packet's label is in the correct range for labeled 10741676Sjpk * sender, or is equal to the default label for unlabeled sender. 10751676Sjpk */ 10761676Sjpk } else if ((src_rhtp->tpc_tp.host_type != UNLABELED && 10771676Sjpk !_blinrange(label2bslabel(plabel), 10781676Sjpk &src_rhtp->tpc_tp.tp_sl_range_cipso) && 10791676Sjpk !blinlset(label2bslabel(plabel), 10801676Sjpk src_rhtp->tpc_tp.tp_sl_set_cipso)) || 10811676Sjpk (src_rhtp->tpc_tp.host_type == UNLABELED && 10821676Sjpk !blequal(&plabel->tsl_label, &src_rhtp->tpc_tp.tp_def_label))) { 10831676Sjpk retv = B_FALSE; 10841676Sjpk 10851676Sjpk } else if (check_host) { 10861676Sjpk retv = B_TRUE; 10871676Sjpk 10881676Sjpk /* 10891676Sjpk * Until we have SL range in the Zone structure, pass it 10901676Sjpk * when our own address lookup returned an internal entry. 10911676Sjpk */ 10921676Sjpk } else switch (dst_rhtp->tpc_tp.host_type) { 10931676Sjpk case UNLABELED: 10941676Sjpk retv = B_TRUE; 10951676Sjpk break; 10961676Sjpk 10971676Sjpk case SUN_CIPSO: 10981676Sjpk retv = _blinrange(label2bslabel(plabel), 10991676Sjpk &dst_rhtp->tpc_tp.tp_sl_range_cipso) || 11001676Sjpk blinlset(label2bslabel(plabel), 11011676Sjpk dst_rhtp->tpc_tp.tp_sl_set_cipso); 11021676Sjpk break; 11031676Sjpk 11041676Sjpk default: 11051676Sjpk retv = B_FALSE; 11061676Sjpk } 11071676Sjpk TPC_RELE(src_rhtp); 11081676Sjpk TPC_RELE(dst_rhtp); 11091676Sjpk return (retv); 11101676Sjpk } 11111676Sjpk 11121676Sjpk /* 11131676Sjpk * This routine determines whether a response to a failed packet delivery or 11141676Sjpk * connection should be sent back. By default, the policy is to allow such 11151676Sjpk * messages to be sent at all times, as these messages reveal little useful 11161676Sjpk * information and are healthy parts of TCP/IP networking. 11171676Sjpk * 11181676Sjpk * If tsol_strict_error is set, then we do strict tests: if the packet label is 11191676Sjpk * within the label range/set of this host/zone, return B_TRUE; otherwise 11201676Sjpk * return B_FALSE, which causes the packet to be dropped silently. 11211676Sjpk * 11221676Sjpk * Note that tsol_get_pkt_label will cause the packet to drop if the sender is 11231676Sjpk * marked as labeled in the remote host database, but the packet lacks a label. 11241676Sjpk * This means that we don't need to do a lookup on the source; the 11251676Sjpk * TSLF_UNLABELED flag is sufficient. 11261676Sjpk */ 11271676Sjpk boolean_t 1128*11042SErik.Nordmark@Sun.COM tsol_can_reply_error(const mblk_t *mp, ip_recv_attr_t *ira) 11291676Sjpk { 11301676Sjpk ts_label_t *plabel = NULL; 11311676Sjpk tsol_tpc_t *rhtp; 11321676Sjpk const ipha_t *ipha; 11331676Sjpk const ip6_t *ip6h; 11341676Sjpk boolean_t retv; 11351676Sjpk bslabel_t *pktbs; 11361676Sjpk 11371676Sjpk /* Caller must pull up at least the IP header */ 11381676Sjpk ASSERT(MBLKL(mp) >= (IPH_HDR_VERSION(mp->b_rptr) == IPV4_VERSION ? 11391676Sjpk sizeof (*ipha) : sizeof (*ip6h))); 11401676Sjpk 11411676Sjpk if (!tsol_strict_error) 11421676Sjpk return (B_TRUE); 11431676Sjpk 1144*11042SErik.Nordmark@Sun.COM plabel = ira->ira_tsl; 11451676Sjpk 11461676Sjpk /* We are bootstrapping or the internal template was never deleted */ 11471676Sjpk if (plabel == NULL) 11481676Sjpk return (B_TRUE); 11491676Sjpk 115010934Ssommerfeld@sun.com if (plabel->tsl_flags & TSLF_IMPLICIT_IN) { 115110934Ssommerfeld@sun.com DTRACE_PROBE3(tx__ip__log__drop__replyerror__unresolved__label, 115210934Ssommerfeld@sun.com char *, 115310934Ssommerfeld@sun.com "cannot send error report for packet mp(1) with " 115410934Ssommerfeld@sun.com "unresolved security label sl(2)", 115510934Ssommerfeld@sun.com mblk_t *, mp, ts_label_t *, plabel); 115610934Ssommerfeld@sun.com return (B_FALSE); 115710934Ssommerfeld@sun.com } 115810934Ssommerfeld@sun.com 115910934Ssommerfeld@sun.com 11601676Sjpk if (IPH_HDR_VERSION(mp->b_rptr) == IPV4_VERSION) { 11611676Sjpk ipha = (const ipha_t *)mp->b_rptr; 11621676Sjpk rhtp = find_tpc(&ipha->ipha_dst, IPV4_VERSION, B_FALSE); 11631676Sjpk } else { 11641676Sjpk ip6h = (const ip6_t *)mp->b_rptr; 11651676Sjpk rhtp = find_tpc(&ip6h->ip6_dst, IPV6_VERSION, B_FALSE); 11661676Sjpk } 11671676Sjpk 11681676Sjpk if (rhtp == NULL || label2doi(plabel) != rhtp->tpc_tp.tp_doi) { 11691676Sjpk retv = B_FALSE; 11701676Sjpk } else { 11711676Sjpk /* 11721676Sjpk * If we're in the midst of forwarding, then the destination 11731676Sjpk * address might not be labeled. In that case, allow unlabeled 11741676Sjpk * packets through only if the default label is the same, and 11751676Sjpk * labeled ones if they dominate. 11761676Sjpk */ 11771676Sjpk pktbs = label2bslabel(plabel); 11781676Sjpk switch (rhtp->tpc_tp.host_type) { 11791676Sjpk case UNLABELED: 11801676Sjpk if (plabel->tsl_flags & TSLF_UNLABELED) { 11811676Sjpk retv = blequal(pktbs, 11821676Sjpk &rhtp->tpc_tp.tp_def_label); 11831676Sjpk } else { 11841676Sjpk retv = bldominates(pktbs, 11851676Sjpk &rhtp->tpc_tp.tp_def_label); 11861676Sjpk } 11871676Sjpk break; 11881676Sjpk 11891676Sjpk case SUN_CIPSO: 11901676Sjpk retv = _blinrange(pktbs, 11911676Sjpk &rhtp->tpc_tp.tp_sl_range_cipso) || 11921676Sjpk blinlset(pktbs, rhtp->tpc_tp.tp_sl_set_cipso); 11931676Sjpk break; 11941676Sjpk 11951676Sjpk default: 11961676Sjpk retv = B_FALSE; 11971676Sjpk break; 11981676Sjpk } 11991676Sjpk } 12001676Sjpk 12011676Sjpk if (rhtp != NULL) 12021676Sjpk TPC_RELE(rhtp); 12031676Sjpk 12041676Sjpk return (retv); 12051676Sjpk } 12061676Sjpk 12071676Sjpk /* 1208*11042SErik.Nordmark@Sun.COM * Finds the zone associated with the receive attributes. Returns GLOBAL_ZONEID 1209*11042SErik.Nordmark@Sun.COM * if the zone cannot be located. 12101676Sjpk * 12111676Sjpk * This is used by the classifier when the packet matches an ALL_ZONES IRE, and 12121676Sjpk * there's no MLP defined. 12133448Sdh155122 * 12143448Sdh155122 * Note that we assume that this is only invoked in the ALL_ZONES case. 1215*11042SErik.Nordmark@Sun.COM * Handling other cases would require handling exclusive IP zones where either 12163448Sdh155122 * this routine or the callers would have to map from 12173448Sdh155122 * the zoneid (zone->zone_id) to what IP uses in conn_zoneid etc. 12181676Sjpk */ 12191676Sjpk zoneid_t 1220*11042SErik.Nordmark@Sun.COM tsol_attr_to_zoneid(const ip_recv_attr_t *ira) 12211676Sjpk { 12221676Sjpk zone_t *zone; 12231676Sjpk ts_label_t *label; 12241676Sjpk 1225*11042SErik.Nordmark@Sun.COM if ((label = ira->ira_tsl) != NULL) { 1226*11042SErik.Nordmark@Sun.COM zone = zone_find_by_label(label); 1227*11042SErik.Nordmark@Sun.COM if (zone != NULL) { 1228*11042SErik.Nordmark@Sun.COM zoneid_t zoneid = zone->zone_id; 12291676Sjpk 1230*11042SErik.Nordmark@Sun.COM zone_rele(zone); 1231*11042SErik.Nordmark@Sun.COM return (zoneid); 12321676Sjpk } 12331676Sjpk } 12341676Sjpk return (GLOBAL_ZONEID); 12351676Sjpk } 12361676Sjpk 12371676Sjpk int 12381676Sjpk tsol_ire_match_gwattr(ire_t *ire, const ts_label_t *tsl) 12391676Sjpk { 12401676Sjpk int error = 0; 12411676Sjpk tsol_ire_gw_secattr_t *attrp = NULL; 12421676Sjpk tsol_tnrhc_t *gw_rhc = NULL; 12431676Sjpk tsol_gcgrp_t *gcgrp = NULL; 12441676Sjpk tsol_gc_t *gc = NULL; 12451676Sjpk in_addr_t ga_addr4; 12461676Sjpk void *paddr = NULL; 12471676Sjpk 12481676Sjpk /* Not in Trusted mode or IRE is local/loopback/broadcast/interface */ 12491676Sjpk if (!is_system_labeled() || 12501676Sjpk (ire->ire_type & (IRE_LOCAL | IRE_LOOPBACK | IRE_BROADCAST | 1251*11042SErik.Nordmark@Sun.COM IRE_IF_ALL | IRE_MULTICAST | IRE_NOROUTE))) 12521676Sjpk goto done; 12531676Sjpk 12541676Sjpk /* 12551676Sjpk * If we don't have a label to compare with, or the IRE does not 12561676Sjpk * contain any gateway security attributes, there's not much that 12571676Sjpk * we can do. We let the former case pass, and the latter fail, 12581676Sjpk * since the IRE doesn't qualify for a match due to the lack of 12591676Sjpk * security attributes. 12601676Sjpk */ 12611676Sjpk if (tsl == NULL || ire->ire_gw_secattr == NULL) { 12621676Sjpk if (tsl != NULL) { 126310934Ssommerfeld@sun.com DTRACE_PROBE3( 126410934Ssommerfeld@sun.com tx__ip__log__drop__irematch__nogwsec, char *, 126510934Ssommerfeld@sun.com "ire(1) lacks ire_gw_secattr when matching " 126610934Ssommerfeld@sun.com "label(2)", ire_t *, ire, ts_label_t *, tsl); 12671676Sjpk error = EACCES; 12681676Sjpk } 12691676Sjpk goto done; 12701676Sjpk } 12711676Sjpk 12721676Sjpk attrp = ire->ire_gw_secattr; 12731676Sjpk 12741676Sjpk /* 12751676Sjpk * The possible lock order scenarios related to the tsol gateway 12761676Sjpk * attribute locks are documented at the beginning of ip.c in the 12771676Sjpk * lock order scenario section. 12781676Sjpk */ 12791676Sjpk mutex_enter(&attrp->igsa_lock); 12801676Sjpk 12811676Sjpk /* 1282*11042SErik.Nordmark@Sun.COM * We seek the group 12831676Sjpk * structure which contains all security credentials of the gateway. 1284*11042SErik.Nordmark@Sun.COM * An offline IRE is associated with at most one gateway credential. 12851676Sjpk */ 1286*11042SErik.Nordmark@Sun.COM if ((gc = attrp->igsa_gc) != NULL) { 12871676Sjpk gcgrp = gc->gc_grp; 12881676Sjpk ASSERT(gcgrp != NULL); 12891676Sjpk rw_enter(&gcgrp->gcgrp_rwlock, RW_READER); 1290*11042SErik.Nordmark@Sun.COM GCGRP_REFHOLD(gcgrp); 12911676Sjpk } 12921676Sjpk 12931676Sjpk if ((gw_rhc = attrp->igsa_rhc) != NULL) { 12941676Sjpk /* 12951676Sjpk * If our cached entry has grown stale, then discard it so we 12961676Sjpk * can get a new one. 12971676Sjpk */ 12981676Sjpk if (gw_rhc->rhc_invalid || gw_rhc->rhc_tpc->tpc_invalid) { 12991676Sjpk TNRHC_RELE(gw_rhc); 13001676Sjpk attrp->igsa_rhc = gw_rhc = NULL; 13011676Sjpk } else { 13021676Sjpk TNRHC_HOLD(gw_rhc) 13031676Sjpk } 13041676Sjpk } 13051676Sjpk 13061676Sjpk /* Last attempt at loading the template had failed; try again */ 13071676Sjpk if (gw_rhc == NULL) { 13081676Sjpk if (gcgrp != NULL) { 13091676Sjpk tsol_gcgrp_addr_t *ga = &gcgrp->gcgrp_addr; 13101676Sjpk 13111676Sjpk if (ire->ire_ipversion == IPV4_VERSION) { 13121676Sjpk ASSERT(ga->ga_af == AF_INET); 13131676Sjpk IN6_V4MAPPED_TO_IPADDR(&ga->ga_addr, ga_addr4); 13141676Sjpk paddr = &ga_addr4; 13151676Sjpk } else { 13161676Sjpk ASSERT(ga->ga_af == AF_INET6); 13171676Sjpk paddr = &ga->ga_addr; 13181676Sjpk } 1319*11042SErik.Nordmark@Sun.COM } else if (ire->ire_type & IRE_OFFLINK) { 1320*11042SErik.Nordmark@Sun.COM if (ire->ire_ipversion == IPV6_VERSION) 1321*11042SErik.Nordmark@Sun.COM paddr = &ire->ire_gateway_addr_v6; 1322*11042SErik.Nordmark@Sun.COM else if (ire->ire_ipversion == IPV4_VERSION) 1323*11042SErik.Nordmark@Sun.COM paddr = &ire->ire_gateway_addr; 13241676Sjpk } 13251676Sjpk 13261676Sjpk /* We've found a gateway address to do the template lookup */ 13271676Sjpk if (paddr != NULL) { 13281676Sjpk ASSERT(gw_rhc == NULL); 13293292Skp158701 gw_rhc = find_rhc(paddr, ire->ire_ipversion, B_FALSE); 13301676Sjpk if (gw_rhc != NULL) { 13311676Sjpk /* 13321676Sjpk * Note that if the lookup above returned an 13331676Sjpk * internal template, we'll use it for the 13341676Sjpk * time being, and do another lookup next 13351676Sjpk * time around. 13361676Sjpk */ 13371676Sjpk /* Another thread has loaded the template? */ 13381676Sjpk if (attrp->igsa_rhc != NULL) { 13391676Sjpk TNRHC_RELE(gw_rhc) 13401676Sjpk /* reload, it could be different */ 13411676Sjpk gw_rhc = attrp->igsa_rhc; 13421676Sjpk } else { 13431676Sjpk attrp->igsa_rhc = gw_rhc; 13441676Sjpk } 13451676Sjpk /* 13461676Sjpk * Hold an extra reference just like we did 13471676Sjpk * above prior to dropping the igsa_lock. 13481676Sjpk */ 13491676Sjpk TNRHC_HOLD(gw_rhc) 13501676Sjpk } 13511676Sjpk } 13521676Sjpk } 13531676Sjpk 13541676Sjpk mutex_exit(&attrp->igsa_lock); 13551676Sjpk /* Gateway template not found */ 13561676Sjpk if (gw_rhc == NULL) { 13571676Sjpk /* 13581676Sjpk * If destination address is directly reachable through an 13591676Sjpk * interface rather than through a learned route, pass it. 13601676Sjpk */ 13611676Sjpk if (paddr != NULL) { 13621676Sjpk DTRACE_PROBE3( 13631676Sjpk tx__ip__log__drop__irematch__nogwtmpl, char *, 13641676Sjpk "ire(1), label(2) off-link with no gw_rhc", 13651676Sjpk ire_t *, ire, ts_label_t *, tsl); 13661676Sjpk error = EINVAL; 13671676Sjpk } 13681676Sjpk goto done; 13691676Sjpk } 13701676Sjpk 13711676Sjpk if (gc != NULL) { 1372*11042SErik.Nordmark@Sun.COM 13731676Sjpk tsol_gcdb_t *gcdb; 13741676Sjpk /* 13751676Sjpk * In the case of IRE_CACHE we've got one or more gateway 13761676Sjpk * security credentials to compare against the passed in label. 13771676Sjpk * Perform label range comparison against each security 13781676Sjpk * credential of the gateway. In the case of a prefix ire 13791676Sjpk * we need to match against the security attributes of 13801676Sjpk * just the route itself, so the loop is executed only once. 13811676Sjpk */ 13821676Sjpk ASSERT(gcgrp != NULL); 1383*11042SErik.Nordmark@Sun.COM gcdb = gc->gc_db; 1384*11042SErik.Nordmark@Sun.COM if (tsl->tsl_doi != gcdb->gcdb_doi || 1385*11042SErik.Nordmark@Sun.COM !_blinrange(&tsl->tsl_label, &gcdb->gcdb_slrange)) { 13861676Sjpk DTRACE_PROBE3( 13871676Sjpk tx__ip__log__drop__irematch__nogcmatched, 13881676Sjpk char *, "ire(1), tsl(2): all gc failed match", 13891676Sjpk ire_t *, ire, ts_label_t *, tsl); 13901676Sjpk error = EACCES; 13911676Sjpk } 13921676Sjpk } else { 13931676Sjpk /* 13941676Sjpk * We didn't find any gateway credentials in the IRE 13951676Sjpk * attributes; fall back to the gateway's template for 13961676Sjpk * label range checks, if we are required to do so. 13971676Sjpk */ 13981676Sjpk ASSERT(gw_rhc != NULL); 13991676Sjpk switch (gw_rhc->rhc_tpc->tpc_tp.host_type) { 14001676Sjpk case SUN_CIPSO: 14016596Skp158701 if (tsl->tsl_doi != gw_rhc->rhc_tpc->tpc_tp.tp_doi || 14021676Sjpk (!_blinrange(&tsl->tsl_label, 14036596Skp158701 &gw_rhc->rhc_tpc->tpc_tp.tp_sl_range_cipso) && 14041676Sjpk !blinlset(&tsl->tsl_label, 14051676Sjpk gw_rhc->rhc_tpc->tpc_tp.tp_sl_set_cipso))) { 14061676Sjpk error = EACCES; 14071676Sjpk DTRACE_PROBE4( 14081676Sjpk tx__ip__log__drop__irematch__deftmpl, 14091676Sjpk char *, "ire(1), tsl(2), gw_rhc(3) " 14101676Sjpk "failed match (cipso gw)", 14111676Sjpk ire_t *, ire, ts_label_t *, tsl, 14121676Sjpk tsol_tnrhc_t *, gw_rhc); 14131676Sjpk } 14141676Sjpk break; 14151676Sjpk 14161676Sjpk case UNLABELED: 14176596Skp158701 if (tsl->tsl_doi != gw_rhc->rhc_tpc->tpc_tp.tp_doi || 14181676Sjpk (!_blinrange(&tsl->tsl_label, 14191676Sjpk &gw_rhc->rhc_tpc->tpc_tp.tp_gw_sl_range) && 14201676Sjpk !blinlset(&tsl->tsl_label, 14211676Sjpk gw_rhc->rhc_tpc->tpc_tp.tp_gw_sl_set))) { 14221676Sjpk error = EACCES; 14231676Sjpk DTRACE_PROBE4( 14241676Sjpk tx__ip__log__drop__irematch__deftmpl, 14251676Sjpk char *, "ire(1), tsl(2), gw_rhc(3) " 14261676Sjpk "failed match (unlabeled gw)", 14271676Sjpk ire_t *, ire, ts_label_t *, tsl, 14281676Sjpk tsol_tnrhc_t *, gw_rhc); 14291676Sjpk } 14301676Sjpk break; 14311676Sjpk } 14321676Sjpk } 14331676Sjpk 14341676Sjpk done: 14351676Sjpk 14361676Sjpk if (gcgrp != NULL) { 14371676Sjpk rw_exit(&gcgrp->gcgrp_rwlock); 14381676Sjpk GCGRP_REFRELE(gcgrp); 14391676Sjpk } 14401676Sjpk 14411676Sjpk if (gw_rhc != NULL) 14421676Sjpk TNRHC_RELE(gw_rhc) 14431676Sjpk 14441676Sjpk return (error); 14451676Sjpk } 14461676Sjpk 14471676Sjpk /* 14481676Sjpk * Performs label accreditation checks for packet forwarding. 1449*11042SErik.Nordmark@Sun.COM * Add or remove a CIPSO option as needed. 14501676Sjpk * 14511676Sjpk * Returns a pointer to the modified mblk if allowed for forwarding, 14521676Sjpk * or NULL if the packet must be dropped. 14531676Sjpk */ 14541676Sjpk mblk_t * 1455*11042SErik.Nordmark@Sun.COM tsol_ip_forward(ire_t *ire, mblk_t *mp, const ip_recv_attr_t *ira) 14561676Sjpk { 14571676Sjpk tsol_ire_gw_secattr_t *attrp = NULL; 14581676Sjpk ipha_t *ipha; 14591676Sjpk ip6_t *ip6h; 14601676Sjpk const void *pdst; 14611676Sjpk const void *psrc; 14621676Sjpk boolean_t off_link; 14631676Sjpk tsol_tpc_t *dst_rhtp, *gw_rhtp; 14641676Sjpk tsol_ip_label_t label_type; 14651676Sjpk uchar_t *opt_ptr = NULL; 14661676Sjpk ts_label_t *tsl; 14671676Sjpk uint8_t proto; 14681676Sjpk int af, adjust; 14691676Sjpk uint16_t iplen; 14702535Ssangeeta boolean_t need_tpc_rele = B_FALSE; 14712535Ssangeeta ipaddr_t *gw; 14723448Sdh155122 ip_stack_t *ipst = ire->ire_ipst; 1473*11042SErik.Nordmark@Sun.COM int err; 1474*11042SErik.Nordmark@Sun.COM ts_label_t *effective_tsl = NULL; 14751676Sjpk 14761676Sjpk ASSERT(ire != NULL && mp != NULL); 1477*11042SErik.Nordmark@Sun.COM /* 1478*11042SErik.Nordmark@Sun.COM * Note that the ire is the first one found, i.e., an IRE_OFFLINK if 1479*11042SErik.Nordmark@Sun.COM * the destination is offlink. 1480*11042SErik.Nordmark@Sun.COM */ 14811676Sjpk 14821676Sjpk af = (ire->ire_ipversion == IPV4_VERSION) ? AF_INET : AF_INET6; 14831676Sjpk 14841676Sjpk if (IPH_HDR_VERSION(mp->b_rptr) == IPV4_VERSION) { 14851676Sjpk ASSERT(ire->ire_ipversion == IPV4_VERSION); 14861676Sjpk ipha = (ipha_t *)mp->b_rptr; 14871676Sjpk psrc = &ipha->ipha_src; 14881676Sjpk pdst = &ipha->ipha_dst; 14891676Sjpk proto = ipha->ipha_protocol; 149010181SKen.Powell@Sun.COM if (!tsol_get_option_v4(mp, &label_type, &opt_ptr)) 149110181SKen.Powell@Sun.COM return (NULL); 14921676Sjpk } else { 14931676Sjpk ASSERT(ire->ire_ipversion == IPV6_VERSION); 14941676Sjpk ip6h = (ip6_t *)mp->b_rptr; 14951676Sjpk psrc = &ip6h->ip6_src; 14961676Sjpk pdst = &ip6h->ip6_dst; 14971676Sjpk proto = ip6h->ip6_nxt; 14981676Sjpk 14991676Sjpk if (proto != IPPROTO_TCP && proto != IPPROTO_UDP && 15001676Sjpk proto != IPPROTO_ICMPV6) { 15011676Sjpk uint8_t *nexthdrp; 15021676Sjpk uint16_t hdr_len; 15031676Sjpk 15041676Sjpk if (!ip_hdr_length_nexthdr_v6(mp, ip6h, &hdr_len, 15051676Sjpk &nexthdrp)) { 15061676Sjpk /* malformed packet; drop it */ 15071676Sjpk return (NULL); 15081676Sjpk } 15091676Sjpk proto = *nexthdrp; 15101676Sjpk } 151110181SKen.Powell@Sun.COM if (!tsol_get_option_v6(mp, &label_type, &opt_ptr)) 151210181SKen.Powell@Sun.COM return (NULL); 15131676Sjpk } 1514*11042SErik.Nordmark@Sun.COM /* 1515*11042SErik.Nordmark@Sun.COM * off_link is TRUE if destination not directly reachable. 1516*11042SErik.Nordmark@Sun.COM */ 1517*11042SErik.Nordmark@Sun.COM off_link = (ire->ire_type & IRE_OFFLINK); 15181676Sjpk 1519*11042SErik.Nordmark@Sun.COM if ((tsl = ira->ira_tsl) == NULL) 15201676Sjpk return (mp); 15211676Sjpk 152210934Ssommerfeld@sun.com if (tsl->tsl_flags & TSLF_IMPLICIT_IN) { 152310934Ssommerfeld@sun.com DTRACE_PROBE3(tx__ip__log__drop__forward__unresolved__label, 152410934Ssommerfeld@sun.com char *, 152510934Ssommerfeld@sun.com "cannot forward packet mp(1) with unresolved " 152610934Ssommerfeld@sun.com "security label sl(2)", 152710934Ssommerfeld@sun.com mblk_t *, mp, ts_label_t *, tsl); 152810934Ssommerfeld@sun.com 152910934Ssommerfeld@sun.com return (NULL); 153010934Ssommerfeld@sun.com } 153110934Ssommerfeld@sun.com 153210934Ssommerfeld@sun.com 15331676Sjpk ASSERT(psrc != NULL && pdst != NULL); 15341676Sjpk dst_rhtp = find_tpc(pdst, ire->ire_ipversion, B_FALSE); 15351676Sjpk 15361676Sjpk if (dst_rhtp == NULL) { 15371676Sjpk /* 15381676Sjpk * Without a template we do not know if forwarding 15391676Sjpk * violates MAC 15401676Sjpk */ 15411676Sjpk DTRACE_PROBE3(tx__ip__log__drop__forward__nodst, char *, 15421676Sjpk "mp(1) dropped, no template for destination ip4|6(2)", 15431676Sjpk mblk_t *, mp, void *, pdst); 15441676Sjpk return (NULL); 15451676Sjpk } 15461676Sjpk 15471676Sjpk /* 15481676Sjpk * Gateway template must have existed for off-link destinations, 15491676Sjpk * since tsol_ire_match_gwattr has ensured such condition. 15501676Sjpk */ 15512535Ssangeeta if (ire->ire_ipversion == IPV4_VERSION && off_link) { 15522535Ssangeeta /* 15532535Ssangeeta * Surya note: first check if we can get the gw_rhtp from 15542535Ssangeeta * the ire_gw_secattr->igsa_rhc; if this is null, then 15552535Ssangeeta * do a lookup based on the ire_addr (address of gw) 15562535Ssangeeta */ 15572535Ssangeeta if (ire->ire_gw_secattr != NULL && 15582535Ssangeeta ire->ire_gw_secattr->igsa_rhc != NULL) { 15592535Ssangeeta attrp = ire->ire_gw_secattr; 15602535Ssangeeta gw_rhtp = attrp->igsa_rhc->rhc_tpc; 15612535Ssangeeta } else { 1562*11042SErik.Nordmark@Sun.COM gw = &ire->ire_gateway_addr; 15632535Ssangeeta gw_rhtp = find_tpc(gw, ire->ire_ipversion, B_FALSE); 15642535Ssangeeta need_tpc_rele = B_TRUE; 15652535Ssangeeta } 15662535Ssangeeta if (gw_rhtp == NULL) { 15672535Ssangeeta DTRACE_PROBE3(tx__ip__log__drop__forward__nogw, char *, 15682535Ssangeeta "mp(1) dropped, no gateway in ire attributes(2)", 15692535Ssangeeta mblk_t *, mp, tsol_ire_gw_secattr_t *, attrp); 15702535Ssangeeta mp = NULL; 15712535Ssangeeta goto keep_label; 15722535Ssangeeta } 15732535Ssangeeta } 15742535Ssangeeta if (ire->ire_ipversion == IPV6_VERSION && 15752535Ssangeeta ((attrp = ire->ire_gw_secattr) == NULL || attrp->igsa_rhc == NULL || 15761676Sjpk (gw_rhtp = attrp->igsa_rhc->rhc_tpc) == NULL) && off_link) { 15771676Sjpk DTRACE_PROBE3(tx__ip__log__drop__forward__nogw, char *, 15781676Sjpk "mp(1) dropped, no gateway in ire attributes(2)", 15791676Sjpk mblk_t *, mp, tsol_ire_gw_secattr_t *, attrp); 15801676Sjpk mp = NULL; 15811676Sjpk goto keep_label; 15821676Sjpk } 15831676Sjpk 15841676Sjpk /* 15851676Sjpk * Check that the label for the packet is acceptable 15861676Sjpk * by destination host; otherwise, drop it. 15871676Sjpk */ 15881676Sjpk switch (dst_rhtp->tpc_tp.host_type) { 15891676Sjpk case SUN_CIPSO: 15901676Sjpk if (tsl->tsl_doi != dst_rhtp->tpc_tp.tp_doi || 15911676Sjpk (!_blinrange(&tsl->tsl_label, 15921676Sjpk &dst_rhtp->tpc_tp.tp_sl_range_cipso) && 15931676Sjpk !blinlset(&tsl->tsl_label, 15941676Sjpk dst_rhtp->tpc_tp.tp_sl_set_cipso))) { 15951676Sjpk DTRACE_PROBE4(tx__ip__log__drop__forward__mac, char *, 15961676Sjpk "labeled packet mp(1) dropped, label(2) fails " 15971676Sjpk "destination(3) accredation check", 15981676Sjpk mblk_t *, mp, ts_label_t *, tsl, 15991676Sjpk tsol_tpc_t *, dst_rhtp); 16001676Sjpk mp = NULL; 16011676Sjpk goto keep_label; 16021676Sjpk } 16031676Sjpk break; 16041676Sjpk 16051676Sjpk 16061676Sjpk case UNLABELED: 16071676Sjpk if (tsl->tsl_doi != dst_rhtp->tpc_tp.tp_doi || 16081676Sjpk !blequal(&dst_rhtp->tpc_tp.tp_def_label, 16091676Sjpk &tsl->tsl_label)) { 16101676Sjpk DTRACE_PROBE4(tx__ip__log__drop__forward__mac, char *, 16111676Sjpk "unlabeled packet mp(1) dropped, label(2) fails " 16121676Sjpk "destination(3) accredation check", 16131676Sjpk mblk_t *, mp, ts_label_t *, tsl, 16141676Sjpk tsol_tpc_t *, dst_rhtp); 16151676Sjpk mp = NULL; 16161676Sjpk goto keep_label; 16171676Sjpk } 16181676Sjpk break; 16191676Sjpk } 16201676Sjpk if (label_type == OPT_CIPSO) { 16211676Sjpk /* 16221676Sjpk * We keep the label on any of the following cases: 16231676Sjpk * 16241676Sjpk * 1. The destination is labeled (on/off-link). 16251676Sjpk * 2. The unlabeled destination is off-link, 16261676Sjpk * and the next hop gateway is labeled. 16271676Sjpk */ 16281676Sjpk if (dst_rhtp->tpc_tp.host_type != UNLABELED || 16291676Sjpk (off_link && 16301676Sjpk gw_rhtp->tpc_tp.host_type != UNLABELED)) 16311676Sjpk goto keep_label; 16321676Sjpk 16331676Sjpk /* 16341676Sjpk * Strip off the CIPSO option from the packet because: the 16351676Sjpk * unlabeled destination host is directly reachable through 16361676Sjpk * an interface (on-link); or, the unlabeled destination host 16371676Sjpk * is not directly reachable (off-link), and the next hop 16381676Sjpk * gateway is unlabeled. 16391676Sjpk */ 16401676Sjpk adjust = (af == AF_INET) ? tsol_remove_secopt(ipha, MBLKL(mp)) : 16411676Sjpk tsol_remove_secopt_v6(ip6h, MBLKL(mp)); 16421676Sjpk 16431676Sjpk ASSERT(adjust <= 0); 16441676Sjpk if (adjust != 0) { 16451676Sjpk 16461676Sjpk /* adjust is negative */ 16471676Sjpk ASSERT((mp->b_wptr + adjust) >= mp->b_rptr); 16481676Sjpk mp->b_wptr += adjust; 1649*11042SErik.Nordmark@Sun.COM /* 1650*11042SErik.Nordmark@Sun.COM * Note that caller adjusts ira_pktlen and 1651*11042SErik.Nordmark@Sun.COM * ira_ip_hdr_length 1652*11042SErik.Nordmark@Sun.COM * 1653*11042SErik.Nordmark@Sun.COM * For AF_INET6 note that tsol_remove_secopt_v6 1654*11042SErik.Nordmark@Sun.COM * adjusted ip6_plen. 1655*11042SErik.Nordmark@Sun.COM */ 16561676Sjpk if (af == AF_INET) { 16571676Sjpk ipha = (ipha_t *)mp->b_rptr; 16581676Sjpk iplen = ntohs(ipha->ipha_length) + adjust; 16591676Sjpk ipha->ipha_length = htons(iplen); 16601676Sjpk ipha->ipha_hdr_checksum = 0; 16611676Sjpk ipha->ipha_hdr_checksum = ip_csum_hdr(ipha); 16621676Sjpk } 16631676Sjpk DTRACE_PROBE3(tx__ip__log__info__forward__adjust, 16641676Sjpk char *, 16651676Sjpk "mp(1) adjusted(2) for CIPSO option removal", 16661676Sjpk mblk_t *, mp, int, adjust); 16671676Sjpk } 16681676Sjpk goto keep_label; 16691676Sjpk } 16701676Sjpk 16711676Sjpk ASSERT(label_type == OPT_NONE); 16721676Sjpk ASSERT(dst_rhtp != NULL); 16731676Sjpk 16741676Sjpk /* 16751676Sjpk * We need to add CIPSO option if the destination or the next hop 16761676Sjpk * gateway is labeled. Otherwise, pass the packet as is. 16771676Sjpk */ 16781676Sjpk if (dst_rhtp->tpc_tp.host_type == UNLABELED && 16791676Sjpk (!off_link || gw_rhtp->tpc_tp.host_type == UNLABELED)) 16801676Sjpk goto keep_label; 16811676Sjpk 1682*11042SErik.Nordmark@Sun.COM /* 1683*11042SErik.Nordmark@Sun.COM * Since we are forwarding packets we use GLOBAL_ZONEID for 1684*11042SErik.Nordmark@Sun.COM * the IRE lookup in tsol_check_label. 1685*11042SErik.Nordmark@Sun.COM * Since mac_exempt is false the zoneid isn't used for anything 1686*11042SErik.Nordmark@Sun.COM * but the IRE lookup, hence we set zone_is_global to false. 1687*11042SErik.Nordmark@Sun.COM */ 1688*11042SErik.Nordmark@Sun.COM if (af == AF_INET) { 1689*11042SErik.Nordmark@Sun.COM err = tsol_check_label_v4(tsl, GLOBAL_ZONEID, &mp, 1690*11042SErik.Nordmark@Sun.COM CONN_MAC_DEFAULT, B_FALSE, ipst, &effective_tsl); 1691*11042SErik.Nordmark@Sun.COM } else { 1692*11042SErik.Nordmark@Sun.COM err = tsol_check_label_v6(tsl, GLOBAL_ZONEID, &mp, 1693*11042SErik.Nordmark@Sun.COM CONN_MAC_DEFAULT, B_FALSE, ipst, &effective_tsl); 1694*11042SErik.Nordmark@Sun.COM } 1695*11042SErik.Nordmark@Sun.COM if (err != 0) { 1696*11042SErik.Nordmark@Sun.COM BUMP_MIB(&ipst->ips_ip_mib, ipIfStatsOutDiscards); 1697*11042SErik.Nordmark@Sun.COM ip_drop_output("tsol_check_label", mp, NULL); 1698*11042SErik.Nordmark@Sun.COM freemsg(mp); 16991676Sjpk mp = NULL; 17001676Sjpk goto keep_label; 17011676Sjpk } 17021676Sjpk 1703*11042SErik.Nordmark@Sun.COM /* 1704*11042SErik.Nordmark@Sun.COM * The effective_tsl must never affect the routing decision, hence 1705*11042SErik.Nordmark@Sun.COM * we ignore it here. 1706*11042SErik.Nordmark@Sun.COM */ 1707*11042SErik.Nordmark@Sun.COM if (effective_tsl != NULL) 1708*11042SErik.Nordmark@Sun.COM label_rele(effective_tsl); 1709*11042SErik.Nordmark@Sun.COM 17106596Skp158701 if (af == AF_INET) { 17116596Skp158701 ipha = (ipha_t *)mp->b_rptr; 17126596Skp158701 ipha->ipha_hdr_checksum = 0; 17136596Skp158701 ipha->ipha_hdr_checksum = ip_csum_hdr(ipha); 17141676Sjpk } 17151676Sjpk 17161676Sjpk keep_label: 17171676Sjpk TPC_RELE(dst_rhtp); 17182535Ssangeeta if (need_tpc_rele && gw_rhtp != NULL) 17192535Ssangeeta TPC_RELE(gw_rhtp); 17201676Sjpk return (mp); 17211676Sjpk } 17221676Sjpk 17231676Sjpk /* 17244564Swy83408 * Name: tsol_pmtu_adjust() 17254564Swy83408 * 17264564Swy83408 * Returns the adjusted mtu after removing security option. 17274564Swy83408 * Removes/subtracts the option if the packet's cred indicates an unlabeled 17284564Swy83408 * sender or if pkt_diff indicates this system enlarged the packet. 17294564Swy83408 */ 17304564Swy83408 uint32_t 17314564Swy83408 tsol_pmtu_adjust(mblk_t *mp, uint32_t mtu, int pkt_diff, int af) 17324564Swy83408 { 17334564Swy83408 int label_adj = 0; 17344564Swy83408 uint32_t min_mtu = IP_MIN_MTU; 17354564Swy83408 tsol_tpc_t *src_rhtp; 17364564Swy83408 void *src; 17374564Swy83408 17384564Swy83408 /* 17394564Swy83408 * Note: label_adj is non-positive, indicating the number of 17404564Swy83408 * bytes removed by removing the security option from the 17414564Swy83408 * header. 17424564Swy83408 */ 17434564Swy83408 if (af == AF_INET6) { 17444564Swy83408 ip6_t *ip6h; 17454564Swy83408 17464564Swy83408 min_mtu = IPV6_MIN_MTU; 17474564Swy83408 ip6h = (ip6_t *)mp->b_rptr; 17484564Swy83408 src = &ip6h->ip6_src; 17494564Swy83408 if ((src_rhtp = find_tpc(src, IPV6_VERSION, B_FALSE)) == NULL) 17504564Swy83408 return (mtu); 17514564Swy83408 if (pkt_diff > 0 || src_rhtp->tpc_tp.host_type == UNLABELED) { 17524564Swy83408 label_adj = tsol_remove_secopt_v6( 17534564Swy83408 (ip6_t *)mp->b_rptr, MBLKL(mp)); 17544564Swy83408 } 17554564Swy83408 } else { 17564564Swy83408 ipha_t *ipha; 17574564Swy83408 17584564Swy83408 ASSERT(af == AF_INET); 17594564Swy83408 ipha = (ipha_t *)mp->b_rptr; 17604564Swy83408 src = &ipha->ipha_src; 17614564Swy83408 if ((src_rhtp = find_tpc(src, IPV4_VERSION, B_FALSE)) == NULL) 17624564Swy83408 return (mtu); 17634564Swy83408 if (pkt_diff > 0 || src_rhtp->tpc_tp.host_type == UNLABELED) 17644564Swy83408 label_adj = tsol_remove_secopt( 17654564Swy83408 (ipha_t *)mp->b_rptr, MBLKL(mp)); 17664564Swy83408 } 17674564Swy83408 /* 17684564Swy83408 * Make pkt_diff non-negative and the larger of the bytes 17694564Swy83408 * previously added (if any) or just removed, since label 17704564Swy83408 * addition + subtraction may not be completely idempotent. 17714564Swy83408 */ 17724564Swy83408 if (pkt_diff < -label_adj) 17734564Swy83408 pkt_diff = -label_adj; 17744564Swy83408 if (pkt_diff > 0 && pkt_diff < mtu) 17754564Swy83408 mtu -= pkt_diff; 17764564Swy83408 17774564Swy83408 TPC_RELE(src_rhtp); 17784564Swy83408 return (MAX(mtu, min_mtu)); 17794564Swy83408 } 17804564Swy83408 17814564Swy83408 /* 17821676Sjpk * Name: tsol_rtsa_init() 17831676Sjpk * 17841676Sjpk * Normal: Sanity checks on the route security attributes provided by 17851676Sjpk * user. Convert it into a route security parameter list to 17861676Sjpk * be returned to caller. 17871676Sjpk * 17881676Sjpk * Output: EINVAL if bad security attributes in the routing message 17891676Sjpk * ENOMEM if unable to allocate data structures 17901676Sjpk * 0 otherwise. 17911676Sjpk * 17921676Sjpk * Note: On input, cp must point to the end of any addresses in 17931676Sjpk * the rt_msghdr_t structure. 17941676Sjpk */ 17951676Sjpk int 17961676Sjpk tsol_rtsa_init(rt_msghdr_t *rtm, tsol_rtsecattr_t *sp, caddr_t cp) 17971676Sjpk { 17981676Sjpk uint_t sacnt; 17991676Sjpk int err; 18001676Sjpk caddr_t lim; 18011676Sjpk tsol_rtsecattr_t *tp; 18021676Sjpk 18031676Sjpk ASSERT((cp >= (caddr_t)&rtm[1]) && sp != NULL); 18041676Sjpk 18051676Sjpk /* 18061676Sjpk * In theory, we could accept as many security attributes configured 18071676Sjpk * per route destination. However, the current design is limited 18081676Sjpk * such that at most only one set security attributes is allowed to 18091676Sjpk * be associated with a prefix IRE. We therefore assert for now. 18101676Sjpk */ 18111676Sjpk /* LINTED */ 18121676Sjpk ASSERT(TSOL_RTSA_REQUEST_MAX == 1); 18131676Sjpk 18141676Sjpk sp->rtsa_cnt = 0; 18151676Sjpk lim = (caddr_t)rtm + rtm->rtm_msglen; 18161676Sjpk ASSERT(cp <= lim); 18171676Sjpk 18181676Sjpk if ((lim - cp) < sizeof (rtm_ext_t) || 18191676Sjpk ((rtm_ext_t *)cp)->rtmex_type != RTMEX_GATEWAY_SECATTR) 18201676Sjpk return (0); 18211676Sjpk 18221676Sjpk if (((rtm_ext_t *)cp)->rtmex_len < sizeof (tsol_rtsecattr_t)) 18231676Sjpk return (EINVAL); 18241676Sjpk 18251676Sjpk cp += sizeof (rtm_ext_t); 18261676Sjpk 18271676Sjpk if ((lim - cp) < sizeof (*tp) || 18281676Sjpk (tp = (tsol_rtsecattr_t *)cp, (sacnt = tp->rtsa_cnt) == 0) || 18291676Sjpk (lim - cp) < TSOL_RTSECATTR_SIZE(sacnt)) 18301676Sjpk return (EINVAL); 18311676Sjpk 18321676Sjpk /* 18331676Sjpk * Trying to add route security attributes when system 18341676Sjpk * labeling service is not available, or when user supllies 18351676Sjpk * more than the maximum number of security attributes 18361676Sjpk * allowed per request. 18371676Sjpk */ 18381676Sjpk if ((sacnt > 0 && !is_system_labeled()) || 18391676Sjpk sacnt > TSOL_RTSA_REQUEST_MAX) 18401676Sjpk return (EINVAL); 18411676Sjpk 18421676Sjpk /* Ensure valid credentials */ 18431676Sjpk if ((err = rtsa_validate(&((tsol_rtsecattr_t *)cp)-> 18441676Sjpk rtsa_attr[0])) != 0) { 18451676Sjpk cp += sizeof (*sp); 18461676Sjpk return (err); 18471676Sjpk } 18481676Sjpk 18491676Sjpk bcopy(cp, sp, sizeof (*sp)); 18501676Sjpk cp += sizeof (*sp); 18511676Sjpk return (0); 18521676Sjpk } 18531676Sjpk 18541676Sjpk int 1855*11042SErik.Nordmark@Sun.COM tsol_ire_init_gwattr(ire_t *ire, uchar_t ipversion, tsol_gc_t *gc) 18561676Sjpk { 18571676Sjpk tsol_ire_gw_secattr_t *attrp; 18581676Sjpk boolean_t exists = B_FALSE; 18591676Sjpk in_addr_t ga_addr4; 18601676Sjpk void *paddr = NULL; 1861*11042SErik.Nordmark@Sun.COM tsol_gcgrp_t *gcgrp = NULL; 18621676Sjpk 18631676Sjpk ASSERT(ire != NULL); 18641676Sjpk 18651676Sjpk /* 18661676Sjpk * The only time that attrp can be NULL is when this routine is 18671676Sjpk * called for the first time during the creation/initialization 18681676Sjpk * of the corresponding IRE. It will only get cleared when the 18691676Sjpk * IRE is deleted. 18701676Sjpk */ 18711676Sjpk if ((attrp = ire->ire_gw_secattr) == NULL) { 18721676Sjpk attrp = ire_gw_secattr_alloc(KM_NOSLEEP); 18731676Sjpk if (attrp == NULL) 18741676Sjpk return (ENOMEM); 18751676Sjpk ire->ire_gw_secattr = attrp; 18761676Sjpk } else { 18771676Sjpk exists = B_TRUE; 18781676Sjpk mutex_enter(&attrp->igsa_lock); 18791676Sjpk 18801676Sjpk if (attrp->igsa_rhc != NULL) { 18811676Sjpk TNRHC_RELE(attrp->igsa_rhc); 18821676Sjpk attrp->igsa_rhc = NULL; 18831676Sjpk } 18841676Sjpk 18851676Sjpk if (attrp->igsa_gc != NULL) 18861676Sjpk GC_REFRELE(attrp->igsa_gc); 18871676Sjpk } 18881676Sjpk ASSERT(!exists || MUTEX_HELD(&attrp->igsa_lock)); 18891676Sjpk 18901676Sjpk /* 18911676Sjpk * References already held by caller and we keep them; 1892*11042SErik.Nordmark@Sun.COM * note that gc may be set to NULL to clear out igsa_gc. 18931676Sjpk */ 18941676Sjpk attrp->igsa_gc = gc; 18951676Sjpk 1896*11042SErik.Nordmark@Sun.COM if (gc != NULL) { 18971676Sjpk gcgrp = gc->gc_grp; 18981676Sjpk ASSERT(gcgrp != NULL); 18991676Sjpk } 19001676Sjpk 19011676Sjpk /* 19021676Sjpk * Intialize the template for gateway; we use the gateway's 19031676Sjpk * address found in either the passed in gateway credential 19041676Sjpk * or group pointer, or the ire_gateway_addr{_v6} field. 19051676Sjpk */ 19061676Sjpk if (gcgrp != NULL) { 19071676Sjpk tsol_gcgrp_addr_t *ga = &gcgrp->gcgrp_addr; 19081676Sjpk 19091676Sjpk /* 19101676Sjpk * Caller is holding a reference, and that we don't 19111676Sjpk * need to hold any lock to access the address. 19121676Sjpk */ 19131676Sjpk if (ipversion == IPV4_VERSION) { 19141676Sjpk ASSERT(ga->ga_af == AF_INET); 19151676Sjpk IN6_V4MAPPED_TO_IPADDR(&ga->ga_addr, ga_addr4); 19161676Sjpk paddr = &ga_addr4; 19171676Sjpk } else { 19181676Sjpk ASSERT(ga->ga_af == AF_INET6); 19191676Sjpk paddr = &ga->ga_addr; 19201676Sjpk } 1921*11042SErik.Nordmark@Sun.COM } else if (ire->ire_type & IRE_OFFLINK) { 1922*11042SErik.Nordmark@Sun.COM if (ipversion == IPV6_VERSION) 1923*11042SErik.Nordmark@Sun.COM paddr = &ire->ire_gateway_addr_v6; 1924*11042SErik.Nordmark@Sun.COM else if (ipversion == IPV4_VERSION) 1925*11042SErik.Nordmark@Sun.COM paddr = &ire->ire_gateway_addr; 19261676Sjpk } 19271676Sjpk 19281676Sjpk /* 19291676Sjpk * Lookup the gateway template; note that we could get an internal 19301676Sjpk * template here, which we cache anyway. During IRE matching, we'll 19311676Sjpk * try to update this gateway template cache and hopefully get a 19321676Sjpk * real one. 19331676Sjpk */ 19341676Sjpk if (paddr != NULL) { 19353292Skp158701 attrp->igsa_rhc = find_rhc(paddr, ipversion, B_FALSE); 19361676Sjpk } 19371676Sjpk 19381676Sjpk if (exists) 19391676Sjpk mutex_exit(&attrp->igsa_lock); 19401676Sjpk 19411676Sjpk return (0); 19421676Sjpk } 19431676Sjpk 19441676Sjpk /* 19451676Sjpk * This function figures the type of MLP that we'll be using based on the 19461676Sjpk * address that the user is binding and the zone. If the address is 19471676Sjpk * unspecified, then we're looking at both private and shared. If it's one 19481676Sjpk * of the zone's private addresses, then it's private only. If it's one 194910493SJarrett.Lu@Sun.COM * of the global addresses, then it's shared only. Multicast addresses are 195010493SJarrett.Lu@Sun.COM * treated same as unspecified address. 19511676Sjpk * 19521676Sjpk * If we can't figure out what it is, then return mlptSingle. That's actually 19531676Sjpk * an error case. 19543448Sdh155122 * 1955*11042SErik.Nordmark@Sun.COM * The callers are assumed to pass in zone->zone_id and not the zoneid that 19563448Sdh155122 * is stored in a conn_t (since the latter will be GLOBAL_ZONEID in an 19573448Sdh155122 * exclusive stack zone). 19581676Sjpk */ 19591676Sjpk mlp_type_t 19603448Sdh155122 tsol_mlp_addr_type(zoneid_t zoneid, uchar_t version, const void *addr, 19613448Sdh155122 ip_stack_t *ipst) 19621676Sjpk { 19631676Sjpk in_addr_t in4; 19641676Sjpk ire_t *ire; 19651676Sjpk ipif_t *ipif; 19661676Sjpk zoneid_t addrzone; 19673448Sdh155122 zoneid_t ip_zoneid; 19681676Sjpk 19691676Sjpk ASSERT(addr != NULL); 19701676Sjpk 19713448Sdh155122 /* 19723448Sdh155122 * For exclusive stacks we set the zoneid to zero 19733448Sdh155122 * to operate as if in the global zone for IRE and conn_t comparisons. 19743448Sdh155122 */ 19753448Sdh155122 if (ipst->ips_netstack->netstack_stackid != GLOBAL_NETSTACKID) 19763448Sdh155122 ip_zoneid = GLOBAL_ZONEID; 19773448Sdh155122 else 19783448Sdh155122 ip_zoneid = zoneid; 19793448Sdh155122 19801676Sjpk if (version == IPV6_VERSION && 19811676Sjpk IN6_IS_ADDR_V4MAPPED((const in6_addr_t *)addr)) { 19821676Sjpk IN6_V4MAPPED_TO_IPADDR((const in6_addr_t *)addr, in4); 19831676Sjpk addr = &in4; 19841676Sjpk version = IPV4_VERSION; 19851676Sjpk } 19861676Sjpk 1987*11042SErik.Nordmark@Sun.COM /* Check whether the IRE_LOCAL (or ipif) is ALL_ZONES */ 19881676Sjpk if (version == IPV4_VERSION) { 19891676Sjpk in4 = *(const in_addr_t *)addr; 199010493SJarrett.Lu@Sun.COM if ((in4 == INADDR_ANY) || CLASSD(in4)) { 19911676Sjpk return (mlptBoth); 19923448Sdh155122 } 1993*11042SErik.Nordmark@Sun.COM ire = ire_ftable_lookup_v4(in4, 0, 0, IRE_LOCAL|IRE_LOOPBACK, 1994*11042SErik.Nordmark@Sun.COM NULL, ip_zoneid, NULL, MATCH_IRE_TYPE | MATCH_IRE_ZONEONLY, 1995*11042SErik.Nordmark@Sun.COM 0, ipst, NULL); 19961676Sjpk } else { 199710493SJarrett.Lu@Sun.COM if (IN6_IS_ADDR_UNSPECIFIED((const in6_addr_t *)addr) || 199810493SJarrett.Lu@Sun.COM IN6_IS_ADDR_MULTICAST((const in6_addr_t *)addr)) { 19991676Sjpk return (mlptBoth); 20003448Sdh155122 } 2001*11042SErik.Nordmark@Sun.COM ire = ire_ftable_lookup_v6(addr, 0, 0, IRE_LOCAL|IRE_LOOPBACK, 2002*11042SErik.Nordmark@Sun.COM NULL, ip_zoneid, NULL, MATCH_IRE_TYPE | MATCH_IRE_ZONEONLY, 2003*11042SErik.Nordmark@Sun.COM 0, ipst, NULL); 20041676Sjpk } 20051676Sjpk /* 20061676Sjpk * If we can't find the IRE, then we have to behave exactly like 2007*11042SErik.Nordmark@Sun.COM * ip_laddr_verify_{v4,v6}. That means looking up the IPIF so that 2008*11042SErik.Nordmark@Sun.COM * users can bind to addresses on "down" interfaces. 20091676Sjpk * 20101676Sjpk * If we can't find that either, then the bind is going to fail, so 20111676Sjpk * just give up. Note that there's a miniscule chance that the address 20121676Sjpk * is in transition, but we don't bother handling that. 20131676Sjpk */ 20141676Sjpk if (ire == NULL) { 20151676Sjpk if (version == IPV4_VERSION) 20161676Sjpk ipif = ipif_lookup_addr(*(const in_addr_t *)addr, NULL, 2017*11042SErik.Nordmark@Sun.COM ip_zoneid, ipst); 20181676Sjpk else 20191676Sjpk ipif = ipif_lookup_addr_v6((const in6_addr_t *)addr, 2020*11042SErik.Nordmark@Sun.COM NULL, ip_zoneid, ipst); 20213448Sdh155122 if (ipif == NULL) { 20221676Sjpk return (mlptSingle); 20233448Sdh155122 } 20241676Sjpk addrzone = ipif->ipif_zoneid; 20251676Sjpk ipif_refrele(ipif); 20261676Sjpk } else { 20271676Sjpk addrzone = ire->ire_zoneid; 20281676Sjpk ire_refrele(ire); 20291676Sjpk } 20301676Sjpk return (addrzone == ALL_ZONES ? mlptShared : mlptPrivate); 20311676Sjpk } 20321676Sjpk 20331676Sjpk /* 20341676Sjpk * Since we are configuring local interfaces, and we know trusted 20351676Sjpk * extension CDE requires local interfaces to be cipso host type in 20361676Sjpk * order to function correctly, we'll associate a cipso template 20371676Sjpk * to each local interface and let the interface come up. Configuring 20381676Sjpk * a local interface to be "unlabeled" host type is a configuration error. 20391676Sjpk * We'll override that error and make the interface host type to be cipso 20401676Sjpk * here. 20411676Sjpk * 20421676Sjpk * The code is optimized for the usual "success" case and unwinds things on 20431676Sjpk * error. We don't want to go to the trouble and expense of formatting the 20441676Sjpk * interface name for the usual case where everything is configured correctly. 20451676Sjpk */ 20461676Sjpk boolean_t 20471676Sjpk tsol_check_interface_address(const ipif_t *ipif) 20481676Sjpk { 20491676Sjpk tsol_tpc_t *tp; 20501676Sjpk char addrbuf[INET6_ADDRSTRLEN]; 20511676Sjpk int af; 20521676Sjpk const void *addr; 20531676Sjpk zone_t *zone; 20541676Sjpk ts_label_t *plabel; 20551676Sjpk const bslabel_t *label; 20561676Sjpk char ifbuf[LIFNAMSIZ + 10]; 20571676Sjpk const char *ifname; 20581676Sjpk boolean_t retval; 20591676Sjpk tsol_rhent_t rhent; 20603448Sdh155122 netstack_t *ns = ipif->ipif_ill->ill_ipst->ips_netstack; 20611676Sjpk 20621676Sjpk if (IN6_IS_ADDR_V4MAPPED(&ipif->ipif_v6lcl_addr)) { 20631676Sjpk af = AF_INET; 20641676Sjpk addr = &V4_PART_OF_V6(ipif->ipif_v6lcl_addr); 20651676Sjpk } else { 20661676Sjpk af = AF_INET6; 20671676Sjpk addr = &ipif->ipif_v6lcl_addr; 20681676Sjpk } 20691676Sjpk 20701676Sjpk tp = find_tpc(&ipif->ipif_v6lcl_addr, IPV6_VERSION, B_FALSE); 20713448Sdh155122 20723448Sdh155122 /* assumes that ALL_ZONES implies that there is no exclusive stack */ 20733448Sdh155122 if (ipif->ipif_zoneid == ALL_ZONES) { 20743448Sdh155122 zone = NULL; 20753448Sdh155122 } else if (ns->netstack_stackid == GLOBAL_NETSTACKID) { 20763448Sdh155122 /* Shared stack case */ 20773448Sdh155122 zone = zone_find_by_id(ipif->ipif_zoneid); 20783448Sdh155122 } else { 20793448Sdh155122 /* Exclusive stack case */ 20803448Sdh155122 zone = zone_find_by_id(crgetzoneid(ipif->ipif_ill->ill_credp)); 20813448Sdh155122 } 20821676Sjpk if (zone != NULL) { 20831676Sjpk plabel = zone->zone_slabel; 20841676Sjpk ASSERT(plabel != NULL); 20851676Sjpk label = label2bslabel(plabel); 20861676Sjpk } 20871676Sjpk 20881676Sjpk /* 20891676Sjpk * If it's CIPSO and an all-zones address, then we're done. 20901676Sjpk * If it's a CIPSO zone specific address, the zone's label 20911676Sjpk * must be in the range or set specified in the template. 20921676Sjpk * When the remote host entry is missing or the template 20931676Sjpk * type is incorrect for this interface, we create a 20941676Sjpk * CIPSO host entry in kernel and allow the interface to be 20951676Sjpk * brought up as CIPSO type. 20961676Sjpk */ 20971676Sjpk if (tp != NULL && ( 20981676Sjpk /* The all-zones case */ 20991676Sjpk (tp->tpc_tp.host_type == SUN_CIPSO && 21001676Sjpk tp->tpc_tp.tp_doi == default_doi && 21011676Sjpk ipif->ipif_zoneid == ALL_ZONES) || 21021676Sjpk /* The local-zone case */ 21031676Sjpk (zone != NULL && plabel->tsl_doi == tp->tpc_tp.tp_doi && 21041676Sjpk ((tp->tpc_tp.host_type == SUN_CIPSO && 21051676Sjpk (_blinrange(label, &tp->tpc_tp.tp_sl_range_cipso) || 21061676Sjpk blinlset(label, tp->tpc_tp.tp_sl_set_cipso))))))) { 21071676Sjpk if (zone != NULL) 21081676Sjpk zone_rele(zone); 21091676Sjpk TPC_RELE(tp); 21101676Sjpk return (B_TRUE); 21111676Sjpk } 21121676Sjpk 21131676Sjpk ifname = ipif->ipif_ill->ill_name; 21141676Sjpk if (ipif->ipif_id != 0) { 21151676Sjpk (void) snprintf(ifbuf, sizeof (ifbuf), "%s:%u", ifname, 21161676Sjpk ipif->ipif_id); 21171676Sjpk ifname = ifbuf; 21181676Sjpk } 21191676Sjpk (void) inet_ntop(af, addr, addrbuf, sizeof (addrbuf)); 21201676Sjpk 21211676Sjpk if (tp == NULL) { 21221676Sjpk cmn_err(CE_NOTE, "template entry for %s missing. Default to " 21231676Sjpk "CIPSO type for %s", ifname, addrbuf); 21241676Sjpk retval = B_TRUE; 21251676Sjpk } else if (tp->tpc_tp.host_type == UNLABELED) { 21261676Sjpk cmn_err(CE_NOTE, "template type for %s incorrectly configured. " 21271676Sjpk "Change to CIPSO type for %s", ifname, addrbuf); 21281676Sjpk retval = B_TRUE; 21291676Sjpk } else if (ipif->ipif_zoneid == ALL_ZONES) { 21301676Sjpk if (tp->tpc_tp.host_type != SUN_CIPSO) { 21311676Sjpk cmn_err(CE_NOTE, "%s failed: %s isn't set to CIPSO for " 21321676Sjpk "all-zones. Converted to CIPSO.", ifname, addrbuf); 21331676Sjpk retval = B_TRUE; 21341676Sjpk } else { 21351676Sjpk cmn_err(CE_NOTE, "%s failed: %s has wrong DOI %d " 21361676Sjpk "instead of %d", ifname, addrbuf, 21371676Sjpk tp->tpc_tp.tp_doi, default_doi); 21381676Sjpk retval = B_FALSE; 21391676Sjpk } 21401676Sjpk } else if (zone == NULL) { 21411676Sjpk cmn_err(CE_NOTE, "%s failed: zoneid %d unknown", 21421676Sjpk ifname, ipif->ipif_zoneid); 21431676Sjpk retval = B_FALSE; 21441676Sjpk } else if (plabel->tsl_doi != tp->tpc_tp.tp_doi) { 21451676Sjpk cmn_err(CE_NOTE, "%s failed: zone %s has DOI %d but %s has " 21461676Sjpk "DOI %d", ifname, zone->zone_name, plabel->tsl_doi, 21471676Sjpk addrbuf, tp->tpc_tp.tp_doi); 21481676Sjpk retval = B_FALSE; 21491676Sjpk } else { 21501676Sjpk cmn_err(CE_NOTE, "%s failed: zone %s label incompatible with " 21511676Sjpk "%s", ifname, zone->zone_name, addrbuf); 21521676Sjpk tsol_print_label(label, "zone label"); 21531676Sjpk retval = B_FALSE; 21541676Sjpk } 21551676Sjpk 21561676Sjpk if (zone != NULL) 21571676Sjpk zone_rele(zone); 21581676Sjpk if (tp != NULL) 21591676Sjpk TPC_RELE(tp); 21601676Sjpk if (retval) { 21611676Sjpk /* 21621676Sjpk * we've corrected a config error and let the interface 21631676Sjpk * come up as cipso. Need to insert an rhent. 21641676Sjpk */ 21651676Sjpk if ((rhent.rh_address.ta_family = af) == AF_INET) { 21661676Sjpk rhent.rh_prefix = 32; 21671676Sjpk rhent.rh_address.ta_addr_v4 = *(struct in_addr *)addr; 21681676Sjpk } else { 21691676Sjpk rhent.rh_prefix = 128; 21701676Sjpk rhent.rh_address.ta_addr_v6 = *(in6_addr_t *)addr; 21711676Sjpk } 21721676Sjpk (void) strcpy(rhent.rh_template, "cipso"); 21731676Sjpk if (tnrh_load(&rhent) != 0) { 21741676Sjpk cmn_err(CE_NOTE, "%s failed: Cannot insert CIPSO " 21751676Sjpk "template for local addr %s", ifname, addrbuf); 21761676Sjpk retval = B_FALSE; 21771676Sjpk } 21781676Sjpk } 21791676Sjpk return (retval); 21801676Sjpk } 2181