summaryrefslogtreecommitdiffstats
path: root/freebsd/sbin/dhclient
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2013-11-04 11:33:00 +0100
committerSebastian Huber <sebastian.huber@embedded-brains.de>2013-11-04 15:28:21 +0100
commitaf5333e0a02b2295304d4e029b15ee15a4fe2b3a (patch)
treec5c43680d374f58b487eeeaf18fb7ec6b84ba074 /freebsd/sbin/dhclient
parentBUS_SPACE(9): Use simple memory model for ARM (diff)
downloadrtems-libbsd-af5333e0a02b2295304d4e029b15ee15a4fe2b3a.tar.bz2
Update to FreeBSD 8.4
Diffstat (limited to 'freebsd/sbin/dhclient')
-rw-r--r--freebsd/sbin/dhclient/clparse.c2
-rw-r--r--freebsd/sbin/dhclient/dhclient.c50
-rw-r--r--freebsd/sbin/dhclient/dhcp.h1
-rw-r--r--freebsd/sbin/dhclient/dhcpd.h6
-rw-r--r--freebsd/sbin/dhclient/errwarn.c2
-rw-r--r--freebsd/sbin/dhclient/options.c174
-rw-r--r--freebsd/sbin/dhclient/tables.c5
7 files changed, 236 insertions, 4 deletions
diff --git a/freebsd/sbin/dhclient/clparse.c b/freebsd/sbin/dhclient/clparse.c
index 5d7084e7..7c1e74fc 100644
--- a/freebsd/sbin/dhclient/clparse.c
+++ b/freebsd/sbin/dhclient/clparse.c
@@ -100,6 +100,8 @@ read_client_conf(void)
DHO_DOMAIN_NAME_SERVERS;
top_level_config.requested_options
[top_level_config.requested_option_count++] = DHO_HOST_NAME;
+ top_level_config.requested_options
+ [top_level_config.requested_option_count++] = DHO_DOMAIN_SEARCH;
if ((cfile = fopen(path_dhclient_conf, "r")) != NULL) {
do {
diff --git a/freebsd/sbin/dhclient/dhclient.c b/freebsd/sbin/dhclient/dhclient.c
index b72d5bff..8ee70084 100644
--- a/freebsd/sbin/dhclient/dhclient.c
+++ b/freebsd/sbin/dhclient/dhclient.c
@@ -95,6 +95,9 @@ struct iaddr iaddr_broadcast = { 4, { 255, 255, 255, 255 } };
struct in_addr inaddr_any;
struct sockaddr_in sockaddr_broadcast;
+char *path_dhclient_pidfile;
+struct pidfh *pidfile;
+
/*
* ASSERT_STATE() does nothing now; it used to be
* assert (state_is == state_shouldbe).
@@ -215,6 +218,7 @@ routehandler(struct protocol *p)
struct sockaddr *sa;
struct iaddr a;
ssize_t n;
+ int linkstat;
n = read(routefd, &msg, sizeof(msg));
rtm = (struct rt_msghdr *)msg;
@@ -275,6 +279,15 @@ routehandler(struct protocol *p)
ifi->name);
goto die;
}
+ linkstat = interface_link_status(ifi->name);
+ if (linkstat != ifi->linkstat) {
+ debug("%s link state %s -> %s", ifi->name,
+ ifi->linkstat ? "up" : "down",
+ linkstat ? "up" : "down");
+ ifi->linkstat = linkstat;
+ if (linkstat)
+ state_reboot(ifi);
+ }
break;
case RTM_IFANNOUNCE:
ifan = (struct if_announcemsghdr *)rtm;
@@ -316,6 +329,8 @@ die:
if (ifi->client->alias)
script_write_params("alias_", ifi->client->alias);
script_go();
+ if (pidfile != NULL)
+ pidfile_remove(pidfile);
exit(1);
}
@@ -327,12 +342,13 @@ main(int argc, char *argv[])
int pipe_fd[2];
int immediate_daemon = 0;
struct passwd *pw;
+ pid_t otherpid;
/* Initially, log errors to stderr as well as to syslogd. */
openlog(__progname, LOG_PID | LOG_NDELAY, DHCPD_LOG_FACILITY);
setlogmask(LOG_UPTO(LOG_DEBUG));
- while ((ch = getopt(argc, argv, "bc:dl:qu")) != -1)
+ while ((ch = getopt(argc, argv, "bc:dl:p:qu")) != -1)
switch (ch) {
case 'b':
immediate_daemon = 1;
@@ -346,6 +362,9 @@ main(int argc, char *argv[])
case 'l':
path_dhclient_db = optarg;
break;
+ case 'p':
+ path_dhclient_pidfile = optarg;
+ break;
case 'q':
quiet = 1;
break;
@@ -362,6 +381,24 @@ main(int argc, char *argv[])
if (argc != 1)
usage();
+ if (path_dhclient_pidfile == NULL) {
+#ifdef __rtems__
+#define _PATH_VARRUN "/var/run"
+#endif /* __rtems__ */
+ asprintf(&path_dhclient_pidfile,
+ "%sdhclient.%s.pid", _PATH_VARRUN, *argv);
+ if (path_dhclient_pidfile == NULL)
+ error("asprintf");
+ }
+ pidfile = pidfile_open(path_dhclient_pidfile, 0600, &otherpid);
+ if (pidfile == NULL) {
+ if (errno == EEXIST)
+ error("dhclient already running, pid: %d.", otherpid);
+ if (errno == EAGAIN)
+ error("dhclient already running.");
+ warning("Cannot open or create pidfile: %m");
+ }
+
if ((ifi = calloc(1, sizeof(struct interface_info))) == NULL)
error("calloc");
if (strlcpy(ifi->name, argv[0], IFNAMSIZ) >= IFNAMSIZ)
@@ -385,6 +422,12 @@ main(int argc, char *argv[])
read_client_conf();
+ /* The next bit is potentially very time-consuming, so write out
+ the pidfile right away. We will write it out again with the
+ correct pid after daemonizing. */
+ if (pidfile != NULL)
+ pidfile_write(pidfile);
+
if (!interface_link_status(ifi->name)) {
fprintf(stderr, "%s: no link ...", ifi->name);
fflush(stderr);
@@ -400,6 +443,7 @@ main(int argc, char *argv[])
}
fprintf(stderr, " got link\n");
}
+ ifi->linkstat = 1;
if ((nullfd = open(_PATH_DEVNULL, O_RDWR, 0)) == -1)
error("cannot open %s: %m", _PATH_DEVNULL);
@@ -2302,6 +2346,9 @@ go_daemon(void)
if (daemon(1, 0) == -1)
error("daemon");
+ if (pidfile != NULL)
+ pidfile_write(pidfile);
+
/* we are chrooted, daemon(3) fails to open /dev/null */
if (nullfd != -1) {
dup2(nullfd, STDIN_FILENO);
@@ -2372,6 +2419,7 @@ check_option(struct client_lease *l, int option)
}
return (1);
case DHO_DOMAIN_NAME:
+ case DHO_DOMAIN_SEARCH:
if (!res_hnok(sbuf)) {
if (!check_search(sbuf)) {
warning("Bogus domain search list %d: %s (%s)",
diff --git a/freebsd/sbin/dhclient/dhcp.h b/freebsd/sbin/dhclient/dhcp.h
index e4fa9d17..6e7d1a74 100644
--- a/freebsd/sbin/dhclient/dhcp.h
+++ b/freebsd/sbin/dhclient/dhcp.h
@@ -169,6 +169,7 @@ struct dhcp_packet {
#define DHO_STREETTALK_SERVER 75
#define DHO_STREETTALK_DA_SERVER 76
#define DHO_DHCP_USER_CLASS_ID 77
+#define DHO_DOMAIN_SEARCH 119
#define DHO_CLASSLESS_ROUTES 121
#define DHO_END 255
diff --git a/freebsd/sbin/dhclient/dhcpd.h b/freebsd/sbin/dhclient/dhcpd.h
index 0c47a9f8..d7844bc6 100644
--- a/freebsd/sbin/dhclient/dhcpd.h
+++ b/freebsd/sbin/dhclient/dhcpd.h
@@ -41,7 +41,7 @@
* $FreeBSD$
*/
-#include <rtems/bsd/sys/types.h>
+#include <rtems/bsd/sys/param.h>
#include <sys/socket.h>
#include <sys/sockio.h>
@@ -60,6 +60,7 @@
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
+#include <libutil.h>
#include <limits.h>
#include <netdb.h>
#include <paths.h>
@@ -207,6 +208,7 @@ struct interface_info {
int errors;
int dead;
u_int16_t index;
+ int linkstat;
};
struct timeout {
@@ -353,6 +355,8 @@ extern int log_perror;
extern struct client_config top_level_config;
+extern struct pidfh *pidfile;
+
void dhcpoffer(struct packet *);
void dhcpack(struct packet *);
void dhcpnak(struct packet *);
diff --git a/freebsd/sbin/dhclient/errwarn.c b/freebsd/sbin/dhclient/errwarn.c
index de345832..57207807 100644
--- a/freebsd/sbin/dhclient/errwarn.c
+++ b/freebsd/sbin/dhclient/errwarn.c
@@ -83,6 +83,8 @@ error(char *fmt, ...)
fprintf(stderr, "exiting.\n");
fflush(stderr);
}
+ if (pidfile != NULL)
+ pidfile_remove(pidfile);
exit(1);
}
diff --git a/freebsd/sbin/dhclient/options.c b/freebsd/sbin/dhclient/options.c
index 09aa4d8f..17643e76 100644
--- a/freebsd/sbin/dhclient/options.c
+++ b/freebsd/sbin/dhclient/options.c
@@ -55,6 +55,10 @@ void parse_options(struct packet *);
void parse_option_buffer(struct packet *, unsigned char *, int);
int store_options(unsigned char *, int, struct tree_cache **,
unsigned char *, int, int, int, int);
+void expand_domain_search(struct packet *packet);
+int find_search_domain_name_len(struct option_data *option, int *offset);
+void expand_search_domain_name(struct option_data *option, int *offset,
+ unsigned char **domain_search);
/*
@@ -94,6 +98,11 @@ parse_options(struct packet *packet)
(unsigned char *)packet->raw->sname,
sizeof(packet->raw->sname));
}
+
+ /* Expand DHCP Domain Search option. */
+ if (packet->options_valid) {
+ expand_domain_search(packet);
+ }
}
/*
@@ -194,6 +203,171 @@ parse_option_buffer(struct packet *packet,
}
/*
+ * Expand DHCP Domain Search option. The value of this option is
+ * encoded like DNS' list of labels. See:
+ * RFC 3397
+ * RFC 1035
+ */
+void
+expand_domain_search(struct packet *packet)
+{
+ int offset, expanded_len, next_domain_len;
+ struct option_data *option;
+ unsigned char *domain_search, *cursor;
+
+ if (packet->options[DHO_DOMAIN_SEARCH].data == NULL)
+ return;
+
+ option = &packet->options[DHO_DOMAIN_SEARCH];
+
+ /* Compute final expanded length. */
+ expanded_len = 0;
+ offset = 0;
+ while (offset < option->len) {
+ next_domain_len = find_search_domain_name_len(option, &offset);
+ if (next_domain_len < 0)
+ /* The Domain Search option value is invalid. */
+ return;
+
+ /* We add 1 for the space between domain names. */
+ expanded_len += next_domain_len + 1;
+ }
+ if (expanded_len > 0)
+ /* Remove 1 for the superfluous trailing space. */
+ --expanded_len;
+
+ domain_search = malloc(expanded_len + 1);
+ if (domain_search == NULL)
+ error("Can't allocate storage for expanded domain-search\n");
+
+ offset = 0;
+ cursor = domain_search;
+ while (offset < option->len) {
+ expand_search_domain_name(option, &offset, &cursor);
+ cursor[0] = ' ';
+ cursor++;
+ }
+ domain_search[expanded_len] = '\0';
+
+ free(option->data);
+ option->len = expanded_len;
+ option->data = domain_search;
+}
+
+int
+find_search_domain_name_len(struct option_data *option, int *offset)
+{
+ int domain_name_len, i, label_len, pointer, pointed_len;
+
+ domain_name_len = 0;
+
+ i = *offset;
+ while (i < option->len) {
+ label_len = option->data[i];
+ if (label_len == 0) {
+ /*
+ * A zero-length label marks the end of this
+ * domain name.
+ */
+ *offset = i + 1;
+ return (domain_name_len);
+ } else if (label_len & 0xC0) {
+ /* This is a pointer to another list of labels. */
+ if (i + 1 >= option->len) {
+ /* The pointer is truncated. */
+ warning("Truncated pointer in DHCP Domain "
+ "Search option.");
+ return (-1);
+ }
+
+ pointer = ((label_len & ~(0xC0)) << 8) +
+ option->data[i + 1];
+ if (pointer >= *offset) {
+ /*
+ * The pointer must indicates a prior
+ * occurance.
+ */
+ warning("Invalid forward pointer in DHCP "
+ "Domain Search option compression.");
+ return (-1);
+ }
+
+ pointed_len = find_search_domain_name_len(option,
+ &pointer);
+ domain_name_len += pointed_len;
+
+ *offset = i + 2;
+ return (domain_name_len);
+ }
+
+ if (i + label_len >= option->len) {
+ warning("Truncated label in DHCP Domain Search "
+ "option.");
+ return (-1);
+ }
+
+ /*
+ * Update the domain name length with the length of the
+ * current label, plus a trailing dot ('.').
+ */
+ domain_name_len += label_len + 1;
+
+ /* Move cursor. */
+ i += label_len + 1;
+ }
+
+ warning("Truncated DHCP Domain Search option.");
+
+ return (-1);
+}
+
+void
+expand_search_domain_name(struct option_data *option, int *offset,
+ unsigned char **domain_search)
+{
+ int i, label_len, pointer;
+ unsigned char *cursor;
+
+ /*
+ * This is the same loop than the function above
+ * (find_search_domain_name_len). Therefore, we remove checks,
+ * they're already done. Here, we just make the copy.
+ */
+ i = *offset;
+ cursor = *domain_search;
+ while (i < option->len) {
+ label_len = option->data[i];
+ if (label_len == 0) {
+ /*
+ * A zero-length label marks the end of this
+ * domain name.
+ */
+ *offset = i + 1;
+ *domain_search = cursor;
+ return;
+ } else if (label_len & 0xC0) {
+ /* This is a pointer to another list of labels. */
+ pointer = ((label_len & ~(0xC0)) << 8) +
+ option->data[i + 1];
+
+ expand_search_domain_name(option, &pointer, &cursor);
+
+ *offset = i + 2;
+ *domain_search = cursor;
+ return;
+ }
+
+ /* Copy the label found. */
+ memcpy(cursor, option->data + i + 1, label_len);
+ cursor[label_len] = '.';
+
+ /* Move cursor. */
+ i += label_len + 1;
+ cursor += label_len + 1;
+ }
+}
+
+/*
* cons options into a big buffer, and then split them out into the
* three separate buffers if needed. This allows us to cons up a set of
* vendor options using the same routine.
diff --git a/freebsd/sbin/dhclient/tables.c b/freebsd/sbin/dhclient/tables.c
index 81a9acc8..c7bac57e 100644
--- a/freebsd/sbin/dhclient/tables.c
+++ b/freebsd/sbin/dhclient/tables.c
@@ -184,7 +184,7 @@ struct option dhcp_options[256] = {
{ "option-116", "X", &dhcp_universe, 116 },
{ "option-117", "X", &dhcp_universe, 117 },
{ "option-118", "X", &dhcp_universe, 118 },
- { "option-119", "X", &dhcp_universe, 119 },
+ { "domain-search", "t", &dhcp_universe, 119 },
{ "option-120", "X", &dhcp_universe, 120 },
{ "classless-routes", "BA", &dhcp_universe, 121 },
{ "option-122", "X", &dhcp_universe, 122 },
@@ -400,12 +400,13 @@ unsigned char dhcp_option_default_priority_list[] = {
DHO_IRC_SERVER,
DHO_STREETTALK_SERVER,
DHO_STREETTALK_DA_SERVER,
+ DHO_DOMAIN_SEARCH,
/* Presently-undefined options... */
62, 63, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91,
92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105,
106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117,
- 118, 119, 120, 122, 123, 124, 125, 126, 127, 128, 129, 130,
+ 118, 120, 122, 123, 124, 125, 126, 127, 128, 129, 130,
131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142,
143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154,
155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166,