2 __RCSID("$NetBSD: duid.c,v 1.9 2015/07/09 10:15:34 roy Exp $");
5 * dhcpcd - DHCP client daemon
6 * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 #define DUID_TIME_EPOCH 946684800
35 #include <sys/socket.h>
36 #include <sys/types.h>
39 #include <net/if_arp.h>
49 # define ARPHRD_NETROM 0
57 duid_make(unsigned char *d
, const struct interface
*ifp
, uint16_t type
)
68 u16
= htons(ifp
->family
);
71 if (type
== DUID_LLT
) {
72 /* time returns seconds from jan 1 1970, but DUID-LLT is
73 * seconds from jan 1 2000 modulo 2^32 */
74 t
= time(NULL
) - DUID_TIME_EPOCH
;
75 u32
= htonl((uint32_t)t
& 0xffffffff);
79 /* Finally, add the MAC address of the interface */
80 memcpy(p
, ifp
->hwaddr
, ifp
->hwlen
);
82 return (size_t)(p
- d
);
85 #define DUID_STRLEN DUID_LEN * 3
87 duid_get(unsigned char *d
, const struct interface
*ifp
)
92 char line
[DUID_STRLEN
];
93 const struct interface
*ifp2
;
95 /* If we already have a DUID then use it as it's never supposed
96 * to change once we have one even if the interfaces do */
97 if ((fp
= fopen(DUID
, "r"))) {
98 while (fgets(line
, DUID_STRLEN
, fp
)) {
101 if (line
[len
- 1] == '\n')
102 line
[len
- 1] = '\0';
104 len
= hwaddr_aton(NULL
, line
);
105 if (len
&& len
<= DUID_LEN
) {
106 hwaddr_aton(d
, line
);
116 logger(ifp
->ctx
, LOG_ERR
,
117 "error reading DUID: %s: %m", DUID
);
120 /* No file? OK, lets make one based on our interface */
121 if (ifp
->family
== ARPHRD_NETROM
) {
122 logger(ifp
->ctx
, LOG_WARNING
,
123 "%s: is a NET/ROM psuedo interface", ifp
->name
);
124 TAILQ_FOREACH(ifp2
, ifp
->ctx
->ifaces
, next
) {
125 if (ifp2
->family
!= ARPHRD_NETROM
)
130 logger(ifp
->ctx
, LOG_WARNING
,
131 "picked interface %s to generate a DUID",
134 logger(ifp
->ctx
, LOG_WARNING
,
135 "no interfaces have a fixed hardware address");
136 return duid_make(d
, ifp
, DUID_LL
);
140 if (!(fp
= fopen(DUID
, "w"))) {
141 logger(ifp
->ctx
, LOG_ERR
, "error writing DUID: %s: %m", DUID
);
142 return duid_make(d
, ifp
, DUID_LL
);
144 len
= duid_make(d
, ifp
, DUID_LLT
);
145 x
= fprintf(fp
, "%s\n", hwaddr_ntoa(d
, len
, line
, sizeof(line
)));
146 if (fclose(fp
) == EOF
)
148 /* Failed to write the duid? scrub it, we cannot use it */
150 logger(ifp
->ctx
, LOG_ERR
, "error writing DUID: %s: %m", DUID
);
152 return duid_make(d
, ifp
, DUID_LL
);
157 size_t duid_init(const struct interface
*ifp
)
160 if (ifp
->ctx
->duid
== NULL
) {
161 ifp
->ctx
->duid
= malloc(DUID_LEN
);
162 if (ifp
->ctx
->duid
== NULL
) {
163 logger(ifp
->ctx
, LOG_ERR
, "%s: %m", __func__
);
166 ifp
->ctx
->duid_len
= duid_get(ifp
->ctx
->duid
, ifp
);
168 return ifp
->ctx
->duid_len
;