1 1676 jpk /* 2 1676 jpk * CDDL HEADER START 3 1676 jpk * 4 1676 jpk * The contents of this file are subject to the terms of the 5 1676 jpk * Common Development and Distribution License (the "License"). 6 1676 jpk * You may not use this file except in compliance with the License. 7 1676 jpk * 8 1676 jpk * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 1676 jpk * or http://www.opensolaris.org/os/licensing. 10 1676 jpk * See the License for the specific language governing permissions 11 1676 jpk * and limitations under the License. 12 1676 jpk * 13 1676 jpk * When distributing Covered Code, include this CDDL HEADER in each 14 1676 jpk * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 1676 jpk * If applicable, add the following below this CDDL HEADER, with the 16 1676 jpk * fields enclosed by brackets "[]" replaced with your own identifying 17 1676 jpk * information: Portions Copyright [yyyy] [name of copyright owner] 18 1676 jpk * 19 1676 jpk * CDDL HEADER END 20 1676 jpk */ 21 1676 jpk /* 22 8778 Erik * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 1676 jpk * Use is subject to license terms. 24 1676 jpk */ 25 1676 jpk 26 1676 jpk #include <sys/types.h> 27 1676 jpk #include <sys/systm.h> 28 1676 jpk #include <sys/kmem.h> 29 1676 jpk #include <sys/disp.h> 30 1676 jpk #include <sys/stream.h> 31 1676 jpk #include <sys/strsubr.h> 32 1676 jpk #include <sys/strsun.h> 33 1676 jpk #include <sys/policy.h> 34 1676 jpk #include <sys/tsol/label_macro.h> 35 1676 jpk #include <sys/tsol/tndb.h> 36 1676 jpk #include <sys/tsol/tnet.h> 37 1676 jpk #include <inet/ip.h> 38 1676 jpk #include <inet/ip6.h> 39 1676 jpk #include <inet/tcp.h> 40 1676 jpk #include <inet/ipclassifier.h> 41 1676 jpk #include <inet/ip_ire.h> 42 2535 sangeeta #include <inet/ip_ftable.h> 43 1676 jpk 44 1676 jpk /* 45 1676 jpk * This routine takes a sensitivity label as input and creates a CIPSO 46 1676 jpk * option in the specified buffer. It returns the size of the CIPSO option. 47 1676 jpk * If the sensitivity label is too large for the CIPSO option, then 0 48 1676 jpk * is returned. 49 1676 jpk * 50 1676 jpk * tsol2cipso_tt1 returns 0 for failure and greater than 0 for success 51 1676 jpk * (more accurately, success means a return value between 10 and 40). 52 1676 jpk */ 53 1676 jpk 54 1676 jpk static int 55 1676 jpk tsol2cipso_tt1(const bslabel_t *sl, unsigned char *cop, uint32_t doi) 56 1676 jpk { 57 1676 jpk struct cipso_tag_type_1 *tt1; 58 1676 jpk const _bslabel_impl_t *bsl; 59 1676 jpk const uchar_t *ucp; 60 1676 jpk int i; 61 1676 jpk 62 1676 jpk if (doi == 0) 63 1676 jpk return (0); 64 1676 jpk 65 1676 jpk /* check for Admin High sensitivity label */ 66 1676 jpk if (blequal(sl, label2bslabel(l_admin_high))) 67 1676 jpk return (0); 68 1676 jpk 69 1676 jpk /* check whether classification will fit in one octet */ 70 1676 jpk bsl = (const _bslabel_impl_t *)sl; 71 1676 jpk if (LCLASS(bsl) & 0xFF00) 72 1676 jpk return (0); 73 1676 jpk 74 1676 jpk /* 75 1676 jpk * Check whether compartments will fit in 30 octets. 76 1676 jpk * Compartments 241 - 256 are not allowed. 77 1676 jpk */ 78 1676 jpk if (ntohl(bsl->compartments.c8) & 0x0000FFFF) 79 1676 jpk return (0); 80 1676 jpk 81 1676 jpk /* 82 1676 jpk * Compute option length and tag length. 83 1676 jpk * 'p' points to the last two bytes in the Sensitivity Label's 84 1676 jpk * compartments; these cannot be mapped into CIPSO compartments. 85 1676 jpk */ 86 1676 jpk ucp = (const uchar_t *)&bsl->compartments.c8 + 2; 87 1676 jpk while (--ucp >= (const uchar_t *)&bsl->compartments.c1) 88 1676 jpk if (*ucp != 0) 89 1676 jpk break; 90 1676 jpk 91 1676 jpk i = ucp - (const uchar_t *)&bsl->compartments.c1 + 1; 92 1676 jpk 93 1676 jpk if (cop == NULL) 94 1676 jpk return (10 + i); 95 1676 jpk 96 1676 jpk doi = htonl(doi); 97 1676 jpk ucp = (const uchar_t *)&doi; 98 1676 jpk cop[IPOPT_OPTVAL] = IPOPT_COMSEC; 99 1676 jpk cop[IPOPT_OLEN] = 10 + i; 100 1676 jpk cop[IPOPT_OLEN+1] = ucp[0]; 101 1676 jpk cop[IPOPT_OLEN+2] = ucp[1]; 102 1676 jpk cop[IPOPT_OLEN+3] = ucp[2]; 103 1676 jpk cop[IPOPT_OLEN+4] = ucp[3]; 104 1676 jpk tt1 = (struct cipso_tag_type_1 *)&cop[IPOPT_OLEN + 5]; 105 1676 jpk tt1->tag_type = 1; 106 1676 jpk tt1->tag_align = 0; 107 1676 jpk tt1->tag_sl = LCLASS(bsl); 108 1676 jpk tt1->tag_length = 4 + i; 109 1676 jpk 110 1676 jpk bcopy(&bsl->compartments.c1, tt1->tag_cat, i); 111 1676 jpk 112 1676 jpk return (cop[IPOPT_OLEN]); 113 1676 jpk } 114 1676 jpk 115 1676 jpk /* 116 10181 Ken * The following routine searches for a security label in an IPv4 datagram. 117 10181 Ken * It returns label_type of: 118 10181 Ken * OPT_CIPSO if a CIPSO IP option is found. 119 10181 Ken * OPT_NONE if no security label is found. 120 1676 jpk * 121 10181 Ken * If OPT_CIPSO, a pointer to the CIPSO IP option will be returned in 122 10181 Ken * the buffer parameter. 123 10181 Ken * 124 10181 Ken * The function will return with B_FALSE if an IP format error 125 10181 Ken * is encountered. 126 1676 jpk */ 127 1676 jpk 128 10181 Ken boolean_t 129 10181 Ken tsol_get_option_v4(mblk_t *mp, tsol_ip_label_t *label_type, uchar_t **buffer) 130 1676 jpk { 131 1676 jpk ipha_t *ipha; 132 1676 jpk uchar_t *opt; 133 1676 jpk uint32_t totallen; 134 1676 jpk uint32_t optval; 135 1676 jpk uint32_t optlen; 136 1676 jpk 137 10181 Ken *label_type = OPT_NONE; 138 1676 jpk 139 1676 jpk /* 140 1676 jpk * Get length (in 4 byte octets) of IP header options. 141 10181 Ken * If header doesn't contain options, then return a label_type 142 10181 Ken * of OPT_NONE. 143 1676 jpk */ 144 10181 Ken ipha = (ipha_t *)mp->b_rptr; 145 1676 jpk totallen = ipha->ipha_version_and_hdr_length - 146 10181 Ken (uint8_t)((IP_VERSION << 4)); 147 10181 Ken totallen <<= 2; 148 10181 Ken if (totallen < IP_SIMPLE_HDR_LENGTH || totallen > MBLKL(mp)) 149 10181 Ken return (B_FALSE); 150 10181 Ken totallen -= IP_SIMPLE_HDR_LENGTH; 151 1676 jpk if (totallen == 0) 152 10181 Ken return (B_TRUE); 153 1676 jpk 154 1676 jpk /* 155 1676 jpk * Search for CIPSO option. 156 1676 jpk * If no such option is present, then return OPT_NONE. 157 1676 jpk */ 158 1676 jpk opt = (uchar_t *)&ipha[1]; 159 1676 jpk while (totallen != 0) { 160 1676 jpk switch (optval = opt[IPOPT_OPTVAL]) { 161 1676 jpk case IPOPT_EOL: 162 10181 Ken return (B_TRUE); 163 1676 jpk case IPOPT_NOP: 164 1676 jpk optlen = 1; 165 1676 jpk break; 166 1676 jpk default: 167 1676 jpk if (totallen <= IPOPT_OLEN) 168 10181 Ken return (B_FALSE); 169 1676 jpk optlen = opt[IPOPT_OLEN]; 170 1676 jpk if (optlen < 2) 171 10181 Ken return (B_FALSE); 172 1676 jpk } 173 1676 jpk if (optlen > totallen) 174 10181 Ken return (B_FALSE); 175 1676 jpk /* 176 1676 jpk * Copy pointer to option into '*buffer' and 177 1676 jpk * return the option type. 178 1676 jpk */ 179 1676 jpk switch (optval) { 180 1676 jpk case IPOPT_COMSEC: 181 1676 jpk if (TSOL_CIPSO_TAG_OFFSET < optlen && 182 10181 Ken opt[TSOL_CIPSO_TAG_OFFSET] == 1) { 183 10181 Ken *label_type = OPT_CIPSO; 184 10181 Ken *buffer = opt; 185 10181 Ken return (B_TRUE); 186 10181 Ken } 187 10181 Ken return (B_FALSE); 188 1676 jpk } 189 1676 jpk totallen -= optlen; 190 1676 jpk opt += optlen; 191 1676 jpk } 192 10181 Ken return (B_TRUE); 193 10181 Ken } 194 10181 Ken 195 10181 Ken /* 196 10181 Ken * The following routine searches for a security label in an IPv6 datagram. 197 10181 Ken * It returns label_type of: 198 10181 Ken * OPT_CIPSO if a CIPSO IP option is found. 199 10181 Ken * OPT_NONE if no security label is found. 200 10181 Ken * 201 10181 Ken * If OPT_CIPSO, a pointer to the IPv4 portion of the CIPSO IP option will 202 10181 Ken * be returned in the buffer parameter. 203 10181 Ken * 204 10181 Ken * The function will return with B_FALSE if an IP format error 205 10181 Ken * or an unexpected label content error is encountered. 206 10181 Ken */ 207 10181 Ken 208 10181 Ken boolean_t 209 10181 Ken tsol_get_option_v6(mblk_t *mp, tsol_ip_label_t *label_type, uchar_t **buffer) 210 10181 Ken { 211 10181 Ken uchar_t *opt_ptr = NULL; 212 10181 Ken uchar_t *after_secopt; 213 10181 Ken boolean_t hbh_needed; 214 10181 Ken const uchar_t *ip6hbh; 215 10181 Ken size_t optlen; 216 10181 Ken uint32_t doi; 217 10181 Ken const ip6_t *ip6h; 218 10181 Ken 219 10181 Ken *label_type = OPT_NONE; 220 10181 Ken *buffer = NULL; 221 10181 Ken ip6h = (const ip6_t *)mp->b_rptr; 222 10181 Ken if (ip6h->ip6_nxt != IPPROTO_HOPOPTS) 223 10181 Ken return (B_TRUE); 224 10181 Ken ip6hbh = (const uchar_t *)&ip6h[1]; 225 10181 Ken if (ip6hbh + MIN_EHDR_LEN > mp->b_wptr) 226 10181 Ken return (B_FALSE); 227 10181 Ken optlen = (ip6hbh[1] + 1) << 3; 228 10181 Ken if (ip6hbh + optlen > mp->b_wptr) 229 10181 Ken return (B_FALSE); 230 10181 Ken if (!tsol_find_secopt_v6(ip6hbh, optlen, 231 10181 Ken &opt_ptr, &after_secopt, &hbh_needed)) 232 10181 Ken return (B_FALSE); 233 10181 Ken /* tsol_find_secopt_v6 guarantees some sanity */ 234 10181 Ken if (opt_ptr != NULL) { 235 10181 Ken /* 236 10181 Ken * IPv6 Option 237 10181 Ken * opt_ptr[0]: Option type 238 10181 Ken * opt_ptr[1]: Length of option data in bytes 239 10181 Ken * opt_ptr[2]: First byte of option data 240 10181 Ken */ 241 10181 Ken if ((optlen = opt_ptr[1]) < 8) 242 10181 Ken return (B_FALSE); 243 10181 Ken opt_ptr += 2; 244 10181 Ken /* 245 10181 Ken * From "Generalized Labeled Security Option for IPv6" draft 246 10181 Ken * opt_ptr[0] - opt_ptr[4]: DOI = IP6LS_DOI_V4 247 10181 Ken * opt_ptr[4]: Tag type = IP6LS_TT_V4 248 10181 Ken * opt_ptr[5]: Tag length in bytes starting at Tag type field 249 10181 Ken * IPv4 CIPSO Option 250 10181 Ken * opt_ptr[6]: option type 251 10181 Ken * opt_ptr[7]: option length in bytes starting at type field 252 10181 Ken */ 253 10181 Ken bcopy(opt_ptr, &doi, sizeof (doi)); 254 10181 Ken doi = ntohl(doi); 255 10181 Ken if (doi == IP6LS_DOI_V4 && 256 10181 Ken opt_ptr[4] == IP6LS_TT_V4 && 257 10181 Ken opt_ptr[5] <= optlen - 4 && 258 10181 Ken opt_ptr[7] <= optlen - 6 && 259 10181 Ken opt_ptr[7] <= opt_ptr[5] - 2) { 260 10181 Ken opt_ptr += sizeof (doi) + 2; 261 10181 Ken *label_type = OPT_CIPSO; 262 10181 Ken *buffer = opt_ptr; 263 10181 Ken return (B_TRUE); 264 10181 Ken } 265 10181 Ken return (B_FALSE); 266 10181 Ken } 267 10181 Ken return (B_TRUE); 268 1676 jpk } 269 1676 jpk 270 1676 jpk /* 271 9710 Ken * tsol_check_dest() 272 9710 Ken * 273 9710 Ken * This routine verifies if a destination is allowed to recieve messages 274 11042 Erik * based on the security label. If any adjustments to the label are needed 275 11042 Erik * due to the connection's MAC mode or the destination's ability 276 11042 Erik * to receive labels, an "effective label" will be returned. 277 9710 Ken * 278 11042 Erik * zone_is_global is set if the actual zoneid is global. That is, it is 279 11042 Erik * not set for an exclusive-IP zone. 280 11042 Erik * 281 11042 Erik * On successful return, effective_tsl will point to the new label needed 282 11042 Erik * or will be NULL if a new label isn't needed. On error, effective_tsl will 283 11042 Erik * point to NULL. 284 9710 Ken * 285 9710 Ken * Returns: 286 11042 Erik * 0 Label (was|is now) correct 287 11042 Erik * EHOSTUNREACH The label failed the remote host accreditation 288 9710 Ken * ENOMEM Memory allocation failure 289 9710 Ken */ 290 9710 Ken int 291 11042 Erik tsol_check_dest(const ts_label_t *tsl, const void *dst, 292 11042 Erik uchar_t version, uint_t mac_mode, boolean_t zone_is_global, 293 11042 Erik ts_label_t **effective_tsl) 294 9710 Ken { 295 11042 Erik ts_label_t *newtsl = NULL; 296 9710 Ken tsol_tpc_t *dst_rhtp; 297 9710 Ken 298 11042 Erik if (effective_tsl != NULL) 299 11042 Erik *effective_tsl = NULL; 300 9710 Ken ASSERT(version == IPV4_VERSION || 301 9710 Ken (version == IPV6_VERSION && 302 9710 Ken !IN6_IS_ADDR_V4MAPPED((in6_addr_t *)dst))); 303 9710 Ken 304 9710 Ken /* Always pass kernel level communication (NULL label) */ 305 11042 Erik if (tsl == NULL) { 306 9710 Ken DTRACE_PROBE2(tx__tnopt__log__info__labeling__mac__allownull, 307 11042 Erik char *, "destination ip(1) with null label was passed", 308 9710 Ken ipaddr_t, dst); 309 9710 Ken return (0); 310 10934 sommerfeld } 311 10934 sommerfeld 312 10934 sommerfeld if (tsl->tsl_flags & TSLF_IMPLICIT_IN) { 313 10934 sommerfeld DTRACE_PROBE3(tx__tnopt__log__info__labeling__unresolved__label, 314 10934 sommerfeld char *, 315 10934 sommerfeld "implicit-in packet to ip(1) reached tsol_check_dest " 316 10934 sommerfeld "with implied security label sl(2)", 317 10934 sommerfeld ipaddr_t, dst, ts_label_t *, tsl); 318 9710 Ken } 319 9710 Ken 320 9710 Ken /* Always pass multicast */ 321 9710 Ken if (version == IPV4_VERSION && 322 9710 Ken CLASSD(*(ipaddr_t *)dst)) { 323 9710 Ken DTRACE_PROBE2(tx__tnopt__log__info__labeling__mac__allowmult, 324 9710 Ken char *, "destination ip(1) with multicast dest was passed", 325 9710 Ken ipaddr_t, dst); 326 9710 Ken return (0); 327 9710 Ken } else if (version == IPV6_VERSION && 328 9710 Ken IN6_IS_ADDR_MULTICAST((in6_addr_t *)dst)) { 329 9710 Ken DTRACE_PROBE2(tx__tnopt__log__info__labeling__mac__allowmult_v6, 330 9710 Ken char *, "destination ip(1) with multicast dest was passed", 331 9710 Ken in6_addr_t *, dst); 332 9710 Ken return (0); 333 9710 Ken } 334 9710 Ken 335 9710 Ken /* Never pass an undefined destination */ 336 9710 Ken if ((dst_rhtp = find_tpc(dst, version, B_FALSE)) == NULL) { 337 9710 Ken DTRACE_PROBE2(tx__tnopt__log__info__labeling__lookupdst, 338 9710 Ken char *, "destination ip(1) not in tn database.", 339 9710 Ken void *, dst); 340 9710 Ken return (EHOSTUNREACH); 341 9710 Ken } 342 9710 Ken 343 9710 Ken switch (dst_rhtp->tpc_tp.host_type) { 344 9710 Ken case UNLABELED: 345 9710 Ken /* 346 9710 Ken * Can talk to unlabeled hosts if 347 9710 Ken * (1) zone's label matches the default label, or 348 10934 sommerfeld * (2) SO_MAC_EXEMPT is on and we 349 10934 sommerfeld * dominate the peer's label, or 350 10934 sommerfeld * (3) SO_MAC_EXEMPT is on and 351 10934 sommerfeld * this is the global zone 352 9710 Ken */ 353 9710 Ken if (dst_rhtp->tpc_tp.tp_doi != tsl->tsl_doi) { 354 10181 Ken DTRACE_PROBE4(tx__tnopt__log__info__labeling__doi, 355 9710 Ken char *, "unlabeled dest ip(1)/tpc(2) doi does " 356 9710 Ken "not match msg label(3) doi.", void *, dst, 357 9710 Ken tsol_tpc_t *, dst_rhtp, ts_label_t *, tsl); 358 9710 Ken TPC_RELE(dst_rhtp); 359 9710 Ken return (EHOSTUNREACH); 360 9710 Ken } 361 9710 Ken if (!blequal(&dst_rhtp->tpc_tp.tp_def_label, 362 9710 Ken &tsl->tsl_label)) { 363 10934 sommerfeld if (mac_mode != CONN_MAC_AWARE || 364 11042 Erik !(zone_is_global || 365 9710 Ken bldominates(&tsl->tsl_label, 366 9710 Ken &dst_rhtp->tpc_tp.tp_def_label))) { 367 9710 Ken DTRACE_PROBE4( 368 9710 Ken tx__tnopt__log__info__labeling__mac, 369 9710 Ken char *, "unlabeled dest ip(1)/tpc(2) does " 370 9710 Ken "not match msg label(3).", void *, dst, 371 9710 Ken tsol_tpc_t *, dst_rhtp, ts_label_t *, tsl); 372 9710 Ken TPC_RELE(dst_rhtp); 373 9710 Ken return (EHOSTUNREACH); 374 9710 Ken } 375 9710 Ken /* 376 9710 Ken * This is a downlabel MAC-exempt exchange. 377 9710 Ken * Use the remote destination's default label 378 9710 Ken * as the label of the message data. 379 9710 Ken */ 380 9710 Ken if ((newtsl = labelalloc(&dst_rhtp->tpc_tp.tp_def_label, 381 9710 Ken dst_rhtp->tpc_tp.tp_doi, KM_NOSLEEP)) == NULL) { 382 9710 Ken TPC_RELE(dst_rhtp); 383 9710 Ken return (ENOMEM); 384 9710 Ken } 385 9710 Ken newtsl->tsl_flags |= TSLF_UNLABELED; 386 9710 Ken 387 9710 Ken } else if (!(tsl->tsl_flags & TSLF_UNLABELED)) { 388 9710 Ken /* 389 9710 Ken * The security labels are the same but we need 390 9710 Ken * to flag that the remote node is unlabeled. 391 9710 Ken */ 392 9710 Ken if ((newtsl = labeldup(tsl, KM_NOSLEEP)) == NULL) { 393 9710 Ken TPC_RELE(dst_rhtp); 394 9710 Ken return (ENOMEM); 395 9710 Ken } 396 9710 Ken newtsl->tsl_flags |= TSLF_UNLABELED; 397 9710 Ken } 398 9710 Ken break; 399 9710 Ken 400 9710 Ken case SUN_CIPSO: 401 9710 Ken /* 402 9710 Ken * Can talk to labeled hosts if zone's label is within target's 403 9710 Ken * label range or set. 404 9710 Ken */ 405 9710 Ken if (dst_rhtp->tpc_tp.tp_cipso_doi_cipso != tsl->tsl_doi || 406 9710 Ken (!_blinrange(&tsl->tsl_label, 407 9710 Ken &dst_rhtp->tpc_tp.tp_sl_range_cipso) && 408 9710 Ken !blinlset(&tsl->tsl_label, 409 9710 Ken dst_rhtp->tpc_tp.tp_sl_set_cipso))) { 410 9710 Ken DTRACE_PROBE4(tx__tnopt__log__info__labeling__mac, 411 9710 Ken char *, "labeled dest ip(1)/tpc(2) does not " 412 9710 Ken "match msg label(3).", void *, dst, 413 9710 Ken tsol_tpc_t *, dst_rhtp, ts_label_t *, tsl); 414 9710 Ken TPC_RELE(dst_rhtp); 415 9710 Ken return (EHOSTUNREACH); 416 9710 Ken } 417 10934 sommerfeld if ((tsl->tsl_flags & TSLF_UNLABELED) || 418 10934 sommerfeld (mac_mode == CONN_MAC_IMPLICIT)) { 419 9710 Ken /* 420 10934 sommerfeld * Copy label so we can modify the flags 421 9710 Ken */ 422 9710 Ken if ((newtsl = labeldup(tsl, KM_NOSLEEP)) == NULL) { 423 9710 Ken TPC_RELE(dst_rhtp); 424 9710 Ken return (ENOMEM); 425 9710 Ken } 426 10934 sommerfeld /* 427 10934 sommerfeld * The security label is a match but we need to 428 10934 sommerfeld * clear the unlabeled flag for this remote node. 429 10934 sommerfeld */ 430 10934 sommerfeld newtsl->tsl_flags &= ~TSLF_UNLABELED; 431 10934 sommerfeld if (mac_mode == CONN_MAC_IMPLICIT) 432 10934 sommerfeld newtsl->tsl_flags |= TSLF_IMPLICIT_OUT; 433 9710 Ken } 434 9710 Ken break; 435 9710 Ken 436 9710 Ken default: 437 9710 Ken TPC_RELE(dst_rhtp); 438 9710 Ken return (EHOSTUNREACH); 439 9710 Ken } 440 9710 Ken 441 9710 Ken /* 442 11042 Erik * Return the new label. 443 9710 Ken */ 444 9710 Ken if (newtsl != NULL) { 445 11042 Erik if (effective_tsl != NULL) 446 11042 Erik *effective_tsl = newtsl; 447 11042 Erik else 448 11042 Erik label_rele(newtsl); 449 9710 Ken } 450 9710 Ken TPC_RELE(dst_rhtp); 451 9710 Ken return (0); 452 9710 Ken } 453 9710 Ken 454 9710 Ken /* 455 11042 Erik * tsol_compute_label_v4() 456 1676 jpk * 457 1676 jpk * This routine computes the IP label that should be on a packet based on the 458 1676 jpk * connection and destination information. 459 11042 Erik * 460 11042 Erik * The zoneid is the IP zoneid (i.e., GLOBAL_ZONEID for exlusive-IP zones). 461 1676 jpk * 462 1676 jpk * Returns: 463 1676 jpk * 0 Fetched label 464 9710 Ken * EHOSTUNREACH No route to destination 465 1676 jpk * EINVAL Label cannot be computed 466 1676 jpk */ 467 1676 jpk int 468 11042 Erik tsol_compute_label_v4(const ts_label_t *tsl, zoneid_t zoneid, ipaddr_t dst, 469 11042 Erik uchar_t *opt_storage, ip_stack_t *ipst) 470 1676 jpk { 471 1676 jpk uint_t sec_opt_len; 472 11042 Erik ire_t *ire; 473 11042 Erik tsol_ire_gw_secattr_t *attrp = NULL; 474 1676 jpk 475 1676 jpk if (opt_storage != NULL) 476 1676 jpk opt_storage[IPOPT_OLEN] = 0; 477 1676 jpk 478 11042 Erik if (tsl == NULL) 479 1676 jpk return (0); 480 1676 jpk 481 1676 jpk /* always pass multicast */ 482 1676 jpk if (CLASSD(dst)) 483 10934 sommerfeld return (0); 484 10934 sommerfeld 485 10934 sommerfeld if (tsl->tsl_flags & TSLF_IMPLICIT_OUT) 486 1676 jpk return (0); 487 1676 jpk 488 9710 Ken if (tsl->tsl_flags & TSLF_UNLABELED) { 489 9710 Ken /* 490 9710 Ken * The destination is unlabeled. Only add a label if the 491 9710 Ken * destination is not a broadcast/local/loopback address, 492 9710 Ken * the destination is not on the same subnet, and the 493 9710 Ken * next-hop gateway is labeled. 494 9710 Ken */ 495 11042 Erik ire = ire_route_recursive_v4(dst, 0, NULL, zoneid, tsl, 496 11042 Erik MATCH_IRE_SECATTR, B_TRUE, 0, ipst, NULL, &attrp, NULL); 497 11042 Erik ASSERT(ire != NULL); 498 11042 Erik if (ire->ire_flags & (RTF_REJECT|RTF_BLACKHOLE)) { 499 11042 Erik /* no route to destination */ 500 11042 Erik ire_refrele(ire); 501 9710 Ken DTRACE_PROBE3( 502 1676 jpk tx__tnopt__log__info__labeling__routedst__v4, 503 9710 Ken char *, "No route to unlabeled dest ip(1) with " 504 11042 Erik "with label(2).", ipaddr_t, dst, ts_label_t *, tsl); 505 9710 Ken return (EHOSTUNREACH); 506 11042 Erik } 507 11042 Erik if (ire->ire_type & (IRE_BROADCAST | IRE_LOCAL | IRE_LOOPBACK | 508 11042 Erik IRE_INTERFACE)) { 509 11042 Erik ire_refrele(ire); 510 11042 Erik return (0); 511 1676 jpk } 512 1676 jpk 513 1676 jpk /* 514 11042 Erik * ire_route_recursive gives us the first attrp it finds 515 11042 Erik * in the recursive lookup. 516 1676 jpk */ 517 9710 Ken /* 518 9710 Ken * Return now if next hop gateway is unlabeled. There is 519 9710 Ken * no need to generate a CIPSO option for this message. 520 9710 Ken */ 521 9710 Ken if (attrp == NULL || attrp->igsa_rhc == NULL || 522 9710 Ken attrp->igsa_rhc->rhc_tpc->tpc_tp.host_type == UNLABELED) { 523 11042 Erik ire_refrele(ire); 524 9710 Ken return (0); 525 1676 jpk } 526 11042 Erik ire_refrele(ire); 527 1676 jpk } 528 1676 jpk 529 1676 jpk /* compute the CIPSO option */ 530 9710 Ken sec_opt_len = tsol2cipso_tt1(&tsl->tsl_label, opt_storage, 531 9710 Ken tsl->tsl_doi); 532 1676 jpk 533 1676 jpk if (sec_opt_len == 0) { 534 9710 Ken DTRACE_PROBE3(tx__tnopt__log__error__labeling__lostops__v4, 535 11042 Erik char *, "options lack length for dest ip(1) with label(2).", 536 11042 Erik ipaddr_t, dst, ts_label_t *, tsl); 537 1676 jpk return (EINVAL); 538 1676 jpk } 539 1676 jpk 540 1676 jpk return (0); 541 1676 jpk } 542 1676 jpk 543 1676 jpk /* 544 1676 jpk * Remove any existing security option (CIPSO) from the given IP 545 1676 jpk * header, move the 'buflen' bytes back to fill the gap, and return the number 546 1676 jpk * of bytes removed (as zero or negative number). Assumes that the headers are 547 1676 jpk * sane. 548 11042 Erik * 549 11042 Erik * Note that tsol_remove_secopt does not adjust ipha_length but 550 11042 Erik * tsol_remove_secopt_v6 does adjust ip6_plen. 551 1676 jpk */ 552 1676 jpk int 553 1676 jpk tsol_remove_secopt(ipha_t *ipha, int buflen) 554 1676 jpk { 555 1676 jpk int remlen, olen, oval, delta; 556 1676 jpk uchar_t *fptr, *tptr; 557 1676 jpk boolean_t noop_keep; 558 1676 jpk 559 1676 jpk remlen = IPH_HDR_LENGTH(ipha) - IP_SIMPLE_HDR_LENGTH; 560 1676 jpk fptr = tptr = (uchar_t *)(ipha + 1); 561 1676 jpk noop_keep = B_TRUE; 562 1676 jpk while (remlen > 0) { 563 1676 jpk oval = fptr[IPOPT_OPTVAL]; 564 1676 jpk 565 1676 jpk /* terminate on end of list */ 566 1676 jpk if (oval == IPOPT_EOL) 567 1676 jpk break; 568 1676 jpk 569 1676 jpk /* 570 1676 jpk * Delete any no-ops following a deleted option, at least up 571 1676 jpk * to a 4 octet alignment; copy others. 572 1676 jpk */ 573 1676 jpk if (oval == IPOPT_NOP) { 574 1676 jpk if (((fptr - (uchar_t *)ipha) & 3) == 0) 575 1676 jpk noop_keep = B_TRUE; 576 1676 jpk if (noop_keep) 577 1676 jpk *tptr++ = oval; 578 1676 jpk fptr++; 579 1676 jpk remlen--; 580 1676 jpk continue; 581 1676 jpk } 582 1676 jpk 583 1676 jpk /* stop on corrupted list; just do nothing. */ 584 1676 jpk if (remlen < 2) 585 1676 jpk return (0); 586 1676 jpk olen = fptr[IPOPT_OLEN]; 587 1676 jpk if (olen < 2 || olen > remlen) 588 1676 jpk return (0); 589 1676 jpk 590 1676 jpk /* skip over security options to delete them */ 591 1676 jpk if (oval == IPOPT_COMSEC || oval == IPOPT_SECURITY) { 592 1676 jpk noop_keep = B_FALSE; 593 1676 jpk fptr += olen; 594 1676 jpk remlen -= olen; 595 1676 jpk continue; 596 1676 jpk } 597 1676 jpk 598 1676 jpk /* copy the rest */ 599 1676 jpk noop_keep = B_TRUE; 600 1676 jpk if (tptr != fptr) 601 1676 jpk ovbcopy(fptr, tptr, olen); 602 1676 jpk fptr += olen; 603 1676 jpk tptr += olen; 604 1676 jpk remlen -= olen; 605 1676 jpk } 606 1676 jpk 607 1676 jpk fptr += remlen; 608 1676 jpk 609 1676 jpk /* figure how much padding we'll need for header alignment */ 610 1676 jpk olen = (tptr - (uchar_t *)ipha) & 3; 611 1676 jpk if (olen > 0) { 612 1676 jpk olen = 4 - olen; 613 1676 jpk /* pad with end-of-list */ 614 1676 jpk bzero(tptr, olen); 615 1676 jpk tptr += olen; 616 1676 jpk } 617 1676 jpk 618 1676 jpk /* slide back the headers that follow and update the IP header */ 619 1676 jpk delta = fptr - tptr; 620 1676 jpk if (delta != 0) { 621 1676 jpk ovbcopy(fptr, tptr, ((uchar_t *)ipha + buflen) - fptr); 622 1676 jpk ipha->ipha_version_and_hdr_length -= delta / 4; 623 1676 jpk } 624 1676 jpk return (-delta); 625 1676 jpk } 626 1676 jpk 627 1676 jpk /* 628 1676 jpk * Insert the option in 'optbuf' into the IP header pointed to by 'ipha', and 629 1676 jpk * move the data following the IP header (up to buflen) to accomodate the new 630 1676 jpk * option. Assumes that up to IP_MAX_OPT_LENGTH bytes are available (in total) 631 1676 jpk * for IP options. Returns the number of bytes actually inserted, or -1 if the 632 1676 jpk * option cannot be inserted. (Note that negative return values are possible 633 1676 jpk * when noops must be compressed, and that only -1 indicates error. Successful 634 1676 jpk * return value is always evenly divisible by 4, by definition.) 635 11042 Erik * 636 11042 Erik * Note that tsol_prepend_option does not adjust ipha_length but 637 11042 Erik * tsol_prepend_option_v6 does adjust ip6_plen. 638 1676 jpk */ 639 1676 jpk int 640 1676 jpk tsol_prepend_option(uchar_t *optbuf, ipha_t *ipha, int buflen) 641 1676 jpk { 642 1676 jpk int remlen, padding, lastpad, totlen; 643 1676 jpk int oval, olen; 644 1676 jpk int delta; 645 1676 jpk uchar_t *optr; 646 1676 jpk uchar_t tempopt[IP_MAX_OPT_LENGTH], *toptr; 647 1676 jpk 648 1676 jpk if (optbuf[IPOPT_OPTVAL] == IPOPT_EOL || 649 1676 jpk optbuf[IPOPT_OPTVAL] == IPOPT_NOP || 650 1676 jpk optbuf[IPOPT_OLEN] == 0) 651 1676 jpk return (0); 652 1676 jpk 653 1676 jpk ASSERT(optbuf[IPOPT_OLEN] >= 2 && 654 1676 jpk optbuf[IPOPT_OLEN] <= IP_MAX_OPT_LENGTH); 655 1676 jpk 656 1676 jpk /* first find the real (unpadded) length of the existing options */ 657 1676 jpk remlen = IPH_HDR_LENGTH(ipha) - IP_SIMPLE_HDR_LENGTH; 658 1676 jpk padding = totlen = lastpad = 0; 659 1676 jpk optr = (uchar_t *)(ipha + 1); 660 1676 jpk while (remlen > 0) { 661 1676 jpk oval = optr[IPOPT_OPTVAL]; 662 1676 jpk 663 1676 jpk /* stop at end of list */ 664 1676 jpk if (oval == IPOPT_EOL) 665 1676 jpk break; 666 1676 jpk 667 1676 jpk /* skip no-ops, noting that length byte isn't present */ 668 1676 jpk if (oval == IPOPT_NOP) { 669 1676 jpk optr++; 670 1676 jpk padding++; 671 1676 jpk lastpad++; 672 1676 jpk totlen++; 673 1676 jpk remlen--; 674 1676 jpk continue; 675 1676 jpk } 676 1676 jpk 677 1676 jpk /* give up on a corrupted list; report failure */ 678 1676 jpk if (remlen < 2) 679 1676 jpk return (-1); 680 1676 jpk olen = optr[IPOPT_OLEN]; 681 1676 jpk if (olen < 2 || olen > remlen) 682 1676 jpk return (-1); 683 1676 jpk 684 1676 jpk lastpad = 0; 685 1676 jpk optr += olen; 686 1676 jpk totlen += olen; 687 1676 jpk remlen -= olen; 688 1676 jpk } 689 1676 jpk 690 1676 jpk /* completely ignore any trailing padding */ 691 1676 jpk totlen -= lastpad; 692 1676 jpk padding -= lastpad; 693 1676 jpk 694 1676 jpk /* 695 1676 jpk * If some sort of inter-option alignment was present, try to preserve 696 1676 jpk * that alignment. If alignment pushes us out past the maximum, then 697 1676 jpk * discard it and try to compress to fit. (We just "assume" that any 698 1676 jpk * padding added was attempting to get 32 bit alignment. If that's 699 1676 jpk * wrong, that's just too bad.) 700 1676 jpk */ 701 1676 jpk if (padding > 0) { 702 1676 jpk olen = (optbuf[IPOPT_OLEN] + 3) & ~3; 703 1676 jpk if (olen + totlen > IP_MAX_OPT_LENGTH) { 704 1676 jpk totlen -= padding; 705 1676 jpk if (olen + totlen > IP_MAX_OPT_LENGTH) 706 1676 jpk return (-1); 707 1676 jpk padding = 0; 708 1676 jpk } 709 1676 jpk } 710 1676 jpk 711 1676 jpk /* 712 1676 jpk * Since we may need to compress or expand the option list, we write to 713 1676 jpk * a temporary buffer and then copy the results back to the IP header. 714 1676 jpk */ 715 1676 jpk toptr = tempopt; 716 1676 jpk 717 1676 jpk /* compute actual option to insert */ 718 1676 jpk olen = optbuf[IPOPT_OLEN]; 719 1676 jpk bcopy(optbuf, toptr, olen); 720 1676 jpk toptr += olen; 721 1676 jpk if (padding > 0) { 722 1676 jpk while ((olen & 3) != 0) { 723 1676 jpk *toptr++ = IPOPT_NOP; 724 1676 jpk olen++; 725 1676 jpk } 726 1676 jpk } 727 1676 jpk 728 1676 jpk /* copy over the existing options */ 729 1676 jpk optr = (uchar_t *)(ipha + 1); 730 1676 jpk while (totlen > 0) { 731 1676 jpk oval = optr[IPOPT_OPTVAL]; 732 1676 jpk 733 1676 jpk /* totlen doesn't include end-of-list marker */ 734 1676 jpk ASSERT(oval != IPOPT_EOL); 735 1676 jpk 736 1676 jpk /* handle no-ops; copy if desired, ignore otherwise */ 737 1676 jpk if (oval == IPOPT_NOP) { 738 1676 jpk if (padding > 0) { 739 1676 jpk /* note: cannot overflow due to checks above */ 740 1676 jpk ASSERT(toptr < tempopt + IP_MAX_OPT_LENGTH); 741 1676 jpk *toptr++ = oval; 742 1676 jpk } 743 1676 jpk optr++; 744 1676 jpk totlen--; 745 1676 jpk continue; 746 1676 jpk } 747 1676 jpk 748 1676 jpk /* list cannot be corrupt at this point */ 749 1676 jpk ASSERT(totlen >= 2); 750 1676 jpk olen = optr[IPOPT_OLEN]; 751 1676 jpk ASSERT(olen >= 2 && olen <= totlen); 752 1676 jpk 753 1676 jpk /* cannot run out of room due to tests above */ 754 1676 jpk ASSERT(toptr + olen <= tempopt + IP_MAX_OPT_LENGTH); 755 1676 jpk 756 1676 jpk bcopy(optr, toptr, olen); 757 1676 jpk optr += olen; 758 1676 jpk toptr += olen; 759 1676 jpk totlen -= olen; 760 1676 jpk } 761 1676 jpk 762 1676 jpk /* figure how much padding we'll need for header alignment */ 763 1676 jpk olen = (toptr - tempopt) & 3; 764 1676 jpk if (olen > 0) { 765 1676 jpk olen = 4 - olen; 766 1676 jpk ASSERT(toptr + olen <= tempopt + IP_MAX_OPT_LENGTH); 767 1676 jpk /* pad with end-of-list value */ 768 1676 jpk bzero(toptr, olen); 769 1676 jpk toptr += olen; 770 1676 jpk } 771 1676 jpk 772 1676 jpk /* move the headers as needed and update IP header */ 773 1676 jpk olen = (toptr - tempopt) + IP_SIMPLE_HDR_LENGTH; 774 1676 jpk remlen = IPH_HDR_LENGTH(ipha); 775 1676 jpk delta = olen - remlen; 776 1676 jpk if (delta != 0) { 777 1676 jpk ovbcopy((uchar_t *)ipha + remlen, (uchar_t *)ipha + olen, 778 1676 jpk buflen - remlen); 779 1676 jpk ipha->ipha_version_and_hdr_length += delta / 4; 780 1676 jpk } 781 1676 jpk 782 1676 jpk /* slap in the new options */ 783 1676 jpk bcopy(tempopt, ipha + 1, olen - IP_SIMPLE_HDR_LENGTH); 784 1676 jpk 785 1676 jpk return (delta); 786 1676 jpk } 787 1676 jpk 788 1676 jpk /* 789 11042 Erik * tsol_check_label_v4() 790 1676 jpk * 791 1676 jpk * This routine computes the IP label that should be on the packet based on the 792 11042 Erik * connection and destination information. It's called by the IP forwarding 793 11042 Erik * logic and by ip_output_simple. The ULPs generate the labels before calling 794 11042 Erik * conn_ip_output. If any adjustments to 795 11042 Erik * the label are needed due to the connection's MAC-exempt status or 796 11042 Erik * the destination's ability to receive labels, an "effective label" 797 11042 Erik * will be returned. 798 1676 jpk * 799 6596 kp158701 * The packet's header is clear before entering IPsec's engine. 800 1676 jpk * 801 11042 Erik * The zoneid is the IP zoneid (i.e., GLOBAL_ZONEID for exlusive-IP zones). 802 11042 Erik * zone_is_global is set if the actual zoneid is global. 803 11042 Erik * 804 11042 Erik * On successful return, effective_tslp will point to the new label needed 805 11042 Erik * or will be NULL if a new label isn't needed. On error, effective_tsl will 806 11042 Erik * point to NULL. 807 11042 Erik * 808 1676 jpk * Returns: 809 11077 Erik * 0 Label (was|is now) correct 810 1676 jpk * EACCES The packet failed the remote host accreditation. 811 1676 jpk * ENOMEM Memory allocation failure. 812 1676 jpk * EINVAL Label cannot be computed 813 1676 jpk */ 814 1676 jpk int 815 11042 Erik tsol_check_label_v4(const ts_label_t *tsl, zoneid_t zoneid, mblk_t **mpp, 816 11042 Erik uint_t mac_mode, boolean_t zone_is_global, ip_stack_t *ipst, 817 11042 Erik ts_label_t **effective_tslp) 818 1676 jpk { 819 1676 jpk mblk_t *mp = *mpp; 820 1676 jpk ipha_t *ipha; 821 11042 Erik ts_label_t *effective_tsl = NULL; 822 1676 jpk uchar_t opt_storage[IP_MAX_OPT_LENGTH]; 823 1676 jpk uint_t hlen; 824 1676 jpk uint_t sec_opt_len; 825 1676 jpk uchar_t *optr; 826 6596 kp158701 int delta_remove = 0, delta_add, adjust; 827 1676 jpk int retv; 828 1676 jpk 829 11042 Erik *effective_tslp = NULL; 830 1676 jpk opt_storage[IPOPT_OPTVAL] = 0; 831 1676 jpk 832 1676 jpk ipha = (ipha_t *)mp->b_rptr; 833 1676 jpk 834 9710 Ken /* 835 9710 Ken * Verify the destination is allowed to receive packets at 836 11042 Erik * the security label of the message data. tsol_check_dest() 837 11042 Erik * may create a new effective label or label flags. 838 9710 Ken */ 839 11042 Erik retv = tsol_check_dest(tsl, &ipha->ipha_dst, IPV4_VERSION, 840 11042 Erik mac_mode, zone_is_global, &effective_tsl); 841 1676 jpk if (retv != 0) 842 1676 jpk return (retv); 843 9710 Ken 844 9710 Ken /* 845 9710 Ken * Calculate the security label to be placed in the text 846 9710 Ken * of the message (if any). 847 9710 Ken */ 848 11042 Erik if (effective_tsl != NULL) { 849 11042 Erik if ((retv = tsol_compute_label_v4(effective_tsl, zoneid, 850 9710 Ken ipha->ipha_dst, opt_storage, ipst)) != 0) { 851 11042 Erik label_rele(effective_tsl); 852 9710 Ken return (retv); 853 9710 Ken } 854 11042 Erik *effective_tslp = effective_tsl; 855 9710 Ken } else { 856 11042 Erik if ((retv = tsol_compute_label_v4(tsl, zoneid, 857 9710 Ken ipha->ipha_dst, opt_storage, ipst)) != 0) { 858 9710 Ken return (retv); 859 9710 Ken } 860 9710 Ken } 861 1676 jpk 862 1676 jpk optr = (uchar_t *)(ipha + 1); 863 1676 jpk hlen = IPH_HDR_LENGTH(ipha) - IP_SIMPLE_HDR_LENGTH; 864 1676 jpk sec_opt_len = opt_storage[IPOPT_OLEN]; 865 1676 jpk 866 1676 jpk if (hlen >= sec_opt_len) { 867 1676 jpk /* If no option is supposed to be there, make sure it's not */ 868 1676 jpk if (sec_opt_len == 0 && hlen > 0 && 869 1676 jpk optr[IPOPT_OPTVAL] != IPOPT_COMSEC && 870 1676 jpk optr[IPOPT_OPTVAL] != IPOPT_SECURITY) 871 1676 jpk return (0); 872 1676 jpk /* if the option is there, it's always first */ 873 1676 jpk if (sec_opt_len != 0 && 874 1676 jpk bcmp(opt_storage, optr, sec_opt_len) == 0) 875 1676 jpk return (0); 876 1676 jpk } 877 1676 jpk 878 1676 jpk /* 879 1676 jpk * If there is an option there, then it must be the wrong one; delete. 880 1676 jpk */ 881 6596 kp158701 if (hlen > 0) { 882 6596 kp158701 delta_remove = tsol_remove_secopt(ipha, MBLKL(mp)); 883 6596 kp158701 mp->b_wptr += delta_remove; 884 6596 kp158701 } 885 1676 jpk 886 1676 jpk /* Make sure we have room for the worst-case addition */ 887 1676 jpk hlen = IPH_HDR_LENGTH(ipha) + opt_storage[IPOPT_OLEN]; 888 1676 jpk hlen = (hlen + 3) & ~3; 889 1676 jpk if (hlen > IP_MAX_HDR_LENGTH) 890 1676 jpk hlen = IP_MAX_HDR_LENGTH; 891 1676 jpk hlen -= IPH_HDR_LENGTH(ipha); 892 1676 jpk if (mp->b_wptr + hlen > mp->b_datap->db_lim) { 893 1676 jpk int copylen; 894 1676 jpk mblk_t *new_mp; 895 1676 jpk 896 1676 jpk /* allocate enough to be meaningful, but not *too* much */ 897 1676 jpk copylen = MBLKL(mp); 898 1676 jpk if (copylen > 256) 899 1676 jpk copylen = 256; 900 8778 Erik new_mp = allocb_tmpl(hlen + copylen + 901 8778 Erik (mp->b_rptr - mp->b_datap->db_base), mp); 902 11042 Erik if (new_mp == NULL) { 903 11042 Erik if (effective_tsl != NULL) { 904 11042 Erik label_rele(effective_tsl); 905 11042 Erik *effective_tslp = NULL; 906 11042 Erik } 907 1676 jpk return (ENOMEM); 908 11042 Erik } 909 1676 jpk 910 1676 jpk /* keep the bias */ 911 1676 jpk new_mp->b_rptr += mp->b_rptr - mp->b_datap->db_base; 912 1676 jpk new_mp->b_wptr = new_mp->b_rptr + copylen; 913 1676 jpk bcopy(mp->b_rptr, new_mp->b_rptr, copylen); 914 1676 jpk new_mp->b_cont = mp; 915 1676 jpk if ((mp->b_rptr += copylen) >= mp->b_wptr) { 916 1676 jpk new_mp->b_cont = mp->b_cont; 917 1676 jpk freeb(mp); 918 1676 jpk } 919 1676 jpk *mpp = mp = new_mp; 920 1676 jpk ipha = (ipha_t *)mp->b_rptr; 921 1676 jpk } 922 1676 jpk 923 6596 kp158701 delta_add = tsol_prepend_option(opt_storage, ipha, MBLKL(mp)); 924 6596 kp158701 if (delta_add == -1) 925 1676 jpk goto param_prob; 926 1676 jpk 927 6596 kp158701 ASSERT((mp->b_wptr + delta_add) <= DB_LIM(mp)); 928 6596 kp158701 mp->b_wptr += delta_add; 929 1676 jpk 930 6596 kp158701 adjust = delta_remove + delta_add; 931 6596 kp158701 adjust += ntohs(ipha->ipha_length); 932 6596 kp158701 ipha->ipha_length = htons(adjust); 933 1676 jpk 934 1676 jpk return (0); 935 1676 jpk 936 1676 jpk param_prob: 937 11042 Erik if (effective_tsl != NULL) { 938 11042 Erik label_rele(effective_tsl); 939 11042 Erik *effective_tslp = NULL; 940 11042 Erik } 941 1676 jpk return (EINVAL); 942 1676 jpk } 943 1676 jpk 944 1676 jpk /* 945 1676 jpk * IPv6 HopOpt extension header for the label option layout: 946 1676 jpk * - One octet giving the type of the 'next extension header' 947 1676 jpk * - Header extension length in 8-byte words, not including the 948 1676 jpk * 1st 8 bytes, but including any pad bytes at the end. 949 1676 jpk * Eg. A value of 2 means 16 bytes not including the 1st 8 bytes. 950 1676 jpk * - Followed by TLV encoded IPv6 label option. Option layout is 951 1676 jpk * * One octet, IP6OPT_LS 952 1676 jpk * * One octet option length in bytes of the option data following 953 1676 jpk * the length, but not including any pad bytes at the end. 954 1676 jpk * * Four-octet DOI (IP6LS_DOI_V4) 955 1676 jpk * * One octet suboption, IP6LS_TT_V4 956 1676 jpk * * One octet suboption length in bytes of the suboption 957 1676 jpk * following the suboption length, including the suboption 958 1676 jpk * header length, but not including any pad bytes at the end. 959 1676 jpk * - Pad to make the extension header a multiple of 8 bytes. 960 1676 jpk * 961 1676 jpk * This function returns the contents of 'IPv6 option structure' in the above. 962 1676 jpk * i.e starting from the IP6OPT_LS but not including the pad at the end. 963 1676 jpk * The user must prepend two octets (either padding or next header / length) 964 1676 jpk * and append padding out to the next 8 octet boundary. 965 11042 Erik * 966 11042 Erik * The zoneid is the IP zoneid (i.e., GLOBAL_ZONEID for exlusive-IP zones). 967 1676 jpk */ 968 1676 jpk int 969 11042 Erik tsol_compute_label_v6(const ts_label_t *tsl, zoneid_t zoneid, 970 11042 Erik const in6_addr_t *dst, uchar_t *opt_storage, ip_stack_t *ipst) 971 1676 jpk { 972 1676 jpk uint_t sec_opt_len; 973 1676 jpk uint32_t doi; 974 11042 Erik ire_t *ire; 975 11042 Erik tsol_ire_gw_secattr_t *attrp = NULL; 976 1676 jpk 977 1676 jpk if (ip6opt_ls == 0) 978 1676 jpk return (EINVAL); 979 1676 jpk 980 1676 jpk if (opt_storage != NULL) 981 1676 jpk opt_storage[IPOPT_OLEN] = 0; 982 1676 jpk 983 11042 Erik if (tsl == NULL) 984 1676 jpk return (0); 985 1676 jpk 986 1676 jpk /* Always pass multicast */ 987 1676 jpk if (IN6_IS_ADDR_MULTICAST(dst)) 988 1676 jpk return (0); 989 3448 dh155122 990 3448 dh155122 /* 991 1676 jpk * Fill in a V6 label. If a new format is added here, make certain 992 1676 jpk * that the maximum size of this label is reflected in sys/tsol/tnet.h 993 1676 jpk * as TSOL_MAX_IPV6_OPTION. 994 1676 jpk */ 995 10934 sommerfeld if (tsl->tsl_flags & TSLF_IMPLICIT_OUT) 996 10934 sommerfeld return (0); 997 10934 sommerfeld 998 9710 Ken if (tsl->tsl_flags & TSLF_UNLABELED) { 999 1676 jpk /* 1000 9710 Ken * The destination is unlabeled. Only add a label if the 1001 11042 Erik * destination is not a broadcast/local/loopback address, 1002 9710 Ken * the destination is not on the same subnet, and the 1003 9710 Ken * next-hop gateway is labeled. 1004 1676 jpk */ 1005 11042 Erik ire = ire_route_recursive_v6(dst, 0, NULL, zoneid, tsl, 1006 11042 Erik MATCH_IRE_SECATTR, B_TRUE, 0, ipst, NULL, &attrp, NULL); 1007 11042 Erik ASSERT(ire != NULL); 1008 11042 Erik if (ire->ire_flags & (RTF_REJECT|RTF_BLACKHOLE)) { 1009 11042 Erik /* no route to destination */ 1010 11042 Erik ire_refrele(ire); 1011 9710 Ken DTRACE_PROBE3( 1012 1676 jpk tx__tnopt__log__info__labeling__routedst__v6, 1013 9710 Ken char *, "No route to unlabeled dest ip6(1) with " 1014 11042 Erik "label(2).", in6_addr_t *, dst, ts_label_t *, tsl); 1015 9710 Ken return (EHOSTUNREACH); 1016 1676 jpk } 1017 11042 Erik if (ire->ire_type & (IRE_LOCAL | IRE_LOOPBACK | 1018 11042 Erik IRE_INTERFACE)) { 1019 11042 Erik ire_refrele(ire); 1020 11042 Erik return (0); 1021 11042 Erik } 1022 1676 jpk /* 1023 11042 Erik * ire_route_recursive gives us the first attrp it finds 1024 11042 Erik * in the recursive lookup. 1025 1676 jpk */ 1026 9710 Ken /* 1027 9710 Ken * Return now if next hop gateway is unlabeled. There is 1028 9710 Ken * no need to generate a CIPSO option for this message. 1029 9710 Ken */ 1030 9710 Ken if (attrp == NULL || attrp->igsa_rhc == NULL || 1031 9710 Ken attrp->igsa_rhc->rhc_tpc->tpc_tp.host_type == UNLABELED) { 1032 11042 Erik ire_refrele(ire); 1033 9710 Ken return (0); 1034 1676 jpk } 1035 11042 Erik ire_refrele(ire); 1036 1676 jpk } 1037 1676 jpk 1038 1676 jpk /* compute the CIPSO option */ 1039 1676 jpk if (opt_storage != NULL) 1040 1676 jpk opt_storage += 8; 1041 9710 Ken sec_opt_len = tsol2cipso_tt1(&tsl->tsl_label, opt_storage, 1042 9710 Ken tsl->tsl_doi); 1043 1676 jpk 1044 1676 jpk if (sec_opt_len == 0) { 1045 9710 Ken DTRACE_PROBE3(tx__tnopt__log__error__labeling__lostops__v6, 1046 9710 Ken char *, "options lack length for dest ip6(1) with " 1047 11042 Erik "label(2).", in6_addr_t *, dst, ts_label_t *, tsl); 1048 1676 jpk return (EINVAL); 1049 1676 jpk } 1050 1676 jpk 1051 1676 jpk if (opt_storage == NULL) 1052 1676 jpk return (0); 1053 1676 jpk 1054 1676 jpk if (sec_opt_len < IP_MAX_OPT_LENGTH) 1055 1676 jpk opt_storage[sec_opt_len] = IPOPT_EOL; 1056 1676 jpk 1057 1676 jpk /* 1058 1676 jpk * Just in case the option length is odd, round it up to the next even 1059 1676 jpk * multiple. The IPv6 option definition doesn't like odd numbers for 1060 1676 jpk * some reason. 1061 1676 jpk * 1062 1676 jpk * Length in the overall option header (IP6OPT_LS) does not include the 1063 1676 jpk * option header itself, but the length in the suboption does include 1064 1676 jpk * the suboption header. Thus, when there's just one suboption, the 1065 1676 jpk * length in the option header is the suboption length plus 4 (for the 1066 1676 jpk * DOI value). 1067 1676 jpk */ 1068 1676 jpk opt_storage[-2] = IP6LS_TT_V4; 1069 1676 jpk opt_storage[-1] = (sec_opt_len + 2 + 1) & ~1; 1070 1676 jpk opt_storage[-8] = ip6opt_ls; 1071 1676 jpk opt_storage[-7] = opt_storage[-1] + 4; 1072 1676 jpk doi = htons(IP6LS_DOI_V4); 1073 1676 jpk bcopy(&doi, opt_storage - 6, 4); 1074 1676 jpk 1075 1676 jpk return (0); 1076 1676 jpk } 1077 1676 jpk 1078 1676 jpk /* 1079 1676 jpk * Locate the start of the IP6OPT_LS label option and return it. 1080 1676 jpk * Also return the start of the next non-pad option in after_secoptp. 1081 1676 jpk * Usually the label option is the first option at least when packets 1082 1676 jpk * are generated, but for generality we don't assume that on received packets. 1083 10181 Ken * 1084 10181 Ken * The function will return with B_FALSE if an IP format error 1085 10181 Ken * or an unexpected label content error is encountered. 1086 1676 jpk */ 1087 10181 Ken boolean_t 1088 1676 jpk tsol_find_secopt_v6( 1089 1676 jpk const uchar_t *ip6hbh, /* Start of the hop-by-hop extension header */ 1090 1676 jpk uint_t hbhlen, /* Length of the hop-by-hop extension header */ 1091 10181 Ken uchar_t **secoptp, /* Location of IP6OPT_LS label option */ 1092 1676 jpk uchar_t **after_secoptp, /* Non-pad option following the label option */ 1093 1676 jpk boolean_t *hbh_needed) /* Is hop-by-hop hdr needed w/o label */ 1094 1676 jpk { 1095 1676 jpk uint_t optlen; 1096 1676 jpk uint_t optused; 1097 1676 jpk const uchar_t *optptr; 1098 1676 jpk uchar_t opt_type; 1099 1676 jpk 1100 10181 Ken *secoptp = NULL; 1101 1676 jpk *hbh_needed = B_FALSE; 1102 1676 jpk *after_secoptp = NULL; 1103 1676 jpk optlen = hbhlen - 2; 1104 1676 jpk optptr = ip6hbh + 2; 1105 1676 jpk while (optlen != 0) { 1106 1676 jpk opt_type = *optptr; 1107 1676 jpk if (opt_type == IP6OPT_PAD1) { 1108 1676 jpk optptr++; 1109 1676 jpk optlen--; 1110 1676 jpk continue; 1111 1676 jpk } 1112 1676 jpk if (optlen == 1) 1113 10181 Ken return (B_FALSE); 1114 1676 jpk optused = 2 + optptr[1]; 1115 1676 jpk if (optused > optlen) 1116 10181 Ken return (B_FALSE); 1117 1676 jpk /* 1118 1676 jpk * if we get here, ip6opt_ls can 1119 1676 jpk * not be 0 because it will always 1120 1676 jpk * match the IP6OPT_PAD1 above. 1121 1676 jpk * Therefore ip6opt_ls == 0 forces 1122 1676 jpk * this test to always fail here. 1123 1676 jpk */ 1124 10181 Ken if (opt_type == ip6opt_ls) { 1125 10181 Ken if (*secoptp != NULL) 1126 10181 Ken /* More than one security option found */ 1127 10181 Ken return (B_FALSE); 1128 10181 Ken *secoptp = (uchar_t *)optptr; 1129 10181 Ken } else switch (opt_type) { 1130 1676 jpk case IP6OPT_PADN: 1131 1676 jpk break; 1132 1676 jpk default: 1133 1676 jpk /* 1134 1676 jpk * There is at least 1 option other than 1135 1676 jpk * the label option. So the hop-by-hop header is needed 1136 1676 jpk */ 1137 1676 jpk *hbh_needed = B_TRUE; 1138 10181 Ken if (*secoptp != NULL) { 1139 1676 jpk *after_secoptp = (uchar_t *)optptr; 1140 10181 Ken return (B_TRUE); 1141 1676 jpk } 1142 1676 jpk break; 1143 1676 jpk } 1144 1676 jpk optlen -= optused; 1145 1676 jpk optptr += optused; 1146 1676 jpk } 1147 10181 Ken return (B_TRUE); 1148 1676 jpk } 1149 1676 jpk 1150 1676 jpk /* 1151 1676 jpk * Remove the label option from the hop-by-hop options header if it exists. 1152 1676 jpk * 'buflen' is the total length of the packet typically b_wptr - b_rptr. 1153 1676 jpk * Header and data following the label option that is deleted are copied 1154 4564 wy83408 * (i.e. slid backward) to the right position, and returns the number 1155 4564 wy83408 * of bytes removed (as zero or negative number.) 1156 11042 Erik * 1157 11042 Erik * Note that tsol_remove_secopt does not adjust ipha_length but 1158 11042 Erik * tsol_remove_secopt_v6 does adjust ip6_plen. 1159 1676 jpk */ 1160 1676 jpk int 1161 1676 jpk tsol_remove_secopt_v6(ip6_t *ip6h, int buflen) 1162 1676 jpk { 1163 1676 jpk uchar_t *ip6hbh; /* hop-by-hop header */ 1164 1676 jpk uint_t hbhlen; /* hop-by-hop extension header length */ 1165 1676 jpk uchar_t *secopt = NULL; 1166 1676 jpk uchar_t *after_secopt; 1167 1676 jpk uint_t pad; 1168 1676 jpk uint_t delta; 1169 1676 jpk boolean_t hbh_needed; 1170 1676 jpk 1171 1676 jpk /* 1172 1676 jpk * hop-by-hop extension header must appear first, if it does not 1173 1676 jpk * exist, there is no label option. 1174 1676 jpk */ 1175 1676 jpk if (ip6h->ip6_nxt != IPPROTO_HOPOPTS) 1176 1676 jpk return (0); 1177 1676 jpk 1178 1676 jpk ip6hbh = (uchar_t *)&ip6h[1]; 1179 1676 jpk hbhlen = (ip6hbh[1] + 1) << 3; 1180 1676 jpk /* 1181 1676 jpk * Locate the start of the label option if it exists and the end 1182 1676 jpk * of the label option including pads if any. 1183 1676 jpk */ 1184 10181 Ken if (!tsol_find_secopt_v6(ip6hbh, hbhlen, &secopt, &after_secopt, 1185 10181 Ken &hbh_needed)) { 1186 10181 Ken /* 1187 10181 Ken * This function should not see invalid messages. 1188 10181 Ken * If one occurs, it would indicate either an 1189 10181 Ken * option previously verified in the forwarding 1190 10181 Ken * path has been corrupted or an option was 1191 10181 Ken * incorrectly generated locally. 1192 10181 Ken */ 1193 10181 Ken ASSERT(0); 1194 10181 Ken return (0); 1195 10181 Ken } 1196 1676 jpk if (secopt == NULL) 1197 1676 jpk return (0); 1198 1676 jpk if (!hbh_needed) { 1199 1676 jpk uchar_t next_hdr; 1200 1676 jpk /* 1201 1676 jpk * The label option was the only option in the hop-by-hop 1202 1676 jpk * header. We don't need the hop-by-hop header itself any 1203 1676 jpk * longer. 1204 1676 jpk */ 1205 1676 jpk next_hdr = ip6hbh[0]; 1206 1676 jpk ovbcopy(ip6hbh + hbhlen, ip6hbh, 1207 1676 jpk buflen - (IPV6_HDR_LEN + hbhlen)); 1208 2776 kp158701 ip6h->ip6_plen = htons(ntohs(ip6h->ip6_plen) - hbhlen); 1209 1676 jpk ip6h->ip6_nxt = next_hdr; 1210 4564 wy83408 return (-hbhlen); 1211 1676 jpk } 1212 1676 jpk 1213 1676 jpk if (after_secopt == NULL) { 1214 1676 jpk /* There is no option following the label option */ 1215 1676 jpk after_secopt = ip6hbh + hbhlen; 1216 1676 jpk } 1217 1676 jpk 1218 1676 jpk /* 1219 1676 jpk * After deleting the label option, we need to slide the headers 1220 1676 jpk * and data back, while still maintaining the same alignment (module 8) 1221 1676 jpk * for the other options. So we slide the headers and data back only 1222 1676 jpk * by an integral multiple of 8 bytes, and fill the remaining bytes 1223 1676 jpk * with pads. 1224 1676 jpk */ 1225 1676 jpk delta = after_secopt - secopt; 1226 1676 jpk pad = delta % 8; 1227 1676 jpk if (pad == 1) { 1228 1676 jpk secopt[0] = IP6OPT_PAD1; 1229 1676 jpk } else if (pad > 1) { 1230 1676 jpk secopt[0] = IP6OPT_PADN; 1231 1676 jpk secopt[1] = pad - 2; 1232 1676 jpk if (pad > 2) 1233 1676 jpk bzero(&secopt[2], pad - 2); 1234 1676 jpk } 1235 1676 jpk secopt += pad; 1236 1676 jpk delta -= pad; 1237 1676 jpk ovbcopy(after_secopt, secopt, 1238 1676 jpk (uchar_t *)ip6h + buflen - after_secopt); 1239 1676 jpk ip6hbh[1] -= delta/8; 1240 2776 kp158701 ip6h->ip6_plen = htons(ntohs(ip6h->ip6_plen) - delta); 1241 1676 jpk 1242 4564 wy83408 return (-delta); 1243 1676 jpk } 1244 1676 jpk 1245 1676 jpk /* 1246 1676 jpk * 'optbuf' contains a CIPSO label embedded in an IPv6 hop-by-hop option, 1247 1676 jpk * starting with the IP6OPT_LS option type. The format of this hop-by-hop 1248 1676 jpk * option is described in the block comment above tsol_compute_label_v6. 1249 1676 jpk * This function prepends this hop-by-hop option before any other hop-by-hop 1250 1676 jpk * options in the hop-by-hop header if one already exists, else a new 1251 1676 jpk * hop-by-hop header is created and stuffed into the packet following 1252 1676 jpk * the IPv6 header. 'buflen' is the total length of the packet i.e. 1253 1676 jpk * b_wptr - b_rptr. The caller ensures that there is enough space for the 1254 1676 jpk * extra option being added. Header and data following the position where 1255 1676 jpk * the label option is inserted are copied (i.e. slid forward) to the right 1256 1676 jpk * position. 1257 11042 Erik * 1258 11042 Erik * Note that tsol_prepend_option does not adjust ipha_length but 1259 11042 Erik * tsol_prepend_option_v6 does adjust ip6_plen. 1260 1676 jpk */ 1261 1676 jpk int 1262 1676 jpk tsol_prepend_option_v6(uchar_t *optbuf, ip6_t *ip6h, int buflen) 1263 1676 jpk { 1264 1676 jpk /* 1265 1676 jpk * rawlen is the length of the label option in bytes, not including 1266 1676 jpk * any pads, starting from the IP6OPT_LS (option type) byte. 1267 1676 jpk */ 1268 1676 jpk uint_t rawlen; 1269 1676 jpk 1270 1676 jpk uint_t optlen; /* rawlen rounded to an 8 byte multiple */ 1271 1676 jpk uchar_t *ip6hbh; /* start of the hop-by-hop extension header */ 1272 1676 jpk uint_t hbhlen; /* Length of the hop-by-hop extension header */ 1273 1676 jpk uint_t pad_len; 1274 1676 jpk uchar_t *pad_position; 1275 1676 jpk int delta; /* Actual number of bytes inserted */ 1276 1676 jpk 1277 1676 jpk rawlen = optbuf[1] + 2; /* Add 2 for the option type, option length */ 1278 1676 jpk ip6hbh = (uchar_t *)&ip6h[1]; 1279 1676 jpk if (ip6h->ip6_nxt == IPPROTO_HOPOPTS) { 1280 1676 jpk /* 1281 1676 jpk * There is a hop-by-hop header present already. In order to 1282 1676 jpk * preserve the alignment of the other options at the existing 1283 1676 jpk * value (modulo 8) we need to pad the label option to a 1284 1676 jpk * multiple of 8 bytes before prepending it to the other 1285 1676 jpk * options. Slide the extension headers and data forward to 1286 1676 jpk * accomodate the label option at the start of the hop-by-hop 1287 1676 jpk * header 1288 1676 jpk */ 1289 1676 jpk delta = optlen = (rawlen + 7) & ~7; 1290 1676 jpk pad_len = optlen - rawlen; 1291 1676 jpk pad_position = ip6hbh + 2 + rawlen; 1292 1676 jpk ovbcopy(ip6hbh + 2, ip6hbh + 2 + optlen, 1293 1676 jpk buflen - (IPV6_HDR_LEN + 2)); 1294 1676 jpk /* 1295 1676 jpk * Bump up the hop-by-hop extension header length by 1296 1676 jpk * the number of 8-byte words added 1297 1676 jpk */ 1298 1676 jpk optlen >>= 3; 1299 1676 jpk if (ip6hbh[1] + optlen > 255) 1300 1676 jpk return (-1); 1301 1676 jpk ip6hbh[1] += optlen; 1302 1676 jpk } else { 1303 1676 jpk /* 1304 1676 jpk * There is no hop-by-hop header in the packet. Construct a 1305 1676 jpk * new Hop-by-hop extension header (a multiple of 8 bytes). 1306 1676 jpk * Slide any other extension headers and data forward to 1307 1676 jpk * accomodate this hop-by-hop header 1308 1676 jpk */ 1309 1676 jpk delta = hbhlen = (2 + rawlen + 7) & ~7; /* +2 for nxthdr, len */ 1310 1676 jpk pad_len = hbhlen - (2 + rawlen); 1311 1676 jpk pad_position = ip6hbh + 2 + rawlen; 1312 1676 jpk ovbcopy(ip6hbh, ip6hbh + hbhlen, buflen - IPV6_HDR_LEN); 1313 1676 jpk ip6hbh[0] = ip6h->ip6_nxt; 1314 1676 jpk /* 1315 1676 jpk * hop-by-hop extension header length in 8-byte words, not 1316 1676 jpk * including the 1st 8 bytes of the hop-by-hop header. 1317 1676 jpk */ 1318 1676 jpk ip6hbh[1] = (hbhlen >> 3) - 1; 1319 1676 jpk ip6h->ip6_nxt = IPPROTO_HOPOPTS; 1320 1676 jpk } 1321 1676 jpk /* 1322 1676 jpk * Copy the label option into the hop-by-hop header and insert any 1323 1676 jpk * needed pads 1324 1676 jpk */ 1325 1676 jpk bcopy(optbuf, ip6hbh + 2, rawlen); 1326 1676 jpk if (pad_len == 1) { 1327 1676 jpk pad_position[0] = IP6OPT_PAD1; 1328 1676 jpk } else if (pad_len > 1) { 1329 1676 jpk pad_position[0] = IP6OPT_PADN; 1330 1676 jpk pad_position[1] = pad_len - 2; 1331 1676 jpk if (pad_len > 2) 1332 1676 jpk bzero(pad_position + 2, pad_len - 2); 1333 1676 jpk } 1334 2776 kp158701 ip6h->ip6_plen = htons(ntohs(ip6h->ip6_plen) + delta); 1335 1676 jpk return (delta); 1336 1676 jpk } 1337 1676 jpk 1338 1676 jpk /* 1339 1676 jpk * tsol_check_label_v6() 1340 1676 jpk * 1341 1676 jpk * This routine computes the IP label that should be on the packet based on the 1342 11042 Erik * connection and destination information. It's called by the IP forwarding 1343 11042 Erik * logic and by ip_output_simple. The ULPs generate the labels before calling 1344 11042 Erik * conn_ip_output. If any adjustments to 1345 11042 Erik * the label are needed due to the connection's MAC-exempt status or 1346 11042 Erik * the destination's ability to receive labels, an "effective label" 1347 11042 Erik * will be returned. 1348 11042 Erik * 1349 11042 Erik * The packet's header is clear before entering IPsec's engine. 1350 11042 Erik * 1351 11042 Erik * The zoneid is the IP zoneid (i.e., GLOBAL_ZONEID for exlusive-IP zones). 1352 11042 Erik * zone_is_global is set if the actual zoneid is global. 1353 11042 Erik * 1354 11042 Erik * On successful return, effective_tslp will point to the new label needed 1355 11042 Erik * or will be NULL if a new label isn't needed. On error, effective_tsl will 1356 11042 Erik * point to NULL. 1357 1676 jpk * 1358 1676 jpk * Returns: 1359 11077 Erik * 0 Label (was|is now) correct 1360 9710 Ken * EACCES The packet failed the remote host accreditation. 1361 1676 jpk * ENOMEM Memory allocation failure. 1362 11042 Erik * EINVAL Label cannot be computed 1363 1676 jpk */ 1364 1676 jpk int 1365 11042 Erik tsol_check_label_v6(const ts_label_t *tsl, zoneid_t zoneid, mblk_t **mpp, 1366 11042 Erik uint_t mac_mode, boolean_t zone_is_global, ip_stack_t *ipst, 1367 11042 Erik ts_label_t **effective_tslp) 1368 1676 jpk { 1369 1676 jpk mblk_t *mp = *mpp; 1370 1676 jpk ip6_t *ip6h; 1371 11042 Erik ts_label_t *effective_tsl = NULL; 1372 1676 jpk /* 1373 1676 jpk * Label option length is limited to IP_MAX_OPT_LENGTH for 1374 1676 jpk * symmetry with IPv4. Can be relaxed if needed 1375 1676 jpk */ 1376 1676 jpk uchar_t opt_storage[TSOL_MAX_IPV6_OPTION]; 1377 1676 jpk uint_t hlen; 1378 1676 jpk uint_t sec_opt_len; /* label option length not including type, len */ 1379 6596 kp158701 int delta_remove = 0, delta_add; 1380 1676 jpk int retv; 1381 1676 jpk uchar_t *after_secopt; 1382 1676 jpk uchar_t *secopt = NULL; 1383 1676 jpk uchar_t *ip6hbh; 1384 1676 jpk uint_t hbhlen; 1385 1676 jpk boolean_t hbh_needed; 1386 1676 jpk 1387 11042 Erik *effective_tslp = NULL; 1388 11042 Erik 1389 9710 Ken /* 1390 9710 Ken * Verify the destination is allowed to receive packets at 1391 11042 Erik * the security label of the message data. tsol_check_dest() 1392 11042 Erik * may create a new effective label or label flags. 1393 9710 Ken */ 1394 1676 jpk ip6h = (ip6_t *)mp->b_rptr; 1395 11042 Erik retv = tsol_check_dest(tsl, &ip6h->ip6_dst, IPV6_VERSION, 1396 11042 Erik mac_mode, zone_is_global, &effective_tsl); 1397 1676 jpk if (retv != 0) 1398 1676 jpk return (retv); 1399 9710 Ken 1400 9710 Ken /* 1401 9710 Ken * Calculate the security label to be placed in the text 1402 9710 Ken * of the message (if any). 1403 9710 Ken */ 1404 11042 Erik if (effective_tsl != NULL) { 1405 11042 Erik if ((retv = tsol_compute_label_v6(effective_tsl, zoneid, 1406 9710 Ken &ip6h->ip6_dst, opt_storage, ipst)) != 0) { 1407 11042 Erik label_rele(effective_tsl); 1408 9710 Ken return (retv); 1409 9710 Ken } 1410 11042 Erik *effective_tslp = effective_tsl; 1411 9710 Ken } else { 1412 11042 Erik if ((retv = tsol_compute_label_v6(tsl, zoneid, 1413 9710 Ken &ip6h->ip6_dst, opt_storage, ipst)) != 0) 1414 9710 Ken return (retv); 1415 9710 Ken } 1416 1676 jpk 1417 1676 jpk sec_opt_len = opt_storage[1]; 1418 1676 jpk 1419 1676 jpk if (ip6h->ip6_nxt == IPPROTO_HOPOPTS) { 1420 1676 jpk ip6hbh = (uchar_t *)&ip6h[1]; 1421 1676 jpk hbhlen = (ip6hbh[1] + 1) << 3; 1422 10181 Ken if (!tsol_find_secopt_v6(ip6hbh, hbhlen, &secopt, 1423 10181 Ken &after_secopt, &hbh_needed)) { 1424 10181 Ken /* 1425 10181 Ken * This function should not see invalid messages. 1426 10181 Ken * If one occurs, it would indicate either an 1427 10181 Ken * option previously verified in the forwarding 1428 10181 Ken * path has been corrupted or an option was 1429 10181 Ken * incorrectly generated locally. 1430 10181 Ken */ 1431 10181 Ken ASSERT(0); 1432 10181 Ken return (EACCES); 1433 10181 Ken } 1434 1676 jpk } 1435 1676 jpk 1436 1676 jpk if (sec_opt_len == 0 && secopt == NULL) { 1437 1676 jpk /* 1438 1676 jpk * The packet is not supposed to have a label, and it 1439 1676 jpk * does not have one currently 1440 1676 jpk */ 1441 1676 jpk return (0); 1442 10934 sommerfeld } 1443 10934 sommerfeld 1444 1676 jpk if (secopt != NULL && sec_opt_len != 0 && 1445 1676 jpk (bcmp(opt_storage, secopt, sec_opt_len + 2) == 0)) { 1446 1676 jpk /* The packet has the correct label already */ 1447 1676 jpk return (0); 1448 1676 jpk } 1449 1676 jpk 1450 1676 jpk /* 1451 1676 jpk * If there is an option there, then it must be the wrong one; delete. 1452 1676 jpk */ 1453 6596 kp158701 if (secopt != NULL) { 1454 6596 kp158701 delta_remove = tsol_remove_secopt_v6(ip6h, MBLKL(mp)); 1455 6596 kp158701 mp->b_wptr += delta_remove; 1456 6596 kp158701 } 1457 1676 jpk 1458 1676 jpk /* 1459 1676 jpk * Make sure we have room for the worst-case addition. Add 2 bytes for 1460 1676 jpk * the hop-by-hop ext header's next header and length fields. Add 1461 1676 jpk * another 2 bytes for the label option type, len and then round 1462 1676 jpk * up to the next 8-byte multiple. 1463 1676 jpk */ 1464 1676 jpk hlen = (4 + sec_opt_len + 7) & ~7; 1465 1676 jpk if (mp->b_wptr + hlen > mp->b_datap->db_lim) { 1466 1676 jpk int copylen; 1467 1676 jpk mblk_t *new_mp; 1468 1676 jpk uint16_t hdr_len; 1469 1676 jpk 1470 1676 jpk hdr_len = ip_hdr_length_v6(mp, ip6h); 1471 1676 jpk /* 1472 1676 jpk * Allocate enough to be meaningful, but not *too* much. 1473 1676 jpk * Also all the IPv6 extension headers must be in the same mblk 1474 1676 jpk */ 1475 1676 jpk copylen = MBLKL(mp); 1476 1676 jpk if (copylen > 256) 1477 1676 jpk copylen = 256; 1478 1676 jpk if (copylen < hdr_len) 1479 1676 jpk copylen = hdr_len; 1480 8778 Erik new_mp = allocb_tmpl(hlen + copylen + 1481 8778 Erik (mp->b_rptr - mp->b_datap->db_base), mp); 1482 11042 Erik if (new_mp == NULL) { 1483 11042 Erik if (effective_tsl != NULL) { 1484 11042 Erik label_rele(effective_tsl); 1485 11042 Erik *effective_tslp = NULL; 1486 11042 Erik } 1487 1676 jpk return (ENOMEM); 1488 11042 Erik } 1489 1676 jpk 1490 1676 jpk /* keep the bias */ 1491 1676 jpk new_mp->b_rptr += mp->b_rptr - mp->b_datap->db_base; 1492 1676 jpk new_mp->b_wptr = new_mp->b_rptr + copylen; 1493 1676 jpk bcopy(mp->b_rptr, new_mp->b_rptr, copylen); 1494 1676 jpk new_mp->b_cont = mp; 1495 1676 jpk if ((mp->b_rptr += copylen) >= mp->b_wptr) { 1496 1676 jpk new_mp->b_cont = mp->b_cont; 1497 1676 jpk freeb(mp); 1498 1676 jpk } 1499 1676 jpk *mpp = mp = new_mp; 1500 1676 jpk ip6h = (ip6_t *)mp->b_rptr; 1501 1676 jpk } 1502 1676 jpk 1503 6596 kp158701 delta_add = tsol_prepend_option_v6(opt_storage, ip6h, MBLKL(mp)); 1504 6596 kp158701 if (delta_add == -1) 1505 1676 jpk goto param_prob; 1506 1676 jpk 1507 6596 kp158701 ASSERT(mp->b_wptr + delta_add <= DB_LIM(mp)); 1508 6596 kp158701 mp->b_wptr += delta_add; 1509 1676 jpk 1510 11042 Erik /* tsol_prepend_option_v6 has adjusted ip6_plen */ 1511 1676 jpk return (0); 1512 1676 jpk 1513 1676 jpk param_prob: 1514 11042 Erik if (effective_tsl != NULL) { 1515 11042 Erik label_rele(effective_tsl); 1516 11042 Erik *effective_tslp = NULL; 1517 11042 Erik } 1518 1676 jpk return (EINVAL); 1519 1676 jpk } 1520