📄 mn_reg.c
字号:
* Home Agent */ LOG2(LOG_ALERT, "No authentication in the reply\n"); if (config.use_aaa) mn.aaa_rekey = 1; return 0; } /* check the possible mf_auth */ fa_spi = get_fa_spi(0, addr.sin_addr); if (ext->rep->code == REGREP_MN_FAILED_AUTH_FA && config.use_aaa && fa_spi != NULL && fa_spi->created != 0) { DEBUG(DEBUG_INFO, "FA reported incorrect authentication - " "trying to create a new security association\n"); remove_fa_spi(fa_spi); free(fa_spi); fa_spi = NULL; mn.try_to_fix_sec_assoc = 1; } if (fa_spi != NULL) { if (ext->mf_auth == NULL) { LOG2(LOG_ALERT, "No mf_auth in the reply even though " "there is a security association with the FA.\n"); return 0; } else if (!auth_check(fa_spi->alg, fa_spi->shared_secret, fa_spi->shared_secret_len, (unsigned char *) ext->rep, ext->mf_auth)) { LOG2(LOG_ALERT, "Incorrect FA->MN authentication " "extension received the reply\n"); return 0; } } else if (ext->mf_auth != NULL && !mn.try_to_fix_sec_assoc) { LOG2(LOG_ALERT, "Reply has an MN-FA auth. ext., but there is " "no security association with the FA.\n"); return 0; } /* verify id */ if (ntohl(ext->rep->id[1]) != mn.registration_id[1]) { LOG2(LOG_ALERT, "Wrong id field in the reply (was %08x, " "expected %08x)\n", ext->rep->id[1], (u32) htonl(mn.registration_id[1])); return 0; } if (ntohs(ext->rep->lifetime) > 0 && IS_REGREP_ACCEPTED(ext->rep->code) && config.ha_ip_addr.s_addr == 0) { DEBUG(DEBUG_INFO, "Discovered HA address from reply: %s\n", inet_ntoa(ext->rep->ha_addr)); config.ha_ip_addr.s_addr = ext->rep->ha_addr.s_addr; } if (ntohs(ext->rep->lifetime) > 0 && IS_REGREP_ACCEPTED(ext->rep->code) && config.mn_home_ip_addr.s_addr == 0) { DEBUG(DEBUG_INFO, "Discovered MN home address from " "reply: %s\n", inet_ntoa(ext->rep->home_addr)); mn.local_addr.s_addr = config.mn_home_ip_addr.s_addr = ext->rep->home_addr.s_addr; if (mn.current_adv != NULL && dyn_ip_iface_address(mn.current_adv->ifindex, &config.mn_home_ip_addr) != 1) { DEBUG(DEBUG_INFO, "Adding assigned home address to the" " interface\n"); if (dyn_ip_addr_add(mn.current_adv->ifname, config.mn_home_ip_addr) == 0) { mn.dynamic_home_addr.s_addr = config.mn_home_ip_addr.s_addr; memcpy(mn.dynamic_home_addr_dev, mn.current_adv->ifname, IFNAMSIZ); } else DEBUG(DEBUG_INFO, "dyn_ip_addr_add failed\n"); } } /* don't accept any further messages with same id */ mn.registration_id[1]++; return 1;#endif}/* Handle session key extension. Decrypt and copy to session_key */static void handle_key_ext(struct reg_rep *rep, struct msg_key *key){ ASSERT(rep != NULL && key != NULL); DEBUG(DEBUG_MESSAGES, "mobile-home key extension received\n"); /* If SPIs are different, something went wrong and we should * send another registration request to obtain session key. */ if (ntohl(key->spi) != config.spi) { LOG2(LOG_WARNING, "Wrong SPI in the key reply extension.\n"); return; } /* Extract new session key */ if (mn.session_key) free(mn.session_key); mn.session_key = auth_decrypt(config.auth_alg, config.shared_secret, config.shared_secret_len, key, rep, (int *) &mn.session_key_len); if (mn.session_key == NULL) { LOG2(LOG_ERR, "handle_key_ext: session key decryption failed\n"); mn.session_key_len = 0; return; } show_key_dump("Session key", mn.session_key, mn.session_key_len);}/* Handle registration accepting registration reply */static void handle_reg_accept(struct msg_extensions *ext){#ifdef MN_LOCUPD_PROFILER char tmp[30];#endif ASSERT(ext != NULL && ext->rep != NULL); /* Connection succeeded. It's ok to monitor agent adv. expiring */ mn.expire_check = 1; if (mn.current_adv != NULL) { /* reset retry wait time for next registration */ DEBUG(DEBUG_TIMERS, "FA[%s] reg_retry_time: " "%i => %i (reg. reply ok)\n", inet_ntoa(mn.current_adv->addr), mn.current_adv->reg_retry_time, MIN_REGISTRATION_TIME); mn.current_adv->reg_retry_time = MIN_REGISTRATION_TIME; } else mn.HA_reg_retry_time = MIN_REGISTRATION_TIME; if (ntohs(ext->rep->lifetime) > 0) { DEBUG(DEBUG_INFO, "Registration accepted\n");#ifdef INCLUDE_IPAY if (mn.current_adv != NULL) ipay_new_fa(mn.current_adv);#endif } else DEBUG(DEBUG_INFO, "Deregistration accepted\n"); switch (mn.state) { case MN_CLOSE_FOR_HOME: mn.ha_error_count = 0; if (ntohs(ext->rep->lifetime) == 0) at_home(); break; case MN_FIND_AGENT: case MN_PASSIVE_FIND: /* The answer is coming later than expected, * so we just skip it. */ DEBUG(DEBUG_MESSAGES, "handle_reg_accept - in find agent or " "passive find state - skipping reg. reply\n"); break; case MN_REQUEST_TUNNEL: case MN_CONNECTED: mn.ha_error_count = 0; if (ext->mn_keyrep != NULL) handle_key_ext(ext->rep, ext->mn_keyrep); if (ext->rep->lifetime == 0) { LOG2(LOG_INFO, "Got registration accepted reply with " "zero lifetime - aborting registration and going " "to passive find state\n"); reply_waiting_api(API_FAILED, NULL, 0); passive_find(); return; } else { connected((ext->mh_auth) ? CON_HA : CON_FA, ntohs(ext->rep->lifetime));#ifdef MN_LOCUPD_PROFILER snprintf(tmp, sizeof(tmp), "CON %s", inet_ntoa(mn.fa_addr)); write_profiler(tmp);#endif reply_waiting_api(API_SUCCESS, NULL, 0); } break; case MN_DISCONNECTED:#ifdef MN_LOCUPD_PROFILER write_profiler("DIS");#endif break; default: break; }}/* returns: 1 = try again, 0 = give up */static int handle_id_mismatch_ha(struct msg_extensions *ext){ /* If reply code is 133, id failed and we should resynchronize * clock/nonce and try again */#ifdef MN_LOCUPD_PROFILER write_profiler("DENY_ID");#endif switch (config.replay_meth) { case REPLAY_PROTECTION_NONE: LOG2(LOG_INFO, "ID mismatch from HA even with " "disabled replay protection\n"); reply_waiting_api(API_FAILED, &ext->rep->code, 1); disconnect(); break; case REPLAY_PROTECTION_TIMESTAMP: mn.clock_correction = ntohl(ext->rep->id[0]) - UNIX_NTP_DIFF - time(NULL); if (mn.ha_error_count++ < MAX_HA_ERRORS) { LOG2(LOG_INFO, "Clock synchronization %d seconds\n", mn.clock_correction); return 1; } else { LOG2(LOG_INFO, "Clock resynchronization failed. " "Disconnecting.\n"); reply_waiting_api(API_FAILED, &ext->rep->code, 1); disconnect(); } break; case REPLAY_PROTECTION_NONCE: if (mn.ha_error_count++ < MAX_HA_ERRORS) { LOG2(LOG_INFO, "Nonce mismatch - syncronizing\n"); return 1; } else { LOG2(LOG_INFO, "Nonce mismatch - " "syncronization failed\n"); reply_waiting_api(API_FAILED, &ext->rep->code, 1); disconnect(); } break; } return 0;}/* returns: 1 = try again, 0 = give up */static int handle_long_lifetime(struct msg_extensions *ext){#ifdef MN_LOCUPD_PROFILER write_profiler("LIFETIME_FA");#endif if (mn.req_lifetime > ntohs(ext->rep->lifetime) && ntohs(ext->rep->lifetime) >= MIN_ALLOWED_LIFETIME) { LOG2(LOG_INFO, "FA (closest FA %s), " "requests smaller lifetime (%d) - retrying\n", inet_ntoa(mn.fa_addr), ntohs(ext->rep->lifetime)); mn.req_lifetime = ntohs(ext->rep->lifetime); return 1; } /* this FA failed - try to find another one */ LOG2(LOG_INFO, "FA %s denies requested lifetime %d s with bad " "suggestion %d s - changing FA\n", inet_ntoa(mn.fa_addr), mn.req_lifetime, ntohs(ext->rep->lifetime)); if (mn.current_adv != NULL) mn.current_adv->reg_failed = 1; else LOG2(LOG_INFO, "handle_long_lifetime - current_adv == NULL\n"); find_agent(STATE_INIT); return 0;}/* returns: 1 = try again, 0 = give up */static int handle_unknown_ha(struct msg_extensions *ext){ int retry_hadisc = 0; /* dynamic home agent address resolution */ if (config.ha_ip_addr.s_addr != 0 || config.home_net_addr_plen < 0) { LOG2(LOG_INFO, "HA did not accept HA address %s\n", inet_ntoa(config.ha_ip_addr)); retry_hadisc = 1; } if (ext->rep->ha_addr.s_addr == config.home_net_subnet_bc.s_addr) { LOG2(LOG_INFO, "HA returned same subnet-directed broadcast " "address in dynamic address resolution\n"); retry_hadisc = 1; } if (retry_hadisc) { if (config.use_hadisc) { DEBUG(DEBUG_MESSAGES, "Try to discover another HA\n"); mn.info_str = "restarting HA discovery"; config.ha_ip_addr.s_addr = 0; return 1; } return 0; } LOG2(LOG_INFO, "Learned HA address (%s) with dynamic address " "resolution\n", inet_ntoa(ext->rep->ha_addr)); mn.info_str = "HA discovery completed successfully"; config.ha_ip_addr.s_addr = ext->rep->ha_addr.s_addr; return 1; /* try to register with the new HA address */}/** * handle_reg_denied: * ext: received and parsed registration reply * * Handle registration reply denying registration. * * Returns 1 if registration should be retried or 0 if registration should be * aborted. */static int handle_reg_denied(struct msg_extensions *ext){ ASSERT(ext != NULL && ext->rep != NULL); if (mn.state != MN_REQUEST_TUNNEL && mn.state != MN_CLOSE_FOR_HOME && mn.state != MN_CONNECTED) { DEBUG(DEBUG_MESSAGES, "handle_reg_denied - received denial " "reply while not trying to register\n"); return 0; } DEBUG(DEBUG_MESSAGES, "Registration denied, code = %d (%s)\n", ext->rep->code, reply_code_str(ext->rep->code)); switch (ext->rep->code) { case REGREP_ID_MISMATCH_HA: return handle_id_mismatch_ha(ext); case REGREP_LONG_LIFETIME_FA: return handle_long_lifetime(ext); case REGREP_UNKNOWN_HA_HA: return handle_unknown_ha(ext); case REGREP_HA_HOST_UNCREACHABLE_FA: case REGREP_HA_PORT_UNCREACHABLE_FA: case REGREP_HA_UNREACHABLE_FA: if (config.use_hadisc && config.ha_ip_addr.s_addr != 0) { DEBUG(DEBUG_MESSAGES, "HA unreachable => try to " "discover another HA\n"); mn.info_str = "restarting HA discovery"; config.ha_ip_addr.s_addr = 0; return 1; } return 0; case REGREP_UNKNOWN_CHALLENGE_FA: case REGREP_STALE_CHALLENGE_FA: return 1; /* try to reregister; FIX: should get a new challenge * value, if no new agent advertisement has been * received */ case REGREP_MN_FAILED_AUTH_FA: if (mn.try_to_fix_sec_assoc) { /* dynamic security association was removed in * is_valid_reply() so try to reregister and create a * new security association with the FA */ return 1; } /* no method for fixing the security association, so just fall * through to the default case */ default:#ifdef MN_LOCUPD_PROFILER write_profiler("DENY");#endif LOG2(LOG_INFO, "Registration denied, code = %d (%s)\n", ext->rep->code, reply_code_str(ext->rep->code)); reply_waiting_api(API_FAILED, &ext->rep->code, 1); /* Try to change the FA by degrading the priority of the " "current FA. */ degrade_current_fa_priority(); } return 0;}/* Handle registration message from socket s. * Returns 1 if registration should be re-tried */int handle_registration(int s){ char msg[MAXMSG]; unsigned int len; struct sockaddr_in addr; int n, res; struct msg_extensions ext; len = sizeof(addr); n = recvfrom(s, msg, MAXMSG, 0, (struct sockaddr*) &addr, &len); if (n < 0) { LOG2(LOG_ERR, "registration recv: %s\n", strerror(errno)); return 0; } DEBUG(DEBUG_MESSAGES, "Received %d bytes from %s:%d\n", n, inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); res = parse_msg(msg, n, &ext); if (res != 0 || ext.double_auth_ext != 0) { char *reason = "N/A"; DEBUG(DEBUG_MESSAGES, "Dropping invalid message\n"); mn.discarded_msgs++; if (res == -1) reason = "unknown extension"; else if (res == -2) reason = "malformed message"; else if (res == -3 || res == -4 || res == -5) reason = "unknown vendor extension"; else if (ext.double_auth_ext != 0) reason = "double authentication extension"; report_discarded_msg(msg, n, &addr, reason); return 0; } mn.try_to_fix_sec_assoc = 0; if (is_valid_reply(&ext, addr)) { mn.prev_req_replied = 1; time(&mn.last_reply_rcvd); mn.last_reply_code = ext.rep->code; mn.last_nonce = ext.rep->id[0]; if (ext.challenge != NULL) { int len; gettimeofday(&mn.last_challenge_time, NULL); len = GET_CHALLENGE_EXT_LEN(ext.challenge); if (mn.last_challenge_ext == NULL || GET_CHALLENGE_EXT_LEN(mn.last_challenge_ext) != len) { if (mn.last_challenge_ext != NULL) free(mn.last_challenge_ext); mn.last_challenge_ext = (struct challenge_ext *) malloc(len); } if (mn.last_challenge_ext != NULL) memcpy(mn.last_challenge_ext, ext.challenge, len); else DEBUG(DEBUG_INFO, "Could not malloc() memory " "for challenge extension\n"); } if (IS_REGREP_ACCEPTED(ext.rep->code)) handle_reg_accept(&ext); else return handle_reg_denied(&ext); } else { report_discarded_msg(msg, n, &addr, "invalid reply"); mn.discarded_msgs++; } return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -