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

📄 dhcp6s.c

📁 DHCPv6协议在Linux操作系统下的一个客户端实现。
💻 C
📖 第 1 页 / 共 2 页
字号:
/*	$Id: dhcp6s.c,v 1.19 2004/03/15 22:03:21 shemminger Exp $	*//*	ported from KAME: dhcp6s.c,v 1.91 2002/09/24 14:20:50 itojun 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/stat.h>#include <sys/socket.h>#include <linux/sockios.h>#include <sys/ioctl.h>#include <sys/file.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 <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 "queue.h"#include "timer.h"#include "dhcp6.h"#include "config.h"#include "common.h"#include "server6_conf.h"#include "lease.h"typedef enum { DHCP6_CONFINFO_PREFIX, DHCP6_CONFINFO_ADDRS } 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 char *device[100];static int num_device = 0;static int debug = 0;const dhcp6_mode_t dhcp6_mode = DHCP6_MODE_SERVER;int insock;	/* inbound udp port */int outsock;	/* outbound udp port */extern FILE *server6_lease_file;char server6_lease_temp[100];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 dns_list arg_dnslist;static struct dhcp6_timer *sync_lease_timer;struct link_decl *subnet = NULL;struct host_decl *host = NULL;struct rootgroup *globalgroup = NULL;#define DUID_FILE "/var/lib/dhcpv6/dhcp6s_duid"#define DHCP6S_CONF "/etc/dhcp6s.conf"#define DH6_VALID_MESSAGE(a) \	(a == DH6_SOLICIT || a == DH6_REQUEST || a == DH6_RENEW || \	 a == DH6_REBIND || a == DH6_CONFIRM || a == DH6_RELEASE || \	 a == DH6_DECLINE || a == DH6_INFORM_REQ)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_message __P((struct dhcp6_if *,				      struct in6_pktinfo *, 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 struct dhcp6_timer *check_lease_file_timo __P((void *arg));extern struct link_decl *dhcp6_allocate_link __P((struct dhcp6_if *, struct rootgroup *, 			struct in6_addr *));extern struct host_decl *dhcp6_allocate_host __P((struct dhcp6_if *, struct rootgroup *, 			struct dhcp6_optinfo *));extern int dhcp6_get_hostconf __P((struct dhcp6_optinfo *, struct dhcp6_optinfo *,			struct dhcp6_iaidaddr *, struct host_decl *)); static void random_init(void) {	int f, n;	unsigned int seed = time(NULL) & getpid();	char rand_state[256];	f = open("/dev/urandom", O_RDONLY);	if (f > 0) {		n = read(f, rand_state, sizeof(rand_state));		close(f);		if (n > 32) {			initstate(seed, rand_state, n);			return;		}	}	srandom(seed);}intmain(argc, argv)	int argc;	char **argv;{	int ch, i = 0;	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.addrlist);	random_init();	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.addrlist, dlv, link);			break;		default:			usage();			/* NOTREACHED */		}	}	while (optind < argc) {		device[num_device] = argv[optind++];		num_device += 1;	}	if (foreground == 0) {		if (daemon(0, 0) < 0)			err(1, "daemon");		openlog(progname, LOG_NDELAY|LOG_PID, LOG_DAEMON);	}	setloglevel(debug);	server6_init();	if ((server6_lease_file = init_leases(PATH_SERVER6_LEASE)) == NULL) {		dprintf(LOG_ERR, "%s" "failed to parse lease file",			FNAME);		exit(1);	}	strcpy(server6_lease_temp, PATH_SERVER6_LEASE);	strcat(server6_lease_temp, "XXXXXX");	server6_lease_file = 		sync_leases(server6_lease_file, PATH_SERVER6_LEASE, server6_lease_temp);		if (server6_lease_file == NULL)		exit(1);	globalgroup = (struct rootgroup *)malloc(sizeof(struct rootgroup));	if (globalgroup == NULL) {		dprintf(LOG_ERR, "failed to allocate memory %s", strerror(errno));		exit(1);	}	memset(globalgroup, 0, sizeof(*globalgroup));	TAILQ_INIT(&globalgroup->scope.dnslist.addrlist);	if ((sfparse(conffile)) != 0) {		dprintf(LOG_ERR, "%s" "failed to parse addr configuration file",			FNAME);		exit(1);	}	server6_mainloop();	exit(0);}static voidusage(){	fprintf(stderr,		"usage: dhcp6s [-c configfile] [-dDf] [interface]\n");	exit(0);}/*------------------------------------------------------------*/voidserver6_init(){	struct addrinfo hints;	struct addrinfo *res, *res2;	int error, skfd, i;	int on = 1;	int ifidx[MAX_DEVICE];	struct ipv6_mreq mreq6;	static struct iovec iov;	static struct sockaddr_in6 sa6_any_downstream_storage;	char buff[1024];	struct ifconf ifc;	struct ifreq *ifr;	double d;	struct timeval timo;	/* initialize inbound 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);	}#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);	/* initiallize outbound interface */	hints.ai_flags = AI_PASSIVE;	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);	}	if (bind(outsock, res->ai_addr, res->ai_addrlen) < 0) {		dprintf(LOG_ERR, "%s" "bind(outsock): %s",			FNAME, strerror(errno));		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);	/* 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);	}	if (num_device != 0) {		for (i = 0; i < num_device; i++) {			ifidx[i] = if_nametoindex(device[i]);			if (ifidx[i] == 0) {				dprintf(LOG_ERR, "%s" 					"invalid interface %s", FNAME, device[0]);				exit(1);			}			ifinit(device[i]);		}		if (get_duid(DUID_FILE, device[0], &server_duid)) {			dprintf(LOG_ERR, "%s" "failed to get a DUID", FNAME);			exit(1);		}	} else {				/* all the interfaces join multicast group */		ifc.ifc_len = sizeof(buff);		ifc.ifc_buf = buff;		if ((skfd = socket(AF_INET, SOCK_DGRAM,0)) < 0) {			dprintf(LOG_ERR, "new socket failed");			exit(1);		}		if (ioctl(skfd, SIOCGIFCONF, &ifc) < 0) {			dprintf(LOG_ERR, "SIOCGIFCONF: %s\n", strerror(errno));			exit(1);		}		ifr = ifc.ifc_req;		for (i = ifc.ifc_len / sizeof(struct ifreq); --i >= 0; ifr++) {			dprintf(LOG_DEBUG, "found device %s", ifr->ifr_name);			ifidx[num_device] = if_nametoindex(ifr->ifr_name);			if (ifidx[num_device] < 0) {				dprintf(LOG_ERR, "%s: unknown interface.\n",					ifr->ifr_name);				continue;			}			dprintf(LOG_DEBUG, "if %s index is %d", ifr->ifr_name, 				ifidx[num_device]);#ifdef mshirley			if (((ifr->ifr_flags & IFF_UP) == 0)) continue;#endif			if (strcmp(ifr->ifr_name, "lo")) {				/* get our DUID */				if (get_duid(DUID_FILE, ifr->ifr_name, &server_duid)) {					dprintf(LOG_ERR, "%s" "failed to get a DUID", FNAME);					exit(1);				}			}			ifinit(ifr->ifr_name);			num_device += 1;		}	}	for (i = 0; i < num_device; i++) {		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[i];		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(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[i];		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);		/* set outgoing interface of multicast packets for DHCP reconfig */		if (setsockopt(outsock, IPPROTO_IPV6, IPV6_MULTICAST_IF,		    &ifidx[i], sizeof(ifidx[i])) < 0) {			dprintf(LOG_ERR,				"%s" "setsockopt(outsock, IPV6_MULTICAST_IF): %s",				FNAME, strerror(errno));			exit(1);		}	}	/* set up sync lease file timer */	sync_lease_timer = dhcp6_add_timer(check_lease_file_timo, NULL);	d = DHCP6_SYNCFILE_TIME;	timo.tv_sec = (long)d;	timo.tv_usec = 0;	dprintf(LOG_DEBUG, "set timer for syncing file ...");	dhcp6_set_timer(&timo, sync_lease_timer);	return;}static voidserver6_mainloop(){	struct timeval *w;	int ret;	fd_set r;	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;

⌨️ 快捷键说明

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