📄 mn_reg.c
字号:
/* $Id: mn_reg.c,v 1.64 2001/09/29 14:56:23 jm Exp $ * Mobile Node - registration * * Dynamic hierarchial IP tunnel * Copyright (C) 1998-2001, Dynamics group * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. See README and COPYING for * more details. */#include "config.h"#include <stdlib.h>#include <assert.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <errno.h>#ifdef DYN_TARGET_LINUX#include <net/if_arp.h>#endif#include <string.h>#include <time.h>#include "agentapi.h"#include "auth.h"#include "debug.h"#include "msgparser.h"#include "proxyarp.h"#include "util.h"#include "mn.h"#ifdef INCLUDE_IPAY#include "mn_ipay.h"#endifextern struct mn_data mn;extern struct mn_config config;extern struct timeval timers[TIMER_COUNT];static int fill_req_header(char *pos, int request_type, int use_reverse){ struct reg_req *req; int new_reg_time; unsigned int new_reg_rand; static int last_reg_time = 0; static unsigned int last_reg_rand = 0; struct timeval tv; req = (struct reg_req *) pos; req->type = REG_REQ; req->opts = 0; /* Note: the agent adv should be checked for allowed tunneling modes * and req->opts should be adjusted with that information if needed * (i.e. do not request unsupported mode) */ if (!config.enable_fa_decapsulation) req->opts |= REGREQ_MN_DECAPS; if (use_reverse) req->opts |= REGREQ_REVERSE_TUNNEL; if (request_type != REG_DISC) { if (mn.tunnel_mode == API_TUNNEL_FULL_HA) req->lifetime = htons(config.mn_default_tunnel_lifetime); else req->lifetime = htons(MIN(mn.req_lifetime, config.mn_default_tunnel_lifetime)); if (ntohs(req->lifetime) == 0) { LOG2(LOG_INFO, "send_registration - trying to register" ", but lifetime=0 - aborting\n"); return -1; } } else req->lifetime = 0; req->home_addr.s_addr = config.mn_home_ip_addr.s_addr; if (config.ha_ip_addr.s_addr == 0 && config.use_aaa) { req->ha_addr.s_addr = config.allow_home_addr_from_foreign_net ? 0 : -1; } else if (config.ha_ip_addr.s_addr == 0 && config.home_net_addr_plen > -1) { /* dynamic HA address resolution */ req->ha_addr.s_addr = config.home_net_subnet_bc.s_addr; } else req->ha_addr.s_addr = config.ha_ip_addr.s_addr; req->co_addr.s_addr = mn.co_addr.s_addr; switch (config.replay_meth) { case REPLAY_PROTECTION_NONE: req->id[0] = 0; req->id[1] = get_rand32(); break; case REPLAY_PROTECTION_TIMESTAMP: /* set the timestamp according to RFC 2002, 5.6.1 (NTP format): * high-order 32 bits: time in seconds from year 1900, * low-order 32 bits: fractional seconds (1/256 sec resolution, * i.e., 8 bits, used) and the last bits random */ gettimeofday(&tv, NULL); new_reg_time = tv.tv_sec + mn.clock_correction; new_reg_rand = ((tv.tv_usec * 256 / 1000000) << 24) | (get_rand32() & 0xffffff); if (new_reg_time == last_reg_time && new_reg_rand <= last_reg_rand) { /* id must always increase - forcing a larger id */ new_reg_rand = last_reg_rand + 1; } req->id[0] = htonl(new_reg_time + UNIX_NTP_DIFF); req->id[1] = htonl(new_reg_rand); last_reg_time = new_reg_time; last_reg_rand = new_reg_rand; break; case REPLAY_PROTECTION_NONCE: req->id[0] = mn.last_nonce; req->id[1] = get_rand32(); break; } return sizeof(struct reg_req);}static int nai_equal(struct fa_nai_ext *nai1, struct fa_nai_ext *nai2){ int len = GET_NAI_LEN(nai1); if (nai2 == NULL || GET_NAI_LEN(nai2) != len) return 0; if (memcmp(MSG_NAI_DATA(nai1), MSG_NAI_DATA(nai2), len) == 0) return 1; return 0;}static int add_localized_reg_extensions(char *pos, int left, char *start){ static int last_req_seq_num = 0; struct registration_ext_dynamics *dyn_ext; int n, added = 0, add_auth = 1; if (mn.current_adv == NULL || mn.current_adv->adv.fa_nai == NULL || mn.last_req_FA_NAI->type == 0 || (!mn.prev_req_replied && !nai_equal(mn.last_req_FA_NAI, mn.current_adv->adv.fa_nai))) { if (mn.current_adv == NULL) DEBUG(DEBUG_INFO, "\tmn.current_adv == NULL\n"); if (mn.current_adv != NULL && mn.current_adv->adv.fa_nai == NULL) DEBUG(DEBUG_INFO, "\tcurrent_adv->fa_nai == NULL\n"); if (mn.last_req_FA_NAI->type == 0) DEBUG(DEBUG_INFO, "\tlast_req_FA_NAI->type == 0\n"); if (!mn.prev_req_replied) DEBUG(DEBUG_INFO, "\t!mn.prev_req_replied\n"); if (mn.current_adv != NULL && !nai_equal(mn.last_req_FA_NAI, mn.current_adv->adv.fa_nai)) DEBUG(DEBUG_INFO, "\t!nai_equal()\n"); if (mn.current_adv == NULL || mn.current_adv->adv.fa_nai != NULL) { DEBUG(DEBUG_INFO, "Not adding SK auth because " "current_adv == NULL or FA NAI advertised and " "forcing req. to HA\n"); add_auth = 0; } DEBUG(DEBUG_INFO, "Excluding previous FA NAI extension " "(forcing request to HA)\n"); mn.last_req_FA_NAI->type = 0; } if (left < sizeof(struct registration_ext_dynamics)) return -1; DEBUG(DEBUG_MESSAGES, " * ext_dynamics\n"); dyn_ext = (struct registration_ext_dynamics *) pos; dyn_ext->type = VENDOR_EXT_TYPE2; dyn_ext->length = sizeof(struct registration_ext_dynamics) - 2; dyn_ext->reserved = 0; dyn_ext->vendor_id = htonl(VENDOR_ID_DYNAMICS); dyn_ext->sub_type = htons(VENDOR_EXT_DYNAMICS_OPTIONS); dyn_ext->version = VENDOR_EXT_VERSION; dyn_ext->opts = 0; dyn_ext->seq = htonl(++last_req_seq_num); added += sizeof(struct registration_ext_dynamics); left -= sizeof(struct registration_ext_dynamics); if (mn.current_adv != NULL && mn.current_adv->adv.fa_nai != NULL) { /* previous FA NAI ext. */ if (mn.prev_req_replied && mn.last_req_FA_NAI->type != 0) { n = GET_NAI_EXT_LEN(mn.last_req_FA_NAI); if (left < n) return -1; mn.last_req_FA_NAI->sub_type = htons(VENDOR_EXT_DYNAMICS_PREVIOUS_FA_NAI); memcpy(pos + added, mn.last_req_FA_NAI, n); added += n; left -= n; DEBUG(DEBUG_MESSAGES, " * previous FA NAI (len=%i)\n", n); } /* current FA NAI ext. */ n = GET_NAI_EXT_LEN(mn.current_adv->adv.fa_nai); memcpy(mn.last_req_FA_NAI, mn.current_adv->adv.fa_nai, n); if (left < n) return -1; memcpy(pos + added, mn.last_req_FA_NAI, n); added += n; left -= n; DEBUG(DEBUG_MESSAGES, " * current FA NAI (len=%i)\n", n); } if (add_auth) { if (left < sizeof(struct vendor_msg_auth) + MAX_SK_LEN) return -1; DEBUG(DEBUG_MESSAGES, " * sk_auth\n"); n = auth_add_vendor( config.auth_alg, mn.session_key, mn.session_key_len, (unsigned char *) start, (struct vendor_msg_auth *) (pos + added), VENDOR_EXT_DYNAMICS_SK_AUTH, htonl(config.spi)); added += n; left -= n; } return added;}static int add_req_extensions(char *pos, int left, char *start, int request_type, int use_reverse){ int use_dynamics_ext, n; struct fa_spi_entry *fa_spi = NULL; struct msg_key *mn_keyreq; struct challenge_ext *challenge = NULL; char *orig = pos; int add_mn_aaa_auth_ext = 0; int send_to_ha = 0; if (request_type == REG_DISC && mn.fa_addr.s_addr == config.ha_ip_addr.s_addr) send_to_ha = 1; if (config.priv_ha > 0) { struct priv_ha_ext *priv = (struct priv_ha_ext *) pos; if (left < sizeof(struct priv_ha_ext)) return -1; memset(priv, 0, sizeof(struct priv_ha_ext)); priv->type = VENDOR_EXT_TYPE2; priv->length = sizeof(struct priv_ha_ext) - 2; priv->vendor_id = htonl(VENDOR_ID_DYNAMICS); priv->sub_type = htons(VENDOR_EXT_DYNAMICS_PRIV_HA); priv->priv_ha = htonl(config.priv_ha); pos += GET_PRIV_HA_EXT_LEN(priv); left -= GET_PRIV_HA_EXT_LEN(priv); DEBUG(DEBUG_MESSAGES, " * priv_ha\n"); } if (config.mn_nai_len > 0) { struct mn_nai_ext *nai; if (left < sizeof(struct mn_nai_ext) + config.mn_nai_len) return -1; nai = (struct mn_nai_ext *) pos; nai->type = MN_NAI_EXT; nai->length = config.mn_nai_len; memcpy(nai + 1, config.mn_nai, config.mn_nai_len); pos += GET_MN_NAI_EXT_LEN(nai); left -= GET_MN_NAI_EXT_LEN(nai); DEBUG(DEBUG_MESSAGES, " * mn_nai\n"); }#ifdef INCLUDE_IPAY if (config.mn_nai_len == 0 && mn.nai.nai != NULL) { struct mn_nai_ext *nai; if (left < sizeof(struct mn_nai_ext) + mn.nai.len) return -1; nai = (struct mn_nai_ext *) pos; nai->type = MN_NAI_EXT; nai->length = mn.nai.len; memcpy(nai + 1, mn.nai.nai, mn.nai.len); pos += GET_MN_NAI_EXT_LEN(nai); left -= GET_MN_NAI_EXT_LEN(nai); DEBUG(DEBUG_MESSAGES, " * mn_nai (Ipay)\n"); }#endif /* add Dynamics extensions if the Foreign Agent advertised support for * them or if the registration is made directly to the Home Agent */ use_dynamics_ext = mn.fa_dynamics_ext.type != 0 || mn.tunnel_mode == API_TUNNEL_FULL_HA; if (use_dynamics_ext) { /* add mn_keyreq extension */ if (left < MIN_KEY_EXT_LEN) return -1; DEBUG(DEBUG_MESSAGES, " * mn_keyreq\n"); mn_keyreq = (struct msg_key *) pos; init_key_extension(mn_keyreq, VENDOR_EXT_DYNAMICS_MN_KEYREQ, htonl(config.spi), 0); pos += GET_KEY_EXT_LEN(mn_keyreq); left -= GET_KEY_EXT_LEN(mn_keyreq); /* add HFA public key hash extension if the hash is available * from the agent advertisement */ if (mn.current_adv != NULL) { struct msg_key *hashext = mn.current_adv->adv.pubkey_hash; if (hashext != NULL && hashext->type != 0) { if (left < GET_KEY_EXT_LEN(hashext)) return -1; DEBUG(DEBUG_MESSAGES, " * pubkey_hash\n"); memcpy(pos, hashext, GET_KEY_EXT_LEN(hashext)); pos += GET_KEY_EXT_LEN(hashext); left -= GET_KEY_EXT_LEN(hashext); } } } else { DEBUG(DEBUG_INFO, "FA did not advertise support for Dynamics " "extensions - not using them\n"); } if (config.use_aaa && config.mn_ha_key_timestamp != 0 && config.mn_ha_key_lifetime != 0 && config.mn_ha_key_timestamp + config.mn_ha_key_lifetime < time(NULL)) { DEBUG(DEBUG_INFO, "Dynamic MN-HA security association (from " "AAA) expired\n"); config.shared_secret_len = -1; } if (config.shared_secret_len >= 0) { /* add MN->HA authentication extension */ if (left < sizeof(struct msg_auth) + MAX_SK_LEN) return -1; DEBUG(DEBUG_MESSAGES, " * mh_auth\n"); n = auth_add(mn.use_auth_alg, config.shared_secret, config.shared_secret_len, (unsigned char *) start, (struct msg_auth *) pos, MH_AUTH, htonl(config.spi)); pos += n; left -= n; } /* Add encapsulating delivery extension if MN decaps and reverse * tunnel is in use [RFC 2344, Chap. 3.3] */ if (!config.enable_fa_decapsulation && use_reverse) { struct encaps_delivery_ext *edel = (struct encaps_delivery_ext *) pos; if (left < sizeof(struct encaps_delivery_ext)) return -1; DEBUG(DEBUG_MESSAGES, " * encaps_delivery\n"); edel->type = ENCAPS_DELIVERY_EXT; edel->length = 0; pos += sizeof(struct encaps_delivery_ext); left -= sizeof(struct encaps_delivery_ext); } /* add FA NAI extensions and session key based MN->FA authentication * if Dynamics extensions are used and the session key is available * and this is not a reregistration */ if (use_dynamics_ext && mn.session_key != NULL && request_type != REG_REREG) { n = add_localized_reg_extensions(pos, left, start); if (n < 0) return -1; pos += n; left -= n; } else if (mn.current_adv != NULL && mn.current_adv->adv.fa_nai != NULL) { /* current FA NAI ext. */ memcpy(mn.last_req_FA_NAI, mn.current_adv->adv.fa_nai, MAX_FA_NAI_LEN); n = GET_NAI_EXT_LEN(mn.last_req_FA_NAI); if (left < n) return -1; memcpy(pos, mn.last_req_FA_NAI, n); pos += n; left -= n; DEBUG(DEBUG_MESSAGES, " * current FA NAI (len=%i)\n", n); } /* if the agent advertisement from the FA has a Challenge extension, * copy it to the registration request or if the previous registration * reply had a more recent Challenge ext, use it */ /* FIX: MN must not use the same challenge again, so if no new * challenge is available, it is no use sending this registration * without first acquiring a new challenge fron an agent advertisement. * MN could send an agent soliciation in that case. Now the request * will be denied by FA and MN might get a new challenge from that * denial reply. */ if (mn.last_challenge_ext != NULL && (mn.current_adv == NULL || cmp_timeval(&mn.current_adv->last, &mn.last_challenge_time) < 0)) { DEBUG(DEBUG_INFO, "Using challenge from last reg. reply\n"); challenge = mn.last_challenge_ext; } else if (mn.current_adv != NULL && mn.current_adv->adv.challenge != NULL) { DEBUG(DEBUG_INFO, "Using challenge from last agentadv\n"); challenge = mn.current_adv->adv.challenge; } else challenge = NULL; if (!send_to_ha) fa_spi = get_fa_spi(0, mn.fa_addr); if (challenge != NULL && (fa_spi != NULL || config.use_aaa)) { n = GET_CHALLENGE_EXT_LEN(challenge); DEBUG(DEBUG_MESSAGES, " * challenge (len=%i)\n", n); if (left < n) return -1; memcpy(pos, challenge, n); challenge = (struct challenge_ext *) pos; challenge->type = MN_FA_CHALLENGE_EXT; pos += n; left -= n; add_mn_aaa_auth_ext = 1; } /* add shared secret based MN->FA authentication if the security * association is configured */ if (!send_to_ha && fa_spi != NULL && !mn.aaa_rekey) { if (left < sizeof(struct msg_auth) + MAX_SK_LEN) return -1; DEBUG(DEBUG_MESSAGES, " * mf_auth\n"); n = auth_add(fa_spi->alg, fa_spi->shared_secret, fa_spi->shared_secret_len, (unsigned char *) start, (struct msg_auth *) pos, MF_AUTH, htonl(fa_spi->spi)); pos += n; left -= n; add_mn_aaa_auth_ext = 0; } else if (!send_to_ha && config.use_aaa) { struct generalized_mn_fa_key_req_ext *keyreq; add_mn_aaa_auth_ext = 1; /* add MN-FA key req. from AAA */ keyreq = (struct generalized_mn_fa_key_req_ext *) pos; if (left < sizeof(*keyreq)) return -1; DEBUG(DEBUG_MESSAGES, " * MN-FA Key Req from AAA\n"); keyreq->type = GENERALIZED_MN_FA_KEY_REQ_EXT; keyreq->subtype = GEN_MN_FA_KEY_REQ_FROM_AAA; keyreq->length = htons(4); /* FIX: mn_spi is the SPI that MN will assign for the security * association; this may need to be uniquely selected for some * cases(?) */ keyreq->mn_spi = htonl(1000); pos += GET_GEN_MN_FA_KEY_REQ_EXT_LEN(keyreq); left -= GET_GEN_MN_FA_KEY_REQ_EXT_LEN(keyreq); } if ((config.shared_secret_len < 0 || mn.aaa_rekey) && config.use_aaa) { struct generalized_mn_ha_key_req_ext *keyreq; add_mn_aaa_auth_ext = 1; /* add MN-HA key req. from AAA */ keyreq = (struct generalized_mn_ha_key_req_ext *) pos; if (left < sizeof(*keyreq)) return -1; DEBUG(DEBUG_MESSAGES, " * MN-HA Key Req from AAA\n"); keyreq->type = GENERALIZED_MN_HA_KEY_REQ_EXT; keyreq->subtype = GEN_MN_HA_KEY_REQ_FROM_AAA;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -