diff options
author | shin <shin@FreeBSD.org> | 2000-01-06 12:40:54 +0000 |
---|---|---|
committer | shin <shin@FreeBSD.org> | 2000-01-06 12:40:54 +0000 |
commit | 9b5932fc47f3a7c965da9d2e15425aabc7f7dd26 (patch) | |
tree | bffabec553873cccf6ad30da0425fe8c806387da /usr.sbin | |
parent | f1787f2960aaad85fe0cce147b1d910ca08c1055 (diff) | |
download | FreeBSD-src-9b5932fc47f3a7c965da9d2e15425aabc7f7dd26.zip FreeBSD-src-9b5932fc47f3a7c965da9d2e15425aabc7f7dd26.tar.gz |
libipsec and IPsec related apps. (and some KAME related man pages)
Reviewed by: freebsd-arch, cvs-committers
Obtained from: KAME project
Diffstat (limited to 'usr.sbin')
40 files changed, 10565 insertions, 1 deletions
diff --git a/usr.sbin/Makefile b/usr.sbin/Makefile index 220b989..9ab3104 100644 --- a/usr.sbin/Makefile +++ b/usr.sbin/Makefile @@ -48,6 +48,7 @@ SUBDIR= IPXrouted \ mrouted \ mtest \ mtree \ + ndp \ newsyslog \ ngctl \ ntp \ @@ -80,10 +81,13 @@ SUBDIR= IPXrouted \ rpc.yppasswdd \ rpc.ypupdated \ rpc.ypxfrd \ + rrenumd \ + rtadvd \ rtprio \ rtsold \ rwhod \ sa \ + setkey \ sliplogin \ slstat \ spray \ diff --git a/usr.sbin/ndp/Makefile b/usr.sbin/ndp/Makefile new file mode 100644 index 0000000..b0ba348 --- /dev/null +++ b/usr.sbin/ndp/Makefile @@ -0,0 +1,25 @@ +# Copyright (c) 1996 WIDE Project. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modifications, are permitted provided that the above copyright notice +# and this paragraph are duplicated in all such forms and that any +# documentation, advertising materials, and other materials related to +# such distribution and use acknowledge that the software was developed +# by the WIDE Project, Japan. The name of the Project may not be used to +# endorse or promote products derived from this software without +# specific prior written permission. THIS SOFTWARE IS PROVIDED ``AS IS'' +# AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT +# LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE. +# $FreeBSD$ + +.PATH: ${.CURDIR}/../../contrib/tcpdump + +PROG= ndp +SRCS= ndp.c gmt2local.c +MAN8= ndp.8 + +CFLAGS+=-DINET6 +CFLAGS+=-I. -I${.CURDIR} -I${.CURDIR}/../../contrib/tcpdump + +.include <bsd.prog.mk> diff --git a/usr.sbin/ndp/gnuc.h b/usr.sbin/ndp/gnuc.h new file mode 100644 index 0000000..c641296 --- /dev/null +++ b/usr.sbin/ndp/gnuc.h @@ -0,0 +1,2 @@ +/* $FreeBSD$ */ +/* this is dummy to pacify gmt2local.c. */ diff --git a/usr.sbin/ndp/ndp.8 b/usr.sbin/ndp/ndp.8 new file mode 100644 index 0000000..6f0382f --- /dev/null +++ b/usr.sbin/ndp/ndp.8 @@ -0,0 +1,138 @@ +.\" Copyright (C) 1995, 1996, 1997, and 1998 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. +.\" +.\" $Id: ndp.8,v 1.2 1999/10/07 05:26:13 itojun Exp $ +.\" $FreeBSD$ +.\" +.Dd May 17, 1998 +.Dt NDP 8 +.Os KAME +.\" +.Sh NAME +.Nm ndp +.Nd control/diagnose IPv6 neighbor discovery protocol +.\" +.Sh SYNOPSIS +.Nm ndp +.Fl a +.Op Fl ntl +.Nm ndp +.Fl A Ar wait +.Op Fl ntl +.Nm ndp +.Fl c +.Op Fl nt +.Nm ndp +.Fl d +.Op Fl nt +.Ar hostname +.Nm ndp +.Fl f +.Op Fl nt +.Ar filename +.Nm ndp +.Fl H +.Nm ndp +.Fl i +.Ar interface +.Nm ndp +.Fl p +.Nm ndp +.Fl P +.Nm ndp +.Fl r +.Nm ndp +.Fl R +.Nm ndp +.Fl s +.Op Fl nt +.Ar nodename +.Ar ether_addr +.Op temp +.\" +.Sh DESCRIPTION +.Nm +command manipulates the address mapping table +used by Neighbor Discovery Protocol (NDP). +.Bl -tag -width Ds +.It Fl a +Dump the currently existing NDP entries. +.It Fl A Ar wait +Repeat +.Fl a +.Pq dump NDP entries +every +.Ar wait +seconds. +.It Fl c +Erase all the NDP entries. +.It Fl d +Delete specified NDP entry. +.It Fl f +Parse the file specified by +.Ar filename . +.It Fl H +Harmonize consistency between the routing table and the default router +list; install the top entry of the list into the kernel routing table. +.It Fl i +view ND information for specified interface. +.It Fl l +Do not truncate numeric IPv6 address. +.It Fl n +Do not try to resolve numeric address to hostname. +.It Fl p +Show prefix list. +.It Fl P +Flush all the entries in the prefix list. +.It Fl r +Show default router list. +.It Fl R +Flush all the entries in the default router list. +.It Fl s +Register a NDP entry for a node. +.It Fl t +Print timestamp on each entries, +to make it possible to merge output with +.Xr tcpdump 1 . +Most useful when used with +.Fl A . +.El +.\" +.Sh RETURN VALUES +.Nm Ndp +will exit with 0 on success, and non-zero on errors. +.\" +.Sh SEE ALSO +.Xr arp 8 +.\" +.Sh HISTORY +The +.Nm +command first appeared in WIDE Hydrangea IPv6 protocol stack kit. +.\" +.\" .Sh BUGS +.\" (to be written) diff --git a/usr.sbin/ndp/ndp.c b/usr.sbin/ndp/ndp.c new file mode 100644 index 0000000..01cea32 --- /dev/null +++ b/usr.sbin/ndp/ndp.c @@ -0,0 +1,1028 @@ +/* + * Copyright (C) 1995, 1996, 1997, 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. + * + * $FreeBSD$ + */ +/* + * Copyright (c) 1984, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Sun Microsystems, Inc. + * + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + */ + +/* + * Based on: + * "@(#) Copyright (c) 1984, 1993\n\ + * The Regents of the University of California. All rights reserved.\n"; + * + * "@(#)arp.c 8.2 (Berkeley) 1/2/94"; + */ + +/* + * ndp - display, set, delete and flush neighbor cache + */ + + +#include <sys/param.h> +#include <sys/file.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <sys/sysctl.h> +#include <sys/time.h> + +#include <net/if.h> +#include <net/if_var.h> +#include <net/if_dl.h> +#include <net/if_types.h> +#include <net/route.h> + +#include <netinet/in.h> +#include <netinet/if_ether.h> + +#include <netinet/icmp6.h> +#include <netinet6/in6_var.h> +#include <netinet6/nd6.h> + +#include <arpa/inet.h> + +#include <netdb.h> +#include <errno.h> +#include <nlist.h> +#include <stdio.h> +#include <string.h> +#include <paths.h> +#include <err.h> +#include <stdlib.h> +#include <fcntl.h> +#include <unistd.h> +#include "gmt2local.h" + +/* packing rule for routing socket */ +#define ROUNDUP(a) \ + ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) +#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) + +extern int errno; +static int pid; +static int fflag; +static int nflag; +static int tflag; +static int32_t thiszone; /* time difference with gmt */ +static int s = -1; +static int repeat = 0; +static int lflag = 0; + +char ntop_buf[INET6_ADDRSTRLEN]; /* inet_ntop() */ +char host_buf[NI_MAXHOST]; /* getnameinfo() */ +char ifix_buf[IFNAMSIZ]; /* if_indextoname() */ + +int main __P((int, char **)); +int file __P((char *)); +void getsocket __P((void)); +int set __P((int, char **)); +void get __P((char *)); +int delete __P((char *)); +void dump __P((struct in6_addr *)); +static struct in6_nbrinfo *getnbrinfo __P((struct in6_addr *addr, int ifindex)); +static char *ether_str __P((struct sockaddr_dl *)); +int ndp_ether_aton __P((char *, u_char *)); +void usage __P((void)); +int rtmsg __P((int)); +void ifinfo __P((char *)); +void list __P((void)); +void plist __P((void)); +void pfx_flush __P((void)); +void rtr_flush __P((void)); +void harmonize_rtr __P((void)); +static char *sec2str __P((time_t t)); +static char *ether_str __P((struct sockaddr_dl *sdl)); +static void ts_print __P((const struct timeval *)); + +int +main(argc, argv) + int argc; + char **argv; +{ + int ch; + int aflag = 0, cflag = 0, dflag = 0, sflag = 0, Hflag = 0, + pflag = 0, rflag = 0, Pflag = 0, Rflag = 0; + extern char *optarg; + extern int optind; + + pid = getpid(); + thiszone = gmt2local(0); + while ((ch = getopt(argc, argv, "acndfilprstA:HPR")) != EOF) + switch ((char)ch) { + case 'a': + aflag = 1; + break; + case 'c': + fflag = 1; + cflag = 1; + break; + case 'd': + dflag = 1; + break; + case 'i' : + if (argc != 3) + usage(); + ifinfo(argv[2]); + exit(0); + case 'n': + nflag = 1; + continue; + case 'p': + pflag = 1; + break; + case 'f' : + if (argc != 3) + usage(); + file(argv[2]); + exit(0); + case 'l' : + lflag = 1; + break; + case 'r' : + rflag = 1; + break; + case 's': + sflag = 1; + break; + case 't': + tflag = 1; + break; + case 'A': + aflag = 1; + repeat = atoi(optarg); + if (repeat < 0) + usage(); + break; + case 'H' : + Hflag = 1; + break; + case 'P': + Pflag = 1; + break; + case 'R': + Rflag = 1; + break; + default: + usage(); + } + + argc -= optind; + argv += optind; + + if (aflag || cflag) { + dump(0); + exit(0); + } + if (dflag) { + if (argc != 1) + usage(); + delete(argv[0]); + } + if (pflag) { + plist(); + exit(0); + } + if (rflag) { + rtrlist(); + exit(0); + } + if (sflag) { + if (argc < 2 || argc > 4) + usage(); + exit(set(argc, argv) ? 1 : 0); + } + if (Hflag) { + harmonize_rtr(); + exit(0); + } + if (Pflag) { + pfx_flush(); + exit(0); + } + if (Rflag) { + rtr_flush(); + exit(0); + } + + if (argc != 1) + usage(); + get(argv[0]); + exit(0); +} + +/* + * Process a file to set standard ndp entries + */ +int +file(name) + char *name; +{ + FILE *fp; + int i, retval; + char line[100], arg[5][50], *args[5]; + + if ((fp = fopen(name, "r")) == NULL) { + fprintf(stderr, "ndp: cannot open %s\n", name); + exit(1); + } + args[0] = &arg[0][0]; + args[1] = &arg[1][0]; + args[2] = &arg[2][0]; + args[3] = &arg[3][0]; + args[4] = &arg[4][0]; + retval = 0; + while(fgets(line, 100, fp) != NULL) { + i = sscanf(line, "%s %s %s %s %s", arg[0], arg[1], arg[2], + arg[3], arg[4]); + if (i < 2) { + fprintf(stderr, "ndp: bad line: %s\n", line); + retval = 1; + continue; + } + if (set(i, args)) + retval = 1; + } + fclose(fp); + return (retval); +} + +void +getsocket() +{ + if (s < 0) { + s = socket(PF_ROUTE, SOCK_RAW, 0); + if (s < 0) { + perror("ndp: socket"); + exit(1); + } + } +} + +struct sockaddr_in so_mask = {8, 0, 0, { 0xffffffff}}; +struct sockaddr_in6 blank_sin = {sizeof(blank_sin), AF_INET6 }, sin_m; +struct sockaddr_dl blank_sdl = {sizeof(blank_sdl), AF_LINK }, sdl_m; +int expire_time, flags, found_entry; +struct { + struct rt_msghdr m_rtm; + char m_space[512]; +} m_rtmsg; + +/* + * Set an individual neighbor cache entry + */ +int +set(argc, argv) + int argc; + char **argv; +{ + register struct sockaddr_in6 *sin = &sin_m; + register struct sockaddr_dl *sdl; + register struct rt_msghdr *rtm = &(m_rtmsg.m_rtm); + struct addrinfo hints, *res; + int gai_error; + u_char *ea; + char *host = argv[0], *eaddr = argv[1]; + + getsocket(); + argc -= 2; + argv += 2; + sdl_m = blank_sdl; + sin_m = blank_sin; + + bzero(&hints, sizeof(hints)); + hints.ai_family = AF_INET6; + gai_error = getaddrinfo(host, NULL, &hints, &res); + if (gai_error) { + fprintf(stderr, "ndp: %s: %s\n", host, + gai_strerror(gai_error)); + return 1; + } + sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr; + ea = (u_char *)LLADDR(&sdl_m); + if (ndp_ether_aton(eaddr, ea) == 0) + sdl_m.sdl_alen = 6; + flags = expire_time = 0; + while (argc-- > 0) { + if (strncmp(argv[0], "temp", 4) == 0) { + struct timeval time; + gettimeofday(&time, 0); + expire_time = time.tv_sec + 20 * 60; + } + argv++; + } +tryagain: + if (rtmsg(RTM_GET) < 0) { + perror(host); + return (1); + } + sin = (struct sockaddr_in6 *)(rtm + 1); + sdl = (struct sockaddr_dl *)(ROUNDUP(sin->sin6_len) + (char *)sin); + if (IN6_ARE_ADDR_EQUAL(&sin->sin6_addr, &sin_m.sin6_addr)) { + if (sdl->sdl_family == AF_LINK && + (rtm->rtm_flags & RTF_LLINFO) && + !(rtm->rtm_flags & RTF_GATEWAY)) switch (sdl->sdl_type) { + case IFT_ETHER: case IFT_FDDI: case IFT_ISO88023: + case IFT_ISO88024: case IFT_ISO88025: + goto overwrite; + } + goto tryagain; + } +overwrite: + if (sdl->sdl_family != AF_LINK) { + printf("cannot intuit interface index and type for %s\n", host); + return (1); + } + sdl_m.sdl_type = sdl->sdl_type; + sdl_m.sdl_index = sdl->sdl_index; + return (rtmsg(RTM_ADD)); +} + +/* + * Display an individual neighbor cache entry + */ +void +get(host) + char *host; +{ + struct sockaddr_in6 *sin = &sin_m; + struct addrinfo hints, *res; + int gai_error; + + sin_m = blank_sin; + bzero(&hints, sizeof(hints)); + hints.ai_family = AF_INET6; + gai_error = getaddrinfo(host, NULL, &hints, &res); + if (gai_error) { + fprintf(stderr, "ndp: %s: %s\n", host, + gai_strerror(gai_error)); + return; + } + sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr; + dump(&sin->sin6_addr); + if (found_entry == 0) { + getnameinfo((struct sockaddr *)sin, sin->sin6_len, host_buf, + sizeof(host_buf), NULL ,0, + NI_WITHSCOPEID | (nflag ? NI_NUMERICHOST : 0)); + printf("%s (%s) -- no entry\n", host, host_buf); + exit(1); + } +} + +/* + * Delete a neighbor cache entry + */ +int +delete(host) + char *host; +{ + struct sockaddr_in6 *sin = &sin_m; + register struct rt_msghdr *rtm = &m_rtmsg.m_rtm; + struct sockaddr_dl *sdl; + struct addrinfo hints, *res; + int gai_error; + + getsocket(); + sin_m = blank_sin; + + bzero(&hints, sizeof(hints)); + hints.ai_family = AF_INET6; + gai_error = getaddrinfo(host, NULL, &hints, &res); + if (gai_error) { + fprintf(stderr, "ndp: %s: %s\n", host, + gai_strerror(gai_error)); + return 1; + } + sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr; +/*tryagain:*/ + if (rtmsg(RTM_GET) < 0) { + perror(host); + return (1); + } + sin = (struct sockaddr_in6 *)(rtm + 1); + sdl = (struct sockaddr_dl *)(ROUNDUP(sin->sin6_len) + (char *)sin); + if (IN6_ARE_ADDR_EQUAL(&sin->sin6_addr, &sin_m.sin6_addr)) { + if (sdl->sdl_family == AF_LINK && + (rtm->rtm_flags & RTF_LLINFO) && + !(rtm->rtm_flags & RTF_GATEWAY)) switch (sdl->sdl_type) { + case IFT_ETHER: case IFT_FDDI: case IFT_ISO88023: + case IFT_ISO88024: case IFT_ISO88025: + goto delete; + } + } +delete: + if (sdl->sdl_family != AF_LINK) { + printf("cannot locate %s\n", host); + return (1); + } + if (rtmsg(RTM_DELETE) == 0) { + getnameinfo((struct sockaddr *)sin, + sin->sin6_len, host_buf, + sizeof(host_buf), NULL, 0, + NI_WITHSCOPEID | (nflag ? NI_NUMERICHOST : 0)); + printf("%s (%s) deleted\n", host, host_buf); + } + + return 0; +} + +/* + * Dump the entire neighbor cache + */ +void +dump(addr) + struct in6_addr *addr; +{ + int mib[6]; + size_t needed; + char *host, *lim, *buf, *next; + struct rt_msghdr *rtm; + struct sockaddr_in6 *sin; + struct sockaddr_dl *sdl; + extern int h_errno; + struct hostent *hp; + struct in6_nbrinfo *nbi; + struct timeval time; + int addrwidth; + + /* Print header */ + if (!tflag) + printf("%-29.29s %-18.18s %6.6s %-9.9s %2s %4s %4s\n", + "Neighbor", "Linklayer Address", "Netif", "Expire", + "St", "Flgs", "Prbs"); + +again:; + mib[0] = CTL_NET; + mib[1] = PF_ROUTE; + mib[2] = 0; + mib[3] = AF_INET6; + mib[4] = NET_RT_FLAGS; + mib[5] = RTF_LLINFO; + if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) + err(1, "sysctl(PF_ROUTE estimate)"); + if (needed > 0) { + if ((buf = malloc(needed)) == NULL) + errx(1, "malloc"); + if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) + err(1, "sysctl(PF_ROUTE, NET_RT_FLAGS)"); + lim = buf + needed; + } else + buf = lim = NULL; + + for (next = buf; next && next < lim; next += rtm->rtm_msglen) { + int isrouter = 0, prbs = 0; + + rtm = (struct rt_msghdr *)next; + sin = (struct sockaddr_in6 *)(rtm + 1); + sdl = (struct sockaddr_dl *)((char *)sin + ROUNDUP(sin->sin6_len)); + if (addr) { + if (!IN6_ARE_ADDR_EQUAL(addr, &sin->sin6_addr)) + continue; + found_entry = 1; + } else if (IN6_IS_ADDR_MULTICAST(&sin->sin6_addr)) + continue; + if (fflag == 1) { + delete((char *)inet_ntop(AF_INET6, &sin->sin6_addr, + ntop_buf, sizeof(ntop_buf))); + continue; + } + + if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr) || + IN6_IS_ADDR_MC_LINKLOCAL(&sin->sin6_addr)) { + /* XXX: should scope id be filled in the kernel? */ + if (sin->sin6_scope_id == 0) + sin->sin6_scope_id = sdl->sdl_index; + + /* XXX: KAME specific hack; removed the embedded id */ + *(u_int16_t *)&sin->sin6_addr.s6_addr[2] = 0; + } + getnameinfo((struct sockaddr *)sin, sin->sin6_len, host_buf, + sizeof(host_buf), NULL, 0, + NI_WITHSCOPEID | (nflag ? NI_NUMERICHOST : 0)); + gettimeofday(&time, 0); + if (tflag) + ts_print(&time); + + if (lflag) { + addrwidth = strlen(host_buf); + if (addrwidth < 29) + addrwidth = 29; + } else + addrwidth = 29; + + printf("%-*.*s %-18.18s %6.6s", addrwidth, addrwidth, host_buf, + ether_str(sdl), + if_indextoname(sdl->sdl_index, ifix_buf)); + + /* Print neighbor discovery specific informations */ + putchar(' '); + nbi = getnbrinfo(&sin->sin6_addr, sdl->sdl_index); + if (nbi) { + if (nbi->expire > time.tv_sec) { + printf(" %-9.9s", + sec2str(nbi->expire - time.tv_sec)); + } + else if (nbi->expire == 0) + printf(" %-9.9s", "permanent"); + else + printf(" %-9.9s", "expired"); + + switch(nbi->state) { + case ND6_LLINFO_NOSTATE: + printf(" N"); + break; + case ND6_LLINFO_WAITDELETE: + printf(" W"); + break; + case ND6_LLINFO_INCOMPLETE: + printf(" I"); + break; + case ND6_LLINFO_REACHABLE: + printf(" R"); + break; + case ND6_LLINFO_STALE: + printf(" S"); + break; + case ND6_LLINFO_DELAY: + printf(" D"); + break; + case ND6_LLINFO_PROBE: + printf(" P"); + break; + default: + printf(" ?"); + break; + } + + isrouter = nbi->isrouter; + prbs = nbi->asked; + } + else { + warnx("failed to get neighbor information"); + printf(" "); + } + + /* other flags */ + putchar(' '); + { + u_char flgbuf[8], *p = flgbuf; + + flgbuf[0] = '\0'; + if (isrouter) + p += sprintf((char *)p, "R"); +#ifndef RADISH + if (rtm->rtm_addrs & RTA_NETMASK) { + sin = (struct sockaddr_in6 *) + (sdl->sdl_len + (char *)sdl); + if (!IN6_IS_ADDR_UNSPECIFIED(&sin->sin6_addr)) + p += sprintf((char *)p, "P"); + if (sin->sin6_len != sizeof(struct sockaddr_in6)) + p += sprintf((char *)p, "W"); + } +#endif /*RADISH*/ + printf("%4s", flgbuf); + } + + putchar(' '); + if (prbs) + printf("% 4d", prbs); + + printf("\n"); + } + + if (repeat) { + printf("\n"); + sleep(repeat); + goto again; + } +} + +static struct in6_nbrinfo * +getnbrinfo(addr, ifindex) + struct in6_addr *addr; + int ifindex; +{ + static struct in6_nbrinfo nbi; + int s; + + if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) + err(1, "socket"); + + bzero(&nbi, sizeof(nbi)); + if_indextoname(ifindex, nbi.ifname); + nbi.addr = *addr; + if (ioctl(s, SIOCGNBRINFO_IN6, (caddr_t)&nbi) < 0) { + warn("ioctl"); + close(s); + return(NULL); + } + + close(s); + return(&nbi); +} + +static char * +ether_str(sdl) + struct sockaddr_dl *sdl; +{ + static char ebuf[32]; + u_char *cp; + + if (sdl->sdl_alen) { + cp = (u_char *)LLADDR(sdl); + sprintf(ebuf, "%x:%x:%x:%x:%x:%x", + cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]); + } + else { + sprintf(ebuf, "(incomplete)"); + } + + return(ebuf); +} + +int +ndp_ether_aton(a, n) + char *a; + u_char *n; +{ + int i, o[6]; + + i = sscanf(a, "%x:%x:%x:%x:%x:%x", &o[0], &o[1], &o[2], + &o[3], &o[4], &o[5]); + if (i != 6) { + fprintf(stderr, "ndp: invalid Ethernet address '%s'\n", a); + return (1); + } + for (i=0; i<6; i++) + n[i] = o[i]; + return (0); +} + +void +usage() +{ + printf("usage: ndp hostname\n"); + printf(" ndp -a[ntl]\n"); + printf(" ndp [-ntl] -A wait\n"); + printf(" ndp -c[nt]\n"); + printf(" ndp -d[nt] hostname\n"); + printf(" ndp -f[nt] filename\n"); + printf(" ndp -i interface\n"); + printf(" ndp -p\n"); + printf(" ndp -r\n"); + printf(" ndp -s hostname ether_addr [temp]\n"); + printf(" ndp -H\n"); + printf(" ndp -P\n"); + printf(" ndp -R\n"); + exit(1); +} + +int +rtmsg(cmd) + int cmd; +{ + static int seq; + int rlen; + register struct rt_msghdr *rtm = &m_rtmsg.m_rtm; + register char *cp = m_rtmsg.m_space; + register int l; + + errno = 0; + if (cmd == RTM_DELETE) + goto doit; + bzero((char *)&m_rtmsg, sizeof(m_rtmsg)); + rtm->rtm_flags = flags; + rtm->rtm_version = RTM_VERSION; + + switch (cmd) { + default: + fprintf(stderr, "ndp: internal wrong cmd\n"); + exit(1); + case RTM_ADD: + rtm->rtm_addrs |= RTA_GATEWAY; + rtm->rtm_rmx.rmx_expire = expire_time; + rtm->rtm_inits = RTV_EXPIRE; + rtm->rtm_flags |= (RTF_HOST | RTF_STATIC); + /* FALLTHROUGH */ + case RTM_GET: + rtm->rtm_addrs |= RTA_DST; + } +#define NEXTADDR(w, s) \ + if (rtm->rtm_addrs & (w)) { \ + bcopy((char *)&s, cp, sizeof(s)); cp += sizeof(s);} + + NEXTADDR(RTA_DST, sin_m); + NEXTADDR(RTA_GATEWAY, sdl_m); + NEXTADDR(RTA_NETMASK, so_mask); + + rtm->rtm_msglen = cp - (char *)&m_rtmsg; +doit: + l = rtm->rtm_msglen; + rtm->rtm_seq = ++seq; + rtm->rtm_type = cmd; + if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) { + if (errno != ESRCH || cmd != RTM_DELETE) { + perror("writing to routing socket"); + return (-1); + } + } + do { + l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg)); + } while (l > 0 && (rtm->rtm_seq != seq || rtm->rtm_pid != pid)); + if (l < 0) + (void) fprintf(stderr, "ndp: read from routing socket: %s\n", + strerror(errno)); + return (0); +} + +void +ifinfo(ifname) + char *ifname; +{ + struct in6_ndireq nd; + int s; + + if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + perror("ndp: socket"); + exit(1); + } + bzero(&nd, sizeof(nd)); + strcpy(nd.ifname, ifname); + if (ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&nd) < 0) { + perror("ioctl (SIOCGIFINFO_IN6)"); + exit(1); + } +#define ND nd.ndi + printf("linkmtu=%d", ND.linkmtu); + printf(", curhlim=%d", ND.chlim); + printf(", basereachable=%ds%dms", + ND.basereachable / 1000, ND.basereachable % 1000); + printf(", reachable=%ds", ND.reachable); + printf(", retrans=%ds%dms\n", ND.retrans / 1000, ND.retrans % 1000); +#undef ND + close(s); +} + +void +rtrlist() +{ + struct in6_drlist dr; + int s, i; + struct timeval time; + + if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + perror("ndp: socket"); + exit(1); + } + bzero(&dr, sizeof(dr)); + strcpy(dr.ifname, "lo0"); /* dummy */ + if (ioctl(s, SIOCGDRLST_IN6, (caddr_t)&dr) < 0) { + perror("ioctl (SIOCGDRLST_IN6)"); + exit(1); + } +#define DR dr.defrouter[i] + for (i = 0 ; DR.if_index && i < PRLSTSIZ ; i++) { + struct sockaddr_in6 sin6; + + bzero(&sin6, sizeof(sin6)); + sin6.sin6_family = AF_INET6; + sin6.sin6_len = sizeof(sin6); + sin6.sin6_addr = DR.rtaddr; + getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len, host_buf, + sizeof(host_buf), NULL, 0, + NI_WITHSCOPEID | (nflag ? NI_NUMERICHOST : 0)); + + printf("%s if=%s", host_buf, + if_indextoname(DR.if_index, ifix_buf)); + printf(", flags=%s%s", + DR.flags & ND_RA_FLAG_MANAGED ? "M" : "", + DR.flags & ND_RA_FLAG_OTHER ? "O" : ""); + gettimeofday(&time, 0); + if (DR.expire == 0) + printf(", expire=Never\n"); + else + printf(", expire=%s\n", + sec2str(DR.expire - time.tv_sec)); + } +#undef DR + close(s); +} + +void +plist() +{ + struct in6_prlist pr; + int s, i; + struct timeval time; + + gettimeofday(&time, 0); + + if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + perror("ndp: socket"); + exit(1); + } + bzero(&pr, sizeof(pr)); + strcpy(pr.ifname, "lo0"); /* dummy */ + if (ioctl(s, SIOCGPRLST_IN6, (caddr_t)&pr) < 0) { + perror("ioctl (SIOCGPRLST_IN6)"); + exit(1); + } +#define PR pr.prefix[i] + for (i = 0; PR.if_index && i < PRLSTSIZ ; i++) { + printf("%s/%d if=%s\n", + inet_ntop(AF_INET6, &PR.prefix, ntop_buf, + sizeof(ntop_buf)), PR.prefixlen, + if_indextoname(PR.if_index, ifix_buf)); + gettimeofday(&time, 0); + printf(" flags=%s%s", + PR.raflags.onlink ? "L" : "", + PR.raflags.autonomous ? "A" : ""); + if (PR.vltime == ND6_INFINITE_LIFETIME) + printf(" vltime=infinity"); + else + printf(" vltime=%ld", (long)PR.vltime); + if (PR.pltime == ND6_INFINITE_LIFETIME) + printf(", pltime=infinity"); + else + printf(", pltime=%ld", (long)PR.pltime); + if (PR.expire == 0) + printf(", expire=Never\n"); + else if (PR.expire >= time.tv_sec) + printf(", expire=%s\n", + sec2str(PR.expire - time.tv_sec)); + else + printf(", expired\n"); + if (PR.advrtrs) { + int j; + printf(" advertised by\n"); + for (j = 0; j < PR.advrtrs; j++) { + struct sockaddr_in6 sin6; + + bzero(&sin6, sizeof(sin6)); + sin6.sin6_family = AF_INET6; + sin6.sin6_len = sizeof(sin6); + sin6.sin6_addr = PR.advrtr[j]; + getnameinfo((struct sockaddr *)&sin6, + sin6.sin6_len, host_buf, + sizeof(host_buf), NULL, 0, + NI_WITHSCOPEID | (nflag ? NI_NUMERICHOST : 0)); + + printf(" %s\n", host_buf); + } + if (PR.advrtrs > DRLSTSIZ) + printf(" and %d routers\n", + PR.advrtrs - DRLSTSIZ); + } + else + printf(" No advertising router\n"); + } +#undef PR + close(s); +} + +void +pfx_flush() +{ + char dummyif[IFNAMSIZ+8]; + int s; + + if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) + err(1, "socket"); + strcpy(dummyif, "lo0"); /* dummy */ + if (ioctl(s, SIOCSPFXFLUSH_IN6, (caddr_t)&dummyif) < 0) + err(1, "ioctl(SIOCSPFXFLUSH_IN6)"); +} + +void +rtr_flush() +{ + char dummyif[IFNAMSIZ+8]; + int s; + + if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) + err(1, "socket"); + strcpy(dummyif, "lo0"); /* dummy */ + if (ioctl(s, SIOCSRTRFLUSH_IN6, (caddr_t)&dummyif) < 0) + err(1, "ioctl(SIOCSRTRFLUSH_IN6)"); +} + +void +harmonize_rtr() +{ + char dummyif[IFNAMSIZ+8]; + int s; + + if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + perror("ndp: socket"); + exit(1); + } + strcpy(dummyif, "lo0"); /* dummy */ + if (ioctl(s, SIOCSNDFLUSH_IN6, (caddr_t)&dummyif) < 0) { + perror("ioctl (SIOCSNDFLUSH_IN6)"); + exit(1); + } +} + +static char * +sec2str(total) + time_t total; +{ + static char result[256]; + int days, hours, mins, secs; + int first = 1; + char *p = result; + + days = total / 3600 / 24; + hours = (total / 3600) % 24; + mins = (total / 60) % 60; + secs = total % 60; + + if (days) { + first = 0; + p += sprintf(p, "%dd", days); + } + if (!first || hours) { + first = 0; + p += sprintf(p, "%dh", hours); + } + if (!first || mins) { + first = 0; + p += sprintf(p, "%dm", mins); + } + sprintf(p, "%ds", secs); + + return(result); +} + +/* + * Print the timestamp + * from tcpdump/util.c + */ +static void +ts_print(tvp) + const struct timeval *tvp; +{ + int s; + + /* Default */ + s = (tvp->tv_sec + thiszone) % 86400; + (void)printf("%02d:%02d:%02d.%06u ", + s / 3600, (s % 3600) / 60, s % 60, (u_int32_t)tvp->tv_usec); +} diff --git a/usr.sbin/rrenumd/Makefile b/usr.sbin/rrenumd/Makefile new file mode 100644 index 0000000..990ddab --- /dev/null +++ b/usr.sbin/rrenumd/Makefile @@ -0,0 +1,41 @@ +# Copyright (c) 1996 WIDE Project. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modifications, are permitted provided that the above copyright notice +# and this paragraph are duplicated in all such forms and that any +# documentation, advertising materials, and other materials related to +# such distribution and use acknowledge that the software was developed +# by the WIDE Project, Japan. The name of the Project may not be used to +# endorse or promote products derived from this software without +# specific prior written permission. THIS SOFTWARE IS PROVIDED ``AS IS'' +# AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT +# LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE. +# $FreeBSD$ + +PROG= rrenumd +SRCS= rrenumd.c parser.y lexer.l +YFLAGS+= -d + +CC= gcc + +CFLAGS+= -DINET6 -DIPSEC -I${.OBJDIR} +LDADD+= -lipsec -lcompat +DPADD+= ${LIBIPSEC} ${LIBCOMPAT} +LDADD+= -ll -ly +DPADD+= ${LIBL} ${LIBY} + +MAN5= rrenumd.conf.5 +MAN8= rrenumd.8 + +SRCS+=y.tab.h +y.tab.h: parser.y + +.if defined(YACCDEBUG) +CFLAGS+= -DYYDEBUG +YFLAGS+= -t -v +.endif + +.include <bsd.prog.mk> + +CLEANFILES+= y.tab.h diff --git a/usr.sbin/rrenumd/lexer.l b/usr.sbin/rrenumd/lexer.l new file mode 100644 index 0000000..80429af --- /dev/null +++ b/usr.sbin/rrenumd/lexer.l @@ -0,0 +1,248 @@ +/* + * Copyright (C) 1995, 1996, 1997, and 1998 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. + * + * $FreeBSD$ + */ + +%{ +#include <sys/param.h> +#include <sys/ioctl.h> +#include <sys/socket.h> + +#include <string.h> + +#include <net/if.h> +#include <net/if_var.h> + +#include <netinet/in.h> +#include <netinet/in_var.h> +#include <netinet/icmp6.h> +#include "y.tab.h" + +int lineno = 1; + +#define LINEBUF_SIZE 1000 +char linebuf[LINEBUF_SIZE]; +%} + +/* common section */ +nl \n +ws [ \t]+ +digit [0-9] +letter [0-9A-Za-z] +hexdigit [0-9A-Fa-f] +special [()+\|\?\*,] +dot \. +hyphen \- +colon \: +slash \/ +bcl \{ +ecl \} +semi \; +usec {dot}{digit}{1,6} +comment \#.* +qstring \"[^"]*\" +decstring {digit}+ +hexpair {hexdigit}{hexdigit} +hexstring 0[xX]{hexdigit}+ +octetstring {octet}({dot}{octet})+ +ipv4addr {digit}{1,3}({dot}{digit}{1,3}){0,3} +ipv6addr {hexdigit}{0,4}({colon}{hexdigit}{0,4}){2,7} +ipaddrmask {slash}{digit}{1,3} +keyword {letter}{letter}+ +name {letter}(({letter}|{digit}|{hyphen})*({letter}|{digit}))* +hostname {name}(({dot}{name})+{dot}?)? + +timeval {digit}{0,2} +days d{timeval} +hours h{timeval} +minutes m{timeval} +seconds s{timeval} + +mprefix match_prefix|match-prefix +uprefix use_prefix|use-prefix + +%% + /* rrenumd keywords */ +debug { + return(DEBUG_CMD); + } +dest { + return(DEST_CMD); + } +retry { + return(RETRY_CMD); + } +seqnum { + return(SEQNUM_CMD); + } +add { + yylval.num = RPM_PCO_ADD; + return(ADD); + } +change { + yylval.num = RPM_PCO_CHANGE; + return(CHANGE); + } +setglobal { + yylval.num = RPM_PCO_SETGLOBAL; + return(SETGLOBAL); + } +{mprefix} { + return(MATCH_PREFIX_CMD); + } +maxlen { + return(MAXLEN_CMD); + } +minlen { + return(MINLEN_CMD); + } +{uprefix} { + return(USE_PREFIX_CMD); + } +keeplen { + return(KEEPLEN_CMD); + } + +vltime { + return(VLTIME_CMD); + } +pltime { + return(PLTIME_CMD); + } +raf_onlink { + return(RAF_ONLINK_CMD); + } +raf_auto { + return(RAF_AUTO_CMD); + } +rrf_decrvalid { + return(RAF_DECRVALID_CMD); + } +rrf_decrprefd { + return(RAF_DECRPREFD_CMD); + } +{days} { + yytext++; + yylval.num = atoi(yytext); + return(DAYS); + } +{hours} { + yytext++; + yylval.num = atoi(yytext); + return(HOURS); + } +{minutes} { + yytext++; + yylval.num = atoi(yytext); + return(MINUTES); + } +{seconds} { + yytext++; + yylval.num = atoi(yytext); + return(SECONDS); + } +infinity { + return(INFINITY); + } + +on { + yylval.num = 1; + return(ON); + } +off { + yylval.num = 0; + return(OFF); + } + + /* basic rules */ +{ws} ; +{nl} { + lineno++; + } +{semi} { + return EOS; + } +{bcl} { + return BCL; + } +{ecl} { + return ECL; + } +{qstring} { + yylval.cs.cp = yytext; + yylval.cs.len = yyleng; + return QSTRING; + } +{decstring} { + yylval.cs.cp = yytext; + yylval.cs.len = yyleng; + return DECSTRING; + } +{name} { + yylval.cs.cp = yytext; + yylval.cs.len = yyleng; + return NAME; + } +{ipv6addr} { + memset(&yylval.addr6, 0, sizeof(struct in6_addr)); + if (inet_pton(AF_INET6, yytext, + &yylval.addr6) == 1) { + return IPV6ADDR; + } else { + return ERROR; + } + } +{ipaddrmask} { + yytext++; + yylval.num = atoi(yytext); + return(PREFIXLEN); + } +{hostname} { + yylval.cs.cp = yytext; + yylval.cs.len = yyleng; + return HOSTNAME; + } +%% + +int parse(FILE **fp) +{ + yyin = *fp; + + if(yyparse()) + return(-1); + + return(0); + +} + +void +yyerror(const char *s) +{ + printf("%s: at %s in line %d\n", s, yytext, lineno); +} diff --git a/usr.sbin/rrenumd/parser.y b/usr.sbin/rrenumd/parser.y new file mode 100644 index 0000000..eecc7bb --- /dev/null +++ b/usr.sbin/rrenumd/parser.y @@ -0,0 +1,637 @@ +/* + * Copyright (C) 1995, 1996, 1997, and 1998 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. + * + * $FreeBSD$ + */ + +%{ +#include <sys/param.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <sys/uio.h> + +#include <net/if.h> +#include <net/if_var.h> + +#include <netinet/in.h> +#include <netinet/in_var.h> +#include <netinet/icmp6.h> + +#include <netdb.h> +#include <string.h> + +#include "rrenumd.h" + +struct config_is_set { + u_short cis_dest : 1; +} cis; + +struct dst_list *dl_head; +struct payload_list *pl_head, ple_cur; +u_int retry; +char errbuf[LINE_MAX]; + +extern int lineno; +extern void yyerror __P((const char *s)); +static struct payload_list * pllist_lookup __P((int seqnum)); +static void pllist_enqueue __P((struct payload_list *pl_entry)); + +#define MAX_RETRYNUM 10 /* upper limit of retry in this rrenumd program */ +#define MAX_SEQNUM 256 /* upper limit of seqnum in this rrenumd program */ +#define NOSPEC -1 + +%} + +%union { + u_long num; + struct { + char *cp; + int len; + } cs; + struct in_addr addr4; + struct in6_addr addr6; + struct { + struct in6_addr addr; + u_char plen; + } prefix; + struct dst_list *dl; + struct payload_list *pl; + struct sockaddr *sa; +} + +%token <num> ADD CHANGE SETGLOBAL +%token DEBUG_CMD DEST_CMD RETRY_CMD SEQNUM_CMD +%token MATCH_PREFIX_CMD MAXLEN_CMD MINLEN_CMD +%token USE_PREFIX_CMD KEEPLEN_CMD +%token VLTIME_CMD PLTIME_CMD +%token RAF_ONLINK_CMD RAF_AUTO_CMD RAF_DECRVALID_CMD RAF_DECRPREFD_CMD +%token <num> DAYS HOURS MINUTES SECONDS INFINITY +%token <num> ON OFF +%token BCL ECL EOS ERROR +%token <cs> NAME HOSTNAME QSTRING DECSTRING +%token <addr4> IPV4ADDR +%token <addr6> IPV6ADDR +%token <num> PREFIXLEN + +%type <num> retrynum seqnum rrenum_cmd +%type <num> prefixlen maxlen minlen keeplen vltime pltime +%type <num> lifetime days hours minutes seconds +%type <num> decstring +%type <num> raf_onlink raf_auto raf_decrvalid raf_decrprefd flag +%type <dl> dest_addrs dest_addr sin6 +%type <pl> rrenum_statement +%type <cs> ifname +%type <prefix> prefixval + +%% +config: + /* empty */ + | statements + ; + +statements: + statement + | statements statement + ; + +statement: + debug_statement + | destination_statement + | rrenum_statement_without_seqnum + | rrenum_statement_with_seqnum + | error EOS + { + yyerrok; + } + | EOS + ; + +debug_statement: + DEBUG_CMD flag EOS + { +#ifdef YYDEBUG + yydebug = $2; +#endif /* YYDEBUG */ + } + ; + +destination_statement: + DEST_CMD dest_addrs retrynum EOS + { + dl_head = $2; + retry = $3; + } + ; + +dest_addrs: + dest_addr + | dest_addrs dest_addr + { + $2->dl_next = $1; + $$ = $2; + } + ; + +dest_addr : + sin6 + { + with_v6dest = 1; + } + | sin6 ifname + { + struct sockaddr_in6 *sin6; + + sin6 = (struct sockaddr_in6 *)$1->dl_dst; + sin6->sin6_scope_id = if_nametoindex($2.cp); + with_v6dest = 1; + $$ = $1; + } + | HOSTNAME + { + struct sockaddr_storage *ss; + struct addrinfo hints, *res; + int error; + + memset(&hints, 0, sizeof(hints)); + hints.ai_flags = AI_CANONNAME; + hints.ai_family = AF_INET6; + hints.ai_socktype = SOCK_RAW; + hints.ai_protocol = 0; + error = getaddrinfo($1.cp, 0, &hints, &res); + if (error) { + sprintf(errbuf, "name resolution failed for %s" + ":%s", $1, gai_strerror(error)); + yyerror(errbuf); + } + ss = (struct sockaddr_storage *)malloc(sizeof(*ss)); + memset(ss, 0, sizeof(*ss)); + memcpy(ss, res->ai_addr, res->ai_addr->sa_len); + freeaddrinfo(res); + + $$ = (struct dst_list *) + malloc(sizeof(struct dst_list)); + memset($$, 0, sizeof(struct dst_list)); + $$->dl_dst = (struct sockaddr *)ss; + } + ; + +sin6: + IPV6ADDR + { + struct sockaddr_in6 *sin6; + + sin6 = (struct sockaddr_in6 *)malloc(sizeof(*sin6)); + memset(sin6, 0, sizeof(*sin6)); + sin6->sin6_len = sizeof(*sin6); + sin6->sin6_family = AF_INET6; + sin6->sin6_addr = $1; + + $$ = (struct dst_list *) + malloc(sizeof(struct dst_list)); + memset($$, 0, sizeof(struct dst_list)); + $$->dl_dst = (struct sockaddr *)sin6; + } + +ifname: + NAME + { + $$.cp = strdup($1.cp); + $$.len = $1.len; + } + | QSTRING + { + $1.cp[$1.len - 1] = 0; + $$.cp = strdup(&$1.cp[1]); + $$.len = $1.len - 2; + } + ; + +retrynum: + /* empty */ + { + $$ = 2; + } + | RETRY_CMD decstring + { + if ($2 > MAX_RETRYNUM) + $2 = MAX_RETRYNUM; + $$ = $2; + } + ; + +rrenum_statement_with_seqnum: + SEQNUM_CMD seqnum + { + if (pllist_lookup($2)) { + sprintf(errbuf, "duplicate seqnum %d specified" + " at %d", $2, lineno); + yyerror(errbuf); + } + } + BCL rrenum_statement EOS ECL EOS + { + $5->pl_irr.rr_seqnum = $2; + pllist_enqueue($5); + } + ; + +seqnum: + /* empty */ + { + $$ = 0; + } + | decstring + { + if ($1 > MAX_SEQNUM) { + sprintf(errbuf, "seqnum %d is illegal for this" + " program. should be between 0 and %d", + $1, MAX_SEQNUM); + yyerror(errbuf); + } + $$ = $1; + } + ; + +rrenum_statement_without_seqnum: + rrenum_statement EOS + { + if (pllist_lookup(0)) { + sprintf(errbuf, "duplicate seqnum %d specified" + " at %d", 0, lineno); + yyerror(errbuf); + } + $1->pl_irr.rr_seqnum = 0; + pllist_enqueue($1); + } + ; + +rrenum_statement: + match_prefix_definition use_prefix_definition + { + $$ = (struct payload_list *) + malloc(sizeof(struct payload_list)); + memcpy($$, &ple_cur, sizeof(ple_cur)); + } + ; + +match_prefix_definition: + rrenum_cmd MATCH_PREFIX_CMD prefixval maxlen minlen + { + struct icmp6_router_renum *irr; + struct rr_pco_match *rpm; + + irr = (struct icmp6_router_renum *)&ple_cur.pl_irr; + rpm = (struct rr_pco_match *)(irr + 1); + memset(rpm, 0, sizeof(*rpm)); + + rpm->rpm_code = $1; + rpm->rpm_prefix = $3.addr; + rpm->rpm_matchlen = $3.plen; + rpm->rpm_maxlen = $4; + rpm->rpm_minlen = $5; + } + ; + +rrenum_cmd: + /* empty */ + { + $$ = RPM_PCO_ADD; + } + | ADD + | CHANGE + | SETGLOBAL + ; + +prefixval: + IPV6ADDR prefixlen + { + $$.addr = $1; + $$.plen = $2; + } + ; + +prefixlen: + /* empty */ + { + $$ = 64; + } + | PREFIXLEN + ; + +maxlen: + /* empty */ + { + $$ = 128; + } + | MAXLEN_CMD decstring + { + if ($2 > 128) + $2 = 128; + $$ = $2; + } + ; + +minlen: + /* empty */ + { + $$ = 0; + } + | MINLEN_CMD decstring + { + if ($2 > 128) + $2 = 128; + $$ = $2; + } + ; + +use_prefix_definition: + /* empty */ + { + struct icmp6_router_renum *irr; + struct rr_pco_match *rpm; + struct rr_pco_use *rpu; + + irr = (struct icmp6_router_renum *)&ple_cur.pl_irr; + rpm = (struct rr_pco_match *)(irr + 1); + rpu = (struct rr_pco_use *)(rpm + 1); + memset(rpu, 0, sizeof(*rpu)); + } + | USE_PREFIX_CMD prefixval keeplen use_prefix_values + { + struct icmp6_router_renum *irr; + struct rr_pco_match *rpm; + struct rr_pco_use *rpu; + + irr = (struct icmp6_router_renum *)&ple_cur.pl_irr; + rpm = (struct rr_pco_match *)(irr + 1); + rpu = (struct rr_pco_use *)(rpm + 1); + + rpu->rpu_prefix = $2.addr; + rpu->rpu_uselen = $2.plen; + rpu->rpu_keeplen = $3; + } + ; + +use_prefix_values: + /* empty */ + { + struct icmp6_router_renum *irr; + struct rr_pco_match *rpm; + struct rr_pco_use *rpu; + + irr = (struct icmp6_router_renum *)&ple_cur.pl_irr; + rpm = (struct rr_pco_match *)(irr + 1); + rpu = (struct rr_pco_use *)(rpm + 1); + memset(rpu, 0, sizeof(*rpu)); + + rpu->rpu_vltime = DEF_VLTIME; + rpu->rpu_pltime = DEF_PLTIME; + rpu->rpu_ramask = 0; + rpu->rpu_flags = 0; + } + | BCL vltime pltime raf_onlink raf_auto raf_decrvalid raf_decrprefd ECL + { + struct icmp6_router_renum *irr; + struct rr_pco_match *rpm; + struct rr_pco_use *rpu; + + irr = (struct icmp6_router_renum *)&ple_cur.pl_irr; + rpm = (struct rr_pco_match *)(irr + 1); + rpu = (struct rr_pco_use *)(rpm + 1); + memset(rpu, 0, sizeof(*rpu)); + + rpu->rpu_vltime = $2; + rpu->rpu_pltime = $3; + if ($4 == NOSPEC) + rpu->rpu_ramask &= + ~ICMP6_RR_PCOUSE_RAFLAGS_ONLINK; + else { + rpu->rpu_ramask |= + ICMP6_RR_PCOUSE_RAFLAGS_ONLINK; + if ($4 == ON) + rpu->rpu_raflags |= + ICMP6_RR_PCOUSE_RAFLAGS_ONLINK; + else + rpu->rpu_raflags &= + ~ICMP6_RR_PCOUSE_RAFLAGS_ONLINK; + } + if ($5 == NOSPEC) + rpu->rpu_ramask &= + ICMP6_RR_PCOUSE_RAFLAGS_AUTO; + else { + rpu->rpu_ramask |= + ICMP6_RR_PCOUSE_RAFLAGS_AUTO; + if ($5 == ON) + rpu->rpu_raflags |= + ICMP6_RR_PCOUSE_RAFLAGS_AUTO; + else + rpu->rpu_raflags &= + ~ICMP6_RR_PCOUSE_RAFLAGS_AUTO; + } + rpu->rpu_flags = 0; + if ($6 == ON) + rpu->rpu_flags |= + ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME; + if ($7 == ON) + rpu->rpu_flags |= + ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME; + } + ; + +keeplen: + /* empty */ + { + $$ = 0; + } + | KEEPLEN_CMD decstring + { + if ($2 > 128) + $2 = 128; + $$ = $2; + } + ; + + +vltime: + /* empty */ + { + $$ = DEF_VLTIME; + } + | VLTIME_CMD lifetime + { + $$ = htonl($2); + } + ; + +pltime: + /* empty */ + { + $$ = DEF_PLTIME; + } + | PLTIME_CMD lifetime + { + $$ = htonl($2); + } + +raf_onlink: + /* empty */ + { + $$ = NOSPEC; + } + | RAF_ONLINK_CMD flag + { + $$ = $2; + } + ; + +raf_auto: + /* empty */ + { + $$ = NOSPEC; + } + | RAF_AUTO_CMD flag + { + $$ = $2; + } + ; + +raf_decrvalid: + /* empty */ + { + $$ = NOSPEC; + } + | RAF_DECRVALID_CMD flag + { + $$ = $2; + } + ; + +raf_decrprefd: + /* empty */ + { + $$ = NOSPEC; + } + | RAF_DECRPREFD_CMD flag + { + $$ = $2; + } + ; + +flag: + ON + | OFF + ; + +lifetime: + decstring + | INFINITY + { + $$ = 0xffffffff; + } + | days hours minutes seconds + { + int d, h, m, s; + + d = $1 * 24 * 60 * 60; + h = $2 * 60 * 60; + m = $3 * 60; + s = $4; + $$ = d + h + m + s; + } + ; + +days: + /* empty */ + { + $$ = 0; + } + | DAYS + ; + +hours: + /* empty */ + { + $$ = 0; + } + | HOURS + ; + +minutes: + /* empty */ + { + $$ = 0; + } + | MINUTES + ; + +seconds: + /* empty */ + { + $$ = 0; + } + | SECONDS + ; + +decstring: + DECSTRING + { + int dval; + + dval = atoi($1.cp); + $$ = dval; + } + ; + +%% + +static struct payload_list * +pllist_lookup(int seqnum) +{ + struct payload_list *pl; + for (pl = pl_head; pl && pl->pl_irr.rr_seqnum != seqnum; + pl = pl->pl_next) + continue; + return (pl); +} + +static void +pllist_enqueue(struct payload_list *pl_entry) +{ + struct payload_list *pl, *pl_last; + if (pl_head == NULL) { + pl_head = pl_entry; + return; + } + for (pl = pl_head; + pl && pl->pl_irr.rr_seqnum < pl_entry->pl_irr.rr_seqnum; + pl_last = pl, pl = pl->pl_next) + continue; + pl_last->pl_next = pl_entry; + + return; +} diff --git a/usr.sbin/rrenumd/rrenumd.8 b/usr.sbin/rrenumd/rrenumd.8 new file mode 100644 index 0000000..aa7ae6b --- /dev/null +++ b/usr.sbin/rrenumd/rrenumd.8 @@ -0,0 +1,95 @@ +.\" Copyright (C) 1995, 1996, 1997, and 1998 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. +.\" +.\" $Id: rrenumd.8,v 1.1.1.1 1999/08/08 23:31:38 itojun Exp $ +.\" $FreeBSD$ +.\" +.Dd Sep 7, 1998 +.Dt RRENUMD 8 +.Os KAME +.Sh NAME +.Nm rrenumd +.Nd router renumbering daemon +.Sh SYNOPSIS +.Nm +.Oo +.Fl c Ar conf_file | Fl s +.Oc +.Op Fl P Ar policy +.Op Fl df +.Sh DESCRIPTION +.Nm Rrenumd +assigns prefixes to subnets inside the site, or renumbers them. +.Pp +The program will daemonize itself on invocation. +It reads configuration information from standard input if +.Fl s +is specified, or from +.Ar conf_file +if +.Fl c Ar conf_file +is specified. +.Pp +The contents of configuration information are described in +.Xr rrenumd.conf 5 . +.Pp +After successful configuration, +.Nm +sends router renumbering +messages periodically to configured destinations. +Messages contain prefixes configured to be renumbered. +.Bl -tag -width indent +.\" +.It Fl d +Debug mode. +.It Fl f +Foreground mode. +Do not become daemon. +.It Fl s +Script mode. +Configuration information is obtained from standard input. +.It Fl P Ar policy +.Ar policy +specifies IPsec policy for the rrenumd session. +For details please refer to +.Xr ipsec 4 +and +.Xr ipsec_set_policy 3 . +.It Fl c Ar conf_file +Specify a configuration file where configuration information is kept. +.Sh RETURN VALUES +The program exits with 0 on success, and non-zero on failures. +.El +.Sh SEE ALSO +.Xr daemon 3 +.Xr rrenumd.conf 5 , +.Sh HISTORY +The +.Nm +command first appeared in KAME IPv6 protocol stack kit. +.\" .Sh BUGS +.\" (to be written) diff --git a/usr.sbin/rrenumd/rrenumd.c b/usr.sbin/rrenumd/rrenumd.c new file mode 100644 index 0000000..ced5afc --- /dev/null +++ b/usr.sbin/rrenumd/rrenumd.c @@ -0,0 +1,460 @@ +/* + * Copyright (C) 1995, 1996, 1997, and 1998 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. + * + * $FreeBSD$ + */ + +#include <sys/param.h> +#include <sys/socket.h> +#include <sys/uio.h> +#include <sys/time.h> + +#include <string.h> + +#include <net/route.h> + +#include <netinet/in_systm.h> +#include <netinet/in.h> +#include <netinet/ip.h> +#include <netinet/ip6.h> +#include <netinet/icmp6.h> + +#ifdef IPSEC +#include <netinet6/ipsec.h> +#endif + +#include <stdio.h> +#include <errno.h> +#include <stdlib.h> +#include <unistd.h> +#include <syslog.h> + +#include "rrenumd.h" + +#define LL_ALLROUTERS "ff02::2" +#define SL_ALLROUTERS "ff05::2" + +#ifndef IN6_IS_SCOPE_LINKLOCAL +#define IN6_IS_SCOPE_LINKLOCAL(a) \ + ((IN6_IS_ADDR_LINKLOCAL(a)) || \ + (IN6_IS_ADDR_MC_LINKLOCAL(a))) +#endif /* IN6_IS_SCOPE_LINKLOCAL */ + +struct flags { + u_long debug : 1; + u_long fg : 1; +#ifdef IPSEC +#ifdef IPSEC_POLICY_IPSEC + u_long policy : 1; +#endif /* IPSEC_POLICY_IPSEC */ +#endif /*IPSEC*/ +}; + +struct msghdr sndmhdr; +struct msghdr rcvmhdr; +struct sockaddr_in6 from; +struct sockaddr_in6 sin6_ll_allrouters; + +int s6; +int with_v6dest; +struct in6_addr prefix; /* ADHOC */ +int prefixlen = 64; /* ADHOC */ + +extern int parse(FILE **fp); + +/* Print usage. Don't call this after daemonized. */ +static void +show_usage() +{ + fprintf(stderr, "usage: rrenumd [-c conf_file|-s] [-df" +#ifdef IPSEC +#ifdef IPSEC_POLICY_IPSEC + "] [-P policy" +#endif /* IPSEC_POLICY_IPSEC */ +#endif /* IPSEC */ + "]\n"); + exit(1); +} + +void +init_sin6(struct sockaddr_in6 *sin6, const char *addr_ascii) +{ + memset(sin6, 0, sizeof(*sin6)); + sin6->sin6_len = sizeof(*sin6); + sin6->sin6_family = AF_INET6; + if (inet_pton(AF_INET6, addr_ascii, &sin6->sin6_addr) != 1) + ; /* XXX do something */ +} + +void +init_globals() +{ + static struct iovec rcviov; + static u_char rprdata[4500]; /* maximal MTU of connected links */ + static u_char rcvcmsgbuf[CMSG_SPACE(sizeof(struct in6_pktinfo)) + + CMSG_SPACE(sizeof(int))]; + static u_char sndcmsgbuf[CMSG_SPACE(sizeof(struct in6_pktinfo)) + + CMSG_SPACE(sizeof(int))]; + + /* init ll_allrouters */ + init_sin6(&sin6_ll_allrouters, LL_ALLROUTERS); + + /* initialize msghdr for receiving packets */ + rcviov.iov_base = (caddr_t)rprdata; + rcviov.iov_len = sizeof(rprdata); + rcvmhdr.msg_namelen = sizeof(struct sockaddr_in6); + rcvmhdr.msg_iov = &rcviov; + rcvmhdr.msg_iovlen = 1; + rcvmhdr.msg_control = (caddr_t)rcvcmsgbuf; + rcvmhdr.msg_controllen = sizeof(rcvcmsgbuf); + + /* initialize msghdr for sending packets */ + sndmhdr.msg_namelen = sizeof(struct sockaddr_in6); + sndmhdr.msg_iovlen = 1; + sndmhdr.msg_control = (caddr_t)sndcmsgbuf; + sndmhdr.msg_controllen = sizeof(sndcmsgbuf); +} + +void +config(FILE **fpp) +{ + struct payload_list *pl; + struct iovec *iov; + struct icmp6_router_renum *irr; + struct rr_pco_match *rpm; + + if (parse(fpp) < 0) { + syslog(LOG_ERR, "<%s> parse failed", __FUNCTION__); + exit(1); + } + + /* initialize fields not configured by parser */ + for (pl = pl_head; pl; pl = pl->pl_next) { + iov = (struct iovec *)&pl->pl_sndiov; + irr = (struct icmp6_router_renum *)&pl->pl_irr; + rpm = (struct rr_pco_match *)&pl->pl_rpm; + + irr->rr_type = ICMP6_ROUTER_RENUMBERING; + irr->rr_code = 0; + /* + * now we don't support multiple PCOs in a rr message. + * so segment number is not supported. + */ + /* TODO: rr flags config in parser */ + irr->rr_flags |= ICMP6_RR_FLAGS_SPECSITE; + /* TODO: max delay config in parser */ + + /* + * means only 1 use_prefix is contained as router-renum-05.txt. + * now we don't support multiple PCOs in a rr message, + * nor multiple use_prefix in one PCO. + */ + rpm->rpm_len = 4*1 +3; + rpm->rpm_ordinal = 0; + iov->iov_base = (caddr_t)irr; + iov->iov_len = sizeof(struct icmp6_router_renum) + + sizeof(struct rr_pco_match) + + sizeof(struct rr_pco_use); + } +} + +void +sock6_open(struct flags *flags +#ifdef IPSEC_POLICY_IPSEC + , char *policy +#endif /* IPSEC_POLICY_IPSEC */ + ) +{ + struct icmp6_filter filt; + int on, optval; + + if (with_v6dest == 0) + return; + if (with_v6dest && + (s6 = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) { + syslog(LOG_ERR, "<%s> socket(v6): %s", __FUNCTION__, + strerror(errno)); + exit(1); + } + + /* join all routers multicast addresses, not necessary? */ + + /* set icmpv6 filter */ + ICMP6_FILTER_SETBLOCKALL(&filt); + ICMP6_FILTER_SETPASS(ICMP6_ROUTER_RENUMBERING, &filt); + if (setsockopt(s6, IPPROTO_ICMPV6, ICMP6_FILTER, &filt, + sizeof(filt)) < 0) { + syslog(LOG_ERR, "<%s> IICMP6_FILTER: %s", + __FUNCTION__, strerror(errno)); + exit(1); + } + + /* specify to tell receiving interface */ + on = 1; + if (setsockopt(s6, IPPROTO_IPV6, IPV6_PKTINFO, &on, + sizeof(on)) < 0) { + syslog(LOG_ERR, "<%s> IPV6_PKTINFO: %s", + __FUNCTION__, strerror(errno)); + exit(1); + } + +#ifdef IPSEC +#ifdef IPSEC_POLICY_IPSEC + if (flags->policy) { + char *buf; + buf = ipsec_set_policy(policy, strlen(policy)); + if (buf == NULL) + errx(1, ipsec_strerror()); + /* XXX should handle in/out bound policy. */ + if (setsockopt(s6, IPPROTO_IPV6, IPV6_IPSEC_POLICY, + buf, ipsec_get_policylen(buf)) < 0) + err(1, NULL); + free(buf); + } +#endif /* IPSEC_POLICY_IPSEC */ +#endif /* IPSEC */ + + return; +} + +void +rrenum_output(struct payload_list *pl, struct dst_list *dl) +{ + int i, msglen = 0; + struct cmsghdr *cm; + struct in6_pktinfo *pi; + struct icmp6_router_renum *rr; + struct sockaddr_in6 *sin6 = NULL; + + sndmhdr.msg_name = (caddr_t)dl->dl_dst; + if (dl->dl_dst->sa_family == AF_INET6) + sin6 = (struct sockaddr_in6 *)dl->dl_dst; + + if (sin6 != NULL && + IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr)) { + int hoplimit = 255; + + cm = CMSG_FIRSTHDR(&sndmhdr); + /* specify the outgoing interface */ + cm->cmsg_level = IPPROTO_IPV6; + cm->cmsg_type = IPV6_PKTINFO; + cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); + pi = (struct in6_pktinfo *)CMSG_DATA(cm); + memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr)); /*XXX*/ + pi->ipi6_ifindex = sin6->sin6_scope_id; + msglen += CMSG_SPACE(sizeof(struct in6_pktinfo)); + + /* specify the hop limit of the packet if dest is link local */ + /* not defined by router-renum-05.txt, but maybe its OK */ + cm = CMSG_NXTHDR(&sndmhdr, cm); + cm->cmsg_level = IPPROTO_IPV6; + cm->cmsg_type = IPV6_HOPLIMIT; + cm->cmsg_len = CMSG_LEN(sizeof(int)); + memcpy(CMSG_DATA(cm), &hoplimit, sizeof(int)); + msglen += CMSG_SPACE(sizeof(int)); + } + sndmhdr.msg_controllen = msglen; + if (sndmhdr.msg_controllen == 0) + sndmhdr.msg_control = 0; + + sndmhdr.msg_iov = &pl->pl_sndiov; + i = sendmsg(s6, &sndmhdr, 0); + + if (i < 0 || i != sndmhdr.msg_iov->iov_len) + syslog(LOG_ERR, "<%s> sendmsg: %s", __FUNCTION__, + strerror(errno)); +} + +void +rrenum_snd_eachdst(struct payload_list *pl) +{ + struct dst_list *dl; + + for (dl = dl_head; dl; dl = dl->dl_next) { + rrenum_output(pl, dl); + } +} + +void +rrenum_snd_fullsequence() +{ + struct payload_list *pl; + + for (pl = pl_head; pl; pl = pl->pl_next) { + rrenum_snd_eachdst(pl); + } +} + +void +rrenum_input(int s) +{ + int i; + struct icmp6_router_renum *rr; + + /* get message */ + if ((i = recvmsg(s, &rcvmhdr, 0)) < 0) { + syslog(LOG_ERR, "<%s> recvmsg: %s", __FUNCTION__, + strerror(errno)); + return; + } + if (i < sizeof(struct icmp6_router_renum)) { + syslog(LOG_ERR, "<%s> packet size(%d) is too short", + __FUNCTION__, i); + return; + } + rr = (struct icmp6_router_renum *)rcvmhdr.msg_iov->iov_base; + + switch(rr->rr_code) { + case ICMP6_ROUTER_RENUMBERING_COMMAND: + /* COMMAND will be processed by rtadvd */ + break; + case ICMP6_ROUTER_RENUMBERING_RESULT: + /* TODO: receiving result message */ + break; + default: + syslog(LOG_ERR, "<%s> received unknown code %d" + __FUNCTION__, rr->rr_code); + break; + } +} + +int +main(int argc, char *argv[]) +{ + char *cfile = NULL; + FILE *fp = stdin; + fd_set fdset; + struct timeval timeout; + int ch, i, maxfd = 0, send_counter = 0; + struct flags flags; + struct payload_list *pl; +#ifdef IPSEC_POLICY_IPSEC + char *policy = NULL; +#endif + + memset(&flags, 0, sizeof(flags)); + openlog(*argv, LOG_PID, LOG_DAEMON); + + /* get options */ + while ((ch = getopt(argc, argv, "c:sdf" +#ifdef IPSEC +#ifdef IPSEC_POLICY_IPSEC + "P:" +#endif /* IPSEC_POLICY_IPSEC */ +#endif /* IPSEC */ + )) != -1){ + switch (ch) { + case 'c': + if((fp = fopen(optarg, "r")) == NULL) { + syslog(LOG_ERR, + "<%s> config file %s open failed", + __FUNCTION__, optarg); + exit(1); + } + break; + case 's': + fp = stdin; + break; + case 'd': + flags.debug = 1; + break; + case 'f': + flags.fg = 1; + break; +#ifdef IPSEC +#ifdef IPSEC_POLICY_IPSEC + case 'P': + flags.policy = 1; + policy = strdup(optarg); + break; +#endif /* IPSEC_POLICY_IPSEC */ +#endif /*IPSEC*/ + default: + show_usage(); + } + } + argc -= optind; + argv += optind; + + /* set log level */ + if (flags.debug == 0) + (void)setlogmask(LOG_UPTO(LOG_ERR)); + if (flags.debug == 1) + (void)setlogmask(LOG_UPTO(LOG_INFO)); + + /* init global variables */ + init_globals(); + + config(&fp); + + sock6_open(&flags +#ifdef IPSEC_POLICY_IPSEC + , policy +#endif /* IPSEC_POLICY_IPSEC */ + ); + + if (!flags.fg) + daemon(0, 0); + + FD_ZERO(&fdset); + if (with_v6dest) { + FD_SET(s6, &fdset); + if (s6 > maxfd) + maxfd = s6; + } + + /* ADHOC: timeout each 30seconds */ + memset(&timeout, 0, sizeof(timeout)); + timeout.tv_sec = 30; + + /* init temporal payload_list and send_counter*/ + pl = pl_head; + send_counter = retry + 1; + while (1) { + struct fd_set select_fd = fdset; /* reinitialize */ + + if ((i = select(maxfd + 1, &select_fd, NULL, NULL, + &timeout)) < 0){ + syslog(LOG_ERR, "<%s> select: %s", + __FUNCTION__, strerror(errno)); + continue; + } + if (i == 0) { /* timeout */ + if (pl == NULL) + exit(0); + rrenum_snd_eachdst(pl); + send_counter--; + if (send_counter == 0) { + pl = pl->pl_next; + send_counter = retry + 1; + } + } + if (FD_ISSET(s6, &select_fd)) + rrenum_input(s6); + } +} diff --git a/usr.sbin/rrenumd/rrenumd.conf.5 b/usr.sbin/rrenumd/rrenumd.conf.5 new file mode 100644 index 0000000..76453cb --- /dev/null +++ b/usr.sbin/rrenumd/rrenumd.conf.5 @@ -0,0 +1,330 @@ +.\" Copyright (C) 1995, 1996, 1997, and 1998 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. +.\" +.\" $Id: rrenumd.conf.5,v 1.1.1.1 1999/08/08 23:31:39 itojun Exp $ +.\" $FreeBSD$ +.\" +.Dd Nov 5, 1998 +.Dt RRENUMD.CONF 5 +.Os KAME +.Sh NAME +.\" +.Nm rrenumd.conf +.Nd configuration file for router renumbering daemon +.\" +.Sh DESCRIPTION +The rrenumd config file describes how the router renumbering packet +must be constructed and to which destinations it should be sent. +This file consists of a sequence of statements terminated by a semi-colon (`;'). +Statements are composed of tokens +separated by white space, which can be any combination of blanks, tabs +and newlines. +This structure simplifies identification of +the parts of the configuration associated with each other. +Lines beginning with +.Ql # +are comments. +.\" +.Sh Meta Syntax +Keywords and special characters that the parser expects exactly are +displayed using the +.Ic bold +font. +Parameters are specifying with +.Ar underline . +Parameters shown in +square brackets (`[' and `]') are used to show optional +keywords and parameters. +The vertical bar (`|') is used to indicate +between a choice of optional parameters. +Parentheses (`(' and +`)') are used to group keywords and parameters when necessary. +.\" +.Sh Interface specification +There are some statements that may or have to specify interface. +Interfaces are specified in the form of "name unit", such as +.Ar lo0 +and +.Ar ep1. +.\" +.Sh Configuration Statements +.Bl -tag -width Ds +.\" +.It Ic debug on|off ; +Enables configuration file parser debugging. +If +.Ic on +is specified, +then debugging is enabled, +If +.Ic off +is specified, +then debugging is disabled. It is disabled by default. +.\" +.It Ic dest Ar dest-list Op Ar retrycmd ; +Specifies destinations to which router renumbering messages should be +sent. +.Ar dest-list +can be any combination of single or multiple numerical IPv6 addrs, +or Full Qualified Domain Names. +.Ar retrycmd +has following syntax. + +.\" +.Bl -tag -width Ds -compact +.It Ic retry Ar retry-num +.Ar retry-num +specifies how many router renumbering messages are sent repeatedly. +.El +.It Op Ic add|change|setglobal +.Cm match-prefix Ar match-prefix-val +.Op /match-prefix-len +.Op Cm maxlen Ar maxlen-val +.Op Cm minlen Ar minlen-val +.Op Cm use-prefix Ar use-prefix-val +.Op /use-prefix-len +.Op Cm keeplen Ar keeplen-val +.Op Ar use-prefix-values ; +.Pp +Specifies contents of sending router renumbering message with seqnum 0. +If +.Cm add|change|setglobal +is not specified, then +.Cm add +is assumed. +.Ar use-prefix-values +has following syntax. +.Pp +{ +.Op Cm vltime Ar vltime-val +.Op Cm pltime Ar pltime-val +.Op Cm raf_onlink Cm on|off +.Op Cm raf_auto Cm on|off +.Op Cm rrf_decrprefd Cm on|off +.Op Cm rrf_decrvalid Cm on|off +} +.Pp +Each value has following meaning. +.Pp +.Bl -tag -width Ds -compact +.It Cm match-prefix Ar match-prefix-val Op /match-prefix-len +Specify +.Ar match-prefix-val +that is used for matching with preassigned prefixes to which +.Cm add|change|setglobal +command should be applied. +.Ar /match-prefix-len +Specify the starting part of +.Ar match-prefix-val +to be used for matching with preassigned prefixes, as decimal bit number. +.It Cm maxlen Ar maxlen-val +Specify the maximum length of prefixes which is allowed to be +matched to +.Ar match-prefix-val , +as decimal bit number. +.It Cm minlen Ar minlen-val +Specify the minimum length of prefixes which is allowed to be matched to +.Ar match-prefix-val , +as decimal bit number. +.It Cm use-prefix Ar use-prefix-val Op /usr-prefix-len +Specify +.Ar use-prefix-val +that is used for prefixes to be added on +.Cm add|change|setglobal +command. +.Ar /use-prefix-len +Specify the starting part of +.Ar use-prefix-val +copied to the starting part of prefixes to be added on +.Cm add|change|setglobal +command, as decimal bit number. +.It Cm keeplen Ar keeplen-val +Specify the midium part of +.Ar use-prefix-val +just next to the starting part specified by +.Ar use-prefix-len +, as decimal bit number. +Contiguous bits part in the same bit position of an existent prefix +matched with +.Ar match-prefix-val +is copied to the same bit position of prefixes to be added. +.It Cm vltime Ar vmtime-val +Assign an +.Ar time +as prefix valid life time for a prefix to be added. +Valid value for +.Ar time +is decimal seconds number or special format as "d00h00m00s00", +where 00 can take any decimal number, and "d" means days, "h" means hours, +"m" means minutes, "s" means seconds. And alternatively, special keyword +"infinity" can be also be specified. +.It Cm pltime Ar pltime-val +Assign an +.Ar time +as prefix preferred life time for a prefix to be added. +Valid value for +.Ar time +is same as for +.Ar vltime-val . +.It Cm raf_onlink Cm on|off +Let the prefix to be added to have on-link or off-link nature +for the assigned interface. If +.Cm on +is specified, the prefix have on-link nature. (e.g. the prefix +belong to the link) If +.Cm off +is specified, the prefix have off-link nature. (e.g. the +prefix does not belong to the link) +.It Cm raf_auto Cm on|off +Enable or disable the autonomous address auto configuration +for the prefix to be added. If +.Cm on +is specified, autonomous address auto configuration is +enabled. If +.Cm off +is specified, it is disabled. +.It Cm rrf_decrprefd Cm on|off +Enable or disable the decrementation of the pltime. If +.Cm on +is specified, decrementation of the pltime is enabled. If +.Cm off +is specified, decrementation of the pltime is disabled. +.It Cm rrf_decrvalid Cm on|off +Enable or disable the decrementation of the vltime. If +.Cm on +is specified, decrementation of the vltime is enabled. If +.Cm off +is specified, decrementation of the vltime is disabled. +.El +.\" +.It seqnum Ar seqnum-val { Ar rrenum-cmd } ; +Specifies contents of sending router renumbering message with some +specific seqnum. Multiple of this statement can be specified if they +have different +.Ar seqnum-val +each other. +.Ar rrenum-cmd +has just same syntax with above add|change|setglobal statement. +.El +.\" +.Sh EXAMPLE +For each configuration file example shown below, we suppose +every IPv6 subnet has its own prefix beginning with +fec0:0:0::/48 and with its own subnet number. (in this case, +subnet number is 7th and 8th octet value of the prefix) +.Pp +If you want to assigne prefixes beginning with fec0:1:1::/48 +to each subnet, then following configuration will be enough, +if each of your routers supports IPv6 multicast forwarding. +The subnet number of the existing fec0:0:0::/48 prefix and the +newly assigned fec0:1:1::/48 prefix will be same. +.\" +.Bd -literal -offset indent +dest ff05::2; + +add match-prefix fec0:0:0:: /48 use-prefix fec0:1:1:: /48 keeplen 16; +.Ed +.\" + +If your routers don't support IPv6 multicast forwarding, +you'll need to specify each destination at +.Cm dest +command. +.\" +.Bd -literal -offset indent +dest fec0:0:0:1:260:8ff:fe24:fb3a fec0:0:0:2:200:eff:fe2e:dfe1 fec0:0:0:3:5254:ff:fedc:5217; + +add match-prefix fec0:0:0:: /48 use-prefix fec0:1:1:: /48 keeplen 16; +.Ed +.\" + +If you are going to do renumbering, then following procedure will be natural. +.Bl -enum -offset indent +.It +Assigne new prefix. +.It +Set old prefix lifetimes to some appropriate transition +period. In the followng example we use 1 week for valid +lifetime, and 0 for preferred lifetime. +Also, enable old prefix lifetime expiration. +(By default, it is static and does not expire) +.It +After the transition period, old prefixes should become +invalid, and may have been deleted. +To make sure that they are deleted, send new router +renumbering message, which specifies old prefixes as match +prefix, and no use prefix. +.El +.\" + +The following configuration file will do 1 and 2. +.\" +.Bd -literal -offset indent +dest ff05::2; + +seqnum 0 { + add match-prefix fec0:0:0:: /48 use-prefix fec0:2:2:: /48 keeplen 16; + }; + +seqnum 1 { + change match-prefix fec0:1:1:: /48 use-prefix fec0:1:1:: /48 keeplen 16 vltime d7 pltime 0 rrf_decrvalid on rrf_decrprefd on; + }; +.Ed +.\" + +And the following configuration file will do 3. (should be +used for the router renumbering message to be sent 1 week +afterward) +.\" +.Bd -literal -offset indent +dest ff05::2; + +change match-prefix fec0:1:1:: /48; +.Ed +.\" + +In the above example, only +.Cm add +and +.Cm change +commands are used, and there is no example for +.Cm setglobal +command. +.Cm setglobal +command is almost same with +.Cm change +command except that it deletes all pre-defined IPv6 global address. + +.Sh SEE ALSO +.Xr rrenumd 8 +.Xr prefix 8 +.Sh HISTORY +The +.Nm +configuration file was first appeared in KAME IPv6 protocol stack kit. +.\" .Sh BUGS +.\" (to be written) diff --git a/usr.sbin/rrenumd/rrenumd.h b/usr.sbin/rrenumd/rrenumd.h new file mode 100644 index 0000000..dae2cd0 --- /dev/null +++ b/usr.sbin/rrenumd/rrenumd.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 1998 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by WIDE Project and + * its contributors. + * 4. 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. + * + * $FreeBSD$ + */ + +struct dst_list { + struct dst_list *dl_next; + struct sockaddr *dl_dst; +}; + +extern struct dst_list *dl_head; + +struct payload_list { + struct payload_list *pl_next; + struct iovec pl_sndiov; + struct icmp6_router_renum pl_irr; + struct rr_pco_match pl_rpm; + /* currently, support only 1 rr_pco_use field per packet */ + struct rr_pco_use pl_rpu; +}; + +extern struct payload_list *pl_head; +extern u_int retry; +extern int with_v4dest, with_v6dest; + +#define DEF_VLTIME 2592000 +#define DEF_PLTIME 604800 diff --git a/usr.sbin/rtadvd/Makefile b/usr.sbin/rtadvd/Makefile new file mode 100644 index 0000000..7b5d2a8 --- /dev/null +++ b/usr.sbin/rtadvd/Makefile @@ -0,0 +1,26 @@ +# Copyright (c) 1996 WIDE Project. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modifications, are permitted provided that the above copyright notice +# and this paragraph are duplicated in all such forms and that any +# documentation, advertising materials, and other materials related to +# such distribution and use acknowledge that the software was developed +# by the WIDE Project, Japan. The name of the Project may not be used to +# endorse or promote products derived from this software without +# specific prior written permission. THIS SOFTWARE IS PROVIDED ``AS IS'' +# AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT +# LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE. +# $FreeBSD$ + +PROG= rtadvd +SRCS= rtadvd.c rrenum.c advcap.c if.c config.c timer.c + +CFLAGS+=-DINET6 -DIPSEC +LDADD+= -lcompat -lipsec +DPADD+= ${LIBCOMPAT} ${LIBIPSEC} + +MAN5= rtadvd.conf.5 +MAN8= rtadvd.8 + +.include <bsd.prog.mk> diff --git a/usr.sbin/rtadvd/advcap.c b/usr.sbin/rtadvd/advcap.c new file mode 100644 index 0000000..f0825b5 --- /dev/null +++ b/usr.sbin/rtadvd/advcap.c @@ -0,0 +1,452 @@ +/* + * Copyright (c) 1983 The Regents of the University of California. + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * $FreeBSD$ + */ + +#ifndef lint +static char sccsid[] = "@(#)remcap.c 5.5 (Berkeley) 2/2/91"; +#endif /* not lint */ + +/* + * remcap - routines for dealing with the remote host data base + * + * derived from termcap + */ +#include <sys/types.h> +#include <sys/uio.h> +#include <unistd.h> +#include <fcntl.h> +#include <ctype.h> +#include <stdlib.h> +#include <stdio.h> +#include <syslog.h> +#include <errno.h> +#include <string.h> +#include "pathnames.h" + +#ifndef BUFSIZ +#define BUFSIZ 1024 +#endif +#define MAXHOP 32 /* max number of tc= indirections */ + +#define tgetent agetent +#define tnchktc anchktc +#define tnamatch anamatch +#define tgetnum agetnum +#define tgetflag agetflag +#define tgetstr agetstr + +char *RM; + +/* + * termcap - routines for dealing with the terminal capability data base + * + * BUG: Should use a "last" pointer in tbuf, so that searching + * for capabilities alphabetically would not be a n**2/2 + * process when large numbers of capabilities are given. + * Note: If we add a last pointer now we will screw up the + * tc capability. We really should compile termcap. + * + * Essentially all the work here is scanning and decoding escapes + * in string capabilities. We don't use stdio because the editor + * doesn't, and because living w/o it is not hard. + */ + +static char *tbuf; +static int hopcount; /* detect infinite loops in termcap, init 0 */ + +static char *remotefile; + +extern char *conffile; + +int tgetent __P((char *, char *)); +int getent __P((char *, char *, char *)); +int tnchktc __P((void)); +int tnamatch __P((char *)); +static char *tskip __P((char *)); +int tgetnum __P((char *)); +int tgetflag __P((char *)); +char *tgetstr __P((char *, char **)); +static char *tdecode __P((char *, char **)); + +/* + * Get an entry for terminal name in buffer bp, + * from the termcap file. Parse is very rudimentary; + * we just notice escaped newlines. + */ +int +tgetent(bp, name) + char *bp, *name; +{ + char *cp; + + remotefile = cp = conffile ? conffile : _PATH_RTADVDCONF; + return (getent(bp, name, cp)); +} + +int +getent(bp, name, cp) + char *bp, *name, *cp; +{ + register int c; + register int i = 0, cnt = 0; + char ibuf[BUFSIZ]; + int tf; + + tbuf = bp; + tf = 0; + /* + * TERMCAP can have one of two things in it. It can be the + * name of a file to use instead of /etc/termcap. In this + * case it better start with a "/". Or it can be an entry to + * use so we don't have to read the file. In this case it + * has to already have the newlines crunched out. + */ + if (cp && *cp) { + tf = open(RM = cp, O_RDONLY); + } + if (tf < 0) { + syslog(LOG_WARNING, + "<%s> open: %s", __FUNCTION__, strerror(errno)); + return (-2); + } + for (;;) { + cp = bp; + for (;;) { + if (i == cnt) { + cnt = read(tf, ibuf, BUFSIZ); + if (cnt <= 0) { + close(tf); + return (0); + } + i = 0; + } + c = ibuf[i++]; + if (c == '\n') { + if (cp > bp && cp[-1] == '\\') { + cp--; + continue; + } + break; + } + if (cp >= bp+BUFSIZ) { + write(2,"Remcap entry too long\n", 23); + break; + } else + *cp++ = c; + } + *cp = 0; + + /* + * The real work for the match. + */ + if (tnamatch(name)) { + close(tf); + return (tnchktc()); + } + } +} + +/* + * tnchktc: check the last entry, see if it's tc=xxx. If so, + * recursively find xxx and append that entry (minus the names) + * to take the place of the tc=xxx entry. This allows termcap + * entries to say "like an HP2621 but doesn't turn on the labels". + * Note that this works because of the left to right scan. + */ +int +tnchktc() +{ + register char *p, *q; + char tcname[16]; /* name of similar terminal */ + char tcbuf[BUFSIZ]; + char *holdtbuf = tbuf; + int l; + + p = tbuf + strlen(tbuf) - 2; /* before the last colon */ + while (*--p != ':') + if (p<tbuf) { + write(2, "Bad remcap entry\n", 18); + return (0); + } + p++; + /* p now points to beginning of last field */ + if (p[0] != 't' || p[1] != 'c') + return (1); + strcpy(tcname, p+3); + q = tcname; + while (*q && *q != ':') + q++; + *q = 0; + if (++hopcount > MAXHOP) { + write(2, "Infinite tc= loop\n", 18); + return (0); + } + if (getent(tcbuf, tcname, remotefile) != 1) { + return (0); + } + for (q = tcbuf; *q++ != ':'; ) + ; + l = p - holdtbuf + strlen(q); + if (l > BUFSIZ) { + write(2, "Remcap entry too long\n", 23); + q[BUFSIZ - (p-holdtbuf)] = 0; + } + strcpy(p, q); + tbuf = holdtbuf; + return (1); +} + +/* + * Tnamatch deals with name matching. The first field of the termcap + * entry is a sequence of names separated by |'s, so we compare + * against each such name. The normal : terminator after the last + * name (before the first field) stops us. + */ +int +tnamatch(np) + char *np; +{ + register char *Np, *Bp; + + Bp = tbuf; + if (*Bp == '#') + return (0); + for (;;) { + for (Np = np; *Np && *Bp == *Np; Bp++, Np++) + continue; + if (*Np == 0 && (*Bp == '|' || *Bp == ':' || *Bp == 0)) + return (1); + while (*Bp && *Bp != ':' && *Bp != '|') + Bp++; + if (*Bp == 0 || *Bp == ':') + return (0); + Bp++; + } +} + +/* + * Skip to the next field. Notice that this is very dumb, not + * knowing about \: escapes or any such. If necessary, :'s can be put + * into the termcap file in octal. + */ +static char * +tskip(bp) + register char *bp; +{ + int dquote; + + dquote = 0; + while (*bp) { + switch (*bp) { + case ':': + if (!dquote) + goto breakbreak; + else + bp++; + break; + case '\\': + bp++; + if (isdigit(*bp)) { + while (isdigit(*bp++)) + ; + } else + bp++; + case '"': + dquote = (dquote ? 1 : 0); + bp++; + break; + default: + bp++; + break; + } + } +breakbreak: + if (*bp == ':') + bp++; + return (bp); +} + +/* + * Return the (numeric) option id. + * Numeric options look like + * li#80 + * i.e. the option string is separated from the numeric value by + * a # character. If the option is not found we return -1. + * Note that we handle octal numbers beginning with 0. + */ +int +tgetnum(id) + char *id; +{ + register long int i; + register int base; + register char *bp = tbuf; + + for (;;) { + bp = tskip(bp); + if (*bp == 0) + return (-1); + if (strncmp(bp, id, strlen(id)) != 0) + continue; + bp += strlen(id); + if (*bp == '@') + return (-1); + if (*bp != '#') + continue; + bp++; + base = 10; + if (*bp == '0') + base = 8; + i = 0; + while (isdigit(*bp)) + i *= base, i += *bp++ - '0'; + return (i); + } +} + +/* + * Handle a flag option. + * Flag options are given "naked", i.e. followed by a : or the end + * of the buffer. Return 1 if we find the option, or 0 if it is + * not given. + */ +int +tgetflag(id) + char *id; +{ + register char *bp = tbuf; + + for (;;) { + bp = tskip(bp); + if (!*bp) + return (0); + if (strncmp(bp, id, strlen(id)) == 0) { + bp += strlen(id); + if (!*bp || *bp == ':') + return (1); + else if (*bp == '@') + return (0); + } + } +} + +/* + * Get a string valued option. + * These are given as + * cl=^Z + * Much decoding is done on the strings, and the strings are + * placed in area, which is a ref parameter which is updated. + * No checking on area overflow. + */ +char * +tgetstr(id, area) + char *id, **area; +{ + register char *bp = tbuf; + + for (;;) { + bp = tskip(bp); + if (!*bp) + return (0); + if (strncmp(bp, id, strlen(id)) != 0) + continue; + bp += strlen(id); + if (*bp == '@') + return (0); + if (*bp != '=') + continue; + bp++; + return (tdecode(bp, area)); + } +} + +/* + * Tdecode does the grung work to decode the + * string capability escapes. + */ +static char * +tdecode(str, area) + register char *str; + char **area; +{ + register char *cp; + register int c; + register char *dp; + int i; + char term; + + term = ':'; + cp = *area; +again: + if (*str == '"') { + term = '"'; + str++; + } + while ((c = *str++) && c != term) { + switch (c) { + + case '^': + c = *str++ & 037; + break; + + case '\\': + dp = "E\033^^\\\\::n\nr\rt\tb\bf\f\"\""; + c = *str++; +nextc: + if (*dp++ == c) { + c = *dp++; + break; + } + dp++; + if (*dp) + goto nextc; + if (isdigit(c)) { + c -= '0', i = 2; + do + c <<= 3, c |= *str++ - '0'; + while (--i && isdigit(*str)); + } + break; + } + *cp++ = c; + } + if (c == term && term != ':') { + term = ':'; + goto again; + } + *cp++ = 0; + str = *area; + *area = cp; + return (str); +} diff --git a/usr.sbin/rtadvd/advcap.h b/usr.sbin/rtadvd/advcap.h new file mode 100644 index 0000000..9c4520b --- /dev/null +++ b/usr.sbin/rtadvd/advcap.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 1994,1995 by Andrey A. Chernov, Moscow, Russia. + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * $FreeBSD$ + */ + +/* Based on Id: termcap.h,v 1.8 1996/09/10 12:42:10 peter Exp */ + +#ifndef _ADVCAP_H_ +#define _ADVCAP_H_ + +#include <sys/cdefs.h> + +__BEGIN_DECLS + +extern int agetent __P((char *, const char *)); +extern int agetflag __P((const char *)); +extern int agetnum __P((const char *)); +extern char *agetstr __P((const char *, char **)); + +__END_DECLS + +#endif /* _ADVCAP_H_ */ diff --git a/usr.sbin/rtadvd/config.c b/usr.sbin/rtadvd/config.c new file mode 100644 index 0000000..3055161 --- /dev/null +++ b/usr.sbin/rtadvd/config.c @@ -0,0 +1,639 @@ +/* + * Copyright (C) 1998 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. + * + * $FreeBSD$ + */ + +#include <sys/param.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <sys/time.h> + +#include <net/if.h> +#include <net/if_var.h> +#include <net/route.h> +#include <net/if_dl.h> + +#include <netinet/in.h> +#include <netinet/in_var.h> +#include <netinet6/ip6.h> +#include <netinet6/ip6_var.h> +#include <netinet6/icmp6.h> + +#include <arpa/inet.h> + +#include <stdio.h> +#include <syslog.h> +#include <errno.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> + +#include "rtadvd.h" +#include "advcap.h" +#include "timer.h" +#include "if.h" +#include "config.h" + +static void makeentry __P((char *, int, char *, int)); +static void make_packet __P((struct rainfo *)); +static void get_prefix __P((struct rainfo *)); + +extern struct rainfo *ralist; + +void +getconfig(intface) + char *intface; +{ + int stat, pfxs, i; + char tbuf[BUFSIZ]; + struct rainfo *tmp; + long val; + char buf[BUFSIZ]; + char *bp = buf; + char *addr; + +#define MUSTHAVE(var, cap) \ + { \ + int t; \ + if ((t = agetnum(cap)) < 0) { \ + fprintf(stderr, "rtadvd: need %s for interface %s\n", \ + cap, intface); \ + exit(1); \ + } \ + var = t; \ + } +#define MAYHAVE(var, cap, def) \ + { \ + if ((var = agetnum(cap)) < 0) \ + var = def; \ + } + + if ((stat = agetent(tbuf, intface)) <= 0) { + memset(tbuf, 0, sizeof(tbuf)); + syslog(LOG_INFO, + "<%s> %s isn't defined in the configuration file" + " or the configuration file doesn't exist." + " Treat it as default", + __FUNCTION__, intface); + } + + tmp = (struct rainfo *)malloc(sizeof(*ralist)); + memset(tmp, 0, sizeof(*tmp)); + tmp->prefix.next = tmp->prefix.prev = &tmp->prefix; + + /* get interface information */ + if (agetflag("nolladdr")) + tmp->advlinkopt = 0; + else + tmp->advlinkopt = 1; + if (tmp->advlinkopt) { + if ((tmp->sdl = if_nametosdl(intface)) == NULL) { + syslog(LOG_ERR, + "<%s> can't get information of %s", + __FUNCTION__, intface); + exit(1); + } + tmp->ifindex = tmp->sdl->sdl_index; + } else + tmp->ifindex = if_nametoindex(intface); + strncpy(tmp->ifname, intface, sizeof(tmp->ifname)); + if ((tmp->phymtu = if_getmtu(intface)) == 0) { + tmp->phymtu = IPV6_MMTU; + syslog(LOG_WARNING, + "<%s> can't get interface mtu of %s. Treat as %d", + __FUNCTION__, intface, IPV6_MMTU); + } + + /* + * set router configuration variables. + */ + MAYHAVE(val, "maxinterval", DEF_MAXRTRADVINTERVAL); + if (val < MIN_MAXINTERVAL || val > MAX_MAXINTERVAL) { + syslog(LOG_ERR, + "<%s> maxinterval must be between %d and %d", + __FUNCTION__, MIN_MAXINTERVAL, MAX_MAXINTERVAL); + exit(1); + } + tmp->maxinterval = (u_int)val; + MAYHAVE(val, "mininterval", tmp->maxinterval/3); + if (val < MIN_MININTERVAL || val > (tmp->maxinterval * 3) / 4) { + syslog(LOG_ERR, + "<%s> mininterval must be between %d and %d", + __FUNCTION__, + MIN_MININTERVAL, + (tmp->maxinterval * 3) / 4); + exit(1); + } + tmp->mininterval = (u_int)val; + + MAYHAVE(val, "chlim", DEF_ADVCURHOPLIMIT); + tmp->hoplimit = val & 0xff; + + MAYHAVE(val, "raflags", 0); + tmp->managedflg= val & ND_RA_FLAG_MANAGED; + tmp->otherflg = val & ND_RA_FLAG_OTHER; + + MAYHAVE(val, "rltime", tmp->maxinterval * 3); + if (val && (val < tmp->maxinterval || val > MAXROUTERLIFETIME)) { + syslog(LOG_ERR, + "<%s> router lifetime on %s must be 0 or" + " between %d and %d", + __FUNCTION__, intface, + tmp->maxinterval, MAXROUTERLIFETIME); + exit(1); + } + tmp->lifetime = val & 0xffff; + + MAYHAVE(val, "rtime", DEF_ADVREACHABLETIME); + if (val > MAXREACHABLETIME) { + syslog(LOG_ERR, + "<%s> reachable time must be no greater than %d", + __FUNCTION__, MAXREACHABLETIME); + exit(1); + } + tmp->reachabletime = (u_int32_t)val; + + MAYHAVE(val, "retrans", DEF_ADVRETRANSTIMER); + if (val < 0 || val > 0xffffffff) { + syslog(LOG_ERR, + "<%s> retrans time out of range", __FUNCTION__); + exit(1); + } + tmp->retranstimer = (u_int32_t)val; + + /* prefix information */ + if ((pfxs = agetnum("addrs")) < 0) { + /* auto configure prefix information */ + if (agetstr("addr", &bp) || agetstr("addr1", &bp)) { + syslog(LOG_ERR, + "<%s> conflicting prefix configuration for %s: " + "automatic and manual config at the same time", + __FUNCTION__, intface); + exit(1); + } + get_prefix(tmp); + } + else { + tmp->pfxs = pfxs; + for (i = 0; i < pfxs; i++) { + struct prefix *pfx; + char entbuf[256]; + int added = (pfxs > 1) ? 1 : 0; + + /* allocate memory to store prefix information */ + if ((pfx = malloc(sizeof(struct prefix))) == NULL) { + syslog(LOG_ERR, + "<%s> can't allocate enough memory", + __FUNCTION__); + exit(1); + } + /* link into chain */ + insque(pfx, &tmp->prefix); + + makeentry(entbuf, i, "prefixlen", added); + MAYHAVE(val, entbuf, 64); + if (val < 0 || val > 128) { + syslog(LOG_ERR, + "<%s> prefixlen out of range", + __FUNCTION__); + exit(1); + } + pfx->prefixlen = (int)val; + + makeentry(entbuf, i, "pinfoflags", added); + MAYHAVE(val, entbuf, + (ND_OPT_PI_FLAG_ONLINK|ND_OPT_PI_FLAG_AUTO)); + pfx->onlinkflg = val & ND_OPT_PI_FLAG_ONLINK; + pfx->autoconfflg = val & ND_OPT_PI_FLAG_AUTO; + + makeentry(entbuf, i, "vltime", added); + MAYHAVE(val, entbuf, DEF_ADVVALIDLIFETIME); + if (val < 0 || val > 0xffffffff) { + syslog(LOG_ERR, + "<%s> vltime out of range", + __FUNCTION__); + exit(1); + } + pfx->validlifetime = (u_int32_t)val; + + makeentry(entbuf, i, "pltime", added); + MAYHAVE(val, entbuf, DEF_ADVPREFERREDLIFETIME); + if (val < 0 || val > 0xffffffff) { + syslog(LOG_ERR, + "<%s> pltime out of range", + __FUNCTION__); + exit(1); + } + pfx->preflifetime = (u_int32_t)val; + + makeentry(entbuf, i, "addr", added); + addr = (char *)agetstr(entbuf, &bp); + if (addr == NULL) { + syslog(LOG_ERR, + "<%s> need %s as an prefix for " + "interface %s", + __FUNCTION__, entbuf, intface); + exit(1); + } + if (inet_pton(AF_INET6, addr, + &pfx->prefix) != 1) { + syslog(LOG_ERR, + "<%s> inet_pton failed for %s", + __FUNCTION__, addr); + exit(1); + } + if (IN6_IS_ADDR_MULTICAST(&pfx->prefix)) { + syslog(LOG_ERR, + "<%s> multicast prefix(%s) must " + "not be advertised (IF=%s)", + __FUNCTION__, addr, intface); + exit(1); + } + if (IN6_IS_ADDR_LINKLOCAL(&pfx->prefix)) + syslog(LOG_NOTICE, + "<%s> link-local prefix(%s) will be" + " advertised on %s", + __FUNCTION__, addr, intface); + } + } + + MAYHAVE(val, "mtu", 0); + if (val < 0 || val > 0xffffffff) { + syslog(LOG_ERR, + "<%s> mtu out of range", __FUNCTION__); + exit(1); + } + tmp->linkmtu = (u_int32_t)val; + if (tmp->linkmtu == 0) { + char *mtustr; + + if ((mtustr = (char *)agetstr("mtu", &bp)) && + strcmp(mtustr, "auto") == 0) + tmp->linkmtu = tmp->phymtu; + } + else if (tmp->linkmtu < IPV6_MMTU || tmp->linkmtu > tmp->phymtu) { + syslog(LOG_ERR, + "<%s> advertised link mtu must be between" + " least MTU and physical link MTU", + __FUNCTION__); + exit(1); + } + + /* okey */ + tmp->next = ralist; + ralist = tmp; + + /* construct the sending packet */ + make_packet(tmp); + + /* set timer */ + tmp->timer = rtadvd_add_timer(ra_timeout, ra_timer_update, + tmp, tmp); + ra_timer_update((void *)tmp, &tmp->timer->tm); + rtadvd_set_timer(&tmp->timer->tm, tmp->timer); +} + +static void +get_prefix(struct rainfo *rai) +{ + size_t len; + u_char *buf, *lim, *next; + u_char ntopbuf[INET6_ADDRSTRLEN]; + + if ((len = rtbuf_len()) < 0) { + syslog(LOG_ERR, + "<%s> can't get buffer length for routing info", + __FUNCTION__); + exit(1); + } + if ((buf = malloc(len)) == NULL) { + syslog(LOG_ERR, + "<%s> can't allocate buffer", __FUNCTION__); + exit(1); + } + if (get_rtinfo(buf, &len) < 0) { + syslog(LOG_ERR, + "<%s> can't get routing inforamtion", __FUNCTION__); + exit(1); + } + + lim = buf + len; + next = get_next_msg(buf, lim, rai->ifindex, &len, + RTADV_TYPE2BITMASK(RTM_GET)); + while (next < lim) { + struct prefix *pp; + struct in6_addr *a; + + /* allocate memory to store prefix info. */ + if ((pp = malloc(sizeof(*pp))) == NULL) { + syslog(LOG_ERR, + "<%s> can't get allocate buffer for prefix", + __FUNCTION__); + exit(1); + } + memset(pp, 0, sizeof(*pp)); + + /* set prefix and its length */ + a = get_addr(next); + memcpy(&pp->prefix, a, sizeof(*a)); + if ((pp->prefixlen = get_prefixlen(next)) < 0) { + syslog(LOG_ERR, + "<%s> failed to get prefixlen " + "or prefixl is invalid", + __FUNCTION__); + exit(1); + } + syslog(LOG_DEBUG, + "<%s> add %s/%d to prefix list on %s", + __FUNCTION__, + inet_ntop(AF_INET6, a, ntopbuf, INET6_ADDRSTRLEN), + pp->prefixlen, rai->ifname); + + /* set other fields with protocol defaults */ + pp->validlifetime = DEF_ADVVALIDLIFETIME; + pp->preflifetime = DEF_ADVPREFERREDLIFETIME; + pp->onlinkflg = 1; + pp->autoconfflg = 1; + + /* link into chain */ + insque(pp, &rai->prefix); + + /* counter increment */ + rai->pfxs++; + + /* forward pointer and get next prefix(if any) */ + next += len; + next = get_next_msg(next, lim, rai->ifindex, + &len, RTADV_TYPE2BITMASK(RTM_GET)); + } + + free(buf); +} + +static void +makeentry(buf, id, string, add) + char *buf, *string; + int id, add; +{ + strcpy(buf, string); + if (add) { + char *cp; + + cp = (char *)index(buf, '\0'); + cp += sprintf(cp, "%d", id); + *cp = '\0'; + } +} + +/* + * Add a prefix to the list of specified interface and reconstruct + * the outgoing packet. + * The prefix must not be in the list. + * XXX: other parameter of the prefix(e.g. lifetime) shoule be + * able to be specified. + */ +static void +add_prefix(struct rainfo *rai, struct in6_prefixreq *ipr) +{ + struct prefix *prefix; + u_char ntopbuf[INET6_ADDRSTRLEN]; + + if ((prefix = malloc(sizeof(*prefix))) == NULL) { + syslog(LOG_ERR, "<%s> memory allocation failed", + __FUNCTION__); + return; /* XXX: error or exit? */ + } + prefix->prefix = ipr->ipr_prefix.sin6_addr; + prefix->prefixlen = ipr->ipr_plen; + prefix->validlifetime = ipr->ipr_vltime; + prefix->preflifetime = ipr->ipr_pltime; + prefix->onlinkflg = ipr->ipr_raf_onlink; + prefix->autoconfflg = ipr->ipr_raf_auto; + + insque(prefix, &rai->prefix); + + syslog(LOG_DEBUG, "<%s> new prefix %s/%d was added on %s", + __FUNCTION__, inet_ntop(AF_INET6, &ipr->ipr_prefix.sin6_addr, + ntopbuf, INET6_ADDRSTRLEN), + ipr->ipr_plen, rai->ifname); + + /* free the previous packet */ + free(rai->ra_data); + rai->ra_data = 0; + + /* reconstruct the packet */ + rai->pfxs++; + make_packet(rai); + + /* + * reset the timer so that the new prefix will be advertised quickly. + */ + rai->initcounter = 0; + ra_timer_update((void *)rai, &rai->timer->tm); + rtadvd_set_timer(&rai->timer->tm, rai->timer); +} + +/* + * Delete a prefix to the list of specified interface and reconstruct + * the outgoing packet. + * The prefix must be in the list + */ +void +delete_prefix(struct rainfo *rai, struct prefix *prefix) +{ + u_char ntopbuf[INET6_ADDRSTRLEN]; + + remque(prefix); + syslog(LOG_DEBUG, "<%s> prefix %s/%d was deleted on %s", + __FUNCTION__, inet_ntop(AF_INET6, &prefix->prefix, + ntopbuf, INET6_ADDRSTRLEN), + prefix->prefixlen, rai->ifname); + free(prefix); + rai->pfxs--; + make_packet(rai); +} + +/* + * Try to get an in6_prefixreq contents for a prefix which matches + * ipr->ipr_prefix and ipr->ipr_plen and belongs to + * the interface whose name is ipr->ipr_name[]. + */ +static int +init_prefix(struct in6_prefixreq *ipr) +{ + int s; + + if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + syslog(LOG_ERR, "<%s> socket: %s", __FUNCTION__, + strerror(errno)); + exit(1); + } + + if (ioctl(s, SIOCGIFPREFIX_IN6, (caddr_t)ipr) < 0) { + syslog(LOG_INFO, "<%s> ioctl:SIOCGIFPREFIX %s", __FUNCTION__, + strerror(errno)); + + ipr->ipr_vltime = DEF_ADVVALIDLIFETIME; + ipr->ipr_pltime = DEF_ADVPREFERREDLIFETIME; + ipr->ipr_raf_onlink = 1; + ipr->ipr_raf_auto = 1; + /* omit other field initialization */ + } + else if (ipr->ipr_origin < PR_ORIG_RR) { + u_char ntopbuf[INET6_ADDRSTRLEN]; + + syslog(LOG_WARNING, "<%s> Added prefix(%s)'s origin %d is" + "lower than PR_ORIG_RR(router renumbering)." + "This should not happen if I am router", __FUNCTION__, + inet_ntop(AF_INET6, &ipr->ipr_prefix.sin6_addr, ntopbuf, + sizeof(ntopbuf)), ipr->ipr_origin); + return 1; + } + + close(s); + return 0; +} + +void +make_prefix(struct rainfo *rai, int ifindex, struct in6_addr *addr, int plen) +{ + struct in6_prefixreq ipr; + + memset(&ipr, 0, sizeof(ipr)); + if (if_indextoname(ifindex, ipr.ipr_name) == NULL) { + syslog(LOG_ERR, "<%s> Prefix added interface No.%d doesn't" + "exist. This should not happen! %s", __FUNCTION__, + ifindex, strerror(errno)); + exit(1); + } + ipr.ipr_prefix.sin6_len = sizeof(ipr.ipr_prefix); + ipr.ipr_prefix.sin6_family = AF_INET6; + ipr.ipr_prefix.sin6_addr = *addr; + ipr.ipr_plen = plen; + + if (init_prefix(&ipr)) + return; /* init failed by some error */ + add_prefix(rai, &ipr); +} + +static void +make_packet(struct rainfo *rainfo) +{ + size_t packlen, lladdroptlen = 0; + char *buf; + struct nd_router_advert *ra; + struct nd_opt_prefix_info *ndopt_pi; + struct nd_opt_mtu *ndopt_mtu; + struct prefix *pfx; + + /* calculate total length */ + packlen = sizeof(struct nd_router_advert); + if (rainfo->advlinkopt) { + if ((lladdroptlen = lladdropt_length(rainfo->sdl)) == 0) { + syslog(LOG_INFO, + "<%s> link-layer address option has" + " null length on %s." + " Treat as not included.", + __FUNCTION__, rainfo->ifname); + rainfo->advlinkopt = 0; + } + packlen += lladdroptlen; + } + if (rainfo->pfxs) + packlen += sizeof(struct nd_opt_prefix_info) * rainfo->pfxs; + if (rainfo->linkmtu) + packlen += sizeof(struct nd_opt_mtu); + + /* allocate memory for the packet */ + if ((buf = malloc(packlen)) == NULL) { + syslog(LOG_ERR, + "<%s> can't get enough memory for an RA packet", + __FUNCTION__); + exit(1); + } + rainfo->ra_data = buf; + /* XXX: what if packlen > 576? */ + rainfo->ra_datalen = packlen; + + /* + * construct the packet + */ + ra = (struct nd_router_advert *)buf; + ra->nd_ra_type = ND_ROUTER_ADVERT; + ra->nd_ra_code = 0; + ra->nd_ra_cksum = 0; + ra->nd_ra_curhoplimit = (u_int8_t)(0xff & rainfo->hoplimit); + ra->nd_ra_flags_reserved = 0; + ra->nd_ra_flags_reserved |= + rainfo->managedflg ? ND_RA_FLAG_MANAGED : 0; + ra->nd_ra_flags_reserved |= + rainfo->otherflg ? ND_RA_FLAG_OTHER : 0; + ra->nd_ra_router_lifetime = htons(rainfo->lifetime); + ra->nd_ra_reachable = htonl(rainfo->reachabletime); + ra->nd_ra_retransmit = htonl(rainfo->retranstimer); + buf += sizeof(*ra); + + if (rainfo->advlinkopt) { + lladdropt_fill(rainfo->sdl, (struct nd_opt_hdr *)buf); + buf += lladdroptlen; + } + + if (rainfo->linkmtu) { + ndopt_mtu = (struct nd_opt_mtu *)buf; + ndopt_mtu->nd_opt_mtu_type = ND_OPT_MTU; + ndopt_mtu->nd_opt_mtu_len = 1; + ndopt_mtu->nd_opt_mtu_reserved = 0; + ndopt_mtu->nd_opt_mtu_mtu = ntohl(rainfo->linkmtu); + buf += sizeof(struct nd_opt_mtu); + } + + for (pfx = rainfo->prefix.next; + pfx != &rainfo->prefix; pfx = pfx->next) { + ndopt_pi = (struct nd_opt_prefix_info *)buf; + ndopt_pi->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION; + ndopt_pi->nd_opt_pi_len = 4; + ndopt_pi->nd_opt_pi_prefix_len = pfx->prefixlen; + ndopt_pi->nd_opt_pi_flags_reserved = 0; + if (pfx->onlinkflg) + ndopt_pi->nd_opt_pi_flags_reserved |= + ND_OPT_PI_FLAG_ONLINK; + if (pfx->autoconfflg) + ndopt_pi->nd_opt_pi_flags_reserved |= + ND_OPT_PI_FLAG_AUTO; + ndopt_pi->nd_opt_pi_valid_time = ntohl(pfx->validlifetime); + ndopt_pi->nd_opt_pi_preferred_time = + ntohl(pfx->preflifetime); + ndopt_pi->nd_opt_pi_reserved2 = 0; + ndopt_pi->nd_opt_pi_prefix = pfx->prefix; + + buf += sizeof(struct nd_opt_prefix_info); + } + + return; +} diff --git a/usr.sbin/rtadvd/config.h b/usr.sbin/rtadvd/config.h new file mode 100644 index 0000000..f8729d4 --- /dev/null +++ b/usr.sbin/rtadvd/config.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 1995, 1996, 1997, 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. + * + * $FreeBSD$ + */ + +extern void getconfig __P((char *)); +extern void delete_prefix __P((struct rainfo *, struct prefix *)); +extern void make_prefix __P((struct rainfo *, int, struct in6_addr *, int)); diff --git a/usr.sbin/rtadvd/if.c b/usr.sbin/rtadvd/if.c new file mode 100644 index 0000000..98aefee --- /dev/null +++ b/usr.sbin/rtadvd/if.c @@ -0,0 +1,556 @@ +/* + * Copyright (C) 1995, 1996, 1997, and 1998 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. + * + * $FreeBSD$ + */ + +#include <sys/param.h> +#include <sys/socket.h> +#include <sys/sysctl.h> +#include <sys/ioctl.h> +#include <net/if.h> +#include <net/if_types.h> +#include <net/ethernet.h> +#include <net/route.h> +#include <net/if_dl.h> +#include <netinet/in.h> +#include <netinet/icmp6.h> +#include <unistd.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <syslog.h> +#include "rtadvd.h" +#include "if.h" + +#define ROUNDUP(a, size) \ + (((a) & ((size)-1)) ? (1 + ((a) | ((size)-1))) : (a)) + +#define NEXT_SA(ap) (ap) = (struct sockaddr *) \ + ((caddr_t)(ap) + ((ap)->sa_len ? ROUNDUP((ap)->sa_len,\ + sizeof(u_long)) :\ + sizeof(u_long))) + +struct if_msghdr **iflist; +int iflist_init_ok; +size_t ifblock_size; +char *ifblock; + +static void get_iflist __P((char **buf, size_t *size)); +static void parse_iflist __P((struct if_msghdr ***ifmlist_p, char *buf, + size_t bufsize)); + +static void +get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info) +{ + int i; + + for (i = 0; i < RTAX_MAX; i++) { + if (addrs & (1 << i)) { + rti_info[i] = sa; + NEXT_SA(sa); + } + else + rti_info[i] = NULL; + } +} + +struct sockaddr_dl * +if_nametosdl(char *name) +{ + int mib[6] = {CTL_NET, AF_ROUTE, 0, 0, NET_RT_IFLIST, 0}; + char *buf, *next, *lim; + size_t len; + struct if_msghdr *ifm; + struct sockaddr *sa, *rti_info[RTAX_MAX]; + struct sockaddr_dl *sdl = NULL, *ret_sdl; + + if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) + return(NULL); + if ((buf = malloc(len)) == NULL) + return(NULL); + if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) { + free(buf); + return(NULL); + } + + lim = buf + len; + for (next = buf; next < lim; next += ifm->ifm_msglen) { + ifm = (struct if_msghdr *)next; + if (ifm->ifm_type == RTM_IFINFO) { + sa = (struct sockaddr *)(ifm + 1); + get_rtaddrs(ifm->ifm_addrs, sa, rti_info); + if ((sa = rti_info[RTAX_IFP]) != NULL) { + if (sa->sa_family == AF_LINK) { + sdl = (struct sockaddr_dl *)sa; + if (strncmp(&sdl->sdl_data[0], + name, + sdl->sdl_nlen) == 0) { + break; + } + } + } + } + } + if (next == lim) { + /* search failed */ + free(buf); + return(NULL); + } + + if ((ret_sdl = malloc(sdl->sdl_len)) == NULL) + return(NULL); + memcpy((caddr_t)ret_sdl, (caddr_t)sdl, sdl->sdl_len); + return(ret_sdl); +} + +int +if_getmtu(char *name) +{ + struct ifreq ifr; + int s; + + if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) + return(0); + + ifr.ifr_addr.sa_family = AF_INET6; + strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); + if (ioctl(s, SIOCGIFMTU, (caddr_t)&ifr) < 0) { + close(s); + return(0); + } + + close(s); + + return(ifr.ifr_mtu); +} + +/* give interface index and its old flags, then new flags returned */ +int +if_getflags(int ifindex, int oifflags) +{ + struct ifreq ifr; + int s; + + if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + syslog(LOG_ERR, "<%s> socket: %s", __FUNCTION__, + strerror(errno)); + return (oifflags & ~IFF_UP); + } + + if_indextoname(ifindex, ifr.ifr_name); + if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) { + syslog(LOG_ERR, "<%s> ioctl:SIOCGIFFLAGS: failed for %s", + __FUNCTION__, ifr.ifr_name); + close(s); + return (oifflags & ~IFF_UP); + } + return (ifr.ifr_flags); +} + +#define ROUNDUP8(a) (1 + (((a) - 1) | 7)) +int +lladdropt_length(struct sockaddr_dl *sdl) +{ + switch(sdl->sdl_type) { + case IFT_ETHER: + return(ROUNDUP8(ETHER_ADDR_LEN + 2)); + default: + return(0); + } +} + +void +lladdropt_fill(struct sockaddr_dl *sdl, struct nd_opt_hdr *ndopt) +{ + char *addr; + + ndopt->nd_opt_type = ND_OPT_SOURCE_LINKADDR; /* fixed */ + + switch(sdl->sdl_type) { + case IFT_ETHER: + ndopt->nd_opt_len = (ROUNDUP8(ETHER_ADDR_LEN + 2)) >> 3; + addr = (char *)(ndopt + 1); + memcpy(addr, LLADDR(sdl), ETHER_ADDR_LEN); + break; + default: + syslog(LOG_ERR, + "<%s> unsupported link type(%d)", + __FUNCTION__, sdl->sdl_type); + exit(1); + } + + return; +} + +int +rtbuf_len() +{ + size_t len; + + int mib[6] = {CTL_NET, AF_ROUTE, 0, AF_INET6, NET_RT_DUMP, 0}; + + if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) + return(-1); + + return(len); +} + +int +get_rtinfo(char *buf, size_t *len) +{ + int mib[6] = {CTL_NET, AF_ROUTE, 0, AF_INET6, NET_RT_DUMP, 0}; + + if (sysctl(mib, 6, buf, len, NULL, 0) < 0) + return(-1); + + return(0); +} + +#define FILTER_MATCH(type, filter) ((0x1 << type) & filter) +#define SIN6(s) ((struct sockaddr_in6 *)(s)) +#define SDL(s) ((struct sockaddr_dl *)(s)) +char * +get_next_msg(char *buf, char *lim, int ifindex, size_t *lenp, int filter) +{ + struct rt_msghdr *rtm; + struct ifa_msghdr *ifam; + struct sockaddr *sa, *dst, *gw, *ifa, *rti_info[RTAX_MAX]; + + *lenp = 0; + for (rtm = (struct rt_msghdr *)buf; + rtm < (struct rt_msghdr *)lim; + rtm = (struct rt_msghdr *)(((char *)rtm) + rtm->rtm_msglen)) { + /* just for safety */ + if (!rtm->rtm_msglen) { + syslog(LOG_WARNING, "<%s> rtm_msglen is 0 " + "(buf=%p lim=%p rtm=%p)", __FUNCTION__, + buf, lim, rtm); + break; + } + if (FILTER_MATCH(rtm->rtm_type, filter) == 0) { + continue; + } + + switch (rtm->rtm_type) { + case RTM_GET: + case RTM_ADD: + case RTM_DELETE: + /* address related checks */ + sa = (struct sockaddr *)(rtm + 1); + get_rtaddrs(rtm->rtm_addrs, sa, rti_info); + if ((dst = rti_info[RTAX_DST]) == NULL || + dst->sa_family != AF_INET6) + continue; + + if (IN6_IS_ADDR_LINKLOCAL(&SIN6(dst)->sin6_addr) || + IN6_IS_ADDR_MULTICAST(&SIN6(dst)->sin6_addr)) + continue; + + if ((gw = rti_info[RTAX_GATEWAY]) == NULL || + gw->sa_family != AF_LINK) + continue; + if (ifindex && SDL(gw)->sdl_index != ifindex) + continue; + + if (rti_info[RTAX_NETMASK] == NULL) + continue; + + /* found */ + *lenp = rtm->rtm_msglen; + return (char *)rtm; + /* NOTREACHED */ + case RTM_NEWADDR: + case RTM_DELADDR: + ifam = (struct ifa_msghdr *)rtm; + + /* address related checks */ + sa = (struct sockaddr *)(ifam + 1); + get_rtaddrs(ifam->ifam_addrs, sa, rti_info); + if ((ifa = rti_info[RTAX_IFA]) == NULL || + (ifa->sa_family != AF_INET && + ifa->sa_family != AF_INET6)) + continue; + + if (ifa->sa_family == AF_INET6 && + (IN6_IS_ADDR_LINKLOCAL(&SIN6(ifa)->sin6_addr) || + IN6_IS_ADDR_MULTICAST(&SIN6(ifa)->sin6_addr))) + continue; + + if (ifindex && ifam->ifam_index != ifindex) + continue; + + /* found */ + *lenp = ifam->ifam_msglen; + return (char *)rtm; + /* NOTREACHED */ + case RTM_IFINFO: + /* found */ + *lenp = rtm->rtm_msglen; + return (char *)rtm; + /* NOTREACHED */ + } + } + + return (char *)rtm; +} +#undef FILTER_MATCH(type, filter) + +struct in6_addr * +get_addr(char *buf) +{ + struct rt_msghdr *rtm = (struct rt_msghdr *)buf; + struct sockaddr *sa, *rti_info[RTAX_MAX]; + + sa = (struct sockaddr *)(rtm + 1); + get_rtaddrs(rtm->rtm_addrs, sa, rti_info); + + return(&SIN6(rti_info[RTAX_DST])->sin6_addr); +} + +int +get_rtm_ifindex(char *buf) +{ + struct rt_msghdr *rtm = (struct rt_msghdr *)buf; + struct sockaddr *sa, *rti_info[RTAX_MAX]; + + sa = (struct sockaddr *)(rtm + 1); + get_rtaddrs(rtm->rtm_addrs, sa, rti_info); + + return(((struct sockaddr_dl *)rti_info[RTAX_GATEWAY])->sdl_index); +} + +int +get_ifm_ifindex(char *buf) +{ + struct if_msghdr *ifm = (struct if_msghdr *)buf; + + return ((int)ifm->ifm_index); +} + +int +get_ifam_ifindex(char *buf) +{ + struct ifa_msghdr *ifam = (struct ifa_msghdr *)buf; + + return ((int)ifam->ifam_index); +} + +int +get_ifm_flags(char *buf) +{ + struct if_msghdr *ifm = (struct if_msghdr *)buf; + + return (ifm->ifm_flags); +} + +int +get_prefixlen(char *buf) +{ + struct rt_msghdr *rtm = (struct rt_msghdr *)buf; + struct sockaddr *sa, *rti_info[RTAX_MAX]; + int masklen; + u_char *p, *lim; + + sa = (struct sockaddr *)(rtm + 1); + get_rtaddrs(rtm->rtm_addrs, sa, rti_info); + sa = rti_info[RTAX_NETMASK]; + + p = (u_char *)(&SIN6(sa)->sin6_addr); + lim = (u_char *)sa + sa->sa_len; + for (masklen = 0; p < lim; p++) { + switch (*p) { + case 0xff: + masklen += 8; + break; + case 0xfe: + masklen += 7; + break; + case 0xfc: + masklen += 6; + break; + case 0xf8: + masklen += 5; + break; + case 0xf0: + masklen += 4; + break; + case 0xe0: + masklen += 3; + break; + case 0xc0: + masklen += 2; + break; + case 0x80: + masklen += 1; + break; + case 0x00: + break; + default: + return(-1); + } + } + + return(masklen); +} + +int +rtmsg_type(char *buf) +{ + struct rt_msghdr *rtm = (struct rt_msghdr *)buf; + + return(rtm->rtm_type); +} + +int +rtmsg_len(char *buf) +{ + struct rt_msghdr *rtm = (struct rt_msghdr *)buf; + + return(rtm->rtm_msglen); +} + +int +ifmsg_len(char *buf) +{ + struct if_msghdr *ifm = (struct if_msghdr *)buf; + + return(ifm->ifm_msglen); +} + +/* + * alloc buffer and get if_msghdrs block from kernel, + * and put them into the buffer + */ +static void +get_iflist(char **buf, size_t *size) +{ + int mib[6]; + + mib[0] = CTL_NET; + mib[1] = PF_ROUTE; + mib[2] = 0; + mib[3] = AF_INET6; + mib[4] = NET_RT_IFLIST; + mib[5] = 0; + + if (sysctl(mib, 6, NULL, size, NULL, 0) < 0) { + syslog(LOG_ERR, "<%s> sysctl: iflist size get failed", + __FUNCTION__); + exit(1); + } + if ((*buf = malloc(*size)) == NULL) { + syslog(LOG_ERR, "<%s> malloc failed", __FUNCTION__); + exit(1); + } + if (sysctl(mib, 6, *buf, size, NULL, 0) < 0) { + syslog(LOG_ERR, "<%s> sysctl: iflist get failed", + __FUNCTION__); + exit(1); + } + return; +} + +/* + * alloc buffer and parse if_msghdrs block passed as arg, + * and init the buffer as list of pointers ot each of the if_msghdr. + */ +static void +parse_iflist(struct if_msghdr ***ifmlist_p, char *buf, size_t bufsize) +{ + int iflentry_size, malloc_size; + struct if_msghdr *ifm; + struct ifa_msghdr *ifam; + char *lim; + + /* + * Estimate least size of an iflist entry, to be obtained from kernel. + * Should add sizeof(sockaddr) ?? + */ + iflentry_size = sizeof(struct if_msghdr); + /* roughly estimate max list size of pointers to each if_msghdr */ + malloc_size = (bufsize/iflentry_size) * sizeof(size_t); + if ((*ifmlist_p = (struct if_msghdr **)malloc(malloc_size)) == NULL) { + syslog(LOG_ERR, "<%s> malloc failed", __FUNCTION__); + exit(1); + } + + lim = buf + bufsize; + for (ifm = (struct if_msghdr *)buf; ifm < (struct if_msghdr *)lim;) { + if (ifm->ifm_msglen == 0) { + syslog(LOG_WARNING, "<%s> ifm_msglen is 0 " + "(buf=%p lim=%p ifm=%p)", __FUNCTION__, + buf, lim, ifm); + return; + } + + if (ifm->ifm_type == RTM_IFINFO) { + (*ifmlist_p)[ifm->ifm_index] = ifm; + } else { + syslog(LOG_ERR, "out of sync parsing NET_RT_IFLIST\n" + "expected %d, got %d\n msglen = %d\n" + "buf:%p, ifm:%p, lim:%p\n", + RTM_IFINFO, ifm->ifm_type, ifm->ifm_msglen, + buf, ifm, lim); + exit (1); + } + for (ifam = (struct ifa_msghdr *) + ((char *)ifm + ifm->ifm_msglen); + ifam < (struct ifa_msghdr *)lim; + ifam = (struct ifa_msghdr *) + ((char *)ifam + ifam->ifam_msglen)) { + /* just for safety */ + if (!ifam->ifam_msglen) { + syslog(LOG_WARNING, "<%s> ifa_msglen is 0 " + "(buf=%p lim=%p ifam=%p)", __FUNCTION__, + buf, lim, ifam); + return; + } + if (ifam->ifam_type != RTM_NEWADDR) + break; + } + ifm = (struct if_msghdr *)ifam; + } +} + +void +init_iflist() +{ + if (ifblock) { + free(ifblock); + ifblock_size = 0; + } + if (iflist) + free(iflist); + /* get iflist block from kernel */ + get_iflist(&ifblock, &ifblock_size); + + /* make list of pointers to each if_msghdr */ + parse_iflist(&iflist, ifblock, ifblock_size); + +} diff --git a/usr.sbin/rtadvd/if.h b/usr.sbin/rtadvd/if.h new file mode 100644 index 0000000..e8e14d4 --- /dev/null +++ b/usr.sbin/rtadvd/if.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 1995, 1996, 1997, 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. + * + * $FreeBSD$ + */ + +#define RTADV_TYPE2BITMASK(type) (0x1 << type) + +extern struct if_msghdr **iflist; +extern size_t ifblock_size; +extern char *ifblock; + +struct sockaddr_dl *if_nametosdl __P((char *name)); +int if_getmtu __P((char *name)); +int if_getflags __P((int ifindex, int oifflags)); +int lladdropt_length __P((struct sockaddr_dl *sdl)); +void lladdropt_fill __P((struct sockaddr_dl *sdl, struct nd_opt_hdr *ndopt)); +int rtbuf_len __P((void)); +int get_rtinfo __P((char *buf, size_t *len)); +char *get_next_msg __P((char *buf, char *lim, int ifindex, size_t *lenp, + int filter)); +struct in6_addr *get_addr __P((char *buf)); +int get_rtm_ifindex __P((char *buf)); +int get_ifm_ifindex __P((char *buf)); +int get_ifam_ifindex __P((char *buf)); +int get_ifm_flags __P((char *buf)); +int get_prefixlen __P((char *buf)); +int rtmsg_type __P((char *buf)); +int ifmsg_type __P((char *buf)); +int rtmsg_len __P((char *buf)); +int ifmsg_len __P((char *buf)); +void init_iflist __P((void)); diff --git a/usr.sbin/rtadvd/pathnames.h b/usr.sbin/rtadvd/pathnames.h new file mode 100644 index 0000000..70d9021 --- /dev/null +++ b/usr.sbin/rtadvd/pathnames.h @@ -0,0 +1,2 @@ +/* $FreeBSD$ */ +#define _PATH_RTADVDCONF "/usr/local/v6/etc/rtadvd.conf" diff --git a/usr.sbin/rtadvd/rrenum.c b/usr.sbin/rtadvd/rrenum.c new file mode 100644 index 0000000..ec69ff2 --- /dev/null +++ b/usr.sbin/rtadvd/rrenum.c @@ -0,0 +1,414 @@ +/* + * Copyright (C) 1995, 1996, 1997, and 1998 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. + * + * $FreeBSD$ + */ + +#include <sys/param.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <sys/sysctl.h> + +#include <net/if.h> +#include <net/if_var.h> +#include <net/route.h> +#include <netinet/in.h> +#include <netinet/in_var.h> +#include <netinet/icmp6.h> + +#include <arpa/inet.h> + +#include <errno.h> +#include <string.h> +#include <stdlib.h> +#include <syslog.h> +#include "rrenum.h" +#include "if.h" + +#define RR_ISSET_SEGNUM(segnum_bits, segnum) \ + ((((segnum_bits)[(segnum) >> 5]) & (1 << ((segnum) & 31))) != 0) +#define RR_SET_SEGNUM(segnum_bits, segnum) \ + (((segnum_bits)[(segnum) >> 5]) |= (1 << ((segnum) & 31))) + +struct rr_operation { + u_long rro_seqnum; + u_long rro_segnum_bits[8]; +}; + +static struct rr_operation rro; +static int rr_rcvifindex; +static int rrcmd2pco[4] = {0, + SIOCAIFPREFIX_IN6, + SIOCCIFPREFIX_IN6, + SIOCSGIFPREFIX_IN6 +}; +static int s; + +/* + * Check validity of a Prefix Control Operation(PCO). + * Return 0 on success, 1 on failure. + */ +static int +rr_pco_check(int len, struct rr_pco_match *rpm) +{ + struct rr_pco_use *rpu, *rpulim; + int checklen; + + /* rpm->rpm_len must be (4N * 3) as router-renum-05.txt */ + if ((rpm->rpm_len - 3) < 0 || /* must be at least 3 */ + (rpm->rpm_len - 3) & 0x3) { /* must be multiple of 4 */ + syslog(LOG_WARNING, "<%s> rpm_len %d is not 4N * 3", + __FUNCTION__, rpm->rpm_len); + return 1; + } + /* rpm->rpm_code must be valid value */ + switch(rpm->rpm_code) { + case RPM_PCO_ADD: + case RPM_PCO_CHANGE: + case RPM_PCO_SETGLOBAL: + break; + default: + syslog(LOG_WARNING, "<%s> unknown rpm_code %d", __FUNCTION__, + rpm->rpm_code); + return 1; + } + /* rpm->rpm_matchlen must be 0 to 128 inclusive */ + if (rpm->rpm_matchlen > 128) { + syslog(LOG_WARNING, "<%s> rpm_matchlen %d is over 128", + __FUNCTION__, rpm->rpm_matchlen); + return 1; + } + + /* + * rpu->rpu_uselen, rpu->rpu_keeplen, and sum of them must be + * between 0 and 128 inclusive + */ + for (rpu = (struct rr_pco_use *)(rpm + 1), + rpulim = (struct rr_pco_use *)((char *)rpm + len); + rpu < rpulim; + rpu += 1) { + checklen = rpu->rpu_uselen; + checklen += rpu->rpu_keeplen; + /* + * omit these check, because either of rpu_uselen + * and rpu_keeplen is unsigned char + * (128 > rpu_uselen > 0) + * (128 > rpu_keeplen > 0) + * (rpu_uselen + rpu_keeplen > 0) + */ + if (checklen > 128) { + syslog(LOG_WARNING, "<%s> sum of rpu_uselen %d and" + " rpu_keeplen %d is %d(over 128)", + __FUNCTION__, rpu->rpu_uselen, + rpu->rpu_keeplen, + rpu->rpu_uselen + rpu->rpu_keeplen); + return 1; + } + } + return 0; +} + +static void +do_use_prefix(int len, struct rr_pco_match *rpm, struct in6_rrenumreq *irr) { + struct rr_pco_use *rpu, *rpulim; + + rpu = (struct rr_pco_use *)(rpm + 1); + rpulim = (struct rr_pco_use *)((char *)rpm + len); + + if (rpu == rpulim) { + if (rpm->rpm_code == RPM_PCO_ADD) + return; + + irr->irr_u_uselen = 0; + irr->irr_u_keeplen = 0; + irr->irr_raf_mask_onlink = 0; + irr->irr_raf_mask_auto = 0; + irr->irr_vltime = 0; + irr->irr_pltime = 0; + memset(&irr->irr_flags, 0, sizeof(irr->irr_flags)); + irr->irr_useprefix.sin6_len = 0; /* let it mean, no addition */ + irr->irr_useprefix.sin6_family = 0; + irr->irr_useprefix.sin6_addr = in6addr_any; + if (ioctl(s, rrcmd2pco[rpm->rpm_code], (caddr_t)irr) < 0 && + errno != EADDRNOTAVAIL) + syslog(LOG_ERR, "<%s> ioctl: %s", __FUNCTION__, + strerror(errno)); + return; + } + + for (rpu = (struct rr_pco_use *)(rpm + 1), + rpulim = (struct rr_pco_use *)((char *)rpm + len); + rpu < rpulim; + rpu += 1) { + /* init in6_rrenumreq fields */ + irr->irr_u_uselen = rpu->rpu_uselen; + irr->irr_u_keeplen = rpu->rpu_keeplen; + irr->irr_raf_mask_onlink = + (rpu->rpu_ramask & ICMP6_RR_PCOUSE_RAFLAGS_ONLINK); + irr->irr_raf_mask_auto = + (rpu->rpu_ramask & ICMP6_RR_PCOUSE_RAFLAGS_AUTO); + irr->irr_vltime = rpu->rpu_vltime; + irr->irr_pltime = rpu->rpu_pltime; + irr->irr_raf_onlink = + (rpu->rpu_raflags & ICMP6_RR_PCOUSE_RAFLAGS_ONLINK); + irr->irr_raf_auto = + (rpu->rpu_raflags & ICMP6_RR_PCOUSE_RAFLAGS_AUTO); + irr->irr_rrf_decrvalid = + (rpu->rpu_flags & ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME); + irr->irr_rrf_decrprefd = + (rpu->rpu_flags & ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME); + irr->irr_useprefix.sin6_len = sizeof(irr->irr_useprefix); + irr->irr_useprefix.sin6_family = AF_INET6; + irr->irr_useprefix.sin6_addr = rpu->rpu_prefix; + + if (ioctl(s, rrcmd2pco[rpm->rpm_code], (caddr_t)irr) < 0 && + errno != EADDRNOTAVAIL) + syslog(LOG_ERR, "<%s> ioctl: %s", __FUNCTION__, + strerror(errno)); + } +} + +/* + * process a Prefix Control Operation(PCO). + * return 0 on success, 1 on failure + */ +static int +do_pco(struct icmp6_router_renum *rr, int len, struct rr_pco_match *rpm) +{ + int ifindex = 0; + struct in6_rrenumreq irr; + + if ((rr_pco_check(len, rpm) != NULL)) + return 1; + + if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + syslog(LOG_ERR, "<%s> socket: %s", __FUNCTION__, + strerror(errno)); + exit(1); + } + + memset(&irr, 0, sizeof(irr)); + irr.irr_origin = PR_ORIG_RR; + irr.irr_m_len = rpm->rpm_matchlen; + irr.irr_m_minlen = rpm->rpm_minlen; + irr.irr_m_maxlen = rpm->rpm_maxlen; + irr.irr_matchprefix.sin6_len = sizeof(irr.irr_matchprefix); + irr.irr_matchprefix.sin6_family = AF_INET6; + irr.irr_matchprefix.sin6_addr = rpm->rpm_prefix; + + while (if_indextoname(++ifindex, irr.irr_name)) { + /* + * if ICMP6_RR_FLAGS_FORCEAPPLY(A flag) is 0 and IFF_UP is off, + * the interface is not applied + */ + if ((rr->rr_flags & ICMP6_RR_FLAGS_FORCEAPPLY) == 0 && + (iflist[ifindex]->ifm_flags & IFF_UP) == 0) + continue; + /* TODO: interface scope check */ + do_use_prefix(len, rpm, &irr); + } + if (errno == ENXIO) + return 0; + else if (errno) { + syslog(LOG_ERR, "<%s> if_indextoname: %s", __FUNCTION__, + strerror(errno)); + return 1; + } + return 0; +} + +/* + * call do_pco() for each Prefix Control Operations(PCOs) in a received + * Router Renumbering Command packet. + * return 0 on success, 1 on failure + */ +static int +do_rr(int len, struct icmp6_router_renum *rr) +{ + struct rr_pco_match *rpm; + char *cp, *lim; + + lim = (char *)rr + len; + cp = (char *)(rr + 1); + len -= sizeof(struct icmp6_router_renum); + + /* get iflist block from kernel again, to get up-to-date information */ + init_iflist(); + + while (cp < lim) { + int rpmlen; + + rpm = (struct rr_pco_match *)cp; + if (len < sizeof(struct rr_pco_match)) { + tooshort: + syslog(LOG_ERR, "<%s> pkt too short. left len = %d. " + "gabage at end of pkt?", __FUNCTION__, len); + return 1; + } + rpmlen = rpm->rpm_len << 3; + if (len < rpmlen) + goto tooshort; + + if (do_pco(rr, rpmlen, rpm)) { + syslog(LOG_WARNING, "<%s> invalid PCO", __FUNCTION__); + goto next; + } + + next: + cp += rpmlen; + len -= rpmlen; + } + + return 0; +} + +/* + * check validity of a router renumbering command packet + * return 0 on success, 1 on failure + */ +static int +rr_command_check(int len, struct icmp6_router_renum *rr, struct in6_addr *from, + struct in6_addr *dst) +{ + u_char ntopbuf[INET6_ADDRSTRLEN]; + + /* omit rr minimal length check. hope kernel have done it. */ + /* rr_command length check */ + if (len < (sizeof(struct icmp6_router_renum) + + sizeof(struct rr_pco_match))) { + syslog(LOG_ERR, "<%s> rr_command len %d is too short", + __FUNCTION__, len); + return 1; + } + + /* destination check. only for multicast. omit unicast check. */ + if (IN6_IS_ADDR_MULTICAST(dst) && !IN6_IS_ADDR_MC_LINKLOCAL(dst) && + !IN6_IS_ADDR_MC_SITELOCAL(dst)) { + syslog(LOG_ERR, "<%s> dst mcast addr %s is illegal", + __FUNCTION__, + inet_ntop(AF_INET6, dst, ntopbuf, INET6_ADDRSTRLEN)); + return 1; + } + + /* seqnum and segnum check */ + if (rro.rro_seqnum > rr->rr_seqnum) { + syslog(LOG_WARNING, + "<%s> rcvd old seqnum %d from %s", + __FUNCTION__, (u_int32_t)ntohl(rr->rr_seqnum), + inet_ntop(AF_INET6, from, ntopbuf, INET6_ADDRSTRLEN)); + return 1; + } + if (rro.rro_seqnum == rr->rr_seqnum && + (rr->rr_flags & ICMP6_RR_FLAGS_TEST) == 0 && + RR_ISSET_SEGNUM(rro.rro_segnum_bits, rr->rr_segnum)) { + if ((rr->rr_flags & ICMP6_RR_FLAGS_REQRESULT) != 0) + syslog(LOG_WARNING, + "<%s> rcvd duped segnum %d from %s", + __FUNCTION__, rr->rr_segnum, + inet_ntop(AF_INET6, from, ntopbuf, + INET6_ADDRSTRLEN)); + return 0; + } + + /* update seqnum */ + if (rro.rro_seqnum != rr->rr_seqnum) { + /* then must be "<" */ + + /* init rro_segnum_bits */ + memset(rro.rro_segnum_bits, 0, + sizeof(rro.rro_segnum_bits)); + } + rro.rro_seqnum = rr->rr_seqnum; + + return 0; +} + +static void +rr_command_input(int len, struct icmp6_router_renum *rr, + struct in6_addr *from, struct in6_addr *dst) +{ + /* rr_command validity check */ + if (rr_command_check(len, rr, from, dst)) + goto failed; + if ((rr->rr_flags & (ICMP6_RR_FLAGS_TEST|ICMP6_RR_FLAGS_REQRESULT)) == + ICMP6_RR_FLAGS_TEST) + return; + + /* do router renumbering */ + if (do_rr(len, rr)) { + goto failed; + } + + /* update segnum */ + RR_SET_SEGNUM(rro.rro_segnum_bits, rr->rr_segnum); + + return; + + failed: + syslog(LOG_ERR, "<%s> received RR was invalid", __FUNCTION__); + return; +} + +void +rr_input(int len, struct icmp6_router_renum *rr, struct in6_pktinfo *pi, + struct sockaddr_in6 *from, struct in6_addr *dst) +{ + u_char ntopbuf[2][INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ]; + + syslog(LOG_DEBUG, + "<%s> RR received from %s to %s on %s", + __FUNCTION__, + inet_ntop(AF_INET6, &from->sin6_addr, + ntopbuf[0], INET6_ADDRSTRLEN), + inet_ntop(AF_INET6, &dst, ntopbuf[1], INET6_ADDRSTRLEN), + if_indextoname(pi->ipi6_ifindex, ifnamebuf)); + + rr_rcvifindex = pi->ipi6_ifindex; + + /* TODO: some consistency check. */ + + switch (rr->rr_code) { + case ICMP6_ROUTER_RENUMBERING_COMMAND: + rr_command_input(len, rr, &from->sin6_addr, dst); + /* TODO: send reply msg */ + break; + case ICMP6_ROUTER_RENUMBERING_RESULT: + /* RESULT will be processed by rrenumd */ + break; + case ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET: + /* TODO: sequence number reset */ + break; + default: + syslog(LOG_ERR, "<%s> received unknown code %d", + __FUNCTION__, rr->rr_code); + break; + + } + + return; +} diff --git a/usr.sbin/rtadvd/rrenum.h b/usr.sbin/rtadvd/rrenum.h new file mode 100644 index 0000000..d3c73a7 --- /dev/null +++ b/usr.sbin/rtadvd/rrenum.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 1998 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. + * + * $FreeBSD$ + */ + +void rr_input __P((int len, struct icmp6_router_renum *rr, + struct in6_pktinfo *pi, struct sockaddr_in6 *from, + struct in6_addr *dst)); diff --git a/usr.sbin/rtadvd/rtadvd.8 b/usr.sbin/rtadvd/rtadvd.8 new file mode 100644 index 0000000..a9b36b8 --- /dev/null +++ b/usr.sbin/rtadvd/rtadvd.8 @@ -0,0 +1,134 @@ +.\" Copyright (C) 1995, 1996, 1997, and 1998 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. +.\" +.\" $Id: rtadvd.8,v 1.1.1.1 1999/08/08 23:31:42 itojun Exp $ +.\" $FreeBSD$ +.\" +.Dd May 17, 1998 +.Dt RTADVD 8 +.Os KAME +.Sh NAME +.Nm rtadvd +.Nd router advertisement daemon +.Sh SYNOPSIS +.Nm +.Op Fl c Ar configfile +.Op Fl P Ar policy +.Op Fl dDfs +.Ar interface ... +.Sh DESCRIPTION +.Nm Rtadvd +advertises router advertisement packet to the specified +.Ar interfaces . +.Pp +The program will daemonize itself on invocation. +Then, it will voluntarily send router advertisement packet periodically. +If a router solicitation packet from host has reached the program, +the program will respond by router advertisement packet. +.Pp +For each interface, which is called advertising interface, +content of router advertisement can be described in +.Xr rtadvd.conf 5 . +.Pp +If there is no description for the interface in the configuration file +or if the configuration file does not exist, +.Nm +sets all the parameters to their default values. +In particular, +.Nm +gets all the interface routes from the routing table and advertises +them as on-link prefixes. +.Pp +.Nm Rtadvd +watches the routing table. +By default, if an interface direct route is +added/deleted on an advertising interface, +.Nm +adds/deletes the corresponding prefix to/from its advertising list, +respectively. +If you do not want to enable this feature, you should specify the +.Ic Fl s +command line option when advocation. +.Pp +.Nm Rtadvd +can also receive router renumbering packets, and can do router +renumbering for the system it runs on, as the contents of those +packets. +.Bl -tag -width indent +.\" +.It Fl c +Specify an alternate location, +.Ar configfile , +for the configuration file. +By default, +.Pa /usr/local/v6/etc/rtadvd.conf +is used. +.It Fl P +Specifies that +.Nm +receives router renumbering messages. Also, specifies IPsec policy for +rrenumd sessions. Because router renumbering can change the system's +IPv6 prefix, its messages must be protected by IPsec. For details about +.Ar policy , +please refer to +.Xr ipsec 4 +and +.Xr ipsec_set_policy 3 . +.It Fl d +Debug. +.It Fl D +More debug. +.It Fl f +Foreground mode. +Do not become daemon. +.It Fl s +Static prefix. +Do not watch the routing table. +.El +.Sh RETURN VALUES +The program exits with 0 on success, and non-zero on failures. +.Sh FILES +.Bl -tag -width /usr/local/v6/etc/rtadvd.conf -compact +.It Pa /usr/local/v6/etc/rtadvd.conf +The default configuration file. +.El +.Sh SEE ALSO +.Xr daemon 3 , +.Xr rtadvd.conf 5 , +.Xr rtsol 8 +.Sh HISTORY +The +.Nm +command first appeared in WIDE Hydrangea IPv6 protocol stack kit. +.Sh CAVEAT +Do not perform router advertisement toward upstream direction, +you should only advertise to downstream direction. +If you advertise toward upstream by mistake, +you will see icmp6 redirect storm on that subnet. +This is because of the specification, +which says that advertising router is assumed to become +the default outgoing router for end hosts in the subnet. diff --git a/usr.sbin/rtadvd/rtadvd.c b/usr.sbin/rtadvd/rtadvd.c new file mode 100644 index 0000000..03ed974 --- /dev/null +++ b/usr.sbin/rtadvd/rtadvd.c @@ -0,0 +1,1239 @@ +/* + * Copyright (C) 1995, 1996, 1997, and 1998 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. + * + * $FreeBSD$ + */ + +#include <sys/param.h> +#include <sys/socket.h> +#include <sys/uio.h> +#include <sys/time.h> + +#include <net/if.h> +#include <net/route.h> +#include <net/if_dl.h> +#include <netinet/in.h> +#include <netinet/ip6.h> +#include <netinet6/ip6_var.h> +#include <netinet/icmp6.h> + +#include <arpa/inet.h> + +#ifdef IPSEC +#include <netinet6/ipsec.h> +#endif /*IPSEC*/ + +#include <time.h> +#include <unistd.h> +#include <stdio.h> +#include <err.h> +#include <errno.h> +#include <string.h> +#include <sysexits.h> +#include <stdlib.h> +#include <syslog.h> +#include "rtadvd.h" +#include "rrenum.h" +#include "advcap.h" +#include "timer.h" +#include "if.h" +#include "config.h" + +struct msghdr rcvmhdr; +static u_char rcvcmsgbuf[CMSG_SPACE(sizeof(struct in6_pktinfo)) + + CMSG_SPACE(sizeof(int))]; +struct msghdr sndmhdr; +struct iovec rcviov[2]; +struct iovec sndiov[2]; +struct sockaddr_in6 from; +struct sockaddr_in6 sin6_allnodes = {sizeof(sin6_allnodes), AF_INET6}; +int sock, rrsock, rtsock; +int accept_rr = 0; +int dflag = 0, sflag = 0; + +u_char *conffile = NULL; + +struct rainfo *ralist = NULL; +struct nd_optlist { + struct nd_optlist *next; + struct nd_opt_hdr *opt; +}; +union nd_opts { + struct nd_opt_hdr *nd_opt_array[7]; + struct { + struct nd_opt_hdr *zero; + struct nd_opt_hdr *src_lladdr; + struct nd_opt_hdr *tgt_lladdr; + struct nd_opt_prefix_info *pi; + struct nd_opt_rd_hdr *rh; + struct nd_opt_mtu *mtu; + struct nd_optlist *list; + } nd_opt_each; +}; +#define nd_opts_src_lladdr nd_opt_each.src_lladdr +#define nd_opts_tgt_lladdr nd_opt_each.tgt_lladdr +#define nd_opts_pi nd_opt_each.pi +#define nd_opts_rh nd_opt_each.rh +#define nd_opts_mtu nd_opt_each.mtu +#define nd_opts_list nd_opt_each.list + +#define NDOPT_FLAG_SRCLINKADDR 0x1 +#define NDOPT_FLAG_TGTLINKADDR 0x2 +#define NDOPT_FLAG_PREFIXINFO 0x4 +#define NDOPT_FLAG_RDHDR 0x8 +#define NDOPT_FLAG_MTU 0x10 + +u_int32_t ndopt_flags[] = { + 0, NDOPT_FLAG_SRCLINKADDR, NDOPT_FLAG_TGTLINKADDR, + NDOPT_FLAG_PREFIXINFO, NDOPT_FLAG_RDHDR, NDOPT_FLAG_MTU +}; + +int main __P((int, char *[])); +static void sock_open __P((int *, int, char *)); +static void rtsock_open __P((void)); +static void rtadvd_input __P((int)); +static void rs_input __P((int, struct nd_router_solicit *, + struct in6_pktinfo *, struct sockaddr_in6 *)); +static void ra_input __P((int, struct nd_router_advert *, + struct in6_pktinfo *, struct sockaddr_in6 *)); +static void prefix_check __P((struct nd_opt_prefix_info *, struct rainfo *, + struct sockaddr_in6 *)); +static int nd6_options __P((struct nd_opt_hdr *, int, + union nd_opts *, u_int32_t)); +static void free_ndopts __P((union nd_opts *)); +static struct rainfo *if_indextorainfo __P((int)); +static void ra_output __P((struct rainfo *)); +static void rtmsg_input __P((void)); +struct prefix *find_prefix __P((struct rainfo *, struct in6_addr *, int)); + + +int +main(argc, argv) + int argc; + char *argv[]; +{ + fd_set fdset; + int maxfd = 0; + struct timeval *timeout; + int i, ch; + int fflag = 0; +#ifdef IPSEC +#ifdef IPSEC_POLICY_IPSEC + char *policy = NULL; +#endif /*IPSEC_POLICY_IPSEC*/ +#endif /*IPSEC*/ + + openlog(*argv, LOG_NDELAY|LOG_PID, LOG_DAEMON); + + /* get command line options and arguments */ + while ((ch = getopt(argc, argv, "c:dDfR:s")) != -1) { + switch(ch) { + case 'c': + conffile = optarg; + break; + case 'd': + dflag = 1; + break; + case 'D': + dflag = 2; + break; + case 'f': + fflag = 1; + break; +#ifdef IPSEC +#ifdef IPSEC_POLICY_IPSEC + case 'P': + policy = strdup(optarg); + accept_rr = 1; + break; +#endif /*IPSEC_POLICY_IPSEC*/ +#endif /*IPSEC*/ + case 's': + sflag = 1; + } + } + argc -= optind; + argv += optind; + if (argc == 0) { + fprintf(stderr, + "usage: rtadvd [-c conffile] [-d|D] [-f] [-s]" + "interfaces...\n"); + exit(1); + } + + /* set log level */ + if (dflag == 0) + (void)setlogmask(LOG_UPTO(LOG_ERR)); + if (dflag == 1) + (void)setlogmask(LOG_UPTO(LOG_INFO)); + + /* timer initialization */ + rtadvd_timer_init(); + + /* random value initialization */ + srandom((u_long)time(NULL)); + + /* get iflist block from kernel */ + init_iflist(); + + while (argc--) + getconfig(*argv++); + + if (inet_pton(AF_INET6, ALLNODES, &sin6_allnodes.sin6_addr) != 1) { + fprintf(stderr, "fatal: inet_pton failed\n"); + exit(1); + } + sock_open(&sock, 0, NULL); + if (accept_rr != 0) + sock_open(&rrsock, 1, policy); + + if (!fflag) + daemon(1, 0); + + FD_ZERO(&fdset); + FD_SET(sock, &fdset); + if (accept_rr) + FD_SET(rrsock, &fdset); + maxfd = sock > rrsock ? sock : rrsock; + if (sflag == 0) { + rtsock_open(); + FD_SET(rtsock, &fdset); + if (rtsock > maxfd) + maxfd = rtsock; + } + + while (1) { + struct fd_set select_fd = fdset; /* reinitialize */ + + /* timer expiration check and reset the timer */ + timeout = rtadvd_check_timer(); + + syslog(LOG_DEBUG, + "<%s> set timer to %ld:%ld. waiting for inputs " + "or timeout", + __FUNCTION__, + timeout->tv_sec, timeout->tv_usec); + + if ((i = select(maxfd + 1, &select_fd, + NULL, NULL, timeout)) < 0){ + syslog(LOG_ERR, "<%s> select: %s", + __FUNCTION__, strerror(errno)); + continue; + } + if (i == 0) /* timeout */ + continue; + if (sflag == 0 && FD_ISSET(rtsock, &select_fd)) + rtmsg_input(); + if (FD_ISSET(sock, &select_fd)) + rtadvd_input(sock); + if (accept_rr && FD_ISSET(rrsock, &select_fd)) + rtadvd_input(rrsock); + } + exit(0); /* NOTREACHED */ +} + +static void +rtmsg_input() +{ + int n, type, ifindex, plen; + size_t len; + char msg[2048], *next, *lim; + u_char ifname[16]; + struct prefix *prefix; + struct rainfo *rai; + struct in6_addr *addr; + char addrbuf[INET6_ADDRSTRLEN]; + + n = read(rtsock, msg, 2048); + if (dflag > 1) { + syslog(LOG_DEBUG, + "<%s> received a routing message " + "(type = %d, len = %d)", + __FUNCTION__, + rtmsg_type(msg), n); + } + if (n > rtmsg_len(msg)) { + /* + * This usually won't happen for messages received on + * an routing socket. + */ + if (dflag > 1) + syslog(LOG_DEBUG, + "<%s> received data length is larger than" + "1st routing message len. multiple messages?" + " read %d bytes, but 1st msg len = %d", + __FUNCTION__, n, rtmsg_len(msg)); + } + + lim = msg + n; + for (next = msg; next < lim; next += len) { + next = get_next_msg(next, lim, 0, &len, + RTADV_TYPE2BITMASK(RTM_ADD) | + RTADV_TYPE2BITMASK(RTM_DELETE) | + RTADV_TYPE2BITMASK(RTM_NEWADDR) | + RTADV_TYPE2BITMASK(RTM_DELADDR) | + RTADV_TYPE2BITMASK(RTM_IFINFO)); + if (len == 0) + break; + type = rtmsg_type(next); + switch (type) { + case RTM_ADD: + case RTM_DELETE: + ifindex = get_rtm_ifindex(next); + break; + case RTM_NEWADDR: + case RTM_DELADDR: + ifindex = get_ifam_ifindex(next); + break; + case RTM_IFINFO: + ifindex = get_ifm_ifindex(next); + break; + default: + /* should not reach here */ + if (dflag > 1) { + syslog(LOG_DEBUG, + "<%s:%d> unknown rtmsg %d on %s", + __FUNCTION__, __LINE__, type, + if_indextoname(ifindex, ifname)); + } + return; + } + + if ((rai = if_indextorainfo(ifindex)) == NULL) { + if (dflag > 1) { + syslog(LOG_DEBUG, + "<%s> route changed on " + "non advertising interface(%s)", + __FUNCTION__, + if_indextoname(ifindex, ifname)); + } + return; + } + + switch(type) { + case RTM_ADD: + /* init iffalgs because it may have changed */ + iflist[ifindex]->ifm_flags = + if_getflags(ifindex, + iflist[ifindex]->ifm_flags); + + addr = get_addr(msg); + plen = get_prefixlen(msg); + /* sanity check for plen */ + if (plen < 4 /* as RFC2373, prefixlen is at least 4 */ + || plen > 127) { + syslog(LOG_INFO, "<%s> new interface route's" + "plen %d is invalid for a prefix", + __FUNCTION__, plen); + return; + } + prefix = find_prefix(rai, addr, plen); + if (prefix) { + if (dflag > 1) { + syslog(LOG_DEBUG, + "<%s> new prefix(%s/%d) " + "added on %s, " + "but it was already in list", + __FUNCTION__, + inet_ntop(AF_INET6, + addr, (char *)addrbuf, + INET6_ADDRSTRLEN), + plen, + rai->ifname); + } + return; + } + make_prefix(rai, ifindex, addr, plen); + break; + case RTM_DELETE: + /* init ifflags because it may have changed */ + iflist[ifindex]->ifm_flags = + if_getflags(ifindex, + iflist[ifindex]->ifm_flags); + + addr = get_addr(msg); + plen = get_prefixlen(msg); + /* sanity check for plen */ + if (plen < 4 /* as RFC2373, prefixlen is at least 4 */ + || plen > 127) { + syslog(LOG_INFO, "<%s> deleted interface" + "route's" + "plen %d is invalid for a prefix", + __FUNCTION__, plen); + return; + } + prefix = find_prefix(rai, addr, plen); + if (prefix == NULL) { + if (dflag > 1) { + syslog(LOG_DEBUG, + "<%s> prefix(%s/%d) was " + "deleted on %s, " + "but it was not in list", + __FUNCTION__, + inet_ntop(AF_INET6, + addr, (char *)addrbuf, + INET6_ADDRSTRLEN), + plen, + rai->ifname); + } + return; + } + delete_prefix(rai, prefix); + break; + case RTM_NEWADDR: + case RTM_DELADDR: + /* init ifflags because it may have changed */ + iflist[ifindex]->ifm_flags = + if_getflags(ifindex, + iflist[ifindex]->ifm_flags); + break; + case RTM_IFINFO: + iflist[ifindex]->ifm_flags = get_ifm_flags(next); + break; + default: + /* should not reach here */ + if (dflag > 1) { + syslog(LOG_DEBUG, + "<%s:%d> unknown rtmsg %d on %s", + __FUNCTION__, __LINE__, type, + if_indextoname(ifindex, ifname)); + } + return; + } + } + + return; +} + +void +rtadvd_input(skt) +{ + int i; + int *hlimp = NULL; + struct icmp6_hdr *icp; + int ifindex = 0; + struct cmsghdr *cm; + struct in6_pktinfo *pi = NULL; + u_char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ]; + struct in6_addr dst = in6addr_any; + + /* + * Get message. We reset msg_controllen since the field could + * be modified if we had received a message before setting + * receive options. + */ + rcvmhdr.msg_controllen = sizeof(rcvcmsgbuf); + if ((i = recvmsg(skt, &rcvmhdr, 0)) < 0) + return; + + /* extract optional information via Advanced API */ + for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&rcvmhdr); + cm; + cm = (struct cmsghdr *)CMSG_NXTHDR(&rcvmhdr, cm)) { + if (cm->cmsg_level == IPPROTO_IPV6 && + cm->cmsg_type == IPV6_PKTINFO && + cm->cmsg_len == CMSG_LEN(sizeof(struct in6_pktinfo))) { + pi = (struct in6_pktinfo *)(CMSG_DATA(cm)); + ifindex = pi->ipi6_ifindex; + dst = pi->ipi6_addr; + } + if (cm->cmsg_level == IPPROTO_IPV6 && + cm->cmsg_type == IPV6_HOPLIMIT && + cm->cmsg_len == CMSG_LEN(sizeof(int))) + hlimp = (int *)CMSG_DATA(cm); + } + if (ifindex == 0) { + syslog(LOG_ERR, + "<%s> failed to get receiving interface", + __FUNCTION__); + return; + } + if (hlimp == NULL) { + syslog(LOG_ERR, + "<%s> failed to get receiving hop limit", + __FUNCTION__); + return; + } + + if (i < sizeof(struct icmp6_hdr)) { + syslog(LOG_ERR, + "<%s> packet size(%d) is too short", + __FUNCTION__, i); + return; + } + + icp = (struct icmp6_hdr *)rcvmhdr.msg_iov[0].iov_base; + + switch(icp->icmp6_type) { + case ND_ROUTER_SOLICIT: + /* hop limit verification - RFC-2461 6.1.1 */ + if (*hlimp != 255) { + syslog(LOG_NOTICE, + "<%s> invalid hop limit(%d) " + "received from %s on %s", + __FUNCTION__, *hlimp, + inet_ntop(AF_INET6, &from.sin6_addr, ntopbuf, + INET6_ADDRSTRLEN), + if_indextoname(pi->ipi6_ifindex, ifnamebuf)); + return; + } + rs_input(i, (struct nd_router_solicit *)icp, pi, &from); + break; + case ND_ROUTER_ADVERT: + /* hop limit verification - RFC-2461 6.1.1 */ + if (*hlimp != 255) { + syslog(LOG_NOTICE, + "<%s> invalid hop limit(%d) " + "received from %s on %s", + __FUNCTION__, *hlimp, + inet_ntop(AF_INET6, &from.sin6_addr, ntopbuf, + INET6_ADDRSTRLEN), + if_indextoname(pi->ipi6_ifindex, ifnamebuf)); + return; + } + ra_input(i, (struct nd_router_advert *)icp, pi, &from); + break; + case ICMP6_ROUTER_RENUMBERING: + if (accept_rr == 0) { + syslog(LOG_ERR, + "<%s> received a router renumbering " + "message, but not allowed to be accepted", + __FUNCTION__); + break; + } + rr_input(i, (struct icmp6_router_renum *)icp, pi, &from, + &dst); + break; + default: + /* + * Note that this case is POSSIBLE, especially just + * after invocation of the daemon. This is because we + * could receive message after opening the socket and + * before setting ICMP6 type filter(see sock_open()). + */ + syslog(LOG_ERR, + "<%s> invalid icmp type(%d)", + __FUNCTION__, icp->icmp6_type); + return; + } + + return; +} + +static void +rs_input(int len, struct nd_router_solicit *rs, + struct in6_pktinfo *pi, struct sockaddr_in6 *from) +{ + u_char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ]; + union nd_opts ndopts; + struct rainfo *ra; + + syslog(LOG_DEBUG, + "<%s> RS received from %s on %s", + __FUNCTION__, + inet_ntop(AF_INET6, &from->sin6_addr, + ntopbuf, INET6_ADDRSTRLEN), + if_indextoname(pi->ipi6_ifindex, ifnamebuf)); + + /* ND option check */ + memset(&ndopts, 0, sizeof(ndopts)); + if (nd6_options((struct nd_opt_hdr *)(rs + 1), + len - sizeof(struct nd_router_solicit), + &ndopts, NDOPT_FLAG_SRCLINKADDR)) { + syslog(LOG_DEBUG, + "<%s> ND option check failed for an RS from %s on %s", + __FUNCTION__, + inet_ntop(AF_INET6, &from->sin6_addr, + ntopbuf, INET6_ADDRSTRLEN), + if_indextoname(pi->ipi6_ifindex, ifnamebuf)); + return; + } + + /* + * If the IP source address is the unspecified address, there + * must be no source link-layer address option in the message. + * (RFC-2461 6.1.1) + */ + if (IN6_IS_ADDR_UNSPECIFIED(&from->sin6_addr) && + ndopts.nd_opts_src_lladdr) { + syslog(LOG_ERR, + "<%s> RS from unspecified src on %s has a link-layer" + " address option", + __FUNCTION__, + if_indextoname(pi->ipi6_ifindex, ifnamebuf)); + goto done; + } + + ra = ralist; + while (ra != NULL) { + if (pi->ipi6_ifindex == ra->ifindex) + break; + ra = ra->next; + } + if (ra == NULL) { + syslog(LOG_INFO, + "<%s> RS received on non advertising interface(%s)", + __FUNCTION__, + if_indextoname(pi->ipi6_ifindex, ifnamebuf)); + goto done; + } + + /* + * Decide whether to send RA according to the rate-limit + * consideration. + */ + { + long delay; /* must not be greater than 1000000 */ + struct timeval interval, now, min_delay, tm_tmp, *rest; + + /* + * If there is already a waiting RS packet, don't + * update the timer. + */ + if (ra->waiting++) + goto done; + + /* + * Compute a random delay. If the computed value + * corresponds to a time later than the time the next + * multicast RA is scheduled to be sent, ignore the random + * delay and send the advertisement at the + * already-scheduled time. RFC-2461 6.2.6 + */ + delay = random() % MAX_RA_DELAY_TIME; + interval.tv_sec = 0; + interval.tv_usec = delay; + rest = rtadvd_timer_rest(ra->timer); + if (TIMEVAL_LT(*rest, interval)) { + syslog(LOG_DEBUG, + "<%s> random delay is larger than " + "the rest of normal timer", + __FUNCTION__); + interval = *rest; + } + + /* + * If we sent a multicast Router Advertisement within + * the last MIN_DELAY_BETWEEN_RAS seconds, schedule + * the advertisement to be sent at a time corresponding to + * MIN_DELAY_BETWEEN_RAS plus the random value after the + * previous advertisement was sent. + */ + gettimeofday(&now, NULL); + TIMEVAL_SUB(&now, &ra->lastsent, &tm_tmp); + min_delay.tv_sec = MIN_DELAY_BETWEEN_RAS; + min_delay.tv_usec = 0; + if (TIMEVAL_LT(tm_tmp, min_delay)) { + TIMEVAL_SUB(&min_delay, &tm_tmp, &min_delay); + TIMEVAL_ADD(&min_delay, &interval, &interval); + } + rtadvd_set_timer(&interval, ra->timer); + goto done; + } + + done: + free_ndopts(&ndopts); + return; +} + +static void +ra_input(int len, struct nd_router_advert *ra, + struct in6_pktinfo *pi, struct sockaddr_in6 *from) +{ + struct rainfo *rai; + u_char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ]; + union nd_opts ndopts; + char *on_off[] = {"OFF", "ON"}; + u_int32_t reachabletime, retranstimer, mtu; + + syslog(LOG_DEBUG, + "<%s> RA received from %s on %s", + __FUNCTION__, + inet_ntop(AF_INET6, &from->sin6_addr, + ntopbuf, INET6_ADDRSTRLEN), + if_indextoname(pi->ipi6_ifindex, ifnamebuf)); + + /* ND option check */ + memset(&ndopts, 0, sizeof(ndopts)); + if (nd6_options((struct nd_opt_hdr *)(ra + 1), + len - sizeof(struct nd_router_advert), + &ndopts, + NDOPT_FLAG_PREFIXINFO | NDOPT_FLAG_MTU)) { + syslog(LOG_ERR, + "<%s> ND option check failed for an RA from %s on %s", + __FUNCTION__, + inet_ntop(AF_INET6, &from->sin6_addr, + ntopbuf, INET6_ADDRSTRLEN), + if_indextoname(pi->ipi6_ifindex, ifnamebuf)); + return; + } + + /* + * RA consistency check according to RFC-2461 6.2.7 + */ + if ((rai = if_indextorainfo(pi->ipi6_ifindex)) == 0) { + syslog(LOG_INFO, + "<%s> received RA from %s on non-advertising" + " interface(%s)", + __FUNCTION__, + inet_ntop(AF_INET6, &from->sin6_addr, + ntopbuf, INET6_ADDRSTRLEN), + if_indextoname(pi->ipi6_ifindex, ifnamebuf)); + goto done; + } + /* Cur Hop Limit value */ + if (ra->nd_ra_curhoplimit && rai->hoplimit && + ra->nd_ra_curhoplimit != rai->hoplimit) { + syslog(LOG_WARNING, + "<%s> CurHopLimit inconsistent on %s:" + " %d from %s, %d from us", + __FUNCTION__, + rai->ifname, + ra->nd_ra_curhoplimit, + inet_ntop(AF_INET6, &from->sin6_addr, + ntopbuf, INET6_ADDRSTRLEN), + rai->hoplimit); + } + /* M flag */ + if ((ra->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED) != + rai->managedflg) { + syslog(LOG_WARNING, + "<%s> M flag inconsistent on %s:" + " %s from %s, %s from us", + __FUNCTION__, + rai->ifname, + on_off[!rai->managedflg], + inet_ntop(AF_INET6, &from->sin6_addr, + ntopbuf, INET6_ADDRSTRLEN), + on_off[rai->managedflg]); + } + /* O flag */ + if ((ra->nd_ra_flags_reserved & ND_RA_FLAG_OTHER) != + rai->otherflg) { + syslog(LOG_WARNING, + "<%s> O flag inconsistent on %s:" + " %s from %s, %s from us", + __FUNCTION__, + rai->ifname, + on_off[!rai->otherflg], + inet_ntop(AF_INET6, &from->sin6_addr, + ntopbuf, INET6_ADDRSTRLEN), + on_off[rai->otherflg]); + } + /* Reachable Time */ + reachabletime = ntohl(ra->nd_ra_reachable); + if (reachabletime && rai->reachabletime && + reachabletime != rai->reachabletime) { + syslog(LOG_WARNING, + "<%s> ReachableTime inconsistent on %s:" + " %d from %s, %d from us", + __FUNCTION__, + rai->ifname, + reachabletime, + inet_ntop(AF_INET6, &from->sin6_addr, + ntopbuf, INET6_ADDRSTRLEN), + rai->reachabletime); + } + /* Retrans Timer */ + retranstimer = ntohl(ra->nd_ra_retransmit); + if (retranstimer && rai->retranstimer && + retranstimer != rai->retranstimer) { + syslog(LOG_WARNING, + "<%s> RetranceTimer inconsistent on %s:" + " %d from %s, %d from us", + __FUNCTION__, + rai->ifname, + retranstimer, + inet_ntop(AF_INET6, &from->sin6_addr, + ntopbuf, INET6_ADDRSTRLEN), + rai->retranstimer); + } + /* Values in the MTU options */ + if (ndopts.nd_opts_mtu) { + mtu = ntohl(ndopts.nd_opts_mtu->nd_opt_mtu_mtu); + if (mtu && rai->linkmtu && mtu != rai->linkmtu) { + syslog(LOG_WARNING, + "<%s> MTU option value inconsistent on %s:" + " %d from %s, %d from us", + __FUNCTION__, + rai->ifname, mtu, + inet_ntop(AF_INET6, &from->sin6_addr, + ntopbuf, INET6_ADDRSTRLEN), + rai->linkmtu); + } + } + /* Preferred and Valid Lifetimes for prefixes */ + { + struct nd_optlist *optp = ndopts.nd_opts_list; + + if (ndopts.nd_opts_pi) + prefix_check(ndopts.nd_opts_pi, rai, from); + while (optp) { + prefix_check((struct nd_opt_prefix_info *)optp->opt, + rai, from); + optp = optp->next; + } + } + + done: + free_ndopts(&ndopts); + return; +} + +static void +prefix_check(struct nd_opt_prefix_info *pinfo, + struct rainfo *rai, struct sockaddr_in6 *from) +{ + u_int32_t preferred_time, valid_time; + struct prefix *pp; + u_char ntopbuf[INET6_ADDRSTRLEN], prefixbuf[INET6_ADDRSTRLEN]; + + /* + * log if the adveritsed prefix has link-local scope(sanity check?) + */ + if (IN6_IS_ADDR_LINKLOCAL(&pinfo->nd_opt_pi_prefix)) { + syslog(LOG_INFO, + "<%s> link-local prefix %s/%d is advertised " + "from %s on %s", + __FUNCTION__, + inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix, + prefixbuf, INET6_ADDRSTRLEN), + pinfo->nd_opt_pi_prefix_len, + inet_ntop(AF_INET6, &from->sin6_addr, + ntopbuf, INET6_ADDRSTRLEN), + rai->ifname); + } + + if ((pp = find_prefix(rai, &pinfo->nd_opt_pi_prefix, + pinfo->nd_opt_pi_prefix_len)) == NULL) { + syslog(LOG_INFO, + "<%s> prefix %s/%d from %s on %s is not in our list", + __FUNCTION__, + inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix, + prefixbuf, INET6_ADDRSTRLEN), + pinfo->nd_opt_pi_prefix_len, + inet_ntop(AF_INET6, &from->sin6_addr, + ntopbuf, INET6_ADDRSTRLEN), + rai->ifname); + return; + } + + preferred_time = ntohl(pinfo->nd_opt_pi_preferred_time); + if (preferred_time != pp->preflifetime) + syslog(LOG_WARNING, + "<%s> prefeerred lifetime for %s/%d" + " inconsistent on %s:" + " %d from %s, %d from us", + __FUNCTION__, + inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix, + prefixbuf, INET6_ADDRSTRLEN), + pinfo->nd_opt_pi_prefix_len, + rai->ifname, preferred_time, + inet_ntop(AF_INET6, &from->sin6_addr, + ntopbuf, INET6_ADDRSTRLEN), + pp->preflifetime); + + valid_time = ntohl(pinfo->nd_opt_pi_valid_time); + if (valid_time != pp->validlifetime) + syslog(LOG_WARNING, + "<%s> valid lifetime for %s/%d" + " inconsistent on %s:" + " %d from %s, %d from us", + __FUNCTION__, + inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix, + prefixbuf, INET6_ADDRSTRLEN), + pinfo->nd_opt_pi_prefix_len, + rai->ifname, valid_time, + inet_ntop(AF_INET6, &from->sin6_addr, + ntopbuf, INET6_ADDRSTRLEN), + pp->validlifetime); +} + +struct prefix * +find_prefix(struct rainfo *rai, struct in6_addr *prefix, int plen) +{ + struct prefix *pp; + int bytelen, bitlen; + + for (pp = rai->prefix.next; pp != &rai->prefix; pp = pp->next) { + if (plen != pp->prefixlen) + continue; + bytelen = plen / 8; + bitlen = plen % 8; + if (memcmp((void *)prefix, (void *)&pp->prefix, bytelen)) + continue; + if (prefix->s6_addr[bytelen] >> (8 - bitlen) == + pp->prefix.s6_addr[bytelen] >> (8 - bitlen)) + return(pp); + } + + return(NULL); +} + +static int +nd6_options(struct nd_opt_hdr *hdr, int limit, + union nd_opts *ndopts, u_int32_t optflags) +{ + int optlen = 0; + + for (; limit > 0; limit -= optlen) { + hdr = (struct nd_opt_hdr *)((caddr_t)hdr + optlen); + optlen = hdr->nd_opt_len << 3; + if (hdr->nd_opt_len == 0) { + syslog(LOG_ERR, + "<%s> bad ND option length(0) (type = %d)", + __FUNCTION__, hdr->nd_opt_type); + goto bad; + } + + if (hdr->nd_opt_type > ND_OPT_MTU) { + syslog(LOG_INFO, + "<%s> unknown ND option(type %d)", + __FUNCTION__, + hdr->nd_opt_type); + continue; + } + + if ((ndopt_flags[hdr->nd_opt_type] & optflags) == 0) { + syslog(LOG_INFO, + "<%s> unexpected ND option(type %d)", + __FUNCTION__, + hdr->nd_opt_type); + continue; + } + + switch(hdr->nd_opt_type) { + case ND_OPT_SOURCE_LINKADDR: + case ND_OPT_TARGET_LINKADDR: + case ND_OPT_REDIRECTED_HEADER: + case ND_OPT_MTU: + if (ndopts->nd_opt_array[hdr->nd_opt_type]) { + syslog(LOG_INFO, + "<%s> duplicated ND option" + " (type = %d)", + __FUNCTION__, + hdr->nd_opt_type); + } + ndopts->nd_opt_array[hdr->nd_opt_type] = hdr; + break; + case ND_OPT_PREFIX_INFORMATION: + { + struct nd_optlist *pfxlist; + + if (ndopts->nd_opts_pi == 0) { + ndopts->nd_opts_pi = + (struct nd_opt_prefix_info *)hdr; + continue; + } + if ((pfxlist = malloc(sizeof(*pfxlist))) == NULL) { + syslog(LOG_ERR, + "<%s> can't allocate memory", + __FUNCTION__); + goto bad; + } + pfxlist->next = ndopts->nd_opts_list; + pfxlist->opt = hdr; + ndopts->nd_opts_list = pfxlist; + + break; + } + default: /* impossible */ + break; + } + } + + return(0); + + bad: + free_ndopts(ndopts); + + return(-1); +} + +static void +free_ndopts(union nd_opts *ndopts) +{ + struct nd_optlist *opt = ndopts->nd_opts_list, *next; + + while(opt) { + next = opt->next; + free(opt); + opt = next; + } +} + +void +sock_open(int *sockp, int is_rr, char *policy) +{ + struct icmp6_filter filt; + struct ipv6_mreq mreq; + struct rainfo *ra = ralist; + int on; + char *rtr_str; + /* XXX: should be max MTU attached to the node */ + static u_char answer[1500]; + static u_char sndcmsgbuf[CMSG_SPACE(sizeof(struct in6_pktinfo)) + + CMSG_SPACE(sizeof(int))]; + + if ((*sockp = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) { + syslog(LOG_ERR, "<%s> socket: %s", __FUNCTION__, + strerror(errno)); + exit(1); + } + + /* specify to tell receiving interface */ + on = 1; + if (setsockopt(*sockp, IPPROTO_IPV6, IPV6_PKTINFO, &on, + sizeof(on)) < 0) { + syslog(LOG_ERR, "<%s> IPV6_PKTINFO: %s", + __FUNCTION__, strerror(errno)); + exit(1); + } + + on = 1; + /* specify to tell value of hoplimit field of received IP6 hdr */ + if (setsockopt(*sockp, IPPROTO_IPV6, IPV6_HOPLIMIT, &on, + sizeof(on)) < 0) { + syslog(LOG_ERR, "<%s> IPV6_HOPLIMIT: %s", + __FUNCTION__, strerror(errno)); + exit(1); + } + + ICMP6_FILTER_SETBLOCKALL(&filt); + if (is_rr) + ICMP6_FILTER_SETPASS(ICMP6_ROUTER_RENUMBERING, &filt); + else { + ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &filt); + ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filt); + } + if (setsockopt(*sockp, IPPROTO_ICMPV6, ICMP6_FILTER, &filt, + sizeof(filt)) < 0) { + syslog(LOG_ERR, "<%s> IICMP6_FILTER: %s", + __FUNCTION__, strerror(errno)); + exit(1); + } + + +#ifdef IPSEC +#ifdef IPSEC_POLICY_IPSEC + if (is_rr && policy != NULL) { + char *buf; + + buf = ipsec_set_policy(policy, strlen(policy)); + if (buf == NULL) + errx(EX_CONFIG, ipsec_strerror()); + if (setsockopt(*sockp, IPPROTO_IPV6, IPV6_IPSEC_POLICY, + buf, ipsec_get_policylen(buf)) < 0) + err(EX_CONFIG, "ipsec policy cannot be configured"); + free(buf); + } +#endif /*IPSEC_POLICY_IPSEC*/ +#endif /*IPSEC*/ + + /* + * join all routers multicast address on each advertising interface. + */ + rtr_str = is_rr ? ALLSITEROUTERS : ALLROUTERS; + if (inet_pton(AF_INET6, rtr_str, &mreq.ipv6mr_multiaddr.s6_addr) + != 1) { + syslog(LOG_ERR, "<%s> inet_pton for %s failed(library bug?)", + __FUNCTION__, rtr_str); + exit(1); + } + while(ra) { + mreq.ipv6mr_interface = ra->ifindex; + if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, + sizeof(mreq)) < 0) { + syslog(LOG_ERR, "<%s> IPV6_JOIN_GROUP for %s on" + "%s: %s", __FUNCTION__, + rtr_str, ra->ifname, strerror(errno)); + exit(1); + } + ra = ra->next; + } + if (is_rr) /* msghdrs should have been alreadey initialized. */ + return; + + /* initialize msghdr for receiving packets */ + rcviov[0].iov_base = (caddr_t)answer; + rcviov[0].iov_len = sizeof(answer); + rcvmhdr.msg_name = (caddr_t)&from; + rcvmhdr.msg_namelen = sizeof(from); + rcvmhdr.msg_iov = rcviov; + rcvmhdr.msg_iovlen = 1; + rcvmhdr.msg_control = (caddr_t) rcvcmsgbuf; + rcvmhdr.msg_controllen = sizeof(rcvcmsgbuf); + + /* initialize msghdr for sending packets */ + sndmhdr.msg_namelen = sizeof(struct sockaddr_in6); + sndmhdr.msg_iov = sndiov; + sndmhdr.msg_iovlen = 1; + sndmhdr.msg_control = (caddr_t)sndcmsgbuf; + sndmhdr.msg_controllen = sizeof(sndcmsgbuf); + + return; +} + +/* open a routing socket to watch the routing table */ +static void +rtsock_open() +{ + if ((rtsock = socket(PF_ROUTE, SOCK_RAW, 0)) < 0) { + syslog(LOG_ERR, + "<%s> socket: %s", __FUNCTION__, strerror(errno)); + exit(1); + } +} + +static struct rainfo * +if_indextorainfo(int index) +{ + struct rainfo *rai = ralist; + + for (rai = ralist; rai; rai = rai->next) { + if (rai->ifindex == index) + return(rai); + } + + return(NULL); /* search failed */ +} + +static void +ra_output(rainfo) +struct rainfo *rainfo; +{ + int i; + + struct cmsghdr *cm; + struct in6_pktinfo *pi; + + sndmhdr.msg_name = (caddr_t)&sin6_allnodes; + sndmhdr.msg_iov[0].iov_base = (caddr_t)rainfo->ra_data; + sndmhdr.msg_iov[0].iov_len = rainfo->ra_datalen; + + cm = CMSG_FIRSTHDR(&sndmhdr); + /* specify the outgoing interface */ + cm->cmsg_level = IPPROTO_IPV6; + cm->cmsg_type = IPV6_PKTINFO; + cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); + pi = (struct in6_pktinfo *)CMSG_DATA(cm); + memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr)); /*XXX*/ + pi->ipi6_ifindex = rainfo->ifindex; + + /* specify the hop limit of the packet */ + { + int hoplimit = 255; + + cm = CMSG_NXTHDR(&sndmhdr, cm); + cm->cmsg_level = IPPROTO_IPV6; + cm->cmsg_type = IPV6_HOPLIMIT; + cm->cmsg_len = CMSG_LEN(sizeof(int)); + memcpy(CMSG_DATA(cm), &hoplimit, sizeof(int)); + } + + syslog(LOG_DEBUG, + "<%s> send RA on %s, # of waitings = %d", + __FUNCTION__, rainfo->ifname, rainfo->waiting); + + i = sendmsg(sock, &sndmhdr, 0); + + if (i < 0 || i != rainfo->ra_datalen) { + if (i < 0) { + syslog(LOG_ERR, "<%s> sendmsg: %s", + __FUNCTION__, strerror(errno)); + } + } + + /* update counter */ + if (rainfo->initcounter < MAX_INITIAL_RTR_ADVERTISEMENTS) + rainfo->initcounter++; + + /* update timestamp */ + gettimeofday(&rainfo->lastsent, NULL); + + /* reset waiting conter */ + rainfo->waiting = 0; +} + +/* process RA timer */ +void +ra_timeout(void *data) +{ + struct rainfo *rai = (struct rainfo *)data; + +#ifdef notyet + /* if necessary, reconstruct the packet. */ +#endif + + syslog(LOG_DEBUG, + "<%s> RA timer on %s is expired", + __FUNCTION__, rai->ifname); + + if (iflist[rai->ifindex]->ifm_flags & IFF_UP) + ra_output(rai); + else + syslog(LOG_DEBUG, "<%s> %s is not up, skip sending RA", + __FUNCTION__, rai->ifname); +} + +/* update RA timer */ +void +ra_timer_update(void *data, struct timeval *tm) +{ + struct rainfo *rai = (struct rainfo *)data; + long interval; + + /* + * Whenever a multicast advertisement is sent from an interface, + * the timer is reset to a uniformly-distributed random value + * between the interface's configured MinRtrAdvInterval and + * MaxRtrAdvInterval(discovery-v2-02 6.2.4). + */ + interval = rai->mininterval; + interval += random() % (rai->maxinterval - rai->mininterval); + + /* + * For the first few advertisements (up to + * MAX_INITIAL_RTR_ADVERTISEMENTS), if the randomly chosen interval + * is greater than MAX_INITIAL_RTR_ADVERT_INTERVAL, the timer + * SHOULD be set to MAX_INITIAL_RTR_ADVERT_INTERVAL instead. + * (RFC-2461 6.2.4) + */ + if (rai->initcounter < MAX_INITIAL_RTR_ADVERTISEMENTS && + interval > MAX_INITIAL_RTR_ADVERT_INTERVAL) + interval = MAX_INITIAL_RTR_ADVERT_INTERVAL; + + tm->tv_sec = interval; + tm->tv_usec = 0; + + syslog(LOG_DEBUG, + "<%s> RA timer on %s is set to %ld:%ld", + __FUNCTION__, rai->ifname, tm->tv_sec, tm->tv_usec); + + return; +} diff --git a/usr.sbin/rtadvd/rtadvd.conf b/usr.sbin/rtadvd/rtadvd.conf new file mode 100644 index 0000000..f40a650 --- /dev/null +++ b/usr.sbin/rtadvd/rtadvd.conf @@ -0,0 +1,14 @@ +# $FreeBSD$ +# +# common definitions. +# +default:\ + :chlim#64:raflags#0:rltime#1800:rtime#30000:retrans#1000:\ + :pinfoflags#192:vltime#3600000:pltime#3600000:mtu#1500: +ether:\ + :mtu#1500:tc=default: +# +# interfaces. +# +ef0:\ + :addrs#1:addr="fec0:0:0:1000::":prefixlen#64:tc=ether: diff --git a/usr.sbin/rtadvd/rtadvd.conf.5 b/usr.sbin/rtadvd/rtadvd.conf.5 new file mode 100644 index 0000000..5d1fed2 --- /dev/null +++ b/usr.sbin/rtadvd/rtadvd.conf.5 @@ -0,0 +1,250 @@ +.\" Copyright (C) 1995, 1996, 1997, and 1998 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. +.\" +.\" $Id: rtadvd.conf.5,v 1.1.1.1 1999/08/08 23:31:42 itojun Exp $ +.\" $FreeBSD$ +.\" +.Dd May 17, 1998 +.Dt RTADVD.CONF 5 +.Os KAME +.Sh NAME +.Nm rtadvd.conf +.Nd config file for router advertisement daemon +.Sh DESCRIPTION +The file describes how the router advertisement packet must be constructed +for each of the interfaces. +.Pp +It obeys famous +.Xr termcap 5 +file format. +Each line in the file describes a network interface. +Fields are separated by a colon +.Po +.Dq \&: +.Pc , +and each field contains one capability description. +Lines may be concatenated by \e character. +The comment marker is `#' character. +.Pp +.Sh CAPABILITIES +Capabilities describe the value to be filled into ICMPv6 router +advertisement message and to control +.Xr rtadvd 8 +behavior. +Therefore, you are encouraged to read IETF neighbor discovery documents +if you would like to modify sample configuration file. +.Pp +Note that almost all items have default values. +If you omit an item, the default value of the item will be used. +.Pp +There are two items to control interval of sending router advertisements. +.Bl -tag -width indent +.It Cm \&maxinterval +(num) The maximum time allowed between sending unsolicited +multicast router advertisements +.Pq unit: seconds . +The default value is 600. Its value must be no less than 4 seconds +and no greater than 1800 seconds. +.It Cm \&mininterval +(num) The minimum time allowed between sending unsolicited multicast +router advertisements +.Pq unit: seconds . +The default value is the one third of value of +.Ic maxinterval. +Its value must be no less than 3 seconds and no greater than .75 * +the value of +.Ic maxinterval. +.El +.Pp +The following items are for ICMPv6 router advertisement message +header. +.Bl -tag -width indent +.It Cm \&chlim +(num) The value for Cur Hop Limit field. +The default value is 64. +.It Cm \&raflags +(num) Flags field in router advertisement message header. +Bit 7 +.Po +.Li 0x80 +.Pc +means Managed address configuration flag bit, +and Bit 6 +.Po +.Li 0x40 +.Pc +means Other stateful configuration flag bit. +The default value is 0. +.It Cm \&rltime +(num) Router lifetime field +.Pq unit: seconds . +Its value must be no greater than 3600000. +The default value is 1800. +.It Cm \&rtime +(num) Reachable time field +.Pq unit: milliseconds . +The default value is 0, which means unspecified by this router. +.It Cm \&retrans +(num) Retrans Timer field +.Pq unit: milliseconds . +The default value is 0, which means unspecified by this router. +.El +.Pp +The following items are for ICMPv6 prefix information option, +which will be attached to router advertisement header. +.Bl -tag -width indent +.It Cm \&addrs +(num) Number of prefixes. +Its default is 0, so it must explicitly be set to positve values +if you want to specify any prefix information option. +If its value is 0, +.Xr rtadvd 8 +looks up the system routing table and +advertise the prefixes corresponding to interface routes +on the interface. +If its value is more than 1, you must specify the index of the prefix +for each item below. +Indices vary from 0 to N-1, where N is the +value of +.Ic addrs. +Each index shall follows the name of each item, e.g. +.Dq prefixlen2 . +.It Cm \&prefixlen +(num) Prefix length field. +The default value is 64. +.It Cm \&pinfoflags +(num) Flags field in prefix information option. +Bit 7 +.Po +.Li 0x80 +.Pc +means On-link flag bit, +and Bit 6 +.Po +.Li 0x40 +.Pc +means Autonomous address-configuration flag bit. +The default value is 0xc0, i.e. both bits are set. +.It Cm \&addr +(str) The address filled into Prefix field. +Since +.Dq \&: +is used for +.Xr termcap 5 +file format as well as IPv6 numeric address, the field MUST be quoted by +doublequote character. +This field cannot be +omitted if the value of +.Ic addrs +is more than 0. +.It Cm \&vltime +(num) Valid lifetime field +.Pq unit: seconds . +The default value is 2592000(30 days). +.It Cm \&pltime +(num) Preferred lifetime field +.Pq unit: seconds . +The default value is 604800(7 days). +.El +.Pp +The following items are for ICMPv6 MTU option, +which will be attached to router advertisement header. +.Bl -tag -width indent +.It Cm \&mtu +(num or str) MTU (maximum transmission unit) field. +If 0 is specified, it means that the option will not be included. +The default value is 0. If the special string +.Dq auto +is specified for this item, MTU option will be included and its value +will be set to the interface MTU automatically. +.El +.Pp +The following item controls ICMPv6 source link-layer address option, +which will be attached to router advertisement header. +.Bl -tag -width indent +.It Cm \&nolladdr +(bool) By default +.Po +if +.Cm \&nolladdr +is not specified +.Pc , +.Xr rtadvd 8 +will try to get link-layer address for the interface from the kernel, +and attach that in source link-layer address option. +If this capability exists, +.Xr rtadvd 8 +will not attach source link-layer address option to +router advertisement packets. +.El +.Pp +You can also refer one line from another by using +.Cm tc +capability. +See +.Xr termcap 5 +for details on the capability. +.Sh EXAMPLE +.Bd -literal -offset +# +# common definitions. +# +default:\\ + :raflags#0:rltime#3600:\\ + :pinfoflags#64:vltime#360000:pltime#360000:mtu#1500: +ether:\\ + :mtu#1280:tc=default: + +# +# interfaces. +# +ef0:\\ + :addrs#1:\\ + :addr="3ffe:501:4819:1000::":tc=ether: +ef1:\\ + :addrs#2:addr0="3ffe:501:4819:2000::":\\ + :addr1="3ffe:501:4819:3000::":tc=ether: + +.Ed +.Sh SEE ALSO +.Xr termcap 5 , +.Xr rtadvd 8 , +.Xr rtsol 8 +.Pp +Thomas Narten, Erik Nordmark and W. A. Simpson, +.Do +Neighbor Discovery for IP version 6 (IPv6) +.Dc , +RFC 2461 +.Sh HISTORY +The +.Xr rtadvd 8 +and the configuration file +.Nm +first appeared in WIDE Hydrangea IPv6 protocol stack kit. +.\" .Sh BUGS +.\" (to be written) diff --git a/usr.sbin/rtadvd/rtadvd.h b/usr.sbin/rtadvd/rtadvd.h new file mode 100644 index 0000000..92fbcdf --- /dev/null +++ b/usr.sbin/rtadvd/rtadvd.h @@ -0,0 +1,107 @@ +/* + * Copyright (C) 1998 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. + * + * $FreeBSD$ + */ + +#define ALLNODES "ff02::1" +#define ALLROUTERS "ff02::2" +#define ALLSITEROUTERS "ff05::2" +#define ANY "::" +#define RTSOLLEN 8 + +/* protocol constants and default values */ +#define DEF_MAXRTRADVINTERVAL 600 +#define DEF_ADVLINKMTU 0 +#define DEF_ADVREACHABLETIME 0 +#define DEF_ADVRETRANSTIMER 0 +#define DEF_ADVCURHOPLIMIT 64 +#define DEF_ADVVALIDLIFETIME 2592000 +#define DEF_ADVPREFERREDLIFETIME 604800 + +#define MAXROUTERLIFETIME 9000 +#define MIN_MAXINTERVAL 4 +#define MAX_MAXINTERVAL 1800 +#define MIN_MININTERVAL 3 +#define MAXREACHABLETIME 3600000 + +#define MAX_INITIAL_RTR_ADVERT_INTERVAL 16 +#define MAX_INITIAL_RTR_ADVERTISEMENTS 3 +#define MAX_FINAL_RTR_ADVERTISEMENTS 3 +#define MIN_DELAY_BETWEEN_RAS 3 +#define MAX_RA_DELAY_TIME 500000 /* usec */ + +struct prefix { + struct prefix *next; /* forward link */ + struct prefix *prev; /* previous link */ + + u_int32_t validlifetime; /* AdvValidLifetime */ + u_int32_t preflifetime; /* AdvPreferredLifetime */ + u_int onlinkflg; /* bool: AdvOnLinkFlag */ + u_int autoconfflg; /* bool: AdvAutonomousFlag */ + int prefixlen; + struct in6_addr prefix; +}; + +struct rainfo { + /* pointer for list */ + struct rainfo *next; + + /* timer related parameters */ + struct rtadvd_timer *timer; + int initcounter; /* counter for the first few advertisements */ + struct timeval lastsent; /* timestamp when the lates RA was sent */ + int waiting; /* number of RS waiting for RA */ + + /* interface information */ + int ifindex; + int advlinkopt; /* bool: whether include link-layer addr opt */ + struct sockaddr_dl *sdl; + char ifname[16]; + int phymtu; /* mtu of the physical interface */ + + /* Router configuration variables */ + u_short lifetime; /* AdvDefaultLifetime */ + u_int maxinterval; /* MaxRtrAdvInterval */ + u_int mininterval; /* MinRtrAdvInterval */ + int managedflg; /* AdvManagedFlag */ + int otherflg; /* AdvOtherConfigFlag */ + u_int32_t linkmtu; /* AdvLinkMTU */ + u_int32_t reachabletime; /* AdvReachableTime */ + u_int32_t retranstimer; /* AdvRetransTimer */ + u_int hoplimit; /* AdvCurHopLimit */ + struct prefix prefix; /* AdvPrefixList(link head) */ + int pfxs; /* number of prefixes */ + + /* actual RA packet data and its length */ + size_t ra_datalen; + u_char *ra_data; +}; + +void ra_timeout __P((void *)); +void ra_timer_update __P((void *, struct timeval *)); diff --git a/usr.sbin/rtadvd/timer.c b/usr.sbin/rtadvd/timer.c new file mode 100644 index 0000000..f93968a --- /dev/null +++ b/usr.sbin/rtadvd/timer.c @@ -0,0 +1,201 @@ +/* + * Copyright (C) 1998 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. + * + * $FreeBSD$ + */ + +#include <sys/time.h> + +#include <unistd.h> +#include <syslog.h> +#include <stdlib.h> +#include <string.h> +#ifdef __NetBSD__ +#include <search.h> +#endif +#include "timer.h" + +static struct rtadvd_timer timer_head; + +#define MILLION 1000000 + +static struct timeval tm_max = {0x7fffffff, 0x7fffffff}; + +void +rtadvd_timer_init() +{ + memset(&timer_head, 0, sizeof(timer_head)); + + timer_head.next = timer_head.prev = &timer_head; + timer_head.tm = tm_max; +} + +struct rtadvd_timer * +rtadvd_add_timer(void (*timeout) __P((void *)), + void (*update) __P((void *, struct timeval *)), + void *timeodata, void *updatedata) +{ + struct rtadvd_timer *newtimer; + + if ((newtimer = malloc(sizeof(*newtimer))) == NULL) { + syslog(LOG_ERR, + "<%s> can't allocate memory", __FUNCTION__); + exit(1); + } + + memset(newtimer, 0, sizeof(*newtimer)); + + if (timeout == NULL) { + syslog(LOG_ERR, + "<%s> timeout function unspecfied", __FUNCTION__); + exit(1); + } + if (update == NULL) { + syslog(LOG_ERR, + "<%s> update function unspecfied", __FUNCTION__); + exit(1); + } + newtimer->expire = timeout; + newtimer->update = update; + newtimer->expire_data = timeodata; + newtimer->update_data = updatedata; + newtimer->tm = tm_max; + + /* link into chain */ + insque(newtimer, &timer_head); + + return(newtimer); +} + +void +rtadvd_set_timer(struct timeval *tm, struct rtadvd_timer *timer) +{ + struct timeval now; + + /* reset the timer */ + gettimeofday(&now, NULL); + + TIMEVAL_ADD(&now, tm, &timer->tm); + + /* update the next expiration time */ + if (TIMEVAL_LT(timer->tm, timer_head.tm)) + timer_head.tm = timer->tm; + + return; +} + +/* + * Check expiration for each timer. If a timer is expired, + * call the expire function for the timer and update the timer. + * Return the next interval for select() call. + */ +struct timeval * +rtadvd_check_timer() +{ + static struct timeval returnval; + struct timeval now; + struct rtadvd_timer *tm = timer_head.next; + + gettimeofday(&now, NULL); + + timer_head.tm = tm_max; + + while(tm != &timer_head) { + if (TIMEVAL_LEQ(tm->tm, now)) { + (*tm->expire)(tm->expire_data); + (*tm->update)(tm->update_data, &tm->tm); + TIMEVAL_ADD(&tm->tm, &now, &tm->tm); + } + + if (TIMEVAL_LT(tm->tm, timer_head.tm)) + timer_head.tm = tm->tm; + + tm = tm->next; + } + + if (TIMEVAL_LT(timer_head.tm, now)) { + /* this may occur when the interval is too small */ + returnval.tv_sec = returnval.tv_usec = 0; + } + else + TIMEVAL_SUB(&timer_head.tm, &now, &returnval); + return(&returnval); +} + +struct timeval * +rtadvd_timer_rest(struct rtadvd_timer *timer) +{ + static struct timeval returnval, now; + + gettimeofday(&now, NULL); + if (TIMEVAL_LEQ(timer->tm, now)) { + syslog(LOG_DEBUG, + "<%s> a timer must be expired, but not yet", + __FUNCTION__); + returnval.tv_sec = returnval.tv_usec = 0; + } + else + TIMEVAL_SUB(&timer->tm, &now, &returnval); + + return(&returnval); +} + +/* result = a + b */ +void +TIMEVAL_ADD(struct timeval *a, struct timeval *b, struct timeval *result) +{ + long l; + + if ((l = a->tv_usec + b->tv_usec) < MILLION) { + result->tv_usec = l; + result->tv_sec = a->tv_sec + b->tv_sec; + } + else { + result->tv_usec = l - MILLION; + result->tv_sec = a->tv_sec + b->tv_sec + 1; + } +} + +/* + * result = a - b + * XXX: this function assumes that a >= b. + */ +void +TIMEVAL_SUB(struct timeval *a, struct timeval *b, struct timeval *result) +{ + long l; + + if ((l = a->tv_usec - b->tv_usec) >= 0) { + result->tv_usec = l; + result->tv_sec = a->tv_sec - b->tv_sec; + } + else { + result->tv_usec = MILLION + l; + result->tv_sec = a->tv_sec - b->tv_sec - 1; + } +} diff --git a/usr.sbin/rtadvd/timer.h b/usr.sbin/rtadvd/timer.h new file mode 100644 index 0000000..e9f2c35 --- /dev/null +++ b/usr.sbin/rtadvd/timer.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 1998 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. + * + * $FreeBSD$ + */ + +/* a < b */ +#define TIMEVAL_LT(a, b) (((a).tv_sec < (b).tv_sec) ||\ + (((a).tv_sec == (b).tv_sec) && \ + ((a).tv_usec < (b).tv_usec))) + +/* a <= b */ +#define TIMEVAL_LEQ(a, b) (((a).tv_sec < (b).tv_sec) ||\ + (((a).tv_sec == (b).tv_sec) &&\ + ((a).tv_usec <= (b).tv_usec))) + +struct rtadvd_timer { + struct rtadvd_timer *next; + struct rtadvd_timer *prev; + struct rainfo *rai; + struct timeval tm; + + void (*expire) __P((void *)); /* expiration function */ + void *expire_data; + void (*update) __P((void *, struct timeval *)); /* update function */ + void *update_data; +}; + +void rtadvd_timer_init __P((void)); +struct rtadvd_timer *rtadvd_add_timer __P((void (*) __P((void *)), + void (*) __P((void *, struct timeval *)), void *, void *)); +void rtadvd_set_timer __P((struct timeval *, struct rtadvd_timer *)); +struct timeval * rtadvd_check_timer __P((void)); +struct timeval * rtadvd_timer_rest __P((struct rtadvd_timer *)); +void TIMEVAL_ADD __P((struct timeval *, struct timeval *, + struct timeval *)); +void TIMEVAL_SUB __P((struct timeval *, struct timeval *, + struct timeval *)); diff --git a/usr.sbin/setkey/Makefile b/usr.sbin/setkey/Makefile new file mode 100644 index 0000000..918dbf4 --- /dev/null +++ b/usr.sbin/setkey/Makefile @@ -0,0 +1,56 @@ +# Copyright (C) 1995, 1996, 1997, 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. +# $FreeBSD$ + +PROG= setkey +SRCS= setkey.c parse.y token.l +CFLAGS+=-g +LDADD+= -ll -ly +CLEANFILES+= y.tab.c y.tab.h key_test.o keytest +YFLAGS+=-d + +SCRIPTS= scriptdump + +BINOWN = root +BINGRP = bin +BINMODE = 555 + +all: ${PROG} scriptdump + +SRCS+=y.tab.h +y.tab.h: parse.y +CFLAGS+=-DIPSEC_DEBUG -DINET6 -DYY_NO_UNPUT -I${.OBJDIR} +LDADD+= -lipsec +CLEANFILES+= scriptdump y.tab.h + +MAN8= setkey.8 +LOCALPREFIX= /usr/local + +scriptdump: scriptdump.pl + sed -e 's#@LOCALPREFIX@#${LOCALPREFIX}#' < $> > scriptdump + +.include <bsd.prog.mk> diff --git a/usr.sbin/setkey/parse.y b/usr.sbin/setkey/parse.y new file mode 100644 index 0000000..761c34d --- /dev/null +++ b/usr.sbin/setkey/parse.y @@ -0,0 +1,787 @@ +/* + * Copyright (C) 1995, 1996, 1997, 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. + * + * $FreeBSD$ + */ +/* KAME $Id: parse.y,v 1.7 1999/10/27 17:08:57 sakane Exp $ */ + +%{ +#include <sys/types.h> +#include <sys/param.h> +#include <sys/socket.h> + +#include <net/route.h> +#include <netinet/in.h> +#include <net/pfkeyv2.h> +#include <netkey/key_var.h> +#include <netinet6/ipsec.h> +#include <arpa/inet.h> + +#include <string.h> +#include <unistd.h> +#include <stdio.h> +#include <ctype.h> +#include <errno.h> +#include <netdb.h> + +#include "vchar.h" + +#define ATOX(c) \ + (isdigit(c) ? (c - '0') : (isupper(c) ? (c - 'A' + 10) : (c - 'a' + 10) )) + +u_int p_type; +u_int32_t p_spi; +struct sockaddr *p_src, *p_dst; +u_int p_prefs, p_prefd, p_upper; +u_int p_satype, p_ext, p_alg_enc, p_alg_auth, p_replay, p_mode; +u_int p_key_enc_len, p_key_auth_len; +caddr_t p_key_enc, p_key_auth; +time_t p_lt_hard, p_lt_soft; + +u_int p_policy_len; +char *p_policy; + +/* temporary buffer */ +static struct sockaddr *pp_addr; +static u_int pp_prefix; +static u_int pp_port; +static caddr_t pp_key; + +extern u_char m_buf[BUFSIZ]; +extern int m_len; +extern char cmdarg[8192]; +extern int f_debug; + +int setkeymsg __P((void)); +static int setvarbuf __P((int *, struct sadb_ext *, int, caddr_t, int)); +void parse_init __P((void)); +void free_buffer __P((void)); + +extern int setkeymsg __P((void)); +extern int sendkeymsg __P((void)); + +extern int yylex __P((void)); +extern void yyerror __P((char *)); +%} + +%union { + unsigned long num; + vchar_t val; +} + +%token EOT +%token ADD GET DELETE FLUSH DUMP +%token IP4_ADDRESS IP6_ADDRESS PREFIX PORT PORTANY +%token UP_PROTO PR_ESP PR_AH PR_IPCOMP +%token F_PROTOCOL F_AUTH F_ENC F_REPLAY F_COMP F_RAWCPI +%token F_MODE MODE +%token F_EXT EXTENSION +%token ALG_AUTH ALG_ENC ALG_ENC_DESDERIV ALG_ENC_DES32IV ALG_COMP +%token F_LIFETIME_HARD F_LIFETIME_SOFT +%token DECSTRING QUOTEDSTRING HEXSTRING ANY + /* SPD management */ +%token SPDADD SPDDELETE SPDDUMP SPDFLUSH +%token F_POLICY PL_REQUESTS + +%% +commands + : /*NOTHING*/ + | commands command + { + if (f_debug) { + printf("cmdarg:\n%s\n", cmdarg); + } else { + setkeymsg(); + sendkeymsg(); + } + free_buffer(); + parse_init(); + } + ; + +command + : add_command + | get_command + | delete_command + | flush_command + | dump_command + | spdadd_command + | spddelete_command + | spddump_command + | spdflush_command + ; + /* commands concerned with management, there is in tail of this file. */ + + /* add command */ +add_command + : ADD { p_type = SADB_ADD; } + sa_selector_spec extension_spec algorithm_spec EOT + ; + + /* delete */ +delete_command + : DELETE { p_type = SADB_DELETE; } + sa_selector_spec extension_spec EOT + ; + + /* get command */ +get_command + : GET { p_type = SADB_GET; } + sa_selector_spec extension_spec EOT + ; + + /* flush */ +flush_command + : FLUSH { p_type = SADB_FLUSH; } + protocol_spec EOT + ; + + /* dump */ +dump_command + : DUMP { p_type = SADB_DUMP; } + protocol_spec EOT + ; + + /* sa_selector_spec */ +sa_selector_spec + : ipaddress { p_src = pp_addr; } + ipaddress { p_dst = pp_addr; } + protocol_spec spi + ; + +protocol_spec + : /*NOTHING*/ { p_satype = SADB_SATYPE_UNSPEC; } + | PR_ESP + { + p_satype = SADB_SATYPE_ESP; + if ($1.num == 1) + p_ext |= SADB_X_EXT_OLD; + else + p_ext &= ~SADB_X_EXT_OLD; + } + | PR_AH + { + p_satype = SADB_SATYPE_AH; + if ($1.num == 1) + p_ext |= SADB_X_EXT_OLD; + else + p_ext &= ~SADB_X_EXT_OLD; + } + | PR_IPCOMP + { + p_satype = SADB_X_SATYPE_IPCOMP; + } + ; + +spi + : DECSTRING { p_spi = $1.num; } + | HEXSTRING + { + caddr_t bp; + caddr_t yp = $1.val.buf; + char buf0[4], buf[4]; + int i, j; + + /* sanity check */ + if ($1.val.len > 4) { + yyerror("SPI too big."); + free($1.val.buf); + return -1; + } + + bp = buf0; + while (*yp) { + *bp = (ATOX(yp[0]) << 4) | ATOX(yp[1]); + yp += 2, bp++; + } + + /* initialize */ + for (i = 0; i < 4; i++) buf[i] = 0; + + for (j = $1.val.len - 1, i = 3; j >= 0; j--, i--) + buf[i] = buf0[j]; + + /* XXX: endian */ + p_spi = ntohl(*(u_int32_t *)buf); + + free($1.val.buf); + } + ; + +algorithm_spec + : esp_spec + | ah_spec + | ipcomp_spec + ; + +esp_spec + : F_ENC enc_alg enc_key F_AUTH auth_alg auth_key + | F_ENC enc_alg enc_key + ; + +ah_spec + : F_AUTH auth_alg auth_key + ; + +ipcomp_spec + : F_COMP ALG_COMP { p_alg_enc = $2.num; } + | F_COMP ALG_COMP { p_alg_enc = $2.num; } + F_RAWCPI { p_ext |= SADB_X_EXT_RAWCPI; } + ; + +enc_alg + : ALG_ENC { p_alg_enc = $1.num; } + | ALG_ENC_DESDERIV + { + p_alg_enc = $1.num; + if (p_ext & SADB_X_EXT_OLD) { + yyerror("algorithm mismatched."); + return -1; + } + p_ext |= SADB_X_EXT_DERIV; + } + | ALG_ENC_DES32IV + { + p_alg_enc = $1.num; + if (!(p_ext & SADB_X_EXT_OLD)) { + yyerror("algorithm mismatched."); + return -1; + } + p_ext |= SADB_X_EXT_IV4B; + } + ; + +enc_key + : /*NOTHING*/ + { + if (p_alg_enc != SADB_EALG_NULL) { + yyerror("no key found."); + return -1; + } + } + | key_string + { + p_key_enc_len = $1.val.len; + p_key_enc = pp_key; + + if (ipsec_check_keylen(SADB_EXT_SUPPORTED_ENCRYPT, + p_alg_enc, + PFKEY_UNUNIT64(p_key_enc_len)) < 0) { + yyerror(ipsec_strerror()); + return -1; + } + } + ; + +auth_alg + : ALG_AUTH { p_alg_auth = $1.num; } + ; + +auth_key + : /*NOTHING*/ + { + if (p_alg_auth != SADB_AALG_NULL) { + yyerror("no key found."); + return -1; + } + } + | key_string + { + p_key_auth_len = $1.val.len; + p_key_auth = pp_key; + + if (ipsec_check_keylen(SADB_EXT_SUPPORTED_AUTH, + p_alg_auth, + PFKEY_UNUNIT64(p_key_auth_len)) < 0) { + yyerror(ipsec_strerror()); + return -1; + } + } + ; + +key_string + : QUOTEDSTRING + { + pp_key = $1.val.buf; + /* free pp_key later */ + } + | HEXSTRING + { + caddr_t bp; + caddr_t yp = $1.val.buf; + + if ((pp_key = malloc($1.val.len)) == 0) { + free($1.val.buf); + yyerror(strerror(errno)); + return -1; + } + memset(pp_key, 0, $1.val.len); + + bp = pp_key; + while (*yp) { + *bp = (ATOX(yp[0]) << 4) | ATOX(yp[1]); + yp += 2, bp++; + } + + free($1.val.buf); + } + ; + +extension_spec + : /*NOTHING*/ + | extension_spec extension + ; + +extension + : F_EXT EXTENSION { p_ext |= $1.num; } + | F_MODE MODE { p_mode = $2.num; } + | F_MODE ANY { p_mode = IPSEC_MODE_ANY; } + | F_REPLAY DECSTRING + { + if (p_ext & SADB_X_EXT_OLD) { + yyerror("replay prevention " + "only use on new spec."); + return -1; + } + p_replay = $2.num; + } + | F_LIFETIME_HARD DECSTRING { p_lt_hard = $2.num; } + | F_LIFETIME_SOFT DECSTRING { p_lt_soft = $2.num; } + ; + + /* definition about command for SPD management */ + /* spdadd */ +spdadd_command + : SPDADD + { + p_type = SADB_X_SPDADD; + p_satype = SADB_SATYPE_UNSPEC; + } + sp_selector_spec policy_spec EOT + ; + +spddelete_command: + SPDDELETE + { + p_type = SADB_X_SPDDELETE; + p_satype = SADB_SATYPE_UNSPEC; + } + sp_selector_spec EOT + ; + +spddump_command: + SPDDUMP + { + p_type = SADB_X_SPDDUMP; + p_satype = SADB_SATYPE_UNSPEC; + } + EOT + ; + +spdflush_command: + SPDFLUSH + { + p_type = SADB_X_SPDFLUSH; + p_satype = SADB_SATYPE_UNSPEC; + } + EOT + ; + + /* sp_selector_spec */ +sp_selector_spec + : ipaddress { p_src = pp_addr; } + prefix { p_prefs = pp_prefix; } + port { _INPORTBYSA(p_src) = htons(pp_port); } + ipaddress { p_dst = pp_addr; } + prefix { p_prefd = pp_prefix; } + port { _INPORTBYSA(p_dst) = htons(pp_port); } + upper_spec + ; + +ipaddress + : IP4_ADDRESS + { + struct sockaddr_in *in; + u_int sa_len = $1.val.len; + + if ((in = (struct sockaddr_in *)malloc(sa_len)) == 0) { + yyerror(strerror(errno)); + free($1.val.buf); + return -1; + } + memset((caddr_t)in, 0, sa_len); + + in->sin_family = PF_INET; + in->sin_len = sa_len; + in->sin_port = IPSEC_PORT_ANY; + (void)inet_pton(PF_INET, $1.val.buf, &in->sin_addr); + + pp_addr = (struct sockaddr *)in; + free($1.val.buf); + } + | IP6_ADDRESS + { +#ifdef INET6 + struct sockaddr_in6 *in6; + u_int sa_len = $1.val.len; + struct addrinfo hints, *res; + int ret_gai; + + if ((in6 = (struct sockaddr_in6 *)malloc(sa_len)) == 0) { + free($1.val.buf); + yyerror(strerror(errno)); + return -1; + } + memset((caddr_t)in6, 0, sa_len); + + bzero(&hints, sizeof(struct addrinfo)); + hints.ai_flags = AI_NUMERICHOST; + hints.ai_family = AF_INET6; + ret_gai = getaddrinfo($1.val.buf, NULL, &hints, &res); + if (ret_gai) { + free($1.val.buf); + free(in6); + yyerror(gai_strerror(ret_gai)); + if (ret_gai == EAI_SYSTEM) + yyerror(strerror(errno)); + return -1; + } + (void)memcpy(in6, res->ai_addr, res->ai_addrlen); + + /* + * XXX: If the scope of the destination is link-local, + * embed the scope-id(in this case, interface index) + * into the address. + */ + if (IN6_IS_ADDR_LINKLOCAL(&in6->sin6_addr) && + in6->sin6_scope_id != 0) + *(u_short *)&in6->sin6_addr.s6_addr[2] = + htons(in6->sin6_scope_id & 0xffff); + + freeaddrinfo(res); + + pp_addr = (struct sockaddr *)in6; +#else + yyerror("IPv6 address not supported"); +#endif + free($1.val.buf); + } + ; + +prefix + : /*NOTHING*/ { pp_prefix = ~0; } + | PREFIX { pp_prefix = $1.num; } + ; + +port + : /*NOTHING*/ { pp_port = IPSEC_PORT_ANY; } + | PORT { pp_port = $1.num; } + | PORTANY { pp_port = IPSEC_PORT_ANY; } + ; + +upper_spec + : DECSTRING { p_upper = $1.num; } + | UP_PROTO { p_upper = $1.num; } + | PR_ESP { p_upper = IPPROTO_ESP; }; + | PR_AH { p_upper = IPPROTO_AH; }; + | PR_IPCOMP { p_upper = IPPROTO_IPCOMP; }; + | ANY { p_upper = IPSEC_ULPROTO_ANY; } + ; + +policy_spec + : F_POLICY policy_requests + { + p_policy = ipsec_set_policy($2.val.buf, $2.val.len); + if (p_policy == NULL) { + free($2.val.buf); + p_policy = NULL; + yyerror(ipsec_strerror()); + return -1; + } + + p_policy_len = ipsec_get_policylen(p_policy); + + free($2.val.buf); + } + ; + +policy_requests: + /*NOTHING*/ + | PL_REQUESTS { $$ = $1; } + ; + +%% + +int +setkeymsg() +{ + struct sadb_msg m_msg; + + m_msg.sadb_msg_version = PF_KEY_V2; + m_msg.sadb_msg_type = p_type; + m_msg.sadb_msg_errno = 0; + m_msg.sadb_msg_satype = p_satype; + m_msg.sadb_msg_mode = p_mode; + m_msg.sadb_msg_reserved = 0; + m_msg.sadb_msg_seq = 0; + m_msg.sadb_msg_pid = getpid(); + + m_len = sizeof(struct sadb_msg); + memcpy(m_buf, &m_msg, m_len); + + switch (p_type) { + case SADB_FLUSH: + case SADB_DUMP: + break; + + case SADB_ADD: + /* set encryption algorithm, if present. */ + if (p_satype != SADB_X_SATYPE_IPCOMP && p_alg_enc != SADB_EALG_NONE) { + struct sadb_key m_key; + + m_key.sadb_key_len = + PFKEY_UNIT64(sizeof(m_key) + + PFKEY_ALIGN8(p_key_enc_len)); + m_key.sadb_key_exttype = SADB_EXT_KEY_ENCRYPT; + m_key.sadb_key_bits = p_key_enc_len * 8; + m_key.sadb_key_reserved = 0; + + setvarbuf(&m_len, + (struct sadb_ext *)&m_key, sizeof(m_key), + (caddr_t)p_key_enc, p_key_enc_len); + } + + /* set authentication algorithm, if present. */ + if (p_alg_auth != SADB_AALG_NONE) { + struct sadb_key m_key; + + m_key.sadb_key_len = + PFKEY_UNIT64(sizeof(m_key) + + PFKEY_ALIGN8(p_key_auth_len)); + m_key.sadb_key_exttype = SADB_EXT_KEY_AUTH; + m_key.sadb_key_bits = p_key_auth_len * 8; + m_key.sadb_key_reserved = 0; + + setvarbuf(&m_len, + (struct sadb_ext *)&m_key, sizeof(m_key), + (caddr_t)p_key_auth, p_key_auth_len); + } + + /* set lifetime for HARD */ + if (p_lt_hard != 0) { + struct sadb_lifetime m_lt; + u_int len = sizeof(struct sadb_lifetime); + + m_lt.sadb_lifetime_len = PFKEY_UNIT64(len); + m_lt.sadb_lifetime_exttype = SADB_EXT_LIFETIME_HARD; + m_lt.sadb_lifetime_allocations = 0; + m_lt.sadb_lifetime_bytes = 0; + m_lt.sadb_lifetime_addtime = p_lt_hard; + m_lt.sadb_lifetime_usetime = 0; + + memcpy(m_buf + m_len, &m_lt, len); + m_len += len; + } + + /* set lifetime for SOFT */ + if (p_lt_soft != 0) { + struct sadb_lifetime m_lt; + u_int len = sizeof(struct sadb_lifetime); + + m_lt.sadb_lifetime_len = PFKEY_UNIT64(len); + m_lt.sadb_lifetime_exttype = SADB_EXT_LIFETIME_SOFT; + m_lt.sadb_lifetime_allocations = 0; + m_lt.sadb_lifetime_bytes = 0; + m_lt.sadb_lifetime_addtime = p_lt_soft; + m_lt.sadb_lifetime_usetime = 0; + + memcpy(m_buf + m_len, &m_lt, len); + m_len += len; + } + /* FALLTHROUGH */ + + case SADB_DELETE: + case SADB_GET: + { + struct sadb_sa m_sa; + struct sadb_address m_addr; + u_int len; + + len = sizeof(struct sadb_sa); + m_sa.sadb_sa_len = PFKEY_UNIT64(len); + m_sa.sadb_sa_exttype = SADB_EXT_SA; + m_sa.sadb_sa_spi = htonl(p_spi); + m_sa.sadb_sa_replay = p_replay; + m_sa.sadb_sa_state = 0; + m_sa.sadb_sa_auth = p_alg_auth; + m_sa.sadb_sa_encrypt = p_alg_enc; + m_sa.sadb_sa_flags = p_ext; + + memcpy(m_buf + m_len, &m_sa, len); + m_len += len; + + /* set src */ + m_addr.sadb_address_len = + PFKEY_UNIT64(sizeof(m_addr) + + PFKEY_ALIGN8(p_src->sa_len)); + m_addr.sadb_address_exttype = SADB_EXT_ADDRESS_SRC; + m_addr.sadb_address_proto = IPSEC_ULPROTO_ANY; + m_addr.sadb_address_prefixlen = + _INALENBYAF(p_src->sa_family) << 3; + m_addr.sadb_address_reserved = 0; + + setvarbuf(&m_len, + (struct sadb_ext *)&m_addr, sizeof(m_addr), + (caddr_t)p_src, p_src->sa_len); + + /* set dst */ + m_addr.sadb_address_len = + PFKEY_UNIT64(sizeof(m_addr) + + PFKEY_ALIGN8(p_dst->sa_len)); + m_addr.sadb_address_exttype = SADB_EXT_ADDRESS_DST; + m_addr.sadb_address_proto = IPSEC_ULPROTO_ANY; + m_addr.sadb_address_prefixlen = + _INALENBYAF(p_dst->sa_family) << 3; + m_addr.sadb_address_reserved = 0; + + setvarbuf(&m_len, + (struct sadb_ext *)&m_addr, sizeof(m_addr), + (caddr_t)p_dst, p_dst->sa_len); + } + break; + + /* for SPD management */ + case SADB_X_SPDFLUSH: + case SADB_X_SPDDUMP: + break; + + case SADB_X_SPDADD: + { + memcpy(m_buf + m_len, p_policy, p_policy_len); + m_len += p_policy_len; + free(p_policy); + p_policy = NULL; + } + /* FALLTHROUGH */ + + case SADB_X_SPDDELETE: + { + struct sadb_address m_addr; + + /* set src */ + m_addr.sadb_address_len = + PFKEY_UNIT64(sizeof(m_addr) + + PFKEY_ALIGN8(p_src->sa_len)); + m_addr.sadb_address_exttype = SADB_EXT_ADDRESS_SRC; + m_addr.sadb_address_proto = p_upper; + m_addr.sadb_address_prefixlen = + (p_prefs != ~0 ? p_prefs : + _INALENBYAF(p_src->sa_family) << 3); + m_addr.sadb_address_reserved = 0; + + setvarbuf(&m_len, + (struct sadb_ext *)&m_addr, sizeof(m_addr), + (caddr_t)p_src, p_src->sa_len); + + /* set dst */ + m_addr.sadb_address_len = + PFKEY_UNIT64(sizeof(m_addr) + + PFKEY_ALIGN8(p_dst->sa_len)); + m_addr.sadb_address_exttype = SADB_EXT_ADDRESS_DST; + m_addr.sadb_address_proto = p_upper; + m_addr.sadb_address_prefixlen = + (p_prefd != ~0 ? p_prefd : + _INALENBYAF(p_dst->sa_family) << 3); + m_addr.sadb_address_reserved = 0; + + setvarbuf(&m_len, + (struct sadb_ext *)&m_addr, sizeof(m_addr), + (caddr_t)p_dst, p_dst->sa_len); + } + break; + } + + ((struct sadb_msg *)m_buf)->sadb_msg_len = PFKEY_UNIT64(m_len); + + return 0; +} + +static int +setvarbuf(off, ebuf, elen, vbuf, vlen) + caddr_t vbuf; + struct sadb_ext *ebuf; + int *off, elen, vlen; +{ + memset(m_buf + *off, 0, PFKEY_UNUNIT64(ebuf->sadb_ext_len)); + memcpy(m_buf + *off, (caddr_t)ebuf, elen); + memcpy(m_buf + *off + elen, vbuf, vlen); + (*off) += PFKEY_ALIGN8(elen + vlen); + + return 0; +} + +void +parse_init() +{ + p_type = 0; + p_spi = 0; + + p_src = 0, p_dst = 0; + pp_prefix = p_prefs = p_prefd = ~0; + pp_port = IPSEC_PORT_ANY; + p_upper = 0; + + p_satype = 0; + p_ext = SADB_X_EXT_NONE; + p_alg_enc = SADB_EALG_NONE; + p_alg_auth = SADB_AALG_NONE; + p_mode = IPSEC_MODE_ANY; + p_replay = 4; + p_key_enc_len = p_key_auth_len = 0; + p_key_enc = p_key_auth = 0; + p_lt_hard = p_lt_soft = 0; + + p_policy_len = 0; + p_policy = NULL; + + memset(cmdarg, 0, sizeof(cmdarg)); + + return; +} + +void +free_buffer() +{ + if (p_src) free(p_src); + if (p_dst) free(p_dst); + if (p_key_enc) free(p_key_enc); + if (p_key_auth) free(p_key_auth); + + return; +} + diff --git a/usr.sbin/setkey/sample.cf b/usr.sbin/setkey/sample.cf new file mode 100644 index 0000000..886c449 --- /dev/null +++ b/usr.sbin/setkey/sample.cf @@ -0,0 +1,219 @@ +# Copyright (C) 1995, 1996, 1997, 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. +# +# $FreeBSD$ + +# There are sample scripts for IPsec configuration by manual keying. +# A security association is uniquely identified by a triple consisting +# of a Security Parameter Index (SPI), an IP Destination Address, and a +# security protocol (AH or ESP) identifier. You must take care of these +# parameters when you configure by manual keying. + +# ESP transport mode is recommended for TCP port number 110 between +# Host-A and Host-B. Encryption algorithm is blowfish-cbc whose key +# is "kamekame", and authentication algorithm is hmac-sha1 whose key +# is "this is the test key". +# +# ============ ESP ============ +# | | +# Host-A Host-B +# fec0::10 -------------------- fec0::11 +# +# At Host-A and Host-B, +spdadd fec0::10[any] fec0::11[110] tcp -P out ipsec + esp/transport/fec0::10-fec0::11/use ; +spdadd fec0::11[110] fec0::10[any] tcp -P in ipsec + esp/transport/fec0::11-fec0::10/use ; +add fec0::10 fec0::11 esp 0x10001 + -m transport + -E blowfish-cbc "kamekame" + -A hmac-sha1 "this is the test key" ; +add fec0::11 fec0::10 esp 0x10002 + -m transport + -E blowfish-cbc "kamekame" + -A hmac-sha1 "this is the test key" ; + +# "[any]" is wildcard of port number. Note that "[0]" is the number of +# zero in port number. + +# Security protocol is old AH tunnel mode, i.e. RFC1826, with keyed-md5 +# whose key is "this is the test" as authentication algorithm. +# That protocol takes place between Gateway-A and Gateway-B. +# +# ======= AH ======= +# | | +# Network-A Gateway-A Gateway-B Network-B +# 10.0.1.0/24 ---- 172.16.0.1 ----- 172.16.0.2 ---- 10.0.2.0/24 +# +# At Gateway-A: +spdadd 10.0.1.0/24 10.0.2.0/24 any -P out ipsec + ah/tunnel/172.16.0.1-172.16.0.2/require ; +spdadd 10.0.2.0/24 10.0.1.0/24 any -P in ipsec + ah/tunnel/172.16.0.2-172.16.0.1/require ; +add 172.16.0.1 172.16.0.2 ah-old 0x10003 + -m any + -A keyed-md5 "this is the test" ; +add 172.16.0.2 172.16.0.1 ah-old 0x10004 + -m any + -A keyed-md5 "this is the test" ; + +# If port number field is omitted such above then "[any]" is employed. +# -m specifies the mode of SA to be used. "-m any" means wildcard of +# mode of security protocol. You can use this SAs for both tunnel and +# transport mode. + +# At Gateway-B. Attention to the selector and peer's IP address for tunnel. +spdadd 10.0.2.0/24 10.0.1.0/24 any -P out ipsec + ah/tunnel/172.16.0.2-172.16.0.1/require ; +spdadd 10.0.1.0/24 10.0.2.0/24 any -P in ipsec + ah/tunnel/172.16.0.1-172.16.0.2/require ; +add 172.16.0.1 172.16.0.2 ah-old 0x10003 + -m tunnel + -A keyed-md5 "this is the test" ; +add 172.16.0.2 172.16.0.1 ah-old 0x10004 + -m tunnel + -A keyed-md5 "this is the test" ; + +# AH transport mode followed by ESP tunnel mode is required between +# Gateway-A and Gateway-B. +# Encryption algorithm is 3des-cbc, and authentication algorithm for ESP +# is hmac-sha1. Authentication algorithm for AH is hmac-md5. +# +# ========== AH ========= +# | ======= ESP ===== | +# | | | | +# Network-A Gateway-A Gateway-B Network-B +# fec0:0:0:1::/64 --- fec0:0:0:1::1 ---- fec0:0:0:2::1 --- fec0:0:0:2::/64 +# +# At Gateway-A: +spdadd fec0:0:0:1::/64 fec0:0:0:2::/64 any -P out ipsec + esp/tunnel/fec0:0:0:1::1-fec0:0:0:2::1/require + ah/transport/fec0:0:0:1::1-fec0:0:0:2::1/require ; +spdadd fec0:0:0:2::/64 fec0:0:0:1::/64 any -P in ipsec + esp/tunnel/fec0:0:0:2::1-fec0:0:0:1::1/require + ah/transport/fec0:0:0:2::1-fec0:0:0:1::1/require ; +add fec0:0:0:1::1 fec0:0:0:2::1 esp 0x10001 + -m tunnel + -E 3des-cbc "kamekame12341234kame1234" + -A hmac-sha1 "this is the test key" ; +add fec0:0:0:1::1 fec0:0:0:2::1 ah 0x10001 + -m transport + -A hmac-md5 "this is the test" ; +add fec0:0:0:2::1 fec0:0:0:1::1 esp 0x10001 + -m tunnel + -E 3des-cbc "kamekame12341234kame1234" + -A hmac-sha1 "this is the test key" ; +add fec0:0:0:2::1 fec0:0:0:1::1 ah 0x10001 + -m transport + -A hmac-md5 "this is the test" ; + +# ESP tunnel mode is required between Host-A and Gateway-A. +# Encryption algorithm is cast128-cbc, and authentication algorithm +# for ESP is hmac-sha1. +# ESP transport mode is recommended between Host-A and Host-B. +# Encryption algorithm is rc5-cbc, and authentication algorithm +# for ESP is hmac-md5. +# +# ================== ESP ================= +# | ======= ESP ======= | +# | | | | +# Host-A Gateway-A Host-B +# fec0:0:0:1::1 ---- fec0:0:0:2::1 ---- fec0:0:0:2::2 +# +# At Host-A: +spdadd fec0:0:0:1::1[any] fec0:0:0:2::2[80] tcp -P out ipsec + esp/transport/fec0:0:0:1::1-fec0:0:0:2::2/use + esp/tunnel/fec0:0:0:1::1-fec0:0:0:2::1/require ; +spdadd fec0:0:0:2::1[80] fec0:0:0:1::1[any] tcp -P in ipsec + esp/transport/fec0:0:0:2::2-fec0:0:0:1::1/use + esp/tunnel/fec0:0:0:2::1-fec0:0:0:1::1/require ; +add fec0:0:0:1::1 fec0:0:0:2::2 esp 0x10001 + -m transport + -E cast128-cbc "12341234" + -A hmac-sha1 "this is the test key" ; +add fec0:0:0:1::1 fec0:0:0:2::1 esp 0x10002 + -E rc5-cbc "kamekame" + -A hmac-md5 "this is the test" ; +add fec0:0:0:2::2 fec0:0:0:1::1 esp 0x10003 + -m transport + -E cast128-cbc "12341234" + -A hmac-sha1 "this is the test key" ; +add fec0:0:0:2::1 fec0:0:0:1::1 esp 0x10004 + -E rc5-cbc "kamekame" + -A hmac-md5 "this is the test" ; + +# By "get" command, you can get a entry of either SP or SA. +get fec0:0:0:1::1 fec0:0:0:2::2 ah 0x10004 ; + +# Also delete command, you can delete a entry of either SP or SA. +spddelete out fec0:0:0:1::/64 fec0:0:0:2:/64 any ; +delete fec0:0:0:1::1 fec0:0:0:2::2 ah 0x10004 ; + +# By dump command, you can dump all entry of either SP or SA. +dump ; +spddump ; +dump esp ; +flush esp ; + +# By flush command, you can flush all entry of either SP or SA. +flush ; +spdflush ; + +# "flush" and "dump" commands can specify a security protocol. +dump esp ; +flush ah ; + +# XXX +add ::1 ::1 esp 10001 -m transport -E simple ; +add ::1 ::1 esp 10002 -m transport -E des-deriv "12341234" ; +add ::1 ::1 esp-old 10003 -m transport -E des-32iv "12341234" ; +add ::1 ::1 esp 10004 -m transport -E simple -A null ; +add ::1 ::1 esp 10005 -m transport -E simple -A hmac-md5 "1234123412341234" ; +add ::1 ::1 esp 10006 -m tunnel -E simple -A hmac-sha1 "12341234123412341234" ; +add ::1 ::1 esp 10007 -m transport -E simple -A keyed-md5 "1234123412341234" ; +add ::1 ::1 esp 10008 -m any -E simple -A keyed-sha1 "12341234123412341234" ; +add ::1 ::1 esp 10009 -m transport -E des-cbc "testtest" ; +add ::1 ::1 esp 10010 -m transport -E 3des-cbc "testtest12341234testtest" ; +add ::1 ::1 esp 10011 -m tunnel -E cast128-cbc "testtest1234" ; +add ::1 ::1 esp 10012 -m tunnel -E blowfish-cbc "testtest1234" ; +add ::1 ::1 esp 10013 -m tunnel -E rc5-cbc "testtest1234" ; +add ::1 ::1 esp 10014 -m any -E rc5-cbc "testtest1234" ; +add ::1 ::1 esp 10015 -m transport -f zero-pad -E simple ; +add ::1 ::1 esp 10016 -m tunnel -f random-pad -r 8 -lh 100 -ls 80 -E simple ; +add ::1 ::1 esp 10017 -m transport -f seq-pad -f cyclic-seq -E simple ; +add ::1 ::1 esp 10018 -m transport -E simple ; +#add ::1 ::1 ah 20000 -m transport -A null ; +add ::1 ::1 ah 20001 -m any -A hmac-md5 "1234123412341234"; +add ::1 ::1 ah 20002 -m tunnel -A hmac-sha1 "12341234123412341234"; +add ::1 ::1 ah 20003 -m transport -A keyed-md5 "1234123412341234"; +add ::1 ::1 ah-old 20004 -m transport -A keyed-md5 "1234123412341234"; +add ::1 ::1 ah 20005 -m transport -A keyed-sha1 "12341234123412341234"; +#add ::1 ::1 ipcomp 30000 -C oui ; +add ::1 ::1 ipcomp 30001 -C deflate ; +#add ::1 ::1 ipcomp 30002 -C lzs ; + +# enjoy. diff --git a/usr.sbin/setkey/scriptdump.pl b/usr.sbin/setkey/scriptdump.pl new file mode 100644 index 0000000..5df9b4f --- /dev/null +++ b/usr.sbin/setkey/scriptdump.pl @@ -0,0 +1,54 @@ +#! @LOCALPREFIX@/bin/perl +# $FreeBSD$ + +if ($< != 0) { + print STDERR "must be root to invoke this\n"; + exit 1; +} + +$mode = 'add'; +while ($i = shift @ARGV) { + if ($i eq '-d') { + $mode = 'delete'; + } else { + print STDERR "usage: scriptdump [-d]\n"; + exit 1; + } +} + +open(IN, "setkey -D |") || die; +foreach $_ (<IN>) { + if (/^[^\t]/) { + ($src, $dst) = split(/\s+/, $_); + } elsif (/^\t(esp|ah) mode=(\S+) spi=(\d+).*replay=(\d+)/) { + ($proto, $ipsecmode, $spi, $replay) = ($1, $2, $3, $4); + } elsif (/^\tE: (\S+) (.*)/) { + $ealgo = $1; + $ekey = $2; + $ekey =~ s/\s//g; + $ekey =~ s/^/0x/g; + } elsif (/^\tA: (\S+) (.*)/) { + $aalgo = $1; + $akey = $2; + $akey =~ s/\s//g; + $akey =~ s/^/0x/g; + } elsif (/^\tstate=/) { + print "$mode $src $dst $proto $spi -m $ipsecmode"; + print " -r $replay" if $replay; + if ($mode eq 'add') { + if ($proto eq 'esp') { + print " -E $ealgo $ekey" if $ealgo; + print " -A $aalgo $akey" if $aalgo; + } elsif ($proto eq 'ah') { + print " -A $aalgo $akey" if $aalgo; + } + } + print ";\n"; + + $src = $dst = $upper = $proxy = ''; + $ealgo = $ekey = $aalgo = $akey = ''; + } +} +close(IN); + +exit 0; diff --git a/usr.sbin/setkey/setkey.8 b/usr.sbin/setkey/setkey.8 new file mode 100644 index 0000000..1f6f33c --- /dev/null +++ b/usr.sbin/setkey/setkey.8 @@ -0,0 +1,550 @@ +.\" Copyright (C) 1995, 1996, 1997, 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. +.\" +.\" $Id: setkey.8,v 1.14 1999/10/27 17:08:58 sakane Exp $ +.\" $FreeBSD$ +.\" +.Dd May 17, 1998 +.Dt SETKEY 8 +.Os KAME +.\" +.Sh NAME +.Nm setkey +.Nd manually manipulate the SA/SP database. +.\" +.Sh SYNOPSIS +.Nm setkey +.Op Fl dv +.Fl c +.Nm setkey +.Op Fl dv +.Fl f Ar filename +.Nm setkey +.Op Fl adPlv +.Fl D +.Nm setkey +.Op Fl dPv +.Fl F +.Nm setkey +.Op Fl h +.Fl x +.\" +.Sh DESCRIPTION +.Nm +updates, or lists the content of, Security Association Database (SAD) entries +in the kernel as well as Security Policy Database (SPD) entries. +.Pp +.Nm +takes a series of operation from standard input +.Po +if invoked with +.Fl c +.Pc +or file named +.Ar filename +.Po +if invoked with +.Fl f Ar filename +.Pc . +.Bl -tag -width Ds +.It Fl D +Dump the SAD entries. +If with +.Fl P , +the SPD entries are dumped. +.It Fl F +Flush the SAD. +If with +.Fl P , +the SPD are flushed. +.It Fl a +.Nm +usually do not display dead SAD entries on +.Fl D . +With +.Fl a , +dead SAD entries will be displayed as well. +Dead SAD entries are kept in the kernel, +when they are referenced from any of SPD entries in the kernel. +.It Fl d +Enable debugging messages. +.It Fl x +Loop forever and dump all the messages transmitted to +.Dv PF_KEY +socket. +.It Fl h +Add hexadecimal dump on +.Fl x +mode. The order is significant. +.It Fl l +Loop forever with short output on +.Fl D . +.It Fl v +Be verbose. +.Dv PF_KEY +socket +.Po +including messages sent from other processes +.Pc . +.El +.Pp +Operation has the following grammar. Note that lines, that start with a +hashmark ('#') are treated as comment lines. +Description of meta-arguments follows. +.Bl -tag -width Ds +.It Xo +.Li add +.Ar src Ar dst Ar protocol Ar spi +.Op Ar extensions +.Ar algorithm... +.Li ; +.Xc +Add a SAD entry. +.\" +.It Xo +.Li get +.Ar src Ar dst Ar protocol Ar spi +.Op Ar mode +.Li ; +.Xc +Show a SAD entry. +.\" +.It Xo +.Li delete +.Ar src Ar dst Ar protocol Ar spi +.Op Ar mode +.Li ; +.Xc +Remove a SAD entry. +.\" +.It Xo +.Li flush +.Op Ar protocol +.Li ; +.Xc +Clear all SAD entries that matches the options. +.\" +.It Xo +.Li dump +.Op Ar protocol +.Li ; +.Xc +Dumps all SAD entries that matches the options. +.\" +.It Xo +.Li spdadd +.Ar src_range Ar dst_range Ar upperspec Ar policy +.Li ; +.Xc +Add a SPD entry. +.\" +.It Xo +.Li spddelete +.Ar src_range Ar dst_range Ar upperspec +.Li ; +.Xc +Delete a SPD entry. +.\" +.It Xo +.Li spdflush +.Li ; +.Xc +Clear all SPD entries. +.\" +.It Xo +.Li spddump +.Li ; +.Xc +Dumps all SAD entries. +.El +.\" +.Pp +Meta-arguments are as follows: +.Bl -tag -compact -width Ds +.It Ar src +.It Ar dst +Source/destination of the secure communication is specified as +IPv4/v6 address. +.Nm +does not consult hostname-to-address for arguments +.Ar src +and +.Ar dst . +They must be in numeric form. +.\" +.Pp +.It Ar protocol +.Ar protocol +is one of following: +.Bl -tag -width Fl -compact +.It Li esp +ESP based on rfc2405 +.It Li esp-old +ESP based on rfc1827 +.It Li ah +AH based on rfc2402 +.It Li ah-old +AH based on rfc1826 +.It Li ipcomp +IPCOMP +.El +.\" +.Pp +.It Ar spi +Security Parameter Index (SPI) for the SA and SPD. +It must be decimal number or hexadecimal number +.Po +with +.Li 0x +attached +.Pc . +.\" +.Pp +.It Ar extensions +takes some of the following: +.Bl -tag -width Fl -compact +.It Fl m Ar mode +Specify an security protocol mode for use. By default, +.Li any . +.Ar mode +is one of following: +.Li transport , tunnel +or +.Li any . +.It Fl r Ar size +Specify window size of bytes for replay prevention. +.Ar size +must be decimal number in 32-bit word. If +.Ar size +is zero or not specified, replay check don't take place. +.It Fl f Ar pad_option +.Ar pad_option +is one of following: +.Li zero-pad , random-pad +or +.Li seq-pad +.It Fl f Li cyclic-seq +Allow cyclic sequence number. +.It Fl lh Ar time +.It Fl ls Ar time +Specify hard/soft lifetime. +.El +.\" +.Pp +.It Ar algorithm +.Bl -tag -width Fl -compact +.It Fl E Ar ealgo Ar key +Specify encryption algorithm. +.It Fl A Ar ealgo Ar key +Specify authentication algorithm. +If +.Fl A +is used for esp, it will be treated as ESP payload authentication algorithm. +.It Fl C Ar calgo Op Fl R +Specify compression algorithm. +If +.Fl R +is specified with +.Li ipcomp +line, the kernel will use well-known IPComp CPI +.Pq compression parameter index +on IPComp CPI field on packets, and +.Ar spi +field will be ignored. +.Ar spi +field is only for kernel internal use in this case. +.\"Therefore, compression protocol number will appear on IPComp CPI field. +If +.Fl R +is not used, +the value on +.Ar spi +field will appear on IPComp CPI field on outgoing packets. +.Ar spi +field needs to be smaller than +.Li 0x10000 +in this case. +.El +.Pp +.Li esp +SAs accept +.Fl E +and +.Fl A . +.Li esp-old +SAs accept +.Fl E +only. +.Li ah +and +.Li ah-old +SAs accept +.Fl A +only. +.Li ipcomp +SAs accept +.Fl C +only. +.Pp +.Ar key +must be double-quoted character string or a series of hexadecimal digits. +.Pp +Possible values for +.Ar ealgo , +.Ar aalgo +and +.Ar calgo +are specified in separate section. +.\" +.It Ar src_range +.It Ar dst_range +These are selection of the secure communication is specified as +IPv4/v6 address or IPv4/v6 address range, and it may accompany +TCP/UDP port specification. +This takes the following form: +.Bd -literal -offset +.Ar address +.Ar address/prefixlen +.Ar address[port] +.Ar address/prefixlen[port] +.Ed +.Pp +.Ar prefixlen +and +.Ar port +must be decimal number. +The square bracket around +.Ar port +is really necessary. +They are not manpage metacharacters. +.Pp +.Nm +does not consult hostname-to-address for arguments +.Ar src +and +.Ar dst . +They must be in numeric form. +.\" +.It Ar upperspec +Upper-layer protocol to be used. +Currently +.Li tcp , +.Li udp +and +.Li any +can be specified. +.Li any +stands for +.Dq any protocol . +.Pp +NOTE: +.Ar upperspec +does not work against forwarding case at this moment, +as it requires extra reassembly at forwarding node +.Pq not implemented as this moment . +.\" +.It Ar policy +.Ar policy +is the one of following: +.Bd -literal -offset +.Xo +.Fl P +.Ar direction +.Li discard +.Xc +.Xo +.Fl P +.Ar direction +.Li none +.Xc +.Xo +.Fl P +.Ar direction +.Li ipsec +.Ar protocol/mode/src-dst/level +.Xc +.Ed +.Pp +You must specify the direction of its policy as +.Ar direction . +Either +.Li out +or +.Li in +are used. +.Li discard +means the packet matching indexes will be discarded. +.Li none +means that IPsec operation will not take place onto the packet. +.Li ipsec +means that IPsec operation will take place onto the packet. +Either +.Li ah , +.Li esp +or +.Li ipcomp +is to be set as +.Ar protocol . +.Ar mode +is either +.Li transport +or +.Li tunnel . +You must specify the end-points addresses of the SA as +.Ar src +and +.Ar dst +with +.Sq - +between these addresses which is used to specify the SA to use. +.Ar level +is to be one of the following: +.Li default , use +or +.Li require . +.Li default +means kernel consults to the system wide default against protocol you +specified, e.g. +.Li esp_trans_deflev +sysctl variable, when kernel processes the packet. +.Li use +means that kernel use a SA if it's available, +otherwise kernel keeps normal operation. +.Li require +means SA is required whenever kernel deals with the packet. +Note that +.Dq Li discard +and +.Dq Li none +are not in the syntax described in +.Xr ipsec_set_policy 3 . +There are little differences in the syntax. +See +.Xr ipsec_set_policy 3 +for detail. +.Pp +.El +.Pp +.\" +.Sh ALGORITHMS +The following list shows the supported algorithms. +.Sy protocol +and +.Sy algorithm +are almost orthogonal. +Following are the list of authentication algorithms that can be used as +.Ar aalgo +in +.Fl A Ar aalgo +of +.Ar protocol +parameter: +.Pp +.Bd -literal -offset indent +algorithm keylen (bits) comment +hmac-md5 128 ah: rfc2403 + 128 ah-old: rfc2085 +hmac-sha1 160 ah: rfc2404 + 160 ah-old: 128bit ICV (no document) +keyed-md5 128 ah: 96bit ICV (no document) + 128 ah-old: rfc1828 +keyed-sha1 160 ah: 96bit ICV (no document) + 160 ah-old: 128bit ICV (no document) +null 0 to 2048 for debugging +.Ed +.Pp +Following are the list of encryption algorithms that can be used as +.Ar ealgo +in +.Fl E Ar ealgo +of +.Ar protocol +parameter: +.Pp +.Bd -literal -offset indent +algorithm keylen (bits) comment +des-cbc 64 esp-old: rfc1829, esp: rfc2405 +3des-cbc 192 rfc2451 +simple 0 to 2048 rfc2410 +blowfish-cbc 40 to 448 rfc2451 +cast128-cbc 40 to 128 rfc2451 +rc5-cbc 40 to 2040 rfc2451 +des-deriv 64 ipsec-ciph-des-derived-01 (expired) +3des-deriv 192 no document +.Ed +.Pp +Following are the list of compression algorithms that can be used as +.Ar calgo +in +.Fl C Ar calgo +of +.Ar protocol +parameter: +.Pp +.Bd -literal -offset indent +algorithm comment +deflate rfc2394 +lzs rfc2395 +.Ed +.\" +.Sh EXAMPLES +.Bd -literal -offset +add 3ffe:501:4819::1 3ffe:501:481d::1 esp 123457 + -E des-cbc "ESP SA!!" + +add 3ffe:501:4819::1 3ffe:501:481d::1 ah 123456 + -A hmac-sha1 "AH SA configuration!" ; + +add 10.0.11.41 10.0.11.33 esp 0x10001 + -E des-cbc "ESP with" + -A hmac-md5 "authentication!!" ; + +get 3ffe:501:4819::1 3ffe:501:481d::1 ah 123456 ; + +flush ; + +dump esp ; + +spdadd 10.0.11.41/32[21] 10.0.11.33/32[any] any + -P out ipsec esp/tunnel/192.168.0.1-192.168.1.2/require ; + +.Ed +.\" +.Sh RETURN VALUES +The command exits with 0 on success, and non-zero on errors. +.\" +.Sh SEE ALSO +.Xr ipsec_set_policy 3 , +.Xr sysctl 8 +.\" +.Sh HISTORY +The +.Nm +command first appeared in WIDE Hydrangea IPv6 protocol stack kit. +The command was completely re-designed in June 1998. +.\" +.\" .Sh BUGS diff --git a/usr.sbin/setkey/setkey.c b/usr.sbin/setkey/setkey.c new file mode 100644 index 0000000..73edc3f --- /dev/null +++ b/usr.sbin/setkey/setkey.c @@ -0,0 +1,566 @@ +/* + * Copyright (C) 1995, 1996, 1997, 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. + * + * $FreeBSD$ + */ +/* KAME $Id: setkey.c,v 1.5 1999/10/26 09:39:37 sakane Exp $ */ + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/socket.h> +#include <sys/time.h> +#include <err.h> +#include <net/route.h> +#include <netinet/in.h> +#include <net/pfkeyv2.h> +#include <netkey/keydb.h> +#include <netkey/key_debug.h> +#include <netinet6/ipsec.h> + +#include <stdio.h> +#include <stdlib.h> +#include <limits.h> +#include <string.h> +#include <ctype.h> +#include <unistd.h> +#include <errno.h> +#include <netdb.h> + +void Usage __P((void)); +int main __P((int, char **)); +int get_supported __P((void)); +void sendkeyshort __P((u_int)); +void promisc __P((void)); +int sendkeymsg __P((void)); +int postproc __P((struct sadb_msg *, int)); +const char *numstr __P((int)); +void shortdump_hdr __P((void)); +void shortdump __P((struct sadb_msg *)); + +#define MODE_SCRIPT 1 +#define MODE_CMDDUMP 2 +#define MODE_CMDFLUSH 3 + +int so; + +int f_forever = 0; +int f_all = 0; +int f_debug = 0; +int f_verbose = 0; +int f_mode = 0; +int f_cmddump = 0; +int f_policy = 0; +int f_promisc = 0; +int f_hexdump = 0; +char *pname; + +u_char m_buf[BUFSIZ]; +u_int m_len; + +extern int lineno; + +extern int parse __P((FILE **)); + +void +Usage() +{ + printf("Usage:\t%s [-dv] -c\n", pname); + printf("\t%s [-dv] -f (file)\n", pname); + printf("\t%s [-Padlv] -D\n", pname); + printf("\t%s [-Pdv] -F\n", pname); + printf("\t%s [-h] -x\n", pname); + pfkey_close(so); + exit(0); +} + +int +main(ac, av) + int ac; + char **av; +{ + FILE *fp = stdin; + int c; + + pname = *av; + + if (ac == 1) Usage(); + + while ((c = getopt(ac, av, "acdf:hlvxDFP")) != EOF) { + switch (c) { + case 'c': + f_mode = MODE_SCRIPT; + fp = stdin; + break; + case 'f': + f_mode = MODE_SCRIPT; + if ((fp = fopen(optarg, "r")) == NULL) { + err(-1, "fopen"); + /*NOTREACHED*/ + } + break; + case 'D': + f_mode = MODE_CMDDUMP; + break; + case 'F': + f_mode = MODE_CMDFLUSH; + break; + case 'a': + f_all = 1; + break; + case 'l': + f_forever = 1; + break; + case 'h': + f_hexdump = 1; + break; + case 'x': + f_promisc = 1; + promisc(); + /*NOTREACHED*/ + case 'P': + f_policy = 1; + break; + case 'd': + f_debug = 1; + break; + case 'v': + f_verbose = 1; + break; + default: + Usage(); + /*NOTREACHED*/ + } + } + + switch (f_mode) { + case MODE_CMDDUMP: + sendkeyshort(f_policy ? SADB_X_SPDDUMP: SADB_DUMP); + break; + case MODE_CMDFLUSH: + sendkeyshort(f_policy ? SADB_X_SPDFLUSH: SADB_FLUSH); + pfkey_close(so); + break; + case MODE_SCRIPT: + if (get_supported() < 0) { + errx(-1, "%s", ipsec_strerror()); + /*NOTREACHED*/ + } + parse(&fp); + break; + default: + Usage(); + } + + exit(0); +} + +int +get_supported() +{ + int so; + + if ((so = pfkey_open()) < 0) { + perror("pfkey_open"); + return -1; + } + + /* debug mode ? */ + if (f_debug) + return 0; + + if (pfkey_send_register(so, PF_UNSPEC) < 0) + return -1; + + if (pfkey_recv_register(so) < 0) + return -1; + + return 0; +} + +void +sendkeyshort(type) + u_int type; +{ + struct sadb_msg *m_msg = (struct sadb_msg *)m_buf; + + m_len = sizeof(struct sadb_msg); + + m_msg->sadb_msg_version = PF_KEY_V2; + m_msg->sadb_msg_type = type; + m_msg->sadb_msg_errno = 0; + m_msg->sadb_msg_satype = SADB_SATYPE_UNSPEC; + m_msg->sadb_msg_len = PFKEY_UNIT64(m_len); + m_msg->sadb_msg_reserved = 0; + m_msg->sadb_msg_reserved = 0; + m_msg->sadb_msg_seq = 0; + m_msg->sadb_msg_pid = getpid(); + + sendkeymsg(); + + return; +} + +void +promisc() +{ + struct sadb_msg *m_msg = (struct sadb_msg *)m_buf; + u_char rbuf[1024 * 32]; /* XXX: Enough ? Should I do MSG_PEEK ? */ + int so, len; + + m_len = sizeof(struct sadb_msg); + + m_msg->sadb_msg_version = PF_KEY_V2; + m_msg->sadb_msg_type = SADB_X_PROMISC; + m_msg->sadb_msg_errno = 0; + m_msg->sadb_msg_satype = 1; + m_msg->sadb_msg_len = PFKEY_UNIT64(m_len); + m_msg->sadb_msg_reserved = 0; + m_msg->sadb_msg_reserved = 0; + m_msg->sadb_msg_seq = 0; + m_msg->sadb_msg_pid = getpid(); + + if ((so = socket(PF_KEY, SOCK_RAW, PF_KEY_V2)) < 0) { + err(1, "socket(PF_KEY)"); + /*NOTREACHED*/ + } + + if ((len = send(so, m_buf, m_len, 0)) < 0) { + err(1, "send"); + /*NOTREACHED*/ + } + + while (1) { + struct sadb_msg *base; + + if ((len = recv(so, rbuf, sizeof(*base), MSG_PEEK)) < 0) { + err(1, "recv"); + /*NOTREACHED*/ + } + + if (len != sizeof(*base)) + continue; + + base = (struct sadb_msg *)rbuf; + if ((len = recv(so, rbuf, PFKEY_UNUNIT64(base->sadb_msg_len), + 0)) < 0) { + err(1, "recv"); + /*NOTREACHED*/ + } + if (f_hexdump) { + int i; + for (i = 0; i < len; i++) { + if (i % 16 == 0) + printf("%08x: ", i); + printf("%02x ", rbuf[i] & 0xff); + if (i % 16 == 15) + printf("\n"); + } + if (len % 16) + printf("\n"); + } + /* adjust base pointer for promisc mode */ + if (base->sadb_msg_type == SADB_X_PROMISC) { + if (sizeof(*base) < len) + base++; + else + base = NULL; + } + if (base) { + kdebug_sadb(base); + printf("\n"); + fflush(stdout); + } + } +} + +int +sendkeymsg() +{ + int so; + + u_char rbuf[1024 * 32]; /* XXX: Enough ? Should I do MSG_PEEK ? */ + int len; + struct sadb_msg *msg; + + if ((so = pfkey_open()) < 0) { + perror("pfkey_open"); + return -1; + } + + { + struct timeval tv; + tv.tv_sec = 1; + tv.tv_usec = 0; + if (setsockopt(so, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) { + perror("setsockopt"); + goto end; + } + } + + if (f_forever) + shortdump_hdr(); +again: + if (f_verbose) + kdebug_sadb((struct sadb_msg *)m_buf); + + if ((len = send(so, m_buf, m_len, 0)) < 0) { + perror("send"); + goto end; + } + + msg = (struct sadb_msg *)rbuf; + do { + if ((len = recv(so, rbuf, sizeof(rbuf), 0)) < 0) { + perror("recv"); + goto end; + } + + if (PFKEY_UNUNIT64(msg->sadb_msg_len) != len) { + warnx("invalid keymsg length"); + break; + } + + if (f_verbose) + kdebug_sadb((struct sadb_msg *)rbuf); + if (postproc(msg, len) < 0) + break; + } while (msg->sadb_msg_errno || msg->sadb_msg_seq); + + if (f_forever) { + fflush(stdout); + sleep(1); + goto again; + } + +end: + pfkey_close(so); + return(0); +} + +int +postproc(msg, len) + struct sadb_msg *msg; + int len; +{ + + if (msg->sadb_msg_errno != 0) { + char inf[80]; + char *errmsg = NULL; + + if (f_mode == MODE_SCRIPT) + snprintf(inf, sizeof(inf), "The result of line %d: ", lineno); + else + inf[0] = '\0'; + + switch (msg->sadb_msg_errno) { + case ENOENT: + switch (msg->sadb_msg_type) { + case SADB_DELETE: + case SADB_GET: + case SADB_X_SPDDELETE: + errmsg = "No entry"; + break; + case SADB_DUMP: + errmsg = "No SAD entries"; + break; + case SADB_X_SPDDUMP: + errmsg = "No SPD entries"; + break; + } + break; + default: + errmsg = strerror(msg->sadb_msg_errno); + } + printf("%s%s.\n", inf, errmsg); + return(-1); + } + + switch (msg->sadb_msg_type) { + case SADB_GET: + pfkey_sadump(msg); + break; + + case SADB_DUMP: + /* filter out DEAD SAs */ + if (!f_all) { + caddr_t mhp[SADB_EXT_MAX + 1]; + struct sadb_sa *sa; + pfkey_align(msg, mhp); + pfkey_check(mhp); + if ((sa = (struct sadb_sa *)mhp[SADB_EXT_SA]) != NULL) { + if (sa->sadb_sa_state == SADB_SASTATE_DEAD) + break; + } + } + if (f_forever) + shortdump(msg); + else + pfkey_sadump(msg); + msg = (struct sadb_msg *)((caddr_t)msg + + PFKEY_UNUNIT64(msg->sadb_msg_len)); + if (f_verbose) + kdebug_sadb((struct sadb_msg *)msg); + break; + + case SADB_X_SPDDUMP: + pfkey_spdump(msg); + if (msg->sadb_msg_seq == 0) break; + msg = (struct sadb_msg *)((caddr_t)msg + + PFKEY_UNUNIT64(msg->sadb_msg_len)); + if (f_verbose) + kdebug_sadb((struct sadb_msg *)msg); + break; + } + + return(0); +} + +/*------------------------------------------------------------*/ +static char *satype[] = { + NULL, NULL, "ah", "esp" +}; +static char *sastate[] = { + "L", "M", "D", "d" +}; +static char *ipproto[] = { +/*0*/ "ip", "icmp", "igmp", "ggp", "ip4", + NULL, "tcp", NULL, "egp", NULL, +/*10*/ NULL, NULL, NULL, NULL, NULL, + NULL, NULL, "udp", NULL, NULL, +/*20*/ NULL, NULL, "idp", NULL, NULL, + NULL, NULL, NULL, NULL, "tp", +/*30*/ NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, +/*40*/ NULL, "ip6", NULL, "rt6", "frag6", + NULL, "rsvp", "gre", NULL, NULL, +/*50*/ "esp", "ah", NULL, NULL, NULL, + NULL, NULL, NULL, "icmp6", "none", +/*60*/ "dst6", +}; + +#define STR_OR_ID(x, tab) \ + (((x) < sizeof(tab)/sizeof(tab[0]) && tab[(x)]) ? tab[(x)] : numstr(x)) + +const char * +numstr(x) + int x; +{ + static char buf[20]; + snprintf(buf, sizeof(buf), "#%d", x); + return buf; +} + +void +shortdump_hdr() +{ + printf("%-4s %-3s %-1s %-8s %-7s %s -> %s\n", + "time", "p", "s", "spi", "ltime", "src", "dst"); +} + +void +shortdump(msg) + struct sadb_msg *msg; +{ + caddr_t mhp[SADB_EXT_MAX + 1]; + char buf[1024], pbuf[10]; + struct sadb_sa *sa; + struct sadb_address *saddr; + struct sadb_lifetime *lts, *lth, *ltc; + struct sockaddr *s; + u_int t; + time_t cur = time(0); + + pfkey_align(msg, mhp); + pfkey_check(mhp); + + printf("%02lu%02lu", (u_long)(cur % 3600) / 60, (u_long)(cur % 60)); + + printf(" %-3s", STR_OR_ID(msg->sadb_msg_satype, satype)); + + if ((sa = (struct sadb_sa *)mhp[SADB_EXT_SA]) != NULL) { + printf(" %-1s", STR_OR_ID(sa->sadb_sa_state, sastate)); + printf(" %08x", (u_int32_t)ntohl(sa->sadb_sa_spi)); + } else + printf("%-1s %-8s", "?", "?"); + + lts = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_SOFT]; + lth = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_HARD]; + ltc = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_CURRENT]; + if (lts && lth && ltc) { + if (ltc->sadb_lifetime_addtime == 0) + t = (u_long)0; + else + t = (u_long)(cur - ltc->sadb_lifetime_addtime); + if (t >= 1000) + strcpy(buf, " big/"); + else + snprintf(buf, sizeof(buf), " %3lu/", (u_long)t); + printf("%s", buf); + + t = (u_long)lth->sadb_lifetime_addtime; + if (t >= 1000) + strcpy(buf, "big"); + else + snprintf(buf, sizeof(buf), "%-3lu", (u_long)t); + printf("%s", buf); + } else + printf(" ???/???"); + + printf(" "); + + if ((saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_SRC]) != NULL) { + if (saddr->sadb_address_proto) + printf("%s ", STR_OR_ID(saddr->sadb_address_proto, ipproto)); + s = (struct sockaddr *)(saddr + 1); + getnameinfo(s, s->sa_len, buf, sizeof(buf), + pbuf, sizeof(pbuf), NI_NUMERICHOST|NI_NUMERICSERV); + if (strcmp(pbuf, "0") != 0) + printf("%s[%s]", buf, pbuf); + else + printf("%s", buf); + } else + printf("?"); + + printf(" -> "); + + if ((saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_DST]) != NULL) { + if (saddr->sadb_address_proto) + printf("%s ", STR_OR_ID(saddr->sadb_address_proto, ipproto)); + + s = (struct sockaddr *)(saddr + 1); + getnameinfo(s, s->sa_len, buf, sizeof(buf), + pbuf, sizeof(pbuf), NI_NUMERICHOST|NI_NUMERICSERV); + if (strcmp(pbuf, "0") != 0) + printf("%s[%s]", buf, pbuf); + else + printf("%s", buf); + } else + printf("?"); + + printf("\n"); +} diff --git a/usr.sbin/setkey/test-pfkey.c b/usr.sbin/setkey/test-pfkey.c new file mode 100644 index 0000000..849aba3 --- /dev/null +++ b/usr.sbin/setkey/test-pfkey.c @@ -0,0 +1,480 @@ +/* + * Copyright (C) 1995, 1996, 1997, 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. + * + * $FreeBSD$ + */ +/* KAME $Id: test-pfkey.c,v 1.2 1999/10/26 08:09:17 itojun Exp $ */ + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/socket.h> +#include <net/route.h> +#include <net/pfkeyv2.h> +#include <netinet/in.h> +#include <netkey/keydb.h> +#include <netkey/key_var.h> +#include <netkey/key_debug.h> + +#include <stdio.h> +#include <stdlib.h> +#include <limits.h> +#include <string.h> +#include <ctype.h> +#include <unistd.h> +#include <errno.h> + +u_char m_buf[BUFSIZ]; +u_int m_len; +char *pname; + +void Usage __P((void)); +int sendkeymsg __P((void)); +void key_setsadbmsg __P((u_int)); +void key_setsadbsens __P((void)); +void key_setsadbprop __P((void)); +void key_setsadbid __P((u_int, caddr_t)); +void key_setsadblft __P((u_int, u_int)); +void key_setspirange __P((void)); +void key_setsadbkey __P((u_int, caddr_t)); +void key_setsadbsa __P((void)); +void key_setsadbaddr __P((u_int, u_int, caddr_t)); +void key_setsadbextbuf __P((caddr_t, int, caddr_t, int, caddr_t, int)); + +void +Usage() +{ + printf("Usage:\t%s number\n", pname); + exit(0); +} + +int +main(ac, av) + int ac; + char **av; +{ + pname = *av; + + if (ac == 1) Usage(); + + key_setsadbmsg(atoi(*(av+1))); + sendkeymsg(); + + exit(0); +} + +/* %%% */ +int +sendkeymsg() +{ + u_char rbuf[1024 * 32]; /* XXX: Enough ? Should I do MSG_PEEK ? */ + int so, len; + + if ((so = socket(PF_KEY, SOCK_RAW, PF_KEY_V2)) < 0) { + perror("socket(PF_KEY)"); + goto end; + } + + pfkey_sadump((struct sadb_msg *)m_buf); + + if ((len = send(so, m_buf, m_len, 0)) < 0) { + perror("send"); + goto end; + } + + if ((len = recv(so, rbuf, sizeof(rbuf), 0)) < 0) { + perror("recv"); + goto end; + } + + pfkey_sadump((struct sadb_msg *)rbuf); + +end: + (void)close(so); + return(0); +} + +void +key_setsadbmsg(type) + u_int type; +{ + struct sadb_msg m_msg; + + m_msg.sadb_msg_version = PF_KEY_V2; + m_msg.sadb_msg_type = type; + m_msg.sadb_msg_errno = 0; + m_msg.sadb_msg_satype = SADB_SATYPE_ESP; + m_msg.sadb_msg_reserved = 0; + m_msg.sadb_msg_seq = 0; + m_msg.sadb_msg_pid = getpid(); + + m_len = sizeof(struct sadb_msg); + memcpy(m_buf, &m_msg, m_len); + + switch (type) { + case SADB_GETSPI: + /*<base, address(SD), SPI range>*/ + key_setsadbaddr(SADB_EXT_ADDRESS_SRC, AF_INET, "10.0.3.4"); + key_setsadbaddr(SADB_EXT_ADDRESS_DST, AF_INET, "127.0.0.1"); + key_setspirange(); + /*<base, SA(*), address(SD)>*/ + break; + + case SADB_ADD: + /* <base, SA, (lifetime(HSC),) address(SD), (address(P),) + key(AE), (identity(SD),) (sensitivity)> */ + key_setsadbaddr(SADB_EXT_ADDRESS_PROXY, AF_INET6, "3ffe::1"); + case SADB_UPDATE: + key_setsadbsa(); + key_setsadblft(SADB_EXT_LIFETIME_HARD, 10); + key_setsadblft(SADB_EXT_LIFETIME_SOFT, 5); + key_setsadbaddr(SADB_EXT_ADDRESS_SRC, AF_INET, "192.168.1.1"); + key_setsadbaddr(SADB_EXT_ADDRESS_DST, AF_INET, "10.0.3.4"); + /* XXX key_setsadbkey(SADB_EXT_KEY_AUTH, "abcde"); */ + key_setsadbkey(SADB_EXT_KEY_AUTH, "1234567812345678"); + key_setsadbkey(SADB_EXT_KEY_ENCRYPT, "12345678"); + key_setsadbid(SADB_EXT_IDENTITY_SRC, "hoge1234@hoge.com"); + key_setsadbid(SADB_EXT_IDENTITY_DST, "hage5678@hage.net"); + key_setsadbsens(); + /* <base, SA, (lifetime(HSC),) address(SD), (address(P),) + (identity(SD),) (sensitivity)> */ + break; + + case SADB_DELETE: + /* <base, SA(*), address(SDP)> */ + key_setsadbsa(); + key_setsadbaddr(SADB_EXT_ADDRESS_SRC, AF_INET, "192.168.1.1"); + key_setsadbaddr(SADB_EXT_ADDRESS_DST, AF_INET, "10.0.3.4"); + key_setsadbaddr(SADB_EXT_ADDRESS_PROXY, AF_INET6, "3ffe::1"); + /* <base, SA(*), address(SDP)> */ + break; + + case SADB_GET: + /* <base, SA(*), address(SDP)> */ + key_setsadbsa(); + key_setsadbaddr(SADB_EXT_ADDRESS_SRC, AF_INET, "192.168.1.1"); + key_setsadbaddr(SADB_EXT_ADDRESS_DST, AF_INET, "10.0.3.4"); + key_setsadbaddr(SADB_EXT_ADDRESS_PROXY, AF_INET6, "3ffe::1"); + /* <base, SA, (lifetime(HSC),) address(SD), (address(P),) + key(AE), (identity(SD),) (sensitivity)> */ + break; + + case SADB_ACQUIRE: + /* <base, address(SD), (address(P),) (identity(SD),) + (sensitivity,) proposal> */ + key_setsadbaddr(SADB_EXT_ADDRESS_SRC, AF_INET, "192.168.1.1"); + key_setsadbaddr(SADB_EXT_ADDRESS_DST, AF_INET, "10.0.3.4"); + key_setsadbaddr(SADB_EXT_ADDRESS_PROXY, AF_INET6, "3ffe::1"); + key_setsadbid(SADB_EXT_IDENTITY_SRC, "hoge1234@hoge.com"); + key_setsadbid(SADB_EXT_IDENTITY_DST, "hage5678@hage.net"); + key_setsadbsens(); + key_setsadbprop(); + /* <base, address(SD), (address(P),) (identity(SD),) + (sensitivity,) proposal> */ + break; + + case SADB_REGISTER: + /* <base> */ + /* <base, supported> */ + break; + + case SADB_EXPIRE: + case SADB_FLUSH: + break; + + case SADB_DUMP: + break; + + case SADB_X_PROMISC: + /* <base> */ + /* <base, base(, others)> */ + break; + + case SADB_X_PCHANGE: + break; + + /* for SPD management */ + case SADB_X_SPDFLUSH: + case SADB_X_SPDDUMP: + break; + + case SADB_X_SPDADD: + case SADB_X_SPDDELETE: + key_setsadbaddr(SADB_EXT_ADDRESS_SRC, AF_INET, "192.168.1.1"); + key_setsadbaddr(SADB_EXT_ADDRESS_DST, AF_INET, "10.0.3.4"); + break; + } + + ((struct sadb_msg *)m_buf)->sadb_msg_len = PFKEY_UNIT64(m_len); + + return; +} + +void +key_setsadbsens() +{ + struct sadb_sens m_sens; + u_char buf[64]; + u_int s, i, slen, ilen, len; + + /* make sens & integ */ + s = htonl(0x01234567); + i = htonl(0x89abcdef); + slen = sizeof(s); + ilen = sizeof(i); + memcpy(buf, &s, slen); + memcpy(buf + slen, &i, ilen); + + len = sizeof(m_sens) + PFKEY_ALIGN8(slen) + PFKEY_ALIGN8(ilen); + m_sens.sadb_sens_len = PFKEY_UNIT64(len); + m_sens.sadb_sens_exttype = SADB_EXT_SENSITIVITY; + m_sens.sadb_sens_dpd = 1; + m_sens.sadb_sens_sens_level = 2; + m_sens.sadb_sens_sens_len = PFKEY_ALIGN8(slen); + m_sens.sadb_sens_integ_level = 3; + m_sens.sadb_sens_integ_len = PFKEY_ALIGN8(ilen); + m_sens.sadb_sens_reserved = 0; + + key_setsadbextbuf(m_buf, m_len, + (caddr_t)&m_sens, sizeof(struct sadb_sens), + buf, slen + ilen); + m_len += len; + + return; +} + +void +key_setsadbprop() +{ + struct sadb_prop m_prop; + struct sadb_comb *m_comb; + u_char buf[256]; + u_int len = sizeof(m_prop) + sizeof(m_comb) * 2; + + /* make prop & comb */ + m_prop.sadb_prop_len = PFKEY_UNIT64(len); + m_prop.sadb_prop_exttype = SADB_EXT_PROPOSAL; + m_prop.sadb_prop_replay = 0; + m_prop.sadb_prop_reserved[0] = 0; + m_prop.sadb_prop_reserved[1] = 0; + m_prop.sadb_prop_reserved[2] = 0; + + /* the 1st is ESP DES-CBC HMAC-MD5 */ + m_comb = (struct sadb_comb *)buf; + m_comb->sadb_comb_auth = SADB_AALG_MD5HMAC; + m_comb->sadb_comb_encrypt = SADB_EALG_DESCBC; + m_comb->sadb_comb_flags = 0; + m_comb->sadb_comb_auth_minbits = 8; + m_comb->sadb_comb_auth_maxbits = 96; + m_comb->sadb_comb_encrypt_minbits = 64; + m_comb->sadb_comb_encrypt_maxbits = 64; + m_comb->sadb_comb_reserved = 0; + m_comb->sadb_comb_soft_allocations = 0; + m_comb->sadb_comb_hard_allocations = 0; + m_comb->sadb_comb_soft_bytes = 0; + m_comb->sadb_comb_hard_bytes = 0; + m_comb->sadb_comb_soft_addtime = 0; + m_comb->sadb_comb_hard_addtime = 0; + m_comb->sadb_comb_soft_usetime = 0; + m_comb->sadb_comb_hard_usetime = 0; + + /* the 2st is ESP 3DES-CBC and AH HMAC-SHA1 */ + m_comb = (struct sadb_comb *)(buf + sizeof(*m_comb)); + m_comb->sadb_comb_auth = SADB_AALG_SHA1HMAC; + m_comb->sadb_comb_encrypt = SADB_EALG_3DESCBC; + m_comb->sadb_comb_flags = 0; + m_comb->sadb_comb_auth_minbits = 8; + m_comb->sadb_comb_auth_maxbits = 96; + m_comb->sadb_comb_encrypt_minbits = 64; + m_comb->sadb_comb_encrypt_maxbits = 64; + m_comb->sadb_comb_reserved = 0; + m_comb->sadb_comb_soft_allocations = 0; + m_comb->sadb_comb_hard_allocations = 0; + m_comb->sadb_comb_soft_bytes = 0; + m_comb->sadb_comb_hard_bytes = 0; + m_comb->sadb_comb_soft_addtime = 0; + m_comb->sadb_comb_hard_addtime = 0; + m_comb->sadb_comb_soft_usetime = 0; + m_comb->sadb_comb_hard_usetime = 0; + + key_setsadbextbuf(m_buf, m_len, + (caddr_t)&m_prop, sizeof(struct sadb_prop), + buf, sizeof(*m_comb) * 2); + m_len += len; + + return; +} + +void +key_setsadbid(ext, str) + u_int ext; + caddr_t str; +{ + struct sadb_ident m_id; + u_int idlen = strlen(str), len; + + len = sizeof(m_id) + PFKEY_ALIGN8(idlen); + m_id.sadb_ident_len = PFKEY_UNIT64(len); + m_id.sadb_ident_exttype = ext; + m_id.sadb_ident_type = SADB_IDENTTYPE_USERFQDN; + m_id.sadb_ident_reserved = 0; + m_id.sadb_ident_id = getpid(); + + key_setsadbextbuf(m_buf, m_len, + (caddr_t)&m_id, sizeof(struct sadb_ident), + str, idlen); + m_len += len; + + return; +} + +void +key_setsadblft(ext, time) + u_int ext, time; +{ + struct sadb_lifetime m_lft; + + m_lft.sadb_lifetime_len = PFKEY_UNIT64(sizeof(m_lft)); + m_lft.sadb_lifetime_exttype = ext; + m_lft.sadb_lifetime_allocations = 0x2; + m_lft.sadb_lifetime_bytes = 0x1000; + m_lft.sadb_lifetime_addtime = time; + m_lft.sadb_lifetime_usetime = 0x0020; + + memcpy(m_buf + m_len, &m_lft, sizeof(struct sadb_lifetime)); + m_len += sizeof(struct sadb_lifetime); + + return; +} + +void +key_setspirange() +{ + struct sadb_spirange m_spi; + + m_spi.sadb_spirange_len = PFKEY_UNIT64(sizeof(m_spi)); + m_spi.sadb_spirange_exttype = SADB_EXT_SPIRANGE; + m_spi.sadb_spirange_min = 0x00001000; + m_spi.sadb_spirange_max = 0x00002000; + m_spi.sadb_spirange_reserved = 0; + + memcpy(m_buf + m_len, &m_spi, sizeof(struct sadb_spirange)); + m_len += sizeof(struct sadb_spirange); + + return; +} + +void +key_setsadbkey(ext, str) + u_int ext; + caddr_t str; +{ + struct sadb_key m_key; + u_int keylen = strlen(str); + u_int len; + + len = sizeof(struct sadb_key) + PFKEY_ALIGN8(keylen); + m_key.sadb_key_len = PFKEY_UNIT64(len); + m_key.sadb_key_exttype = ext; + m_key.sadb_key_bits = keylen * 8; + m_key.sadb_key_reserved = 0; + + key_setsadbextbuf(m_buf, m_len, + (caddr_t)&m_key, sizeof(struct sadb_key), + str, keylen); + m_len += len; + + return; +} + +void +key_setsadbsa() +{ + struct sadb_sa m_sa; + + m_sa.sadb_sa_len = PFKEY_UNIT64(sizeof(struct sadb_sa)); + m_sa.sadb_sa_exttype = SADB_EXT_SA; + m_sa.sadb_sa_spi = htonl(0x12345678); + m_sa.sadb_sa_replay = 4; + m_sa.sadb_sa_state = 0; + m_sa.sadb_sa_auth = SADB_AALG_MD5HMAC; + m_sa.sadb_sa_encrypt = SADB_EALG_DESCBC; + m_sa.sadb_sa_flags = 0; + + memcpy(m_buf + m_len, &m_sa, sizeof(struct sadb_sa)); + m_len += sizeof(struct sadb_sa); + + return; +} + +void +key_setsadbaddr(ext, af, str) + u_int ext, af; + caddr_t str; +{ + struct sadb_address m_addr; + u_char abuf[64]; + struct sockaddr *a = (struct sockaddr *)abuf; + u_int len; + + /* make sockaddr buffer */ + memset(abuf, 0, sizeof(abuf)); + a->sa_len = _SALENBYAF(af); + a->sa_family = af; + _INPORTBYSA(a) = + (ext == SADB_EXT_ADDRESS_PROXY ? 0 : htons(0x1234)); + if (inet_pton(af, str, _INADDRBYSA(a)) != 1) + ; /* XXX do something */ + + len = sizeof(struct sadb_address) + PFKEY_ALIGN8(a->sa_len); + m_addr.sadb_address_len = PFKEY_UNIT64(len); + m_addr.sadb_address_exttype = ext; + m_addr.sadb_address_proto = + (ext == SADB_EXT_ADDRESS_PROXY ? 0 : IPPROTO_TCP); + m_addr.sadb_address_prefixlen = _INALENBYAF(af); + m_addr.sadb_address_reserved = 0; + + key_setsadbextbuf(m_buf, m_len, + (caddr_t)&m_addr, sizeof(struct sadb_address), + abuf, a->sa_len); + m_len += len; + + return; +} + +void +key_setsadbextbuf(dst, off, ebuf, elen, vbuf, vlen) + caddr_t dst, ebuf, vbuf; + int off, elen, vlen; +{ + memset(dst + off, 0, elen + vlen); + memcpy(dst + off, (caddr_t)ebuf, elen); + memcpy(dst + off + elen, vbuf, vlen); + + return; +} + diff --git a/usr.sbin/setkey/test-policy.c b/usr.sbin/setkey/test-policy.c new file mode 100644 index 0000000..27cd478 --- /dev/null +++ b/usr.sbin/setkey/test-policy.c @@ -0,0 +1,161 @@ +/* + * Copyright (C) 1995, 1996, 1997, 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. + * + * $FreeBSD$ + */ + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <netinet6/in6.h> +#include <netkey/keyv2.h> +#include <stdlib.h> +#include <string.h> + +#include <netinet6/ipsec.h> + +char *requests[] = { +"must_error", /* must be error */ +"ipsec must_error", /* must be error */ +"ipsec esp/must_error", /* must be error */ +"discard", +"none", +"entrust", +"bypass", /* may be error */ +"ipsec esp", /* must be error */ +"ipsec ah/require", +"ipsec ah/use/", +"ipsec esp/require ah/default/203.178.141.194", +"ipsec ah/use/203.178.141.195 esp/use/203.178.141.194", +"ipsec esp/elf.wide.ydc.co.jp esp/www.wide.ydc.co.jp" +" +ipsec esp/require ah/use esp/require/10.0.0.1 +ah/use/3ffe:501:481d::1 ah/use/3ffe:501:481d::1 ah/use/3ffe:501:481d::1 +ah/use/3ffe:501:481d::1 ah/use/3ffe:501:481d::1 ah/use/3ffe:501:481d::1 +ah/use/3ffe:501:481d::1 ah/use/3ffe:501:481d::1 ah/use/3ffe:501:481d::1 +ah/use/3ffe:501:481d::1 ah/use/3ffe:501:481d::1 ah/use/3ffe:501:481d::1 +ah/use/3ffe:501:481d::1 ah/use/3ffe:501:481d::1 ah/use/3ffe:501:481d::1 +ah/use/3ffe:501:481d::1 ah/use/3ffe:501:481d::1 ah/use/3ffe:501:481d::1 +ah/use/3ffe:501:481d::1 ah/use/3ffe:501:481d::1 ah/use/3ffe:501:481d::1 +ah/use/3ffe:501:481d::1 ah/use/3ffe:501:481d::1ah/use/3ffe:501:481d::1 +", +}; + +u_char *p_secpolicy; + +int test(char *buf, int family); +char *setpolicy(char *req); + +main() +{ + int i; + char *buf; + + for (i = 0; i < sizeof(requests)/sizeof(requests[0]); i++) { + printf("* requests:[%s]\n", requests[i]); + if ((buf = setpolicy(requests[i])) == NULL) + continue; + printf("\tsetlen:%d\n", PFKEY_EXTLEN(buf)); + + printf("\tPF_INET:\n"); + test(buf, PF_INET); + + printf("\tPF_INET6:\n"); + test(buf, PF_INET6); + free(buf); + } +} + +int test(char *policy, int family) +{ + int so, proto, optname; + int len; + char getbuf[1024]; + + switch (family) { + case PF_INET: + proto = IPPROTO_IP; + optname = IP_IPSEC_POLICY; + break; + case PF_INET6: + proto = IPPROTO_IPV6; + optname = IPV6_IPSEC_POLICY; + break; + } + + if ((so = socket(family, SOCK_DGRAM, 0)) < 0) + perror("socket"); + + if (setsockopt(so, proto, optname, policy, PFKEY_EXTLEN(policy)) < 0) + perror("setsockopt"); + + len = sizeof(getbuf); + memset(getbuf, 0, sizeof(getbuf)); + if (getsockopt(so, proto, optname, getbuf, &len) < 0) + perror("getsockopt"); + + { + char *buf = NULL; + + printf("\tgetlen:%d\n", len); + + if ((buf = ipsec_dump_policy(getbuf, NULL)) == NULL) + ipsec_strerror(); + else + printf("\t[%s]\n", buf); + + free(buf); + } + + close (so); +} + +char *setpolicy(char *req) +{ + int len; + char *buf; + + if ((len = ipsec_get_policylen(req)) < 0) { + printf("ipsec_get_policylen: %s\n", ipsec_strerror()); + return NULL; + } + + if ((buf = malloc(len)) == NULL) { + perror("malloc"); + return NULL; + } + + if ((len = ipsec_set_policy(buf, len, req)) < 0) { + printf("ipsec_set_policy: %s\n", ipsec_strerror()); + free(buf); + return NULL; + } + + return buf; +} diff --git a/usr.sbin/setkey/token.l b/usr.sbin/setkey/token.l new file mode 100644 index 0000000..b75fd45 --- /dev/null +++ b/usr.sbin/setkey/token.l @@ -0,0 +1,322 @@ +/* + * Copyright (C) 1995, 1996, 1997, 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. + * + * $FreeBSD$ + */ + +%{ +#include <sys/types.h> +#include <sys/param.h> +#include <sys/socket.h> +#include <net/route.h> +#include <net/pfkeyv2.h> +#include <netkey/keydb.h> +#include <netkey/key_debug.h> +#include <netinet/in.h> +#include <netinet6/ipsec.h> + +#include <stdlib.h> +#include <limits.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> +#include "vchar.h" +#include "y.tab.h" + +#define DECHO \ + if (f_debug) {printf("<%d>", yy_start); ECHO ; printf("\n"); } + +#define CMDARG \ +{ \ + char *__buf__ = strdup(yytext), *__p__; \ + for (__p__ = __buf__; *__p__ != NULL; __p__++) \ + if (*__p__ == '\n' || *__p__ == '\t') \ + *__p__ = ' '; \ + strcat(cmdarg, __buf__); \ + free(__buf__); \ +} + +#define PREPROC DECHO CMDARG + +int lineno = 1; +char cmdarg[8192]; /* XXX: BUFSIZ is the better ? */ + +extern u_char m_buf[BUFSIZ]; +extern u_int m_len; +extern int f_debug; + +int yylex __P((void)); +void yyerror __P((char *s)); +extern void parse_init __P((void)); +int parse __P((FILE **)); +int yyparse __P((void)); + +%} + +/* common section */ +nl \n +ws [ \t]+ +digit [0-9] +letter [0-9A-Za-z] +hexdigit [0-9A-Fa-f] +/*octet (([01]?{digit}?{digit})|((2([0-4]{digit}))|(25[0-5])))*/ +special [()+\|\?\*,] +dot \. +comma \, +hyphen \- +colon \: +slash \/ +bcl \{ +ecl \} +blcl \[ +elcl \] +percent \% +semi \; +usec {dot}{digit}{1,6} +comment \#.* +ccomment "/*" +bracketstring \<[^>]*\> +quotedstring \"[^"]*\" +decstring {digit}+ +hexpair {hexdigit}{hexdigit} +hexstring 0[xX]{hexdigit}+ +octetstring {octet}({dot}{octet})+ +ipaddress {ipv4addr}|{ipv6addr} +ipv4addr {digit}{1,3}({dot}{digit}{1,3}){0,3} +ipv6addr {hexdigit}{0,4}({colon}{hexdigit}{0,4}){2,7}(@{letter}{letter}+)? +ipaddrmask {slash}{digit}{1,3} +ipaddrport {blcl}{decstring}{elcl} +keyword {letter}{letter}+ +name {letter}(({letter}|{digit}|{hyphen})*({letter}|{digit}))* +hostname {name}(({dot}{name})+{dot}?)? + +%s S_PL + +%% + +add { PREPROC; return(ADD); } +delete { PREPROC; return(DELETE); } +get { PREPROC; return(GET); } +flush { PREPROC; return(FLUSH); } +dump { PREPROC; return(DUMP); } + + /* for management SPD */ +spdadd { PREPROC; return(SPDADD); } +spddelete { PREPROC; return(SPDDELETE); } +spddump { PREPROC; return(SPDDUMP); } +spdflush { PREPROC; return(SPDFLUSH); } +{hyphen}P { BEGIN S_PL; PREPROC; return(F_POLICY); } +<S_PL>[a-zA-Z0-9:\.\-_/ \n\t][a-zA-Z0-9:\.\-_/ \n\t]* { + yymore(); + + /* count up for nl */ + { + char *p; + for (p = yytext; *p != NULL; p++) + if (*p == '\n') + lineno++; + } + + yylval.val.len = strlen(yytext); + yylval.val.buf = strdup(yytext); + + return(PL_REQUESTS); +} +<S_PL>{semi} { PREPROC; BEGIN INITIAL; return(EOT); } + + /* security protocols */ +ah { PREPROC; yylval.num = 0; return(PR_AH); } +esp { PREPROC; yylval.num = 0; return(PR_ESP); } +ah-old { PREPROC; yylval.num = 1; return(PR_AH); } +esp-old { PREPROC; yylval.num = 1; return(PR_ESP); } +ipcomp { PREPROC; yylval.num = 0; return(PR_IPCOMP); } + + /* authentication alogorithm */ +{hyphen}A { PREPROC; return(F_AUTH); } +hmac-md5 { PREPROC; yylval.num = SADB_AALG_MD5HMAC; return(ALG_AUTH); } +hmac-sha1 { PREPROC; yylval.num = SADB_AALG_SHA1HMAC; return(ALG_AUTH); } +keyed-md5 { PREPROC; yylval.num = SADB_AALG_MD5; return(ALG_AUTH); } +keyed-sha1 { PREPROC; yylval.num = SADB_AALG_SHA; return(ALG_AUTH); } +null { PREPROC; yylval.num = SADB_AALG_NULL; return(ALG_AUTH); } + + /* encryption alogorithm */ +{hyphen}E { PREPROC; return(F_ENC); } +des-cbc { PREPROC; yylval.num = SADB_EALG_DESCBC; return(ALG_ENC); } +3des-cbc { PREPROC; yylval.num = SADB_EALG_3DESCBC; return(ALG_ENC); } +simple { PREPROC; yylval.num = SADB_EALG_NULL; return(ALG_ENC); } +blowfish-cbc { PREPROC; yylval.num = SADB_EALG_BLOWFISHCBC; return(ALG_ENC); } +cast128-cbc { PREPROC; yylval.num = SADB_EALG_CAST128CBC; return(ALG_ENC); } +rc5-cbc { PREPROC; yylval.num = SADB_EALG_RC5CBC; return(ALG_ENC); } +des-deriv { PREPROC; yylval.num = SADB_EALG_DESCBC; return(ALG_ENC_DESDERIV); } +des-32iv { PREPROC; yylval.num = SADB_EALG_DESCBC; return(ALG_ENC_DES32IV); } + + /* compression algorithms */ +{hyphen}C { PREPROC; return(F_COMP); } +oui { PREPROC; yylval.num = SADB_X_CALG_OUI; return(ALG_COMP); } +deflate { PREPROC; yylval.num = SADB_X_CALG_DEFLATE; return(ALG_COMP); } +lzs { PREPROC; yylval.num = SADB_X_CALG_LZS; return(ALG_COMP); } +{hyphen}R { PREPROC; return(F_RAWCPI); } + + /* extension */ +{hyphen}m { PREPROC; return(F_MODE); } +transport { PREPROC; yylval.num = IPSEC_MODE_TRANSPORT; return(MODE); } +tunnel { PREPROC; yylval.num = IPSEC_MODE_TUNNEL; return(MODE); } +{hyphen}f { PREPROC; return(F_EXT); } +random-pad { PREPROC; yylval.num = SADB_X_EXT_PRAND; return(EXTENSION); } +seq-pad { PREPROC; yylval.num = SADB_X_EXT_PSEQ; return(EXTENSION); } +zero-pad { PREPROC; yylval.num = SADB_X_EXT_PZERO; return(EXTENSION); } +cyclic-seq { PREPROC; yylval.num = SADB_X_EXT_CYCSEQ; return(EXTENSION); } +{hyphen}r { PREPROC; return(F_REPLAY); } +{hyphen}lh { PREPROC; return(F_LIFETIME_HARD); } +{hyphen}ls { PREPROC; return(F_LIFETIME_SOFT); } + + + /* upper layer protocols */ +icmp { PREPROC; yylval.num = IPPROTO_ICMP; return(UP_PROTO); } +icmp6 { PREPROC; yylval.num = IPPROTO_ICMPV6; return(UP_PROTO); } +tcp { PREPROC; yylval.num = IPPROTO_TCP; return(UP_PROTO); } +udp { PREPROC; yylval.num = IPPROTO_UDP; return(UP_PROTO); } + + /* ... */ +any { PREPROC; return(ANY); } +{ws} { PREPROC; } +{nl} { lineno++; } +{comment} +{semi} { PREPROC; return(EOT); } + + /* parameter */ +{decstring} { + char *bp; + + PREPROC; + yylval.num = strtol(yytext, &bp, 10); + return(DECSTRING); + } + +{ipv4addr} { + /* + * I can't supprt the type without dot, + * because it's umbiguous against {decstring}. + * e.g. 127 + */ + PREPROC; + + yylval.val.len = sizeof(struct sockaddr_in); + yylval.val.buf = strdup(yytext); + + return(IP4_ADDRESS); + } + +{ipv6addr} { +#ifdef INET6 + PREPROC; + + yylval.val.len = sizeof(struct sockaddr_in6); + yylval.val.buf = strdup(yytext); + + return(IP6_ADDRESS); +#else + yyerror("IPv6 address not supported"); +#endif + } + +{ipaddrmask} { + PREPROC; + yytext++; + yylval.num = atoi(yytext); + return(PREFIX); + } + +{ipaddrport} { + char *p = yytext; + PREPROC; + while (*++p != ']') ; + *p = NULL; + yytext++; + yylval.num = atoi(yytext); + return(PORT); + } + +{blcl}any{elcl} { + char *p = yytext; + PREPROC; + return(PORTANY); + } + +{hexstring} { + int len = yyleng - 2; /* (str - "0x") */ + PREPROC; + yylval.val.len = (len & 1) + (len / 2); + /* fixed string if length is odd. */ + if (len & 1) { + yytext[1] = '0'; + yylval.val.buf = strdup(yytext + 1); + } else + yylval.val.buf = strdup(yytext + 2); + + return(HEXSTRING); + } + +{quotedstring} { + char *p = yytext; + PREPROC; + while (*++p != '"') ; + *p = NULL; + yytext++; + yylval.val.len = yyleng - 2; + yylval.val.buf = strdup(yytext); + + return(QUOTEDSTRING); + } + +. { yyerror("Syntax error"); } + +%% + +void +yyerror(char *s) +{ + printf("line %d: %s at [%s]\n", lineno, s, yytext); +} + +int +parse(fp) + FILE **fp; +{ + yyin = *fp; + + parse_init(); + + if (yyparse()) { + printf("parse failed, line %d.\n", lineno); + return(-1); + } + + return(0); +} + diff --git a/usr.sbin/setkey/vchar.h b/usr.sbin/setkey/vchar.h new file mode 100644 index 0000000..977f5f0 --- /dev/null +++ b/usr.sbin/setkey/vchar.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 1995, 1996, 1997, 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. + * + * $FreeBSD$ + */ + +typedef struct { + u_int len; + caddr_t buf; +} vchar_t; diff --git a/usr.sbin/traceroute6/Makefile b/usr.sbin/traceroute6/Makefile index 2b151a6..d2f6de1 100644 --- a/usr.sbin/traceroute6/Makefile +++ b/usr.sbin/traceroute6/Makefile @@ -19,7 +19,9 @@ BINOWN= root BINGRP= bin BINMODE=4555 -CFLAGS+=-DINET6 +CFLAGS+=-DINET6 -DIPSEC +DPADD= ${LIBIPSEC} +LDADD= -lipsec MAN8= traceroute6.8 |