common.c

来自「IPv6环境下的DHCP实现」· C语言 代码 · 共 1,486 行 · 第 1/3 页

C
1,486
字号
/*	$KAME: common.c,v 1.63 2002/06/21 10:23:32 jinmei Exp $	*//* * Copyright (C) 1998 and 1999 WIDE Project. * 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. */#include <sys/types.h>#include <sys/socket.h>#include <sys/sockio.h>#include <sys/ioctl.h>#include <sys/queue.h>#if TIME_WITH_SYS_TIME# include <sys/time.h># include <time.h>#else# if HAVE_SYS_TIME_H#  include <sys/time.h># else#  include <time.h># endif#endif#include <net/if.h>#include <net/if_types.h>#if defined(__FreeBSD__) && __FreeBSD__ >= 3#include <net/if_var.h>#endif#include <net/if_dl.h>#include <net/if_arp.h>#include <netinet/in.h>#include <netinet6/in6_var.h>#include <errno.h>#include <limits.h>#include <stdio.h>#include <stdarg.h>#include <syslog.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include <err.h>#include <netdb.h>#ifdef HAVE_GETIFADDRS # ifdef HAVE_IFADDRS_H#  define USE_GETIFADDRS#  include <ifaddrs.h># endif#endif#include <dhcp6.h>#include <config.h>#include <common.h>#include <timer.h>int foreground;int debug_thresh;#if 0static unsigned int if_maxindex __P((void));#endifstatic int in6_matchflags __P((struct sockaddr *, char *, int));static ssize_t gethwid __P((char *, int, const char *, u_int16_t *));static int get_delegated_prefixes __P((char *, char *,				       struct dhcp6_optinfo *));intdhcp6_copy_list(dst, src)	struct dhcp6_list *dst, *src;{	struct dhcp6_listval *ent, *dent;	for (ent = TAILQ_FIRST(src); ent; ent = TAILQ_NEXT(ent, link)) {		if ((dent = malloc(sizeof(*dent))) == NULL)			goto fail;		memset(dent, 0, sizeof(*dent));		memcpy(&dent->uv, &ent->uv, sizeof(ent->uv));		TAILQ_INSERT_TAIL(dst, dent, link);	}	return 0;  fail:	dhcp6_clear_list(dst);	return -1;}voiddhcp6_clear_list(head)	struct dhcp6_list *head;{	struct dhcp6_listval *v;	while (v = TAILQ_FIRST(head)) {		TAILQ_REMOVE(head, v, link);		free(v);	}	return;}intdhcp6_count_list(head)	struct dhcp6_list *head;{	struct dhcp6_listval *v;	int i;	for (i = 0, v = TAILQ_FIRST(head); v; v = TAILQ_NEXT(v, link))		i++;	return i;}struct dhcp6_listval *dhcp6_find_listval(head, val, type)	struct dhcp6_list *head;	void *val;	dhcp6_listval_type_t type;{	struct dhcp6_listval *lv;	for (lv = TAILQ_FIRST(head); lv; lv = TAILQ_NEXT(lv, link)) {		switch(type) {		case DHCP6_LISTVAL_NUM:			if (lv->val_num == *(int *)val)				return(lv);			break;		case DHCP6_LISTVAL_ADDR6:			if (IN6_ARE_ADDR_EQUAL(&lv->val_addr6,			    (struct in6_addr *)val)) {				return(lv);			}			break;		case DHCP6_LISTVAL_PREFIX6:			if (IN6_ARE_ADDR_EQUAL(&lv->val_prefix6.addr,			    &((struct dhcp6_prefix *)val)->addr) &&			    lv->val_prefix6.plen ==			    ((struct dhcp6_prefix *)val)->plen) {				return(lv);			}			break;		}	}	return(NULL);}struct dhcp6_listval *dhcp6_add_listval(head, val, type)	struct dhcp6_list *head;	void *val;	dhcp6_listval_type_t type;{	struct dhcp6_listval *lv;	if ((lv = malloc(sizeof(*lv))) == NULL) {		dprintf(LOG_ERR, "%s" "failed to allocate memory for list "		    "entry", FNAME);		return(NULL);	}	memset(lv, 0, sizeof(*lv));	switch(type) {	case DHCP6_LISTVAL_NUM:		lv->val_num = *(int *)val;		break;	case DHCP6_LISTVAL_ADDR6:		lv->val_addr6 = *(struct in6_addr *)val;		break;	case DHCP6_LISTVAL_PREFIX6:		lv->val_prefix6 = *(struct dhcp6_prefix *)val;		break;	default:		dprintf(LOG_ERR, "%s" "unexpected list value type (%d)",		    FNAME, type);		exit(1);	}	TAILQ_INSERT_TAIL(head, lv, link);	return(lv);}struct dhcp6_event *dhcp6_create_event(ifp, state)	struct dhcp6_if *ifp;	int state;{	struct dhcp6_event *ev;	if ((ev = malloc(sizeof(*ev))) == NULL) {		dprintf(LOG_ERR, "%s" "failed to allocate memory for an event",			FNAME);		return(NULL);	}	ev->ifp = ifp;	ev->state = state;	TAILQ_INIT(&ev->data_list);	return(ev);}voiddhcp6_remove_event(ev)	struct dhcp6_event *ev;{	dprintf(LOG_DEBUG, "%s" "removing an event on %s, state=%d", FNAME,		ev->ifp->ifname, ev->state);	if (!TAILQ_EMPTY(&ev->data_list)) {		dprintf(LOG_ERR, "%s" "assumption failure: "			"event data list is not empty", FNAME);		exit(1);	}	duidfree(&ev->serverid);	if (ev->timer)		dhcp6_remove_timer(&ev->timer);	TAILQ_REMOVE(&ev->ifp->event_list, ev, link);	free(ev);}#if 0static unsigned intif_maxindex(){	struct if_nameindex *p, *p0;	unsigned int max = 0;	p0 = if_nameindex();	for (p = p0; p && p->if_index && p->if_name; p++) {		if (max < p->if_index)			max = p->if_index;	}	if_freenameindex(p0);	return max;}#endifintgetifaddr(addr, ifnam, prefix, plen, strong, ignoreflags)	struct in6_addr *addr;	char *ifnam;	struct in6_addr *prefix;	int plen;	int strong;		/* if strong host model is required or not */	int ignoreflags;{	struct ifaddrs *ifap, *ifa;	struct sockaddr_in6 sin6;	int error = -1;	if (getifaddrs(&ifap) != 0) {		err(1, "getifaddr: getifaddrs");		/*NOTREACHED*/	}	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {		int s1, s2;		if (strong && strcmp(ifnam, ifa->ifa_name) != 0)			continue;		/* in any case, ignore interfaces in different scope zones. */		if ((s1 = in6_addrscopebyif(prefix, ifnam)) < 0 ||		    (s2 = in6_addrscopebyif(prefix, ifa->ifa_name)) < 0 ||		     s1 != s2)			continue;		if (ifa->ifa_addr->sa_family != AF_INET6)			continue;		if (ifa->ifa_addr->sa_len > sizeof(sin6))			continue;		if (in6_matchflags(ifa->ifa_addr, ifa->ifa_name, ignoreflags))			continue;		memcpy(&sin6, ifa->ifa_addr, ifa->ifa_addr->sa_len);#ifdef __KAME__		if (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr)) {			sin6.sin6_addr.s6_addr[2] = 0;			sin6.sin6_addr.s6_addr[3] = 0;		}#endif		if (plen % 8 == 0) {			if (memcmp(&sin6.sin6_addr, prefix, plen / 8) != 0)				continue;		} else {			struct in6_addr a, m;			int i;			memcpy(&a, &sin6.sin6_addr, sizeof(sin6.sin6_addr));			memset(&m, 0, sizeof(m));			memset(&m, 0xff, plen / 8);			m.s6_addr[plen / 8] = (0xff00 >> (plen % 8)) & 0xff;			for (i = 0; i < sizeof(a); i++)				a.s6_addr[i] &= m.s6_addr[i];			if (memcmp(&a, prefix, plen / 8) != 0 ||			    a.s6_addr[plen / 8] !=			    (prefix->s6_addr[plen / 8] & m.s6_addr[plen / 8]))				continue;		}		memcpy(addr, &sin6.sin6_addr, sizeof(sin6.sin6_addr));#ifdef __KAME__		if (IN6_IS_ADDR_LINKLOCAL(addr))			addr->s6_addr[2] = addr->s6_addr[3] = 0; #endif		error = 0;		break;	}	freeifaddrs(ifap);	return(error);}intin6_addrscopebyif(addr, ifnam)	struct in6_addr *addr;	char *ifnam;{	u_int ifindex; 	if ((ifindex = if_nametoindex(ifnam)) == 0)		return(-1);	if (IN6_IS_ADDR_LINKLOCAL(addr) || IN6_IS_ADDR_MC_LINKLOCAL(addr))		return(ifindex);	if (IN6_IS_ADDR_SITELOCAL(addr) || IN6_IS_ADDR_MC_SITELOCAL(addr))		return(1);	/* XXX */	if (IN6_IS_ADDR_MC_ORGLOCAL(addr))		return(1);	/* XXX */	return(1);		/* treat it as global */}/* XXX: this code assumes getifaddrs(3) */const char *getdev(addr)	struct sockaddr_in6 *addr;{	struct ifaddrs *ifap, *ifa;	struct sockaddr_in6 *a6;	static char ret_ifname[IF_NAMESIZE];	if (getifaddrs(&ifap) != 0) {		err(1, "getdev: getifaddrs");		/* NOTREACHED */	}	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {		if (ifa->ifa_addr->sa_family != AF_INET6)			continue;		a6 = (struct sockaddr_in6 *)ifa->ifa_addr;		if (!IN6_ARE_ADDR_EQUAL(&a6->sin6_addr, &addr->sin6_addr) ||		    a6->sin6_scope_id != addr->sin6_scope_id)			continue;		break;	}	if (ifa)		strlcpy(ret_ifname, ifa->ifa_name, sizeof(ret_ifname));	freeifaddrs(ifap);	return(ifa ? ret_ifname : NULL);}inttransmit_sa(s, sa, buf, len)	int s;	struct sockaddr *sa;	char *buf;	size_t len;{	int error;	error = sendto(s, buf, len, 0, sa, sa->sa_len);	return (error != len) ? -1 : 0;}longrandom_between(x, y)	long x;	long y;{	long ratio;	ratio = 1 << 16;	while ((y - x) * ratio < (y - x))		ratio = ratio / 2;	return x + ((y - x) * (ratio - 1) / random() & (ratio - 1));}intprefix6_mask(in6, plen)	struct in6_addr *in6;	int plen;{	struct sockaddr_in6 mask6;	int i;	if (sa6_plen2mask(&mask6, plen))		return(-1);	for (i = 0; i < 16; i++)		in6->s6_addr[i] &= mask6.sin6_addr.s6_addr[i];	return(0);}intsa6_plen2mask(sa6, plen)	struct sockaddr_in6 *sa6;	int plen;{	u_char *cp;	if (plen < 0 || plen > 128)		return(-1);	memset(sa6, 0, sizeof(*sa6));	sa6->sin6_family = AF_INET6;	sa6->sin6_len = sizeof(*sa6);		for (cp = (u_char *)&sa6->sin6_addr; plen > 7; plen -= 8)		*cp++ = 0xff;	*cp = 0xff << (8 - plen);	return(0);}char *addr2str(sa)	struct sockaddr *sa;{	static char addrbuf[8][NI_MAXHOST];	static int round = 0;	char *cp;	round = (round + 1) & 7;	cp = addrbuf[round];	getnameinfo(sa, sa->sa_len, cp, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);	return(cp);}char *in6addr2str(in6, scopeid)	struct in6_addr *in6;	int scopeid;{	struct sockaddr_in6 sa6;	memset(&sa6, 0, sizeof(sa6));	sa6.sin6_family = AF_INET6;	sa6.sin6_len = sizeof(sa6);	sa6.sin6_addr = *in6;	sa6.sin6_scope_id = scopeid;	return(addr2str((struct sockaddr *)&sa6));}

⌨️ 快捷键说明

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