in6_ifattach.c

来自「eCos操作系统源码」· C语言 代码 · 共 1,344 行 · 第 1/3 页

C
1,344
字号
//==========================================================================////      src/sys/netinet6/in6_ifattach.c////==========================================================================//####BSDCOPYRIGHTBEGIN####//// -------------------------------------------//// Portions of this software may have been derived from OpenBSD, // FreeBSD or other sources, and are covered by the appropriate// copyright disclaimers included herein.//// Portions created by Red Hat are// Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.//// -------------------------------------------////####BSDCOPYRIGHTEND####//==========================================================================/*	$KAME: in6_ifattach.c,v 1.149 2001/12/07 07:07:09 itojun Exp $	*//* * Copyright (C) 1995, 1996, 1997, and 1998 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/param.h>#include <sys/malloc.h>#include <sys/socket.h>#include <sys/sockio.h>#ifdef __bsdi__#include <crypto/md5.h>#elif defined(__OpenBSD__)#include <sys/md5k.h>#else#include <sys/md5.h>#endif#ifdef __OpenBSD__#include <dev/rndvar.h>#endif#include <net/if.h>#include <net/if_dl.h>#include <net/if_types.h>#include <net/route.h>#include <netinet/in.h>#include <netinet/in_var.h>#ifndef __NetBSD__#include <netinet/if_ether.h>#endif#if (defined(__FreeBSD__) && __FreeBSD__ >= 4)#include <netinet/in_pcb.h>#endif#include <netinet/ip6.h>#include <netinet6/ip6_var.h>#include <netinet6/in6_var.h>#if (defined(__FreeBSD__) && __FreeBSD__ >= 4)#include <netinet6/in6_pcb.h>#endif#include <netinet6/in6_ifattach.h>#include <netinet6/ip6_var.h>#include <netinet6/nd6.h>#include <netinet6/scope6_var.h>struct in6_ifstat **in6_ifstat = NULL;struct icmp6_ifstat **icmp6_ifstat = NULL;size_t in6_ifstatmax = 0;size_t icmp6_ifstatmax = 0;unsigned long in6_maxmtu = 0;#ifdef IP6_AUTO_LINKLOCALint ip6_auto_linklocal = IP6_AUTO_LINKLOCAL;#elseint ip6_auto_linklocal = 1;	/* enable by default */#endif#ifdef __NetBSD__struct callout in6_tmpaddrtimer_ch = CALLOUT_INITIALIZER;#elif (defined(__FreeBSD__) && __FreeBSD__ >= 3)struct callout in6_tmpaddrtimer_ch;#elif defined(__OpenBSD__)struct timeout in6_tmpaddrtimer_ch;#endif#if (defined(__FreeBSD__) && __FreeBSD__ >= 4)extern struct inpcbinfo udbinfo;extern struct inpcbinfo ripcbinfo;#endif#if defined(__NetBSD__) || defined(__OpenBSD__)static int get_hostid_ifid __P((struct ifnet *, struct in6_addr *));#endifstatic int get_rand_ifid __P((struct ifnet *, struct in6_addr *));static int generate_tmp_ifid __P((u_int8_t *, const u_int8_t *, u_int8_t *));static int get_hw_ifid __P((struct ifnet *, struct in6_addr *));#ifndef MIP6static int get_ifid __P((struct ifnet *, struct ifnet *, struct in6_addr *));#endif /* !MIP6 */static int in6_ifattach_linklocal __P((struct ifnet *, struct ifnet *));static int in6_ifattach_loopback __P((struct ifnet *));#define EUI64_GBIT	0x01#define EUI64_UBIT	0x02#define EUI64_TO_IFID(in6)	do {(in6)->s6_addr[8] ^= EUI64_UBIT; } while (0)#define EUI64_GROUP(in6)	((in6)->s6_addr[8] & EUI64_GBIT)#define EUI64_INDIVIDUAL(in6)	(!EUI64_GROUP(in6))#define EUI64_LOCAL(in6)	((in6)->s6_addr[8] & EUI64_UBIT)#define EUI64_UNIVERSAL(in6)	(!EUI64_LOCAL(in6))#define IFID_LOCAL(in6)		(!EUI64_LOCAL(in6))#define IFID_UNIVERSAL(in6)	(!EUI64_UNIVERSAL(in6))#define GEN_TEMPID_RETRY_MAX 5#if defined(__NetBSD__) || defined(__OpenBSD__)/* * Generate a last-resort interface identifier from hostid. * works only for certain architectures (like sparc). * also, using hostid itself may constitute a privacy threat, much worse * than MAC addresses (hostids are used for software licensing). * maybe we should use MD5(hostid) instead. */static intget_hostid_ifid(ifp, in6)	struct ifnet *ifp;	struct in6_addr *in6;	/* upper 64bits are preserved */{	int off, len;	static u_int8_t allzero[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };	static u_int8_t allone[8] =		{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };	if (!hostid)		return -1;	/* get up to 8 bytes from the hostid field - should we get */	len = (sizeof(hostid) > 8) ? 8 : sizeof(hostid);	off = sizeof(*in6) - len;	bcopy(&hostid, &in6->s6_addr[off], len);	/* make sure we do not return anything bogus */	if (bcmp(&in6->s6_addr[8], allzero, sizeof(allzero)))		return -1;	if (bcmp(&in6->s6_addr[8], allone, sizeof(allone)))		return -1;	/* make sure to set "u" bit to local, and "g" bit to individual. */	in6->s6_addr[8] &= ~EUI64_GBIT;	/* g bit to "individual" */	in6->s6_addr[8] |= EUI64_UBIT;	/* u bit to "local" */	/* convert EUI64 into IPv6 interface identifier */	EUI64_TO_IFID(in6);	return 0;}#endif/* * Generate a last-resort interface identifier, when the machine has no * IEEE802/EUI64 address sources. * The goal here is to get an interface identifier that is * (1) random enough and (2) does not change across reboot. * We currently use MD5(hostname) for it. */static intget_rand_ifid(ifp, in6)	struct ifnet *ifp;	struct in6_addr *in6;	/* upper 64bits are preserved */{	MD5_CTX ctxt;	u_int8_t digest[16];#ifdef __FreeBSD__	int hostnamelen	= strlen(hostname);#endif#if 0	/* we need at least several letters as seed for ifid */	if (hostnamelen < 3)		return -1;#endif	/* generate 8 bytes of pseudo-random value. */	bzero(&ctxt, sizeof(ctxt));	MD5Init(&ctxt);	MD5Update(&ctxt, hostname, hostnamelen);	MD5Final(digest, &ctxt);	/* assumes sizeof(digest) > sizeof(ifid) */	bcopy(digest, &in6->s6_addr[8], 8);	/* make sure to set "u" bit to local, and "g" bit to individual. */	in6->s6_addr[8] &= ~EUI64_GBIT;	/* g bit to "individual" */	in6->s6_addr[8] |= EUI64_UBIT;	/* u bit to "local" */	/* convert EUI64 into IPv6 interface identifier */	EUI64_TO_IFID(in6);	return 0;}static intgenerate_tmp_ifid(seed0, seed1, ret)	u_int8_t *seed0, *ret;	const u_int8_t *seed1;{	MD5_CTX ctxt;	u_int8_t seed[16], digest[16], nullbuf[8];	u_int32_t val32;#ifndef __OpenBSD__	struct timeval tv;#endif	/*	 * interface ID for subnet anycast addresses.	 * XXX: we assume the unicast address range that requires IDs	 * in EUI-64 format.	 */	const u_int8_t anycast_id[8] = {0xfd, 0xff, 0xff, 0xff,					0xff, 0xff, 0xff, 0x80};	const u_int8_t isatap_id[4] = {0x00, 0x00, 0x5e, 0xfe};	int badid, retry = 0; 	/* If there's no hisotry, start with a random seed. */	bzero(nullbuf, sizeof(nullbuf));	if (bcmp(nullbuf, seed0, sizeof(nullbuf)) == 0) {		int i;		for (i = 0; i < 2; i++) {#ifndef __OpenBSD__			microtime(&tv);			val32 = random() ^ tv.tv_usec;#else			val32 = arc4random();#endif			bcopy(&val32, seed + sizeof(val32) * i, sizeof(val32));		}	} else {		bcopy(seed0, seed, 8);	}	/* copy the right-most 64-bits of the given address */	/* XXX assumption on the size of IFID */	bcopy(seed1, &seed[8], 8);  again:	if (0) {		/* for debugging purposes only */		int i;		printf("generate_tmp_ifid: new randomized ID from: ");		for (i = 0; i < 16; i++)			printf("%02x", seed[i]);		printf(" ");	}	/* generate 16 bytes of pseudo-random value. */	bzero(&ctxt, sizeof(ctxt));	MD5Init(&ctxt);	MD5Update(&ctxt, seed, sizeof(seed));	MD5Final(digest, &ctxt);	/*	 * draft-ietf-ipngwg-temp-addresses-v2-00.txt 3.2.1. (3)	 * Take the left-most 64-bits of the MD5 digest and set bit 6 (the	 * left-most bit is numbered 0) to zero.	 */	bcopy(digest, ret, 8);	ret[0] &= ~EUI64_UBIT;	/*	 * Reject inappropriate identifiers according to	 * draft-ietf-ipngwg-temp-addresses-v2-00.txt 3.2.1. (4)	 * At this moment, we reject following cases:	 * - all 0 identifier	 * - identifiers that conflict with reserved subnet anycast addresses,	 *   which are defined in RFC 2526.	 * - identifiers that conflict with ISATAP addresses	 * - identifiers used in our own addresses	 */	badid = 0;	if (bcmp(nullbuf, ret, sizeof(nullbuf)) == 0)		badid = 1;	else if (bcmp(anycast_id, ret, 7) == 0 &&	    (anycast_id[7] & ret[7]) == anycast_id[7]) {		badid = 1;	} else if (bcmp(isatap_id, ret, sizeof(isatap_id)) == 0)		badid = 1;	else {		struct in6_ifaddr *ia;		for (ia = in6_ifaddr; ia; ia = ia->ia_next) {			if (bcmp(&ia->ia_addr.sin6_addr.s6_addr[8], ret, 8)				== 0) {				badid = 1;				break;			}		}	}	/*	 * In the event that an unacceptable identifier has been generated,	 * restart the process, using the right-most 64 bits of the MD5 digest	 * obtained in place of the history value.	 */	if (badid) {		if (0) {	/* for debugging purposes only */			int i;			printf("unacceptable random ID: ");			for (i = 0; i < 16; i++)				printf("%02x", digest[i]);			printf("\n");		}		if (++retry < GEN_TEMPID_RETRY_MAX) {			bcopy(&digest[8], seed, 8);			goto again;		} else {			/*			 * We're so unlucky.  Give up for now, and return			 * all 0 IDs to tell the caller not to make a			 * temporary address.			 */			nd6log((LOG_NOTICE,				"generate_tmp_ifid: never found a good ID\n"));			bzero(ret, 8);		}	}	/*	 * draft-ietf-ipngwg-temp-addresses-v2-00.txt 3.2.1. (6)	 * Take the rightmost 64-bits of the MD5 digest and save them in	 * stable storage as the history value to be used in the next	 * iteration of the algorithm. 	 */	bcopy(&digest[8], seed0, 8);	if (0) {		/* for debugging purposes only */		int i;		printf("to: ");		for (i = 0; i < 16; i++)			printf("%02x", digest[i]);		printf("\n");	}	return 0;}/* * Get interface identifier for the specified interface. * XXX assumes single sockaddr_dl (AF_LINK address) per an interface */static intget_hw_ifid(ifp, in6)	struct ifnet *ifp;	struct in6_addr *in6;	/* upper 64bits are preserved */{	struct ifaddr *ifa;	struct sockaddr_dl *sdl;	u_int8_t *addr;	size_t addrlen;	static u_int8_t allzero[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };	static u_int8_t allone[8] =		{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)	for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)#else	for (ifa = ifp->if_addrlist.tqh_first;	     ifa;	     ifa = ifa->ifa_list.tqe_next)#endif	{		if (ifa->ifa_addr->sa_family != AF_LINK)			continue;		sdl = (struct sockaddr_dl *)ifa->ifa_addr;		if (sdl == NULL)			continue;		if (sdl->sdl_alen == 0)			continue;		goto found;	}	return -1;found:	addr = LLADDR(sdl);	addrlen = sdl->sdl_alen;	switch (ifp->if_type) {	case IFT_IEEE1394:#ifdef IFT_IEEE80211	case IFT_IEEE80211:#endif		/* IEEE1394 uses 16byte length address starting with EUI64 */		if (addrlen > 8)			addrlen = 8;		break;	default:		break;	}	/* get EUI64 */	switch (ifp->if_type) {	/* IEEE802/EUI64 cases - what others? */	case IFT_ETHER:	case IFT_FDDI:	case IFT_ATM:	case IFT_IEEE1394:#ifdef IFT_IEEE80211	case IFT_IEEE80211:#endif		/* look at IEEE802/EUI64 only */		if (addrlen != 8 && addrlen != 6)			return -1;		/*		 * check for invalid MAC address - on bsdi, we see it a lot		 * since wildboar configures all-zero MAC on pccard before

⌨️ 快捷键说明

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