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

📄 mn_tunnel.c

📁 mobile ip 在linux下的一种实现
💻 C
字号:
/* $Id: mn_tunnel.c,v 1.7 2001/09/09 15:11:18 jm Exp $ * Mobile Node - tunnel 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 <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <time.h>#include "mn.h"#include "mn_tunnel.h"#include "debug.h"#include "util.h"extern struct mn_data mn;extern struct mn_config config;int real_tunnel_up;/* If there exists any tunnels at all. When the			     * first tunnel is created, this variable becomes			     * true. */static char tunnel_device[IFNAMSIZ]; /* tunneling device name */static struct in_addr old_tunnel_addr; /* tunnel endpoint of the old (lazy deleted)				   tunnel */static char old_tunnel_device[IFNAMSIZ];static time_t old_tunnel_expire; /* time after which old tunnel can be				  * deleted, 0 = no old tunnel */static int tunnel_b_up;      /* Used to select tunnel device name */static char* return_home_net_route(void){	int i;	char *dev = NULL, *adv_dev = NULL;	if (config.home_net_addr_plen < 0) {		DEBUG(DEBUG_MESSAGES, "return_home_net_route:"		      " config.home_net_addr_plen < 0\n");		return NULL;	}	/* get the current advertisement interface if it is still up */	if (mn.current_adv != NULL) {		for (i = 0; i < MAX_INTERFACES; i++) {			if (mn.iface[i].s > -1 &&			    strcmp(mn.current_adv->ifname, mn.iface[i].device)			    == 0) {				DEBUG(DEBUG_MESSAGES, "return_home_net_route:"				      " found current adv interface\n");				adv_dev = mn.current_adv->ifname;				break;			}		}	}	/* use the interface from which the possible HA agentadv was heard,	 * if the interface is up */	if (adv_dev != NULL &&	    ntohs(mn.current_adv->adv.ext->opts) & AGENT_ADV_HOME_AGENT &&	    config.ha_ip_addr.s_addr == mn.current_adv->addr.s_addr) {		DEBUG(DEBUG_MESSAGES, "return_home_net_route: "		      "found interface where the HA is\n");		dev = adv_dev;	}	/* check if the originally used device is still available */	if (dev == NULL && mn.start_default_device[0] != '\0') {		for (i = 0; i < MAX_INTERFACES; i++) {			if (mn.iface[i].s > -1 &&			    strcmp(mn.start_default_device, mn.iface[i].device)			    == 0) {				dev = mn.start_default_device;				break;			}		}	}	/* check the previously used device */	if (dev == NULL && adv_dev != NULL)		dev = adv_dev;	if (dev == NULL) {		/* take any device that is up */		for (i = 0; i < MAX_INTERFACES; i++) {			if (mn.iface[i].s > -1) {				dev = mn.iface[i].device;				break;			}		}	}	if (dev == NULL) {		DEBUG(DEBUG_INFO,		      "No active device found - home net route not added\n");		return NULL;	}	mn.cur_route_info.known = 1;	mn.cur_route_info.via.s_addr = config.home_net_gateway.s_addr;	memcpy(mn.cur_route_info.ifname, dev, IFNAMSIZ);	mn.cur_route_info.ifindex = dyn_ip_get_ifindex(dev);	memcpy(mn.cur_route_info.ifname, dev, IFNAMSIZ);	mn.cur_route_info.ifindex_net = mn.cur_route_info.ifindex;#ifdef DYN_TARGET_WINDOWS	if (mn.home_net_route_set_via_fa) {		int count;		DEBUG(DEBUG_INFO, "Trying to delete home net route via FA\n");		count = dyn_ip_route_delete_net_routes(			&config.home_net_addr,			config.home_net_addr_plen);		if (count < 0) {			DEBUG(DEBUG_INFO, "   failed to delete home net route "			      "via FA\n");		} else {			DEBUG(DEBUG_INFO, "   home net route delete count: "			      "%i\n", count);			mn.home_net_route_set_via_fa = 0;		}	}#endif /* DYN_TARGET_WINDOWS */	DEBUG(DEBUG_INFO, "Returning home net route %s/%i to %s\n",	      inet_ntoa(config.home_net_addr), config.home_net_addr_plen, dev);	if (dyn_ip_route_add_net(dev, &config.home_net_addr,				 config.home_net_addr_plen) != 0) {		LOG2(LOG_ERR,		     "Home net route (%s/%i => %s) add failed\n",		     inet_ntoa(config.home_net_addr),		     config.home_net_addr_plen, dev);	}	return dev;}void check_old_tunnel_expiration(void){#ifdef MN_ENABLE_TUNNELING	if (old_tunnel_expire == 0 ||	    time(NULL) <= old_tunnel_expire)		return;	old_tunnel_expire = 0;	if (dyn_ip_tunnel_del(old_tunnel_device) != 0) {		LOG2(LOG_ERR, "tunnel delete failed for old tunnel\n");		return;	}#endif}void init_tunneling(void){	DEBUG(DEBUG_INFO, "Init tunneling\n");	dynamics_strlcpy(tunnel_device, TUNNEL_DEVICE, sizeof(tunnel_device));	real_tunnel_up = 0;	tunnel_b_up = 0;}/* Free tunneling structures */void close_tunneling(void){	DEBUG(DEBUG_INFO, "Close tunneling\n");	/* clean up tunnel first */	if (real_tunnel_up) stop_tunneling();	/* disconnect any waiting api calls */	reply_waiting_api(API_FAILED, NULL, 0);}/** * make_tunnel: * @local_addr: MN's address * @ma_addr: address of mobility agent (FA/HA) to create the tunnel to * * Create a tunnel from @local_addr to @ma_addr.  * * Returns: 0 if successful */static intmake_tunnel(struct in_addr local_addr, struct in_addr ma_addr){	struct in_addr any;	if (old_tunnel_expire != 0) {		/* try to use the lazy deleted tunnel, if it is to the correct		 * FA */		old_tunnel_expire = 0;		if (old_tunnel_addr.s_addr == ma_addr.s_addr) {			DEBUG(DEBUG_INFO, "make_tunnel - reusing old (lazy "			      "deleted) tunnel\n");			return 0;		}		/* old tunnel was to a wrong FA - remove it and make new tunnel		 */		if (dyn_ip_tunnel_del(old_tunnel_device) != 0) {			LOG2(LOG_ERR, "tunnel delete failed for old tunnel\n");		}	}	any.s_addr = 0;	DEBUG(DEBUG_INFO, "Adding tunnel %s => %s\n", tunnel_device,	      inet_ntoa(ma_addr));	if (dyn_ip_tunnel_add(tunnel_device, ma_addr, any) != 0) {		LOG2(LOG_ERR, "tunnel add failed (%s => %s)\n",		       tunnel_device, inet_ntoa(ma_addr));		return -1;	}	if (dyn_ip_addr_add(tunnel_device, local_addr) != 0) {		DEBUG(DEBUG_INFO, "dyn_ip_addr_add(%s, %s) failed!\n",		      tunnel_device,		      inet_ntoa(local_addr));		if (dyn_ip_tunnel_del(tunnel_device) != 0) {			DEBUG(DEBUG_INFO, "tunnel delete failed\n");		}		return -1;	}	if (dyn_ip_link_set_dev_up(tunnel_device) != 0) {		DEBUG(DEBUG_INFO,		      "dyn_ip_link_set_dev_up(%s) failed!\n",		      tunnel_device);		if (dyn_ip_tunnel_del(tunnel_device) != 0) {			DEBUG(DEBUG_INFO, "tunnel delete failed\n");		}		return -1;	}	return 0;}/** * start_tunneling: * * Create tunnel and set default route to tunnel and set route for FA. * * Returns: 0 if successful. */int start_tunneling(void){	int failed = 0;	if (real_tunnel_up) {		DEBUG(DEBUG_INFO, "Start tunneling - tunnel is already up\n");	   	mn.tunnel_up = 1;                return 0;	}#ifdef MN_ENABLE_TUNNELING	DEBUG(DEBUG_INFO, "Start tunneling - FA addr %s\n",	      inet_ntoa(mn.fa_addr));	if (mn.tunnel_mode == API_TUNNEL_FULL_HA) {		/* set a host route to the HA so that the default route		 * replacing will not kill the route */		if (dyn_ip_route_to_host(config.ha_ip_addr) != 0) {			LOG2(LOG_ERR, "Could not set host route to the HA\n");		}	}	if (!config.enable_fa_decapsulation) {		if (make_tunnel(config.mn_home_ip_addr, mn.fa_addr) < 0)			return -1;		switch (config.mndecaps_route_handling) {		case MNDECAPS_ROUTE_DEFAULT:			/* set default route to the tunnel */			DEBUG(DEBUG_INFO, "Setting default route to %s\n",			      tunnel_device);			if (dyn_ip_route_replace_default(				tunnel_device, NULL,				&config.mn_home_ip_addr) != 0) {				LOG2(LOG_ERR,				     "Set default route to dev %s failed\n",				     tunnel_device);				failed = 1;			}			break;		case MNDECAPS_ROUTE_HOME_NET:			/* only set home net route to the tunnel			 * This entry will be automatically removed when the			 * tunnel is set down. */			DEBUG(DEBUG_INFO, "Setting home net route to %s\n",			      tunnel_device);			if (dyn_ip_route_replace_net(tunnel_device,						     &config.home_net_addr,						     config.home_net_addr_plen)			    != 0) {				LOG2(LOG_ERR,				     "Set home net route to dev %s failed\n",				     tunnel_device);				failed = 1;			}			break;		case MNDECAPS_ROUTE_NONE:			DEBUG(DEBUG_INFO, "No route set to %s\n",			      tunnel_device);			break;		}		if (failed) {			/* rollback */			if (dyn_ip_tunnel_del(tunnel_device) != 0) {				DEBUG(DEBUG_INFO, "tunnel delete failed\n");			}			return -1;		}	} else if (mn.current_adv != NULL) {		/* FA decapsulation and we have heard an advertisement:		 * set default route to FA, and remove all routes to		 * home network */		if (update_fa_decaps_routes(mn.current_adv->ifname,					    mn.current_adv->ifindex,					    mn.fa_addr,					    config.home_net_addr,					    config.home_net_addr_plen) < 0)			return -1;	} else		LOG2(LOG_WARNING, "start_tunneling() - current_adv == NULL\n");#else	DEBUG(DEBUG_INFO, "Start tunneling - tunneling disabled\n");#endif	mn.tunnel_addr.s_addr = mn.fa_addr.s_addr;	mn.tunnel_up = 1;	real_tunnel_up = 1;	return 0;}/* * Tunneling is up. * Create new (second) tunnel and set default route to this new tunnel. * Delete old tunnel. * Set route for FA. * Returns nonzero if successful. */int restart_tunneling(void){#ifdef MN_ENABLE_TUNNELING	struct in_addr old;	/* roll tunnel device names */	if (!tunnel_b_up) {		dynamics_strlcpy(tunnel_device, TUNNEL_DEVICE_B,				 sizeof(tunnel_device));		tunnel_b_up = 1;	} else {		dynamics_strlcpy(tunnel_device, TUNNEL_DEVICE,				 sizeof(tunnel_device));		tunnel_b_up = 0;	}	old.s_addr = mn.tunnel_addr.s_addr;	mn.tunnel_up = 0;	real_tunnel_up = 0;	start_tunneling();	if (tunnel_b_up)		dynamics_strlcpy(old_tunnel_device, TUNNEL_DEVICE,				 sizeof(old_tunnel_device));	else		dynamics_strlcpy(old_tunnel_device, TUNNEL_DEVICE_B,				 sizeof(old_tunnel_device));	if (!config.enable_fa_decapsulation) {		/* Mark the old tunnel to be deleted */		old_tunnel_addr.s_addr = old.s_addr;		old_tunnel_expire = time(NULL) + OLD_TUNNEL_EXTRA_TIME;	}#else	DEBUG(DEBUG_INFO, "Restart tunneling - tunneling disabled\n");#endif	return 0;}/** * stop_tunneling: * * Close tunnel, reset routing. * * Returns: 0 if successful. */int stop_tunneling(void){	int ret = 1;	char dev[IFNAMSIZ], *home_dev = NULL;#ifdef MN_ENABLE_TUNNELING	DEBUG(DEBUG_INFO, "Stop tunneling\n");	if (mn.current_adv == NULL)		LOG2(LOG_WARNING, "stop_tunneling - current_adv == NULL\n");	if (mn.tunnel_mode == API_TUNNEL_FULL_HA) {		/* remove the host route to the HA */		dev[0] = '\0';		if (dyn_ip_route_get(config.ha_ip_addr, dev, IFNAMSIZ) != 0 ||		    dyn_ip_route_del(config.ha_ip_addr, dev) != 0) {			LOG2(LOG_ERR, "Could not remove host route to the "			     "HA (dev=%s)\n", dev);		}	}	if (config.enable_fa_decapsulation)		home_dev = return_home_net_route();	/* restore default route */	DEBUG(DEBUG_INFO, "Restoring default route\n");	if (dyn_ip_route_restore_default(home_dev) != 0 &&	    device_up(dyn_ip_get_saved_ifindex())) {		LOG2(LOG_ERR, "restoring default route failed\n");		ret = 0;	}	if (config.enable_fa_decapsulation) {		if (mn.current_adv)			remove_fa_host_routes(1);	} else {		if (dyn_ip_tunnel_del(tunnel_device) != 0) {			LOG2(LOG_ERR, "tunnel delete failed\n");			ret = 0;		}		if (old_tunnel_expire != 0 &&		    dyn_ip_tunnel_del(old_tunnel_device) != 0) {			LOG2(LOG_ERR, "tunnel delete failed for old tunnel\n");		}		old_tunnel_expire = 0;	}#else	DEBUG(DEBUG_INFO, "Stop tunneling - tunneling disabled\n");#endif	mn.tunnel_up = 0;	real_tunnel_up = 0;	if (mn.current_adv != NULL) mn.current_adv->in_use = 0;	return ret;}

⌨️ 快捷键说明

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