This commit is contained in:
roy 2013-09-20 10:56:32 +00:00
parent 71f31e7121
commit f6e48aaf0c
9 changed files with 243 additions and 2200 deletions

View File

@ -1,5 +1,5 @@
#include <sys/cdefs.h>
__RCSID("$NetBSD: dhcp.c,v 1.6 2013/07/29 20:39:28 roy Exp $");
__RCSID("$NetBSD: dhcp.c,v 1.7 2013/09/20 10:56:32 roy Exp $");
/*
* dhcpcd - DHCP client daemon
@ -1702,7 +1702,6 @@ dhcp_rebind(void *arg)
send_rebind(ifp);
}
void
dhcp_bind(void *arg)
{
@ -1724,10 +1723,10 @@ dhcp_bind(void *arg)
state->offer = NULL;
get_lease(lease, state->new);
if (ifo->options & DHCPCD_STATIC) {
syslog(LOG_INFO, "%s: using static address %s",
iface->name, inet_ntoa(lease->addr));
syslog(LOG_INFO, "%s: using static address %s/%d",
iface->name, inet_ntoa(lease->addr),
inet_ntocidr(lease->net));
lease->leasetime = ~0U;
lease->net.s_addr = ifo->req_mask.s_addr;
state->reason = "STATIC";
} else if (state->new->cookie != htonl(MAGIC_COOKIE)) {
syslog(LOG_INFO, "%s: using IPv4LL address %s",
@ -1834,7 +1833,7 @@ dhcp_timeout(void *arg)
}
struct dhcp_message *
dhcp_message_new(struct in_addr *addr, struct in_addr *mask)
dhcp_message_new(const struct in_addr *addr, const struct in_addr *mask)
{
struct dhcp_message *dhcp;
uint8_t *p;
@ -1854,60 +1853,65 @@ dhcp_message_new(struct in_addr *addr, struct in_addr *mask)
return dhcp;
}
static int
handle_3rdparty(struct interface *ifp)
{
struct if_options *ifo;
struct dhcp_state *state;
struct in_addr addr, net, dst;
ifo = ifp->options;
if (ifo->req_addr.s_addr != INADDR_ANY)
return 0;
if (ipv4_getaddress(ifp->name, &addr, &net, &dst) == 1)
ipv4_handleifa(RTM_NEWADDR, ifp->name, &addr, &net, &dst);
else {
syslog(LOG_INFO,
"%s: waiting for 3rd party to configure IP address",
ifp->name);
state = D_STATE(ifp);
state->reason = "3RDPARTY";
script_runreason(ifp, state->reason);
}
return 1;
}
static void
dhcp_static(struct interface *ifp)
{
struct if_options *ifo;
struct dhcp_state *state;
if (handle_3rdparty(ifp))
return;
ifo = ifp->options;
state = D_STATE(ifp);
ifo = ifp->options;
if (ifo->req_addr.s_addr == INADDR_ANY) {
syslog(LOG_INFO,
"%s: waiting for 3rd party to "
"configure IP address",
ifp->name);
state->reason = "3RDPARTY";
script_runreason(ifp, state->reason);
return;
}
state->offer = dhcp_message_new(&ifo->req_addr, &ifo->req_mask);
eloop_timeout_delete(NULL, ifp);
dhcp_bind(ifp);
if (state->offer) {
eloop_timeout_delete(NULL, ifp);
dhcp_bind(ifp);
}
}
void
dhcp_inform(struct interface *ifp)
{
struct dhcp_state *state;
if (handle_3rdparty(ifp))
return;
struct if_options *ifo;
struct ipv4_addr *ap;
state = D_STATE(ifp);
ifo = ifp->options;
if (options & DHCPCD_TEST) {
state->addr.s_addr = ifp->options->req_addr.s_addr;
state->net.s_addr = ifp->options->req_mask.s_addr;
state->addr.s_addr = ifo->req_addr.s_addr;
state->net.s_addr = ifo->req_mask.s_addr;
} else {
ifp->options->options |= DHCPCD_STATIC;
dhcp_static(ifp);
if (ifo->req_addr.s_addr == INADDR_ANY) {
state = D_STATE(ifp);
ap = ipv4_findaddr(ifp, NULL, NULL);
if (ap == NULL) {
syslog(LOG_INFO,
"%s: waiting for 3rd party to "
"configure IP address",
ifp->name);
state->reason = "3RDPARTY";
script_runreason(ifp, state->reason);
return;
}
state->offer =
dhcp_message_new(&ap->addr, &ap->net);
} else
state->offer =
dhcp_message_new(&ifo->req_addr, &ifo->req_mask);
if (state->offer) {
ifo->options |= DHCPCD_STATIC;
dhcp_bind(ifp);
ifo->options &= ~DHCPCD_STATIC;
}
}
state->state = DHS_INFORM;
@ -2220,6 +2224,8 @@ dhcp_handle(struct interface *iface, struct dhcp_message **dhcpp,
if (!(ifo->options & DHCPCD_INFORM))
log_dhcp(LOG_DEBUG, "acknowledged", iface, dhcp, from);
else
ifo->options &= ~DHCPCD_STATIC;
}
/* BOOTP could have already assigned this above, so check we still
@ -2244,7 +2250,7 @@ dhcp_handle(struct interface *iface, struct dhcp_message **dhcpp,
/* If the interface already has the address configured
* then we can't ARP for duplicate detection. */
addr.s_addr = state->offer->yiaddr;
if (ipv4_hasaddress(iface->name, &addr, NULL) != 1) {
if (!ipv4_findaddr(iface, &addr, NULL)) {
state->claims = 0;
state->probes = 0;
state->conflicts = 0;
@ -2687,3 +2693,70 @@ dhcp_start(struct interface *ifp)
else
dhcp_reboot(ifp);
}
void
dhcp_handleifa(int type, struct interface *ifp,
const struct in_addr *addr,
const struct in_addr *net,
const struct in_addr *dst)
{
struct dhcp_state *state;
struct if_options *ifo;
int i;
state = D_STATE(ifp);
if (state == NULL)
return;
if (type == RTM_DELADDR) {
if (state->new &&
(state->new->yiaddr == addr->s_addr ||
(state->new->yiaddr == INADDR_ANY &&
state->new->ciaddr == addr->s_addr)))
{
syslog(LOG_INFO, "%s: removing IP address %s/%d",
ifp->name, inet_ntoa(state->lease.addr),
inet_ntocidr(state->lease.net));
dhcp_drop(ifp, "EXPIRE");
}
return;
}
if (type != RTM_NEWADDR)
return;
ifo = ifp->options;
if (ifo->options & DHCPCD_INFORM) {
if (state->state != DHS_INFORM)
dhcp_inform(ifp);
return;
}
if (!(ifo->options & DHCPCD_STATIC))
return;
if (ifo->req_addr.s_addr != INADDR_ANY)
return;
free(state->old);
state->old = state->new;
state->new = dhcp_message_new(addr, net);
if (state->new == NULL)
return;
state->dst.s_addr = dst ? dst->s_addr : INADDR_ANY;
if (dst) {
for (i = 1; i < 255; i++)
if (i != DHO_ROUTER && has_option_mask(ifo->dstmask,i))
dhcp_message_add_addr(state->new, i, *dst);
}
state->reason = "STATIC";
ipv4_buildroutes();
script_runreason(ifp, state->reason);
if (ifo->options & DHCPCD_INFORM) {
state->state = DHS_INFORM;
state->xid = dhcp_xid(ifp);
state->lease.server.s_addr = dst ? dst->s_addr : INADDR_ANY;
state->addr = *addr;
state->net = *net;
dhcp_inform(ifp);
}
}

View File

@ -1,4 +1,4 @@
.\" $NetBSD: dhcpcd.8.in,v 1.21 2013/07/29 20:39:28 roy Exp $
.\" $NetBSD: dhcpcd.8.in,v 1.22 2013/09/20 10:56:32 roy Exp $
.\" Copyright (c) 2006-2013 Roy Marples
.\" All rights reserved
.\"
@ -23,7 +23,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.Dd June 6, 2013
.Dd September 12, 2013
.Dt DHCPCD 8
.Os
.Sh NAME
@ -31,7 +31,7 @@
.Nd a DHCP client
.Sh SYNOPSIS
.Nm
.Op Fl 46ABbDdEGgHJKkLnpqTVw
.Op Fl 46ABbDdEGgHJKLpqTV
.Op Fl C , Fl Fl nohook Ar hook
.Op Fl c , Fl Fl script Ar script
.Op Fl e , Fl Fl env Ar value
@ -52,6 +52,7 @@
.Op Fl u , Fl Fl userclass Ar class
.Op Fl v , Fl Fl vendor Ar code , Ar value
.Op Fl W , Fl Fl whitelist Ar address Ns Op Ar /cidr
.Op Fl w , Fl Fl waitip Op 4 | 6
.Op Fl y , Fl Fl reboot Ar seconds
.Op Fl X , Fl Fl blacklist Ar address Ns Op Ar /cidr
.Op Fl Z , Fl Fl denyinterfaces Ar pattern
@ -59,6 +60,9 @@
.Op interface
.Op ...
.Nm
.Fl n , Fl Fl rebind
.Op interface
.Nm
.Fl k , Fl Fl release
.Op interface
.Nm
@ -300,16 +304,19 @@ For example
If not set then none is sent.
Some badly configured DHCP servers reject unknown vendorclassids.
To work around it, try and impersonate Windows by using the MSFT vendorclassid.
.It Fl k , Fl Fl release
.It Fl k , Fl Fl release Op Ar interface
This causes an existing
.Nm
process running on the
.Ar interface
to release its lease, de-configure the
to release its lease and de-configure the
.Ar interface .
If no
.Ar interface
and then exit.
is specified then this applies to all interfaces.
If no interfaces are left running,
.Nm
then waits until this process has exited.
will exit.
.It Fl l , Fl Fl leasetime Ar seconds
Request a specific lease time in
.Ar seconds .
@ -323,10 +330,12 @@ Metrics are used to prefer an interface over another one, lowest wins.
will supply a default metic of 200 +
.Xr if_nametoindex 3 .
An extra 100 will be added for wireless interfaces.
.It Fl n , Fl Fl rebind
.It Fl n , Fl Fl rebind Op Ar interface
Notifies
.Nm
to reload its configuration and rebind its interfaces.
to reload its configuration and rebind the specified
.Ar interface .
If no interface is specified then this applies to all interfaces.
If
.Nm
is not running, then it starts up as normal.
@ -344,7 +353,8 @@ normally de-configures the
.Ar interface
and configuration when it exits.
Sometimes, this isn't desirable if, for example, you have root mounted over
NFS.
NFS or SSH clients connect to this host and they need to be notified of
the host shutting down.
You can use this option to stop this from happening.
.It Fl r , Fl Fl request Op Ar address
Request the
@ -374,6 +384,21 @@ If
.Nm
fails to contact a DHCP server then it returns a failure instead of falling
back on IPv4LL.
.It Fl S, Fl Fl static Ar value
Configures a static
.Ar value .
If you set
.Ic ip_address
then
.Nm
will not attempt to obtain a lease and just use the value for the address with
an infinite lease time.
.Pp
Here is an example which configures a static address, routes and dns.
.D1 dhcpcd -S ip_address=192.168.0.10/24 \e
.D1 -S routers=192.168.0.1 \e
.D1 -S domain_name_servers=192.168.0.1 \e
.D1 eth0
.It Fl t , Fl Fl timeout Ar seconds
Timeout after
.Ar seconds ,
@ -409,9 +434,17 @@ Set un-encapsulated vendor option to hello world.
Display both program version and copyright information.
.Nm
then exits before doing any configuration.
.It Fl w , Fl Fl waitip
.It Fl w , Fl Fl waitip Op 4 | 6
Wait for an address to be assigned before forking to the background.
.It Fl x , Fl Fl exit
4 means wait for an IPv4 address to be assigned.
6 means wait for an IPv6 address to be assigned.
If no argument is given,
.Nm
will wait for any address protocol to be assigned.
It is possible to wait for more than one address protocol and
.Nm
will only fork to the background when all waiting conditions are satisfied.
.It Fl x , Fl Fl exit Op Ar interface
This will signal an existing
.Nm
process running on the
@ -419,6 +452,7 @@ process running on the
to de-configure the
.Ar interface
and exit.
If no interface is specified, then the above is applied to all interfaces.
.Nm
then waits until this process has exited.
.It Fl y , Fl Fl reboot Ar seconds
@ -494,21 +528,6 @@ Quiet
.Nm
on the command line, only warnings and errors will be displayed.
The messages are still logged though.
.It Fl S, Fl Fl static Ar value
Configures a static
.Ar value .
If you set
.Ic ip_address
then
.Nm
will not attempt to obtain a lease and just use the value for the address with
an infinite lease time.
.Pp
Here is an example which configures a static address, routes and dns.
.D1 dhcpcd -S ip_address=192.168.0.10/24 \e
.D1 -S routers=192.168.0.1 \e
.D1 -S domain_name_servers=192.168.0.1 \e
.D1 eth0
.It Fl T, Fl Fl test
On receipt of DHCP messages just call
.Pa @SCRIPT@
@ -554,6 +573,10 @@ which is a space or comma separated list of patterns passed to
If the same interface is matched in
.Fl Z , Fl Fl denyinterfaces
then it is still denied.
.It Fl Fl nodev
Don't load any
.Pa /dev
management modules.
.El
.Sh 3RDPARTY LINK MANAGEMENT
Some interfaces require configuration by 3rd parties, such as PPP or VPN.
@ -582,6 +605,9 @@ If you always use the same options, put them here.
Text file that holds the DUID used to identify the host.
.It Pa @SCRIPT@
Bourne shell script that is run to configure or de-configure an interface.
.It Pa @LIBDIR@/dhcpcd/dev
.Pa /dev
management modules.
.It Pa @HOOKDIR@
A directory containing bourne shell scripts that are run by the above script.
Each script can be disabled by using the
@ -612,7 +638,7 @@ running on the
RFC\ 951 RFC\ 1534 RFC\ 2131, RFC\ 2132, RFC\ 2855, RFC\ 3004, RFC\ 3315,
RFC\ 3361, RFC\ 3633, RFC\ 3396, RFC\ 3397, RFC\ 3442, RFC\ 3927, RFC\ 4039
RFC\ 4075, RFC\ 4361, RFC\ 4390, RFC\ 4702, RFC\ 4704, RFC\ 4861, RFC\ 4833,
RFC\ 5227, RFC\ 5969, RFC\ 6106.
RFC\ 5227, RFC\ 5942, RFC\ 5969, RFC\ 6106.
.Sh AUTHORS
.An Roy Marples Aq Mt roy@marples.name
.Sh BUGS

View File

@ -1,4 +1,4 @@
# $NetBSD: dhcpcd.conf,v 1.7 2013/07/29 20:39:28 roy Exp $
# $NetBSD: dhcpcd.conf,v 1.8 2013/09/20 10:56:32 roy Exp $
# A sample configuration for dhcpcd.
# See dhcpcd.conf(5) for details.
@ -12,6 +12,9 @@ hostname
# Use the same DUID + IAID as set in DHCPv6 for DHCPv4 ClientID as per RFC4361.
duid
# Persist interface configuration when dhcpcd exits.
persistent
# Rapid commit support.
# Safe to enable by default because it requires the equivalent option set
# on the server to actually work.

View File

@ -1,4 +1,4 @@
.\" $NetBSD: dhcpcd.conf.5.in,v 1.3 2013/07/29 20:39:28 roy Exp $
.\" $NetBSD: dhcpcd.conf.5.in,v 1.4 2013/09/20 10:56:32 roy Exp $
.\" Copyright (c) 2006-2013 Roy Marples
.\" All rights reserved
.\"
@ -23,7 +23,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.Dd July 25, 2013
.Dd September 12, 2013
.Dt DHCPCD.CONF 5 SMM
.Os
.Sh NAME
@ -91,6 +91,13 @@ such as FireWire and InfiniBand.
In most cases,
.Nm dhcpcd
will set this automatically.
.It Ic dev Ar value
Load the
.Ar value
.Pa /dev
management module.
.Nm dhcpcd
will load the first one found to work, if any.
.It Ic env Ar value
Push
.Ar value
@ -135,6 +142,13 @@ is generated, otherwise DUID-LL is generated (link local address).
The DUID-LLT generated will be held in
.Pa @SYSCONFDIR@/dhcpcd.duid
and should not be copied to other hosts.
.It Ic persistent
.Nm dhcpcd
normally de-configures the interface and configuration when it exits.
Sometimes, this isn't desirable if, for example, you have root mounted over
NFS or SSH clients connect to this host and they need to be notified of
the host shutting down.
You can use this option to stop this from happening.
.It Ic fallback Ar profile
Fallback to using this profile if DHCP fails.
This allows you to configure a static profile instead of using ZeroConf.
@ -164,9 +178,11 @@ If none is specified, a default
is used.
If the interface name is 4 characters or less then that is used,
otherwise the interface index is used.
You can request more than one ia_na by specifying a unique iaid for each one.
.It Ic ia_ta Op Ar iaid
Request a DHCPv6 Temporary Address for
.Ar iaid .
You can request more than one ia_ta by specifying a unique iaid for each one.
.It Ic ia_pd Op Ar iaid Op Ar interface Op / Ar sla_id Op / Ar prefix_len
Request a DHCPv6 Delegated Prefix for
.Ar iaid .
@ -255,6 +271,10 @@ alongside.
.It Ic noarp
Don't send any ARP requests.
This also disables IPv4LL.
.It Ic nodev
Don't load
.Pa /dev
management modules.
.It Ic nogateway
Don't install any default routes.
.It Ic nohook Ar script
@ -404,8 +424,16 @@ For example
If not set then none is sent.
Some badly configured DHCP servers reject unknown vendorclassids.
To work around it, try and impersonate Windows by using the MSFT vendorclassid.
.It Ic waitip
.It Ic waitip Op 4 | 6
Wait for an address to be assigned before forking to the background.
4 means wait for an IPv4 address to be assigned.
6 means wait for an IPv6 address to be assigned.
If no argument is given,
.Nm
will wait for any address protocol to be assigned.
It is possible to wait for more than one address protocol and
.Nm
will only fork to the background when all waiting conditions are satisfied.
.It Ic xidhwaddr
Use the last four bytes of the hardware address as the DHCP xid instead
of a randomly generated number.

View File

@ -1,690 +0,0 @@
#include <sys/cdefs.h>
__RCSID("$NetBSD: ipv6ns.c,v 1.1.1.3 2013/06/21 19:33:08 roy Exp $");
/*
* dhcpcd - DHCP client daemon
* Copyright (c) 2006-2013 Roy Marples <roy@marples.name>
* 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/ioctl.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <net/if.h>
#include <netinet/in.h>
#include <netinet/ip6.h>
#include <netinet/icmp6.h>
#include <errno.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
#ifdef __linux__
# define _LINUX_IN6_H
# include <linux/ipv6.h>
#endif
#define ELOOP_QUEUE 2
#include "common.h"
#include "dhcpcd.h"
#include "dhcp6.h"
#include "eloop.h"
#include "ipv6.h"
#include "ipv6ns.h"
#include "script.h"
#define MIN_RANDOM_FACTOR 500 /* millisecs */
#define MAX_RANDOM_FACTOR 1500 /* millisecs */
#define MIN_RANDOM_FACTOR_U MIN_RANDOM_FACTOR * 1000 /* usecs */
#define MAX_RANDOM_FACTOR_U MAX_RANDOM_FACTOR * 1000 /* usecs */
#if BYTE_ORDER == BIG_ENDIAN
#define IPV6_ADDR_INT32_ONE 1
#define IPV6_ADDR_INT16_MLL 0xff02
#elif BYTE_ORDER == LITTLE_ENDIAN
#define IPV6_ADDR_INT32_ONE 0x01000000
#define IPV6_ADDR_INT16_MLL 0x02ff
#endif
/* Debugging Neighbor Solicitations is a lot of spam, so disable it */
//#define DEBUG_NS
//
/* Currently, no known kernel allows us to send from the unspecified address
* which is required for DAD to work. This isn't that much of a problem as
* the kernel will do DAD for us correctly, however we don't know the exact
* randomness the kernel applies to the timeouts. So we just follow the same
* logic and have a little faith.
* This define is purely for completeness */
// #define IPV6_SEND_DAD
static int sock = -1;
#ifdef IPV6_SEND_DAD
static int unspec_sock = -1;
#endif
static struct sockaddr_in6 from;
static struct msghdr sndhdr;
static struct iovec sndiov[2];
static unsigned char *sndbuf;
static struct msghdr rcvhdr;
static struct iovec rcviov[2];
static unsigned char *rcvbuf;
static unsigned char ansbuf[1500];
static char ntopbuf[INET6_ADDRSTRLEN];
static void ipv6ns_handledata(__unused void *arg);
#if DEBUG_MEMORY
static void
ipv6ns_cleanup(void)
{
free(sndbuf);
free(rcvbuf);
}
#endif
static int
ipv6ns_open(void)
{
int on;
int len;
struct icmp6_filter filt;
#ifdef IPV6_SEND_DAD
union {
struct sockaddr sa;
struct sockaddr_in6 sin;
} su;
#endif
if (sock != -1)
return sock;
sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
if (sock == -1)
return -1;
on = 1;
if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO,
&on, sizeof(on)) == -1)
goto eexit;
on = 1;
if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT,
&on, sizeof(on)) == -1)
goto eexit;
ICMP6_FILTER_SETBLOCKALL(&filt);
#ifdef IPV6_SEND_DAD
/* We send DAD requests from the unspecified address. */
unspec_sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
if (unspec_sock == -1)
goto eexit;
if (setsockopt(unspec_sock, IPPROTO_ICMPV6, ICMP6_FILTER,
&filt, sizeof(filt)) == -1)
goto eexit;
memset(&su, 0, sizeof(su));
su.sin.sin6_family = AF_INET6;
#ifdef SIN6_LEN
su.sin.sin6_len = sizeof(su.sin);
#endif
if (bind(unspec_sock, &su.sa, sizeof(su.sin)) == -1)
goto eexit;
#endif
ICMP6_FILTER_SETPASS(ND_NEIGHBOR_ADVERT, &filt);
if (setsockopt(sock, IPPROTO_ICMPV6, ICMP6_FILTER,
&filt, sizeof(filt)) == -1)
goto eexit;
set_cloexec(sock);
#if DEBUG_MEMORY
atexit(ipv6ns_cleanup);
#endif
#ifdef LISTEN_DAD
syslog(LOG_WARNING, "kernel does not report DAD results to userland");
syslog(LOG_WARNING,
"warning listening to duplicated addresses on the wire");
#endif
len = CMSG_SPACE(sizeof(struct in6_pktinfo)) + CMSG_SPACE(sizeof(int));
sndbuf = calloc(1, len);
if (sndbuf == NULL)
goto eexit;
sndhdr.msg_namelen = sizeof(struct sockaddr_in6);
sndhdr.msg_iov = sndiov;
sndhdr.msg_iovlen = 1;
sndhdr.msg_control = sndbuf;
sndhdr.msg_controllen = len;
rcvbuf = calloc(1, len);
if (rcvbuf == NULL)
goto eexit;
rcvhdr.msg_name = &from;
rcvhdr.msg_namelen = sizeof(from);
rcvhdr.msg_iov = rcviov;
rcvhdr.msg_iovlen = 1;
rcvhdr.msg_control = rcvbuf;
rcvhdr.msg_controllen = len;
rcviov[0].iov_base = ansbuf;
rcviov[0].iov_len = sizeof(ansbuf);
eloop_event_add(sock, ipv6ns_handledata, NULL);
return sock;
eexit:
syslog(LOG_ERR, "%s: %m", __func__);
close(sock);
sock = -1;
free(sndbuf);
sndbuf = NULL;
free(rcvbuf);
rcvbuf = NULL;
return -1;
}
static void
ipv6ns_unreachable(void *arg)
{
struct ra *rap = arg;
struct timeval tv;
/* We could add an unreachable flag and persist the information,
* but that is more effort than it's probably worth. */
syslog(LOG_WARNING, "%s: %s is unreachable, expiring it",
rap->iface->name, rap->sfrom);
rap->expired = 1;
ipv6_buildroutes();
script_runreason(rap->iface, "ROUTERADVERT"); /* XXX not RA */
/* We should still test if it's reachable or not so
* incase it comes back to life and it's preferable. */
if (rap->reachable) {
ms_to_tv(&tv, rap->reachable);
} else {
tv.tv_sec = REACHABLE_TIME;
tv.tv_usec = 0;
}
eloop_timeout_add_tv(&tv, ipv6ns_proberouter, rap);
}
#ifdef LISTEN_DAD
void
ipv6ns_cancelprobeaddr(struct ipv6_addr *ap)
{
eloop_timeout_delete(ipv6ns_probeaddr, ap);
if (ap->dadcallback)
eloop_timeout_delete(ap->dadcallback, ap);
}
#endif
void
ipv6ns_probeaddr(void *arg)
{
struct ipv6_addr *ap = arg;
#ifdef IPV6_SEND_DAD
struct nd_neighbor_solicit *ns;
struct nd_opt_hdr *nd;
struct sockaddr_in6 dst;
struct cmsghdr *cm;
struct in6_pktinfo pi;
int hoplimit = HOPLIMIT;
#else
#ifdef LISTEN_DAD
struct timeval tv, rtv;
struct timeval mtv;
int i;
#endif
#endif
if (ap->dadcallback &&
((ap->flags & IPV6_AF_NEW) == 0 ||
ap->nsprobes >= ap->iface->options->dadtransmits))
{
#ifdef IPV6_SEND_DAD
ap->dadcallback(ap);
#else
ipv6_addaddr(ap);
#endif
return;
}
if (ipv6ns_open() == -1)
return;
ap->flags &= ~IPV6_AF_DADCOMPLETED;
#ifdef IPV6_SEND_DAD
if (!ap->ns) {
ap->nslen = sizeof(*ns) + ROUNDUP8(ap->iface->hwlen + 2);
ap->ns = calloc(1, ap->nslen);
if (ap->ns == NULL) {
syslog(LOG_ERR, "%s: %m", __func__);
return;
}
ns = (struct nd_neighbor_solicit *)(void *)ap->ns;
ns->nd_ns_type = ND_NEIGHBOR_SOLICIT;
//ns->nd_ns_cksum = 0;
//ns->nd_ns_code = 0;
//ns->nd_ns_reserved = 0;
ns->nd_ns_target = ap->addr;
nd = (struct nd_opt_hdr *)(ap->ns + sizeof(*ns));
nd->nd_opt_type = ND_OPT_SOURCE_LINKADDR;
nd->nd_opt_len = (ROUNDUP8(ap->iface->hwlen + 2)) >> 3;
memcpy(nd + 1, ap->iface->hwaddr, ap->iface->hwlen);
}
memset(&dst, 0, sizeof(dst));
dst.sin6_family = AF_INET6;
#ifdef SIN6_LEN
dst.sin6_len = sizeof(dst);
#endif
dst.sin6_addr.s6_addr16[0] = IPV6_ADDR_INT16_MLL;
dst.sin6_addr.s6_addr16[1] = 0;
dst.sin6_addr.s6_addr32[1] = 0;
dst.sin6_addr.s6_addr32[2] = IPV6_ADDR_INT32_ONE;
dst.sin6_addr.s6_addr32[3] = ap->addr.s6_addr32[3];
dst.sin6_addr.s6_addr[12] = 0xff;
//memcpy(&dst.sin6_addr, &ap->addr, sizeof(dst.sin6_addr));
dst.sin6_scope_id = ap->iface->index;
sndhdr.msg_name = (caddr_t)&dst;
sndhdr.msg_iov[0].iov_base = ap->ns;
sndhdr.msg_iov[0].iov_len = ap->nslen;
/* Set the outbound interface */
cm = CMSG_FIRSTHDR(&sndhdr);
cm->cmsg_level = IPPROTO_IPV6;
cm->cmsg_type = IPV6_PKTINFO;
cm->cmsg_len = CMSG_LEN(sizeof(pi));
memset(&pi, 0, sizeof(pi));
pi.ipi6_ifindex = ap->iface->index;
memcpy(CMSG_DATA(cm), &pi, sizeof(pi));
/* Hop limit */
cm = CMSG_NXTHDR(&sndhdr, cm);
cm->cmsg_level = IPPROTO_IPV6;
cm->cmsg_type = IPV6_HOPLIMIT;
cm->cmsg_len = CMSG_LEN(sizeof(hoplimit));
memcpy(CMSG_DATA(cm), &hoplimit, sizeof(hoplimit));
#ifdef DEBUG_NS
syslog(LOG_INFO, "%s: sending IPv6 NS for %s",
ap->iface->name, ap->saddr);
if (ap->dadcallback == NULL)
syslog(LOG_WARNING, "%s: no callback!", ap->iface->name);
#endif
if (sendmsg(unspec_sock, &sndhdr, 0) == -1) {
syslog(LOG_ERR, "%s: %s: sendmsg: %m",
ap->iface->name, __func__);
return;
}
if (ap->dadcallback) {
ms_to_tv(&tv, RETRANS_TIMER);
ms_to_tv(&rtv, MIN_RANDOM_FACTOR);
timeradd(&tv, &rtv, &tv);
rtv.tv_sec = 0;
rtv.tv_usec = arc4random() %
(MAX_RANDOM_FACTOR_U - MIN_RANDOM_FACTOR_U);
timeradd(&tv, &rtv, &tv);
eloop_timeout_add_tv(&tv,
++(ap->nsprobes) < ap->iface->options->dadtransmits ?
ipv6ns_probeaddr : ap->dadcallback,
ap);
}
#else /* IPV6_SEND_DAD */
ipv6_addaddr(ap);
#ifdef LISTEN_DAD
/* Let the kernel handle DAD.
* We don't know the timings, so just wait for the max */
if (ap->dadcallback) {
mtv.tv_sec = 0;
mtv.tv_usec = 0;
for (i = 0; i < ap->iface->options->dadtransmits; i++) {
ms_to_tv(&tv, RETRANS_TIMER);
ms_to_tv(&rtv, MAX_RANDOM_FACTOR);
timeradd(&tv, &rtv, &tv);
timeradd(&mtv, &tv, &mtv);
}
eloop_timeout_add_tv(&mtv, ap->dadcallback, ap);
}
#endif
#endif /* IPV6_SEND_DAD */
}
ssize_t
ipv6ns_probeaddrs(struct ipv6_addrhead *addrs)
{
struct ipv6_addr *ap, *apn;
ssize_t i;
i = 0;
TAILQ_FOREACH_SAFE(ap, addrs, next, apn) {
if (ap->prefix_vltime == 0) {
TAILQ_REMOVE(addrs, ap, next);
if (ap->flags & IPV6_AF_ADDED) {
syslog(LOG_INFO, "%s: deleting address %s",
ap->iface->name, ap->saddr);
i++;
}
if (!IN6_IS_ADDR_UNSPECIFIED(&ap->addr) &&
del_address6(ap) == -1 &&
errno != EADDRNOTAVAIL && errno != ENXIO)
syslog(LOG_ERR, "del_address6 %m");
if (ap->dadcallback)
eloop_q_timeout_delete(0, NULL,
ap->dadcallback);
free(ap);
} else if (!IN6_IS_ADDR_UNSPECIFIED(&ap->addr) &&
!(ap->flags & IPV6_AF_DELEGATED))
{
ipv6ns_probeaddr(ap);
if (ap->flags & IPV6_AF_NEW)
i++;
}
}
return i;
}
void
ipv6ns_proberouter(void *arg)
{
struct ra *rap = arg;
struct nd_neighbor_solicit *ns;
struct nd_opt_hdr *nd;
struct sockaddr_in6 dst;
struct cmsghdr *cm;
struct in6_pktinfo pi;
int hoplimit = HOPLIMIT;
struct timeval tv, rtv;
if (ipv6ns_open() == -1)
return;
if (!rap->ns) {
rap->nslen = sizeof(*ns) + ROUNDUP8(rap->iface->hwlen + 2);
rap->ns = calloc(1, rap->nslen);
if (rap->ns == NULL) {
syslog(LOG_ERR, "%s: %m", __func__);
return;
}
ns = (struct nd_neighbor_solicit *)(void *)rap->ns;
ns->nd_ns_type = ND_NEIGHBOR_SOLICIT;
//ns->nd_ns_cksum = 0;
//ns->nd_ns_code = 0;
//ns->nd_ns_reserved = 0;
ns->nd_ns_target = rap->from;
nd = (struct nd_opt_hdr *)(rap->ns + sizeof(*ns));
nd->nd_opt_type = ND_OPT_SOURCE_LINKADDR;
nd->nd_opt_len = (ROUNDUP8(rap->iface->hwlen + 2)) >> 3;
memcpy(nd + 1, rap->iface->hwaddr, rap->iface->hwlen);
}
memset(&dst, 0, sizeof(dst));
dst.sin6_family = AF_INET6;
#ifdef SIN6_LEN
dst.sin6_len = sizeof(dst);
#endif
memcpy(&dst.sin6_addr, &rap->from, sizeof(dst.sin6_addr));
dst.sin6_scope_id = rap->iface->index;
sndhdr.msg_name = (caddr_t)&dst;
sndhdr.msg_iov[0].iov_base = rap->ns;
sndhdr.msg_iov[0].iov_len = rap->nslen;
/* Set the outbound interface */
cm = CMSG_FIRSTHDR(&sndhdr);
cm->cmsg_level = IPPROTO_IPV6;
cm->cmsg_type = IPV6_PKTINFO;
cm->cmsg_len = CMSG_LEN(sizeof(pi));
memset(&pi, 0, sizeof(pi));
pi.ipi6_ifindex = rap->iface->index;
memcpy(CMSG_DATA(cm), &pi, sizeof(pi));
/* Hop limit */
cm = CMSG_NXTHDR(&sndhdr, cm);
cm->cmsg_level = IPPROTO_IPV6;
cm->cmsg_type = IPV6_HOPLIMIT;
cm->cmsg_len = CMSG_LEN(sizeof(hoplimit));
memcpy(CMSG_DATA(cm), &hoplimit, sizeof(hoplimit));
#ifdef DEBUG_NS
syslog(LOG_INFO, "%s: sending IPv6 NS for %s",
rap->iface->name, rap->sfrom);
#endif
if (sendmsg(sock, &sndhdr, 0) == -1) {
syslog(LOG_ERR, "%s: %s: sendmsg: %m",
rap->iface->name, __func__);
return;
}
ms_to_tv(&tv, rap->retrans == 0 ? RETRANS_TIMER : rap->retrans);
ms_to_tv(&rtv, MIN_RANDOM_FACTOR);
timeradd(&tv, &rtv, &tv);
rtv.tv_sec = 0;
rtv.tv_usec = arc4random() % (MAX_RANDOM_FACTOR_U -MIN_RANDOM_FACTOR_U);
timeradd(&tv, &rtv, &tv);
eloop_timeout_add_tv(&tv, ipv6ns_proberouter, rap);
if (rap->nsprobes++ == 0)
eloop_timeout_add_sec(DELAY_FIRST_PROBE_TIME,
ipv6ns_unreachable, rap);
}
void
ipv6ns_cancelproberouter(struct ra *rap)
{
eloop_timeout_delete(ipv6ns_proberouter, rap);
eloop_timeout_delete(ipv6ns_unreachable, rap);
}
/* ARGSUSED */
static void
ipv6ns_handledata(__unused void *arg)
{
ssize_t len;
struct cmsghdr *cm;
int hoplimit;
struct in6_pktinfo pkt;
struct icmp6_hdr *icp;
struct interface *ifp;
const char *sfrom;
struct nd_neighbor_advert *nd_na;
struct ra *rap;
int is_router, is_solicited;
#ifdef DEBUG_NS
int found;
#endif
struct timeval tv;
#ifdef LISTEN_DAD
struct dhcp6_state *d6state;
struct ipv6_addr *ap;
#endif
len = recvmsg(sock, &rcvhdr, 0);
if (len == -1) {
syslog(LOG_ERR, "recvmsg: %m");
return;
}
sfrom = inet_ntop(AF_INET6, &from.sin6_addr,
ntopbuf, INET6_ADDRSTRLEN);
if ((size_t)len < sizeof(struct nd_neighbor_advert)) {
syslog(LOG_ERR, "IPv6 NA packet too short from %s", sfrom);
return;
}
pkt.ipi6_ifindex = hoplimit = 0;
for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&rcvhdr);
cm;
cm = (struct cmsghdr *)CMSG_NXTHDR(&rcvhdr, cm))
{
if (cm->cmsg_level != IPPROTO_IPV6)
continue;
switch(cm->cmsg_type) {
case IPV6_PKTINFO:
if (cm->cmsg_len == CMSG_LEN(sizeof(pkt)))
memcpy(&pkt, CMSG_DATA(cm), sizeof(pkt));
break;
case IPV6_HOPLIMIT:
if (cm->cmsg_len == CMSG_LEN(sizeof(int)))
memcpy(&hoplimit, CMSG_DATA(cm), sizeof(int));
break;
}
}
if (pkt.ipi6_ifindex == 0 || hoplimit != 255) {
syslog(LOG_ERR,
"IPv6 NA did not contain index or hop limit from %s",
sfrom);
return;
}
icp = (struct icmp6_hdr *)rcvhdr.msg_iov[0].iov_base;
if (icp->icmp6_type != ND_NEIGHBOR_ADVERT ||
icp->icmp6_code != 0)
{
syslog(LOG_ERR, "invalid IPv6 type or code from %s", sfrom);
return;
}
TAILQ_FOREACH(ifp, ifaces, next) {
if (ifp->index == (unsigned int)pkt.ipi6_ifindex)
break;
}
if (ifp == NULL) {
#ifdef DEBUG_NS
syslog(LOG_DEBUG, "NA for unexpected interface from %s", sfrom);
#endif
return;
}
nd_na = (struct nd_neighbor_advert *)icp;
is_router = nd_na->nd_na_flags_reserved & ND_NA_FLAG_ROUTER;
is_solicited = nd_na->nd_na_flags_reserved & ND_NA_FLAG_SOLICITED;
if (IN6_IS_ADDR_MULTICAST(&nd_na->nd_na_target)) {
syslog(LOG_ERR, "%s: NA for multicast address from %s",
ifp->name, sfrom);
return;
}
#ifdef DEBUG_NS
found = 0;
#endif
TAILQ_FOREACH(rap, &ipv6_routers, next) {
if (rap->iface != ifp)
continue;
if (memcmp(rap->from.s6_addr, nd_na->nd_na_target.s6_addr,
sizeof(rap->from.s6_addr)) == 0)
break;
#ifdef LISTEN_DAD
TAILQ_FOREACH(ap, &rap->addrs, next) {
if (memcmp(ap->addr.s6_addr,
nd_na->nd_na_target.s6_addr,
sizeof(ap->addr.s6_addr)) == 0)
{
ap->flags |= IPV6_AF_DUPLICATED;
if (ap->dadcallback)
ap->dadcallback(ap);
#ifdef DEBUG_NS
found++;
#endif
}
}
#endif
}
if (rap == NULL) {
#ifdef LISTEN_DAD
d6state = D6_STATE(ifp);
if (d6state) {
TAILQ_FOREACH(ap, &d6state->addrs, next) {
if (memcmp(ap->addr.s6_addr,
nd_na->nd_na_target.s6_addr,
sizeof(ap->addr.s6_addr)) == 0)
{
ap->flags |= IPV6_AF_DUPLICATED;
if (ap->dadcallback)
ap->dadcallback(ap);
#ifdef DEBUG_NS
found++;
#endif
}
}
}
#endif
#ifdef DEBUG_NS
if (found == 0)
syslog(LOG_DEBUG, "%s: unexpected NA from %s",
ifp->name, sfrom);
#endif
return;
}
#ifdef DEBUG_NS
syslog(LOG_DEBUG, "%s: %sNA from %s",
ifp->name, is_solicited ? "solicited " : "", sfrom);
#endif
/* Node is no longer a router, so remove it from consideration */
if (!is_router && !rap->expired) {
syslog(LOG_INFO, "%s: %s is no longer a router",
ifp->name, sfrom);
rap->expired = 1;
ipv6ns_cancelproberouter(rap);
ipv6_buildroutes();
script_runreason(ifp, "ROUTERADVERT");
return;
}
if (is_solicited && is_router && rap->lifetime) {
if (rap->expired) {
rap->expired = 0;
syslog(LOG_INFO, "%s: %s is reachable again",
ifp->name, sfrom);
ipv6_buildroutes();
script_runreason(rap->iface, "ROUTERADVERT"); /* XXX */
}
rap->nsprobes = 0;
if (rap->reachable) {
ms_to_tv(&tv, rap->reachable);
} else {
tv.tv_sec = REACHABLE_TIME;
tv.tv_usec = 0;
}
eloop_timeout_add_tv(&tv, ipv6ns_proberouter, rap);
eloop_timeout_delete(ipv6ns_unreachable, rap);
}
}

View File

@ -1,51 +0,0 @@
/* $NetBSD: ipv6ns.h,v 1.1.1.3 2013/06/21 19:33:08 roy Exp $ */
/*
* dhcpcd - DHCP client daemon
* Copyright (c) 2006-2013 Roy Marples <roy@marples.name>
* 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 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 AUTHOR 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 IPV6NS_H
#define IPV6NS_H
#include "dhcpcd.h"
#include "ipv6rs.h"
#define MAX_REACHABLE_TIME 3600 /* seconds */
#define REACHABLE_TIME 30 /* seconds */
#define RETRANS_TIMER 1000 /* milliseconds */
#define DELAY_FIRST_PROBE_TIME 5 /* seconds */
void ipv6ns_probeaddr(void *);
ssize_t ipv6ns_probeaddrs(struct ipv6_addrhead *);
void ipv6ns_proberouter(void *);
void ipv6ns_cancelproberouter(struct ra *);
#ifdef LISTEN_DAD
void ipv6ns_cancelprobeaddr(struct ipv6_addr *);
#else
#define ipv6ns_cancelprobeaddr(a)
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,100 +0,0 @@
/* $NetBSD: ipv6rs.h,v 1.1.1.5 2013/06/21 19:33:08 roy Exp $ */
/*
* dhcpcd - DHCP client daemon
* Copyright (c) 2006-2013 Roy Marples <roy@marples.name>
* 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 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 AUTHOR 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 IPV6RS_H
#define IPV6RS_H
#include <sys/queue.h>
#include <time.h>
#include "dhcpcd.h"
#include "ipv6.h"
struct ra_opt {
TAILQ_ENTRY(ra_opt) next;
uint8_t type;
struct timeval expire;
char *option;
};
struct ra {
TAILQ_ENTRY(ra) next;
struct interface *iface;
struct in6_addr from;
char sfrom[INET6_ADDRSTRLEN];
unsigned char *data;
ssize_t data_len;
struct timeval received;
unsigned char flags;
uint32_t lifetime;
uint32_t reachable;
uint32_t retrans;
uint32_t mtu;
struct ipv6_addrhead addrs;
TAILQ_HEAD(, ra_opt) options;
unsigned char *ns;
size_t nslen;
int nsprobes;
int expired;
};
extern TAILQ_HEAD(rahead, ra) ipv6_routers;
struct rs_state {
unsigned char *rs;
size_t rslen;
int rsprobes;
};
#define RS_STATE(a) ((struct rs_state *)(ifp)->if_data[IF_DATA_IPV6RS])
#ifdef INET6
int ipv6rs_start(struct interface *);
ssize_t ipv6rs_env(char **, const char *, const struct interface *);
const struct ipv6_addr * ipv6rs_findprefix(const struct ipv6_addr *);
int ipv6rs_addrexists(const struct ipv6_addr *);
void ipv6rs_freedrop_ra(struct ra *, int);
#define ipv6rs_free_ra(ra) ipv6rs_freedrop_ra((ra), 0)
#define ipv6rs_drop_ra(ra) ipv6rs_freedrop_ra((ra), 1)
ssize_t ipv6rs_free(struct interface *);
void ipv6rs_expire(void *arg);
int ipv6rs_has_ra(const struct interface *);
void ipv6rs_handleifa(int, const char *, const struct in6_addr *, int);
void ipv6rs_drop(struct interface *);
#else
#define ipv6rs_start(a) {}
#define ipv6rs_free(a)
#define ipv6rs_has_ra(a) 0
#define ipv6rs_drop(a)
#endif
#endif

View File

@ -1,5 +1,5 @@
#include <sys/cdefs.h>
__RCSID("$NetBSD: net.c,v 1.2 2013/09/11 18:50:00 drochner Exp $");
__RCSID("$NetBSD: net.c,v 1.3 2013/09/20 10:56:32 roy Exp $");
/*
* dhcpcd - DHCP client daemon
@ -70,10 +70,12 @@
#include "config.h"
#include "common.h"
#include "dev.h"
#include "dhcp.h"
#include "dhcp6.h"
#include "if-options.h"
#include "ipv6rs.h"
#include "ipv4.h"
#include "ipv6nd.h"
#include "net.h"
int socket_afnet = -1;
@ -141,10 +143,11 @@ free_interface(struct interface *ifp)
if (ifp == NULL)
return;
ipv4_free(ifp);
dhcp_free(ifp);
ipv6_free(ifp);
dhcp6_free(ifp);
ipv6rs_free(ifp);
ipv6nd_free(ifp);
free_options(ifp->options);
free(ifp);
}
@ -226,6 +229,10 @@ discover_interfaces(int argc, char * const *argv)
#ifdef __linux__
char ifn[IF_NAMESIZE];
#endif
#ifdef INET
const struct sockaddr_in *addr;
const struct sockaddr_in *net;
const struct sockaddr_in *dst;
#ifdef INET6
const struct sockaddr_in6 *sin6;
int ifa_flags;
@ -264,6 +271,10 @@ discover_interfaces(int argc, char * const *argv)
#endif
}
/* Ensure that the interface name has settled */
if (!dev_initialized(ifa->ifa_name))
continue;
/* It's possible for an interface to have >1 AF_LINK.
* For our purposes, we use the first one. */
TAILQ_FOREACH(ifp, ifs, next) {
@ -444,11 +455,29 @@ discover_interfaces(int argc, char * const *argv)
TAILQ_INSERT_TAIL(ifs, ifp, next);
}
#ifdef INET6
for (ifa = ifaddrs; ifa; ifa = ifa->ifa_next) {
if (ifa->ifa_addr != NULL &&
ifa->ifa_addr->sa_family == AF_INET6)
{
if (ifa->ifa_addr == NULL)
continue;
switch(ifa->ifa_addr->sa_family) {
#ifdef INET
case AF_INET:
addr = (const struct sockaddr_in *)
(void *)ifa->ifa_addr;
net = (const struct sockaddr_in *)
(void *)ifa->ifa_netmask;
if (ifa->ifa_flags & IFF_POINTOPOINT)
dst = (const struct sockaddr_in *)
(void *)ifa->ifa_dstaddr;
else
dst = NULL;
ipv4_handleifa(RTM_NEWADDR, ifs, ifa->ifa_name,
&addr->sin_addr,
&net->sin_addr,
dst ? &dst->sin_addr : NULL);
break;
#endif
#ifdef INET6
case AF_INET6:
sin6 = (const struct sockaddr_in6 *)
(void *)ifa->ifa_addr;
ifa_flags = in6_addr_flags(ifa->ifa_name,
@ -457,6 +486,8 @@ discover_interfaces(int argc, char * const *argv)
ipv6_handleifa(RTM_NEWADDR, ifs,
ifa->ifa_name,
&sin6->sin6_addr, ifa_flags);
break;
#endif
}
}
#endif