Import dhpcd-4.0.0rc3. Major changes since beta4:
- support for link state notification (e.g. renew lease after carrier returned) - support to start go into background immediately - don't cleanup interface state. dhcpcd will leave the interface in the same state as before if the lease uses separate addresses. -p still stops it from removing the configured address on exit - various smaller bugfixes, optimisations and cleanups
This commit is contained in:
parent
c8ccd39051
commit
b2f096aeb9
|
@ -0,0 +1,65 @@
|
|||
dhcpcd-4 - DHCP client daemon
|
||||
Copyright 2006-2008 Roy Marples <roy@marples.name>
|
||||
|
||||
|
||||
Installation
|
||||
------------
|
||||
Edit config.h to match your building requirements.
|
||||
Then just make; make install
|
||||
man dhcpcd for command line options
|
||||
|
||||
|
||||
Notes
|
||||
-----
|
||||
If you're cross compiling you may need to set the below knobs to avoid
|
||||
automatic tests.
|
||||
OS=BSD | Linux
|
||||
|
||||
If you're building for a NOMMU system where fork() does not work, you should
|
||||
add -DTHERE_IS_NO_FORK to your CPPFLAGS.
|
||||
|
||||
You can change the default dir with these knobs.
|
||||
For example, to satisfy FHS compliance you would do this:-
|
||||
LIBEXECDIR=/lib/dhcpcd
|
||||
DBDIR=/var/lib/dhcpcd
|
||||
|
||||
We now default to using -std=c99. For 64-bit linux, this always works, but
|
||||
for 32-bit linux it requires either gnu99 or a patch to asm/types.h.
|
||||
Most distros patch linux headers so this should work fine.
|
||||
linux-2.6.24 finally ships with a working 32-bit header.
|
||||
If your linux headers are older, or your distro hasn't patched them you can
|
||||
set CSTD=gnu99 to work around this.
|
||||
|
||||
|
||||
Hooks
|
||||
-----
|
||||
Not all the hooks in dhcpcd-hooks are installed by default.
|
||||
By default we install 01-test, 10-mtu, 20-resolv.conf and 30-hostname.
|
||||
To add more simply add them in the HOOKSCRIPTS variable.
|
||||
make HOOKSCRIPTS=50-ntp install
|
||||
|
||||
|
||||
Compatibility
|
||||
-------------
|
||||
If you require compatibility with dhcpcd-3 and older style variables,
|
||||
you can install 50-dhcpcd-compat into the directory $LIBEXECDIR/dhcpcd-hooks
|
||||
We don't install this by default.
|
||||
You should also add -DCMDLINE_COMPAT to your CPPFLAGS if you need to be fully
|
||||
commandline compatible with prior versions.
|
||||
|
||||
dhcpcd-3 enabled DUID support by default - this has changed in dhcpcd-4.
|
||||
You can enable it via the --duid, -D command line option or by using the
|
||||
duid directive in dhcpcd.conf.
|
||||
If CMDLINE_COMPAT is defined the we renable DUID support by default IF
|
||||
the dhcpcd.duid file exits. This keeps the clients working as they were,
|
||||
which is good.
|
||||
|
||||
dhcpcd-4 is NOT fully commandline compatible with dhcpcd-2 and older and
|
||||
changes the meaning of some options.
|
||||
|
||||
|
||||
ChangeLog
|
||||
---------
|
||||
We no longer supply a ChangeLog.
|
||||
However, you're more than welcome to read the git commit comments at
|
||||
http://git.marples.name/?p=dhcpcd/.git;a=summary
|
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* dhcpcd - DHCP client daemon
|
||||
* Copyright 2006-2008 Roy Marples <roy@marples.name>
|
||||
*
|
||||
* 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 BPF_ETHCOOK
|
||||
# define BPF_ETHCOOK 0
|
||||
#endif
|
||||
#ifndef BPF_WHOLEPACKET
|
||||
# define BPF_WHOLEPACKET ~0U
|
||||
#endif
|
||||
static const struct bpf_insn const arp_bpf_filter [] = {
|
||||
#ifndef BPF_SKIPTYPE
|
||||
/* Make sure this is an ARP packet... */
|
||||
BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 12),
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_ARP, 0, 3),
|
||||
#endif
|
||||
/* Make sure this is an ARP REQUEST... */
|
||||
BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 20 + BPF_ETHCOOK),
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ARPOP_REQUEST, 2, 0),
|
||||
/* or ARP REPLY... */
|
||||
BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 20 + BPF_ETHCOOK),
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ARPOP_REPLY, 0, 1),
|
||||
/* If we passed all the tests, ask for the whole packet. */
|
||||
BPF_STMT(BPF_RET + BPF_K, BPF_WHOLEPACKET),
|
||||
/* Otherwise, drop it. */
|
||||
BPF_STMT(BPF_RET + BPF_K, 0),
|
||||
};
|
||||
static const size_t arp_bpf_filter_len =
|
||||
sizeof(arp_bpf_filter) / sizeof(arp_bpf_filter[0]);
|
||||
|
||||
|
||||
/* dhcp_bpf_filter taken from bpf.c in dhcp-3.1.0
|
||||
*
|
||||
* Copyright (c) 2004,2007 by Internet Systems Consortium, Inc. ("ISC")
|
||||
* Copyright (c) 1996-2003 by Internet Software Consortium
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* Internet Systems Consortium, Inc.
|
||||
* 950 Charter Street
|
||||
* Redwood City, CA 94063
|
||||
* <info@isc.org>
|
||||
* http://www.isc.org/
|
||||
*/
|
||||
|
||||
static const struct bpf_insn const dhcp_bpf_filter [] = {
|
||||
#ifndef BPF_SKIPTYPE
|
||||
/* Make sure this is an IP packet... */
|
||||
BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 12),
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 0, 8),
|
||||
#endif
|
||||
/* Make sure it's a UDP packet... */
|
||||
BPF_STMT(BPF_LD + BPF_B + BPF_ABS, 23 + BPF_ETHCOOK),
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 0, 6),
|
||||
/* Make sure this isn't a fragment... */
|
||||
BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 20 + BPF_ETHCOOK),
|
||||
BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, 0x1fff, 4, 0),
|
||||
/* Get the IP header length... */
|
||||
BPF_STMT(BPF_LDX + BPF_B + BPF_MSH, 14 + BPF_ETHCOOK),
|
||||
/* Make sure it's to the right port... */
|
||||
BPF_STMT(BPF_LD + BPF_H + BPF_IND, 16 + BPF_ETHCOOK),
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, DHCP_CLIENT_PORT, 0, 1),
|
||||
/* If we passed all the tests, ask for the whole packet. */
|
||||
BPF_STMT(BPF_RET + BPF_K, BPF_WHOLEPACKET),
|
||||
/* Otherwise, drop it. */
|
||||
BPF_STMT(BPF_RET + BPF_K, 0),
|
||||
};
|
||||
static const size_t dhcp_bpf_filter_len =
|
||||
sizeof(dhcp_bpf_filter) / sizeof(dhcp_bpf_filter[0]);
|
|
@ -0,0 +1,206 @@
|
|||
/*
|
||||
* dhcpcd - DHCP client daemon
|
||||
* Copyright 2006-2008 Roy Marples <roy@marples.name>
|
||||
*
|
||||
* 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/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/uio.h>
|
||||
|
||||
#include <net/bpf.h>
|
||||
#include <net/if.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <paths.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "common.h"
|
||||
#include "dhcp.h"
|
||||
#include "logger.h"
|
||||
#include "net.h"
|
||||
#include "bpf-filter.h"
|
||||
|
||||
int
|
||||
open_socket(struct interface *iface, int protocol)
|
||||
{
|
||||
int fd = -1;
|
||||
int *fdp = NULL;
|
||||
struct ifreq ifr;
|
||||
int buf_len = 0;
|
||||
struct bpf_version pv;
|
||||
struct bpf_program pf;
|
||||
#ifdef BIOCIMMEDIATE
|
||||
int flags;
|
||||
#endif
|
||||
#ifdef _PATH_BPF
|
||||
fd = open(_PATH_BPF, O_RDWR | O_NONBLOCK);
|
||||
#else
|
||||
char *device;
|
||||
int n = 0;
|
||||
|
||||
device = xmalloc(sizeof(char) * PATH_MAX);
|
||||
do {
|
||||
snprintf(device, PATH_MAX, "/dev/bpf%d", n++);
|
||||
fd = open(device, O_RDWR | O_NONBLOCK);
|
||||
} while (fd == -1 && errno == EBUSY);
|
||||
free(device);
|
||||
#endif
|
||||
|
||||
if (fd == -1)
|
||||
return -1;
|
||||
|
||||
if (ioctl(fd, BIOCVERSION, &pv) == -1)
|
||||
goto eexit;
|
||||
if (pv.bv_major != BPF_MAJOR_VERSION ||
|
||||
pv.bv_minor < BPF_MINOR_VERSION) {
|
||||
logger(LOG_ERR, "BPF version mismatch - recompile " PACKAGE);
|
||||
goto eexit;
|
||||
}
|
||||
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
strlcpy(ifr.ifr_name, iface->name, sizeof(ifr.ifr_name));
|
||||
if (ioctl(fd, BIOCSETIF, &ifr) == -1)
|
||||
goto eexit;
|
||||
|
||||
/* Get the required BPF buffer length from the kernel. */
|
||||
if (ioctl(fd, BIOCGBLEN, &buf_len) == -1)
|
||||
goto eexit;
|
||||
if (iface->buffer_size != (size_t)buf_len) {
|
||||
free(iface->buffer);
|
||||
iface->buffer_size = buf_len;
|
||||
iface->buffer = xmalloc(buf_len);
|
||||
iface->buffer_len = iface->buffer_pos = 0;
|
||||
}
|
||||
|
||||
#ifdef BIOCIMMEDIATE
|
||||
flags = 1;
|
||||
if (ioctl(fd, BIOCIMMEDIATE, &flags) == -1)
|
||||
goto eexit;
|
||||
#endif
|
||||
|
||||
/* Install the DHCP filter */
|
||||
if (protocol == ETHERTYPE_ARP) {
|
||||
pf.bf_insns = UNCONST(arp_bpf_filter);
|
||||
pf.bf_len = arp_bpf_filter_len;
|
||||
fdp = &iface->arp_fd;
|
||||
} else {
|
||||
pf.bf_insns = UNCONST(dhcp_bpf_filter);
|
||||
pf.bf_len = dhcp_bpf_filter_len;
|
||||
fdp = &iface->raw_fd;
|
||||
}
|
||||
if (ioctl(fd, BIOCSETF, &pf) == -1)
|
||||
goto eexit;
|
||||
if (set_cloexec(fd) == -1)
|
||||
goto eexit;
|
||||
if (fdp) {
|
||||
if (*fdp != -1)
|
||||
close(*fdp);
|
||||
*fdp = fd;
|
||||
}
|
||||
return fd;
|
||||
|
||||
eexit:
|
||||
free(iface->buffer);
|
||||
iface->buffer = NULL;
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ssize_t
|
||||
send_raw_packet(const struct interface *iface, int protocol,
|
||||
const void *data, ssize_t len)
|
||||
{
|
||||
struct iovec iov[2];
|
||||
struct ether_header hw;
|
||||
int fd;
|
||||
|
||||
memset(&hw, 0, ETHER_HDR_LEN);
|
||||
memset(&hw.ether_dhost, 0xff, ETHER_ADDR_LEN);
|
||||
hw.ether_type = htons(protocol);
|
||||
iov[0].iov_base = &hw;
|
||||
iov[0].iov_len = ETHER_HDR_LEN;
|
||||
iov[1].iov_base = UNCONST(data);
|
||||
iov[1].iov_len = len;
|
||||
if (protocol == ETHERTYPE_ARP)
|
||||
fd = iface->arp_fd;
|
||||
else
|
||||
fd = iface->raw_fd;
|
||||
return writev(fd, iov, 2);
|
||||
}
|
||||
|
||||
/* BPF requires that we read the entire buffer.
|
||||
* So we pass the buffer in the API so we can loop on >1 packet. */
|
||||
ssize_t
|
||||
get_raw_packet(struct interface *iface, int protocol,
|
||||
void *data, ssize_t len)
|
||||
{
|
||||
int fd = -1;
|
||||
struct bpf_hdr packet;
|
||||
ssize_t bytes;
|
||||
const unsigned char *payload;
|
||||
|
||||
if (protocol == ETHERTYPE_ARP)
|
||||
fd = iface->arp_fd;
|
||||
else
|
||||
fd = iface->raw_fd;
|
||||
|
||||
for (;;) {
|
||||
if (iface->buffer_len == 0) {
|
||||
bytes = read(fd, iface->buffer, iface->buffer_size);
|
||||
if (bytes == -1)
|
||||
return errno == EAGAIN ? 0 : -1;
|
||||
else if ((size_t)bytes < sizeof(packet))
|
||||
return -1;
|
||||
iface->buffer_len = bytes;
|
||||
iface->buffer_pos = 0;
|
||||
}
|
||||
bytes = -1;
|
||||
memcpy(&packet, iface->buffer + iface->buffer_pos,
|
||||
sizeof(packet));
|
||||
if (packet.bh_caplen != packet.bh_datalen)
|
||||
goto next; /* Incomplete packet, drop. */
|
||||
if (iface->buffer_pos + packet.bh_caplen + packet.bh_hdrlen >
|
||||
iface->buffer_len)
|
||||
goto next; /* Packet beyond buffer, drop. */
|
||||
payload = iface->buffer + packet.bh_hdrlen + ETHER_HDR_LEN;
|
||||
bytes = packet.bh_caplen - ETHER_HDR_LEN;
|
||||
if (bytes > len)
|
||||
bytes = len;
|
||||
memcpy(data, payload, bytes);
|
||||
next:
|
||||
iface->buffer_pos += BPF_WORDALIGN(packet.bh_hdrlen +
|
||||
packet.bh_caplen);
|
||||
if (iface->buffer_pos >= iface->buffer_len)
|
||||
iface->buffer_len = iface->buffer_pos = 0;
|
||||
if (bytes != -1)
|
||||
return bytes;
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* dhcpcd - DHCP client daemon
|
||||
* Copyright 2006-2008 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 CLIENT_H
|
||||
#define CLIENT_H
|
||||
|
||||
#include "dhcpcd.h"
|
||||
|
||||
int dhcp_run(const struct options *, int *);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,284 @@
|
|||
/*
|
||||
* dhcpcd - DHCP client daemon
|
||||
* Copyright 2006-2008 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 <errno.h>
|
||||
#include <fcntl.h>
|
||||
#ifdef BSD
|
||||
# include <paths.h>
|
||||
#endif
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "logger.h"
|
||||
|
||||
#ifndef _PATH_DEVNULL
|
||||
# define _PATH_DEVNULL "/dev/null"
|
||||
#endif
|
||||
|
||||
/* Handy routine to read very long lines in text files.
|
||||
* This means we read the whole line and avoid any nasty buffer overflows. */
|
||||
ssize_t
|
||||
get_line(char **line, size_t *len, FILE *fp)
|
||||
{
|
||||
char *p;
|
||||
size_t last = 0;
|
||||
|
||||
while(!feof(fp)) {
|
||||
if (*line == NULL || last != 0) {
|
||||
*len += BUFSIZ;
|
||||
*line = xrealloc(*line, *len);
|
||||
}
|
||||
p = *line + last;
|
||||
memset(p, 0, BUFSIZ);
|
||||
fgets(p, BUFSIZ, fp);
|
||||
last += strlen(p);
|
||||
if (last && (*line)[last - 1] == '\n') {
|
||||
(*line)[last - 1] = '\0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
return last;
|
||||
}
|
||||
|
||||
/* Simple hack to return a random number without arc4random */
|
||||
#ifndef HAVE_ARC4RANDOM
|
||||
uint32_t arc4random(void)
|
||||
{
|
||||
int fd;
|
||||
static unsigned long seed = 0;
|
||||
|
||||
if (!seed) {
|
||||
fd = open("/dev/urandom", 0);
|
||||
if (fd == -1 || read(fd, &seed, sizeof(seed)) == -1)
|
||||
seed = time(0);
|
||||
if (fd >= 0)
|
||||
close(fd);
|
||||
srandom(seed);
|
||||
}
|
||||
|
||||
return (uint32_t)random();
|
||||
}
|
||||
#endif
|
||||
|
||||
/* strlcpy is nice, shame glibc does not define it */
|
||||
#if HAVE_STRLCPY
|
||||
#else
|
||||
size_t
|
||||
strlcpy(char *dst, const char *src, size_t size)
|
||||
{
|
||||
const char *s = src;
|
||||
size_t n = size;
|
||||
|
||||
if (n && --n)
|
||||
do {
|
||||
if (!(*dst++ = *src++))
|
||||
break;
|
||||
} while (--n);
|
||||
|
||||
if (!n) {
|
||||
if (size)
|
||||
*dst = '\0';
|
||||
while (*src++);
|
||||
}
|
||||
|
||||
return src - s - 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if HAVE_CLOSEFROM
|
||||
#else
|
||||
int
|
||||
closefrom(int fd)
|
||||
{
|
||||
int max = getdtablesize();
|
||||
int i;
|
||||
int r = 0;
|
||||
|
||||
for (i = fd; i < max; i++)
|
||||
r += close(i);
|
||||
return r;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Close our fd's */
|
||||
int
|
||||
close_fds(void)
|
||||
{
|
||||
int fd;
|
||||
|
||||
if ((fd = open(_PATH_DEVNULL, O_RDWR)) == -1)
|
||||
return -1;
|
||||
|
||||
dup2(fd, fileno(stdin));
|
||||
dup2(fd, fileno(stdout));
|
||||
dup2(fd, fileno(stderr));
|
||||
if (fd > 2)
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
set_cloexec(int fd)
|
||||
{
|
||||
int flags;
|
||||
|
||||
if ((flags = fcntl(fd, F_GETFD, 0)) == -1
|
||||
|| fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1)
|
||||
{
|
||||
logger(LOG_ERR, "fcntl: %s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
set_nonblock(int fd)
|
||||
{
|
||||
int flags;
|
||||
|
||||
if ((flags = fcntl(fd, F_GETFL, 0)) == -1
|
||||
|| fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1)
|
||||
{
|
||||
logger(LOG_ERR, "fcntl: %s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Handy function to get the time.
|
||||
* We only care about time advancements, not the actual time itself
|
||||
* Which is why we use CLOCK_MONOTONIC, but it is not available on all
|
||||
* platforms.
|
||||
*/
|
||||
int
|
||||
clock_monotonic(struct timeval *tp)
|
||||
{
|
||||
#if defined(_POSIX_MONOTONIC_CLOCK) && defined(CLOCK_MONOTONIC)
|
||||
struct timespec ts;
|
||||
static clockid_t posix_clock;
|
||||
static int posix_clock_set = 0;
|
||||
|
||||
if (!posix_clock_set) {
|
||||
if (sysconf(_SC_MONOTONIC_CLOCK) >= 0)
|
||||
posix_clock = CLOCK_MONOTONIC;
|
||||
else
|
||||
posix_clock = CLOCK_REALTIME;
|
||||
posix_clock_set = 1;
|
||||
}
|
||||
|
||||
if (clock_gettime(posix_clock, &ts) == -1)
|
||||
return -1;
|
||||
|
||||
tp->tv_sec = ts.tv_sec;
|
||||
tp->tv_usec = ts.tv_nsec / 1000;
|
||||
return 0;
|
||||
#else
|
||||
return gettimeofday(tp, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
time_t
|
||||
uptime(void)
|
||||
{
|
||||
struct timeval tv;
|
||||
|
||||
if (clock_monotonic(&tv) == -1)
|
||||
return -1;
|
||||
return tv.tv_sec;
|
||||
}
|
||||
|
||||
int
|
||||
writepid(int fd, pid_t pid)
|
||||
{
|
||||
char spid[16];
|
||||
ssize_t len;
|
||||
|
||||
if (ftruncate(fd, (off_t)0) == -1)
|
||||
return -1;
|
||||
snprintf(spid, sizeof(spid), "%u", pid);
|
||||
len = pwrite(fd, spid, strlen(spid), (off_t)0);
|
||||
if (len != (ssize_t)strlen(spid))
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *
|
||||
xmalloc(size_t s)
|
||||
{
|
||||
void *value = malloc(s);
|
||||
|
||||
if (value)
|
||||
return value;
|
||||
logger(LOG_ERR, "memory exhausted");
|
||||
exit (EXIT_FAILURE);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
void *
|
||||
xzalloc(size_t s)
|
||||
{
|
||||
void *value = xmalloc(s);
|
||||
|
||||
memset(value, 0, s);
|
||||
return value;
|
||||
}
|
||||
|
||||
void *
|
||||
xrealloc(void *ptr, size_t s)
|
||||
{
|
||||
void *value = realloc(ptr, s);
|
||||
|
||||
if (value)
|
||||
return (value);
|
||||
logger(LOG_ERR, "memory exhausted");
|
||||
exit(EXIT_FAILURE);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
char *
|
||||
xstrdup(const char *str)
|
||||
{
|
||||
char *value;
|
||||
|
||||
if (!str)
|
||||
return NULL;
|
||||
|
||||
if ((value = strdup(str)))
|
||||
return value;
|
||||
|
||||
logger(LOG_ERR, "memory exhausted");
|
||||
exit(EXIT_FAILURE);
|
||||
/* NOTREACHED */
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
* dhcpcd - DHCP client daemon
|
||||
* Copyright 2006-2008 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 COMMON_H
|
||||
#define COMMON_H
|
||||
|
||||
/* string.h pulls in features.h so the below define checks work */
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#define UNCONST(a) ((void *)(unsigned long)(const void *)(a))
|
||||
|
||||
#if __GNUC__ > 2 || defined(__INTEL_COMPILER)
|
||||
# define _unused __attribute__((__unused__))
|
||||
#else
|
||||
# define _unused
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_ARC4RANDOM
|
||||
# ifdef __GLIBC__
|
||||
uint32_t arc4random(void);
|
||||
#else
|
||||
# define HAVE_ARC4RANDOM
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRLCPY
|
||||
# define HAVE_STRLCPY 1
|
||||
#endif
|
||||
/* Only GLIBC doesn't support strlcpy */
|
||||
#ifdef __GLIBC__
|
||||
# if !defined(__UCLIBC__) && !defined (__dietlibc__)
|
||||
# undef HAVE_STRLCPY
|
||||
size_t strlcpy(char *, const char *, size_t);
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_CLOSEFROM
|
||||
# if defined(__NetBSD__) || defined(__OpenBSD__)
|
||||
# define HAVE_CLOSEFROM 1
|
||||
# endif
|
||||
#endif
|
||||
#ifndef HAVE_CLOSEFROM
|
||||
int closefrom(int);
|
||||
#endif
|
||||
|
||||
int close_fds(void);
|
||||
int set_cloexec(int);
|
||||
int set_nonblock(int);
|
||||
ssize_t get_line(char **, size_t *, FILE *);
|
||||
int clock_monotonic(struct timeval *);
|
||||
time_t uptime(void);
|
||||
int writepid(int, pid_t);
|
||||
void *xrealloc(void *, size_t);
|
||||
void *xmalloc(size_t);
|
||||
void *xzalloc(size_t);
|
||||
char *xstrdup(const char *);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* dhcpcd - DHCP client daemon
|
||||
* Copyright 2006-2008 Roy Marples <roy@marples.name>
|
||||
*
|
||||
* 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 CONFIG_H
|
||||
#define CONFIG_H
|
||||
|
||||
#define PACKAGE "dhcpcd"
|
||||
#define VERSION "4.0.0-rc3"
|
||||
|
||||
/*
|
||||
* By default we don't add a local link route if we got a routeable address.
|
||||
* This is because dhcpcd can't really decide which interface should allow
|
||||
* link local routing when we have more than one interface.
|
||||
* Ideally the host network scripts should add the link local route for us.
|
||||
* If not, you can define this to get dhcpcd to always add the link local route.
|
||||
*/
|
||||
// #define IPV4LL_ALWAYSROUTE
|
||||
|
||||
/* Some systems do not have a working fork. */
|
||||
/* #define THERE_IS_NO_FORK */
|
||||
|
||||
/* Paths to things */
|
||||
#ifndef SYSCONFDIR
|
||||
# define SYSCONFDIR "/etc"
|
||||
#endif
|
||||
#ifndef LIBEXECDIR
|
||||
# define LIBEXECDIR "/libexec"
|
||||
#endif
|
||||
#ifndef RUNDIR
|
||||
# define RUNDIR "/var/run"
|
||||
#endif
|
||||
#ifndef DBDIR
|
||||
# define DBDIR "/var/db"
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG
|
||||
# define CONFIG SYSCONFDIR "/" PACKAGE ".conf"
|
||||
#endif
|
||||
#ifndef SCRIPT
|
||||
# define SCRIPT LIBEXECDIR "/" PACKAGE "-run-hooks"
|
||||
#endif
|
||||
#ifndef DUID
|
||||
# define DUID SYSCONFDIR "/" PACKAGE ".duid"
|
||||
#endif
|
||||
#ifndef LEASEFILE
|
||||
# define LEASEFILE DBDIR "/" PACKAGE "-%s.lease"
|
||||
#endif
|
||||
#ifndef PIDFILE
|
||||
# define PIDFILE RUNDIR "/" PACKAGE "-%s.pid"
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,501 @@
|
|||
/*
|
||||
* dhcpcd - DHCP client daemon
|
||||
* Copyright 2006-2008 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/wait.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "common.h"
|
||||
#include "configure.h"
|
||||
#include "dhcp.h"
|
||||
#include "dhcpcd.h"
|
||||
#include "logger.h"
|
||||
#include "net.h"
|
||||
#include "signals.h"
|
||||
|
||||
#define DEFAULT_PATH "PATH=/usr/bin:/usr/sbin:/bin:/sbin"
|
||||
|
||||
int
|
||||
exec_script(const struct options *options, const char *iface,
|
||||
const char *reason,
|
||||
const struct dhcp_message *dhcpn, const struct dhcp_message *dhcpo)
|
||||
{
|
||||
char *const argv[2] = { UNCONST(options->script), NULL };
|
||||
char **env = NULL, **ep;
|
||||
char *path;
|
||||
ssize_t e, elen;
|
||||
int ret = 0;
|
||||
pid_t pid;
|
||||
int status = 0;
|
||||
sigset_t full;
|
||||
sigset_t old;
|
||||
|
||||
logger(LOG_DEBUG, "executing `%s', reason %s", options->script, reason);
|
||||
|
||||
/* Make our env */
|
||||
elen = 5;
|
||||
env = xmalloc(sizeof(char *) * (elen + 1));
|
||||
path = getenv("PATH");
|
||||
if (path) {
|
||||
e = strlen("PATH") + strlen(path) + 2;
|
||||
env[0] = xmalloc(e);
|
||||
snprintf(env[0], e, "PATH=%s", path);
|
||||
} else
|
||||
env[0] = xstrdup(DEFAULT_PATH);
|
||||
e = strlen("interface") + strlen(iface) + 2;
|
||||
env[1] = xmalloc(e);
|
||||
snprintf(env[1], e, "interface=%s", iface);
|
||||
e = strlen("reason") + strlen(reason) + 2;
|
||||
env[2] = xmalloc(e);
|
||||
snprintf(env[2], e, "reason=%s", reason);
|
||||
e = 20;
|
||||
env[3] = xmalloc(e);
|
||||
snprintf(env[3], e, "pid=%d", getpid());
|
||||
env[4] = xmalloc(e);
|
||||
snprintf(env[4], e, "metric=%d", options->metric);
|
||||
if (dhcpo) {
|
||||
e = configure_env(NULL, NULL, dhcpo, options);
|
||||
if (e > 0) {
|
||||
env = xrealloc(env, sizeof(char *) * (elen + e + 1));
|
||||
elen += configure_env(env + elen, "old", dhcpo, options);
|
||||
}
|
||||
}
|
||||
if (dhcpn) {
|
||||
e = configure_env(NULL, NULL, dhcpn, options);
|
||||
if (e > 0) {
|
||||
env = xrealloc(env, sizeof(char *) * (elen + e + 1));
|
||||
elen += configure_env(env + elen, "new", dhcpn, options);
|
||||
}
|
||||
}
|
||||
/* Add our base environment */
|
||||
if (options->environ) {
|
||||
e = 0;
|
||||
while (options->environ[e++])
|
||||
;
|
||||
env = xrealloc(env, sizeof(char *) * (elen + e + 1));
|
||||
e = 0;
|
||||
while (options->environ[e]) {
|
||||
env[elen + e] = xstrdup(options->environ[e]);
|
||||
e++;
|
||||
}
|
||||
elen += e;
|
||||
}
|
||||
env[elen] = '\0';
|
||||
|
||||
/* OK, we need to block signals */
|
||||
sigfillset(&full);
|
||||
sigprocmask(SIG_SETMASK, &full, &old);
|
||||
|
||||
#ifdef THERE_IS_NO_FORK
|
||||
signal_reset();
|
||||
pid = vfork();
|
||||
#else
|
||||
pid = fork();
|
||||
#endif
|
||||
|
||||
switch (pid) {
|
||||
case -1:
|
||||
#ifdef THERE_IS_NO_FORK
|
||||
logger(LOG_ERR, "vfork: %s", strerror(errno));
|
||||
#else
|
||||
logger(LOG_ERR, "fork: %s", strerror(errno));
|
||||
#endif
|
||||
ret = -1;
|
||||
break;
|
||||
case 0:
|
||||
#ifndef THERE_IS_NO_FORK
|
||||
signal_reset();
|
||||
#endif
|
||||
sigprocmask(SIG_SETMASK, &old, NULL);
|
||||
execve(options->script, argv, env);
|
||||
logger(LOG_ERR, "%s: %s", options->script, strerror(errno));
|
||||
_exit(111);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
#ifdef THERE_IS_NO_FORK
|
||||
signal_setup();
|
||||
#endif
|
||||
|
||||
/* Restore our signals */
|
||||
sigprocmask(SIG_SETMASK, &old, NULL);
|
||||
|
||||
/* Wait for the script to finish */
|
||||
while (waitpid(pid, &status, 0) == -1) {
|
||||
if (errno != EINTR) {
|
||||
logger(LOG_ERR, "waitpid: %s", strerror(errno));
|
||||
status = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Cleanup */
|
||||
ep = env;
|
||||
while (*ep)
|
||||
free(*ep++);
|
||||
free(env);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static struct rt *
|
||||
reverse_routes(struct rt *routes)
|
||||
{
|
||||
struct rt *rt;
|
||||
struct rt *rtn = NULL;
|
||||
|
||||
while (routes) {
|
||||
rt = routes->next;
|
||||
routes->next = rtn;
|
||||
rtn = routes;
|
||||
routes = rt;
|
||||
}
|
||||
return rtn;
|
||||
}
|
||||
|
||||
static int
|
||||
delete_route(const char *iface, struct rt *rt, int metric)
|
||||
{
|
||||
char *addr;
|
||||
int retval;
|
||||
|
||||
addr = xstrdup(inet_ntoa(rt->dest));
|
||||
logger(LOG_DEBUG, "deleting route %s/%d via %s",
|
||||
addr, inet_ntocidr(rt->net), inet_ntoa(rt->gate));
|
||||
free(addr);
|
||||
retval = del_route(iface, &rt->dest, &rt->net, &rt->gate, metric);
|
||||
if (retval != 0 && errno != ENOENT && errno != ESRCH)
|
||||
logger(LOG_ERR," del_route: %s", strerror(errno));
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int
|
||||
delete_routes(struct interface *iface, int metric)
|
||||
{
|
||||
struct rt *rt;
|
||||
struct rt *rtn;
|
||||
int retval = 0;
|
||||
|
||||
rt = reverse_routes(iface->routes);
|
||||
while (rt) {
|
||||
rtn = rt->next;
|
||||
retval += delete_route(iface->name, rt, metric);
|
||||
free(rt);
|
||||
rt = rtn;
|
||||
}
|
||||
iface->routes = NULL;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int
|
||||
in_routes(const struct rt *routes, const struct rt *rt)
|
||||
{
|
||||
while (routes) {
|
||||
if (routes->dest.s_addr == rt->dest.s_addr &&
|
||||
routes->net.s_addr == rt->net.s_addr &&
|
||||
routes->gate.s_addr == rt->gate.s_addr)
|
||||
return 0;
|
||||
routes = routes->next;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
configure_routes(struct interface *iface, const struct dhcp_message *dhcp,
|
||||
const struct options *options)
|
||||
{
|
||||
struct rt *rt, *ort;
|
||||
struct rt *rtn = NULL, *nr = NULL;
|
||||
int remember;
|
||||
int retval = 0;
|
||||
char *addr;
|
||||
|
||||
#ifdef THERE_IS_NO_FORK
|
||||
char *skipp;
|
||||
size_t skiplen;
|
||||
int skip = 0;
|
||||
|
||||
free(dhcpcd_skiproutes);
|
||||
/* We can never have more than 255 routes. So we need space
|
||||
* for 255 3 digit numbers and commas */
|
||||
skiplen = 255 * 4 + 1;
|
||||
skipp = dhcpcd_skiproutes = xmalloc(sizeof(char) * skiplen);
|
||||
*skipp = '\0';
|
||||
#endif
|
||||
|
||||
ort = get_option_routes(dhcp);
|
||||
|
||||
#ifdef IPV4LL_ALWAYSROUTE
|
||||
if (options->options & DHCPCD_IPV4LL &&
|
||||
IN_PRIVATE(ntohl(dhcp->yiaddr)))
|
||||
{
|
||||
for (rt = ort; rt; rt = rt->next) {
|
||||
/* Check if we have already got a link locale route
|
||||
* dished out by the DHCP server */
|
||||
if (rt->dest.s_addr == htonl(LINKLOCAL_ADDR) &&
|
||||
rt->net.s_addr == htonl(LINKLOCAL_MASK))
|
||||
break;
|
||||
rtn = rt;
|
||||
}
|
||||
|
||||
if (!rt) {
|
||||
rt = xmalloc(sizeof(*rt));
|
||||
rt->dest.s_addr = htonl(LINKLOCAL_ADDR);
|
||||
rt->net.s_addr = htonl(LINKLOCAL_MASK);
|
||||
rt->gate.s_addr = 0;
|
||||
rt->next = NULL;
|
||||
if (rtn)
|
||||
rtn->next = rt;
|
||||
else
|
||||
ort = rt;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef THERE_IS_NO_FORK
|
||||
if (dhcpcd_skiproutes) {
|
||||
int i = -1;
|
||||
char *sk, *skp, *token;
|
||||
free_routes(iface->routes);
|
||||
for (rt = ort; rt; rt = rt->next) {
|
||||
i++;
|
||||
/* Check that we did add this route or not */
|
||||
sk = skp = xstrdup(dhcpcd_skiproutes);
|
||||
while ((token = strsep(&skp, ","))) {
|
||||
if (isdigit((unsigned char)*token) &&
|
||||
atoi(token) == i)
|
||||
break;
|
||||
}
|
||||
free(sk);
|
||||
if (token)
|
||||
continue;
|
||||
if (nr) {
|
||||
rtn->next = xmalloc(sizeof(*rtn));
|
||||
rtn = rtn->next;
|
||||
} else {
|
||||
nr = rtn = xmalloc(sizeof(*rtn));
|
||||
}
|
||||
rtn->dest.s_addr = rt->dest.s_addr;
|
||||
rtn->net.s_addr = rt->net.s_addr;
|
||||
rtn->gate.s_addr = rt->gate.s_addr;
|
||||
rtn->next = NULL;
|
||||
}
|
||||
iface->routes = nr;
|
||||
nr = NULL;
|
||||
|
||||
/* We no longer need this */
|
||||
free(dhcpcd_skiproutes);
|
||||
dhcpcd_skiproutes = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Now remove old routes we no longer use.
|
||||
* We should do this in reverse order. */
|
||||
iface->routes = reverse_routes(iface->routes);
|
||||
for (rt = iface->routes; rt; rt = rt->next)
|
||||
if (in_routes(ort, rt) != 0)
|
||||
delete_route(iface->name, rt, options->metric);
|
||||
|
||||
for (rt = ort; rt; rt = rt->next) {
|
||||
/* Don't set default routes if not asked to */
|
||||
if (rt->dest.s_addr == 0 &&
|
||||
rt->net.s_addr == 0 &&
|
||||
!(options->options & DHCPCD_GATEWAY))
|
||||
continue;
|
||||
|
||||
addr = xstrdup(inet_ntoa(rt->dest));
|
||||
logger(LOG_DEBUG, "adding route to %s/%d via %s",
|
||||
addr, inet_ntocidr(rt->net), inet_ntoa(rt->gate));
|
||||
free(addr);
|
||||
remember = add_route(iface->name, &rt->dest,
|
||||
&rt->net, &rt->gate,
|
||||
options->metric);
|
||||
retval += remember;
|
||||
|
||||
/* If we failed to add the route, we may have already added it
|
||||
ourselves. If so, remember it again. */
|
||||
if (remember < 0) {
|
||||
if (errno != EEXIST)
|
||||
logger(LOG_ERR, "add_route: %s",
|
||||
strerror(errno));
|
||||
if (in_routes(iface->routes, rt) == 0)
|
||||
remember = 1;
|
||||
}
|
||||
|
||||
/* This login is split from above due to the #ifdef below */
|
||||
if (remember >= 0) {
|
||||
if (nr) {
|
||||
rtn->next = xmalloc(sizeof(*rtn));
|
||||
rtn = rtn->next;
|
||||
} else {
|
||||
nr = rtn = xmalloc(sizeof(*rtn));
|
||||
}
|
||||
rtn->dest.s_addr = rt->dest.s_addr;
|
||||
rtn->net.s_addr = rt->net.s_addr;
|
||||
rtn->gate.s_addr = rt->gate.s_addr;
|
||||
rtn->next = NULL;
|
||||
}
|
||||
#ifdef THERE_IS_NO_FORK
|
||||
/* If we have daemonised yet we need to record which routes
|
||||
* we failed to add so we can skip them */
|
||||
else if (!(options->options & DHCPCD_DAEMONISED)) {
|
||||
/* We can never have more than 255 / 4 routes,
|
||||
* so 3 chars is plently */
|
||||
printf("foo\n");
|
||||
if (*skipp)
|
||||
*skipp++ = ',';
|
||||
skipp += snprintf(skipp,
|
||||
dhcpcd_skiproutes + skiplen - skipp,
|
||||
"%d", skip);
|
||||
}
|
||||
skip++;
|
||||
#endif
|
||||
}
|
||||
free_routes(ort);
|
||||
free_routes(iface->routes);
|
||||
iface->routes = nr;
|
||||
|
||||
#ifdef THERE_IS_NO_FORK
|
||||
if (dhcpcd_skiproutes) {
|
||||
if (*dhcpcd_skiproutes)
|
||||
*skipp = '\0';
|
||||
else {
|
||||
free(dhcpcd_skiproutes);
|
||||
dhcpcd_skiproutes = NULL;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int
|
||||
delete_address(struct interface *iface)
|
||||
{
|
||||
int retval;
|
||||
logger(LOG_DEBUG, "deleting IP address %s/%d",
|
||||
inet_ntoa(iface->addr),
|
||||
inet_ntocidr(iface->net));
|
||||
retval = del_address(iface->name, &iface->addr, &iface->net);
|
||||
if (retval == -1 && errno != EADDRNOTAVAIL)
|
||||
logger(LOG_ERR, "del_address: %s", strerror(errno));
|
||||
iface->addr.s_addr = 0;
|
||||
iface->net.s_addr = 0;
|
||||
return retval;
|
||||
}
|
||||
|
||||
int
|
||||
configure(struct interface *iface, const char *reason,
|
||||
const struct dhcp_message *dhcp, const struct dhcp_message *old,
|
||||
const struct dhcp_lease *lease, const struct options *options,
|
||||
int up)
|
||||
{
|
||||
struct in_addr addr;
|
||||
struct in_addr net;
|
||||
struct in_addr brd;
|
||||
#ifdef __linux__
|
||||
struct in_addr dest;
|
||||
struct in_addr gate;
|
||||
#endif
|
||||
|
||||
/* Grab our IP config */
|
||||
if (dhcp == NULL || dhcp->yiaddr == 0)
|
||||
up = 0;
|
||||
else {
|
||||
addr.s_addr = dhcp->yiaddr;
|
||||
/* Ensure we have all the needed values */
|
||||
if (get_option_addr(&net.s_addr, dhcp, DHCP_SUBNETMASK) == -1)
|
||||
net.s_addr = get_netmask(addr.s_addr);
|
||||
if (get_option_addr(&brd.s_addr, dhcp, DHCP_BROADCAST) == -1)
|
||||
brd.s_addr = addr.s_addr | ~net.s_addr;
|
||||
}
|
||||
|
||||
/* If we aren't up, then reset the interface as much as we can */
|
||||
if (!up) {
|
||||
/* Only reset things if we had set them before */
|
||||
if (iface->addr.s_addr != 0) {
|
||||
delete_routes(iface, options->metric);
|
||||
delete_address(iface);
|
||||
}
|
||||
|
||||
exec_script(options, iface->name, reason, NULL, old);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This also changes netmask */
|
||||
if (!(options->options & DHCPCD_INFORM) ||
|
||||
!has_address(iface->name, &addr, &net)) {
|
||||
logger(LOG_DEBUG, "adding IP address %s/%d",
|
||||
inet_ntoa(addr), inet_ntocidr(net));
|
||||
if (add_address(iface->name, &addr, &net, &brd) == -1 &&
|
||||
errno != EEXIST)
|
||||
{
|
||||
logger(LOG_ERR, "add_address: %s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now delete the old address if different */
|
||||
if (iface->addr.s_addr != addr.s_addr &&
|
||||
iface->addr.s_addr != 0)
|
||||
delete_address(iface);
|
||||
|
||||
#ifdef __linux__
|
||||
/* On linux, we need to change the subnet route to have our metric. */
|
||||
if (iface->addr.s_addr != lease->addr.s_addr &&
|
||||
options->metric > 0 && net.s_addr != INADDR_BROADCAST)
|
||||
{
|
||||
dest.s_addr = addr.s_addr & net.s_addr;
|
||||
gate.s_addr = 0;
|
||||
add_route(iface->name, &dest, &net, &gate, options->metric);
|
||||
del_route(iface->name, &dest, &net, &gate, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
configure_routes(iface, dhcp, options);
|
||||
up = (iface->addr.s_addr != addr.s_addr ||
|
||||
iface->net.s_addr != net.s_addr);
|
||||
iface->addr.s_addr = addr.s_addr;
|
||||
iface->net.s_addr = net.s_addr;
|
||||
|
||||
if (!lease->frominfo)
|
||||
if (write_lease(iface, dhcp) == -1)
|
||||
logger(LOG_ERR, "write_lease: %s", strerror(errno));
|
||||
|
||||
exec_script(options, iface->name, reason, dhcp, old);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* dhcpcd - DHCP client daemon
|
||||
* Copyright 2006-2008 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 DHCPCONFIG_H
|
||||
#define DHCPCONFIG_H
|
||||
|
||||
#include "dhcpcd.h"
|
||||
#include "dhcp.h"
|
||||
#include "net.h"
|
||||
|
||||
int exec_script(const struct options *, const char *, const char *,
|
||||
const struct dhcp_message *, const struct dhcp_message *);
|
||||
int configure(struct interface *, const char *,
|
||||
const struct dhcp_message *, const struct dhcp_message *,
|
||||
const struct dhcp_lease *, const struct options *, int);
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,185 @@
|
|||
/*
|
||||
* dhcpcd - DHCP client daemon
|
||||
* Copyright 2006-2008 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 DHCP_H
|
||||
#define DHCP_H
|
||||
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "dhcpcd.h"
|
||||
#include "net.h"
|
||||
|
||||
/* Max MTU - defines dhcp option length */
|
||||
#define MTU_MAX 1500
|
||||
#define MTU_MIN 576
|
||||
|
||||
/* UDP port numbers for DHCP */
|
||||
#define DHCP_SERVER_PORT 67
|
||||
#define DHCP_CLIENT_PORT 68
|
||||
|
||||
#define MAGIC_COOKIE 0x63825363
|
||||
#define BROADCAST_FLAG 0x8000
|
||||
|
||||
/* DHCP message OP code */
|
||||
#define DHCP_BOOTREQUEST 1
|
||||
#define DHCP_BOOTREPLY 2
|
||||
|
||||
/* DHCP message type */
|
||||
#define DHCP_DISCOVER 1
|
||||
#define DHCP_OFFER 2
|
||||
#define DHCP_REQUEST 3
|
||||
#define DHCP_DECLINE 4
|
||||
#define DHCP_ACK 5
|
||||
#define DHCP_NAK 6
|
||||
#define DHCP_RELEASE 7
|
||||
#define DHCP_INFORM 8
|
||||
|
||||
/* DHCP options */
|
||||
enum DHCP_OPTIONS
|
||||
{
|
||||
DHCP_PAD = 0,
|
||||
DHCP_SUBNETMASK = 1,
|
||||
DHCP_ROUTER = 3,
|
||||
DHCP_DNSSERVER = 6,
|
||||
DHCP_HOSTNAME = 12,
|
||||
DHCP_DNSDOMAIN = 15,
|
||||
DHCP_MTU = 26,
|
||||
DHCP_BROADCAST = 28,
|
||||
DHCP_STATICROUTE = 33,
|
||||
DHCP_NISDOMAIN = 40,
|
||||
DHCP_NISSERVER = 41,
|
||||
DHCP_NTPSERVER = 42,
|
||||
DHCP_VENDOR = 43,
|
||||
DHCP_IPADDRESS = 50,
|
||||
DHCP_LEASETIME = 51,
|
||||
DHCP_OPTIONSOVERLOADED = 52,
|
||||
DHCP_MESSAGETYPE = 53,
|
||||
DHCP_SERVERID = 54,
|
||||
DHCP_PARAMETERREQUESTLIST = 55,
|
||||
DHCP_MESSAGE = 56,
|
||||
DHCP_MAXMESSAGESIZE = 57,
|
||||
DHCP_RENEWALTIME = 58,
|
||||
DHCP_REBINDTIME = 59,
|
||||
DHCP_CLASSID = 60,
|
||||
DHCP_CLIENTID = 61,
|
||||
DHCP_USERCLASS = 77, /* RFC 3004 */
|
||||
DHCP_FQDN = 81,
|
||||
DHCP_DNSSEARCH = 119, /* RFC 3397 */
|
||||
DHCP_CSR = 121, /* RFC 3442 */
|
||||
DHCP_MSCSR = 249, /* MS code for RFC 3442 */
|
||||
DHCP_END = 255
|
||||
};
|
||||
|
||||
/* SetFQDNHostName values - lsnybble used in flags
|
||||
* byte (see buildmsg.c), hsnybble to create order
|
||||
* and to allow 0x00 to mean disable
|
||||
*/
|
||||
enum FQQN {
|
||||
FQDN_DISABLE = 0x00,
|
||||
FQDN_NONE = 0x18,
|
||||
FQDN_PTR = 0x20,
|
||||
FQDN_BOTH = 0x31
|
||||
};
|
||||
|
||||
struct fqdn
|
||||
{
|
||||
uint8_t flags;
|
||||
uint8_t r1;
|
||||
uint8_t r2;
|
||||
char *name;
|
||||
};
|
||||
|
||||
/* Sizes for DHCP options */
|
||||
#define DHCP_CHADDR_LEN 16
|
||||
#define SERVERNAME_LEN 64
|
||||
#define BOOTFILE_LEN 128
|
||||
#define DHCP_UDP_LEN (20 + 8)
|
||||
#define DHCP_BASE_LEN (4 + 4 + 2 + 2 + 4 + 4 + 4 + 4 + 4)
|
||||
#define DHCP_RESERVE_LEN (4 + 4 + 4 + 4 + 2)
|
||||
#define DHCP_FIXED_LEN (DHCP_BASE_LEN + DHCP_CHADDR_LEN + \
|
||||
+ SERVERNAME_LEN + BOOTFILE_LEN)
|
||||
#define DHCP_OPTION_LEN (MTU_MAX - DHCP_FIXED_LEN - DHCP_UDP_LEN \
|
||||
- DHCP_RESERVE_LEN)
|
||||
|
||||
/* Some crappy DHCP servers require the BOOTP minimum length */
|
||||
#define BOOTP_MESSAGE_LENTH_MIN 300
|
||||
|
||||
struct dhcp_message {
|
||||
uint8_t op; /* message type */
|
||||
uint8_t hwtype; /* hardware address type */
|
||||
uint8_t hwlen; /* hardware address length */
|
||||
uint8_t hwopcount; /* should be zero in client message */
|
||||
uint32_t xid; /* transaction id */
|
||||
uint16_t secs; /* elapsed time in sec. from boot */
|
||||
uint16_t flags;
|
||||
uint32_t ciaddr; /* (previously allocated) client IP */
|
||||
uint32_t yiaddr; /* 'your' client IP address */
|
||||
uint32_t siaddr; /* should be zero in client's messages */
|
||||
uint32_t giaddr; /* should be zero in client's messages */
|
||||
uint8_t chaddr[DHCP_CHADDR_LEN]; /* client's hardware address */
|
||||
uint8_t servername[SERVERNAME_LEN]; /* server host name */
|
||||
uint8_t bootfile[BOOTFILE_LEN]; /* boot file name */
|
||||
uint32_t cookie;
|
||||
uint8_t options[DHCP_OPTION_LEN]; /* message options - cookie */
|
||||
};
|
||||
|
||||
struct dhcp_lease {
|
||||
struct in_addr addr;
|
||||
struct in_addr net;
|
||||
uint32_t leasetime;
|
||||
uint32_t renewaltime;
|
||||
uint32_t rebindtime;
|
||||
struct in_addr server;
|
||||
uint32_t leasedfrom;
|
||||
uint8_t frominfo;
|
||||
};
|
||||
|
||||
#define add_reqmask(var, val) (var[val >> 3] |= 1 << (val & 7))
|
||||
#define del_reqmask(var, val) (var[val >> 3] &= ~(1 << (val & 7)))
|
||||
#define has_reqmask(var, val) (var[val >> 3] & (1 << (val & 7)))
|
||||
int make_reqmask(uint8_t *, char **, int);
|
||||
void print_options(void);
|
||||
char *get_option_string(const struct dhcp_message *, uint8_t);
|
||||
int get_option_addr(uint32_t *, const struct dhcp_message *, uint8_t);
|
||||
int get_option_uint32(uint32_t *, const struct dhcp_message *, uint8_t);
|
||||
int get_option_uint16(uint16_t *, const struct dhcp_message *, uint8_t);
|
||||
int get_option_uint8(uint8_t *, const struct dhcp_message *, uint8_t);
|
||||
struct rt *get_option_routes(const struct dhcp_message *);
|
||||
ssize_t configure_env(char **, const char *, const struct dhcp_message *,
|
||||
const struct options *);
|
||||
|
||||
ssize_t make_message(struct dhcp_message **,
|
||||
const struct interface *, const struct dhcp_lease *,
|
||||
uint32_t, uint8_t, const struct options *);
|
||||
int valid_dhcp_packet(unsigned char *);
|
||||
|
||||
ssize_t write_lease(const struct interface *, const struct dhcp_message *);
|
||||
struct dhcp_message *read_lease(const struct interface *iface);
|
||||
#endif
|
|
@ -0,0 +1,6 @@
|
|||
# Just echo our DHCP options we have
|
||||
|
||||
if [ "${reason}" = "TEST" ]; then
|
||||
set | grep "^\(interface\|metric\|pid\|reason\|skip_hooks\)=" | sort
|
||||
set | grep "^\(new_\|old_\)" | sort
|
||||
fi
|
|
@ -0,0 +1,5 @@
|
|||
# Configure the MTU for the interface
|
||||
|
||||
if [ -n "${new_interface_mtu}" ]; then
|
||||
ifconfig "${interface}" mtu "${new_interface_mtu}"
|
||||
fi
|
|
@ -0,0 +1,40 @@
|
|||
# Generate /etc/resolv.conf
|
||||
# Support resolvconf(8) if available
|
||||
|
||||
make_resolv_conf()
|
||||
{
|
||||
if [ -z "${new_domain_name_servers}" -a \
|
||||
-z "${new_domain_name}" -a \
|
||||
-z "${new_domain_search}" ]; then
|
||||
return 0
|
||||
fi
|
||||
local x= conf="${signature}\n"
|
||||
if [ -n "${new_domain_search}" ]; then
|
||||
conf="${conf}search ${new_domain_search}\n"
|
||||
elif [ -n "${new_domain_name}" ]; then
|
||||
conf="${conf}search ${new_domain_name}\n"
|
||||
fi
|
||||
for x in ${new_domain_name_servers}; do
|
||||
conf="${conf}nameserver ${x}\n"
|
||||
done
|
||||
if type resolvconf >/dev/null 2>&1; then
|
||||
printf "${conf}" | resolvconf -a "${interface}"
|
||||
else
|
||||
save_conf /etc/resolv.conf
|
||||
printf "${conf}" > /etc/resolv.conf
|
||||
fi
|
||||
}
|
||||
|
||||
restore_resolv_conf()
|
||||
{
|
||||
if type resolvconf >/dev/null 2>&1; then
|
||||
resolvconf -d "${interface}" -f
|
||||
else
|
||||
restore_conf /etc/resolv.conf || return 0
|
||||
fi
|
||||
}
|
||||
|
||||
case "${reason}" in
|
||||
BOUND|INFORM|REBIND|REBOOT|RENEW|TIMEOUT) make_resolv_conf;;
|
||||
EXPIRE|FAIL|IPV4LL|RELEASE|STOP) restore_resolv_conf;;
|
||||
esac
|
|
@ -0,0 +1,33 @@
|
|||
# Lookup the hostname in DNS if not set
|
||||
|
||||
lookup_hostname()
|
||||
{
|
||||
local h=
|
||||
# Silly ISC programs love to send error text to stdout
|
||||
if type dig >/dev/null 2>&1; then
|
||||
h=`dig +short -x ${new_ip_address}`
|
||||
if [ $? = 0 ]; then
|
||||
echo "${h}" | sed 's/\.$//'
|
||||
return 0
|
||||
fi
|
||||
elif type host >/dev/null 2>&1; then
|
||||
h=`host ${new_ip_address}`
|
||||
if [ $? = 0 ]; then
|
||||
echo "${h}" \
|
||||
| sed 's/.* domain name pointer \(.*\)./\1/'
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
set_hostname()
|
||||
{
|
||||
if [ -z "${new_host_name}" ]; then
|
||||
export new_host_name="$(lookup_hostname)"
|
||||
fi
|
||||
}
|
||||
|
||||
case "${reason}" in
|
||||
BOUND|INFORM|REBIND|REBOOT|RENEW|TIMEOUT) set_hostname;;
|
||||
esac
|
|
@ -0,0 +1,21 @@
|
|||
# Set the hostname from DHCP data if required
|
||||
|
||||
need_hostname()
|
||||
{
|
||||
case "$(hostname)" in
|
||||
""|"(none)"|localhost) [ -n "${new_host_name}" ];;
|
||||
"${old_host_name}") true;;
|
||||
*) false;;
|
||||
esac
|
||||
}
|
||||
|
||||
set_hostname()
|
||||
{
|
||||
if need_hostname; then
|
||||
hostname "${new_host_name}"
|
||||
fi
|
||||
}
|
||||
|
||||
case "${reason}" in
|
||||
BOUND|INFORM|REBIND|REBOOT|RENEW|TIMEOUT) set_hostname;;
|
||||
esac
|
|
@ -0,0 +1,51 @@
|
|||
# Sample dhcpcd hook script for ntp
|
||||
|
||||
# Detect OpenRC or BSD rc
|
||||
# Distributions may want to just have their command here instead of this
|
||||
if type rc-service >/dev/null 2>&1 && rc-service --exists ntpd; then
|
||||
ntpd_restart_cmd="rc-service ntpd -- --ifstarted --quiet restart"
|
||||
elif [ -x /etc/rc.d/ntpd ]; then
|
||||
ntpd_restart_cmd="/etc/rc.d/ntpd restart"
|
||||
elif [ -x /usr/local/etc/rc.d/ntpd ]; then
|
||||
ntpd_restart_cmd="/usr/local/etc/rc.d/ntpd restart"
|
||||
fi
|
||||
|
||||
make_ntp_conf()
|
||||
{
|
||||
[ -z "${new_ntp_servers}" ] && return 0
|
||||
local cf=/etc/ntp.conf."${interface}" x=
|
||||
echo "${signature}" > "${cf}"
|
||||
echo "restrict default noquery notrust nomodify" >> "${cf}"
|
||||
echo "restrict 127.0.0.1" >> "${cf}"
|
||||
for x in ${new_ntp_servers}; do
|
||||
echo "restrict ${x} nomodify notrap noquery" >> "${cf}"
|
||||
echo "server ${x}" >> "${cf}"
|
||||
done
|
||||
if [ ! -e /etc/ntp.conf ]; then
|
||||
false
|
||||
elif type cmp >/dev/null 2>&1; then
|
||||
cmp -s /etc/ntp.conf "${cf}"
|
||||
elif type diff >/dev/null 2>&1; then
|
||||
diff -q /etc/ntp.conf "${cf}" >/dev/null
|
||||
else
|
||||
false
|
||||
fi
|
||||
if [ $? = 0 ]; then
|
||||
rm -f "${cf}"
|
||||
else
|
||||
save_conf /etc/ntp.conf
|
||||
mv -f "${cf}" /etc/ntp.conf
|
||||
[ -n "${ntpd_restart_cmd}" ] && ${ntpd_restart_cmd}
|
||||
fi
|
||||
}
|
||||
|
||||
restore_ntp_conf()
|
||||
{
|
||||
restore_conf /etc/ntp.conf || return 0
|
||||
[ -n "${ntpd_restart_cmd}" ] && ${ntpd_restart_cmd}
|
||||
}
|
||||
|
||||
case "${reason}" in
|
||||
BOUND|INFORM|REBIND|REBOOT|RENEW|TIMEOUT) make_ntp_conf;;
|
||||
EXPIRE|FAIL|IPV4LL|RELEASE|STOP) restore_ntp_conf;;
|
||||
esac
|
|
@ -0,0 +1,108 @@
|
|||
.\" Copyright 2006-2008 Roy Marples
|
||||
.\" 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.
|
||||
.\"
|
||||
.Dd Jul 12, 2008
|
||||
.Dt DHCPCD.SH 8 SMM
|
||||
.Sh NAME
|
||||
.Nm dhcpcd-run-hooks
|
||||
.Nd DHCP client configuration script
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
is used by
|
||||
.Xr dhcpcd 8
|
||||
to run any system and user defined hook scripts.
|
||||
System hook scripts are found in
|
||||
.Pa @HOOKDIR@
|
||||
and the user defined hooks are
|
||||
.Pa @SYSCONFDIR@/dhcpcd.enter-hook .
|
||||
and
|
||||
.Pa @SYSCONFDIR@/dhcpcd.exit-hook .
|
||||
The default install supplies hook scripts for configuring
|
||||
.Pa /etc/resolv.conf
|
||||
and the hostname.
|
||||
Your distribution may have included other hook scripts to say configure
|
||||
ntp or ypbind.
|
||||
A test hook is also supplied that simply echos the dhcp variables to the
|
||||
console from DISCOVER message.
|
||||
.Pp
|
||||
Each time
|
||||
.Nm
|
||||
is invoked,
|
||||
.Ev $interface
|
||||
is set to the interface that
|
||||
.Nm dhcpcd
|
||||
is run on and
|
||||
.Ev $reason
|
||||
is to the reason why
|
||||
.Nm
|
||||
was invoked.
|
||||
DHCP information to be configured is held in variables starting with the word
|
||||
new_ and old DHCP information to be removed is held in variables starting with
|
||||
the word old_.
|
||||
.Nm dhcpcd
|
||||
can display the full list of variables it knows how about by using the
|
||||
.Fl V , -variables
|
||||
argument.
|
||||
.Pp
|
||||
Here's a list of reasons why
|
||||
.Nm
|
||||
could be invoked:
|
||||
.Bl -tag -width indent
|
||||
.It Dv BOUND
|
||||
dhcpcd obtained a new lease from a DHCP server.
|
||||
.It Dv RENEW
|
||||
dhcpcd renewed it's lease.
|
||||
.It Dv REBIND
|
||||
dhcpcd has rebound to a new DHCP server.
|
||||
.It Dv REBOOT
|
||||
dhcpcd successfully requested a lease from a DHCP server.
|
||||
.It Dv EXPIRE
|
||||
dhcpcd's lease expired and it failed to obtain a new one.
|
||||
.It Dv IPV4LL
|
||||
dhcpcd failed to contact any DHCP servers but did obtain an IPV4LL address.
|
||||
.It Dv FAIL
|
||||
dhcpcd failed to contact any DHCP servers or use an old lease.
|
||||
.It Dv TIMEOUT
|
||||
dhcpcd failed to contact any DHCP servers but was able to use an old lease.
|
||||
.It Dv TEST
|
||||
dhcpcd received an OFFER from a DHCP server but will not configure the
|
||||
interface.
|
||||
This is primarily used to test the variables are filled correctly for the
|
||||
script to process them.
|
||||
.El
|
||||
.Sh FILES
|
||||
When
|
||||
.Nm
|
||||
runs, it loads
|
||||
.Pa @SYSCONFDIR@/dhcpcd.enter-hook
|
||||
and any scripts found in
|
||||
.Pa @HOOKDIR@
|
||||
in a lexical order and then finally
|
||||
.Pa @SYSCONFDIR@/dhcpcd.exit-hook
|
||||
.Sh SEE ALSO
|
||||
.Xr dhcpcd 8
|
||||
.Sh AUTHORS
|
||||
.An Roy Marples <roy@marples.name>
|
||||
.Sh BUGS
|
||||
Please report them to http://bugs.marples.name
|
|
@ -0,0 +1,39 @@
|
|||
#!/bin/sh
|
||||
# dhcpcd client configuration script
|
||||
|
||||
# Handy functions for our hooks to use
|
||||
signature="# Generated by dhcpcd for ${interface}"
|
||||
save_conf()
|
||||
{
|
||||
if [ -f "$1" ]; then
|
||||
rm -f "$1"-pre."${interface}"
|
||||
mv -f "$1" "$1"-pre."${interface}"
|
||||
fi
|
||||
}
|
||||
restore_conf()
|
||||
{
|
||||
[ -f "$1"-pre."${interface}" ] || return 1
|
||||
rm -f "$1"
|
||||
mv -f "$1"-pre."${interface}" "$1"
|
||||
}
|
||||
|
||||
# We source each script into this one so that scripts run earlier can
|
||||
# remove variables from the environment so later scripts don't see them.
|
||||
# Thus, the user can create their dhcpcd.hook script to configure
|
||||
# /etc/resolv.conf how they want and stop the system scripts ever updating it.
|
||||
for hook in \
|
||||
@SYSCONFDIR@/dhcpcd.enter-hook \
|
||||
@HOOKDIR@/* \
|
||||
@SYSCONFDIR@/dhcpcd.exit-hook
|
||||
do
|
||||
for skip in ${skip_hooks}; do
|
||||
case "${hook}" in
|
||||
"${skip}") continue 2;;
|
||||
*/[0-9][0-9]"-${skip}") continue 2;;
|
||||
*/[0-9][0-9]"-${skip}.sh") continue 2;;
|
||||
esac
|
||||
done
|
||||
if [ -f "${hook}" ]; then
|
||||
. "${hook}"
|
||||
fi
|
||||
done
|
|
@ -0,0 +1,395 @@
|
|||
.\" Copyright 2006-2008 Roy Marples
|
||||
.\" 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.
|
||||
.\"
|
||||
.Dd Jul 18, 2008
|
||||
.Dt DHCPCD 8 SMM
|
||||
.Sh NAME
|
||||
.Nm dhcpcd
|
||||
.Nd an RFC 2131 compliant DHCP client
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl bdknpqABDEGKLSTV
|
||||
.Op Fl c , -script Ar script
|
||||
.Op Fl f , -config Ar file
|
||||
.Op Fl h , -hostname Ar hostname
|
||||
.Op Fl i , -classid Ar classid
|
||||
.Op Fl l , -leasetime Ar seconds
|
||||
.Op Fl m , -metric Ar metric
|
||||
.Op Fl o , -option Ar option
|
||||
.Op Fl r , -request Ar address
|
||||
.Op Fl s , -inform Ar address Ns Op Ar /cidr
|
||||
.Op Fl t , -timeout Ar seconds
|
||||
.Op Fl u , -userclass Ar class
|
||||
.Op Fl v , -vendor Ar code , Ar value
|
||||
.Op Fl C , -nohook Ar hook
|
||||
.Op Fl F , -fqdn Ar FQDN
|
||||
.Op Fl I , -clientid Ar clientid
|
||||
.Op Fl O , -nooption Ar option
|
||||
.Ar interface
|
||||
.Nm
|
||||
.Fl k , -release
|
||||
.Ar interface
|
||||
.Nm
|
||||
.Fl x , -exit
|
||||
.Ar interface
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
is an implementation of the DHCP client specified in
|
||||
.Rs
|
||||
.%T "RFC 2131"
|
||||
.Re
|
||||
.Nm
|
||||
gets the host information
|
||||
.Po
|
||||
IP address, routes, etc
|
||||
.Pc
|
||||
from a DHCP server and configures the network
|
||||
.Ar interface
|
||||
of the
|
||||
machine on which it is running.
|
||||
.Nm
|
||||
will then write DNS information to
|
||||
.Xr resolvconf 8 ,
|
||||
if available, otherwise directly to
|
||||
.Pa /etc/resolv.conf .
|
||||
If the hostname is currenly blank, (null) or localhost then
|
||||
.Nm
|
||||
will set the hostname to the one supplied by the DHCP server.
|
||||
.Nm
|
||||
then daemonises and waits for the lease renewal time to lapse.
|
||||
Then it attempts to renew its lease and reconfigure if the new lease changes.
|
||||
.Ss Local Link configuration
|
||||
If
|
||||
.Nm
|
||||
failed to obtain a lease, it will probe for a valid IPv4LL address
|
||||
.Po
|
||||
aka Zeroconf, aka APIPA
|
||||
.Pc .
|
||||
Once obtained it will restart the process of looking for a DHCP server to get a
|
||||
proper address.
|
||||
.Pp
|
||||
When using IPv4LL,
|
||||
.Nm
|
||||
will always succeed and return a 0 exit code. To disable this behaviour, you
|
||||
can use the
|
||||
.Fl L , -noipv4ll
|
||||
option.
|
||||
.Ss Hooking into DHCP events
|
||||
.Nm
|
||||
will run
|
||||
.Pa @SCRIPT@ ,
|
||||
or the script specified by the
|
||||
.Fl c , -script
|
||||
option.
|
||||
This script will run each script found in
|
||||
.Pa @HOOKDIR@
|
||||
in a lexical order.
|
||||
The default installation supplies the scripts
|
||||
.Pa 01-test ,
|
||||
.Pa 10-mtu ,
|
||||
.Pa 20-resolv.conf
|
||||
and
|
||||
.Pa 30-hostname .
|
||||
You can disable each script by using the
|
||||
.Fl C , -nohook
|
||||
option.
|
||||
See
|
||||
.Xr dhcpcd-run-hooks 8
|
||||
for details on how these scripts work.
|
||||
.Nm
|
||||
currently ignores the exit code of the script.
|
||||
.Ss Fine tuning
|
||||
You can fine tune the behaviour of
|
||||
.Nm
|
||||
with the following options:
|
||||
.Bl -tag -width indent
|
||||
.It Fl b , -background
|
||||
Background immediately.
|
||||
This is useful for startup scripts which don't disable link messages for
|
||||
carrier status.
|
||||
.It Fl c , -script Ar script
|
||||
Use this
|
||||
.Ar script
|
||||
instead of the default
|
||||
.Pa @SCRIPT@ .
|
||||
.It Fl d , -debug
|
||||
Echo debug and informational messages to the console.
|
||||
Subsequent debug options stop
|
||||
.Nm
|
||||
from daemonising.
|
||||
.It Fl f , -config Ar file
|
||||
Specify a config to load instead of
|
||||
.Pa @SYSCONFDIR@/dhcpcd.conf .
|
||||
.Nm
|
||||
always processes the config file before any command line options.
|
||||
.It Fl h , -hostname Ar hostname
|
||||
By default,
|
||||
.Nm
|
||||
will send the current hostname to the DHCP server so it can register in DNS.
|
||||
You can use this option to specify the
|
||||
.Ar hostname
|
||||
sent, or an empty string to
|
||||
stop any
|
||||
.Ar hostname
|
||||
from being sent.
|
||||
.It Fl i , -classid Ar classid
|
||||
Override the
|
||||
.Ar classid
|
||||
field sent. The default is
|
||||
dhcpcd <version>.
|
||||
If not set then none is sent.
|
||||
.It Fl k , -release
|
||||
This causes an existing
|
||||
.Nm
|
||||
process running on the
|
||||
.Ar interface
|
||||
to release its lease, deconfigure the
|
||||
.Ar interface
|
||||
and then exit.
|
||||
.It Fl l , -leasetime Ar seconds
|
||||
Request a specific lease time in
|
||||
.Ar seconds .
|
||||
By default
|
||||
.Nm
|
||||
does not request any lease time and leaves the it in the hands of the
|
||||
DHCP server.
|
||||
.It Fl m , -metric Ar metric
|
||||
Added routes will use the
|
||||
.Ar metric
|
||||
on systems where this is supported
|
||||
.Po
|
||||
presently only Linux
|
||||
.Pc .
|
||||
Route metrics allow the addition of routes to the same destination across
|
||||
different interfaces, the lower the metric the more it is preferred.
|
||||
.It Fl o , -option Ar option
|
||||
Request the DHCP
|
||||
.Ar option
|
||||
variable for use in
|
||||
.Pa @SCRIPT@ .
|
||||
.It Fl n , -renew
|
||||
Notifies an existing
|
||||
.Nm
|
||||
process running on the
|
||||
.Ar interface
|
||||
to renew it's lease. If
|
||||
.Nm
|
||||
is not running, then it starts up as normal.
|
||||
.It Fl p , -persistent
|
||||
.Nm
|
||||
normally deconfigures the
|
||||
.Ar interface
|
||||
and configuration when it exits.
|
||||
Sometimes, this isn't desirable if for example you have root mounted over NFS.
|
||||
You can use this option to stop this from happening.
|
||||
.It Fl r , -request Op Ar address
|
||||
.Nm
|
||||
normally sends a DHCP Broadcast to find servers to offer an address.
|
||||
.Nm
|
||||
will then request the address used.
|
||||
You can use this option to skip the broadcast step and just request an
|
||||
.Ar address .
|
||||
The downside is if you request an
|
||||
.Ar address
|
||||
the DHCP server does not know about or the DHCP server is not
|
||||
authorative, it will remain silent.
|
||||
In this situation, we go back to the init state and broadcast again.
|
||||
If no
|
||||
.Ar address
|
||||
is given then the first address currently assigned to the
|
||||
.Ar interface
|
||||
is used.
|
||||
.It Fl s , -inform Op Ar address Ns Op Ar /cidr
|
||||
Behaves exactly like
|
||||
.Fl r , -request
|
||||
as above, but sends a DHCP INFORM instead of a REQUEST.
|
||||
This does not get a lease as such, just notifies the DHCP server of the
|
||||
.Ar address
|
||||
in use.
|
||||
.Nm
|
||||
remains running and pretends it has an infinite lease.
|
||||
.Nm
|
||||
will not de-configure the interface when it exits.
|
||||
If
|
||||
.Nm
|
||||
fails to contact a DHCP server then it returns a failure instead of falling
|
||||
back on IPv4LL.
|
||||
.It Fl t , -timeout Ar seconds
|
||||
Timeout after
|
||||
.Ar seconds ,
|
||||
instead of the default 30.
|
||||
A setting of 0
|
||||
.Ar seconds
|
||||
causes
|
||||
.Nm
|
||||
to wait forever to get a lease.
|
||||
.It Fl u , -userclass Ar class
|
||||
Tags the DHCP message with the userclass
|
||||
.Ar class .
|
||||
DHCP servers use this give members of the class DHCP options other than the
|
||||
default, without having to know things like hardware address or hostname.
|
||||
.It Fl v , -vendor Ar code , Ns Ar value
|
||||
Add an enscapulated vendor option.
|
||||
.Ar code
|
||||
should be between 1 and 254 inclusive.
|
||||
Examples.
|
||||
.Pp
|
||||
Set the vendor option 01 with an IP address.
|
||||
.D1 dhcpcd -v 01,192.168.0.2 eth0
|
||||
Set the vendor option 02 with a hex code.
|
||||
.D1 dhcpcd -v 02,01:02:03:04:05 eth0
|
||||
Do the above and set a third option with a string and not an IP address.
|
||||
.D1 dhcpcd -v 01,192.168.0.2 -v 02,01:02:03:04:05 -v 03,\e"192.168.0.2\e" eth0
|
||||
.It Fl x , -exit
|
||||
This causes an existing
|
||||
.Nm
|
||||
process running on the
|
||||
.Ar interface
|
||||
to deconfigure the
|
||||
.Ar interface
|
||||
and exit.
|
||||
.It Fl D , -duid
|
||||
Generate an
|
||||
.Rs
|
||||
.%T "RFC 4361"
|
||||
.Re
|
||||
compliant clientid.
|
||||
This requires persistent storage and not all DHCP servers work with it so it's
|
||||
not enabled by default.
|
||||
The DUID generated will be held in
|
||||
.Pa @SYSCONFDIR@/dhcpcd.duid
|
||||
and should not be copied to other hosts.
|
||||
.It Fl E , -lastlease
|
||||
If
|
||||
.Nm
|
||||
cannot obtain a lease, then try to use the last lease acquired for the
|
||||
interface.
|
||||
If the
|
||||
.Fl p, -persistent
|
||||
option is not given then the lease is used if it hasn't expired.
|
||||
.It Fl F , -fqdn Ar fqdn
|
||||
Requests that the DHCP server updates DNS using FQDN instead of just a
|
||||
hostname.
|
||||
Valid values for
|
||||
.Ar fqdn
|
||||
are none, ptr and both.
|
||||
The current hostname or the hostname specified using the
|
||||
.Fl h , -hostname
|
||||
option must be a FQDN.
|
||||
.Nm
|
||||
itself never does any DNS updates.
|
||||
.It Fl I , -clientid Ar clientid
|
||||
Change the default clientid sent from the interface hardware address.
|
||||
If the string is of the format 01:02:03 then it is encoded as hex.
|
||||
If not set then none is sent.
|
||||
.El
|
||||
.Ss Restriciting behaviour
|
||||
.Nm
|
||||
will try to do as much as it can by default.
|
||||
However, there are sometimes situations where you don't want the things to be
|
||||
configured exactly how the the DHCP server wants.
|
||||
Here are some options that deal with turning these bits off.
|
||||
.Bl -tag -width indent
|
||||
.It Fl q , -quiet
|
||||
Quiet
|
||||
.Nm
|
||||
on the command line, only warnings and errors will be displayed.
|
||||
The messages are still logged though.
|
||||
.It Fl A , -noarp
|
||||
Don't request or claim the address by ARP.
|
||||
This also disables IPv4LL.
|
||||
.It Fl B , -nobackground
|
||||
Don't run in the background when we acquire a lease.
|
||||
This is mainly useful for running under the control of another process, such
|
||||
as a debugger or a network manager.
|
||||
.It Fl C , -nohook Ar script
|
||||
Don't run this hook script.
|
||||
Matches full name, or prefixed with 2 numbers optionally ending with
|
||||
.Pa .sh .
|
||||
.Pp
|
||||
So to stop dhcpcd from touching your DNS or MTU settings you would do:-
|
||||
.D1 dhcpcd -C resolv.conf -C mtu eth0
|
||||
.It Fl G , -nogateway
|
||||
Don't set any default routes.
|
||||
.It Fl K , -nolink
|
||||
Don't receive link messages for carrier status.
|
||||
You should only have to use this with buggy device drivers or running
|
||||
.Nm
|
||||
through a network manager.
|
||||
.It Fl L , -noipv4ll
|
||||
Don't use IPv4LL (aka APIPA, aka Bonjour, aka ZeroConf).
|
||||
.It Fl O , -nooption Ar option
|
||||
Don't request the specified option.
|
||||
If no option given, then don't request any options other than those to
|
||||
configure the interface and routing.
|
||||
.It Fl T, -test
|
||||
On receipt of OFFER messages just call
|
||||
.Pa @SCRIPT@
|
||||
with the reason of TEST which echo's the DHCP variables found in the message
|
||||
to the console.
|
||||
The interface configuration isn't touched and neither are any configuration
|
||||
files.
|
||||
.It Fl V, -variables
|
||||
Display a list of option codes and the associated variable for use in
|
||||
.Xr dhcpcd-run-hooks 8 .
|
||||
.El
|
||||
.Sh NOTES
|
||||
.Nm
|
||||
requires a Berkley Packet Filter, or BPF device on BSD based systems and a
|
||||
Linux Socket Filter, or LPF device on Linux based systems.
|
||||
.Sh FILES
|
||||
.Bl -ohang
|
||||
.It Pa @SYSCONFDIR@/dhcpcd.conf
|
||||
Configuration file for dhcpcd.
|
||||
If you always use the same options, put them here.
|
||||
.It Pa @SYSCONFDIR@/dhcpcd.duid
|
||||
Text file that holds the DUID used to identify the host.
|
||||
.It Pa @SCRIPT@
|
||||
Bourne shell script that is run to configure or deconfigure an interface.
|
||||
.It Pa @HOOKDIR@
|
||||
A directory containing bourne shell scripts that are run by the above script.
|
||||
Each script can be disabled by using the
|
||||
.Fl C , -nohook
|
||||
option described above.
|
||||
.It Pa @DBDIR@/dhcpcd\- Ns Ar interface Ns .lease
|
||||
The actual DHCP message send by the server. We use this when reading the last
|
||||
lease and use the files mtime as when it was issued.
|
||||
.It Pa /var/run/dhcpcd\- Ns Ar interface Ns .pid
|
||||
Stores the PID of
|
||||
.Nm
|
||||
running on the
|
||||
.Ar interface .
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr dhcpcd.conf 5 ,
|
||||
.Xr dhcpcd-run-hooks 8 ,
|
||||
.Xr resolv.conf 5 ,
|
||||
.Xr resolvconf 8 ,
|
||||
.Sh STANDARDS
|
||||
RFC 2131, RFC 2132, RFC 2855, RFC 3004, RFC 3361, RFC 3396, RFC 3397,
|
||||
RFC 3442, RFC 3927, RFC 4361, RFC 4390, RFC 4702.
|
||||
.Sh AUTHORS
|
||||
.An Roy Marples <roy@marples.name>
|
||||
.Sh BUGS
|
||||
Please report them to http://bugs.marples.name
|
|
@ -0,0 +1,996 @@
|
|||
/*
|
||||
* dhcpcd - DHCP client daemon
|
||||
* Copyright 2006-2008 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.
|
||||
*/
|
||||
|
||||
const char copyright[] = "Copyright (c) 2006-2008 Roy Marples";
|
||||
|
||||
#include <sys/file.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <getopt.h>
|
||||
#include <paths.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "client.h"
|
||||
#include "dhcpcd.h"
|
||||
#include "dhcp.h"
|
||||
#include "net.h"
|
||||
#include "logger.h"
|
||||
|
||||
/* Don't set any optional arguments here so we retain POSIX
|
||||
* compatibility with getopt */
|
||||
#define OPTS "bc:df:h:i:kl:m:no:pqr:s:t:u:v:xABC:DEF:GI:KLO:TV"
|
||||
|
||||
static int doversion = 0;
|
||||
static int dohelp = 0;
|
||||
static const struct option longopts[] = {
|
||||
{"background", no_argument, NULL, 'b'},
|
||||
{"script", required_argument, NULL, 'c'},
|
||||
{"debug", no_argument, NULL, 'd'},
|
||||
{"config", required_argument, NULL, 'f'},
|
||||
{"hostname", optional_argument, NULL, 'h'},
|
||||
{"classid", optional_argument, NULL, 'i'},
|
||||
{"release", no_argument, NULL, 'k'},
|
||||
{"leasetime", required_argument, NULL, 'l'},
|
||||
{"metric", required_argument, NULL, 'm'},
|
||||
{"renew", no_argument, NULL, 'n'},
|
||||
{"option", required_argument, NULL, 'o'},
|
||||
{"persistent", no_argument, NULL, 'p'},
|
||||
{"quiet", no_argument, NULL, 'q'},
|
||||
{"inform", optional_argument, NULL, 's'},
|
||||
{"request", optional_argument, NULL, 'r'},
|
||||
{"timeout", required_argument, NULL, 't'},
|
||||
{"userclass", required_argument, NULL, 'u'},
|
||||
{"vendor", required_argument, NULL, 'v'},
|
||||
{"exit", no_argument, NULL, 'x'},
|
||||
{"noarp", no_argument, NULL, 'A'},
|
||||
{"nobackground",no_argument, NULL, 'B'},
|
||||
{"nohook", required_argument, NULL, 'C'},
|
||||
{"duid", no_argument, NULL, 'D'},
|
||||
{"lastlease", no_argument, NULL, 'E'},
|
||||
{"fqdn", optional_argument, NULL, 'F'},
|
||||
{"nogateway", no_argument, NULL, 'G'},
|
||||
{"clientid", optional_argument, NULL, 'I'},
|
||||
{"nolink", no_argument, NULL, 'K'},
|
||||
{"noipv4ll", no_argument, NULL, 'L'},
|
||||
{"nooption", optional_argument, NULL, 'O'},
|
||||
{"test", no_argument, NULL, 'T'},
|
||||
{"variables", no_argument, NULL, 'V'},
|
||||
{"help", no_argument, &dohelp, 1},
|
||||
{"version", no_argument, &doversion, 1},
|
||||
#ifdef THERE_IS_NO_FORK
|
||||
{"daemonised", no_argument, NULL, 'z'},
|
||||
{"skiproutes", required_argument, NULL, 'Z'},
|
||||
#endif
|
||||
#ifdef CMDLINE_COMPAT
|
||||
{"nohostname", no_argument, NULL, 'H'},
|
||||
{"nomtu", no_argument, NULL, 'M'},
|
||||
{"nontp", no_argument, NULL, 'N'},
|
||||
{"nodns", no_argument, NULL, 'R'},
|
||||
{"msscr", no_argument, NULL, 'S'},
|
||||
{"nonis", no_argument, NULL, 'Y'},
|
||||
#endif
|
||||
{NULL, 0, NULL, '\0'}
|
||||
};
|
||||
|
||||
#ifdef THERE_IS_NO_FORK
|
||||
char dhcpcd[PATH_MAX];
|
||||
char **dhcpcd_argv = NULL;
|
||||
int dhcpcd_argc = 0;
|
||||
char *dhcpcd_skiproutes = NULL;
|
||||
#define EXTRA_OPTS "zZ:"
|
||||
#endif
|
||||
|
||||
#ifdef CMDLINE_COMPAT
|
||||
# define EXTRA_OPTS "HMNRSY"
|
||||
#endif
|
||||
|
||||
#ifndef EXTRA_OPTS
|
||||
# define EXTRA_OPTS
|
||||
#endif
|
||||
|
||||
static int
|
||||
atoint(const char *s)
|
||||
{
|
||||
char *t;
|
||||
long n;
|
||||
|
||||
errno = 0;
|
||||
n = strtol(s, &t, 0);
|
||||
if ((errno != 0 && n == 0) || s == t ||
|
||||
(errno == ERANGE && (n == LONG_MAX || n == LONG_MIN)))
|
||||
{
|
||||
logger(LOG_ERR, "`%s' out of range", s);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return (int)n;
|
||||
}
|
||||
|
||||
static pid_t
|
||||
read_pid(const char *pidfile)
|
||||
{
|
||||
FILE *fp;
|
||||
pid_t pid = 0;
|
||||
|
||||
if ((fp = fopen(pidfile, "r")) == NULL) {
|
||||
errno = ENOENT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
fscanf(fp, "%d", &pid);
|
||||
fclose(fp);
|
||||
|
||||
return pid;
|
||||
}
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
#ifndef MINIMAL
|
||||
printf("usage: "PACKAGE" [-dknpqxADEGHKLOTV] [-c script] [-f file ] [-h hostname]\n"
|
||||
" [-i classID ] [-l leasetime] [-m metric] [-o option] [-r ipaddr]\n"
|
||||
" [-s ipaddr] [-t timeout] [-u userclass] [-F none|ptr|both]\n"
|
||||
" [-I clientID] [-C hookscript] <interface>\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
static char *
|
||||
add_environ(struct options *options, const char *value, int uniq)
|
||||
{
|
||||
char **newlist;
|
||||
char **lst = options->environ;
|
||||
size_t i = 0, l, lv;
|
||||
char *match = NULL, *p;
|
||||
|
||||
match = xstrdup(value);
|
||||
p = strchr(match, '=');
|
||||
if (p)
|
||||
*p++ = '\0';
|
||||
l = strlen(match);
|
||||
|
||||
while (lst && lst[i]) {
|
||||
if (match && strncmp(lst[i], match, l) == 0) {
|
||||
if (uniq) {
|
||||
free(lst[i]);
|
||||
lst[i] = xstrdup(value);
|
||||
} else {
|
||||
/* Append a space and the value to it */
|
||||
l = strlen(lst[i]);
|
||||
lv = strlen(p);
|
||||
lst[i] = xrealloc(lst[i], l + lv + 2);
|
||||
lst[i][l] = ' ';
|
||||
memcpy(lst[i] + l + 1, p, lv);
|
||||
lst[i][l + lv + 1] = '\0';
|
||||
}
|
||||
free(match);
|
||||
return lst[i];
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
newlist = xrealloc(lst, sizeof(char *) * (i + 2));
|
||||
newlist[i] = xstrdup(value);
|
||||
newlist[i + 1] = NULL;
|
||||
options->environ = newlist;
|
||||
free(match);
|
||||
return newlist[i];
|
||||
}
|
||||
|
||||
#ifndef MINIMAL
|
||||
#define parse_string(buf, len, arg) parse_string_hwaddr(buf, len, arg, 0)
|
||||
static ssize_t
|
||||
parse_string_hwaddr(char *sbuf, ssize_t slen, char *str, int clid)
|
||||
{
|
||||
ssize_t l;
|
||||
char *p;
|
||||
int i;
|
||||
char c[4];
|
||||
|
||||
/* If surrounded by quotes then it's a string */
|
||||
if (*str == '"') {
|
||||
str++;
|
||||
l = strlen(str);
|
||||
p = str + l - 1;
|
||||
if (*p == '"')
|
||||
*p = '\0';
|
||||
} else {
|
||||
l = hwaddr_aton(NULL, str);
|
||||
if (l > 1) {
|
||||
if (l > slen) {
|
||||
errno = ENOBUFS;
|
||||
return -1;
|
||||
}
|
||||
hwaddr_aton((uint8_t *)sbuf, str);
|
||||
return l;
|
||||
}
|
||||
}
|
||||
|
||||
/* Process escapes */
|
||||
l = 0;
|
||||
/* If processing a string on the clientid, first byte should be
|
||||
* 0 to indicate a non hardware type */
|
||||
if (clid) {
|
||||
*sbuf++ = 0;
|
||||
l++;
|
||||
}
|
||||
c[3] = '\0';
|
||||
while (*str) {
|
||||
if (++l > slen) {
|
||||
errno = ENOBUFS;
|
||||
return -1;
|
||||
}
|
||||
if (*str == '\\') {
|
||||
str++;
|
||||
switch(*str++) {
|
||||
case '\0':
|
||||
break;
|
||||
case 'b':
|
||||
*sbuf++ = '\b';
|
||||
break;
|
||||
case 'n':
|
||||
*sbuf++ = '\n';
|
||||
break;
|
||||
case 'r':
|
||||
*sbuf++ = '\r';
|
||||
break;
|
||||
case 't':
|
||||
*sbuf++ = '\t';
|
||||
break;
|
||||
case 'x':
|
||||
/* Grab a hex code */
|
||||
c[1] = '\0';
|
||||
for (i = 0; i < 2; i++) {
|
||||
if (isxdigit((unsigned char)*str) == 0)
|
||||
break;
|
||||
c[i] = *str++;
|
||||
}
|
||||
if (c[1] != '\0') {
|
||||
c[2] = '\0';
|
||||
*sbuf++ = strtol(c, NULL, 16);
|
||||
} else
|
||||
l--;
|
||||
break;
|
||||
case '0':
|
||||
/* Grab an octal code */
|
||||
c[2] = '\0';
|
||||
for (i = 0; i < 3; i++) {
|
||||
if (*str < '0' || *str > '7')
|
||||
break;
|
||||
c[i] = *str++;
|
||||
}
|
||||
if (c[2] != '\0') {
|
||||
i = strtol(c, NULL, 8);
|
||||
if (i > 255)
|
||||
i = 255;
|
||||
*sbuf ++= i;
|
||||
} else
|
||||
l--;
|
||||
break;
|
||||
default:
|
||||
*sbuf++ = *str++;
|
||||
}
|
||||
} else
|
||||
*sbuf++ = *str++;
|
||||
}
|
||||
return l;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
parse_option(int opt, char *oarg, struct options *options)
|
||||
{
|
||||
int i;
|
||||
char *p;
|
||||
ssize_t s;
|
||||
#ifndef MINIMAL
|
||||
struct in_addr addr;
|
||||
#endif
|
||||
|
||||
switch(opt) {
|
||||
case 'b':
|
||||
options->options |= DHCPCD_BACKGROUND;
|
||||
break;
|
||||
case 'c':
|
||||
strlcpy(options->script, oarg, sizeof(options->script));
|
||||
break;
|
||||
case 'h':
|
||||
#ifndef MINIMAL
|
||||
if (oarg)
|
||||
s = parse_string(options->hostname + 1,
|
||||
MAXHOSTNAMELEN, oarg);
|
||||
else
|
||||
s = 0;
|
||||
if (s == -1) {
|
||||
logger(LOG_ERR, "hostname: %s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
options->hostname[0] = (uint8_t)s;
|
||||
#endif
|
||||
break;
|
||||
case 'i':
|
||||
#ifndef MINIMAL
|
||||
if (oarg)
|
||||
s = parse_string((char *)options->classid + 1,
|
||||
CLASSID_MAX_LEN, oarg);
|
||||
else
|
||||
s = 0;
|
||||
if (s == -1) {
|
||||
logger(LOG_ERR, "classid: %s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
*options->classid = (uint8_t)s;
|
||||
#endif
|
||||
break;
|
||||
case 'l':
|
||||
#ifndef MINIMAL
|
||||
if (*oarg == '-') {
|
||||
logger(LOG_ERR,
|
||||
"leasetime must be a positive value");
|
||||
return -1;
|
||||
}
|
||||
errno = 0;
|
||||
options->leasetime = (uint32_t)strtol(oarg, NULL, 0);
|
||||
if (errno == EINVAL || errno == ERANGE) {
|
||||
logger(LOG_ERR, "`%s' out of range", oarg);
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case 'm':
|
||||
options->metric = atoint(oarg);
|
||||
if (options->metric < 0) {
|
||||
logger(LOG_ERR, "metric must be a positive value");
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case 'o':
|
||||
if (make_reqmask(options->reqmask, &oarg, 1) != 0) {
|
||||
logger(LOG_ERR, "unknown option `%s'", oarg);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case 'p':
|
||||
options->options |= DHCPCD_PERSISTENT;
|
||||
break;
|
||||
case 'q':
|
||||
setloglevel(LOG_WARNING);
|
||||
break;
|
||||
case 's':
|
||||
options->options |= DHCPCD_INFORM;
|
||||
options->options |= DHCPCD_PERSISTENT;
|
||||
options->options &= ~DHCPCD_ARP;
|
||||
if (!oarg || *oarg == '\0') {
|
||||
options->request_address.s_addr = 0;
|
||||
break;
|
||||
} else {
|
||||
if ((p = strchr(oarg, '/'))) {
|
||||
/* nullify the slash, so the -r option
|
||||
* can read the address */
|
||||
*p++ = '\0';
|
||||
if (sscanf(p, "%d", &i) != 1 ||
|
||||
inet_cidrtoaddr(i, &options->request_netmask) != 0)
|
||||
{
|
||||
logger(LOG_ERR,
|
||||
"`%s' is not a valid CIDR",
|
||||
p);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* FALLTHROUGH */
|
||||
case 'r':
|
||||
if (!(options->options & DHCPCD_INFORM))
|
||||
options->options |= DHCPCD_REQUEST;
|
||||
if (*oarg && !inet_aton(oarg, &options->request_address)) {
|
||||
logger(LOG_ERR, "`%s' is not a valid IP address",
|
||||
oarg);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case 't':
|
||||
options->timeout = atoint(oarg);
|
||||
if (options->timeout < 0) {
|
||||
logger (LOG_ERR, "timeout must be a positive value");
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case 'u':
|
||||
#ifndef MINIMAL
|
||||
s = USERCLASS_MAX_LEN - options->userclass[0] - 1;
|
||||
s = parse_string((char *)options->userclass + options->userclass[0] + 2,
|
||||
s, oarg);
|
||||
if (s == -1) {
|
||||
logger(LOG_ERR, "userclass: %s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
if (s != 0) {
|
||||
options->userclass[options->userclass[0] + 1] = s;
|
||||
options->userclass[0] += s + 1;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case 'v':
|
||||
#ifndef MINIMAL
|
||||
p = strchr(oarg, ',');
|
||||
if (!p || !p[1]) {
|
||||
logger(LOG_ERR, "invalid vendor format");
|
||||
return -1;
|
||||
}
|
||||
*p = '\0';
|
||||
i = atoint(oarg);
|
||||
oarg = p + 1;
|
||||
if (i < 1 || i > 254) {
|
||||
logger(LOG_ERR, "vendor option should be between"
|
||||
" 1 and 254 inclusive");
|
||||
return -1;
|
||||
}
|
||||
s = VENDOR_MAX_LEN - options->vendor[0] - 2;
|
||||
if (inet_aton(oarg, &addr) == 1) {
|
||||
if (s < 6) {
|
||||
s = -1;
|
||||
errno = ENOBUFS;
|
||||
} else
|
||||
memcpy(options->vendor + options->vendor[0] + 3,
|
||||
&addr.s_addr, sizeof(addr.s_addr));
|
||||
} else {
|
||||
s = parse_string((char *)options->vendor + options->vendor[0] + 3,
|
||||
s, oarg);
|
||||
}
|
||||
if (s == -1) {
|
||||
logger(LOG_ERR, "vendor: %s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
if (s != 0) {
|
||||
options->vendor[options->vendor[0] + 1] = i;
|
||||
options->vendor[options->vendor[0] + 2] = s;
|
||||
options->vendor[0] += s + 2;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case 'A':
|
||||
options->options &= ~DHCPCD_ARP;
|
||||
/* IPv4LL requires ARP */
|
||||
options->options &= ~DHCPCD_IPV4LL;
|
||||
break;
|
||||
case 'B':
|
||||
options->options &= ~DHCPCD_DAEMONISE;
|
||||
break;
|
||||
case 'C':
|
||||
/* Commas to spaces for shell */
|
||||
while ((p = strchr(oarg, ',')))
|
||||
*p = ' ';
|
||||
s = strlen("skip_hooks=") + strlen(oarg) + 1;
|
||||
p = xmalloc(sizeof(char) * s);
|
||||
snprintf(p, s, "skip_hooks=%s", oarg);
|
||||
add_environ(options, p, 0);
|
||||
free(p);
|
||||
break;
|
||||
case 'D':
|
||||
options->options |= DHCPCD_DUID;
|
||||
break;
|
||||
case 'E':
|
||||
options->options |= DHCPCD_LASTLEASE;
|
||||
break;
|
||||
case 'F':
|
||||
#ifndef MINIMAL
|
||||
if (!oarg) {
|
||||
options->fqdn = FQDN_BOTH;
|
||||
break;
|
||||
}
|
||||
if (strcmp(oarg, "none") == 0)
|
||||
options->fqdn = FQDN_NONE;
|
||||
else if (strcmp(oarg, "ptr") == 0)
|
||||
options->fqdn = FQDN_PTR;
|
||||
else if (strcmp(oarg, "both") == 0)
|
||||
options->fqdn = FQDN_BOTH;
|
||||
else {
|
||||
logger(LOG_ERR, "invalid value `%s' for FQDN",
|
||||
oarg);
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case 'G':
|
||||
options->options &= ~DHCPCD_GATEWAY;
|
||||
break;
|
||||
case 'I':
|
||||
#ifndef MINIMAL
|
||||
/* Strings have a type of 0 */;
|
||||
options->classid[1] = 0;
|
||||
if (oarg)
|
||||
s = parse_string_hwaddr((char *)options->clientid + 1,
|
||||
CLIENTID_MAX_LEN, oarg, 1);
|
||||
else
|
||||
s = 0;
|
||||
if (s == -1) {
|
||||
logger(LOG_ERR, "clientid: %s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
options->clientid[0] = (uint8_t)s;
|
||||
if (s == 0) {
|
||||
options->options &= ~DHCPCD_DUID;
|
||||
options->options &= ~DHCPCD_CLIENTID;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case 'K':
|
||||
options->options &= ~DHCPCD_LINK;
|
||||
break;
|
||||
case 'L':
|
||||
options->options &= ~DHCPCD_IPV4LL;
|
||||
break;
|
||||
case 'O':
|
||||
if (make_reqmask(options->reqmask, &optarg, -1) != 0 ||
|
||||
make_reqmask(options->nomask, &optarg, 1) != 0)
|
||||
{
|
||||
logger(LOG_ERR, "unknown option `%s'", optarg);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
parse_config_line(const char *opt, char *line, struct options *options)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < sizeof(longopts) / sizeof(longopts[0]); i++) {
|
||||
if (!longopts[i].name ||
|
||||
strcmp(longopts[i].name, opt) != 0)
|
||||
continue;
|
||||
|
||||
if (longopts[i].has_arg == required_argument && !line) {
|
||||
fprintf(stderr,
|
||||
PACKAGE ": option requires an argument -- %s\n",
|
||||
opt);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return parse_option(longopts[i].val, line, options);
|
||||
}
|
||||
|
||||
fprintf(stderr, PACKAGE ": unknown option -- %s\n", opt);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
struct options *options;
|
||||
int opt;
|
||||
int option_index = 0;
|
||||
char *prefix;
|
||||
pid_t pid;
|
||||
int debug = 0;
|
||||
int i, r;
|
||||
int pid_fd = -1;
|
||||
int sig = 0;
|
||||
int retval = EXIT_FAILURE;
|
||||
char *line, *option, *p, *buffer = NULL;
|
||||
size_t len = 0;
|
||||
FILE *f;
|
||||
char *cf = NULL;
|
||||
char *intf = NULL;
|
||||
#ifdef THERE_IS_NO_FORK
|
||||
char argvp[PATH_MAX];
|
||||
char *path, *token;
|
||||
struct stat sb;
|
||||
#endif
|
||||
|
||||
closefrom(3);
|
||||
openlog(PACKAGE, LOG_PID, LOG_LOCAL0);
|
||||
setlogprefix(PACKAGE ": ");
|
||||
|
||||
options = xzalloc(sizeof(*options));
|
||||
options->options |= DHCPCD_CLIENTID | DHCPCD_GATEWAY | DHCPCD_DAEMONISE;
|
||||
options->options |= DHCPCD_ARP | DHCPCD_IPV4LL | DHCPCD_LINK;
|
||||
options->timeout = DEFAULT_TIMEOUT;
|
||||
strlcpy(options->script, SCRIPT, sizeof(options->script));
|
||||
|
||||
options->classid[0] = snprintf((char *)options->classid + 1, CLASSID_MAX_LEN,
|
||||
"%s %s", PACKAGE, VERSION);
|
||||
|
||||
#ifdef CMDLINE_COMPAT
|
||||
add_reqmask(options->reqmask, DHCP_DNSSERVER);
|
||||
add_reqmask(options->reqmask, DHCP_DNSDOMAIN);
|
||||
add_reqmask(options->reqmask, DHCP_DNSSEARCH);
|
||||
add_reqmask(options->reqmask, DHCP_NISSERVER);
|
||||
add_reqmask(options->reqmask, DHCP_NISDOMAIN);
|
||||
add_reqmask(options->reqmask, DHCP_NTPSERVER);
|
||||
|
||||
/* If the duid file exists, then enable duid by default
|
||||
* This means we don't break existing clients that easily :) */
|
||||
if ((f = fopen(DUID, "r"))) {
|
||||
options->options |= DHCPCD_DUID;
|
||||
fclose(f);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef THERE_IS_NO_FORK
|
||||
dhcpcd_argv = argv;
|
||||
dhcpcd_argc = argc;
|
||||
if (*argv[0] == '/' || *argv[0] == '.')
|
||||
strncpy(argvp, argv[0], sizeof(argvp));
|
||||
else {
|
||||
p = path = xstrdup(getenv("PATH"));
|
||||
while ((token = strsep(&p, ":"))) {
|
||||
snprintf(argvp, sizeof(argvp), "%s/%s", token, argv[0]);
|
||||
if (stat(argvp, &sb) == 0)
|
||||
break;
|
||||
}
|
||||
free(path);
|
||||
}
|
||||
if (!realpath(argvp, dhcpcd)) {
|
||||
logger(LOG_ERR, "unable to resolve the path `%s': %s\n",
|
||||
argv[0], strerror(errno));
|
||||
goto abort;
|
||||
}
|
||||
#endif
|
||||
|
||||
gethostname(options->hostname + 1, sizeof(options->hostname));
|
||||
if (strcmp(options->hostname + 1, "(none)") == 0 ||
|
||||
strcmp(options->hostname + 1, "localhost") == 0)
|
||||
options->hostname[1] = '\0';
|
||||
*options->hostname = strlen(options->hostname + 1);
|
||||
|
||||
while ((opt = getopt_long(argc, argv, OPTS EXTRA_OPTS,
|
||||
longopts, &option_index)) != -1)
|
||||
{
|
||||
switch (opt) {
|
||||
case 0:
|
||||
if (longopts[option_index].flag)
|
||||
break;
|
||||
logger(LOG_ERR, "option `%s' should set a flag",
|
||||
longopts[option_index].name);
|
||||
goto abort;
|
||||
case 'f':
|
||||
cf = optarg;
|
||||
break;
|
||||
case 'V':
|
||||
print_options();
|
||||
goto abort;
|
||||
case '?':
|
||||
usage();
|
||||
goto abort;
|
||||
}
|
||||
}
|
||||
|
||||
if (doversion)
|
||||
printf(""PACKAGE" "VERSION"\n%s\n", copyright);
|
||||
|
||||
if (dohelp)
|
||||
usage();
|
||||
|
||||
if (optind < argc) {
|
||||
if (strlen(argv[optind]) >= IF_NAMESIZE) {
|
||||
logger(LOG_ERR,
|
||||
"`%s' too long for an interface name (max=%d)",
|
||||
argv[optind], IF_NAMESIZE);
|
||||
goto abort;
|
||||
}
|
||||
strlcpy(options->interface, argv[optind],
|
||||
sizeof(options->interface));
|
||||
} else {
|
||||
/* If only version was requested then exit now */
|
||||
if (doversion || dohelp) {
|
||||
retval = 0;
|
||||
goto abort;
|
||||
}
|
||||
|
||||
logger(LOG_ERR, "no interface specified");
|
||||
goto abort;
|
||||
}
|
||||
|
||||
/* Parse our options file */
|
||||
f = fopen(cf ? cf : CONFIG, "r");
|
||||
if (f) {
|
||||
r = 1;
|
||||
while ((get_line(&buffer, &len, f))) {
|
||||
line = buffer;
|
||||
while ((option = strsep(&line, " \t")))
|
||||
if (*option != '\0')
|
||||
break;
|
||||
if (!option || *option == '\0' || *option == '#')
|
||||
continue;
|
||||
/* Trim leading whitespace */
|
||||
if (line) {
|
||||
while (*line != '\0' && (*line == ' ' || *line == '\t'))
|
||||
line++;
|
||||
}
|
||||
/* Trim trailing whitespace */
|
||||
if (line && *line) {
|
||||
p = line + strlen(line) - 1;
|
||||
while (p != line &&
|
||||
(*p == ' ' || *p == '\t') &&
|
||||
*(p - 1) != '\\')
|
||||
*p-- = '\0';
|
||||
}
|
||||
if (strcmp(option, "interface") == 0) {
|
||||
free(intf);
|
||||
intf = xstrdup(line);
|
||||
continue;
|
||||
}
|
||||
/* If we're in an interface block don't use these
|
||||
* options unless it's for us */
|
||||
if (intf && strcmp(intf, options->interface) != 0)
|
||||
continue;
|
||||
r = parse_config_line(option, line, options);
|
||||
if (r != 1)
|
||||
break;
|
||||
}
|
||||
free(buffer);
|
||||
free(intf);
|
||||
fclose(f);
|
||||
if (r == 0)
|
||||
usage();
|
||||
if (r != 1)
|
||||
goto abort;
|
||||
} else {
|
||||
if (errno != ENOENT || cf) {
|
||||
logger(LOG_ERR, "fopen `%s': %s", cf ? cf : CONFIG,
|
||||
strerror(errno));
|
||||
goto abort;
|
||||
}
|
||||
}
|
||||
|
||||
optind = 0;
|
||||
while ((opt = getopt_long(argc, argv, OPTS EXTRA_OPTS,
|
||||
longopts, &option_index)) != -1)
|
||||
{
|
||||
switch (opt) {
|
||||
case 'd':
|
||||
debug++;
|
||||
switch (debug) {
|
||||
case 1:
|
||||
setloglevel(LOG_DEBUG);
|
||||
break;
|
||||
case 2:
|
||||
options->options &= ~DHCPCD_DAEMONISE;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'f':
|
||||
break;
|
||||
#ifdef THERE_IS_NO_FORK
|
||||
case 'z':
|
||||
options->options |= DHCPCD_DAEMONISED;
|
||||
close_fds();
|
||||
break;
|
||||
case 'Z':
|
||||
dhcpcd_skiproutes = xstrdup(optarg);
|
||||
break;
|
||||
#endif
|
||||
case 'k':
|
||||
sig = SIGHUP;
|
||||
break;
|
||||
case 'n':
|
||||
sig = SIGALRM;
|
||||
break;
|
||||
case 'x':
|
||||
sig = SIGTERM;
|
||||
break;
|
||||
case 'T':
|
||||
options->options |= DHCPCD_TEST | DHCPCD_PERSISTENT;
|
||||
break;
|
||||
#ifdef CMDLINE_COMPAT
|
||||
case 'H': /* FALLTHROUGH */
|
||||
case 'M':
|
||||
del_reqmask(options->reqmask, DHCP_MTU);
|
||||
break;
|
||||
case 'N':
|
||||
del_reqmask(options->reqmask, DHCP_NTPSERVER);
|
||||
break;
|
||||
case 'R':
|
||||
del_reqmask(options->reqmask, DHCP_DNSSERVER);
|
||||
del_reqmask(options->reqmask, DHCP_DNSDOMAIN);
|
||||
del_reqmask(options->reqmask, DHCP_DNSSEARCH);
|
||||
break;
|
||||
case 'S':
|
||||
add_reqmask(options->reqmask, DHCP_MSCSR);
|
||||
break;
|
||||
case 'Y':
|
||||
del_reqmask(options->reqmask, DHCP_NISSERVER);
|
||||
del_reqmask(options->reqmask, DHCP_NISDOMAIN);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
i = parse_option(opt, optarg, options);
|
||||
if (i == 1)
|
||||
break;
|
||||
if (i == 0)
|
||||
usage();
|
||||
goto abort;
|
||||
}
|
||||
}
|
||||
|
||||
if ((p = strchr(options->hostname, '.'))) {
|
||||
if (options->fqdn == FQDN_DISABLE)
|
||||
*p = '\0';
|
||||
} else {
|
||||
if (options->fqdn != FQDN_DISABLE) {
|
||||
logger(LOG_WARNING, "hostname `%s' is not a FQDN",
|
||||
options->hostname);
|
||||
options->fqdn = FQDN_DISABLE;
|
||||
}
|
||||
}
|
||||
if (options->fqdn != FQDN_DISABLE)
|
||||
del_reqmask(options->reqmask, DHCP_HOSTNAME);
|
||||
|
||||
if (options->request_address.s_addr == 0 &&
|
||||
(options->options & DHCPCD_INFORM ||
|
||||
options->options & DHCPCD_REQUEST))
|
||||
{
|
||||
if (get_address(options->interface,
|
||||
&options->request_address,
|
||||
&options->request_netmask) != 1)
|
||||
{
|
||||
logger(LOG_ERR, "no existing address");
|
||||
goto abort;
|
||||
}
|
||||
}
|
||||
|
||||
if (IN_LINKLOCAL(ntohl(options->request_address.s_addr))) {
|
||||
logger(LOG_ERR,
|
||||
"you are not allowed to request a link local address");
|
||||
goto abort;
|
||||
}
|
||||
|
||||
if (geteuid())
|
||||
logger(LOG_WARNING, PACKAGE " will not work correctly unless"
|
||||
" run as root");
|
||||
|
||||
prefix = xmalloc(sizeof(char) * (IF_NAMESIZE + 3));
|
||||
snprintf(prefix, IF_NAMESIZE, "%s: ", options->interface);
|
||||
setlogprefix(prefix);
|
||||
snprintf(options->pidfile, sizeof(options->pidfile), PIDFILE,
|
||||
options->interface);
|
||||
free(prefix);
|
||||
|
||||
chdir("/");
|
||||
umask(022);
|
||||
|
||||
if (options->options & DHCPCD_TEST) {
|
||||
if (options->options & DHCPCD_REQUEST ||
|
||||
options->options & DHCPCD_INFORM) {
|
||||
logger(LOG_ERR,
|
||||
"cannot test with --inform or --request");
|
||||
goto abort;
|
||||
}
|
||||
|
||||
if (options->options & DHCPCD_LASTLEASE) {
|
||||
logger(LOG_ERR, "cannot test with --lastlease");
|
||||
goto abort;
|
||||
}
|
||||
|
||||
if (sig != 0) {
|
||||
logger(LOG_ERR,
|
||||
"cannot test with --release or --renew");
|
||||
goto abort;
|
||||
}
|
||||
}
|
||||
|
||||
if (sig != 0 && !(options->options & DHCPCD_DAEMONISED)) {
|
||||
i = -1;
|
||||
pid = read_pid(options->pidfile);
|
||||
if (pid != 0)
|
||||
logger(LOG_INFO, "sending signal %d to pid %d",
|
||||
sig, pid);
|
||||
|
||||
if (!pid || (i = kill(pid, sig))) {
|
||||
logger(sig == SIGALRM ? LOG_INFO : LOG_ERR,
|
||||
""PACKAGE" not running");
|
||||
unlink(options->pidfile);
|
||||
}
|
||||
if (i == 0) {
|
||||
retval = EXIT_SUCCESS;
|
||||
goto abort;
|
||||
}
|
||||
if (sig != SIGALRM)
|
||||
goto abort;
|
||||
}
|
||||
|
||||
if (!(options->options & DHCPCD_TEST) &&
|
||||
!(options->options & DHCPCD_DAEMONISED))
|
||||
{
|
||||
if ((pid = read_pid(options->pidfile)) > 0 &&
|
||||
kill(pid, 0) == 0)
|
||||
{
|
||||
logger(LOG_ERR, ""PACKAGE
|
||||
" already running on pid %d (%s)",
|
||||
pid, options->pidfile);
|
||||
goto abort;
|
||||
}
|
||||
|
||||
pid_fd = open(options->pidfile,
|
||||
O_WRONLY | O_CREAT | O_NONBLOCK, 0664);
|
||||
if (pid_fd == -1) {
|
||||
logger(LOG_ERR, "open `%s': %s",
|
||||
options->pidfile, strerror(errno));
|
||||
goto abort;
|
||||
}
|
||||
|
||||
/* Lock the file so that only one instance of dhcpcd runs
|
||||
* on an interface */
|
||||
if (flock(pid_fd, LOCK_EX | LOCK_NB) == -1) {
|
||||
logger(LOG_ERR, "flock `%s': %s",
|
||||
options->pidfile, strerror(errno));
|
||||
goto abort;
|
||||
}
|
||||
|
||||
if (set_cloexec(pid_fd) == -1)
|
||||
goto abort;
|
||||
writepid(pid_fd, getpid());
|
||||
logger(LOG_INFO, PACKAGE " " VERSION " starting");
|
||||
}
|
||||
|
||||
/* Terminate the encapsulated options */
|
||||
if (options->vendor[0]) {
|
||||
options->vendor[0]++;
|
||||
options->vendor[options->vendor[0]] = DHCP_END;
|
||||
}
|
||||
|
||||
if (dhcp_run(options, &pid_fd) == 0)
|
||||
retval = EXIT_SUCCESS;
|
||||
|
||||
abort:
|
||||
/* If we didn't daemonise then we need to punt the pidfile now */
|
||||
if (pid_fd > -1) {
|
||||
close(pid_fd);
|
||||
unlink(options->pidfile);
|
||||
}
|
||||
if (options->environ) {
|
||||
len = 0;
|
||||
while (options->environ[len])
|
||||
free(options->environ[len++]);
|
||||
free(options->environ);
|
||||
}
|
||||
free(options);
|
||||
|
||||
#ifdef THERE_IS_NO_FORK
|
||||
/* There may have been an error before the dhcp_run function
|
||||
* clears this, so just do it here to be safe */
|
||||
free(dhcpcd_skiproutes);
|
||||
#endif
|
||||
|
||||
exit(retval);
|
||||
/* NOTREACHED */
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
# A sample configuration for dhcpcd.
|
||||
# See dhcpcd.conf(5) for details.
|
||||
|
||||
# dhcpcd-run-hooks uses these options.
|
||||
option domain_name_servers, domain_name, domain_search, host_name
|
||||
|
||||
# Most distros have ntp support.
|
||||
option ntp_servers
|
||||
|
||||
# We should behave nicely on networks and respect their MTU.
|
||||
# However, a lot of buggy DHCP servers set invalid MTUs so this is not
|
||||
# enabled by default.
|
||||
#option interface_mtu
|
|
@ -0,0 +1,142 @@
|
|||
.\" Copyright 2006-2008 Roy Marples
|
||||
.\" 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.
|
||||
.\"
|
||||
.Dd Jun 30, 2008
|
||||
.Dt DHCPCD.CONF 5 SMM
|
||||
.Sh NAME
|
||||
.Nm dhcpcd.conf
|
||||
.Nd dhcpcd configuration file
|
||||
.Sh DESCRIPTION
|
||||
Although
|
||||
.Nm dhcpcd
|
||||
can do everything from the command line, there are cases where it's just easier
|
||||
to do it once in a configuration file.
|
||||
Most of the options found in
|
||||
.Xr dhcpcd 8
|
||||
can be used here.
|
||||
The first word on the line is the option and the rest of the line is the value.
|
||||
Leading and trailing whitespace for the option and value are trimmed.
|
||||
You can escape characters in the value using the \\ character.
|
||||
.Pp
|
||||
Blank lines and lines starting with # are ignored.
|
||||
.Pp
|
||||
Here's a list of available options:
|
||||
.Bl -tag -width indent
|
||||
.It Ic classid Ar string
|
||||
Change the default classid sent from dhcpcd-version.
|
||||
If not set then none is sent.
|
||||
.It Ic clientid Ar string
|
||||
Change the default clientid sent from the interface hardware address.
|
||||
If the string is of the format 01:02:03 then it is encoded as hex.
|
||||
If not set then none is sent.
|
||||
.It Ic duid
|
||||
Generate an
|
||||
.Rs
|
||||
.%T "RFC 4361"
|
||||
.Re
|
||||
compliant clientid.
|
||||
This requires persistent storage and not all DHCP servers work with it so it's
|
||||
not enabled by default.
|
||||
The duid generated will be held in
|
||||
.Pa @SYSCONFDIR@/dhcpcd.duid
|
||||
and should not be copied to other hosts.
|
||||
.It Ic hostname Ar name
|
||||
Sends specified
|
||||
.Ar hostname
|
||||
to the DHCP server so it can be registered in DNS. If
|
||||
.Ar hostname
|
||||
if a FQDN (ie, contains a .) then it will be encoded as such.
|
||||
.It Ic fqdn Op none | ptr | both
|
||||
none disables FQDN encoding, ptr just asks the DHCP server to update the PTR
|
||||
record of the host in DNS whereas both also updates the A record.
|
||||
The current hostname or the hostname specified using the
|
||||
.Ic hostname
|
||||
option must be a FQDN.
|
||||
.Nm dhcpcd
|
||||
itself never does any DNS updates.
|
||||
.It Ic interface Ar interface
|
||||
Subsequent options are only parsed for this
|
||||
.Ar interface .
|
||||
.It Ic leasetime Ar seconds
|
||||
Request a leasetime of
|
||||
.Ar seconds .
|
||||
.It Ic noarp
|
||||
Don't send any ARP requests.
|
||||
This also disables IPv4LL.
|
||||
.It Ic nogateway
|
||||
Don't install any default routes.
|
||||
.It Ic nohook Ar script
|
||||
Don't run this hook script.
|
||||
Matches full name, or prefixed with 2 numbers optionally ending with
|
||||
.Pa .sh .
|
||||
.It Ic noipv4ll
|
||||
Don't attempt to obtain an IPv4LL address if we failed to get one via DHCP.
|
||||
See
|
||||
.Rs
|
||||
.%T "RFC 3927"
|
||||
.Re
|
||||
.It Ic nolink
|
||||
Don't receive link messages about carrier status.
|
||||
You should only set this for buggy interface drivers.
|
||||
.It Ic nowait
|
||||
Don't wait to obtain a DHCP lease, fork to the background right away.
|
||||
.It Ic option Ar dhcp-option
|
||||
Requests the
|
||||
.Ar dhcp-option
|
||||
from the server.
|
||||
It can be a variable to be used in
|
||||
.Xr dhcpcd-run-hooks 8
|
||||
or the numerical value.
|
||||
You can specify more seperated by commas, spaces or more option lines.
|
||||
.It Ic script Ar script
|
||||
Use
|
||||
.Ar script
|
||||
instead of the default
|
||||
.Pa @SCRIPT@ .
|
||||
.It Ic timeout Ar seconds
|
||||
The default timeout for waiting for a DHCP response is 30 seconds which may
|
||||
be too long or too short and can be changed here.
|
||||
.It Ic userclass Ar string
|
||||
Tag the DHCP messages with the userclass.
|
||||
You can specify more than one.
|
||||
.It vendor Ar code , Ns Ar value
|
||||
Add an enscapulated vendor option.
|
||||
.Ar code
|
||||
should be between 1 and 254 inclusive.
|
||||
Examples.
|
||||
.Pp
|
||||
Set the vendor option 01 with an IP address.
|
||||
.D1 vendor 01,192.168.0.2
|
||||
Set the vendor option 02 with a hex code.
|
||||
.D1 vendor 02,01:02:03:04:05
|
||||
Set the vendor option 03 with an IP address as a string.
|
||||
.D1 vendor 03,\e"192.168.0.2\e"
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr dhcpcd-run-hooks 8 ,
|
||||
.Xr dhcpcd 8
|
||||
.Sh AUTHORS
|
||||
.An Roy Marples <roy@marples.name>
|
||||
.Sh BUGS
|
||||
Please report them to http://bugs.marples.name
|
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
* dhcpcd - DHCP client daemon
|
||||
* Copyright 2006-2008 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 DHCPCD_H
|
||||
#define DHCPCD_H
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#define DEFAULT_TIMEOUT 30
|
||||
#define DEFAULT_LEASETIME 3600 /* 1 hour */
|
||||
|
||||
#define CLASSID_MAX_LEN 48
|
||||
#define CLIENTID_MAX_LEN 48
|
||||
#define USERCLASS_MAX_LEN 255
|
||||
#define VENDOR_MAX_LEN 255
|
||||
|
||||
#ifdef THERE_IS_NO_FORK
|
||||
extern char dhcpcd[PATH_MAX];
|
||||
extern char **dhcpcd_argv;
|
||||
extern int dhcpcd_argc;
|
||||
extern char *dhcpcd_skiproutes;
|
||||
#endif
|
||||
|
||||
#define DHCPCD_ARP (1 << 0)
|
||||
#define DHCPCD_DOMAIN (1 << 2)
|
||||
#define DHCPCD_GATEWAY (1 << 3)
|
||||
#define DHCPCD_LASTLEASE (1 << 7)
|
||||
#define DHCPCD_INFORM (1 << 8)
|
||||
#define DHCPCD_REQUEST (1 << 9)
|
||||
#define DHCPCD_IPV4LL (1 << 10)
|
||||
#define DHCPCD_DUID (1 << 11)
|
||||
#define DHCPCD_PERSISTENT (1 << 12)
|
||||
#define DHCPCD_DAEMONISE (1 << 14)
|
||||
#define DHCPCD_DAEMONISED (1 << 15)
|
||||
#define DHCPCD_TEST (1 << 16)
|
||||
#define DHCPCD_FORKED (1 << 17)
|
||||
#define DHCPCD_HOSTNAME (1 << 18)
|
||||
#define DHCPCD_CLIENTID (1 << 19)
|
||||
#define DHCPCD_LINK (1 << 20)
|
||||
#define DHCPCD_BACKGROUND (1 << 21)
|
||||
|
||||
struct options {
|
||||
char interface[IF_NAMESIZE];
|
||||
int metric;
|
||||
uint8_t reqmask[256 / 8];
|
||||
uint8_t nomask[256 / 8];
|
||||
uint32_t leasetime;
|
||||
time_t timeout;
|
||||
int options;
|
||||
|
||||
struct in_addr request_address;
|
||||
struct in_addr request_netmask;
|
||||
|
||||
char **environ;
|
||||
char script[PATH_MAX];
|
||||
char pidfile[PATH_MAX];
|
||||
|
||||
char hostname[MAXHOSTNAMELEN];
|
||||
int fqdn;
|
||||
uint8_t classid[CLASSID_MAX_LEN + 1];
|
||||
char clientid[CLIENTID_MAX_LEN + 1];
|
||||
uint8_t userclass[USERCLASS_MAX_LEN + 1];
|
||||
uint8_t vendor[VENDOR_MAX_LEN + 1];
|
||||
};
|
||||
#endif
|
|
@ -0,0 +1,241 @@
|
|||
/*
|
||||
* dhcpcd - DHCP client daemon
|
||||
* Copyright 2006-2008 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/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/param.h>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <net/if_dl.h>
|
||||
#include <net/if_types.h>
|
||||
#include <net/route.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "common.h"
|
||||
#include "dhcp.h"
|
||||
#include "net.h"
|
||||
|
||||
/* Darwin doesn't define this for some very odd reason */
|
||||
#ifndef SA_SIZE
|
||||
# define SA_SIZE(sa) \
|
||||
( (!(sa) || ((struct sockaddr *)(sa))->sa_len == 0) ? \
|
||||
sizeof(long) : \
|
||||
1 + ( (((struct sockaddr *)(sa))->sa_len - 1) | (sizeof(long) - 1) ) )
|
||||
#endif
|
||||
|
||||
int
|
||||
if_address(const char *ifname, const struct in_addr *address,
|
||||
const struct in_addr *netmask, const struct in_addr *broadcast,
|
||||
int action)
|
||||
{
|
||||
int s;
|
||||
int retval;
|
||||
struct ifaliasreq ifa;
|
||||
union {
|
||||
struct sockaddr *sa;
|
||||
struct sockaddr_in *sin;
|
||||
} _s;
|
||||
|
||||
if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
|
||||
return -1;
|
||||
|
||||
memset(&ifa, 0, sizeof(ifa));
|
||||
strlcpy(ifa.ifra_name, ifname, sizeof(ifa.ifra_name));
|
||||
|
||||
#define ADDADDR(_var, _addr) \
|
||||
_s.sa = &_var; \
|
||||
_s.sin->sin_family = AF_INET; \
|
||||
_s.sin->sin_len = sizeof(*_s.sin); \
|
||||
memcpy(&_s.sin->sin_addr, _addr, sizeof(_s.sin->sin_addr));
|
||||
|
||||
ADDADDR(ifa.ifra_addr, address);
|
||||
ADDADDR(ifa.ifra_mask, netmask);
|
||||
if (action >= 0) {
|
||||
ADDADDR(ifa.ifra_broadaddr, broadcast);
|
||||
}
|
||||
#undef ADDADDR
|
||||
|
||||
if (action < 0)
|
||||
retval = ioctl(s, SIOCDIFADDR, &ifa);
|
||||
else
|
||||
retval = ioctl(s, SIOCAIFADDR, &ifa);
|
||||
close(s);
|
||||
return retval;
|
||||
}
|
||||
|
||||
int
|
||||
if_route(const char *ifname, const struct in_addr *destination,
|
||||
const struct in_addr *netmask, const struct in_addr *gateway,
|
||||
_unused int metric, int action)
|
||||
{
|
||||
int s;
|
||||
static int seq;
|
||||
union sockunion {
|
||||
struct sockaddr sa;
|
||||
struct sockaddr_in sin;
|
||||
#ifdef INET6
|
||||
struct sockaddr_in6 sin6;
|
||||
#endif
|
||||
struct sockaddr_dl sdl;
|
||||
struct sockaddr_storage ss;
|
||||
} su;
|
||||
struct rtm
|
||||
{
|
||||
struct rt_msghdr hdr;
|
||||
char buffer[sizeof(su) * 3];
|
||||
} rtm;
|
||||
char *bp = rtm.buffer;
|
||||
size_t l;
|
||||
unsigned char *hwaddr;
|
||||
size_t hwlen = 0;
|
||||
int retval = 0;
|
||||
|
||||
if ((s = socket(PF_ROUTE, SOCK_RAW, 0)) == -1)
|
||||
return -1;
|
||||
|
||||
memset(&rtm, 0, sizeof(rtm));
|
||||
rtm.hdr.rtm_version = RTM_VERSION;
|
||||
rtm.hdr.rtm_seq = ++seq;
|
||||
if (action == 0)
|
||||
rtm.hdr.rtm_type = RTM_CHANGE;
|
||||
else if (action > 0)
|
||||
rtm.hdr.rtm_type = RTM_ADD;
|
||||
else
|
||||
rtm.hdr.rtm_type = RTM_DELETE;
|
||||
rtm.hdr.rtm_flags = RTF_UP | RTF_STATIC;
|
||||
if (netmask->s_addr == INADDR_BROADCAST)
|
||||
rtm.hdr.rtm_flags |= RTF_HOST;
|
||||
|
||||
/* This order is important */
|
||||
rtm.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
|
||||
|
||||
#define ADDADDR(_addr) \
|
||||
memset (&su, 0, sizeof(su)); \
|
||||
su.sin.sin_family = AF_INET; \
|
||||
su.sin.sin_len = sizeof(su.sin); \
|
||||
memcpy (&su.sin.sin_addr, _addr, sizeof(su.sin.sin_addr)); \
|
||||
l = SA_SIZE (&(su.sa)); \
|
||||
memcpy (bp, &(su), l); \
|
||||
bp += l;
|
||||
|
||||
ADDADDR(destination);
|
||||
|
||||
if (gateway->s_addr == INADDR_ANY) {
|
||||
/* Make us a link layer socket */
|
||||
hwaddr = xmalloc(sizeof(unsigned char) * HWADDR_LEN);
|
||||
do_interface(ifname, hwaddr, &hwlen, NULL, 0, 0);
|
||||
memset(&su, 0, sizeof(su));
|
||||
su.sdl.sdl_len = sizeof(su.sdl);
|
||||
su.sdl.sdl_family = AF_LINK;
|
||||
su.sdl.sdl_nlen = strlen(ifname);
|
||||
memcpy(&su.sdl.sdl_data, ifname, (size_t)su.sdl.sdl_nlen);
|
||||
su.sdl.sdl_alen = hwlen;
|
||||
memcpy(((unsigned char *)&su.sdl.sdl_data) + su.sdl.sdl_nlen,
|
||||
hwaddr, (size_t)su.sdl.sdl_alen);
|
||||
|
||||
l = SA_SIZE(&(su.sa));
|
||||
memcpy(bp, &su, l);
|
||||
bp += l;
|
||||
free(hwaddr);
|
||||
} else {
|
||||
rtm.hdr.rtm_flags |= RTF_GATEWAY;
|
||||
ADDADDR(gateway);
|
||||
}
|
||||
|
||||
ADDADDR(netmask);
|
||||
#undef ADDADDR
|
||||
|
||||
rtm.hdr.rtm_msglen = l = bp - (char *)&rtm;
|
||||
if (write(s, &rtm, l) == -1)
|
||||
retval = -1;
|
||||
close(s);
|
||||
return retval;
|
||||
}
|
||||
|
||||
int
|
||||
open_link_socket(struct interface *iface)
|
||||
{
|
||||
int fd;
|
||||
|
||||
fd = socket(PF_ROUTE, SOCK_RAW, 0);
|
||||
if (fd == -1)
|
||||
return -1;
|
||||
set_cloexec(fd);
|
||||
if (iface->link_fd != -1)
|
||||
close(iface->link_fd);
|
||||
iface->link_fd = fd;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define BUFFER_LEN 2048
|
||||
int
|
||||
link_changed(struct interface *iface)
|
||||
{
|
||||
char buffer[2048], *p;
|
||||
ssize_t bytes;
|
||||
struct rt_msghdr *rtm;
|
||||
struct if_msghdr *ifm;
|
||||
int i;
|
||||
|
||||
if ((i = if_nametoindex(iface->name)) == -1)
|
||||
return -1;
|
||||
for (;;) {
|
||||
bytes = recv(iface->link_fd, buffer, BUFFER_LEN, MSG_DONTWAIT);
|
||||
if (bytes == -1) {
|
||||
if (errno == EAGAIN)
|
||||
return 0;
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
return -1;
|
||||
}
|
||||
for (p = buffer; bytes > 0;
|
||||
bytes -= ((struct rt_msghdr *)p)->rtm_msglen,
|
||||
p += ((struct rt_msghdr *)p)->rtm_msglen)
|
||||
{
|
||||
rtm = (struct rt_msghdr *)p;
|
||||
if (rtm->rtm_type != RTM_IFINFO)
|
||||
continue;
|
||||
ifm = (struct if_msghdr *)p;
|
||||
if (ifm->ifm_index != i)
|
||||
continue;
|
||||
|
||||
/* Link changed */
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
* dhcpcd - DHCP client daemon
|
||||
* Copyright 2006-2008 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 <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <syslog.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "logger.h"
|
||||
|
||||
static int loglevel = LOG_INFO;
|
||||
static char logprefix[12] = {0};
|
||||
|
||||
struct logname {
|
||||
int level;
|
||||
const char *name;
|
||||
};
|
||||
static const struct logname const lognames[] = {
|
||||
{ LOG_DEBUG, "debug" },
|
||||
{ LOG_INFO, "info" },
|
||||
{ LOG_WARNING, "warning" },
|
||||
{ LOG_ERR, "error" },
|
||||
{ -1, NULL }
|
||||
};
|
||||
|
||||
int
|
||||
logtolevel(const char *priority)
|
||||
{
|
||||
const struct logname *lt;
|
||||
|
||||
if (isdigit((unsigned char)*priority))
|
||||
return atoi(priority);
|
||||
for (lt = lognames; lt->name; lt++)
|
||||
if (!strcasecmp(priority, lt->name))
|
||||
return lt->level;
|
||||
return -1;
|
||||
}
|
||||
|
||||
void
|
||||
setloglevel(int level)
|
||||
{
|
||||
loglevel = level;
|
||||
}
|
||||
|
||||
void
|
||||
setlogprefix(const char *prefix)
|
||||
{
|
||||
strlcpy(logprefix, prefix, sizeof(logprefix));
|
||||
}
|
||||
|
||||
void
|
||||
logger(int level, const char *fmt, ...)
|
||||
{
|
||||
va_list p, p2;
|
||||
FILE *f = stderr;
|
||||
size_t len, fmt2len;
|
||||
char *fmt2, *pf;
|
||||
|
||||
va_start(p, fmt);
|
||||
va_copy(p2, p);
|
||||
|
||||
if (level <= LOG_ERR || level <= loglevel) {
|
||||
fprintf(f, "%s", logprefix);
|
||||
vfprintf(f, fmt, p);
|
||||
fputc('\n', f);
|
||||
|
||||
/* stdout, stderr may be re-directed to some kind of buffer.
|
||||
* So we always flush to ensure it's written. */
|
||||
fflush(f);
|
||||
}
|
||||
|
||||
if (level < LOG_DEBUG || level <= loglevel) {
|
||||
len = strlen(logprefix);
|
||||
fmt2len = strlen(fmt) + len + 1;
|
||||
fmt2 = pf = malloc(sizeof(char) * fmt2len);
|
||||
if (fmt2) {
|
||||
strlcpy(pf, logprefix, fmt2len);
|
||||
pf += len;
|
||||
strlcpy(pf, fmt, fmt2len - len);
|
||||
vsyslog(level, fmt2, p2);
|
||||
free(fmt2);
|
||||
} else {
|
||||
vsyslog(level, fmt, p2);
|
||||
syslog(LOG_ERR, "logger: memory exhausted");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
va_end(p2);
|
||||
va_end(p);
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* dhcpcd - DHCP client daemon
|
||||
* Copyright 2006-2008 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 LOGGER_H
|
||||
#define LOGGER_H
|
||||
|
||||
#if defined(__GNUC__)
|
||||
# define _PRINTF_LIKE(_one, _two) __attribute__ ((__format__ (__printf__, _one, _two)))
|
||||
#else
|
||||
# define _PRINTF_LIKE(_one, _two)
|
||||
#endif
|
||||
|
||||
#include <syslog.h>
|
||||
|
||||
int logtolevel(const char *);
|
||||
void setloglevel(int);
|
||||
void setlogprefix(const char *);
|
||||
void logger(int, const char *, ...) _PRINTF_LIKE (2, 3);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,693 @@
|
|||
/*
|
||||
* dhcpcd - DHCP client daemon
|
||||
* Copyright 2006-2008 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/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <net/if_arp.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in_systm.h>
|
||||
#ifdef __linux__
|
||||
#include <netinet/ether.h>
|
||||
#include <netpacket/packet.h>
|
||||
#endif
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/ip.h>
|
||||
#define __FAVOR_BSD /* Nasty glibc hack so we can use BSD semantics for UDP */
|
||||
#include <netinet/udp.h>
|
||||
#undef __FAVOR_BSD
|
||||
#ifdef SIOCGIFMEDIA
|
||||
#include <net/if_media.h>
|
||||
#endif
|
||||
#include <arpa/inet.h>
|
||||
#ifdef AF_LINK
|
||||
# include <net/if_dl.h>
|
||||
#endif
|
||||
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <poll.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "common.h"
|
||||
#include "dhcp.h"
|
||||
#include "logger.h"
|
||||
#include "net.h"
|
||||
#include "signals.h"
|
||||
|
||||
int
|
||||
inet_ntocidr(struct in_addr address)
|
||||
{
|
||||
int cidr = 0;
|
||||
uint32_t mask = htonl(address.s_addr);
|
||||
|
||||
while (mask) {
|
||||
cidr++;
|
||||
mask <<= 1;
|
||||
}
|
||||
|
||||
return cidr;
|
||||
}
|
||||
|
||||
int
|
||||
inet_cidrtoaddr (int cidr, struct in_addr *addr)
|
||||
{
|
||||
int ocets;
|
||||
|
||||
if (cidr < 0 || cidr > 32) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
ocets = (cidr + 7) / 8;
|
||||
|
||||
addr->s_addr = 0;
|
||||
if (ocets > 0) {
|
||||
memset(&addr->s_addr, 255, (size_t)ocets - 1);
|
||||
memset((unsigned char *)&addr->s_addr + (ocets - 1),
|
||||
(256 - (1 << (32 - cidr) % 8)), 1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
get_netmask(uint32_t addr)
|
||||
{
|
||||
uint32_t dst;
|
||||
|
||||
if (addr == 0)
|
||||
return 0;
|
||||
|
||||
dst = htonl(addr);
|
||||
if (IN_CLASSA(dst))
|
||||
return ntohl(IN_CLASSA_NET);
|
||||
if (IN_CLASSB (dst))
|
||||
return ntohl(IN_CLASSB_NET);
|
||||
if (IN_CLASSC (dst))
|
||||
return ntohl(IN_CLASSC_NET);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *
|
||||
hwaddr_ntoa(const unsigned char *hwaddr, size_t hwlen)
|
||||
{
|
||||
static char buffer[(HWADDR_LEN * 3) + 1];
|
||||
char *p = buffer;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < hwlen && i < HWADDR_LEN; i++) {
|
||||
if (i > 0)
|
||||
*p ++= ':';
|
||||
p += snprintf(p, 3, "%.2x", hwaddr[i]);
|
||||
}
|
||||
|
||||
*p ++= '\0';
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
size_t
|
||||
hwaddr_aton(unsigned char *buffer, const char *addr)
|
||||
{
|
||||
char c[3];
|
||||
const char *p = addr;
|
||||
unsigned char *bp = buffer;
|
||||
size_t len = 0;
|
||||
|
||||
c[2] = '\0';
|
||||
while (*p) {
|
||||
c[0] = *p++;
|
||||
c[1] = *p++;
|
||||
/* Ensure that digits are hex */
|
||||
if (isxdigit((unsigned char)c[0]) == 0 ||
|
||||
isxdigit((unsigned char)c[1]) == 0)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
/* We should have at least two entries 00:01 */
|
||||
if (len == 0 && *p == '\0') {
|
||||
errno = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
/* Ensure that next data is EOL or a seperator with data */
|
||||
if (!(*p == '\0' || (*p == ':' && *(p + 1) != '\0'))) {
|
||||
errno = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
if (*p)
|
||||
p++;
|
||||
if (bp)
|
||||
*bp++ = (unsigned char)strtol(c, NULL, 16);
|
||||
len++;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
int
|
||||
do_interface(const char *ifname,
|
||||
_unused unsigned char *hwaddr, _unused size_t *hwlen,
|
||||
struct in_addr *addr, struct in_addr *net, int get)
|
||||
{
|
||||
int s;
|
||||
struct ifconf ifc;
|
||||
int retval = 0;
|
||||
int len = 10 * sizeof(struct ifreq);
|
||||
int lastlen = 0;
|
||||
char *p;
|
||||
union {
|
||||
char *buffer;
|
||||
struct ifreq *ifr;
|
||||
} ifreqs;
|
||||
struct sockaddr_in address;
|
||||
struct ifreq *ifr;
|
||||
struct sockaddr_in netmask;
|
||||
|
||||
#ifdef AF_LINK
|
||||
struct sockaddr_dl sdl;
|
||||
#endif
|
||||
|
||||
if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
|
||||
return -1;
|
||||
|
||||
/* Not all implementations return the needed buffer size for
|
||||
* SIOGIFCONF so we loop like so for all until it works */
|
||||
memset(&ifc, 0, sizeof(ifc));
|
||||
for (;;) {
|
||||
ifc.ifc_len = len;
|
||||
ifc.ifc_buf = xmalloc((size_t)len);
|
||||
if (ioctl(s, SIOCGIFCONF, &ifc) == -1) {
|
||||
if (errno != EINVAL || lastlen != 0) {
|
||||
close(s);
|
||||
free(ifc.ifc_buf);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
if (ifc.ifc_len == lastlen)
|
||||
break;
|
||||
lastlen = ifc.ifc_len;
|
||||
}
|
||||
|
||||
free(ifc.ifc_buf);
|
||||
ifc.ifc_buf = NULL;
|
||||
len *= 2;
|
||||
}
|
||||
|
||||
for (p = (char *)ifc.ifc_buf; p < (char *)ifc.ifc_buf + ifc.ifc_len;) {
|
||||
/* Cast the ifc buffer to an ifreq cleanly */
|
||||
ifreqs.buffer = p;
|
||||
ifr = ifreqs.ifr;
|
||||
|
||||
#ifndef __linux__
|
||||
if (ifr->ifr_addr.sa_len > sizeof(ifr->ifr_ifru))
|
||||
p += offsetof(struct ifreq, ifr_ifru) +
|
||||
ifr->ifr_addr.sa_len;
|
||||
else
|
||||
#endif
|
||||
p += sizeof(*ifr);
|
||||
|
||||
if (strcmp(ifname, ifr->ifr_name) != 0)
|
||||
continue;
|
||||
|
||||
#ifdef AF_LINK
|
||||
if (hwaddr && hwlen && ifr->ifr_addr.sa_family == AF_LINK) {
|
||||
memcpy(&sdl, &ifr->ifr_addr, sizeof(sdl));
|
||||
*hwlen = sdl.sdl_alen;
|
||||
memcpy(hwaddr, sdl.sdl_data + sdl.sdl_nlen,
|
||||
(size_t)sdl.sdl_alen);
|
||||
retval = 1;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (ifr->ifr_addr.sa_family == AF_INET) {
|
||||
memcpy(&address, &ifr->ifr_addr, sizeof(address));
|
||||
if (ioctl(s, SIOCGIFNETMASK, ifr) == -1)
|
||||
continue;
|
||||
memcpy(&netmask, &ifr->ifr_addr, sizeof(netmask));
|
||||
if (get) {
|
||||
addr->s_addr = address.sin_addr.s_addr;
|
||||
net->s_addr = netmask.sin_addr.s_addr;
|
||||
retval = 1;
|
||||
break;
|
||||
} else {
|
||||
if (address.sin_addr.s_addr == addr->s_addr &&
|
||||
(!net ||
|
||||
netmask.sin_addr.s_addr == net->s_addr))
|
||||
{
|
||||
retval = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
close(s);
|
||||
free(ifc.ifc_buf);
|
||||
return retval;
|
||||
}
|
||||
|
||||
int
|
||||
up_interface(const char *ifname)
|
||||
{
|
||||
int s;
|
||||
struct ifreq ifr;
|
||||
int retval = -1;
|
||||
#ifdef __linux__
|
||||
char *p;
|
||||
#endif
|
||||
|
||||
if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
|
||||
return -1;
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
|
||||
#ifdef __linux__
|
||||
/* We can only bring the real interface up */
|
||||
if ((p = strchr(ifr.ifr_name, ':')))
|
||||
*p = '\0';
|
||||
#endif
|
||||
if (ioctl(s, SIOCGIFFLAGS, &ifr) == 0) {
|
||||
if ((ifr.ifr_flags & IFF_UP))
|
||||
retval = 0;
|
||||
else {
|
||||
ifr.ifr_flags |= IFF_UP;
|
||||
if (ioctl(s, SIOCSIFFLAGS, &ifr) == 0)
|
||||
retval = 0;
|
||||
}
|
||||
}
|
||||
close(s);
|
||||
return retval;
|
||||
}
|
||||
|
||||
int
|
||||
carrier_status(const char *ifname)
|
||||
{
|
||||
int s;
|
||||
struct ifreq ifr;
|
||||
int retval = -1;
|
||||
#ifdef SIOCGIFMEDIA
|
||||
struct ifmediareq ifmr;
|
||||
#endif
|
||||
#ifdef __linux__
|
||||
char *p;
|
||||
#endif
|
||||
|
||||
if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
|
||||
return -1;
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
|
||||
#ifdef __linux__
|
||||
/* We can only test the real interface up */
|
||||
if ((p = strchr(ifr.ifr_name, ':')))
|
||||
*p = '\0';
|
||||
#endif
|
||||
if ((retval = ioctl(s, SIOCGIFFLAGS, &ifr)) == 0) {
|
||||
if (ifr.ifr_flags & IFF_UP && ifr.ifr_flags & IFF_RUNNING)
|
||||
retval = 1;
|
||||
else
|
||||
retval = 0;
|
||||
}
|
||||
|
||||
#ifdef SIOCGIFMEDIA
|
||||
if (retval == 1) {
|
||||
memset(&ifmr, 0, sizeof(ifmr));
|
||||
strncpy(ifmr.ifm_name, ifr.ifr_name, sizeof(ifmr.ifm_name));
|
||||
if (ioctl(s, SIOCGIFMEDIA, &ifmr) != -1 &&
|
||||
ifmr.ifm_status & IFM_AVALID)
|
||||
{
|
||||
if (!(ifmr.ifm_status & IFM_ACTIVE))
|
||||
retval = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
close(s);
|
||||
return retval;
|
||||
}
|
||||
|
||||
struct interface *
|
||||
read_interface(const char *ifname, _unused int metric)
|
||||
{
|
||||
int s;
|
||||
struct ifreq ifr;
|
||||
struct interface *iface = NULL;
|
||||
unsigned char *hwaddr = NULL;
|
||||
size_t hwlen = 0;
|
||||
sa_family_t family = 0;
|
||||
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
|
||||
|
||||
if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
|
||||
return NULL;
|
||||
|
||||
#ifdef __linux__
|
||||
strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
|
||||
if (ioctl(s, SIOCGIFHWADDR, &ifr) == -1)
|
||||
goto eexit;
|
||||
|
||||
switch (ifr.ifr_hwaddr.sa_family) {
|
||||
case ARPHRD_ETHER:
|
||||
case ARPHRD_IEEE802:
|
||||
hwlen = ETHER_ADDR_LEN;
|
||||
break;
|
||||
case ARPHRD_IEEE1394:
|
||||
hwlen = EUI64_ADDR_LEN;
|
||||
case ARPHRD_INFINIBAND:
|
||||
hwlen = INFINIBAND_ADDR_LEN;
|
||||
break;
|
||||
}
|
||||
|
||||
hwaddr = xmalloc(sizeof(unsigned char) * HWADDR_LEN);
|
||||
memcpy(hwaddr, ifr.ifr_hwaddr.sa_data, hwlen);
|
||||
family = ifr.ifr_hwaddr.sa_family;
|
||||
#else
|
||||
ifr.ifr_metric = metric;
|
||||
strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
|
||||
if (ioctl(s, SIOCSIFMETRIC, &ifr) == -1)
|
||||
goto eexit;
|
||||
|
||||
hwaddr = xmalloc(sizeof(unsigned char) * HWADDR_LEN);
|
||||
if (do_interface(ifname, hwaddr, &hwlen, NULL, NULL, 0) != 1)
|
||||
goto eexit;
|
||||
|
||||
family = ARPHRD_ETHER;
|
||||
#endif
|
||||
|
||||
strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
|
||||
if (ioctl(s, SIOCGIFMTU, &ifr) == -1)
|
||||
goto eexit;
|
||||
|
||||
/* Ensure that the MTU is big enough for DHCP */
|
||||
if (ifr.ifr_mtu < MTU_MIN) {
|
||||
ifr.ifr_mtu = MTU_MIN;
|
||||
strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
|
||||
if (ioctl(s, SIOCSIFMTU, &ifr) == -1)
|
||||
goto eexit;
|
||||
}
|
||||
|
||||
if (up_interface(ifname) != 0)
|
||||
goto eexit;
|
||||
|
||||
iface = xzalloc(sizeof(*iface));
|
||||
strlcpy(iface->name, ifname, IF_NAMESIZE);
|
||||
snprintf(iface->leasefile, PATH_MAX, LEASEFILE, ifname);
|
||||
memcpy(&iface->hwaddr, hwaddr, hwlen);
|
||||
iface->hwlen = hwlen;
|
||||
|
||||
iface->family = family;
|
||||
iface->arpable = !(ifr.ifr_flags & (IFF_NOARP | IFF_LOOPBACK));
|
||||
|
||||
/* 0 is a valid fd, so init to -1 */
|
||||
iface->raw_fd = -1;
|
||||
iface->udp_fd = -1;
|
||||
iface->arp_fd = -1;
|
||||
iface->link_fd = -1;
|
||||
|
||||
eexit:
|
||||
close(s);
|
||||
free(hwaddr);
|
||||
return iface;
|
||||
}
|
||||
|
||||
int
|
||||
do_mtu(const char *ifname, short int mtu)
|
||||
{
|
||||
struct ifreq ifr;
|
||||
int r;
|
||||
int s;
|
||||
|
||||
if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
|
||||
return -1;
|
||||
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
|
||||
ifr.ifr_mtu = mtu;
|
||||
r = ioctl(s, mtu ? SIOCSIFMTU : SIOCGIFMTU, &ifr);
|
||||
close(s);
|
||||
if (r == -1)
|
||||
return -1;
|
||||
return ifr.ifr_mtu;
|
||||
}
|
||||
|
||||
void
|
||||
free_routes(struct rt *routes)
|
||||
{
|
||||
struct rt *r;
|
||||
|
||||
while (routes) {
|
||||
r = routes->next;
|
||||
free(routes);
|
||||
routes = r;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
open_udp_socket(struct interface *iface)
|
||||
{
|
||||
int s;
|
||||
union sockunion {
|
||||
struct sockaddr sa;
|
||||
struct sockaddr_in sin;
|
||||
} su;
|
||||
int n = 1;
|
||||
|
||||
if ((s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
|
||||
return -1;
|
||||
|
||||
if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n)) == -1)
|
||||
goto eexit;
|
||||
/* As we don't actually use this socket for anything, set
|
||||
* the receiver buffer to 1 */
|
||||
if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &n, sizeof(n)) == -1)
|
||||
goto eexit;
|
||||
memset(&su, 0, sizeof(su));
|
||||
su.sin.sin_family = AF_INET;
|
||||
su.sin.sin_port = htons(DHCP_CLIENT_PORT);
|
||||
su.sin.sin_addr.s_addr = iface->addr.s_addr;
|
||||
if (bind(s, &su.sa, sizeof(su)) == -1)
|
||||
goto eexit;
|
||||
|
||||
iface->udp_fd = s;
|
||||
set_cloexec(s);
|
||||
return 0;
|
||||
|
||||
eexit:
|
||||
close(s);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ssize_t
|
||||
send_packet(const struct interface *iface, struct in_addr to,
|
||||
const uint8_t *data, ssize_t len)
|
||||
{
|
||||
union sockunion {
|
||||
struct sockaddr sa;
|
||||
struct sockaddr_in sin;
|
||||
} su;
|
||||
|
||||
memset(&su, 0, sizeof(su));
|
||||
su.sin.sin_family = AF_INET;
|
||||
su.sin.sin_addr.s_addr = to.s_addr;
|
||||
su.sin.sin_port = htons(DHCP_SERVER_PORT);
|
||||
|
||||
return sendto(iface->udp_fd, data, len, 0, &su.sa, sizeof(su));
|
||||
}
|
||||
|
||||
struct udp_dhcp_packet
|
||||
{
|
||||
struct ip ip;
|
||||
struct udphdr udp;
|
||||
struct dhcp_message dhcp;
|
||||
};
|
||||
const size_t udp_dhcp_len = sizeof(struct udp_dhcp_packet);
|
||||
|
||||
static uint16_t
|
||||
checksum(const void *data, uint16_t len)
|
||||
{
|
||||
const uint8_t *addr = data;
|
||||
uint32_t sum = 0;
|
||||
|
||||
while (len > 1) {
|
||||
sum += addr[0] * 256 + addr[1];
|
||||
addr += 2;
|
||||
len -= 2;
|
||||
}
|
||||
|
||||
if (len == 1)
|
||||
sum += *addr * 256;
|
||||
|
||||
sum = (sum >> 16) + (sum & 0xffff);
|
||||
sum += (sum >> 16);
|
||||
|
||||
sum = htons(sum);
|
||||
|
||||
return ~sum;
|
||||
}
|
||||
|
||||
ssize_t
|
||||
make_udp_packet(uint8_t **packet, const uint8_t *data, size_t length,
|
||||
struct in_addr source, struct in_addr dest)
|
||||
{
|
||||
struct udp_dhcp_packet *udpp;
|
||||
struct ip *ip;
|
||||
struct udphdr *udp;
|
||||
|
||||
udpp = xzalloc(sizeof(*udpp));
|
||||
ip = &udpp->ip;
|
||||
udp = &udpp->udp;
|
||||
|
||||
/* OK, this is important :)
|
||||
* We copy the data to our packet and then create a small part of the
|
||||
* ip structure and an invalid ip_len (basically udp length).
|
||||
* We then fill the udp structure and put the checksum
|
||||
* of the whole packet into the udp checksum.
|
||||
* Finally we complete the ip structure and ip checksum.
|
||||
* If we don't do the ordering like so then the udp checksum will be
|
||||
* broken, so find another way of doing it! */
|
||||
|
||||
memcpy(&udpp->dhcp, data, length);
|
||||
|
||||
ip->ip_p = IPPROTO_UDP;
|
||||
ip->ip_src.s_addr = source.s_addr;
|
||||
if (dest.s_addr == 0)
|
||||
ip->ip_dst.s_addr = INADDR_BROADCAST;
|
||||
else
|
||||
ip->ip_dst.s_addr = dest.s_addr;
|
||||
|
||||
udp->uh_sport = htons(DHCP_CLIENT_PORT);
|
||||
udp->uh_dport = htons(DHCP_SERVER_PORT);
|
||||
udp->uh_ulen = htons(sizeof(*udp) + length);
|
||||
ip->ip_len = udp->uh_ulen;
|
||||
udp->uh_sum = checksum(udpp, sizeof(*udpp));
|
||||
|
||||
ip->ip_v = IPVERSION;
|
||||
ip->ip_hl = 5;
|
||||
ip->ip_id = 0;
|
||||
ip->ip_tos = IPTOS_LOWDELAY;
|
||||
ip->ip_len = htons (sizeof(*ip) + sizeof(*udp) + length);
|
||||
ip->ip_id = 0;
|
||||
ip->ip_off = htons(IP_DF); /* Don't fragment */
|
||||
ip->ip_ttl = IPDEFTTL;
|
||||
|
||||
ip->ip_sum = checksum(ip, sizeof(*ip));
|
||||
|
||||
*packet = (uint8_t *)udpp;
|
||||
return sizeof(*ip) + sizeof(*udp) + length;
|
||||
}
|
||||
|
||||
ssize_t
|
||||
get_udp_data(const uint8_t **data, const uint8_t *udp)
|
||||
{
|
||||
struct udp_dhcp_packet packet;
|
||||
|
||||
memcpy(&packet, udp, sizeof(packet));
|
||||
*data = udp + offsetof(struct udp_dhcp_packet, dhcp);
|
||||
return ntohs(packet.ip.ip_len) - sizeof(packet.ip) - sizeof(packet.udp);
|
||||
}
|
||||
|
||||
int
|
||||
valid_udp_packet(const uint8_t *data)
|
||||
{
|
||||
struct udp_dhcp_packet packet;
|
||||
uint16_t bytes;
|
||||
uint16_t ipsum;
|
||||
uint16_t iplen;
|
||||
uint16_t udpsum;
|
||||
struct in_addr source;
|
||||
struct in_addr dest;
|
||||
int retval = 0;
|
||||
|
||||
memcpy(&packet, data, sizeof(packet));
|
||||
bytes = ntohs(packet.ip.ip_len);
|
||||
ipsum = packet.ip.ip_sum;
|
||||
iplen = packet.ip.ip_len;
|
||||
udpsum = packet.udp.uh_sum;
|
||||
|
||||
if (0 != checksum(&packet.ip, sizeof(packet.ip))) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
packet.ip.ip_sum = 0;
|
||||
memcpy(&source, &packet.ip.ip_src, sizeof(packet.ip.ip_src));
|
||||
memcpy(&dest, &packet.ip.ip_dst, sizeof(packet.ip.ip_dst));
|
||||
memset(&packet.ip, 0, sizeof(packet.ip));
|
||||
packet.udp.uh_sum = 0;
|
||||
|
||||
packet.ip.ip_p = IPPROTO_UDP;
|
||||
memcpy(&packet.ip.ip_src, &source, sizeof(packet.ip.ip_src));
|
||||
memcpy(&packet.ip.ip_dst, &dest, sizeof(packet.ip.ip_dst));
|
||||
packet.ip.ip_len = packet.udp.uh_ulen;
|
||||
if (udpsum && udpsum != checksum(&packet, bytes)) {
|
||||
errno = EINVAL;
|
||||
retval = -1;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
int
|
||||
send_arp(const struct interface *iface, int op, in_addr_t sip, in_addr_t tip)
|
||||
{
|
||||
struct arphdr *arp;
|
||||
size_t arpsize;
|
||||
uint8_t *p;
|
||||
int retval;
|
||||
|
||||
arpsize = sizeof(*arp) + 2 * iface->hwlen + 2 * sizeof(sip);
|
||||
arp = xmalloc(arpsize);
|
||||
arp->ar_hrd = htons(iface->family);
|
||||
arp->ar_pro = htons(ETHERTYPE_IP);
|
||||
arp->ar_hln = iface->hwlen;
|
||||
arp->ar_pln = sizeof(sip);
|
||||
arp->ar_op = htons(op);
|
||||
p = (uint8_t *)arp;
|
||||
p += sizeof(*arp);
|
||||
memcpy(p, iface->hwaddr, iface->hwlen);
|
||||
p += iface->hwlen;
|
||||
memcpy(p, &sip, sizeof(sip));
|
||||
p += sizeof(sip);
|
||||
/* ARP requests should ignore this */
|
||||
retval = iface->hwlen;
|
||||
while (retval--)
|
||||
*p++ = '\0';
|
||||
memcpy(p, &tip, sizeof(tip));
|
||||
p += sizeof(tip);
|
||||
retval = send_raw_packet(iface, ETHERTYPE_ARP, arp, arpsize);
|
||||
free(arp);
|
||||
return retval;
|
||||
}
|
|
@ -0,0 +1,176 @@
|
|||
/*
|
||||
* dhcpcd - DHCP client daemon
|
||||
* Copyright 2006-2008 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 INTERFACE_H
|
||||
#define INTERFACE_H
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/if_ether.h>
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifndef DUID_LEN
|
||||
# define DUID_LEN 128 + 2
|
||||
#endif
|
||||
|
||||
#define EUI64_ADDR_LEN 8
|
||||
#define INFINIBAND_ADDR_LEN 20
|
||||
|
||||
/* Linux 2.4 doesn't define this */
|
||||
#ifndef ARPHRD_IEEE1394
|
||||
# define ARPHRD_IEEE1394 24
|
||||
#endif
|
||||
|
||||
/* The BSD's don't define this yet */
|
||||
#ifndef ARPHRD_INFINIBAND
|
||||
# define ARPHRD_INFINIBAND 32
|
||||
#endif
|
||||
|
||||
#define HWADDR_LEN 20
|
||||
|
||||
/* Work out if we have a private address or not
|
||||
* 10/8
|
||||
* 172.16/12
|
||||
* 192.168/16
|
||||
*/
|
||||
#ifndef IN_PRIVATE
|
||||
# define IN_PRIVATE(addr) (((addr & IN_CLASSA_NET) == 0x0a000000) || \
|
||||
((addr & 0xfff00000) == 0xac100000) || \
|
||||
((addr & IN_CLASSB_NET) == 0xc0a80000))
|
||||
#endif
|
||||
|
||||
#define LINKLOCAL_ADDR 0xa9fe0000
|
||||
#define LINKLOCAL_MASK IN_CLASSB_NET
|
||||
#define LINKLOCAL_BRDC (LINKLOCAL_ADDR | ~LINKLOCAL_MASK)
|
||||
|
||||
#ifndef IN_LINKLOCAL
|
||||
# define IN_LINKLOCAL(addr) ((addr & IN_CLASSB_NET) == LINKLOCAL_ADDR)
|
||||
#endif
|
||||
|
||||
/* There is an argument that this should be converted to an STAIL using
|
||||
* queue(3). However, that isn't readily available on all libc's that
|
||||
* dhcpcd works on. The only benefit of STAILQ over this is the ability to
|
||||
* quickly loop backwards through the list - currently we reverse the list
|
||||
* and then move through it forwards. This isn't that much of a big deal
|
||||
* though as the norm is to just have one default route, and an IPV4LL route.
|
||||
* You can (and do) get more routes in the DHCP message, but not enough to
|
||||
* really warrant a change to STAIL queue for performance reasons. */
|
||||
struct rt {
|
||||
struct in_addr dest;
|
||||
struct in_addr net;
|
||||
struct in_addr gate;
|
||||
struct rt *next;
|
||||
};
|
||||
|
||||
struct interface
|
||||
{
|
||||
char name[IF_NAMESIZE];
|
||||
sa_family_t family;
|
||||
unsigned char hwaddr[HWADDR_LEN];
|
||||
size_t hwlen;
|
||||
int arpable;
|
||||
|
||||
int raw_fd;
|
||||
int udp_fd;
|
||||
int arp_fd;
|
||||
int link_fd;
|
||||
size_t buffer_size, buffer_len, buffer_pos;
|
||||
unsigned char *buffer;
|
||||
|
||||
struct in_addr addr;
|
||||
struct in_addr net;
|
||||
struct rt *routes;
|
||||
|
||||
char leasefile[PATH_MAX];
|
||||
time_t start_uptime;
|
||||
|
||||
unsigned char *clientid;
|
||||
};
|
||||
|
||||
uint32_t get_netmask(uint32_t);
|
||||
char *hwaddr_ntoa(const unsigned char *, size_t);
|
||||
size_t hwaddr_aton(unsigned char *, const char *);
|
||||
|
||||
struct interface *read_interface(const char *, int);
|
||||
int do_mtu(const char *, short int);
|
||||
#define get_mtu(iface) do_mtu(iface, 0)
|
||||
#define set_mtu(iface, mtu) do_mtu(iface, mtu)
|
||||
|
||||
int inet_ntocidr(struct in_addr);
|
||||
int inet_cidrtoaddr(int, struct in_addr *);
|
||||
|
||||
int up_interface(const char *);
|
||||
int do_interface(const char *, unsigned char *, size_t *,
|
||||
struct in_addr *, struct in_addr *, int);
|
||||
int if_address(const char *, const struct in_addr *, const struct in_addr *,
|
||||
const struct in_addr *, int);
|
||||
#define add_address(ifname, addr, net, brd) \
|
||||
if_address(ifname, addr, net, brd, 1)
|
||||
#define del_address(ifname, addr, net) \
|
||||
if_address(ifname, addr, net, NULL, -1)
|
||||
#define has_address(ifname, addr, net) \
|
||||
do_interface(ifname, NULL, NULL, addr, net, 0)
|
||||
#define get_address(ifname, addr, net) \
|
||||
do_interface(ifname, NULL, NULL, addr, net, 1)
|
||||
|
||||
int if_route(const char *, const struct in_addr *, const struct in_addr *,
|
||||
const struct in_addr *, int, int);
|
||||
#define add_route(ifname, dest, mask, gate, metric) \
|
||||
if_route(ifname, dest, mask, gate, metric, 1)
|
||||
#define change_route(ifname, dest, mask, gate, metric) \
|
||||
if_route(ifname, dest, mask, gate, metric, 0)
|
||||
#define del_route(ifname, dest, mask, gate, metric) \
|
||||
if_route(ifname, dest, mask, gate, metric, -1)
|
||||
void free_routes(struct rt *);
|
||||
|
||||
int open_udp_socket(struct interface *);
|
||||
const size_t udp_dhcp_len;
|
||||
ssize_t make_udp_packet(uint8_t **, const uint8_t *, size_t,
|
||||
struct in_addr, struct in_addr);
|
||||
ssize_t get_udp_data(const uint8_t **, const uint8_t *);
|
||||
int valid_udp_packet(const uint8_t *);
|
||||
|
||||
int open_socket(struct interface *, int);
|
||||
ssize_t send_packet(const struct interface *, struct in_addr,
|
||||
const uint8_t *, ssize_t);
|
||||
ssize_t send_raw_packet(const struct interface *, int,
|
||||
const void *, ssize_t);
|
||||
ssize_t get_raw_packet(struct interface *, int, void *, ssize_t);
|
||||
|
||||
int send_arp(const struct interface *, int, in_addr_t, in_addr_t);
|
||||
|
||||
int open_link_socket(struct interface *);
|
||||
int link_changed(struct interface *);
|
||||
int carrier_status(const char *);
|
||||
#endif
|
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
* dhcpcd - DHCP client daemon
|
||||
* Copyright 2006-2008 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/types.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <poll.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "signals.h"
|
||||
|
||||
static int signal_pipe[2];
|
||||
|
||||
static const int handle_sigs[] = {
|
||||
SIGHUP,
|
||||
SIGALRM,
|
||||
SIGTERM,
|
||||
SIGINT
|
||||
};
|
||||
|
||||
static void
|
||||
signal_handler(int sig)
|
||||
{
|
||||
int serrno = errno;
|
||||
|
||||
write(signal_pipe[1], &sig, sizeof(sig));
|
||||
/* Restore errno */
|
||||
errno = serrno;
|
||||
}
|
||||
|
||||
int
|
||||
signal_fd(void)
|
||||
{
|
||||
return (signal_pipe[0]);
|
||||
}
|
||||
|
||||
/* Read a signal from the signal pipe. Returns 0 if there is
|
||||
* no signal, -1 on error (and sets errno appropriately), and
|
||||
* your signal on success */
|
||||
int
|
||||
signal_read(void)
|
||||
{
|
||||
int sig = -1;
|
||||
char buf[16];
|
||||
size_t bytes;
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
bytes = read(signal_pipe[0], buf, sizeof(buf));
|
||||
if (bytes >= sizeof(sig))
|
||||
memcpy(&sig, buf, sizeof(sig));
|
||||
return sig;
|
||||
}
|
||||
|
||||
/* Call this before doing anything else. Sets up the socket pair
|
||||
* and installs the signal handler */
|
||||
int
|
||||
signal_init(void)
|
||||
{
|
||||
if (pipe(signal_pipe) == -1)
|
||||
return -1;
|
||||
/* Don't block on read */
|
||||
if (set_nonblock(signal_pipe[0]) == -1)
|
||||
return -1;
|
||||
/* Stop any scripts from inheriting us */
|
||||
if (set_cloexec(signal_pipe[0]) == -1)
|
||||
return -1;
|
||||
if (set_cloexec(signal_pipe[1]) == -1)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
signal_handle(void (*func)(int))
|
||||
{
|
||||
unsigned int i;
|
||||
struct sigaction sa;
|
||||
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sa.sa_handler = func;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
|
||||
for (i = 0; i < sizeof(handle_sigs) / sizeof(handle_sigs[0]); i++)
|
||||
if (sigaction(handle_sigs[i], &sa, NULL) == -1)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
signal_setup(void)
|
||||
{
|
||||
return signal_handle(signal_handler);
|
||||
}
|
||||
|
||||
int
|
||||
signal_reset(void)
|
||||
{
|
||||
return signal_handle(SIG_DFL);
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* dhcpcd - DHCP client daemon
|
||||
* Copyright 2006-2008 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 SIGNAL_H
|
||||
#define SIGNAL_H
|
||||
|
||||
#include <poll.h>
|
||||
|
||||
int signal_init(void);
|
||||
int signal_setup(void);
|
||||
int signal_reset(void);
|
||||
int signal_fd(void);
|
||||
int signal_read(void);
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue