📄 ha.c
字号:
return NULL;}/** * get_mn_spi: * @spi: security parameter index (in host byte order) * * Fetches SPI structure for an MN using key @spi. * * Returns: * pointer to the SPI structure or %NULL if requested item not found */static struct spi_entry *get_mn_spi(int spi){ struct spi_entry *s; struct node *node; for (node = list_get_first(&config.spi_list); node != NULL; node = list_get_next(node)) { s = (struct spi_entry *) node; if (s->spi == spi) return s; } return NULL;}/** * ha_add_ext_start: * @start: pointer to the beginning of the authenticated data * @pos: memory position for the added authentication extension * @left: amount of free base in buffer * @ext: parsed registration request or %NULL if not available * @lifetime: lifetime of the binding; zero for deregistration or failure reply * @mn_spi: SPI structure for the MN or %NULL if not available * @binding: bindingentry for the MN or %NULL if not available * @auth_type: authentication data area (%AUTH_RFC2002 / %AUTH_RFC2002BIS) * * Add private HA extension (if SHA is used), copy MN NAI extension from the * request (if available), add a key reply extension (if requested), and * add MN-HA authentication extension if security associated available. * * Returns: * Number of used bytes in the buffer or -1 on failure. */static intha_add_ext_start(unsigned char *start, unsigned char *pos, int left, struct msg_extensions *ext, int lifetime, struct spi_entry *mn_spi, struct bindingentry *binding, int auth_type){ int used = 0, n; if (config.priv_ha > 0) { struct priv_ha_ext *priv = (struct priv_ha_ext *) (pos + used); DEBUG(DEBUG_FLAG, " * priv_ha\n"); 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); used += GET_PRIV_HA_EXT_LEN(priv); left -= GET_PRIV_HA_EXT_LEN(priv); } /* RFC 2794 requires that HA copies MN NAI extension to the reply */ if (ext != NULL && ext->mn_nai != NULL) { DEBUG(DEBUG_FLAG, " * mn_nai\n"); if (left < GET_MN_NAI_EXT_LEN(ext->mn_nai)) return -1; memcpy(pos + used, ext->mn_nai, GET_MN_NAI_EXT_LEN(ext->mn_nai)); used += GET_MN_NAI_EXT_LEN(ext->mn_nai); left -= GET_MN_NAI_EXT_LEN(ext->mn_nai); } /* Add the session key to mobile node, if it requested for a key and * the reply is not a deregistration or failure reply */ if (ext && ext->mn_keyreq != NULL && mn_spi && lifetime != 0) { struct msg_key *key; DEBUG(DEBUG_FLAG, " * mn_keyrep\n"); if (left < sizeof(struct msg_key) + MAX_SK_LEN) return -1; key = (struct msg_key *) (pos + used); n = auth_encrypt(mn_spi->auth_alg, mn_spi->shared_secret, mn_spi->shared_secret_len, binding->key, key, (struct reg_rep *) start, VENDOR_EXT_DYNAMICS_MN_KEYREP, htonl(mn_spi->spi)); used += n; left -= n; } if (ext && mn_spi) { struct msg_auth *auth; DEBUG(DEBUG_FLAG, " * mh_auth\n"); if (left < sizeof(struct msg_auth) + MAX_SK_LEN) return -1; /* Add message authentication for MN */ auth = (struct msg_auth *) (pos + used); n = auth_add((auth_type == AUTH_RFC2002BIS ? AUTH_ALG_MD5_RFC2002 : mn_spi->auth_alg), mn_spi->shared_secret, mn_spi->shared_secret_len, start, (struct msg_auth *) (pos + used), MH_AUTH, htonl(mn_spi->spi)); used += n; left -= n; } /* RFC 3012 requires that HA copies challenge extension to the reply * after Mobile-Home auth. ext.; this will be authenticated with * FA-HA auth. ext. if security association for this is available */ if (ext != NULL && ext->challenge != NULL) { DEBUG(DEBUG_FLAG, " * challenge\n"); n = GET_CHALLENGE_EXT_LEN(ext->challenge); if (left < n) return -1; memcpy(pos + used, ext->challenge, n); used += n; left -= n; } return used;}/** * ha_add_ext_end: * @start: pointer to the beginning of the authenticated data * @pos: memory position for the added authentication extension * @addr: IP address from which the registration request was received * @left: amount of free base in buffer * @ext: parsed registration request or %NULL if not available * * Copy nonce extension from the request (if available) and add an * authentication extension for SHA or FA if a security association is * configured. * * Returns: * Number of used bytes in the buffer or -1 on failure. */static intha_add_ext_end(unsigned char *start, unsigned char *pos, struct in_addr addr, int left, struct msg_extensions *ext){ struct fa_spi_entry *fa_spi; int used = 0; if (config.priv_ha && ext && ext->nonce) { if (ext->nonce->length != sizeof(struct nonce_ext) - 2) { DEBUG(DEBUG_FLAG, " - invalid nonce ext len\n"); } else { DEBUG(DEBUG_FLAG, " * nonce\n"); if (left < GET_NONCE_EXT_LEN(ext->nonce)) return -1; memcpy(pos + used, ext->nonce, GET_NONCE_EXT_LEN(ext->nonce)); used += GET_NONCE_EXT_LEN(ext->nonce); left -= GET_NONCE_EXT_LEN(ext->nonce); } } fa_spi = get_fa_spi(0, addr); if (fa_spi != NULL && config.priv_ha > 0) { DEBUG(DEBUG_FLAG, " * sha_ha_auth\n"); if (left < sizeof(struct vendor_msg_auth) + MAX_SK_LEN) return -1; used += auth_add_vendor( AUTH_ALG_MD5, fa_spi->shared_secret, fa_spi->shared_secret_len, start, (struct vendor_msg_auth *) (pos + used), VENDOR_EXT_DYNAMICS_SHA_HA_AUTH, htonl(fa_spi->spi)); } else if (fa_spi != NULL) { DEBUG(DEBUG_FLAG, " * fh_auth\n"); if (left < sizeof(struct msg_auth) + MAX_SK_LEN) return -1; used += auth_add(fa_spi->alg, fa_spi->shared_secret, fa_spi->shared_secret_len, start, (struct msg_auth *) (pos + used), FH_AUTH, htonl(fa_spi->spi)); } return used;}/** * send_reg_repl: * @s: socket to be used in sending the registration reply * @binding: bindingentry for the MN * @mn_spi: SPI entry for the MN * @ext: parsed registration request or %NULL for teardown reply * @forced_iface: forced destination interface or %NULL for no forcing * @code: registration reply code * * Creates and sends a registration reply message to the foreign agent given * in the binding. This function can also be used for sending a teardown reply * to the old foreign agent by giving %NULL @ext argument. * * Returns: * 0 on success or -1 on failure */static intsend_reg_repl(int s, struct bindingentry *binding, struct spi_entry *mn_spi, struct msg_extensions *ext, struct interface_entry *forced_iface, int code){ unsigned char msg[MAXMSG]; unsigned char *msgpos = msg; struct reg_rep *reply; struct msg_key *key; struct sockaddr_in dest_addr; struct fa_spi_entry *fa_spi;#ifdef USE_TEARDOWN struct registration_ext_dynamics *dyn_ext;#endif int msglen, result, key_to_fa, left = MAXMSG, n; struct ha_tunnel_data *t_data; ASSERT(s >= 0 && binding != NULL && binding->data != NULL && mn_spi != NULL); t_data = (struct ha_tunnel_data *) binding->data; /* Create the reply extension */ DEBUG(DEBUG_FLAG, "Reply\n"); reply = (struct reg_rep *) msg; memset(reply, 0, sizeof(struct reg_rep)); reply->lifetime = htons(binding->timeout); reply->type = REG_REP; reply->code = code; reply->home_addr.s_addr = binding->mn_addr.s_addr; reply->ha_addr.s_addr = config.sha_addr.s_addr != 0 ? config.sha_addr.s_addr : binding->ha_addr.s_addr; memcpy(reply->id, binding->id, REG_REQ_ID_LEN); if (mn_spi->replay_method == REPLAY_PROTECTION_NONCE) t_data->nonce = reply->id[0] = get_rand32(); msgpos += sizeof(struct reg_rep); left -= sizeof(struct reg_rep); n = ha_add_ext_start(msg, msgpos, left, ext, binding->timeout, mn_spi, binding, t_data->auth_type); if (n < 0) return -1; msgpos += n; left -= n; /* Encrypt the session key for the FA if it requested the key with * fa_keyreq (use shared secret and MD5) or fa_pubkey (use RSA) */ key_to_fa = 0; if (binding->fa_spi != 0 && ntohs(reply->lifetime) != 0) { fa_spi = get_fa_spi(binding->fa_spi, t_data->lower_saddr); if (fa_spi == NULL) { LOG2(LOG_ERR, "unknown FA SPI %i\n", binding->fa_spi); return -1; } DEBUG(DEBUG_FLAG, " * fa_keyrep\n"); if (left < sizeof(struct msg_key) + MAX_SK_LEN) return -1; key = (struct msg_key *) msgpos; n = 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)); msgpos += n; left -= n; key_to_fa = 1; } else if (binding->fa_pubkey && ntohs(reply->lifetime) != 0 && binding->last_sent_fa_pubkeyrep) { DEBUG(DEBUG_FLAG, " * fa_pubkeyrep\n"); n = GET_KEY_EXT_LEN(binding->last_sent_fa_pubkeyrep); if (left < n) return -1; /* If the foreign agent included a public key, add an RSA * encrypted session key to the FA */ key = (struct msg_key *) msgpos; memcpy(key, binding->last_sent_fa_pubkeyrep, n); msgpos += n; left -= n; key_to_fa = 1; }#ifdef USE_TEARDOWN if (teardown) { DEBUG(DEBUG_FLAG, " * ext_dynamics (teardown)\n"); if (left < sizeof(struct registration_ext_dynamics)) return -1; dyn_ext = (struct registration_ext_dynamics *) msgpos; dyn_ext->type = VENDOR_EXT_TYPE2; dyn_ext->reserved = 0; dyn_ext->length = sizeof(struct registration_ext_dynamics) - 2; 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 = REG_EXT_OWN_TEAR_DOWN; dyn_ext->seq = 0; msgpos += sizeof(struct registration_ext_dynamics); left -= sizeof(struct registration_ext_dynamics); }#endif if (key_to_fa) { DEBUG(DEBUG_FLAG, " * sk_auth\n"); if (left < sizeof(struct vendor_msg_auth) + MAX_SK_LEN) return -1; /* Add session key-based message authentication for FA */ n = auth_add_vendor(AUTH_ALG_MD5, binding->key, binding->keylen, msg, (struct vendor_msg_auth *) msgpos, VENDOR_EXT_DYNAMICS_SK_AUTH, htonl(mn_spi->spi)); msgpos += n; left -= n; } n = ha_add_ext_end(msg, msgpos, t_data->lower_saddr, left, ext); if (n < 0) return -1; msgpos += n; left -= n; msglen = msgpos - msg; dest_addr.sin_family = AF_INET; dest_addr.sin_addr.s_addr = t_data->lower_saddr.s_addr; dest_addr.sin_port = binding->lower_port; if (forced_iface != NULL && setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, forced_iface->dev, IFNAMSIZ)) { DEBUG(DEBUG_FLAG, "setsockopt(SOL_SOCKET, SO_BINDTODEVICE): " "%s\n", strerror(errno)); } DEBUG(DEBUG_FLAG, " * total %i bytes to %s:%i\n", msglen, inet_ntoa(dest_addr.sin_addr), ntohs(dest_addr.sin_port)); result = sendto(s, msg, msglen, 0, (struct sockaddr *) &dest_addr, sizeof(struct sockaddr_in)); if (forced_iface != NULL) { /* kernel seems to require optlen >= sizeof(int) */ char dummy[sizeof(int)]; memset(dummy, 0, sizeof(dummy)); if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, dummy, sizeof(dummy))) DEBUG(DEBUG_FLAG, "setsockopt(SOL_SOCKET, " "SO_BINDTODEVICE): %s\n", strerror(errno)); } return dynamics_check_sendto(result, msglen, "send_reg_repl");}/** * send_reg_failure: * @s: socket to be used for sending the registration reply * @sock_addr: destination address (IP address and UDP port) * @mn_spi: pointer to SPI structure for the MN or %NULL if not known * @auth_type: authentication data area (%AUTH_RFC2002 / %AUTH_RFC2002BIS) * @code: failure code for the registration reply (3 .. 255) * @nonce: nonce value to be updated if the MN uses nonce-based replay * protection; @nonce can also be %NULL, when the nonce value is not updated * @ext: parsed registration request * @forced_iface: forced destination interface or %NULL for no forcing * @binding: pointer to MN's binding entry if known, or %NULL if not available * @from_iface: interface from which the registration request was received * * Sends a registration reply with a failure code @code to @sock_addr. * * Returns: * 0 on success or -1 on failure */static intsend_reg_failure(int s, struct sockaddr_in *sock_addr, struct spi_entry *mn_spi, int auth_type, int code, __u32 *nonce, struct msg_extensions *ext, struct interface_entry *forced_iface, struct bindingentry *binding, struct interface_entry *from_iface){ unsigned char msg[MAXMSG]; unsigned char *msgpos = msg; struct reg_rep *reply; int msglen, result, n, left = MAXMSG; struct ha_tunnel_data *t_data = NULL; static time_t last_failure_time = 0; time_t *timer, now; ASSERT(s >= 0 && sock_addr && ext && ext->req && code > 2); if (binding) { /* known binding - use MN's own timer */ t_data = (struct ha_tunnel_data *) binding->data; timer = &t_data->last_failure_time; } else { /* no binding - use general timer */ timer = &last_failure_time; } /* do not send failure replys too often */ time(&now); if (*timer > now) { DEBUG(DEBUG_FLAG, "send_reg_failure: timed failure in the " "future - host time changed?\n"); *timer = now; } else if (now - *timer < config.reg_error_reply_interval) { DEBUG(DEBUG_FLAG, "Too frequent error message - skipping\n"); return 0; } *timer = now; if (mn_spi == NULL && ext->mh_auth != NULL) mn_spi = get_mn_spi(ntohl(ext->mh_auth->spi)); /* Create the reply extension */ DEBUG(DEBUG_FLAG, "Failure reply\n"); reply = (struct reg_rep *) msg; memset(reply, 0, sizeof(struct reg_rep)); reply->lifetime = 0; reply->type = REG_REP; reply->code = code; reply->home_addr.s_addr = ext->req->home_addr.s_addr; reply->ha_addr.s_addr = ext->req->ha_addr.s_addr; if (config.sha_addr.s_addr != 0) reply->ha_addr.s_addr = config.sha_addr.s_addr; else if (code == REGREP_UNKNOWN_HA_HA) { /* use the HA's unicast IP address in case of HA discovery */ struct node *node; int found = 0; for (node = list_get_first(&config.interfaces); node != NULL; node = list_get_next(node)) { struct interface_entry *iface = (struct interface_entry *) node; if (iface->ha_disc && iface->bcaddr.s_addr == ext->req->ha_addr.s_addr) { reply->ha_addr.s_addr = iface->addr.s_addr;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -