📄 sha.c
字号:
/* $Id: sha.c,v 1.6 2001/09/08 14:29:40 jm Exp $ * Surrogate Home Agent * * Dynamic hierarchial IP tunnel * Copyright (C) 2000-2001, Jouni Malinen * * 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 <stdio.h>#include <sys/types.h>#include <sys/stat.h>#include <sys/socket.h>#include <sys/un.h>#include <sys/time.h>#include <string.h>#include <arpa/inet.h>#include <errno.h>#include <unistd.h>#include <syslog.h>#include <signal.h>#include <time.h>#include <assert.h>#include <getopt.h>#include "sha.h"#include "sha_config.h"#include "sha_utils.h"#include "tunnel.h"#include "list.h"#include "hashtable.h"#include "debug.h"#include "fixed_fd_zero.h"#include "dyn_ip.h"#include "util.h"#include "agent_utils.h"/* sockets */int sha_sock = -1;struct hashtable *tunnels_hash;struct bindingtable *bindings_hash;struct sha_config *config;int bindingcount = 0; /* number of confirmed bindings */static char *program_name; /* the name this program was run with */static void init_sockets(void);static void init_config_data(void);/* util.c - common command line arguments */extern int opt_foreground;extern char *opt_config;static voidclose_sockets(void){ close(sha_sock); sha_sock = -1;}/* Free all reserved memory. Destroy hashes. * Unlink the unix domain socket filenames. */static voidclean_up(int sig){ /* destroy all hashes and finish nicely */ DEBUG(DEBUG_FLAG, "clean_up(%d)\n", sig); syslog(LOG_INFO, "Surrogate Home Agent daemon cleaning up (signal %d)", sig); close_sockets(); unlink(SHA_PID_FILE); /* Free hashtables */ if (bindings_hash != NULL) { DEBUG(DEBUG_FLAG, "Removing bindings..\n"); binding_iterator(bindings_hash, eliminate_binding_entry_force, &bindingcount); binding_destroy(bindings_hash); } if (tunnels_hash != NULL) { DEBUG(DEBUG_FLAG, "Removing tunnels..\n"); tunnel_destroy_hash(tunnels_hash); } cleanup_sha_config(config); if (config != NULL) free(config); closelog(); exit(sig);}static voidreload_config(int sig){ LOG2(LOG_INFO, "Reloading configuration\n"); /* remove possible entries from the solrep list; this needs to be done * because the iface pointers change during configuration reloading */ cleanup_sha_config(config); if (load_sha(config, program_name, opt_config == NULL ? SHA_GLOBAL_CONF_FILE : opt_config) == FALSE) { LOG2(LOG_ALERT, "Reloading configuration failed\n"); clean_up(-1); } close_sockets(); closelog(); init_sockets(); init_config_data();}/* search for spi/addr/priv_HA_ID match from the SHA SPI list * if spi=0, accept any spi * if addr=0.0.0.0, accept any addr * Returns: pointer to the SPI entry or NULL on failure */struct sha_spi_entry *get_sha_spi(int spi, struct in_addr addr, __u32 id){ struct sha_spi_entry *s; struct node *node; for (node = list_get_first(&config->sha_spi_list); node != NULL; node = list_get_next(node)) { s = (struct sha_spi_entry *) node; if ((spi == 0 || s->spi == spi) && (addr.s_addr == 0 || s->addr.s_addr == addr.s_addr) && id == s->priv_ha) { return s; } } return NULL;}/* Received registration message. Process it. returns: 0 if successful 1 on error*/static inthandle_reg_msg(){ char *msg; int res, n, cli_len; struct sockaddr_in cli_addr; struct msg_extensions ext; msg = malloc(MAXMSG); if (msg == NULL) { LOG2(LOG_WARNING, "Not enough memory for msg\n"); return 1; } memset(&cli_addr, 0, sizeof(cli_addr)); cli_len = sizeof(cli_addr); n = recvfrom(sha_sock, msg, MAXMSG, 0, (struct sockaddr *) &cli_addr, &cli_len); if (n < 0) { DEBUG(DEBUG_FLAG, "handle_reg_msg - recvfrom: (errno=%i) %s\n", errno, strerror(errno)); free(msg); return 1; } DEBUG(DEBUG_FLAG, "Received %d bytes from %s:%d\n", n, inet_ntoa(cli_addr.sin_addr), ntohs(cli_addr.sin_port)); res = parse_msg(msg, n, &ext); if (res != 0) { DEBUG(DEBUG_FLAG, "parse_msg returned %i\n", res); free(msg); return 0; } if (ext.req) { handle_request(msg, n, &ext, &cli_addr); } else if (ext.rep) { handle_reply(msg, n, &ext, &cli_addr); } else { DEBUG(DEBUG_FLAG, "Unknown registration message type\n"); } free(msg); return 0;}/* Open sockets and initialize them. */static voidinit_sockets(void){ struct sockaddr_in addr; sha_sock = socket(AF_INET, SOCK_DGRAM, 0); if (sha_sock < 0) { LOG2(LOG_ALERT, "init_sockets - socket: %s\n", strerror(errno)); clean_up(-1); } memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = INADDR_ANY; addr.sin_port = htons(config->udp_port); if (bind(sha_sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { LOG2(LOG_ALERT, "init_sockets - bind: %s\n", strerror(errno)); clean_up(-1); } if (config->socket_priority > -1 && setsockopt(sha_sock, SOL_SOCKET, SO_PRIORITY, (char *)&config->socket_priority, sizeof(config->socket_priority)) < 0) { LOG2(LOG_ERR, "inet_sockets - setsockopt SO_PRIORITY: %s\n", strerror(errno)); /* continue without SO_PRIORITY */ } DEBUG(DEBUG_FLAG, "Listening UDP on port %i\n", ntohs(addr.sin_port));}/* initializations that are run on all config reads */static voidinit_config_data(void){ /* Configure logging */ openlog("surrogate home agent", LOG_PID | LOG_CONS, config->syslog_facility);}/* initializations that are run only once (not on config reloads) */static voidinit_data(void){ allow_ipv4_forwarding(); /* Initialize hashes */ tunnels_hash = tunnel_init(config->tunnel_device, config->routing_table_start, config->routing_table_end); if (tunnels_hash == NULL) { LOG2(LOG_ALERT, "init_data: Tunnels hash not initialized!\n"); clean_up(1); } bindings_hash = binding_init(config->max_bindings, config->max_lifetime); if (bindings_hash == NULL) { LOG2(LOG_ALERT, "init_data: Could not initialize" " bindings_hash\n"); clean_up(1); } DEBUG(DEBUG_FLAG, "\tinit_data: Hashes initialized\n"); /* Set up signal actions */ signal(SIGHUP, reload_config); signal(SIGTERM, clean_up); /* clean death */ signal(SIGINT, clean_up); /* clean death */}/* Schedule next wake up time */static intset_expr_timer(struct timeval *tv){ int expire_time; struct timeval now; gettimeofday(&now, NULL); 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); tv->tv_sec = expire_time; tv->tv_usec = 0; } if (tv->tv_sec == -1 && tunnel_delayed_exists(tunnels_hash)) tv->tv_sec = TUNNEL_DELAYED_CHECK_INTERVAL; return 0;}static voidmain_loop(void){ fd_set set; struct timeval tv, now; int oldmask; for (;;) { FD_ZERO(&set); FD_SET(sha_sock, &set); /* Wake up when the next scheduled task timer expires or there * is something in the sockets. */ set_expr_timer(&tv); DEBUG(DEBUG_FLAG2, "SHA 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; } /* get timestamp */ gettimeofday(&now, NULL); /* 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, &bindingcount, (time_t)now.tv_sec); if (FD_ISSET(sha_sock, &set)) { DEBUG(DEBUG_FLAG, "Got UDP message\n"); handle_reg_msg(); } tunnel_check_delayed(tunnels_hash, 0); sigsetmask(oldmask); }}static intsha_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'}, /* SHA specific arguments */ /* end of arguments */ {0, 0, 0, 0} }; DEBUG(DEBUG_FLAG, "SHA command line parsing\n"); while ((c = getopt_long(argc, argv, "+hv", long_options, &oindex)) != EOF) { switch (c) { case 'h': /* show SHA 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); sha_parse_command_line(argc, argv); config = malloc(sizeof(struct sha_config)); if (config == NULL) { fprintf(stderr, "Not enough memory for struct sha_config\n"); exit(1); } if (load_sha(config, program_name, opt_config == NULL ? SHA_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_SHA 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(SHA_PID_FILE); syslog(LOG_INFO, "%s surrogate home agent daemon version %s started\n", PACKAGE, VERSION); main_loop(); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -