Print this page
4586 dhcpv6 client id malformed
Reviewed by: Sebastien Roy <sebastien.roy@delphix.com>
Reviewed by: Marcel Telka <marcel@telka.sk>
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/lib/libdhcpagent/common/dhcp_stable.c
+++ new/usr/src/lib/libdhcpagent/common/dhcp_stable.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
↓ open down ↓ |
16 lines elided |
↑ open up ↑ |
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
24 24 * Use is subject to license terms.
25 25 */
26 26
27 -#pragma ident "%Z%%M% %I% %E% SMI"
28 -
29 27 /*
30 28 * This module reads and writes the stable identifier values, DUID and IAID.
31 29 */
32 30
33 31 #include <stdio.h>
34 32 #include <stdlib.h>
35 33 #include <unistd.h>
36 34 #include <string.h>
37 35 #include <limits.h>
38 36 #include <fcntl.h>
39 37 #include <errno.h>
40 38 #include <libdlpi.h>
41 39 #include <uuid/uuid.h>
42 40 #include <sys/types.h>
43 41 #include <sys/stat.h>
44 42 #include <net/if.h>
45 43 #include <netinet/dhcp6.h>
46 44 #include <dhcp_inittab.h>
47 45
48 46 #define DUID_FILE "/etc/dhcp/duid"
49 47 #define IAID_FILE "/etc/dhcp/iaid"
50 48
51 49 struct iaid_ent {
52 50 uint32_t ie_iaid;
53 51 char ie_name[LIFNAMSIZ];
54 52 };
55 53
56 54 /*
57 55 * read_stable_duid(): read the system's stable DUID, if any
58 56 *
59 57 * input: size_t *: pointer to a size_t to return the DUID length
60 58 * output: uchar_t *: the DUID buffer, or NULL on error (and errno is set)
61 59 * note: memory returned is from malloc; caller must free.
62 60 */
63 61
64 62 uchar_t *
65 63 read_stable_duid(size_t *duidlen)
66 64 {
67 65 int fd;
68 66 ssize_t retv;
69 67 struct stat sb;
70 68 uchar_t *duid = NULL;
71 69
72 70 if ((fd = open(DUID_FILE, O_RDONLY)) == -1)
73 71 return (NULL);
74 72 if (fstat(fd, &sb) != -1 && S_ISREG(sb.st_mode) &&
75 73 (duid = malloc(sb.st_size)) != NULL) {
76 74 retv = read(fd, duid, sb.st_size);
77 75 if (retv == sb.st_size) {
78 76 *duidlen = sb.st_size;
79 77 } else {
80 78 free(duid);
81 79 /*
82 80 * Make sure that errno always gets set when something
83 81 * goes wrong.
84 82 */
85 83 if (retv >= 0)
86 84 errno = EINVAL;
87 85 duid = NULL;
88 86 }
89 87 }
90 88 (void) close(fd);
91 89 return (duid);
92 90 }
93 91
94 92 /*
95 93 * write_stable_duid(): write the system's stable DUID.
96 94 *
97 95 * input: const uchar_t *: pointer to the DUID buffer
98 96 * size_t: length of the DUID
99 97 * output: int: 0 on success, -1 on error. errno is set on error.
100 98 */
101 99
102 100 int
103 101 write_stable_duid(const uchar_t *duid, size_t duidlen)
104 102 {
105 103 int fd;
106 104 ssize_t retv;
107 105
108 106 (void) unlink(DUID_FILE);
109 107 if ((fd = open(DUID_FILE, O_WRONLY | O_CREAT, 0644)) == -1)
110 108 return (-1);
111 109 retv = write(fd, duid, duidlen);
112 110 if (retv == duidlen) {
113 111 return (close(fd));
114 112 } else {
115 113 (void) close(fd);
116 114 if (retv >= 0)
117 115 errno = ENOSPC;
118 116 return (-1);
119 117 }
120 118 }
121 119
122 120 /*
123 121 * make_stable_duid(): create a new DUID
124 122 *
125 123 * input: const char *: name of physical interface for reference
126 124 * size_t *: pointer to a size_t to return the DUID length
127 125 * output: uchar_t *: the DUID buffer, or NULL on error (and errno is set)
128 126 * note: memory returned is from malloc; caller must free.
129 127 */
130 128
131 129 uchar_t *
132 130 make_stable_duid(const char *physintf, size_t *duidlen)
133 131 {
134 132 int len;
135 133 dlpi_info_t dlinfo;
↓ open down ↓ |
97 lines elided |
↑ open up ↑ |
136 134 dlpi_handle_t dh = NULL;
137 135 uint_t arptype;
138 136 duid_en_t *den;
139 137
140 138 /*
141 139 * Try to read the MAC layer address for the physical interface
142 140 * provided as a hint. If that works, we can use a DUID-LLT.
143 141 */
144 142
145 143 if (dlpi_open(physintf, &dh, 0) == DLPI_SUCCESS &&
144 + dlpi_bind(dh, DLPI_ANY_SAP, NULL) == DLPI_SUCCESS &&
146 145 dlpi_info(dh, &dlinfo, 0) == DLPI_SUCCESS &&
147 146 (len = dlinfo.di_physaddrlen) > 0 &&
148 147 (arptype = dlpi_arptype(dlinfo.di_mactype) != 0)) {
149 148 duid_llt_t *dllt;
150 149 time_t now;
151 150
152 151 if ((dllt = malloc(sizeof (*dllt) + len)) == NULL) {
153 152 dlpi_close(dh);
154 153 return (NULL);
155 154 }
156 155
157 156 (void) memcpy((dllt + 1), dlinfo.di_physaddr, len);
158 157 dllt->dllt_dutype = htons(DHCPV6_DUID_LLT);
159 158 dllt->dllt_hwtype = htons(arptype);
160 159 now = time(NULL) - DUID_TIME_BASE;
161 160 dllt->dllt_time = htonl(now);
162 161 *duidlen = sizeof (*dllt) + len;
163 162 dlpi_close(dh);
164 163 return ((uchar_t *)dllt);
165 164 }
166 165 if (dh != NULL)
167 166 dlpi_close(dh);
168 167
169 168 /*
170 169 * If we weren't able to create a DUID based on the network interface
171 170 * in use, then generate one based on a UUID.
172 171 */
173 172 den = malloc(sizeof (*den) + UUID_LEN);
174 173 if (den != NULL) {
175 174 uuid_t uuid;
176 175
177 176 den->den_dutype = htons(DHCPV6_DUID_EN);
178 177 DHCPV6_SET_ENTNUM(den, DHCPV6_SUN_ENT);
179 178 uuid_generate(uuid);
180 179 (void) memcpy(den + 1, uuid, UUID_LEN);
181 180 *duidlen = sizeof (*den) + UUID_LEN;
182 181 }
183 182 return ((uchar_t *)den);
184 183 }
185 184
186 185 /*
187 186 * read_stable_iaid(): read a link's stable IAID, if any
188 187 *
189 188 * input: const char *: interface name
190 189 * output: uint32_t: the IAID, or 0 if none
191 190 */
192 191
193 192 uint32_t
194 193 read_stable_iaid(const char *intf)
195 194 {
196 195 int fd;
197 196 struct iaid_ent ie;
198 197
199 198 if ((fd = open(IAID_FILE, O_RDONLY)) == -1)
200 199 return (0);
201 200 while (read(fd, &ie, sizeof (ie)) == sizeof (ie)) {
202 201 if (strcmp(intf, ie.ie_name) == 0) {
203 202 (void) close(fd);
204 203 return (ie.ie_iaid);
205 204 }
206 205 }
207 206 (void) close(fd);
208 207 return (0);
209 208 }
210 209
211 210 /*
212 211 * write_stable_iaid(): write out a link's stable IAID
213 212 *
214 213 * input: const char *: interface name
215 214 * output: uint32_t: the IAID, or 0 if none
216 215 */
217 216
218 217 int
219 218 write_stable_iaid(const char *intf, uint32_t iaid)
220 219 {
221 220 int fd;
222 221 struct iaid_ent ie;
223 222 ssize_t retv;
224 223
225 224 if ((fd = open(IAID_FILE, O_RDWR | O_CREAT, 0644)) == -1)
226 225 return (0);
227 226 while (read(fd, &ie, sizeof (ie)) == sizeof (ie)) {
228 227 if (strcmp(intf, ie.ie_name) == 0) {
229 228 (void) close(fd);
230 229 if (iaid == ie.ie_iaid) {
231 230 return (0);
232 231 } else {
233 232 errno = EINVAL;
234 233 return (-1);
235 234 }
236 235 }
237 236 }
238 237 (void) memset(&ie, 0, sizeof (ie));
239 238 ie.ie_iaid = iaid;
240 239 (void) strlcpy(ie.ie_name, intf, sizeof (ie.ie_name));
241 240 retv = write(fd, &ie, sizeof (ie));
242 241 (void) close(fd);
243 242 if (retv == sizeof (ie)) {
244 243 return (0);
245 244 } else {
246 245 if (retv >= 0)
247 246 errno = ENOSPC;
248 247 return (-1);
249 248 }
250 249 }
251 250
252 251 /*
253 252 * make_stable_iaid(): create a stable IAID for a link
254 253 *
255 254 * input: const char *: interface name
256 255 * uint32_t: the ifIndex for this link (as a "hint")
257 256 * output: uint32_t: the new IAID, never zero
258 257 */
259 258
260 259 /* ARGSUSED */
261 260 uint32_t
262 261 make_stable_iaid(const char *intf, uint32_t hint)
263 262 {
264 263 int fd;
265 264 struct iaid_ent ie;
266 265 uint32_t maxid, minunused;
267 266 boolean_t recheck;
268 267
269 268 if ((fd = open(IAID_FILE, O_RDONLY)) == -1)
270 269 return (hint);
271 270 maxid = 0;
272 271 minunused = 1;
273 272 /*
274 273 * This logic is deliberately unoptimized. The reason is that it runs
275 274 * essentially just once per interface for the life of the system.
276 275 * Once the IAID is established, there's no reason to generate it
277 276 * again, and all we care about here is correctness. Also, IAIDs tend
278 277 * to get added in a logical sequence order, so the outer loop should
279 278 * not normally run more than twice.
280 279 */
281 280 do {
282 281 recheck = B_FALSE;
283 282 while (read(fd, &ie, sizeof (ie)) == sizeof (ie)) {
284 283 if (ie.ie_iaid > maxid)
285 284 maxid = ie.ie_iaid;
286 285 if (ie.ie_iaid == minunused) {
287 286 recheck = B_TRUE;
288 287 minunused++;
289 288 }
290 289 if (ie.ie_iaid == hint)
291 290 hint = 0;
292 291 }
293 292 if (recheck)
294 293 (void) lseek(fd, 0, SEEK_SET);
295 294 } while (recheck);
296 295 (void) close(fd);
297 296 if (hint != 0)
298 297 return (hint);
299 298 else if (maxid != UINT32_MAX)
300 299 return (maxid + 1);
301 300 else
302 301 return (minunused);
303 302 }
↓ open down ↓ |
148 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX