📄 ha.c
字号:
/* $Id: ha.c,v 1.204 2001/10/20 15:41:38 jm Exp $ * Home Agent daemon * * 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#define DEBUG_FLAG 'H'#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <string.h>#include <stdio.h>#include <arpa/inet.h>#include <sys/un.h>#include <net/if.h>#include <sys/time.h>#include <unistd.h>#include <syslog.h>#ifndef __USE_BSD#define __USE_BSD /* for sigblock et al. */#endif#include <signal.h>#include <time.h>#include <stdlib.h>#include <assert.h>#include <errno.h>#include <getopt.h>#include <sys/uio.h>#include "ha.h"#include "list.h"#include "hashtable.h"#include "fileio.h"#include "msgparser.h"#include "agentadv.h"#include "proxyarp.h"#include "binding.h"#include "auth.h"#include "tunnel.h"#include "debug.h"#include "agentapi.h"#include "util.h"#include "fixed_fd_zero.h"#include "dyn_ip.h"#include "ha_config.h"#include "agent_utils.h"#include "md5_mac.h"/* util.c - common command line arguments */extern int opt_foreground;extern char *opt_config;/******************** * defines ********************/#define ASSERT assert#define MIN(x, y) ( (x) < (y) ? (x) : (y))#define LOG2(lev, fmt, args...) { DEBUG(DEBUG_FLAG, fmt, ## args); \ syslog(lev, fmt, ## args); }#define MAX_ADV_DELAY 200000.0 /* wait random 0 - MAX_ADV_DELAY microseconds befora sending agent advertisement (either broadcast or unicast, answer to agent solicitation *//********************* * function prototypes *********************//* called before the home agent terminates to do some cleaning */static void clean_up();/* functions for handling requests, creating and destroying * tunnels (bindings) */static void remove_tunnel(struct bindingentry *binding);static void destroy_binding(struct bindingentry *binding);static struct fa_spi_entry* get_fa_spi(int spi, struct in_addr addr);static struct spi_entry* get_mn_spi(int spi);static void init_interfaces(void);/******************** * global variables ********************/static struct ha_config config;struct fa_nai_ext *ha_nai = NULL;static HASH *tunnels;static struct bindingtable *bindings;static int bindingcount = 0;static char *program_name; /* the name this program was run with */static struct dynamics_ha_status stats;/**********************************************************************//** * set_ha_nai: * * Setup global variable ha_nai according to config.ha_nai. set_ha_nai() * release the previously allocated buffer and allocates a new buffer for the * new HA NAI extension. */static voidset_ha_nai(void){ if (ha_nai != NULL) { free(ha_nai); ha_nai = NULL; } if (config.ha_nai[0] != '\0') { ha_nai = (struct fa_nai_ext *) malloc(sizeof(struct fa_nai_ext) + strlen(config.ha_nai)); if (ha_nai == NULL) { DEBUG(DEBUG_FLAG, "Not enough memory for ha_nai\n"); clean_up(1); } ha_nai->type = VENDOR_EXT_TYPE2; ha_nai->reserved = 0; ha_nai->length = sizeof(struct fa_nai_ext) - 2 + strlen(config.ha_nai); ha_nai->vendor_id = htonl(VENDOR_ID_DYNAMICS); ha_nai->sub_type = htons(VENDOR_EXT_DYNAMICS_FA_NAI); memcpy(ha_nai + 1, config.ha_nai, strlen(config.ha_nai)); }}/** * reload_config: * * SIGHUP handler for reloading the configuration. */static voidreload_config(int sig){ LOG2(LOG_INFO, "Received signal %d, rereading configuration\n", sig); cleanup_config(&config); if (load_config(&config, program_name, opt_config == NULL ? HA_GLOBAL_CONF_FILE : opt_config) == FALSE) { LOG2(LOG_ALERT, "Reloading configuration file failed\n"); clean_up(1); } init_interfaces(); set_ha_nai(); /* If the Port configuration is changed in the configuration * file, it will have no effect on a reload. If this functionality * is needed, the code should close the old sockets and reopen them * here. */}/********************************************************************** * clean up stuff **********************************************************************//** * binding_hash_iterator: * @node: bindingentry * @dummy: not used * * Hashtable iterator for clean_up() function; releases the resources reserved * for the bindings. * * Returns: * 1 (to continue iterator loop) */static intbinding_cleanup_iterator(struct node *node, void *dummy){ struct bindingentry *data = (struct bindingentry *) node; ASSERT(data != NULL); binding_remove(data); remove_tunnel(data); destroy_binding(data); return 1;}/** * sig_handler: * * Called on various signals to end the process. */static voidsig_handler(int sig){ LOG2(LOG_INFO, "signal %d received, cleaning up\n", sig); clean_up(sig); /* calls clean_up */} /** * clean_up: * * Clean up allocated resources and terminate HA daemon execution. */static voidclean_up(int value){ /* destroy all hashes and finish nicely */ if (bindings != NULL) { binding_iterator(bindings, binding_cleanup_iterator, NULL); binding_destroy(bindings); } if (tunnels != NULL) tunnel_destroy_hash(tunnels); /* remove old unix sockets */ if (config.ha_api_read_socket_path[0] != '\0') unlink(config.ha_api_read_socket_path); if (config.ha_api_admin_socket_path[0] != '\0') unlink(config.ha_api_admin_socket_path); if (unlink(HA_PID_FILE) < 0) { LOG2(LOG_INFO, "clean_up() could not remove PID file (" HA_PID_FILE "): %s\n", strerror(errno)); } cleanup_config(&config); if (ha_nai != NULL) { free(ha_nai); ha_nai = NULL; } syslog(LOG_INFO, "%s home agent daemon version %s stopped\n", PACKAGE, VERSION); closelog(); exit(value);}/********************************************************************** * API handling **********************************************************************//** * 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 = 0; memcpy((char *) api_msg->params + api_msg->length, &id, sizeof(dyn_tunnel_id)); api_msg->length += sizeof(dyn_tunnel_id); return 1;}/** * api_fetch_binding: * @msg: pointer to received API message * * Check that the dynamics_tunnel_id is in correct format and fetch the * requested binding. * * Returns: * Pointer to the requested binding or NULL on failure. */static struct bindingentry*api_fetch_binding(struct api_msg *msg){ dyn_tunnel_id *tid; struct bindingkey bkey; struct bindingentry *binding; if (msg->length != sizeof(dyn_tunnel_id)) { LOG2(LOG_ERR, "API message has wrong length (%i, expected %i)" "\n", msg->length, sizeof(dyn_tunnel_id)); return NULL; } tid = (dyn_tunnel_id *) msg->params; bkey.mn_addr = tid->mn_addr; if (config.sha_addr.s_addr != 0) bkey.ha_addr = config.sha_addr; else if (tid->ha_addr.s_addr != 0) bkey.ha_addr = tid->ha_addr; else { struct interface_entry *iface; iface = (struct interface_entry *) list_get_first(&config.interfaces); if (iface == NULL) return NULL; bkey.ha_addr = iface->addr; } bkey.priv_ha = config.priv_ha; binding = binding_fetch(bindings, &bkey); if (!binding) { DEBUG(DEBUG_FLAG, " API call could not find the request " "binding\n"); } return binding;}/** * handle_api: * @socket: the socket where the request arrived * @priv: whether the request is privileged to do administrative actions * * Receives an API request, executes the requested tasks, and sends the result. * * Returns: * 0 on success, -1 on failure */static inthandle_api(int socket, int priv){ struct sockaddr_un cli_addr; socklen_t cli_len; int n; struct api_msg recv_msg; struct api_msg send_msg; struct bindingentry *binding; struct dynamics_tunnel_info *info; struct dynamics_ha_status *status; memset(&cli_addr, 0, sizeof(cli_addr)); cli_len = sizeof(cli_addr); n = recvfrom(socket, &recv_msg, sizeof(struct api_msg), 0, (struct sockaddr*)&cli_addr, &cli_len); LOG2(LOG_DEBUG, "API: received %d bytes from %s\n", n, cli_addr.sun_path); if (n < 0) { LOG2(LOG_ERR, "handle_api - recvfrom failed - %s\n", strerror(errno)); return -1; } if (priv) stats.apicalls_admin++; else stats.apicalls_read++; memset(&send_msg, 0, sizeof(struct api_msg)); send_msg.type = API_REPLY_MSG; send_msg.code = API_UNDEFINED; send_msg.length = 0; switch (recv_msg.code) { case API_GET_TUNNELS: DEBUG(DEBUG_FLAG, "Received API_GET_TUNNELS\n"); if (recv_msg.length != 0) { LOG2(LOG_ERR, "API_GET_TUNNELS message has wrong length\n"); send_msg.code = API_ILLEGAL_PARAMETERS; break; } /* get the list of bindings into send_msg */ if (binding_iterator(bindings, 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"); binding = api_fetch_binding(&recv_msg); if (!binding) { send_msg.code = API_FAILED; break; } info = (struct dynamics_tunnel_info *) send_msg.params; memset(info, 0, sizeof(struct dynamics_tunnel_info)); info->id.mn_addr.s_addr = binding->mn_addr.s_addr; info->id.ha_addr.s_addr = binding->ha_addr.s_addr; info->mn_addr.s_addr = binding->mn_addr.s_addr; info->co_addr.s_addr = binding->lower_addr.s_addr; info->ha_addr.s_addr = binding->ha_addr.s_addr; info->expiration_time = binding->exp_time; info->creation_time = binding->create_time; info->refresh_time = binding->mod_time; info->last_timestamp[0] = ntohl(binding->id[0]); info->last_timestamp[1] = ntohl(binding->id[1]); info->spi = binding->spi; info->confirmed = 1; 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 (!priv) { send_msg.code = API_NOT_PERMITTED; break; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -