Update build glue for dhcpcd 4.0.0rc3 and move it to

src/external/dhcpcd.

Make dhcpcd quiet by default when run from rc.
This commit is contained in:
joerg 2008-07-27 19:31:02 +00:00
parent b2f096aeb9
commit d249112fae
40 changed files with 42 additions and 7369 deletions

65
dist/dhcpcd/README vendored
View File

@ -1,65 +0,0 @@
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 CFLAGS.
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 hook.d are installed by default.
By default we install 01-test.sh, 10-resolv.conf.sh and 15-hostname.sh.
To add more simply add them in the HOOKSCRIPTS variable.
make HOOKSCRIPTS=50-ntp.sh install
Compatibility
-------------
If you require compatibility with dhcpcd-3 and older style variables,
you can install 50-dhcpcd-compat.sh into the directory $LIBEXECDIR/dhcpcd.hook.d
We don't install this by default.
You should also add -DCMDLINE_COMPAT to your CFLAGS 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

View File

@ -1,107 +0,0 @@
/*
* 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 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]);

203
dist/dhcpcd/bpf.c vendored
View File

@ -1,203 +0,0 @@
/*
* 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;
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;
} else {
pf.bf_insns = UNCONST(dhcp_bpf_filter);
pf.bf_len = dhcp_bpf_filter_len;
}
if (ioctl(fd, BIOCSETF, &pf) == -1)
goto eexit;
if (iface->fd != -1)
close(iface->fd);
close_on_exec(fd);
iface->fd = fd;
return fd;
eexit:
free(iface->buffer);
iface->buffer = NULL;
close(fd);
return -1;
}
ssize_t
send_raw_packet(const struct interface *iface, int type,
const void *data, ssize_t len)
{
struct iovec iov[2];
struct ether_header hw;
memset(&hw, 0, sizeof(hw));
memset(&hw.ether_dhost, 0xff, ETHER_ADDR_LEN);
hw.ether_type = htons(type);
iov[0].iov_base = &hw;
iov[0].iov_len = sizeof(hw);
iov[1].iov_base = UNCONST(data);
iov[1].iov_len = len;
return writev(iface->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 dhcp packet. */
ssize_t
get_packet(struct interface *iface, void *data, ssize_t len)
{
struct bpf_hdr packet;
struct ether_header hw;
ssize_t bytes;
const unsigned char *payload, *d;
for (;;) {
if (iface->buffer_len == 0) {
bytes = read(iface->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. */
memcpy(&hw, iface->buffer + packet.bh_hdrlen, sizeof(hw));
payload = iface->buffer + packet.bh_hdrlen + sizeof(hw);
if (hw.ether_type == htons(ETHERTYPE_ARP)) {
bytes = packet.bh_caplen - sizeof(hw);
if (bytes > len)
bytes = len;
memcpy(data, payload, bytes);
} else if (valid_udp_packet(payload) >= 0) {
bytes = get_udp_data(&d, payload);
if (bytes > len)
bytes = len;
memcpy(data, d, bytes);
} else
bytes = -1;
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;
}
}

1315
dist/dhcpcd/client.c vendored

File diff suppressed because it is too large Load Diff

35
dist/dhcpcd/client.h vendored
View File

@ -1,35 +0,0 @@
/*
* 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

271
dist/dhcpcd/common.c vendored
View File

@ -1,271 +0,0 @@
/*
* 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
close_on_exec(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;
}
/* 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
get_time(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 tp;
if (get_time(&tp) == -1)
return -1;
return tp.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 */
}

82
dist/dhcpcd/common.h vendored
View File

@ -1,82 +0,0 @@
/*
* 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>
#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
#define HAVE_CLOSEFROM 1
#endif
#if defined(__linux__) || defined(__FreeBSD__)
# undef HAVE_CLOSEFROM
int closefrom(int);
#endif
int close_fds(void);
int close_on_exec(int);
ssize_t get_line(char **, size_t *, FILE *);
int get_time(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

94
dist/dhcpcd/config.h vendored
View File

@ -1,94 +0,0 @@
/*
* 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-beta5"
/* You can enable/disable various chunks of optional code here.
* You would only do this to try and shrink the end binary if dhcpcd
* was running on a low memory device */
#define ENABLE_ARP
/* IPV4LL, aka ZeroConf, aka APIPA, aka RFC 3927.
* Needs ARP. */
#define ENABLE_IPV4LL
/*
* 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 ENABLE_IPV4LL_ALWAYSROUTE
/* Allow dhcpcd to create a DUID (LLT) and use it to make an IAID for the
* ClientID. Even enabled here, we need a config directive to actually use it
* so this toggle is just to remove it from dhcpcd to make the binary smaller.
* You can always create your own DUID file that just contains the
* hex string that represents the DUID.
* See RFC 3315 for details on this. */
#define ENABLE_DUID
/* 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
#define UNCONST(a) ((void *)(unsigned long)(const void *)(a))
#endif

View File

@ -1,497 +0,0 @@
/*
* 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, "exec `%s'", options->script);
/* Make our env */
elen = 4;
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());
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, "removing 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)
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 ENABLE_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;
}
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) {
if (!(options->options & DHCPCD_KEEPADDRESS)) {
delete_routes(iface, options->metric);
logger(LOG_DEBUG, "deleting IP address %s/%d",
inet_ntoa(iface->addr),
inet_ntocidr(iface->net));
if (del_address(iface->name, &iface->addr,
&iface->net) == -1 &&
errno != ENOENT)
logger(LOG_ERR, "del_address: %s",
strerror(errno));
iface->addr.s_addr = 0;
iface->net.s_addr = 0;
}
}
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 &&
!(options->options & DHCPCD_KEEPADDRESS))
del_address(iface->name, &iface->addr, &iface->net);
#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;
}

View File

@ -1,41 +0,0 @@
/*
* 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

1202
dist/dhcpcd/dhcp.c vendored

File diff suppressed because it is too large Load Diff

184
dist/dhcpcd/dhcp.h vendored
View File

@ -1,184 +0,0 @@
/*
* 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_BROADCAST = 28,
DHCP_STATICROUTE = 33,
DHCP_NISDOMAIN = 40,
DHCP_NISSERVER = 41,
DHCP_NTPSERVER = 42,
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);
//const uint8_t *get_option(const struct dhcp_message *, uint8_t);
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

View File

@ -1,105 +0,0 @@
.\" 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 May 21, 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 or user defined hook scripts.
System hook scripts are found in
.Pa @HOOKDIR@
and the user defined hook is
.Pa @SYSCONFDIR@/dhcpcd.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.hook
and any scripts found in
.Pa @HOOKDIR@
in a lexical order.
.Sh SEE ALSO
.Xr dhcpcd 8
.Sh AUTHORS
.An Roy Marples <roy@marples.name>
.Sh BUGS
Please report them to http://bugs.marples.name

View File

@ -1,38 +0,0 @@
#!/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.hook \
@HOOKDIR@/*
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

View File

@ -1,347 +0,0 @@
.\" 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 May 21, 2008
.Dt DHCPCD 8 SMM
.Sh NAME
.Nm dhcpcd
.Nd an RFC 2131 compliant DHCP client
.Sh SYNOPSIS
.Nm
.Op Fl dknpADEGLSTV
.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 t , -timeout Ar seconds
.Op Fl u , -userclass Ar class
.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 probe every 10 seconds for a DHCP server to get a
proper address.
.Pp
Even when
.Nm
obtains a proper lease, it will still add a Local Link route
.Po
165.254.0.0/16
.Pc
so that the host can communicate with clients using these addresses.
.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 test ,
.Pa resolv.conf
and
.Pa 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 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 DHCP vendor
.Ar classid
field we send. 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 it's 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 we use the first address currently assigned to the
.Ar interface .
.It Fl s , -inform Op Ar address Op / Ar cidr
Behaves exactly like
.Fl r , -request
as above, but sends a DHCP inform instead of a request.
This requires the interface to be configured first.
This does not get a lease as such, just notifies the DHCP server of the
.Ar address
we are using.
If we fail to contact a DHCP server then we return a failure instead of falling
back on IPv4LL.
.It Fl t , -timeout Ar seconds
Timeout after
.Ar seconds ,
instead of the default 20.
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 memebers of the class DHCP options other than the
default, without having to know things like hardware address or hostname.
.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 we got for the
interface if it hasn't yet 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 option that deal with turning these bits off.
.Bl -tag -width indent
.It Fl A , -noarp
Don't request or claim the address by ARP.
.It Fl G , -nogateway
Don't set any default routes.
.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 settings you would do:-
.D1 dhcpcd -C resolv.conf
.It Fl L , -noipv4ll
Don't use IPv4LL at all.
.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 discover messages we 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 when we 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.
.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

852
dist/dhcpcd/dhcpcd.c vendored
View File

@ -1,852 +0,0 @@
/*
* 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 <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 "c:df:h:i:kl:m:no:pr:s:t:u:xAC:DEF:GI:LO:TV"
static int doversion = 0;
static int dohelp = 0;
static const struct option longopts[] = {
{"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'},
{"inform", optional_argument, NULL, 's'},
{"request", optional_argument, NULL, 'r'},
{"timeout", required_argument, NULL, 't'},
{"userclass", required_argument, NULL, 'u'},
{"exit", no_argument, NULL, 'x'},
{"noarp", no_argument, NULL, 'A'},
{"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'},
{"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, 'X'},
{"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 "XZ:"
#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)
{
printf("usage: "PACKAGE" [-dknpxADEGHLOSTV] [-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");
}
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];
}
static int
parse_option(int opt, char *oarg, struct options *options)
{
static int userclasses = 0;
int i;
int j;
char *p;
size_t s;
switch(opt) {
case 'h':
if (!oarg)
*options->hostname = '\0';
else if (strlen(oarg) >= MAXHOSTNAMELEN) {
logger(LOG_ERR,
"`%s' too long for HostName string, max is %d",
oarg, MAXHOSTNAMELEN);
return -1;
} else
strlcpy(options->hostname, oarg,
sizeof(options->hostname));
break;
case 'i':
if (!oarg) {
*options->classid = '\0';
} else if (strlen(oarg) >= CLASS_ID_MAX_LEN) {
logger(LOG_ERR,
"`%s' too long for ClassID string, max is %d",
oarg, CLASS_ID_MAX_LEN);
return -1;
} else
strlcpy(options->classid, oarg,
sizeof(options->classid));
break;
case 'l':
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;
}
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 's':
options->options |= DHCPCD_INFORM;
options->options &= ~DHCPCD_ARP;
if (!oarg || strlen(optarg) == 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 (strlen(oarg) > 0 &&
!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':
j = 0;
for (i = 0; i < userclasses; i++)
j += (int)options->userclass[j] + 1;
if (j + 1 + strlen(oarg) >= USERCLASS_MAX_LEN) {
logger(LOG_ERR,
"userclass overrun, max is %d",
USERCLASS_MAX_LEN);
return -1;
}
userclasses++;
memcpy(options->userclass + j + 1 ,
oarg, strlen(optarg));
options->userclass[j] = strlen(oarg);
options->userclass_len += (strlen(oarg)) + 1;
break;
case 'A':
options->options &= ~DHCPCD_ARP;
/* IPv4LL requires ARP */
options->options &= ~DHCPCD_IPV4LL;
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':
if (!oarg) {
options->fqdn = FQDN_BOTH;
break;
}
if (strncmp(oarg, "none", strlen(optarg)) == 0)
options->fqdn = FQDN_NONE;
else if (strncmp(oarg, "ptr", strlen(optarg)) == 0)
options->fqdn = FQDN_PTR;
else if (strncmp(oarg, "both", strlen(optarg)) == 0)
options->fqdn = FQDN_BOTH;
else {
logger(LOG_ERR, "invalid value `%s' for FQDN",
oarg);
return -1;
}
break;
case 'G':
options->options &= ~DHCPCD_GATEWAY;
break;
case 'I':
if (oarg) {
if (strlen(oarg) >= CLIENT_ID_MAX_LEN) {
logger(LOG_ERR, "`%s' is too long for"
" ClientID, max is %d",
oarg, CLIENT_ID_MAX_LEN);
return -1;
}
if (strlcpy(options->clientid, oarg,
sizeof(options->clientid)) == 0) {
/* empty string disabled duid */
options->options &= ~DHCPCD_DUID;
options->options &= ~DHCPCD_CLIENTID;
}
} else {
options->clientid[0] = '\0';
options->options &= ~DHCPCD_DUID;
options->options &= ~DHCPCD_CLIENTID;
}
break;
case 'L':
options->options &= ~DHCPCD_IPV4LL;
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 pidfd = -1;
int sig = 0;
int retval = EXIT_FAILURE;
char *line, *option, *p, *lp, *buffer = NULL;
char lt;
size_t len = 0;
FILE *f;
char *cf = NULL;
char *intf = NULL;
closefrom(3);
openlog(PACKAGE, LOG_PID, LOG_LOCAL0);
#ifdef THERE_IS_NO_FORK
dhcpcd_argv = argv;
dhcpcd_argc = argc;
if (!realpath(argv[0], dhcpcd)) {
fprintf(stderr, "unable to resolve the path `%s': %s",
argv[0], strerror(errno));
goto abort;
}
#endif
options = xzalloc(sizeof(*options));
options->script = SCRIPT;
snprintf(options->classid, CLASS_ID_MAX_LEN, "%s %s",
PACKAGE, VERSION);
options->options |= DHCPCD_GATEWAY | DHCPCD_DAEMONISE | DHCPCD_CLIENTID;
#ifdef ENABLE_ARP
options->options |= DHCPCD_ARP;
#ifdef ENABLE_IPV4LL
options->options |= DHCPCD_IPV4LL;
#endif
#endif
options->timeout = DEFAULT_TIMEOUT;
#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 :) */
# ifdef ENABLE_DUID
if ((f = fopen(DUID, "r"))) {
options->options |= DHCPCD_DUID;
fclose(f);
}
# endif
#endif
gethostname(options->hostname, sizeof(options->hostname));
if (strcmp(options->hostname, "(none)") == 0 ||
strcmp(options->hostname, "localhost") == 0)
*options->hostname = '\0';
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");
printf("Compile time options:"
#ifdef ENABLE_ARP
" ARP"
#endif
#ifdef ENABLE_DUID
" DUID"
#endif
#ifdef ENABLE_IPV4LL
" IPV4LL"
#endif
#ifdef THERE_IS_NO_FORK
" THERE_IS_NO_FORK"
#endif
"\n");
}
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 */
lt = '\\';
if (line && *line) {
p = line + strlen(line) - 1;
while (p != line && (*p == ' ' || *p == '\t')) {
/* Remember the last char trimmed */
lt = *p;
*p-- = '\0';
}
}
/* Remove quotes if present */
if (line && *line == '"') {
p = line + strlen(line) - 1;
if (*p == '"') {
line++;
*p = '\0';
}
}
/* Process escapes */
lp = p = line;
while (p && *p) {
if (*p == '\\')
p++;
/* EOL? */
if (*p == '\0') {
/* Restore the last char trimmed */
*lp++ = lt;
break;
}
*lp++ = *p++;
}
if (lp)
*lp = '\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 'X':
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 'O':
if (make_reqmask(options->reqmask, &optarg, -1) != 0) {
logger(LOG_ERR, "unknown option `%s'", optarg);
return -1;
}
if (make_reqmask(options->nomask, &optarg, 1) != 0) {
logger(LOG_ERR, "unknown option `%s'", optarg);
return -1;
}
break;
case 'T':
options->options |= DHCPCD_TEST | DHCPCD_PERSISTENT;
break;
#ifdef CMDLINE_COMPAT
case 'H': /* FALLTHROUGH */
case 'M':
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)
{
if (get_address(options->interface,
&options->request_address,
&options->request_netmask) == 0)
options->options |= DHCPCD_KEEPADDRESS;
}
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) {
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");
if (pid != 0 && (sig != SIGALRM || i != 0))
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;
}
pidfd = open(options->pidfile,
O_WRONLY | O_CREAT | O_NONBLOCK, 0664);
if (pidfd == -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(pidfd, LOCK_EX | LOCK_NB) == -1) {
logger(LOG_ERR, "flock `%s': %s",
options->pidfile, strerror(errno));
goto abort;
}
close_on_exec(pidfd);
writepid(pidfd, getpid());
logger(LOG_INFO, PACKAGE " " VERSION " starting");
}
if (dhcp_run(options, &pidfd) == 0)
retval = EXIT_SUCCESS;
abort:
/* If we didn't daemonise then we need to punt the pidfile now */
if (pidfd > -1) {
close(pidfd);
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 */
}

View File

@ -1,8 +0,0 @@
# 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

View File

@ -1,125 +0,0 @@
.\" 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 May 20, 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
.Fl h , -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 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 20 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.
.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

95
dist/dhcpcd/dhcpcd.h vendored
View File

@ -1,95 +0,0 @@
/*
* 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 20
#define DEFAULT_LEASETIME 3600 /* 1 hour */
#define CLASS_ID_MAX_LEN 48
#define CLIENT_ID_MAX_LEN 48
#define USERCLASS_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_KEEPADDRESS (1 << 13)
#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)
struct options {
char interface[IF_NAMESIZE];
char hostname[MAXHOSTNAMELEN];
int fqdn;
char classid[CLASS_ID_MAX_LEN];
char clientid[CLIENT_ID_MAX_LEN];
char userclass[USERCLASS_MAX_LEN];
uint8_t reqmask[256 / 8];
uint8_t nomask[256 / 8];
size_t userclass_len;
uint32_t leasetime;
time_t timeout;
int metric;
int options;
struct in_addr request_address;
struct in_addr request_netmask;
char **environ;
const char *script;
char pidfile[PATH_MAX];
};
#endif

View File

@ -1,6 +0,0 @@
# Just echo our DHCP options we have
if [ "${reason}" = "TEST" ]; then
env | grep "^\(interface\|pid\|reason\|skip_hooks\)="
env | grep "^\(new_\|old_\)" | sort
fi

View File

@ -1,40 +0,0 @@
# 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

View File

@ -1,33 +0,0 @@
# 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

View File

@ -1,21 +0,0 @@
# 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

View File

@ -1,51 +0,0 @@
# 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

187
dist/dhcpcd/if-bsd.c vendored
View File

@ -1,187 +0,0 @@
/*
* 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;
}

118
dist/dhcpcd/logger.c vendored
View File

@ -1,118 +0,0 @@
/*
* 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_WARNING;
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);
}

44
dist/dhcpcd/logger.h vendored
View File

@ -1,44 +0,0 @@
/*
* 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

800
dist/dhcpcd/net.c vendored
View File

@ -1,800 +0,0 @@
/*
* 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
#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 next data is EOL or a seperator with data */
if (!(*p == '\0' || (*p == ':' && *(p + 1) != '\0'))) {
errno = EINVAL;
return 0;
}
/* Ensure that digits are hex */
if (isxdigit((unsigned char)c[0]) == 0 ||
isxdigit((unsigned char)c[1]) == 0)
{
errno = EINVAL;
return 0;
}
p++;
if (bp)
*bp++ = (unsigned char)strtol(c, NULL, 16);
else
len++;
}
if (bp)
return bp - buffer;
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;
}
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;
#ifdef __linux__
char *p;
#endif
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;
}
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) == -1)
goto eexit;
if (!(ifr.ifr_flags & IFF_UP) || !(ifr.ifr_flags & IFF_RUNNING)) {
ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
if (ioctl(s, SIOCSIFFLAGS, &ifr) != 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->fd = -1;
iface->udp_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;
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 (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;
if (bind(s, &su.sa, sizeof(su)) == -1)
goto eexit;
iface->udp_fd = s;
close_on_exec(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;
};
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;
}
#ifdef ENABLE_ARP
/* These are really for IPV4LL */
#define NPROBES 3
#define PROBE_INTERVAL 200
#define NCLAIMS 2
#define CLAIM_INTERVAL 200
static int
send_arp(const struct interface *iface, int op, struct in_addr sip,
const unsigned char *taddr, struct in_addr tip)
{
struct arphdr *arp;
size_t arpsize;
unsigned char *p;
int retval;
arpsize = sizeof(*arp) + 2 * iface->hwlen + 2 *sizeof(sip);
arp = xzalloc(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 = (unsigned char *)arp;
p += sizeof(*arp);
memcpy(p, iface->hwaddr, iface->hwlen);
p += iface->hwlen;
memcpy(p, &sip, sizeof(sip));
p += sizeof(sip);
if (taddr != NULL)
memcpy(p, taddr, iface->hwlen);
else
memset(p, 0, iface->hwlen);
p += iface->hwlen;
memcpy(p, &tip, sizeof(tip));
retval = send_raw_packet(iface, ETHERTYPE_ARP, arp, arpsize);
if (retval == -1)
logger(LOG_ERR,"send_packet: %s", strerror(errno));
free(arp);
return retval;
}
int
arp_claim(struct interface *iface, struct in_addr address)
{
struct arphdr reply;
uint8_t arp_reply[sizeof(reply) + 2 * 4 /* IPv4 */ + 2 * 8 /* EUI64 */];
struct in_addr reply_ipv4;
struct ether_addr reply_mac;
long timeout = 0;
int retval = -1;
int nprobes = 0;
int nclaims = 0;
struct in_addr null_address;
struct pollfd fds[] = {
{ -1, POLLIN, 0 },
{ -1, POLLIN, 0 }
};
int bytes;
int s = 0;
struct timeval stopat;
struct timeval now;
if (!iface->arpable) {
logger(LOG_DEBUG, "interface `%s' is not ARPable", iface->name);
return 0;
}
if (!IN_LINKLOCAL(ntohl(iface->addr.s_addr)) &&
!IN_LINKLOCAL(ntohl(address.s_addr)))
logger(LOG_INFO,
"checking %s is available on attached networks",
inet_ntoa(address));
if (!open_socket(iface, ETHERTYPE_ARP)) {
logger (LOG_ERR, "open_socket: %s", strerror(errno));
return -1;
}
fds[0].fd = signal_fd();
fds[1].fd = iface->fd;
memset(&null_address, 0, sizeof(null_address));
for (;;) {
s = 0;
/* Only poll if we have a timeout */
if (timeout > 0) {
s = poll(fds, 2, timeout);
if (s == -1) {
if (errno == EINTR) {
if (signal_exists(NULL) == -1) {
errno = 0;
continue;
} else
break;
}
logger(LOG_ERR, "poll: `%s'", strerror(errno));
break;
}
}
/* Timed out */
if (s == 0) {
if (nprobes < NPROBES) {
nprobes ++;
timeout = PROBE_INTERVAL;
logger(LOG_DEBUG, "sending ARP probe #%d",
nprobes);
if (send_arp(iface, ARPOP_REQUEST,
null_address, NULL,
address) == -1)
break;
/* IEEE1394 cannot set ARP target address
* according to RFC2734 */
if (nprobes >= NPROBES &&
iface->family == ARPHRD_IEEE1394)
nclaims = NCLAIMS;
} else if (nclaims < NCLAIMS) {
nclaims ++;
timeout = CLAIM_INTERVAL;
logger(LOG_DEBUG, "sending ARP claim #%d",
nclaims);
if (send_arp(iface, ARPOP_REQUEST,
address, iface->hwaddr,
address) == -1)
break;
} else {
/* No replies, so done */
retval = 0;
break;
}
/* Setup our stop time */
if (get_time(&stopat) != 0)
break;
stopat.tv_usec += timeout;
continue;
}
/* We maybe ARP flooded, so check our time */
if (get_time(&now) != 0)
break;
if (timercmp(&now, &stopat, >)) {
timeout = 0;
continue;
}
if (!(fds[1].revents & POLLIN))
continue;
for(;;) {
memset(arp_reply, 0, sizeof(arp_reply));
bytes = get_packet(iface,
arp_reply, sizeof(arp_reply));
if (bytes == -1 || bytes == 0)
break;
memcpy(&reply, arp_reply, sizeof(reply));
/* Only these types are recognised */
if (reply.ar_op != htons(ARPOP_REPLY))
continue;
/* Protocol must be IP. */
if (reply.ar_pro != htons(ETHERTYPE_IP))
continue;
if (reply.ar_pln != sizeof(reply_ipv4))
continue;
if ((size_t)bytes < sizeof(reply) + 2 *
(4 + reply.ar_hln) ||
reply.ar_hln > 8)
continue;
memcpy(&reply_mac,
arp_reply + sizeof(reply), reply.ar_hln);
memcpy(&reply_ipv4,
arp_reply + sizeof(reply) + reply.ar_hln,
reply.ar_hln);
/* Ensure the ARP reply is for the our address */
if (reply_ipv4.s_addr != address.s_addr)
continue;
/* Some systems send a reply back from our hwaddress,
* which is wierd */
if (reply.ar_hln == iface->hwlen &&
memcmp(&reply_mac, iface->hwaddr,
iface->hwlen) == 0)
continue;
logger(LOG_ERR, "ARPOP_REPLY received from %s (%s)",
inet_ntoa(reply_ipv4),
hwaddr_ntoa((unsigned char *)&reply_mac,
(size_t)reply.ar_hln));
retval = -1;
goto eexit;
}
}
eexit:
close(iface->fd);
iface->fd = -1;
return retval;
}
#endif

176
dist/dhcpcd/net.h vendored
View File

@ -1,176 +0,0 @@
/*
* 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"
#ifdef ENABLE_DUID
#ifndef DUID_LEN
# define DUID_LEN 128 + 2
#endif
#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 0xffff0000
#define LINKLOCAL_BRDC 0xa9feffff
#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 fd;
int udp_fd;
size_t buffer_size, buffer_len, buffer_pos;
unsigned char *buffer;
#ifdef __linux__
int socket_protocol;
#endif
char leasefile[PATH_MAX];
struct in_addr addr;
struct in_addr net;
struct rt *routes;
time_t start_uptime;
unsigned char *clientid;
size_t clientid_len;
};
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 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 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 *);
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_packet(struct interface *, void *, ssize_t);
#ifdef ENABLE_ARP
int arp_claim(struct interface *, struct in_addr);
#endif
#endif

170
dist/dhcpcd/signals.c vendored
View File

@ -1,170 +0,0 @@
/*
* 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 int signals[5];
static const int handle_sigs[] = {
SIGHUP,
SIGALRM,
SIGTERM,
SIGINT
};
static void
signal_handler(int sig)
{
unsigned int i = 0;
int serrno = errno;
/* Add a signal to our stack */
while (signals[i])
i++;
if (i <= sizeof(signals) / sizeof(signals[0]))
signals[i] = sig;
write(signal_pipe[1], &sig, sizeof(sig));
/* Restore errno */
errno = serrno;
}
int
signal_fd(void)
{
return (signal_pipe[0]);
}
/* Check if we have a signal or not */
int
signal_exists(const struct pollfd *fd)
{
if (signals[0] || (fd && fd->revents & POLLIN))
return 0;
return -1;
}
/* 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(struct pollfd *fd)
{
int sig = -1;
unsigned int i = 0;
char buf[16];
size_t bytes;
/* Pop a signal off the our stack */
if (signals[0]) {
sig = signals[0];
while (i < (sizeof(signals) / sizeof(signals[0])) - 1) {
signals[i] = signals[i + 1];
if (!signals[++i])
break;
}
}
if (fd && fd->revents & POLLIN) {
memset(buf, 0, sizeof(buf));
bytes = read(signal_pipe[0], buf, sizeof(buf));
if (bytes >= sizeof(sig))
memcpy(&sig, buf, sizeof(sig));
/* We need to clear us from rset if nothing left in the buffer
* in case we are called many times */
if (bytes == sizeof(sig))
fd->revents = 0;
}
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;
/* Stop any scripts from inheriting us */
close_on_exec(signal_pipe[0]);
close_on_exec(signal_pipe[1]);
memset(signals, 0, sizeof(signals));
return 0;
}
static int
signal_handle(void (*func)(int), int restore)
{
unsigned int i;
struct sigaction sa, sa_old;
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, &sa_old) == -1)
return -1;
if (restore && sigaction(handle_sigs[i], &sa_old, NULL) == -1)
return -1;
return 0;
}
int
signal_setup(void)
{
return signal_handle(signal_handler, 0);
}
int
signal_reset(void)
{
return signal_handle(SIG_DFL, 0);
}
int
signal_clear(void)
{
return signal_handle(SIG_IGN, 1);
}

