?? dhcp6relay.c
字號:
/* $KAME: dhcp6relay.c,v 1.33 2002/04/24 14:31:32 jinmei Exp $ *//* * Copyright (C) 2000 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/queue.h>#include <sys/uio.h>#include <net/if.h>#if defined(__FreeBSD__) && __FreeBSD__ >= 3#include <net/if_var.h>#endif#include <netinet/in.h>#include <netinet/icmp6.h>#include <netinet6/in6_var.h>#include <netdb.h>#include <arpa/inet.h>#include <stdio.h>#include <stdarg.h>#include <syslog.h>#include <unistd.h>#include <stdlib.h> /* XXX: freebsd2 needs this for opt{arg,ind} */#include <errno.h>#include <err.h>#include <string.h>#include <dhcp6.h>#include <common.h>static int ssock; /* socket for servers */static int csock; /* socket for clients */static int icmp6sock; /* socket to receive ICMPv6 errors */static int maxfd; /* maxi file descriptor for select(2) */static int debug = 0;char *device = NULL; /* must be global */static char *rmsgctlbuf, *smsgctlbuf;static int rmsgctllen, smsgctllen;static struct msghdr rmh, smh;static char rdatabuf[BUFSIZ];static struct in6_pktinfo *spktinfo;static int mhops = DEFAULT_SOLICIT_HOPCOUNT;static struct sockaddr_in6 sa6_all_servers, sa6_client;struct prefix_list { TAILQ_ENTRY(prefix_list) plink; struct sockaddr_in6 paddr; /* contains meaningless but enough members */ int plen;};TAILQ_HEAD(, prefix_list) global_prefixes; /* list of non-link-local prefixes */static char *global_strings[] = { "fec0::/10", "2000::/3",};static void usage __P((void));static struct prefix_list *make_prefix __P((char *));static void relay6_init __P((void));static void relay6_loop __P((void));static int relay6_recv __P((int, char *));static void relay6_react __P((size_t, char *, char *, int));static void relay6_react_solicit __P((char *, size_t, char *));static void relay6_react_advert __P((char *, size_t, char *));static void relay6_forward_response __P((char *, size_t, struct in6_addr *, const char *));intmain(argc, argv) int argc; char *argv[];{ int ch; char *progname; char *p; if ((progname = strrchr(*argv, '/')) == NULL) progname = *argv; else progname++; while((ch = getopt(argc, argv, "dDfH:")) != -1) { switch(ch) { case 'd': debug = 1; break; case 'D': debug = 2; break; case 'f': foreground++; break; case 'H': p = NULL; mhops = (int)strtoul(optarg, &p, 10); if (!*optarg || *p) { errx(1, "illegal hop limit: %s", optarg); /* NOTREACHED */ } if (mhops <= 0 || mhops > 255) { errx(1, "illegal hop limit: %d", mhops); /* NOTREACHED */ } break; default: usage(); exit(0); } } 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); relay6_init(); relay6_loop(); exit(0);}static voidusage(){ fprintf(stderr, "usage: dhcp6relay [-dDf] [-H hoplim] intface\n"); exit(0);}static struct prefix_list *make_prefix(pstr0) char *pstr0;{ struct prefix_list *pent; char *p, *ep; int plen; char pstr[BUFSIZ]; struct in6_addr paddr; /* make a local copy for safety */ if (strlcpy(pstr, pstr0, sizeof(pstr)) >= sizeof(pstr)) { dprintf(LOG_WARNING, "prefix string too long (maybe bogus): %s", pstr0); return(NULL); } /* parse the string */ if ((p = strchr(pstr, '/')) == NULL) plen = 128; /* assumes it as a host prefix */ else { if (p[1] == '\0') { dprintf(LOG_WARNING, "no prefix length (ignored): %s", p + 1); return(NULL); } plen = (int)strtoul(p + 1, &ep, 10); if (*ep != '\0') { dprintf(LOG_WARNING, "illegal prefix length (ignored): %s", p + 1); return(NULL); } *p = '\0'; } if (inet_pton(AF_INET6, pstr, &paddr) != 1) { dprintf(LOG_ERR, "inet_pton failed for %s", pstr); /* warn? */ exit(1); /* NOTREACHED */ } /* allocate a new entry */ if ((pent = (struct prefix_list *)malloc(sizeof(*pent))) == NULL) { dprintf(LOG_ERR, "memory allocation failed"); exit(1); /* NOTREACHED */ } /* fill in each member of the entry */ memset(pent, 0, sizeof(*pent)); pent->paddr.sin6_family = AF_INET6; pent->paddr.sin6_len = sizeof(struct sockaddr_in6); pent->paddr.sin6_addr = paddr; pent->plen = plen; return(pent);}static voidrelay6_init(){ struct addrinfo hints; struct addrinfo *res, *res2; int i, ifidx, error; struct ipv6_mreq mreq6; int type; struct icmp6_filter filt; int on = 1; static struct iovec iov[2]; struct cmsghdr *cm; /* initialize non-link-local prefixes list */ TAILQ_INIT(&global_prefixes); for (i = 0; global_strings[i]; i++) { struct prefix_list *p; if ((p = make_prefix(global_strings[i])) != NULL) TAILQ_INSERT_TAIL(&global_prefixes, p, plink); } /* initialize special socket addresses */ 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(DH6ADDR_ALLSERVER, DH6PORT_UPSTREAM, &hints, &res); if (error) { errx(1, "getaddrinfo: %s", gai_strerror(error)); /* NOTREACHED */ } if (res->ai_family != PF_INET6 || res->ai_addrlen < sizeof(sa6_all_servers)) { /* this should be impossible, but check for safety */ errx(1, "getaddrinfor returned a bogus address"); /* NOTREACHED */ } memcpy(&sa6_all_servers, res->ai_addr, sizeof(sa6_all_servers)); freeaddrinfo(res); /* initialize send/receive buffer */ iov[0].iov_base = (caddr_t)rdatabuf; iov[0].iov_len = sizeof(rdatabuf); rmh.msg_iov = iov; rmh.msg_iovlen = 1; rmsgctllen = smsgctllen = CMSG_SPACE(sizeof(struct in6_pktinfo)); if ((rmsgctlbuf = (char *)malloc(rmsgctllen)) == NULL) { errx(1, "memory allocation failed"); /* NOTREACHED */ } if ((smsgctlbuf = (char *)malloc(smsgctllen)) == NULL) { errx(1, "memory allocation failed"); /* NOTREACHED */ } smh.msg_controllen = smsgctllen; smh.msg_control = smsgctlbuf; cm = (struct cmsghdr *)CMSG_FIRSTHDR(&smh); cm->cmsg_len = CMSG_LEN(sizeof(*spktinfo)); cm->cmsg_level = IPPROTO_IPV6; cm->cmsg_type = IPV6_PKTINFO; spktinfo = (struct in6_pktinfo *)CMSG_DATA((struct cmsghdr *)cm); /* * Setup a socket to communicate with clients. */ ifidx = if_nametoindex(device); if (ifidx == 0) errx(1, "invalid interface %s", device); 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) { errx(1, "getaddrinfo: %s", gai_strerror(error)); /* NOTREACHED */ } csock = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (csock < 0) { err(1, "socket(csock)"); /* NOTREACHED */ } if (csock > maxfd) maxfd = csock; if (setsockopt(csock, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on)) < 0) { err(1, "setsockopt(csock, SO_REUSEPORT)"); /* NOTREACHED */ } if (setsockopt(csock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) { err(1, "setsockopt(csock, SO_REUSEADDR)"); /* NOTREACHED */ } if (bind(csock, res->ai_addr, res->ai_addrlen) < 0) { err(1, "bind(csock)"); /* NOTREACHED */ } freeaddrinfo(res);#ifdef IPV6_RECVPKTINFO if (setsockopt(csock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on)) < 0) { err(1, "setsockopt(IPV6_RECVPKTINFO)"); /* NOTREACHED */ }#else if (setsockopt(csock, IPPROTO_IPV6, IPV6_PKTINFO, &on, sizeof(on)) < 0) { err(1, "setsockopt(IPV6_PKTINFO)"); /* NOTREACHED */ }#endif hints.ai_flags = 0; error = getaddrinfo(DH6ADDR_ALLAGENT, 0, &hints, &res2); if (error) { errx(1, "getaddrinfo: %s", gai_strerror(error)); /* NOTREACHED */ } 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(csock, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq6, sizeof(mreq6))) { err(1, "setsockopt(csock, IPV6_JOIN_GROUP)"); } freeaddrinfo(res2); /* * Setup a socket to communicate with servers. */ hints.ai_flags = AI_PASSIVE; error = getaddrinfo(NULL, DH6PORT_DOWNSTREAM, &hints, &res); if (error) { errx(1, "getaddrinfo: %s", gai_strerror(error));
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -