2 * dhcpcd - DHCP client daemon
3 * Copyright (c) 2006-2009 Roy Marples <roy@marples.name>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 #include <sys/types.h>
30 #include <arpa/inet.h>
45 #include "if-options.h"
48 /* These options only make sense in the config file, so don't use any
49 valid short options for them */
50 #define O_BASE MAX('z', 'Z') + 1
51 #define O_ARPING O_BASE + 1
52 #define O_FALLBACK O_BASE + 2
54 const struct option cf_options
[] = {
55 {"background", no_argument
, NULL
, 'b'},
56 {"script", required_argument
, NULL
, 'c'},
57 {"debug", no_argument
, NULL
, 'd'},
58 {"env", required_argument
, NULL
, 'e'},
59 {"config", required_argument
, NULL
, 'f'},
60 {"reconfigure", no_argument
, NULL
, 'g'},
61 {"hostname", optional_argument
, NULL
, 'h'},
62 {"vendorclassid", optional_argument
, NULL
, 'i'},
63 {"release", no_argument
, NULL
, 'k'},
64 {"leasetime", required_argument
, NULL
, 'l'},
65 {"metric", required_argument
, NULL
, 'm'},
66 {"rebind", no_argument
, NULL
, 'n'},
67 {"option", required_argument
, NULL
, 'o'},
68 {"persistent", no_argument
, NULL
, 'p'},
69 {"quiet", no_argument
, NULL
, 'q'},
70 {"request", optional_argument
, NULL
, 'r'},
71 {"inform", optional_argument
, NULL
, 's'},
72 {"timeout", required_argument
, NULL
, 't'},
73 {"userclass", required_argument
, NULL
, 'u'},
74 {"vendor", required_argument
, NULL
, 'v'},
75 {"waitip", no_argument
, NULL
, 'w'},
76 {"exit", no_argument
, NULL
, 'x'},
77 {"allowinterfaces", required_argument
, NULL
, 'z'},
78 {"reboot", required_argument
, NULL
, 'y'},
79 {"noarp", no_argument
, NULL
, 'A'},
80 {"nobackground", no_argument
, NULL
, 'B'},
81 {"nohook", required_argument
, NULL
, 'C'},
82 {"duid", no_argument
, NULL
, 'D'},
83 {"lastlease", no_argument
, NULL
, 'E'},
84 {"fqdn", optional_argument
, NULL
, 'F'},
85 {"nogateway", no_argument
, NULL
, 'G'},
86 {"clientid", optional_argument
, NULL
, 'I'},
87 {"nolink", no_argument
, NULL
, 'K'},
88 {"noipv4ll", no_argument
, NULL
, 'L'},
89 {"destination", required_argument
, NULL
, 'N'},
90 {"nooption", optional_argument
, NULL
, 'O'},
91 {"require", required_argument
, NULL
, 'Q'},
92 {"static", required_argument
, NULL
, 'S'},
93 {"test", no_argument
, NULL
, 'T'},
94 {"variables", no_argument
, NULL
, 'V'},
95 {"whitelist", required_argument
, NULL
, 'W'},
96 {"blacklist", required_argument
, NULL
, 'X'},
97 {"denyinterfaces", required_argument
, NULL
, 'Z'},
98 {"arping", required_argument
, NULL
, O_ARPING
},
99 {"fallback", required_argument
, NULL
, O_FALLBACK
},
100 {NULL
, 0, NULL
, '\0'}
104 atoint(const char *s
)
110 n
= strtol(s
, &t
, 0);
111 if ((errno
!= 0 && n
== 0) || s
== t
||
112 (errno
== ERANGE
&& (n
== LONG_MAX
|| n
== LONG_MIN
)))
114 syslog(LOG_ERR
, "`%s' out of range", s
);
122 add_environ(struct if_options
*ifo
, const char *value
, int uniq
)
125 char **lst
= ifo
->environ
;
127 char *match
= NULL
, *p
;
129 match
= xstrdup(value
);
130 p
= strchr(match
, '=');
135 while (lst
&& lst
[i
]) {
136 if (match
&& strncmp(lst
[i
], match
, l
) == 0) {
139 lst
[i
] = xstrdup(value
);
141 /* Append a space and the value to it */
144 lst
[i
] = xrealloc(lst
[i
], l
+ lv
+ 2);
146 memcpy(lst
[i
] + l
+ 1, p
, lv
);
147 lst
[i
][l
+ lv
+ 1] = '\0';
155 newlist
= xrealloc(lst
, sizeof(char *) * (i
+ 2));
156 newlist
[i
] = xstrdup(value
);
157 newlist
[i
+ 1] = NULL
;
158 ifo
->environ
= newlist
;
163 #define parse_string(buf, len, arg) parse_string_hwaddr(buf, len, arg, 0)
165 parse_string_hwaddr(char *sbuf
, ssize_t slen
, const char *str
, int clid
)
169 int i
, punt_last
= 0;
172 /* If surrounded by quotes then it's a string */
180 l
= hwaddr_aton(NULL
, str
);
186 hwaddr_aton((uint8_t *)sbuf
, str
);
191 /* Process escapes */
193 /* If processing a string on the clientid, first byte should be
194 * 0 to indicate a non hardware type */
227 /* Grab a hex code */
229 for (i
= 0; i
< 2; i
++) {
230 if (isxdigit((unsigned char)*str
) == 0)
236 *sbuf
++ = strtol(c
, NULL
, 16);
241 /* Grab an octal code */
243 for (i
= 0; i
< 3; i
++) {
244 if (*str
< '0' || *str
> '7')
249 i
= strtol(c
, NULL
, 8);
270 splitv(int *argc
, char **argv
, const char *arg
)
273 char *o
= xstrdup(arg
), *p
, *t
;
276 while ((t
= strsep(&p
, ", "))) {
278 v
= xrealloc(v
, sizeof(char *) * ((*argc
)));
279 v
[(*argc
) - 1] = xstrdup(t
);
286 parse_addr(struct in_addr
*addr
, struct in_addr
*net
, const char *arg
)
291 if (arg
== NULL
|| *arg
== '\0') {
298 if ((p
= strchr(arg
, '/')) != NULL
) {
301 (sscanf(p
, "%d", &i
) != 1 ||
302 inet_cidrtoaddr(i
, net
) != 0))
304 syslog(LOG_ERR
, "`%s' is not a valid CIDR", p
);
309 if (addr
!= NULL
&& inet_aton(arg
, addr
) == 0) {
310 syslog(LOG_ERR
, "`%s' is not a valid IP address", arg
);
315 else if (net
!= NULL
)
316 net
->s_addr
= get_netmask(addr
->s_addr
);
321 parse_option(struct if_options
*ifo
, int opt
, const char *arg
)
326 struct in_addr addr
, addr2
;
330 case 'f': /* FALLTHROUGH */
331 case 'g': /* FALLTHROUGH */
332 case 'n': /* FALLTHROUGH */
333 case 'x': /* FALLTHROUGH */
334 case 'T': /* We need to handle non interface options */
337 ifo
->options
|= DHCPCD_BACKGROUND
;
340 strlcpy(ifo
->script
, arg
, sizeof(ifo
->script
));
343 ifo
->options
|= DHCPCD_DEBUG
;
346 add_environ(ifo
, arg
, 1);
350 s
= parse_string(ifo
->hostname
,
351 HOSTNAME_MAX_LEN
, arg
);
353 syslog(LOG_ERR
, "hostname: %m");
356 if (s
!= 0 && ifo
->hostname
[0] == '.') {
358 "hostname cannot begin with .");
361 ifo
->hostname
[s
] = '\0';
363 if (ifo
->hostname
[0] == '\0')
364 ifo
->options
&= ~DHCPCD_HOSTNAME
;
366 ifo
->options
|= DHCPCD_HOSTNAME
;
370 s
= parse_string((char *)ifo
->vendorclassid
+ 1,
371 VENDORCLASSID_MAX_LEN
, arg
);
375 syslog(LOG_ERR
, "vendorclassid: %m");
378 *ifo
->vendorclassid
= (uint8_t)s
;
381 ifo
->options
|= DHCPCD_RELEASE
;
386 "leasetime must be a positive value");
390 ifo
->leasetime
= (uint32_t)strtol(arg
, NULL
, 0);
391 if (errno
== EINVAL
|| errno
== ERANGE
) {
392 syslog(LOG_ERR
, "`%s' out of range", arg
);
397 ifo
->metric
= atoint(arg
);
398 if (ifo
->metric
< 0) {
399 syslog(LOG_ERR
, "metric must be a positive value");
404 if (make_option_mask(ifo
->requestmask
, arg
, 1) != 0) {
405 syslog(LOG_ERR
, "unknown option `%s'", arg
);
410 ifo
->options
|= DHCPCD_PERSISTENT
;
413 ifo
->options
|= DHCPCD_QUIET
;
416 ifo
->options
|= DHCPCD_REQUEST
;
417 if (parse_addr(&ifo
->req_addr
, NULL
, arg
) != 0)
419 ifo
->req_mask
.s_addr
= 0;
422 ifo
->options
|= DHCPCD_INFORM
| DHCPCD_PERSISTENT
;
423 ifo
->options
&= ~(DHCPCD_ARP
| DHCPCD_STATIC
);
424 if (arg
&& *arg
!= '\0') {
425 if (parse_addr(&ifo
->req_addr
, &ifo
->req_mask
,
429 ifo
->req_addr
.s_addr
= 0;
430 ifo
->req_mask
.s_addr
= 0;
434 ifo
->timeout
= atoint(arg
);
435 if (ifo
->timeout
< 0) {
436 syslog(LOG_ERR
, "timeout must be a positive value");
441 s
= USERCLASS_MAX_LEN
- ifo
->userclass
[0] - 1;
442 s
= parse_string((char *)ifo
->userclass
+
443 ifo
->userclass
[0] + 2,
446 syslog(LOG_ERR
, "userclass: %m");
450 ifo
->userclass
[ifo
->userclass
[0] + 1] = s
;
451 ifo
->userclass
[0] += s
+ 1;
455 p
= strchr(arg
, ',');
457 syslog(LOG_ERR
, "invalid vendor format");
461 /* If vendor starts with , then it is not encapsulated */
464 s
= parse_string((char *)ifo
->vendor
+ 1,
465 VENDOR_MAX_LEN
, arg
);
467 syslog(LOG_ERR
, "vendor: %m");
470 ifo
->vendor
[0] = (uint8_t)s
;
471 ifo
->options
|= DHCPCD_VENDORRAW
;
475 /* Encapsulated vendor options */
476 if (ifo
->options
& DHCPCD_VENDORRAW
) {
477 ifo
->options
&= ~DHCPCD_VENDORRAW
;
484 if (i
< 1 || i
> 254) {
485 syslog(LOG_ERR
, "vendor option should be between"
486 " 1 and 254 inclusive");
489 s
= VENDOR_MAX_LEN
- ifo
->vendor
[0] - 2;
490 if (inet_aton(arg
, &addr
) == 1) {
495 memcpy(ifo
->vendor
+ ifo
->vendor
[0] + 3,
496 &addr
.s_addr
, sizeof(addr
.s_addr
));
498 s
= parse_string((char *)ifo
->vendor
+
499 ifo
->vendor
[0] + 3, s
, arg
);
502 syslog(LOG_ERR
, "vendor: %m");
506 ifo
->vendor
[ifo
->vendor
[0] + 1] = i
;
507 ifo
->vendor
[ifo
->vendor
[0] + 2] = s
;
508 ifo
->vendor
[0] += s
+ 2;
512 ifo
->options
|= DHCPCD_WAITIP
;
515 ifo
->reboot
= atoint(arg
);
516 if (ifo
->reboot
< 0) {
517 syslog(LOG_ERR
, "reboot must be a positive value");
522 /* We only set this if we haven't got any interfaces */
524 ifav
= splitv(&ifac
, ifav
, arg
);
527 ifo
->options
&= ~DHCPCD_ARP
;
528 /* IPv4LL requires ARP */
529 ifo
->options
&= ~DHCPCD_IPV4LL
;
532 ifo
->options
&= ~DHCPCD_DAEMONISE
;
535 /* Commas to spaces for shell */
536 while ((p
= strchr(arg
, ',')))
538 s
= strlen("skip_hooks=") + strlen(arg
) + 1;
539 p
= xmalloc(sizeof(char) * s
);
540 snprintf(p
, s
, "skip_hooks=%s", arg
);
541 add_environ(ifo
, p
, 0);
545 ifo
->options
|= DHCPCD_CLIENTID
| DHCPCD_DUID
;
548 ifo
->options
|= DHCPCD_LASTLEASE
;
552 ifo
->fqdn
= FQDN_BOTH
;
555 if (strcmp(arg
, "none") == 0)
556 ifo
->fqdn
= FQDN_NONE
;
557 else if (strcmp(arg
, "ptr") == 0)
558 ifo
->fqdn
= FQDN_PTR
;
559 else if (strcmp(arg
, "both") == 0)
560 ifo
->fqdn
= FQDN_BOTH
;
561 else if (strcmp(arg
, "disable") == 0)
562 ifo
->fqdn
= FQDN_DISABLE
;
564 syslog(LOG_ERR
, "invalid value `%s' for FQDN", arg
);
569 ifo
->options
&= ~DHCPCD_GATEWAY
;
572 /* Strings have a type of 0 */;
573 ifo
->clientid
[1] = 0;
575 s
= parse_string_hwaddr((char *)ifo
->clientid
+ 1,
576 CLIENTID_MAX_LEN
, arg
, 1);
580 syslog(LOG_ERR
, "clientid: %m");
583 ifo
->options
|= DHCPCD_CLIENTID
;
584 ifo
->clientid
[0] = (uint8_t)s
;
587 ifo
->options
&= ~DHCPCD_LINK
;
590 ifo
->options
&= ~DHCPCD_IPV4LL
;
593 if (make_option_mask(ifo
->dstmask
, arg
, 2) != 0) {
595 syslog(LOG_ERR
, "option `%s' does not take"
596 " an IPv4 address", arg
);
598 syslog(LOG_ERR
, "unknown otpion `%s'", arg
);
603 if (make_option_mask(ifo
->requestmask
, arg
, -1) != 0 ||
604 make_option_mask(ifo
->requiremask
, arg
, -1) != 0 ||
605 make_option_mask(ifo
->nomask
, arg
, 1) != 0)
607 syslog(LOG_ERR
, "unknown option `%s'", arg
);
612 if (make_option_mask(ifo
->requiremask
, arg
, 1) != 0 ||
613 make_option_mask(ifo
->requestmask
, arg
, 1) != 0)
615 syslog(LOG_ERR
, "unknown option `%s'", arg
);
620 p
= strchr(arg
, '=');
622 syslog(LOG_ERR
, "static assignment required");
626 if (strncmp(arg
, "ip_address=", strlen("ip_address=")) == 0) {
627 if (parse_addr(&ifo
->req_addr
, &ifo
->req_mask
, p
) != 0)
630 ifo
->options
|= DHCPCD_STATIC
;
631 ifo
->options
&= ~DHCPCD_INFORM
;
632 } else if (strncmp(arg
, "routes=", strlen("routes=")) == 0 ||
633 strncmp(arg
, "static_routes=", strlen("static_routes=")) == 0 ||
634 strncmp(arg
, "classless_static_routes=", strlen("classless_static_routes=")) == 0 ||
635 strncmp(arg
, "ms_classless_static_routes=", strlen("ms_classless_static_routes=")) == 0)
639 syslog(LOG_ERR
, "all routes need a gateway");
645 if (ifo
->routes
== NULL
) {
646 rt
= ifo
->routes
= xmalloc(sizeof(*rt
));
651 rt
->next
= xmalloc(sizeof(*rt
));
655 if (parse_addr(&rt
->dest
, &rt
->net
, p
) == -1 ||
656 parse_addr(&rt
->gate
, NULL
, np
) == -1)
658 } else if (strncmp(arg
, "routers=", strlen("routers=")) == 0) {
659 if (ifo
->routes
== NULL
) {
660 rt
= ifo
->routes
= xzalloc(sizeof(*rt
));
665 rt
->next
= xmalloc(sizeof(*rt
));
668 rt
->dest
.s_addr
= INADDR_ANY
;
669 rt
->net
.s_addr
= INADDR_ANY
;
671 if (parse_addr(&rt
->gate
, NULL
, p
) == -1)
675 if (ifo
->config
!= NULL
) {
676 while (ifo
->config
[s
] != NULL
) {
677 if (strncmp(ifo
->config
[s
], arg
,
680 free(ifo
->config
[s
]);
681 ifo
->config
[s
] = xstrdup(arg
);
687 ifo
->config
= xrealloc(ifo
->config
,
688 sizeof(char *) * (s
+ 2));
689 ifo
->config
[s
] = xstrdup(arg
);
690 ifo
->config
[s
+ 1] = NULL
;
694 if (parse_addr(&addr
, &addr2
, arg
) != 0)
696 if (strchr(arg
, '/') == NULL
)
697 addr2
.s_addr
= INADDR_BROADCAST
;
698 ifo
->whitelist
= xrealloc(ifo
->whitelist
,
699 sizeof(in_addr_t
) * (ifo
->whitelist_len
+ 2));
700 ifo
->whitelist
[ifo
->whitelist_len
++] = addr
.s_addr
;
701 ifo
->whitelist
[ifo
->whitelist_len
++] = addr2
.s_addr
;
704 if (parse_addr(&addr
, &addr2
, arg
) != 0)
706 if (strchr(arg
, '/') == NULL
)
707 addr2
.s_addr
= INADDR_BROADCAST
;
708 ifo
->blacklist
= xrealloc(ifo
->blacklist
,
709 sizeof(in_addr_t
) * (ifo
->blacklist_len
+ 2));
710 ifo
->blacklist
[ifo
->blacklist_len
++] = addr
.s_addr
;
711 ifo
->blacklist
[ifo
->blacklist_len
++] = addr2
.s_addr
;
714 /* We only set this if we haven't got any interfaces */
716 ifdv
= splitv(&ifdc
, ifdv
, arg
);
719 if (parse_addr(&addr
, NULL
, arg
) != 0)
721 ifo
->arping
= xrealloc(ifo
->arping
,
722 sizeof(in_addr_t
) * (ifo
->arping_len
+ 1));
723 ifo
->arping
[ifo
->arping_len
++] = addr
.s_addr
;
727 ifo
->fallback
= xstrdup(arg
);
737 parse_config_line(struct if_options
*ifo
, const char *opt
, char *line
)
741 for (i
= 0; i
< sizeof(cf_options
) / sizeof(cf_options
[0]); i
++) {
742 if (!cf_options
[i
].name
||
743 strcmp(cf_options
[i
].name
, opt
) != 0)
746 if (cf_options
[i
].has_arg
== required_argument
&& !line
) {
748 PACKAGE
": option requires an argument -- %s\n",
753 return parse_option(ifo
, cf_options
[i
].val
, line
);
756 fprintf(stderr
, PACKAGE
": unknown option -- %s\n", opt
);
761 read_config(const char *file
,
762 const char *ifname
, const char *ssid
, const char *profile
)
764 struct if_options
*ifo
;
766 char *line
, *option
, *p
;
767 int skip
= 0, have_profile
= 0;
769 /* Seed our default options */
770 ifo
= xzalloc(sizeof(*ifo
));
771 ifo
->options
|= DHCPCD_GATEWAY
| DHCPCD_DAEMONISE
;
772 ifo
->options
|= DHCPCD_ARP
| DHCPCD_IPV4LL
| DHCPCD_LINK
;
773 ifo
->timeout
= DEFAULT_TIMEOUT
;
774 ifo
->reboot
= DEFAULT_REBOOT
;
776 strlcpy(ifo
->script
, SCRIPT
, sizeof(ifo
->script
));
777 gethostname(ifo
->hostname
, HOSTNAME_MAX_LEN
);
778 /* Ensure that the hostname is NULL terminated */
779 ifo
->hostname
[HOSTNAME_MAX_LEN
] = '\0';
780 if (strcmp(ifo
->hostname
, "(none)") == 0 ||
781 strcmp(ifo
->hostname
, "localhost") == 0)
782 ifo
->hostname
[0] = '\0';
783 ifo
->vendorclassid
[0] = snprintf((char *)ifo
->vendorclassid
+ 1,
784 VENDORCLASSID_MAX_LEN
,
785 "%s %s", PACKAGE
, VERSION
);
787 /* Parse our options file */
788 f
= fopen(file
? file
: CONFIG
, "r");
791 syslog(LOG_ERR
, "fopen `%s': %m", file
);
795 while ((line
= get_line(f
))) {
796 option
= strsep(&line
, " \t");
797 /* Trim trailing whitespace */
799 p
= line
+ strlen(line
) - 1;
801 (*p
== ' ' || *p
== '\t') &&
805 /* Start of an interface block, skip if not ours */
806 if (strcmp(option
, "interface") == 0) {
807 if (ifname
&& line
&& strcmp(line
, ifname
) == 0)
813 /* Start of an ssid block, skip if not ours */
814 if (strcmp(option
, "ssid") == 0) {
815 if (ssid
&& line
&& strcmp(line
, ssid
) == 0)
821 /* Start of a profile block, skip if not ours */
822 if (strcmp(option
, "profile") == 0) {
823 if (profile
&& line
&& strcmp(line
, profile
) == 0) {
832 if (parse_config_line(ifo
, option
, line
) != 1)
837 if (profile
&& !have_profile
) {
843 /* Terminate the encapsulated options */
844 if (ifo
&& ifo
->vendor
[0] && !(ifo
->options
& DHCPCD_VENDORRAW
)) {
846 ifo
->vendor
[ifo
->vendor
[0]] = DHO_END
;
852 add_options(struct if_options
*ifo
, int argc
, char **argv
)
857 while ((opt
= getopt_long(argc
, argv
, IF_OPTS
, cf_options
, &oi
)) != -1)
859 r
= parse_option(ifo
, opt
, optarg
);
863 /* Terminate the encapsulated options */
864 if (r
== 1 && ifo
->vendor
[0] && !(ifo
->options
& DHCPCD_VENDORRAW
)) {
866 ifo
->vendor
[ifo
->vendor
[0]] = DHO_END
;
872 free_options(struct if_options
*ifo
)
879 while (ifo
->environ
[i
])
880 free(ifo
->environ
[i
++]);
885 while (ifo
->config
[i
])
886 free(ifo
->config
[i
++]);
889 free_routes(ifo
->routes
);
891 free(ifo
->blacklist
);