diff options
Diffstat (limited to 'usr/src/lib/libdhcpagent/common/dhcp_hostconf.c')
| -rw-r--r-- | usr/src/lib/libdhcpagent/common/dhcp_hostconf.c | 210 |
1 files changed, 173 insertions, 37 deletions
diff --git a/usr/src/lib/libdhcpagent/common/dhcp_hostconf.c b/usr/src/lib/libdhcpagent/common/dhcp_hostconf.c index 49a8b09723..49fa6a8f38 100644 --- a/usr/src/lib/libdhcpagent/common/dhcp_hostconf.c +++ b/usr/src/lib/libdhcpagent/common/dhcp_hostconf.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -43,23 +42,26 @@ #include "dhcp_hostconf.h" static void relativize_time(DHCP_OPT *, time_t, time_t); +static void relativize_v6(uint32_t *, time_t, time_t); /* * ifname_to_hostconf(): converts an interface name into a hostconf file for * that interface * * input: const char *: the interface name + * boolean_t: B_TRUE if using DHCPv6 * output: char *: the hostconf filename * note: uses an internal static buffer (not threadsafe) */ char * -ifname_to_hostconf(const char *ifname) +ifname_to_hostconf(const char *ifname, boolean_t isv6) { - static char filename[sizeof (DHCP_HOSTCONF_TMPL) + IFNAMSIZ]; + static char filename[sizeof (DHCP_HOSTCONF_TMPL6) + LIFNAMSIZ]; (void) snprintf(filename, sizeof (filename), "%s%s%s", - DHCP_HOSTCONF_PREFIX, ifname, DHCP_HOSTCONF_SUFFIX); + DHCP_HOSTCONF_PREFIX, ifname, + isv6 ? DHCP_HOSTCONF_SUFFIX6 : DHCP_HOSTCONF_SUFFIX); return (filename); } @@ -68,14 +70,15 @@ ifname_to_hostconf(const char *ifname) * remove_hostconf(): removes an interface.dhc file * * input: const char *: the interface name + * boolean_t: B_TRUE if using DHCPv6 * output: int: 0 if the file is removed, -1 if it can't be removed * (errno is set) */ int -remove_hostconf(const char *ifname) +remove_hostconf(const char *ifname, boolean_t isv6) { - return (unlink(ifname_to_hostconf(ifname))); + return (unlink(ifname_to_hostconf(ifname, isv6))); } /* @@ -84,13 +87,15 @@ remove_hostconf(const char *ifname) * input: const char *: the interface name * PKT_LIST **: a pointer to a PKT_LIST * to store the info in * uint_t: the length of the list of PKT_LISTs - * output: int: 0 if the file is read and loaded into the PKT_LIST * + * boolean_t: B_TRUE if using DHCPv6 + * output: int: >0 if the file is read and loaded into the PKT_LIST * * successfully, -1 otherwise (errno is set) * note: the PKT and PKT_LISTs are dynamically allocated here */ int -read_hostconf(const char *ifname, PKT_LIST **plpp, uint_t plplen) +read_hostconf(const char *ifname, PKT_LIST **plpp, uint_t plplen, + boolean_t isv6) { PKT_LIST *plp = NULL; PKT *pkt = NULL; @@ -101,23 +106,23 @@ read_hostconf(const char *ifname, PKT_LIST **plpp, uint_t plplen) int pcnt = 0; int retval; - fd = open(ifname_to_hostconf(ifname), O_RDONLY); + fd = open(ifname_to_hostconf(ifname, isv6), O_RDONLY); if (fd == -1) return (-1); if (read(fd, &magic, sizeof (magic)) != sizeof (magic)) goto failure; - if (magic != DHCP_HOSTCONF_MAGIC) + if (magic != (isv6 ? DHCP_HOSTCONF_MAGIC6 : DHCP_HOSTCONF_MAGIC)) goto failure; if (read(fd, &orig_time, sizeof (orig_time)) != sizeof (orig_time)) goto failure; /* - * read the packet back in from disk, and run it through - * dhcp_options_scan(). note that we use calloc() since - * dhcp_options_scan() relies on the packet being zeroed. + * read the packet back in from disk, and for v4, run it through + * dhcp_options_scan(). note that we use calloc() because + * dhcp_options_scan() relies on the structure being zeroed. */ for (pcnt = 0; pcnt < plplen; pcnt++) { @@ -151,7 +156,7 @@ read_hostconf(const char *ifname, PKT_LIST **plpp, uint_t plplen) plpp[pcnt] = plp; - if (dhcp_options_scan(plp, B_TRUE) != 0) + if (!isv6 && dhcp_options_scan(plp, B_TRUE) != 0) goto failure; /* @@ -162,26 +167,129 @@ read_hostconf(const char *ifname, PKT_LIST **plpp, uint_t plplen) if (pcnt == 0) continue; - /* - * make sure the lease is still valid. - */ + if (isv6) { + dhcpv6_option_t d6o; + dhcpv6_ia_na_t d6in; + dhcpv6_iaaddr_t d6ia; + uchar_t *opts, *optmax, *subomax; - if (plp->opts[CD_LEASE_TIME] != NULL && - plp->opts[CD_LEASE_TIME]->len == sizeof (lease_t)) { + /* + * Loop over contents of the packet to find the address + * options. + */ + opts = (uchar_t *)pkt + sizeof (dhcpv6_message_t); + optmax = (uchar_t *)pkt + plp->len; + while (opts + sizeof (d6o) <= optmax) { + + /* + * Extract option header and make sure option + * is intact. + */ + (void) memcpy(&d6o, opts, sizeof (d6o)); + d6o.d6o_code = ntohs(d6o.d6o_code); + d6o.d6o_len = ntohs(d6o.d6o_len); + subomax = opts + sizeof (d6o) + d6o.d6o_len; + if (subomax > optmax) + break; + + /* + * If this isn't an option that contains + * address or prefix leases, then skip over it. + */ + if (d6o.d6o_code != DHCPV6_OPT_IA_NA && + d6o.d6o_code != DHCPV6_OPT_IA_TA && + d6o.d6o_code != DHCPV6_OPT_IA_PD) { + opts = subomax; + continue; + } + + /* + * Handle the option first. + */ + if (d6o.d6o_code == DHCPV6_OPT_IA_TA) { + /* no timers in this structure */ + opts += sizeof (dhcpv6_ia_ta_t); + } else { + /* both na and pd */ + if (opts + sizeof (d6in) > subomax) { + opts = subomax; + continue; + } + (void) memcpy(&d6in, opts, + sizeof (d6in)); + relativize_v6(&d6in.d6in_t1, orig_time, + current_time); + relativize_v6(&d6in.d6in_t2, orig_time, + current_time); + (void) memcpy(opts, &d6in, + sizeof (d6in)); + opts += sizeof (d6in); + } + + /* + * Now handle each suboption (address) inside. + */ + while (opts + sizeof (d6o) <= subomax) { + /* + * Verify the suboption header first. + */ + (void) memcpy(&d6o, opts, + sizeof (d6o)); + d6o.d6o_code = ntohs(d6o.d6o_code); + d6o.d6o_len = ntohs(d6o.d6o_len); + if (opts + sizeof (d6o) + d6o.d6o_len > + subomax) + break; + if (d6o.d6o_code != DHCPV6_OPT_IAADDR) { + opts += sizeof (d6o) + + d6o.d6o_len; + continue; + } + + /* + * Now process the contents. + */ + if (opts + sizeof (d6ia) > subomax) + break; + (void) memcpy(&d6ia, opts, + sizeof (d6ia)); + relativize_v6(&d6ia.d6ia_preflife, + orig_time, current_time); + relativize_v6(&d6ia.d6ia_vallife, + orig_time, current_time); + (void) memcpy(opts, &d6ia, + sizeof (d6ia)); + opts += sizeof (d6o) + d6o.d6o_len; + } + opts = subomax; + } + } else { - (void) memcpy(&lease, plp->opts[CD_LEASE_TIME]->value, - sizeof (lease_t)); + /* + * make sure the IPv4 DHCP lease is still valid. + */ - lease = ntohl(lease); - if ((lease != DHCP_PERM) && - (orig_time + lease) <= current_time) - goto failure; + if (plp->opts[CD_LEASE_TIME] != NULL && + plp->opts[CD_LEASE_TIME]->len == + sizeof (lease_t)) { + + (void) memcpy(&lease, + plp->opts[CD_LEASE_TIME]->value, + sizeof (lease_t)); + + lease = ntohl(lease); + if ((lease != DHCP_PERM) && + (orig_time + lease) <= current_time) + goto failure; + } + + relativize_time(plp->opts[CD_T1_TIME], orig_time, + current_time); + relativize_time(plp->opts[CD_T2_TIME], orig_time, + current_time); + relativize_time(plp->opts[CD_LEASE_TIME], orig_time, + current_time); } - - relativize_time(plp->opts[CD_T1_TIME], orig_time, current_time); - relativize_time(plp->opts[CD_T2_TIME], orig_time, current_time); - relativize_time(plp->opts[CD_LEASE_TIME], orig_time, - current_time); } (void) close(fd); @@ -203,9 +311,10 @@ failure: * * input: const char *: the interface name * PKT_LIST **: a list of pointers to PKT_LIST to write - * int: length of the list of PKT_LIST pointers + * uint_t: length of the list of PKT_LIST pointers * time_t: a starting time to treat the relative lease times * in the first packet as relative to + * boolean_t: B_TRUE if using DHCPv6 * output: int: 0 if the file is written successfully, -1 otherwise * (errno is set) */ @@ -215,16 +324,18 @@ write_hostconf( const char *ifname, PKT_LIST *pl[], uint_t pllen, - time_t relative_to) + time_t relative_to, + boolean_t isv6) { int fd; struct iovec iov[IOV_MAX]; int retval; - uint32_t magic = DHCP_HOSTCONF_MAGIC; + uint32_t magic; ssize_t explen = 0; /* Expected length of write */ int i, iovlen = 0; - fd = open(ifname_to_hostconf(ifname), O_WRONLY|O_CREAT|O_TRUNC, 0600); + fd = open(ifname_to_hostconf(ifname, isv6), O_WRONLY|O_CREAT|O_TRUNC, + 0600); if (fd == -1) return (-1); @@ -235,6 +346,7 @@ write_hostconf( * read_hostconf() to recalculate the lease times for the first packet. */ + magic = isv6 ? DHCP_HOSTCONF_MAGIC6 : DHCP_HOSTCONF_MAGIC; iov[iovlen].iov_base = (caddr_t)&magic; explen += iov[iovlen++].iov_len = sizeof (magic); iov[iovlen].iov_base = (caddr_t)&relative_to; @@ -280,3 +392,27 @@ relativize_time(DHCP_OPT *option, time_t orig_time, time_t current_time) (void) memcpy(option->value, &pkt_time, option->len); } + +/* + * relativize_v6(): re-relativizes a time in a DHCPv6 option + * + * input: uint32_t *: the time value to convert + * time_t: the time the leases in the packet are currently relative to + * time_t: the current time which leases will become relative to + * output: void + */ + +static void +relativize_v6(uint32_t *val, time_t orig_time, time_t current_time) +{ + uint32_t hval; + time_t time_diff = current_time - orig_time; + + hval = ntohl(*val); + if (hval != DHCPV6_INFTIME) { + if (hval < time_diff) + *val = 0; + else + *val = htonl(hval - time_diff); + } +} |
