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

📄 sha_reply.c

📁 mobile ip 在linux下的一种实现
💻 C
字号:
/* $Id: sha_reply.c,v 1.8 2001/08/23 17:00:47 jm Exp $ * Surrogate Home Agent - reply handling * * Dynamic hierarchial IP tunnel * Copyright (C) 2000-2001, Jouni Malinen * * 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 <stdio.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <errno.h>#include <syslog.h>#include <string.h>#include <assert.h>#include "agent_utils.h"#include "debug.h"#include "dyn_ip.h"#include "tunnel.h"#include "sha_config.h"#include "sha.h"#include "sha_utils.h"extern int sha_sock;extern struct hashtable *tunnels_hash;extern struct bindingtable *bindings_hash;extern struct sha_config *config;extern int bindingcount;static struct unconfirmed_request*find_matching_request(struct bindingentry *binding, __u32 id){	struct unconfirmed_request *unc;	struct tunnel_data *t_data;	t_data = (struct tunnel_data *) binding->data;	/* 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");			return unc;		}		unc = unc->next;	}	return NULL;}static voidunconfirmed_to_binding(struct bindingentry *binding,		       struct unconfirmed_request *unc){	struct tunnel_data *t_data = binding->data;	binding->lower_addr = unc->lower_addr;	binding->lower_port = unc->lower_port;	binding->spi = unc->spi;	binding->fa_spi = unc->fa_spi;	binding->ha_addr = unc->ha_addr;	t_data->down_type = unc->tunnel_type;	t_data->down_key = unc->tunnel_key;}static intcreate_tunnels(struct bindingentry *binding, struct sha_spi_entry *spi){	struct tunnel_data *t_data = binding->data;	char dev[IFNAMSIZ];	struct in_addr addr;	t_data->down_tunl = tunnel_add(tunnels_hash, binding->lower_addr,				       binding->tun_dev, config->sha_addr,				       1, t_data->down_type, t_data->down_key);	if (t_data->down_tunl == NULL) {		LOG2(LOG_WARNING, "create_tunnels: tunnel_add(down) failed\n");		return -1;	}	addr = config->sha_addr;	if (dyn_ip_route_get(spi->addr, dev, IFNAMSIZ) < 0 ||	    dyn_ip_get_ifaddr(dev, &addr) < 0) {		LOG2(LOG_WARNING, "create_tunnels: could not get interface "		     "address towards private HA %s\n", inet_ntoa(spi->addr));	}	t_data->up_tunl = tunnel_add(tunnels_hash, spi->addr,				     t_data->ha_tun_dev, addr,				     1, t_data->up_type, t_data->up_key);	if (t_data->up_tunl == NULL) {		LOG2(LOG_WARNING, "create_tunnels: tunnel_add(up) failed\n");		return -1;	}	if (tunnel_connect(t_data->up_tunl, t_data->down_tunl,			   binding->mn_addr, 1, NULL, NULL) < 0) {		LOG2(LOG_WARNING, "create_tunnels - tunnel_connect failed\n");	}	return 0;}static voidforward_reply(struct msg_extensions *ext, struct bindingentry *binding,	      struct unconfirmed_request *unc, struct sha_spi_entry *ha_spi){	char buf[MAXMSG];	int res, len;	struct sockaddr_in dst;	struct sha_spi_entry *spi;	unsigned char *sk = NULL;	int sk_len;	assert(ext != NULL && binding != NULL && unc != NULL &&	       ha_spi != NULL);	if (ext->rep == NULL || ext->mh_auth == NULL) {		LOG2(LOG_WARNING, "forward_reply: not rep or mh_auth\n");		return;	}	/* copy the MAC protected area directly from the received message */	len = (__u8 *) ext->mh_auth - (__u8 *) ext->rep +		GET_AUTH_EXT_LEN(ext->mh_auth);	if (len < sizeof(struct reg_req) + GET_AUTH_EXT_LEN(ext->mh_auth) ||	    len > MAXMSG) {		LOG2(LOG_WARNING, "forward_request: invalid length %i\n",		     len);		return;	}	memcpy(buf, ext->rep, len);	DEBUG(DEBUG_FLAG, " * copying up to and including mh_auth "	      "(len ==> %i)\n", len);	if (ext->fa_keyrep != NULL) {		sk = auth_decrypt(ha_spi->alg, ha_spi->shared_secret,				  ha_spi->shared_secret_len,				  ext->fa_keyrep, ext->rep, &sk_len);		if (sk_len < 0 || sk_len > MAX_SK_LEN) {			DEBUG(DEBUG_FLAG, "Could not decrypt fa_keyrep\n");			if (sk != NULL)				free(sk);			return;		}	}	    	spi = get_sha_spi(0, unc->lower_addr, 0);	if (sk != NULL && unc->fa_pubkey != NULL) {		struct msg_key *pubrep;		DEBUG(DEBUG_FLAG, " * adding fa_pubkeyrep\n");		pubrep = dynamics_do_rsa_encrypt(sk, sk_len, unc->fa_pubkey);		if (pubrep == NULL) {			DEBUG(DEBUG_FLAG, "Could not encrypt with pubkey\n");			if (sk != NULL)				free(sk);			return;		}		if (len + GET_KEY_EXT_LEN(pubrep) > MAXMSG) {			DEBUG(DEBUG_FLAG, "Message overflow\n");			if (sk != NULL)				free(sk);			return;		}		memcpy(&buf[len], pubrep, GET_KEY_EXT_LEN(pubrep));		free(pubrep);	} else if (sk != NULL && unc->fa_spi != 0 && spi != NULL) {		struct msg_key *key;		DEBUG(DEBUG_FLAG, " * adding fa_keyrep\n");		key = (struct msg_key *) &buf[len];		len += auth_encrypt(spi->alg, spi->shared_secret,				    spi->shared_secret_len, sk,				    key, (struct reg_rep *) buf,				    VENDOR_EXT_DYNAMICS_FA_KEYREP,				    htonl(spi->spi));	}	if (sk != NULL) {		free(sk);		sk = NULL;	}	/* Add SHA-FA ext. auth. */	if (spi != NULL) {		if (len + sizeof(struct msg_auth) + MAX_SK_LEN > MAXMSG) {			DEBUG(DEBUG_FLAG, "\tnot enough space for the "			      "message\n");			return;		}		len += auth_add(spi->alg, spi->shared_secret,				spi->shared_secret_len, (unsigned char *) buf,				(struct msg_auth *) &buf[len],				FH_AUTH, htonl(spi->spi));	}	memset(&dst, 0, sizeof(dst));	dst.sin_family = AF_INET;	dst.sin_addr = unc->lower_addr;	dst.sin_port = unc->lower_port;	DEBUG(DEBUG_FLAG, "\tforwarding reply to %s:%i\n",	      inet_ntoa(dst.sin_addr), dst.sin_port);	if (!send_address_ok(dst.sin_addr)) {		DEBUG(DEBUG_FLAG, "\tinvalid address\n");		return;	}	res = sendto(sha_sock, buf, len, 0, (struct sockaddr *) &dst,		     sizeof(dst));	if (res < 0) {		DEBUG(DEBUG_FLAG, "\tsendto: %s\n", strerror(errno));	}}static voidswitch_tunnels(struct bindingentry *binding, struct unconfirmed_request *unc){	struct tunnel *old_tunl;	struct tunnel_data *t_data = binding->data;	if (unc->tunnel_type == t_data->down_type &&	    unc->tunnel_key == t_data->down_key &&	    unc->lower_addr.s_addr == binding->lower_addr.s_addr)		return;	DEBUG(DEBUG_FLAG, "Switching tunnels: %s (%i,%i) => ",	      inet_ntoa(binding->lower_addr), t_data->down_type,	      t_data->down_key);	DEBUG(DEBUG_FLAG, "%s (%i,%i)\n",	      inet_ntoa(unc->lower_addr), unc->tunnel_type, unc->tunnel_key);	old_tunl = t_data->down_tunl;	t_data->down_type = unc->tunnel_type;	t_data->down_key = unc->tunnel_key;	binding->lower_addr = unc->lower_addr;	t_data->down_tunl = tunnel_add(tunnels_hash, binding->lower_addr,				       binding->tun_dev, config->sha_addr,				       1, t_data->down_type, t_data->down_key);	if (tunnel_unconnect(t_data->up_tunl, old_tunl, binding->mn_addr, 1,			     0, NULL, NULL) < 0) {		LOG2(LOG_WARNING, "switch_tunnels - tunnel_unconnect "		     "failed\n");	}	if (tunnel_connect(t_data->up_tunl, t_data->down_tunl,			   binding->mn_addr, 1, NULL, NULL) < 0) {		LOG2(LOG_WARNING, "switch_tunnels - tunnel_connect failed\n");	}	if (tunnel_delete_ptr(old_tunl, 0)) {		LOG2(LOG_WARNING, "switch_tunnels - tunnel_delete_ptr "		     "failed\n");	}}voidhandle_reply(char *msg, int len, struct msg_extensions *ext,	     struct sockaddr_in *addr){	struct bindingentry *binding;	struct bindingkey bkey;	struct tunnel_data *t_data;	struct unconfirmed_request *unc;	struct sha_spi_entry *spi;	struct in_addr tmpaddr;	DEBUG(DEBUG_FLAG, "Handling reply to MN %s",	      inet_ntoa(ext->rep->home_addr));	DEBUG(DEBUG_FLAG, " (%s:%d)\n", inet_ntoa(addr->sin_addr),	      ntohs(addr->sin_port));	if (ext->nonce == NULL) {		DEBUG(DEBUG_FLAG, "\tno nonce ext\n");		return;	}	if (ext->priv_ha == NULL) {		DEBUG(DEBUG_FLAG, "\tno priv_ha ext\n");		return;	}	if (ntohl(ext->priv_ha->priv_ha) == 0) {		DEBUG(DEBUG_FLAG, "\tpriv_ha=0\n");		return;	}	/* Check SHA-HA auth. ext */	tmpaddr.s_addr = 0;	spi = get_sha_spi(0, tmpaddr, ntohl(ext->priv_ha->priv_ha));	if (spi == NULL) {		DEBUG(DEBUG_FLAG, "\tprivate HA ID %u not found\n",		      ntohl(ext->priv_ha->priv_ha));		return;	}	if (ext->sha_ha_auth == NULL) {		DEBUG(DEBUG_FLAG, "\tno SHA-HA auth. ext.\n");		return;	}	if (!auth_check_vendor(spi->alg, spi->shared_secret,			       spi->shared_secret_len, (unsigned char *) msg,			       ext->sha_ha_auth)) {		DEBUG(DEBUG_FLAG, "\tinvalid SHA-HA auth. ext.\n");		return;	}	memcpy(&bkey.mn_addr, &(ext->rep->home_addr), sizeof(bkey.mn_addr));	memcpy(&bkey.ha_addr, &(ext->rep->ha_addr), sizeof(bkey.ha_addr));	bkey.priv_ha = ntohl(ext->priv_ha->priv_ha);	binding = binding_fetch(bindings_hash, &bkey);	if (binding == NULL) {		DEBUG(DEBUG_FLAG, "\tno binding found (MN=%s, ",		      inet_ntoa(bkey.mn_addr));		DEBUG(DEBUG_FLAG, "HA=%s, priv_ha=%i)\n",		      inet_ntoa(bkey.ha_addr), bkey.priv_ha);		return;	}	t_data = (struct tunnel_data *) binding->data;	unc = find_matching_request(binding, ntohl(ext->rep->id[1]));	if (unc == NULL) {		DEBUG(DEBUG_FLAG, "\tcould not found a matching request for "		      "the reply - dropping it\n");		return;	}	if (ntohl(ext->nonce->nonce) != unc->nonce) {		DEBUG(DEBUG_FLAG, "\tinvalid nonce: expected 0x%08x, got "		      "0x%08x\n", unc->nonce, ntohl(ext->nonce->nonce));		return;	}	if (IS_REGREP_ACCEPTED(ext->rep->code)) {		if (ntohs(ext->rep->lifetime) == 0) {			if (binding->timeout > 2) {				DEBUG(DEBUG_FLAG, "Deregistration reply - "				      "setting tunnel lifetime to 2 secs\n");				binding->timeout = 2;			}		} else {			if (t_data->confirmed) {				switch_tunnels(binding, unc);			}			unconfirmed_to_binding(binding, unc);			if (!t_data->confirmed) {				if (create_tunnels(binding, spi) < 0) {					DEBUG(DEBUG_FLAG,					      "create_tunnels failed\n");					return;				}				t_data->confirmed = 1;			}			binding->timeout = ntohs(ext->rep->lifetime);			if (binding->timeout > config->max_lifetime)				binding->timeout = config->max_lifetime;			binding->timeout++;		}		binding->exp_time = time(NULL) + binding->timeout;		if (update_binding(bindings_hash, binding,				   &bindingcount) != 0)			LOG2(LOG_WARNING, "update_binding failed\n");	}	forward_reply(ext, binding, unc, spi);}

⌨️ 快捷键说明

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