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

📄 fa.c

📁 mobile ip 在linux下的一种实现
💻 C
📖 第 1 页 / 共 3 页
字号:
 * Schedule next wake up time. The next wake up time can be caused * by any of the following events: * - a regular Agent advertisement is due * - a binding has expired * - a delayed Solicitation reply is due * - FA registration is due * - delayed tunnel deletion is due */static intset_expr_timer(struct timeval *tv, struct timeval next_agentadv) {	int expire_time, diff;	struct timeval solrep;	struct timeval now;	gettimeofday(&now, NULL);	if (timerisset(&next_agentadv)) {		tv->tv_sec = next_agentadv.tv_sec - now.tv_sec ;		tv->tv_usec = next_agentadv.tv_usec - now.tv_usec;		if (tv->tv_usec <0) {			tv->tv_sec--;			tv->tv_usec += 1000000;		}		if (tv->tv_sec < 0) {			tv->tv_sec = 0;			tv->tv_usec = 0;		}	} else {		tv->tv_sec = -1;		tv->tv_usec = 0;	}	if ((expire_time = binding_nextexpiretime(bindings_hash)) >= 0) {		DEBUG(DEBUG_FLAG2, "set_expr_timer: binding next expire %d\n",		      expire_time);		if (tv->tv_sec < 0 || expire_time < tv->tv_sec) {			tv->tv_sec = expire_time;			tv->tv_usec = 0;		}	}	solrep.tv_sec = 0;	solrep.tv_usec = 0;	check_delayed_solrep(&now, &solrep);	if (solrep.tv_sec >= 0) {		DEBUG(DEBUG_FLAG, "set_expr_timer: remaining delayed "		      "solicitation reply\n");		if (tv->tv_sec < 0 || solrep.tv_sec < tv->tv_sec ||		    (solrep.tv_sec == tv->tv_sec && 		     solrep.tv_usec < tv->tv_usec)) {			tv->tv_sec = solrep.tv_sec;			tv->tv_usec = solrep.tv_usec;		}	}	diff = fa_reg_next_try - now.tv_sec;	if (fa_reg_next_try > 0 && (tv->tv_sec == -1 || diff < tv->tv_sec))		tv->tv_sec = diff < 0 ? 0 : diff;	if (tv->tv_sec == -1 && tunnel_delayed_exists(tunnels_hash))		tv->tv_sec = TUNNEL_DELAYED_CHECK_INTERVAL;	return 0;}struct search_data {	struct bindingentry *binding;	struct unconfirmed_request *unc;	struct in_addr addr;};static inthandle_dest_iter(struct node *node, void *data){	struct bindingentry *binding;	struct tunnel_data *t_data;	struct search_data *search;	struct unconfirmed_request *unc;	binding = (struct bindingentry *) node;	if (binding == NULL || data == NULL) return 0;	t_data = (struct tunnel_data *) binding->data;	if (t_data == NULL) return 0;	search = (struct search_data *) data;	unc = t_data->unc_req;	while (unc != NULL) {		if (unc->ha_addr.s_addr == search->addr.s_addr) {			search->binding = binding;			search->unc = unc;			return 0;		}		unc = unc->next;	}	return 1;}static voidhandle_dest_unreach(struct dest_unreachable_data *data){	struct search_data search;	struct msg_extensions ext;	struct reg_req req;	int reply_code;	struct tunnel_data *t_data;	if (!config->highest_FA)		return;	if (data->port != -1 && data->port != htons(config->ha_udp_port))		return;	search.binding = NULL;	search.unc = NULL;	search.addr = data->addr;	binding_iterator(bindings_hash, handle_dest_iter, &search);	if (search.unc == NULL)		return;	switch (data->code) {	case ICMP_NET_UNREACH:		reply_code = REGREP_HN_UNCREACHABLE_FA;		break;	case ICMP_HOST_UNREACH:		reply_code = REGREP_HA_HOST_UNCREACHABLE_FA;		break;	case ICMP_PORT_UNREACH:		reply_code = REGREP_HA_PORT_UNCREACHABLE_FA;		break;	default:		reply_code = REGREP_HA_UNREACHABLE_FA;		break;	}	DEBUG(DEBUG_FLAG, "handle_dest_unreach: found unconfirmed "	      "request that resulted in HA unreachable\n");	memset(&ext, 0, sizeof(ext));	ext.req = &req;	memset(&req, 0, sizeof(req));	req.home_addr.s_addr = search.binding->mn_addr.s_addr;	req.ha_addr.s_addr = search.unc->ha_addr.s_addr;	req.id[0] = htonl(search.unc->id[0]);	req.id[1] = htonl(search.unc->id[1]);	send_failure_reply(reply_code, &ext, &search.unc->info, NULL, 0);	/* no need to inform MN about pending request timing out after this	 * error reply */	t_data = (struct tunnel_data *) search.binding->data;	if (t_data != NULL)		t_data->pending_request = FALSE;}static intfa_send_agent_adv(struct interface_entry *iface, struct sockaddr_ll *to,		  struct in_addr *dest){	__u16 adv_opts;	__u8 own_adv_opts;	int ret;	struct challenge_ext *challenge = NULL;	/* Set Agent Advertisement data */	adv_opts = AGENT_ADV_FOREIGN_AGENT;	if (config->reg_required)		adv_opts |= AGENT_ADV_REGISTRATION_REQUIRED;	if (config->enable_reverse_tunneling)		adv_opts |= AGENT_ADV_BIDIR_TUNNELING;	if (bcounters.bindingcount >= config->max_bindings ||	    (config->max_pending > 0 &&	     bcounters.pendingcount >= config->max_pending))		adv_opts |= AGENT_ADV_BUSY;	own_adv_opts = 0;	if (config->enable_triangle_tunneling)		own_adv_opts |= AGENT_ADV_OWN_TRIANGLE_TUNNELING;	set_agent_adv_data(		config->fa_default_tunnel_lifetime,		config->highest_fa_addr,		iface->addr, adv_opts, own_adv_opts,		iface->interval > 21845 ?		65535 : iface->interval * 3, config->hfa_pubkey_hash_len > 0 ?		config->hfa_pubkey_hash : NULL,		config->hfa_pubkey_hash_len);	set_agent_adv_nai(fa_nai);#ifdef INCLUDE_IPAY	set_agent_adv_ipay(config->timePrice, config->bytePrice);#endif	if (config->enable_challenge_response) {		challenge = create_challenge_ext(config,						 AGENT_ADV_CHALLENGE_EXT);		set_agent_adv_challenge(challenge);	}	ret = send_agent_advertisement(iface->icmp_sock,				       (struct sockaddr *) to, dest,				       iface->if_index);	if (ret < 0) {		DEBUG(DEBUG_FLAG, "Sending agent advertisement to interface "		      "'%s' failed\n", iface->dev);	}	if (config->enable_challenge_response) {		set_agent_adv_challenge(NULL);		/* record the last challenge_window advertised challenges */		if (last_challenges[last_challenges_pos] != NULL)			free(last_challenges[last_challenges_pos]);		last_challenges[last_challenges_pos] = challenge;		last_challenges_pos++;		if (last_challenges_pos >= config->challenge_window)			last_challenges_pos = 0;	}	return ret;}/* send_agent_advs: *  * Send agent advertisements on interfaces.  * * Fill in next_agentadv with the time when the next advertisement * is due.  * * Updates iface.last_adv in the config.interfaces list. */static voidsend_agent_advs(struct timeval *next_agentadv){	struct interface_entry *iface;	struct node *node;	struct timeval now, next;	unsigned int diff;	int first = 1;	/* Send ICMP Agent Advertisement message and save the timestamp */	gettimeofday(&now, NULL);	next.tv_sec = 0;	next.tv_usec = 0;	for (node = list_get_first(&config->interfaces); node != NULL;	     node = list_get_next(node)) {		iface = (struct interface_entry *) node;		if (iface->agentadv != INTERFACE_AGENTADV_ALL)			continue;		if (now.tv_sec > iface->last_adv.tv_sec + iface->interval - 1)		{			if (!fa_send_agent_adv(iface, NULL, NULL))				stats.adv_sent++;			iface->last_adv.tv_sec = now.tv_sec;			iface->last_adv.tv_usec = now.tv_usec;		}		next.tv_sec  = iface->last_adv.tv_sec + iface->interval;		/* Add random delay */		next.tv_usec = iface->last_adv.tv_usec +			(int) (MAX_ADV_DELAY * rand() / (RAND_MAX + 1.0));		if (next.tv_usec > 999999) {			next.tv_sec++;			next.tv_usec -= 1000000;		}		if (first || next.tv_sec < next_agentadv->tv_sec) {			DEBUG(DEBUG_FLAG, "** ");			*next_agentadv = next;		}		first = 0;		/* for debuging */		diff = ((next.tv_sec - now.tv_sec) * 1000000 + 			next.tv_usec - now.tv_usec) / 1000; 		DEBUG(DEBUG_FLAG, "send_agent_advs: next agentadv: "		      "%ld.%ld diff = %d msec\n", 		      next.tv_sec, next.tv_usec, diff);	}}static intcheck_delayed_solrep(struct timeval *now, struct timeval *next){	struct sol_reply_list *list = solrep_list;	unsigned int passed = 0;	assert(next != NULL);	while (list != NULL && cmp_timeval(now, &list->send) == 1) {		DEBUG(DEBUG_FLAG, "Found delayed solicitation reply\n");		fa_send_agent_adv(list->iface, &list->to, &list->addr);		solrep_list = list->next;		free(list);		list = solrep_list;	}		/* if any pending replys */	if (list != NULL) {		passed = 1000000 * (list->send.tv_sec - now->tv_sec) +			list->send.tv_usec - now->tv_usec;		DEBUG(DEBUG_FLAG, "Pending agent sol reply. %u usecs\n",		      passed);		set_usecs(next, passed);	} else		next->tv_sec = -1;	return 0;}static intadd_agent_sol_reply(struct interface_entry *iface, struct sockaddr_ll *to,		    struct in_addr *addr){	struct sol_reply_list *new, *prev, *list = solrep_list;	unsigned int usec_random =		(int) (MAX_ADV_DELAY * rand() / (RAND_MAX + 1.0));		assert(iface != NULL);	new = (struct sol_reply_list *)		calloc(1, sizeof(struct sol_reply_list));	if (new == NULL) {		DEBUG(DEBUG_FLAG, "add_agent_sol_reply: Out of memory\n");		return -1;	}	gettimeofday(&new->send, NULL);	add_usecs(&new->send, usec_random);	new->iface = iface;	memcpy(&new->to, to, sizeof(*to));	new->addr.s_addr = addr->s_addr;	if (list == NULL) {		/* add first entry */		solrep_list = new;		new->next = NULL;		return 0;	}	/* Find proper place */	prev = NULL;	while (list != NULL) {		if(cmp_timeval(&list->send, &new->send) == 1)			break;		prev = list;		list = list->next;	}	/* Add to the list */	if (prev == NULL) {		/* add to the beginning */		new->next = solrep_list;		solrep_list = new;	} else {		prev->next = new;		new->next = list;	}		return 0;}static voidhandle_icmp(struct interface_entry *iface){	int r;	struct sockaddr_ll from;	struct in_addr to, fromaddr;	r = check_icmp_sol(iface->icmp_sock, &from, &to, &fromaddr);	if (r == 0 && iface->agentadv != INTERFACE_AGENTADV_NONE) {		/* Agent solicitation */		add_agent_sol_reply(iface, &from, &fromaddr);	}}static voidmain_loop(void){	fd_set set;	struct timeval tv;	int oldmask;	struct interface_entry *iface;	struct node *node;	struct timeval next_agentadv;	next_agentadv.tv_sec = 0;	next_agentadv.tv_usec = 0;	send_agent_advs(&next_agentadv);	/* Main loop	 * Wait for incoming ICMP and UDP packets, and API calls. */	for (;;) {		fa_register(FA_REGISTER);		FD_ZERO(&set);		for (node = list_get_first(&config->interfaces); node != NULL;		     node = list_get_next(node)) {			iface = (struct interface_entry *) node;			FD_SET(iface->udp_sock, &set);			FD_SET(iface->udp_packet, &set);			FD_SET(iface->icmp_sock, &set);		}#ifdef INCLUDE_IPAY		FD_SET(ipay_sock, &set);#endif		if (api_rw_sock > -1)			FD_SET(api_rw_sock, &set);		if (api_ro_sock > -1)			FD_SET(api_ro_sock, &set);		/* Wake up when the next scheduled task timer expires or there		 * is something in the sockets. */		set_expr_timer(&tv, next_agentadv);		DEBUG(DEBUG_FLAG2, "FA main: timer for select %ld.%ld\n",		      tv.tv_sec, tv.tv_usec);		if (select(FD_SETSIZE, &set, NULL, NULL,			   tv.tv_sec == -1 ? NULL : &tv) < 0) {			/* don't exit on e.g. SIGHUP */			if (errno != EINTR) {				LOG2(LOG_ERR, "select error: %s\n",				     strerror(errno));				clean_up(1);			}			continue;		}		/* we don't want to reread the configuration file		 * while we are handling requests; hold the signal		 * until we are ready */		oldmask = sigblock(sigmask(SIGHUP));		/* Check if any of the bindings have expired.		 * Due to the binding module implementation this must be done		 * just before using binding_add in order to get the binding		 * module to current time. */		check_bindings(bindings_hash, tunnels_hash, &bcounters);#ifdef INCLUDE_IPAY		if (FD_ISSET(ipay_sock, &set))			handle_ipay(ipay_sock);#endif		if (api_rw_sock > -1 && FD_ISSET(api_rw_sock, &set)) {			/* privileged API call */			handle_api(api_rw_sock, 1);		}		if (api_ro_sock > -1 && FD_ISSET(api_ro_sock, &set)) {			/* unprivileged API call */			handle_api(api_ro_sock, 0);		}		for (node = list_get_first(&config->interfaces); node != NULL;		     node = list_get_next(node)) {			iface = (struct interface_entry *) node;			if (FD_ISSET(iface->udp_packet, &set)) {				DEBUG(DEBUG_FLAG, "Got UDP message(%s, packet "				      "socket)\n", iface->dev);				handle_reg_msg_packet(iface);			}			if (FD_ISSET(iface->udp_sock, &set)) {				DEBUG(DEBUG_FLAG, "Got UDP message(%s)\n",				      iface->dev);				handle_reg_msg(iface);			}			if (FD_ISSET(iface->icmp_sock, &set)) {				handle_icmp(iface);			}		}		if (timerisset(&next_agentadv))			send_agent_advs(&next_agentadv);		tunnel_check_delayed(tunnels_hash, 0);		fa_hash_expire();		expire_denial_records(0);#ifdef INCLUDE_IPAY		ipay_send_statistics(ipay_sock);#endif		sigsetmask(oldmask);	}}static intfa_parse_command_line(int argc, char *argv[]){	int c, oindex = 0;	static struct option long_options[] = {		/* common arguments */		{"help", no_argument, NULL, 'h'},		{"version", no_argument, NULL, 'v'},		{"debug", no_argument, NULL, 0},		{"fg", no_argument, NULL, 0},		{"config", required_argument, NULL, 'c'},		/* FA specific arguments */		/* end of arguments */		{0, 0, 0, 0}	};	DEBUG(DEBUG_FLAG, "FA command line parsing\n");	while ((c = getopt_long(argc, argv, "+hv", long_options, &oindex)) !=	       EOF) {				switch (c) {		case 'h':			/* show FA specific parameters */			/* N/A */			exit(1);			break;					case '?':			printf("Command line parsing failed - aborting\n");			exit(1);		case 'v':		case 'c':		case 0:			break;					default:			printf("?? getopt returned character code 0%o ??\n",			       c);			exit(1);		}	}	return 0;}intmain(int argc, char *argv[]){	program_name = parse_long_options(argc, argv, "foreign agent",					  PACKAGE, VERSION, dynamics_usage);	fa_parse_command_line(argc, argv);        config = malloc(sizeof(struct fa_config));        if (config == NULL) {                fprintf(stderr, "Not enough memory for struct fa_config\n");                exit(1);        }        if (load_fa(config, program_name,		    opt_config == NULL ? FA_GLOBAL_CONF_FILE : opt_config) ==	    FALSE) {                fprintf(stderr, "Configuration file reading failed.\n");                exit(1);        }	check_kernel_support(CHECK_KERNEL_ADV_ROUTING | CHECK_KERNEL_IPIP |			     CHECK_KERNEL_NETLINK);#ifndef NO_SUID_CHECK_FOR_FA	if (getuid()) {		fprintf(stderr, "This program must be run by root.\n");		exit(1);	}#endif 	/* These routines don't return any values. If something is           wrong clean_up() is used */	init_sockets();	init_data();	init_config_data();	if (!opt_foreground && dynamics_fork_daemon() == -1)		clean_up(1);	dynamics_write_pid_file(FA_PID_FILE);	syslog(LOG_INFO, "%s foreign agent daemon version %s started\n",	       PACKAGE, VERSION);	main_loop();        return 0;}

⌨️ 快捷键说明

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