dhcp_hostconf.c (7c478bd9) dhcp_hostconf.c (d04ccbb3)
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22/*
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27#pragma ident "%Z%%M% %I% %E% SMI"
28
29#include <stdio.h>
30#include <stdlib.h>
31#include <unistd.h>

--- 6 unchanged lines hidden (view full) ---

38#include <time.h>
39#include <string.h> /* memcpy */
40#include <fcntl.h>
41#include <limits.h>
42
43#include "dhcp_hostconf.h"
44
45static void relativize_time(DHCP_OPT *, time_t, time_t);
23 * Use is subject to license terms.
24 */
25
26#pragma ident "%Z%%M% %I% %E% SMI"
27
28#include <stdio.h>
29#include <stdlib.h>
30#include <unistd.h>

--- 6 unchanged lines hidden (view full) ---

37#include <time.h>
38#include <string.h> /* memcpy */
39#include <fcntl.h>
40#include <limits.h>
41
42#include "dhcp_hostconf.h"
43
44static void relativize_time(DHCP_OPT *, time_t, time_t);
45static void relativize_v6(uint32_t *, time_t, time_t);
46
47/*
48 * ifname_to_hostconf(): converts an interface name into a hostconf file for
49 * that interface
50 *
51 * input: const char *: the interface name
46
47/*
48 * ifname_to_hostconf(): converts an interface name into a hostconf file for
49 * that interface
50 *
51 * input: const char *: the interface name
52 * boolean_t: B_TRUE if using DHCPv6
52 * output: char *: the hostconf filename
53 * note: uses an internal static buffer (not threadsafe)
54 */
55
56char *
53 * output: char *: the hostconf filename
54 * note: uses an internal static buffer (not threadsafe)
55 */
56
57char *
57ifname_to_hostconf(const char *ifname)
58ifname_to_hostconf(const char *ifname, boolean_t isv6)
58{
59{
59 static char filename[sizeof (DHCP_HOSTCONF_TMPL) + IFNAMSIZ];
60 static char filename[sizeof (DHCP_HOSTCONF_TMPL6) + LIFNAMSIZ];
60
61 (void) snprintf(filename, sizeof (filename), "%s%s%s",
61
62 (void) snprintf(filename, sizeof (filename), "%s%s%s",
62 DHCP_HOSTCONF_PREFIX, ifname, DHCP_HOSTCONF_SUFFIX);
63 DHCP_HOSTCONF_PREFIX, ifname,
64 isv6 ? DHCP_HOSTCONF_SUFFIX6 : DHCP_HOSTCONF_SUFFIX);
63
64 return (filename);
65}
66
67/*
68 * remove_hostconf(): removes an interface.dhc file
69 *
70 * input: const char *: the interface name
65
66 return (filename);
67}
68
69/*
70 * remove_hostconf(): removes an interface.dhc file
71 *
72 * input: const char *: the interface name
73 * boolean_t: B_TRUE if using DHCPv6
71 * output: int: 0 if the file is removed, -1 if it can't be removed
72 * (errno is set)
73 */
74
75int
74 * output: int: 0 if the file is removed, -1 if it can't be removed
75 * (errno is set)
76 */
77
78int
76remove_hostconf(const char *ifname)
79remove_hostconf(const char *ifname, boolean_t isv6)
77{
80{
78 return (unlink(ifname_to_hostconf(ifname)));
81 return (unlink(ifname_to_hostconf(ifname, isv6)));
79}
80
81/*
82 * read_hostconf(): reads the contents of an <if>.dhc file into a PKT_LIST
83 *
84 * input: const char *: the interface name
85 * PKT_LIST **: a pointer to a PKT_LIST * to store the info in
86 * uint_t: the length of the list of PKT_LISTs
82}
83
84/*
85 * read_hostconf(): reads the contents of an <if>.dhc file into a PKT_LIST
86 *
87 * input: const char *: the interface name
88 * PKT_LIST **: a pointer to a PKT_LIST * to store the info in
89 * uint_t: the length of the list of PKT_LISTs
87 * output: int: 0 if the file is read and loaded into the PKT_LIST *
90 * boolean_t: B_TRUE if using DHCPv6
91 * output: int: >0 if the file is read and loaded into the PKT_LIST *
88 * successfully, -1 otherwise (errno is set)
89 * note: the PKT and PKT_LISTs are dynamically allocated here
90 */
91
92int
92 * successfully, -1 otherwise (errno is set)
93 * note: the PKT and PKT_LISTs are dynamically allocated here
94 */
95
96int
93read_hostconf(const char *ifname, PKT_LIST **plpp, uint_t plplen)
97read_hostconf(const char *ifname, PKT_LIST **plpp, uint_t plplen,
98 boolean_t isv6)
94{
95 PKT_LIST *plp = NULL;
96 PKT *pkt = NULL;
97 int fd;
98 time_t orig_time, current_time = time(NULL);
99 uint32_t lease;
100 uint32_t magic;
101 int pcnt = 0;
102 int retval;
103
99{
100 PKT_LIST *plp = NULL;
101 PKT *pkt = NULL;
102 int fd;
103 time_t orig_time, current_time = time(NULL);
104 uint32_t lease;
105 uint32_t magic;
106 int pcnt = 0;
107 int retval;
108
104 fd = open(ifname_to_hostconf(ifname), O_RDONLY);
109 fd = open(ifname_to_hostconf(ifname, isv6), O_RDONLY);
105 if (fd == -1)
106 return (-1);
107
108 if (read(fd, &magic, sizeof (magic)) != sizeof (magic))
109 goto failure;
110
110 if (fd == -1)
111 return (-1);
112
113 if (read(fd, &magic, sizeof (magic)) != sizeof (magic))
114 goto failure;
115
111 if (magic != DHCP_HOSTCONF_MAGIC)
116 if (magic != (isv6 ? DHCP_HOSTCONF_MAGIC6 : DHCP_HOSTCONF_MAGIC))
112 goto failure;
113
114 if (read(fd, &orig_time, sizeof (orig_time)) != sizeof (orig_time))
115 goto failure;
116
117 /*
117 goto failure;
118
119 if (read(fd, &orig_time, sizeof (orig_time)) != sizeof (orig_time))
120 goto failure;
121
122 /*
118 * read the packet back in from disk, and run it through
119 * dhcp_options_scan(). note that we use calloc() since
120 * dhcp_options_scan() relies on the packet being zeroed.
123 * read the packet back in from disk, and for v4, run it through
124 * dhcp_options_scan(). note that we use calloc() because
125 * dhcp_options_scan() relies on the structure being zeroed.
121 */
122
123 for (pcnt = 0; pcnt < plplen; pcnt++) {
124
125 plp = NULL;
126 pkt = NULL;
127
128 if ((plp = calloc(1, sizeof (PKT_LIST))) == NULL)

--- 17 unchanged lines hidden (view full) ---

146
147 if (read(fd, pkt, plp->len) != plp->len)
148 goto failure;
149
150 plp->pkt = pkt;
151
152 plpp[pcnt] = plp;
153
126 */
127
128 for (pcnt = 0; pcnt < plplen; pcnt++) {
129
130 plp = NULL;
131 pkt = NULL;
132
133 if ((plp = calloc(1, sizeof (PKT_LIST))) == NULL)

--- 17 unchanged lines hidden (view full) ---

151
152 if (read(fd, pkt, plp->len) != plp->len)
153 goto failure;
154
155 plp->pkt = pkt;
156
157 plpp[pcnt] = plp;
158
154 if (dhcp_options_scan(plp, B_TRUE) != 0)
159 if (!isv6 && dhcp_options_scan(plp, B_TRUE) != 0)
155 goto failure;
156
157 /*
158 * First packet used to validate that we're interested,
159 * the rest are presumed to be historical reference and
160 * are not relativized
161 */
162 if (pcnt == 0)
163 continue;
164
160 goto failure;
161
162 /*
163 * First packet used to validate that we're interested,
164 * the rest are presumed to be historical reference and
165 * are not relativized
166 */
167 if (pcnt == 0)
168 continue;
169
165 /*
166 * make sure the lease is still valid.
167 */
170 if (isv6) {
171 dhcpv6_option_t d6o;
172 dhcpv6_ia_na_t d6in;
173 dhcpv6_iaaddr_t d6ia;
174 uchar_t *opts, *optmax, *subomax;
168
175
169 if (plp->opts[CD_LEASE_TIME] != NULL &&
170 plp->opts[CD_LEASE_TIME]->len == sizeof (lease_t)) {
176 /*
177 * Loop over contents of the packet to find the address
178 * options.
179 */
180 opts = (uchar_t *)pkt + sizeof (dhcpv6_message_t);
181 optmax = (uchar_t *)pkt + plp->len;
182 while (opts + sizeof (d6o) <= optmax) {
171
183
172 (void) memcpy(&lease, plp->opts[CD_LEASE_TIME]->value,
173 sizeof (lease_t));
184 /*
185 * Extract option header and make sure option
186 * is intact.
187 */
188 (void) memcpy(&d6o, opts, sizeof (d6o));
189 d6o.d6o_code = ntohs(d6o.d6o_code);
190 d6o.d6o_len = ntohs(d6o.d6o_len);
191 subomax = opts + sizeof (d6o) + d6o.d6o_len;
192 if (subomax > optmax)
193 break;
174
194
175 lease = ntohl(lease);
176 if ((lease != DHCP_PERM) &&
177 (orig_time + lease) <= current_time)
178 goto failure;
179 }
195 /*
196 * If this isn't an option that contains
197 * address or prefix leases, then skip over it.
198 */
199 if (d6o.d6o_code != DHCPV6_OPT_IA_NA &&
200 d6o.d6o_code != DHCPV6_OPT_IA_TA &&
201 d6o.d6o_code != DHCPV6_OPT_IA_PD) {
202 opts = subomax;
203 continue;
204 }
180
205
181 relativize_time(plp->opts[CD_T1_TIME], orig_time, current_time);
182 relativize_time(plp->opts[CD_T2_TIME], orig_time, current_time);
183 relativize_time(plp->opts[CD_LEASE_TIME], orig_time,
184 current_time);
206 /*
207 * Handle the option first.
208 */
209 if (d6o.d6o_code == DHCPV6_OPT_IA_TA) {
210 /* no timers in this structure */
211 opts += sizeof (dhcpv6_ia_ta_t);
212 } else {
213 /* both na and pd */
214 if (opts + sizeof (d6in) > subomax) {
215 opts = subomax;
216 continue;
217 }
218 (void) memcpy(&d6in, opts,
219 sizeof (d6in));
220 relativize_v6(&d6in.d6in_t1, orig_time,
221 current_time);
222 relativize_v6(&d6in.d6in_t2, orig_time,
223 current_time);
224 (void) memcpy(opts, &d6in,
225 sizeof (d6in));
226 opts += sizeof (d6in);
227 }
228
229 /*
230 * Now handle each suboption (address) inside.
231 */
232 while (opts + sizeof (d6o) <= subomax) {
233 /*
234 * Verify the suboption header first.
235 */
236 (void) memcpy(&d6o, opts,
237 sizeof (d6o));
238 d6o.d6o_code = ntohs(d6o.d6o_code);
239 d6o.d6o_len = ntohs(d6o.d6o_len);
240 if (opts + sizeof (d6o) + d6o.d6o_len >
241 subomax)
242 break;
243 if (d6o.d6o_code != DHCPV6_OPT_IAADDR) {
244 opts += sizeof (d6o) +
245 d6o.d6o_len;
246 continue;
247 }
248
249 /*
250 * Now process the contents.
251 */
252 if (opts + sizeof (d6ia) > subomax)
253 break;
254 (void) memcpy(&d6ia, opts,
255 sizeof (d6ia));
256 relativize_v6(&d6ia.d6ia_preflife,
257 orig_time, current_time);
258 relativize_v6(&d6ia.d6ia_vallife,
259 orig_time, current_time);
260 (void) memcpy(opts, &d6ia,
261 sizeof (d6ia));
262 opts += sizeof (d6o) + d6o.d6o_len;
263 }
264 opts = subomax;
265 }
266 } else {
267
268 /*
269 * make sure the IPv4 DHCP lease is still valid.
270 */
271
272 if (plp->opts[CD_LEASE_TIME] != NULL &&
273 plp->opts[CD_LEASE_TIME]->len ==
274 sizeof (lease_t)) {
275
276 (void) memcpy(&lease,
277 plp->opts[CD_LEASE_TIME]->value,
278 sizeof (lease_t));
279
280 lease = ntohl(lease);
281 if ((lease != DHCP_PERM) &&
282 (orig_time + lease) <= current_time)
283 goto failure;
284 }
285
286 relativize_time(plp->opts[CD_T1_TIME], orig_time,
287 current_time);
288 relativize_time(plp->opts[CD_T2_TIME], orig_time,
289 current_time);
290 relativize_time(plp->opts[CD_LEASE_TIME], orig_time,
291 current_time);
292 }
185 }
186
187 (void) close(fd);
188 return (pcnt);
189
190failure:
191 free(pkt);
192 free(plp);

--- 5 unchanged lines hidden (view full) ---

198 return (-1);
199}
200
201/*
202 * write_hostconf(): writes the contents of a PKT_LIST into an <if>.dhc file
203 *
204 * input: const char *: the interface name
205 * PKT_LIST **: a list of pointers to PKT_LIST to write
293 }
294
295 (void) close(fd);
296 return (pcnt);
297
298failure:
299 free(pkt);
300 free(plp);

--- 5 unchanged lines hidden (view full) ---

306 return (-1);
307}
308
309/*
310 * write_hostconf(): writes the contents of a PKT_LIST into an <if>.dhc file
311 *
312 * input: const char *: the interface name
313 * PKT_LIST **: a list of pointers to PKT_LIST to write
206 * int: length of the list of PKT_LIST pointers
314 * uint_t: length of the list of PKT_LIST pointers
207 * time_t: a starting time to treat the relative lease times
208 * in the first packet as relative to
315 * time_t: a starting time to treat the relative lease times
316 * in the first packet as relative to
317 * boolean_t: B_TRUE if using DHCPv6
209 * output: int: 0 if the file is written successfully, -1 otherwise
210 * (errno is set)
211 */
212
213int
214write_hostconf(
215 const char *ifname,
216 PKT_LIST *pl[],
217 uint_t pllen,
318 * output: int: 0 if the file is written successfully, -1 otherwise
319 * (errno is set)
320 */
321
322int
323write_hostconf(
324 const char *ifname,
325 PKT_LIST *pl[],
326 uint_t pllen,
218 time_t relative_to)
327 time_t relative_to,
328 boolean_t isv6)
219{
220 int fd;
221 struct iovec iov[IOV_MAX];
222 int retval;
329{
330 int fd;
331 struct iovec iov[IOV_MAX];
332 int retval;
223 uint32_t magic = DHCP_HOSTCONF_MAGIC;
333 uint32_t magic;
224 ssize_t explen = 0; /* Expected length of write */
225 int i, iovlen = 0;
226
334 ssize_t explen = 0; /* Expected length of write */
335 int i, iovlen = 0;
336
227 fd = open(ifname_to_hostconf(ifname), O_WRONLY|O_CREAT|O_TRUNC, 0600);
337 fd = open(ifname_to_hostconf(ifname, isv6), O_WRONLY|O_CREAT|O_TRUNC,
338 0600);
228 if (fd == -1)
229 return (-1);
230
231 /*
232 * first write our magic number, then the relative time of the
233 * leases, then for each packet we write the length of the packet
234 * followed by the packet. we will then use the relative time in
235 * read_hostconf() to recalculate the lease times for the first packet.
236 */
237
339 if (fd == -1)
340 return (-1);
341
342 /*
343 * first write our magic number, then the relative time of the
344 * leases, then for each packet we write the length of the packet
345 * followed by the packet. we will then use the relative time in
346 * read_hostconf() to recalculate the lease times for the first packet.
347 */
348
349 magic = isv6 ? DHCP_HOSTCONF_MAGIC6 : DHCP_HOSTCONF_MAGIC;
238 iov[iovlen].iov_base = (caddr_t)&magic;
239 explen += iov[iovlen++].iov_len = sizeof (magic);
240 iov[iovlen].iov_base = (caddr_t)&relative_to;
241 explen += iov[iovlen++].iov_len = sizeof (relative_to);
242 for (i = 0; i < pllen && iovlen < (IOV_MAX - 1); i++) {
243 iov[iovlen].iov_base = (caddr_t)&pl[i]->len;
244 explen += iov[iovlen++].iov_len = sizeof (pl[i]->len);
245 iov[iovlen].iov_base = (caddr_t)pl[i]->pkt;

--- 29 unchanged lines hidden (view full) ---

275 return;
276
277 (void) memcpy(&pkt_time, option->value, option->len);
278 if (ntohl(pkt_time) != DHCP_PERM)
279 pkt_time = htonl(ntohl(pkt_time) - time_diff);
280
281 (void) memcpy(option->value, &pkt_time, option->len);
282}
350 iov[iovlen].iov_base = (caddr_t)&magic;
351 explen += iov[iovlen++].iov_len = sizeof (magic);
352 iov[iovlen].iov_base = (caddr_t)&relative_to;
353 explen += iov[iovlen++].iov_len = sizeof (relative_to);
354 for (i = 0; i < pllen && iovlen < (IOV_MAX - 1); i++) {
355 iov[iovlen].iov_base = (caddr_t)&pl[i]->len;
356 explen += iov[iovlen++].iov_len = sizeof (pl[i]->len);
357 iov[iovlen].iov_base = (caddr_t)pl[i]->pkt;

--- 29 unchanged lines hidden (view full) ---

387 return;
388
389 (void) memcpy(&pkt_time, option->value, option->len);
390 if (ntohl(pkt_time) != DHCP_PERM)
391 pkt_time = htonl(ntohl(pkt_time) - time_diff);
392
393 (void) memcpy(option->value, &pkt_time, option->len);
394}
395
396/*
397 * relativize_v6(): re-relativizes a time in a DHCPv6 option
398 *
399 * input: uint32_t *: the time value to convert
400 * time_t: the time the leases in the packet are currently relative to
401 * time_t: the current time which leases will become relative to
402 * output: void
403 */
404
405static void
406relativize_v6(uint32_t *val, time_t orig_time, time_t current_time)
407{
408 uint32_t hval;
409 time_t time_diff = current_time - orig_time;
410
411 hval = ntohl(*val);
412 if (hval != DHCPV6_INFTIME) {
413 if (hval < time_diff)
414 *val = 0;
415 else
416 *val = htonl(hval - time_diff);
417 }
418}