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

📄 server6_addr.c

📁 DHCPv6协议在Linux操作系统下的一个客户端实现。
💻 C
📖 第 1 页 / 共 2 页
字号:
/*	$Id: server6_addr.c,v 1.21 2004/03/15 22:02:55 shemminger 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 <stdlib.h>#include <time.h>//#include <openssl/md5.h>#include <sys/types.h>#include <sys/time.h>#include <sys/socket.h>#include <sys/ioctl.h>#include <linux/ipv6.h>#include <net/if.h>#include <errno.h>#include <syslog.h>#include <string.h>#include <unistd.h>#include "queue.h"#include "dhcp6.h"#include "config.h"#include "common.h"#include "server6_conf.h"#include "lease.h"#include "timer.h"#include "hash.h"extern FILE *server6_lease_file;struct dhcp6_lease *dhcp6_find_lease __P((struct dhcp6_iaidaddr *, struct dhcp6_addr *));static int dhcp6_add_lease __P((struct dhcp6_iaidaddr *, struct dhcp6_addr *));static int dhcp6_update_lease __P((struct dhcp6_addr *, struct dhcp6_lease *));static int addr_on_segment __P((struct v6addrseg *, struct dhcp6_addr *));static void  server6_get_newaddr __P((iatype_t, struct dhcp6_addr *, struct v6addrseg *));static void  server6_get_addrpara __P((struct dhcp6_addr *, struct v6addrseg *));static void  server6_get_prefixpara __P((struct dhcp6_addr *, struct v6prefix *));struct link_decl *dhcp6_allocate_link __P((struct dhcp6_if *, struct rootgroup *, 			struct in6_addr *));struct host_decl *dhcp6_allocate_host __P((struct dhcp6_if *, struct rootgroup *, 			struct dhcp6_optinfo *));int dhcp6_get_hostconf __P((struct dhcp6_optinfo *, struct dhcp6_optinfo *,			struct dhcp6_iaidaddr *, struct host_decl *)); struct host_decl*find_hostdecl(duid, iaid, hostlist)	struct duid *duid;	u_int32_t iaid;	struct host_decl *hostlist;{	struct host_decl *host;	for (host = hostlist; host; host = host->next) {		if (!duidcmp(duid, &host->cid) && host->iaidinfo.iaid == iaid)			return host;		continue;	}			return NULL;}/* for request/solicit rapid commit */intdhcp6_add_iaidaddr(optinfo)	struct dhcp6_optinfo *optinfo;{	struct dhcp6_iaidaddr *iaidaddr;	struct dhcp6_listval *lv, *lv_next = NULL;	struct timeval timo;	double d;		iaidaddr = (struct dhcp6_iaidaddr *)malloc(sizeof(*iaidaddr));	if (iaidaddr == NULL) {		dprintf(LOG_ERR, "%s" "failed to allocate memory", FNAME);		return (-1);	}	memset(iaidaddr, 0, sizeof(*iaidaddr));	duidcpy(&iaidaddr->client6_info.clientid, &optinfo->clientID);	iaidaddr->client6_info.iaidinfo.iaid = optinfo->iaidinfo.iaid;	iaidaddr->client6_info.type = optinfo->type;	TAILQ_INIT(&iaidaddr->lease_list);	/* add new leases */	for (lv = TAILQ_FIRST(&optinfo->addr_list); lv; lv = lv_next) {		lv_next = TAILQ_NEXT(lv, link);		if ((hash_search(lease_hash_table, (void *)&lv->val_dhcp6addr)) != NULL) {			dprintf(LOG_INFO, "%s" "address for %s has been used",				FNAME, in6addr2str(&lv->val_dhcp6addr.addr, 0));			TAILQ_REMOVE(&optinfo->addr_list, lv, link);			continue;		}		if (dhcp6_add_lease(iaidaddr, &lv->val_dhcp6addr) != 0)			TAILQ_REMOVE(&optinfo->addr_list, lv, link); 	}	/* it's meaningless to have an iaid without any leases */		if (TAILQ_EMPTY(&iaidaddr->lease_list)) {		dprintf(LOG_INFO, "%s" "no leases are added for duid %s iaid %u", 			FNAME, duidstr(&iaidaddr->client6_info.clientid), 				iaidaddr->client6_info.iaidinfo.iaid);		return (0);	}	if (hash_add(server6_hash_table, &iaidaddr->client6_info, iaidaddr)) {		dprintf(LOG_ERR, "%s" "failed to hash_add an iaidaddr %u for client duid %s", 			FNAME, iaidaddr->client6_info.iaidinfo.iaid,				duidstr(&iaidaddr->client6_info.clientid));		dhcp6_remove_iaidaddr(iaidaddr);		return (-1);	}	dprintf(LOG_DEBUG, "%s" "hash_add an iaidaddr %u for client duid %s", 		FNAME, iaidaddr->client6_info.iaidinfo.iaid,			duidstr(&iaidaddr->client6_info.clientid));	/* set up timer for iaidaddr */	if ((iaidaddr->timer =	    dhcp6_add_timer(dhcp6_iaidaddr_timo, iaidaddr)) == NULL) {		dprintf(LOG_ERR, "%s" "failed to add a timer for iaid %u",			FNAME, iaidaddr->client6_info.iaidinfo.iaid);		dhcp6_remove_iaidaddr(iaidaddr);		return (-1);	}	time(&iaidaddr->start_date);	iaidaddr->state = ACTIVE;	d = get_max_validlifetime(iaidaddr);	timo.tv_sec = (long)d;	timo.tv_usec = 0;	dhcp6_set_timer(&timo, iaidaddr->timer);	return (0);}int dhcp6_remove_iaidaddr(iaidaddr)	struct dhcp6_iaidaddr *iaidaddr;{	struct dhcp6_lease *lv, *lv_next;	struct dhcp6_lease *lease;		/* remove all the leases in this iaid */	for (lv = TAILQ_FIRST(&iaidaddr->lease_list); lv; lv = lv_next) {		lv_next = TAILQ_NEXT(lv, link);		if ((lease = hash_search(lease_hash_table, (void *)&lv->lease_addr)) != NULL) {			if (dhcp6_remove_lease(lv)) {				dprintf(LOG_ERR, "%s" "failed to remove an iaid %u", FNAME,					 iaidaddr->client6_info.iaidinfo.iaid);				return (-1);			}		}	}	if (hash_delete(server6_hash_table, &iaidaddr->client6_info) != 0) {		dprintf(LOG_ERR, "%s" "failed to remove an iaid %u from hash",			FNAME, iaidaddr->client6_info.iaidinfo.iaid);		return (-1);	}	if (iaidaddr->timer)		dhcp6_remove_timer(iaidaddr->timer);	dprintf(LOG_DEBUG, "%s" "removed iaidaddr %u", FNAME,		iaidaddr->client6_info.iaidinfo.iaid);	free(iaidaddr);	return (0);}struct dhcp6_iaidaddr*dhcp6_find_iaidaddr(optinfo)	struct dhcp6_optinfo *optinfo;{	struct dhcp6_iaidaddr *iaidaddr;	struct client6_if client6_info;	duidcpy(&client6_info.clientid, &optinfo->clientID);	client6_info.iaidinfo.iaid = optinfo->iaidinfo.iaid;	client6_info.type = optinfo->type;	if ((iaidaddr = hash_search(server6_hash_table, (void *)&client6_info)) == NULL) {		dprintf(LOG_DEBUG, "%s" "iaid %u iaidaddr for client duid %s doesn't exists", 			FNAME, client6_info.iaidinfo.iaid, 			duidstr(&client6_info.clientid));	}	duidfree(&client6_info.clientid);	return iaidaddr;}intdhcp6_remove_lease(lease)	struct dhcp6_lease *lease;{	lease->state = INVALID;	if (write_lease(lease, server6_lease_file) != 0) {		dprintf(LOG_ERR, "%s" "failed to write an invalid lease %s to lease file", 			FNAME, in6addr2str(&lease->lease_addr.addr, 0));		return (-1);	}	if (hash_delete(lease_hash_table, &lease->lease_addr) != 0) {		dprintf(LOG_ERR, "%s" "failed to remove an address %s from hash", 			FNAME, in6addr2str(&lease->lease_addr.addr, 0));		return (-1);	}	if (lease->timer)		dhcp6_remove_timer(lease->timer);	TAILQ_REMOVE(&lease->iaidaddr->lease_list, lease, link);	dprintf(LOG_DEBUG, "%s" "removed lease %s", FNAME,		in6addr2str(&lease->lease_addr.addr, 0));	free(lease);	return 0;}		/* for renew/rebind/release/decline */intdhcp6_update_iaidaddr(optinfo, flag)	struct dhcp6_optinfo *optinfo;	int flag;{	struct dhcp6_iaidaddr *iaidaddr;	struct dhcp6_lease *lease, *lease_next = NULL;	struct dhcp6_listval *lv, *lv_next = NULL;	struct timeval timo;	double d;	if ((iaidaddr = dhcp6_find_iaidaddr(optinfo)) == NULL) {		return (-1);	}		if (flag == ADDR_UPDATE) {				/* add or update new lease */		for (lv = TAILQ_FIRST(&optinfo->addr_list); lv; lv = lv_next) {			lv_next = TAILQ_NEXT(lv, link);			dprintf(LOG_DEBUG, "%s" "address is %s " , FNAME, 					in6addr2str(&lv->val_dhcp6addr.addr,0));			if ((lease = dhcp6_find_lease(iaidaddr, &lv->val_dhcp6addr)) 					!= NULL) {				dhcp6_update_lease(&lv->val_dhcp6addr, lease);			} else {				dhcp6_add_lease(iaidaddr, &lv->val_dhcp6addr);			}		}		/* remove leases that not on the reply list */		for (lease = TAILQ_FIRST(&iaidaddr->lease_list); lease; lease = lease_next) {			lease_next = TAILQ_NEXT(lease, link);			if (!addr_on_addrlist(&optinfo->addr_list, &lease->lease_addr)) {				dprintf(LOG_DEBUG, "%s" "lease %s is not on the link", 						FNAME, in6addr2str(&lease->lease_addr.addr,0));				dhcp6_remove_lease(lease);			}		}		dprintf(LOG_DEBUG, "%s" "update iaidaddr for iaid %u", FNAME, 			iaidaddr->client6_info.iaidinfo.iaid);	} else {		/* remove leases */		for (lv = TAILQ_FIRST(&optinfo->addr_list); lv; lv = lv_next) {			lv_next = TAILQ_NEXT(lv, link);			lease = dhcp6_find_lease(iaidaddr, &lv->val_dhcp6addr);			if (lease) {				if (flag == ADDR_ABANDON) {					/* XXX: preallocate a abandoned duid 					 * for maintain abandoned list with					 * preferlifetime xxx, validlifetime xxx					 */				}				dhcp6_remove_lease(lease);			} else {				dprintf(LOG_INFO, "%s" "address is not on the iaid", FNAME);			}		}		}	/* it's meaningless to have an iaid without any leases */		if (TAILQ_EMPTY(&iaidaddr->lease_list)) {		dprintf(LOG_INFO, "%s" "no leases are added for duid %s iaid %u", 			FNAME, duidstr(&iaidaddr->client6_info.clientid), 				iaidaddr->client6_info.iaidinfo.iaid);		dhcp6_remove_iaidaddr(iaidaddr);		return (0);	}	/* update the start date and timer */	if (iaidaddr->timer == NULL) {		if ((iaidaddr->timer = 		     dhcp6_add_timer(dhcp6_iaidaddr_timo, iaidaddr)) == NULL) {	 		dprintf(LOG_ERR, "%s" "failed to add a timer for iaid %u",				FNAME, iaidaddr->client6_info.iaidinfo.iaid);	 		return (-1);	    	}	}	time(&iaidaddr->start_date);	iaidaddr->state = ACTIVE;	d = get_max_validlifetime(iaidaddr);	timo.tv_sec = (long)d;	timo.tv_usec = 0;	dhcp6_set_timer(&timo, iaidaddr->timer);	return (0);}intdhcp6_validate_bindings(optinfo, iaidaddr)	struct dhcp6_optinfo *optinfo;	struct dhcp6_iaidaddr *iaidaddr;{	struct dhcp6_listval *lv;	/* XXX: confirm needs to update bindings ?? */	for (lv = TAILQ_FIRST(&optinfo->addr_list); lv; lv = TAILQ_NEXT(lv, link)) {		if (dhcp6_find_lease(iaidaddr, &lv->val_dhcp6addr) == NULL) 			return (-1);	}	return 0;}intdhcp6_add_lease(iaidaddr, addr)	struct dhcp6_iaidaddr *iaidaddr;	struct dhcp6_addr *addr;{	struct dhcp6_lease *sp;	struct timeval timo;	double d;	if (addr->status_code != DH6OPT_STCODE_SUCCESS &&			addr->status_code != DH6OPT_STCODE_UNDEFINE) {		dprintf(LOG_ERR, "%s" "not successful status code for %s is %s", FNAME,			in6addr2str(&addr->addr, 0), dhcp6_stcodestr(addr->status_code));		return (0);	}	/* ignore meaningless address, this never happens */	if (addr->validlifetime == 0 || addr->preferlifetime == 0) {		dprintf(LOG_INFO, "%s" "zero address life time for %s",			FNAME, in6addr2str(&addr->addr, 0));		return (0);	}	if (((sp = hash_search(lease_hash_table, (void *)addr))) != NULL) {		dprintf(LOG_INFO, "%s" "duplicated address: %s",		    FNAME, in6addr2str(&addr->addr, 0));		return (-1);	}	if ((sp = (struct dhcp6_lease *)malloc(sizeof(*sp))) == NULL) {		dprintf(LOG_ERR, "%s" "failed to allocate memory"			" for an address", FNAME);		return (-1);	}	memset(sp, 0, sizeof(*sp));	memcpy(&sp->lease_addr, addr, sizeof(sp->lease_addr));	sp->iaidaddr = iaidaddr;		/* ToDo: preferlifetime EXPIRED; validlifetime DELETED; */	/* if a finite lease perferlifetime is specified, set up a timer. */	time(&sp->start_date);	dprintf(LOG_DEBUG, "%s" "start date is %ld", FNAME, sp->start_date);	sp->state = ACTIVE;	if (write_lease(sp, server6_lease_file) != 0) {		dprintf(LOG_ERR, "%s" "failed to write a new lease address %s to lease file", 			FNAME, in6addr2str(&sp->lease_addr.addr, 0));		free(sp->timer);		free(sp);		return (-1);	}	dprintf(LOG_DEBUG, "%s" "write lease %s/%d to lease file", FNAME,		in6addr2str(&sp->lease_addr.addr, 0), sp->lease_addr.plen);	if (hash_add(lease_hash_table, &sp->lease_addr, sp)) {		dprintf(LOG_ERR, "%s" "failed to add hash for an address", FNAME);			free(sp->timer);			free(sp);			return (-1);	}	TAILQ_INSERT_TAIL(&iaidaddr->lease_list, sp, link);	if (sp->lease_addr.validlifetime == DHCP6_DURATITION_INFINITE || 	    sp->lease_addr.preferlifetime == DHCP6_DURATITION_INFINITE) {		dprintf(LOG_INFO, "%s" "infinity address life time for %s",			FNAME, in6addr2str(&addr->addr, 0));		return (0);	}	if ((sp->timer = dhcp6_add_timer(dhcp6_lease_timo, sp)) == NULL) {		dprintf(LOG_ERR, "%s" "failed to create a new event "	    		"timer", FNAME);		free(sp);		return (-1); 	}	d = sp->lease_addr.preferlifetime; 	timo.tv_sec = (long)d;	timo.tv_usec = 0;	dhcp6_set_timer(&timo, sp->timer);	dprintf(LOG_DEBUG, "%s" "add lease for %s/%d iaid %u with preferlifetime %u"			" with validlifetime %u", FNAME,		in6addr2str(&sp->lease_addr.addr, 0), sp->lease_addr.plen, 		sp->iaidaddr->client6_info.iaidinfo.iaid,		sp->lease_addr.preferlifetime, sp->lease_addr.validlifetime);	return (0);}/* assume we've found the updated lease already */intdhcp6_update_lease(addr, sp)	struct dhcp6_addr *addr;	struct dhcp6_lease *sp;{	struct timeval timo;	double d;	if (addr->status_code != DH6OPT_STCODE_SUCCESS &&			addr->status_code != DH6OPT_STCODE_UNDEFINE) {		dprintf(LOG_ERR, "%s" "not successful status code for %s is %s", FNAME,			in6addr2str(&addr->addr, 0), dhcp6_stcodestr(addr->status_code));		dhcp6_remove_lease(sp);		return (0);	}	/* remove lease with perferlifetime or validlifetime 0 */	if (addr->validlifetime == 0 || addr->preferlifetime == 0) {		dprintf(LOG_INFO, "%s" "zero address life time for %s",			FNAME, in6addr2str(&addr->addr, 0));		dhcp6_remove_lease(sp);		return (0);	}	memcpy(&sp->lease_addr, addr, sizeof(sp->lease_addr));	time(&sp->start_date);	sp->state = ACTIVE;	if (write_lease(sp, server6_lease_file) != 0) {		dprintf(LOG_ERR, "%s" "failed to write an updated lease %s to lease file", 			FNAME, in6addr2str(&sp->lease_addr.addr, 0));		return (-1);	}	if (sp->lease_addr.validlifetime == DHCP6_DURATITION_INFINITE || 	    sp->lease_addr.preferlifetime == DHCP6_DURATITION_INFINITE) {		dprintf(LOG_INFO, "%s" "infinity address life time for %s",			FNAME, in6addr2str(&addr->addr, 0));		return (0);	}	if (sp->timer == NULL) {		if ((sp->timer = dhcp6_add_timer(dhcp6_lease_timo, sp)) == NULL) {			dprintf(LOG_ERR, "%s" "failed to create a new event "	    			"timer", FNAME);			return (-1); 		}	}	d = sp->lease_addr.preferlifetime; 	timo.tv_sec = (long)d;	timo.tv_usec = 0;	dhcp6_set_timer(&timo, sp->timer);	return (0);}struct dhcp6_lease *dhcp6_find_lease(iaidaddr, ifaddr)	struct dhcp6_iaidaddr *iaidaddr;	struct dhcp6_addr *ifaddr;{	struct dhcp6_lease *sp;	for (sp = TAILQ_FIRST(&iaidaddr->lease_list); sp;	     sp = TAILQ_NEXT(sp, link)) {		/* check for prefix length		 * sp->lease_addr.plen == ifaddr->plen &&		 */      		dprintf(LOG_DEBUG, "%s" "request address is %s/%d ", FNAME,			in6addr2str(&ifaddr->addr, 0), ifaddr->plen);		      		dprintf(LOG_DEBUG, "%s" "lease address is %s/%d ", FNAME,			in6addr2str(&sp->lease_addr.addr, 0), ifaddr->plen);			      	if (IN6_ARE_ADDR_EQUAL(&sp->lease_addr.addr, &ifaddr->addr)) {

⌨️ 快捷键说明

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