📄 fa_request.c
字号:
} DEBUG(DEBUG_FLAG, "\tbinding->timeout=%i, calculated timeout=%i\n", binding->timeout, timeout); reply->lifetime = htons(timeout); reply->home_addr.s_addr = ext->req->home_addr.s_addr; reply->ha_addr.s_addr = ext->req->ha_addr.s_addr; reply->id[0] = ext->req->id[0]; reply->id[1] = ext->req->id[1]; len += sizeof(struct reg_rep); if (config->send_sfa_debug_ext) { struct sfa_debug_ext *sfa_ext = (struct sfa_debug_ext *) (msg + len); sfa_ext->type = VENDOR_EXT_TYPE2; sfa_ext->reserved = 0; sfa_ext->vendor_id = htonl(VENDOR_ID_DYNAMICS); sfa_ext->sub_type = htons(VENDOR_EXT_DYNAMICS_SFA_DEBUG); sfa_ext->length = sizeof(struct sfa_debug_ext) - 2; sfa_ext->sfa_addr = up_interface->addr; len += GET_SFA_DEBUG_EXT_LEN(sfa_ext); DEBUG(DEBUG_FLAG, " * added SFA debug ext\n"); } if (t_data->is_lowest_fa && config->enable_challenge_response && config->challenge_in_reg_reply) { struct challenge_ext *challenge; challenge = create_challenge_ext(config, MN_FA_CHALLENGE_EXT); if (challenge != NULL) { int n = GET_CHALLENGE_EXT_LEN(challenge); if (len + n > MAXMSG) { free(challenge); return 1; } memcpy(msg + len, challenge, n); len += n; /* save the last challenge so that MN's registration * requests can be checked to contain a valid challenge */ if (t_data->last_challenge != NULL) free(t_data->last_challenge); t_data->last_challenge = challenge; DEBUG(DEBUG_FLAG, " * added challenge ext\n"); } } if (len + sizeof(struct msg_auth) + MD5_MAC_LEN > MAXMSG) return 1; len += auth_add_vendor( AUTH_ALG_MD5, binding->key, binding->keylen, msg, (struct vendor_msg_auth *) (msg + len), VENDOR_EXT_DYNAMICS_SK_AUTH, ext->sk_auth != NULL ? ext->sk_auth->spi : 0); /* Foreign Agent key reply - add only if not lowest FA * Use shared secret and MD5 if fa_keyreq was used or RSA if * fa_pubkey was used */ if (binding->fa_spi != 0) { fa_spi = get_fa_spi(binding->fa_spi, binding->lower_addr, SPI_AGENT_FA); 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 (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 (t_data->fa_pubkey != NULL) { 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) 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)); len += GET_KEY_EXT_LEN(t_data->last_sent_fa_pubkeyrep); } len += add_fa_auth_ext(binding->lower_addr, ext->req->home_addr, msg, msg + len); 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); if (config->packet_socket_mode != PACKET_SOCKET_MODE_ONLY_RECEIVE && t_data->is_lowest_fa) ret = packet_socket_send(&t_data->info, msg, len); else ret = own_sendto(t_data->info.iface->udp_sock, binding->lower_addr, binding->lower_port, msg, len); dynamics_check_sendto(ret, len, "reply_message"); return 0;}/** * update_request_binding_info: * @binding: * @ext: * @iface: NULL if reply * @info: Source of the request message * @dst_addr: Destination address of the request message * * */static voidupdate_request_binding_info(struct bindingentry *binding, struct msg_extensions *ext, struct packet_from_info *info){ struct tunnel_data *t_data = (struct tunnel_data *) binding->data; /* update down interface pointer */ memcpy(&t_data->info, info, sizeof(*info)); t_data->old_if_index = info->iface->if_index; /* update lower end type (MN/FA) */ t_data->is_lowest_fa = is_sender_mobile(ext); /* update MN/FA decapsulation mode */ t_data->fa_decapsulation = t_data->is_lowest_fa && (ext->req->opts & REGREQ_MN_DECAPS) == 0; /* update encapsulating delivery mode */ t_data->encaps_delivery = !t_data->is_lowest_fa || ext->encaps_del != NULL; /* update down_type and down_key */ if (ext->gre_key != NULL) { t_data->down_type = TUNNEL_GRE; t_data->down_key = ntohl(ext->gre_key->key); } else if (!t_data->fa_decapsulation || t_data->encaps_delivery) { t_data->down_type = TUNNEL_IPIP; t_data->down_key = 0; } else { t_data->down_type = TUNNEL_NO_ENCAPS; t_data->down_key = info->iface->if_index; } /* update FA public key */ if (!equal_pubkey(t_data->fa_pubkey, ext->fa_pubkey)) { 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->fa_pubkey != NULL) { DEBUG(DEBUG_FLAG, "Removing the previous fa_pubkey\n"); free(t_data->fa_pubkey); t_data->fa_pubkey = NULL; } if (ext->fa_pubkey) { DEBUG(DEBUG_FLAG, "Adding new fa_pubkey\n"); t_data->fa_pubkey = (struct msg_key *) malloc(GET_KEY_EXT_LEN(ext->fa_pubkey)); if (t_data->fa_pubkey != NULL) { memcpy(t_data->fa_pubkey, ext->fa_pubkey, GET_KEY_EXT_LEN(ext->fa_pubkey)); } else { LOG2(LOG_WARNING, "Not enough memory " "for fa_pubkey\n"); } } } /* update binding lower address and port */ binding->lower_addr = info->src.sin_addr; binding->lower_port = info->src.sin_port; /* update FA keyreq SPI */ if (ext->fa_keyreq) binding->fa_spi = ntohl(ext->fa_keyreq->spi); else binding->fa_spi = 0; setup_device_forcing(t_data); /* update tunnel mode */ if ((ext->req->opts & REGREQ_REVERSE_TUNNEL) != 0 || config->force_reverse_tunneling) t_data->tunnel_mode = TUNNEL_MODE_REVERSE; else t_data->tunnel_mode = TUNNEL_MODE_TRIANGLE; #ifdef USE_TEARDOWN /* FIX-JM: update t_data->upper_id ?? */#endif}/** * save_binding_information: * @save: Where to copy binding info * @binding: A binding containing the info to copy * * Copies information from @binding to @save. */voidsave_binding_info(struct saved_binding_info *save, const struct bindingentry *binding){ struct tunnel_data *t_data; t_data = binding->data; save->lower_addr = binding->lower_addr; save->lower_port = binding->lower_port; save->is_lowest_fa = t_data->is_lowest_fa; save->down_type = t_data->down_type; save->down_key = t_data->down_key; save->fa_decapsulation = t_data->fa_decapsulation; save->encaps_delivery = t_data->encaps_delivery; save->down_tunl = t_data->down_tunl; save->down_iface = t_data->info.iface; memcpy(save->force_route_dev, t_data->force_route_dev, IFNAMSIZ); memcpy(save->force_reverse_dev, t_data->force_reverse_dev, IFNAMSIZ); save->tunnel_mode = t_data->tunnel_mode; return;}/** * debug_compare_binding_info: * @old: * @binding: * * Compare old and changed binding information and print * debug information about it */static voiddebug_compare_binding_info(const struct saved_binding_info *old, const struct bindingentry *binding){ struct tunnel_data *t_data; t_data = binding->data; if (t_data->info.iface != old->down_iface) { DEBUG(DEBUG_FLAG, "\tdown interface changed %s => %s\n", old->down_iface->dev, t_data->info.iface->dev); } if (t_data->is_lowest_fa && !old->is_lowest_fa) DEBUG(DEBUG_FLAG, "\tlower end changed FA -> MN\n"); else if (!t_data->is_lowest_fa && old->is_lowest_fa) DEBUG(DEBUG_FLAG, "\tlower end changed MN -> FA\n"); if (old->fa_decapsulation != t_data->fa_decapsulation) { DEBUG(DEBUG_FLAG, "\tFA decapsulation changed %i => %i\n", old->fa_decapsulation, t_data->fa_decapsulation); } if (old->encaps_delivery != t_data->encaps_delivery) { DEBUG(DEBUG_FLAG, "\tencaps. delivery changed: %i => %i\n", old->encaps_delivery, t_data->encaps_delivery); } if (t_data->down_type != old->down_type || t_data->down_key != old->down_key) { DEBUG(DEBUG_FLAG, "\ttunnel type changed: %i,%i => %i,%i\n", old->down_type, old->down_key, t_data->down_type, t_data->down_key); } if (binding->lower_addr.s_addr != old->lower_addr.s_addr) { DEBUG(DEBUG_FLAG, "\tlower addr changed %s => ", inet_ntoa(old->lower_addr)); DEBUG(DEBUG_FLAG, "%s\n", inet_ntoa(binding->lower_addr)); } if (binding->lower_port != old->lower_port) { DEBUG(DEBUG_FLAG, "\tlower port changed %i => %i\n", ntohs(old->lower_port), ntohs(binding->lower_port)); } if (strcmp(t_data->force_route_dev, old->force_route_dev) != 0) { DEBUG(DEBUG_FLAG, "\tforce route dev changed %s => %s\n", old->force_route_dev, t_data->force_route_dev); } if (strcmp(t_data->force_reverse_dev, old->force_reverse_dev) != 0) { DEBUG(DEBUG_FLAG, "\tforce reverse dev changed %s => %s\n", old->force_reverse_dev, t_data->force_reverse_dev); }} /** * handle_lower_switch: * @binding: MN's binding entry * @old: saved binding data * @ext: request/reply message data * @info: source of the request message * * Handle registration request as switched FA. * * 1. Send reply * 2. Make tunnel to new lower FA * 3. Connect the new tunnel to upper agent and change route from HA * to new lower FA/MN * 4. Send Tear Down message * 5. Unconnect old tunnel * 6. Delete old tunnel (delayed) * * Returns: 0 if successful, * 1 on error */inthandle_lower_switch(struct bindingentry *binding, struct saved_binding_info *old, struct msg_extensions *ext, struct in_addr *addr, int request_auth_ok){ struct tunnel_data *t_data; int reverse; assert(binding != NULL && binding->data != NULL); DEBUG(DEBUG_FLAG, "Lower FA or MN address changed (locupd)\n"); t_data = binding->data; assert(t_data->info.iface != NULL); /* tell about the changes made */ debug_compare_binding_info(old, binding);#ifdef DYNAMICS_SET_MAIN_TABLE_MN_ROUTE if (old->fa_decapsulation && !t_data->fa_decapsulation && dyn_ip_route_del(binding->mn_addr, old->down_iface->dev) != 0) { LOG2(LOG_WARNING, "dyn_ip_route_del(%s,%s) failed\n", inet_ntoa(binding->mn_addr), old->down_iface->dev); } /* add/replace host route to MN if in FA decaps mode */ if (t_data->is_lowest_fa && !old->is_lowest_fa && t_data->fa_decapsulation && dyn_ip_route_replace(binding->mn_addr, t_data->info.iface->dev) == -1) { LOG2(LOG_WARNING, "handle_lower_switch: " "dyn_ip_route_replace(%s,%s) failed.\n", inet_ntoa(binding->mn_addr), t_data->info.iface->dev); }#endif /* DYNAMICS_SET_MAIN_TABLE_MN_ROUTE */ /* 1. Send reply */ /* Send reply if the request is valid * (if not valid, the reply is forwarded elsewhere) */ if (request_auth_ok) { reply_message(binding, ext); } /* 2. Make tunnel to new lower FA */ t_data->down_tunl = tunnel_add( tunnels_hash, *addr, binding->tun_dev, t_data->info.iface->addr, 1, t_data->down_type, t_data->down_key); if (t_data->down_tunl == NULL) { LOG2(LOG_WARNING, "handle_lower_switch: tunnel_add failed!\n"); return 1; } /* 3. Connect the new tunnel to upper agent */ /* Note: "To MN" routing table does not change, so no need to update * routing rule for locally generated packets. */ /* Use delayed tunnel unconnect and make a new connect */ reverse = old->tunnel_mode == TUNNEL_MODE_REVERSE ? 1 : 0; if (tunnel_unconnect(t_data->up_tunl, old->down_tunl, binding->mn_addr, reverse, 0, old->force_route_dev, old->force_reverse_dev) < 0) { LOG2(LOG_WARNING, "handle_lower_switch: tunnel_unconnect failed!\n"); } reverse = t_data->tunnel_mode == TUNNEL_MODE_REVERSE ? 1 : 0; if (tunnel_connect(t_data->up_tunl, t_data->down_tunl, binding->mn_addr, reverse, t_data->force_route_dev, t_data->force_reverse_dev) < 0) { LOG2(LOG_WARNING, "handle_lower_switch: tunnel_connect failed!\n"); return 1; }#ifdef USE_TEARDOWN /* 4. Send Tear Down message */ /* Send a tear down message only if this is not the lowest FA */ if (old->lowest_fa == FALSE) { if (send_tear_down(binding, old->lower_addr, old->lower_port, old->down_iface)) DEBUG(DEBUG_FLAG, "send_tear_down failed\n"); } else DEBUG(DEBUG_FLAG, "Lowest FA - no tear down reply sent\n");#endif /* 5. Delayed tunnel deletion (6. delete tunnel) */ if (tunnel_delete_ptr(old->down_tunl, 0) < 0) { LOG2(LOG_WARNING, "handle_lower_switch: tunnel delete " "failed\n"); return 1; } return 0;}/* Create tunnel and table for the tunnel. The table will get route for MN. * This enables data coming from upper mobility agent to be routed to MN. * --> Lesser packet loss when SFA or HA changes the route (data path is * already made available for downstream packets). * * For security reasons, do nothing if this is the HFA. * * Returns 0 if successful, else 1 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -