📄 dhcp6c.c
字号:
/* $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 + -