]>
git.ipfire.org Git - thirdparty/dhcpcd.git/blob - dhcp-common.c
d8028ce74e7a3d9468ffe2939820121fff761dbd
2 * dhcpcd - DHCP client daemon
3 * Copyright (c) 2006-2016 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/utsname.h>
38 #include <arpa/nameser.h> /* after normal includes for sunos */
43 #include "dhcp-common.h"
48 /* Support very old arpa/nameser.h as found in OpenBSD */
50 #define NS_MAXCDNAME MAXCDNAME
51 #define NS_MAXDNAME MAXDNAME
52 #define NS_MAXLABEL MAXLABEL
56 dhcp_get_hostname(char *buf
, size_t buf_len
, const struct if_options
*ifo
)
59 if (ifo
->hostname
[0] == '\0') {
60 if (gethostname(buf
, buf_len
) != 0)
62 buf
[buf_len
- 1] = '\0';
64 strlcpy(buf
, ifo
->hostname
, buf_len
);
66 /* Deny sending of these local hostnames */
67 if (buf
[0] == '\0' || buf
[0] == '.' ||
68 strcmp(buf
, "(none)") == 0 ||
69 strcmp(buf
, "localhost") == 0 ||
70 strncmp(buf
, "localhost.", strlen("localhost.")) == 0)
73 /* Shorten the hostname if required */
74 if (ifo
->options
& DHCPCD_HOSTNAME_SHORT
) {
77 hp
= strchr(buf
, '.');
86 dhcp_print_option_encoding(const struct dhcp_opt
*opt
, int cols
)
94 if (opt
->type
& OT_EMBED
)
96 if (opt
->type
& OT_ENCAP
)
98 if (opt
->type
& OT_INDEX
)
100 if (opt
->type
& OT_ARRAY
)
102 if (opt
->type
& OT_UINT8
)
104 else if (opt
->type
& OT_INT8
)
106 else if (opt
->type
& OT_UINT16
)
108 else if (opt
->type
& OT_INT16
)
110 else if (opt
->type
& OT_UINT32
)
112 else if (opt
->type
& OT_INT32
)
114 else if (opt
->type
& OT_ADDRIPV4
)
115 printf(" ipaddress");
116 else if (opt
->type
& OT_ADDRIPV6
)
117 printf(" ip6address");
118 else if (opt
->type
& OT_FLAG
)
120 else if (opt
->type
& OT_BITFLAG
)
122 else if (opt
->type
& OT_RFC1035
)
124 else if (opt
->type
& OT_DOMAIN
)
126 else if (opt
->type
& OT_ASCII
)
128 else if (opt
->type
& OT_RAW
)
130 else if (opt
->type
& OT_BINHEX
)
132 else if (opt
->type
& OT_STRING
)
134 if (opt
->type
& OT_RFC3361
)
136 if (opt
->type
& OT_RFC3442
)
138 if (opt
->type
& OT_REQUEST
)
140 if (opt
->type
& OT_NOREQ
)
141 printf(" norequest");
146 vivso_find(uint32_t iana_en
, const void *arg
)
148 const struct interface
*ifp
;
150 struct dhcp_opt
*opt
;
153 for (i
= 0, opt
= ifp
->options
->vivso_override
;
154 i
< ifp
->options
->vivso_override_len
;
156 if (opt
->option
== iana_en
)
158 for (i
= 0, opt
= ifp
->ctx
->vivso
;
159 i
< ifp
->ctx
->vivso_len
;
161 if (opt
->option
== iana_en
)
167 dhcp_vendor(char *str
, size_t len
)
173 if (uname(&utn
) != 0)
174 return (ssize_t
)snprintf(str
, len
, "%s-%s",
178 "%s-%s:%s-%s:%s", PACKAGE
, VERSION
,
179 utn
.sysname
, utn
.release
, utn
.machine
);
180 if (l
== -1 || (size_t)(l
+ 1) > len
)
184 l
= if_machinearch(p
, len
);
185 if (l
== -1 || (size_t)(l
+ 1) > len
)
192 make_option_mask(const struct dhcp_opt
*dopts
, size_t dopts_len
,
193 const struct dhcp_opt
*odopts
, size_t odopts_len
,
194 uint8_t *mask
, const char *opts
, int add
)
197 const struct dhcp_opt
*opt
;
204 o
= p
= strdup(opts
);
205 while ((token
= strsep(&p
, ", "))) {
209 for (i
= 0, opt
= odopts
; i
< odopts_len
; i
++, opt
++) {
210 if (opt
->var
== NULL
|| opt
->option
== 0)
211 continue; /* buggy dhcpcd-definitions.conf */
212 if (strcmp(opt
->var
, token
) == 0)
215 n
= (unsigned int)strtou(token
, NULL
, 0,
217 if (e
== 0 && opt
->option
== n
)
224 for (i
= 0, opt
= dopts
; i
< dopts_len
; i
++, opt
++) {
225 if (strcmp(opt
->var
, token
) == 0)
228 n
= (unsigned int)strtou(token
, NULL
, 0,
230 if (e
== 0 && opt
->option
== n
)
237 if (!match
|| !opt
->option
) {
242 if (add
== 2 && !(opt
->type
& OT_ADDRIPV4
)) {
247 if (add
== 1 || add
== 2)
248 add_option_mask(mask
, opt
->option
);
250 del_option_mask(mask
, opt
->option
);
257 encode_rfc1035(const char *src
, uint8_t *dst
)
264 if (src
== NULL
|| *src
== '\0')
271 /* Silence bogus GCC warnings */
277 for (; *src
; src
++) {
281 /* Skip the trailing . */
286 *lp
= (uint8_t)(p
- lp
- 1);
292 *p
++ = (uint8_t)*src
;
297 *lp
= (uint8_t)(p
- lp
- 1);
308 /* Decode an RFC1035 DNS search order option into a space
309 * separated string. Returns length of string (including
310 * terminating zero) or zero on error. out may be NULL
311 * to just determine output length. */
313 decode_rfc1035(char *out
, size_t len
, const uint8_t *p
, size_t pl
)
316 size_t start_len
, l
, count
;
317 const uint8_t *r
, *q
= p
, *e
;
321 if (pl
> NS_MAXCDNAME
) {
334 /* Check we are inside our length again in-case
335 * the name isn't fully qualified (ie, not terminated) */
336 while (q
< e
&& (l
= (size_t)*q
++)) {
338 if (ltype
== 0x80 || ltype
== 0x40) {
339 /* Currently reserved for future use as noted
340 * in RFC1035 4.1.4 as the 10 and 01
345 else if (ltype
== 0xc0) { /* pointer */
352 /* save source of first jump. */
366 /* straightforward name segment, add with '.' */
377 if (l
+ 1 > NS_MAXLABEL
) {
390 /* change last dot to space */
391 if (out
&& out
!= start
)
397 /* change last space to zero terminator */
401 else if (start_len
> 0)
406 /* Don't count the trailing NUL */
408 if (count
> NS_MAXDNAME
) {
412 return (ssize_t
)count
;
415 /* Check for a valid domain name as per RFC1123 with the exception of
416 * allowing - and _ (but not at start or end) as they seem to be widely used. */
418 valid_domainname(char *lbl
, int type
)
422 int start
, len
, errset
;
424 if (lbl
== NULL
|| *lbl
== '\0') {
434 c
= (unsigned char)*lbl
++;
438 if (lbl
- 1 == slbl
) /* No space at start */
440 if (!(type
& OT_ARRAY
))
442 /* Skip to the next label */
457 if (((c
== '-' || c
== '_') &&
458 !start
&& *lbl
!= ' ' && *lbl
!= '\0') ||
461 if (++len
> NS_MAXLABEL
) {
475 /* At least one valid domain, return it */
483 * Prints a chunk of data to a string.
484 * PS_SHELL goes as it is these days, it's upto the target to validate it.
485 * PS_SAFE has all non ascii and non printables changes to escaped octal.
487 static const char hexchrs
[] = "0123456789abcdef";
489 print_string(char *dst
, size_t len
, int type
, const uint8_t *data
, size_t dl
)
502 if (type
& OT_BINHEX
) {
504 if (len
== 0 || len
== 1) {
508 *dst
++ = hexchrs
[(c
& 0xF0) >> 4];
509 *dst
++ = hexchrs
[(c
& 0x0F)];
515 if (type
& OT_ASCII
&& (!isascii(c
))) {
519 if (!(type
& (OT_ASCII
| OT_RAW
| OT_ESCSTRING
| OT_ESCFILE
)) &&
520 (!isascii(c
) && !isprint(c
)))
525 if ((type
& (OT_ESCSTRING
| OT_ESCFILE
) &&
526 (c
== '\\' || !isascii(c
) || !isprint(c
))) ||
527 (type
& OT_ESCFILE
&& (c
== '/' || c
== ' ')))
532 if (len
== 0 || len
== 1) {
536 *dst
++ = '\\'; *dst
++ = '\\';
548 *dst
++ = (char)(((c
>> 6) & 03) + '0');
549 *dst
++ = (char)(((c
>> 3) & 07) + '0');
550 *dst
++ = (char)(( c
& 07) + '0');
575 /* Now we've printed it, validate the domain */
576 if (type
& OT_DOMAIN
&& !valid_domainname(odst
, type
)) {
583 return (ssize_t
)bytes
;
588 dhcp_optlen(const struct dhcp_opt
*opt
, size_t dl
)
592 if (opt
->type
& OT_ADDRIPV6
)
594 else if (opt
->type
& (OT_INT32
| OT_UINT32
| OT_ADDRIPV4
))
595 sz
= sizeof(uint32_t);
596 else if (opt
->type
& (OT_INT16
| OT_UINT16
))
597 sz
= sizeof(uint16_t);
598 else if (opt
->type
& (OT_INT8
| OT_UINT8
| OT_BITFLAG
))
599 sz
= sizeof(uint8_t);
600 else if (opt
->type
& OT_FLAG
)
603 /* All other types are variable length */
605 if ((size_t)opt
->len
> dl
) {
609 return (ssize_t
)opt
->len
;
618 /* Trim any extra data.
619 * Maybe we need a settng to reject DHCP options with extra data? */
620 if (opt
->type
& OT_ARRAY
)
621 return (ssize_t
)(dl
- (dl
% sz
));
625 /* It's possible for DHCPv4 to contain an IPv6 address */
627 ipv6_printaddr(char *s
, size_t sl
, const uint8_t *d
, const char *ifname
)
629 char buf
[INET6_ADDRSTRLEN
];
633 p
= inet_ntop(AF_INET6
, d
, buf
, sizeof(buf
));
638 if (d
[0] == 0xfe && (d
[1] & 0xc0) == 0x80)
639 l
+= 1 + strlen(ifname
);
649 s
+= strlcpy(s
, p
, sl
);
650 if (d
[0] == 0xfe && (d
[1] & 0xc0) == 0x80) {
652 s
+= strlcpy(s
, ifname
, sl
);
659 print_option(char *s
, size_t len
, const struct dhcp_opt
*opt
,
660 const uint8_t *data
, size_t dl
, const char *ifname
)
662 const uint8_t *e
, *t
;
668 ssize_t bytes
= 0, sl
;
672 if (opt
->type
& OT_RFC1035
) {
673 sl
= decode_rfc1035(NULL
, 0, data
, dl
);
674 if (sl
== 0 || sl
== -1)
680 decode_rfc1035(tmp
, l
, data
, dl
);
681 sl
= print_string(s
, len
, opt
->type
, (uint8_t *)tmp
, l
- 1);
687 if (opt
->type
& OT_RFC3361
) {
688 if ((tmp
= decode_rfc3361(data
, dl
)) == NULL
)
691 sl
= print_string(s
, len
, opt
->type
, (uint8_t *)tmp
, l
);
696 if (opt
->type
& OT_RFC3442
)
697 return decode_rfc3442(s
, len
, data
, dl
);
700 if (opt
->type
& OT_STRING
)
701 return print_string(s
, len
, opt
->type
, data
, dl
);
703 if (opt
->type
& OT_FLAG
) {
711 if (opt
->type
& OT_BITFLAG
) {
712 /* bitflags are a string, MSB first, such as ABCDEFGH
713 * where A is 10000000, B is 01000000, etc. */
715 for (l
= 0, sl
= sizeof(opt
->bitflags
) - 1;
716 l
< sizeof(opt
->bitflags
);
719 /* Don't print NULL or 0 flags */
720 if (opt
->bitflags
[l
] != '\0' &&
721 opt
->bitflags
[l
] != '0' &&
725 *s
++ = opt
->bitflags
[l
];
735 if (opt
->type
& OT_UINT8
)
737 else if (opt
->type
& OT_INT8
)
739 else if (opt
->type
& OT_UINT16
) {
742 } else if (opt
->type
& OT_INT16
) {
745 } else if (opt
->type
& OT_UINT32
) {
748 } else if (opt
->type
& OT_INT32
) {
751 } else if (opt
->type
& OT_ADDRIPV4
) {
754 } else if (opt
->type
& OT_ADDRIPV6
) {
760 sl
= ipv6_printaddr(NULL
, 0, data
, ifname
);
762 return l
== 0 ? -1 : (ssize_t
)l
;
771 return (ssize_t
)(l
* dl
);
782 if (opt
->type
& OT_UINT8
) {
783 sl
= snprintf(s
, len
, "%u", *data
);
785 } else if (opt
->type
& OT_INT8
) {
786 sl
= snprintf(s
, len
, "%d", *data
);
788 } else if (opt
->type
& OT_UINT16
) {
789 memcpy(&u16
, data
, sizeof(u16
));
791 sl
= snprintf(s
, len
, "%u", u16
);
793 } else if (opt
->type
& OT_INT16
) {
794 memcpy(&u16
, data
, sizeof(u16
));
795 s16
= (int16_t)ntohs(u16
);
796 sl
= snprintf(s
, len
, "%d", s16
);
798 } else if (opt
->type
& OT_UINT32
) {
799 memcpy(&u32
, data
, sizeof(u32
));
801 sl
= snprintf(s
, len
, "%u", u32
);
803 } else if (opt
->type
& OT_INT32
) {
804 memcpy(&u32
, data
, sizeof(u32
));
805 s32
= (int32_t)ntohl(u32
);
806 sl
= snprintf(s
, len
, "%d", s32
);
808 } else if (opt
->type
& OT_ADDRIPV4
) {
809 memcpy(&addr
.s_addr
, data
, sizeof(addr
.s_addr
));
810 sl
= snprintf(s
, len
, "%s", inet_ntoa(addr
));
811 data
+= sizeof(addr
.s_addr
);
812 } else if (opt
->type
& OT_ADDRIPV6
) {
813 sl
= ipv6_printaddr(s
, len
, data
, ifname
);
820 return bytes
== 0 ? -1 : bytes
;
830 dhcp_set_leasefile(char *leasefile
, size_t len
, int family
,
831 const struct interface
*ifp
)
835 if (ifp
->name
[0] == '\0') {
836 strlcpy(leasefile
, ifp
->ctx
->pidfile
, len
);
851 print_string(ssid
+ 1, sizeof(ssid
) - 1,
853 (const uint8_t *)ifp
->ssid
, ifp
->ssid_len
);
856 return snprintf(leasefile
, len
,
857 family
== AF_INET
? LEASEFILE
: LEASEFILE6
,
862 dhcp_envoption1(char **env
, const char *prefix
,
863 const struct dhcp_opt
*opt
, int vname
, const uint8_t *od
, size_t ol
,
870 /* Ensure a valid length */
871 ol
= (size_t)dhcp_optlen(opt
, ol
);
872 if ((ssize_t
)ol
== -1)
875 len
= print_option(NULL
, 0, opt
, od
, ol
, ifname
);
879 e
= strlen(opt
->var
) + 1;
884 e
+= (size_t)len
+ 2;
887 v
= val
= *env
= malloc(e
);
891 v
+= snprintf(val
, e
, "%s_%s=", prefix
, opt
->var
);
893 v
+= snprintf(val
, e
, "%s=", prefix
);
895 print_option(v
, (size_t)len
+ 1, opt
, od
, ol
, ifname
);
900 dhcp_envoption(struct dhcpcd_ctx
*ctx
, char **env
, const char *prefix
,
901 const char *ifname
, struct dhcp_opt
*opt
,
902 const uint8_t *(*dgetopt
)(struct dhcpcd_ctx
*,
903 size_t *, unsigned int *, size_t *,
904 const uint8_t *, size_t, struct dhcp_opt
**),
905 const uint8_t *od
, size_t ol
)
907 size_t e
, i
, n
, eos
, eol
;
912 struct dhcp_opt
*eopt
, *oopt
;
915 /* If no embedded or encapsulated options, it's easy */
916 if (opt
->embopts_len
== 0 && opt
->encopts_len
== 0) {
917 if (!(opt
->type
& OT_RESERVED
)) {
918 if (dhcp_envoption1(env
== NULL
? NULL
: &env
[0],
919 prefix
, opt
, 1, od
, ol
, ifname
))
922 logger(ctx
, LOG_ERR
, "%s: %s %d: %m",
923 ifname
, __func__
, opt
->option
);
928 /* Create a new prefix based on the option */
930 if (opt
->type
& OT_INDEX
) {
931 if (opt
->index
> 999) {
933 logger(ctx
, LOG_ERR
, "%s: %m", __func__
);
937 e
= strlen(prefix
) + strlen(opt
->var
) + 2 +
938 (opt
->type
& OT_INDEX
? 3 : 0);
941 logger(ctx
, LOG_ERR
, "%s: %m", __func__
);
944 if (opt
->type
& OT_INDEX
)
945 snprintf(pfx
, e
, "%s_%s%d", prefix
,
946 opt
->var
, ++opt
->index
);
948 snprintf(pfx
, e
, "%s_%s", prefix
, opt
->var
);
952 /* Embedded options are always processed first as that
953 * is a fixed layout */
955 for (i
= 0, eopt
= opt
->embopts
; i
< opt
->embopts_len
; i
++, eopt
++) {
956 eo
= dhcp_optlen(eopt
, ol
);
961 "malformed embedded option",
962 ifname
, __func__
, opt
->option
,
967 /* An option was expected, but there is no data
969 * This may not be an error as some options like
970 * DHCP FQDN in RFC4702 have a string as the last
971 * option which is optional. */
973 (ol
!= 0 || !(eopt
->type
& OT_OPTIONAL
)))
975 "%s: %s %d.%d/%zu: missing embedded option",
976 ifname
, __func__
, opt
->option
,
980 /* Use the option prefix if the embedded option
982 * This avoids new_fqdn_fqdn which would be silly. */
983 if (!(eopt
->type
& OT_RESERVED
)) {
984 ov
= strcmp(opt
->var
, eopt
->var
);
985 if (dhcp_envoption1(env
== NULL
? NULL
: &env
[n
],
986 pfx
, eopt
, ov
, od
, (size_t)eo
, ifname
))
988 else if (env
== NULL
)
990 "%s: %s %d.%d/%zu: %m",
992 opt
->option
, eopt
->option
, i
);
998 /* Enumerate our encapsulated options */
999 if (opt
->encopts_len
&& ol
> 0) {
1000 /* Zero any option indexes
1001 * We assume that referenced encapsulated options are NEVER
1002 * recursive as the index order could break. */
1003 for (i
= 0, eopt
= opt
->encopts
;
1004 i
< opt
->encopts_len
;
1008 if (eopt
->type
& OT_OPTION
) {
1009 dgetopt(ctx
, NULL
, &eoc
, NULL
, NULL
, 0, &oopt
);
1015 while ((eod
= dgetopt(ctx
, &eos
, &eoc
, &eol
, od
, ol
, &oopt
))) {
1016 for (i
= 0, eopt
= opt
->encopts
;
1017 i
< opt
->encopts_len
;
1020 if (eopt
->option
== eoc
) {
1021 if (eopt
->type
& OT_OPTION
) {
1026 n
+= dhcp_envoption(ctx
,
1027 env
== NULL
? NULL
: &env
[n
], pfx
,
1029 eopt
->type
& OT_OPTION
? oopt
:eopt
,
1043 /* Return number of options found */
1048 dhcp_zero_index(struct dhcp_opt
*opt
)
1054 for (i
= 0, o
= opt
->embopts
; i
< opt
->embopts_len
; i
++, o
++)
1056 for (i
= 0, o
= opt
->encopts
; i
< opt
->encopts_len
; i
++, o
++)