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

📄 dhcp6s.c

📁 IPv6环境下的DHCP实现
💻 C
📖 第 1 页 / 共 3 页
字号:
/*	$KAME: dhcp6s.c,v 1.90 2002/06/28 07:29:43 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>#include <sys/uio.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 <errno.h>#include <net/if.h>#if defined(__FreeBSD__) && __FreeBSD__ >= 3#include <net/if_var.h>#endif#include <netinet/in.h>#include <netinet6/in6_var.h>#include <arpa/inet.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>#include <limits.h>#include <dhcp6.h>#include <config.h>#include <common.h>#include <timer.h>typedef enum { DHCP6_CONFINFO_PREFIX } dhcp6_conftype_t;struct dhcp6_binding {	TAILQ_ENTRY(dhcp6_binding) link;	dhcp6_conftype_t type;	struct duid clientid;	void *val;	u_int32_t duration;	struct dhcp6_timer *timer;};static TAILQ_HEAD(, dhcp6_binding) dhcp6_binding_head;static int debug = 0;const dhcp6_mode_t dhcp6_mode = DHCP6_MODE_SERVER;char *device = NULL;int insock;	/* inbound udp port */int outsock;	/* outbound udp port */static const struct sockaddr_in6 *sa6_any_downstream;static struct msghdr rmh;static char rdatabuf[BUFSIZ];static int rmsgctllen;static char *rmsgctlbuf;static struct duid server_duid;static struct dhcp6_list arg_dnslist;#define DUID_FILE "/etc/dhcp6s_duid"#define DHCP6S_CONF "/usr/local/v6/etc/dhcp6s.conf"static void usage __P((void));static void server6_init __P((void));static void server6_mainloop __P((void));static int server6_recv __P((int));static int server6_react_solicit __P((struct dhcp6_if *, struct dhcp6 *,				      struct dhcp6_optinfo *,				      struct sockaddr *, int));static int server6_react_request __P((struct dhcp6_if *,				      struct in6_pktinfo *, struct dhcp6 *,				      struct dhcp6_optinfo *,				      struct sockaddr *, int));static int server6_react_renew __P((struct dhcp6_if *,				     struct in6_pktinfo *, struct dhcp6 *,				     struct dhcp6_optinfo *,				     struct sockaddr *, int));static int server6_react_rebind __P((struct dhcp6_if *,				     struct dhcp6 *, struct dhcp6_optinfo *,				     struct sockaddr *, int));static int server6_react_informreq __P((struct dhcp6_if *, struct dhcp6 *,					struct dhcp6_optinfo *,					struct sockaddr *, int));static int server6_send __P((int, struct dhcp6_if *, struct dhcp6 *,			     struct dhcp6_optinfo *,			     struct sockaddr *, int,			     struct dhcp6_optinfo *));static int create_conflist __P((dhcp6_conftype_t, struct duid *,				struct dhcp6_list *, struct dhcp6_list *,				struct dhcp6_list *, int));static struct dhcp6_binding *add_binding __P((struct duid *,					      dhcp6_conftype_t, void *));static struct dhcp6_binding *find_binding __P((struct duid *,					       dhcp6_conftype_t, void *));static void update_binding __P((struct dhcp6_binding *));static void remove_binding __P((struct dhcp6_binding *));static struct dhcp6_timer *binding_timo __P((void *));static char *bindingstr __P((struct dhcp6_binding *));intmain(argc, argv)	int argc;	char **argv;{	int ch;	struct in6_addr a;	struct dhcp6_listval *dlv;	char *progname, *conffile = DHCP6S_CONF;	if ((progname = strrchr(*argv, '/')) == NULL)		progname = *argv;	else		progname++;	TAILQ_INIT(&arg_dnslist);	srandom(time(NULL) & getpid());	while ((ch = getopt(argc, argv, "c:dDfn:")) != -1) {		switch (ch) {		case 'c':			conffile = optarg;			break;		case 'd':			debug = 1;			break;		case 'D':			debug = 2;			break;		case 'f':			foreground++;			break;		case 'n':			warnx("-n dnsserv option was obsoleted.  "			    "use configuration file.");			if (inet_pton(AF_INET6, optarg, &a) != 1) {				errx(1, "invalid DNS server %s", optarg);				/* NOTREACHED */			}			if ((dlv = malloc(sizeof *dlv)) == NULL) {				errx(1, "malloc failed for a DNS server");				/* NOTREACHED */			}			dlv->val_addr6 = a;			TAILQ_INSERT_TAIL(&arg_dnslist, dlv, link);			break;		default:			usage();			/* NOTREACHED */		}	}	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);	ifinit(device);	if ((cfparse(conffile)) != 0) {		dprintf(LOG_ERR, "%s" "failed to parse configuration file",			FNAME);		exit(1);	}	/* prohibit a mixture of old and new style of DNS server config */	if (!TAILQ_EMPTY(&arg_dnslist)) {		if (!TAILQ_EMPTY(&dnslist)) {			dprintf(LOG_INFO, "%s" "do not specify DNS servers "			    "both by command line and by configuration file.",			    FNAME);			exit(1);		}		dnslist = arg_dnslist;		TAILQ_INIT(&arg_dnslist);	}	server6_init();	server6_mainloop();	exit(0);}static voidusage(){	fprintf(stderr,		"usage: dhcp6s [-c configfile] [-dDf] intface\n");	exit(0);}/*------------------------------------------------------------*/voidserver6_init(){	struct addrinfo hints;	struct addrinfo *res, *res2;	int error;	int ifidx;	int on = 1;	struct ipv6_mreq mreq6;	static struct iovec iov;	static struct sockaddr_in6 sa6_any_downstream_storage;	TAILQ_INIT(&dhcp6_binding_head);	ifidx = if_nametoindex(device);	if (ifidx == 0) {		dprintf(LOG_ERR, "%s" "invalid interface %s", FNAME, device);		exit(1);	}	/* get our DUID */	if (get_duid(DUID_FILE, &server_duid)) {		dprintf(LOG_ERR, "%s" "failed to get a DUID", FNAME);		exit(1);	}	/* initialize send/receive buffer */	iov.iov_base = (caddr_t)rdatabuf;	iov.iov_len = sizeof(rdatabuf);	rmh.msg_iov = &iov;	rmh.msg_iovlen = 1;	rmsgctllen = CMSG_SPACE(sizeof(struct in6_pktinfo));	if ((rmsgctlbuf = (char *)malloc(rmsgctllen)) == NULL) {		dprintf(LOG_ERR, "%s" "memory allocation failed", FNAME);		exit(1);	}	/* initialize socket */	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) {		dprintf(LOG_ERR, "%s" "getaddrinfo: %s",			FNAME, gai_strerror(error));		exit(1);	}	insock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);	if (insock < 0) {		dprintf(LOG_ERR, "%s" "socket(insock): %s",			FNAME, strerror(errno));		exit(1);	}	if (setsockopt(insock, SOL_SOCKET, SO_REUSEPORT, &on,		       sizeof(on)) < 0) {		dprintf(LOG_ERR, "%s" "setsockopt(insock, SO_REUSEPORT): %s",			FNAME, strerror(errno));		exit(1);	}	if (setsockopt(insock, SOL_SOCKET, SO_REUSEADDR, &on,		       sizeof(on)) < 0) {		dprintf(LOG_ERR, "%s" "setsockopt(insock, SO_REUSEADDR): %s",			FNAME, strerror(errno));		exit(1);	}#ifdef IPV6_RECVPKTINFO	if (setsockopt(insock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on,		       sizeof(on)) < 0) {		dprintf(LOG_ERR, "%s"			"setsockopt(inbound, IPV6_RECVPKTINFO): %s",			FNAME, strerror(errno));		exit(1);	}#else	if (setsockopt(insock, IPPROTO_IPV6, IPV6_PKTINFO, &on,		       sizeof(on)) < 0) {		dprintf(LOG_ERR, "%s"			"setsockopt(inbound, IPV6_PKTINFO): %s",			FNAME, strerror(errno));		exit(1);	}#endif	if (bind(insock, res->ai_addr, res->ai_addrlen) < 0) {		dprintf(LOG_ERR, "%s" "bind(insock): %s",			FNAME, strerror(errno));		exit(1);	}	freeaddrinfo(res);	hints.ai_flags = 0;	error = getaddrinfo(DH6ADDR_ALLAGENT, DH6PORT_UPSTREAM, &hints, &res2);	if (error) {		dprintf(LOG_ERR, "%s" "getaddrinfo: %s",			FNAME, gai_strerror(error));		exit(1);	}	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(insock, IPPROTO_IPV6, IPV6_JOIN_GROUP,	    &mreq6, sizeof(mreq6))) {		dprintf(LOG_ERR, "%s" "setsockopt(insock, IPV6_JOIN_GROUP)",			FNAME, strerror(errno));		exit(1);	}	freeaddrinfo(res2);	hints.ai_flags = 0;	error = getaddrinfo(DH6ADDR_ALLSERVER, DH6PORT_UPSTREAM,			    &hints, &res2);	if (error) {		dprintf(LOG_ERR, "%s" "getaddrinfo: %s",			FNAME, gai_strerror(error));		exit(1);	}	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(insock, IPPROTO_IPV6, IPV6_JOIN_GROUP,	    &mreq6, sizeof(mreq6))) {		dprintf(LOG_ERR,			"%s" "setsockopt(insock, IPV6_JOIN_GROUP): %s",			FNAME, strerror(errno));		exit(1);	}	freeaddrinfo(res2);	hints.ai_flags = 0;	error = getaddrinfo(NULL, DH6PORT_DOWNSTREAM, &hints, &res);	if (error) {		dprintf(LOG_ERR, "%s" "getaddrinfo: %s",			FNAME, gai_strerror(error));		exit(1);	}	outsock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);	if (outsock < 0) {		dprintf(LOG_ERR, "%s" "socket(outsock): %s",			FNAME, strerror(errno));		exit(1);	}	/* set outgoing interface of multicast packets for DHCP reconfig */	if (setsockopt(outsock, IPPROTO_IPV6, IPV6_MULTICAST_IF,	    &ifidx, sizeof(ifidx)) < 0) {		dprintf(LOG_ERR,			"%s" "setsockopt(outsock, IPV6_MULTICAST_IF): %s",			FNAME, strerror(errno));		exit(1);	}	/* make the socket write-only */	if (shutdown(outsock, 0)) {		dprintf(LOG_ERR, "%s" "shutdown(outbound, 0): %s",			FNAME, strerror(errno));		exit(1);	}	freeaddrinfo(res);	memset(&hints, 0, sizeof(hints));	hints.ai_family = PF_INET6;	hints.ai_socktype = SOCK_DGRAM;	hints.ai_protocol = IPPROTO_UDP;	error = getaddrinfo("::", DH6PORT_DOWNSTREAM, &hints, &res);	if (error) {		dprintf(LOG_ERR, "%s" "getaddrinfo: %s",			FNAME, gai_strerror(error));		exit(1);	}	memcpy(&sa6_any_downstream_storage, res->ai_addr, res->ai_addrlen);	sa6_any_downstream =		(const struct sockaddr_in6*)&sa6_any_downstream_storage;	freeaddrinfo(res);}static voidserver6_mainloop(){	struct timeval *w;	int ret;	fd_set r;	ssize_t l;	while (1) {		w = dhcp6_check_timer();		FD_ZERO(&r);		FD_SET(insock, &r);		ret = select(insock + 1, &r, NULL, NULL, w);		switch (ret) {		case -1:			dprintf(LOG_ERR, "%s" "select: %s",				FNAME, strerror(errno));			exit(1);			/* NOTREACHED */		case 0:		/* timeout */			break;		default:			break;		}		if (FD_ISSET(insock, &r))			server6_recv(insock);	}}static intserver6_recv(s)	int s;{	ssize_t len;	struct sockaddr_storage from;	int fromlen;	struct msghdr mhdr;	struct iovec iov;	char cmsgbuf[BUFSIZ];	struct cmsghdr *cm;	struct in6_pktinfo *pi = NULL;	struct dhcp6_if *ifp;	struct dhcp6 *dh6;	struct dhcp6opt *opt, *eopt;

⌨️ 快捷键说明

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