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

📄 dhcp6c.c

📁 DHCPv6协议在Linux操作系统下的一个客户端实现。
💻 C
📖 第 1 页 / 共 4 页
字号:
/*	$Id: dhcp6c.c,v 1.35 2004/03/04 23:31:24 shirleyma Exp $	*//*	ported from KAME: dhcp6c.c,v 1.97 2002/09/24 14:20:49 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/socket.h>#include <sys/uio.h>#include <sys/stat.h>#include <unistd.h>#include <errno.h>#if TIME_WITH_SYS_TIME# include <sys/time.h># include <sys/timeb.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 <linux/sockios.h>#if defined(__FreeBSD__) && __FreeBSD__ >= 3#include <net/if_var.h>#endif#include <arpa/inet.h>#include <netdb.h>#include <signal.h>#include <stdio.h>#include <stdarg.h>#include <syslog.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include <err.h>#include <ifaddrs.h>#include "queue.h"#include "dhcp6.h"#include "config.h"#include "common.h"#include "timer.h"#include "lease.h"static int debug = 0;static u_long sig_flags = 0;#define SIGF_TERM 0x1#define SIGF_HUP 0x2#define SIGF_CLEAN 0x4#define DHCP6S_VALID_REPLY(a) \	(a == DHCP6S_REQUEST || a == DHCP6S_RENEW || \	 a == DHCP6S_REBIND || a == DHCP6S_DECLINE || \	 a == DHCP6S_RELEASE || a == DHCP6S_CONFIRM || \	 a == DHCP6S_INFOREQ)const dhcp6_mode_t dhcp6_mode = DHCP6_MODE_CLIENT;static char *device = NULL;static int num_device = 0;static struct iaid_table iaidtab[100];static u_int8_t client6_request_flag = 0;static	char leasename[100];static int rapatch = 0;#define CLIENT6_RELEASE_ADDR	0x1#define CLIENT6_CONFIRM_ADDR	0x2#define CLIENT6_REQUEST_ADDR	0x4#define CLIENT6_DECLINE_ADDR	0x8#define CLIENT6_INFO_REQ	0x10int insock;	/* inbound udp port */int outsock;	/* outbound udp port */int nlsock;	extern char *raproc_file;extern char *ifproc_file;extern struct ifproc_info *dadlist;extern FILE *client6_lease_file;extern struct dhcp6_iaidaddr client6_iaidaddr;FILE *dhcp6_resolv_file;static const struct sockaddr_in6 *sa6_allagent;static struct duid client_duid;static void usage __P((void));static void client6_init __P((char *));static void client6_ifinit __P((char *));void free_servers __P((struct dhcp6_if *));static void free_resources __P((struct dhcp6_if *));static int create_request_list __P((int));static void client6_mainloop __P((void));static void process_signals __P((void));static struct dhcp6_serverinfo *find_server __P((struct dhcp6_if *,						 struct duid *));static struct dhcp6_serverinfo *allocate_newserver __P((struct dhcp6_if *, struct dhcp6_optinfo *));static struct dhcp6_serverinfo *select_server __P((struct dhcp6_if *));void client6_send __P((struct dhcp6_event *));int client6_send_newstate __P((struct dhcp6_if *, int));static void client6_recv __P((void));static int client6_recvadvert __P((struct dhcp6_if *, struct dhcp6 *,				   ssize_t, struct dhcp6_optinfo *));static int client6_recvreply __P((struct dhcp6_if *, struct dhcp6 *,				  ssize_t, struct dhcp6_optinfo *));static void client6_signal __P((int));static struct dhcp6_event *find_event_withid __P((struct dhcp6_if *,						  u_int32_t));static struct dhcp6_timer *check_lease_file_timo __P((void *));static struct dhcp6_timer *check_link_timo __P((void *));static struct dhcp6_timer *check_dad_timo __P((void *));static void setup_check_timer __P((struct dhcp6_if *));static void setup_interface __P((char *));struct dhcp6_timer *client6_timo __P((void *));extern int client6_ifaddrconf __P((ifaddrconf_cmd_t, struct dhcp6_addr *));extern struct dhcp6_timer *syncfile_timo __P((void *));extern int radvd_parse (struct dhcp6_iaidaddr *, int);#define DHCP6C_CONF "/etc/dhcp6c.conf"#define DHCP6C_PIDFILE "/var/run/dhcpv6/dhcp6c.pid"#define DUID_FILE "/var/lib/dhcpv6/dhcp6c_duid"static int pid;static char cmdbuf[1024];static char oldlink[256];char client6_lease_temp[256];struct dhcp6_list request_list;intmain(argc, argv)	int argc;	char **argv;{	int ch;	char *progname, *conffile = DHCP6C_CONF;	FILE *pidfp;	char *addr;	pid = getpid();	srandom(time(NULL) & pid);	if ((progname = strrchr(*argv, '/')) == NULL)		progname = *argv;	else		progname++;	TAILQ_INIT(&request_list);	while ((ch = getopt(argc, argv, "c:r:R:P:dDfI")) != -1) {		switch (ch) {		case 'c':			conffile = optarg;			break;		case 'P':			client6_request_flag |= CLIENT6_REQUEST_ADDR;			for (addr = strtok(optarg, " "); addr; addr = strtok(NULL, " ")) {				struct dhcp6_listval *lv;				if ((lv = (struct dhcp6_listval *)malloc(sizeof(*lv)))				    == NULL) {					dprintf(LOG_ERR, "failed to allocate memory");					exit(1);				}				memset(lv, 0, sizeof(*lv));				if (inet_pton(AF_INET6, strtok(addr, "/"), 				    &lv->val_dhcp6addr.addr) < 1) {					dprintf(LOG_ERR, 						"invalid ipv6address for release");					usage();					exit(1);				}				lv->val_dhcp6addr.type = IAPD;				lv->val_dhcp6addr.plen = atoi(strtok(NULL, "/"));				lv->val_dhcp6addr.status_code = DH6OPT_STCODE_UNDEFINE;				TAILQ_INSERT_TAIL(&request_list, lv, link);			} 			break;		case 'R':			client6_request_flag |= CLIENT6_REQUEST_ADDR;			for (addr = strtok(optarg, " "); addr; addr = strtok(NULL, " ")) {				struct dhcp6_listval *lv;				if ((lv = (struct dhcp6_listval *)malloc(sizeof(*lv)))				    == NULL) {					dprintf(LOG_ERR, "failed to allocate memory");					exit(1);				}				memset(lv, 0, sizeof(*lv));				if (inet_pton(AF_INET6, addr, &lv->val_dhcp6addr.addr) < 1) {					dprintf(LOG_ERR, 						"invalid ipv6address for release");					usage();					exit(1);				}				lv->val_dhcp6addr.type = IANA;				lv->val_dhcp6addr.status_code = DH6OPT_STCODE_UNDEFINE;				TAILQ_INSERT_TAIL(&request_list, lv, link);			} 			break;		case 'r':			client6_request_flag |= CLIENT6_RELEASE_ADDR;			if (strcmp(optarg, "all")) {				for (addr = strtok(optarg, " "); addr; 				     addr = strtok(NULL, " ")) {					struct dhcp6_listval *lv;					if ((lv = (struct dhcp6_listval *)malloc(sizeof(*lv)))					    == NULL) {						dprintf(LOG_ERR, "failed to allocate memory");						exit(1);					}					memset(lv, 0, sizeof(*lv));					if (inet_pton(AF_INET6, addr, 					    &lv->val_dhcp6addr.addr) < 1) {						dprintf(LOG_ERR, 							"invalid ipv6address for release");						usage();						exit(1);					}					lv->val_dhcp6addr.type = IANA;					TAILQ_INSERT_TAIL(&request_list, lv, link);				}			} 			break;		case 'I':			client6_request_flag |= CLIENT6_INFO_REQ;			break;		case 'd':			debug = 1;			break;		case 'D':			debug = 2;			break;		case 'f':			foreground++;			break;		default:			usage();			exit(0);		}	}	argc -= optind;	argv += optind;	if (argc != 1) {		usage();		exit(0);	}	device = argv[0];	if (foreground == 0) {		if (daemon(0, 0) < 0)			err(1, "daemon");		openlog(progname, LOG_NDELAY|LOG_PID, LOG_DAEMON);	}	setloglevel(debug);	/* dump current PID */	if ((pidfp = fopen(DHCP6C_PIDFILE, "w")) != NULL) {		fprintf(pidfp, "%d\n", pid);		fclose(pidfp);	}	ifinit(device);	if ((cfparse(conffile)) != 0) {		dprintf(LOG_ERR, "%s" "failed to parse configuration file",			FNAME);		exit(1);	}	client6_init(device);	client6_ifinit(device);	client6_mainloop();	exit(0);}static voidusage(){	fprintf(stderr, 	"usage: dhcpc [-c configfile] [-r all or (ipv6address ipv6address...)]\n"	"       [-R (ipv6 address ipv6address...) [-dDIf] interface\n");}/*------------------------------------------------------------*/voidclient6_init(device)	char *device;{	struct addrinfo hints, *res;	static struct sockaddr_in6 sa6_allagent_storage;	int error, on = 1;	struct dhcp6_if *ifp;	int ifidx;	struct ifaddrs *ifa, *ifap;	char linklocal[64];	struct in6_addr lladdr;		ifidx = if_nametoindex(device);	if (ifidx == 0) {		dprintf(LOG_ERR, "if_nametoindex(%s)", device);		exit(1);	}	/* get our DUID */	if (get_duid(DUID_FILE, device, &client_duid)) {		dprintf(LOG_ERR, "%s" "failed to get a DUID", FNAME);		exit(1);	}	if (get_linklocal(device, &lladdr) < 0) {		exit(1);	}	if (inet_ntop(AF_INET6, &lladdr, linklocal, sizeof(linklocal)) < 0) {		exit(1);	}	dprintf(LOG_DEBUG, "link local addr is %s", linklocal);		memset(&hints, 0, sizeof(hints));	hints.ai_family = PF_INET6;	hints.ai_socktype = SOCK_DGRAM;	hints.ai_protocol = IPPROTO_UDP;	hints.ai_flags = 0;	error = getaddrinfo(linklocal, DH6PORT_DOWNSTREAM, &hints, &res);	if (error) {		dprintf(LOG_ERR, "%s" "getaddrinfo: %s",			FNAME, strerror(error));		exit(1);	}	insock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);	if (insock < 0) {		dprintf(LOG_ERR, "%s" "socket(inbound)", FNAME);		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	((struct sockaddr_in6 *)(res->ai_addr))->sin6_scope_id = ifidx;	dprintf(LOG_DEBUG, "res addr is %s/%d", addr2str(res->ai_addr), res->ai_addrlen);	if (bind(insock, res->ai_addr, res->ai_addrlen) < 0) {		dprintf(LOG_ERR, "%s" "bind(inbound): %s",			FNAME, strerror(errno));		exit(1);	}	freeaddrinfo(res);	hints.ai_flags = 0;	error = getaddrinfo(linklocal, DH6PORT_UPSTREAM, &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(outbound): %s",			FNAME, strerror(errno));		exit(1);	}	if (setsockopt(outsock, IPPROTO_IPV6, IPV6_MULTICAST_IF,			&ifidx, sizeof(ifidx)) < 0) {		dprintf(LOG_ERR, "%s"			"setsockopt(outbound, IPV6_MULTICAST_IF): %s",			FNAME, strerror(errno));		exit(1);	}	((struct sockaddr_in6 *)(res->ai_addr))->sin6_scope_id = ifidx;	if (bind(outsock, res->ai_addr, res->ai_addrlen) < 0) {		dprintf(LOG_ERR, "%s" "bind(outbound): %s",			FNAME, strerror(errno));		exit(1);	}	freeaddrinfo(res);	/* open a socket to watch the off-on link for confirm messages */	if ((nlsock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {		dprintf(LOG_ERR, "%s" "open a socket: %s",			FNAME, strerror(errno));		exit(1);	}	memset(&hints, 0, sizeof(hints));	hints.ai_family = PF_INET6;	hints.ai_socktype = SOCK_DGRAM;	hints.ai_protocol = IPPROTO_UDP;	error = getaddrinfo(DH6ADDR_ALLAGENT, DH6PORT_UPSTREAM, &hints, &res);	if (error) {		dprintf(LOG_ERR, "%s" "getaddrinfo: %s",			FNAME, gai_strerror(error));		exit(1);	}	memcpy(&sa6_allagent_storage, res->ai_addr, res->ai_addrlen);	sa6_allagent = (const struct sockaddr_in6 *)&sa6_allagent_storage;	freeaddrinfo(res);	/* client interface configuration */	if ((ifp = find_ifconfbyname(device)) == NULL) {		dprintf(LOG_ERR, "%s" "interface %s not configured",			FNAME, device);		exit(1);	}	ifp->outsock = outsock;	if (signal(SIGHUP, client6_signal) == SIG_ERR) {		dprintf(LOG_WARNING, "%s" "failed to set signal: %s",			FNAME, strerror(errno));		exit(1);	}	if (signal(SIGTERM|SIGKILL, client6_signal) == SIG_ERR) {		dprintf(LOG_WARNING, "%s" "failed to set signal: %s",			FNAME, strerror(errno));		exit(1);	}	if (signal(SIGINT, client6_signal) == SIG_ERR) {		dprintf(LOG_WARNING, "%s" "failed to set signal: %s",

⌨️ 快捷键说明

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