1 /* SPDX-License-Identifier: BSD-2-Clause */
3 * dhcpcd - DHCP client daemon
4 * Copyright (c) 2006-2023 Roy Marples <roy@marples.name>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 #include <sys/utsname.h>
42 #include "dhcp-common.h"
50 dhcp_get_hostname(char *buf
, size_t buf_len
, const struct if_options
*ifo
)
53 if (ifo
->hostname
[0] == '\0') {
54 if (gethostname(buf
, buf_len
) != 0)
56 buf
[buf_len
- 1] = '\0';
58 strlcpy(buf
, ifo
->hostname
, buf_len
);
60 /* Deny sending of these local hostnames */
61 if (buf
[0] == '\0' || buf
[0] == '.' ||
62 strcmp(buf
, "(none)") == 0 ||
63 strcmp(buf
, "localhost") == 0 ||
64 strncmp(buf
, "localhost.", strlen("localhost.")) == 0)
67 /* Shorten the hostname if required */
68 if (ifo
->options
& DHCPCD_HOSTNAME_SHORT
) {
71 hp
= strchr(buf
, '.');
80 dhcp_print_option_encoding(const struct dhcp_opt
*opt
, int cols
)
88 if (opt
->type
& OT_EMBED
)
90 if (opt
->type
& OT_ENCAP
)
92 if (opt
->type
& OT_INDEX
)
94 if (opt
->type
& OT_ARRAY
)
96 if (opt
->type
& OT_UINT8
)
98 else if (opt
->type
& OT_INT8
)
100 else if (opt
->type
& OT_UINT16
)
102 else if (opt
->type
& OT_INT16
)
104 else if (opt
->type
& OT_UINT32
)
106 else if (opt
->type
& OT_INT32
)
108 else if (opt
->type
& OT_ADDRIPV4
)
109 printf(" ipaddress");
110 else if (opt
->type
& OT_ADDRIPV6
)
111 printf(" ip6address");
112 else if (opt
->type
& OT_FLAG
)
114 else if (opt
->type
& OT_BITFLAG
)
116 else if (opt
->type
& OT_RFC1035
)
118 else if (opt
->type
& OT_DOMAIN
)
120 else if (opt
->type
& OT_ASCII
)
122 else if (opt
->type
& OT_RAW
)
124 else if (opt
->type
& OT_BINHEX
)
126 else if (opt
->type
& OT_STRING
)
128 if (opt
->type
& OT_RFC3361
)
130 if (opt
->type
& OT_RFC3442
)
132 if (opt
->type
& OT_REQUEST
)
134 if (opt
->type
& OT_NOREQ
)
135 printf(" norequest");
140 vivso_find(uint32_t iana_en
, const void *arg
)
142 const struct interface
*ifp
;
144 struct dhcp_opt
*opt
;
147 for (i
= 0, opt
= ifp
->options
->vivso_override
;
148 i
< ifp
->options
->vivso_override_len
;
150 if (opt
->option
== iana_en
)
152 for (i
= 0, opt
= ifp
->ctx
->vivso
;
153 i
< ifp
->ctx
->vivso_len
;
155 if (opt
->option
== iana_en
)
161 dhcp_vendor(char *str
, size_t len
)
167 if (uname(&utn
) == -1)
168 return (ssize_t
)snprintf(str
, len
, "%s-%s",
172 "%s-%s:%s-%s:%s", PACKAGE
, VERSION
,
173 utn
.sysname
, utn
.release
, utn
.machine
);
174 if (l
== -1 || (size_t)(l
+ 1) > len
)
178 l
= if_machinearch(p
+ 1, len
- 1);
179 if (l
== -1 || (size_t)(l
+ 1) > len
)
187 make_option_mask(const struct dhcp_opt
*dopts
, size_t dopts_len
,
188 const struct dhcp_opt
*odopts
, size_t odopts_len
,
189 uint8_t *mask
, const char *opts
, int add
)
192 const struct dhcp_opt
*opt
;
199 o
= p
= strdup(opts
);
200 while ((token
= strsep(&p
, ", "))) {
203 if (strncmp(token
, "dhcp6_", 6) == 0)
205 if (strncmp(token
, "nd_", 3) == 0)
208 for (i
= 0, opt
= odopts
; i
< odopts_len
; i
++, opt
++) {
209 if (opt
->var
== NULL
|| opt
->option
== 0)
210 continue; /* buggy dhcpcd-definitions.conf */
211 if (strcmp(opt
->var
, token
) == 0)
214 n
= (unsigned int)strtou(token
, NULL
, 0,
216 if (e
== 0 && opt
->option
== n
)
223 for (i
= 0, opt
= dopts
; i
< dopts_len
; i
++, opt
++) {
224 if (strcmp(opt
->var
, token
) == 0)
227 n
= (unsigned int)strtou(token
, NULL
, 0,
229 if (e
== 0 && opt
->option
== n
)
236 if (!match
|| !opt
->option
) {
241 if (add
== 2 && !(opt
->type
& OT_ADDRIPV4
)) {
246 if (add
== 1 || add
== 2)
247 add_option_mask(mask
, opt
->option
);
249 del_option_mask(mask
, opt
->option
);
256 encode_rfc1035(const char *src
, uint8_t *dst
)
263 if (src
== NULL
|| *src
== '\0')
270 /* Silence bogus GCC warnings */
276 for (; *src
; src
++) {
280 /* Skip the trailing . */
285 *lp
= (uint8_t)(p
- lp
- 1);
291 *p
++ = (uint8_t)*src
;
296 *lp
= (uint8_t)(p
- lp
- 1);
307 /* Decode an RFC1035 DNS search order option into a space
308 * separated string. Returns length of string (including
309 * terminating zero) or zero on error. out may be NULL
310 * to just determine output length. */
312 decode_rfc1035(char *out
, size_t len
, const uint8_t *p
, size_t pl
)
315 size_t start_len
, l
, d_len
, o_len
;
316 const uint8_t *r
, *q
= p
, *e
;
329 /* Check we are inside our length again in-case
330 * the name isn't fully qualified (ie, not terminated) */
331 while (q
< e
&& (l
= (size_t)*q
++)) {
333 if (ltype
== 0x80 || ltype
== 0x40) {
334 /* Currently reserved for future use as noted
335 * in RFC1035 4.1.4 as the 10 and 01
340 else if (ltype
== 0xc0) { /* pointer */
347 /* save source of first jump. */
361 /* straightforward name segment, add with '.' */
366 if (l
> NS_MAXLABEL
) {
386 /* Don't count the trailing NUL */
387 if (d_len
> NS_MAXDNAME
+ 1) {
393 /* change last dot to space */
394 if (out
&& out
!= start
)
400 /* change last space to zero terminator */
404 else if (start_len
> 0)
408 /* Remove the trailing NUL */
412 return (ssize_t
)o_len
;
415 /* Check for a valid name as per RFC952 and RFC1123 section 2.1 */
417 valid_domainname(char *lbl
, int type
)
419 char *slbl
= lbl
, *lst
= NULL
;
422 bool start
= true, errset
= false;
424 if (lbl
== NULL
|| *lbl
== '\0') {
430 c
= (unsigned char)*lbl
++;
432 return lbl
- slbl
- 1;
434 if (lbl
- 1 == slbl
) /* No space at start */
436 if (!(type
& OT_ARRAY
))
438 /* Skip to the next label */
453 if (((c
== '-' || c
== '_') &&
454 !start
&& *lbl
!= ' ' && *lbl
!= '\0') ||
457 if (++len
> NS_MAXLABEL
) {
471 /* At least one valid domain, return it */
479 * Prints a chunk of data to a string.
480 * PS_SHELL goes as it is these days, it's upto the target to validate it.
481 * PS_SAFE has all non ascii and non printables changes to escaped octal.
483 static const char hexchrs
[] = "0123456789abcdef";
485 print_string(char *dst
, size_t len
, int type
, const uint8_t *data
, size_t dl
)
498 if (type
& OT_BINHEX
) {
500 if (len
== 0 || len
== 1) {
504 *dst
++ = hexchrs
[(c
& 0xF0) >> 4];
505 *dst
++ = hexchrs
[(c
& 0x0F)];
511 if (type
& OT_ASCII
&& (!isascii(c
))) {
515 if (!(type
& (OT_ASCII
| OT_RAW
| OT_ESCSTRING
| OT_ESCFILE
)) &&
516 (!isascii(c
) && !isprint(c
)))
521 if ((type
& (OT_ESCSTRING
| OT_ESCFILE
) &&
522 (c
== '\\' || !isascii(c
) || !isprint(c
))) ||
523 (type
& OT_ESCFILE
&& (c
== '/' || c
== ' ')))
528 if (len
== 0 || len
== 1) {
532 *dst
++ = '\\'; *dst
++ = '\\';
544 *dst
++ = (char)(((c
>> 6) & 03) + '0');
545 *dst
++ = (char)(((c
>> 3) & 07) + '0');
546 *dst
++ = (char)(( c
& 07) + '0');
571 /* Now we've printed it, validate the domain */
572 if (type
& OT_DOMAIN
&& !valid_domainname(odst
, type
)) {
579 return (ssize_t
)bytes
;
584 dhcp_optlen(const struct dhcp_opt
*opt
, size_t dl
)
588 if (opt
->type
& OT_ADDRIPV6
)
590 else if (opt
->type
& (OT_INT32
| OT_UINT32
| OT_ADDRIPV4
))
591 sz
= sizeof(uint32_t);
592 else if (opt
->type
& (OT_INT16
| OT_UINT16
))
593 sz
= sizeof(uint16_t);
594 else if (opt
->type
& (OT_INT8
| OT_UINT8
| OT_BITFLAG
))
595 sz
= sizeof(uint8_t);
596 else if (opt
->type
& OT_FLAG
)
599 /* All other types are variable length */
601 if ((size_t)opt
->len
> dl
) {
605 return (ssize_t
)opt
->len
;
614 /* Trim any extra data.
615 * Maybe we need a setting to reject DHCP options with extra data? */
616 if (opt
->type
& OT_ARRAY
)
617 return (ssize_t
)(dl
- (dl
% sz
));
622 print_option(FILE *fp
, const char *prefix
, const struct dhcp_opt
*opt
,
624 const uint8_t *data
, size_t dl
, const char *ifname
)
627 const uint8_t *e
, *t
;
636 /* Ensure a valid length */
637 dl
= (size_t)dhcp_optlen(opt
, dl
);
638 if ((ssize_t
)dl
== -1)
641 if (fgetpos(fp
, &fp_pos
) == -1)
643 if (fprintf(fp
, "%s", prefix
) == -1)
646 /* We printed something, so always goto err from now-on
647 * to terminate the string. */
649 if (fprintf(fp
, "_%s", opt
->var
) == -1)
652 if (fputc('=', fp
) == EOF
)
657 if (opt
->type
& OT_RFC1035
) {
658 char domain
[NS_MAXDNAME
];
660 sl
= decode_rfc1035(domain
, sizeof(domain
), data
, dl
);
665 if (!valid_domainname(domain
, opt
->type
))
667 return efprintf(fp
, "%s", domain
);
671 if (opt
->type
& OT_RFC3361
)
672 return print_rfc3361(fp
, data
, dl
);
674 if (opt
->type
& OT_RFC3442
)
675 return print_rfc3442(fp
, data
, dl
);
678 if (opt
->type
& OT_STRING
) {
681 if (print_string(buf
, sizeof(buf
), opt
->type
, data
, dl
) == -1)
683 return efprintf(fp
, "%s", buf
);
686 if (opt
->type
& OT_FLAG
)
687 return efprintf(fp
, "1");
689 if (opt
->type
& OT_BITFLAG
) {
690 /* bitflags are a string, MSB first, such as ABCDEFGH
691 * where A is 10000000, B is 01000000, etc. */
692 for (l
= 0, sl
= sizeof(opt
->bitflags
) - 1;
693 l
< sizeof(opt
->bitflags
);
696 /* Don't print NULL or 0 flags */
697 if (opt
->bitflags
[l
] != '\0' &&
698 opt
->bitflags
[l
] != '0' &&
701 if (fputc(opt
->bitflags
[l
], fp
) == EOF
)
712 if (fputc(' ', fp
) == EOF
)
715 if (opt
->type
& OT_UINT8
) {
716 if (fprintf(fp
, "%u", *data
) == -1)
719 } else if (opt
->type
& OT_INT8
) {
720 if (fprintf(fp
, "%d", *data
) == -1)
723 } else if (opt
->type
& OT_UINT16
) {
724 memcpy(&u16
, data
, sizeof(u16
));
726 if (fprintf(fp
, "%u", u16
) == -1)
729 } else if (opt
->type
& OT_INT16
) {
730 memcpy(&u16
, data
, sizeof(u16
));
731 s16
= (int16_t)ntohs(u16
);
732 if (fprintf(fp
, "%d", s16
) == -1)
735 } else if (opt
->type
& OT_UINT32
) {
736 memcpy(&u32
, data
, sizeof(u32
));
738 if (fprintf(fp
, "%u", u32
) == -1)
741 } else if (opt
->type
& OT_INT32
) {
742 memcpy(&u32
, data
, sizeof(u32
));
743 s32
= (int32_t)ntohl(u32
);
744 if (fprintf(fp
, "%d", s32
) == -1)
747 } else if (opt
->type
& OT_ADDRIPV4
) {
748 memcpy(&addr
.s_addr
, data
, sizeof(addr
.s_addr
));
749 if (fprintf(fp
, "%s", inet_ntoa(addr
)) == -1)
751 data
+= sizeof(addr
.s_addr
);
752 } else if (opt
->type
& OT_ADDRIPV6
) {
753 char buf
[INET6_ADDRSTRLEN
];
755 if (inet_ntop(AF_INET6
, data
, buf
, sizeof(buf
)) == NULL
)
757 if (fprintf(fp
, "%s", buf
) == -1)
759 if (data
[0] == 0xfe && (data
[1] & 0xc0) == 0x80) {
760 if (fprintf(fp
,"%%%s", ifname
) == -1)
771 if (fputc('\0', fp
) == EOF
)
776 (void)fsetpos(fp
, &fp_pos
);
781 dhcp_set_leasefile(char *leasefile
, size_t len
, int family
,
782 const struct interface
*ifp
)
784 char ssid
[1 + (IF_SSIDLEN
* 4) + 1]; /* - prefix and NUL terminated. */
786 if (ifp
->name
[0] == '\0') {
787 strlcpy(leasefile
, ifp
->ctx
->pidfile
, len
);
802 print_string(ssid
+ 1, sizeof(ssid
) - 1,
804 (const uint8_t *)ifp
->ssid
, ifp
->ssid_len
);
807 return snprintf(leasefile
, len
,
808 family
== AF_INET
? LEASEFILE
: LEASEFILE6
,
813 dhcp_envoption(struct dhcpcd_ctx
*ctx
, FILE *fp
, const char *prefix
,
814 const char *ifname
, struct dhcp_opt
*opt
,
815 const uint8_t *(*dgetopt
)(struct dhcpcd_ctx
*,
816 size_t *, unsigned int *, size_t *,
817 const uint8_t *, size_t, struct dhcp_opt
**),
818 const uint8_t *od
, size_t ol
)
825 struct dhcp_opt
*eopt
, *oopt
;
828 /* If no embedded or encapsulated options, it's easy */
829 if (opt
->embopts_len
== 0 && opt
->encopts_len
== 0) {
830 if (opt
->type
& OT_RESERVED
)
832 if (print_option(fp
, prefix
, opt
, 1, od
, ol
, ifname
) == -1)
833 logerr("%s: %s %d", ifname
, __func__
, opt
->option
);
837 /* Create a new prefix based on the option */
838 if (opt
->type
& OT_INDEX
) {
839 if (asprintf(&pfx
, "%s_%s%d",
840 prefix
, opt
->var
, ++opt
->index
) == -1)
843 if (asprintf(&pfx
, "%s_%s", prefix
, opt
->var
) == -1)
851 /* Embedded options are always processed first as that
852 * is a fixed layout */
853 for (i
= 0, eopt
= opt
->embopts
; i
< opt
->embopts_len
; i
++, eopt
++) {
854 eo
= dhcp_optlen(eopt
, ol
);
856 logerrx("%s: %s %d.%d/%zu: "
857 "malformed embedded option",
858 ifname
, __func__
, opt
->option
,
863 /* An option was expected, but there is no data
865 * This may not be an error as some options like
866 * DHCP FQDN in RFC4702 have a string as the last
867 * option which is optional. */
868 if (ol
!= 0 || !(eopt
->type
& OT_OPTIONAL
))
869 logerrx("%s: %s %d.%d/%zu: "
870 "missing embedded option",
871 ifname
, __func__
, opt
->option
,
875 /* Use the option prefix if the embedded option
877 * This avoids new_fqdn_fqdn which would be silly. */
878 if (!(eopt
->type
& OT_RESERVED
)) {
879 ov
= strcmp(opt
->var
, eopt
->var
);
880 if (print_option(fp
, pfx
, eopt
, ov
, od
, (size_t)eo
,
882 logerr("%s: %s %d.%d/%zu",
884 opt
->option
, eopt
->option
, i
);
890 /* Enumerate our encapsulated options */
891 if (opt
->encopts_len
&& ol
> 0) {
892 /* Zero any option indexes
893 * We assume that referenced encapsulated options are NEVER
894 * recursive as the index order could break. */
895 for (i
= 0, eopt
= opt
->encopts
;
896 i
< opt
->encopts_len
;
900 if (eopt
->type
& OT_OPTION
) {
901 dgetopt(ctx
, NULL
, &eoc
, NULL
, NULL
, 0, &oopt
);
907 while ((eod
= dgetopt(ctx
, &eos
, &eoc
, &eol
, od
, ol
, &oopt
))) {
908 for (i
= 0, eopt
= opt
->encopts
;
909 i
< opt
->encopts_len
;
912 if (eopt
->option
!= eoc
)
914 if (eopt
->type
& OT_OPTION
) {
919 dhcp_envoption(ctx
, fp
, pfx
, ifname
,
920 eopt
->type
& OT_OPTION
? oopt
:eopt
,
933 dhcp_zero_index(struct dhcp_opt
*opt
)
939 for (i
= 0, o
= opt
->embopts
; i
< opt
->embopts_len
; i
++, o
++)
941 for (i
= 0, o
= opt
->encopts
; i
< opt
->encopts_len
; i
++, o
++)
946 dhcp_readfile(struct dhcpcd_ctx
*ctx
, const char *file
, void *data
, size_t len
)
950 if (ctx
->options
& DHCPCD_PRIVSEP
&&
951 !(ctx
->options
& DHCPCD_PRIVSEPROOT
))
952 return ps_root_readfile(ctx
, file
, data
, len
);
957 return readfile(file
, data
, len
);
961 dhcp_writefile(struct dhcpcd_ctx
*ctx
, const char *file
, mode_t mode
,
962 const void *data
, size_t len
)
966 if (ctx
->options
& DHCPCD_PRIVSEP
&&
967 !(ctx
->options
& DHCPCD_PRIVSEPROOT
))
968 return ps_root_writefile(ctx
, file
, mode
, data
, len
);
973 return writefile(file
, mode
, data
, len
);
977 dhcp_filemtime(struct dhcpcd_ctx
*ctx
, const char *file
, time_t *time
)
981 if (ctx
->options
& DHCPCD_PRIVSEP
&&
982 !(ctx
->options
& DHCPCD_PRIVSEPROOT
))
983 return (int)ps_root_filemtime(ctx
, file
, time
);
988 return filemtime(file
, time
);
992 dhcp_unlink(struct dhcpcd_ctx
*ctx
, const char *file
)
996 if (ctx
->options
& DHCPCD_PRIVSEP
&&
997 !(ctx
->options
& DHCPCD_PRIVSEPROOT
))
998 return (int)ps_root_unlink(ctx
, file
);
1003 return unlink(file
);
1007 dhcp_read_hwaddr_aton(struct dhcpcd_ctx
*ctx
, uint8_t **data
, const char *file
)
1013 bytes
= dhcp_readfile(ctx
, file
, buf
, sizeof(buf
));
1014 if (bytes
== -1 || bytes
== sizeof(buf
))
1018 len
= hwaddr_aton(NULL
, buf
);
1021 *data
= malloc(len
);
1024 hwaddr_aton(*data
, buf
);