📄 mn_util.c
字号:
/* $Id: mn_util.c,v 1.89 2001/10/20 14:20:38 jm Exp $ * Mobile Node - help functions * * 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 <unistd.h>#include <errno.h>#include <getopt.h>#include <signal.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <string.h>#include <assert.h>#ifdef DYN_TARGET_WINDOWS#include <fcntl.h>#endif#include "debug.h"#include "dyn_ip.h"#include "proxyarp.h"#include "agentapi.h"#include "util.h"#ifdef WITH_WIRELESS#include "monitor.h"#endif#include "mn_handler.h"#include "mn.h"#include "mn_tunnel.h"#ifdef INCLUDE_IPAY#include "mn_ipay.h"#endif#include "device_info.h"extern struct mn_data mn;extern struct mn_config config;extern struct timeval timers[TIMER_COUNT];extern char* program_name;extern char *opt_config;extern int opt_foreground;extern int real_tunnel_up; /* from mn_tunnel */static int wireless_extensions;/** * check_ignore_iface: * @ifname: Interface name * * Check whether an interface is to be ignored * * Returns: 1 if it should be ignored, else 0 */static int check_ignore_iface(const char *ifname){ struct ignore_iflist_entry *i; struct node *node; if (strcmp(ifname, TUNNEL_DEVICE) == 0) return 1; if (strcmp(ifname, TUNNEL_DEVICE_B) == 0) return 1; for (node = list_get_first(&config.ignore_iflist); node != NULL; node = list_get_next(node)) { i = (struct ignore_iflist_entry *)node; if (strncmp(ifname, i->ifname, IFNAMSIZ) == 0) return 1; } return 0;}struct fa_spi_entry* get_fa_spi(int spi, struct in_addr addr){ struct fa_spi_entry *s; struct node *node; time_t now; time(&now); node = list_get_first(&config.fa_spi_list); while (node != NULL) { s = (struct fa_spi_entry *) node; node = list_get_next(node); /* Expire dynamic entries that are not infinite (lifetime=0) */ if (s->created != 0 && s->lifetime != 0 && now > s->created + s->lifetime) { DEBUG(DEBUG_INFO, "get_fa_spi: dynamic " "security association (SPI=%i, addr=%s) " "expired\n", s->spi, inet_ntoa(s->addr)); list_remove((struct node *) s); free(s); continue; } if ((spi != 0 && s->spi != spi) || s->addr.s_addr != addr.s_addr) continue; return s; } return NULL;}int add_fa_spi(struct fa_spi_entry *spi, int replace_any_spi){ struct fa_spi_entry *old; old = get_fa_spi(replace_any_spi ? 0 : spi->spi, spi->addr); if (old != NULL) { if (old->created == 0) { DEBUG(DEBUG_INFO, "add_fa_spi: trying to replace " "static security association - aborting " "operation\n"); return -1; } DEBUG(DEBUG_INFO, "add_fa_spi: overwriting previous dynamic " "security association\n"); remove_fa_spi(old); free(old); old = NULL; } DEBUG(DEBUG_INFO, "add_fa_spi: adding dynamic security association " "(SPI=%i, addr=%s)\n", spi->spi, inet_ntoa(spi->addr)); list_init_node(&spi->node); list_add_tail(&config.fa_spi_list, &spi->node); return 0;}void remove_fa_spi(struct fa_spi_entry *spi){ DEBUG(DEBUG_INFO, "remove_fa_spi: removing security association " "(SPI=%i, addr=%s)\n", spi->spi, inet_ntoa(spi->addr)); list_remove(&spi->node);}/** * send_gratuitous_arp: * @route_addr: * @gratuituous_addr: * * A gratuituous arp message for address @gratuitous_addr will be sent * on the interface where there is a route to @route_addr. */void send_gratuitous_arp(struct in_addr route_addr, struct in_addr gratuitous_addr){ char arp_if[IFNAMSIZ]; if (dyn_ip_route_get(route_addr, arp_if, IFNAMSIZ) != 0) { DEBUG(DEBUG_INFO, "Could not get ARP interface\n"); return; } proxyarp_gratuitous(gratuitous_addr, arp_if);}#ifdef MN_LOCUPD_PROFILERvoid write_profiler(const char *msg){ struct timeval tv; gettimeofday(&tv, NULL); fprintf(mn.profile, "%s %u.%06u (%li usec)\n", msg, (unsigned int) tv.tv_sec, (unsigned int) tv.tv_usec, (tv.tv_sec - mn.last_api.tv_sec) * 1000000 + tv.tv_usec - mn.last_api.tv_usec);}#endif/** * update_fa_decsps_routes: * @ifname: interface name * @ifindex: interface index @ifname * @fa_addr: foreign agent addres * @home_net_addr: home network addres * @home_net_addr_plen: home network prefix length, -1 if no * home network * * Set the default route to @ifname via @fa_addr and delete all * routes to @home_net_addr/@home_net_addr_plen. * * Returns: 0 if successful */int update_fa_decaps_routes(const char *ifname, int ifindex, struct in_addr fa_addr, struct in_addr home_net_addr, int home_net_addr_plen){ DEBUG(DEBUG_INFO, "FA decapsulation - setting default route to " "%s via %s\n", ifname, inet_ntoa(fa_addr)); mn.cur_route_info.known = 1; mn.cur_route_info.via.s_addr = fa_addr.s_addr; mn.cur_route_info.ifindex = ifindex; memcpy(mn.cur_route_info.ifname, ifname, IFNAMSIZ); mn.cur_route_info.ifindex_net = -1; if (dyn_ip_route_replace_default(ifname, &fa_addr, &config.mn_home_ip_addr) != 0) { LOG2(LOG_ERR, "Set default route (to %s via %s) failed\n", ifname, inet_ntoa(fa_addr)); return -1; } if (home_net_addr_plen > -1) { int count; DEBUG(DEBUG_INFO, "Deleting home net route (%s/%i)\n", inet_ntoa(home_net_addr), home_net_addr_plen); count = dyn_ip_route_delete_net_routes(&home_net_addr, home_net_addr_plen); if (count < 0) { LOG2(LOG_ERR, "Home net route (%s/%i) delete failed\n", inet_ntoa(home_net_addr), home_net_addr_plen);#ifdef DYN_TARGET_WINDOWS /* at least Win98 does not seem to like to remove * home net route.. */ DEBUG(DEBUG_INFO, "Trying to set net route via the FA " "to circumvent failed net route removal\n"); if (dyn_ip_route_set_net(ifname, &home_net_addr, home_net_addr_plen, NULL, 2) < 0) { DEBUG(DEBUG_INFO, "Could not increase home " "net route metric\n"); } if (dyn_ip_route_set_net(ifname, &home_net_addr, home_net_addr_plen, &fa_addr, 1) < 0) { DEBUG(DEBUG_INFO, "Could not set net route via" " FA\n"); } else mn.home_net_route_set_via_fa = 1;#endif /* DYN_TARGET_WINDOWS */ } else { DEBUG(DEBUG_INFO, " %i net route%s deleted\n", count, count != 1 ? "s" : ""); } } return 0;}/** * modify_new_interface: * @iface: new or removed interface * @idx: interface map */static void modify_new_interface(struct interface_data *iface, struct idxmap *idx){ struct event_INTERFACE data; int ret; DEBUG(DEBUG_INFO, "modify_new_interface (start): device_count %d\n", mn.device_count); if (config.enable_fa_decapsulation) { ret = dyn_ip_iface_address(idx->index, &config.mn_home_ip_addr); if ((ret == 2 || ret == 0) && config.use_aaa && config.mn_home_ip_addr.s_addr == 0 && config.enable_fa_decapsulation) { DEBUG(DEBUG_INFO, "modify_interface: interface with no" " addresses - using AAA to obtain a home " "address\n"); } else { if (ret == 0) { DEBUG(DEBUG_INFO, "FA decapsulation and an " "interface does not have the home " "address\n"); mn.warn_str = "FA decapsulation and an " "interface does not have the home " "address"; return; } /* continue only if the interface has a correct * address */ if (ret != 1) { DEBUG(DEBUG_INFO, "modify_interface: no " "addresses found (ret=%i)\n", ret); return; } } } if (iface->handlers_off == 1) { DEBUG(DEBUG_INFO, "modify_interface: interface up\n"); memset(&data, 0, sizeof(data)); data.iface = iface; data.ifname = iface->device; data.index = &iface->index; data.icmp_sock = &iface->s; data.icmp_sock_adv = &iface->s_adv; assert(idx != NULL); data.idx = idx; data.last_reg_send_time = &mn.last_reg_send_time; data.current_adv = &mn.current_adv; data.priority = &iface->priority; ret = handler_call_all(INTERFACE_INIT, &data); if (ret == -1) { DEBUG(DEBUG_INFO, "modify_interface: interface " "initialization failed\n"); return; } iface->handlers_off = 0; if (config.enable_fa_decapsulation && mn.current_adv != NULL && real_tunnel_up) { DEBUG(DEBUG_INFO, "modify_new_interface: fix possibly " "changed routing entries\n"); update_fa_decaps_routes(mn.current_adv->ifname, mn.current_adv->ifindex, mn.fa_addr, config.home_net_addr, config.home_net_addr_plen); } } mn.device_count++; DEBUG(DEBUG_INFO, "modify_new_interface (end): device_count %d\n", mn.device_count); /* go from passive find to find agent state if a new interface is up * and there was previously no interfaces available OR if the current * adv. was removed */ if ((mn.device_count == 1 && mn.state == MN_PASSIVE_FIND) || (mn.current_adv == NULL && mn.state != MN_DISCONNECTED)) { find_agent(STATE_INIT); }}/** * modify_removed_interface: * @iface: interface */static void modify_removed_interface(struct interface_data *iface){ struct event_INTERFACE data; int ret; DEBUG(DEBUG_INFO, "modify_remved_interface (start): device_count %d\n", mn.device_count); if (iface->handlers_off != 1) { DEBUG(DEBUG_INFO, "modify_removed_interface: interface down\n"); memset(&data, 0, sizeof(data)); data.ifname = iface->device; data.index = &iface->index; data.icmp_sock = &iface->s; data.icmp_sock_adv = &iface->s_adv; ret = handler_call_all(INTERFACE_DOWN, &data); if (ret == -1) { DEBUG(DEBUG_INFO, "modify_interface: interface " "down failed\n"); return; } iface->handlers_off = 1; } mn.device_count--; if (mn.device_count < 0) { DEBUG(DEBUG_INFO, "modify_interface: device " "count < 0!\n"); mn.device_count = 0; } DEBUG(DEBUG_INFO, "modify_remived_interface (end): device_count %d\n", mn.device_count); /* go from passive find to find agent state if the current * adv. was removed */ if (mn.current_adv == NULL && mn.state != MN_DISCONNECTED) { find_agent(STATE_INIT); }}/** * check_interfaces: * @iface: array of interfaces * @iface_num: number of interfaces in @iface * * Check whether new interfaces can be detected or if an interface * has been removed * * Returns: 0 if successfully executed, 1 on error */int check_interfaces(struct interface_data *iface, int iface_num){ int i; struct idxmap *idxmap, *idx; idxmap = dyn_ip_get_interface_map(); if (idxmap == NULL) { DEBUG(DEBUG_INFO, "check_interfaces: interface map could " "not be created\n"); return 1; } /* remove the ignored interfaces */ /* FIX: add list of interfaces to be ignored to dynmnd.conf and try to * eliminate 'virtual' interfaces like tunnels etc. */ idx = idxmap; while (idx != NULL) { if (check_ignore_iface(idx->name) || (dyn_ip_get_ifflags(idx->name) & IFF_UP) == 0) idx->index = -1; idx = idx->next; } /* check removed interfaces */ for (i = 0; i < iface_num; i++) { idx = idxmap; while (idx != NULL) { if (iface[i].index == idx->index) break; idx = idx->next; } if (iface[i].s > -1) { if (idx != NULL) { /* mark the interface used */ idx->index = -1; } else { DEBUG(DEBUG_INFO, "check_interfaces: " "removed interface\n"); /* this interface has been removed */ modify_removed_interface(&iface[i]); } } } /* check new interfaces */ idx = idxmap; while (idx != NULL) { if (idx->index == -1) { idx = idx->next; continue; } /* find a free slot */ i = 0; while (i < iface_num && iface[i].s > -1) i++; if (i >= iface_num) { DEBUG(DEBUG_INFO, "Not enough space for all " "the interfaces\n"); break; } /* call handlers for INTERFACE_INIT event */ DEBUG(DEBUG_INFO, "check_interfaces: new interface\n"); modify_new_interface(&iface[i], idx); idx = idx->next; } dyn_ip_free_interface_map(idxmap); return 0;}/** * create_registration_socket: * * Create registration socket and bind it to specified port. * * Returns: created socket or -1 on error. */int create_registration_socket(void){ int s; unsigned char ttl;#ifdef BIND_UDP_SOCKET struct sockaddr_in addr;#endif if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { LOG2(LOG_ERR, "create_reg_socket - socket: %s\n", strerror(errno)); return -1; }#ifdef BIND_UDP_SOCKET memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = config.bind_addr.s_addr; addr.sin_port = config.bind_port; DEBUG(DEBUG_INFO, "binding UDP socket to %s:%i\n", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { LOG2(LOG_ERR, "create_reg_socket - bind: %s\n", strerror(errno)); return -1; }#endif if (config.socket_priority > -1 && setsockopt(s, SOL_SOCKET, SO_PRIORITY, (char *)&config.socket_priority, sizeof(config.socket_priority)) < 0) { LOG2(LOG_ERR, "create_reg_socket - setsockopt SO_PRIORITY: %s\n", strerror(errno)); /* continue without SO_PRIORITY set */ } /* send registration request with TTL 255 [RFC 2344, Chap. 3.2] */ ttl = 255; if (setsockopt(s, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl)) < 0) { LOG2(LOG_ERR, "setsockopt: IP_TTL failed: %s\n", strerror(errno)); /* continue with the default setting anyway */#ifdef DYN_TARGET_WINDOWS if (dyn_ip_set_ttl(255) < 0) { DEBUG(DEBUG_INFO, "Also dyn_ip_set_ttl() failed\n"); }#endif /* DYN_TARGET_WINDOWS */ } return s;}static void show_usage(void){ printf(" --wireless_policy <integer>\n" "\t\tset wireless handoff policy (1=on, 0=off):\n" "\t\t bit 0: rely on MN's agent adv. expiration\n" "\t\t bit 1: use shorter agent adv. expiration interval\n" "\t\t bit 2: use FA with newest agent advertisement\n" "\t\t bit 3: eager switching\n" "\t\t bit 4: use newest agent advertisement\n" " --no-wireless\tdisable wireless extensions\n" " --disconnect\tstart in disconnected state\n");}int mn_parse_command_line(int argc, char *argv[]){ int c, oindex = 0; static struct option long_options[] = { {"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'}, /* MN specific arguments */ {"no-wireless", no_argument, NULL, 'n'}, {"wireless_policy", required_argument, NULL, 'p'}, {"disconnect", no_argument, NULL, 'd'}, /* end of arguments */ {0, 0, 0, 0} }; mn.opt_connect = 1; mn.policy_bits = 0; /* parse mn specific options */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -