2011-03-31 09:29:22 +05:30
|
|
|
/* ndhc.c - DHCP client
|
2010-11-12 14:32:18 +05:30
|
|
|
*
|
2013-02-09 11:00:19 +05:30
|
|
|
* Copyright (c) 2004-2013 Nicholas J. Kain <njkain at gmail dot com>
|
2011-07-25 12:00:57 +05:30
|
|
|
* All rights reserved.
|
2010-11-12 14:32:18 +05:30
|
|
|
*
|
2011-07-25 12:00:57 +05:30
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions are met:
|
2010-11-12 14:32:18 +05:30
|
|
|
*
|
2011-07-25 12:00:57 +05:30
|
|
|
* - Redistributions of source code must retain the above copyright notice,
|
|
|
|
* this list of conditions and the following disclaimer.
|
2010-11-12 14:32:18 +05:30
|
|
|
*
|
2011-07-25 12:00:57 +05:30
|
|
|
* - 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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.
|
2010-11-12 14:32:18 +05:30
|
|
|
*/
|
2010-11-13 01:03:17 +05:30
|
|
|
|
2010-11-12 14:32:18 +05:30
|
|
|
#include <stdio.h>
|
|
|
|
#include <sys/time.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/file.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <getopt.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <signal.h>
|
|
|
|
#include <time.h>
|
|
|
|
#include <string.h>
|
2011-07-03 15:06:47 +05:30
|
|
|
#include <ctype.h>
|
2011-06-30 09:17:31 +05:30
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <arpa/inet.h>
|
2010-12-01 23:41:09 +05:30
|
|
|
#include <sys/epoll.h>
|
2010-12-01 23:05:13 +05:30
|
|
|
#include <sys/signalfd.h>
|
2010-11-12 14:32:18 +05:30
|
|
|
#include <net/if.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <pwd.h>
|
|
|
|
#include <grp.h>
|
|
|
|
|
2010-11-13 05:14:49 +05:30
|
|
|
#include "ndhc-defines.h"
|
2010-12-24 16:30:37 +05:30
|
|
|
#include "config.h"
|
2011-06-30 09:17:31 +05:30
|
|
|
#include "state.h"
|
2010-11-12 14:32:18 +05:30
|
|
|
#include "options.h"
|
2011-07-02 13:21:44 +05:30
|
|
|
#include "dhcp.h"
|
2010-12-24 20:02:58 +05:30
|
|
|
#include "sys.h"
|
2010-12-24 20:42:41 +05:30
|
|
|
#include "ifchange.h"
|
2010-12-24 20:28:47 +05:30
|
|
|
#include "arp.h"
|
2011-07-04 03:00:55 +05:30
|
|
|
#include "nl.h"
|
2011-03-30 00:07:45 +05:30
|
|
|
#include "netlink.h"
|
2011-04-20 02:07:43 +05:30
|
|
|
#include "leasefile.h"
|
2011-03-30 00:07:45 +05:30
|
|
|
|
2010-11-12 14:32:18 +05:30
|
|
|
#include "log.h"
|
2010-11-12 16:12:07 +05:30
|
|
|
#include "chroot.h"
|
2010-11-12 19:34:43 +05:30
|
|
|
#include "cap.h"
|
2010-11-12 16:12:07 +05:30
|
|
|
#include "strl.h"
|
2010-11-13 05:14:49 +05:30
|
|
|
#include "pidfile.h"
|
2010-12-02 10:03:25 +05:30
|
|
|
#include "io.h"
|
2012-07-20 18:53:18 +05:30
|
|
|
#include "seccomp-bpf.h"
|
2010-11-12 14:32:18 +05:30
|
|
|
|
2010-12-24 17:30:42 +05:30
|
|
|
struct client_state_t cs = {
|
2011-06-27 03:51:40 +05:30
|
|
|
.init = 1,
|
2010-12-24 17:30:42 +05:30
|
|
|
.epollFd = -1,
|
|
|
|
.signalFd = -1,
|
|
|
|
.listenFd = -1,
|
|
|
|
.arpFd = -1,
|
2011-03-30 01:04:00 +05:30
|
|
|
.nlFd = -1,
|
2012-04-13 05:36:05 +05:30
|
|
|
.nlPortId = -1,
|
2011-03-31 08:47:27 +05:30
|
|
|
.routerArp = "\0\0\0\0\0\0",
|
2011-07-11 22:54:59 +05:30
|
|
|
.serverArp = "\0\0\0\0\0\0",
|
2010-12-24 17:30:42 +05:30
|
|
|
};
|
2010-11-12 14:32:18 +05:30
|
|
|
|
|
|
|
struct client_config_t client_config = {
|
2010-11-13 01:03:17 +05:30
|
|
|
.interface = "eth0",
|
2011-03-31 08:47:27 +05:30
|
|
|
.arp = "\0\0\0\0\0\0",
|
2010-11-12 14:32:18 +05:30
|
|
|
};
|
|
|
|
|
|
|
|
static void show_usage(void)
|
|
|
|
{
|
2010-11-13 01:03:17 +05:30
|
|
|
printf(
|
2012-07-23 22:54:15 +05:30
|
|
|
"ndhc " NDHC_VERSION ", dhcp client. Licensed under 2-clause BSD.\n"
|
2012-07-20 19:07:41 +05:30
|
|
|
"Copyright (C) 2004-2012 Nicholas J. Kain\n"
|
2010-11-12 14:32:18 +05:30
|
|
|
"Usage: ndhc [OPTIONS]\n\n"
|
|
|
|
" -c, --clientid=CLIENTID Client identifier\n"
|
2011-07-05 20:44:35 +05:30
|
|
|
" -h, --hostname=HOSTNAME Client hostname\n"
|
2011-07-05 20:48:28 +05:30
|
|
|
" -V, --vendorid=VENDORID Client vendor identification string\n"
|
2010-11-12 14:32:18 +05:30
|
|
|
" -f, --foreground Do not fork after getting lease\n"
|
|
|
|
" -b, --background Fork to background if lease cannot be\n"
|
|
|
|
" immediately negotiated.\n"
|
2011-07-05 20:48:28 +05:30
|
|
|
" -p, --pidfile=FILE File to which the pid will be written\n"
|
|
|
|
" -l, --leasefile=FILE File to which the lease IP will be written\n"
|
2010-11-12 14:32:18 +05:30
|
|
|
" -i, --interface=INTERFACE Interface to use (default: eth0)\n"
|
|
|
|
" -n, --now Exit with failure if lease cannot be\n"
|
|
|
|
" immediately negotiated.\n"
|
|
|
|
" -q, --quit Quit after obtaining lease\n"
|
|
|
|
" -r, --request=IP IP address to request (default: none)\n"
|
2011-07-05 20:48:28 +05:30
|
|
|
" -u, --user=USER Change privileges to this user\n"
|
|
|
|
" -C, --chroot=DIR Chroot to this directory\n"
|
2011-07-05 22:33:55 +05:30
|
|
|
" -d, --relentless-defense Never back off in defending IP against\n"
|
|
|
|
" conflicting hosts (servers only)\n"
|
2013-02-09 11:00:19 +05:30
|
|
|
" -w, --arp-probe-wait Time to delay before first ARP probe\n"
|
|
|
|
" -W, --arp-probe-num Number of ARP probes before lease is ok\n"
|
|
|
|
" -m, --arp-probe-min Min ms to wait for ARP response\n"
|
|
|
|
" -M, --arp-probe-max Max ms to wait for ARP response\n"
|
2010-11-12 14:32:18 +05:30
|
|
|
" -v, --version Display version\n"
|
2010-11-13 01:03:17 +05:30
|
|
|
);
|
|
|
|
exit(EXIT_SUCCESS);
|
2010-11-12 14:32:18 +05:30
|
|
|
}
|
|
|
|
|
2012-07-20 18:53:18 +05:30
|
|
|
static int enforce_seccomp(void)
|
|
|
|
{
|
|
|
|
struct sock_filter filter[] = {
|
|
|
|
VALIDATE_ARCHITECTURE,
|
|
|
|
EXAMINE_SYSCALL,
|
|
|
|
ALLOW_SYSCALL(sendto), // used for glibc syslog routines
|
|
|
|
ALLOW_SYSCALL(epoll_wait),
|
|
|
|
ALLOW_SYSCALL(epoll_ctl),
|
|
|
|
ALLOW_SYSCALL(read),
|
|
|
|
ALLOW_SYSCALL(write),
|
|
|
|
ALLOW_SYSCALL(close),
|
2012-07-21 04:18:26 +05:30
|
|
|
ALLOW_SYSCALL(recvmsg),
|
2012-07-20 18:53:18 +05:30
|
|
|
ALLOW_SYSCALL(socket),
|
|
|
|
ALLOW_SYSCALL(setsockopt),
|
|
|
|
ALLOW_SYSCALL(fcntl),
|
|
|
|
ALLOW_SYSCALL(bind),
|
|
|
|
ALLOW_SYSCALL(open),
|
|
|
|
ALLOW_SYSCALL(connect),
|
2012-07-21 04:18:26 +05:30
|
|
|
ALLOW_SYSCALL(getsockname),
|
|
|
|
|
2012-07-22 19:19:51 +05:30
|
|
|
// Allowed by vDSO
|
|
|
|
ALLOW_SYSCALL(getcpu),
|
|
|
|
ALLOW_SYSCALL(time),
|
|
|
|
ALLOW_SYSCALL(gettimeofday),
|
|
|
|
ALLOW_SYSCALL(clock_gettime),
|
|
|
|
|
2012-07-21 04:18:26 +05:30
|
|
|
// These are for 'write_leasefile()'
|
|
|
|
ALLOW_SYSCALL(ftruncate),
|
|
|
|
ALLOW_SYSCALL(lseek),
|
|
|
|
ALLOW_SYSCALL(fsync),
|
2012-07-20 18:53:18 +05:30
|
|
|
|
|
|
|
// These are for 'background()'
|
|
|
|
ALLOW_SYSCALL(socketpair),
|
|
|
|
ALLOW_SYSCALL(clone),
|
|
|
|
ALLOW_SYSCALL(set_robust_list),
|
|
|
|
ALLOW_SYSCALL(setsid),
|
|
|
|
ALLOW_SYSCALL(chdir),
|
|
|
|
ALLOW_SYSCALL(fstat),
|
|
|
|
ALLOW_SYSCALL(dup2),
|
|
|
|
ALLOW_SYSCALL(rt_sigprocmask),
|
|
|
|
ALLOW_SYSCALL(signalfd4),
|
|
|
|
ALLOW_SYSCALL(mmap),
|
|
|
|
ALLOW_SYSCALL(munmap),
|
|
|
|
|
|
|
|
ALLOW_SYSCALL(rt_sigreturn),
|
|
|
|
#ifdef __NR_sigreturn
|
|
|
|
ALLOW_SYSCALL(sigreturn),
|
|
|
|
#endif
|
|
|
|
ALLOW_SYSCALL(exit_group),
|
|
|
|
ALLOW_SYSCALL(exit),
|
|
|
|
KILL_PROCESS,
|
|
|
|
};
|
|
|
|
struct sock_fprog prog = {
|
|
|
|
.len = (unsigned short)(sizeof filter / sizeof filter[0]),
|
|
|
|
.filter = filter,
|
|
|
|
};
|
|
|
|
if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0))
|
|
|
|
return -1;
|
|
|
|
if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog))
|
|
|
|
return -1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-12-01 23:05:13 +05:30
|
|
|
static void signal_dispatch()
|
|
|
|
{
|
|
|
|
int t, off = 0;
|
|
|
|
struct signalfd_siginfo si;
|
|
|
|
again:
|
2010-12-24 17:30:42 +05:30
|
|
|
t = read(cs.signalFd, (char *)&si + off, sizeof si - off);
|
2010-12-01 23:05:13 +05:30
|
|
|
if (t < sizeof si - off) {
|
|
|
|
if (t < 0) {
|
|
|
|
if (t == EAGAIN || t == EWOULDBLOCK || t == EINTR)
|
|
|
|
goto again;
|
|
|
|
else
|
|
|
|
suicide("signalfd read error");
|
|
|
|
}
|
|
|
|
off += t;
|
|
|
|
}
|
|
|
|
switch (si.ssi_signo) {
|
|
|
|
case SIGUSR1:
|
2011-06-30 09:17:31 +05:30
|
|
|
force_renew_action(&cs);
|
2010-12-01 23:05:13 +05:30
|
|
|
break;
|
|
|
|
case SIGUSR2:
|
2011-06-30 09:17:31 +05:30
|
|
|
force_release_action(&cs);
|
2010-12-01 23:05:13 +05:30
|
|
|
break;
|
|
|
|
case SIGTERM:
|
2010-11-13 01:03:17 +05:30
|
|
|
log_line("Received SIGTERM. Exiting gracefully.");
|
|
|
|
exit(EXIT_SUCCESS);
|
2010-12-01 23:05:13 +05:30
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-07-03 15:15:05 +05:30
|
|
|
static int is_string_hwaddr(char *str, size_t slen)
|
2011-07-03 15:06:47 +05:30
|
|
|
{
|
2011-07-03 15:15:05 +05:30
|
|
|
if (slen == 17 && str[2] == ':' && str[5] == ':' && str[8] == ':' &&
|
|
|
|
str[11] == ':' && str[14] == ':' &&
|
2011-07-03 15:06:47 +05:30
|
|
|
isxdigit(str[0]) && isxdigit(str[1]) && isxdigit(str[3]) &&
|
|
|
|
isxdigit(str[4]) && isxdigit(str[6]) && isxdigit(str[7]) &&
|
|
|
|
isxdigit(str[9]) && isxdigit(str[10]) && isxdigit(str[12]) &&
|
2011-07-03 15:15:05 +05:30
|
|
|
isxdigit(str[13]) && isxdigit(str[15]) && isxdigit(str[16])
|
|
|
|
)
|
2011-07-03 15:06:47 +05:30
|
|
|
return 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-07-03 15:15:05 +05:30
|
|
|
static int get_clientid_mac_string(char *str, size_t slen)
|
|
|
|
{
|
|
|
|
if (!is_string_hwaddr(str, slen))
|
|
|
|
return 0;
|
|
|
|
client_config.clientid[0] = strtol(str, NULL, 16);
|
|
|
|
client_config.clientid[1] = strtol(str+3, NULL, 16);
|
|
|
|
client_config.clientid[2] = strtol(str+6, NULL, 16);
|
|
|
|
client_config.clientid[3] = strtol(str+9, NULL, 16);
|
|
|
|
client_config.clientid[4] = strtol(str+12, NULL, 16);
|
|
|
|
client_config.clientid[5] = strtol(str+15, NULL, 16);
|
|
|
|
client_config.clientid[6] = '\0';
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2010-12-01 23:05:13 +05:30
|
|
|
static void do_work(void)
|
|
|
|
{
|
2010-12-24 17:30:42 +05:30
|
|
|
struct epoll_event events[3];
|
2011-07-11 21:01:27 +05:30
|
|
|
long long nowts;
|
|
|
|
int timeout;
|
2010-11-13 01:03:17 +05:30
|
|
|
|
2010-12-24 17:30:42 +05:30
|
|
|
cs.epollFd = epoll_create1(0);
|
|
|
|
if (cs.epollFd == -1)
|
2010-12-01 23:41:09 +05:30
|
|
|
suicide("epoll_create1 failed");
|
2012-07-20 18:53:18 +05:30
|
|
|
|
|
|
|
if (enforce_seccomp())
|
|
|
|
log_line("seccomp filter cannot be installed");
|
|
|
|
|
2012-07-21 04:18:26 +05:30
|
|
|
setup_signals(&cs);
|
|
|
|
|
2011-03-30 01:04:00 +05:30
|
|
|
epoll_add(&cs, cs.nlFd);
|
2011-07-01 07:03:38 +05:30
|
|
|
set_listen_raw(&cs);
|
2011-07-11 20:09:36 +05:30
|
|
|
nowts = curms();
|
|
|
|
goto jumpstart;
|
2010-11-13 01:03:17 +05:30
|
|
|
|
2010-12-01 23:41:09 +05:30
|
|
|
for (;;) {
|
2011-07-11 20:09:36 +05:30
|
|
|
int r = epoll_wait(cs.epollFd, events, 3, timeout);
|
2010-12-01 23:41:09 +05:30
|
|
|
if (r == -1) {
|
|
|
|
if (errno == EINTR)
|
|
|
|
continue;
|
|
|
|
else
|
|
|
|
suicide("epoll_wait failed");
|
|
|
|
}
|
|
|
|
for (int i = 0; i < r; ++i) {
|
|
|
|
int fd = events[i].data.fd;
|
2010-12-24 17:30:42 +05:30
|
|
|
if (fd == cs.signalFd)
|
2010-12-01 23:41:09 +05:30
|
|
|
signal_dispatch();
|
2010-12-24 17:30:42 +05:30
|
|
|
else if (fd == cs.listenFd)
|
2010-12-24 19:25:59 +05:30
|
|
|
handle_packet(&cs);
|
2010-12-24 17:30:42 +05:30
|
|
|
else if (fd == cs.arpFd)
|
2010-12-24 20:02:58 +05:30
|
|
|
handle_arp_response(&cs);
|
2011-03-30 01:04:00 +05:30
|
|
|
else if (fd == cs.nlFd)
|
|
|
|
handle_nl_message(&cs);
|
2010-12-01 23:41:09 +05:30
|
|
|
else
|
|
|
|
suicide("epoll_wait: unknown fd");
|
2010-11-13 01:03:17 +05:30
|
|
|
}
|
2010-12-02 10:45:03 +05:30
|
|
|
|
2011-07-11 21:01:27 +05:30
|
|
|
for (;;) {
|
|
|
|
nowts = curms();
|
|
|
|
long long arp_wake_ts = arp_get_wake_ts();
|
|
|
|
long long dhcp_wake_ts = dhcp_get_wake_ts();
|
|
|
|
if (arp_wake_ts == -1) {
|
|
|
|
if (dhcp_wake_ts != -1) {
|
|
|
|
timeout = dhcp_wake_ts - nowts;
|
|
|
|
if (timeout < 0)
|
|
|
|
timeout = 0;
|
|
|
|
} else
|
|
|
|
timeout = -1;
|
|
|
|
} else {
|
|
|
|
// If dhcp_wake_ts is -1 then we want to sleep anyway.
|
|
|
|
timeout = (arp_wake_ts < dhcp_wake_ts ?
|
|
|
|
arp_wake_ts : dhcp_wake_ts) - nowts;
|
|
|
|
if (timeout < 0)
|
|
|
|
timeout = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!timeout) {
|
2011-07-11 20:09:36 +05:30
|
|
|
jumpstart:
|
2011-07-11 21:01:27 +05:30
|
|
|
timeout_action(&cs, nowts);
|
|
|
|
} else
|
|
|
|
break;
|
2010-12-23 22:04:57 +05:30
|
|
|
}
|
2010-11-13 01:03:17 +05:30
|
|
|
}
|
2010-11-12 14:32:18 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
int main(int argc, char **argv)
|
|
|
|
{
|
2010-11-13 06:13:16 +05:30
|
|
|
char chroot_dir[MAX_PATH_LENGTH] = "";
|
2011-07-02 13:18:08 +05:30
|
|
|
int c;
|
2010-11-13 01:03:17 +05:30
|
|
|
struct passwd *pwd;
|
|
|
|
uid_t uid = 0;
|
|
|
|
gid_t gid = 0;
|
2011-07-11 15:05:40 +05:30
|
|
|
static const struct option arg_options[] = {
|
2010-11-13 01:03:17 +05:30
|
|
|
{"clientid", required_argument, 0, 'c'},
|
|
|
|
{"foreground", no_argument, 0, 'f'},
|
|
|
|
{"background", no_argument, 0, 'b'},
|
2010-11-13 05:14:49 +05:30
|
|
|
{"pidfile", required_argument, 0, 'p'},
|
2011-04-20 02:07:43 +05:30
|
|
|
{"leasefile", required_argument, 0, 'l'},
|
2011-07-02 13:18:08 +05:30
|
|
|
{"hostname", required_argument, 0, 'h'},
|
2010-11-13 01:03:17 +05:30
|
|
|
{"interface", required_argument, 0, 'i'},
|
|
|
|
{"now", no_argument, 0, 'n'},
|
2011-07-02 13:18:08 +05:30
|
|
|
{"quit", no_argument, 0, 'q'},
|
|
|
|
{"request", required_argument, 0, 'r'},
|
|
|
|
{"vendorid", required_argument, 0, 'V'},
|
|
|
|
{"user", required_argument, 0, 'u'},
|
|
|
|
{"chroot", required_argument, 0, 'C'},
|
2011-07-05 22:33:55 +05:30
|
|
|
{"relentless-defense", no_argument, 0, 'd'},
|
2013-02-09 11:00:19 +05:30
|
|
|
{"arp-probe-wait", required_argument, 0, 'w'},
|
|
|
|
{"arp-probe-num", required_argument, 0, 'W'},
|
|
|
|
{"arp-probe-min", required_argument, 0, 'm'},
|
|
|
|
{"arp-probe-max", required_argument, 0, 'M'},
|
2011-07-05 22:33:55 +05:30
|
|
|
{"version", no_argument, 0, 'v'},
|
2011-07-02 13:18:08 +05:30
|
|
|
{"help", no_argument, 0, '?'},
|
2010-11-13 01:03:17 +05:30
|
|
|
{0, 0, 0, 0}
|
|
|
|
};
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
int option_index = 0;
|
2013-02-09 11:00:19 +05:30
|
|
|
c = getopt_long(argc, argv, "c:fbp:h:i:np:l:qr:V:u:C:dw:W:m:M:v",
|
|
|
|
arg_options, &option_index);
|
2010-11-13 01:03:17 +05:30
|
|
|
if (c == -1) break;
|
|
|
|
|
|
|
|
switch (c) {
|
|
|
|
case 'c':
|
2011-07-03 15:06:47 +05:30
|
|
|
if (!get_clientid_mac_string(optarg, strlen(optarg)))
|
2013-05-06 16:37:54 +05:30
|
|
|
strnkcpy(client_config.clientid, optarg,
|
|
|
|
sizeof client_config.clientid);
|
2011-07-03 15:06:47 +05:30
|
|
|
else
|
|
|
|
client_config.clientid_mac = 1;
|
|
|
|
break;
|
2010-11-13 01:03:17 +05:30
|
|
|
case 'f':
|
|
|
|
client_config.foreground = 1;
|
2010-12-23 22:04:57 +05:30
|
|
|
gflags_detach = 0;
|
2010-11-13 01:03:17 +05:30
|
|
|
break;
|
|
|
|
case 'b':
|
|
|
|
client_config.background_if_no_lease = 1;
|
2010-12-23 22:04:57 +05:30
|
|
|
gflags_detach = 1;
|
2010-11-13 01:03:17 +05:30
|
|
|
break;
|
2010-11-13 05:14:49 +05:30
|
|
|
case 'p':
|
2013-05-06 16:37:54 +05:30
|
|
|
strnkcpy(pidfile, optarg, sizeof pidfile);
|
2010-11-13 05:14:49 +05:30
|
|
|
break;
|
2011-04-20 02:07:43 +05:30
|
|
|
case 'l':
|
|
|
|
set_leasefile(optarg);
|
|
|
|
break;
|
2010-11-13 01:03:17 +05:30
|
|
|
case 'h':
|
2013-05-06 16:37:54 +05:30
|
|
|
strnkcpy(client_config.hostname, optarg,
|
|
|
|
sizeof client_config.hostname);
|
2010-11-13 01:03:17 +05:30
|
|
|
break;
|
|
|
|
case 'i':
|
2010-12-24 21:14:06 +05:30
|
|
|
client_config.interface = optarg;
|
2010-11-13 01:03:17 +05:30
|
|
|
break;
|
|
|
|
case 'n':
|
|
|
|
client_config.abort_if_no_lease = 1;
|
|
|
|
break;
|
|
|
|
case 'q':
|
|
|
|
client_config.quit_after_lease = 1;
|
|
|
|
break;
|
|
|
|
case 'r':
|
2011-07-01 21:07:13 +05:30
|
|
|
cs.clientAddr = inet_addr(optarg);
|
2010-11-13 01:03:17 +05:30
|
|
|
break;
|
|
|
|
case 'u':
|
|
|
|
pwd = getpwnam(optarg);
|
|
|
|
if (pwd) {
|
|
|
|
uid = (int)pwd->pw_uid;
|
|
|
|
gid = (int)pwd->pw_gid;
|
|
|
|
} else {
|
|
|
|
printf("Bad username provided.\n");
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'C':
|
2013-05-06 16:37:54 +05:30
|
|
|
strnkcpy(chroot_dir, optarg, sizeof chroot_dir);
|
2010-11-13 01:03:17 +05:30
|
|
|
break;
|
2011-07-05 22:33:55 +05:30
|
|
|
case 'd':
|
|
|
|
arp_relentless_def = 1;
|
|
|
|
break;
|
2013-02-09 11:00:19 +05:30
|
|
|
case 'w':
|
|
|
|
case 'W': {
|
|
|
|
int t = atoi(optarg);
|
|
|
|
if (t < 0)
|
|
|
|
break;
|
|
|
|
if (c == 'w')
|
|
|
|
arp_probe_wait = t;
|
|
|
|
else
|
|
|
|
arp_probe_num = t;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 'm':
|
|
|
|
case 'M': {
|
|
|
|
int t = atoi(optarg);
|
|
|
|
if (c == 'm')
|
|
|
|
arp_probe_min = t;
|
|
|
|
else
|
|
|
|
arp_probe_max = t;
|
|
|
|
if (arp_probe_min > arp_probe_max) {
|
|
|
|
t = arp_probe_max;
|
|
|
|
arp_probe_max = arp_probe_min;
|
|
|
|
arp_probe_min = t;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2010-11-13 01:03:17 +05:30
|
|
|
case 'v':
|
2012-07-23 22:54:15 +05:30
|
|
|
printf("ndhc %s, dhcp client.\n", NDHC_VERSION);
|
2013-02-09 11:00:19 +05:30
|
|
|
printf("Copyright (c) 2004-2013 Nicholas J. Kain\n"
|
2012-07-21 23:32:42 +05:30
|
|
|
"All rights reserved.\n\n"
|
|
|
|
"Redistribution and use in source and binary forms, with or without\n"
|
|
|
|
"modification, are permitted provided that the following conditions are met:\n\n"
|
|
|
|
"- Redistributions of source code must retain the above copyright notice,\n"
|
|
|
|
" this list of conditions and the following disclaimer.\n"
|
|
|
|
"- Redistributions in binary form must reproduce the above copyright notice,\n"
|
|
|
|
" this list of conditions and the following disclaimer in the documentation\n"
|
|
|
|
" and/or other materials provided with the distribution.\n\n"
|
|
|
|
"THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n"
|
|
|
|
"AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n"
|
|
|
|
"IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n"
|
|
|
|
"ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\n"
|
|
|
|
"LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n"
|
|
|
|
"CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n"
|
|
|
|
"SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n"
|
|
|
|
"INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n"
|
|
|
|
"CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n"
|
|
|
|
"ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n"
|
|
|
|
"POSSIBILITY OF SUCH DAMAGE.\n");
|
2010-11-13 01:03:17 +05:30
|
|
|
exit(EXIT_SUCCESS);
|
|
|
|
break;
|
2011-07-02 13:18:08 +05:30
|
|
|
case 'V':
|
2013-05-06 16:37:54 +05:30
|
|
|
strnkcpy(client_config.vendor, optarg,
|
|
|
|
sizeof client_config.vendor);
|
2011-07-02 13:18:08 +05:30
|
|
|
break;
|
2010-11-13 01:03:17 +05:30
|
|
|
default:
|
|
|
|
show_usage();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-23 22:54:15 +05:30
|
|
|
log_line("ndhc client " NDHC_VERSION " started.");
|
2010-11-13 01:03:17 +05:30
|
|
|
|
2010-11-13 06:38:16 +05:30
|
|
|
if (client_config.foreground && !client_config.background_if_no_lease) {
|
|
|
|
if (file_exists(pidfile, "w") == -1) {
|
|
|
|
log_line("FATAL - cannot open pidfile for write!");
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
write_pid(pidfile);
|
|
|
|
}
|
|
|
|
|
2012-04-13 05:36:05 +05:30
|
|
|
if ((cs.nlFd = nl_open(NETLINK_ROUTE, RTMGRP_LINK, &cs.nlPortId)) < 0) {
|
2011-03-30 00:07:45 +05:30
|
|
|
log_line("FATAL - failed to open netlink socket");
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
2012-04-04 07:30:47 +05:30
|
|
|
if (nl_getifdata(&cs) < 0) {
|
2011-03-30 00:07:45 +05:30
|
|
|
log_line("FATAL - failed to get interface MAC and index");
|
2010-11-13 01:03:17 +05:30
|
|
|
exit(EXIT_FAILURE);
|
2011-03-30 00:07:45 +05:30
|
|
|
}
|
2010-11-13 01:03:17 +05:30
|
|
|
|
2011-04-20 02:07:43 +05:30
|
|
|
open_leasefile();
|
|
|
|
|
2010-11-13 01:03:17 +05:30
|
|
|
if (chdir(chroot_dir)) {
|
|
|
|
printf("Failed to chdir(%s)!\n", chroot_dir);
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (chroot(chroot_dir)) {
|
|
|
|
printf("Failed to chroot(%s)!\n", chroot_dir);
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
|
|
|
|
set_cap(uid, gid,
|
|
|
|
"cap_net_bind_service,cap_net_broadcast,cap_net_raw=ep");
|
|
|
|
drop_root(uid, gid);
|
|
|
|
|
2011-07-02 14:28:58 +05:30
|
|
|
if (cs.ifsPrevState != IFS_UP)
|
2011-07-05 06:21:27 +05:30
|
|
|
ifchange_deconfig();
|
2010-11-13 01:03:17 +05:30
|
|
|
|
|
|
|
do_work();
|
2011-07-02 11:04:50 +05:30
|
|
|
return EXIT_SUCCESS; // Never reached.
|
2010-11-12 14:32:18 +05:30
|
|
|
}
|