⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fa_reply.c

📁 mobile ip 在linux下的一种实现
💻 C
📖 第 1 页 / 共 3 页
字号:
/* $Id: fa_reply.c,v 1.56 2001/09/16 17:21:59 jm Exp $ * Foreign Agent - registration reply 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 <string.h>#include <assert.h>#include "fa.h"#include "debug.h"#include "agent_utils.h"#include "md5_mac.h"#include "util.h"extern struct fa_config *config;extern struct hashtable *tunnels_hash;extern struct bindingtable *bindings_hash;extern struct binding_counters bcounters;static int forward_reply(struct bindingentry *binding,			 struct msg_extensions *ext, int error_reply,			 struct unconfirmed_request *unc);/* returns: *   0 = auth. ext. ok *   1 = ff_auth missing/invalid *   2 = fh_auth missing/invalid */static intcheck_rep_auth_ext(struct packet_from_info *info, struct msg_extensions *ext){	struct fa_spi_entry *fa_spi;	fa_spi = get_fa_spi(0, info->src.sin_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->rep,				       ext->ff_auth))			return 1;		else			return 0;	}	fa_spi = get_fa_spi(0, info->src.sin_addr, SPI_AGENT_HA);	if (fa_spi != NULL) {		if (ext->fh_auth == NULL ||		    !auth_check(fa_spi->alg, fa_spi->shared_secret,				fa_spi->shared_secret_len,				(unsigned char *) ext->rep,				ext->fh_auth))			return 2;		else			return 0;	}	return 0;}/* Returns: * 0: valid reply * 1: valid reply, but no Dynamics extensions * -1: invalid reply */static intvalidate_reply(struct msg_extensions* ext, struct bindingentry *binding,	       struct packet_from_info *info, struct unconfirmed_request *unc){	int error_code = 0, i;	char *error_text = NULL;	struct sockaddr_in addr;	struct tunnel_data *t_data;	t_data = (struct tunnel_data *) binding->data;	if ((i = check_rep_auth_ext(info, ext)) != 0) {		if (i == 2) {			error_text = "invalid hf_auth";			error_code = REGREP_HA_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_FH_AUTH)			error_code = REGREP_HA_FAILED_AUTH_FA;		else			error_code = REGREP_REASON_UNSPEC_FA;#if 0	/* This check causes some interoperability problems at least with	 * PSU Mobile IP implementation. Since the src address is not really	 * protected, this check does not affect security and it is thus	 * removed at least for now. */	} else if (ext->rep->code != REGREP_UNKNOWN_HA_HA &&		   config->highest_FA && info->src.sin_addr.s_addr !=		   (unc ? unc->ha_addr.s_addr : binding->ha_addr.s_addr)) {		error_text = "reply's source address does not match with the "			"HA address";		error_code = REGREP_ADMIN_PROHIBITED_FA;#endif	} else if (!config->highest_FA && info->src.sin_addr.s_addr !=		   config->upper_fa_addr.s_addr) {		error_text = "reply's source address does not match with "			"the upper FA address";		error_code = REGREP_ADMIN_PROHIBITED_FA;	} else if (ext->rep->code != REGREP_UNKNOWN_HA_HA &&		   ext->rep->ha_addr.s_addr !=		   (unc ? unc->ha_addr.s_addr : binding->ha_addr.s_addr)) {		error_text = "HA address changed from request";		error_code = REGREP_ADMIN_PROHIBITED_FA;	} else if (ext->rep->ha_addr.s_addr == 0) {		error_text = "missing home agent";		error_code = REGREP_MISSING_HOME_AGENT_FA;	} else if (ext->rep->home_addr.s_addr == 0) {		error_text = "missing home address";		error_code = REGREP_MISSING_HOMEADDR_FA;	} else if (unc && unc->mn_nai_included && ext->mn_nai == NULL) {		error_text = "missing MN NAI";		error_code = REGREP_MISSING_NAI_FA;	} else if (unc && unc->challenge &&		   (ext->challenge == NULL ||		    !equal_challenge(unc->challenge, ext->challenge))) {		error_text = "missing challenge";		error_code = REGREP_MISSING_CHALLENGE_FA;	} else if (ext->unknown_cvse) {		error_text = "unknown CVSE";		error_code = REGREP_UNSUPP_VENDOR_ID_HA_FA;	} else if (config->require_mnfa_sec_assoc &&		   ext->mn_fa_key_material_aaa == NULL &&		   get_fa_spi(0, ext->rep->home_addr, SPI_AGENT_MN) == NULL) {		error_text = "missing MN-FA sec. assoc.";		error_code = REGREP_MISSING_MN_FA_FA;	}	if (error_code > 0) {		char mn[30], ha[30];		struct interface_entry *iface;		dynamics_strlcpy(mn, inet_ntoa(ext->rep->home_addr), 30);		dynamics_strlcpy(ha, inet_ntoa(ext->rep->ha_addr), 30);		if (error_text != NULL) {			LOG2(LOG_WARNING, "SRC=%s, MN=%s, HA=%s - "			     "reply denied: %s\n",			     inet_ntoa(info->src.sin_addr), mn,			     ha, error_text);			report_discarded_msg(ext->start, ext->len, &info->src,					     error_text);		}		addr.sin_family = AF_INET;		addr.sin_addr = unc ? unc->info.src.sin_addr :			binding->lower_addr;		addr.sin_port = unc ? unc->info.src.sin_port :			binding->lower_port;		iface = unc ? unc->info.iface : t_data->info.iface;		if (iface == NULL || addr.sin_addr.s_addr == 0 ||		    addr.sin_port == 0) {			DEBUG(DEBUG_FLAG,			      "validate_reply: unknown lower end (%s:%u:%p)\n",			      inet_ntoa(addr.sin_addr), ntohs(addr.sin_port),			      iface);			return -1;		}		send_failure_reply(error_code, ext,				   unc ? &unc->info : &t_data->info, NULL, 0);		return -1;	}	/* check the existance of the Dynamics extensions */	if (!ext->sk_auth && IS_REGREP_ACCEPTED(ext->rep->code)) {		DEBUG(DEBUG_FLAG,		      "validate_reply: missing sk_auth\n");		return 1;	}	if (ext->rep->lifetime != 0 && !ext->fa_pubkeyrep &&		!ext->fa_keyrep) {		DEBUG(DEBUG_FLAG,		      "validate_reply: missing fa_keyrep/fa_pubkeyrep\n");		return 1;	}	return 0;}#ifdef USE_TEARDOWN/* Forward tear down message in the special case when the binding id field * has changed in the lower part of the tunnel; i.e. the id must be changed * by this FA and new sk_auth MAC must be calculated. * This function removes a possible mh_auth as it cannot be recalculated, so * this should be called only for tear down messages. */static inthandle_teardown_changed_id(struct bindingentry *binding,			   struct msg_extensions *ext,			   struct unconfirmed_request *unc){	unsigned char msg[MAXMSG];	int len, ret;	struct reg_rep *reply;	struct registration_ext_dynamics *dyn_ext;	struct tunnel_data *t_data;	struct in_addr addr;	int port;	DEBUG(DEBUG_FLAG, "handle_teardown_changed_id\n");	t_data = (struct tunnel_data *) binding->data;	if (unc != NULL) {		addr = unc->lower_addr;		port = unc->lower_port;	} else {		addr = binding->lower_addr;		port = binding->lower_port;	}	memcpy(msg, ext->rep, sizeof(struct reg_rep));	reply = (struct reg_rep *) msg;	reply->id[0] = htonl(binding->id[0]);	reply->id[1] = htonl(binding->id[1]);	len = sizeof(struct reg_rep);	if (ext->mh_auth != NULL)		DEBUG(DEBUG_FLAG, "\tdropping mh_auth\n");	/* add Dynamics options extension */	dyn_ext = (struct registration_ext_dynamics *) &msg[len];	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;	len += sizeof(struct registration_ext_dynamics);	len += auth_add_vendor(AUTH_ALG_MD5, binding->key, binding->keylen,			       msg, (struct vendor_msg_auth *) (msg + len),			       VENDOR_EXT_DYNAMICS_SK_AUTH,			       htonl(binding->spi));	len += add_fa_auth_ext(addr, reply->home_addr,			       (unsigned char *) reply, msg + len);	LOG2(LOG_WARNING, "handle_teardown_changed_id - "	     "forwarding to %s:%i\n", inet_ntoa(addr), ntohs(port));	assert(t_data->iface != NULL);	ret = own_sendto(t_data->iface->udp_sock, addr, port, msg, len);	dynamics_check_sendto(ret, len, "handle_teardown_changed_id");	return 0;}#endifenum { ID_NOT_FOUND, ID_CURRENT,#ifdef USE_TEARDOWN       ID_CHANGED,#endif       ID_NEW };static struct unconfirmed_request*find_matching_request(struct bindingentry *binding, __u32 id, int *type){	struct unconfirmed_request *unc;	struct tunnel_data *t_data;	t_data = (struct tunnel_data *) binding->data;	if (t_data->confirmed) {		if (id == binding->id[1]) {			DEBUG(DEBUG_FLAG, "Reply to current confirmed data\n");			*type = ID_CURRENT;			return NULL;		}#ifdef USE_TEARDOWN		if (id == t_data->upper_id[1]) {			DEBUG(DEBUG_FLAG, "Reply to confirmed data - ID "			      "changed\n");			*type = ID_CHANGED;			return NULL; /* use current data */		}#endif	}	/* check the unconfirmed request list for id match */	unc = t_data->unc_req;	while (unc != NULL) {		if (unc->id[1] == id) {			DEBUG(DEBUG_FLAG, "Reply to unconfirmed data\n");			*type = ID_NEW;			return unc;		}		unc = unc->next;	}	*type = ID_NOT_FOUND;	return NULL;}/* Takes care of the disconnect reply from HA or Switching FA */static inthandle_reply_disconnect(struct bindingentry *binding,			struct unconfirmed_request *unc,			struct msg_extensions *ext, int idtype){	struct tunnel_data *t_data;	int is_lowest_fa;	t_data = binding->data;	if (idtype == ID_NEW && unc != NULL) {		/* lower end changed */		is_lowest_fa = unc->is_lowest_fa;	} else		is_lowest_fa = t_data->is_lowest_fa;	/* Reply is forwarded to lower mobility agent in any case if it is	 * a FA; if it is a MN, the tear down message is not forwarded */#ifdef USE_TEARDOWN	if (!is_lowest_fa && idtype == ID_CHANGED &&	    binding->id[1] != ntohl(ext->rep->id[1]) &&	    ext->ext_dyn != NULL &&	    (ext->ext_dyn->opts & REG_EXT_OWN_TEAR_DOWN) != 0) {		handle_teardown_changed_id(binding, ext, unc);	} else#endif	if (!t_data->is_lowest_fa || ext->ext_dyn == NULL ||

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -