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

📄 tunnel.c

📁 mobile ip 在linux下的一种实现
💻 C
📖 第 1 页 / 共 2 页
字号:
/* $Id: tunnel.c,v 1.87 2001/09/26 18:25:24 jm Exp $ * Tunnel interface 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. */#ifndef _GNU_SOURCE#define _GNU_SOURCE#endif#include <stdio.h>#include <stdlib.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <string.h>#include <sys/time.h>#include <unistd.h>#include <syslog.h>#include <assert.h>#include "tunnel.h"#include "hashtable.h"#include "debug.h"#include "list.h"#include "dyn_ip.h"#include "util.h"/* defines */#ifndef TRUE#define TRUE 1#endif#ifndef FALSE#define FALSE 0#endif#define DEBUG_FLAG 'T'#define PURGE_TUNNEL_TIME 3 /* seconds */#define LOG2(lev, fmt, args...) { DEBUG(DEBUG_FLAG, fmt, ## args); \  syslog(lev, fmt, ## args); }static char tunnel_dev_start[IFNAMSIZ];/* Maximum numbers of concurrent tunnels * This can be increased if needed, but Linux kernel (at least 2.2.3) seems * to take quite a long time, when the number of interfaces goes beyond * 2048. */#define MAX_TUNNEL_COUNT 2048#define MAX_TUNNEL_INTS (MAX_TUNNEL_COUNT >> 5)static unsigned int tunnel_numbers[MAX_TUNNEL_INTS];#define MAX_TABLE_COUNT 256#define MAX_TABLE_INTS (MAX_TABLE_COUNT >> 5)static unsigned int table_numbers[MAX_TABLE_INTS];#define DYN_SET_BIT(bits, bit) \        (bits[(bit) / 32] |= (1 << ((bit) & 0x1f)))#define DYN_CLR_BIT(bits, bit) \        (bits[(bit) / 32] &= ~(1 << ((bit) & 0x1f)))#define DYN_BIT(bits, bit) \        (bits[(bit) / 32] & (1 << ((bit) & 0x1f)))static voiddebug_print_bitfield(char *name, unsigned int bits[], int ints){#if 0	int i;	DEBUG(DEBUG_FLAG, "%s[", name);	for (i = 0; i < ints; i++)		DEBUG(DEBUG_FLAG, "%08x", bits[i]);	DEBUG(DEBUG_FLAG, "]\n");#endif}#define DELAY_UNCONNECTION_USEC 200000struct delayed_connection_deletion {	struct delayed_connection_deletion *next;	struct timeval timeout; /* when the connection can be deleted */	struct in_addr mn_addr;	int reverse;	int delete_route;	int to_ha_table_id;	int to_mn_table_id;	char route_dev[IFNAMSIZ];	char reverse_dev[IFNAMSIZ];};/* priority queue (sorted by increasing timeout) of delayed connection * deletions */static struct delayed_connection_deletion *delayed = NULL;#define TUNNEL_HASH_SIZE 256static inthashfunc(void *key, const int hashsize){	__u8 hash;	__u32 data;	data = ((struct in_addr *) key)->s_addr;	hash = (__u8)((data & 0xff000000) >> 24) ^		(__u8)((data & 0x00ff0000) >> 16) ^		(__u8)((data & 0x0000ff00) >> 8) ^		(__u8)(data & 0x000000ff);	return ((int) hash);}/* * Comparison function for hash table * * Arguments: *  key        First data structure *  cmprd      Second data structure * * Return: *  0          Not equal *  1          Equal */static intcmpfunc(void *key, struct node *cmprd){	struct tunnel_key *data1;	struct tunnel *data2;	if (key == NULL) {		DEBUG(DEBUG_FLAG, "tunnel module, cmpfunc:\n"		      "value for argument 'key' was NULL !\n"		      "Illegal value, returning 0 ! \n");		return 0;	}	if (cmprd == NULL) {		DEBUG(DEBUG_FLAG, "tunnel module, cmpfunc:\n"		      "value for argument 'cmpd' was NULL !\n"		      "Illegal value, returning 0 ! \n");		return 0;	}	data1 = (struct tunnel_key *) key;	data2 = (struct tunnel *) cmprd;	/* Compare the tunnel destination addresses */        if (data1->dst_addr.s_addr == data2->dst_addr.s_addr &&	    data1->type == data2->type &&	    (data1->type == TUNNEL_IPIP ||	     (data1->key == data2->key)))		return 1;	return 0;}static voidprint_tunnel_data(struct tunnel *data){	DEBUG(DEBUG_FLAG, "\tdevice=%s, num=%i, dst=%s, ref=%i\n",	      data->device, data->number, inet_ntoa(data->dst_addr),	      data->ref);}/** * tunnel_init: * @start_dev: The prefix to be used with tunnel device names, e.g., TUNL * @table_start: The first routing table that can be used, e.g., 1 * @table_end: The last routing table that can be used, e.g., 253 * * Initialize hash table for tunnels. Every tunnel has one entry * in the hash table. * * Returns: A pointer to the empty hash table or NULL on error */HASH *tunnel_init(char *start_dev, int table_start, int table_end){	int i;	dynamics_strlcpy(tunnel_dev_start, start_dev, IFNAMSIZ);	tunnel_dev_start[IFNAMSIZ - 1] = '\0';	for (i = 0; i < MAX_TUNNEL_INTS; i++)		tunnel_numbers[i] = 0;	/* only allow tables between table_start and table_end (including	 * both ends), i.e. mark other tables used */	for (i = 0; i < MAX_TABLE_INTS; i++)		table_numbers[i] = 0;	for (i = 0; i < table_start; i++)		DYN_SET_BIT(table_numbers, i);	for (i = table_end + 1; i < 256; i++)		DYN_SET_BIT(table_numbers, i);	debug_print_bitfield("TABLE_NUMBERS", table_numbers, MAX_TABLE_INTS);	return (hashtable_init(TUNNEL_HASH_SIZE));}/* Destroy tunnel. Called from the iterator. This function removes the real * tunnel and frees the released resources. */static int tunnel_destroy(struct tunnel *data){	int ret;	DEBUG(DEBUG_FLAG, "tunnel_destroy - dst=%s, dev=%s\n",	      inet_ntoa(data->dst_addr), data->device);	if (data->direction == TUNNEL_UP && data->to_ha_table_id != -1) {		DEBUG(DEBUG_FLAG, "Removing to_ha_table %i\n",		      data->to_ha_table_id);		if (!DYN_BIT(table_numbers, data->to_ha_table_id))			LOG2(LOG_WARNING,			     "tunnel_destroy - to HA table already freed?\n");		DYN_CLR_BIT(table_numbers, data->to_ha_table_id);		debug_print_bitfield("TABLE_NUMBERS", table_numbers,				     MAX_TABLE_INTS);		/* remove the default route from the to_ha_table */		if (dyn_ip_route_del_table(data->device, data->to_ha_table_id,					   NULL) != 0) {			LOG2(LOG_WARNING, "tunnel_destroy: could not remove "			     "default route from to_ha_table\n");			return -1;		}	}	if (data->direction == TUNNEL_UP && data->to_mn_table_id != -1) {		DEBUG(DEBUG_FLAG, "Removing to_mn_table %i\n",		      data->to_mn_table_id);		if (dyn_ip_rule_del_table(NULL, NULL, data->to_mn_table_id,					  data->device) != 0) {			LOG2(LOG_ALERT, "tunnel_destroy: could not remove rule"			     " to MN routing table (table=%i, dev=%s)\n",			     data->to_mn_table_id, data->device);		}		if (dyn_ip_route_del_blackhole(data->to_mn_table_id) != 0) {			LOG2(LOG_ALERT, "tunnel_destroy: could not remove "			     "blackhole from MN routing table %i\n",			     data->to_mn_table_id);		}		if (!DYN_BIT(table_numbers, data->to_mn_table_id))			LOG2(LOG_WARNING,			     "tunnel_destroy - to MN table already freed?\n");		DYN_CLR_BIT(table_numbers, data->to_mn_table_id);		debug_print_bitfield("TABLE_NUMBERS", table_numbers,				     MAX_TABLE_INTS);	}	ret = 1;	/* remove the tunnel device */	DEBUG(DEBUG_FLAG, "\tdyn_ip_tunnel_del(%s)\n", data->device);	if (data->type != TUNNEL_NO_ENCAPS &&	    dyn_ip_tunnel_del(data->device) != 0) {		DEBUG(DEBUG_FLAG, "\tdyn_ip_tunnel_del(%s) failed!\n",		      data->device);		ret = -1;	}	if (ret != -1 && data->type != TUNNEL_NO_ENCAPS) {		if (!DYN_BIT(tunnel_numbers, data->number)) {			LOG2(LOG_WARNING, "tunnel_destroy: bit not set!?\n");		} else			DYN_CLR_BIT(tunnel_numbers, data->number);		debug_print_bitfield("TUNNEL_NUMBERS", tunnel_numbers,				     MAX_TUNNEL_INTS);	} else if (data->type != TUNNEL_NO_ENCAPS) {		LOG2(LOG_ALERT, "Tunnel #%i could not be released - keeping "		     "the number reserved\n", data->number);	}	hashtable_remove(&data->hashnode);	free(data);	return ret;}/* Iterator function for delayed tunnel deletion tunnel_check_delayed(). * tv = current time value or NULL for forced removal */static int check_tunnel(struct node *node, void *tv){	TUNNEL *data = (struct tunnel *) node;	struct timeval *now;		if (tv != NULL && (data->ref > 0 || data->do_not_remove))		return 1;	now = (struct timeval *) tv;	if (now == NULL || now->tv_sec < data->zero_ref_tstamp.tv_sec ||	    now->tv_sec - data->zero_ref_tstamp.tv_sec > PURGE_TUNNEL_TIME)		tunnel_destroy(data);	return 1;}/** * tunnel_destroy_hash: * @hash: The pointer to the tunnel hash table * * Remove the possibly forgotten tunnel entries and destroy the hashtable. * * Returns 0 on success or 1 on error */inttunnel_destroy_hash(HASH *hash){	DEBUG(DEBUG_FLAG, "Removing delayed tunnel deletions..\n");	tunnel_check_delayed(hash, 1);	if (hashtable_destroy(hash) == 0)		return 1;	else		return 0;}/** * tunnel_add: * @hash:        The pointer to the tunnel hashtable * @dst_addr:    The remote address of the tunnel * @local_addr:  The local address to be added to the tunnel. * @set_link_up: 1 = set the tunnel device up, *               0 = do not set the device up (caller takes care of it later) * @type:        The type of the tunnel to be created * @key:         The key of the tunnel to be created * @dev:         If dev != NULL, the device name of the created or modified *               tunnel will be copied to it. At least char[IFNAMSIZ]. * * Add or update an entry in the hash table. The entry is identified with the * source and destination addresses of the tunnel. The new tunnel is created * if it does not exist. This function does not change the routing tables. * * Returns: a pointer to the added/reused tunnel entry or NULL on failure */TUNNEL *tunnel_add(HASH *hash, struct in_addr dst_addr, char *dev,	   struct in_addr local_addr, int set_link_up, int type, int key){	TUNNEL *data, *new = NULL;	char device[IFNAMSIZ];	int number = 0, ok;	struct tunnel_key tkey;	DEBUG(DEBUG_FLAG, "tunnel_add %s, type=%i, key=%i\n",	      inet_ntoa(dst_addr), type, key);	tkey.dst_addr = dst_addr;	tkey.type = type;	tkey.key = key;	data = (struct tunnel *) hashtable_fetch(hash, hashfunc, &tkey,						 cmpfunc);	if (data != NULL) {		/* tunnel already exists */		data->ref++;		if (dev != NULL)			dynamics_strlcpy(dev, data->device, IFNAMSIZ);		DEBUG(DEBUG_FLAG, "\ttunnel already exists, %s (ref = %d)\n",		      inet_ntoa(dst_addr), data->ref);		return data;	}	if (type == TUNNEL_NO_ENCAPS) {		if (dyn_ip_get_ifname(key, device) < 0) {			LOG2(LOG_WARNING,			     "tunnel_add - could not get ifname\n");			return NULL;		}	} else {		/* create tunnel */		number = 0;		while (number < MAX_TUNNEL_COUNT && DYN_BIT(tunnel_numbers,							    number))			number++;		if (number >= MAX_TUNNEL_COUNT) {			DEBUG(DEBUG_FLAG, "\tnot enough space for another "			      "tunnel (%i/%i)\n", number, MAX_TUNNEL_COUNT);			return NULL;		}		snprintf(device, IFNAMSIZ, "%s%d", tunnel_dev_start, number);	}	if (type == TUNNEL_IPIP) {		DEBUG(DEBUG_FLAG, "\tdyn_ip_tunnel_add(%s,%s,",		      device, inet_ntoa(dst_addr));		DEBUG(DEBUG_FLAG, "%s)\n", inet_ntoa(local_addr));		if (dyn_ip_tunnel_add(device, dst_addr, local_addr) != 0) {			DEBUG(DEBUG_FLAG, "\tdyn_ip_tunnel_add failed!\n");			return NULL;		}	} else if (type == TUNNEL_GRE) {		DEBUG(DEBUG_FLAG, "\tdyn_ip_tunnel_add_gre(%s,%s,",		      device, inet_ntoa(dst_addr));		DEBUG(DEBUG_FLAG, "%s,%i)\n", inet_ntoa(local_addr), key);		if (dyn_ip_tunnel_add_gre(device, dst_addr, local_addr, key) !=		    0) {			DEBUG(DEBUG_FLAG, "\tdyn_ip_tunnel_add_gre failed!\n");			return NULL;		}	}	ok = TRUE;	/* Add local address to the tunnel */	if (type != TUNNEL_NO_ENCAPS && dyn_ip_addr_add(device, local_addr) !=	    0) {		DEBUG(DEBUG_FLAG, "\tdyn_ip_addr_add(%s, %s) failed!\n",		      device, inet_ntoa(local_addr));		ok = FALSE;	}	/* Tunnel device up */	if (type != TUNNEL_NO_ENCAPS && set_link_up && ok &&	    dyn_ip_link_set_dev_up(device) != 0) {		DEBUG(DEBUG_FLAG, "\tdyn_ip_link_set_dev_up(%s) failed!\n",		      device);		ok = FALSE;	}	if (ok) {		/* update the hashtable */		new = (struct tunnel *) calloc(1, sizeof(struct tunnel));		if (new == NULL) {			DEBUG(DEBUG_FLAG, "\tmemory allocation failure!\n");			ok = FALSE;		}	}	if (ok) {		list_init_node(&new->hashnode);		new->to_ha_table_id = -1;		new->to_mn_table_id = -1;		new->ref = 1;		new->dst_addr = dst_addr;		new->number = number;		dynamics_strlcpy(new->device, device, IFNAMSIZ);		new->type = type;		new->key = key;		new->direction = TUNNEL_NOT_CONNECTED;		new->do_not_remove = 0;		if (dev != NULL)			dynamics_strlcpy(dev, device, IFNAMSIZ);	}	if (ok &&	    hashtable_add(hash, hashfunc, &dst_addr, &new->hashnode) != TRUE) {		DEBUG(DEBUG_FLAG, "\thashtable_add failed\n");		ok = FALSE;	}	if (!ok) {		DEBUG(DEBUG_FLAG, "\tdyn_ip_tunnel_del(%s)\n", device);		if (dyn_ip_tunnel_del(device) != 0)			DEBUG(DEBUG_FLAG, "\tdyn_ip_tunnel_dev(%s) failed\n",			      device);		if (new != NULL)			free(new);		return NULL;	}	/* okay, tunnel adding succeeded, update the bitfields etc. */	if (type != TUNNEL_NO_ENCAPS) {		DYN_SET_BIT(tunnel_numbers, number);		debug_print_bitfield("TUNNEL_NUMBERS", tunnel_numbers,				     MAX_TUNNEL_INTS);	}	return new;}/** * tunnel_set_remove: * @tunl:	A tunnel entry * @remove:	0 = allow removal of unneeded tunnel, *		1 = deny removal of the tunnel even if reference count reaches *		    zero * * Set 'tunnel removing possible' flag for a tunnel entry. */void tunnel_set_remove(TUNNEL *tunl, int remove){	tunl->do_not_remove = remove;}/* Iterator function for tunnel_set_remove_all() */static int set_remove_iter(struct node *node, void *a){	TUNNEL *data = (struct tunnel *) node;	struct in_addr *addr = (struct in_addr *) a;	if (data->dst_addr.s_addr == addr->s_addr &&	    data->do_not_remove) {

⌨️ 快捷键说明

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