Clean compile, basic DHCPv6 functionality is there.

TODO
     hostname handling.
     update DHCP6 configs from dns
     parse domain=<domain>,<IPv6 range>
     pretty-print counted string options.
     DECLINE messages
     lease-script fro DHCPv6
This commit is contained in:
Simon Kelley
2012-02-06 14:30:41 +00:00
parent 3268e90f5e
commit 4cb1b32009
17 changed files with 2025 additions and 718 deletions

View File

@@ -30,14 +30,9 @@ void lease_init(time_t now)
FILE *leasestream;
#ifdef HAVE_DHCP6
int v6pass = 0;
int lease_type = 0;
#endif
/* These each hold a DHCP option max size 255
and get a terminating zero added */
daemon->dhcp_buff = safe_malloc(256);
daemon->dhcp_buff2 = safe_malloc(256);
daemon->dhcp_buff3 = safe_malloc(256);
leases_left = daemon->dhcp_max;
if (option_bool(OPT_LEASE_RO))
@@ -86,7 +81,18 @@ void lease_init(time_t now)
{
#ifdef HAVE_DHCP6
if (v6pass)
hw_type = atoi(daemon->dhcp_buff2);
{
char *s = daemon->dhcp_buff2;
if (s[0] == 'T')
{
lease_type = LEASE_TA;
s++;
}
else
lease_type = LEASE_NA;
hw_type = atoi(s);
}
else
#endif
{
@@ -109,7 +115,7 @@ void lease_init(time_t now)
#ifdef HAVE_DHCP6
if (v6pass)
lease = lease6_allocate(&addr.addr.addr6);
lease = lease6_allocate(&addr.addr.addr6, lease_type);
else
#endif
lease = lease4_allocate(addr.addr.addr4);
@@ -130,16 +136,24 @@ void lease_init(time_t now)
#endif
#ifdef HAVE_DHCP6
if (!v6pass)
if (v6pass)
lease_set_hwaddr(lease, NULL, (unsigned char *)daemon->packet, 0, hw_type, clid_len);
else
#endif
lease_set_hwaddr(lease, (unsigned char *)daemon->dhcp_buff2, (unsigned char *)daemon->packet, hw_len, hw_type, clid_len);
if (strcmp(daemon->dhcp_buff, "*") != 0)
lease_set_hostname(lease, daemon->dhcp_buff, 0);
{
#ifdef HAVE_DHCP6
if (v6pass)
lease_set_hostname(lease, daemon->dhcp_buff, 0, get_domain6((struct in6_addr *)lease->hwaddr));
else
#endif
lease_set_hostname(lease, daemon->dhcp_buff, 0, get_domain(lease->addr));
}
/* set these correctly: the "old" events are generated later from
the startup synthesised SIGHUP. */
lease->new = lease->changed = 0;
lease->flags |= ~(LEASE_NEW | LEASE_CHANGED);
}
#ifdef HAVE_DHCP6
@@ -196,17 +210,17 @@ void lease_update_from_configs(void)
struct dhcp_lease *lease;
struct dhcp_config *config;
char *name;
for (lease = leases; lease; lease = lease->next)
if ((config = find_config(daemon->dhcp_conf, NULL, lease->clid, lease->clid_len,
lease->hwaddr, lease->hwaddr_len, lease->hwaddr_type, NULL)) &&
(config->flags & CONFIG_NAME) &&
(!(config->flags & CONFIG_ADDR) || config->addr.s_addr == lease->addr.s_addr))
lease_set_hostname(lease, config->hostname, 1);
lease_set_hostname(lease, config->hostname, 1, get_domain(lease->addr));
else if ((name = host_from_dns(lease->addr)))
lease_set_hostname(lease, name, 1); /* updates auth flag only */
lease_set_hostname(lease, name, 1, get_domain(lease->addr)); /* updates auth flag only */
}
static void ourprintf(int *errp, char *format, ...)
{
va_list ap;
@@ -234,7 +248,7 @@ void lease_update_file(time_t now)
{
#ifdef HAVE_DHCP6
if (lease->is_ipv6)
if (lease->flags & (LEASE_TA | LEASE_NA))
continue;
#endif
@@ -279,7 +293,7 @@ void lease_update_file(time_t now)
for (lease = leases; lease; lease = lease->next)
{
if (!lease->is_ipv6)
if (!(lease->flags & (LEASE_TA | LEASE_NA)))
continue;
#ifdef HAVE_BROKEN_RTC
@@ -290,7 +304,8 @@ void lease_update_file(time_t now)
inet_ntop(AF_INET6, lease->hwaddr, daemon->addrbuff, ADDRSTRLEN);
ourprintf(&err, "%u %s ", lease->hwaddr_type, daemon->addrbuff);
ourprintf(&err, "%s%u %s ", (lease->flags & LEASE_TA) ? "T" : "",
lease->hwaddr_type, daemon->addrbuff);
ourprintf(&err, "%s ", lease->hostname ? lease->hostname : "*");
if (lease->clid && lease->clid_len != 0)
@@ -343,11 +358,21 @@ void lease_update_dns(void)
for (lease = leases; lease; lease = lease->next)
{
int prot = AF_INET;
#ifdef HAVE_DHCP6
if (lease->flags & (LEASE_TA | LEASE_NA))
prot = AF_INET6;
#endif
if (lease->fqdn)
cache_add_dhcp_entry(lease->fqdn, &lease->addr, lease->expires);
cache_add_dhcp_entry(lease->fqdn, prot,
prot == AF_INET ? (struct all_addr *)&lease->addr : (struct all_addr *)&lease->hwaddr,
lease->expires);
if (!option_bool(OPT_DHCP_FQDN) && lease->hostname)
cache_add_dhcp_entry(lease->hostname, &lease->addr, lease->expires);
cache_add_dhcp_entry(lease->hostname, prot,
prot == AF_INET ? (struct all_addr *)&lease->addr : (struct all_addr *)&lease->hwaddr,
lease->expires);
}
dns_dirty = 0;
@@ -391,7 +416,7 @@ struct dhcp_lease *lease_find_by_client(unsigned char *hwaddr, int hw_len, int h
for (lease = leases; lease; lease = lease->next)
{
#ifdef HAVE_DHCP6
if (lease->is_ipv6)
if (lease->flags & (LEASE_TA | LEASE_NA))
continue;
#endif
if (lease->clid && clid_len == lease->clid_len &&
@@ -402,7 +427,7 @@ struct dhcp_lease *lease_find_by_client(unsigned char *hwaddr, int hw_len, int h
for (lease = leases; lease; lease = lease->next)
{
#ifdef HAVE_DHCP6
if (lease->is_ipv6)
if (lease->flags & (LEASE_TA | LEASE_NA))
continue;
#endif
if ((!lease->clid || !clid) &&
@@ -423,7 +448,7 @@ struct dhcp_lease *lease_find_by_addr(struct in_addr addr)
for (lease = leases; lease; lease = lease->next)
{
#ifdef HAVE_DHCP6
if (lease->is_ipv6)
if (lease->flags & (LEASE_TA | LEASE_NA))
continue;
#endif
if (lease->addr.s_addr == addr.s_addr)
@@ -434,19 +459,36 @@ struct dhcp_lease *lease_find_by_addr(struct in_addr addr)
}
#ifdef HAVE_DHCP6
struct dhcp_lease *lease6_find_by_client(unsigned char *clid, int clid_len, int iaid)
/* addr or clid may be NULL for "don't care, both NULL resets "USED" flags both
set activates USED check */
struct dhcp_lease *lease6_find(unsigned char *clid, int clid_len,
int lease_type, int iaid, struct in6_addr *addr)
{
struct dhcp_lease *lease;
for (lease = leases; lease; lease = lease->next)
{
if (!lease->is_ipv6)
continue;
if (!(lease->flags & lease_type) || lease->hwaddr_type != iaid)
continue;
if (lease->hwaddr_type == iaid &&
lease->clid && clid_len == lease->clid_len &&
memcmp(clid, lease->clid, clid_len) == 0)
return lease;
if (clid && addr && (lease->flags & LEASE_USED))
continue;
if (addr && memcmp(lease->hwaddr, addr, IN6ADDRSZ) != 0)
continue;
if (clid &&
(clid_len != lease->clid_len ||
memcmp(clid, lease->clid, clid_len) != 0))
continue;
if (clid || addr)
{
lease->flags |= LEASE_USED;
return lease;
}
else
lease->flags &= ~LEASE_USED;
}
return NULL;
@@ -455,12 +497,12 @@ struct dhcp_lease *lease6_find_by_client(unsigned char *clid, int clid_len, int
struct dhcp_lease *lease6_find_by_addr(struct in6_addr *net, int prefix, u64 addr)
{
struct dhcp_lease *lease;
for (lease = leases; lease; lease = lease->next)
{
if (!lease->is_ipv6)
if (!(lease->flags & (LEASE_TA | LEASE_NA)))
continue;
if (is_same_net6((struct in6_addr *)lease->hwaddr, net, prefix) &&
(prefix == 128 || addr6part((struct in6_addr *)lease->hwaddr) == addr))
return lease;
@@ -468,7 +510,6 @@ struct dhcp_lease *lease6_find_by_addr(struct in6_addr *net, int prefix, u64 add
return NULL;
}
#endif
/* Find largest assigned address in context */
@@ -481,7 +522,7 @@ struct in_addr lease_find_max_addr(struct dhcp_context *context)
for (lease = leases; lease; lease = lease->next)
{
#ifdef HAVE_DHCP6
if (lease->is_ipv6)
if (lease->flags & (LEASE_TA | LEASE_NA))
continue;
#endif
if (((unsigned)ntohl(lease->addr.s_addr)) > ((unsigned)ntohl(context->start.s_addr)) &&
@@ -500,7 +541,7 @@ static struct dhcp_lease *lease_allocate(void)
return NULL;
memset(lease, 0, sizeof(struct dhcp_lease));
lease->new = 1;
lease->flags = LEASE_NEW;
lease->expires = 1;
#ifdef HAVE_BROKEN_RTC
lease->length = 0xffffffff; /* illegal value */
@@ -524,11 +565,11 @@ struct dhcp_lease *lease4_allocate(struct in_addr addr)
}
#ifdef HAVE_DHCP6
struct dhcp_lease *lease6_allocate(struct in6_addr *addrp)
struct dhcp_lease *lease6_allocate(struct in6_addr *addrp, int lease_type)
{
struct dhcp_lease *lease = lease_allocate();
memcpy(lease->hwaddr, addrp, sizeof(*addrp)) ;
lease->is_ipv6 = 1;
lease->flags |= lease_type;
return lease;
}
@@ -549,7 +590,8 @@ void lease_set_expires(struct dhcp_lease *lease, unsigned int len, time_t now)
dns_dirty = 1;
lease->expires = exp;
#ifndef HAVE_BROKEN_RTC
lease->aux_changed = file_dirty = 1;
lease->flags |= LEASE_AUX_CHANGED;
file_dirty = 1;
#endif
}
@@ -569,10 +611,12 @@ void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
hw_type != lease->hwaddr_type ||
(hw_len != 0 && memcmp(lease->hwaddr, hwaddr, hw_len) != 0))
{
memcpy(lease->hwaddr, hwaddr, hw_len);
if (hw_len != 0)
memcpy(lease->hwaddr, hwaddr, hw_len);
lease->hwaddr_len = hw_len;
lease->hwaddr_type = hw_type;
lease->changed = file_dirty = 1; /* run script on change */
lease->flags |= LEASE_CHANGED;
file_dirty = 1; /* run script on change */
}
/* only update clid when one is available, stops packets
@@ -585,14 +629,18 @@ void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
if (lease->clid_len != clid_len)
{
lease->aux_changed = file_dirty = 1;
lease->flags |= LEASE_AUX_CHANGED;
file_dirty = 1;
free(lease->clid);
if (!(lease->clid = whine_malloc(clid_len)))
return;
}
else if (memcmp(lease->clid, clid, clid_len) != 0)
lease->aux_changed = file_dirty = 1;
{
lease->flags |= LEASE_AUX_CHANGED;
file_dirty = 1;
}
lease->clid_len = clid_len;
memcpy(lease->clid, clid, clid_len);
}
@@ -608,7 +656,7 @@ static void kill_name(struct dhcp_lease *lease)
free(lease->old_hostname);
/* If we know the fqdn, pass that. The helper will derive the
unqualified name from it, free the unqulaified name here. */
unqualified name from it, free the unqualified name here. */
if (lease->fqdn)
{
@@ -621,14 +669,15 @@ static void kill_name(struct dhcp_lease *lease)
lease->hostname = lease->fqdn = NULL;
}
void lease_set_hostname(struct dhcp_lease *lease, char *name, int auth)
void lease_set_hostname(struct dhcp_lease *lease, char *name, int auth, char *domain)
{
struct dhcp_lease *lease_tmp;
char *new_name = NULL, *new_fqdn = NULL;
if (lease->hostname && name && hostname_isequal(lease->hostname, name))
{
lease->auth_name = auth;
if (auth)
lease->flags |= LEASE_AUTH_NAME;
return;
}
@@ -638,19 +687,21 @@ void lease_set_hostname(struct dhcp_lease *lease, char *name, int auth)
/* If a machine turns up on a new net without dropping the old lease,
or two machines claim the same name, then we end up with two interfaces with
the same name. Check for that here and remove the name from the old lease.
Note that IPv6 leases are different. All the leases to the same DUID are
allowed the same name.
Don't allow a name from the client to override a name from dnsmasq config. */
if (name)
{
if ((new_name = whine_malloc(strlen(name) + 1)))
{
char *suffix = get_domain(lease->addr);
strcpy(new_name, name);
if (suffix && (new_fqdn = whine_malloc(strlen(new_name) + strlen(suffix) + 2)))
if (domain && (new_fqdn = whine_malloc(strlen(new_name) + strlen(domain) + 2)))
{
strcpy(new_fqdn, name);
strcat(new_fqdn, ".");
strcat(new_fqdn, suffix);
strcat(new_fqdn, domain);
}
}
@@ -659,7 +710,7 @@ void lease_set_hostname(struct dhcp_lease *lease, char *name, int auth)
{
if (option_bool(OPT_DHCP_FQDN))
{
if (!new_fqdn || !lease_tmp->fqdn || !hostname_isequal(lease_tmp->fqdn, new_fqdn) )
if (!new_fqdn || !lease_tmp->fqdn || !hostname_isequal(lease_tmp->fqdn, new_fqdn))
continue;
}
else
@@ -667,8 +718,22 @@ void lease_set_hostname(struct dhcp_lease *lease, char *name, int auth)
if (!new_name || !lease_tmp->hostname || !hostname_isequal(lease_tmp->hostname, new_name) )
continue;
}
if (lease_tmp->auth_name && !auth)
if (lease->flags & (LEASE_TA | LEASE_NA))
{
if (!(lease_tmp->flags & (LEASE_TA | LEASE_NA)))
continue;
/* another lease for the saem DUID is OK for IPv6 */
if (lease->clid_len == lease_tmp->clid_len &&
lease->clid && lease_tmp->clid &&
memcmp(lease->clid, lease_tmp->clid, lease->clid_len) == 0)
continue;
}
else if (lease_tmp->flags & (LEASE_TA | LEASE_NA))
continue;
if ((lease_tmp->flags & LEASE_AUTH_NAME) && !auth)
{
free(new_name);
free(new_fqdn);
@@ -685,11 +750,13 @@ void lease_set_hostname(struct dhcp_lease *lease, char *name, int auth)
lease->hostname = new_name;
lease->fqdn = new_fqdn;
lease->auth_name = auth;
if (auth)
lease->flags |= LEASE_AUTH_NAME;
file_dirty = 1;
dns_dirty = 1;
lease->changed = 1; /* run script on change */
lease->flags |= LEASE_CHANGED; /* run script on change */
}
void lease_set_interface(struct dhcp_lease *lease, int interface)
@@ -698,7 +765,7 @@ void lease_set_interface(struct dhcp_lease *lease, int interface)
return;
lease->last_interface = interface;
lease->changed = 1;
lease->flags |= LEASE_CHANGED;
}
void rerun_scripts(void)
@@ -706,7 +773,7 @@ void rerun_scripts(void)
struct dhcp_lease *lease;
for (lease = leases; lease; lease = lease->next)
lease->changed = 1;
lease->flags |= LEASE_CHANGED;
}
/* deleted leases get transferred to the old_leases list.
@@ -772,18 +839,18 @@ int do_script_run(time_t now)
}
for (lease = leases; lease; lease = lease->next)
if (lease->new || lease->changed ||
(lease->aux_changed && option_bool(OPT_LEASE_RO)))
if ((lease->flags & (LEASE_NEW | LEASE_CHANGED)) ||
((lease->flags & LEASE_AUX_CHANGED) && option_bool(OPT_LEASE_RO)))
{
#ifdef HAVE_SCRIPT
queue_script(lease->new ? ACTION_ADD : ACTION_OLD, lease,
queue_script((lease->flags & LEASE_NEW) ? ACTION_ADD : ACTION_OLD, lease,
lease->fqdn ? lease->fqdn : lease->hostname, now);
#endif
#ifdef HAVE_DBUS
emit_dbus_signal(lease->new ? ACTION_ADD : ACTION_OLD, lease,
emit_dbus_signal((lease->flags & LEASE_NEW) ? ACTION_ADD : ACTION_OLD, lease,
lease->fqdn ? lease->fqdn : lease->hostname);
#endif
lease->new = lease->changed = lease->aux_changed = 0;
lease->flags &= ~(LEASE_NEW | LEASE_CHANGED | LEASE_AUX_CHANGED);
/* this is used for the "add" call, then junked, since they're not in the database */
free(lease->extradata);