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

📄 dhcp6relay.c

📁 IPv6环境下的DHCP实现
💻 C
📖 第 1 页 / 共 2 页
字号:
/*	$KAME: dhcp6relay.c,v 1.33 2002/04/24 14:31:32 jinmei Exp $	*//* * Copyright (C) 2000 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/queue.h>#include <sys/uio.h>#include <net/if.h>#if defined(__FreeBSD__) && __FreeBSD__ >= 3#include <net/if_var.h>#endif#include <netinet/in.h>#include <netinet/icmp6.h>#include <netinet6/in6_var.h>#include <netdb.h>#include <arpa/inet.h>#include <stdio.h>#include <stdarg.h>#include <syslog.h>#include <unistd.h>#include <stdlib.h>		/* XXX: freebsd2 needs this for opt{arg,ind} */#include <errno.h>#include <err.h>#include <string.h>#include <dhcp6.h>#include <common.h>static int ssock;		/* socket for servers */static int csock;		/* socket for clients */static int icmp6sock;		/* socket to receive ICMPv6 errors */static int maxfd;		/* maxi file descriptor for select(2) */static int debug = 0;char *device = NULL;		/* must be global */static char *rmsgctlbuf, *smsgctlbuf;static int rmsgctllen, smsgctllen;static struct msghdr rmh, smh;static char rdatabuf[BUFSIZ];static struct in6_pktinfo *spktinfo;static int mhops = DEFAULT_SOLICIT_HOPCOUNT;static struct sockaddr_in6 sa6_all_servers, sa6_client;struct prefix_list {	TAILQ_ENTRY(prefix_list) plink;	struct sockaddr_in6 paddr; /* contains meaningless but enough members */	int plen;};TAILQ_HEAD(, prefix_list) global_prefixes; /* list of non-link-local prefixes */static char *global_strings[] = {	"fec0::/10", "2000::/3",};static void usage __P((void));static struct prefix_list *make_prefix __P((char *));static void relay6_init __P((void));static void relay6_loop __P((void));static int relay6_recv __P((int, char *));static void relay6_react __P((size_t, char *, char *, int));static void relay6_react_solicit __P((char *, size_t, char *));static void relay6_react_advert __P((char *, size_t, char *));static void relay6_forward_response __P((char *, size_t, struct in6_addr *,	const char *));intmain(argc, argv)	int argc;	char *argv[];{	int ch;	char *progname;	char *p;	if ((progname = strrchr(*argv, '/')) == NULL)		progname = *argv;	else		progname++;	while((ch = getopt(argc, argv, "dDfH:")) != -1) {		switch(ch) {		case 'd':			debug = 1;			break;		case 'D':			debug = 2;			break;		case 'f':			foreground++;			break;		case 'H':			p = NULL;			mhops = (int)strtoul(optarg, &p, 10);			if (!*optarg || *p) {				errx(1, "illegal hop limit: %s", optarg);				/* NOTREACHED */			}			if (mhops <= 0 || mhops > 255) {				errx(1, "illegal hop limit: %d", mhops);				/* NOTREACHED */			}			break;		default:			usage();			exit(0);		}	}	argc -= optind;	argv += optind;	if (argc != 1) {		usage();		/* NOTREACHED */	}	device = argv[0];	if (foreground == 0) {		if (daemon(0, 0) < 0)			err(1, "daemon");		openlog(progname, LOG_NDELAY|LOG_PID, LOG_DAEMON);	}	setloglevel(debug);	relay6_init();	relay6_loop();	exit(0);}static voidusage(){	fprintf(stderr,		"usage: dhcp6relay [-dDf] [-H hoplim] intface\n");	exit(0);}static struct prefix_list *make_prefix(pstr0)	char *pstr0;{	struct prefix_list *pent;	char *p, *ep;	int plen;	char pstr[BUFSIZ];	struct in6_addr paddr;	/* make a local copy for safety */	if (strlcpy(pstr, pstr0, sizeof(pstr)) >= sizeof(pstr)) {		dprintf(LOG_WARNING,			"prefix string too long (maybe bogus): %s", pstr0);		return(NULL);	}	/* parse the string */	if ((p = strchr(pstr, '/')) == NULL)		plen = 128; /* assumes it as a host prefix */	else {		if (p[1] == '\0') {			dprintf(LOG_WARNING,				"no prefix length (ignored): %s", p + 1);			return(NULL);		}		plen = (int)strtoul(p + 1, &ep, 10);		if (*ep != '\0') {			dprintf(LOG_WARNING,				"illegal prefix length (ignored): %s", p + 1);			return(NULL);		}		*p = '\0';	}	if (inet_pton(AF_INET6, pstr, &paddr) != 1) {		dprintf(LOG_ERR, "inet_pton failed for %s", pstr); /* warn? */		exit(1);		/* NOTREACHED */	}	/* allocate a new entry */	if ((pent = (struct prefix_list *)malloc(sizeof(*pent))) == NULL) {		dprintf(LOG_ERR, "memory allocation failed");		exit(1);		/* NOTREACHED */	}	/* fill in each member of the entry */	memset(pent, 0, sizeof(*pent));	pent->paddr.sin6_family = AF_INET6;	pent->paddr.sin6_len = sizeof(struct sockaddr_in6);	pent->paddr.sin6_addr = paddr;	pent->plen = plen;	return(pent);}static voidrelay6_init(){	struct addrinfo hints;	struct addrinfo *res, *res2;	int i, ifidx, error;	struct ipv6_mreq mreq6;	int type;	struct icmp6_filter filt;	int on = 1;	static struct iovec iov[2];	struct cmsghdr *cm;	/* initialize non-link-local prefixes list */	TAILQ_INIT(&global_prefixes);	for (i = 0; global_strings[i]; i++) {		struct prefix_list *p;				if ((p = make_prefix(global_strings[i])) != NULL)			TAILQ_INSERT_TAIL(&global_prefixes, p, plink);	}	/* initialize special socket addresses */	memset(&hints, 0, sizeof(hints));	hints.ai_family = PF_INET6;	hints.ai_socktype = SOCK_DGRAM;	hints.ai_protocol = IPPROTO_UDP;	hints.ai_flags = AI_PASSIVE;	error = getaddrinfo(DH6ADDR_ALLSERVER, DH6PORT_UPSTREAM, &hints, &res);	if (error) {		errx(1, "getaddrinfo: %s", gai_strerror(error));		/* NOTREACHED */	}	if (res->ai_family != PF_INET6 ||	    res->ai_addrlen < sizeof(sa6_all_servers)) {		/* this should be impossible, but check for safety */		errx(1, "getaddrinfor returned a bogus address");		/* NOTREACHED */	}	memcpy(&sa6_all_servers, res->ai_addr, sizeof(sa6_all_servers));	freeaddrinfo(res);	/* initialize send/receive buffer */	iov[0].iov_base = (caddr_t)rdatabuf;	iov[0].iov_len = sizeof(rdatabuf);	rmh.msg_iov = iov;	rmh.msg_iovlen = 1;	rmsgctllen = smsgctllen = CMSG_SPACE(sizeof(struct in6_pktinfo));	if ((rmsgctlbuf = (char *)malloc(rmsgctllen)) == NULL) {		errx(1, "memory allocation failed");		/* NOTREACHED */	}	if ((smsgctlbuf = (char *)malloc(smsgctllen)) == NULL) {		errx(1, "memory allocation failed");		/* NOTREACHED */	}	smh.msg_controllen = smsgctllen;	smh.msg_control = smsgctlbuf;	cm = (struct cmsghdr *)CMSG_FIRSTHDR(&smh);	cm->cmsg_len = CMSG_LEN(sizeof(*spktinfo));	cm->cmsg_level = IPPROTO_IPV6;	cm->cmsg_type = IPV6_PKTINFO;	spktinfo = (struct in6_pktinfo *)CMSG_DATA((struct cmsghdr *)cm);	/*	 * Setup a socket to communicate with clients.	 */	ifidx = if_nametoindex(device);	if (ifidx == 0)		errx(1, "invalid interface %s", device);	memset(&hints, 0, sizeof(hints));	hints.ai_family = PF_INET6;	hints.ai_socktype = SOCK_DGRAM;	hints.ai_protocol = IPPROTO_UDP;	hints.ai_flags = AI_PASSIVE;	error = getaddrinfo(NULL, DH6PORT_UPSTREAM, &hints, &res);	if (error) {		errx(1, "getaddrinfo: %s", gai_strerror(error));		/* NOTREACHED */	}	csock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);	if (csock < 0) {		err(1, "socket(csock)");		/* NOTREACHED */	}	if (csock > maxfd)		maxfd = csock;	if (setsockopt(csock, SOL_SOCKET, SO_REUSEPORT,		       &on, sizeof(on)) < 0) {		err(1, "setsockopt(csock, SO_REUSEPORT)");		/* NOTREACHED */	}	if (setsockopt(csock, SOL_SOCKET, SO_REUSEADDR,		       &on, sizeof(on)) < 0) {		err(1, "setsockopt(csock, SO_REUSEADDR)");		/* NOTREACHED */	}	if (bind(csock, res->ai_addr, res->ai_addrlen) < 0) {		err(1, "bind(csock)");		/* NOTREACHED */	}	freeaddrinfo(res);#ifdef IPV6_RECVPKTINFO	if (setsockopt(csock, IPPROTO_IPV6, IPV6_RECVPKTINFO,		       &on, sizeof(on)) < 0) {		err(1, "setsockopt(IPV6_RECVPKTINFO)");		/* NOTREACHED */	}#else	if (setsockopt(csock, IPPROTO_IPV6, IPV6_PKTINFO,		       &on, sizeof(on)) < 0) {		err(1, "setsockopt(IPV6_PKTINFO)");		/* NOTREACHED */	}#endif	hints.ai_flags = 0;	error = getaddrinfo(DH6ADDR_ALLAGENT, 0, &hints, &res2);	if (error) {		errx(1, "getaddrinfo: %s", gai_strerror(error));		/* NOTREACHED */	}	memset(&mreq6, 0, sizeof(mreq6));	mreq6.ipv6mr_interface = ifidx;	memcpy(&mreq6.ipv6mr_multiaddr,		&((struct sockaddr_in6 *)res2->ai_addr)->sin6_addr,		sizeof(mreq6.ipv6mr_multiaddr));	if (setsockopt(csock, IPPROTO_IPV6, IPV6_JOIN_GROUP,			&mreq6, sizeof(mreq6))) {		err(1, "setsockopt(csock, IPV6_JOIN_GROUP)");	}	freeaddrinfo(res2);	/*	 * Setup a socket to communicate with servers.	 */	hints.ai_flags = AI_PASSIVE;	error = getaddrinfo(NULL, DH6PORT_DOWNSTREAM, &hints, &res);	if (error) {		errx(1, "getaddrinfo: %s", gai_strerror(error));

⌨️ 快捷键说明

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