diff options
author | hrs <hrs@FreeBSD.org> | 2009-09-12 22:08:20 +0000 |
---|---|---|
committer | hrs <hrs@FreeBSD.org> | 2009-09-12 22:08:20 +0000 |
commit | 2eb62239d7432351eb544690c4ea2fc648ae2abc (patch) | |
tree | a8b68cd78a93144234b4c47ac70911fd744e48ff /sbin | |
parent | 02e6d1c7f95b09e7d57ae3d261a65a3ea25aa637 (diff) | |
download | FreeBSD-src-2eb62239d7432351eb544690c4ea2fc648ae2abc.zip FreeBSD-src-2eb62239d7432351eb544690c4ea2fc648ae2abc.tar.gz |
Improve flexibility of receiving Router Advertisement and
automatic link-local address configuration:
- Convert a sysctl net.inet6.ip6.accept_rtadv to one for the
default value of a per-IF flag ND6_IFF_ACCEPT_RTADV, not a
global knob. The default value of the sysctl is 0.
- Add a new per-IF flag ND6_IFF_AUTO_LINKLOCAL and convert a
sysctl net.inet6.ip6.auto_linklocal to one for its default
value. The default value of the sysctl is 1.
- Make ND6_IFF_IFDISABLED more robust. It can be used to disable
IPv6 functionality of an interface now.
- Receiving RA is allowed if ip6_forwarding==0 *and*
ND6_IFF_ACCEPT_RTADV is set on that interface. The former
condition will be revisited later to support a "host + router" box
like IPv6 CPE router. The current behavior is compatible with
the older releases of FreeBSD.
- The ifconfig(8) now supports these ND6 flags as well as "nud",
"prefer_source", and "disabled" in ndp(8). The ndp(8) now
supports "auto_linklocal".
Discussed with: bz and jinmei
Reviewed by: bz
MFC after: 3 days
Diffstat (limited to 'sbin')
-rw-r--r-- | sbin/ifconfig/Makefile | 1 | ||||
-rw-r--r-- | sbin/ifconfig/af_inet6.c | 15 | ||||
-rw-r--r-- | sbin/ifconfig/af_nd6.c | 251 | ||||
-rw-r--r-- | sbin/ifconfig/ifconfig.8 | 64 |
4 files changed, 322 insertions, 9 deletions
diff --git a/sbin/ifconfig/Makefile b/sbin/ifconfig/Makefile index e5b78af..367ad9c 100644 --- a/sbin/ifconfig/Makefile +++ b/sbin/ifconfig/Makefile @@ -18,6 +18,7 @@ SRCS+= af_link.c # LLC support SRCS+= af_inet.c # IPv4 support SRCS+= af_inet6.c # IPv6 support SRCS+= af_atalk.c # AppleTalk support +SRCS+= af_nd6.c # ND6 support SRCS+= ifclone.c # clone device support SRCS+= ifmac.c # MAC support diff --git a/sbin/ifconfig/af_inet6.c b/sbin/ifconfig/af_inet6.c index 13789dc..8fc143a 100644 --- a/sbin/ifconfig/af_inet6.c +++ b/sbin/ifconfig/af_inet6.c @@ -67,6 +67,9 @@ static int prefix(void *, int); static char *sec2str(time_t); static int explicit_prefix = 0; +extern void setnd6flags(const char *, int, int, const struct afswtch *); +extern void setnd6defif(const char *, int, int, const struct afswtch *); + static char addr_buf[MAXHOSTNAMELEN *2 + 1]; /*for getnameinfo()*/ static void @@ -493,6 +496,18 @@ static struct cmd inet6_cmds[] = { DEF_CMD("-deprecated", -IN6_IFF_DEPRECATED, setip6flags), DEF_CMD("autoconf", IN6_IFF_AUTOCONF, setip6flags), DEF_CMD("-autoconf", -IN6_IFF_AUTOCONF, setip6flags), + DEF_CMD("accept_rtadv", ND6_IFF_ACCEPT_RTADV, setnd6flags), + DEF_CMD("-accept_rtadv",-ND6_IFF_ACCEPT_RTADV, setnd6flags), + DEF_CMD("defaultif", 1, setnd6defif), + DEF_CMD("-defaultif", -1, setnd6defif), + DEF_CMD("ifdisabled", ND6_IFF_IFDISABLED, setnd6flags), + DEF_CMD("-ifdisabled", -ND6_IFF_IFDISABLED, setnd6flags), + DEF_CMD("nud", ND6_IFF_PERFORMNUD, setnd6flags), + DEF_CMD("-nud", -ND6_IFF_PERFORMNUD, setnd6flags), + DEF_CMD("prefer_source",ND6_IFF_PREFER_SOURCE, setnd6flags), + DEF_CMD("-prefer_source",-ND6_IFF_PREFER_SOURCE,setnd6flags), + DEF_CMD("auto_linklocal",ND6_IFF_AUTO_LINKLOCAL,setnd6flags), + DEF_CMD("-auto_linklocal",-ND6_IFF_AUTO_LINKLOCAL,setnd6flags), DEF_CMD_ARG("pltime", setip6pltime), DEF_CMD_ARG("vltime", setip6vltime), DEF_CMD("eui64", 0, setip6eui64), diff --git a/sbin/ifconfig/af_nd6.c b/sbin/ifconfig/af_nd6.c new file mode 100644 index 0000000..4fde0c4 --- /dev/null +++ b/sbin/ifconfig/af_nd6.c @@ -0,0 +1,251 @@ +/* + * Copyright (c) 2009 Hiroki Sato. 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 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. + */ + +#ifndef lint +static const char rcsid[] = + "$FreeBSD$"; +#endif /* not lint */ + +#include <sys/param.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <sys/sysctl.h> +#include <net/if.h> +#include <net/route.h> + +#include <err.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <ifaddrs.h> + +#include <arpa/inet.h> + +#include <netinet/in.h> +#include <net/if_var.h> +#include <netinet/in_var.h> +#include <arpa/inet.h> +#include <netdb.h> + +#include <netinet6/nd6.h> + +#include "ifconfig.h" + +#define MAX_SYSCTL_TRY 5 + +static struct nd6_opt_list { + const char *label; + u_int mask; +} nd6_opts[] = { + { "IFDISABLED", ND6_IFF_IFDISABLED, }, + { "PERFORMNUD", ND6_IFF_PERFORMNUD, }, + { "ACCEPT_RTADV", ND6_IFF_ACCEPT_RTADV, }, + { "PREFER_SOURCE", ND6_IFF_PREFER_SOURCE, }, + { "AUTO_LINKLOCAL", ND6_IFF_AUTO_LINKLOCAL, }, +}; + +static int isnd6defif(int); +void setnd6flags(const char *, int, int, const struct afswtch *); +void setnd6defif(const char *, int, int, const struct afswtch *); + +void +setnd6flags(const char *dummyaddr __unused, + int d, int s, + const struct afswtch *afp) +{ + struct in6_ndireq nd; + int error; + + memset(&nd, 0, sizeof(nd)); + strncpy(nd.ifname, ifr.ifr_name, sizeof(nd.ifname)); + error = ioctl(s, SIOCGIFINFO_IN6, &nd); + if (error) { + warn("ioctl(SIOCGIFINFO_IN6)"); + return; + } + if (d < 0) + nd.ndi.flags &= ~(-d); + else + nd.ndi.flags |= d; + error = ioctl(s, SIOCSIFINFO_IN6, (caddr_t)&nd); + if (error) + warn("ioctl(SIOCSIFINFO_IN6)"); +} + +void +setnd6defif(const char *dummyaddr __unused, + int d, int s, + const struct afswtch *afp) +{ + struct in6_ndifreq ndifreq; + int ifindex; + int error; + + memset(&ndifreq, 0, sizeof(ndifreq)); + strncpy(ndifreq.ifname, ifr.ifr_name, sizeof(ndifreq.ifname)); + + if (d < 0) { + if (isnd6defif(s)) { + /* ifindex = 0 means to remove default if */ + ifindex = 0; + } else + return; + } else if ((ifindex = if_nametoindex(ndifreq.ifname)) == 0) { + warn("if_nametoindex(%s)", ndifreq.ifname); + return; + } + + ndifreq.ifindex = ifindex; + error = ioctl(s, SIOCSDEFIFACE_IN6, (caddr_t)&ndifreq); + if (error) + warn("ioctl(SIOCSDEFIFACE_IN6)"); +} + +static int +isnd6defif(int s) +{ + struct in6_ndifreq ndifreq; + unsigned int ifindex; + int error; + + memset(&ndifreq, 0, sizeof(ndifreq)); + strncpy(ndifreq.ifname, ifr.ifr_name, sizeof(ndifreq.ifname)); + + ifindex = if_nametoindex(ndifreq.ifname); + error = ioctl(s, SIOCGDEFIFACE_IN6, (caddr_t)&ndifreq); + if (error) { + warn("ioctl(SIOCGDEFIFACE_IN6)"); + return (error); + } + return (ndifreq.ifindex == ifindex); +} + +static void +nd6_status(int s) +{ + struct in6_ndireq nd; + struct rt_msghdr *rtm; + size_t needed; + char *buf, *next; + int mib[6], ntry; + int s6; + int i, error; + int isinet6, isdefif; + int nopts; + + /* Check if the interface has at least one IPv6 address. */ + mib[0] = CTL_NET; + mib[1] = PF_ROUTE; + mib[2] = 0; + mib[3] = AF_INET6; + mib[4] = NET_RT_IFLIST; + mib[5] = if_nametoindex(ifr.ifr_name); + + /* Try to prevent a race between two sysctls. */ + ntry = 0; + do { + error = sysctl(mib, 6, NULL, &needed, NULL, 0); + if (error) { + warn("sysctl(NET_RT_IFLIST)/estimate"); + return; + } + buf = malloc(needed); + if (buf == NULL) { + warn("malloc for sysctl(NET_RT_IFLIST) failed"); + return; + } + if ((error = sysctl(mib, 6, buf, &needed, NULL, 0)) < 0) { + if (errno != ENOMEM || ++ntry >= MAX_SYSCTL_TRY) { + warn("sysctl(NET_RT_IFLIST)/get"); + free(buf); + return; + } + free(buf); + buf = NULL; + } + } while (buf == NULL); + + isinet6 = 0; + for (next = buf; next < buf + needed; next += rtm->rtm_msglen) { + rtm = (struct rt_msghdr *)next; + + if (rtm->rtm_version != RTM_VERSION) + continue; + if (rtm->rtm_type == RTM_NEWADDR) { + isinet6 = 1; + break; + } + } + free(buf); + if (!isinet6) + return; + + memset(&nd, 0, sizeof(nd)); + strncpy(nd.ifname, ifr.ifr_name, sizeof(nd.ifname)); + if ((s6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + warn("socket(AF_INET6, SOCK_DGRAM)"); + return; + } + error = ioctl(s6, SIOCGIFINFO_IN6, &nd); + if (error) { + warn("ioctl(SIOCGIFINFO_IN6)"); + close(s6); + return; + } + isdefif = isnd6defif(s6); + close(s6); + if (nd.ndi.flags == 0 && !isdefif) + return; + + nopts = 0; + printf("\tnd6 options=%d<", nd.ndi.flags); + for (i=0; i < sizeof(nd6_opts)/sizeof(nd6_opts[0]); i++) { + if (nd.ndi.flags & nd6_opts[i].mask) { + if (nopts++) + printf(","); + printf("%s", nd6_opts[i].label); + } + } + if (isdefif) { + if (nopts) + printf(","); + printf("DEFAULTIF"); + } + printf(">\n"); +} + +static struct afswtch af_nd6 = { + .af_name = "nd6", + .af_af = AF_LOCAL, + .af_other_status= nd6_status, +}; + +static __constructor void +nd6_ctor(void) +{ + af_register(&af_nd6); +} diff --git a/sbin/ifconfig/ifconfig.8 b/sbin/ifconfig/ifconfig.8 index 1d2f096..f4bcc5a 100644 --- a/sbin/ifconfig/ifconfig.8 +++ b/sbin/ifconfig/ifconfig.8 @@ -28,7 +28,7 @@ .\" From: @(#)ifconfig.8 8.3 (Berkeley) 1/5/94 .\" $FreeBSD$ .\" -.Dd July 8, 2009 +.Dd September 2, 2009 .Dt IFCONFIG 8 .Os .Sh NAME @@ -598,6 +598,48 @@ If the interface was reset when previously marked down, the hardware will be re-initialized. .El .Pp +The following parameters are for ICMPv6 Neightbor Discovery Protocol: +.Bl -tag -width indent +.It Cm accept_rtadv +Set a flag to enable accepting ICMPv6 Router Advertisement messages. +.It Cm -accept_rtadv +Clear a flag +.Cm accept_rtadv . +.It Cm auto_linklocal +Set a flag to perform automatic link-local address configuration when +the interface becomes avalilable. +.It Cm -auto_linklocal +Clear a flag +.Cm auto_linklocal . +.It Cm defaultif +Set the specified interface as the default route when there is no +default router. +.It Cm -defaultif +Clear a flag +.Cm defaultif . +.It Cm ifdisabled +Set a flag to disable all of IPv6 network communications on the +specified interface. +.It Cm -ifdisabled +Clear a flag +.Cm ifdisabled . +When this flag is cleared and +.Cm auto_linklocal +flag is enabled, automatic configuration of a link-local address is +performed. +.It Cm nud +Set a flag to enable Neighbor Unreachability Detection. +.It Cm -nud +Clear a flag +.Cm nud . +.It Cm prefer_source +Set a flag to prefer addesses on the interface as candidates of the +source address for outgoing packets. +.It Cm -prefer_source +Clear a flag +.Cm prefer_source . +.El +.Pp The following parameters are specific to cloning IEEE 802.11 wireless interfaces with the .Cm create @@ -2421,6 +2463,9 @@ from the interface .Li ed0 : .Dl # ifconfig ed0 inet 192.0.2.45 -alias .Pp +Enable IPv6 functionality of the interface: +.Dl # ifconfig em0 inet6 -ifdisabled +.Pp Add the IPv6 address .Li 2001:DB8:DBDB::123/48 to the interface @@ -2475,12 +2520,13 @@ utility appeared in Basic IPv6 node operation requires a link-local address on each interface configured for IPv6. Normally, such an address is automatically configured by the -kernel on each interface added to the system; this behaviour may -be disabled by setting the sysctl MIB variable -.Va net.inet6.ip6.auto_linklocal -to 0. +kernel on each interface added to the system or enabled; this behavior may +be disabled by setting per-interface flag +.Cm -auto_linklocal . +The default value of this flag is 1 and can be disabled by using the sysctl +MIB variable +.Va net.inet6.ip6.auto_linklocal . .Pp -If you delete such an address using -.Nm , -the kernel may act very odd. -Do this at your own risk. +Do not configure IPv6 addresses with no link-local address by using +.Nm . +It can result in unexpected behaviors of the kernel. |