📄 server6_addr.c
字号:
/* $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 + -