ipsec_doi.c
来自「ipsec vpn」· C语言 代码 · 共 2,351 行 · 第 1/5 页
C
2,351 行
* st_connection->interface */ struct state st; struct connection cnx; passert(md); memset(&st, 0, sizeof(st)); memset(&cnx, 0, sizeof(cnx)); st.st_connection = &cnx; st.st_remoteaddr = md->sender; st.st_remoteport = md->sender_port; st.st_localaddr = md->iface->ip_addr; st.st_localport = md->iface->port; st.st_interface = md->iface; cnx.interface = md->iface; send_notification(&st, type, NULL, 0, md->hdr.isa_icookie, md->hdr.isa_rcookie, NULL, 0, PROTO_ISAKMP);}/** Send a Delete Notification to announce deletion of ISAKMP SA or * inbound IPSEC SAs. Does nothing if no such SAs are being deleted. * Delete Notifications cannot announce deletion of outbound IPSEC/ISAKMP SAs. * * @param st State struct (hopefully has some SA's related to it) */voidsend_delete(struct state *st){ pb_stream reply_pbs; pb_stream r_hdr_pbs; msgid_t msgid; u_char buffer[8192]; struct state *p1st; ip_said said[EM_MAXRELSPIS]; ip_said *ns = said; u_char *r_hashval, /* where in reply to jam hash value */ *r_hash_start; /* start of what is to be hashed */ bool isakmp_sa = FALSE; /* If there are IPsec SA's related to this state struct... */ if (IS_IPSEC_SA_ESTABLISHED(st->st_state)) { /* Find their phase1 state object */ p1st = find_phase1_state(st->st_connection, ISAKMP_SA_ESTABLISHED_STATES); if (p1st == NULL) { DBG(DBG_CONTROL, DBG_log("no Phase 1 state for Delete")); return; } if (st->st_ah.present) { ns->spi = st->st_ah.our_spi; ns->dst = st->st_connection->spd.this.host_addr; ns->proto = PROTO_IPSEC_AH; ns++; } if (st->st_esp.present) { ns->spi = st->st_esp.our_spi; ns->dst = st->st_connection->spd.this.host_addr; ns->proto = PROTO_IPSEC_ESP; ns++; } passert(ns != said); /* there must be some SAs to delete */ } /* or ISAKMP SA's... */ else if (IS_ISAKMP_SA_ESTABLISHED(st->st_state)) { p1st = st; isakmp_sa = TRUE; } else { return; /* nothing to do */ } msgid = generate_msgid(p1st); zero(buffer); init_pbs(&reply_pbs, buffer, sizeof(buffer), "delete msg"); /* HDR* */ { struct isakmp_hdr hdr; hdr.isa_version = ISAKMP_MAJOR_VERSION << ISA_MAJ_SHIFT | ISAKMP_MINOR_VERSION; hdr.isa_np = ISAKMP_NEXT_HASH; hdr.isa_xchg = ISAKMP_XCHG_INFO; hdr.isa_msgid = msgid; hdr.isa_flags = ISAKMP_FLAG_ENCRYPTION; memcpy(hdr.isa_icookie, p1st->st_icookie, COOKIE_SIZE); memcpy(hdr.isa_rcookie, p1st->st_rcookie, COOKIE_SIZE); if (!out_struct(&hdr, &isakmp_hdr_desc, &reply_pbs, &r_hdr_pbs)) impossible(); } /* HASH -- value to be filled later */ { pb_stream hash_pbs; if (!out_generic(ISAKMP_NEXT_D, &isakmp_hash_desc, &r_hdr_pbs, &hash_pbs)) impossible(); r_hashval = hash_pbs.cur; /* remember where to plant value */ if (!out_zero(p1st->st_oakley.hasher->hash_digest_len, &hash_pbs, "HASH(1)")) impossible(); close_output_pbs(&hash_pbs); r_hash_start = r_hdr_pbs.cur; /* hash from after HASH(1) */ } /* Delete Payloads */ if (isakmp_sa) { pb_stream del_pbs; struct isakmp_delete isad; u_char isakmp_spi[2*COOKIE_SIZE]; isad.isad_doi = ISAKMP_DOI_IPSEC; isad.isad_np = ISAKMP_NEXT_NONE; isad.isad_spisize = (2 * COOKIE_SIZE); isad.isad_protoid = PROTO_ISAKMP; isad.isad_nospi = 1; memcpy(isakmp_spi, st->st_icookie, COOKIE_SIZE); memcpy(isakmp_spi+COOKIE_SIZE, st->st_rcookie, COOKIE_SIZE); if (!out_struct(&isad, &isakmp_delete_desc, &r_hdr_pbs, &del_pbs) || !out_raw(&isakmp_spi, (2*COOKIE_SIZE), &del_pbs, "delete payload")) impossible(); close_output_pbs(&del_pbs); } else { while (ns != said) { pb_stream del_pbs; struct isakmp_delete isad; ns--; isad.isad_doi = ISAKMP_DOI_IPSEC; isad.isad_np = ns == said? ISAKMP_NEXT_NONE : ISAKMP_NEXT_D; isad.isad_spisize = sizeof(ipsec_spi_t); isad.isad_protoid = ns->proto; isad.isad_nospi = 1; if (!out_struct(&isad, &isakmp_delete_desc, &r_hdr_pbs, &del_pbs) || !out_raw(&ns->spi, sizeof(ipsec_spi_t), &del_pbs, "delete payload")) impossible(); close_output_pbs(&del_pbs); } } /* calculate hash value and patch into Hash Payload */ { struct hmac_ctx ctx; hmac_init_chunk(&ctx, p1st->st_oakley.hasher, p1st->st_skeyid_a); hmac_update(&ctx, (u_char *) &msgid, sizeof(msgid_t)); hmac_update(&ctx, r_hash_start, r_hdr_pbs.cur-r_hash_start); hmac_final(r_hashval, &ctx); DBG(DBG_CRYPT, DBG_log("HASH(1) computed:"); DBG_dump("", r_hashval, ctx.hmac_digest_len); ) } /* Do a dance to avoid needing a new state object. * We use the Phase 1 State. This is the one with right * IV, for one thing. * The tricky bits are: * - we need to preserve (save/restore) st_iv (but not st_iv_new) * - we need to preserve (save/restore) st_tpacket. */ { u_char old_iv[MAX_DIGEST_LEN]; chunk_t saved_tpacket = p1st->st_tpacket; save_iv(p1st, old_iv); init_phase2_iv(p1st, &msgid); if (!encrypt_message(&r_hdr_pbs, p1st)) impossible(); setchunk(p1st->st_tpacket, reply_pbs.start, pbs_offset(&reply_pbs)); send_packet(p1st, "delete notify", TRUE); p1st->st_tpacket = saved_tpacket; /* get back old IV for this state */ set_iv(p1st, old_iv); }}/** Accept a Delete SA notification, and process it if valid. * * @param st State structure * @param md Message Digest * @param p Payload digest */voidaccept_delete(struct state *st, struct msg_digest *md, struct payload_digest *p){ struct isakmp_delete *d = &(p->payload.delete); size_t sizespi; int i; /* We only listen to encrypted notifications */ if (!md->encrypted) { loglog(RC_LOG_SERIOUS, "ignoring Delete SA payload: not encrypted"); return; } /* If there is no SA related to this request, but it was encrypted */ if (!IS_ISAKMP_SA_ESTABLISHED(st->st_state)) { /* can't happen (if msg is encrypt), but just to be sure */ loglog(RC_LOG_SERIOUS, "ignoring Delete SA payload: " "ISAKMP SA not established"); return; } if (d->isad_nospi == 0) { loglog(RC_LOG_SERIOUS, "ignoring Delete SA payload: no SPI"); return; } switch (d->isad_protoid) { case PROTO_ISAKMP: sizespi = 2 * COOKIE_SIZE; break; case PROTO_IPSEC_AH: case PROTO_IPSEC_ESP: sizespi = sizeof(ipsec_spi_t); break; case PROTO_IPCOMP: /* nothing interesting to delete */ return; default: loglog(RC_LOG_SERIOUS , "ignoring Delete SA payload: unknown Protocol ID (%s)" , enum_show(&protocol_names, d->isad_protoid)); return; } if (d->isad_spisize != sizespi) { loglog(RC_LOG_SERIOUS , "ignoring Delete SA payload: bad SPI size (%d) for %s" , d->isad_spisize, enum_show(&protocol_names, d->isad_protoid)); return; } if (pbs_left(&p->pbs) != d->isad_nospi * sizespi) { loglog(RC_LOG_SERIOUS , "ignoring Delete SA payload: invalid payload size"); return; } for (i = 0; i < d->isad_nospi; i++) { u_char *spi = p->pbs.cur + (i * sizespi); if (d->isad_protoid == PROTO_ISAKMP) { /** * ISAKMP */ struct state *dst = find_state(spi /*iCookie*/ , spi+COOKIE_SIZE /*rCookie*/ , &st->st_connection->spd.that.host_addr , MAINMODE_MSGID); if (dst == NULL) { loglog(RC_LOG_SERIOUS, "ignoring Delete SA payload: " "ISAKMP SA not found (maybe expired)"); } else if (!same_peer_ids(st->st_connection, dst->st_connection, NULL)) { /* we've not authenticated the relevant identities */ loglog(RC_LOG_SERIOUS, "ignoring Delete SA payload: " "ISAKMP SA used to convey Delete has different IDs from ISAKMP SA it deletes"); } else { struct connection *oldc; oldc = cur_connection; set_cur_connection(dst->st_connection);#ifdef NAT_TRAVERSAL if (nat_traversal_enabled) { nat_traversal_change_port_lookup(md, dst); }#endif loglog(RC_LOG_SERIOUS, "received Delete SA payload: " "deleting ISAKMP State #%lu", dst->st_serialno); delete_state(dst); set_cur_connection(oldc); } } else { /** * IPSEC (ESP/AH) */ bool bogus; struct state *dst = find_phase2_state_to_delete(st , d->isad_protoid , *(ipsec_spi_t *)spi /* network order */ , &bogus); if (dst == NULL) { loglog(RC_LOG_SERIOUS , "ignoring Delete SA payload: %s SA(0x%08lx) not found (%s)" , enum_show(&protocol_names, d->isad_protoid) , (unsigned long)ntohl((unsigned long)*(ipsec_spi_t *)spi) , bogus ? "our SPI - bogus implementation" : "maybe expired"); } else { struct connection *rc = dst->st_connection; struct connection *oldc; oldc = cur_connection; set_cur_connection(rc);#ifdef NAT_TRAVERSAL if (nat_traversal_enabled) { nat_traversal_change_port_lookup(md, dst); }#endif if (rc->newest_ipsec_sa == dst->st_serialno && (rc->policy & POLICY_UP)) { /* Last IPSec SA for a permanent connection that we * have initiated. Replace it in a few seconds. * * Useful if the other peer is rebooting. */#define DELETE_SA_DELAY EVENT_RETRANSMIT_DELAY_0 if (dst->st_event != NULL && dst->st_event->ev_type == EVENT_SA_REPLACE && dst->st_event->ev_time <= DELETE_SA_DELAY + now()) { /* Patch from Angus Lees to ignore retransmited * Delete SA. */ loglog(RC_LOG_SERIOUS, "received Delete SA payload: " "already replacing IPSEC State #%lu in %d seconds" , dst->st_serialno, (int)(dst->st_event->ev_time - now())); } else { loglog(RC_LOG_SERIOUS, "received Delete SA payload: " "replace IPSEC State #%lu in %d seconds" , dst->st_serialno, DELETE_SA_DELAY); dst->st_margin = DELETE_SA_DELAY; delete_event(dst); event_schedule(EVENT_SA_REPLACE, DELETE_SA_DELAY, dst); } } else { loglog(RC_LOG_SERIOUS, "received Delete SA(0x%08lx) payload: " "deleting IPSEC State #%lu" , (unsigned long)ntohl((unsigned long)*(ipsec_spi_t *)spi) , dst->st_serialno); delete_state(dst); } /* reset connection */ set_cur_connection(oldc); } } }}/** The whole message must be a multiple of 4 octets. * I'm not sure where this is spelled out, but look at * rfc2408 3.6 Transform Payload. * Note: it talks about 4 BYTE boundaries! * * @param pbs PB Stream */voidclose_message(pb_stream *pbs){ size_t padding = pad_up(pbs_offset(pbs), 4); if (padding != 0) (void) out_zero(padding, pbs, "message padding"); close_output_pbs(pbs);}/* Initiate an Oakley Main Mode exchange. * --> HDR;SA * Note: this is not called from demux.c */static stf_statusmain_outI1(int whack_sock , struct connection *c , struct state *predecessor , lset_t policy , unsigned long try , enum crypto_importance importance){ struct state *st = new_state(); pb_stream reply; /* not actually a reply, but you know what I mean */ pb_stream rbody; /* set up new state */ st->st_connection = c; set_state_ike_endpoints(st, c); set_cur_state(st); /* we must reset before exit */ st->st_policy = policy & ~POLICY_IPSEC_MASK; st->st_whack_sock = whack_sock; st->st_try = try; st->st_state = STATE_MAIN_I1; st->st_import = importance; get_cookie(TRUE, st->st_icookie, COOKIE_SIZE, &c->spd.that.host_addr); insert_state(st); /* needs cookies, connection, and msgid (0) */ if (HAS_IPSEC_POLICY(policy)) add_pending(dup_any(whack_sock), st, c, policy, 1 , predecessor == NULL? SOS_NOBODY : predecessor->st_serialno); if (predecessor == NULL) openswan_log("initiating Main Mode"); else openswan_log("initiating Main Mode to replace #%lu", predecessor->st_serialno); /* set up reply */ init_pbs(&reply, reply_buffer, sizeof(reply_buffer), "reply packet"); /* HDR out */ { struct isakmp_hdr hdr; zero(&hdr); /* default to 0 */ hdr.isa_version = ISAKMP_MAJOR_VERSION << ISA_MAJ_SHIFT | ISAKMP_MINOR_VERSION; hdr.isa_np = ISAKMP_NEXT_SA; hdr.isa_xchg = ISAKMP_XCHG_IDPROT; memcpy(hdr.isa_icookie, st->st_icookie, COOKIE_SIZE); /* R-cookie, flags and MessageID are left zero */ if (!out_struct(&hdr, &isakmp_hdr_desc, &reply, &rbody)) { reset_cur_state(); return STF_INTERNAL_ERROR; } } /* SA out */ { u_char *sa_start = rbody.cur; int policy_index = POLICY_ISAKMP(policy , c->spd.this.xauth_server
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?