?? dhcp6c.c
字號:
/* $KAME: dhcp6c.c,v 1.96 2002/06/28 07:30:35 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/uio.h>#include <sys/queue.h>#include <errno.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 <net/if.h>#if defined(__FreeBSD__) && __FreeBSD__ >= 3#include <net/if_var.h>#endif#include <net/if_dl.h>#include <netinet/in.h>#include <netinet6/in6_var.h>#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 <dhcp6.h>#include <config.h>#include <common.h>#include <timer.h>#include <prefixconf.h>static int debug = 0;static u_long sig_flags = 0;#define SIGF_TERM 0x1#define SIGF_HUP 0x2const dhcp6_mode_t dhcp6_mode = DHCP6_MODE_CLIENT;char *device = NULL;int insock; /* inbound udp port */int outsock; /* outbound udp port */int rtsock; /* routing socket */static const struct sockaddr_in6 *sa6_allagent;static struct duid client_duid;static void usage __P((void));static void client6_init __P((void));static void client6_ifinit __P((void));static void free_resources __P((void));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 *select_server __P((struct dhcp6_if *));static void client6_send __P((struct dhcp6_event *));static int 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 int sa2plen __P((struct sockaddr_in6 *));struct dhcp6_timer *client6_timo __P((void *));void client6_send_renew __P((struct dhcp6_event *));void client6_send_rebind __P((struct dhcp6_event *));#define DHCP6C_CONF "/usr/local/v6/etc/dhcp6c.conf"#define DHCP6C_PIDFILE "/var/run/dhcp6c.pid"#define DUID_FILE "/etc/dhcp6c_duid"intmain(argc, argv) int argc; char **argv;{ int ch, pid; char *progname, *conffile = DHCP6C_CONF; FILE *pidfp;#ifndef HAVE_ARC4RANDOM srandom(time(NULL) & getpid());#endif if ((progname = strrchr(*argv, '/')) == NULL) progname = *argv; else progname++; while ((ch = getopt(argc, argv, "c:dDf")) != -1) { switch (ch) { case 'c': conffile = optarg; 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 */ pid = getpid(); 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(); client6_ifinit(); client6_mainloop(); exit(0);}static voidusage(){ fprintf(stderr, "usage: dhcpc [-c configfile] [-dDf] intface\n");}/*------------------------------------------------------------*/voidclient6_init(){ struct addrinfo hints, *res; static struct sockaddr_in6 sa6_allagent_storage; int error, on = 1; struct dhcp6_if *ifp; struct dhcp6_event *ev; int ifidx; ifidx = if_nametoindex(device); if (ifidx == 0) { dprintf(LOG_ERR, "if_nametoindex(%s)"); exit(1); } /* get our DUID */ if (get_duid(DUID_FILE, &client_duid)) { dprintf(LOG_ERR, "%s" "failed to get a DUID", FNAME); exit(1); } 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_DOWNSTREAM, &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(inbound)", FNAME); exit(1); } if (setsockopt(insock, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on)) < 0) { dprintf(LOG_ERR, "%s" "setsockopt(inbound, SO_REUSEPORT): %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(inbonud): %s", FNAME, strerror(errno)); exit(1); } freeaddrinfo(res); hints.ai_flags = 0; error = getaddrinfo(NULL, 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); } if (setsockopt(outsock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &on, sizeof(on)) < 0) { dprintf(LOG_ERR, "%s" "setsockopt(outsock, IPV6_MULTICAST_LOOP): %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); /* * bind the well-known incoming port to the outgoing socket * for interoperability with some servers. */ 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_DOWNSTREAM, &hints, &res); if (error) { dprintf(LOG_ERR, "%s" "getaddrinfo: %s", FNAME, gai_strerror(error)); exit(1); } if (setsockopt(outsock, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on)) < 0) { dprintf(LOG_ERR, "%s" "setsockopt(inbound, SO_REUSEPORT): %s", FNAME, strerror(errno)); exit(1); } if (bind(outsock, res->ai_addr, res->ai_addrlen) < 0) { dprintf(LOG_ERR, "%s" "bind(inbonud): %s", FNAME, strerror(errno)); exit(1); } freeaddrinfo(res); /* open a routing socket to watch the routing table */ if ((rtsock = socket(PF_ROUTE, SOCK_RAW, 0)) < 0) { dprintf(LOG_ERR, "%s" "open a routing 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; prefix6_init(); if (signal(SIGHUP, client6_signal) == SIG_ERR) { dprintf(LOG_WARNING, "%s" "failed to set signal: %s", FNAME, strerror(errno)); exit(1); } if (signal(SIGTERM, client6_signal) == SIG_ERR) { dprintf(LOG_WARNING, "%s" "failed to set signal: %s", FNAME, strerror(errno)); exit(1); }}static voidclient6_ifinit(){ struct dhcp6_if *ifp; struct dhcp6_event *ev; for (ifp = dhcp6_if; ifp; ifp = ifp->next) { /* create an event for the initial delay */ if ((ev = dhcp6_create_event(ifp, DHCP6S_INIT)) == NULL) { dprintf(LOG_ERR, "%s" "failed to create an event", FNAME); exit(1); } TAILQ_INSERT_TAIL(&ifp->event_list, ev, link); if ((ev->timer = dhcp6_add_timer(client6_timo, ev)) == NULL) { dprintf(LOG_ERR, "%s" "failed to add a timer for %s", FNAME, ifp->ifname); exit(1); } dhcp6_reset_timer(ev); }}static voidfree_resources(){ struct dhcp6_if *ifp; /* release delegated prefixes (should send DHCPv6 release?) */ prefix6_remove_all(); for (ifp = dhcp6_if; ifp; ifp = ifp->next) { struct dhcp6_event *ev, *ev_next; struct dhcp6_serverinfo *sp, *sp_next; /* cancel all outstanding events for each interface */ for (ev = TAILQ_FIRST(&ifp->event_list); ev; ev = ev_next) { ev_next = TAILQ_NEXT(ev, link); dhcp6_remove_event(ev); } /* free all servers we've seen so far */ for (sp = ifp->servers; sp; sp = sp_next) { sp_next = sp->next; dprintf(LOG_DEBUG, "%s" "removing server (ID: %s)", FNAME, duidstr(&sp->optinfo.serverID)); dhcp6_clear_options(&sp->optinfo); free(sp); } ifp->servers = NULL; ifp->current_server = NULL; }}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -