mirror of
https://github.com/rsmarples/dhcpcd.git
synced 2024-11-27 12:03:45 +08:00
When requesting a IA_PD and another IA type, create a psuedo interface
to handle the IA_PD. ia_pd_mix config option disables this and mixes IA_PD in the single session as per draft-ietf-dhc-dhcpv6-stateful-issues-06.
This commit is contained in:
parent
ab234549b1
commit
9d5cb9f924
88
dhcp6.c
88
dhcp6.c
@ -2221,6 +2221,8 @@ dhcp6_delegate_prefix(struct interface *ifp)
|
||||
}
|
||||
|
||||
TAILQ_FOREACH(ifd, ifp->ctx->ifaces, next) {
|
||||
if (ifp->options->options & DHCPCD_NOPFXDLG)
|
||||
continue;
|
||||
k = 0;
|
||||
carrier_warned = abrt = 0;
|
||||
TAILQ_FOREACH(ap, &state->addrs, next) {
|
||||
@ -2357,6 +2359,24 @@ dhcp6_find_delegates(struct interface *ifp)
|
||||
return k;
|
||||
}
|
||||
|
||||
static struct interface *
|
||||
dhcp6_findpfxdlgif(struct interface *ifp)
|
||||
{
|
||||
struct interface *ifn;
|
||||
|
||||
if (ifp->options && ifp->options->options & DHCPCD_PFXDLGONLY)
|
||||
return NULL;
|
||||
|
||||
if (ifp->ctx && ifp->ctx->ifaces) {
|
||||
TAILQ_FOREACH(ifn, ifp->ctx->ifaces, next) {
|
||||
if (strcmp(ifn->name, ifp->name) == 0 &&
|
||||
ifn->options->options & DHCPCD_PFXDLGONLY)
|
||||
return ifn;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static void
|
||||
dhcp6_handledata(void *arg)
|
||||
@ -2367,7 +2387,7 @@ dhcp6_handledata(void *arg)
|
||||
ssize_t bytes;
|
||||
struct cmsghdr *cm;
|
||||
struct in6_pktinfo pkt;
|
||||
struct interface *ifp;
|
||||
struct interface *ifp, *ifpx;
|
||||
const char *op;
|
||||
struct dhcp6_message *r;
|
||||
struct dhcp6_state *state;
|
||||
@ -2431,22 +2451,31 @@ dhcp6_handledata(void *arg)
|
||||
ctx->sfrom);
|
||||
return;
|
||||
}
|
||||
|
||||
r = (struct dhcp6_message *)ctx->rcvhdr.msg_iov[0].iov_base;
|
||||
|
||||
/* Which interface state is the IAID for? */
|
||||
ifpx = dhcp6_findpfxdlgif(ifp);
|
||||
if (ifpx && D6_STATE(ifpx)) {
|
||||
state = D6_STATE(ifpx);
|
||||
if (r->xid[0] == state->send->xid[0] &&
|
||||
r->xid[1] == state->send->xid[1] &&
|
||||
r->xid[2] == state->send->xid[2])
|
||||
ifp = ifpx;
|
||||
}
|
||||
|
||||
state = D6_STATE(ifp);
|
||||
if (state == NULL || state->send == NULL) {
|
||||
syslog(LOG_DEBUG, "%s: DHCPv6 reply received but not running",
|
||||
ifp->name);
|
||||
return;
|
||||
}
|
||||
|
||||
r = (struct dhcp6_message *)ctx->rcvhdr.msg_iov[0].iov_base;
|
||||
|
||||
/* We're already bound and this message is for another machine */
|
||||
/* XXX DELEGATED? */
|
||||
if (r->type != DHCP6_RECONFIGURE &&
|
||||
(state->state == DH6S_BOUND || state->state == DH6S_INFORMED))
|
||||
return;
|
||||
|
||||
r = (struct dhcp6_message *)ctx->rcvhdr.msg_iov[0].iov_base;
|
||||
if (r->type != DHCP6_RECONFIGURE &&
|
||||
(r->xid[0] != state->send->xid[0] ||
|
||||
r->xid[1] != state->send->xid[1] ||
|
||||
@ -2929,6 +2958,47 @@ dhcp6_start1(void *arg)
|
||||
if (dhcp6_findselfsla(ifp, NULL))
|
||||
del_option_mask(ifo->requestmask6, D6_OPTION_RAPID_COMMIT);
|
||||
|
||||
/* Create a 2nd interface to handle the PD state */
|
||||
if (!(ifo->options & (DHCPCD_PFXDLGONLY | DHCPCD_PFXDLGMIX)) &&
|
||||
dhcp6_hasprefixdelegation(ifp))
|
||||
{
|
||||
const char * const argv[] = { ifp->name };
|
||||
struct if_head *ifs;
|
||||
struct interface *ifn;
|
||||
|
||||
ifn = dhcp6_findpfxdlgif(ifp);
|
||||
if (ifn == NULL) {
|
||||
ifs = if_discover(ifp->ctx, -1, UNCONST(argv));
|
||||
if (ifs) {
|
||||
ifn = TAILQ_FIRST(ifs);
|
||||
if (ifn) {
|
||||
syslog(LOG_INFO,
|
||||
"%s: creating psuedo interface"
|
||||
" to handle Prefix Delegation",
|
||||
ifp->name);
|
||||
ifp->options->options |=
|
||||
DHCPCD_NOPFXDLG;
|
||||
TAILQ_REMOVE(ifs, ifn, next);
|
||||
TAILQ_INSERT_AFTER(ifp->ctx->ifaces,
|
||||
ifp, ifn, next);
|
||||
dhcpcd_initstate(ifn);
|
||||
ifn->options->options |=
|
||||
DHCPCD_PFXDLGONLY;
|
||||
ifn->options->options &=
|
||||
~(DHCPCD_IPV4 | DHCPCD_IPV6RS |
|
||||
DHCPCD_NOPFXDLG);
|
||||
eloop_timeout_add_sec(ifp->ctx->eloop,
|
||||
0, dhcpcd_startinterface, ifn);
|
||||
}
|
||||
while ((ifn = TAILQ_FIRST(ifs))) {
|
||||
TAILQ_REMOVE(ifs, ifn, next);
|
||||
if_free(ifn);
|
||||
}
|
||||
free(ifs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (state->state == DH6S_INFORM) {
|
||||
add_option_mask(ifo->requestmask6, D6_OPTION_INFO_REFRESH_TIME);
|
||||
dhcp6_startinform(ifp);
|
||||
@ -3019,10 +3089,18 @@ dhcp6_reboot(struct interface *ifp)
|
||||
static void
|
||||
dhcp6_freedrop(struct interface *ifp, int drop, const char *reason)
|
||||
{
|
||||
struct interface *ifpx;
|
||||
struct dhcp6_state *state;
|
||||
struct dhcpcd_ctx *ctx;
|
||||
unsigned long long options;
|
||||
|
||||
ifpx = dhcp6_findpfxdlgif(ifp);
|
||||
if (ifpx) {
|
||||
dhcp6_freedrop(ifpx, drop, reason);
|
||||
TAILQ_REMOVE(ifp->ctx->ifaces, ifpx, next);
|
||||
if_free(ifpx);
|
||||
}
|
||||
|
||||
if (ifp->ctx->eloop)
|
||||
eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
|
||||
|
||||
|
38
dhcpcd.8.in
38
dhcpcd.8.in
@ -22,7 +22,7 @@
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.Dd July 4, 2014
|
||||
.Dd July 7, 2014
|
||||
.Dt DHCPCD 8
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -68,10 +68,6 @@
|
||||
.Fl U, Fl Fl dumplease
|
||||
.Ar interface
|
||||
.Nm
|
||||
.Fl Fl pfxdlgonly
|
||||
.Nm
|
||||
.Fl Fl nopfxdlg
|
||||
.Nm
|
||||
.Fl Fl version
|
||||
.Nm
|
||||
.Fl x , Fl Fl exit
|
||||
@ -556,6 +552,14 @@ Dumps the last lease for the
|
||||
to stdout.
|
||||
.Ar interface
|
||||
could also be a path to a DHCP wire formatted file.
|
||||
Use the
|
||||
.Fl 4
|
||||
or
|
||||
.Fl 6
|
||||
flags to specify an address family.
|
||||
Pass a 2nd
|
||||
.Fl U, Fl Fl dumplease option to dump a secondary lease, such as
|
||||
DHCPv6 Prefix Delegation when not being mixed with another IA type.
|
||||
.It Fl V, Fl Fl variables
|
||||
Display a list of option codes and the associated variable for use in
|
||||
.Xr dhcpcd-run-hooks 8 .
|
||||
@ -618,30 +622,6 @@ to rebind, reconfigure or exit need to include the same restrictive flags
|
||||
so that
|
||||
.Nm
|
||||
knows which process to signal.
|
||||
.Pp
|
||||
.Li RFC3633
|
||||
DHCPv6 Prefix Delegation does not work in the same state or session as
|
||||
Normal or Temporary Addresses.
|
||||
.Nm
|
||||
is designed for a single state per protocol and as such
|
||||
.Li draft-ietf-dhc-dhcpv6-stateful-issues-06
|
||||
is supported by default, but that is not a published RFC yet.
|
||||
To allow RFC conformance,
|
||||
.Nm
|
||||
supports the
|
||||
.Fl Fl pfxdlgonly
|
||||
and
|
||||
.Fl Fl nopfxdlg
|
||||
options which allow the spawning of two
|
||||
.Nm
|
||||
instances to separate the Prefix Delegation state from the others.
|
||||
You may wish to disable
|
||||
.Xr dhcpcd-run-hooks 8
|
||||
on the
|
||||
.Fl Fl pfxdlgonly
|
||||
instance using the
|
||||
.Fl Fl script \"\"
|
||||
option.
|
||||
.Sh FILES
|
||||
.Bl -ohang
|
||||
.It Pa @SYSCONFDIR@/dhcpcd.conf
|
||||
|
44
dhcpcd.c
44
dhcpcd.c
@ -581,7 +581,7 @@ warn_iaid_conflict(struct interface *ifp, uint8_t *iaid)
|
||||
}
|
||||
|
||||
/* This is only a problem if the interfaces are on the same network. */
|
||||
if (ifn)
|
||||
if (ifn && strcmp(ifp->name, ifn->name))
|
||||
syslog(LOG_ERR,
|
||||
"%s: IAID conflicts with one assigned to %s",
|
||||
ifp->name, ifn->name);
|
||||
@ -702,7 +702,7 @@ handle_link(void *arg)
|
||||
}
|
||||
|
||||
static void
|
||||
init_state(struct interface *ifp, int argc, char **argv)
|
||||
dhcpcd_initstate1(struct interface *ifp, int argc, char **argv)
|
||||
{
|
||||
struct if_options *ifo;
|
||||
|
||||
@ -728,6 +728,13 @@ init_state(struct interface *ifp, int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
dhcpcd_initstate(struct interface *ifp)
|
||||
{
|
||||
|
||||
dhcpcd_initstate1(ifp, ifp->ctx->argc, ifp->ctx->argv);
|
||||
}
|
||||
|
||||
static void
|
||||
run_preinit(struct interface *ifp)
|
||||
{
|
||||
@ -794,7 +801,7 @@ dhcpcd_handleinterface(void *arg, int action, const char *ifname)
|
||||
syslog(LOG_DEBUG, "%s: interface added", ifp->name);
|
||||
TAILQ_REMOVE(ifs, ifp, next);
|
||||
TAILQ_INSERT_TAIL(ctx->ifaces, ifp, next);
|
||||
init_state(ifp, ctx->argc, ctx->argv);
|
||||
dhcpcd_initstate(ifp);
|
||||
run_preinit(ifp);
|
||||
iff = ifp;
|
||||
}
|
||||
@ -874,7 +881,7 @@ reconf_reboot(struct dhcpcd_ctx *ctx, int action, int argc, char **argv, int oi)
|
||||
if_free(ifp);
|
||||
} else {
|
||||
TAILQ_INSERT_TAIL(ctx->ifaces, ifp, next);
|
||||
init_state(ifp, argc, argv);
|
||||
dhcpcd_initstate1(ifp, argc, argv);
|
||||
run_preinit(ifp);
|
||||
dhcpcd_startinterface(ifp);
|
||||
}
|
||||
@ -887,7 +894,7 @@ reconf_reboot(struct dhcpcd_ctx *ctx, int action, int argc, char **argv, int oi)
|
||||
static void
|
||||
stop_all_interfaces(struct dhcpcd_ctx *ctx, int do_release)
|
||||
{
|
||||
struct interface *ifp;
|
||||
struct interface *ifp, *ifpm;
|
||||
|
||||
/* drop_dhcp could change the order, so we do it like this. */
|
||||
for (;;) {
|
||||
@ -895,6 +902,10 @@ stop_all_interfaces(struct dhcpcd_ctx *ctx, int do_release)
|
||||
ifp = TAILQ_LAST(ctx->ifaces, if_head);
|
||||
if (ifp == NULL)
|
||||
break;
|
||||
/* Stop the master interface only */
|
||||
ifpm = if_find(ifp->ctx, ifp->name);
|
||||
if (ifpm)
|
||||
ifp = ifpm;
|
||||
if (do_release) {
|
||||
ifp->options->options |= DHCPCD_RELEASE;
|
||||
ifp->options->options &= ~DHCPCD_PERSISTENT;
|
||||
@ -1267,10 +1278,13 @@ main(int argc, char **argv)
|
||||
i = 1;
|
||||
break;
|
||||
case 'U':
|
||||
i = 2;
|
||||
if (i == 3)
|
||||
i = 4;
|
||||
else if (i != 4)
|
||||
i = 3;
|
||||
break;
|
||||
case 'V':
|
||||
i = 3;
|
||||
i = 2;
|
||||
break;
|
||||
case '?':
|
||||
usage();
|
||||
@ -1292,7 +1306,7 @@ main(int argc, char **argv)
|
||||
usage();
|
||||
goto exit_failure;
|
||||
}
|
||||
if (i == 3) {
|
||||
if (i == 2) {
|
||||
printf("Interface options:\n");
|
||||
if (optind == argc - 1) {
|
||||
free_options(ifo);
|
||||
@ -1324,6 +1338,8 @@ main(int argc, char **argv)
|
||||
ctx.options |= DHCPCD_TEST;
|
||||
else
|
||||
ctx.options |= DHCPCD_DUMPLEASE;
|
||||
if (i == 4)
|
||||
ctx.options |= DHCPCD_PFXDLGONLY;
|
||||
ctx.options |= DHCPCD_PERSISTENT;
|
||||
ctx.options &= ~DHCPCD_DAEMONISE;
|
||||
}
|
||||
@ -1373,9 +1389,7 @@ main(int argc, char **argv)
|
||||
snprintf(pidfile, sizeof(pidfile),
|
||||
PIDFILE, "-", argv[optind], per);
|
||||
} else {
|
||||
snprintf(pidfile, sizeof(pidfile), PIDFILE,
|
||||
ctx.options & DHCPCD_PFXDLGONLY ? ".pd" : "",
|
||||
"", "");
|
||||
snprintf(pidfile, sizeof(pidfile), PIDFILE, "", "", "");
|
||||
ctx.options |= DHCPCD_MASTER;
|
||||
}
|
||||
}
|
||||
@ -1414,6 +1428,8 @@ main(int argc, char **argv)
|
||||
TAILQ_INSERT_HEAD(ctx.ifaces, ifp, next);
|
||||
}
|
||||
configure_interface(ifp, ctx.argc, ctx.argv);
|
||||
if (ctx.options & DHCPCD_PFXDLGONLY)
|
||||
ifp->options->options |= DHCPCD_PFXDLGONLY;
|
||||
if (family == 0 || family == AF_INET) {
|
||||
if (dhcp_dump(ifp) == -1)
|
||||
i = 1;
|
||||
@ -1428,7 +1444,7 @@ main(int argc, char **argv)
|
||||
}
|
||||
|
||||
#ifdef USE_SIGNALS
|
||||
if (!(ctx.options & (DHCPCD_TEST | DHCPCD_PFXDLGONLY)) &&
|
||||
if (!(ctx.options & DHCPCD_TEST) &&
|
||||
(sig == 0 || ctx.ifc != 0))
|
||||
{
|
||||
#endif
|
||||
@ -1544,7 +1560,7 @@ main(int argc, char **argv)
|
||||
}
|
||||
|
||||
|
||||
if (ctx.options & DHCPCD_MASTER && !(ctx.options & DHCPCD_PFXDLGONLY)) {
|
||||
if (ctx.options & DHCPCD_MASTER) {
|
||||
if (control_start(&ctx, NULL) == -1)
|
||||
syslog(LOG_ERR, "control_start: %m");
|
||||
}
|
||||
@ -1613,7 +1629,7 @@ main(int argc, char **argv)
|
||||
}
|
||||
|
||||
TAILQ_FOREACH(ifp, ctx.ifaces, next) {
|
||||
init_state(ifp, argc, argv);
|
||||
dhcpcd_initstate1(ifp, argc, argv);
|
||||
}
|
||||
|
||||
if (ctx.options & DHCPCD_BACKGROUND && dhcpcd_daemonise(&ctx))
|
||||
|
@ -22,7 +22,7 @@
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.Dd July 4, 2014
|
||||
.Dd July 7, 2014
|
||||
.Dt DHCPCD.CONF 5
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -293,12 +293,18 @@ IPv6RS should be disabled globally when requesting a Prefix Delegation like so:
|
||||
.D1 interface eth1
|
||||
.D1 ipv4
|
||||
.D1 ipv6rs
|
||||
.Pp
|
||||
Using this option with other IA options in the same interface block is not
|
||||
currently RFC conformant.
|
||||
Please see the
|
||||
.Li BUGS
|
||||
section below.
|
||||
.It Ic ia_pd_mix
|
||||
To be RFC compliant,
|
||||
.Nm dhcpcd
|
||||
cannot mix Prefix Delegation with other DHCPv6 address types in the same
|
||||
session.
|
||||
This has a number of issues: additional DHCP traffic and potential collisions
|
||||
between options.
|
||||
.Ic ia_pd_mix
|
||||
enables
|
||||
.Li draft-ietf-dhc-dhcpv6-stateful-issues-06
|
||||
support so that Prefix Delegation can be mixed with other address types in
|
||||
the same session.
|
||||
.It Ic ipv4only
|
||||
Only configure IPv4.
|
||||
.It Ic ipv6only
|
||||
@ -751,21 +757,5 @@ Same as
|
||||
.Sh AUTHORS
|
||||
.An Roy Marples Aq Mt roy@marples.name
|
||||
.Sh BUGS
|
||||
Combining different DHCPv6 IA options in the same interface block is not
|
||||
currently RFC conformant.
|
||||
See
|
||||
.Lk http://datatracker.ietf.org/doc/draft-ietf-dhc-dhcpv6-stateful-issues
|
||||
for details.
|
||||
.Nm dhcpcd
|
||||
strives to comply with this document and will be updated when finally published.
|
||||
To enable RFC conformance, spawn separate
|
||||
.Nm dhcpcd
|
||||
instances using the
|
||||
.Fl Fl pfxdlgonly
|
||||
and
|
||||
.Fl Fl nopfxdlg
|
||||
options as described in
|
||||
.Xr dhcpcd 8 .
|
||||
.Pp
|
||||
Please report them to
|
||||
.Lk http://roy.marples.name/projects/dhcpcd
|
||||
|
1
dhcpcd.h
1
dhcpcd.h
@ -151,5 +151,6 @@ void dhcpcd_dropinterface(struct interface *, const char *);
|
||||
int dhcpcd_selectprofile(struct interface *, const char *);
|
||||
|
||||
void dhcpcd_startinterface(void *);
|
||||
void dhcpcd_initstate(struct interface *);
|
||||
|
||||
#endif
|
||||
|
13
if-options.c
13
if-options.c
@ -93,8 +93,7 @@
|
||||
#define O_CONTROLGRP O_BASE + 34
|
||||
#define O_SLAAC O_BASE + 35
|
||||
#define O_GATEWAY O_BASE + 36
|
||||
#define O_NOPFXDLG O_BASE + 37
|
||||
#define O_PFXDLGONLY O_BASE + 38
|
||||
#define O_PFXDLGMIX O_BASE + 37
|
||||
|
||||
const struct option cf_options[] = {
|
||||
{"background", no_argument, NULL, 'b'},
|
||||
@ -181,8 +180,7 @@ const struct option cf_options[] = {
|
||||
{"controlgroup", required_argument, NULL, O_CONTROLGRP},
|
||||
{"slaac", required_argument, NULL, O_SLAAC},
|
||||
{"gateway", no_argument, NULL, O_GATEWAY},
|
||||
{"nopfxdlg", no_argument, NULL, O_NOPFXDLG},
|
||||
{"pfxdlgonly", no_argument, NULL, O_PFXDLGONLY},
|
||||
{"ia_pd_mix", no_argument, NULL, O_PFXDLGMIX},
|
||||
{NULL, 0, NULL, '\0'}
|
||||
};
|
||||
|
||||
@ -1900,11 +1898,8 @@ err_sla:
|
||||
else
|
||||
ifo->options &= ~DHCPCD_SLAACPRIVATE;
|
||||
break;
|
||||
case O_NOPFXDLG:
|
||||
ifo->options |= DHCPCD_NOPFXDLG;
|
||||
break;
|
||||
case O_PFXDLGONLY:
|
||||
ifo->options |= DHCPCD_PFXDLGONLY;
|
||||
case O_PFXDLGMIX:
|
||||
ifo->options |= DHCPCD_PFXDLGMIX;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
|
@ -105,6 +105,7 @@
|
||||
#define DHCPCD_DHCP6 (1ULL << 50)
|
||||
#define DHCPCD_NOPFXDLG (1ULL << 51)
|
||||
#define DHCPCD_PFXDLGONLY (1ULL << 52)
|
||||
#define DHCPCD_PFXDLGMIX (1ULL << 53)
|
||||
|
||||
extern const struct option cf_options[];
|
||||
|
||||
|
5
if.c
5
if.c
@ -240,6 +240,7 @@ if_discover(struct dhcpcd_ctx *ctx, int argc, char * const *argv)
|
||||
}
|
||||
if (ifp)
|
||||
continue;
|
||||
|
||||
if (argc > 0) {
|
||||
for (i = 0; i < argc; i++) {
|
||||
#ifdef __linux__
|
||||
@ -483,7 +484,9 @@ if_find(struct dhcpcd_ctx *ctx, const char *ifname)
|
||||
|
||||
if (ctx != NULL && ctx->ifaces != NULL) {
|
||||
TAILQ_FOREACH(ifp, ctx->ifaces, next) {
|
||||
if (strcmp(ifp->name, ifname) == 0)
|
||||
if ((ifp->options ||
|
||||
!(ifp->options->options & DHCPCD_PFXDLGONLY)) &&
|
||||
strcmp(ifp->name, ifname) == 0)
|
||||
return ifp;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user