📄 spdb_struct.c
字号:
, enum_show(&sa_lifetime_names, val)); return FALSE; } seen_durations |= LELEM(val); life_type = val; break; case SA_LIFE_DURATION | ISAKMP_ATTR_AF_TLV: val = decode_long_duration(&attr_pbs); /* fall through */ case SA_LIFE_DURATION | ISAKMP_ATTR_AF_TV: ipcomp_inappropriate = FALSE; if (!LHAS(seen_attrs, SA_LIFE_DURATION)) { loglog(RC_LOG_SERIOUS, "SA_LIFE_DURATION IPsec attribute not preceded by SA_LIFE_TYPE attribute"); return FALSE; } seen_attrs &= ~(LELEM(SA_LIFE_DURATION) | LELEM(SA_LIFE_TYPE)); switch (life_type) { case SA_LIFE_TYPE_SECONDS: /* silently limit duration to our maximum */ attrs->life_seconds = val <= SA_LIFE_DURATION_MAXIMUM ? val : SA_LIFE_DURATION_MAXIMUM; break; case SA_LIFE_TYPE_KBYTES: attrs->life_kilobytes = val; break; default: bad_case(life_type); } break; case GROUP_DESCRIPTION | ISAKMP_ATTR_AF_TV: if (is_ipcomp) { /* Accept reluctantly. Should not happen, according to * draft-shacham-ippcp-rfc2393bis-05.txt 4.1. */ ipcomp_inappropriate = FALSE; loglog(RC_COMMENT , "IPCA (IPcomp SA) contains GROUP_DESCRIPTION." " Ignoring inapproprate attribute."); } pfs_group = lookup_group(val); if (pfs_group == NULL) { loglog(RC_LOG_SERIOUS, "only OAKLEY_GROUP_MODP1024 and OAKLEY_GROUP_MODP1536 supported for PFS"); return FALSE; } break; case ENCAPSULATION_MODE | ISAKMP_ATTR_AF_TV: ipcomp_inappropriate = FALSE;#ifdef NAT_TRAVERSAL switch (val) { case ENCAPSULATION_MODE_TUNNEL: case ENCAPSULATION_MODE_TRANSPORT: if (st->nat_traversal & NAT_T_DETECTED) { loglog(RC_LOG_SERIOUS, "%s must only be used if " "NAT-Traversal is not detected", enum_name(&enc_mode_names, val)); /* * Accept it anyway because SSH-Sentinel does not * use UDP_TUNNEL or UDP_TRANSPORT for the diagnostic. * * remove when SSH-Sentinel is fixed */#ifdef I_DONT_CARE_OF_SSH_SENTINEL return FALSE;#endif } attrs->encapsulation = val; break; case ENCAPSULATION_MODE_UDP_TRANSPORT_DRAFTS:#ifndef I_KNOW_TRANSPORT_MODE_HAS_SECURITY_CONCERN_BUT_I_WANT_IT loglog(RC_LOG_SERIOUS, "NAT-Traversal: Transport mode disabled due " "to security concerns"); return FALSE; break;#endif case ENCAPSULATION_MODE_UDP_TUNNEL_DRAFTS: if (st->nat_traversal & NAT_T_WITH_RFC_VALUES) { loglog(RC_LOG_SERIOUS, "%s must only be used with old IETF drafts", enum_name(&enc_mode_names, val)); return FALSE; } else if (st->nat_traversal & NAT_T_DETECTED) { attrs->encapsulation = val - ENCAPSULATION_MODE_UDP_TUNNEL_DRAFTS + ENCAPSULATION_MODE_TUNNEL; } else { loglog(RC_LOG_SERIOUS, "%s must only be used if " "NAT-Traversal is detected", enum_name(&enc_mode_names, val)); return FALSE; } break; case ENCAPSULATION_MODE_UDP_TRANSPORT_RFC:#ifndef I_KNOW_TRANSPORT_MODE_HAS_SECURITY_CONCERN_BUT_I_WANT_IT loglog(RC_LOG_SERIOUS, "NAT-Traversal: Transport mode disabled due " "to security concerns"); return FALSE; break;#endif case ENCAPSULATION_MODE_UDP_TUNNEL_RFC: if ((st->nat_traversal & NAT_T_DETECTED) && (st->nat_traversal & NAT_T_WITH_RFC_VALUES)) { attrs->encapsulation = val - ENCAPSULATION_MODE_UDP_TUNNEL_RFC + ENCAPSULATION_MODE_TUNNEL; } else if (st->nat_traversal & NAT_T_DETECTED) { loglog(RC_LOG_SERIOUS, "%s must only be used with NAT-T RFC", enum_name(&enc_mode_names, val)); return FALSE; } else { loglog(RC_LOG_SERIOUS, "%s must only be used if " "NAT-Traversal is detected", enum_name(&enc_mode_names, val)); return FALSE; } break; default: loglog(RC_LOG_SERIOUS, "unknown ENCAPSULATION_MODE %d in IPSec SA", val); return FALSE; break; }#else attrs->encapsulation = val;#endif break; case AUTH_ALGORITHM | ISAKMP_ATTR_AF_TV: attrs->auth = val; break; case KEY_LENGTH | ISAKMP_ATTR_AF_TV: attrs->key_len = val; break; case KEY_ROUNDS | ISAKMP_ATTR_AF_TV: attrs->key_rounds = val; break;#if 0 /* not yet implemented */ case COMPRESS_DICT_SIZE | ISAKMP_ATTR_AF_TV: break; case COMPRESS_PRIVATE_ALG | ISAKMP_ATTR_AF_TV: break; case SA_LIFE_DURATION | ISAKMP_ATTR_AF_TLV: break; case COMPRESS_PRIVATE_ALG | ISAKMP_ATTR_AF_TLV: break;#endif default: loglog(RC_LOG_SERIOUS, "unsupported IPsec attribute %s" , enum_show(&ipsec_attr_names, a.isaat_af_type)); return FALSE; } if (ipcomp_inappropriate) { loglog(RC_LOG_SERIOUS, "IPsec attribute %s inappropriate for IPCOMP" , enum_show(&ipsec_attr_names, a.isaat_af_type)); return FALSE; } } /* Although an IPCOMP SA (IPCA) ought not to have a pfs_group, * if it does, demand that it be consistent. * See draft-shacham-ippcp-rfc2393bis-05.txt 4.1. */ if (!is_ipcomp || pfs_group != NULL) { if (st->st_pfs_group == &unset_group) st->st_pfs_group = pfs_group; if (st->st_pfs_group != pfs_group) { loglog(RC_LOG_SERIOUS, "GROUP_DESCRIPTION inconsistent with that of %s in IPsec SA" , selection? "the Proposal" : "a previous Transform"); return FALSE; } } if (LHAS(seen_attrs, SA_LIFE_DURATION)) { loglog(RC_LOG_SERIOUS, "SA_LIFE_TYPE IPsec attribute not followed by SA_LIFE_DURATION attribute in message"); return FALSE; } if (!LHAS(seen_attrs, ENCAPSULATION_MODE)) { if (is_ipcomp) { /* draft-shacham-ippcp-rfc2393bis-05.txt 4.1: * "If the Encapsulation Mode is unspecified, * the default value of Transport Mode is assumed." * This contradicts/overrides the DOI (quuoted below). */ attrs->encapsulation = ENCAPSULATION_MODE_TRANSPORT; } else { /* ??? Technically, RFC 2407 (IPSEC DOI) 4.5 specifies that * the default is "unspecified (host-dependent)". * This makes little sense, so we demand that it be specified. */ loglog(RC_LOG_SERIOUS, "IPsec Transform must specify ENCAPSULATION_MODE"); return FALSE; } } /* ??? should check for key_len and/or key_rounds if required */ return TRUE;}static voidecho_proposal( struct isakmp_proposal r_proposal, /* proposal to emit */ struct isakmp_transform r_trans, /* winning transformation within it */ u_int8_t np, /* Next Payload for proposal */ pb_stream *r_sa_pbs, /* SA PBS into which to emit */ struct ipsec_proto_info *pi, /* info about this protocol instance */ struct_desc *trans_desc, /* descriptor for this transformation */ pb_stream *trans_pbs, /* PBS for incoming transform */ struct spd_route *sr, /* host details for the association */ bool tunnel_mode) /* true for inner most tunnel SA */{ pb_stream r_proposal_pbs; pb_stream r_trans_pbs; /* Proposal */ r_proposal.isap_np = np; r_proposal.isap_notrans = 1; if (!out_struct(&r_proposal, &isakmp_proposal_desc, r_sa_pbs, &r_proposal_pbs)) impossible(); /* allocate and emit our CPI/SPI */ if (r_proposal.isap_protoid == PROTO_IPCOMP) { /* CPI is stored in network low order end of an * ipsec_spi_t. So we start a couple of bytes in. * Note: we may fail to generate a satisfactory CPI, * but we'll ignore that. */ pi->our_spi = get_my_cpi(sr, tunnel_mode); out_raw((u_char *) &pi->our_spi + IPSEC_DOI_SPI_SIZE - IPCOMP_CPI_SIZE , IPCOMP_CPI_SIZE , &r_proposal_pbs, "CPI"); } else { pi->our_spi = get_ipsec_spi(pi->attrs.spi , r_proposal.isap_protoid == PROTO_IPSEC_AH ? IPPROTO_AH : IPPROTO_ESP , sr , tunnel_mode); /* XXX should check for errors */ out_raw((u_char *) &pi->our_spi, IPSEC_DOI_SPI_SIZE , &r_proposal_pbs, "SPI"); } /* Transform */ r_trans.isat_np = ISAKMP_NEXT_NONE; if (!out_struct(&r_trans, trans_desc, &r_proposal_pbs, &r_trans_pbs)) impossible(); /* Transform Attributes: pure echo */ trans_pbs->cur = trans_pbs->start + sizeof(struct isakmp_transform); if (!out_raw(trans_pbs->cur, pbs_left(trans_pbs) , &r_trans_pbs, "attributes")) impossible(); close_output_pbs(&r_trans_pbs); close_output_pbs(&r_proposal_pbs);}notification_tparse_ipsec_sa_body( pb_stream *sa_pbs, /* body of input SA Payload */ const struct isakmp_sa *sa, /* header of input SA Payload */ pb_stream *r_sa_pbs, /* if non-NULL, where to emit body of winning SA */ bool selection, /* if this SA is a selection, only one transform may appear */ struct state *st) /* current state object */{ const struct connection *c = st->st_connection; u_int32_t ipsecdoisit; pb_stream next_proposal_pbs; struct isakmp_proposal next_proposal; ipsec_spi_t next_spi; bool next_full = TRUE; /* DOI */ if (sa->isasa_doi != ISAKMP_DOI_IPSEC) { loglog(RC_LOG_SERIOUS, "Unknown or unsupported DOI %s", enum_show(&doi_names, sa->isasa_doi)); /* XXX Could send notification back */ return DOI_NOT_SUPPORTED; } /* Situation */ if (!in_struct(&ipsecdoisit, &ipsec_sit_desc, sa_pbs, NULL)) return SITUATION_NOT_SUPPORTED; if (ipsecdoisit != SIT_IDENTITY_ONLY) { loglog(RC_LOG_SERIOUS, "unsupported IPsec DOI situation (%s)" , bitnamesof(sit_bit_names, ipsecdoisit)); /* XXX Could send notification back */ return SITUATION_NOT_SUPPORTED; } /* The rules for IPsec SAs are scattered. * RFC 2408 "ISAKMP" section 4.2 gives some info. * There may be multiple proposals. Those with identical proposal * numbers must be considered as conjuncts. Those with different * numbers are disjuncts. * Each proposal may have several transforms, each considered * an alternative. * Each transform may have several attributes, all applying. * * To handle the way proposals are combined, we need to do a * look-ahead. */ if (!in_struct(&next_proposal, &isakmp_proposal_desc, sa_pbs, &next_proposal_pbs)) return BAD_PROPOSAL_SYNTAX; /* for each conjunction of proposals... */ while (next_full) { int propno = next_proposal.isap_proposal; pb_stream ah_prop_pbs, esp_prop_pbs, ipcomp_prop_pbs; struct isakmp_proposal ah_proposal, esp_proposal, ipcomp_proposal; ipsec_spi_t ah_spi, esp_spi, ipcomp_cpi; bool ah_seen = FALSE, esp_seen = FALSE, ipcomp_seen = FALSE; int inner_proto = 0; bool tunnel_mode = FALSE; u_int16_t well_known_cpi = 0; pb_stream ah_trans_pbs, esp_trans_pbs, ipcomp_trans_pbs; struct isakmp_transform ah_trans, esp_trans, ipcomp_trans; struct ipsec_trans_attrs ah_attrs, esp_attrs, ipcomp_attrs; /* for each proposal in the conjunction */ do { if (next_proposal.isap_protoid == PROTO_IPCOMP) { /* IPCOMP CPI */ if (next_proposal.isap_spisize == IPSEC_DOI_SPI_SIZE) { /* This code is to accommodate those peculiar * implementations that send a CPI in the bottom of an * SPI-sized field. * See draft-shacham-ippcp-rfc2393bis-05.txt 4.1 */ u_int8_t filler[IPSEC_DOI_SPI_SIZE - IPCOMP_CPI_SIZE]; if (!in_raw(filler, sizeof(filler) , &next_proposal_pbs, "CPI filler") || !all_zero(filler, sizeof(filler))) return INVALID_SPI; } else if (next_proposal.isap_spisize != IPCOMP_CPI_SIZE) { loglog(RC_LOG_SERIOUS, "IPsec Proposal with improper CPI size (%u)" , next_proposal.isap_spisize); return INVALID_SPI; } /* We store CPI in the low order of a network order * ipsec_spi_t. So we start a couple of bytes in. */ zero(&next_spi); if (!in_raw((u_char *)&next_spi + IPSEC_DOI_SPI_SIZE - IPCOMP_CPI_SIZE , IPCOMP_CPI_SIZE, &next_proposal_pbs, "CPI")) return INVALID_SPI; /* If sanity ruled, CPIs would have to be such that * the SAID (the triple (CPI, IPCOM, destination IP)) * would be unique, just like for SPIs. But there is a * perversion where CPIs can be well-known and consequently * the triple is not unique. We hide this fact from * ourselves by fudging the top 16 bits to make * the property true internally! */ switch (ntohl(next_spi)) { case IPCOMP_DEFLATE: well_known_cpi = ntohl(next_spi); next_spi = uniquify_his_cpi(next_spi, st); if (next_spi == 0) { loglog(RC_LOG_SERIOUS , "IPsec Proposal contains well-known CPI that I cannot uniquify"); return INVALID_SPI; } break; default: if (ntohl(next_spi) < IPCOMP_FIRST_NEGOTIATED || ntohl(next_spi) > IPCOMP_LAST_NEGOTIATED) { loglog(RC_LOG_SERIOUS, "IPsec Proposal contains CPI from non-negotiated range (0x%lx)" , (unsigned long) ntohl(next_spi)); return INVALID_SPI; } break; } } else { /* AH or ESP SPI */ if (next_proposal.isap_spisize != IPSEC_DOI_SPI_SIZE) { loglog(RC_LOG_SERIOUS, "IPsec Proposal with improper SPI size (%u)" , next_proposal.isap_spisize); return INVALID_SPI; } if (!in_raw((u_char *)&next_spi, sizeof(next_spi), &next_proposal_pbs, "SPI")) return INVALID_SPI; /* SPI value 0 is invalid and values 1-255 are reserved to IANA. * RFC 2402 (ESP) 2.4, RFC 2406 (AH) 2.1 * IPCOMP??? */ if (ntohl(next_spi) < IPSEC_DOI_SPI_MIN) { loglog(RC_LOG_SERIOUS, "IPsec Proposal contains invalid SPI (0x%lx)" , (unsigned long) ntohl(next_spi)); return INVALID_SPI; } } if (next_proposal.isap_notrans == 0) { loglog(RC_LOG_SERIOUS, "IPsec Proposal contains no Transforms (skipped)"); continue; } switch (next_proposal.isap_protoid) { case PROTO_IPSEC_AH: if (ah_seen) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -