📄 mn_tunnel.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 + -