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

📄 lease.c

📁 DHCPv6协议在Linux操作系统下的一个客户端实现。
💻 C
字号:
/*	$Id: lease.c,v 1.13 2004/03/03 20:11:16 shirleyma Exp $	*//* * Copyright (C) International Business Machines  Corp., 2003 * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors *    may be used to endorse or promote products derived from this software *    without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. *//* Author: Shirley Ma, xma@us.ibm.com */#include <stdio.h>#include <string.h>#include <time.h>#include <syslog.h>#include <errno.h>#include <stdlib.h>#include <sys/types.h>#include <sys/stat.h>#include <unistd.h>#include <fcntl.h>#include <sys/socket.h>#include <arpa/inet.h>#include <netinet/in.h>#include <net/if.h>#include <linux/sockios.h>#include <ifaddrs.h>#include "queue.h"#include "dhcp6.h"#include "hash.h"#include "config.h"#include "common.h"#include "lease.h"extern struct dhcp6_iaidaddr client6_iaidaddr;extern FILE *server6_lease_file;extern char *server6_lease_temp;extern FILE *client6_lease_file;extern char *client6_lease_temp;u_int32_t do_hash __P((const void *, u_int8_t ));static int init_lease_hashes __P((void));int write_lease(const struct dhcp6_lease *lease_ptr,	    FILE *file){	struct tm brokendown_time;	char addr_str[64];		if ((inet_ntop(AF_INET6, &lease_ptr->lease_addr.addr, 		addr_str, sizeof(addr_str))) == 0) {		dprintf(LOG_DEBUG, "%s" "inet_ntop %s", FNAME, strerror(errno));		return (-1);	}	gmtime_r(&lease_ptr->start_date, &brokendown_time);	fprintf(file, "lease %s/%d { \n", addr_str, lease_ptr->lease_addr.plen);	fprintf(file, "\t DUID: %s;\n", 		duidstr(&lease_ptr->iaidaddr->client6_info.clientid));	if (dhcp6_mode == DHCP6_MODE_CLIENT) 		fprintf(file, "\t SDUID: %s;\n", 			duidstr(&lease_ptr->iaidaddr->client6_info.serverid));	fprintf(file, "\t IAID: %u ", lease_ptr->iaidaddr->client6_info.iaidinfo.iaid);	fprintf(file, "\t type: %d;\n", lease_ptr->iaidaddr->client6_info.type);	fprintf(file, "\t RenewTime: %u;\n", 		lease_ptr->iaidaddr->client6_info.iaidinfo.renewtime);	fprintf(file, "\t RebindTime: %u;\n",		lease_ptr->iaidaddr->client6_info.iaidinfo.rebindtime);	if (!IN6_IS_ADDR_UNSPECIFIED(&lease_ptr->linklocal)) {		if ((inet_ntop(AF_INET6, &lease_ptr->linklocal, addr_str, 			sizeof(struct in6_addr))) == 0) {			dprintf(LOG_DEBUG, "%s" "inet_ntop %s", FNAME, strerror(errno));			return (-1);		}		fprintf(file, "\t linklocal: %s;\n", addr_str);	}	fprintf(file, "\t state: %d;\n", lease_ptr->state);	if (lease_ptr->hostname != NULL)		fprintf(file, "\t hostname: %s;\n",lease_ptr->hostname);	fprintf(file, "\t (start_date: %d %d/%d/%d %d:%d:%d UTC);\n",		     brokendown_time.tm_wday,		     brokendown_time.tm_year + 1900,		     brokendown_time.tm_mon + 1,		     brokendown_time.tm_mday,		     brokendown_time.tm_hour,		     brokendown_time.tm_min,		     brokendown_time.tm_sec);	fprintf(file, "\t start date: %lu;\n", lease_ptr->start_date);	fprintf(file, "\t PreferredLifeTime: %u;\n",                             lease_ptr->lease_addr.preferlifetime);	fprintf(file, "\t ValidLifeTime: %u;\n",                             lease_ptr->lease_addr.validlifetime);	fprintf(file, "}\n");	if (fflush(file) == EOF) {		dprintf(LOG_INFO, "%s" "write lease fflush failed %s", 			FNAME, strerror(errno));		return -1;	}	if (fsync(fileno(file)) < 0) {		dprintf(LOG_INFO, "%s" "write lease fsync failed %s", 			FNAME, strerror(errno));		return -1;	}	return 0;}FILE *sync_leases (FILE *file, const char *original, char *template){	int i, fd;	struct hashlist_element *element;	fd = mkstemp(template);        if (fd < 0 || (sync_file = fdopen(fd, "w")) == NULL) {		dprintf(LOG_ERR, "%s" "could not open sync file", FNAME);                return (NULL);        }	if (dhcp6_mode == DHCP6_MODE_SERVER) {		for (i = 0; i < lease_hash_table->hash_size; i++) {			element = lease_hash_table->hash_list[i];			while (element) {				if (write_lease((struct dhcp6_lease *)element->data, 							sync_file) < 0) {					dprintf(LOG_ERR, "%s" "write lease failed", FNAME);					return (NULL);				}				element = element->next;			}		}	} else if (dhcp6_mode == DHCP6_MODE_CLIENT) {		struct dhcp6_lease *lv, *lv_next;		for (lv = TAILQ_FIRST(&client6_iaidaddr.lease_list); lv; lv = lv_next) {			lv_next = TAILQ_NEXT(lv, link);			if (write_lease(lv, sync_file) < 0)  				dprintf(LOG_ERR, "%s" "write lease failed", FNAME);		}	}	fclose(sync_file);	fclose(file);	if (rename(template, original) < 0) { 		dprintf(LOG_ERR, "%s" "Could not rename sync file", FNAME);		return (NULL);	}        if ((file = fopen(original, "a+")) == NULL) {                dprintf(LOG_ERR, "%s" "could not open sync file", FNAME);		return (NULL);	}	return file; }struct dhcp6_timer *syncfile_timo(void *arg){	/*XXX: ToDo*/	return NULL;}FILE *init_leases(const char *name){	FILE *file;	file = fopen(name, "a+");	if(!file) {		dprintf(LOG_ERR, "%s" "could not open lease file", FNAME);		return (NULL);	}	if (dhcp6_mode == DHCP6_MODE_SERVER) {		if (0 != init_lease_hashes()) {			dprintf(LOG_ERR, "%s" "Could not initialize hash arrays", FNAME);			return (NULL);		}	}	lease_parse(file);	return file;} int init_lease_hashes(void) {	hash_anchors = (struct hash_table **)malloc(HASH_TABLE_COUNT*sizeof(*hash_anchors));	if (!hash_anchors) {		dprintf(LOG_ERR, "%s" "Couldn't malloc hash anchors", FNAME);		return (-1);	}        host_addr_hash_table = hash_table_create(DEFAULT_HASH_SIZE, 			addr_hash, v6addr_findkey, v6addr_key_compare);	if (!host_addr_hash_table) {		dprintf(LOG_ERR, "%s" "Couldn't create hash table", FNAME);		return (-1);	}        lease_hash_table = hash_table_create(DEFAULT_HASH_SIZE, 			addr_hash, lease_findkey, lease_key_compare);	if (!lease_hash_table) {		dprintf(LOG_ERR, "%s" "Couldn't create hash table", FNAME);		return (-1);	}        server6_hash_table = hash_table_create(DEFAULT_HASH_SIZE, 			iaid_hash, iaid_findkey, iaid_key_compare);	if (!server6_hash_table) {		dprintf(LOG_ERR, "%s" "Couldn't create hash table", FNAME);		return (-1);	}	return 0;}u_int32_t do_hash(const void *key, u_int8_t len){	int i;	u_int32_t *p;	u_int32_t index = 0;	u_int32_t tempkey;	for (i = 0, p = (u_int32_t *)key; i < len/sizeof(tempkey); i++, p++ ) {		memcpy(&tempkey, p, sizeof(tempkey));		index ^= tempkey;	}	memcpy(&tempkey, p, len%(sizeof(tempkey)));	index ^= tempkey;	return index;}unsigned intiaid_hash(const void *key){	const struct client6_if *iaidkey = (const struct client6_if *)key;	const struct duid *duid = &iaidkey->clientid;	unsigned int index;	index = do_hash((const void *) duid->duid_id, duid->duid_len);	return index;}unsigned intaddr_hash(const void *key){	const struct in6_addr *addrkey 		= (const struct in6_addr *)&(((const struct dhcp6_addr *)key)->addr);	unsigned int index;	index = do_hash((const void *)addrkey, sizeof(*addrkey));	return index;}void * v6addr_findkey(const void *data){        const struct dhcp6_addr *v6addr = (const struct dhcp6_addr *)data;	return (void *)(&(v6addr->addr));}int v6addr_key_compare(const void *data, const void *key){ 	struct dhcp6_addr *v6addr = (struct dhcp6_addr *)data;		if (IN6_ARE_ADDR_EQUAL(&v6addr->addr, (struct in6_addr *)key)) {		return MATCH;	} else		return MISCOMPARE;}void * lease_findkey(const void *data){        const struct dhcp6_lease *lease = (const struct dhcp6_lease *)data;	return (void *)(&(lease->lease_addr));}int lease_key_compare(const void *data, const void *key){ 	struct dhcp6_lease *lease = (struct dhcp6_lease *)data;		struct dhcp6_addr *lease_address = &lease->lease_addr;	struct dhcp6_addr *addr6 = (struct dhcp6_addr *)key;	if (IN6_ARE_ADDR_EQUAL(&lease_address->addr, &addr6->addr)) {		/* prefix match */		if (addr6->type == IAPD) {			/* XXX: allow duplicated PD for the same DUID */		 	if (lease_address->plen == addr6->plen)	       			return MATCH;		/* ipv6 address match */		} else if (addr6->type == IANA || addr6->type == IATA)			return MATCH;	}	return MISCOMPARE;}void *iaid_findkey(const void *data){        struct dhcp6_iaidaddr *iaidaddr = (struct dhcp6_iaidaddr *)data;	return (void *)(&(iaidaddr->client6_info));}int iaid_key_compare(const void *data,		 const void *key){ 	        const struct dhcp6_iaidaddr *iaidaddr = (const struct dhcp6_iaidaddr *)data;	const struct client6_if *client_key = (const struct client6_if *)key;	if (0 == duidcmp(&client_key->clientid, &iaidaddr->client6_info.clientid)){		if ((client_key->type == iaidaddr->client6_info.type) &&		    (client_key->iaidinfo.iaid == iaidaddr->client6_info.iaidinfo.iaid)) {			return MATCH;		}	}	return MISCOMPARE;}intprefixcmp(addr, prefix, len)	struct in6_addr *addr;	struct in6_addr *prefix;	int len;{	int i, num_bytes;	struct in6_addr mask;	num_bytes = len / 8;	for (i = 0; i < num_bytes; i++) {		mask.s6_addr[i] = 0xFF;	}	mask.s6_addr[num_bytes] = 0xFF << (8 - len % 8);	for (i = 0; i < num_bytes; i++) {		if (addr->s6_addr[i] != prefix->s6_addr[i]) return -1;	}	if((addr->s6_addr[num_bytes] & mask.s6_addr[num_bytes]) != 	   (prefix->s6_addr[num_bytes] & mask.s6_addr[num_bytes])) 		return -1;	return 0;}intget_linklocal(const char *ifname,	      struct in6_addr *linklocal){		struct ifaddrs *ifa, *ifap;	struct sockaddr *sd;	if (getifaddrs(&ifap) < 0) {		dprintf(LOG_ERR, "getifaddrs error");		return -1;	}	/* ifa->ifa_addr is sockaddr_in6 */	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {		if (strcmp(ifa->ifa_name, ifname)) continue;		sd = (struct sockaddr *)ifa->ifa_addr;		if (!sd || sd->sa_family != AF_INET6) continue;		if (!IN6_IS_ADDR_LINKLOCAL(&sd->sa_data[6])) continue;		/* which linklocal do we want, if find many 		 * from scope id??? sa_data[32]		 * */		memcpy(linklocal, &sd->sa_data[6], sizeof(*linklocal));		break;	}	freeifaddrs(ifap);	return 0;}intdhcp6_get_prefixlen(addr, ifp)	struct in6_addr *addr;	struct dhcp6_if *ifp;{	struct ra_info *rainfo;	for (rainfo = ifp->ralist; rainfo; rainfo = rainfo->next) {		/* prefixes are sorted by plen */		if (prefixcmp(addr, &rainfo->prefix, rainfo->plen) == 0)				return rainfo->plen;	}	return PREFIX_LEN_NOTINRA;}int addr_on_addrlist(addrlist, addr6)	struct dhcp6_list *addrlist;	struct dhcp6_addr *addr6;{	struct dhcp6_listval *lv;	for (lv = TAILQ_FIRST(addrlist); lv;	     lv = TAILQ_NEXT(lv, link)) {		if (IN6_ARE_ADDR_EQUAL(&lv->val_dhcp6addr.addr, &addr6->addr)) {			if ((lv->val_dhcp6addr.type != IAPD) 			    || ((lv->val_dhcp6addr.type == IAPD) 			    && (lv->val_dhcp6addr.plen == addr6->plen)))				return (1);		}	}	return (0);}u_int32_tget_min_preferlifetime(struct dhcp6_iaidaddr *sp){	struct dhcp6_lease *lv, *first;	u_int32_t min;	if (TAILQ_EMPTY(&sp->lease_list))		return 0;	first = TAILQ_FIRST(&sp->lease_list);	min = first->lease_addr.preferlifetime;	for (lv = TAILQ_FIRST(&sp->lease_list); lv; lv = TAILQ_NEXT(lv, link)) {		min = MIN(min, lv->lease_addr.preferlifetime);	}	return min;}u_int32_tget_max_validlifetime(struct dhcp6_iaidaddr *sp){	struct dhcp6_lease *lv, *first;	u_int32_t max;	if (TAILQ_EMPTY(&sp->lease_list))		return 0;	first = TAILQ_FIRST(&sp->lease_list);	max = first->lease_addr.validlifetime;	for (lv = TAILQ_FIRST(&sp->lease_list); lv; lv = TAILQ_NEXT(lv, link)) {		max = MAX(max, lv->lease_addr.validlifetime);	}	return max;}

⌨️ 快捷键说明

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