📄 fa_request.c
字号:
/* $Id: fa_request.c,v 1.81 2001/09/27 17:33:54 jm Exp $ * Foreign Agent - registration request handling * * 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. */#ifdef HAVE_CONFIG_H#include <config.h>#endif#include <stdlib.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <syslog.h>#include <assert.h>#include <string.h>#include <errno.h>#include "fa.h"#include "fa_hash.h"#include "fa_mn_addr.h"#include "tunnel.h"#include "debug.h"#include "auth.h"#include "dyn_ip.h"#include "authorized.h"#include "util.h"#include "agent_utils.h"#include "md5_mac.h"#include "list.h"extern struct fa_config *config;extern struct sockaddr_in upper_fa_addr;extern struct interface_entry *up_interface;extern struct msg_key *fa_public_key;extern struct hashtable *tunnels_hash;extern struct bindingtable *bindings_hash;extern struct binding_counters bcounters;extern struct challenge_ext **last_challenges;/* Check if enough memory and other resources to accept new registration request returns: 0 = if enough resources 1 = if not enough resources*/static intcheck_resources(void){ if (bcounters.bindingcount >= config->max_bindings) { LOG2(LOG_ALERT, "check_resources: too many concurrent " "bindings - refusing new ones\n"); return 1; } /* If needed, some other checks might be added here */ return 0;}static intcoaddr_ok(struct in_addr coaddr){ struct interface_entry *iface; struct node *node; if (coaddr.s_addr == config->highest_fa_addr.s_addr) return 1; for (node = list_get_first(&config->interfaces); node != NULL; node = list_get_next(node)) { iface = (struct interface_entry *) node; if (iface->addr.s_addr == coaddr.s_addr) return 1; } return 0;}/* returns: * 0 = auth. ext. ok * 1 = ff_auth missing/invalid * 2 = mf_auth missing/invalid */static intcheck_auth_ext(struct in_addr addr, struct msg_extensions *ext){ struct fa_spi_entry *fa_spi; fa_spi = get_fa_spi(0, addr, SPI_AGENT_FA); if (fa_spi != NULL) { if (ext->ff_auth == NULL || !auth_check_vendor(AUTH_ALG_MD5, fa_spi->shared_secret, fa_spi->shared_secret_len, (unsigned char *) ext->req, ext->ff_auth)) return 1; else return 0; } fa_spi = get_fa_spi(0, ext->req->home_addr, SPI_AGENT_MN); if (fa_spi != NULL) { if (ext->mf_auth == NULL || !auth_check(fa_spi->alg, fa_spi->shared_secret, fa_spi->shared_secret_len, (unsigned char *) ext->req, ext->mf_auth)) return 2; else return 0; } else if (ext->mf_auth != NULL) return 2; return 0;}/* returns 1 on invalid request or 0 on valid request */static intvalidate_request(struct msg_extensions *ext, struct packet_from_info *info){ int error_code = 0, i; char dev[IFNAMSIZ], error_buf[256]; char *error_text = NULL; int discard_silently = 0; if (ext->mh_auth == NULL) { error_text = "no mh_auth"; error_code = REGREP_BAD_REQUEST_FA; } else if (!auth_is_protected(ext->mn_nai, ext->mh_auth)) { error_text = "mh_auth does not protect mn_nai"; error_code = REGREP_BAD_REQUEST_FA; } else if (ext->mf_auth != NULL && !auth_is_protected(ext->mn_nai, ext->mf_auth)) { error_text = "mf_auth does not protect mn_nai"; error_code = REGREP_BAD_REQUEST_FA; } else 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))) { error_text = "mn_aaa_auth does not protect mn_fa_key_req"; error_code = REGREP_BAD_REQUEST_FA; } else 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))) { error_text = "mn_aaa_auth does not protect mn_ha_key_req"; error_code = REGREP_BAD_REQUEST_FA; } else if (ext->challenge != NULL && (ext->mf_auth == NULL || !auth_is_protected(ext->challenge, ext->mf_auth)) && (ext->mn_aaa_auth == NULL || !auth_is_protected(ext->challenge, ext->mn_aaa_auth))) { /* FIX: check only in the lowest FA (?) */ error_text = "mf_auth/mn_aaa_auth does not protect challenge"; error_code = REGREP_MN_FAILED_AUTH_FA; discard_silently = 1;#ifndef DEBUG_SIMULATED_TEST } else if (dyn_ip_route_get(ext->req->ha_addr, dev, IFNAMSIZ) == 0 && strcmp(dev, "lo") == 0) { error_text = "HA address points to local interface - " "possible loop"; error_code = REGREP_UNKNOWN_HA_HA; /* RFC 2002: 3.7.2 */#endif } else if ((ext->req->opts & REGREQ_RESERVED) != 0) { error_text = "reserved option set"; error_code = REGREP_BAD_REQUEST_FA; } else if (ext->encaps_del && (ext->req->opts & REGREQ_REVERSE_TUNNEL) == 0) { error_text = "encapsulating delivery, " "but no reverse tunneling\n"; error_code = REGREP_BAD_REQUEST_FA; } else if ((ext->req->opts & REGREQ_VJ_HC) != 0) { error_text = "unsupported van Jacobson compression option set"; error_code = REGREP_VJ_UNAVAIL_FA; } else if ((ext->req->opts & (REGREQ_GRE_ENCAPS | REGREQ_MINIMAL_ENCAPS)) != 0) { error_text = "unavailable encapsulation"; error_code = REGREP_ENCAP_UNAVAIL_FA; } else if ((ext->req->opts & REGREQ_MN_DECAPS) == 0 && !config->enable_fa_decapsulation && is_sender_mobile(ext)) { /* check this only if this FA is the lowest FA */ error_text = "FA decapsulation denied"; error_code = REGREP_ENCAP_UNAVAIL_FA; } else if ((ext->req->opts & REGREQ_REVERSE_TUNNEL) != 0 && config->enable_reverse_tunneling == 0) { error_text = "reverse tunneling not allowed"; error_code = REGREP_REVERSE_TUNNEL_UNAVAIL_FA; } else if ((ext->req->opts & REGREQ_REVERSE_TUNNEL) == 0 && config->enable_reverse_tunneling != 0 && config->enable_triangle_tunneling == 0 && config->force_reverse_tunneling == 0) { error_text = "denied request for triangle tunnel - " "reverse tunnel required"; error_code = REGREP_REVERSE_TUNNEL_MANDATORY_FA; } else if ((ext->req->opts & REGREQ_REVERSE_TUNNEL) == 0 && config->enable_triangle_tunneling == 0) { error_text = "denied request for triangle tunnel"; error_code = REGREP_ADMIN_PROHIBITED_FA; } else if (!authorized_check(config->authorized_networks, info->src.sin_addr)) { error_text = "request from an unauthorized address"; error_code = REGREP_ADMIN_PROHIBITED_FA; } else if (is_sender_mobile(ext) && config->allow_mobile_nodes == FALSE) { error_text = "MNs not allowed in this FA"; error_code = REGREP_ADMIN_PROHIBITED_FA; } else if ((ext->req->opts & REGREQ_MN_DECAPS) == 0 && !coaddr_ok(ext->req->co_addr)) { error_text = "MN trying to use invalid care-of address"; error_code = REGREP_INVALID_CAREOF_FA; } else if (info->ttl < 255 && is_sender_mobile(ext) && (config->reg_ttl_check == TTL_CHECK_ALL || (config->reg_ttl_check == TTL_CHECK_REVERSE && (ext->req->opts & REGREQ_REVERSE_TUNNEL) != 0))) { error_text = "MN too distant - TTL < 255"; error_code = REGREP_REVERSE_TUNNEL_MN_TOO_DISTANT_FA; } else if ((i = check_auth_ext(info->src.sin_addr, ext)) != 0) { if (i == 2) { error_text = "invalid mf_auth"; error_code = REGREP_MN_FAILED_AUTH_FA; } else { /* actually this is FA-FA auth. failure, but there is * not currently any error code for it */ error_text = "invalid ff_auth"; error_code = REGREP_REASON_UNSPEC_FA; } } else if (ext->double_auth_ext > 0) { error_text = "duplicate authentication extension"; if (ext->double_auth_ext & DOUBLE_MF_AUTH) error_code = REGREP_MN_FAILED_AUTH_FA; else error_code = REGREP_BAD_REQUEST_FA; } else if (ext->sk_auth && ext->fa_nai && (char*) ext->sk_auth < (char*) ext->fa_nai) { error_text = "SK_AUTH before FA_NAI"; error_code = REGREP_REASON_UNSPEC_FA; } else if (ext->sk_auth && ext->prev_fa_nai && (char*) ext->sk_auth < (char*) ext->prev_fa_nai) { error_text = "SK_AUTH before PREV_FA_NAI"; error_code = REGREP_REASON_UNSPEC_FA; } else if (ext->ff_auth == NULL && ext->fa_nai && (GET_NAI_LEN(ext->fa_nai) != config->fa_nai_len || memcmp(MSG_NAI_DATA(ext->fa_nai), config->fa_nai, config->fa_nai_len) != 0)) { /* lowest FA, but the FA NAI does not match */ error_text = "unknown FA NAI"; error_code = REGREP_REASON_UNSPEC_FA; } else if (ntohs(ext->req->lifetime) > config->fa_default_tunnel_lifetime) { snprintf(error_buf, sizeof(error_buf), "requested lifetime too long (%i > %i)", ntohs(ext->req->lifetime), config->fa_default_tunnel_lifetime); error_text = error_buf; error_code = REGREP_LONG_LIFETIME_FA; } else if (ext->req->home_addr.s_addr == 0) { error_text = "non-zero homeaddr required"; error_code = REGREP_NONZERO_HOMEADDR_REQD_FA; } else if (config->enable_challenge_response && ext->challenge == NULL && (config->require_challenge || ext->mf_auth == NULL)) { /* FIX: check only in the lowest FA (?) */ error_text = "missing challenge"; error_code = REGREP_MISSING_CHALLENGE_FA; } if (error_code != 0) { char mn[30], coa[30], ha[30]; dynamics_strlcpy(mn, inet_ntoa(ext->req->home_addr), 30); dynamics_strlcpy(coa, inet_ntoa(ext->req->co_addr), 30); dynamics_strlcpy(ha, inet_ntoa(ext->req->ha_addr), 30); if (error_text != NULL) { LOG2(LOG_WARNING, "SRC=%s, MN=%s, HA=%s, COA=%s - " "request denied: %s\n", inet_ntoa(info->src.sin_addr), mn, ha, coa, error_text); report_discarded_msg(ext->start, ext->len, &info->src, error_text); } if (!discard_silently) send_failure_reply(error_code, ext, info, NULL, 0); else DEBUG(DEBUG_FLAG, "Discarding reg.req. silently\n"); return 1; } return 0;}static intadd_key_request(struct fa_spi_entry *fa_spi, struct msg_extensions *ext, int *len, char *msg){ struct msg_key *key; /* request the session key * use shared secret with highest mobility agent if one exists or * public key cryptography if no security association is available */ if (fa_spi != NULL) { if (*len + sizeof(struct msg_key) > MAXMSG) return 1; key = (struct msg_key *) (msg + *len); init_key_extension(key, VENDOR_EXT_DYNAMICS_FA_KEYREQ, htonl(fa_spi->spi), 0); *len += GET_KEY_EXT_LEN(key); DEBUG(DEBUG_FLAG, " * adding fa_keyreq (len ==> %i)\n", *len); } else { /* add own public key after the copied parts */ if (*len + GET_KEY_EXT_LEN(fa_public_key) > MAXMSG) return 1; memcpy(msg + *len, fa_public_key, GET_KEY_EXT_LEN(fa_public_key)); *len += GET_KEY_EXT_LEN(fa_public_key); DEBUG(DEBUG_FLAG, " * adding fa_public_key (len ==> %i)\n", *len); } return 0;}intadd_fa_auth_ext(struct in_addr lower_addr, struct in_addr home_addr, unsigned char *data, unsigned char *pos){ struct fa_spi_entry *fa_spi; /* Add the FA->FA or FA->MN authentication extension if a security * association is configured */ fa_spi = get_fa_spi(0, lower_addr, SPI_AGENT_FA); if (fa_spi != NULL) { return auth_add_vendor( AUTH_ALG_MD5, fa_spi->shared_secret, fa_spi->shared_secret_len, data, (struct vendor_msg_auth *) pos, VENDOR_EXT_DYNAMICS_FF_AUTH, htonl(fa_spi->spi)); } else { fa_spi = get_fa_spi(0, home_addr, SPI_AGENT_MN); if (fa_spi != NULL) { return auth_add( fa_spi->alg, fa_spi->shared_secret, fa_spi->shared_secret_len, data, (struct msg_auth *) pos, MF_AUTH, htonl(fa_spi->spi)); } } return 0;}#ifdef USE_TEARDOWN/* Send tear down message to lower FA. returns: 0 if succeeded sending 1 if not successful*/static intsend_tear_down(struct bindingentry *binding, struct in_addr lower_addr, unsigned short lower_port, struct interface_entry *iface){ unsigned char msg[MAXMSG]; unsigned char *msgpos; struct reg_rep *reply; int msglen, result; struct tunnel_data *t_data; struct registration_ext_dynamics *dyn_ext; struct fa_spi_entry *fa_spi; t_data = binding->data; msgpos = msg; msglen = 0; result = 0; /* create the reply extension */ reply = (struct reg_rep *) msg; memset(reply, 0, sizeof(struct reg_rep)); reply->lifetime = htons(0); reply->type = REG_REP; reply->code = REGREP_ACCEPTED; memcpy(&reply->home_addr, &binding->mn_addr, sizeof(struct in_addr)); memcpy(&reply->ha_addr, &binding->ha_addr, sizeof(struct in_addr)); reply->id[0] = htonl(binding->id[0]); reply->id[1] = htonl(binding->id[1]); msgpos += sizeof(struct reg_rep); /* add Dynamics options extension */ dyn_ext = (struct registration_ext_dynamics *) msgpos; 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 = REG_EXT_OWN_TEAR_DOWN; dyn_ext->seq = 0; msgpos += sizeof(struct registration_ext_dynamics); /* add sk_auth for authentication between FAs */ msgpos += auth_add_vendor(AUTH_ALG_MD5, binding->key, binding->keylen, msg, (struct vendor_msg_auth *) msgpos, VENDOR_EXT_DYNAMICS_SK_AUTH, htonl(binding->spi)); /* Add tha FA->FA auth. ext. if a security association is * configured */ fa_spi = get_fa_spi(0, lower_addr, SPI_AGENT_FA); if (fa_spi != NULL) { msgpos += auth_add_vendor( AUTH_ALG_MD5, fa_spi->shared_secret, fa_spi->shared_secret_len, msg, (struct vendor_msg_auth *) msgpos,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -