📄 fa_reply.c
字号:
DEBUG(DEBUG_FLAG, "Confirmed binding data - old lower_addr: %s, ", inet_ntoa(binding->lower_addr)); DEBUG(DEBUG_FLAG, "new lower_addr: %s\n", inet_ntoa(unc->info.src.sin_addr)); if (unc->info.src.sin_addr.s_addr != binding->lower_addr.s_addr || unc->info.src.sin_port != binding->lower_port || unc->tunnel_mode != t_data->tunnel_mode || unc->is_lowest_fa != t_data->is_lowest_fa || unc->fa_decapsulation != t_data->fa_decapsulation || unc->encaps_delivery != t_data->encaps_delivery || unc->info.iface != t_data->info.iface) { struct saved_binding_info old; /* the iface argument is NULL because the reply may not come * from the same interface as the request */ save_binding_info(&old, binding); update_reply_binding_info(binding, unc); if (handle_lower_switch(binding, &old, ext, &unc->info.src.sin_addr, FALSE) != 0) return 1; } unconfirmed_to_binding(binding, unc); free_unconfirmed_data(t_data->unc_req); t_data->unc_req = NULL; return 0;}static intget_fa_session_key_sec(unsigned char *sk, int *sk_len, struct reg_rep *reply, struct msg_key *fa_keyrep, struct in_addr addr){ struct fa_spi_entry *fa_spi; unsigned char *tmp_sk;#ifndef NODEBUGMODE int i;#endif fa_spi = get_fa_spi(ntohl(fa_keyrep->spi), addr, 0); if (fa_spi == NULL) { LOG2(LOG_WARNING, "Could not handle fa_keyrep with " "SPI %i\n", ntohl(fa_keyrep->spi)); return 1; } tmp_sk = auth_decrypt(fa_spi->alg, fa_spi->shared_secret, fa_spi->shared_secret_len, fa_keyrep, reply, sk_len); if (*sk_len < 0) { LOG2(LOG_WARNING, "Could not decrypt fa_keyrep with " "SPI %i\n", ntohl(fa_keyrep->spi)); return 1; } if (*sk_len > MAX_SK_LEN) { LOG2(LOG_WARNING, "Too long session key\n"); free(tmp_sk); return 1; } memcpy(sk, tmp_sk, *sk_len); free(tmp_sk);#ifndef NODEBUGMODE DEBUG(DEBUG_FLAG, "Session key (MD5): "); for (i = 0; i < *sk_len; i++) DEBUG(DEBUG_FLAG, "%02x", sk[i]); DEBUG(DEBUG_FLAG, "\n");#endif return 0;}static intget_fa_session_key_pub(unsigned char *sk, int *sk_len, struct tunnel_data *t_data, struct msg_key *fa_pubkeyrep){ if (t_data->last_sent_fa_pubkeyrep != NULL) { free(t_data->last_sent_fa_pubkeyrep); t_data->last_sent_fa_pubkeyrep = NULL; } if (t_data->last_recv_fa_pubkeyrep != NULL) free(t_data->last_recv_fa_pubkeyrep); t_data->last_recv_fa_pubkeyrep = (struct msg_key *) malloc(GET_KEY_EXT_LEN(fa_pubkeyrep)); if (t_data->last_recv_fa_pubkeyrep == NULL) return 1; memcpy(t_data->last_recv_fa_pubkeyrep, fa_pubkeyrep, GET_KEY_EXT_LEN(fa_pubkeyrep)); *sk_len = MD5_SK_LEN; if (do_rsa_decrypt(fa_pubkeyrep, sk, *sk_len) != 0) return 1; return 0;}/** * get_fa_session_key: * @sk: * @sk_len: * @ext: * @addr: * @binding: * * Extract the session key from @ext (distributed either by symmetric * secret encryption, or public key encryption). If the @ext does not * contain a key use an already decrypted key in @binding. * * The key is placed in @sk, and its length in @sk_len. * * Returns: 0 if successful */static intget_fa_session_key(unsigned char *sk, int *sk_len, struct msg_extensions *ext, struct in_addr addr, struct bindingentry *binding){ struct tunnel_data *t_data = (struct tunnel_data *) binding->data; if (ext->fa_keyrep) { /* shared secret based session key distribution */ return get_fa_session_key_sec(sk, sk_len, ext->rep, ext->fa_keyrep, addr); } /* public key based session key distribution */ if (ext->fa_pubkeyrep != NULL && ntohs(ext->rep->lifetime) > 0 && !equal_pubkey(ext->fa_pubkeyrep, t_data->last_recv_fa_pubkeyrep)) { /* new key */ return get_fa_session_key_pub(sk, sk_len, t_data, ext->fa_pubkeyrep); } /* use already decrypted key */ memcpy(sk, binding->key, binding->keylen); *sk_len = binding->keylen; return 0;}struct binding_search_data { struct in_addr mn_addr; __u32 id1;};static struct binding_search_data bsearch_data;/* returns 1 if bsearch_data matches with the given binding or 0 if it does * not match; to be used with binding_fetch_func() */static intbinding_search_check(struct bindingentry *binding){ struct tunnel_data *t_data; struct unconfirmed_request *unc; if (binding->mn_addr.s_addr != bsearch_data.mn_addr.s_addr) return 0; if (binding->data == NULL) return 0; t_data = (struct tunnel_data *) binding->data; if (t_data->confirmed && bsearch_data.id1 == binding->id[1]) return 1; unc = t_data->unc_req; while (unc != NULL) { if (unc->id[1] == bsearch_data.id1) return 1; unc = unc->next; } return 0;}/** * handle_reply: * @ext: * @info: source of reply message * @iface: interface where reply arrived * * Process a registration reply message. * * Returns: 0 if OK, else 1 */inthandle_reply(struct msg_extensions *ext, struct packet_from_info *info){ struct bindingentry *binding; struct tunnel_data *t_data; unsigned char sk[MAX_SK_LEN]; int prev_confirmed, sk_len, i, idtype; struct unconfirmed_request *unc; char tmp[30]; struct bindingkey bkey; DEBUG(DEBUG_FLAG, "Handling reply\n"); memcpy(&bkey.mn_addr, &(ext->rep->home_addr), sizeof(bkey.mn_addr)); memcpy(&bkey.ha_addr, &(ext->rep->ha_addr), sizeof(bkey.ha_addr)); if (ext->priv_ha != NULL) bkey.priv_ha = ntohl(ext->priv_ha->priv_ha); else bkey.priv_ha = 0; if (ext->rep->code == REGREP_UNKNOWN_HA_HA) { bsearch_data.mn_addr.s_addr = ext->rep->home_addr.s_addr; bsearch_data.id1 = ntohl(ext->rep->id[1]); binding = binding_fetch_func(bindings_hash, binding_search_check); } else binding = binding_fetch(bindings_hash, &bkey); if (binding == NULL) { dynamics_strlcpy(tmp, inet_ntoa(info->src.sin_addr), sizeof(tmp)); LOG2(LOG_WARNING, "Received reply from %s:%i for MN %s, but " "no binding found\n", tmp, ntohs(info->src.sin_port), inet_ntoa(ext->rep->home_addr)); return 1; } t_data = binding->data; t_data->pending_request = FALSE; unc = find_matching_request(binding, ntohl(ext->rep->id[1]), &idtype); if (idtype == ID_NOT_FOUND || (t_data->info.iface == NULL && unc == NULL)) { LOG2(LOG_WARNING, "Could not found a matching request for the " "reply - dropping it\n"); return 1; } assert(t_data->confirmed || unc != NULL); i = validate_reply(ext, binding, info, unc); if (i < 0) { LOG2(LOG_WARNING, "Reply validation failed - dropping it\n"); return 1; } if (i == 1) { DEBUG(DEBUG_FLAG, "Reply did not have Dynamics extensions - " "assuming that HA/upper FA does not support them\n"); t_data->dynamics_extensions = 0; } else { t_data->dynamics_extensions = 1; } if (get_fa_session_key(sk, &sk_len, ext, info->src.sin_addr, binding) != 0) return 1; if (!IS_REGREP_ACCEPTED(ext->rep->code)) { /* Note: RFC 2002 - chapter 3.7.2: * "If the Registration Reply indicates that the Request (for * registration or deregistration) was denied by the home * agent, the existing visitor list entry for the mobile node * MUST NOT be modified as a result of receiving the * Registration Reply." */ return forward_reply(binding, ext, 1, unc); } if (ntohs(ext->rep->lifetime) == 0) { /* Tear down or disconnect */ return handle_reply_disconnect(binding, unc, ext, idtype); } prev_confirmed = t_data->confirmed; if (!t_data->confirmed) { if (handle_unconfirmed_reply(binding, ext, sk, sk_len, unc) != 0) { LOG2(LOG_WARNING, "Reply to an unconfirmed binding " "could not be confirmed - dropping reply\n"); return 1; } } else { if (idtype == ID_NEW && handle_confirmed_reply(binding, ext, unc) != 0) { LOG2(LOG_WARNING, "Reply to a confirmed binding - " "confirming request data failed\n"); return 1; } } assert(t_data->confirmed); /* update the session key */ memcpy(binding->key, sk, sk_len); binding->keylen = sk_len; time(&binding->mod_time); if (ntohs(ext->rep->lifetime) > t_data->req_lifetime) { /* RFC 2002, sec. 3.4: * The home agent MUST NOT increase the Lifetime selected by * the mobile node in the Registration Request, since doing so * could increase it beyond the maximum Registration Lifetime * allowed by the foreign agent. If the Lifetime received in * the Registration Reply is greater than that in the * Registration Request, the Lifetime in the Request MUST be * used. */ LOG2(LOG_WARNING, "Lifetime too long in reply (%i) - using the" " lifetime of the request (%i)\n", ntohs(ext->rep->lifetime), t_data->req_lifetime); binding->timeout = t_data->req_lifetime; } else binding->timeout = ntohs(ext->rep->lifetime); if (binding->timeout > config->fa_default_tunnel_lifetime) { DEBUG(DEBUG_FLAG, "Lifetime too long - using max lifetime\n"); binding->timeout = config->fa_default_tunnel_lifetime; } /* increase timeout with one second so that the one second timer * resolution doesn't cause too early expirations */ binding->timeout++; binding->exp_time = time(NULL) + binding->timeout; if (update_binding(bindings_hash, binding, &bcounters) != 0) { LOG2(LOG_WARNING, "handle_reply: update_binding failed\n"); return 1; } /* In LFA prepare the tunnels first but in IFA send the reply first * and do the tunnel stuff afterwards. This speeds up the location * update time when using IFAs */ if (!t_data->is_lowest_fa) { DEBUG(DEBUG_FLAG, "handle_reply: not lowest FA: forwarding " "reply first and then create_tunnels\n"); i = forward_reply(binding, ext, 0, NULL); } /* create the tunnels if the binding was confirmed */ if (!prev_confirmed && t_data->confirmed && create_tunnels(binding, tunnels_hash, config->highest_FA) != 0) { LOG2(LOG_WARNING, "handle_reply: create_tunnels failed\n"); return 1; } if (t_data->is_lowest_fa) { DEBUG(DEBUG_FLAG, "handle_reply: lowest FA: forwarding reply " "after create_tunnels ok\n"); i = forward_reply(binding, ext, 0, NULL); } return i; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -