📄 fa_reply.c
字号:
(ext->ext_dyn->opts & REG_EXT_OWN_TEAR_DOWN) == 0) { forward_reply(binding, ext, 1, unc); } else { DEBUG(DEBUG_FLAG, "handle_reply_disconnect: tear down reply " "not forwarded to MN\n"); } /* Delay binding removal in tear down processing */ if (t_data->confirmed == 1) { DEBUG(DEBUG_FLAG, "Tear down/disconnect: Delay binding " "removal\n"); /* eliminate old session key so that all the new requests will * be forwarded upwards */ memset(&binding->key, 0, MAX_SK_LEN); binding->keylen = 0;#ifdef REMOVE_BINDING_OPTIM binding->timeout = 0; binding->exp_time = time(NULL); if (update_binding(bindings_hash, binding, &bcounters) != 0) LOG2(LOG_WARNING, "binding removal: " "update_binding failed\n");#else /* Leave the disconnect binding up for * DELAY_BINDING_TIME seconds so that possible queued * data can still be forwarded. The tear down message * does not change the binding timeout in order to * avoid DoS attacks with tear down messages. The * session key is still reset, so the returning MN * does not cause problems. */ if (ext->ext_dyn == NULL || (ext->ext_dyn->opts & REG_EXT_OWN_TEAR_DOWN) == 0) { if (binding->timeout > 2) { DEBUG(DEBUG_FLAG, "Deregistration reply - " "setting tunnel lifetime to 2 secs\n"); binding->timeout = 2; } binding->exp_time = time(NULL) + binding->timeout; if (update_binding(bindings_hash, binding, &bcounters) != 0) LOG2(LOG_WARNING, "delay binding removal: " "update_binding failed\n"); } else {#ifdef SHORT_BINDING_DELAY_TIME /* ONLY FOR TESTING */ if (binding->timeout != DELAY_BINDING_TIME) { DEBUG(DEBUG_FLAG, "Deregistration reply - " "setting tunnel lifetime to 2 secs\n"); binding->timeout = DELAY_BINDING_TIME; } binding->exp_time = time(NULL) + binding->timeout; if (update_binding(bindings_hash, binding, &bcounters) != 0) LOG2(LOG_WARNING, "delay binding removal: " "update_binding failed\n");#endif /* SHORT_BINDING_DELAY_TIME */ DEBUG(DEBUG_FLAG, "Teardown - only resetting the " "session key\n"); } return 0;#endif } /* NOTE: With lazy tunnel deletion the tunnel will be up long enough (make sure that tunnel.c:PURGE_TUNNEL_TIME >= 2) */ /* remove the tunnels associated to this binding */ remove_binding_tunnels(binding, tunnels_hash, &bcounters); return 0;}static intforward_reply(struct bindingentry *binding, struct msg_extensions *ext, int error_reply, struct unconfirmed_request *unc){ char msg[MAXMSG]; int len, ret; struct tunnel_data *t_data; struct reg_rep *reply; struct msg_key *key; struct fa_spi_entry *fa_spi; struct packet_from_info *dst; assert(binding != NULL && binding->data != NULL); if (ext->rep == NULL) return 1; t_data = binding->data; if (!t_data->confirmed) error_reply = TRUE; if (error_reply && !IS_REGREP_ACCEPTED(ext->rep->code)) DEBUG(DEBUG_FLAG, "Forwarding error reply - code=%i - %s\n", ext->rep->code, reply_code_str(ext->rep->code)); else DEBUG(DEBUG_FLAG, "Forwarding reply\n"); if (ext->mh_auth != NULL) { /* copy the MAC protected area directly from the received * message. This area should include at least the reply * header, mn_keyrep and mh_auth. */ len = (__u8 *) ext->mh_auth - (__u8 *) ext->rep + GET_AUTH_EXT_LEN(ext->mh_auth); if (len < sizeof(struct reg_rep) + GET_AUTH_EXT_LEN(ext->mh_auth) || len > MAXMSG) { LOG2(LOG_WARNING, "forward_reply: invalid length %i\n", len); return 1; } memcpy(msg, ext->rep, len); DEBUG(DEBUG_FLAG, " * copying up to and including mh_auth " "(len ==> %i)\n", len); } else { /* no mh_auth - copy only the reply header */ memcpy(msg, ext->rep, sizeof(struct reg_rep)); len = sizeof(struct reg_rep); DEBUG(DEBUG_FLAG, " * copying reply header (len=%i)\n", len); } reply = (struct reg_rep *) msg; if (!error_reply && binding->fa_spi != 0 && ntohs(ext->rep->lifetime) > 0) { fa_spi = get_fa_spi(binding->fa_spi, (unc ? unc->info.src.sin_addr : binding->lower_addr), 0); if (fa_spi == NULL) { LOG2(LOG_WARNING, "unknown FA SPI %i, IP=%s\n", binding->fa_spi, inet_ntoa(binding->lower_addr)); return 1; } key = (struct msg_key *) (msg + len); if (((char *) MSG_KEY_DATA(key)) + MAX_SK_LEN > msg + MAXMSG) { LOG2(LOG_WARNING, "not enough space for SK to FA\n"); return 1; } len += auth_encrypt(fa_spi->alg, fa_spi->shared_secret, fa_spi->shared_secret_len, binding->key, key, reply, VENDOR_EXT_DYNAMICS_FA_KEYREP, htonl(fa_spi->spi)); } else if (!error_reply && t_data->fa_pubkey && ntohs(ext->rep->lifetime) > 0) { /* encrypt the SK with lower FA pubkey */ if (t_data->last_sent_fa_pubkeyrep == NULL) { t_data->last_sent_fa_pubkeyrep = dynamics_do_rsa_encrypt(binding->key, binding->keylen, t_data->fa_pubkey); if (t_data->last_sent_fa_pubkeyrep == NULL) { LOG2(LOG_WARNING, "RSA encrypt failed\n"); return 1; } } if (len + GET_KEY_EXT_LEN(t_data->last_sent_fa_pubkeyrep) > MAXMSG) { LOG2(LOG_WARNING, "Message buffer overflow\n"); return 1; } memcpy(msg + len, t_data->last_sent_fa_pubkeyrep, GET_KEY_EXT_LEN(t_data->last_sent_fa_pubkeyrep)); DEBUG(DEBUG_FLAG, " * adding fa_pubkeyrep extension: pos=%i, len=%i\n", len, GET_KEY_EXT_LEN(t_data->last_sent_fa_pubkeyrep)); len += GET_KEY_EXT_LEN(t_data->last_sent_fa_pubkeyrep); } else if (!error_reply) { DEBUG(DEBUG_FLAG, " * no pubkey known - FA encrypt session key not " "added\n"); } if (ext->ext_dyn != NULL) { int elen = ext->ext_dyn->length + 2; if (len + elen > MAXMSG) { LOG2(LOG_WARNING, "Message buffer overflow\n"); return 1; } memcpy(msg + len, ext->ext_dyn, elen); DEBUG(DEBUG_FLAG, " * copying ext_dyn: pos=%i, len=%i\n", len, elen); len += elen; } if (ext->sfa_debug != NULL) { int elen = GET_SFA_DEBUG_EXT_LEN(ext->sfa_debug); if (len + elen > MAXMSG) { LOG2(LOG_WARNING, "Message buffer overflow\n"); return 1; } memcpy(msg + len, ext->sfa_debug, elen); DEBUG(DEBUG_FLAG, " * copying sfa_debug: pos=%i, len=%i\n", len, elen); len += elen; } if (len + sizeof(struct msg_auth) + MD5_MAC_LEN > MAXMSG) { LOG2(LOG_WARNING, "Message buffer overflow\n"); return 1; } if (!error_reply && ext->sk_auth != NULL) { DEBUG(DEBUG_FLAG, " * adding sk_auth extension: pos=%i, len=%i\n", len, MD5_MAC_LEN + SPI_LEN); len += auth_add_vendor(AUTH_ALG_MD5, binding->key, binding->keylen, (unsigned char *) reply, (struct vendor_msg_auth *) (msg + len), VENDOR_EXT_DYNAMICS_SK_AUTH, ext->sk_auth->spi); } len += add_fa_auth_ext((unc ? unc->info.src.sin_addr : binding->lower_addr), reply->home_addr, (unsigned char *) reply, (unsigned char *) msg + len); assert(len <= MAXMSG); dst = NULL; if (unc && unc->is_lowest_fa) dst = &unc->info; else if (!unc && t_data->is_lowest_fa) dst = &t_data->info; if (config->packet_socket_mode != PACKET_SOCKET_MODE_ONLY_RECEIVE && dst != NULL) { DEBUG(DEBUG_FLAG, " * sending %i bytes using packet socket\n", len); ret = packet_socket_send(dst, msg, len); } else if (unc) { DEBUG(DEBUG_FLAG, " * sending %i bytes to %s:%i (unc)\n", len, inet_ntoa(unc->info.src.sin_addr), ntohs(unc->info.src.sin_port)); assert(unc->info.iface != NULL); ret = own_sendto(unc->info.iface->udp_sock, unc->info.src.sin_addr, unc->info.src.sin_port, msg, len); } else { DEBUG(DEBUG_FLAG, " * sending %i bytes to %s:%i\n", len, inet_ntoa(binding->lower_addr), ntohs(binding->lower_port)); assert(t_data->info.iface != NULL); ret = own_sendto(t_data->info.iface->udp_sock, binding->lower_addr, binding->lower_port, msg, len); } return dynamics_check_sendto(ret, len, "Forward reply");}/* try to confirm an unconfirmed binding */static inthandle_unconfirmed_reply(struct bindingentry *binding, struct msg_extensions *ext, unsigned char *sk, int sk_len, struct unconfirmed_request *unc){ struct tunnel_data *t_data = (struct tunnel_data *) binding->data; /* check that the session key and sk_auth extension match */ if ((ext->fa_pubkeyrep != NULL || ext->fa_keyrep) && ext->sk_auth) { if (!auth_check_vendor(AUTH_ALG_MD5, sk, sk_len, (unsigned char *) ext->rep, ext->sk_auth)) { LOG2(LOG_WARNING, "Invalid sk_auth in reply\n"); return 1; } } else if (t_data->dynamics_extensions) { /* this should not be reached as dynamics_extensions implies * both fa_pubkeyrep and sk_auth extensions */ LOG2(LOG_WARNING, "Extensions fa_pubkeyrep, fa_keyrep and/or " "sk_auth missing\n"); return 1; } /* okay, match found - fill the binding with confirmed data */ unconfirmed_to_binding(binding, unc); t_data->confirmed = TRUE; DEBUG(DEBUG_FLAG, "\tconfirming the binding\n"); bcounters.bindingcount++; bcounters.pendingcount--; free_unconfirmed_data(t_data->unc_req); t_data->unc_req = NULL; return 0;}/** * update_reply_binding_info: * @binding: * @unc: * * Update binding info based on request data */static voidupdate_reply_binding_info(struct bindingentry *binding, const struct unconfirmed_request *unc){ struct tunnel_data *t_data = (struct tunnel_data *) binding->data; /* update down interface pointer */ memcpy(&t_data->info, &unc->info, sizeof(unc->info)); t_data->old_if_index = unc->info.iface->if_index; /* update lower end type (MN/FA) */ t_data->is_lowest_fa = unc->is_lowest_fa; /* update MN/FA decapsulation mode */ t_data->fa_decapsulation = unc->fa_decapsulation; /* update encapsulating delivery mode */ t_data->encaps_delivery = !t_data->is_lowest_fa || unc->encaps_delivery; /* update down_type and down_key */ t_data->down_type = unc->tunnel_type; t_data->down_key = unc->tunnel_key; /* update binding lower address and port */ binding->lower_addr = unc->info.src.sin_addr; binding->lower_port = unc->info.src.sin_port; binding->fa_spi = 0; setup_device_forcing(t_data); /* update tunnel mode */ t_data->tunnel_mode = unc->tunnel_mode;#ifdef USE_TEARDOWN /* FIX-JM: update t_data->upper_id ?? */#endif}/* handle a reply to an unconfirmed requests of a confirmed binding and switch * the lower side of the tunnel if needed * Returns: 0 = success, 1 = failure */static inthandle_confirmed_reply(struct bindingentry *binding, struct msg_extensions *ext, struct unconfirmed_request *unc){ struct tunnel_data *t_data = (struct tunnel_data *) binding->data; assert(unc != NULL); /* replace the binding data with the previously unconfirmed data */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -