145916cd2Sjpk /* 245916cd2Sjpk * CDDL HEADER START 345916cd2Sjpk * 445916cd2Sjpk * The contents of this file are subject to the terms of the 545916cd2Sjpk * Common Development and Distribution License (the "License"). 645916cd2Sjpk * You may not use this file except in compliance with the License. 745916cd2Sjpk * 845916cd2Sjpk * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 945916cd2Sjpk * or http://www.opensolaris.org/os/licensing. 1045916cd2Sjpk * See the License for the specific language governing permissions 1145916cd2Sjpk * and limitations under the License. 1245916cd2Sjpk * 1345916cd2Sjpk * When distributing Covered Code, include this CDDL HEADER in each 1445916cd2Sjpk * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1545916cd2Sjpk * If applicable, add the following below this CDDL HEADER, with the 1645916cd2Sjpk * fields enclosed by brackets "[]" replaced with your own identifying 1745916cd2Sjpk * information: Portions Copyright [yyyy] [name of copyright owner] 1845916cd2Sjpk * 1945916cd2Sjpk * CDDL HEADER END 2045916cd2Sjpk */ 2145916cd2Sjpk /* 22de8c4a14SErik Nordmark * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 2345916cd2Sjpk * Use is subject to license terms. 2445916cd2Sjpk */ 2545916cd2Sjpk 2645916cd2Sjpk #include <sys/types.h> 2745916cd2Sjpk #include <sys/stream.h> 2845916cd2Sjpk #include <sys/strsubr.h> 2945916cd2Sjpk #include <sys/stropts.h> 3045916cd2Sjpk #include <sys/sunddi.h> 3145916cd2Sjpk #include <sys/cred.h> 3245916cd2Sjpk #include <sys/debug.h> 3345916cd2Sjpk #include <sys/kmem.h> 3445916cd2Sjpk #include <sys/errno.h> 3545916cd2Sjpk #include <sys/disp.h> 3645916cd2Sjpk #include <netinet/in.h> 3745916cd2Sjpk #include <netinet/in_systm.h> 3845916cd2Sjpk #include <netinet/ip.h> 3945916cd2Sjpk #include <netinet/ip_icmp.h> 4045916cd2Sjpk #include <netinet/tcp.h> 4145916cd2Sjpk #include <inet/common.h> 4245916cd2Sjpk #include <inet/ipclassifier.h> 4345916cd2Sjpk #include <inet/ip.h> 4445916cd2Sjpk #include <inet/mib2.h> 4545916cd2Sjpk #include <inet/nd.h> 4645916cd2Sjpk #include <inet/tcp.h> 4745916cd2Sjpk #include <inet/ip_rts.h> 4845916cd2Sjpk #include <inet/ip_ire.h> 4945916cd2Sjpk #include <inet/ip_if.h> 5045916cd2Sjpk #include <sys/modhash.h> 5145916cd2Sjpk 5245916cd2Sjpk #include <sys/tsol/label.h> 5345916cd2Sjpk #include <sys/tsol/label_macro.h> 5445916cd2Sjpk #include <sys/tsol/tnet.h> 5545916cd2Sjpk #include <sys/tsol/tndb.h> 5645916cd2Sjpk #include <sys/strsun.h> 5745916cd2Sjpk 5845916cd2Sjpk /* tunable for strict error-reply behavior (TCP RST and ICMP Unreachable) */ 5945916cd2Sjpk int tsol_strict_error; 6045916cd2Sjpk 6145916cd2Sjpk /* 6245916cd2Sjpk * Some notes on the Trusted Solaris IRE gateway security attributes: 6345916cd2Sjpk * 6445916cd2Sjpk * When running in Trusted mode, the routing subsystem determines whether or 6545916cd2Sjpk * not a packet can be delivered to an off-link host (not directly reachable 6645916cd2Sjpk * through an interface) based on the accreditation checks of the packet's 6745916cd2Sjpk * security attributes against those associated with the next-hop gateway. 6845916cd2Sjpk * 6945916cd2Sjpk * The next-hop gateway's security attributes can be derived from two sources 7045916cd2Sjpk * (in order of preference): route-related and the host database. A Trusted 7145916cd2Sjpk * system must be configured with at least the host database containing an 7245916cd2Sjpk * entry for the next-hop gateway, or otherwise no accreditation checks can 7345916cd2Sjpk * be performed, which may result in the inability to send packets to any 7445916cd2Sjpk * off-link destination host. 7545916cd2Sjpk * 7645916cd2Sjpk * The major differences between the two sources are the number and type of 7745916cd2Sjpk * security attributes used for accreditation checks. A host database entry 7845916cd2Sjpk * can contain at most one set of security attributes, specific only to the 7945916cd2Sjpk * next-hop gateway. On contrast, route-related security attributes are made 8045916cd2Sjpk * up of a collection of security attributes for the distant networks, and 8145916cd2Sjpk * are grouped together per next-hop gateway used to reach those networks. 8245916cd2Sjpk * This is the preferred method, and the routing subsystem will fallback to 8345916cd2Sjpk * the host database entry only if there are no route-related attributes 8445916cd2Sjpk * associated with the next-hop gateway. 8545916cd2Sjpk * 8645916cd2Sjpk * In Trusted mode, all of the IRE entries (except LOCAL/LOOPBACK/BROADCAST/ 8745916cd2Sjpk * INTERFACE type) are initialized to contain a placeholder to store this 8845916cd2Sjpk * information. The ire_gw_secattr structure gets allocated, initialized 8945916cd2Sjpk * and associated with the IRE during the time of the IRE creation. The 9045916cd2Sjpk * initialization process also includes resolving the host database entry 9145916cd2Sjpk * of the next-hop gateway for fallback purposes. It does not include any 9245916cd2Sjpk * route-related attribute setup, as that process comes separately as part 9345916cd2Sjpk * of the route requests (add/change) made to the routing subsystem. 9445916cd2Sjpk * 9545916cd2Sjpk * The underlying logic which involves associating IREs with the gateway 9645916cd2Sjpk * security attributes are represented by the following data structures: 9745916cd2Sjpk * 9845916cd2Sjpk * tsol_gcdb_t, or "gcdb" 9945916cd2Sjpk * 10045916cd2Sjpk * - This is a system-wide collection of records containing the 10145916cd2Sjpk * currently used route-related security attributes, which are fed 10245916cd2Sjpk * through the routing socket interface, e.g. "route add/change". 10345916cd2Sjpk * 10445916cd2Sjpk * tsol_gc_t, or "gc" 10545916cd2Sjpk * 10645916cd2Sjpk * - This is the gateway credential structure, and it provides for the 10745916cd2Sjpk * only mechanism to access the contents of gcdb. More than one gc 10845916cd2Sjpk * entries may refer to the same gcdb record. gc's in the system are 10945916cd2Sjpk * grouped according to the next-hop gateway address. 11045916cd2Sjpk * 11145916cd2Sjpk * tsol_gcgrp_t, or "gcgrp" 11245916cd2Sjpk * 11345916cd2Sjpk * - Group of gateway credentials, and is unique per next-hop gateway 11445916cd2Sjpk * address. When the group is not empty, i.e. when gcgrp_count is 11545916cd2Sjpk * greater than zero, it contains one or more gc's, each pointing to 11645916cd2Sjpk * a gcdb record which indicates the gateway security attributes 11745916cd2Sjpk * associated with the next-hop gateway. 11845916cd2Sjpk * 11945916cd2Sjpk * The fields of the tsol_ire_gw_secattr_t used from within the IRE are: 12045916cd2Sjpk * 12145916cd2Sjpk * igsa_lock 12245916cd2Sjpk * 12345916cd2Sjpk * - Lock that protects all fields within tsol_ire_gw_secattr_t. 12445916cd2Sjpk * 12545916cd2Sjpk * igsa_rhc 12645916cd2Sjpk * 12745916cd2Sjpk * - Remote host cache database entry of next-hop gateway. This is 12845916cd2Sjpk * used in the case when there are no route-related attributes 12945916cd2Sjpk * configured for the IRE. 13045916cd2Sjpk * 13145916cd2Sjpk * igsa_gc 13245916cd2Sjpk * 13345916cd2Sjpk * - A set of route-related attributes that only get set for prefix 13445916cd2Sjpk * IREs. If this is non-NULL, the prefix IRE has been associated 13545916cd2Sjpk * with a set of gateway security attributes by way of route add/ 136bd670b35SErik Nordmark * change functionality. 13745916cd2Sjpk */ 13845916cd2Sjpk 13945916cd2Sjpk static kmem_cache_t *ire_gw_secattr_cache; 14045916cd2Sjpk 14145916cd2Sjpk #define GCDB_HASH_SIZE 101 14245916cd2Sjpk #define GCGRP_HASH_SIZE 101 14345916cd2Sjpk 14445916cd2Sjpk #define GCDB_REFRELE(p) { \ 14545916cd2Sjpk mutex_enter(&gcdb_lock); \ 14645916cd2Sjpk ASSERT((p)->gcdb_refcnt > 0); \ 14745916cd2Sjpk if (--((p)->gcdb_refcnt) == 0) \ 14845916cd2Sjpk gcdb_inactive(p); \ 14945916cd2Sjpk ASSERT(MUTEX_HELD(&gcdb_lock)); \ 15045916cd2Sjpk mutex_exit(&gcdb_lock); \ 15145916cd2Sjpk } 15245916cd2Sjpk 15345916cd2Sjpk static int gcdb_hash_size = GCDB_HASH_SIZE; 15445916cd2Sjpk static int gcgrp_hash_size = GCGRP_HASH_SIZE; 15545916cd2Sjpk static mod_hash_t *gcdb_hash; 15645916cd2Sjpk static mod_hash_t *gcgrp4_hash; 15745916cd2Sjpk static mod_hash_t *gcgrp6_hash; 15845916cd2Sjpk 15945916cd2Sjpk static kmutex_t gcdb_lock; 16045916cd2Sjpk kmutex_t gcgrp_lock; 16145916cd2Sjpk 16245916cd2Sjpk static uint_t gcdb_hash_by_secattr(void *, mod_hash_key_t); 16345916cd2Sjpk static int gcdb_hash_cmp(mod_hash_key_t, mod_hash_key_t); 16445916cd2Sjpk static tsol_gcdb_t *gcdb_lookup(struct rtsa_s *, boolean_t); 16545916cd2Sjpk static void gcdb_inactive(tsol_gcdb_t *); 16645916cd2Sjpk 16745916cd2Sjpk static uint_t gcgrp_hash_by_addr(void *, mod_hash_key_t); 16845916cd2Sjpk static int gcgrp_hash_cmp(mod_hash_key_t, mod_hash_key_t); 16945916cd2Sjpk 17045916cd2Sjpk static int ire_gw_secattr_constructor(void *, void *, int); 17145916cd2Sjpk static void ire_gw_secattr_destructor(void *, void *); 17245916cd2Sjpk 17345916cd2Sjpk void 17445916cd2Sjpk tnet_init(void) 17545916cd2Sjpk { 17645916cd2Sjpk ire_gw_secattr_cache = kmem_cache_create("ire_gw_secattr_cache", 17745916cd2Sjpk sizeof (tsol_ire_gw_secattr_t), 64, ire_gw_secattr_constructor, 17845916cd2Sjpk ire_gw_secattr_destructor, NULL, NULL, NULL, 0); 17945916cd2Sjpk 18045916cd2Sjpk gcdb_hash = mod_hash_create_extended("gcdb_hash", 18145916cd2Sjpk gcdb_hash_size, mod_hash_null_keydtor, mod_hash_null_valdtor, 18245916cd2Sjpk gcdb_hash_by_secattr, NULL, gcdb_hash_cmp, KM_SLEEP); 18345916cd2Sjpk 18445916cd2Sjpk gcgrp4_hash = mod_hash_create_extended("gcgrp4_hash", 18545916cd2Sjpk gcgrp_hash_size, mod_hash_null_keydtor, mod_hash_null_valdtor, 18645916cd2Sjpk gcgrp_hash_by_addr, NULL, gcgrp_hash_cmp, KM_SLEEP); 18745916cd2Sjpk 18845916cd2Sjpk gcgrp6_hash = mod_hash_create_extended("gcgrp6_hash", 18945916cd2Sjpk gcgrp_hash_size, mod_hash_null_keydtor, mod_hash_null_valdtor, 19045916cd2Sjpk gcgrp_hash_by_addr, NULL, gcgrp_hash_cmp, KM_SLEEP); 19145916cd2Sjpk 19245916cd2Sjpk mutex_init(&gcdb_lock, NULL, MUTEX_DEFAULT, NULL); 19345916cd2Sjpk mutex_init(&gcgrp_lock, NULL, MUTEX_DEFAULT, NULL); 19445916cd2Sjpk } 19545916cd2Sjpk 19645916cd2Sjpk void 19745916cd2Sjpk tnet_fini(void) 19845916cd2Sjpk { 19945916cd2Sjpk kmem_cache_destroy(ire_gw_secattr_cache); 20045916cd2Sjpk mod_hash_destroy_hash(gcdb_hash); 20145916cd2Sjpk mod_hash_destroy_hash(gcgrp4_hash); 20245916cd2Sjpk mod_hash_destroy_hash(gcgrp6_hash); 20345916cd2Sjpk mutex_destroy(&gcdb_lock); 20445916cd2Sjpk mutex_destroy(&gcgrp_lock); 20545916cd2Sjpk } 20645916cd2Sjpk 20745916cd2Sjpk /* ARGSUSED */ 20845916cd2Sjpk static int 20945916cd2Sjpk ire_gw_secattr_constructor(void *buf, void *cdrarg, int kmflags) 21045916cd2Sjpk { 21145916cd2Sjpk tsol_ire_gw_secattr_t *attrp = buf; 21245916cd2Sjpk 21345916cd2Sjpk mutex_init(&attrp->igsa_lock, NULL, MUTEX_DEFAULT, NULL); 21445916cd2Sjpk 21545916cd2Sjpk attrp->igsa_rhc = NULL; 21645916cd2Sjpk attrp->igsa_gc = NULL; 21745916cd2Sjpk 21845916cd2Sjpk return (0); 21945916cd2Sjpk } 22045916cd2Sjpk 22145916cd2Sjpk /* ARGSUSED */ 22245916cd2Sjpk static void 22345916cd2Sjpk ire_gw_secattr_destructor(void *buf, void *cdrarg) 22445916cd2Sjpk { 22545916cd2Sjpk tsol_ire_gw_secattr_t *attrp = (tsol_ire_gw_secattr_t *)buf; 22645916cd2Sjpk 22745916cd2Sjpk mutex_destroy(&attrp->igsa_lock); 22845916cd2Sjpk } 22945916cd2Sjpk 23045916cd2Sjpk tsol_ire_gw_secattr_t * 23145916cd2Sjpk ire_gw_secattr_alloc(int kmflags) 23245916cd2Sjpk { 23345916cd2Sjpk return (kmem_cache_alloc(ire_gw_secattr_cache, kmflags)); 23445916cd2Sjpk } 23545916cd2Sjpk 23645916cd2Sjpk void 23745916cd2Sjpk ire_gw_secattr_free(tsol_ire_gw_secattr_t *attrp) 23845916cd2Sjpk { 23945916cd2Sjpk ASSERT(MUTEX_NOT_HELD(&attrp->igsa_lock)); 24045916cd2Sjpk 24145916cd2Sjpk if (attrp->igsa_rhc != NULL) { 24245916cd2Sjpk TNRHC_RELE(attrp->igsa_rhc); 24345916cd2Sjpk attrp->igsa_rhc = NULL; 24445916cd2Sjpk } 24545916cd2Sjpk 24645916cd2Sjpk if (attrp->igsa_gc != NULL) { 24745916cd2Sjpk GC_REFRELE(attrp->igsa_gc); 24845916cd2Sjpk attrp->igsa_gc = NULL; 24945916cd2Sjpk } 25045916cd2Sjpk 25145916cd2Sjpk ASSERT(attrp->igsa_rhc == NULL); 25245916cd2Sjpk ASSERT(attrp->igsa_gc == NULL); 25345916cd2Sjpk 25445916cd2Sjpk kmem_cache_free(ire_gw_secattr_cache, attrp); 25545916cd2Sjpk } 25645916cd2Sjpk 25745916cd2Sjpk /* ARGSUSED */ 25845916cd2Sjpk static uint_t 25945916cd2Sjpk gcdb_hash_by_secattr(void *hash_data, mod_hash_key_t key) 26045916cd2Sjpk { 26145916cd2Sjpk const struct rtsa_s *rp = (struct rtsa_s *)key; 26245916cd2Sjpk const uint32_t *up, *ue; 26345916cd2Sjpk uint_t hash; 26445916cd2Sjpk int i; 26545916cd2Sjpk 26645916cd2Sjpk ASSERT(rp != NULL); 26745916cd2Sjpk 26845916cd2Sjpk /* See comments in hash_bylabel in zone.c for details */ 26945916cd2Sjpk hash = rp->rtsa_doi + (rp->rtsa_doi << 1); 27045916cd2Sjpk up = (const uint32_t *)&rp->rtsa_slrange; 27145916cd2Sjpk ue = up + sizeof (rp->rtsa_slrange) / sizeof (*up); 27245916cd2Sjpk i = 1; 27345916cd2Sjpk while (up < ue) { 27445916cd2Sjpk /* using 2^n + 1, 1 <= n <= 16 as source of many primes */ 27545916cd2Sjpk hash += *up + (*up << ((i % 16) + 1)); 27645916cd2Sjpk up++; 27745916cd2Sjpk i++; 27845916cd2Sjpk } 27945916cd2Sjpk return (hash); 28045916cd2Sjpk } 28145916cd2Sjpk 28245916cd2Sjpk static int 28345916cd2Sjpk gcdb_hash_cmp(mod_hash_key_t key1, mod_hash_key_t key2) 28445916cd2Sjpk { 28545916cd2Sjpk struct rtsa_s *rp1 = (struct rtsa_s *)key1; 28645916cd2Sjpk struct rtsa_s *rp2 = (struct rtsa_s *)key2; 28745916cd2Sjpk 28845916cd2Sjpk ASSERT(rp1 != NULL && rp2 != NULL); 28945916cd2Sjpk 29045916cd2Sjpk if (blequal(&rp1->rtsa_slrange.lower_bound, 29145916cd2Sjpk &rp2->rtsa_slrange.lower_bound) && 29245916cd2Sjpk blequal(&rp1->rtsa_slrange.upper_bound, 29345916cd2Sjpk &rp2->rtsa_slrange.upper_bound) && 29445916cd2Sjpk rp1->rtsa_doi == rp2->rtsa_doi) 29545916cd2Sjpk return (0); 29645916cd2Sjpk 29745916cd2Sjpk /* No match; not found */ 29845916cd2Sjpk return (-1); 29945916cd2Sjpk } 30045916cd2Sjpk 30145916cd2Sjpk /* ARGSUSED */ 30245916cd2Sjpk static uint_t 30345916cd2Sjpk gcgrp_hash_by_addr(void *hash_data, mod_hash_key_t key) 30445916cd2Sjpk { 30545916cd2Sjpk tsol_gcgrp_addr_t *ga = (tsol_gcgrp_addr_t *)key; 30645916cd2Sjpk uint_t idx = 0; 30745916cd2Sjpk uint32_t *ap; 30845916cd2Sjpk 30945916cd2Sjpk ASSERT(ga != NULL); 31045916cd2Sjpk ASSERT(ga->ga_af == AF_INET || ga->ga_af == AF_INET6); 31145916cd2Sjpk 31245916cd2Sjpk ap = (uint32_t *)&ga->ga_addr.s6_addr32[0]; 31345916cd2Sjpk idx ^= *ap++; 31445916cd2Sjpk idx ^= *ap++; 31545916cd2Sjpk idx ^= *ap++; 31645916cd2Sjpk idx ^= *ap; 31745916cd2Sjpk 31845916cd2Sjpk return (idx); 31945916cd2Sjpk } 32045916cd2Sjpk 32145916cd2Sjpk static int 32245916cd2Sjpk gcgrp_hash_cmp(mod_hash_key_t key1, mod_hash_key_t key2) 32345916cd2Sjpk { 32445916cd2Sjpk tsol_gcgrp_addr_t *ga1 = (tsol_gcgrp_addr_t *)key1; 32545916cd2Sjpk tsol_gcgrp_addr_t *ga2 = (tsol_gcgrp_addr_t *)key2; 32645916cd2Sjpk 32745916cd2Sjpk ASSERT(ga1 != NULL && ga2 != NULL); 32845916cd2Sjpk 32945916cd2Sjpk /* Address family must match */ 33045916cd2Sjpk if (ga1->ga_af != ga2->ga_af) 33145916cd2Sjpk return (-1); 33245916cd2Sjpk 33345916cd2Sjpk if (ga1->ga_addr.s6_addr32[0] == ga2->ga_addr.s6_addr32[0] && 33445916cd2Sjpk ga1->ga_addr.s6_addr32[1] == ga2->ga_addr.s6_addr32[1] && 33545916cd2Sjpk ga1->ga_addr.s6_addr32[2] == ga2->ga_addr.s6_addr32[2] && 33645916cd2Sjpk ga1->ga_addr.s6_addr32[3] == ga2->ga_addr.s6_addr32[3]) 33745916cd2Sjpk return (0); 33845916cd2Sjpk 33945916cd2Sjpk /* No match; not found */ 34045916cd2Sjpk return (-1); 34145916cd2Sjpk } 34245916cd2Sjpk 34345916cd2Sjpk #define RTSAFLAGS "\20\11cipso\3doi\2max_sl\1min_sl" 34445916cd2Sjpk 34545916cd2Sjpk int 34645916cd2Sjpk rtsa_validate(const struct rtsa_s *rp) 34745916cd2Sjpk { 34845916cd2Sjpk uint32_t mask = rp->rtsa_mask; 34945916cd2Sjpk 35045916cd2Sjpk /* RTSA_CIPSO must be set, and DOI must not be zero */ 35145916cd2Sjpk if ((mask & RTSA_CIPSO) == 0 || rp->rtsa_doi == 0) { 35245916cd2Sjpk DTRACE_PROBE2(tx__gcdb__log__error__rtsa__validate, char *, 35345916cd2Sjpk "rtsa(1) lacks flag or has 0 doi.", 35445916cd2Sjpk rtsa_s *, rp); 35545916cd2Sjpk return (EINVAL); 35645916cd2Sjpk } 35745916cd2Sjpk /* 35845916cd2Sjpk * SL range must be specified, and it must have its 35945916cd2Sjpk * upper bound dominating its lower bound. 36045916cd2Sjpk */ 36145916cd2Sjpk if ((mask & RTSA_SLRANGE) != RTSA_SLRANGE || 36245916cd2Sjpk !bldominates(&rp->rtsa_slrange.upper_bound, 36345916cd2Sjpk &rp->rtsa_slrange.lower_bound)) { 36445916cd2Sjpk DTRACE_PROBE2(tx__gcdb__log__error__rtsa__validate, char *, 36545916cd2Sjpk "rtsa(1) min_sl and max_sl not set or max_sl is " 36645916cd2Sjpk "not dominating.", rtsa_s *, rp); 36745916cd2Sjpk return (EINVAL); 36845916cd2Sjpk } 36945916cd2Sjpk return (0); 37045916cd2Sjpk } 37145916cd2Sjpk 37245916cd2Sjpk /* 37345916cd2Sjpk * A brief explanation of the reference counting scheme: 37445916cd2Sjpk * 37545916cd2Sjpk * Apart from dynamic references due to to reference holds done 37645916cd2Sjpk * actively by threads, we have the following references: 37745916cd2Sjpk * 37845916cd2Sjpk * gcdb_refcnt: 37945916cd2Sjpk * - Every tsol_gc_t pointing to a tsol_gcdb_t contributes a reference 38045916cd2Sjpk * to the gcdb_refcnt. 38145916cd2Sjpk * 38245916cd2Sjpk * gc_refcnt: 38345916cd2Sjpk * - A prefix IRE that points to an igsa_gc contributes a reference 38445916cd2Sjpk * to the gc_refcnt. 38545916cd2Sjpk * 38645916cd2Sjpk * gcgrp_refcnt: 38745916cd2Sjpk * - Every tsol_gc_t in the chain headed by tsol_gcgrp_t contributes 38845916cd2Sjpk * a reference to the gcgrp_refcnt. 38945916cd2Sjpk */ 39045916cd2Sjpk static tsol_gcdb_t * 39145916cd2Sjpk gcdb_lookup(struct rtsa_s *rp, boolean_t alloc) 39245916cd2Sjpk { 39345916cd2Sjpk tsol_gcdb_t *gcdb = NULL; 39445916cd2Sjpk 39545916cd2Sjpk if (rtsa_validate(rp) != 0) 39645916cd2Sjpk return (NULL); 39745916cd2Sjpk 39845916cd2Sjpk mutex_enter(&gcdb_lock); 39945916cd2Sjpk /* Find a copy in the cache; otherwise, create one and cache it */ 40045916cd2Sjpk if (mod_hash_find(gcdb_hash, (mod_hash_key_t)rp, 40145916cd2Sjpk (mod_hash_val_t *)&gcdb) == 0) { 40245916cd2Sjpk gcdb->gcdb_refcnt++; 40345916cd2Sjpk ASSERT(gcdb->gcdb_refcnt != 0); 40445916cd2Sjpk 40545916cd2Sjpk DTRACE_PROBE2(tx__gcdb__log__info__gcdb__lookup, char *, 40645916cd2Sjpk "gcdb(1) is in gcdb_hash(global)", tsol_gcdb_t *, gcdb); 40745916cd2Sjpk } else if (alloc) { 40845916cd2Sjpk gcdb = kmem_zalloc(sizeof (*gcdb), KM_NOSLEEP); 40945916cd2Sjpk if (gcdb != NULL) { 41045916cd2Sjpk gcdb->gcdb_refcnt = 1; 41145916cd2Sjpk gcdb->gcdb_mask = rp->rtsa_mask; 41245916cd2Sjpk gcdb->gcdb_doi = rp->rtsa_doi; 41345916cd2Sjpk gcdb->gcdb_slrange = rp->rtsa_slrange; 41445916cd2Sjpk 41545916cd2Sjpk if (mod_hash_insert(gcdb_hash, 41645916cd2Sjpk (mod_hash_key_t)&gcdb->gcdb_attr, 41745916cd2Sjpk (mod_hash_val_t)gcdb) != 0) { 41845916cd2Sjpk mutex_exit(&gcdb_lock); 41945916cd2Sjpk kmem_free(gcdb, sizeof (*gcdb)); 42045916cd2Sjpk return (NULL); 42145916cd2Sjpk } 42245916cd2Sjpk 42345916cd2Sjpk DTRACE_PROBE2(tx__gcdb__log__info__gcdb__insert, char *, 42445916cd2Sjpk "gcdb(1) inserted in gcdb_hash(global)", 42545916cd2Sjpk tsol_gcdb_t *, gcdb); 42645916cd2Sjpk } 42745916cd2Sjpk } 42845916cd2Sjpk mutex_exit(&gcdb_lock); 42945916cd2Sjpk return (gcdb); 43045916cd2Sjpk } 43145916cd2Sjpk 43245916cd2Sjpk static void 43345916cd2Sjpk gcdb_inactive(tsol_gcdb_t *gcdb) 43445916cd2Sjpk { 43545916cd2Sjpk ASSERT(MUTEX_HELD(&gcdb_lock)); 43645916cd2Sjpk ASSERT(gcdb != NULL && gcdb->gcdb_refcnt == 0); 43745916cd2Sjpk 43845916cd2Sjpk (void) mod_hash_remove(gcdb_hash, (mod_hash_key_t)&gcdb->gcdb_attr, 43945916cd2Sjpk (mod_hash_val_t *)&gcdb); 44045916cd2Sjpk 44145916cd2Sjpk DTRACE_PROBE2(tx__gcdb__log__info__gcdb__remove, char *, 44245916cd2Sjpk "gcdb(1) removed from gcdb_hash(global)", 44345916cd2Sjpk tsol_gcdb_t *, gcdb); 44445916cd2Sjpk kmem_free(gcdb, sizeof (*gcdb)); 44545916cd2Sjpk } 44645916cd2Sjpk 44745916cd2Sjpk tsol_gc_t * 44845916cd2Sjpk gc_create(struct rtsa_s *rp, tsol_gcgrp_t *gcgrp, boolean_t *gcgrp_xtrarefp) 44945916cd2Sjpk { 45045916cd2Sjpk tsol_gc_t *gc; 45145916cd2Sjpk tsol_gcdb_t *gcdb; 45245916cd2Sjpk 45345916cd2Sjpk *gcgrp_xtrarefp = B_TRUE; 45445916cd2Sjpk 45545916cd2Sjpk rw_enter(&gcgrp->gcgrp_rwlock, RW_WRITER); 45645916cd2Sjpk if ((gcdb = gcdb_lookup(rp, B_TRUE)) == NULL) { 45745916cd2Sjpk rw_exit(&gcgrp->gcgrp_rwlock); 45845916cd2Sjpk return (NULL); 45945916cd2Sjpk } 46045916cd2Sjpk 46145916cd2Sjpk for (gc = gcgrp->gcgrp_head; gc != NULL; gc = gc->gc_next) { 46245916cd2Sjpk if (gc->gc_db == gcdb) { 46345916cd2Sjpk ASSERT(gc->gc_grp == gcgrp); 46445916cd2Sjpk 46545916cd2Sjpk gc->gc_refcnt++; 46645916cd2Sjpk ASSERT(gc->gc_refcnt != 0); 46745916cd2Sjpk 46845916cd2Sjpk GCDB_REFRELE(gcdb); 46945916cd2Sjpk 47045916cd2Sjpk DTRACE_PROBE3(tx__gcdb__log__info__gc__create, 47145916cd2Sjpk char *, "found gc(1) in gcgrp(2)", 47245916cd2Sjpk tsol_gc_t *, gc, tsol_gcgrp_t *, gcgrp); 47345916cd2Sjpk rw_exit(&gcgrp->gcgrp_rwlock); 47445916cd2Sjpk return (gc); 47545916cd2Sjpk } 47645916cd2Sjpk } 47745916cd2Sjpk 47845916cd2Sjpk gc = kmem_zalloc(sizeof (*gc), KM_NOSLEEP); 47945916cd2Sjpk if (gc != NULL) { 48045916cd2Sjpk if (gcgrp->gcgrp_head == NULL) { 48145916cd2Sjpk gcgrp->gcgrp_head = gcgrp->gcgrp_tail = gc; 48245916cd2Sjpk } else { 48345916cd2Sjpk gcgrp->gcgrp_tail->gc_next = gc; 48445916cd2Sjpk gc->gc_prev = gcgrp->gcgrp_tail; 48545916cd2Sjpk gcgrp->gcgrp_tail = gc; 48645916cd2Sjpk } 48745916cd2Sjpk gcgrp->gcgrp_count++; 48845916cd2Sjpk ASSERT(gcgrp->gcgrp_count != 0); 48945916cd2Sjpk 49045916cd2Sjpk /* caller has incremented gcgrp reference for us */ 49145916cd2Sjpk gc->gc_grp = gcgrp; 49245916cd2Sjpk 49345916cd2Sjpk gc->gc_db = gcdb; 49445916cd2Sjpk gc->gc_refcnt = 1; 49545916cd2Sjpk 49645916cd2Sjpk DTRACE_PROBE3(tx__gcdb__log__info__gc__create, char *, 49745916cd2Sjpk "added gc(1) to gcgrp(2)", tsol_gc_t *, gc, 49845916cd2Sjpk tsol_gcgrp_t *, gcgrp); 49945916cd2Sjpk 50045916cd2Sjpk *gcgrp_xtrarefp = B_FALSE; 50145916cd2Sjpk } 50245916cd2Sjpk rw_exit(&gcgrp->gcgrp_rwlock); 50345916cd2Sjpk 50445916cd2Sjpk return (gc); 50545916cd2Sjpk } 50645916cd2Sjpk 50745916cd2Sjpk void 50845916cd2Sjpk gc_inactive(tsol_gc_t *gc) 50945916cd2Sjpk { 51045916cd2Sjpk tsol_gcgrp_t *gcgrp = gc->gc_grp; 51145916cd2Sjpk 51245916cd2Sjpk ASSERT(gcgrp != NULL); 51345916cd2Sjpk ASSERT(RW_WRITE_HELD(&gcgrp->gcgrp_rwlock)); 51445916cd2Sjpk ASSERT(gc->gc_refcnt == 0); 51545916cd2Sjpk 51645916cd2Sjpk if (gc->gc_prev != NULL) 51745916cd2Sjpk gc->gc_prev->gc_next = gc->gc_next; 51845916cd2Sjpk else 51945916cd2Sjpk gcgrp->gcgrp_head = gc->gc_next; 52045916cd2Sjpk if (gc->gc_next != NULL) 52145916cd2Sjpk gc->gc_next->gc_prev = gc->gc_prev; 52245916cd2Sjpk else 52345916cd2Sjpk gcgrp->gcgrp_tail = gc->gc_prev; 52445916cd2Sjpk ASSERT(gcgrp->gcgrp_count > 0); 52545916cd2Sjpk gcgrp->gcgrp_count--; 52645916cd2Sjpk 52745916cd2Sjpk /* drop lock before it's destroyed */ 52845916cd2Sjpk rw_exit(&gcgrp->gcgrp_rwlock); 52945916cd2Sjpk 53045916cd2Sjpk DTRACE_PROBE3(tx__gcdb__log__info__gc__remove, char *, 53145916cd2Sjpk "removed inactive gc(1) from gcgrp(2)", 53245916cd2Sjpk tsol_gc_t *, gc, tsol_gcgrp_t *, gcgrp); 53345916cd2Sjpk 53445916cd2Sjpk GCGRP_REFRELE(gcgrp); 53545916cd2Sjpk 53645916cd2Sjpk gc->gc_grp = NULL; 53745916cd2Sjpk gc->gc_prev = gc->gc_next = NULL; 53845916cd2Sjpk 53945916cd2Sjpk if (gc->gc_db != NULL) 54045916cd2Sjpk GCDB_REFRELE(gc->gc_db); 54145916cd2Sjpk 54245916cd2Sjpk kmem_free(gc, sizeof (*gc)); 54345916cd2Sjpk } 54445916cd2Sjpk 54545916cd2Sjpk tsol_gcgrp_t * 54645916cd2Sjpk gcgrp_lookup(tsol_gcgrp_addr_t *ga, boolean_t alloc) 54745916cd2Sjpk { 54845916cd2Sjpk tsol_gcgrp_t *gcgrp = NULL; 54945916cd2Sjpk mod_hash_t *hashp; 55045916cd2Sjpk 55145916cd2Sjpk ASSERT(ga->ga_af == AF_INET || ga->ga_af == AF_INET6); 55245916cd2Sjpk 55345916cd2Sjpk hashp = (ga->ga_af == AF_INET) ? gcgrp4_hash : gcgrp6_hash; 55445916cd2Sjpk 55545916cd2Sjpk mutex_enter(&gcgrp_lock); 55645916cd2Sjpk if (mod_hash_find(hashp, (mod_hash_key_t)ga, 55745916cd2Sjpk (mod_hash_val_t *)&gcgrp) == 0) { 55845916cd2Sjpk gcgrp->gcgrp_refcnt++; 55945916cd2Sjpk ASSERT(gcgrp->gcgrp_refcnt != 0); 56045916cd2Sjpk 56145916cd2Sjpk DTRACE_PROBE3(tx__gcdb__log__info__gcgrp__lookup, char *, 56245916cd2Sjpk "found gcgrp(1) in hash(2)", tsol_gcgrp_t *, gcgrp, 56345916cd2Sjpk mod_hash_t *, hashp); 56445916cd2Sjpk 56545916cd2Sjpk } else if (alloc) { 56645916cd2Sjpk gcgrp = kmem_zalloc(sizeof (*gcgrp), KM_NOSLEEP); 56745916cd2Sjpk if (gcgrp != NULL) { 56845916cd2Sjpk gcgrp->gcgrp_refcnt = 1; 56945916cd2Sjpk rw_init(&gcgrp->gcgrp_rwlock, NULL, RW_DEFAULT, NULL); 57045916cd2Sjpk bcopy(ga, &gcgrp->gcgrp_addr, sizeof (*ga)); 57145916cd2Sjpk 57245916cd2Sjpk if (mod_hash_insert(hashp, 57345916cd2Sjpk (mod_hash_key_t)&gcgrp->gcgrp_addr, 57445916cd2Sjpk (mod_hash_val_t)gcgrp) != 0) { 57545916cd2Sjpk mutex_exit(&gcgrp_lock); 57645916cd2Sjpk kmem_free(gcgrp, sizeof (*gcgrp)); 57745916cd2Sjpk return (NULL); 57845916cd2Sjpk } 57945916cd2Sjpk 58045916cd2Sjpk DTRACE_PROBE3(tx__gcdb__log__info__gcgrp__insert, 58145916cd2Sjpk char *, "inserted gcgrp(1) in hash(2)", 58245916cd2Sjpk tsol_gcgrp_t *, gcgrp, mod_hash_t *, hashp); 58345916cd2Sjpk } 58445916cd2Sjpk } 58545916cd2Sjpk mutex_exit(&gcgrp_lock); 58645916cd2Sjpk return (gcgrp); 58745916cd2Sjpk } 58845916cd2Sjpk 58945916cd2Sjpk void 59045916cd2Sjpk gcgrp_inactive(tsol_gcgrp_t *gcgrp) 59145916cd2Sjpk { 59245916cd2Sjpk tsol_gcgrp_addr_t *ga; 59345916cd2Sjpk mod_hash_t *hashp; 59445916cd2Sjpk 59545916cd2Sjpk ASSERT(MUTEX_HELD(&gcgrp_lock)); 59645916cd2Sjpk ASSERT(gcgrp != NULL && gcgrp->gcgrp_refcnt == 0); 59745916cd2Sjpk ASSERT(gcgrp->gcgrp_head == NULL && gcgrp->gcgrp_count == 0); 59845916cd2Sjpk 59945916cd2Sjpk ga = &gcgrp->gcgrp_addr; 60045916cd2Sjpk ASSERT(ga->ga_af == AF_INET || ga->ga_af == AF_INET6); 60145916cd2Sjpk 60245916cd2Sjpk hashp = (ga->ga_af == AF_INET) ? gcgrp4_hash : gcgrp6_hash; 60345916cd2Sjpk (void) mod_hash_remove(hashp, (mod_hash_key_t)ga, 60445916cd2Sjpk (mod_hash_val_t *)&gcgrp); 60545916cd2Sjpk rw_destroy(&gcgrp->gcgrp_rwlock); 60645916cd2Sjpk 60745916cd2Sjpk DTRACE_PROBE3(tx__gcdb__log__info__gcgrp__remove, char *, 60845916cd2Sjpk "removed inactive gcgrp(1) from hash(2)", 60945916cd2Sjpk tsol_gcgrp_t *, gcgrp, mod_hash_t *, hashp); 61045916cd2Sjpk 61145916cd2Sjpk kmem_free(gcgrp, sizeof (*gcgrp)); 61245916cd2Sjpk } 61345916cd2Sjpk 6145d3b8cb7SBill Sommerfeld 6155d3b8cb7SBill Sommerfeld /* 6165d3b8cb7SBill Sommerfeld * Assign a sensitivity label to inbound traffic which arrived without 6175d3b8cb7SBill Sommerfeld * an explicit on-the-wire label. 6185d3b8cb7SBill Sommerfeld * 6195d3b8cb7SBill Sommerfeld * In the case of CIPSO-type hosts, we assume packets arriving without 6205d3b8cb7SBill Sommerfeld * a label are at the most sensitive label known for the host, most 6215d3b8cb7SBill Sommerfeld * likely involving out-of-band key management traffic (such as IKE, 6225d3b8cb7SBill Sommerfeld * etc.,) 6235d3b8cb7SBill Sommerfeld */ 6245d3b8cb7SBill Sommerfeld static boolean_t 6255d3b8cb7SBill Sommerfeld tsol_find_unlabeled_label(tsol_tpc_t *rhtp, bslabel_t *sl, uint32_t *doi) 6265d3b8cb7SBill Sommerfeld { 6275d3b8cb7SBill Sommerfeld *doi = rhtp->tpc_tp.tp_doi; 6285d3b8cb7SBill Sommerfeld switch (rhtp->tpc_tp.host_type) { 6295d3b8cb7SBill Sommerfeld case UNLABELED: 6305d3b8cb7SBill Sommerfeld *sl = rhtp->tpc_tp.tp_def_label; 6315d3b8cb7SBill Sommerfeld break; 6325d3b8cb7SBill Sommerfeld case SUN_CIPSO: 6335d3b8cb7SBill Sommerfeld *sl = rhtp->tpc_tp.tp_sl_range_cipso.upper_bound; 6345d3b8cb7SBill Sommerfeld break; 6355d3b8cb7SBill Sommerfeld default: 6365d3b8cb7SBill Sommerfeld return (B_FALSE); 6375d3b8cb7SBill Sommerfeld } 6385d3b8cb7SBill Sommerfeld setbltype(sl, SUN_SL_ID); 6395d3b8cb7SBill Sommerfeld return (B_TRUE); 6405d3b8cb7SBill Sommerfeld } 6415d3b8cb7SBill Sommerfeld 64245916cd2Sjpk /* 64345916cd2Sjpk * Converts CIPSO option to sensitivity label. 64445916cd2Sjpk * Validity checks based on restrictions defined in 64545916cd2Sjpk * COMMERCIAL IP SECURITY OPTION (CIPSO 2.2) (draft-ietf-cipso-ipsecurity) 64645916cd2Sjpk */ 64745916cd2Sjpk static boolean_t 64845916cd2Sjpk cipso_to_sl(const uchar_t *option, bslabel_t *sl) 64945916cd2Sjpk { 65045916cd2Sjpk const struct cipso_option *co = (const struct cipso_option *)option; 65145916cd2Sjpk const struct cipso_tag_type_1 *tt1; 65245916cd2Sjpk 65345916cd2Sjpk tt1 = (struct cipso_tag_type_1 *)&co->cipso_tag_type[0]; 65445916cd2Sjpk if (tt1->tag_type != 1 || 65545916cd2Sjpk tt1->tag_length < TSOL_TT1_MIN_LENGTH || 65645916cd2Sjpk tt1->tag_length > TSOL_TT1_MAX_LENGTH || 65745916cd2Sjpk tt1->tag_length + TSOL_CIPSO_TAG_OFFSET > co->cipso_length) 65845916cd2Sjpk return (B_FALSE); 65945916cd2Sjpk 66045916cd2Sjpk bsllow(sl); /* assumed: sets compartments to all zeroes */ 66145916cd2Sjpk LCLASS_SET((_bslabel_impl_t *)sl, tt1->tag_sl); 66245916cd2Sjpk bcopy(tt1->tag_cat, &((_bslabel_impl_t *)sl)->compartments, 66345916cd2Sjpk tt1->tag_length - TSOL_TT1_MIN_LENGTH); 66445916cd2Sjpk return (B_TRUE); 66545916cd2Sjpk } 66645916cd2Sjpk 66745916cd2Sjpk /* 668bd670b35SErik Nordmark * If present, parse the CIPSO label in the incoming packet and 669bd670b35SErik Nordmark * construct a ts_label_t that reflects the CIPSO label and put it in 670bd670b35SErik Nordmark * the ip_recv_attr_t. Later as the packet flows up through the stack any 6715d3b8cb7SBill Sommerfeld * code that needs to examine the packet label can inspect the label 672bd670b35SErik Nordmark * from the ira_tsl. This function is 673bd670b35SErik Nordmark * called right in ip_input for all packets, i.e. locally destined and 674bd670b35SErik Nordmark * to be forwarded packets. The forwarding path needs to examine the label 675bd670b35SErik Nordmark * to determine how to forward the packet. 67645916cd2Sjpk * 677c4e55c13Sken Powell - Sun Microsystem * This routine pulls all message text up into the first mblk. 678c4e55c13Sken Powell - Sun Microsystem * For IPv4, only the first 20 bytes of the IP header are guaranteed 679c4e55c13Sken Powell - Sun Microsystem * to exist. For IPv6, only the IPv6 header is guaranteed to exist. 68045916cd2Sjpk */ 68145916cd2Sjpk boolean_t 682bd670b35SErik Nordmark tsol_get_pkt_label(mblk_t *mp, int version, ip_recv_attr_t *ira) 68345916cd2Sjpk { 6845d3b8cb7SBill Sommerfeld tsol_tpc_t *src_rhtp = NULL; 68545916cd2Sjpk uchar_t *opt_ptr = NULL; 68645916cd2Sjpk const ipha_t *ipha; 68745916cd2Sjpk bslabel_t sl; 68845916cd2Sjpk uint32_t doi; 68945916cd2Sjpk tsol_ip_label_t label_type; 6905d3b8cb7SBill Sommerfeld uint32_t label_flags = 0; /* flags to set in label */ 69145916cd2Sjpk const cipso_option_t *co; 69245916cd2Sjpk const void *src; 69345916cd2Sjpk const ip6_t *ip6h; 694de8c4a14SErik Nordmark cred_t *credp; 6955d3b8cb7SBill Sommerfeld int proto; 69645916cd2Sjpk 69745916cd2Sjpk ASSERT(DB_TYPE(mp) == M_DATA); 69845916cd2Sjpk 6995f9878b0Sken Powell - Sun Microsystem if (mp->b_cont != NULL && !pullupmsg(mp, -1)) 7005f9878b0Sken Powell - Sun Microsystem return (B_FALSE); 7015f9878b0Sken Powell - Sun Microsystem 70245916cd2Sjpk if (version == IPV4_VERSION) { 703c4e55c13Sken Powell - Sun Microsystem ASSERT(MBLKL(mp) >= IP_SIMPLE_HDR_LENGTH); 70445916cd2Sjpk ipha = (const ipha_t *)mp->b_rptr; 70545916cd2Sjpk src = &ipha->ipha_src; 706c4e55c13Sken Powell - Sun Microsystem if (!tsol_get_option_v4(mp, &label_type, &opt_ptr)) 707c4e55c13Sken Powell - Sun Microsystem return (B_FALSE); 70845916cd2Sjpk } else { 709c4e55c13Sken Powell - Sun Microsystem ASSERT(MBLKL(mp) >= IPV6_HDR_LEN); 71045916cd2Sjpk ip6h = (const ip6_t *)mp->b_rptr; 71145916cd2Sjpk src = &ip6h->ip6_src; 712c4e55c13Sken Powell - Sun Microsystem if (!tsol_get_option_v6(mp, &label_type, &opt_ptr)) 713c4e55c13Sken Powell - Sun Microsystem return (B_FALSE); 71445916cd2Sjpk } 71545916cd2Sjpk 71645916cd2Sjpk switch (label_type) { 71745916cd2Sjpk case OPT_CIPSO: 71845916cd2Sjpk /* 71945916cd2Sjpk * Convert the CIPSO label to the internal format 72045916cd2Sjpk * and attach it to the dblk cred. 72145916cd2Sjpk * Validity checks based on restrictions defined in 72245916cd2Sjpk * COMMERCIAL IP SECURITY OPTION (CIPSO 2.2) 72345916cd2Sjpk * (draft-ietf-cipso-ipsecurity) 72445916cd2Sjpk */ 72545916cd2Sjpk if (version == IPV6_VERSION && ip6opt_ls == 0) 72645916cd2Sjpk return (B_FALSE); 72745916cd2Sjpk co = (const struct cipso_option *)opt_ptr; 72845916cd2Sjpk if ((co->cipso_length < 72945916cd2Sjpk TSOL_CIPSO_TAG_OFFSET + TSOL_TT1_MIN_LENGTH) || 73045916cd2Sjpk (co->cipso_length > IP_MAX_OPT_LENGTH)) 73145916cd2Sjpk return (B_FALSE); 73245916cd2Sjpk bcopy(co->cipso_doi, &doi, sizeof (doi)); 73345916cd2Sjpk doi = ntohl(doi); 73445916cd2Sjpk if (!cipso_to_sl(opt_ptr, &sl)) 73545916cd2Sjpk return (B_FALSE); 73645916cd2Sjpk setbltype(&sl, SUN_SL_ID); 7375d3b8cb7SBill Sommerfeld 7385d3b8cb7SBill Sommerfeld /* 7395d3b8cb7SBill Sommerfeld * If the source was unlabeled, then flag as such, 7405d3b8cb7SBill Sommerfeld * (since CIPSO routers may add headers) 7415d3b8cb7SBill Sommerfeld */ 7425d3b8cb7SBill Sommerfeld 7435d3b8cb7SBill Sommerfeld if ((src_rhtp = find_tpc(src, version, B_FALSE)) == NULL) 7445d3b8cb7SBill Sommerfeld return (B_FALSE); 7455d3b8cb7SBill Sommerfeld 7465d3b8cb7SBill Sommerfeld if (src_rhtp->tpc_tp.host_type == UNLABELED) 7475d3b8cb7SBill Sommerfeld label_flags = TSLF_UNLABELED; 7485d3b8cb7SBill Sommerfeld 7495d3b8cb7SBill Sommerfeld TPC_RELE(src_rhtp); 7505d3b8cb7SBill Sommerfeld 75145916cd2Sjpk break; 75245916cd2Sjpk 75345916cd2Sjpk case OPT_NONE: 75445916cd2Sjpk /* 7555d3b8cb7SBill Sommerfeld * Handle special cases that may not be labeled, even 75645916cd2Sjpk * though the sending system may otherwise be configured as 75745916cd2Sjpk * labeled. 75845916cd2Sjpk * - IGMP 75945916cd2Sjpk * - IPv4 ICMP Router Discovery 76045916cd2Sjpk * - IPv6 Neighbor Discovery 7615d3b8cb7SBill Sommerfeld * - IPsec ESP 76245916cd2Sjpk */ 76345916cd2Sjpk if (version == IPV4_VERSION) { 7645d3b8cb7SBill Sommerfeld proto = ipha->ipha_protocol; 7655d3b8cb7SBill Sommerfeld if (proto == IPPROTO_IGMP) 76645916cd2Sjpk return (B_TRUE); 7675d3b8cb7SBill Sommerfeld if (proto == IPPROTO_ICMP) { 76845916cd2Sjpk const struct icmp *icmp = (const struct icmp *) 76945916cd2Sjpk (mp->b_rptr + IPH_HDR_LENGTH(ipha)); 77045916cd2Sjpk 771c4e55c13Sken Powell - Sun Microsystem if ((uchar_t *)icmp + ICMP_MINLEN > mp->b_wptr) 77245916cd2Sjpk return (B_FALSE); 77345916cd2Sjpk if (icmp->icmp_type == ICMP_ROUTERADVERT || 77445916cd2Sjpk icmp->icmp_type == ICMP_ROUTERSOLICIT) 77545916cd2Sjpk return (B_TRUE); 77645916cd2Sjpk } 77745916cd2Sjpk } else { 7785d3b8cb7SBill Sommerfeld proto = ip6h->ip6_nxt; 7795d3b8cb7SBill Sommerfeld if (proto == IPPROTO_ICMPV6) { 78045916cd2Sjpk const icmp6_t *icmp6 = (const icmp6_t *) 78145916cd2Sjpk (mp->b_rptr + IPV6_HDR_LEN); 78245916cd2Sjpk 78345916cd2Sjpk if ((uchar_t *)icmp6 + ICMP6_MINLEN > 784c4e55c13Sken Powell - Sun Microsystem mp->b_wptr) 78545916cd2Sjpk return (B_FALSE); 78645916cd2Sjpk if (icmp6->icmp6_type >= MLD_LISTENER_QUERY && 78745916cd2Sjpk icmp6->icmp6_type <= ICMP6_MAX_INFO_TYPE) 78845916cd2Sjpk return (B_TRUE); 78945916cd2Sjpk } 79045916cd2Sjpk } 79145916cd2Sjpk 79245916cd2Sjpk /* 79345916cd2Sjpk * Look up the tnrhtp database and get the implicit label 7945d3b8cb7SBill Sommerfeld * that is associated with the sending host and attach 79545916cd2Sjpk * it to the packet. 79645916cd2Sjpk */ 79745916cd2Sjpk if ((src_rhtp = find_tpc(src, version, B_FALSE)) == NULL) 79845916cd2Sjpk return (B_FALSE); 79945916cd2Sjpk 8005d3b8cb7SBill Sommerfeld /* 8015d3b8cb7SBill Sommerfeld * If peer is label-aware, mark as "implicit" rather than 8025d3b8cb7SBill Sommerfeld * "unlabeled" to cause appropriate mac-exempt processing 8035d3b8cb7SBill Sommerfeld * to happen. 8045d3b8cb7SBill Sommerfeld */ 8055d3b8cb7SBill Sommerfeld if (src_rhtp->tpc_tp.host_type == SUN_CIPSO) 8065d3b8cb7SBill Sommerfeld label_flags = TSLF_IMPLICIT_IN; 8075d3b8cb7SBill Sommerfeld else if (src_rhtp->tpc_tp.host_type == UNLABELED) 8085d3b8cb7SBill Sommerfeld label_flags = TSLF_UNLABELED; 8095d3b8cb7SBill Sommerfeld else { 8105d3b8cb7SBill Sommerfeld DTRACE_PROBE2(tx__get__pkt__label, char *, 8115d3b8cb7SBill Sommerfeld "template(1) has unknown hosttype", 8125d3b8cb7SBill Sommerfeld tsol_tpc_t *, src_rhtp); 81345916cd2Sjpk } 81445916cd2Sjpk 8155d3b8cb7SBill Sommerfeld 8165d3b8cb7SBill Sommerfeld if (!tsol_find_unlabeled_label(src_rhtp, &sl, &doi)) { 8175d3b8cb7SBill Sommerfeld TPC_RELE(src_rhtp); 8185d3b8cb7SBill Sommerfeld return (B_FALSE); 8195d3b8cb7SBill Sommerfeld } 82045916cd2Sjpk TPC_RELE(src_rhtp); 82145916cd2Sjpk break; 82245916cd2Sjpk 82345916cd2Sjpk default: 82445916cd2Sjpk return (B_FALSE); 82545916cd2Sjpk } 82645916cd2Sjpk 827bd670b35SErik Nordmark if (ira->ira_cred == NULL) { 828de8c4a14SErik Nordmark credp = newcred_from_bslabel(&sl, doi, KM_NOSLEEP); 829bd670b35SErik Nordmark if (credp == NULL) 830bd670b35SErik Nordmark return (B_FALSE); 83145916cd2Sjpk } else { 8320e0e37a8SErik Nordmark credp = copycred_from_bslabel(ira->ira_cred, &sl, doi, 83345916cd2Sjpk KM_NOSLEEP); 8340e0e37a8SErik Nordmark if (credp == NULL) 835bd670b35SErik Nordmark return (B_FALSE); 836bd670b35SErik Nordmark if (ira->ira_free_flags & IRA_FREE_CRED) { 837bd670b35SErik Nordmark crfree(ira->ira_cred); 838bd670b35SErik Nordmark ira->ira_free_flags &= ~IRA_FREE_CRED; 839bd670b35SErik Nordmark ira->ira_cred = NULL; 840bd670b35SErik Nordmark } 84145916cd2Sjpk } 8425d3b8cb7SBill Sommerfeld 843bd670b35SErik Nordmark /* 844bd670b35SErik Nordmark * Put the label in ira_tsl for convinience, while keeping 845bd670b35SErik Nordmark * the cred in ira_cred for getpeerucred which is used to get 846bd670b35SErik Nordmark * labels with TX. 847bd670b35SErik Nordmark * Note: no explicit refcnt/free_flag for ira_tsl. The free_flag 848bd670b35SErik Nordmark * for IRA_FREE_CRED is sufficient for both. 849bd670b35SErik Nordmark */ 850bd670b35SErik Nordmark ira->ira_tsl = crgetlabel(credp); 851bd670b35SErik Nordmark ira->ira_cred = credp; 852bd670b35SErik Nordmark ira->ira_free_flags |= IRA_FREE_CRED; 8535d3b8cb7SBill Sommerfeld 854bd670b35SErik Nordmark ira->ira_tsl->tsl_flags |= label_flags; 85545916cd2Sjpk return (B_TRUE); 85645916cd2Sjpk } 85745916cd2Sjpk 85845916cd2Sjpk /* 85945916cd2Sjpk * This routine determines whether the given packet should be accepted locally. 86045916cd2Sjpk * It does a range/set check on the packet's label by looking up the given 86145916cd2Sjpk * address in the remote host database. 86245916cd2Sjpk */ 86345916cd2Sjpk boolean_t 86445916cd2Sjpk tsol_receive_local(const mblk_t *mp, const void *addr, uchar_t version, 865bd670b35SErik Nordmark ip_recv_attr_t *ira, const conn_t *connp) 86645916cd2Sjpk { 86745916cd2Sjpk const cred_t *credp; 86845916cd2Sjpk ts_label_t *plabel, *conn_plabel; 86945916cd2Sjpk tsol_tpc_t *tp; 87045916cd2Sjpk boolean_t retv; 87145916cd2Sjpk const bslabel_t *label, *conn_label; 872bd670b35SErik Nordmark boolean_t shared_addr = (ira->ira_flags & IRAF_TX_SHARED_ADDR); 87345916cd2Sjpk 87445916cd2Sjpk /* 875bd670b35SErik Nordmark * tsol_get_pkt_label intentionally avoids the labeling process for: 876bd670b35SErik Nordmark * - IPv6 router and neighbor discovery as well as redirects. 877bd670b35SErik Nordmark * - MLD packets. (Anything between ICMPv6 code 130 and 138.) 878bd670b35SErik Nordmark * - IGMP packets. 879bd670b35SErik Nordmark * - IPv4 router discovery. 8800e0e37a8SErik Nordmark * In those cases ira_cred is NULL. 88145916cd2Sjpk */ 882bd670b35SErik Nordmark credp = ira->ira_cred; 883bd670b35SErik Nordmark if (credp == NULL) 88445916cd2Sjpk return (B_TRUE); 88545916cd2Sjpk 88645916cd2Sjpk /* 88745916cd2Sjpk * If this packet is from the inside (not a remote host) and has the 88845916cd2Sjpk * same zoneid as the selected destination, then no checks are 88945916cd2Sjpk * necessary. Membership in the zone is enough proof. This is 89045916cd2Sjpk * intended to be a hot path through this function. 891bd670b35SErik Nordmark * Note: Using crgetzone here is ok since the peer is local. 89245916cd2Sjpk */ 89345916cd2Sjpk if (!crisremote(credp) && 89445916cd2Sjpk crgetzone(credp) == crgetzone(connp->conn_cred)) 89545916cd2Sjpk return (B_TRUE); 89645916cd2Sjpk 897bd670b35SErik Nordmark plabel = ira->ira_tsl; 89845916cd2Sjpk conn_plabel = crgetlabel(connp->conn_cred); 89945916cd2Sjpk ASSERT(plabel != NULL && conn_plabel != NULL); 90045916cd2Sjpk 90145916cd2Sjpk label = label2bslabel(plabel); 902bd670b35SErik Nordmark conn_label = label2bslabel(conn_plabel); 90345916cd2Sjpk 9045d3b8cb7SBill Sommerfeld 9055d3b8cb7SBill Sommerfeld /* 9065d3b8cb7SBill Sommerfeld * Implicitly labeled packets from label-aware sources 9075d3b8cb7SBill Sommerfeld * go only to privileged receivers 9085d3b8cb7SBill Sommerfeld */ 9095d3b8cb7SBill Sommerfeld if ((plabel->tsl_flags & TSLF_IMPLICIT_IN) && 9105d3b8cb7SBill Sommerfeld (connp->conn_mac_mode != CONN_MAC_IMPLICIT)) { 9115d3b8cb7SBill Sommerfeld DTRACE_PROBE3(tx__ip__log__drop__receivelocal__mac_impl, 9125d3b8cb7SBill Sommerfeld char *, 9135d3b8cb7SBill Sommerfeld "implicitly labeled packet mp(1) for conn(2) " 9145d3b8cb7SBill Sommerfeld "which isn't in implicit mac mode", 9155d3b8cb7SBill Sommerfeld mblk_t *, mp, conn_t *, connp); 9165d3b8cb7SBill Sommerfeld 9175d3b8cb7SBill Sommerfeld return (B_FALSE); 9185d3b8cb7SBill Sommerfeld } 9195d3b8cb7SBill Sommerfeld 9205d3b8cb7SBill Sommerfeld 92145916cd2Sjpk /* 92245916cd2Sjpk * MLPs are always validated using the range and set of the local 92345916cd2Sjpk * address, even when the remote host is unlabeled. 92445916cd2Sjpk */ 92545916cd2Sjpk if (connp->conn_mlp_type == mlptBoth || 92645916cd2Sjpk /* LINTED: no consequent */ 92745916cd2Sjpk connp->conn_mlp_type == (shared_addr ? mlptShared : mlptPrivate)) { 92845916cd2Sjpk ; 92945916cd2Sjpk 93045916cd2Sjpk /* 93145916cd2Sjpk * If this is a packet from an unlabeled sender, then we must apply 93245916cd2Sjpk * different rules. If the label is equal to the zone's label, then 93345916cd2Sjpk * it's allowed. If it's not equal, but the zone is either the global 93445916cd2Sjpk * zone or the label is dominated by the zone's label, then allow it 93545916cd2Sjpk * as long as it's in the range configured for the destination. 93645916cd2Sjpk */ 93745916cd2Sjpk } else if (plabel->tsl_flags & TSLF_UNLABELED) { 93845916cd2Sjpk if (plabel->tsl_doi == conn_plabel->tsl_doi && 93945916cd2Sjpk blequal(label, conn_label)) 94045916cd2Sjpk return (B_TRUE); 94145916cd2Sjpk 9425d3b8cb7SBill Sommerfeld if ((connp->conn_mac_mode == CONN_MAC_DEFAULT) || 943bd670b35SErik Nordmark (!connp->conn_zone_is_global && 94445916cd2Sjpk (plabel->tsl_doi != conn_plabel->tsl_doi || 94545916cd2Sjpk !bldominates(conn_label, label)))) { 94645916cd2Sjpk DTRACE_PROBE3( 94745916cd2Sjpk tx__ip__log__drop__receivelocal__mac_unl, 94845916cd2Sjpk char *, 94945916cd2Sjpk "unlabeled packet mp(1) fails mac for conn(2)", 95045916cd2Sjpk mblk_t *, mp, conn_t *, connp); 95145916cd2Sjpk return (B_FALSE); 95245916cd2Sjpk } 95345916cd2Sjpk 95445916cd2Sjpk /* 955e071b5fbSkp158701 * If this is a packet from a labeled sender, verify the 956e071b5fbSkp158701 * label on the packet matches the connection label. 95745916cd2Sjpk */ 958e071b5fbSkp158701 } else { 959e071b5fbSkp158701 if (plabel->tsl_doi != conn_plabel->tsl_doi || 960e071b5fbSkp158701 !blequal(label, conn_label)) { 96145916cd2Sjpk DTRACE_PROBE3(tx__ip__log__drop__receivelocal__mac__slp, 962e071b5fbSkp158701 char *, 963e071b5fbSkp158701 "packet mp(1) failed label match to SLP conn(2)", 96445916cd2Sjpk mblk_t *, mp, conn_t *, connp); 96545916cd2Sjpk return (B_FALSE); 96645916cd2Sjpk } 967e071b5fbSkp158701 /* 968e071b5fbSkp158701 * No further checks will be needed if this is a zone- 969e071b5fbSkp158701 * specific address because (1) The process for bringing up 970e071b5fbSkp158701 * the interface ensures the zone's label is within the zone- 971e071b5fbSkp158701 * specific address's valid label range; (2) For cases where 972e071b5fbSkp158701 * the conn is bound to the unspecified addresses, ip fanout 973e071b5fbSkp158701 * logic ensures conn's zoneid equals the dest addr's zoneid; 974e071b5fbSkp158701 * (3) Mac-exempt and mlp logic above already handle all 975e071b5fbSkp158701 * cases where the zone label may not be the same as the 976e071b5fbSkp158701 * conn label. 977e071b5fbSkp158701 */ 978e071b5fbSkp158701 if (!shared_addr) 979e071b5fbSkp158701 return (B_TRUE); 980e071b5fbSkp158701 } 98145916cd2Sjpk 98245916cd2Sjpk tp = find_tpc(addr, version, B_FALSE); 98345916cd2Sjpk if (tp == NULL) { 98445916cd2Sjpk DTRACE_PROBE3(tx__ip__log__drop__receivelocal__no__tnr, 98545916cd2Sjpk char *, "dropping mp(1), host(2) lacks entry", 98645916cd2Sjpk mblk_t *, mp, void *, addr); 98745916cd2Sjpk return (B_FALSE); 98845916cd2Sjpk } 98945916cd2Sjpk 99045916cd2Sjpk /* 99145916cd2Sjpk * The local host address should not be unlabeled at this point. The 99245916cd2Sjpk * only way this can happen is that the destination isn't unicast. We 99345916cd2Sjpk * assume that the packet should not have had a label, and thus should 99445916cd2Sjpk * have been handled by the TSLF_UNLABELED logic above. 99545916cd2Sjpk */ 99645916cd2Sjpk if (tp->tpc_tp.host_type == UNLABELED) { 99745916cd2Sjpk retv = B_FALSE; 99845916cd2Sjpk DTRACE_PROBE3(tx__ip__log__drop__receivelocal__flag, char *, 99945916cd2Sjpk "mp(1) unlabeled source, but tp is not unlabeled.", 100045916cd2Sjpk mblk_t *, mp, tsol_tpc_t *, tp); 100145916cd2Sjpk 100245916cd2Sjpk } else if (tp->tpc_tp.host_type != SUN_CIPSO) { 100345916cd2Sjpk retv = B_FALSE; 100445916cd2Sjpk DTRACE_PROBE3(tx__ip__log__drop__receivelocal__tptype, char *, 100545916cd2Sjpk "delivering mp(1), found unrecognized tpc(2) type.", 100645916cd2Sjpk mblk_t *, mp, tsol_tpc_t *, tp); 100745916cd2Sjpk 100845916cd2Sjpk } else if (plabel->tsl_doi != tp->tpc_tp.tp_doi) { 100945916cd2Sjpk retv = B_FALSE; 101045916cd2Sjpk DTRACE_PROBE3(tx__ip__log__drop__receivelocal__mac, char *, 101145916cd2Sjpk "mp(1) could not be delievered to tp(2), doi mismatch", 101245916cd2Sjpk mblk_t *, mp, tsol_tpc_t *, tp); 101345916cd2Sjpk 101445916cd2Sjpk } else if (!_blinrange(label, &tp->tpc_tp.tp_sl_range_cipso) && 101545916cd2Sjpk !blinlset(label, tp->tpc_tp.tp_sl_set_cipso)) { 101645916cd2Sjpk retv = B_FALSE; 101745916cd2Sjpk DTRACE_PROBE3(tx__ip__log__drop__receivelocal__mac, char *, 101845916cd2Sjpk "mp(1) could not be delievered to tp(2), bad mac", 101945916cd2Sjpk mblk_t *, mp, tsol_tpc_t *, tp); 102045916cd2Sjpk } else { 102145916cd2Sjpk retv = B_TRUE; 102245916cd2Sjpk } 102345916cd2Sjpk 102445916cd2Sjpk TPC_RELE(tp); 102545916cd2Sjpk 102645916cd2Sjpk return (retv); 102745916cd2Sjpk } 102845916cd2Sjpk 102945916cd2Sjpk boolean_t 1030bd670b35SErik Nordmark tsol_can_accept_raw(mblk_t *mp, ip_recv_attr_t *ira, boolean_t check_host) 103145916cd2Sjpk { 103245916cd2Sjpk ts_label_t *plabel = NULL; 103345916cd2Sjpk tsol_tpc_t *src_rhtp, *dst_rhtp; 103445916cd2Sjpk boolean_t retv; 103545916cd2Sjpk 1036bd670b35SErik Nordmark plabel = ira->ira_tsl; 103745916cd2Sjpk 103845916cd2Sjpk /* We are bootstrapping or the internal template was never deleted */ 103945916cd2Sjpk if (plabel == NULL) 104045916cd2Sjpk return (B_TRUE); 104145916cd2Sjpk 104245916cd2Sjpk if (IPH_HDR_VERSION(mp->b_rptr) == IPV4_VERSION) { 104345916cd2Sjpk ipha_t *ipha = (ipha_t *)mp->b_rptr; 104445916cd2Sjpk 104545916cd2Sjpk src_rhtp = find_tpc(&ipha->ipha_src, IPV4_VERSION, 104645916cd2Sjpk B_FALSE); 104745916cd2Sjpk if (src_rhtp == NULL) 104845916cd2Sjpk return (B_FALSE); 104945916cd2Sjpk dst_rhtp = find_tpc(&ipha->ipha_dst, IPV4_VERSION, 105045916cd2Sjpk B_FALSE); 105145916cd2Sjpk } else { 105245916cd2Sjpk ip6_t *ip6h = (ip6_t *)mp->b_rptr; 105345916cd2Sjpk 105445916cd2Sjpk src_rhtp = find_tpc(&ip6h->ip6_src, IPV6_VERSION, 105545916cd2Sjpk B_FALSE); 105645916cd2Sjpk if (src_rhtp == NULL) 105745916cd2Sjpk return (B_FALSE); 105845916cd2Sjpk dst_rhtp = find_tpc(&ip6h->ip6_dst, IPV6_VERSION, 105945916cd2Sjpk B_FALSE); 106045916cd2Sjpk } 106145916cd2Sjpk if (dst_rhtp == NULL) { 106245916cd2Sjpk TPC_RELE(src_rhtp); 106345916cd2Sjpk return (B_FALSE); 106445916cd2Sjpk } 106545916cd2Sjpk 106645916cd2Sjpk if (label2doi(plabel) != src_rhtp->tpc_tp.tp_doi) { 106745916cd2Sjpk retv = B_FALSE; 106845916cd2Sjpk 106945916cd2Sjpk /* 107045916cd2Sjpk * Check that the packet's label is in the correct range for labeled 107145916cd2Sjpk * sender, or is equal to the default label for unlabeled sender. 107245916cd2Sjpk */ 107345916cd2Sjpk } else if ((src_rhtp->tpc_tp.host_type != UNLABELED && 107445916cd2Sjpk !_blinrange(label2bslabel(plabel), 107545916cd2Sjpk &src_rhtp->tpc_tp.tp_sl_range_cipso) && 107645916cd2Sjpk !blinlset(label2bslabel(plabel), 107745916cd2Sjpk src_rhtp->tpc_tp.tp_sl_set_cipso)) || 107845916cd2Sjpk (src_rhtp->tpc_tp.host_type == UNLABELED && 107945916cd2Sjpk !blequal(&plabel->tsl_label, &src_rhtp->tpc_tp.tp_def_label))) { 108045916cd2Sjpk retv = B_FALSE; 108145916cd2Sjpk 108245916cd2Sjpk } else if (check_host) { 108345916cd2Sjpk retv = B_TRUE; 108445916cd2Sjpk 108545916cd2Sjpk /* 108645916cd2Sjpk * Until we have SL range in the Zone structure, pass it 108745916cd2Sjpk * when our own address lookup returned an internal entry. 108845916cd2Sjpk */ 108945916cd2Sjpk } else switch (dst_rhtp->tpc_tp.host_type) { 109045916cd2Sjpk case UNLABELED: 109145916cd2Sjpk retv = B_TRUE; 109245916cd2Sjpk break; 109345916cd2Sjpk 109445916cd2Sjpk case SUN_CIPSO: 109545916cd2Sjpk retv = _blinrange(label2bslabel(plabel), 109645916cd2Sjpk &dst_rhtp->tpc_tp.tp_sl_range_cipso) || 109745916cd2Sjpk blinlset(label2bslabel(plabel), 109845916cd2Sjpk dst_rhtp->tpc_tp.tp_sl_set_cipso); 109945916cd2Sjpk break; 110045916cd2Sjpk 110145916cd2Sjpk default: 110245916cd2Sjpk retv = B_FALSE; 110345916cd2Sjpk } 110445916cd2Sjpk TPC_RELE(src_rhtp); 110545916cd2Sjpk TPC_RELE(dst_rhtp); 110645916cd2Sjpk return (retv); 110745916cd2Sjpk } 110845916cd2Sjpk 110945916cd2Sjpk /* 111045916cd2Sjpk * This routine determines whether a response to a failed packet delivery or 111145916cd2Sjpk * connection should be sent back. By default, the policy is to allow such 111245916cd2Sjpk * messages to be sent at all times, as these messages reveal little useful 111345916cd2Sjpk * information and are healthy parts of TCP/IP networking. 111445916cd2Sjpk * 111545916cd2Sjpk * If tsol_strict_error is set, then we do strict tests: if the packet label is 111645916cd2Sjpk * within the label range/set of this host/zone, return B_TRUE; otherwise 111745916cd2Sjpk * return B_FALSE, which causes the packet to be dropped silently. 111845916cd2Sjpk * 111945916cd2Sjpk * Note that tsol_get_pkt_label will cause the packet to drop if the sender is 112045916cd2Sjpk * marked as labeled in the remote host database, but the packet lacks a label. 112145916cd2Sjpk * This means that we don't need to do a lookup on the source; the 112245916cd2Sjpk * TSLF_UNLABELED flag is sufficient. 112345916cd2Sjpk */ 112445916cd2Sjpk boolean_t 1125bd670b35SErik Nordmark tsol_can_reply_error(const mblk_t *mp, ip_recv_attr_t *ira) 112645916cd2Sjpk { 112745916cd2Sjpk ts_label_t *plabel = NULL; 112845916cd2Sjpk tsol_tpc_t *rhtp; 112945916cd2Sjpk const ipha_t *ipha; 113045916cd2Sjpk const ip6_t *ip6h; 113145916cd2Sjpk boolean_t retv; 113245916cd2Sjpk bslabel_t *pktbs; 113345916cd2Sjpk 113445916cd2Sjpk /* Caller must pull up at least the IP header */ 113545916cd2Sjpk ASSERT(MBLKL(mp) >= (IPH_HDR_VERSION(mp->b_rptr) == IPV4_VERSION ? 113645916cd2Sjpk sizeof (*ipha) : sizeof (*ip6h))); 113745916cd2Sjpk 113845916cd2Sjpk if (!tsol_strict_error) 113945916cd2Sjpk return (B_TRUE); 114045916cd2Sjpk 1141bd670b35SErik Nordmark plabel = ira->ira_tsl; 114245916cd2Sjpk 114345916cd2Sjpk /* We are bootstrapping or the internal template was never deleted */ 114445916cd2Sjpk if (plabel == NULL) 114545916cd2Sjpk return (B_TRUE); 114645916cd2Sjpk 11475d3b8cb7SBill Sommerfeld if (plabel->tsl_flags & TSLF_IMPLICIT_IN) { 11485d3b8cb7SBill Sommerfeld DTRACE_PROBE3(tx__ip__log__drop__replyerror__unresolved__label, 11495d3b8cb7SBill Sommerfeld char *, 11505d3b8cb7SBill Sommerfeld "cannot send error report for packet mp(1) with " 11515d3b8cb7SBill Sommerfeld "unresolved security label sl(2)", 11525d3b8cb7SBill Sommerfeld mblk_t *, mp, ts_label_t *, plabel); 11535d3b8cb7SBill Sommerfeld return (B_FALSE); 11545d3b8cb7SBill Sommerfeld } 11555d3b8cb7SBill Sommerfeld 11565d3b8cb7SBill Sommerfeld 115745916cd2Sjpk if (IPH_HDR_VERSION(mp->b_rptr) == IPV4_VERSION) { 115845916cd2Sjpk ipha = (const ipha_t *)mp->b_rptr; 115945916cd2Sjpk rhtp = find_tpc(&ipha->ipha_dst, IPV4_VERSION, B_FALSE); 116045916cd2Sjpk } else { 116145916cd2Sjpk ip6h = (const ip6_t *)mp->b_rptr; 116245916cd2Sjpk rhtp = find_tpc(&ip6h->ip6_dst, IPV6_VERSION, B_FALSE); 116345916cd2Sjpk } 116445916cd2Sjpk 116545916cd2Sjpk if (rhtp == NULL || label2doi(plabel) != rhtp->tpc_tp.tp_doi) { 116645916cd2Sjpk retv = B_FALSE; 116745916cd2Sjpk } else { 116845916cd2Sjpk /* 116945916cd2Sjpk * If we're in the midst of forwarding, then the destination 117045916cd2Sjpk * address might not be labeled. In that case, allow unlabeled 117145916cd2Sjpk * packets through only if the default label is the same, and 117245916cd2Sjpk * labeled ones if they dominate. 117345916cd2Sjpk */ 117445916cd2Sjpk pktbs = label2bslabel(plabel); 117545916cd2Sjpk switch (rhtp->tpc_tp.host_type) { 117645916cd2Sjpk case UNLABELED: 117745916cd2Sjpk if (plabel->tsl_flags & TSLF_UNLABELED) { 117845916cd2Sjpk retv = blequal(pktbs, 117945916cd2Sjpk &rhtp->tpc_tp.tp_def_label); 118045916cd2Sjpk } else { 118145916cd2Sjpk retv = bldominates(pktbs, 118245916cd2Sjpk &rhtp->tpc_tp.tp_def_label); 118345916cd2Sjpk } 118445916cd2Sjpk break; 118545916cd2Sjpk 118645916cd2Sjpk case SUN_CIPSO: 118745916cd2Sjpk retv = _blinrange(pktbs, 118845916cd2Sjpk &rhtp->tpc_tp.tp_sl_range_cipso) || 118945916cd2Sjpk blinlset(pktbs, rhtp->tpc_tp.tp_sl_set_cipso); 119045916cd2Sjpk break; 119145916cd2Sjpk 119245916cd2Sjpk default: 119345916cd2Sjpk retv = B_FALSE; 119445916cd2Sjpk break; 119545916cd2Sjpk } 119645916cd2Sjpk } 119745916cd2Sjpk 119845916cd2Sjpk if (rhtp != NULL) 119945916cd2Sjpk TPC_RELE(rhtp); 120045916cd2Sjpk 120145916cd2Sjpk return (retv); 120245916cd2Sjpk } 120345916cd2Sjpk 120445916cd2Sjpk /* 1205bd670b35SErik Nordmark * Finds the zone associated with the receive attributes. Returns GLOBAL_ZONEID 1206bd670b35SErik Nordmark * if the zone cannot be located. 120745916cd2Sjpk * 120845916cd2Sjpk * This is used by the classifier when the packet matches an ALL_ZONES IRE, and 120945916cd2Sjpk * there's no MLP defined. 1210f4b3ec61Sdh155122 * 1211f4b3ec61Sdh155122 * Note that we assume that this is only invoked in the ALL_ZONES case. 1212bd670b35SErik Nordmark * Handling other cases would require handling exclusive IP zones where either 1213f4b3ec61Sdh155122 * this routine or the callers would have to map from 1214f4b3ec61Sdh155122 * the zoneid (zone->zone_id) to what IP uses in conn_zoneid etc. 121545916cd2Sjpk */ 121645916cd2Sjpk zoneid_t 1217bd670b35SErik Nordmark tsol_attr_to_zoneid(const ip_recv_attr_t *ira) 121845916cd2Sjpk { 121945916cd2Sjpk zone_t *zone; 122045916cd2Sjpk ts_label_t *label; 122145916cd2Sjpk 1222bd670b35SErik Nordmark if ((label = ira->ira_tsl) != NULL) { 122345916cd2Sjpk zone = zone_find_by_label(label); 122445916cd2Sjpk if (zone != NULL) { 122545916cd2Sjpk zoneid_t zoneid = zone->zone_id; 122645916cd2Sjpk 122745916cd2Sjpk zone_rele(zone); 122845916cd2Sjpk return (zoneid); 122945916cd2Sjpk } 123045916cd2Sjpk } 123145916cd2Sjpk return (GLOBAL_ZONEID); 123245916cd2Sjpk } 123345916cd2Sjpk 123445916cd2Sjpk int 123545916cd2Sjpk tsol_ire_match_gwattr(ire_t *ire, const ts_label_t *tsl) 123645916cd2Sjpk { 123745916cd2Sjpk int error = 0; 123845916cd2Sjpk tsol_ire_gw_secattr_t *attrp = NULL; 123945916cd2Sjpk tsol_tnrhc_t *gw_rhc = NULL; 124045916cd2Sjpk tsol_gcgrp_t *gcgrp = NULL; 124145916cd2Sjpk tsol_gc_t *gc = NULL; 124245916cd2Sjpk in_addr_t ga_addr4; 124345916cd2Sjpk void *paddr = NULL; 124445916cd2Sjpk 124545916cd2Sjpk /* Not in Trusted mode or IRE is local/loopback/broadcast/interface */ 124645916cd2Sjpk if (!is_system_labeled() || 124745916cd2Sjpk (ire->ire_type & (IRE_LOCAL | IRE_LOOPBACK | IRE_BROADCAST | 1248bd670b35SErik Nordmark IRE_IF_ALL | IRE_MULTICAST | IRE_NOROUTE))) 124945916cd2Sjpk goto done; 125045916cd2Sjpk 125145916cd2Sjpk /* 125245916cd2Sjpk * If we don't have a label to compare with, or the IRE does not 125345916cd2Sjpk * contain any gateway security attributes, there's not much that 125445916cd2Sjpk * we can do. We let the former case pass, and the latter fail, 125545916cd2Sjpk * since the IRE doesn't qualify for a match due to the lack of 125645916cd2Sjpk * security attributes. 125745916cd2Sjpk */ 125845916cd2Sjpk if (tsl == NULL || ire->ire_gw_secattr == NULL) { 125945916cd2Sjpk if (tsl != NULL) { 12605d3b8cb7SBill Sommerfeld DTRACE_PROBE3( 12615d3b8cb7SBill Sommerfeld tx__ip__log__drop__irematch__nogwsec, char *, 12625d3b8cb7SBill Sommerfeld "ire(1) lacks ire_gw_secattr when matching " 12635d3b8cb7SBill Sommerfeld "label(2)", ire_t *, ire, ts_label_t *, tsl); 126445916cd2Sjpk error = EACCES; 126545916cd2Sjpk } 126645916cd2Sjpk goto done; 126745916cd2Sjpk } 126845916cd2Sjpk 126945916cd2Sjpk attrp = ire->ire_gw_secattr; 127045916cd2Sjpk 127145916cd2Sjpk /* 127245916cd2Sjpk * The possible lock order scenarios related to the tsol gateway 127345916cd2Sjpk * attribute locks are documented at the beginning of ip.c in the 127445916cd2Sjpk * lock order scenario section. 127545916cd2Sjpk */ 127645916cd2Sjpk mutex_enter(&attrp->igsa_lock); 127745916cd2Sjpk 127845916cd2Sjpk /* 1279bd670b35SErik Nordmark * We seek the group 128045916cd2Sjpk * structure which contains all security credentials of the gateway. 1281bd670b35SErik Nordmark * An offline IRE is associated with at most one gateway credential. 128245916cd2Sjpk */ 1283bd670b35SErik Nordmark if ((gc = attrp->igsa_gc) != NULL) { 128445916cd2Sjpk gcgrp = gc->gc_grp; 128545916cd2Sjpk ASSERT(gcgrp != NULL); 128645916cd2Sjpk rw_enter(&gcgrp->gcgrp_rwlock, RW_READER); 128745916cd2Sjpk GCGRP_REFHOLD(gcgrp); 1288bd670b35SErik Nordmark } 128945916cd2Sjpk 129045916cd2Sjpk if ((gw_rhc = attrp->igsa_rhc) != NULL) { 129145916cd2Sjpk /* 129245916cd2Sjpk * If our cached entry has grown stale, then discard it so we 129345916cd2Sjpk * can get a new one. 129445916cd2Sjpk */ 129545916cd2Sjpk if (gw_rhc->rhc_invalid || gw_rhc->rhc_tpc->tpc_invalid) { 129645916cd2Sjpk TNRHC_RELE(gw_rhc); 129745916cd2Sjpk attrp->igsa_rhc = gw_rhc = NULL; 129845916cd2Sjpk } else { 129945916cd2Sjpk TNRHC_HOLD(gw_rhc) 130045916cd2Sjpk } 130145916cd2Sjpk } 130245916cd2Sjpk 130345916cd2Sjpk /* Last attempt at loading the template had failed; try again */ 130445916cd2Sjpk if (gw_rhc == NULL) { 130545916cd2Sjpk if (gcgrp != NULL) { 130645916cd2Sjpk tsol_gcgrp_addr_t *ga = &gcgrp->gcgrp_addr; 130745916cd2Sjpk 130845916cd2Sjpk if (ire->ire_ipversion == IPV4_VERSION) { 130945916cd2Sjpk ASSERT(ga->ga_af == AF_INET); 131045916cd2Sjpk IN6_V4MAPPED_TO_IPADDR(&ga->ga_addr, ga_addr4); 131145916cd2Sjpk paddr = &ga_addr4; 131245916cd2Sjpk } else { 131345916cd2Sjpk ASSERT(ga->ga_af == AF_INET6); 131445916cd2Sjpk paddr = &ga->ga_addr; 131545916cd2Sjpk } 1316bd670b35SErik Nordmark } else if (ire->ire_type & IRE_OFFLINK) { 1317bd670b35SErik Nordmark if (ire->ire_ipversion == IPV6_VERSION) 131845916cd2Sjpk paddr = &ire->ire_gateway_addr_v6; 1319bd670b35SErik Nordmark else if (ire->ire_ipversion == IPV4_VERSION) 132045916cd2Sjpk paddr = &ire->ire_gateway_addr; 132145916cd2Sjpk } 132245916cd2Sjpk 132345916cd2Sjpk /* We've found a gateway address to do the template lookup */ 132445916cd2Sjpk if (paddr != NULL) { 132545916cd2Sjpk ASSERT(gw_rhc == NULL); 1326bfabfc35Skp158701 gw_rhc = find_rhc(paddr, ire->ire_ipversion, B_FALSE); 132745916cd2Sjpk if (gw_rhc != NULL) { 132845916cd2Sjpk /* 132945916cd2Sjpk * Note that if the lookup above returned an 133045916cd2Sjpk * internal template, we'll use it for the 133145916cd2Sjpk * time being, and do another lookup next 133245916cd2Sjpk * time around. 133345916cd2Sjpk */ 133445916cd2Sjpk /* Another thread has loaded the template? */ 133545916cd2Sjpk if (attrp->igsa_rhc != NULL) { 133645916cd2Sjpk TNRHC_RELE(gw_rhc) 133745916cd2Sjpk /* reload, it could be different */ 133845916cd2Sjpk gw_rhc = attrp->igsa_rhc; 133945916cd2Sjpk } else { 134045916cd2Sjpk attrp->igsa_rhc = gw_rhc; 134145916cd2Sjpk } 134245916cd2Sjpk /* 134345916cd2Sjpk * Hold an extra reference just like we did 134445916cd2Sjpk * above prior to dropping the igsa_lock. 134545916cd2Sjpk */ 134645916cd2Sjpk TNRHC_HOLD(gw_rhc) 134745916cd2Sjpk } 134845916cd2Sjpk } 134945916cd2Sjpk } 135045916cd2Sjpk 135145916cd2Sjpk mutex_exit(&attrp->igsa_lock); 135245916cd2Sjpk /* Gateway template not found */ 135345916cd2Sjpk if (gw_rhc == NULL) { 135445916cd2Sjpk /* 135545916cd2Sjpk * If destination address is directly reachable through an 135645916cd2Sjpk * interface rather than through a learned route, pass it. 135745916cd2Sjpk */ 135845916cd2Sjpk if (paddr != NULL) { 135945916cd2Sjpk DTRACE_PROBE3( 136045916cd2Sjpk tx__ip__log__drop__irematch__nogwtmpl, char *, 136145916cd2Sjpk "ire(1), label(2) off-link with no gw_rhc", 136245916cd2Sjpk ire_t *, ire, ts_label_t *, tsl); 136345916cd2Sjpk error = EINVAL; 136445916cd2Sjpk } 136545916cd2Sjpk goto done; 136645916cd2Sjpk } 136745916cd2Sjpk 136845916cd2Sjpk if (gc != NULL) { 1369bd670b35SErik Nordmark 137045916cd2Sjpk tsol_gcdb_t *gcdb; 137145916cd2Sjpk /* 137245916cd2Sjpk * In the case of IRE_CACHE we've got one or more gateway 137345916cd2Sjpk * security credentials to compare against the passed in label. 137445916cd2Sjpk * Perform label range comparison against each security 137545916cd2Sjpk * credential of the gateway. In the case of a prefix ire 137645916cd2Sjpk * we need to match against the security attributes of 137745916cd2Sjpk * just the route itself, so the loop is executed only once. 137845916cd2Sjpk */ 137945916cd2Sjpk ASSERT(gcgrp != NULL); 138045916cd2Sjpk gcdb = gc->gc_db; 1381bd670b35SErik Nordmark if (tsl->tsl_doi != gcdb->gcdb_doi || 1382bd670b35SErik Nordmark !_blinrange(&tsl->tsl_label, &gcdb->gcdb_slrange)) { 138345916cd2Sjpk DTRACE_PROBE3( 138445916cd2Sjpk tx__ip__log__drop__irematch__nogcmatched, 138545916cd2Sjpk char *, "ire(1), tsl(2): all gc failed match", 138645916cd2Sjpk ire_t *, ire, ts_label_t *, tsl); 138745916cd2Sjpk error = EACCES; 138845916cd2Sjpk } 138945916cd2Sjpk } else { 139045916cd2Sjpk /* 139145916cd2Sjpk * We didn't find any gateway credentials in the IRE 139245916cd2Sjpk * attributes; fall back to the gateway's template for 139345916cd2Sjpk * label range checks, if we are required to do so. 139445916cd2Sjpk */ 139545916cd2Sjpk ASSERT(gw_rhc != NULL); 139645916cd2Sjpk switch (gw_rhc->rhc_tpc->tpc_tp.host_type) { 139745916cd2Sjpk case SUN_CIPSO: 1398222c5bceSkp158701 if (tsl->tsl_doi != gw_rhc->rhc_tpc->tpc_tp.tp_doi || 139945916cd2Sjpk (!_blinrange(&tsl->tsl_label, 1400222c5bceSkp158701 &gw_rhc->rhc_tpc->tpc_tp.tp_sl_range_cipso) && 140145916cd2Sjpk !blinlset(&tsl->tsl_label, 140245916cd2Sjpk gw_rhc->rhc_tpc->tpc_tp.tp_sl_set_cipso))) { 140345916cd2Sjpk error = EACCES; 140445916cd2Sjpk DTRACE_PROBE4( 140545916cd2Sjpk tx__ip__log__drop__irematch__deftmpl, 140645916cd2Sjpk char *, "ire(1), tsl(2), gw_rhc(3) " 140745916cd2Sjpk "failed match (cipso gw)", 140845916cd2Sjpk ire_t *, ire, ts_label_t *, tsl, 140945916cd2Sjpk tsol_tnrhc_t *, gw_rhc); 141045916cd2Sjpk } 141145916cd2Sjpk break; 141245916cd2Sjpk 141345916cd2Sjpk case UNLABELED: 1414222c5bceSkp158701 if (tsl->tsl_doi != gw_rhc->rhc_tpc->tpc_tp.tp_doi || 141545916cd2Sjpk (!_blinrange(&tsl->tsl_label, 141645916cd2Sjpk &gw_rhc->rhc_tpc->tpc_tp.tp_gw_sl_range) && 141745916cd2Sjpk !blinlset(&tsl->tsl_label, 141845916cd2Sjpk gw_rhc->rhc_tpc->tpc_tp.tp_gw_sl_set))) { 141945916cd2Sjpk error = EACCES; 142045916cd2Sjpk DTRACE_PROBE4( 142145916cd2Sjpk tx__ip__log__drop__irematch__deftmpl, 142245916cd2Sjpk char *, "ire(1), tsl(2), gw_rhc(3) " 142345916cd2Sjpk "failed match (unlabeled gw)", 142445916cd2Sjpk ire_t *, ire, ts_label_t *, tsl, 142545916cd2Sjpk tsol_tnrhc_t *, gw_rhc); 142645916cd2Sjpk } 142745916cd2Sjpk break; 142845916cd2Sjpk } 142945916cd2Sjpk } 143045916cd2Sjpk 143145916cd2Sjpk done: 143245916cd2Sjpk 143345916cd2Sjpk if (gcgrp != NULL) { 143445916cd2Sjpk rw_exit(&gcgrp->gcgrp_rwlock); 143545916cd2Sjpk GCGRP_REFRELE(gcgrp); 143645916cd2Sjpk } 143745916cd2Sjpk 143845916cd2Sjpk if (gw_rhc != NULL) 143945916cd2Sjpk TNRHC_RELE(gw_rhc) 144045916cd2Sjpk 144145916cd2Sjpk return (error); 144245916cd2Sjpk } 144345916cd2Sjpk 144445916cd2Sjpk /* 144545916cd2Sjpk * Performs label accreditation checks for packet forwarding. 1446bd670b35SErik Nordmark * Add or remove a CIPSO option as needed. 144745916cd2Sjpk * 144845916cd2Sjpk * Returns a pointer to the modified mblk if allowed for forwarding, 144945916cd2Sjpk * or NULL if the packet must be dropped. 145045916cd2Sjpk */ 145145916cd2Sjpk mblk_t * 1452bd670b35SErik Nordmark tsol_ip_forward(ire_t *ire, mblk_t *mp, const ip_recv_attr_t *ira) 145345916cd2Sjpk { 145445916cd2Sjpk tsol_ire_gw_secattr_t *attrp = NULL; 145545916cd2Sjpk ipha_t *ipha; 145645916cd2Sjpk ip6_t *ip6h; 145745916cd2Sjpk const void *pdst; 145845916cd2Sjpk const void *psrc; 145945916cd2Sjpk boolean_t off_link; 146045916cd2Sjpk tsol_tpc_t *dst_rhtp, *gw_rhtp; 146145916cd2Sjpk tsol_ip_label_t label_type; 146245916cd2Sjpk uchar_t *opt_ptr = NULL; 146345916cd2Sjpk ts_label_t *tsl; 146445916cd2Sjpk uint8_t proto; 146545916cd2Sjpk int af, adjust; 146645916cd2Sjpk uint16_t iplen; 1467c793af95Ssangeeta boolean_t need_tpc_rele = B_FALSE; 1468c793af95Ssangeeta ipaddr_t *gw; 1469f4b3ec61Sdh155122 ip_stack_t *ipst = ire->ire_ipst; 1470bd670b35SErik Nordmark int err; 1471bd670b35SErik Nordmark ts_label_t *effective_tsl = NULL; 147245916cd2Sjpk 147345916cd2Sjpk ASSERT(ire != NULL && mp != NULL); 1474bd670b35SErik Nordmark /* 1475bd670b35SErik Nordmark * Note that the ire is the first one found, i.e., an IRE_OFFLINK if 1476bd670b35SErik Nordmark * the destination is offlink. 1477bd670b35SErik Nordmark */ 147845916cd2Sjpk 147945916cd2Sjpk af = (ire->ire_ipversion == IPV4_VERSION) ? AF_INET : AF_INET6; 148045916cd2Sjpk 148145916cd2Sjpk if (IPH_HDR_VERSION(mp->b_rptr) == IPV4_VERSION) { 148245916cd2Sjpk ASSERT(ire->ire_ipversion == IPV4_VERSION); 148345916cd2Sjpk ipha = (ipha_t *)mp->b_rptr; 148445916cd2Sjpk psrc = &ipha->ipha_src; 148545916cd2Sjpk pdst = &ipha->ipha_dst; 148645916cd2Sjpk proto = ipha->ipha_protocol; 1487c4e55c13Sken Powell - Sun Microsystem if (!tsol_get_option_v4(mp, &label_type, &opt_ptr)) 1488c4e55c13Sken Powell - Sun Microsystem return (NULL); 148945916cd2Sjpk } else { 149045916cd2Sjpk ASSERT(ire->ire_ipversion == IPV6_VERSION); 149145916cd2Sjpk ip6h = (ip6_t *)mp->b_rptr; 149245916cd2Sjpk psrc = &ip6h->ip6_src; 149345916cd2Sjpk pdst = &ip6h->ip6_dst; 149445916cd2Sjpk proto = ip6h->ip6_nxt; 149545916cd2Sjpk 149645916cd2Sjpk if (proto != IPPROTO_TCP && proto != IPPROTO_UDP && 149745916cd2Sjpk proto != IPPROTO_ICMPV6) { 149845916cd2Sjpk uint8_t *nexthdrp; 149945916cd2Sjpk uint16_t hdr_len; 150045916cd2Sjpk 150145916cd2Sjpk if (!ip_hdr_length_nexthdr_v6(mp, ip6h, &hdr_len, 150245916cd2Sjpk &nexthdrp)) { 150345916cd2Sjpk /* malformed packet; drop it */ 150445916cd2Sjpk return (NULL); 150545916cd2Sjpk } 150645916cd2Sjpk proto = *nexthdrp; 150745916cd2Sjpk } 1508c4e55c13Sken Powell - Sun Microsystem if (!tsol_get_option_v6(mp, &label_type, &opt_ptr)) 1509c4e55c13Sken Powell - Sun Microsystem return (NULL); 151045916cd2Sjpk } 1511bd670b35SErik Nordmark /* 1512bd670b35SErik Nordmark * off_link is TRUE if destination not directly reachable. 1513bd670b35SErik Nordmark */ 1514bd670b35SErik Nordmark off_link = (ire->ire_type & IRE_OFFLINK); 151545916cd2Sjpk 1516bd670b35SErik Nordmark if ((tsl = ira->ira_tsl) == NULL) 151745916cd2Sjpk return (mp); 151845916cd2Sjpk 15195d3b8cb7SBill Sommerfeld if (tsl->tsl_flags & TSLF_IMPLICIT_IN) { 15205d3b8cb7SBill Sommerfeld DTRACE_PROBE3(tx__ip__log__drop__forward__unresolved__label, 15215d3b8cb7SBill Sommerfeld char *, 15225d3b8cb7SBill Sommerfeld "cannot forward packet mp(1) with unresolved " 15235d3b8cb7SBill Sommerfeld "security label sl(2)", 15245d3b8cb7SBill Sommerfeld mblk_t *, mp, ts_label_t *, tsl); 15255d3b8cb7SBill Sommerfeld 15265d3b8cb7SBill Sommerfeld return (NULL); 15275d3b8cb7SBill Sommerfeld } 15285d3b8cb7SBill Sommerfeld 15295d3b8cb7SBill Sommerfeld 153045916cd2Sjpk ASSERT(psrc != NULL && pdst != NULL); 153145916cd2Sjpk dst_rhtp = find_tpc(pdst, ire->ire_ipversion, B_FALSE); 153245916cd2Sjpk 153345916cd2Sjpk if (dst_rhtp == NULL) { 153445916cd2Sjpk /* 153545916cd2Sjpk * Without a template we do not know if forwarding 153645916cd2Sjpk * violates MAC 153745916cd2Sjpk */ 153845916cd2Sjpk DTRACE_PROBE3(tx__ip__log__drop__forward__nodst, char *, 153945916cd2Sjpk "mp(1) dropped, no template for destination ip4|6(2)", 154045916cd2Sjpk mblk_t *, mp, void *, pdst); 154145916cd2Sjpk return (NULL); 154245916cd2Sjpk } 154345916cd2Sjpk 154445916cd2Sjpk /* 154545916cd2Sjpk * Gateway template must have existed for off-link destinations, 154645916cd2Sjpk * since tsol_ire_match_gwattr has ensured such condition. 154745916cd2Sjpk */ 1548c793af95Ssangeeta if (ire->ire_ipversion == IPV4_VERSION && off_link) { 1549c793af95Ssangeeta /* 1550c793af95Ssangeeta * Surya note: first check if we can get the gw_rhtp from 1551c793af95Ssangeeta * the ire_gw_secattr->igsa_rhc; if this is null, then 1552c793af95Ssangeeta * do a lookup based on the ire_addr (address of gw) 1553c793af95Ssangeeta */ 1554c793af95Ssangeeta if (ire->ire_gw_secattr != NULL && 1555c793af95Ssangeeta ire->ire_gw_secattr->igsa_rhc != NULL) { 1556c793af95Ssangeeta attrp = ire->ire_gw_secattr; 1557c793af95Ssangeeta gw_rhtp = attrp->igsa_rhc->rhc_tpc; 1558c793af95Ssangeeta } else { 1559bd670b35SErik Nordmark gw = &ire->ire_gateway_addr; 1560c793af95Ssangeeta gw_rhtp = find_tpc(gw, ire->ire_ipversion, B_FALSE); 1561c793af95Ssangeeta need_tpc_rele = B_TRUE; 1562c793af95Ssangeeta } 1563c793af95Ssangeeta if (gw_rhtp == NULL) { 1564c793af95Ssangeeta DTRACE_PROBE3(tx__ip__log__drop__forward__nogw, char *, 1565c793af95Ssangeeta "mp(1) dropped, no gateway in ire attributes(2)", 1566c793af95Ssangeeta mblk_t *, mp, tsol_ire_gw_secattr_t *, attrp); 1567c793af95Ssangeeta mp = NULL; 1568c793af95Ssangeeta goto keep_label; 1569c793af95Ssangeeta } 1570c793af95Ssangeeta } 1571c793af95Ssangeeta if (ire->ire_ipversion == IPV6_VERSION && 1572c793af95Ssangeeta ((attrp = ire->ire_gw_secattr) == NULL || attrp->igsa_rhc == NULL || 157345916cd2Sjpk (gw_rhtp = attrp->igsa_rhc->rhc_tpc) == NULL) && off_link) { 157445916cd2Sjpk DTRACE_PROBE3(tx__ip__log__drop__forward__nogw, char *, 157545916cd2Sjpk "mp(1) dropped, no gateway in ire attributes(2)", 157645916cd2Sjpk mblk_t *, mp, tsol_ire_gw_secattr_t *, attrp); 157745916cd2Sjpk mp = NULL; 157845916cd2Sjpk goto keep_label; 157945916cd2Sjpk } 158045916cd2Sjpk 158145916cd2Sjpk /* 158245916cd2Sjpk * Check that the label for the packet is acceptable 158345916cd2Sjpk * by destination host; otherwise, drop it. 158445916cd2Sjpk */ 158545916cd2Sjpk switch (dst_rhtp->tpc_tp.host_type) { 158645916cd2Sjpk case SUN_CIPSO: 158745916cd2Sjpk if (tsl->tsl_doi != dst_rhtp->tpc_tp.tp_doi || 158845916cd2Sjpk (!_blinrange(&tsl->tsl_label, 158945916cd2Sjpk &dst_rhtp->tpc_tp.tp_sl_range_cipso) && 159045916cd2Sjpk !blinlset(&tsl->tsl_label, 159145916cd2Sjpk dst_rhtp->tpc_tp.tp_sl_set_cipso))) { 159245916cd2Sjpk DTRACE_PROBE4(tx__ip__log__drop__forward__mac, char *, 159345916cd2Sjpk "labeled packet mp(1) dropped, label(2) fails " 159445916cd2Sjpk "destination(3) accredation check", 159545916cd2Sjpk mblk_t *, mp, ts_label_t *, tsl, 159645916cd2Sjpk tsol_tpc_t *, dst_rhtp); 159745916cd2Sjpk mp = NULL; 159845916cd2Sjpk goto keep_label; 159945916cd2Sjpk } 160045916cd2Sjpk break; 160145916cd2Sjpk 160245916cd2Sjpk 160345916cd2Sjpk case UNLABELED: 160445916cd2Sjpk if (tsl->tsl_doi != dst_rhtp->tpc_tp.tp_doi || 160545916cd2Sjpk !blequal(&dst_rhtp->tpc_tp.tp_def_label, 160645916cd2Sjpk &tsl->tsl_label)) { 160745916cd2Sjpk DTRACE_PROBE4(tx__ip__log__drop__forward__mac, char *, 160845916cd2Sjpk "unlabeled packet mp(1) dropped, label(2) fails " 160945916cd2Sjpk "destination(3) accredation check", 161045916cd2Sjpk mblk_t *, mp, ts_label_t *, tsl, 161145916cd2Sjpk tsol_tpc_t *, dst_rhtp); 161245916cd2Sjpk mp = NULL; 161345916cd2Sjpk goto keep_label; 161445916cd2Sjpk } 161545916cd2Sjpk break; 161645916cd2Sjpk } 161745916cd2Sjpk if (label_type == OPT_CIPSO) { 161845916cd2Sjpk /* 161945916cd2Sjpk * We keep the label on any of the following cases: 162045916cd2Sjpk * 162145916cd2Sjpk * 1. The destination is labeled (on/off-link). 162245916cd2Sjpk * 2. The unlabeled destination is off-link, 162345916cd2Sjpk * and the next hop gateway is labeled. 162445916cd2Sjpk */ 162545916cd2Sjpk if (dst_rhtp->tpc_tp.host_type != UNLABELED || 162645916cd2Sjpk (off_link && 162745916cd2Sjpk gw_rhtp->tpc_tp.host_type != UNLABELED)) 162845916cd2Sjpk goto keep_label; 162945916cd2Sjpk 163045916cd2Sjpk /* 163145916cd2Sjpk * Strip off the CIPSO option from the packet because: the 163245916cd2Sjpk * unlabeled destination host is directly reachable through 163345916cd2Sjpk * an interface (on-link); or, the unlabeled destination host 163445916cd2Sjpk * is not directly reachable (off-link), and the next hop 163545916cd2Sjpk * gateway is unlabeled. 163645916cd2Sjpk */ 163745916cd2Sjpk adjust = (af == AF_INET) ? tsol_remove_secopt(ipha, MBLKL(mp)) : 163845916cd2Sjpk tsol_remove_secopt_v6(ip6h, MBLKL(mp)); 163945916cd2Sjpk 164045916cd2Sjpk ASSERT(adjust <= 0); 164145916cd2Sjpk if (adjust != 0) { 164245916cd2Sjpk 164345916cd2Sjpk /* adjust is negative */ 164445916cd2Sjpk ASSERT((mp->b_wptr + adjust) >= mp->b_rptr); 164545916cd2Sjpk mp->b_wptr += adjust; 1646bd670b35SErik Nordmark /* 1647bd670b35SErik Nordmark * Note that caller adjusts ira_pktlen and 1648bd670b35SErik Nordmark * ira_ip_hdr_length 1649bd670b35SErik Nordmark * 1650bd670b35SErik Nordmark * For AF_INET6 note that tsol_remove_secopt_v6 1651bd670b35SErik Nordmark * adjusted ip6_plen. 1652bd670b35SErik Nordmark */ 165345916cd2Sjpk if (af == AF_INET) { 165445916cd2Sjpk ipha = (ipha_t *)mp->b_rptr; 165545916cd2Sjpk iplen = ntohs(ipha->ipha_length) + adjust; 165645916cd2Sjpk ipha->ipha_length = htons(iplen); 165745916cd2Sjpk ipha->ipha_hdr_checksum = 0; 165845916cd2Sjpk ipha->ipha_hdr_checksum = ip_csum_hdr(ipha); 165945916cd2Sjpk } 166045916cd2Sjpk DTRACE_PROBE3(tx__ip__log__info__forward__adjust, 166145916cd2Sjpk char *, 166245916cd2Sjpk "mp(1) adjusted(2) for CIPSO option removal", 166345916cd2Sjpk mblk_t *, mp, int, adjust); 166445916cd2Sjpk } 166545916cd2Sjpk goto keep_label; 166645916cd2Sjpk } 166745916cd2Sjpk 166845916cd2Sjpk ASSERT(label_type == OPT_NONE); 166945916cd2Sjpk ASSERT(dst_rhtp != NULL); 167045916cd2Sjpk 167145916cd2Sjpk /* 167245916cd2Sjpk * We need to add CIPSO option if the destination or the next hop 167345916cd2Sjpk * gateway is labeled. Otherwise, pass the packet as is. 167445916cd2Sjpk */ 167545916cd2Sjpk if (dst_rhtp->tpc_tp.host_type == UNLABELED && 167645916cd2Sjpk (!off_link || gw_rhtp->tpc_tp.host_type == UNLABELED)) 167745916cd2Sjpk goto keep_label; 167845916cd2Sjpk 1679bd670b35SErik Nordmark /* 1680bd670b35SErik Nordmark * Since we are forwarding packets we use GLOBAL_ZONEID for 1681bd670b35SErik Nordmark * the IRE lookup in tsol_check_label. 1682bd670b35SErik Nordmark * Since mac_exempt is false the zoneid isn't used for anything 1683bd670b35SErik Nordmark * but the IRE lookup, hence we set zone_is_global to false. 1684bd670b35SErik Nordmark */ 1685bd670b35SErik Nordmark if (af == AF_INET) { 1686bd670b35SErik Nordmark err = tsol_check_label_v4(tsl, GLOBAL_ZONEID, &mp, 1687bd670b35SErik Nordmark CONN_MAC_DEFAULT, B_FALSE, ipst, &effective_tsl); 1688bd670b35SErik Nordmark } else { 1689bd670b35SErik Nordmark err = tsol_check_label_v6(tsl, GLOBAL_ZONEID, &mp, 1690bd670b35SErik Nordmark CONN_MAC_DEFAULT, B_FALSE, ipst, &effective_tsl); 1691bd670b35SErik Nordmark } 1692bd670b35SErik Nordmark if (err != 0) { 1693bd670b35SErik Nordmark BUMP_MIB(&ipst->ips_ip_mib, ipIfStatsOutDiscards); 1694bd670b35SErik Nordmark ip_drop_output("tsol_check_label", mp, NULL); 1695bd670b35SErik Nordmark freemsg(mp); 169645916cd2Sjpk mp = NULL; 169745916cd2Sjpk goto keep_label; 169845916cd2Sjpk } 169945916cd2Sjpk 1700bd670b35SErik Nordmark /* 1701bd670b35SErik Nordmark * The effective_tsl must never affect the routing decision, hence 1702bd670b35SErik Nordmark * we ignore it here. 1703bd670b35SErik Nordmark */ 1704bd670b35SErik Nordmark if (effective_tsl != NULL) 1705bd670b35SErik Nordmark label_rele(effective_tsl); 1706bd670b35SErik Nordmark 170745916cd2Sjpk if (af == AF_INET) { 170845916cd2Sjpk ipha = (ipha_t *)mp->b_rptr; 170945916cd2Sjpk ipha->ipha_hdr_checksum = 0; 171045916cd2Sjpk ipha->ipha_hdr_checksum = ip_csum_hdr(ipha); 171145916cd2Sjpk } 171245916cd2Sjpk 171345916cd2Sjpk keep_label: 171445916cd2Sjpk TPC_RELE(dst_rhtp); 1715c793af95Ssangeeta if (need_tpc_rele && gw_rhtp != NULL) 1716c793af95Ssangeeta TPC_RELE(gw_rhtp); 171745916cd2Sjpk return (mp); 171845916cd2Sjpk } 171945916cd2Sjpk 172045916cd2Sjpk /* 17210ec92a15Swy83408 * Name: tsol_pmtu_adjust() 17220ec92a15Swy83408 * 17230ec92a15Swy83408 * Returns the adjusted mtu after removing security option. 17240ec92a15Swy83408 * Removes/subtracts the option if the packet's cred indicates an unlabeled 17250ec92a15Swy83408 * sender or if pkt_diff indicates this system enlarged the packet. 17260ec92a15Swy83408 */ 17270ec92a15Swy83408 uint32_t 17280ec92a15Swy83408 tsol_pmtu_adjust(mblk_t *mp, uint32_t mtu, int pkt_diff, int af) 17290ec92a15Swy83408 { 17300ec92a15Swy83408 int label_adj = 0; 17310ec92a15Swy83408 uint32_t min_mtu = IP_MIN_MTU; 17320ec92a15Swy83408 tsol_tpc_t *src_rhtp; 17330ec92a15Swy83408 void *src; 17340ec92a15Swy83408 17350ec92a15Swy83408 /* 17360ec92a15Swy83408 * Note: label_adj is non-positive, indicating the number of 17370ec92a15Swy83408 * bytes removed by removing the security option from the 17380ec92a15Swy83408 * header. 17390ec92a15Swy83408 */ 17400ec92a15Swy83408 if (af == AF_INET6) { 17410ec92a15Swy83408 ip6_t *ip6h; 17420ec92a15Swy83408 17430ec92a15Swy83408 min_mtu = IPV6_MIN_MTU; 17440ec92a15Swy83408 ip6h = (ip6_t *)mp->b_rptr; 17450ec92a15Swy83408 src = &ip6h->ip6_src; 17460ec92a15Swy83408 if ((src_rhtp = find_tpc(src, IPV6_VERSION, B_FALSE)) == NULL) 17470ec92a15Swy83408 return (mtu); 17480ec92a15Swy83408 if (pkt_diff > 0 || src_rhtp->tpc_tp.host_type == UNLABELED) { 17490ec92a15Swy83408 label_adj = tsol_remove_secopt_v6( 17500ec92a15Swy83408 (ip6_t *)mp->b_rptr, MBLKL(mp)); 17510ec92a15Swy83408 } 17520ec92a15Swy83408 } else { 17530ec92a15Swy83408 ipha_t *ipha; 17540ec92a15Swy83408 17550ec92a15Swy83408 ASSERT(af == AF_INET); 17560ec92a15Swy83408 ipha = (ipha_t *)mp->b_rptr; 17570ec92a15Swy83408 src = &ipha->ipha_src; 17580ec92a15Swy83408 if ((src_rhtp = find_tpc(src, IPV4_VERSION, B_FALSE)) == NULL) 17590ec92a15Swy83408 return (mtu); 17600ec92a15Swy83408 if (pkt_diff > 0 || src_rhtp->tpc_tp.host_type == UNLABELED) 17610ec92a15Swy83408 label_adj = tsol_remove_secopt( 17620ec92a15Swy83408 (ipha_t *)mp->b_rptr, MBLKL(mp)); 17630ec92a15Swy83408 } 17640ec92a15Swy83408 /* 17650ec92a15Swy83408 * Make pkt_diff non-negative and the larger of the bytes 17660ec92a15Swy83408 * previously added (if any) or just removed, since label 17670ec92a15Swy83408 * addition + subtraction may not be completely idempotent. 17680ec92a15Swy83408 */ 17690ec92a15Swy83408 if (pkt_diff < -label_adj) 17700ec92a15Swy83408 pkt_diff = -label_adj; 17710ec92a15Swy83408 if (pkt_diff > 0 && pkt_diff < mtu) 17720ec92a15Swy83408 mtu -= pkt_diff; 17730ec92a15Swy83408 17740ec92a15Swy83408 TPC_RELE(src_rhtp); 17750ec92a15Swy83408 return (MAX(mtu, min_mtu)); 17760ec92a15Swy83408 } 17770ec92a15Swy83408 17780ec92a15Swy83408 /* 177945916cd2Sjpk * Name: tsol_rtsa_init() 178045916cd2Sjpk * 178145916cd2Sjpk * Normal: Sanity checks on the route security attributes provided by 178245916cd2Sjpk * user. Convert it into a route security parameter list to 178345916cd2Sjpk * be returned to caller. 178445916cd2Sjpk * 178545916cd2Sjpk * Output: EINVAL if bad security attributes in the routing message 178645916cd2Sjpk * ENOMEM if unable to allocate data structures 178745916cd2Sjpk * 0 otherwise. 178845916cd2Sjpk * 178945916cd2Sjpk * Note: On input, cp must point to the end of any addresses in 179045916cd2Sjpk * the rt_msghdr_t structure. 179145916cd2Sjpk */ 179245916cd2Sjpk int 179345916cd2Sjpk tsol_rtsa_init(rt_msghdr_t *rtm, tsol_rtsecattr_t *sp, caddr_t cp) 179445916cd2Sjpk { 179545916cd2Sjpk uint_t sacnt; 179645916cd2Sjpk int err; 179745916cd2Sjpk caddr_t lim; 179845916cd2Sjpk tsol_rtsecattr_t *tp; 179945916cd2Sjpk 180045916cd2Sjpk ASSERT((cp >= (caddr_t)&rtm[1]) && sp != NULL); 180145916cd2Sjpk 180245916cd2Sjpk /* 180345916cd2Sjpk * In theory, we could accept as many security attributes configured 180445916cd2Sjpk * per route destination. However, the current design is limited 180545916cd2Sjpk * such that at most only one set security attributes is allowed to 180645916cd2Sjpk * be associated with a prefix IRE. We therefore assert for now. 180745916cd2Sjpk */ 180845916cd2Sjpk /* LINTED */ 180945916cd2Sjpk ASSERT(TSOL_RTSA_REQUEST_MAX == 1); 181045916cd2Sjpk 181145916cd2Sjpk sp->rtsa_cnt = 0; 181245916cd2Sjpk lim = (caddr_t)rtm + rtm->rtm_msglen; 181345916cd2Sjpk ASSERT(cp <= lim); 181445916cd2Sjpk 181545916cd2Sjpk if ((lim - cp) < sizeof (rtm_ext_t) || 181645916cd2Sjpk ((rtm_ext_t *)cp)->rtmex_type != RTMEX_GATEWAY_SECATTR) 181745916cd2Sjpk return (0); 181845916cd2Sjpk 181945916cd2Sjpk if (((rtm_ext_t *)cp)->rtmex_len < sizeof (tsol_rtsecattr_t)) 182045916cd2Sjpk return (EINVAL); 182145916cd2Sjpk 182245916cd2Sjpk cp += sizeof (rtm_ext_t); 182345916cd2Sjpk 182445916cd2Sjpk if ((lim - cp) < sizeof (*tp) || 182545916cd2Sjpk (tp = (tsol_rtsecattr_t *)cp, (sacnt = tp->rtsa_cnt) == 0) || 182645916cd2Sjpk (lim - cp) < TSOL_RTSECATTR_SIZE(sacnt)) 182745916cd2Sjpk return (EINVAL); 182845916cd2Sjpk 182945916cd2Sjpk /* 183045916cd2Sjpk * Trying to add route security attributes when system 183145916cd2Sjpk * labeling service is not available, or when user supllies 183245916cd2Sjpk * more than the maximum number of security attributes 183345916cd2Sjpk * allowed per request. 183445916cd2Sjpk */ 183545916cd2Sjpk if ((sacnt > 0 && !is_system_labeled()) || 183645916cd2Sjpk sacnt > TSOL_RTSA_REQUEST_MAX) 183745916cd2Sjpk return (EINVAL); 183845916cd2Sjpk 183945916cd2Sjpk /* Ensure valid credentials */ 184045916cd2Sjpk if ((err = rtsa_validate(&((tsol_rtsecattr_t *)cp)-> 184145916cd2Sjpk rtsa_attr[0])) != 0) { 184245916cd2Sjpk cp += sizeof (*sp); 184345916cd2Sjpk return (err); 184445916cd2Sjpk } 184545916cd2Sjpk 184645916cd2Sjpk bcopy(cp, sp, sizeof (*sp)); 184745916cd2Sjpk cp += sizeof (*sp); 184845916cd2Sjpk return (0); 184945916cd2Sjpk } 185045916cd2Sjpk 185145916cd2Sjpk int 1852bd670b35SErik Nordmark tsol_ire_init_gwattr(ire_t *ire, uchar_t ipversion, tsol_gc_t *gc) 185345916cd2Sjpk { 185445916cd2Sjpk tsol_ire_gw_secattr_t *attrp; 185545916cd2Sjpk boolean_t exists = B_FALSE; 185645916cd2Sjpk in_addr_t ga_addr4; 185745916cd2Sjpk void *paddr = NULL; 1858bd670b35SErik Nordmark tsol_gcgrp_t *gcgrp = NULL; 185945916cd2Sjpk 186045916cd2Sjpk ASSERT(ire != NULL); 186145916cd2Sjpk 186245916cd2Sjpk /* 186345916cd2Sjpk * The only time that attrp can be NULL is when this routine is 186445916cd2Sjpk * called for the first time during the creation/initialization 186545916cd2Sjpk * of the corresponding IRE. It will only get cleared when the 186645916cd2Sjpk * IRE is deleted. 186745916cd2Sjpk */ 186845916cd2Sjpk if ((attrp = ire->ire_gw_secattr) == NULL) { 186945916cd2Sjpk attrp = ire_gw_secattr_alloc(KM_NOSLEEP); 187045916cd2Sjpk if (attrp == NULL) 187145916cd2Sjpk return (ENOMEM); 187245916cd2Sjpk ire->ire_gw_secattr = attrp; 187345916cd2Sjpk } else { 187445916cd2Sjpk exists = B_TRUE; 187545916cd2Sjpk mutex_enter(&attrp->igsa_lock); 187645916cd2Sjpk 187745916cd2Sjpk if (attrp->igsa_rhc != NULL) { 187845916cd2Sjpk TNRHC_RELE(attrp->igsa_rhc); 187945916cd2Sjpk attrp->igsa_rhc = NULL; 188045916cd2Sjpk } 188145916cd2Sjpk 188245916cd2Sjpk if (attrp->igsa_gc != NULL) 188345916cd2Sjpk GC_REFRELE(attrp->igsa_gc); 188445916cd2Sjpk } 188545916cd2Sjpk ASSERT(!exists || MUTEX_HELD(&attrp->igsa_lock)); 188645916cd2Sjpk 188745916cd2Sjpk /* 188845916cd2Sjpk * References already held by caller and we keep them; 1889bd670b35SErik Nordmark * note that gc may be set to NULL to clear out igsa_gc. 189045916cd2Sjpk */ 189145916cd2Sjpk attrp->igsa_gc = gc; 189245916cd2Sjpk 1893bd670b35SErik Nordmark if (gc != NULL) { 189445916cd2Sjpk gcgrp = gc->gc_grp; 189545916cd2Sjpk ASSERT(gcgrp != NULL); 189645916cd2Sjpk } 189745916cd2Sjpk 189845916cd2Sjpk /* 189945916cd2Sjpk * Intialize the template for gateway; we use the gateway's 190045916cd2Sjpk * address found in either the passed in gateway credential 190145916cd2Sjpk * or group pointer, or the ire_gateway_addr{_v6} field. 190245916cd2Sjpk */ 190345916cd2Sjpk if (gcgrp != NULL) { 190445916cd2Sjpk tsol_gcgrp_addr_t *ga = &gcgrp->gcgrp_addr; 190545916cd2Sjpk 190645916cd2Sjpk /* 190745916cd2Sjpk * Caller is holding a reference, and that we don't 190845916cd2Sjpk * need to hold any lock to access the address. 190945916cd2Sjpk */ 191045916cd2Sjpk if (ipversion == IPV4_VERSION) { 191145916cd2Sjpk ASSERT(ga->ga_af == AF_INET); 191245916cd2Sjpk IN6_V4MAPPED_TO_IPADDR(&ga->ga_addr, ga_addr4); 191345916cd2Sjpk paddr = &ga_addr4; 191445916cd2Sjpk } else { 191545916cd2Sjpk ASSERT(ga->ga_af == AF_INET6); 191645916cd2Sjpk paddr = &ga->ga_addr; 191745916cd2Sjpk } 1918bd670b35SErik Nordmark } else if (ire->ire_type & IRE_OFFLINK) { 1919bd670b35SErik Nordmark if (ipversion == IPV6_VERSION) 192045916cd2Sjpk paddr = &ire->ire_gateway_addr_v6; 1921bd670b35SErik Nordmark else if (ipversion == IPV4_VERSION) 192245916cd2Sjpk paddr = &ire->ire_gateway_addr; 192345916cd2Sjpk } 192445916cd2Sjpk 192545916cd2Sjpk /* 192645916cd2Sjpk * Lookup the gateway template; note that we could get an internal 192745916cd2Sjpk * template here, which we cache anyway. During IRE matching, we'll 192845916cd2Sjpk * try to update this gateway template cache and hopefully get a 192945916cd2Sjpk * real one. 193045916cd2Sjpk */ 193145916cd2Sjpk if (paddr != NULL) { 1932bfabfc35Skp158701 attrp->igsa_rhc = find_rhc(paddr, ipversion, B_FALSE); 193345916cd2Sjpk } 193445916cd2Sjpk 193545916cd2Sjpk if (exists) 193645916cd2Sjpk mutex_exit(&attrp->igsa_lock); 193745916cd2Sjpk 193845916cd2Sjpk return (0); 193945916cd2Sjpk } 194045916cd2Sjpk 194145916cd2Sjpk /* 194245916cd2Sjpk * This function figures the type of MLP that we'll be using based on the 194345916cd2Sjpk * address that the user is binding and the zone. If the address is 194445916cd2Sjpk * unspecified, then we're looking at both private and shared. If it's one 194545916cd2Sjpk * of the zone's private addresses, then it's private only. If it's one 19467b564b02SJarrett Lu * of the global addresses, then it's shared only. Multicast addresses are 19477b564b02SJarrett Lu * treated same as unspecified address. 194845916cd2Sjpk * 194945916cd2Sjpk * If we can't figure out what it is, then return mlptSingle. That's actually 195045916cd2Sjpk * an error case. 1951f4b3ec61Sdh155122 * 1952bd670b35SErik Nordmark * The callers are assumed to pass in zone->zone_id and not the zoneid that 1953f4b3ec61Sdh155122 * is stored in a conn_t (since the latter will be GLOBAL_ZONEID in an 1954f4b3ec61Sdh155122 * exclusive stack zone). 195545916cd2Sjpk */ 195645916cd2Sjpk mlp_type_t 1957f4b3ec61Sdh155122 tsol_mlp_addr_type(zoneid_t zoneid, uchar_t version, const void *addr, 1958f4b3ec61Sdh155122 ip_stack_t *ipst) 195945916cd2Sjpk { 196045916cd2Sjpk in_addr_t in4; 196145916cd2Sjpk ire_t *ire; 196245916cd2Sjpk ipif_t *ipif; 196345916cd2Sjpk zoneid_t addrzone; 1964f4b3ec61Sdh155122 zoneid_t ip_zoneid; 196545916cd2Sjpk 196645916cd2Sjpk ASSERT(addr != NULL); 196745916cd2Sjpk 1968f4b3ec61Sdh155122 /* 1969f4b3ec61Sdh155122 * For exclusive stacks we set the zoneid to zero 1970f4b3ec61Sdh155122 * to operate as if in the global zone for IRE and conn_t comparisons. 1971f4b3ec61Sdh155122 */ 1972f4b3ec61Sdh155122 if (ipst->ips_netstack->netstack_stackid != GLOBAL_NETSTACKID) 1973f4b3ec61Sdh155122 ip_zoneid = GLOBAL_ZONEID; 1974f4b3ec61Sdh155122 else 1975f4b3ec61Sdh155122 ip_zoneid = zoneid; 1976f4b3ec61Sdh155122 197745916cd2Sjpk if (version == IPV6_VERSION && 197845916cd2Sjpk IN6_IS_ADDR_V4MAPPED((const in6_addr_t *)addr)) { 197945916cd2Sjpk IN6_V4MAPPED_TO_IPADDR((const in6_addr_t *)addr, in4); 198045916cd2Sjpk addr = &in4; 198145916cd2Sjpk version = IPV4_VERSION; 198245916cd2Sjpk } 198345916cd2Sjpk 1984bd670b35SErik Nordmark /* Check whether the IRE_LOCAL (or ipif) is ALL_ZONES */ 198545916cd2Sjpk if (version == IPV4_VERSION) { 198645916cd2Sjpk in4 = *(const in_addr_t *)addr; 19877b564b02SJarrett Lu if ((in4 == INADDR_ANY) || CLASSD(in4)) { 198845916cd2Sjpk return (mlptBoth); 1989f4b3ec61Sdh155122 } 1990bd670b35SErik Nordmark ire = ire_ftable_lookup_v4(in4, 0, 0, IRE_LOCAL|IRE_LOOPBACK, 1991bd670b35SErik Nordmark NULL, ip_zoneid, NULL, MATCH_IRE_TYPE | MATCH_IRE_ZONEONLY, 1992bd670b35SErik Nordmark 0, ipst, NULL); 199345916cd2Sjpk } else { 19947b564b02SJarrett Lu if (IN6_IS_ADDR_UNSPECIFIED((const in6_addr_t *)addr) || 19957b564b02SJarrett Lu IN6_IS_ADDR_MULTICAST((const in6_addr_t *)addr)) { 199645916cd2Sjpk return (mlptBoth); 1997f4b3ec61Sdh155122 } 1998bd670b35SErik Nordmark ire = ire_ftable_lookup_v6(addr, 0, 0, IRE_LOCAL|IRE_LOOPBACK, 1999bd670b35SErik Nordmark NULL, ip_zoneid, NULL, MATCH_IRE_TYPE | MATCH_IRE_ZONEONLY, 2000bd670b35SErik Nordmark 0, ipst, NULL); 200145916cd2Sjpk } 200245916cd2Sjpk /* 200345916cd2Sjpk * If we can't find the IRE, then we have to behave exactly like 2004bd670b35SErik Nordmark * ip_laddr_verify_{v4,v6}. That means looking up the IPIF so that 2005bd670b35SErik Nordmark * users can bind to addresses on "down" interfaces. 200645916cd2Sjpk * 200745916cd2Sjpk * If we can't find that either, then the bind is going to fail, so 200845916cd2Sjpk * just give up. Note that there's a miniscule chance that the address 200945916cd2Sjpk * is in transition, but we don't bother handling that. 201045916cd2Sjpk */ 201145916cd2Sjpk if (ire == NULL) { 201245916cd2Sjpk if (version == IPV4_VERSION) 201345916cd2Sjpk ipif = ipif_lookup_addr(*(const in_addr_t *)addr, NULL, 2014bd670b35SErik Nordmark ip_zoneid, ipst); 201545916cd2Sjpk else 201645916cd2Sjpk ipif = ipif_lookup_addr_v6((const in6_addr_t *)addr, 2017bd670b35SErik Nordmark NULL, ip_zoneid, ipst); 2018f4b3ec61Sdh155122 if (ipif == NULL) { 201945916cd2Sjpk return (mlptSingle); 2020f4b3ec61Sdh155122 } 202145916cd2Sjpk addrzone = ipif->ipif_zoneid; 202245916cd2Sjpk ipif_refrele(ipif); 202345916cd2Sjpk } else { 202445916cd2Sjpk addrzone = ire->ire_zoneid; 202545916cd2Sjpk ire_refrele(ire); 202645916cd2Sjpk } 202745916cd2Sjpk return (addrzone == ALL_ZONES ? mlptShared : mlptPrivate); 202845916cd2Sjpk } 202945916cd2Sjpk 203045916cd2Sjpk /* 203145916cd2Sjpk * Since we are configuring local interfaces, and we know trusted 203245916cd2Sjpk * extension CDE requires local interfaces to be cipso host type in 203345916cd2Sjpk * order to function correctly, we'll associate a cipso template 203445916cd2Sjpk * to each local interface and let the interface come up. Configuring 203545916cd2Sjpk * a local interface to be "unlabeled" host type is a configuration error. 203645916cd2Sjpk * We'll override that error and make the interface host type to be cipso 203745916cd2Sjpk * here. 203845916cd2Sjpk * 203945916cd2Sjpk * The code is optimized for the usual "success" case and unwinds things on 204045916cd2Sjpk * error. We don't want to go to the trouble and expense of formatting the 204145916cd2Sjpk * interface name for the usual case where everything is configured correctly. 204245916cd2Sjpk */ 204345916cd2Sjpk boolean_t 204445916cd2Sjpk tsol_check_interface_address(const ipif_t *ipif) 204545916cd2Sjpk { 204645916cd2Sjpk tsol_tpc_t *tp; 204745916cd2Sjpk char addrbuf[INET6_ADDRSTRLEN]; 204845916cd2Sjpk int af; 204945916cd2Sjpk const void *addr; 205045916cd2Sjpk zone_t *zone; 205145916cd2Sjpk ts_label_t *plabel; 205245916cd2Sjpk const bslabel_t *label; 2053*e899e593SGirish Moodalbail char ifname[LIFNAMSIZ]; 205445916cd2Sjpk boolean_t retval; 205545916cd2Sjpk tsol_rhent_t rhent; 2056f4b3ec61Sdh155122 netstack_t *ns = ipif->ipif_ill->ill_ipst->ips_netstack; 205745916cd2Sjpk 205845916cd2Sjpk if (IN6_IS_ADDR_V4MAPPED(&ipif->ipif_v6lcl_addr)) { 205945916cd2Sjpk af = AF_INET; 206045916cd2Sjpk addr = &V4_PART_OF_V6(ipif->ipif_v6lcl_addr); 206145916cd2Sjpk } else { 206245916cd2Sjpk af = AF_INET6; 206345916cd2Sjpk addr = &ipif->ipif_v6lcl_addr; 206445916cd2Sjpk } 206545916cd2Sjpk 206645916cd2Sjpk tp = find_tpc(&ipif->ipif_v6lcl_addr, IPV6_VERSION, B_FALSE); 2067f4b3ec61Sdh155122 2068f4b3ec61Sdh155122 /* assumes that ALL_ZONES implies that there is no exclusive stack */ 2069f4b3ec61Sdh155122 if (ipif->ipif_zoneid == ALL_ZONES) { 2070f4b3ec61Sdh155122 zone = NULL; 2071f4b3ec61Sdh155122 } else if (ns->netstack_stackid == GLOBAL_NETSTACKID) { 2072f4b3ec61Sdh155122 /* Shared stack case */ 2073f4b3ec61Sdh155122 zone = zone_find_by_id(ipif->ipif_zoneid); 2074f4b3ec61Sdh155122 } else { 2075f4b3ec61Sdh155122 /* Exclusive stack case */ 2076f4b3ec61Sdh155122 zone = zone_find_by_id(crgetzoneid(ipif->ipif_ill->ill_credp)); 2077f4b3ec61Sdh155122 } 207845916cd2Sjpk if (zone != NULL) { 207945916cd2Sjpk plabel = zone->zone_slabel; 208045916cd2Sjpk ASSERT(plabel != NULL); 208145916cd2Sjpk label = label2bslabel(plabel); 208245916cd2Sjpk } 208345916cd2Sjpk 208445916cd2Sjpk /* 208545916cd2Sjpk * If it's CIPSO and an all-zones address, then we're done. 208645916cd2Sjpk * If it's a CIPSO zone specific address, the zone's label 208745916cd2Sjpk * must be in the range or set specified in the template. 208845916cd2Sjpk * When the remote host entry is missing or the template 208945916cd2Sjpk * type is incorrect for this interface, we create a 209045916cd2Sjpk * CIPSO host entry in kernel and allow the interface to be 209145916cd2Sjpk * brought up as CIPSO type. 209245916cd2Sjpk */ 209345916cd2Sjpk if (tp != NULL && ( 209445916cd2Sjpk /* The all-zones case */ 209545916cd2Sjpk (tp->tpc_tp.host_type == SUN_CIPSO && 209645916cd2Sjpk tp->tpc_tp.tp_doi == default_doi && 209745916cd2Sjpk ipif->ipif_zoneid == ALL_ZONES) || 209845916cd2Sjpk /* The local-zone case */ 209945916cd2Sjpk (zone != NULL && plabel->tsl_doi == tp->tpc_tp.tp_doi && 210045916cd2Sjpk ((tp->tpc_tp.host_type == SUN_CIPSO && 210145916cd2Sjpk (_blinrange(label, &tp->tpc_tp.tp_sl_range_cipso) || 210245916cd2Sjpk blinlset(label, tp->tpc_tp.tp_sl_set_cipso))))))) { 210345916cd2Sjpk if (zone != NULL) 210445916cd2Sjpk zone_rele(zone); 210545916cd2Sjpk TPC_RELE(tp); 210645916cd2Sjpk return (B_TRUE); 210745916cd2Sjpk } 210845916cd2Sjpk 2109*e899e593SGirish Moodalbail ipif_get_name(ipif, ifname, sizeof (ifname)); 211045916cd2Sjpk (void) inet_ntop(af, addr, addrbuf, sizeof (addrbuf)); 211145916cd2Sjpk 211245916cd2Sjpk if (tp == NULL) { 211345916cd2Sjpk cmn_err(CE_NOTE, "template entry for %s missing. Default to " 211445916cd2Sjpk "CIPSO type for %s", ifname, addrbuf); 211545916cd2Sjpk retval = B_TRUE; 211645916cd2Sjpk } else if (tp->tpc_tp.host_type == UNLABELED) { 211745916cd2Sjpk cmn_err(CE_NOTE, "template type for %s incorrectly configured. " 211845916cd2Sjpk "Change to CIPSO type for %s", ifname, addrbuf); 211945916cd2Sjpk retval = B_TRUE; 212045916cd2Sjpk } else if (ipif->ipif_zoneid == ALL_ZONES) { 212145916cd2Sjpk if (tp->tpc_tp.host_type != SUN_CIPSO) { 212245916cd2Sjpk cmn_err(CE_NOTE, "%s failed: %s isn't set to CIPSO for " 212345916cd2Sjpk "all-zones. Converted to CIPSO.", ifname, addrbuf); 212445916cd2Sjpk retval = B_TRUE; 212545916cd2Sjpk } else { 212645916cd2Sjpk cmn_err(CE_NOTE, "%s failed: %s has wrong DOI %d " 212745916cd2Sjpk "instead of %d", ifname, addrbuf, 212845916cd2Sjpk tp->tpc_tp.tp_doi, default_doi); 212945916cd2Sjpk retval = B_FALSE; 213045916cd2Sjpk } 213145916cd2Sjpk } else if (zone == NULL) { 213245916cd2Sjpk cmn_err(CE_NOTE, "%s failed: zoneid %d unknown", 213345916cd2Sjpk ifname, ipif->ipif_zoneid); 213445916cd2Sjpk retval = B_FALSE; 213545916cd2Sjpk } else if (plabel->tsl_doi != tp->tpc_tp.tp_doi) { 213645916cd2Sjpk cmn_err(CE_NOTE, "%s failed: zone %s has DOI %d but %s has " 213745916cd2Sjpk "DOI %d", ifname, zone->zone_name, plabel->tsl_doi, 213845916cd2Sjpk addrbuf, tp->tpc_tp.tp_doi); 213945916cd2Sjpk retval = B_FALSE; 214045916cd2Sjpk } else { 214145916cd2Sjpk cmn_err(CE_NOTE, "%s failed: zone %s label incompatible with " 214245916cd2Sjpk "%s", ifname, zone->zone_name, addrbuf); 214345916cd2Sjpk tsol_print_label(label, "zone label"); 214445916cd2Sjpk retval = B_FALSE; 214545916cd2Sjpk } 214645916cd2Sjpk 214745916cd2Sjpk if (zone != NULL) 214845916cd2Sjpk zone_rele(zone); 214945916cd2Sjpk if (tp != NULL) 215045916cd2Sjpk TPC_RELE(tp); 215145916cd2Sjpk if (retval) { 215245916cd2Sjpk /* 215345916cd2Sjpk * we've corrected a config error and let the interface 215445916cd2Sjpk * come up as cipso. Need to insert an rhent. 215545916cd2Sjpk */ 215645916cd2Sjpk if ((rhent.rh_address.ta_family = af) == AF_INET) { 215745916cd2Sjpk rhent.rh_prefix = 32; 215845916cd2Sjpk rhent.rh_address.ta_addr_v4 = *(struct in_addr *)addr; 215945916cd2Sjpk } else { 216045916cd2Sjpk rhent.rh_prefix = 128; 216145916cd2Sjpk rhent.rh_address.ta_addr_v6 = *(in6_addr_t *)addr; 216245916cd2Sjpk } 216345916cd2Sjpk (void) strcpy(rhent.rh_template, "cipso"); 216445916cd2Sjpk if (tnrh_load(&rhent) != 0) { 216545916cd2Sjpk cmn_err(CE_NOTE, "%s failed: Cannot insert CIPSO " 216645916cd2Sjpk "template for local addr %s", ifname, addrbuf); 216745916cd2Sjpk retval = B_FALSE; 216845916cd2Sjpk } 216945916cd2Sjpk } 217045916cd2Sjpk return (retval); 217145916cd2Sjpk } 2172