📄 ha.c
字号:
binding = api_fetch_binding(&recv_msg); if (!binding) { send_msg.code = API_FAILED; break; } binding_remove(binding); remove_tunnel(binding); destroy_binding(binding); send_msg.length = 0; send_msg.code = API_SUCCESS; LOG2(LOG_NOTICE, "API call removed binding for MN %s\n", inet_ntoa(binding->mn_addr)); break; case API_GET_STATUS: DEBUG(DEBUG_FLAG, "Received API_GET_STATUS\n"); if (recv_msg.length != 0) { LOG2(LOG_ERR, "API_GET_STATUS message has wrong " "length\n"); break; } status = (struct dynamics_ha_status *) send_msg.params; memcpy(status, &stats, sizeof(struct dynamics_ha_status)); UNALIGNED_(&status->tunnel_count, &bindingcount); send_msg.length = sizeof(struct dynamics_ha_status); send_msg.code = API_SUCCESS; break; case API_RELOAD_CONFIG: /* Force a reload of the configuration */ DEBUG(DEBUG_FLAG, "Received API_RELOAD_CONFIG\n"); if (!priv) { send_msg.code = API_NOT_PERMITTED; break; } reload_config(1); DEBUG(DEBUG_FLAG, "Configuration_reloaded\n"); send_msg.code = API_SUCCESS; break; default: LOG2(LOG_ERR, "Received unknown API command: %d\n", recv_msg.code); send_msg.code = API_NOT_SUPPORTED; break; } return api_send(socket, &cli_addr, cli_len, &send_msg);}/********************************************************************** * Registration request handling **********************************************************************//** * pubkey_hash_ok: * @pubkey: pointer to public key extension * @hash: pointer to public key hash extension * * Check whether public key @pubkey matches with its @hash value. * * Returns: * 1 if key hash is correct or 0 if check failed */static intpubkey_hash_ok(struct msg_key *pubkey, struct msg_key *hash){ unsigned char mac[MD5_MAC_LEN]; if (GET_KEY_LEN(hash) != MD5_MAC_LEN) { DEBUG(DEBUG_FLAG, "pubkey_hash_ok: invalid hash length: %i, " "expected %i\n", GET_KEY_LEN(hash), MD5_MAC_LEN); return 0; } md5_mac((unsigned char *) "", 0, (unsigned char *) pubkey, GET_KEY_EXT_LEN(pubkey), mac); return (memcmp(mac, MSG_KEY_DATA(hash), MD5_MAC_LEN) == 0);}/** * check_fa_auth_ext: * @addr: source IP address of the registration message * @ext: registration message extensions * * Check whether registration message FA/SHA-HA authentication is valid. * * Returns: * 0 if auth. ext. okay or 1 if fh_auth missing/invalid */static intcheck_fa_auth_ext(struct in_addr addr, const struct msg_extensions *ext){ struct fa_spi_entry *fa_spi; fa_spi = get_fa_spi(0, addr); if (fa_spi == NULL) { /* no security association with the sender - authentication * extension not required */ if (ext->fh_auth != NULL) { DEBUG(DEBUG_FLAG, "No FA-HA security association, but " "request had FA-HA authentication extension\n"); return 1; } return 0; } if (ext->fh_auth == NULL && ext->sha_ha_auth != NULL && config.sha_addr.s_addr != 0) { DEBUG(DEBUG_FLAG, "Checking sha_ha_auth\n"); if (auth_check_vendor(fa_spi->alg, fa_spi->shared_secret, fa_spi->shared_secret_len, (unsigned char *) ext->req, ext->sha_ha_auth)) return 0; return 1; } DEBUG(DEBUG_FLAG, "Checking fh_auth\n"); if (ext->fh_auth == NULL || !auth_check(fa_spi->alg, fa_spi->shared_secret, fa_spi->shared_secret_len, (unsigned char *) ext->req, ext->fh_auth)) return 1; else return 0;}/** * validate_request: * @binding: binding entry of the MN from which the registration message is * originating or %NULL if no binding for this MN available * @faaddr: source IP address of the registration message * @msg: pointer to the start of registration message * @msg_len: length of the registration message * @ext: received message extensions * @code: pointer to buffer for failure code * @auth_type: pointer to buffer for used MN-HA authentication type * * Validate registration request. Check that it: * - has the necessary extensions * - comes from an authorized mobile node * - has a valid MAC in the authentication extension * - has the right HA address * * Returns: * If everything is OK a pointer to the used SPI entry will be * returned, and code will be REGREP_ACCEPTED or REGREP_ACCEPTED_NO_SB. * * On failure @code is set to the value that should be sent in the failure * reply. If code is negative no reply is to be sent. The returned value * is %NULL if the SPI entry for MN is not found, otherwise it points to the * SPI entry. * * The auth_type is set to a special code AUTH_MAC_RFC2002 if * the MAC of the mh_auth did not included the SPI field (RFC 2002). */#define AUTH_MAC_RFC2002 -100static struct spi_entry *validate_request(struct bindingentry *binding, struct in_addr faaddr, const char *msg, int msg_len, const struct msg_extensions *ext, int *code, int *auth_type){ struct node *node; struct spi_entry *spi = NULL; time_t current_time; enum { NOT_FOUND, UNICAST_FOUND, BROADCAST_FOUND } own_addr_found; struct authorized_entry *auth = NULL; char faaddrstr[16]; char mnaddrstr[16]; struct ha_tunnel_data *t_data = NULL; if (binding != NULL) t_data = (struct ha_tunnel_data *) binding->data; dynamics_strlcpy(faaddrstr, inet_ntoa(faaddr), sizeof(faaddrstr)); *code = REGREP_ACCEPTED; *auth_type = 0; /* check that it has the right extensions */ if (ext->req == NULL || ext->mh_auth == NULL) { LOG2(LOG_WARNING, "FA %s: message does not contain either request " "and/or message authentication\n", faaddrstr); if (ext->mh_auth == NULL) *code = REGREP_MN_FAILED_AUTH_HA; else *code = REGREP_BAD_REQUEST_HA; return NULL; } dynamics_strlcpy(mnaddrstr, inet_ntoa(ext->req->home_addr), sizeof(mnaddrstr)); /* check that the MN is authorized */ for (node = list_get_first(&config.authorized_list); node != NULL; node = list_get_next(node)) { auth = (struct authorized_entry *) node; if (ntohl(ext->mh_auth->spi) >= auth->spi_low && ntohl(ext->mh_auth->spi) <= auth->spi_high && (ext->req->home_addr.s_addr & auth->netmask.s_addr) == auth->network.s_addr) { break; } } if (node == NULL) { LOG2(LOG_WARNING, "FA %s, MN %s: Not authorized\n", faaddrstr, mnaddrstr); *code = REGREP_ADMIN_PROHIBITED_HA; return NULL; } /* check MAC (MN-HA authentication extension) */ spi = get_mn_spi(ntohl(ext->mh_auth->spi)); if (spi == NULL) { LOG2(LOG_WARNING, "FA %s, MN %s: SPI %d not found\n", faaddrstr, mnaddrstr, ntohl(ext->mh_auth->spi)); *code = REGREP_MN_FAILED_AUTH_HA; return NULL; } if (!auth_check(spi->auth_alg, spi->shared_secret, spi->shared_secret_len, (unsigned char *) msg, ext->mh_auth)) { if (spi->auth_alg != AUTH_ALG_MD5 || !auth_check(AUTH_ALG_MD5_RFC2002, spi->shared_secret, spi->shared_secret_len, (unsigned char *) msg, ext->mh_auth)) { LOG2(LOG_WARNING, "FA %s, MN %s, SPI %d: Invalid MN-HA" " authentication extension\n", faaddrstr, mnaddrstr, spi->spi); *code = REGREP_MN_FAILED_AUTH_HA; return spi; } else { /* non-standard authentication method used */ DEBUG(DEBUG_FLAG, "RFC 2002 MAC calculation " "detected - trying to use the same method\n"); *auth_type = AUTH_MAC_RFC2002; } } if (ext->double_auth_ext > 0) { LOG2(LOG_WARNING, "FA %s, MN %s: duplicate authentication " "extension\n", faaddrstr, mnaddrstr); if (ext->double_auth_ext & DOUBLE_MH_AUTH) *code = REGREP_MN_FAILED_AUTH_HA; else if (ext->double_auth_ext & DOUBLE_FH_AUTH) *code = REGREP_FA_FAILED_AUTH_HA; else *code = REGREP_REASON_UNSPEC_HA; return spi; } /* check possible Foreign-Home Authentication Extension */ if (check_fa_auth_ext(faaddr, ext) != 0) { LOG2(LOG_WARNING, "FA %s, MN %s: invalid/missing fh_auth\n", faaddrstr, mnaddrstr); *code = REGREP_FA_FAILED_AUTH_HA; return spi; } /* check that MN-HA auth. ext. protects correct extensions */ if (!auth_is_protected(ext->pubkey_hash, ext->mh_auth) || !auth_is_protected(ext->priv_ha, ext->mh_auth) || !auth_is_protected(ext->mn_keyreq, ext->mh_auth) || !auth_is_protected(ext->mn_nai, ext->mh_auth)) { LOG2(LOG_WARNING, "FA %s, MN %s: MN-HA auth. ext. does not " "protect all the required extensions\n", faaddrstr, mnaddrstr); *code = REGREP_MN_FAILED_AUTH_HA; } /* check that MN-AAA auth. ext. protects correct extensions */ if (ext->mn_fa_key_req_aaa != NULL && (ext->mn_aaa_auth == NULL || !auth_is_protected(ext->mn_fa_key_req_aaa, ext->mn_aaa_auth))) { LOG2(LOG_WARNING, "FA %s, MN %s: MN-AAA auth. ext. does not " "protect MN-FA keyreq from AAA extensions\n", faaddrstr, mnaddrstr); *code = REGREP_MN_FAILED_AUTH_HA; } if (ext->mn_ha_key_req_aaa != NULL && (ext->mn_aaa_auth == NULL || !auth_is_protected(ext->mn_ha_key_req_aaa, ext->mn_aaa_auth))) { LOG2(LOG_WARNING, "FA %s, MN %s: MN-AAA auth. ext. does not " "protect MN-HA keyreq from AAA extensions\n", faaddrstr, mnaddrstr); *code = REGREP_MN_FAILED_AUTH_HA; } if (ext->fh_auth != NULL && !auth_is_protected(ext->challenge, ext->fh_auth)) { LOG2(LOG_WARNING, "FA %s, MN %s: FA-HA auth. ext. does not " "protect all the required extensions\n", faaddrstr, mnaddrstr); *code = REGREP_FA_FAILED_AUTH_HA; } /* check own (HA) address */ own_addr_found = NOT_FOUND; for (node = list_get_first(&config.interfaces); node != NULL; node = list_get_next(node)) { struct interface_entry *iface = (struct interface_entry *) node; if (iface->addr.s_addr == ext->req->ha_addr.s_addr) { own_addr_found = UNICAST_FOUND; break; } if (iface->ha_disc && iface->bcaddr.s_addr == ext->req->ha_addr.s_addr) { own_addr_found = BROADCAST_FOUND; break; } } if (own_addr_found != 1 && (config.sha_addr.s_addr == 0 || ext->req->ha_addr.s_addr != config.sha_addr.s_addr)) { if (own_addr_found == BROADCAST_FOUND) DEBUG(DEBUG_FLAG, "==> HA discovery, deny with unknown HA\n"); else LOG2(LOG_WARNING, "FA %s, MN %s: HA address does not " "match\n", faaddrstr, mnaddrstr); *code = REGREP_UNKNOWN_HA_HA; return spi; } /* check option bits */ if (ext->req->opts & REGREQ_SIMULTANEOUS_BINDINGS) { LOG2(LOG_INFO, "FA %s, MN %s: Received request for unsupported " "simultaneous_bindings\n", faaddrstr, mnaddrstr); /* this is ok, but inform the MN */ *code = REGREP_ACCEPTED_NO_SB; } current_time = time(NULL); if (spi->replay_method == REPLAY_PROTECTION_TIMESTAMP && (ntohl(ext->req->id[0]) < current_time + UNIX_NTP_DIFF - spi->timestamp_tolerance || ntohl(ext->req->id[0]) > current_time + UNIX_NTP_DIFF + spi->timestamp_tolerance)) { time_t t; t = ntohl(ext->req->id[0]) - UNIX_NTP_DIFF; LOG2(LOG_WARNING, "ID mismatch - timestamp difference=%i, " "tolerance=%i\n", abs(t - current_time), spi->timestamp_tolerance); *code = REGREP_ID_MISMATCH_HA; } else if (spi->replay_method == REPLAY_PROTECTION_NONCE && t_data != NULL && ext->req->id[0] != t_data->nonce) { LOG2(LOG_WARNING, "ID mismatch (nonce)\n"); DEBUG(DEBUG_FLAG, "\treq->id: %08x, expected nonce %08x\n", ext->req->id[0], t_data->nonce); *code = REGREP_ID_MISMATCH_HA; } if (ext->req->opts & REGREQ_BROADCAST_DATAGRAMS) { DEBUG(LOG_INFO, "FA %s, MN %s: Received request for unsupported " "broadcast message forwarding\n", faaddrstr, mnaddrstr); /* this is not yet implemented in Dynamics HA, but accept the * connection anyway; there is no accepted reply code that * would indicate this situation, so MN will think that the * request was accepted.. */ } /* REGREQ_VJ_HC is ignored in HA, see RFC 2002, 3.8.2 */ if (ext->req->opts & (REGREQ_MINIMAL_ENCAPS | REGREQ_GRE_ENCAPS)) { LOG2(LOG_INFO, "FA %s, MN %s: Received unsupported option " "request (opts=0x%02x)\n", faaddrstr, mnaddrstr, ext->req->opts); /* RFC 2344 defines new denial code for unavailable * encapsulation */ if ((ext->req->opts & REGREQ_REVERSE_TUNNEL) != 0) *code = REGREP_ENCAP_UNAVAIL_HA; else *code = REGREP_REASON_UNSPEC_HA; return spi; } if (!config.enable_reverse_tunneling && (ext->req->opts & REGREQ_REVERSE_TUNNEL) != 0) { LOG2(LOG_INFO, "FA %s, MN %s: Asked forbidden reverse tunneling\n", faaddrstr, mnaddrstr); *code = REGREP_REVERSE_TUNNEL_UNAVAIL_HA; return spi; } if (!config.enable_triangle_tunneling && (ext->req->opts & REGREQ_REVERSE_TUNNEL) == 0) { LOG2(LOG_INFO, "FA %s, MN %s: Reverse tunneling mandatory\n", faaddrstr, mnaddrstr); *code = REGREP_REVERSE_TUNNEL_MANDATORY_HA; return spi; } if (ext->req->opts & REGREQ_RESERVED) { LOG2(LOG_INFO, "FA %s, MN %s: Received a request with non-zero" " reserved field\n", faaddrstr, mnaddrstr); *code = REGREP_BAD_REQUEST_HA; return spi; } if (config.pubkey_hash_method == HASH_METHOD_REQUIRE && ext->fa_pubkey != NULL && ext->pubkey_hash == NULL) { LOG2(LOG_INFO, "FA %s, MN %s: Received a request with public " "key, but without public key hash extension\n", faaddrstr, mnaddrstr); *code = REGREP_ADMIN_PROHIBITED_HA; return spi; } if (config.pubkey_hash_method != HASH_METHOD_NONE && ext->fa_pubkey != NULL && ext->pubkey_hash != NULL && !pubkey_hash_ok(ext->fa_pubkey, ext->pubkey_hash)) { LOG2(LOG_INFO, "FA %s, MN %s: Received a request with public " "key and mismatching public key hash extension\n", faaddrstr, mnaddrstr); *code = REGREP_ADMIN_PROHIBITED_HA; return spi; } /* request is OK */ return spi;}/** * new_session_key: * @binding: pointer to bindingentry * @mn_spi: pointer to SPI entry for the MN * * Generate a new session key for the given MN (@binding,@mn_spi). * * Returns: * 0 on success or -1 on failure
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -