Remove IPv4 and DHCP4 specific setup from dhcpcd.c and move into ipv4.c

and dhcp.c
Split configure.c into script.c and move the rest into dhcp.c

This starts the goal of making the base of dhcpcd protocol agnostic and
working towards building IPv4 and/or IPv6 code only to reduce size and
allow growing any future new protocol easier.
This commit is contained in:
Roy Marples 2013-02-02 14:05:55 +00:00
parent 1a59b377b5
commit 294eff4df4
20 changed files with 2279 additions and 2156 deletions

View File

@ -1,8 +1,10 @@
# dhcpcd Makefile
PROG= dhcpcd
SRCS= arp.c bind.c common.c control.c dhcp.c dhcpcd.c duid.c eloop.c
SRCS+= configure.c if-options.c if-pref.c ipv4ll.c net.c signals.c
SRCS= arp.c common.c control.c dhcpcd.c duid.c eloop.c
SRCS+= if-options.c if-pref.c net.c script.c signals.c
SRCS+= dhcp-common.c
SRCS+= ipv4.c dhcp.c ipv4ll.c
SRCS+= ipv6.c ipv6rs.c ipv6ns.c dhcp6.c
CFLAGS?= -O2

45
arp.c
View File

@ -1,6 +1,6 @@
/*
* dhcpcd - DHCP client daemon
* Copyright (c) 2006-2012 Roy Marples <roy@marples.name>
* Copyright (c) 2006-2013 Roy Marples <roy@marples.name>
* All rights reserved
* Redistribution and use in source and binary forms, with or without
@ -33,8 +33,9 @@
#include <unistd.h>
#include "arp.h"
#include "bind.h"
#include "ipv4.h"
#include "common.h"
#include "dhcp.h"
#include "dhcpcd.h"
#include "eloop.h"
#include "if-options.h"
@ -45,7 +46,7 @@
(sizeof(struct arphdr) + (2 * sizeof(uint32_t)) + (2 * HWADDR_LEN))
static int
send_arp(const struct interface *ifp, int op, in_addr_t sip, in_addr_t tip)
arp_send(const struct interface *ifp, int op, in_addr_t sip, in_addr_t tip)
{
uint8_t arp_buffer[ARP_LEN];
struct arphdr ar;
@ -76,7 +77,7 @@ send_arp(const struct interface *ifp, int op, in_addr_t sip, in_addr_t tip)
}
static void
handle_arp_failure(struct interface *ifp)
arp_failure(struct interface *ifp)
{
/* If we failed without a magic cookie then we need to try
@ -92,8 +93,8 @@ handle_arp_failure(struct interface *ifp)
unlink(ifp->leasefile);
if (!ifp->state->lease.frominfo)
send_decline(ifp);
close_sockets(ifp);
dhcp_decline(ifp);
dhcp_close(ifp);
eloop_timeout_delete(NULL, ifp);
if (ifp->state->lease.frominfo)
start_interface(ifp);
@ -102,7 +103,7 @@ handle_arp_failure(struct interface *ifp)
}
static void
handle_arp_packet(void *arg)
arp_packet(void *arg)
{
struct interface *ifp = arg;
uint8_t arp_buffer[ARP_LEN];
@ -166,7 +167,7 @@ handle_arp_packet(void *arg)
if (select_profile(ifp, hwaddr) == -1 &&
errno == ENOENT)
select_profile(ifp, inet_ntoa(ina));
close_sockets(ifp);
dhcp_close(ifp);
eloop_timeout_delete(NULL, ifp);
start_interface(ifp);
return;
@ -191,14 +192,14 @@ handle_arp_packet(void *arg)
(size_t)ar.ar_hln),
inet_ntoa(state->fail));
errno = EEXIST;
handle_arp_failure(ifp);
arp_failure(ifp);
return;
}
}
}
void
send_arp_announce(void *arg)
arp_announce(void *arg)
{
struct interface *ifp = arg;
struct if_state *state = ifp->state;
@ -208,7 +209,7 @@ send_arp_announce(void *arg)
return;
if (ifp->arp_fd == -1) {
open_socket(ifp, ETHERTYPE_ARP);
eloop_event_add(ifp->arp_fd, handle_arp_packet, ifp);
eloop_event_add(ifp->arp_fd, arp_packet, ifp);
}
if (++state->claims < ANNOUNCE_NUM)
syslog(LOG_DEBUG,
@ -219,11 +220,11 @@ send_arp_announce(void *arg)
syslog(LOG_DEBUG,
"%s: sending ARP announce (%d of %d)",
ifp->name, state->claims, ANNOUNCE_NUM);
if (send_arp(ifp, ARPOP_REQUEST,
if (arp_send(ifp, ARPOP_REQUEST,
state->new->yiaddr, state->new->yiaddr) == -1)
syslog(LOG_ERR, "send_arp: %m");
if (state->claims < ANNOUNCE_NUM) {
eloop_timeout_add_sec(ANNOUNCE_WAIT, send_arp_announce, ifp);
eloop_timeout_add_sec(ANNOUNCE_WAIT, arp_announce, ifp);
return;
}
if (state->new->cookie != htonl(MAGIC_COOKIE)) {
@ -236,7 +237,7 @@ send_arp_announce(void *arg)
tv.tv_sec = state->interval - DHCP_RAND_MIN;
tv.tv_usec = arc4random() % (DHCP_RAND_MAX_U - DHCP_RAND_MIN_U);
timernorm(&tv);
eloop_timeout_add_tv(&tv, start_discover, ifp);
eloop_timeout_add_tv(&tv, dhcp_discover, ifp);
} else {
eloop_event_delete(ifp->arp_fd);
close(ifp->arp_fd);
@ -245,7 +246,7 @@ send_arp_announce(void *arg)
}
void
send_arp_probe(void *arg)
arp_probe(void *arg)
{
struct interface *ifp = arg;
struct if_state *state = ifp->state;
@ -266,7 +267,7 @@ send_arp_probe(void *arg)
if (ifp->arp_fd == -1) {
open_socket(ifp, ETHERTYPE_ARP);
eloop_event_add(ifp->arp_fd, handle_arp_packet, ifp);
eloop_event_add(ifp->arp_fd, arp_packet, ifp);
}
if (state->probes == 0) {
if (arping)
@ -280,32 +281,32 @@ send_arp_probe(void *arg)
tv.tv_sec = PROBE_MIN;
tv.tv_usec = arc4random() % (PROBE_MAX_U - PROBE_MIN_U);
timernorm(&tv);
eloop_timeout_add_tv(&tv, send_arp_probe, ifp);
eloop_timeout_add_tv(&tv, arp_probe, ifp);
} else {
tv.tv_sec = ANNOUNCE_WAIT;
tv.tv_usec = 0;
if (arping) {
state->probes = 0;
if (++state->arping_index < state->options->arping_len)
eloop_timeout_add_tv(&tv, send_arp_probe, ifp);
eloop_timeout_add_tv(&tv, arp_probe, ifp);
else
eloop_timeout_add_tv(&tv, start_interface, ifp);
} else
eloop_timeout_add_tv(&tv, bind_interface, ifp);
eloop_timeout_add_tv(&tv, dhcp_bind, ifp);
}
syslog(LOG_DEBUG,
"%s: sending ARP probe (%d of %d), next in %0.2f seconds",
ifp->name, state->probes ? state->probes : PROBE_NUM, PROBE_NUM,
timeval_to_double(&tv));
if (send_arp(ifp, ARPOP_REQUEST, 0, addr.s_addr) == -1)
if (arp_send(ifp, ARPOP_REQUEST, 0, addr.s_addr) == -1)
syslog(LOG_ERR, "send_arp: %m");
}
void
start_arping(struct interface *ifp)
arp_start(struct interface *ifp)
{
ifp->state->probes = 0;
ifp->state->arping_index = 0;
send_arp_probe(ifp);
arp_probe(ifp);
}

8
arp.h
View File

@ -1,6 +1,6 @@
/*
* dhcpcd - DHCP client daemon
* Copyright (c) 2006-2008 Roy Marples <roy@marples.name>
* Copyright (c) 2006-2013 Roy Marples <roy@marples.name>
* All rights reserved
* Redistribution and use in source and binary forms, with or without
@ -43,7 +43,7 @@
#include "dhcpcd.h"
void send_arp_announce(void *);
void send_arp_probe(void *);
void start_arping(struct interface *);
void arp_announce(void *);
void arp_probe(void *);
void arp_start(struct interface *);
#endif

231
bind.c
View File

@ -1,231 +0,0 @@
/*
* dhcpcd - DHCP client daemon
* Copyright (c) 2006-2012 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/param.h>
#include <sys/time.h>
#include <fcntl.h>
#ifdef BSD
# include <paths.h>
#endif
#include <signal.h>
#include <stdlib.h>
#include <syslog.h>
#include <unistd.h>
#include "arp.h"
#include "bind.h"
#include "common.h"
#include "configure.h"
#include "dhcpcd.h"
#include "eloop.h"
#include "if-options.h"
#include "net.h"
#include "signals.h"
#ifndef _PATH_DEVNULL
# define _PATH_DEVNULL "/dev/null"
#endif
/* We do things after aquiring the lease, so ensure we have enough time for them */
#define DHCP_MIN_LEASE 20
#ifndef THERE_IS_NO_FORK
pid_t
daemonise(void)
{
pid_t pid;
char buf = '\0';
int sidpipe[2], fd;
eloop_timeout_delete(handle_exit_timeout, NULL);
if (options & DHCPCD_DAEMONISED || !(options & DHCPCD_DAEMONISE))
return 0;
/* Setup a signal pipe so parent knows when to exit. */
if (pipe(sidpipe) == -1) {
syslog(LOG_ERR, "pipe: %m");
return -1;
}
syslog(LOG_DEBUG, "forking to background");
switch (pid = fork()) {
case -1:
syslog(LOG_ERR, "fork: %m");
exit(EXIT_FAILURE);
/* NOTREACHED */
case 0:
setsid();
/* Notify parent it's safe to exit as we've detached. */
close(sidpipe[0]);
if (write(sidpipe[1], &buf, 1) == -1)
syslog(LOG_ERR, "failed to notify parent: %m");
close(sidpipe[1]);
if ((fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {
dup2(fd, STDIN_FILENO);
dup2(fd, STDOUT_FILENO);
dup2(fd, STDERR_FILENO);
close(fd);
}
break;
default:
/* Wait for child to detach */
close(sidpipe[1]);
if (read(sidpipe[0], &buf, 1) == -1)
syslog(LOG_ERR, "failed to read child: %m");
close(sidpipe[0]);
break;
}
/* Done with the fd now */
if (pid != 0) {
syslog(LOG_INFO, "forked to background, child pid %d",pid);
writepid(pidfd, pid);
close(pidfd);
pidfd = -1;
options |= DHCPCD_FORKED;
exit(EXIT_SUCCESS);
}
options |= DHCPCD_DAEMONISED;
return pid;
}
#endif
void
bind_interface(void *arg)
{
struct interface *iface = arg;
struct if_state *state = iface->state;
struct if_options *ifo = state->options;
struct dhcp_lease *lease = &state->lease;
struct timeval tv;
/* We're binding an address now - ensure that sockets are closed */
close_sockets(iface);
state->reason = NULL;
if (clock_monotonic)
get_monotonic(&lease->boundtime);
state->xid = 0;
free(state->old);
state->old = state->new;
state->new = state->offer;
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));
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",
iface->name, inet_ntoa(lease->addr));
lease->leasetime = ~0U;
state->reason = "IPV4LL";
} else if (ifo->options & DHCPCD_INFORM) {
if (ifo->req_addr.s_addr != 0)
lease->addr.s_addr = ifo->req_addr.s_addr;
else
lease->addr.s_addr = iface->addr.s_addr;
syslog(LOG_INFO, "%s: received approval for %s", iface->name,
inet_ntoa(lease->addr));
lease->leasetime = ~0U;
state->reason = "INFORM";
} else {
if (gettimeofday(&tv, NULL) == 0)
lease->leasedfrom = tv.tv_sec;
else if (lease->frominfo)
state->reason = "TIMEOUT";
if (lease->leasetime == ~0U) {
lease->renewaltime =
lease->rebindtime =
lease->leasetime;
syslog(LOG_INFO, "%s: leased %s for infinity",
iface->name, inet_ntoa(lease->addr));
} else {
if (lease->leasetime < DHCP_MIN_LEASE) {
syslog(LOG_WARNING,
"%s: minimum lease is %d seconds",
iface->name, DHCP_MIN_LEASE);
lease->leasetime = DHCP_MIN_LEASE;
}
if (lease->rebindtime == 0)
lease->rebindtime = lease->leasetime * T2;
else if (lease->rebindtime >= lease->leasetime) {
lease->rebindtime = lease->leasetime * T2;
syslog(LOG_ERR,
"%s: rebind time greater than lease "
"time, forcing to %u seconds",
iface->name, lease->rebindtime);
}
if (lease->renewaltime == 0)
lease->renewaltime = lease->leasetime * T1;
else if (lease->renewaltime > lease->rebindtime) {
lease->renewaltime = lease->leasetime * T1;
syslog(LOG_ERR,
"%s: renewal time greater than rebind "
"time, forcing to %u seconds",
iface->name, lease->renewaltime);
}
syslog(LOG_INFO,
"%s: leased %s for %u seconds", iface->name,
inet_ntoa(lease->addr), lease->leasetime);
}
}
if (options & DHCPCD_TEST) {
state->reason = "TEST";
run_script(iface);
exit(EXIT_SUCCESS);
}
if (state->reason == NULL) {
if (state->old) {
if (state->old->yiaddr == state->new->yiaddr &&
lease->server.s_addr)
state->reason = "RENEW";
else
state->reason = "REBIND";
} else if (state->state == DHS_REBOOT)
state->reason = "REBOOT";
else
state->reason = "BOUND";
}
if (lease->leasetime == ~0U)
lease->renewaltime = lease->rebindtime = lease->leasetime;
else {
eloop_timeout_add_sec(lease->renewaltime, start_renew, iface);
eloop_timeout_add_sec(lease->rebindtime, start_rebind, iface);
eloop_timeout_add_sec(lease->leasetime, start_expire, iface);
syslog(LOG_DEBUG,
"%s: renew in %u seconds, rebind in %u seconds",
iface->name, lease->renewaltime, lease->rebindtime);
}
ifo->options &= ~ DHCPCD_CSR_WARNED;
configure(iface);
daemonise();
state->state = DHS_BOUND;
if (ifo->options & DHCPCD_ARP) {
state->claims = 0;
send_arp_announce(iface);
}
}

382
dhcp-common.c Normal file
View File

@ -0,0 +1,382 @@
/*
* dhcpcd - DHCP client daemon
* Copyright (c) 2006-2012 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 <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
#include "config.h"
#include "common.h"
#include "dhcp-common.h"
#include "dhcp.h"
int make_option_mask(const struct dhcp_opt *dopts,
uint8_t *mask, const char *opts, int add)
{
char *token, *o, *p, *t;
const struct dhcp_opt *opt;
int match, n;
o = p = xstrdup(opts);
while ((token = strsep(&p, ", "))) {
if (*token == '\0')
continue;
for (opt = dopts; opt->option; opt++) {
if (!opt->var)
continue;
match = 0;
if (strcmp(opt->var, token) == 0)
match = 1;
else {
errno = 0;
n = strtol(token, &t, 0);
if (errno == 0 && !*t)
if (opt->option == n)
match = 1;
}
if (match) {
if (add == 2 && !(opt->type & ADDRIPV4)) {
free(o);
errno = EINVAL;
return -1;
}
if (add == 1 || add == 2)
add_option_mask(mask,
opt->option);
else
del_option_mask(mask,
opt->option);
break;
}
}
if (!opt->option) {
free(o);
errno = ENOENT;
return -1;
}
}
free(o);
return 0;
}
/* Decode an RFC3397 DNS search order option into a space
* separated string. Returns length of string (including
* terminating zero) or zero on error. out may be NULL
* to just determine output length. */
ssize_t
decode_rfc3397(char *out, ssize_t len, int pl, const uint8_t *p)
{
const char *start;
ssize_t start_len;
const uint8_t *r, *q = p;
int count = 0, l, hops;
uint8_t ltype;
start = out;
start_len = len;
while (q - p < pl) {
r = NULL;
hops = 0;
/* We check we are inside our length again incase
* the data is NOT terminated correctly. */
while ((l = *q++) && q - p < pl) {
ltype = l & 0xc0;
if (ltype == 0x80 || ltype == 0x40)
return 0;
else if (ltype == 0xc0) { /* pointer */
l = (l & 0x3f) << 8;
l |= *q++;
/* save source of first jump. */
if (!r)
r = q;
hops++;
if (hops > 255)
return 0;
q = p + l;
if (q - p >= pl)
return 0;
} else {
/* straightforward name segment, add with '.' */
count += l + 1;
if (out) {
if ((ssize_t)l + 1 > len) {
errno = ENOBUFS;
return -1;
}
memcpy(out, q, l);
out += l;
*out++ = '.';
len -= l;
len--;
}
q += l;
}
}
/* change last dot to space */
if (out && out != start)
*(out - 1) = ' ';
if (r)
q = r;
}
/* change last space to zero terminator */
if (out) {
if (out != start)
*(out - 1) = '\0';
else if (start_len > 0)
*out = '\0';
}
return count;
}
ssize_t
print_string(char *s, ssize_t len, int dl, const uint8_t *data)
{
uint8_t c;
const uint8_t *e, *p;
ssize_t bytes = 0;
ssize_t r;
e = data + dl;
while (data < e) {
c = *data++;
if (c == '\0') {
/* If rest is all NULL, skip it. */
for (p = data; p < e; p++)
if (*p != '\0')
break;
if (p == e)
break;
}
if (!isascii(c) || !isprint(c)) {
if (s) {
if (len < 5) {
errno = ENOBUFS;
return -1;
}
r = snprintf(s, len, "\\%03o", c);
len -= r;
bytes += r;
s += r;
} else
bytes += 4;
continue;
}
switch (c) {
case '"': /* FALLTHROUGH */
case '\'': /* FALLTHROUGH */
case '$': /* FALLTHROUGH */
case '`': /* FALLTHROUGH */
case '\\': /* FALLTHROUGH */
case '|': /* FALLTHROUGH */
case '&':
if (s) {
if (len < 3) {
errno = ENOBUFS;
return -1;
}
*s++ = '\\';
len--;
}
bytes++;
break;
}
if (s) {
*s++ = c;
len--;
}
bytes++;
}
/* NULL */
if (s)
*s = '\0';
bytes++;
return bytes;
}
ssize_t
print_option(char *s, ssize_t len, int type, int dl, const uint8_t *data,
const char *ifname)
{
const uint8_t *e, *t;
uint16_t u16;
int16_t s16;
uint32_t u32;
int32_t s32;
struct in_addr addr;
ssize_t bytes = 0;
ssize_t l;
char *tmp;
if (type & RFC3397) {
l = decode_rfc3397(NULL, 0, dl, data);
if (l < 1)
return l;
tmp = xmalloc(l);
decode_rfc3397(tmp, l, dl, data);
l = print_string(s, len, l - 1, (uint8_t *)tmp);
free(tmp);
return l;
}
if (type & RFC3361) {
if ((tmp = decode_rfc3361(dl, data)) == NULL)
return -1;
l = strlen(tmp);
l = print_string(s, len, l - 1, (uint8_t *)tmp);
free(tmp);
return l;
}
if (type & RFC3442)
return decode_rfc3442(s, len, dl, data);
if (type & RFC5969)
return decode_rfc5969(s, len, dl, data);
if (type & STRING) {
/* Some DHCP servers return NULL strings */
if (*data == '\0')
return 0;
return print_string(s, len, dl, data);
}
/* DHCPv6 status code */
if (type & SCODE && dl >= (int)sizeof(u16)) {
if (s) {
memcpy(&u16, data, sizeof(u16));
u16 = ntohs(u16);
l = snprintf(s, len, "%d ", u16);
len -= l;
} else
l = 7;
data += sizeof(u16);
dl -= sizeof(u16);
if (dl)
l += print_option(s, len, STRING, dl, data, ifname);
return l;
}
if (!s) {
if (type & UINT8)
l = 3;
else if (type & UINT16) {
l = 5;
dl /= 2;
} else if (type & SINT16) {
l = 6;
dl /= 2;
} else if (type & UINT32) {
l = 10;
dl /= 4;
} else if (type & SINT32) {
l = 11;
dl /= 4;
} else if (type & ADDRIPV4) {
l = 16;
dl /= 4;
} else if (type & ADDRIPV6) {
e = data + dl;
l = 0;
while (data < e) {
if (l)
l++; /* space */
dl = ipv6_printaddr(NULL, 0, data, ifname);
if (dl != -1)
l += dl;
data += 16;
}
return l + 1;
} else if (type & BINHEX) {
l = 2;
} else {
errno = EINVAL;
return -1;
}
return (l + 1) * dl;
}
t = data;
e = data + dl;
while (data < e) {
if (data != t && type != BINHEX) {
*s++ = ' ';
bytes++;
len--;
}
if (type & UINT8) {
l = snprintf(s, len, "%d", *data);
data++;
} else if (type & UINT16) {
memcpy(&u16, data, sizeof(u16));
u16 = ntohs(u16);
l = snprintf(s, len, "%d", u16);
data += sizeof(u16);
} else if (type & SINT16) {
memcpy(&s16, data, sizeof(s16));
s16 = ntohs(s16);
l = snprintf(s, len, "%d", s16);
data += sizeof(s16);
} else if (type & UINT32) {
memcpy(&u32, data, sizeof(u32));
u32 = ntohl(u32);
l = snprintf(s, len, "%d", u32);
data += sizeof(u32);
} else if (type & SINT32) {
memcpy(&s32, data, sizeof(s32));
s32 = ntohl(s32);
l = snprintf(s, len, "%d", s32);
data += sizeof(s32);
} else if (type & ADDRIPV4) {
memcpy(&addr.s_addr, data, sizeof(addr.s_addr));
l = snprintf(s, len, "%s", inet_ntoa(addr));
data += sizeof(addr.s_addr);
} else if (type & ADDRIPV6) {
dl = ipv6_printaddr(s, len, data, ifname);
if (dl != -1)
l = dl;
else
l = 0;
data += 16;
} else if (type & BINHEX) {
l = snprintf(s, len, "%.2x", data[0]);
data++;
} else
l = 0;
len -= l;
bytes += l;
s += l;
}
return bytes;
}

74
dhcp-common.h Normal file
View File

@ -0,0 +1,74 @@
/*
* dhcpcd - DHCP client daemon
* Copyright (c) 2006-2012 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 DHCPCOMMON_H
#define DHCPCOMMON_H
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdint.h>
#include "common.h"
/* Max MTU - defines dhcp option length */
#define MTU_MAX 1500
#define MTU_MIN 576
#define REQUEST (1 << 0)
#define UINT8 (1 << 1)
#define UINT16 (1 << 2)
#define SINT16 (1 << 3)
#define UINT32 (1 << 4)
#define SINT32 (1 << 5)
#define ADDRIPV4 (1 << 6)
#define STRING (1 << 7)
#define PAIR (1 << 8)
#define ARRAY (1 << 9)
#define RFC3361 (1 << 10)
#define RFC3397 (1 << 11)
#define RFC3442 (1 << 12)
#define RFC5969 (1 << 13)
#define ADDRIPV6 (1 << 14)
#define BINHEX (1 << 15)
#define SCODE (1 << 16)
struct dhcp_opt {
uint16_t option;
int type;
const char *var;
};
#define add_option_mask(var, val) (var[val >> 3] |= 1 << (val & 7))
#define del_option_mask(var, val) (var[val >> 3] &= ~(1 << (val & 7)))
#define has_option_mask(var, val) (var[val >> 3] & (1 << (val & 7)))
int make_option_mask(const struct dhcp_opt *,uint8_t *, const char *, int);
ssize_t decode_rfc3397(char *, ssize_t, int, const uint8_t *);
ssize_t print_string(char *, ssize_t, int, const uint8_t *);
ssize_t print_option(char *, ssize_t, int, int, const uint8_t *, const char *);
#endif

1479
dhcp.c

File diff suppressed because it is too large Load Diff

57
dhcp.h
View File

@ -1,6 +1,6 @@
/*
* dhcpcd - DHCP client daemon
* Copyright (c) 2006-2012 Roy Marples <roy@marples.name>
* Copyright (c) 2006-2013 Roy Marples <roy@marples.name>
* All rights reserved
* Redistribution and use in source and binary forms, with or without
@ -34,10 +34,7 @@
#include <stdint.h>
#include "common.h"
/* Max MTU - defines dhcp option length */
#define MTU_MAX 1500
#define MTU_MIN 576
#include "dhcp-common.h"
/* UDP port numbers for DHCP */
#define DHCP_SERVER_PORT 67
@ -114,26 +111,6 @@ enum DHO {
DHO_END = 255
};
#define REQUEST (1 << 0)
#define UINT8 (1 << 1)
#define UINT16 (1 << 2)
#define SINT16 (1 << 3)
#define UINT32 (1 << 4)
#define SINT32 (1 << 5)
#define IPV4 (1 << 6)
#define STRING (1 << 7)
#define PAIR (1 << 8)
#define ARRAY (1 << 9)
#define RFC3361 (1 << 10)
#define RFC3397 (1 << 11)
#define RFC3442 (1 << 12)
#define RFC5969 (1 << 13)
#define IPV6 (1 << 14)
#define BINHEX (1 << 15)
#define SCODE (1 << 16)
#define IPV4R IPV4 | REQUEST
/* FQDN values - lsnybble used in flags
* hsnybble to create order
* and to allow 0x00 to mean disable
@ -193,18 +170,12 @@ struct dhcp_lease {
#include "if-options.h"
#include "net.h"
struct dhcp_opt {
uint16_t option;
int type;
const char *var;
};
extern const struct dhcp_opt const dhcp_opts[];
#define add_option_mask(var, val) (var[val >> 3] |= 1 << (val & 7))
#define del_option_mask(var, val) (var[val >> 3] &= ~(1 << (val & 7)))
#define has_option_mask(var, val) (var[val >> 3] & (1 << (val & 7)))
int make_option_mask(const struct dhcp_opt *,uint8_t *, const char *, int);
char *decode_rfc3361(int dl, const uint8_t *data);
ssize_t decode_rfc3442(char *out, ssize_t len, int pl, const uint8_t *p);
ssize_t decode_rfc5969(char *out, ssize_t len, int pl, const uint8_t *p);
void print_options(void);
char *get_option_string(const struct dhcp_message *, uint8_t);
int get_option_addr(struct in_addr *, const struct dhcp_message *, uint8_t);
@ -215,12 +186,12 @@ int get_option_uint8(uint8_t *, const struct dhcp_message *, uint8_t);
!IN_LINKLOCAL(htonl((m)->yiaddr)) && \
get_option_uint8(NULL, m, DHO_MESSAGETYPE) == -1)
struct rt *get_option_routes(struct interface *, const struct dhcp_message *);
ssize_t decode_rfc3397(char *, ssize_t, int, const uint8_t *);
ssize_t print_string(char *, ssize_t, int, const uint8_t *);
ssize_t print_option(char *, ssize_t, int, int, const uint8_t *, const char *);
ssize_t configure_env(char **, const char *, const struct dhcp_message *,
const struct interface *);
uint32_t dhcp_xid(const struct interface *);
struct dhcp_message *dhcp_message_new(struct in_addr *addr,
struct in_addr *mask);
int dhcp_message_add_addr(struct dhcp_message *, uint8_t, struct in_addr);
ssize_t make_message(struct dhcp_message **, const struct interface *,
uint8_t);
@ -230,4 +201,14 @@ ssize_t write_lease(const struct interface *, const struct dhcp_message *);
struct dhcp_message *read_lease(const struct interface *);
void get_lease(struct dhcp_lease *, const struct dhcp_message *);
void dhcp_drop(struct interface *, const char *);
void dhcp_start(struct interface *);
void dhcp_stop(struct interface *);
void dhcp_decline(struct interface *);
void dhcp_discover(void *);
void dhcp_inform(struct interface *);
void dhcp_release(struct interface *);
void dhcp_bind(void *);
void dhcp_close(struct interface *);
#endif

28
dhcp6.c
View File

@ -1,6 +1,6 @@
/*
* dhcpcd - DHCP client daemon
* Copyright (c) 2006-2012 Roy Marples <roy@marples.name>
* Copyright (c) 2006-2013 Roy Marples <roy@marples.name>
* All rights reserved
* Redistribution and use in source and binary forms, with or without
@ -44,16 +44,15 @@
#define ELOOP_QUEUE 2
#include "bind.h"
#include "config.h"
#include "common.h"
#include "configure.h"
#include "dhcp.h"
#include "dhcp6.h"
#include "duid.h"
#include "eloop.h"
#include "ipv6rs.h"
#include "platform.h"
#include "script.h"
#ifndef __UNCONST
#define __UNCONST(a) ((void *)(unsigned long)(const void *)(a))
@ -95,26 +94,27 @@ static const struct dhcp6_op dhcp6_ops[] = {
{ 0, NULL }
};
#define IPV6A ADDRIPV6 | ARRAY
const struct dhcp_opt const dhcp6_opts[] = {
{ D6_OPTION_CLIENTID, BINHEX, "client_id" },
{ D6_OPTION_SERVERID, BINHEX, "server_id" },
{ D6_OPTION_IA_ADDR, IPV6 | ARRAY, "ia_addr" },
{ D6_OPTION_IA_ADDR, IPV6A, "ia_addr" },
{ D6_OPTION_PREFERENCE, UINT8, "preference" },
{ D6_OPTION_RAPID_COMMIT, 0, "rapid_commit" },
{ D6_OPTION_UNICAST, IPV6, "unicast" },
{ D6_OPTION_UNICAST, ADDRIPV6, "unicast" },
{ D6_OPTION_STATUS_CODE, SCODE, "status_code" },
{ D6_OPTION_SIP_SERVERS_NAME, RFC3397, "sip_servers_names" },
{ D6_OPTION_SIP_SERVERS_ADDRESS,IPV6 | ARRAY, "sip_servers_addresses" },
{ D6_OPTION_DNS_SERVERS, IPV6 | ARRAY, "name_servers" },
{ D6_OPTION_SIP_SERVERS_ADDRESS,IPV6A, "sip_servers_addresses" },
{ D6_OPTION_DNS_SERVERS, IPV6A, "name_servers" },
{ D6_OPTION_DOMAIN_LIST, RFC3397, "domain_search" },
{ D6_OPTION_NIS_SERVERS, IPV6 | ARRAY, "nis_servers" },
{ D6_OPTION_NISP_SERVERS, IPV6 | ARRAY, "nisp_servers" },
{ D6_OPTION_NIS_SERVERS, IPV6A, "nis_servers" },
{ D6_OPTION_NISP_SERVERS, IPV6A, "nisp_servers" },
{ D6_OPTION_NIS_DOMAIN_NAME, RFC3397, "nis_domain_name" },
{ D6_OPTION_NISP_DOMAIN_NAME, RFC3397, "nisp_domain_name" },
{ D6_OPTION_SNTP_SERVERS, IPV6 | ARRAY, "sntp_servers" },
{ D6_OPTION_SNTP_SERVERS, IPV6A, "sntp_servers" },
{ D6_OPTION_INFO_REFRESH_TIME, UINT32, "info_refresh_time" },
{ D6_OPTION_BCMS_SERVER_D, RFC3397, "bcms_server_d" },
{ D6_OPTION_BCMS_SERVER_A, IPV6 | ARRAY, "bcms_server_a" },
{ D6_OPTION_BCMS_SERVER_A, IPV6A, "bcms_server_a" },
{ 0, 0, NULL }
};
@ -875,7 +875,7 @@ dhcp6_startexpire(void *arg)
syslog(LOG_ERR, "%s: DHCPv6 lease expired", ifp->name);
dhcp6_freedrop_addrs(ifp, 1);
run_script_reason(ifp, "EXPIRE6");
script_runreason(ifp, "EXPIRE6");
state = D6_CSTATE(ifp);
unlink(state->leasefile);
dhcp6_startdiscover(ifp);
@ -1390,7 +1390,7 @@ recv:
dhcp6_writelease(ifp);
}
run_script_reason(ifp, options & DHCPCD_TEST ? "TEST" : reason);
script_runreason(ifp, options & DHCPCD_TEST ? "TEST" : reason);
if (options & DHCPCD_TEST ||
(ifp->state->options->options & DHCPCD_INFORM &&
!(options & DHCPCD_MASTER)))
@ -1527,7 +1527,7 @@ dhcp6_freedrop(struct interface *ifp, int drop, const char *reason)
if (drop && state->new) {
if (reason == NULL)
reason = "STOP6";
run_script_reason(ifp, reason);
script_runreason(ifp, reason);
}
free(state->send);
free(state->recv);

1035
dhcpcd.c

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
/*
* dhcpcd - DHCP client daemon
* Copyright (c) 2006-2012 Roy Marples <roy@marples.name>
* Copyright (c) 2006-2013 Roy Marples <roy@marples.name>
* All rights reserved
* Redistribution and use in source and binary forms, with or without
@ -128,27 +128,16 @@ extern int ifdc;
extern char **ifdv;
extern struct interface *ifaces;
pid_t daemonise(void);
struct interface *find_interface(const char *);
int handle_args(struct fd_list *, int, char **);
void handle_carrier(int, int, const char *);
void handle_interface(int, const char *);
void handle_hwaddr(const char *, unsigned char *, size_t);
void handle_ifa(int, const char *,
struct in_addr *, struct in_addr *, struct in_addr *);
void handle_exit_timeout(void *);
void handle_signal(int);
void start_interface(void *);
void start_discover(void *);
void start_request(void *);
void start_renew(void *);
void start_rebind(void *);
void start_reboot(struct interface *);
void start_expire(void *);
void send_decline(struct interface *);
int open_sockets(struct interface *);
void close_sockets(struct interface *);
void drop_dhcp(struct interface *, const char *);
void drop_interface(struct interface *, const char *);
int select_profile(struct interface *, const char *);
void start_interface(void *);
#endif

View File

@ -1,6 +1,6 @@
/*
* dhcpcd - DHCP client daemon
* Copyright (c) 2006-2011 Roy Marples <roy@marples.name>
* Copyright (c) 2006-2013 Roy Marples <roy@marples.name>
* All rights reserved
* Redistribution and use in source and binary forms, with or without
@ -57,8 +57,8 @@
#include "config.h"
#include "common.h"
#include "configure.h"
#include "dhcp.h"
#include "ipv4.h"
#include "ipv6.h"
#include "net.h"
@ -294,7 +294,7 @@ link_route(struct nlmsghdr *nlm)
if (rt.iface != NULL) {
if (metric == rt.iface->metric) {
inet_cidrtoaddr(rtm->rtm_dst_len, &rt.net);
route_deleted(&rt);
ipv4_routedeleted(&rt);
}
}
return 1;
@ -346,7 +346,7 @@ link_addr(struct nlmsghdr *nlm)
}
rta = RTA_NEXT(rta, len);
}
handle_ifa(nlm->nlmsg_type, ifn, &addr, &net, &dest);
ipv4_handleifa(nlm->nlmsg_type, ifn, &addr, &net, &dest);
return 1;
}

View File

@ -25,18 +25,16 @@
* SUCH DAMAGE.
*/
#include <sys/stat.h>
#include <sys/uio.h>
#include <sys/wait.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#ifdef __linux__
# include <asm/types.h> /* for systems with broken headers */
# include <linux/rtnetlink.h>
#endif
#include <ctype.h>
#include <errno.h>
#include <signal.h>
/* We can't include spawn.h here because it may not exist.
* config.h will pull it in, or our compat one. */
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
@ -44,433 +42,15 @@
#include "config.h"
#include "common.h"
#include "configure.h"
#include "dhcp.h"
#include "dhcp6.h"
#include "if-options.h"
#include "if-pref.h"
#include "ipv6rs.h"
#include "ipv4.h"
#include "net.h"
#include "signals.h"
#define DEFAULT_PATH "PATH=/usr/bin:/usr/sbin:/bin:/sbin"
#include "script.h"
static struct rt *routes;
static const char *if_params[] = {
"interface",
"reason",
"pid",
"ifmetric",
"ifwireless",
"ifflags",
"ssid",
"profile",
"interface_order",
NULL
};
void
if_printoptions(void)
{
const char **p;
for (p = if_params; *p; p++)
printf(" - %s\n", *p);
}
static int
exec_script(char *const *argv, char *const *env)
{
pid_t pid;
posix_spawnattr_t attr;
short flags;
sigset_t defsigs;
int i;
/* posix_spawn is a safe way of executing another image
* and changing signals back to how they should be. */
if (posix_spawnattr_init(&attr) == -1)
return -1;
flags = POSIX_SPAWN_SETSIGMASK | POSIX_SPAWN_SETSIGDEF;
posix_spawnattr_setflags(&attr, flags);
sigemptyset(&defsigs);
for (i = 0; i < handle_sigs[i]; i++)
sigaddset(&defsigs, handle_sigs[i]);
posix_spawnattr_setsigdefault(&attr, &defsigs);
posix_spawnattr_setsigmask(&attr, &dhcpcd_sigset);
errno = 0;
i = posix_spawn(&pid, argv[0], NULL, &attr, argv, env);
if (i) {
errno = i;
return -1;
}
return pid;
}
static char *
make_var(const char *prefix, const char *var)
{
size_t len;
char *v;
len = strlen(prefix) + strlen(var) + 2;
v = xmalloc(len);
snprintf(v, len, "%s_%s", prefix, var);
return v;
}
static void
append_config(char ***env, ssize_t *len,
const char *prefix, const char *const *config)
{
ssize_t i, j, e1;
char **ne, *eq;
if (config == NULL)
return;
ne = *env;
for (i = 0; config[i] != NULL; i++) {
eq = strchr(config[i], '=');
e1 = eq - config[i] + 1;
for (j = 0; j < *len; j++) {
if (strncmp(ne[j] + strlen(prefix) + 1,
config[i], e1) == 0)
{
free(ne[j]);
ne[j] = make_var(prefix, config[i]);
break;
}
}
if (j == *len) {
j++;
ne = xrealloc(ne, sizeof(char *) * (j + 1));
ne[j - 1] = make_var(prefix, config[i]);
*len = j;
}
}
*env = ne;
}
static size_t
arraytostr(const char *const *argv, char **s)
{
const char *const *ap;
char *p;
size_t len, l;
len = 0;
ap = argv;
while (*ap)
len += strlen(*ap++) + 1;
*s = p = xmalloc(len);
ap = argv;
while (*ap) {
l = strlen(*ap) + 1;
memcpy(p, *ap, l);
p += l;
ap++;
}
return len;
}
static ssize_t
make_env(const struct interface *iface, const char *reason, char ***argv)
{
char **env, *p;
ssize_t e, elen, l;
const struct if_options *ifo = iface->state->options;
const struct interface *ifp;
int dhcp, dhcp6, ra;
const struct dhcp6_state *d6_state;
dhcp = dhcp6 = ra = 0;
d6_state = D6_STATE(iface);
if (strcmp(reason, "TEST") == 0) {
if (d6_state && d6_state->new)
dhcp6 = 1;
else if (ipv6rs_has_ra(iface))
ra = 1;
else
dhcp = 1;
} else if (reason[strlen(reason) - 1] == '6')
dhcp6 = 1;
else if (strcmp(reason, "ROUTERADVERT") == 0)
ra = 1;
else
dhcp = 1;
/* When dumping the lease, we only want to report interface and
reason - the other interface variables are meaningless */
if (options & DHCPCD_DUMPLEASE)
elen = 2;
else
elen = 10;
/* Make our env */
env = xmalloc(sizeof(char *) * (elen + 1));
e = strlen("interface") + strlen(iface->name) + 2;
env[0] = xmalloc(e);
snprintf(env[0], e, "interface=%s", iface->name);
e = strlen("reason") + strlen(reason) + 2;
env[1] = xmalloc(e);
snprintf(env[1], e, "reason=%s", reason);
if (options & DHCPCD_DUMPLEASE)
goto dumplease;
e = 20;
env[2] = xmalloc(e);
snprintf(env[2], e, "pid=%d", getpid());
env[3] = xmalloc(e);
snprintf(env[3], e, "ifmetric=%d", iface->metric);
env[4] = xmalloc(e);
snprintf(env[4], e, "ifwireless=%d", iface->wireless);
env[5] = xmalloc(e);
snprintf(env[5], e, "ifflags=%u", iface->flags);
env[6] = xmalloc(e);
snprintf(env[6], e, "ifmtu=%d", get_mtu(iface->name));
l = e = strlen("interface_order=");
for (ifp = ifaces; ifp; ifp = ifp->next)
e += strlen(ifp->name) + 1;
p = env[7] = xmalloc(e);
strlcpy(p, "interface_order=", e);
e -= l;
p += l;
for (ifp = ifaces; ifp; ifp = ifp->next) {
l = strlcpy(p, ifp->name, e);
p += l;
e -= l;
*p++ = ' ';
e--;
}
*--p = '\0';
if (strcmp(reason, "TEST") == 0) {
env[8] = strdup("if_up=false");
env[9] = strdup("if_down=false");
} else if ((dhcp && iface->state->new) ||
(dhcp6 && d6_state->new) ||
(ra && ipv6rs_has_ra(iface)))
{
env[8] = strdup("if_up=true");
env[9] = strdup("if_down=false");
} else {
env[8] = strdup("if_up=false");
env[9] = strdup("if_down=true");
}
if (*iface->state->profile) {
e = strlen("profile=") + strlen(iface->state->profile) + 2;
env[elen] = xmalloc(e);
snprintf(env[elen++], e, "profile=%s", iface->state->profile);
}
if (iface->wireless) {
e = strlen("new_ssid=") + strlen(iface->ssid) + 2;
if (iface->state->new != NULL ||
strcmp(iface->state->reason, "CARRIER") == 0)
{
env = xrealloc(env, sizeof(char *) * (elen + 2));
env[elen] = xmalloc(e);
snprintf(env[elen++], e, "new_ssid=%s", iface->ssid);
}
if (iface->state->old != NULL ||
strcmp(iface->state->reason, "NOCARRIER") == 0)
{
env = xrealloc(env, sizeof(char *) * (elen + 2));
env[elen] = xmalloc(e);
snprintf(env[elen++], e, "old_ssid=%s", iface->ssid);
}
}
if (dhcp && iface->state->old) {
e = configure_env(NULL, NULL, iface->state->old, iface);
if (e > 0) {
env = xrealloc(env, sizeof(char *) * (elen + e + 1));
elen += configure_env(env + elen, "old",
iface->state->old, iface);
}
append_config(&env, &elen, "old",
(const char *const *)ifo->config);
}
if (dhcp6 && d6_state->old) {
e = dhcp6_env(NULL, NULL, iface,
d6_state->old, d6_state->old_len);
if (e > 0) {
env = xrealloc(env, sizeof(char *) * (elen + e + 1));
elen += dhcp6_env(env + elen, "old", iface,
d6_state->old, d6_state->old_len);
}
}
dumplease:
if (dhcp && iface->state->new) {
e = configure_env(NULL, NULL, iface->state->new, iface);
if (e > 0) {
env = xrealloc(env, sizeof(char *) * (elen + e + 1));
elen += configure_env(env + elen, "new",
iface->state->new, iface);
}
append_config(&env, &elen, "new",
(const char *const *)ifo->config);
}
if (dhcp6 && d6_state->new) {
e = dhcp6_env(NULL, NULL, iface,
d6_state->new, d6_state->new_len);
if (e > 0) {
env = xrealloc(env, sizeof(char *) * (elen + e + 1));
elen += dhcp6_env(env + elen, "new", iface,
d6_state->new, d6_state->new_len);
}
}
if (ra) {
e = ipv6rs_env(NULL, NULL, iface);
if (e > 0) {
env = xrealloc(env, sizeof(char *) * (elen + e + 1));
elen += ipv6rs_env(env + elen, NULL, iface);
}
}
/* Add our base environment */
if (ifo->environ) {
e = 0;
while (ifo->environ[e++])
;
env = xrealloc(env, sizeof(char *) * (elen + e + 1));
e = 0;
while (ifo->environ[e]) {
env[elen + e] = xstrdup(ifo->environ[e]);
e++;
}
elen += e;
}
env[elen] = '\0';
*argv = env;
return elen;
}
static int
send_interface1(int fd, const struct interface *iface, const char *reason)
{
char **env, **ep, *s;
ssize_t elen;
struct iovec iov[2];
int retval;
make_env(iface, reason, &env);
elen = arraytostr((const char *const *)env, &s);
iov[0].iov_base = &elen;
iov[0].iov_len = sizeof(ssize_t);
iov[1].iov_base = s;
iov[1].iov_len = elen;
retval = writev(fd, iov, 2);
ep = env;
while (*ep)
free(*ep++);
free(env);
free(s);
return retval;
}
int
send_interface(int fd, const struct interface *iface)
{
int retval = 0;
if (send_interface1(fd, iface, iface->state->reason) == -1)
retval = -1;
if (ipv6rs_has_ra(iface)) {
if (send_interface1(fd, iface, "ROUTERADVERT") == -1)
retval = -1;
}
if (D6_STATE_RUNNING(iface)) {
if (send_interface1(fd, iface, "INFORM6") == -1)
retval = -1;
}
return retval;
}
int
run_script_reason(const struct interface *iface, const char *reason)
{
char *const argv[2] = { UNCONST(iface->state->options->script), NULL };
char **env = NULL, **ep;
char *path, *bigenv;
ssize_t e, elen = 0;
pid_t pid;
int status = 0;
const struct fd_list *fd;
struct iovec iov[2];
if (iface->state->options->script == NULL ||
iface->state->options->script[0] == '\0' ||
strcmp(iface->state->options->script, "/dev/null") == 0)
return 0;
if (reason == NULL)
reason = iface->state->reason;
syslog(LOG_DEBUG, "%s: executing `%s', reason %s",
iface->name, argv[0], reason);
/* Make our env */
elen = make_env(iface, reason, &env);
env = xrealloc(env, sizeof(char *) * (elen + 2));
/* Add path to it */
path = getenv("PATH");
if (path) {
e = strlen("PATH") + strlen(path) + 2;
env[elen] = xmalloc(e);
snprintf(env[elen], e, "PATH=%s", path);
} else
env[elen] = xstrdup(DEFAULT_PATH);
env[++elen] = '\0';
pid = exec_script(argv, env);
if (pid == -1)
syslog(LOG_ERR, "exec_script: %s: %m", argv[0]);
else if (pid != 0) {
/* Wait for the script to finish */
while (waitpid(pid, &status, 0) == -1) {
if (errno != EINTR) {
syslog(LOG_ERR, "waitpid: %m");
status = 0;
break;
}
}
if (WIFEXITED(status)) {
if (WEXITSTATUS(status))
syslog(LOG_ERR,
"exec_script: %s: WEXITSTATUS %d",
argv[0], WEXITSTATUS(status));
} else if (WIFSIGNALED(status))
syslog(LOG_ERR, "exec_sript: %s: %s",
argv[0], strsignal(WTERMSIG(status)));
}
/* Send to our listeners */
bigenv = NULL;
for (fd = control_fds; fd != NULL; fd = fd->next) {
if (fd->listener) {
if (bigenv == NULL) {
elen = arraytostr((const char *const *)env,
&bigenv);
iov[0].iov_base = &elen;
iov[0].iov_len = sizeof(ssize_t);
iov[1].iov_base = bigenv;
iov[1].iov_len = elen;
}
if (writev(fd->fd, iov, 2) == -1)
syslog(LOG_ERR, "writev: %m");
}
}
free(bigenv);
/* Cleanup */
ep = env;
while (*ep)
free(*ep++);
free(env);
return WEXITSTATUS(status);
}
static struct rt *
find_route(struct rt *rts, const struct rt *r, struct rt **lrt,
const struct rt *srt)
@ -519,7 +99,7 @@ desc_route(const char *cmd, const struct rt *rt)
/* If something other than dhcpcd removes a route,
* we need to remove it from our internal table. */
int
route_deleted(const struct rt *rt)
ipv4_routedeleted(const struct rt *rt)
{
struct rt *f, *l;
@ -636,12 +216,12 @@ add_subnet_route(struct rt *rt, const struct interface *iface)
}
static struct rt *
get_routes(struct interface *iface)
get_routes(struct interface *ifp)
{
struct rt *rt, *nrt = NULL, *r = NULL;
if (iface->state->options->routes != NULL) {
for (rt = iface->state->options->routes;
if (ifp->state->options->routes != NULL) {
for (rt = ifp->state->options->routes;
rt != NULL;
rt = rt->next)
{
@ -659,7 +239,7 @@ get_routes(struct interface *iface)
return nrt;
}
return get_option_routes(iface, iface->state->new);
return get_option_routes(ifp, ifp->state->new);
}
/* Some DHCP servers add set host routes by setting the gateway
@ -746,7 +326,7 @@ add_router_host_route(struct rt *rt, const struct interface *ifp)
}
void
build_routes(void)
ipv4_buildroutes(void)
{
struct rt *nrs = NULL, *dnr, *or, *rt, *rtn, *rtl, *lrt = NULL;
struct interface *ifp;
@ -830,9 +410,10 @@ delete_address(struct interface *iface)
return retval;
}
int
configure(struct interface *iface)
void
ipv4_applyaddr(void *arg)
{
struct interface *iface = arg;
struct dhcp_message *dhcp = iface->state->new;
struct dhcp_lease *lease = &iface->state->lease;
struct if_options *ifo = iface->state->options;
@ -844,12 +425,12 @@ configure(struct interface *iface)
if (dhcp == NULL) {
if (!(ifo->options & DHCPCD_PERSISTENT)) {
build_routes();
ipv4_buildroutes();
if (iface->addr.s_addr != 0)
delete_address(iface);
run_script(iface);
script_run(iface);
}
return 0;
return;
}
/* This also changes netmask */
@ -863,8 +444,8 @@ configure(struct interface *iface)
&lease->addr, &lease->net, &lease->brd) == -1 &&
errno != EEXIST)
{
syslog(LOG_ERR, "add_address: %m");
return -1;
syslog(LOG_ERR, "%s: add_address: %m", __func__);
return;
}
}
@ -887,11 +468,66 @@ configure(struct interface *iface)
free(rt);
}
build_routes();
ipv4_buildroutes();
if (!iface->state->lease.frominfo &&
!(ifo->options & (DHCPCD_INFORM | DHCPCD_STATIC)))
if (write_lease(iface, dhcp) == -1)
syslog(LOG_ERR, "write_lease: %m");
run_script(iface);
return 0;
syslog(LOG_ERR, "%s: write_lease: %m", __func__);
script_run(iface);
}
void
ipv4_handleifa(int type, const char *ifname,
struct in_addr *addr, struct in_addr *net, struct in_addr *dst)
{
struct interface *ifp;
struct if_options *ifo;
int i;
if (addr->s_addr == INADDR_ANY)
return;
for (ifp = ifaces; ifp; ifp = ifp->next)
if (strcmp(ifp->name, ifname) == 0)
break;
if (ifp == NULL)
return;
if (type == RTM_DELADDR) {
if (ifp->state->new &&
ifp->state->new->yiaddr == addr->s_addr)
syslog(LOG_INFO, "%s: removing IP address %s/%d",
ifp->name, inet_ntoa(ifp->state->lease.addr),
inet_ntocidr(ifp->state->lease.net));
return;
}
if (type != RTM_NEWADDR)
return;
ifo = ifp->state->options;
if ((ifo->options & (DHCPCD_INFORM | DHCPCD_STATIC)) == 0 ||
ifo->req_addr.s_addr != INADDR_ANY)
return;
free(ifp->state->old);
ifp->state->old = ifp->state->new;
ifp->state->new = dhcp_message_new(addr, net);
ifp->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(ifp->state->new, i, *dst);
}
ifp->state->reason = "STATIC";
ipv4_buildroutes();
script_run(ifp);
if (ifo->options & DHCPCD_INFORM) {
ifp->state->state = DHS_INFORM;
ifp->state->xid = dhcp_xid(ifp);
ifp->state->lease.server.s_addr =
dst ? dst->s_addr : INADDR_ANY;
ifp->addr = *addr;
ifp->net = *net;
dhcp_inform(ifp);
}
}

