From: Roy Marples Date: Thu, 1 Jan 2009 14:23:36 +0000 (+0000) Subject: Add a static directive that allows the configuration of variables, which X-Git-Tag: v5.0.0~140 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=91a44b91b06f127a98ae7f64e377e59d47eba329;p=thirdparty%2Fdhcpcd.git Add a static directive that allows the configuration of variables, which supercedes any DHCP configured variables. If ip_address is configured then we don't bother with a DHCP transaction. --- diff --git a/bind.c b/bind.c index 38cc74fb..b692ab92 100644 --- a/bind.c +++ b/bind.c @@ -1,6 +1,6 @@ /* * dhcpcd - DHCP client daemon - * Copyright 2006-2008 Roy Marples + * Copyright 2006-2009 Roy Marples * All rights reserved * Redistribution and use in source and binary forms, with or without @@ -129,7 +129,13 @@ bind_interface(void *arg) 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; @@ -146,7 +152,7 @@ bind_interface(void *arg) } 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; @@ -176,7 +182,7 @@ bind_interface(void *arg) 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) diff --git a/configure.c b/configure.c index 769b411a..917bd181 100644 --- a/configure.c +++ b/configure.c @@ -1,6 +1,6 @@ /* * dhcpcd - DHCP client daemon - * Copyright 2006-2008 Roy Marples + * Copyright 2006-2009 Roy Marples * All rights reserved * Redistribution and use in source and binary forms, with or without @@ -91,6 +91,50 @@ exec_script(char *const *argv, char *const *env) 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) { @@ -149,6 +193,8 @@ 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); @@ -157,7 +203,10 @@ run_script(const struct interface *iface, const char *reason) 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; @@ -332,6 +381,30 @@ add_subnet_route(struct rt *rt, const struct interface *iface) 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() { @@ -341,7 +414,7 @@ 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; diff --git a/dhcpcd-hooks/20-resolv.conf b/dhcpcd-hooks/20-resolv.conf index 0d812ca1..601ef0ad 100644 --- a/dhcpcd-hooks/20-resolv.conf +++ b/dhcpcd-hooks/20-resolv.conf @@ -119,6 +119,6 @@ remove_resolv_conf() } 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 diff --git a/dhcpcd-hooks/29-lookup-hostname b/dhcpcd-hooks/29-lookup-hostname index 3dfade3f..3214c50d 100644 --- a/dhcpcd-hooks/29-lookup-hostname +++ b/dhcpcd-hooks/29-lookup-hostname @@ -30,5 +30,5 @@ set_hostname() } case "${reason}" in -BOUND|INFORM|REBIND|REBOOT|RENEW|TIMEOUT) set_hostname;; +BOUND|INFORM|REBIND|REBOOT|RENEW|TIMEOUT|STATIC) set_hostname;; esac diff --git a/dhcpcd-hooks/30-hostname b/dhcpcd-hooks/30-hostname index b2e5fc89..1f73d1fd 100644 --- a/dhcpcd-hooks/30-hostname +++ b/dhcpcd-hooks/30-hostname @@ -24,5 +24,5 @@ set_hostname() } case "${reason}" in -BOUND|INFORM|REBIND|REBOOT|RENEW|TIMEOUT) set_hostname;; +BOUND|INFORM|REBIND|REBOOT|RENEW|TIMEOUT|STATIC) set_hostname;; esac diff --git a/dhcpcd-hooks/50-ntp.conf b/dhcpcd-hooks/50-ntp.conf index 8c92f279..3193cb2d 100644 --- a/dhcpcd-hooks/50-ntp.conf +++ b/dhcpcd-hooks/50-ntp.conf @@ -84,6 +84,6 @@ remove_ntp_conf() } 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 diff --git a/dhcpcd-hooks/50-yp.conf b/dhcpcd-hooks/50-yp.conf index a2296ebf..6060696e 100644 --- a/dhcpcd-hooks/50-yp.conf +++ b/dhcpcd-hooks/50-yp.conf @@ -44,6 +44,6 @@ restore_yp_conf() } 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 diff --git a/dhcpcd-run-hooks.8.in b/dhcpcd-run-hooks.8.in index a8b25ed9..a2e4951d 100644 --- a/dhcpcd-run-hooks.8.in +++ b/dhcpcd-run-hooks.8.in @@ -1,4 +1,4 @@ -.\" Copyright 2006-2008 Roy Marples +.\" Copyright 2006-2009 Roy Marples .\" All rights reserved .\" .\" Redistribution and use in source and binary forms, with or without @@ -22,7 +22,7 @@ .\" 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 @@ -83,7 +83,7 @@ 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. +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 @@ -95,6 +95,9 @@ 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. +.It Dv STATIC +dhcpcd has been configured with a static configuration which has not been +obtained from a DHCP server. .El .Sh FILES When diff --git a/dhcpcd.8.in b/dhcpcd.8.in index f385072c..ac0be091 100644 --- a/dhcpcd.8.in +++ b/dhcpcd.8.in @@ -1,4 +1,4 @@ -.\" Copyright 2006-2008 Roy Marples +.\" Copyright 2006-2009 Roy Marples .\" All rights reserved .\" .\" Redistribution and use in source and binary forms, with or without @@ -22,7 +22,7 @@ .\" 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 @@ -49,6 +49,7 @@ .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 @@ -424,6 +425,21 @@ To enforce that 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@ diff --git a/dhcpcd.c b/dhcpcd.c index 49d48a8e..033f1368 100644 --- a/dhcpcd.c +++ b/dhcpcd.c @@ -1,6 +1,6 @@ /* * dhcpcd - DHCP client daemon - * Copyright 2006-2008 Roy Marples + * Copyright 2006-2009 Roy Marples * All rights reserved * Redistribution and use in source and binary forms, with or without @@ -25,7 +25,7 @@ * SUCH DAMAGE. */ -const char copyright[] = "Copyright (c) 2006-2008 Roy Marples"; +const char copyright[] = "Copyright (c) 2006-2009 Roy Marples"; #include #include @@ -778,6 +778,28 @@ start_reboot(struct interface *iface) 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) { @@ -800,6 +822,10 @@ 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 && diff --git a/dhcpcd.conf.5.in b/dhcpcd.conf.5.in index c7aa7219..f136a944 100644 --- a/dhcpcd.conf.5.in +++ b/dhcpcd.conf.5.in @@ -1,4 +1,4 @@ -.\" Copyright 2006-2008 Roy Marples +.\" Copyright 2006-2009 Roy Marples .\" All rights reserved .\" .\" Redistribution and use in source and binary forms, with or without @@ -22,7 +22,7 @@ .\" 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 @@ -175,6 +175,21 @@ Use .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. diff --git a/if-options.c b/if-options.c index 6d031295..abbb92cc 100644 --- a/if-options.c +++ b/if-options.c @@ -1,6 +1,6 @@ /* * dhcpcd - DHCP client daemon - * Copyright 2006-2008 Roy Marples + * Copyright 2006-2009 Roy Marples * All rights reserved * Redistribution and use in source and binary forms, with or without @@ -80,6 +80,7 @@ const struct option cf_options[] = { {"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'}, @@ -263,13 +264,40 @@ splitv(int *argc, char **argv, const char *arg) 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 */ @@ -351,34 +379,17 @@ parse_option(struct if_options *ifo, int opt, const char *arg) 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); @@ -531,6 +542,78 @@ parse_option(struct if_options *ifo, int opt, const char *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", @@ -674,6 +757,13 @@ free_options(struct if_options *ifo) 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); } diff --git a/if-options.h b/if-options.h index 1d907091..545e7479 100644 --- a/if-options.h +++ b/if-options.h @@ -1,6 +1,6 @@ /* * dhcpcd - DHCP client daemon - * Copyright 2006-2008 Roy Marples + * Copyright 2006-2009 Roy Marples * All rights reserved * Redistribution and use in source and binary forms, with or without @@ -52,6 +52,7 @@ #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) @@ -82,6 +83,8 @@ struct if_options { struct in_addr request_address; struct in_addr request_netmask; + struct rt *routes; + char **config; char **environ; char script[PATH_MAX];