41
dist/dhcpcd/signals.h vendored
View File

@ -1,41 +0,0 @@
/*
* 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_clear(void);
int signal_fd(void);
int signal_exists(const struct pollfd *);
int signal_read(struct pollfd *);
#endif

View File

@ -1,4 +1,4 @@
# $NetBSD: mi,v 1.758 2008/07/22 21:07:59 dyoung Exp $
# $NetBSD: mi,v 1.759 2008/07/27 19:31:02 joerg Exp $
#
# Note: Don't delete entries from here - mark them as "obsolete" instead,
# unless otherwise stated below.
@ -134,9 +134,13 @@
./libexec base-sys-root
./libexec/dhcpcd-hooks base-dhcpcd-root
./libexec/dhcpcd-hooks/01-test base-dhcpcd-root
./libexec/dhcpcd-hooks/10-resolv.conf base-dhcpcd-root
./libexec/dhcpcd-hooks/14-lookup-hostname base-dhcpcd-root
./libexec/dhcpcd-hooks/15-hostname base-dhcpcd-root
./libexec/dhcpcd-hooks/10-mtu base-dhcpcd-root
./libexec/dhcpcd-hooks/10-resolv.conf base-obsolete obsolete
./libexec/dhcpcd-hooks/14-lookup-hostname base-obsolete obsolete
./libexec/dhcpcd-hooks/15-hostname base-obsolete obsolete
./libexec/dhcpcd-hooks/20-resolv.conf base-dhcpcd-root
./libexec/dhcpcd-hooks/29-lookup-hostname base-dhcpcd-root
./libexec/dhcpcd-hooks/30-hostname base-dhcpcd-root
./libexec/dhcpcd-hooks/50-ntp.conf base-dhcpcd-root
./libexec/dhcpcd-run-hooks base-dhcpcd-root
./libexec/lfs_cleanerd base-sysutil-bin

View File

@ -1,4 +1,4 @@
# $NetBSD: Makefile,v 1.356 2008/07/23 01:57:19 dyoung Exp $
# $NetBSD: Makefile,v 1.357 2008/07/27 19:31:03 joerg Exp $
# from: @(#)Makefile 8.7 (Berkeley) 5/25/95
# Environment variables without default values:
@ -336,7 +336,7 @@ install-etc-files: .PHONY .MAKE check_DESTDIR MAKEDEV
.for subdir in . atf defaults bluetooth iscsi mtree namedb pam.d powerd rc.d root skel ssh
${MAKEDIRTARGET} ${subdir} configinstall
.endfor
${MAKEDIRTARGET} ${NETBSDSRCDIR}/sbin/dhcpcd configinstall
${MAKEDIRTARGET} ${NETBSDSRCDIR}/external/bsd/dhcpcd/sbin/dhcpcd configinstall
${MAKEDIRTARGET} ${NETBSDSRCDIR}/usr.bin/mail configinstall
.if (${MKPF} != "no")
${MAKEDIRTARGET} ${NETBSDSRCDIR}/usr.sbin/pf configinstall

View File

@ -1,4 +1,4 @@
# $NetBSD: rc.conf,v 1.94 2008/06/20 15:21:56 yamt Exp $
# $NetBSD: rc.conf,v 1.95 2008/07/27 19:31:03 joerg Exp $
#
# /etc/defaults/rc.conf --
# default configuration of /etc/rc.conf
@ -153,7 +153,7 @@ racoon=NO # IKE daemon
auto_ifconfig=YES # config all avail. interfaces
net_interfaces="" # used only if above is NO
flushroutes=YES # flush routes in netstart
dhcpcd_flags="" # For ifconfig_XXX=dhcp.
dhcpcd_flags="-q" # For ifconfig_XXX=dhcp.
dhclient=NO # behave as a DHCP client
dhclient_flags="" # blank: config all interfaces
ntpdate=NO ntpdate_flags="-b -s" # May need '-u' thru firewall

View File

@ -1,7 +1,8 @@
# $NetBSD: Makefile,v 1.2 2008/07/16 00:41:50 christos Exp $
# $NetBSD: Makefile,v 1.3 2008/07/27 19:31:03 joerg Exp $
.include <bsd.own.mk>
SUBDIR+= dhcpcd
.if (${MKLDAP} != "no")
SUBDIR+= openldap
.endif

5
external/bsd/dhcpcd/Makefile vendored Normal file
View File

@ -0,0 +1,5 @@
# $NetBSD: Makefile,v 1.1 2008/07/27 19:31:03 joerg Exp $
SUBDIR= sbin
.include <bsd.subdir.mk>

5
external/bsd/dhcpcd/sbin/Makefile vendored Normal file
View File

@ -0,0 +1,5 @@
# $NetBSD: Makefile,v 1.1 2008/07/27 19:31:03 joerg Exp $
SUBDIR= dhcpcd
.include <bsd.subdir.mk>

11
external/bsd/dhcpcd/sbin/Makefile.inc vendored Normal file
View File

@ -0,0 +1,11 @@
# $NetBSD: Makefile.inc,v 1.1 2008/07/27 19:31:03 joerg Exp $
.include <bsd.own.mk>
WARNS?= 3
BINDIR= /sbin
.if (${MKDYNAMICROOT} == "no")
LDSTATIC?= -static
.endif

View File

@ -1,4 +1,4 @@
# $NetBSD: Makefile,v 1.2 2008/05/26 20:17:00 joerg Exp $
# $NetBSD: Makefile,v 1.1 2008/07/27 19:31:03 joerg Exp $
#
PROG= dhcpcd
@ -7,7 +7,7 @@ SRCS= bpf.c client.c common.c configure.c dhcp.c dhcpcd.c \
.include <bsd.own.mk>
DIST= ${NETBSDSRCDIR}/dist/dhcpcd
DIST= ${NETBSDSRCDIR}/external/bsd/dhcpcd/dist
.PATH: ${DIST}
CPPFLAGS+= -I${DIST}
@ -18,10 +18,10 @@ SCRIPTSDIR_dhcpcd-run-hooks= /libexec
CONFIGFILES= dhcpcd.conf
FILESDIR_dhcpcd.conf= /etc
HOOKS= 01-test 10-resolv.conf 14-lookup-hostname \
15-hostname 50-ntp.conf
HOOKS= 01-test 10-mtu 20-resolv.conf 29-lookup-hostname \
30-hostname 50-ntp.conf
FILES= ${HOOKS:C,^,${DIST}/hook.d/,}
FILES= ${HOOKS:C,^,${DIST}/dhcpcd-hooks/,}
FILESDIR= /libexec/dhcpcd-hooks
MAN= dhcpcd.conf.5 dhcpcd.8 dhcpcd-run-hooks.8

View File

@ -1,4 +1,4 @@
# $NetBSD: Makefile,v 1.111 2008/05/24 19:39:31 joerg Exp $
# $NetBSD: Makefile,v 1.112 2008/07/27 19:31:03 joerg Exp $
# @(#)Makefile 8.5 (Berkeley) 3/31/94
# Not ported: XNSrouted enpload scsiformat startslip
@ -7,7 +7,7 @@
.include <bsd.own.mk>
SUBDIR= amrctl apmlabel atactl badsect bioctl brconfig ccdconfig \
dhcpcd disklabel dkctl dkscan_bsdlabel dmesg \
disklabel dkctl dkscan_bsdlabel dmesg \
drvctl edlabel fastboot fdisk fsck fsirand gpt ifconfig init ldconfig \
mbrlabel mknod modload modunload mount newbtconf nologin \
pdisk ping pppoectl raidctl reboot rcorder rndctl route routed \