View File

@ -1,6 +1,6 @@
/*
* dhcpcd - DHCP client daemon
* Copyright (c) 2006-2008 Roy Marples <roy@marples.name>
* Copyright (c) 2006-2013 Roy Marples <roy@marples.name>
* All rights reserved
* Redistribution and use in source and binary forms, with or without
@ -25,15 +25,15 @@
* SUCH DAMAGE.
*/
#ifndef BIND_H
#define BIND_H
#ifndef IPV4_H
#define IPV4_H
#include "config.h"
#ifdef THERE_IS_NO_FORK
# define daemonise() {}
#else
pid_t daemonise(void);
#endif
#include "net.h"
void bind_interface(void *);
void ipv4_buildroutes(void);
void ipv4_applyaddr(void *);
int ipv4_routedeleted(const struct rt *);
void ipv4_handleifa(int, const char *,
struct in_addr *, struct in_addr *, struct in_addr *);
#endif

View File

@ -1,6 +1,6 @@
/*
* dhcpcd - DHCP client daemon
* Copyright (c) 2006-2012 Roy Marples <roy@marples.name>
* Copyright (c) 2006-2013 Roy Marples <roy@marples.name>
* All rights reserved
* Redistribution and use in source and binary forms, with or without
@ -94,7 +94,7 @@ ipv4ll_start(void *arg)
if (ifp->addr.s_addr) {
ifp->state->conflicts = 0;
if (IN_LINKLOCAL(htonl(ifp->addr.s_addr))) {
send_arp_announce(ifp);
arp_announce(ifp);
return;
}
}
@ -116,7 +116,7 @@ ipv4ll_start(void *arg)
else
ifp->state->offer = ipv4ll_make_lease(addr);
ifp->state->lease.frominfo = 0;
send_arp_probe(ifp);
arp_probe(ifp);
}
void
@ -131,7 +131,7 @@ ipv4ll_handle_failure(void *arg)
syslog(LOG_DEBUG,
"%s: IPv4LL %d second defence failed",
ifp->name, DEFEND_INTERVAL);
drop_dhcp(ifp, "EXPIRE");
dhcp_drop(ifp, "EXPIRE");
ifp->state->conflicts = -1;
} else {
syslog(LOG_DEBUG, "%s: defended IPv4LL address",
@ -141,7 +141,7 @@ ipv4ll_handle_failure(void *arg)
}
}
close_sockets(ifp);
dhcp_close(ifp);
free(ifp->state->offer);
ifp->state->offer = NULL;
eloop_timeout_delete(NULL, ifp);
@ -149,7 +149,7 @@ ipv4ll_handle_failure(void *arg)
syslog(LOG_ERR, "%s: failed to acquire an IPv4LL address",
ifp->name);
ifp->state->interval = RATE_LIMIT_INTERVAL / 2;
start_discover(ifp);
dhcp_discover(ifp);
} else {
eloop_timeout_add_sec(PROBE_WAIT, ipv4ll_start, ifp);
}

3
ipv6.c
View File

@ -1,6 +1,6 @@
/*
* dhcpcd - DHCP client daemon
* Copyright (c) 2006-2012 Roy Marples <roy@marples.name>
* Copyright (c) 2006-2013 Roy Marples <roy@marples.name>
* All rights reserved
* Redistribution and use in source and binary forms, with or without
@ -37,7 +37,6 @@
#include <syslog.h>
#include "common.h"
#include "configure.h"
#include "dhcpcd.h"
#include "dhcp6.h"
#include "ipv6.h"

View File

@ -1,6 +1,6 @@
/*
* dhcpcd - DHCP client daemon
* Copyright (c) 2006-2012 Roy Marples <roy@marples.name>
* Copyright (c) 2006-2013 Roy Marples <roy@marples.name>
* All rights reserved
* Redistribution and use in source and binary forms, with or without
@ -47,11 +47,11 @@
#define ELOOP_QUEUE 1
#include "common.h"
#include "configure.h"
#include "dhcpcd.h"
#include "eloop.h"
#include "ipv6.h"
#include "ipv6ns.h"
#include "script.h"
#define MIN_RANDOM_FACTOR (500 * 1000) /* milliseconds in usecs */
#define MAX_RANDOM_FACTOR (1500 * 1000) /* milliseconds in usecs */
@ -169,7 +169,7 @@ ipv6ns_unreachable(void *arg)
rap->iface->name, rap->sfrom);
rap->expired = 1;
ipv6_buildroutes();
run_script_reason(rap->iface, "ROUTERADVERT"); /* XXX not RA */
script_runreason(rap->iface, "ROUTERADVERT"); /* XXX not RA */
}
void
@ -342,7 +342,7 @@ ipv6ns_handledata(_unused void *arg)
ifp->name, sfrom);
rap->expired = 1;
ipv6_buildroutes();
run_script_reason(ifp, "ROUTERADVERT");
script_runreason(ifp, "ROUTERADVERT");
return;
}

View File

@ -1,6 +1,6 @@
/*
* dhcpcd - DHCP client daemon
* Copyright (c) 2006-2012 Roy Marples <roy@marples.name>
* Copyright (c) 2006-2013 Roy Marples <roy@marples.name>
* All rights reserved
* Redistribution and use in source and binary forms, with or without
@ -45,15 +45,14 @@
#include <syslog.h>
#define ELOOP_QUEUE 1
#include "bind.h"
#include "common.h"
#include "configure.h"
#include "dhcpcd.h"
#include "dhcp6.h"
#include "eloop.h"
#include "ipv6.h"
#include "ipv6ns.h"
#include "ipv6rs.h"
#include "script.h"
/* Debugging Router Solicitations is a lot of spam, so disable it */
//#define DEBUG_RS
@ -756,13 +755,13 @@ ipv6rs_handledata(_unused void *arg)
if (options & DHCPCD_IPV6RA_OWN && !(options & DHCPCD_TEST))
ipv6_addaddrs(ifp, &rap->addrs);
if (options & DHCPCD_TEST) {
run_script_reason(ifp, "TEST");
script_runreason(ifp, "TEST");
goto handle_flag;
}
ipv6_buildroutes();
/* We will get run by the expire function */
if (rap->lifetime)
run_script_reason(ifp, "ROUTERADVERT");
script_runreason(ifp, "ROUTERADVERT");
/* If we don't require RDNSS then set has_dns = 1 so we fork */
if (!(ifp->state->options->options & DHCPCD_IPV6RA_REQRDNSS))
@ -1070,7 +1069,7 @@ ipv6rs_expire(void *arg)
eloop_timeout_add_tv(&next, ipv6rs_expire, ifp);
if (expired) {
ipv6_buildroutes();
run_script_reason(ifp, "ROUTERADVERT");
script_runreason(ifp, "ROUTERADVERT");
}
}
@ -1125,6 +1124,6 @@ ipv6rs_drop(struct interface *ifp)
ipv6rs_drop_ra(rap);
}
}
run_script_reason(ifp, "ROUTERADVERT");
script_runreason(ifp, "ROUTERADVERT");
}
}

