supercedes any DHCP configured variables.
If ip_address is configured then we don't bother with a DHCP
transaction.
/*
* dhcpcd - DHCP client daemon
- * Copyright 2006-2008 Roy Marples <roy@marples.name>
+ * Copyright 2006-2009 Roy Marples <roy@marples.name>
* All rights reserved
* Redistribution and use in source and binary forms, with or without
state->new = state->offer;
state->offer = NULL;
get_lease(lease, state->new);
- if (IN_LINKLOCAL(htonl(state->new->yiaddr))) {
+ if (ifo->options & DHCPCD_STATIC) {
+ syslog(LOG_INFO, "%s: using static address %s",
+ iface->name, inet_ntoa(lease->addr));
+ lease->leasetime = ~0U;
+ lease->net.s_addr = ifo->request_netmask.s_addr;
+ reason = "STATIC";
+ } else if (IN_LINKLOCAL(htonl(state->new->yiaddr))) {
syslog(LOG_INFO, "%s: using IPv4LL address %s",
iface->name, inet_ntoa(lease->addr));
lease->leasetime = ~0U;
} else {
if (gettimeofday(&tv, NULL) == 0)
lease->leasedfrom = tv.tv_sec;
- if (lease->frominfo)
+ else if (lease->frominfo)
reason = "TIMEOUT";
if (lease->leasetime == ~0U) {
lease->renewaltime = lease->rebindtime = lease->leasetime;
inet_ntoa(lease->addr), lease->leasetime);
}
}
- if (!reason) {
+ if (reason == NULL) {
if (state->old) {
if (state->old->yiaddr == state->new->yiaddr &&
lease->server.s_addr)
/*
* dhcpcd - DHCP client daemon
- * Copyright 2006-2008 Roy Marples <roy@marples.name>
+ * Copyright 2006-2009 Roy Marples <roy@marples.name>
* All rights reserved
* Redistribution and use in source and binary forms, with or without
return pid;
}
+static char *
+make_var(const char *prefix, const char *var)
+{
+ size_t len;
+ char *v;
+
+ len = strlen(prefix) + strlen(var) + 2;
+ v = xmalloc(len);
+ snprintf(v, len, "%s_%s", prefix, var);
+ return v;
+}
+
+
+static void
+append_config(char ***env, ssize_t *len,
+ const char *prefix, const char *const *config)
+{
+ ssize_t i, j, e1;
+ char **ne, *eq;
+
+ if (config == NULL)
+ return;
+
+ ne = *env;
+ for (i = 0; config[i] != NULL; i++) {
+ eq = strchr(config[i], '=');
+ e1 = eq - config[i] + 1;
+ for (j = 0; j < *len; j++) {
+ if (strncmp(ne[j] + strlen(prefix) + 1, config[i], e1) == 0) {
+ free(ne[j]);
+ ne[j] = make_var(prefix, config[i]);
+ break;
+ }
+ }
+ if (j == *len) {
+ j++;
+ ne = xrealloc(ne, sizeof(char *) * (j + 1));
+ ne[j - 1] = make_var(prefix, config[i]);
+ *len = j;
+ }
+ }
+ *env = ne;
+}
+
int
run_script(const struct interface *iface, const char *reason)
{
elen += configure_env(env + elen, "old",
iface->state->old, ifo);
}
+ append_config(&env, &elen, "old",
+ (const char *const *)ifo->config);
}
if (iface->state->new) {
e = configure_env(NULL, NULL, iface->state->new, ifo);
elen += configure_env(env + elen, "new",
iface->state->new, ifo);
}
+ append_config(&env, &elen, "new",
+ (const char *const *)ifo->config);
}
+
/* Add our base environment */
if (ifo->environ) {
e = 0;
return r;
}
+static struct rt *
+get_routes(const struct interface *iface) {
+ struct rt *rt, *nrt, *r = NULL;
+
+ if (iface->state->options->routes != NULL) {
+ for (rt = iface->state->options->routes;
+ rt != NULL;
+ rt = rt->next)
+ {
+ if (r == NULL)
+ r = nrt = xmalloc(sizeof(*r));
+ else {
+ r->next = xmalloc(sizeof(*r));
+ r = r->next;
+ }
+ memcpy(r, rt, sizeof(*r));
+ r->next = NULL;
+ }
+ return nrt;
+ }
+
+ return get_option_routes(iface->state->new);
+}
+
static void
build_routes()
{
for (ifp = ifaces; ifp; ifp = ifp->next) {
if (ifp->state->new == NULL)
continue;
- dnr = get_option_routes(ifp->state->new);
+ dnr = get_routes(ifp);
dnr = add_subnet_route(dnr, ifp);
for (rt = dnr; rt && (rtn = rt->next, 1); lrt = rt, rt = rtn) {
rt->iface = ifp;
}
case "${reason}" in
-BOUND|INFORM|REBIND|REBOOT|RENEW|TIMEOUT) add_resolv_conf;;
-PREINIT|EXPIRE|FAIL|IPV4LL|RELEASE|STOP) remove_resolv_conf;;
+BOUND|INFORM|REBIND|REBOOT|RENEW|TIMEOUT|STATIC) add_resolv_conf;;
+PREINIT|EXPIRE|FAIL|IPV4LL|RELEASE|STOP) remove_resolv_conf;;
esac
}
case "${reason}" in
-BOUND|INFORM|REBIND|REBOOT|RENEW|TIMEOUT) set_hostname;;
+BOUND|INFORM|REBIND|REBOOT|RENEW|TIMEOUT|STATIC) set_hostname;;
esac
}
case "${reason}" in
-BOUND|INFORM|REBIND|REBOOT|RENEW|TIMEOUT) set_hostname;;
+BOUND|INFORM|REBIND|REBOOT|RENEW|TIMEOUT|STATIC) set_hostname;;
esac
}
case "${reason}" in
-BOUND|INFORM|REBIND|REBOOT|RENEW|TIMEOUT) add_ntp_conf add;;
-PREINIT|EXPIRE|FAIL|IPV4LL|RELEASE|STOP) remove_ntp_conf del;;
+BOUND|INFORM|REBIND|REBOOT|RENEW|TIMEOUT|STATIC) add_ntp_conf add;;
+PREINIT|EXPIRE|FAIL|IPV4LL|RELEASE|STOP) remove_ntp_conf del;;
esac
}
case "${reason}" in
-BOUND|INFORM|REBIND|REBOOT|RENEW|TIMEOUT) make_yp_conf;;
-EXPIRE|FAIL|IPV4LL|RELEASE|STOP) restore_yp_conf;;
+BOUND|INFORM|REBIND|REBOOT|RENEW|TIMEOUT|STATIC) make_yp_conf;;
+EXPIRE|FAIL|IPV4LL|RELEASE|STOP) restore_yp_conf;;
esac
-.\" Copyright 2006-2008 Roy Marples
+.\" Copyright 2006-2009 Roy Marples
.\" All rights reserved
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd October 07, 2008
+.Dd January 1, 2008
.Dt DHCPCD.SH 8 SMM
.Sh NAME
.Nm dhcpcd-run-hooks
.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.
+dhcpcd's lease or state 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
interface.
This is primarily used to test the variables are filled correctly for the
script to process them.
+.It Dv STATIC
+dhcpcd has been configured with a static configuration which has not been
+obtained from a DHCP server.
.El
.Sh FILES
When
-.\" Copyright 2006-2008 Roy Marples
+.\" Copyright 2006-2009 Roy Marples
.\" All rights reserved
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd December 16, 2008
+.Dd January 1, 2009
.Dt DHCPCD 8 SMM
.Sh NAME
.Nm dhcpcd
.Op Fl I , -clientid Ar clientid
.Op Fl O , -nooption Ar option
.Op Fl Q , -require Ar option
+.Op Fl S , -static Ar value
.Op Fl X , -blacklist Ar address
.Op Fl Z , -denyinterfaces Ar pattern
.Op interface
only responds to DHCP servers and not BOOTP servers, you can
.Fl Q
.Ar dhcp_message_type .
+.It Fl S, -static Ar value
+Configures a static
+.Ar value .
+If you set
+.Ic ip_address
+then
+.Nm
+will not attempt to obtain a lease and just use the value for the address with
+an infinite lease time.
+.Pp
+Here is an example which configures a static address, routes and dns.
+.D1 dhcpcd -S ip_address=192.168.0.10/24 \e
+.D1 -S routers=192.168.0.1 \e
+.D1 -S domain_name_servers=192.168.0.1 \e
+.D1 eth0
.It Fl T, -test
On receipt of OFFER messages just call
.Pa @SCRIPT@
/*
* dhcpcd - DHCP client daemon
- * Copyright 2006-2008 Roy Marples <roy@marples.name>
+ * Copyright 2006-2009 Roy Marples <roy@marples.name>
* All rights reserved
* Redistribution and use in source and binary forms, with or without
* SUCH DAMAGE.
*/
-const char copyright[] = "Copyright (c) 2006-2008 Roy Marples";
+const char copyright[] = "Copyright (c) 2006-2009 Roy Marples";
#include <sys/file.h>
#include <sys/stat.h>
send_request(iface);
}
+static void
+start_static(struct interface *iface)
+{
+ struct dhcp_message *dhcp;
+ struct if_options *ifo = iface->state->options;
+ uint8_t *p;
+ uint32_t u32;
+
+ dhcp = xzalloc(sizeof(*dhcp));
+ dhcp->yiaddr = ifo->request_address.s_addr;
+ p = dhcp->options;
+ *p++ = DHO_SUBNETMASK;
+ *p++ = sizeof(u32);
+ u32 = ifo->request_netmask.s_addr;
+ memcpy(p, &u32, sizeof(u32));
+ *p++ = DHO_END;
+
+ iface->state->offer = dhcp;
+ delete_timeout(NULL, iface);
+ bind_interface(iface);
+}
+
void
start_interface(void *arg)
{
start_discover(iface);
return;
}
+ if (ifo->options & DHCPCD_STATIC) {
+ start_static(iface);
+ return;
+ }
if (ifo->request_address.s_addr) {
/* This also changes netmask */
if (iface->state->options->options & DHCPCD_INFORM &&
-.\" Copyright 2006-2008 Roy Marples
+.\" Copyright 2006-2009 Roy Marples
.\" All rights reserved
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd December 16, 2008
+.Dd January 1, 2009
.Dt DHCPCD.CONF 5 SMM
.Sh NAME
.Nm dhcpcd.conf
.Ar script
instead of the default
.Pa @SCRIPT@ .
+.It Ic static Ar value
+Configures a static
+.Ar value .
+If you set
+.Ic ip_address
+then
+.Nm dhcpcd
+will not attempt to obtain a lease and just use the value for the address with
+an infinite lease time.
+.Pp
+Here is an example which configures a static address, routes and dns.
+.D1 interface eth0
+.D1 static ip_address=192.168.0.10/24
+.D1 static routers=192.168.0.1
+.D1 static domain_name_servers=192.168.0.1
.It Ic timeout Ar seconds
The default timeout for waiting for a DHCP response is 30 seconds which may
be too long or too short and can be changed here.
/*
* dhcpcd - DHCP client daemon
- * Copyright 2006-2008 Roy Marples <roy@marples.name>
+ * Copyright 2006-2009 Roy Marples <roy@marples.name>
* All rights reserved
* Redistribution and use in source and binary forms, with or without
{"noipv4ll", no_argument, NULL, 'L'},
{"nooption", optional_argument, NULL, 'O'},
{"require", required_argument, NULL, 'Q'},
+ {"static", required_argument, NULL, 'S'},
{"test", no_argument, NULL, 'T'},
{"variables", no_argument, NULL, 'V'},
{"blacklist", required_argument, NULL, 'X'},
return v;
}
+
+static int
+parse_addr(struct in_addr *addr, struct in_addr *net, const char *arg)
+{
+ char *p;
+ int i;
+
+ if (arg == NULL || *arg == '\0')
+ return 0;
+ if ((p = strchr(arg, '/')) != NULL) {
+ *p++ = '\0';
+ if (net != NULL &&
+ (sscanf(p, "%d", &i) != 1 ||
+ inet_cidrtoaddr(i, net) != 0))
+ {
+ syslog(LOG_ERR, "`%s' is not a valid CIDR", p);
+ return -1;
+ }
+ }
+ if (addr != NULL && inet_aton(arg, addr) == 0) {
+ syslog(LOG_ERR, "`%s' is not a valid IP address", arg);
+ return -1;
+ }
+ return 0;
+}
+
static int
parse_option(struct if_options *ifo, int opt, const char *arg)
{
int i;
- char *p = NULL;
+ char *p = NULL, *np;
ssize_t s;
struct in_addr addr;
+ struct rt *rt;
switch(opt) {
case 'd': /* FALLTHROUGH */
ifo->options &= ~DHCPCD_ARP;
if (!arg || *arg == '\0') {
ifo->request_address.s_addr = 0;
- break;
} else {
- if ((p = strchr(arg, '/'))) {
- /* nullify the slash, so the -r option
- * can read the address */
- *p++ = '\0';
- if (sscanf(p, "%d", &i) != 1 ||
- inet_cidrtoaddr(i, &ifo->request_netmask) != 0)
- {
- syslog(LOG_ERR,
- "`%s' is not a valid CIDR",
- p);
- return -1;
- }
- }
+ if (parse_addr(&ifo->request_address,
+ &ifo->request_netmask,
+ arg) != 0)
+ return -1;
}
- /* FALLTHROUGH */
+ break;
case 'r':
- if (!(ifo->options & DHCPCD_INFORM))
- ifo->options |= DHCPCD_REQUEST;
- if (arg && !inet_aton(arg, &ifo->request_address)) {
- syslog(LOG_ERR, "`%s' is not a valid IP address",
- arg);
+ ifo->options |= DHCPCD_REQUEST;
+ if (parse_addr(&ifo->request_address, NULL, arg) != 0)
return -1;
- }
- /* Restore the slash */
- if (ifo->options & DHCPCD_INFORM && p)
- *--p = '/';
break;
case 't':
ifo->timeout = atoint(arg);
return -1;
}
break;
+ case 'S':
+ p = strchr(arg, '=');
+ if (p == NULL) {
+ syslog(LOG_ERR, "static assignment required");
+ return -1;
+ }
+ p++;
+ if (strncmp(arg, "ip_address=", strlen("ip_address=")) == 0) {
+ if (parse_addr(&ifo->request_address,
+ &ifo->request_netmask, p) != 0)
+ return -1;
+
+ ifo->options |= DHCPCD_STATIC;
+ } else if (strncmp(arg, "routes=", strlen("routes=")) == 0 ||
+ strncmp(arg, "static_routes=", strlen("static_routes=")) == 0 ||
+ strncmp(arg, "classless_static_routes=", strlen("classless_static_routes=")) == 0 ||
+ strncmp(arg, "ms_classless_static_routes=", strlen("ms_classless_static_routes=")) == 0)
+ {
+ np = strchr(p, ' ');
+ if (np == NULL) {
+ syslog(LOG_ERR, "all routes need a gateway");
+ return -1;
+ }
+ *np++ = '\0';
+ while (*np == ' ')
+ np++;
+ if (ifo->routes == NULL) {
+ rt = ifo->routes = xmalloc(sizeof(*rt));
+ } else {
+ rt = ifo->routes;
+ while (rt->next)
+ rt = rt->next;
+ rt->next = xmalloc(sizeof(*rt));
+ rt = rt->next;
+ }
+ rt->next = NULL;
+ if (parse_addr(&rt->dest, &rt->net, p) == -1 ||
+ parse_addr(&rt->gate, NULL, np) == -1)
+ return -1;
+ } else if (strncmp(arg, "routers=", strlen("routers=")) == 0) {
+ if (ifo->routes == NULL) {
+ rt = ifo->routes = xzalloc(sizeof(*rt));
+ } else {
+ rt = ifo->routes;
+ while (rt->next)
+ rt = rt->next;
+ rt->next = xmalloc(sizeof(*rt));
+ rt = rt->next;
+ }
+ rt->dest.s_addr = 0;
+ rt->net.s_addr = 0;
+ rt->next = NULL;
+ if (parse_addr(&rt->gate, NULL, p) == -1)
+ return -1;
+ } else {
+ s = 0;
+ if (ifo->config != NULL) {
+ while (ifo->config[s] != NULL) {
+ if (strncmp(ifo->config[s], arg, p - arg) == 0) {
+ printf("match\n");
+ free(ifo->config[s]);
+ ifo->config[s] = xstrdup(arg);
+ return 1;
+ }
+ s++;
+ }
+ }
+ ifo->config = xrealloc(ifo->config, sizeof(char *) * (s + 2));
+ ifo->config[s] = xstrdup(arg);
+ ifo->config[s + 1] = NULL;
+ }
+ break;
case 'X':
if (!inet_aton(arg, &addr)) {
syslog(LOG_ERR, "`%s' is not a valid IP address",
free(ifo->environ[i++]);
free(ifo->environ);
}
+ if (ifo->config) {
+ i = 0;
+ while (ifo->config[i])
+ free(ifo->config[i++]);
+ free(ifo->config);
+ }
+ free_routes(ifo->routes);
free(ifo->blacklist);
free(ifo);
}
/*
* dhcpcd - DHCP client daemon
- * Copyright 2006-2008 Roy Marples <roy@marples.name>
+ * Copyright 2006-2009 Roy Marples <roy@marples.name>
* All rights reserved
* Redistribution and use in source and binary forms, with or without
#define DHCPCD_RELEASE (1 << 1)
#define DHCPCD_DOMAIN (1 << 2)
#define DHCPCD_GATEWAY (1 << 3)
+#define DHCPCD_STATIC (1 << 4)
#define DHCPCD_LASTLEASE (1 << 7)
#define DHCPCD_INFORM (1 << 8)
#define DHCPCD_REQUEST (1 << 9)
struct in_addr request_address;
struct in_addr request_netmask;
+ struct rt *routes;
+ char **config;
char **environ;
char script[PATH_MAX];