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

📄 fa.c

📁 mobile ip 在linux下的一种实现
💻 C
📖 第 1 页 / 共 3 页
字号:
/* $Id: fa.c,v 1.266 2001/09/29 07:52:24 jm Exp $ * Foreign Agent * * 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 <stdio.h>#include <sys/types.h>#include <sys/stat.h>#include <sys/socket.h>#include <sys/un.h>#include <sys/time.h>#include <string.h>#include <arpa/inet.h>#include <errno.h>#include <unistd.h>#include <syslog.h>#include <signal.h>#include <time.h>#include <assert.h>#include <getopt.h>#include <sys/uio.h>#include <fcntl.h>#include <netinet/ip_icmp.h>#include "fa.h"#include "fa_hash.h"#include "tunnel.h"#include "list.h"#include "hashtable.h"#include "agentadv.h"#include "rsa_dyn.h"#include "debug.h"#include "fixed_fd_zero.h"#include "dyn_ip.h"#include "agentapi.h"#include "util.h"#include "dyn_api.h"#include "agent_utils.h"#include "fa_mn_addr.h"#ifdef INCLUDE_IPAY#include "fa_ipay.h"#endifstruct sol_reply_list {	struct timeval send;	struct interface_entry *iface;	struct sockaddr_ll to;	struct in_addr addr;	struct sol_reply_list *next;};struct dest_unreachable_data {	char code;	struct in_addr addr;	int port;};/* sockets */#ifdef INCLUDE_IPAYstatic int ipay_sock = -1;#endifstatic int api_rw_sock = -1;static int api_ro_sock = -1;int fa_info_sock = -1;struct sockaddr_un fa_info_addr;/* dynamic data */static struct dynamics_fa_status stats;struct hashtable *tunnels_hash;struct bindingtable *bindings_hash;struct sockaddr_in upper_fa_addr;struct interface_entry *up_interface = NULL;struct msg_key *fa_public_key = NULL;struct fa_nai_ext *fa_nai = NULL;struct fa_config *config;struct binding_counters bcounters;struct challenge_ext **last_challenges;int last_challenges_pos;static char *program_name; /* the name this program was run with */static struct sol_reply_list *solrep_list = NULL;extern time_t fa_reg_next_try; /* fa_hash */static void init_sockets(void);static void init_config_data(void);static int check_delayed_solrep(struct timeval *now, struct timeval *next);static intfa_send_agent_adv(struct interface_entry *iface, struct sockaddr_ll *to,		  struct in_addr *dest);static void handle_dest_unreach(struct dest_unreachable_data *data);/* util.c - common command line arguments */extern int opt_foreground;extern char *opt_config;static voidclose_sockets(void){#ifdef INCLUDE_IPAY	close_socket(ipay_sock);	ipay_sock = -1;#endif	if (api_rw_sock > -1)		close_socket(api_rw_sock);	api_rw_sock = -1;	if (api_ro_sock > -1)		close_socket(api_ro_sock);	api_ro_sock = -1;	if (fa_info_sock > -1) {		info_send(FA_INFO_CLOSE, FA_INFO_OK, NULL, 0);		close_socket(fa_info_sock);		fa_info_sock = -1;	}	/* remove unix sockets */	if (config != NULL && config->fa_api_read_socket_path != NULL)		unlink(config->fa_api_read_socket_path);	if (config != NULL && config->fa_api_admin_socket_path != NULL)		unlink(config->fa_api_admin_socket_path);}static voidflush_solrep_list(void){	struct sol_reply_list *prev, *tmp = solrep_list;	while (tmp != NULL) {		DEBUG(DEBUG_FLAG, "Flushed solrep entry\n");		prev = tmp;		tmp = tmp->next;		free(prev);	}	solrep_list = NULL;}/* Free all reserved memory. Destroy hashes. * Unlink the unix domain socket filenames. */static voidclean_up(int sig){	/* destroy all hashes and finish nicely */	DEBUG(DEBUG_FLAG, "clean_up(%d)\n", sig);	syslog(LOG_INFO, "Foreign agent daemon cleaning up (signal %d)", sig);	fa_register(FA_DEREGISTER);	close_sockets();	unlink(FA_PID_FILE);	/* Free hashtables */	if (bindings_hash != NULL) {		DEBUG(DEBUG_FLAG, "Removing bindings..\n");		binding_iterator(bindings_hash, eliminate_binding_entry_force,				 &bcounters);		binding_destroy(bindings_hash);	}	if (tunnels_hash != NULL) {		DEBUG(DEBUG_FLAG, "Removing tunnels..\n");		tunnel_destroy_hash(tunnels_hash);	}	fa_hash_destroy();	expire_denial_records(1);	flush_solrep_list(); /* remove possible entries from the solrep list */	cleanup_fa_config(config);	if (config != NULL)		free(config);	if (fa_nai != NULL) {		free(fa_nai);		fa_nai = NULL;	}	closelog();	exit(sig);}static struct interface_entry *get_iface(int ifindex){	struct interface_entry *iface;	struct node *node;	for (node = list_get_first(&config->interfaces); node != NULL;	     node = list_get_next(node)) {		iface = (struct interface_entry *) node;		if (iface->if_index == ifindex)			return iface;	}	return NULL;}/* Update the binding iface pointers after configuration reload. * old_if_index is used to get the new pointer as the interface index does not * change */static intreload_binding_iter(struct node *node, void *data){	struct bindingentry *binding;	struct tunnel_data *t_data;	struct unconfirmed_request *unc;	binding = (struct bindingentry *) node;	t_data = (struct tunnel_data *) binding->data;	assert(t_data != NULL);	if (t_data->info.iface != NULL) {		t_data->info.iface = get_iface(t_data->old_if_index);		if (t_data->info.iface == NULL) {			LOG2(LOG_ALERT, "Interface disappeared during SIGHUP "			     "processing\n");			/* drop the binding and continue operation */			remove_binding_tunnels(binding, tunnels_hash,					       &bcounters);		}	}	unc = t_data->unc_req;	while (unc != NULL) {		unc->info.iface = get_iface(unc->old_if_index);		if (unc->info.iface == NULL) {			LOG2(LOG_ALERT, "Interface disappeared during SIGHUP "			     "processing\n");			/* drop the unconfirmed requests and continue			 * operation */			free_unconfirmed_data(t_data->unc_req);			t_data->unc_req = NULL;			break;		}		unc = unc->next;	}	return 1;}/* Update the interface pointers in bindings and unconfirmed requests */static voidreload_interface_pointers(void){	binding_iterator(bindings_hash, reload_binding_iter, NULL);}static voidreload_config(int sig){	int i;	LOG2(LOG_INFO, "Reloading configuration\n");	for (i = 0; i < config->challenge_window; i++) {		if (last_challenges[i] != NULL)			free(last_challenges[i]);	}	free(last_challenges);	last_challenges = NULL;	/* remove possible entries from the solrep list; this needs to be done	 * because the iface pointers change during configuration reloading */	flush_solrep_list();	cleanup_fa_config(config);        if (load_fa(config, program_name,		    opt_config == NULL ? FA_GLOBAL_CONF_FILE : opt_config) ==	    FALSE) {		LOG2(LOG_ALERT, "Reloading configuration failed\n");		clean_up(-1);        }	close_sockets();	closelog();	init_sockets();	init_config_data();	reload_interface_pointers();}/* search for spi/addr/agent_type match from the FA SPI list * if spi=0, accept any spi * if agent_type=0, accept any type * Returns: pointer to the SPI entry or NULL on failure */struct fa_spi_entry *get_fa_spi(int spi, struct in_addr addr, int agent_type){	struct fa_spi_entry *s;	struct node *node;	/* FIX: this might be optimized by using a hash table index by the	 * address field */	for (node = list_get_first(&config->fa_spi_list); node != NULL;	     node = list_get_next(node)) {		s = (struct fa_spi_entry *) node;		if ((spi == 0 || s->spi == spi) &&		    s->addr.s_addr == addr.s_addr &&		    (agent_type == 0 || agent_type == s->agent_type)) {			return s;		}	}	return NULL;}/** * binding_get_tunnels_iter: * @node: pointer to bindingentry * @data: pointer to the message to be returned to the API caller * * Called from handle_api on an API_GET_TUNNELS request. This function is * called for each existing binding in the bindings list. * * Returns: *  1 (to continue iteration loop) */static intbinding_get_tunnels_iter(struct node *node, void *data){	struct bindingentry *binding = (struct bindingentry *) node;	struct api_msg *api_msg = (struct api_msg *) data;	dyn_tunnel_id id;	if (api_msg->length + sizeof(dyn_tunnel_id) > API_DATA_SIZE) {		DEBUG(DEBUG_FLAG, "API message overflow - skipping rest of "		      "the bindings\n");		return 0;	}	id.mn_addr.s_addr =  binding->mn_addr.s_addr;	id.ha_addr.s_addr =  binding->ha_addr.s_addr;	id.priv_ha = binding->priv_ha;	memcpy((char *) api_msg->params + api_msg->length, &id,	       sizeof(dyn_tunnel_id));	api_msg->length += sizeof(dyn_tunnel_id);	return 1;}/* Handle api call from socket sock. If it is privileged, the admin * is set nonzero. */static voidhandle_api(int sock, int admin){        struct sockaddr_un addr;	socklen_t addrlen;	struct api_msg recv_msg;	struct api_msg send_msg;	struct bindingentry *binding;	struct dynamics_tunnel_info *info;	struct dynamics_fa_status *status;	char *path;	int flags;	dyn_tunnel_id *tid;	struct in_addr tmp_addr;	struct bindingkey bkey;        DEBUG(DEBUG_FLAG, "receive from api\n");	addrlen = sizeof(addr); /* set size of address buffer */	memset(&addr, 0, addrlen); /* zero the address */	if (api_receive(sock, &addr, &addrlen, &recv_msg) < 0) {		LOG2(LOG_ERR, "api receive: %s\n", strerror(errno));		return;	}	if (recv_msg.type != API_CALL_MSG) return;	send_msg.code = API_UNDEFINED;	send_msg.length = 0;	if (admin)		stats.apicalls_admin++;	else		stats.apicalls_read++;	switch (recv_msg.code) {        case API_GET_TUNNELS:		DEBUG(DEBUG_FLAG, "Received API_GET_TUNNELS\n");		if (recv_msg.length != 0) {			send_msg.code = API_ILLEGAL_PARAMETERS;			break;		}		if (binding_iterator(bindings_hash, binding_get_tunnels_iter,				     &send_msg))			send_msg.code = API_SUCCESS;		else			send_msg.code = API_INSUFFICIENT_SPACE;		break;        case API_GET_TUNNEL_INFO:		DEBUG(DEBUG_FLAG, "Received API_GET_TUNNEL_INFO\n");		if (recv_msg.length != sizeof(dyn_tunnel_id)) {			send_msg.code = API_ILLEGAL_PARAMETERS;			break;		}		tid = (dyn_tunnel_id *) recv_msg.params;		UNALIGNED_(&tmp_addr, &tid->ha_addr);		if (tmp_addr.s_addr == 0) {			UNALIGNED_(&tmp_addr, &tid->mn_addr);			binding = binding_fetch2(bindings_hash, &tmp_addr);		} else {			UNALIGNED_(&bkey.mn_addr, &tid->mn_addr);			UNALIGNED_(&bkey.ha_addr, &tid->ha_addr);			UNALIGNED_(&bkey.priv_ha, &tid->priv_ha);			binding = binding_fetch(bindings_hash, &bkey);		}		if (!binding) {			DEBUG(DEBUG_FLAG, "\tbinding not found\n");			send_msg.code = API_FAILED;			break;		}		info = (struct dynamics_tunnel_info *) send_msg.params;		memset(info, 0, sizeof(struct dynamics_tunnel_info));		UNALIGNED_(&info->id.mn_addr, &binding->mn_addr);		UNALIGNED_(&info->id.ha_addr, &binding->ha_addr);		UNALIGNED_(&info->mn_addr, &binding->mn_addr);		UNALIGNED_(&info->co_addr, &binding->lower_addr);		UNALIGNED_(&info->ha_addr, &binding->ha_addr);		UNALIGNED_(&info->priv_ha, &binding->priv_ha);		if (binding->data != NULL) {			struct tunnel_data *t_data = binding->data;			UNALIGNED_(&info->confirmed, &t_data->confirmed);		}		UNALIGNED_(&info->expiration_time, &binding->exp_time);		UNALIGNED_(&info->creation_time, &binding->create_time);		UNALIGNED_(&info->refresh_time, &binding->mod_time);		UNALIGNED_(&info->last_timestamp[0], &binding->id[0]);		UNALIGNED_(&info->last_timestamp[1], &binding->id[1]);		UNALIGNED_(&info->spi, &binding->spi);		UNALIGNED_(&info->timeout, &binding->timeout);		send_msg.code = API_SUCCESS;		send_msg.length = sizeof(struct dynamics_tunnel_info);		break;	case API_DESTROY_TUNNEL:		DEBUG(DEBUG_FLAG, "Received API_DESTROY_TUNNEL\n");		if (!admin) {			send_msg.code = API_NOT_PERMITTED;			break;		}		if (recv_msg.length != sizeof(dyn_tunnel_id)) {			send_msg.code = API_ILLEGAL_PARAMETERS;			break;		}		tid = (dyn_tunnel_id *) recv_msg.params;		if (tid->ha_addr.s_addr == 0)			binding = binding_fetch2(bindings_hash, &tid->mn_addr);		else {			bkey.mn_addr = tid->mn_addr;			bkey.ha_addr = tid->ha_addr;			bkey.priv_ha = tid->priv_ha;			binding = binding_fetch(bindings_hash, &bkey);		}		if (!binding) {			send_msg.code = API_FAILED;			break;		}		eliminate_binding_entry((struct node *) binding, &bcounters);		send_msg.length = 0;		send_msg.code = API_SUCCESS;		break;	case API_GET_STATUS:		DEBUG(DEBUG_FLAG, "Received API_GET_STATUS\n");		if (recv_msg.length != 0) {			send_msg.code = API_ILLEGAL_PARAMETERS;			break;		}		status = (struct dynamics_fa_status *) send_msg.params;		memcpy(status, &stats, sizeof(struct dynamics_fa_status));		UNALIGNED_(&status->tunnel_count, &bcounters.bindingcount);		UNALIGNED_(&status->pending_count, &bcounters.pendingcount);		send_msg.length = sizeof(struct dynamics_fa_status);		send_msg.code = API_SUCCESS;		break;	case API_ATTACH_INFO_SOCKET:		if (!admin) {			send_msg.code = API_NOT_PERMITTED;			break;		}		if (recv_msg.length < 1 ||		    recv_msg.length >= sizeof(fa_info_addr.sun_path)) {			send_msg.code = API_ILLEGAL_PARAMETERS;			break;		}		if (fa_info_sock > -1) {			info_send(FA_INFO_CLOSE, FA_INFO_OK, NULL, 0);			close_socket(fa_info_sock);		}		path = (char *) recv_msg.params;		path[recv_msg.length - 1] = '\0';		DEBUG(DEBUG_FLAG, "API attach info socket[%s]\n", path);		fa_info_sock = socket(AF_LOCAL, SOCK_DGRAM, 0);		if (fa_info_sock < 0) {			DEBUG(DEBUG_FLAG, "\tfailed: %s\n", strerror(errno));			send_msg.code = API_FAILED;			break;		}		/* Set non-blocking */		flags = fcntl(fa_info_sock, F_GETFL, 0);		if (flags == -1 ||		    fcntl(fa_info_sock, F_SETFL, flags | O_NDELAY) == -1) {			DEBUG(DEBUG_FLAG, "\tfcntl F_SETFL failed: %s\n",			      strerror(errno));			close(fa_info_sock);			fa_info_sock = -1;			send_msg.code = API_FAILED;			break;		}		memset(&fa_info_addr, 0, sizeof(fa_info_addr));		fa_info_addr.sun_family = AF_LOCAL;		dynamics_strlcpy(fa_info_addr.sun_path, path, recv_msg.length);		send_msg.code = API_SUCCESS;		break;	case API_DETACH_INFO_SOCKET:		if (!admin) {			send_msg.code = API_NOT_PERMITTED;			break;		}		DEBUG(DEBUG_FLAG, "API detach info socket - ");		if (fa_info_sock < 0) {			DEBUG(DEBUG_FLAG, "failed\n");			send_msg.code = API_FAILED;			break;		}		info_send(FA_INFO_CLOSE, FA_INFO_OK, NULL, 0);		close_socket(fa_info_sock);		fa_info_sock = -1;		send_msg.code = API_SUCCESS;		break;	case API_SEND_ADV:	{		/**		 * Now the only parameter we use is ifindex		 * but i think we should expand it to support		 * direct (send to mac addr) advertisements.		 * - roger@lifix.fi		 */		struct interface_entry *iface;		struct dyn_param_adv *adv;		if (recv_msg.length != sizeof(struct dyn_param_adv) ) {			send_msg.code = API_ILLEGAL_PARAMETERS;			break;		}		adv = (struct dyn_param_adv *) recv_msg.params;		if ( (iface = get_iface(adv->ifindex) ) == NULL ) {			send_msg.code = API_FAILED;			break;		}		fa_send_agent_adv(iface, NULL, NULL);		send_msg.length = 0;		send_msg.code = API_SUCCESS;		break;	}	default:		/* just send a message indicating that function is not		 * supported. No need to confirm that message gets through. */		LOG2(LOG_ERR, "Received unknown API command: %d\n",		     recv_msg.code);		send_msg.code = API_NOT_SUPPORTED;

⌨️ 快捷键说明

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