470
script.c Normal file
View File

@ -0,0 +1,470 @@
/*
* 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/stat.h>
#include <sys/uio.h>
#include <sys/wait.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <ctype.h>
#include <errno.h>
#include <signal.h>
/* We can't include spawn.h here because it may not exist.
* config.h will pull it in, or our compat one. */
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
#include "config.h"
#include "common.h"
#include "dhcp.h"
#include "dhcp6.h"
#include "if-options.h"
#include "if-pref.h"
#include "ipv6rs.h"
#include "net.h"
#include "script.h"
#include "signals.h"
#define DEFAULT_PATH "PATH=/usr/bin:/usr/sbin:/bin:/sbin"
static const char *if_params[] = {
"interface",
"reason",
"pid",
"ifmetric",
"ifwireless",
"ifflags",
"ssid",
"profile",
"interface_order",
NULL
};
void
if_printoptions(void)
{
const char **p;
for (p = if_params; *p; p++)
printf(" - %s\n", *p);
}
static int
exec_script(char *const *argv, char *const *env)
{
pid_t pid;
posix_spawnattr_t attr;
short flags;
sigset_t defsigs;
int i;
/* posix_spawn is a safe way of executing another image
* and changing signals back to how they should be. */
if (posix_spawnattr_init(&attr) == -1)
return -1;
flags = POSIX_SPAWN_SETSIGMASK | POSIX_SPAWN_SETSIGDEF;
posix_spawnattr_setflags(&attr, flags);
sigemptyset(&defsigs);
for (i = 0; i < handle_sigs[i]; i++)
sigaddset(&defsigs, handle_sigs[i]);
posix_spawnattr_setsigdefault(&attr, &defsigs);
posix_spawnattr_setsigmask(&attr, &dhcpcd_sigset);
errno = 0;
i = posix_spawn(&pid, argv[0], NULL, &attr, argv, env);
if (i) {
errno = i;
return -1;
}
return pid;
}
static char *
make_var(const char *prefix, const char *var)
{
size_t len;
char *v;
len = strlen(prefix) + strlen(var) + 2;
v = xmalloc(len);
snprintf(v, len, "%s_%s", prefix, var);
return v;
}
static void
append_config(char ***env, ssize_t *len,
const char *prefix, const char *const *config)
{
ssize_t i, j, e1;
char **ne, *eq;
if (config == NULL)
return;
ne = *env;
for (i = 0; config[i] != NULL; i++) {
eq = strchr(config[i], '=');
e1 = eq - config[i] + 1;
for (j = 0; j < *len; j++) {
if (strncmp(ne[j] + strlen(prefix) + 1,
config[i], e1) == 0)
{
free(ne[j]);
ne[j] = make_var(prefix, config[i]);
break;
}
}
if (j == *len) {
j++;
ne = xrealloc(ne, sizeof(char *) * (j + 1));
ne[j - 1] = make_var(prefix, config[i]);
*len = j;
}
}
*env = ne;
}
static size_t
arraytostr(const char *const *argv, char **s)
{
const char *const *ap;
char *p;
size_t len, l;
len = 0;
ap = argv;
while (*ap)
len += strlen(*ap++) + 1;
*s = p = xmalloc(len);
ap = argv;
while (*ap) {
l = strlen(*ap) + 1;
memcpy(p, *ap, l);
p += l;
ap++;
}
return len;
}
static ssize_t
make_env(const struct interface *iface, const char *reason, char ***argv)
{
char **env, *p;
ssize_t e, elen, l;
const struct if_options *ifo = iface->state->options;
const struct interface *ifp;
int dhcp, dhcp6, ra;
const struct dhcp6_state *d6_state;
dhcp = dhcp6 = ra = 0;
d6_state = D6_STATE(iface);
if (strcmp(reason, "TEST") == 0) {
if (d6_state && d6_state->new)
dhcp6 = 1;
else if (ipv6rs_has_ra(iface))
ra = 1;
else
dhcp = 1;
} else if (reason[strlen(reason) - 1] == '6')
dhcp6 = 1;
else if (strcmp(reason, "ROUTERADVERT") == 0)
ra = 1;
else
dhcp = 1;
/* When dumping the lease, we only want to report interface and
reason - the other interface variables are meaningless */
if (options & DHCPCD_DUMPLEASE)
elen = 2;
else
elen = 10;
/* Make our env */
env = xmalloc(sizeof(char *) * (elen + 1));
e = strlen("interface") + strlen(iface->name) + 2;
env[0] = xmalloc(e);
snprintf(env[0], e, "interface=%s", iface->name);
e = strlen("reason") + strlen(reason) + 2;
env[1] = xmalloc(e);
snprintf(env[1], e, "reason=%s", reason);
if (options & DHCPCD_DUMPLEASE)
goto dumplease;
e = 20;
env[2] = xmalloc(e);
snprintf(env[2], e, "pid=%d", getpid());
env[3] = xmalloc(e);
snprintf(env[3], e, "ifmetric=%d", iface->metric);
env[4] = xmalloc(e);
snprintf(env[4], e, "ifwireless=%d", iface->wireless);
env[5] = xmalloc(e);
snprintf(env[5], e, "ifflags=%u", iface->flags);
env[6] = xmalloc(e);
snprintf(env[6], e, "ifmtu=%d", get_mtu(iface->name));
l = e = strlen("interface_order=");
for (ifp = ifaces; ifp; ifp = ifp->next)
e += strlen(ifp->name) + 1;
p = env[7] = xmalloc(e);
strlcpy(p, "interface_order=", e);
e -= l;
p += l;
for (ifp = ifaces; ifp; ifp = ifp->next) {
l = strlcpy(p, ifp->name, e);
p += l;
e -= l;
*p++ = ' ';
e--;
}
*--p = '\0';
if (strcmp(reason, "TEST") == 0) {
env[8] = strdup("if_up=false");
env[9] = strdup("if_down=false");
} else if ((dhcp && iface->state->new) ||
(dhcp6 && d6_state->new) ||
(ra && ipv6rs_has_ra(iface)))
{
env[8] = strdup("if_up=true");
env[9] = strdup("if_down=false");
} else {
env[8] = strdup("if_up=false");
env[9] = strdup("if_down=true");
}
if (*iface->state->profile) {
e = strlen("profile=") + strlen(iface->state->profile) + 2;
env[elen] = xmalloc(e);
snprintf(env[elen++], e, "profile=%s", iface->state->profile);
}
if (iface->wireless) {
e = strlen("new_ssid=") + strlen(iface->ssid) + 2;
if (iface->state->new != NULL ||
strcmp(iface->state->reason, "CARRIER") == 0)
{
env = xrealloc(env, sizeof(char *) * (elen + 2));
env[elen] = xmalloc(e);
snprintf(env[elen++], e, "new_ssid=%s", iface->ssid);
}
if (iface->state->old != NULL ||
strcmp(iface->state->reason, "NOCARRIER") == 0)
{
env = xrealloc(env, sizeof(char *) * (elen + 2));
env[elen] = xmalloc(e);
snprintf(env[elen++], e, "old_ssid=%s", iface->ssid);
}
}
if (dhcp && iface->state->old) {
e = configure_env(NULL, NULL, iface->state->old, iface);
if (e > 0) {
env = xrealloc(env, sizeof(char *) * (elen + e + 1));
elen += configure_env(env + elen, "old",
iface->state->old, iface);
}
append_config(&env, &elen, "old",
(const char *const *)ifo->config);
}
if (dhcp6 && d6_state->old) {
e = dhcp6_env(NULL, NULL, iface,
d6_state->old, d6_state->old_len);
if (e > 0) {
env = xrealloc(env, sizeof(char *) * (elen + e + 1));
elen += dhcp6_env(env + elen, "old", iface,
d6_state->old, d6_state->old_len);
}
}
dumplease:
if (dhcp && iface->state->new) {
e = configure_env(NULL, NULL, iface->state->new, iface);
if (e > 0) {
env = xrealloc(env, sizeof(char *) * (elen + e + 1));
elen += configure_env(env + elen, "new",
iface->state->new, iface);
}
append_config(&env, &elen, "new",
(const char *const *)ifo->config);
}
if (dhcp6 && d6_state->new) {
e = dhcp6_env(NULL, NULL, iface,
d6_state->new, d6_state->new_len);
if (e > 0) {
env = xrealloc(env, sizeof(char *) * (elen + e + 1));
elen += dhcp6_env(env + elen, "new", iface,
d6_state->new, d6_state->new_len);
}
}
if (ra) {
e = ipv6rs_env(NULL, NULL, iface);
if (e > 0) {
env = xrealloc(env, sizeof(char *) * (elen + e + 1));
elen += ipv6rs_env(env + elen, NULL, iface);
}
}
/* Add our base environment */
if (ifo->environ) {
e = 0;
while (ifo->environ[e++])
;
env = xrealloc(env, sizeof(char *) * (elen + e + 1));
e = 0;
while (ifo->environ[e]) {
env[elen + e] = xstrdup(ifo->environ[e]);
e++;
}
elen += e;
}
env[elen] = '\0';
*argv = env;
return elen;
}
static int
send_interface1(int fd, const struct interface *iface, const char *reason)
{
char **env, **ep, *s;
ssize_t elen;
struct iovec iov[2];
int retval;
make_env(iface, reason, &env);
elen = arraytostr((const char *const *)env, &s);
iov[0].iov_base = &elen;
iov[0].iov_len = sizeof(ssize_t);
iov[1].iov_base = s;
iov[1].iov_len = elen;
retval = writev(fd, iov, 2);
ep = env;
while (*ep)
free(*ep++);
free(env);
free(s);
return retval;
}
int
send_interface(int fd, const struct interface *iface)
{
int retval = 0;
if (send_interface1(fd, iface, iface->state->reason) == -1)
retval = -1;
if (ipv6rs_has_ra(iface)) {
if (send_interface1(fd, iface, "ROUTERADVERT") == -1)
retval = -1;
}
if (D6_STATE_RUNNING(iface)) {
if (send_interface1(fd, iface, "INFORM6") == -1)
retval = -1;
}
return retval;
}
int
script_runreason(const struct interface *iface, const char *reason)
{
char *const argv[2] = { UNCONST(iface->state->options->script), NULL };
char **env = NULL, **ep;
char *path, *bigenv;
ssize_t e, elen = 0;
pid_t pid;
int status = 0;
const struct fd_list *fd;
struct iovec iov[2];
if (iface->state->options->script == NULL ||
iface->state->options->script[0] == '\0' ||
strcmp(iface->state->options->script, "/dev/null") == 0)
return 0;
if (reason == NULL)
reason = iface->state->reason;
syslog(LOG_DEBUG, "%s: executing `%s', reason %s",
iface->name, argv[0], reason);
/* Make our env */
elen = make_env(iface, reason, &env);
env = xrealloc(env, sizeof(char *) * (elen + 2));
/* Add path to it */
path = getenv("PATH");
if (path) {
e = strlen("PATH") + strlen(path) + 2;
env[elen] = xmalloc(e);
snprintf(env[elen], e, "PATH=%s", path);
} else
env[elen] = xstrdup(DEFAULT_PATH);
env[++elen] = '\0';
pid = exec_script(argv, env);
if (pid == -1)
syslog(LOG_ERR, "%s: %s: %m", __func__, argv[0]);
else if (pid != 0) {
/* Wait for the script to finish */
while (waitpid(pid, &status, 0) == -1) {
if (errno != EINTR) {
syslog(LOG_ERR, "waitpid: %m");
status = 0;
break;
}
}
if (WIFEXITED(status)) {
if (WEXITSTATUS(status))
syslog(LOG_ERR,
"%s: %s: WEXITSTATUS %d",
__func__, argv[0], WEXITSTATUS(status));
} else if (WIFSIGNALED(status))
syslog(LOG_ERR, "%s: %s: %s",
__func__, argv[0], strsignal(WTERMSIG(status)));
}
/* Send to our listeners */
bigenv = NULL;
for (fd = control_fds; fd != NULL; fd = fd->next) {
if (fd->listener) {
if (bigenv == NULL) {
elen = arraytostr((const char *const *)env,
&bigenv);
iov[0].iov_base = &elen;
iov[0].iov_len = sizeof(ssize_t);
iov[1].iov_base = bigenv;
iov[1].iov_len = elen;
}
if (writev(fd->fd, iov, 2) == -1)
syslog(LOG_ERR, "%s: writev: %m", __func__);
}
}
free(bigenv);
/* Cleanup */
ep = env;
while (*ep)
free(*ep++);
free(env);
return WEXITSTATUS(status);
}

View File

@ -1,6 +1,6 @@
/*
* dhcpcd - DHCP client daemon
* Copyright (c) 2006-2012 Roy Marples <roy@marples.name>
* Copyright (c) 2006-2013 Roy Marples <roy@marples.name>
* All rights reserved
* Redistribution and use in source and binary forms, with or without
@ -25,17 +25,14 @@
* SUCH DAMAGE.
*/
#ifndef DHCPCONFIG_H
#define DHCPCONFIG_H
#ifndef SCRIPT_H
#define SCRIPT_H
#include "net.h"
void if_printoptions(void);
int send_interface(int, const struct interface *);
int run_script_reason(const struct interface *, const char *);
void build_routes(void);
int configure(struct interface *);
int route_deleted(const struct rt *);
int script_runreason(const struct interface *, const char *);
#define run_script(ifp) run_script_reason(ifp, (ifp)->state->reason);
#define script_run(ifp) script_runreason(ifp, (ifp)->state->reason);
#endif