📄 fa_request.c
字号:
VENDOR_EXT_DYNAMICS_FF_AUTH, htonl(fa_spi->spi)); } msglen = msgpos - msg; assert(iface != NULL); result = own_sendto(iface->udp_sock, lower_addr, lower_port, msg, msglen); dynamics_check_sendto(result, msglen, "send_tear_down - registration " "reply"); if (result != msglen) return 1; DEBUG(DEBUG_FLAG, "send_tear_down: sent %d bytes (of %d) to %s:%i, " "dev[%s]\n", result, msglen, inet_ntoa(lower_addr), ntohs(lower_port), iface->dev); return 0;}#endif/* list structure for denial reply records */struct denial_dst_data { struct in_addr home_addr; struct in_addr ha_addr; __u32 priv_ha; struct timeval last; struct denial_dst_data *next;};static struct denial_dst_data *denials = NULL;/** * expire_denial_records: * @force: 1 = remove all entries, 0 = remove entries that are older than one * second * * Cleanup routine for denial reply records. */voidexpire_denial_records(int force){ struct denial_dst_data *tmp, *tmp2, *prev = NULL; struct timeval tv; static time_t last_check_sec = 0; gettimeofday(&tv, NULL); /* do not expire entries more often than once per 10 seconds */ if (!force && tv.tv_sec < last_check_sec + 10 && tv.tv_sec > last_check_sec) return; last_check_sec = tv.tv_sec; tmp = denials; while (tmp != NULL) { int diff = (tv.tv_sec - tmp->last.tv_sec) * 1000000 + tv.tv_usec - tmp->last.tv_usec; if (force || diff >= 1000000) { DEBUG(DEBUG_FLAG, "Removing expired denial reply " "record for MN <%s,", inet_ntoa(tmp->home_addr)); DEBUG(DEBUG_FLAG, "%s,%u>\n", inet_ntoa(tmp->ha_addr), tmp->priv_ha); if (prev == NULL) denials = tmp->next; else prev->next = tmp->next; tmp2 = tmp; tmp = tmp->next; free(tmp2); } else { prev = tmp; tmp = tmp->next; } }}/** * send_failure_reply: * @code: the error code to be used in the denial reply * @ext: pointer to the parsed message that caused the denial reply * @info: source data of the request for which the denial reply is to be sent * @sk: pointer to the session key if available; NULL = no session key * @sk_len: length of the session key if @sk != NULL * * Send a failure reply to the mobile node (or the lower foreign agent if this * foreign agent is not the lowest one) * * Returns: 0 if successfully sent, 1 if message was not sent (error in * sending, more than one denial per second, or invalid destination address) */intsend_failure_reply(int code, struct msg_extensions *ext, struct packet_from_info *info, unsigned char *sk, int sk_len){ struct denial_dst_data *tmp; unsigned char msg[MAXMSG]; struct reg_rep *reply; int msglen = 0; int result; __u32 priv_ha = 0; struct timeval tv; reply = (struct reg_rep *) msg; memset(reply, 0, sizeof(struct reg_rep)); if (code == REGREP_LONG_LIFETIME_FA) reply->lifetime = htons(config->fa_default_tunnel_lifetime); else reply->lifetime = 0; reply->type = REG_REP; reply->code = code; if (ext != NULL && ext->req != NULL) { reply->home_addr.s_addr = ext->req->home_addr.s_addr; reply->ha_addr.s_addr = ext->req->ha_addr.s_addr; memcpy(reply->id, ext->req->id, sizeof(reply->id)); } else if (ext != NULL && ext->rep != NULL) { reply->home_addr.s_addr = ext->rep->home_addr.s_addr; reply->ha_addr.s_addr = ext->rep->ha_addr.s_addr; memcpy(reply->id, ext->rep->id, sizeof(reply->id)); } msglen += sizeof(struct reg_rep); if (ext != NULL && ext->priv_ha != NULL) priv_ha = ntohl(ext->priv_ha->priv_ha); /* check whether the last denial was sent less than a second ago */ gettimeofday(&tv, NULL); tmp = denials; while (tmp != NULL) { int diff = (tv.tv_sec - tmp->last.tv_sec) * 1000000 + tv.tv_usec - tmp->last.tv_usec; if (tmp->home_addr.s_addr == reply->home_addr.s_addr && tmp->ha_addr.s_addr == reply->ha_addr.s_addr && tmp->priv_ha == priv_ha) { if (diff < 1000000 && diff >= 0) { DEBUG(DEBUG_FLAG, "More than one denial reply " "per second for MN <%s,", inet_ntoa(tmp->home_addr)); DEBUG(DEBUG_FLAG, "%s,%u> - skipping this " "denial\n", inet_ntoa(tmp->ha_addr), tmp->priv_ha); return 1; } tmp->last.tv_sec = tv.tv_sec; tmp->last.tv_usec = tv.tv_usec; break; } tmp = tmp->next; } if (tmp == NULL) { DEBUG(DEBUG_FLAG, "Adding denial reply record for MN <%s,", inet_ntoa(reply->home_addr)); DEBUG(DEBUG_FLAG, "%s,%u>\n", inet_ntoa(reply->ha_addr), priv_ha); tmp = (struct denial_dst_data *) malloc(sizeof(struct denial_dst_data)); if (tmp == NULL) { DEBUG(DEBUG_FLAG, "\tcould not add record (out of " "memory)\n"); return 1; } tmp->home_addr.s_addr = reply->home_addr.s_addr; tmp->ha_addr.s_addr = reply->ha_addr.s_addr; tmp->priv_ha = priv_ha; tmp->last.tv_sec = tv.tv_sec; tmp->last.tv_usec = tv.tv_usec; tmp->next = denials; denials = tmp; } DEBUG(DEBUG_FLAG, "Sending failure reply code %i to %s:%i\n", code, inet_ntoa(info->src.sin_addr), ntohs(info->src.sin_port));#if 0 /* FIX: currently challenge extension adding to denial replies is * commented out do to possibly missing binding (see below) and * ambiguous information in RFC 3012 */ if (config->enable_challenge_response && config->challenge_in_reg_reply) { struct challenge_ext *challenge; /* FIX: in hierarchical FA network only the lowest FA should * add the challenge extension */ challenge = create_challenge_ext(config, MN_FA_CHALLENGE_EXT); if (challenge != NULL) { int n = GET_CHALLENGE_EXT_LEN(challenge); if (msglen + n > MAXMSG) { free(challenge); return 1; } memcpy(msg + msglen, challenge, n); msglen += n; /* FIX: this challenge must be recorded for the MN, * but there may not be a binding for it yet.. */ } }#endif if (sk != NULL && msglen + MAX_SK_LEN + sizeof(struct vendor_msg_auth) <= MAXMSG) { msglen += auth_add_vendor( AUTH_ALG_MD5, sk, sk_len, msg, (struct vendor_msg_auth *) (msg + msglen), VENDOR_EXT_DYNAMICS_SK_AUTH, ext != NULL && ext->mh_auth != NULL ? ext->mh_auth->spi : 0); } if (msglen + MAX_SK_LEN + sizeof(struct msg_auth) <= MAXMSG) msglen += add_fa_auth_ext(info->src.sin_addr, reply->home_addr, msg, msg + msglen); if (config->packet_socket_mode == PACKET_SOCKET_MODE_ONLY_RECEIVE || (ext != NULL && !is_sender_mobile(ext))) { if (!send_address_ok(info->src.sin_addr)) return 1; result = sendto(info->iface->udp_sock, msg, msglen, 0, (struct sockaddr *) &info->src, sizeof(info->src)); } else result = packet_socket_send(info, msg, msglen); dynamics_check_sendto(result, msglen, "send_failure_reply"); return 0;}/* forward unconfirmed request or deregistration to upper FA or HA returns: 0 if successful 1 on error*/static intforward_request(struct bindingentry *binding, struct msg_extensions *ext){ char msg[MAXMSG]; int len, len2, sent; struct fa_spi_entry *fa_spi; struct tunnel_data *t_data; char *auth_ext; char *copy_end; /* pointer to the ext following the copied area */ int auth_len; const char *auth_txt; t_data = binding->data; DEBUG(DEBUG_FLAG, "Forwarding request upwards\n"); if (ext->req == NULL || ext->mh_auth == NULL) { LOG2(LOG_WARNING, "forward_request: not req or mh_auth\n"); return 1; } /* copy the MAC protected area directly from the received message */ if (ext->mn_aaa_auth != NULL) { auth_ext = (char *) ext->mn_aaa_auth; auth_len = GET_GEN_AUTH_EXT_LEN(ext->mn_aaa_auth); auth_txt = "mn_aaa_auth"; } else { auth_ext = (char *) ext->mh_auth; auth_len = GET_AUTH_EXT_LEN(ext->mh_auth); auth_txt = "mh_auth"; } assert(auth_ext > (char *) ext->req); len = (__u8 *) auth_ext - (__u8 *) ext->req + auth_len; if (len < sizeof(struct reg_req) + auth_len || len > MAXMSG) { LOG2(LOG_WARNING, "forward_request: invalid length %i\n", len); return 1; } memcpy(msg, ext->req, len); copy_end = (char *) ext->req + len; DEBUG(DEBUG_FLAG, " * copying up to and including %s (len ==> %i)\n", auth_txt, len); if (ext->sk_auth && !config->highest_FA) { /* if we came here, this FA could not check the session key * based authentication - so, just copy the data to the upper * mobility agent */ if ((void *) ext->sk_auth <= (void *) ext->mh_auth) { LOG2(LOG_WARNING, "forward_request: sk_auth before " "mh_auth - dropping message\n"); return 1; } len2 = (char *) ext->sk_auth - (char *) ext->mh_auth - GET_AUTH_EXT_LEN(ext->mh_auth) + GET_VENDOR_AUTH_EXT_LEN(ext->sk_auth); if (len + len2 > MAXMSG || len2 < 0) { LOG2(LOG_WARNING, "forward_request: message overflow " "(len=%i, len2=%i)\n", len, len2); return 1; } memcpy(msg + len, ((char *) ext->mh_auth) + GET_AUTH_EXT_LEN(ext->mh_auth), len2); len += len2; copy_end += len2; DEBUG(DEBUG_FLAG, " * copying up to and including sk_auth " "(len ==> %i)\n", len); } if (config->highest_FA) fa_spi = get_fa_spi(0, ext->req->ha_addr, SPI_AGENT_HA); else fa_spi = get_fa_spi(0, upper_fa_addr.sin_addr, SPI_AGENT_FA); /* FIX: add key request even to deregistration messages if this FA is * not the highest FA * The keyreq is needed to know whether the lower end is MN or FA */ if (ntohs(ext->req->lifetime) != 0 || !config->highest_FA) { if (add_key_request(fa_spi, ext, &len, msg) != 0) return 1; } /* add GRE key ext. if it is needed (duplicate private address) */ if (t_data->up_type == TUNNEL_GRE) { struct gre_key_ext *gre; if (len + sizeof(struct gre_key_ext) > MAXMSG) return 1; gre = (struct gre_key_ext *) (msg + len); gre->type = VENDOR_EXT_TYPE2; gre->length = sizeof(struct gre_key_ext) - 2; gre->reserved = 0; gre->vendor_id = htonl(VENDOR_ID_DYNAMICS); gre->sub_type = htons(VENDOR_EXT_DYNAMICS_GRE_KEY); gre->key = htonl(t_data->up_key); len += sizeof(struct gre_key_ext); DEBUG(DEBUG_FLAG, " * adding GRE ext\n"); } if (ext->challenge != NULL && (char *) ext->challenge >= copy_end) { int n = GET_CHALLENGE_EXT_LEN(ext->challenge); if (len + n > MAXMSG) return 1; memcpy(msg + len, ext->challenge, n); len += n; DEBUG(DEBUG_FLAG, " * adding Challenge ext (len=%i)\n", n); } /* Add the FA->FA or FA->HA authentication extension if a security * association is configured and send the message */ if (config->highest_FA) { if (fa_spi != NULL) { len += auth_add( fa_spi->alg, fa_spi->shared_secret, fa_spi->shared_secret_len, (unsigned char *) msg, (struct msg_auth *) (msg + len), FH_AUTH, htonl(fa_spi->spi)); } DEBUG(DEBUG_FLAG, "forward_request ==> HA %s:%i\n", inet_ntoa(ext->req->ha_addr), config->ha_udp_port); sent = own_sendto(up_interface->udp_sock, ext->req->ha_addr, htons(config->ha_udp_port), msg, len); } else { if (fa_spi != NULL) { len += auth_add_vendor( AUTH_ALG_MD5, fa_spi->shared_secret, fa_spi->shared_secret_len, (unsigned char *) msg, (struct vendor_msg_auth *) (msg + len), VENDOR_EXT_DYNAMICS_FF_AUTH, htonl(fa_spi->spi)); } DEBUG(DEBUG_FLAG, "forward_request ==> upper FA %s:%i\n", inet_ntoa(upper_fa_addr.sin_addr), ntohs(upper_fa_addr.sin_port)); if (!send_address_ok(upper_fa_addr.sin_addr)) return 1; sent = sendto(up_interface->udp_sock, msg, len, 0, (struct sockaddr *) &upper_fa_addr, sizeof(upper_fa_addr)); } assert(len < MAXMSG); dynamics_check_sendto(sent, len, "forward_request"); if (sent != len) return 1; return 0;}/* reply to authenticated request returns: 0 if successful 1 on error*/static intreply_message(struct bindingentry *binding, struct msg_extensions *ext){ struct tunnel_data *t_data; unsigned char msg[MAXMSG]; int len, ret, timeout; struct reg_rep *reply; struct msg_key *key; struct fa_spi_entry *fa_spi; time_t now; t_data = binding->data; DEBUG(DEBUG_FLAG, "Reply to authenticated request\n"); memset(msg, 0, MAXMSG); len = 0; reply = (struct reg_rep *) msg; reply->type = REG_REP; reply->code = REGREP_ACCEPTED; time(&now); timeout = binding->exp_time - now; if (timeout < 0) timeout = 0; if (timeout > ntohs(ext->req->lifetime)) { /* FIX: should this kind of request be forward upwards to * lower the binding in all the agents? */ DEBUG(DEBUG_FLAG, "Request lifetime=%i < timeout=%i\n", ntohs(ext->req->lifetime), timeout); timeout = ntohs(ext->req->lifetime);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -