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

📄 fa_utils.c

📁 mobile ip 在linux下的一种实现
💻 C
📖 第 1 页 / 共 2 页
字号:
/* $Id: fa_utils.c,v 1.89 2001/09/27 17:33:54 jm Exp $ * Foreign Agent - independent help routines * * 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#ifndef _GNU_SOURCE#define _GNU_SOURCE /* for snprintf() etc. */#endif#include <stdio.h>#include <stdlib.h>#include <string.h>#include <syslog.h>#include <errno.h>#include <unistd.h>#include <assert.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <sys/un.h>#include "tunnel.h"#include "debug.h"#include "rsa_dyn.h"#include "dyn_ip.h"#include "fa.h"#include "fa_mn_addr.h"#include "fa_hash.h"#include "util.h"#include "proxyarp.h"#ifndef IP_PKTINFO#define IP_PKTINFO 8#endif#ifndef IP_RECVTTL#define IP_RECVTTL      12#endif#define PURGE_BINDING_TUNNELS 2extern struct interface_entry *up_interface;extern int fa_info_sock;extern struct sockaddr_un fa_info_addr;extern struct sockaddr_in upper_fa_addr;extern struct fa_config *config;/** * send_address_ok: * @to_addr:  *  * try to avoid looping messages to own addresses * * Returns: TRUE if the address is okay or FALSE if it is not  */intsend_address_ok(struct in_addr to_addr){#ifndef DEBUG_SIMULATED_TEST	char dev[IFNAMSIZ];	/* check that destionation interface != lo */	if (dyn_ip_route_get(to_addr, dev, IFNAMSIZ) == 0 &&	    strcmp(dev, "lo") == 0) {		LOG2(LOG_ALERT,		     "send_address_ok: destination to 'lo' "		     "interface - possible loop => refusing\n");		return FALSE;	}#endif	return TRUE;}/** * own_sendto: * @sock:  * @to_addr:  * @to_port:  * @data:  * @len:  *  *  *  * Returns:  */intown_sendto(int sock, struct in_addr to_addr, unsigned int to_port, void *data,	   int len){	struct sockaddr_in sa;	if (!send_address_ok(to_addr))		return -2;	memset(&sa, 0, sizeof(sa));	sa.sin_family = AF_INET;	sa.sin_addr = to_addr;	sa.sin_port = to_port;	return sendto(sock, data, len, 0,		     (struct sockaddr *) &sa, sizeof(sa));}/** * close_socket: * @fd:  *  *  */voidclose_socket(int fd){	if (fd < 0) return;	if (close(fd) == -1)		DEBUG(DEBUG_FLAG, "close_socket(%i) - %s\n", fd,		      strerror(errno));}/** * free_unconfirmed_data: * @unc:  *  *  */voidfree_unconfirmed_data(struct unconfirmed_request *unc){	struct unconfirmed_request *prev;	while (unc != NULL) {		prev = unc;		unc = unc->next;		if (prev->fa_pubkey != NULL)			free(prev->fa_pubkey);		if (prev->challenge != NULL)			free(prev->challenge);		free(prev);	}}/** * free_binding: * @binding: the binding to be freed * @bcounters: binding counters (confirmed bindings, pending registrations) *  * Frees the memory used by a binding and updates the binding and pending * registration counts. */static voidfree_binding(struct bindingentry *binding, struct binding_counters *bcounters){	struct tunnel_data *t_data;	if (binding == NULL || binding->data == NULL)		return;	t_data = (struct tunnel_data *) binding->data;	if (t_data->used_challenges != NULL) {		int i;		for (i = 0; i < 2 * config->challenge_window; i++)			if (t_data->used_challenges[i] != NULL)				free(t_data->used_challenges[i]);		free(t_data->used_challenges);	}	if (t_data->fa_pubkey != NULL)		free(t_data->fa_pubkey);	if (t_data->last_sent_fa_pubkeyrep != NULL)		free(t_data->last_sent_fa_pubkeyrep);	if (t_data->last_recv_fa_pubkeyrep != NULL)		free(t_data->last_recv_fa_pubkeyrep);	if (t_data->last_challenge != NULL)		free(t_data->last_challenge);	free_unconfirmed_data(t_data->unc_req);	if (bcounters != NULL) {		if (t_data->confirmed)			bcounters->bindingcount--;		else			bcounters->pendingcount--;	}	free(binding->data);	free(binding);}static intelim_binding(struct node *node, void *data, int force){	struct bindingentry *binding;	int type;	struct tunnel_data *t_data;	binding = (struct bindingentry *) node;	t_data = (struct tunnel_data *) binding->data;	if (t_data->arpentry) {		DEBUG(DEBUG_FLAG, "Removing the ARP entry of the MN\n");		if (arp_del_permanent_item(t_data->arp_ipaddr, t_data->arp_dev)		    < 0) {			LOG2(LOG_WARNING, "Could not remove permanent ARP "			     "entry (%s, %s)\n",			     inet_ntoa(t_data->arp_ipaddr), t_data->arp_dev);		} else			t_data->arpentry = 0;	}	if (t_data->confirmed) {#ifdef DYNAMICS_SET_MAIN_TABLE_MN_ROUTE		if (t_data->fa_decapsulation &&		    dyn_ip_route_del(binding->mn_addr, t_data->info.iface->dev)		    != 0) {			LOG2(LOG_WARNING,			     "dyn_ip_route_del(%s,%s) failed\n",			     inet_ntoa(binding->mn_addr),			     t_data->info.iface->dev);		}#endif /* DYNAMICS_SET_MAIN_TABLE_MN_ROUTE */		if (t_data->up_tunl &&		    dyn_ip_rule_del_table(NULL, &binding->mn_addr,					  t_data->up_tunl->to_mn_table_id,					  "lo") != 0) {			LOG2(LOG_WARNING, "Removal of routing rule for "			     "locally generated packets failed (mn_addr=%s, "			     "table=%i)\n", inet_ntoa(binding->mn_addr),			     t_data->up_tunl->to_mn_table_id);		}		if (tunnel_unconnect(t_data->up_tunl, t_data->down_tunl,				     binding->mn_addr, t_data->tunnel_mode ==				     TUNNEL_MODE_REVERSE ? 1 : 0, force,				     t_data->force_route_dev,				     t_data->force_reverse_dev) < 0) {			LOG2(LOG_WARNING, "tunnel unconnect failed "			     "(tun_dev=%s, dev=%s, encaps_delivery=%i)\n",			     binding->tun_dev, t_data->info.iface->dev,			     t_data->encaps_delivery);		}		if (tunnel_delete_ptr(t_data->down_tunl, force) == -1) {			LOG2(LOG_WARNING,			     "tunnel down - tunnel_delete failed\n");		}		if (tunnel_delete_ptr(t_data->up_tunl, force) == -1) {			LOG2(LOG_WARNING,			     "tunnel up - tunnel_delete failed\n");		}	}	if (t_data->up_type == TUNNEL_IPIP)		type = -1;	else		type = t_data->up_key;	if (t_data->mn_addr_added) {		if (mn_addr_remove(&binding->mn_addr, type) < 0) {			LOG2(LOG_WARNING, "mn_addr_remove(%s,%i) failed\n",			     inet_ntoa(binding->mn_addr), type);		} else {			DEBUG(DEBUG_FLAG, "mn_addr - released addr=%s, "			      "type=%i\n", inet_ntoa(binding->mn_addr), type);		}	}	binding_remove(binding);	free_binding(binding, data);	return TRUE;}/** * eliminate_binding_entry: * @node:  * @data:  *  *  *  * Returns:  */inteliminate_binding_entry(struct node *node, void *data){	return elim_binding(node, data, 0);}/** * eliminate_binding_entry_force: * @node:  * @data:  *  *  *  * Returns:  */inteliminate_binding_entry_force(struct node *node, void *data){	return elim_binding(node, data, 1);}/** * update_binding: * @hash: pointer to the binding hashtable * @binding: the binding to be updated * @count: confirmed bindings count * @pcount: pending registration count *  * Updates the binding entry by removing the entry from the binding table and * adding it back. This needs to be done when the lifetime of the binding has * changed. *  * Returns: 1 if successful, else 0 */intupdate_binding(struct bindingtable *hash, struct bindingentry *binding,	       struct binding_counters *bcounters){	if (!binding_update(hash, binding)) {		LOG2(LOG_WARNING, "update_binding: binding_update failed\n");		free_binding(binding, bcounters);		return 1;	}	return 0;}/** * make_new_binding: * @bhash: Table of all bindings. * @ext: Registation request extensions. * @max_lifetime: Maximum lifetime allowed for the binding. *  * Create a binding and add it to the binding table @bhash. The * lifetime for the binding will the smaller value of @max_lifetime * and the requested lifetime in @ext. *  * Returns: A pointer to the binding, or NULL on failure. */struct bindingentry *make_new_binding(struct bindingtable *bhash, struct msg_extensions *ext,		 int max_lifetime, struct binding_counters *bcounters){	struct bindingentry *binding;	struct tunnel_data *t_data;	int i;	binding = (struct bindingentry *) malloc(sizeof(struct bindingentry));	if (binding == NULL)		return NULL;	t_data = (struct tunnel_data *) malloc(sizeof(struct tunnel_data));	if (t_data == NULL) {		free(binding);		return NULL;	}	memset(binding, 0, sizeof(struct bindingentry));	memset(t_data, 0, sizeof(struct tunnel_data));	t_data->used_challenges = (struct challenge_ext **)		malloc(2 * config->challenge_window *		       sizeof(struct challenge_ext *));	if (t_data->used_challenges == NULL) {		free(binding);		free(t_data);		return NULL;	}	for (i = 0; i < 2 * config->challenge_window; i++)		t_data->used_challenges[i] = NULL;	binding->data = t_data;	time(&binding->create_time);	time(&binding->mod_time);	binding->mn_addr.s_addr = ext->req->home_addr.s_addr;	binding->ha_addr.s_addr = ext->req->ha_addr.s_addr;	if (ext->priv_ha != NULL)		binding->priv_ha = ntohl(ext->priv_ha->priv_ha);	else		binding->priv_ha = 0;	t_data->confirmed = FALSE;#ifdef INCLUDE_IPAY	if (ext->mn_nai) {		t_data->mn_nai.len = GET_MN_NAI_LEN(ext->mn_nai);		t_data->mn_nai.nai = malloc(t_data->mn_nai.len);		if (t_data->mn_nai.nai == NULL) {			free(t_data);			free(binding);			return NULL;		}		memcpy(t_data->mn_nai.nai, MSG_MN_NAI_DATA(ext->mn_nai),		       t_data->mn_nai.len);	}#endif	/* add default values for upper tunnel - changed if needed */	t_data->up_type = TUNNEL_IPIP;	t_data->up_key = 0;	if (ntohs(ext->req->lifetime) < max_lifetime)		binding->timeout = ntohs(ext->req->lifetime);	else		binding->timeout = max_lifetime;	binding->exp_time = time(NULL) + binding->timeout;	if (!binding_add(bhash, binding)) {		free_binding(binding, NULL);		return NULL;	}	bcounters->pendingcount++;	return binding;}/** * equal_pubkey: * @key1:  * @key2:  *  * Returns: non-zero if key1 and key2 are identical or zero if they differ  */intequal_pubkey(struct msg_key *key1, struct msg_key *key2){	if (key1 == NULL && key2 == NULL)		return 1;	if (key1 == NULL || key2 == NULL)		return 0;	if (key1->type != key2->type || key1->length != key2->length ||	    key1->spi != key2->spi)		return 0;	return memcmp(MSG_KEY_DATA(key1), MSG_KEY_DATA(key2),		      GET_KEY_LEN(key1)) == 0;}/** * do_rsa_decrypt: * @keyrep:  * @sk:  * @sk_len:  *  *  *  * Returns:  */intdo_rsa_decrypt(struct msg_key *keyrep, unsigned char *sk, int sk_len){#ifndef NODEBUGMODE	int i;#endif	if (rsa_decrypt_session_key(MSG_KEY_DATA(keyrep), keyrep->length,				    sk, sk_len) != 0) {		LOG2(LOG_WARNING, "Session key decryption failed!\n");		return 1;	}#ifndef NODEBUGMODE	DEBUG(DEBUG_FLAG, "Session key (RSA): ");	for (i = 0; i < sk_len; i++)		DEBUG(DEBUG_FLAG, "%02x", sk[i]);	DEBUG(DEBUG_FLAG, "\n");#endif	return 0;}static intcreate_tunnel_upwards(struct bindingentry *binding, struct hashtable *thash,		      int highest_FA){	struct tunnel_data *t_data;	t_data = binding->data;	DEBUG(DEBUG_FLAG, "create_tunnel_upwards: highest_FA=%i, "	      "t_data->up_type=%i, t_data->down_type=%i\n", highest_FA,	      t_data->up_type, t_data->down_type);	assert(up_interface != NULL);	t_data->up_tunl = tunnel_add(thash, highest_FA ? binding->ha_addr :				     upper_fa_addr.sin_addr,				     t_data->ha_tun_dev,				     up_interface->addr, 1, t_data->up_type,				     t_data->up_key);	if (t_data->up_tunl == NULL) {		LOG2(LOG_WARNING,		     "create_tunnel_upwards: tunnel add failed\n");		return -1;	}	if (!highest_FA) {		/* don't remove tunnels to upper FAs */		tunnel_set_remove(t_data->up_tunl, 1);	}	if (tunnel_connect(t_data->up_tunl, t_data->down_tunl,			   binding->mn_addr, t_data->tunnel_mode ==			   TUNNEL_MODE_REVERSE ? 1 : 0,			   (t_data->fa_decapsulation &&			    t_data->encaps_delivery)			   ? t_data->info.iface->dev : NULL,			   (!t_data->fa_decapsulation &&			    !t_data->encaps_delivery)			   ? t_data->info.iface->dev : NULL) < 0) {		LOG2(LOG_WARNING, "create_tunnel_upwards: "		     "- tunnel connection failed\n");		return -1;	}	if (dyn_ip_rule_add_table(NULL, &binding->mn_addr,				  t_data->up_tunl->to_mn_table_id,				  "lo") != 0) {		LOG2(LOG_WARNING, "Adding routing rule for "		     "locally generated packets failed (mn_addr=%s, "		     "table=%i)\n", inet_ntoa(binding->mn_addr),		     t_data->up_tunl->to_mn_table_id);	}	return 0;}/** * create_tunnels: * @binding: * @thash: hash of tunnels * @highest_FA: is this the highest FA? *  * Called when reply received. Takes care of tunnels and routing * upwards.  *  * Returns: 0 if successful, else 1 or -1 */intcreate_tunnels(struct bindingentry *binding, struct hashtable *thash,	       int highest_FA){	struct tunnel_data *t_data;	char *dev;	t_data = binding->data;	/* Tunnel downwards	 * The tunnel should be already made, but with reference count	 * zero as the lazy tunnel deletion keeps the tunnel up long	 * enough. Look in handle_request(). */	assert(t_data->info.iface != NULL);	if (t_data->fa_decapsulation && !t_data->encaps_delivery) {		DEBUG(DEBUG_FLAG, "create_tunnels: down_key - %i=>%i\n",		      t_data->down_key, t_data->info.iface->if_index);		t_data->down_type = TUNNEL_NO_ENCAPS;		/* use ifindex to make separate entries for each interface */		t_data->down_key = t_data->info.iface->if_index;	}	t_data->down_tunl = tunnel_add(thash, binding->lower_addr,				       binding->tun_dev,				       t_data->info.iface->addr,				       1, t_data->down_type, t_data->down_key);	if (t_data->down_tunl == NULL) {		LOG2(LOG_WARNING, "create_tunnels: tunnel_add failed.\n");		return 1;	}	/* Lock the tunnel in use if it is to a lower FA (not to MN using	 * MN decapsulation) */	if (t_data->down_type != TUNNEL_NO_ENCAPS &&	    fa_hash_check_next_hop(binding->lower_addr)) {		/* don't remove tunnels to lower FAs */		tunnel_set_remove(t_data->down_tunl, 1);	}	dev = t_data->fa_decapsulation ? t_data->info.iface->dev :		binding->tun_dev;	if (t_data->down_type == TUNNEL_NO_ENCAPS) {		dynamics_strlcpy(t_data->down_tunl->device, dev, IFNAMSIZ);	}	/* Add an ARP entry if this FA is directly connected to the MN	 * (i.e., LFA) */

⌨️ 快捷键说明

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