It compiles and it allocates a lease! No renewals yet.

This commit is contained in:
Simon Kelley
2012-01-22 16:05:15 +00:00
parent be2daf4ad5
commit 52b92f4db8
13 changed files with 676 additions and 171 deletions

View File

@@ -1,2 +1,15 @@
Worry about IPv6 leases and DUID in script-storage.
dhcpv6-range
dhcpv6-option
dhcpv6-option-force
dhcpv6-script ?
dhcpv6-optsfile
dhcpv6-hostsfile
dhcp-host =
[<hwaddr>][,id:<client_id>|*][,net:<netid>][,<ipv4addr>][\[ipv6addr\]][,<hostname>][,<lease_time>][,ignore]
IPv6 address like [2001:db8:do::2]

View File

@@ -120,8 +120,7 @@ void dhcp_init(void)
check_dhcp_hosts(1);
daemon->dhcp_packet.iov_len = sizeof(struct dhcp_packet);
daemon->dhcp_packet.iov_base = safe_malloc(daemon->dhcp_packet.iov_len);
expand_buf(&daemon->dhcp_packet, sizeof(struct dhcp_packet));
}
ssize_t recv_dhcp_packet(int fd, struct msghdr *msg)

View File

@@ -24,10 +24,10 @@ struct iface_param {
};
static int join_multicast(struct in6_addr *local, int prefix,
int scope, int if_index, void *vparam);
int scope, int if_index, int dad, void *vparam);
static int complete_context6(struct in6_addr *local, int prefix,
int scope, int if_index, void *vparam);
int scope, int if_index, int dad, void *vparam);
void dhcp6_init(void)
{
@@ -58,10 +58,15 @@ void dhcp6_init(void)
daemon->dhcp6fd = fd;
/* If we've already inited DHCPv4, this becomes a no-op,
othewise sizeof(struct dhcp_packet) is as good an initial
size as any. */
expand_buf(&daemon->dhcp_packet, sizeof(struct dhcp_packet));
expand_buf(&daemon->outpacket, sizeof(struct dhcp_packet));
}
static int join_multicast(struct in6_addr *local, int prefix,
int scope, int if_index, void *vparam)
int scope, int if_index, int dad, void *vparam)
{
char ifrn_name[IFNAMSIZ];
struct ipv6_mreq mreq;
@@ -71,7 +76,10 @@ static int join_multicast(struct in6_addr *local, int prefix,
struct iname *tmp;
(void)prefix;
(void)scope; /* warnings */
/* scope == link */
if (scope != 253)
return 1;
if (!indextoname(fd, if_index, ifrn_name))
return 0;
@@ -85,7 +93,7 @@ static int join_multicast(struct in6_addr *local, int prefix,
return 1;
/* weird libvirt-inspired access control */
for (context = daemon->dhcp; context; context = context->next)
for (context = daemon->dhcp6; context; context = context->next)
if (!context->interface || strcmp(context->interface, ifrn_name) == 0)
break;
@@ -93,14 +101,14 @@ static int join_multicast(struct in6_addr *local, int prefix,
return 1;
mreq.ipv6mr_interface = if_index;
inet_pton(AF_INET6, ALL_RELAY_AGENTS_AND_SERVERS, &maddr);
inet_pton(AF_INET6, ALL_RELAY_AGENTS_AND_SERVERS, &mreq.ipv6mr_multiaddr);
if (!setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
if (setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
return 0;
inet_pton(AF_INET6, ALL_SERVERS, &maddr);
inet_pton(AF_INET6, ALL_SERVERS, &mreq.ipv6mr_multiaddr);
if (!setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
if (setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
return 0;
return 1;
@@ -135,7 +143,7 @@ void dhcp6_packet(time_t now)
msg.msg_iov = &daemon->dhcp_packet;
msg.msg_iovlen = 1;
if ((sz = recv_dhcp_packet(daemon->dhcp6fd, &msg) == -1) || sz <= 4)
if ((sz = recv_dhcp_packet(daemon->dhcp6fd, &msg)) == -1 || sz <= 4)
return;
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
@@ -153,7 +161,7 @@ void dhcp6_packet(time_t now)
if (!indextoname(daemon->dhcp6fd, if_index, ifr.ifr_name))
return;
ls -l
if (!iface_check(AF_INET6, (struct all_addr *)&dest, ifr.ifr_name))
return;
@@ -162,7 +170,7 @@ ls -l
return;
/* weird libvirt-inspired access control */
for (context = daemon->dhcp; context; context = context->next)
for (context = daemon->dhcp6; context; context = context->next)
if (!context->interface || strcmp(context->interface, ifr.ifr_name) == 0)
break;
@@ -170,7 +178,7 @@ ls -l
return;
/* unlinked contexts are marked by context->current == context */
for (context = daemon->dhcp; context; context = context->next)
for (context = daemon->dhcp6; context; context = context->next)
context->current = context;
parm.current = NULL;
@@ -182,7 +190,7 @@ ls -l
lease_prune(NULL, now); /* lose any expired leases */
msg.msg_iov = &daemon->dhcp_packet;
sz = dhcp6_reply(parm.current, sz);
sz = dhcp6_reply(parm.current, sz, now);
/* ifr.ifr_name, if_index, (size_t)sz,
now, unicast_dest, &is_inform, pxe_fd, iface_addr); */
lease_update_file(now);
@@ -193,15 +201,15 @@ ls -l
}
static int complete_context6(struct in6_addr *local, int prefix,
int scope, int if_index, void *vparam)
int scope, int if_index, int dad, void *vparam)
{
struct dhcp_context *context;
struct iface_param *param = vparam;
(void)scope; /* warning */
for (context = daemon->dhcp6; context; context = context->next)
{
if ((context->flags & CONTEXT_IPV6) &&
prefix == context->prefix &&
if (prefix == context->prefix &&
is_same_net6(local, &context->start6, prefix) &&
is_same_net6(local, &context->end6, prefix))
{
@@ -215,6 +223,141 @@ static int complete_context6(struct in6_addr *local, int prefix,
}
return 1;
}
struct dhcp_config *config_find_by_address6(struct dhcp_config *configs, struct in6_addr *net, int prefix, u64 addr)
{
struct dhcp_config *config;
for (config = configs; config; config = config->next)
if ((config->flags & CONFIG_ADDR6) &&
is_same_net6(&config->addr6, net, prefix) &&
(prefix == 128 || addr6part(&config->addr6) == addr))
return config;
return NULL;
}
int address6_allocate(struct dhcp_context *context, unsigned char *clid, int clid_len,
struct dhcp_netid *netids, struct in6_addr *ans)
{
/* Find a free address: exclude anything in use and anything allocated to
a particular hwaddr/clientid/hostname in our configuration.
Try to return from contexts which match netids first.
Note that we assume the address prefix lengths are 64 or greater, so we can
get by with 64 bit arithmetic.
*/
u64 start, addr;
struct dhcp_context *c, *d;
int i, pass;
u64 j;
/* hash hwaddr: use the SDBM hashing algorithm. This works
for MAC addresses, let's see how it manages with client-ids! */
for (j = 0, i = 0; i < clid_len; i++)
j += clid[i] + (j << 6) + (j << 16) - j;
for (pass = 0; pass <= 1; pass++)
for (c = context; c; c = c->current)
if (c->flags & (CONTEXT_STATIC | CONTEXT_PROXY))
continue;
else if (!match_netid(c->filter, netids, pass))
continue;
else
{
start = addr6part(&c->start6) + ((j + c->addr_epoch) % (1 + addr6part(&c->end6) - addr6part(&c->start6)));
/* iterate until we find a free address. */
addr = start;
do {
/* eliminate addresses in use by the server. */
for (d = context; d; d = d->current)
if (addr == addr6part(&d->router6))
break;
if (!d &&
!lease6_find_by_addr(&c->start6, c->prefix, addr) &&
!config_find_by_address6(daemon->dhcp_conf, &c->start6, c->prefix, addr))
{
*ans = c->start6;
setaddr6part (ans, addr);
return 1;
}
addr++;
if (addr == addr6part(&c->end6) + 1)
addr = addr6part(&c->start6);
} while (addr != start);
}
return 0;
}
struct dhcp_context *address6_available(struct dhcp_context *context,
struct in6_addr *taddr,
struct dhcp_netid *netids)
{
u64 start, end, addr = addr6part(taddr);
struct dhcp_context *tmp;
for (tmp = context; tmp; tmp = tmp->current)
{
start = addr6part(&tmp->start6);
end = addr6part(&tmp->end6);
if (!(tmp->flags & (CONTEXT_STATIC | CONTEXT_PROXY)) &&
is_same_net6(&context->start6, taddr, context->prefix) &&
is_same_net6(&context->end6, taddr, context->prefix) &&
addr >= start &&
addr <= end &&
match_netid(tmp->filter, netids, 1))
return tmp;
}
return NULL;
}
struct dhcp_context *narrow_context6(struct dhcp_context *context,
struct in6_addr *taddr,
struct dhcp_netid *netids)
{
/* We start of with a set of possible contexts, all on the current physical interface.
These are chained on ->current.
Here we have an address, and return the actual context correponding to that
address. Note that none may fit, if the address came a dhcp-host and is outside
any dhcp-range. In that case we return a static range if possible, or failing that,
any context on the correct subnet. (If there's more than one, this is a dodgy
configuration: maybe there should be a warning.) */
struct dhcp_context *tmp;
if (!(tmp = address6_available(context, taddr, netids)))
{
for (tmp = context; tmp; tmp = tmp->current)
if (match_netid(tmp->filter, netids, 1) &&
is_same_net6(taddr, &tmp->start6, tmp->prefix) &&
(tmp->flags & CONTEXT_STATIC))
break;
if (!tmp)
for (tmp = context; tmp; tmp = tmp->current)
if (match_netid(tmp->filter, netids, 1) &&
is_same_net6(taddr, &tmp->start6, tmp->prefix) &&
!(tmp->flags & CONTEXT_PROXY))
break;
}
/* Only one context allowed now */
if (tmp)
tmp->current = NULL;
return tmp;
}
#endif

View File

@@ -53,3 +53,12 @@
#define OPTION6_INTERFACE_ID 18
#define OPTION6_RECONFIGURE_MSG 19
#define OPTION6_RECONF_ACCEPT 20
#define DHCP6SUCCESS 0
#define DHCP6UNSPEC 1
#define DHCP6NOADDRS 2
#define DHCP6NOBINDING 3
#define DHCP6NOTONLINK 4
#define DHCP6USEMULTI 5

View File

@@ -87,7 +87,7 @@ int main (int argc, char **argv)
#ifdef HAVE_DHCP
if (!daemon->lease_file)
{
if (daemon->dhcp)
if (daemon->dhcp || daemon->dhcp6)
daemon->lease_file = LEASEFILE;
}
#endif
@@ -137,13 +137,18 @@ int main (int argc, char **argv)
now = dnsmasq_time();
#ifdef HAVE_DHCP
if (daemon->dhcp)
if (daemon->dhcp || daemon->dhcp6)
{
/* Note that order matters here, we must call lease_init before
creating any file descriptors which shouldn't be leaked
to the lease-script init process. */
lease_init(now);
dhcp_init();
if (daemon->dhcp)
dhcp_init();
#ifdef HAVE_DHCP6
if (daemon->dhcp6)
dhcp6_init();
#endif
}
#endif
@@ -189,7 +194,7 @@ int main (int argc, char **argv)
#if defined(HAVE_SCRIPT)
/* Note getpwnam returns static storage */
if (daemon->dhcp && daemon->scriptuser &&
if ((daemon->dhcp || daemon->dhcp6) && daemon->scriptuser &&
(daemon->lease_change_command || daemon->luascript))
{
if ((ent_pw = getpwnam(daemon->scriptuser)))
@@ -341,7 +346,7 @@ int main (int argc, char **argv)
/* if we are to run scripts, we need to fork a helper before dropping root. */
daemon->helperfd = -1;
#ifdef HAVE_SCRIPT
if (daemon->dhcp && (daemon->lease_change_command || daemon->luascript))
if ((daemon->dhcp || daemon->dhcp6) && (daemon->lease_change_command || daemon->luascript))
daemon->helperfd = create_helper(pipewrite, err_pipe[1], script_uid, script_gid, max_fd);
#endif
@@ -481,25 +486,51 @@ int main (int argc, char **argv)
my_syslog(LOG_INFO, _("asynchronous logging enabled, queue limit is %d messages"), daemon->max_logs);
#ifdef HAVE_DHCP
if (daemon->dhcp)
if (daemon->dhcp || daemon->dhcp6)
{
struct dhcp_context *dhcp_tmp;
for (dhcp_tmp = daemon->dhcp; dhcp_tmp; dhcp_tmp = dhcp_tmp->next)
int family = AF_INET;
dhcp_tmp = daemon->dhcp;
again:
for (; dhcp_tmp; dhcp_tmp = dhcp_tmp->next)
{
void *start = &dhcp_tmp->start;
void *end = &dhcp_tmp->end;
#ifdef HAVE_DHCP6
if (family == AF_INET6)
{
start = &dhcp_tmp->start6;
end = &dhcp_tmp->end6;
}
#endif
prettyprint_time(daemon->dhcp_buff2, dhcp_tmp->lease_time);
strcpy(daemon->dhcp_buff, inet_ntoa(dhcp_tmp->start));
inet_ntop(family, start, daemon->dhcp_buff, 256);
inet_ntop(family, end, daemon->dhcp_buff3, 256);
my_syslog(MS_DHCP | LOG_INFO,
(dhcp_tmp->flags & CONTEXT_STATIC) ?
_("DHCP, static leases only on %.0s%s, lease time %s") :
(dhcp_tmp->flags & CONTEXT_PROXY) ?
_("DHCP, proxy on subnet %.0s%s%.0s") :
_("DHCP, IP range %s -- %s, lease time %s"),
daemon->dhcp_buff, inet_ntoa(dhcp_tmp->end), daemon->dhcp_buff2);
daemon->dhcp_buff, daemon->dhcp_buff3, daemon->dhcp_buff2);
}
#ifdef HAVE_DHCP6
if (family == AF_INET)
{
family = AF_INET6;
dhcp_tmp = daemon->dhcp6;
goto again;
}
#endif
}
#endif
#ifdef HAVE_TFTP
if (daemon->tftp_unlimited || daemon->tftp_interfaces)
{
@@ -604,6 +635,14 @@ int main (int argc, char **argv)
}
#endif
#ifdef HAVE_DHCP6
if (daemon->dhcp6)
{
FD_SET(daemon->dhcp6fd, &rset);
bump_maxfd(daemon->dhcp6fd, &maxfd);
}
#endif
#ifdef HAVE_LINUX_NETWORK
FD_SET(daemon->netlinkfd, &rset);
bump_maxfd(daemon->netlinkfd, &maxfd);
@@ -699,6 +738,14 @@ int main (int argc, char **argv)
dhcp_packet(now, 1);
}
#ifdef HAVE_DHCP6
if (daemon->dhcp6)
{
if (FD_ISSET(daemon->dhcp6fd, &rset))
dhcp6_packet(now);
}
#endif
# ifdef HAVE_SCRIPT
if (daemon->helperfd != -1 && FD_ISSET(daemon->helperfd, &wset))
helper_write();
@@ -860,7 +907,7 @@ static void async_event(int pipe, time_t now)
case EVENT_ALARM:
#ifdef HAVE_DHCP
if (daemon->dhcp)
if (daemon->dhcp || daemon->dhcp6)
{
lease_prune(NULL, now);
lease_update_file(now);
@@ -1018,7 +1065,7 @@ void clear_cache_and_reload(time_t now)
cache_reload();
#ifdef HAVE_DHCP
if (daemon->dhcp)
if (daemon->dhcp || daemon->dhcp6)
{
if (option_bool(OPT_ETHERS))
dhcp_read_ethers();

View File

@@ -54,6 +54,7 @@
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
typedef unsigned long long u64;
#include "dns_protocol.h"
#include "dhcp_protocol.h"
@@ -448,8 +449,8 @@ struct dhcp_lease {
#ifdef HAVE_BROKEN_RTC
unsigned int length;
#endif
int hwaddr_len, hwaddr_type;
unsigned char hwaddr[DHCP_CHADDR_MAX];
int hwaddr_len, hwaddr_type; /* hw_type used for iaid in v6 */
unsigned char hwaddr[DHCP_CHADDR_MAX]; /* also IPv6 address */
struct in_addr addr, override, giaddr;
unsigned char *extradata;
unsigned int extradata_len, extradata_size;
@@ -489,6 +490,9 @@ struct dhcp_config {
unsigned char *clid; /* clientid */
char *hostname, *domain;
struct dhcp_netid_list *netid;
#ifdef HAVE_DHCP6
struct in6_addr addr6;
#endif
struct in_addr addr;
time_t decline_time;
unsigned int lease_time;
@@ -506,6 +510,7 @@ struct dhcp_config {
#define CONFIG_ADDR_HOSTS 512 /* address added by from /etc/hosts */
#define CONFIG_DECLINED 1024 /* address declined by client */
#define CONFIG_BANK 2048 /* from dhcp hosts file */
#define CONFIG_ADDR6 4096
struct dhcp_opt {
int opt, len, flags;
@@ -588,6 +593,7 @@ struct dhcp_context {
struct in_addr start, end; /* range of available addresses */
#ifdef HAVE_DHCP6
struct in6_addr start6, end6; /* range of available addresses */
struct in6_addr local6, router6;
int prefix;
#endif
int flags;
@@ -600,7 +606,6 @@ struct dhcp_context {
#define CONTEXT_NETMASK 2
#define CONTEXT_BRDCAST 4
#define CONTEXT_PROXY 8
#define CONTEXT_IPV6 16
struct ping_result {
struct in_addr addr;
@@ -681,7 +686,7 @@ extern struct daemon {
struct hostsfile *addn_hosts;
struct dhcp_context *dhcp, *dhcp6;
struct dhcp_config *dhcp_conf;
struct dhcp_opt *dhcp_opts, *dhcp_match;
struct dhcp_opt *dhcp_opts, *dhcp_match, *dhcp_opts6;
struct dhcp_vendor *dhcp_vendors;
struct dhcp_mac *dhcp_macs;
struct dhcp_boot *boot_config;
@@ -814,6 +819,8 @@ time_t dnsmasq_time(void);
int is_same_net(struct in_addr a, struct in_addr b, struct in_addr mask);
#ifdef HAVE_IPV6
int is_same_net6(struct in6_addr *a, struct in6_addr *b, int prefixlen);
u64 addr6part(struct in6_addr *addr);
void setaddr6part(struct in6_addr *addr, u64 host);
#endif
int retry_send(void);
void prettyprint_time(char *buf, unsigned int t);
@@ -908,9 +915,11 @@ char *get_domain(struct in_addr addr);
void lease_update_file(time_t now);
void lease_update_dns();
void lease_init(time_t now);
struct dhcp_lease *lease_allocate4(struct in_addr addr);
struct dhcp_lease *lease4_allocate(struct in_addr addr);
#ifdef HAVE_DHCP6
struct dhcp_lease *lease_allocate6(struct in6_addr *addrp);
struct dhcp_lease *lease6_allocate(struct in6_addr *addrp);
struct dhcp_lease *lease6_find_by_addr(struct in6_addr *net, int prefix, u64 addr);
struct dhcp_lease *lease6_find_by_client(unsigned char *clid, int clid_len, int iaid);
#endif
void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
unsigned char *clid, int hw_len, int hw_type, int clid_len);
@@ -991,8 +1000,22 @@ int get_incoming_mark(union mysockaddr *peer_addr, struct all_addr *local_addr,
int istcp, unsigned int *markp);
#endif
/* dhcp6.c */
#ifdef HAVE_DHCP6
void dhcp6_init(void);
void dhcp6_packet(time_t now);
int address6_allocate(struct dhcp_context *context, unsigned char *clid, int clid_len,
struct dhcp_netid *netids, struct in6_addr *ans);
struct dhcp_context *address6_available(struct dhcp_context *context,
struct in6_addr *taddr,
struct dhcp_netid *netids);
struct dhcp_context *narrow_context6(struct dhcp_context *context,
struct in6_addr *taddr,
struct dhcp_netid *netids);
#endif
/* rfc3315.c */
#ifdef HAVE_DHCP6
void make_duid(time_t now);
size_t dhcp6_reply(struct dhcp_context *context, size_t sz);
size_t dhcp6_reply(struct dhcp_context *context, size_t sz, time_t now);
#endif

View File

@@ -85,7 +85,9 @@ void lease_init(time_t now)
daemon->dhcp_buff, daemon->packet) == 5)
{
#ifdef HAVE_DHCP6
if (!v6pass)
if (v6pass)
hw_type = atoi(daemon->dhcp_buff2);
else
#endif
{
hw_len = parse_hex(daemon->dhcp_buff2, (unsigned char *)daemon->dhcp_buff2, DHCP_CHADDR_MAX, NULL, &hw_type);
@@ -107,10 +109,10 @@ void lease_init(time_t now)
#ifdef HAVE_DHCP6
if (v6pass)
lease = lease_allocate6(&addr.addr.addr6);
lease = lease6_allocate(&addr.addr.addr6);
else
#endif
lease = lease_allocate4(addr.addr.addr4);
lease = lease4_allocate(addr.addr.addr4);
if (!lease)
die (_("too many stored leases"), NULL, EC_MISC);
@@ -288,7 +290,7 @@ void lease_update_file(time_t now)
inet_ntop(AF_INET6, lease->hwaddr, daemon->addrbuff, ADDRSTRLEN);
ourprintf(&err, "* %s ", daemon->addrbuff);
ourprintf(&err, "%u %s ", lease->hwaddr_type, daemon->addrbuff);
ourprintf(&err, "%s ", lease->hostname ? lease->hostname : "*");
if (lease->clid && lease->clid_len != 0)
@@ -431,6 +433,44 @@ struct dhcp_lease *lease_find_by_addr(struct in_addr addr)
return NULL;
}
#ifdef HAVE_DHCP6
struct dhcp_lease *lease6_find_by_client(unsigned char *clid, int clid_len, int iaid)
{
struct dhcp_lease *lease;
for (lease = leases; lease; lease = lease->next)
{
if (!lease->is_ipv6)
continue;
if (lease->hwaddr_type == iaid &&
lease->clid && clid_len == lease->clid_len &&
memcmp(clid, lease->clid, clid_len) == 0)
return lease;
}
return NULL;
}
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)
continue;
if (is_same_net6((struct in6_addr *)lease->hwaddr, net, prefix) &&
(prefix == 128 || addr6part((struct in6_addr *)lease->hwaddr) == addr))
return lease;
}
return NULL;
}
#endif
/* Find largest assigned address in context */
struct in_addr lease_find_max_addr(struct dhcp_context *context)
{
@@ -474,7 +514,7 @@ static struct dhcp_lease *lease_allocate(void)
return lease;
}
struct dhcp_lease *lease_allocate4(struct in_addr addr)
struct dhcp_lease *lease4_allocate(struct in_addr addr)
{
struct dhcp_lease *lease = lease_allocate();
lease->addr = addr;
@@ -484,7 +524,7 @@ struct dhcp_lease *lease_allocate4(struct in_addr addr)
}
#ifdef HAVE_DHCP6
struct dhcp_lease *lease_allocate6(struct in6_addr *addrp)
struct dhcp_lease *lease6_allocate(struct in6_addr *addrp)
{
struct dhcp_lease *lease = lease_allocate();
memcpy(lease->hwaddr, addrp, sizeof(*addrp)) ;

View File

@@ -230,8 +230,8 @@ int iface_enumerate(int family, void *parm, int (*callback)())
}
if (addrp)
if (!((*callback)(addrp, ifa->ifa_prefixlen, ifa->ifa_index,
ifa->ifa_index, ifa->ifa_flags & IFA_F_TENTATIVE, parm)))
if (!((*callback)(addrp, (int)(ifa->ifa_prefixlen), (int)(ifa->ifa_scope),
(int)(ifa->ifa_index), (int)(ifa->ifa_flags & IFA_F_TENTATIVE), parm)))
return 0;
}
#endif

View File

@@ -274,9 +274,10 @@ static int iface_allowed_v6(struct in6_addr *local, int prefix,
{
union mysockaddr addr;
struct in_addr netmask; /* dummy */
(void)prefix; /* warning */
netmask.s_addr = 0;
(void)prefix; /* warning */
(void)scope; /* warning */
memset(&addr, 0, sizeof(addr));
#ifdef HAVE_SOCKADDR_SA_LEN
@@ -285,7 +286,7 @@ static int iface_allowed_v6(struct in6_addr *local, int prefix,
addr.in6.sin6_family = AF_INET6;
addr.in6.sin6_addr = *local;
addr.in6.sin6_port = htons(daemon->port);
addr.in6.sin6_scope_id = scope;
addr.in6.sin6_scope_id = if_index;
return iface_allowed((struct irec **)vparam, if_index, &addr, netmask, dad);
}

View File

@@ -1870,18 +1870,9 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
char *cp, *a[5] = { NULL, NULL, NULL, NULL, NULL };
struct dhcp_context *new = opt_malloc(sizeof(struct dhcp_context));
new->next = daemon->dhcp;
memset (new, 0, sizeof(*new));
new->lease_time = DEFLEASE;
new->addr_epoch = 0;
new->netmask.s_addr = 0;
new->broadcast.s_addr = 0;
new->router.s_addr = 0;
new->local.s_addr = 0;
new->netid.net = NULL;
new->filter = NULL;
new->flags = 0;
new->interface = NULL;
gen_prob = _("bad dhcp-range");
if (!arg)
@@ -1893,7 +1884,9 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
while(1)
{
for (cp = arg; *cp; cp++)
if (!(*cp == ' ' || *cp == '.' || (*cp >='0' && *cp <= '9')))
if (!(*cp == ' ' || *cp == '.' || *cp == ':' ||
(*cp >= 'a' && *cp <= 'f') || (*cp >= 'A' && *cp <= 'F') ||
(*cp >='0' && *cp <= '9')))
break;
if (*cp != ',' && (comma = split(arg)))
@@ -1929,44 +1922,86 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
if (!(a[k] = split(a[k-1])))
break;
if ((k < 2) || ((new->start.s_addr = inet_addr(a[0])) == (in_addr_t)-1))
if (k < 2)
option = '?';
else if (strcmp(a[1], "static") == 0)
else if (inet_pton(AF_INET, a[0], &new->start))
{
new->end = new->start;
new->flags |= CONTEXT_STATIC;
new->next = daemon->dhcp;
daemon->dhcp = new;
if (strcmp(a[1], "static") == 0)
{
new->end = new->start;
new->flags |= CONTEXT_STATIC;
}
else if (strcmp(a[1], "proxy") == 0)
{
new->end = new->start;
new->flags |= CONTEXT_PROXY;
}
else if ((new->end.s_addr = inet_addr(a[1])) == (in_addr_t)-1)
option = '?';
if (ntohl(new->start.s_addr) > ntohl(new->end.s_addr))
{
struct in_addr tmp = new->start;
new->start = new->end;
new->end = tmp;
}
if (option != '?' && k >= 3 && strchr(a[2], '.') &&
((new->netmask.s_addr = inet_addr(a[2])) != (in_addr_t)-1))
{
new->flags |= CONTEXT_NETMASK;
leasepos = 3;
if (!is_same_net(new->start, new->end, new->netmask))
problem = _("inconsistent DHCP range");
}
if (k >= 4 && strchr(a[3], '.') &&
((new->broadcast.s_addr = inet_addr(a[3])) != (in_addr_t)-1))
{
new->flags |= CONTEXT_BRDCAST;
leasepos = 4;
}
}
else if (strcmp(a[1], "proxy") == 0)
#ifdef HAVE_DHCP6
else if (inet_pton(AF_INET6, a[0], &new->start6))
{
new->end = new->start;
new->flags |= CONTEXT_PROXY;
}
else if ((new->end.s_addr = inet_addr(a[1])) == (in_addr_t)-1)
option = '?';
if (ntohl(new->start.s_addr) > ntohl(new->end.s_addr))
{
struct in_addr tmp = new->start;
new->start = new->end;
new->end = tmp;
}
if (option != '?' && k >= 3 && strchr(a[2], '.') &&
((new->netmask.s_addr = inet_addr(a[2])) != (in_addr_t)-1))
{
new->flags |= CONTEXT_NETMASK;
leasepos = 3;
if (!is_same_net(new->start, new->end, new->netmask))
new->next = daemon->dhcp6;
new->prefix = 64; /* default */
daemon->dhcp6 = new;
if (strcmp(a[1], "static") == 0)
{
new->end = new->start;
new->flags |= CONTEXT_STATIC;
}
else if (!inet_pton(AF_INET6, a[1], &new->end6))
option = '?';
/* bare integer < 128 is prefix value */
if (option != '?' && k >= 3)
{
int pref;
for (cp = a[2]; *cp; cp++)
if (!(*cp >= '0' && *cp <= '9'))
break;
if (!*cp && (pref = atoi(a[2])) <= 128)
{
new->prefix = pref;
leasepos = 3;
}
}
if (!is_same_net6(&new->start6, &new->end6, new->prefix))
problem = _("inconsistent DHCP range");
if (addr6part(&new->start6) > addr6part(&new->end6))
{
struct in6_addr tmp = new->start6;
new->start6 = new->end6;
new->end6 = tmp;
}
}
daemon->dhcp = new;
if (k >= 4 && strchr(a[3], '.') &&
((new->broadcast.s_addr = inet_addr(a[3])) != (in_addr_t)-1))
{
new->flags |= CONTEXT_BRDCAST;
leasepos = 4;
}
#endif
if (k >= leasepos+1)
{

View File

@@ -481,7 +481,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
if (!message &&
!lease &&
(!(lease = lease_allocate4(mess->yiaddr))))
(!(lease = lease4_allocate(mess->yiaddr))))
message = _("no leases left");
if (!message)
@@ -1189,7 +1189,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
else if (!lease)
{
if ((lease = lease_allocate4(mess->yiaddr)))
if ((lease = lease4_allocate(mess->yiaddr)))
do_classes = 1;
else
message = _("no leases left");

View File

@@ -23,6 +23,7 @@ static size_t outpacket_counter;
static int make_duid1(unsigned short type, unsigned int flags, char *mac,
size_t maclen, void *parm);
static void do_options6(struct dhcp_context *context, void *oro);
void make_duid(time_t now)
{
@@ -96,9 +97,8 @@ void *opt6_next(void *opts, void *end)
return opts + opt_len;
}
#define opt6_len(opt) ((int)(((unsigned short *)(opt))[1]))
#define opt6_ptr(opt, i) ((void *)&(((unsigned char *)(opt))[4u+(unsigned int)(i)]))
#define opt6_len(opt) (opt6_uint(opt, -2, 2))
#define opt6_ptr(opt, i) ((void *)&(((unsigned char *)(opt))[4+(i)]))
static unsigned int opt6_uint(unsigned char *opt, int offset, int size)
@@ -115,40 +115,73 @@ static unsigned int opt6_uint(unsigned char *opt, int offset, int size)
}
/*
daemon->outpacket_counter = 4; message type and ID
elapsed time:
int o = new_opt(OPTION_ELAPSED_TIME);
put_opt_short(o, 100)
finalise_opt(o);
IA_NA
set of routines to build arbitrarily nested options: eg
int o = new_opt(OPTION_IA_NA);
put_opt_long(o, IAID);
put_opt_long(o, T1);
put_opt_long(0, T2);
put_opt_long(IAID);
put_opt_long(T1);
put_opt_long(T2);
int o1 = new_opt(OPTION_IAADDR);
put_opt(o1, &addr, sizeof(addr));
put_opt_long(preferred_lifetime);
put_opt_long(valid_lifetime);
finalise_opt(o1);
finalise_opt(o);
to go back and fill in fields
int o = new_opt(OPTION_IA_NA);
put_opt_long(IAID);
int t1sav = save_counter(-1);
put_opt_long(0);
put_opt_long(0);
int o1 = new_opt(OPTION_IAADDR);
put_opt(o1, &addr, sizeof(addr));
put_opt_long(o1, preferred_lifetime);
put_opt_long(o1, valid_lifetime);
finalise_opt(o1);
int sav = save_counter(t1sav);
put_opt_long(T1);
save_counter(sav);
finalise_opt(o);
to abandon an option
int o = new_opt(OPTION_IA_NA);
put_opt_long(IAID);
put_opt_long(T1);
put_opt_long(T2);
if (err)
save_counter(o);
*/
void end_opt6(int container)
static void end_opt6(int container)
{
void *p = daemon->outpacket.iov_base + container + 2;
u16 len = outpacket_counter - container - 4 ;
PUTSHORT(len, p);
}
static int save_counter(int newval)
{
int ret = outpacket_counter;
if (newval != -1)
outpacket_counter = newval;
return ret;
}
static void *expand(size_t headroom)
{
@@ -164,7 +197,7 @@ static void *expand(size_t headroom)
return NULL;
}
int new_opt6(int opt)
static int new_opt6(int opt)
{
int ret = outpacket_counter;
void *p;
@@ -181,7 +214,7 @@ int new_opt6(int opt)
void *put_opt6(void *data, size_t len)
static void *put_opt6(void *data, size_t len)
{
void *p;
@@ -191,15 +224,15 @@ void *put_opt6(void *data, size_t len)
return p;
}
void put_opt6_long(unsigned int val)
static void put_opt6_long(unsigned int val)
{
void *p;
if (( p = expand(4)))
PUTLONG(p, val);
PUTLONG(val, p);
}
void put_opt6_short(unsigned int val)
static void put_opt6_short(unsigned int val)
{
void *p;
@@ -207,92 +240,231 @@ void put_opt6_short(unsigned int val)
PUTSHORT(val, p);
}
void put_opt6_byte(unsigned int val)
static void put_opt6_byte(unsigned int val)
{
void *p;
if ((p = expand(1)))
*((unsigned char *)p) = val;
}
static void put_opt6_string(char *s)
{
put_opt6(s, strlen(s));
}
size_t dhcp6_reply(struct dhcp_context *context, size_t sz)
size_t dhcp6_reply(struct dhcp_context *context, size_t sz, time_t now)
{
void *packet_options = ((void *)daemon->dhcp_packet.iov_base) + 4;
void *end = ((void *)daemon->dhcp_packet.iov_base) + sz;
void *na_option, *na_end;
void *opt, *p;
int o;
outpacket_counter = 4; /* skip message type and transaction-id */
int o, msg_type = *((unsigned char *)daemon->dhcp_packet.iov_base);
int make_lease = (msg_type == DHCP6REQUEST || opt6_find(packet_options, end, OPTION6_RAPID_COMMIT, 0));
unsigned char *clid;
int clid_len;
struct dhcp_netid *tags;
/* copy over transaction-id */
memcpy(daemon->outpacket.iov_base, daemon->dhcp_packet.iov_base, 4);
/* set reply message type */
*((unsigned char *)daemon->outpacket.iov_base) = make_lease ? DHCP6REPLY : DHCP6ADVERTISE;
/* skip message type and transaction-id */
outpacket_counter = 4;
if (!(opt = opt6_find(packet_options, end, OPTION6_CLIENT_ID, 1)))
return;
return 0;
clid = opt6_ptr(opt, 0);
clid_len = opt6_len(opt);
o = new_opt6(OPTION6_CLIENT_ID);
put_opt6(opt6_ptr(opt, 0), opt6_len(opt));
put_opt6(clid, clid_len);
end_opt6(o);
/* server-id must match except for SOLICIT meesages */
if (msg_type != DHCP6SOLICIT &&
(!(opt = opt6_find(packet_options, end, OPTION6_SERVER_ID, 1)) ||
opt6_len(opt) != daemon->duid_len ||
memcmp(opt6_ptr(opt, 0), daemon->duid, daemon->duid_len) != 0))
return 0;
o = new_opt6(OPTION6_SERVER_ID);
put_opt6(daemon->duid, daemon->duid_len);
end_opt6(o);
switch (msg_type)
{
case DHCP6SOLICIT:
case DHCP6REQUEST:
{
u16 *req_options = NULL;
if ((opt = opt6_find(packet_options, end, OPTION6_IA_NA, 12)))
{
while (opt = opt6_find(opt, end, OPTION6_IA_NA, 12))
{
void *ia_end = opt6_ptr(opt, opt6_len(opt));
void *ia_option = opt6_find(opt6_ptr(opt, 12), ia_end, OPTION6_IAADDR, 24);
unsigned int iaid = opt6_uint(opt, 0, 4);
unsigned int t1 = opt6_uint(opt, 4, 4);
unsigned int t2 = opt6_uint(opt, 8, 4);
if (ia_option)
while ((ia_option = ia_option, ia_end, OPTION6_IAADDR, 24))
for (opt = opt6_find(packet_options, end, OPTION6_IA_NA, 12);
opt;
opt = opt6_find(opt6_next(opt, end), end, OPTION6_IA_NA, 12))
{
void *ia_end = opt6_ptr(opt, opt6_len(opt));
void *ia_option = opt6_find(opt6_ptr(opt, 12), ia_end, OPTION6_IAADDR, 24);
unsigned int min_time = 0xffffffff;
int t1cntr;
unsigned int iaid = opt6_uint(opt, 0, 4);
int address_assigned = 0;
struct dhcp_lease *lease = NULL;
o = new_opt6(OPTION6_IA_NA);
put_opt6_long(iaid);
/* save pointer */
t1cntr = save_counter(-1);
/* so we can fill these in later */
put_opt6_long(0);
put_opt6_long(0);
while (1)
{
/* do address option */
struct in6_addr alloced_addr, *addrp = NULL;
ia_option = opt6_next(ia_option, ia_end);
}
else
{
/* no preferred address call address allocate */
}
opt = opt6_next(opt, end);
}
}
else if ((opt = opt6_find(packet_options, end, OPTION6_IA_TA, 4)))
while (opt = opt6_find(opt, end, OPTION6_IA_TA, 4))
{
void *ia_end = opt6_ptr(opt, opt6_len(opt));
void *ia_option = opt6_find(opt6_ptr(opt, 4), ia_end, OPTION6_IAADDR, 24);
if (ia_option)
{
struct in6_addr *req_addr = opt6_ptr(ia_option, 0);
u32 preferred_lifetime = opt6_uint(ia_option, 16, 4);
u32 valid_lifetime = opt6_uint(ia_option, 20, 4);
if ((lease = lease6_find_by_addr(req_addr, 128, 0)))
{
/* check if existing lease for host */
if (clid_len == lease->clid_len &&
memcmp(clid, lease->clid, clid_len) == 0)
addrp = req_addr;
}
else if (address6_available(context, req_addr, tags))
addrp = req_addr;
}
else
{
/* must have an address to CONFIRM */
if (msg_type == DHCP6REQUEST)
return 0;
/* existing lease */
if ((lease = lease6_find_by_client(clid, clid_len, iaid)))
addrp = (struct in6_addr *)&lease->hwaddr;
else if (address6_allocate(context, clid, clid_len, tags, &alloced_addr))
addrp = &alloced_addr;
}
if (addrp)
{
unsigned int lease_time;
address_assigned = 1;
context = narrow_context6(context, addrp, tags);
lease_time = context->lease_time;
if (lease_time < min_time)
min_time = lease_time;
/* May fail to create lease */
if (!lease && make_lease)
lease = lease6_allocate(addrp);
if (lease)
{
lease_set_expires(lease, lease_time, now);
lease_set_hwaddr(lease, NULL, clid, 0, iaid, clid_len);
}
if (lease || !make_lease)
{
int o1 = new_opt6(OPTION6_IAADDR);
put_opt6(addrp, sizeof(*addrp));
put_opt6_long(lease_time);
put_opt6_long(lease_time);
end_opt6(o1);
}
}
if (!ia_option ||
!(ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24)))
{
if (address_assigned)
{
/* go back an fill in fields in IA_NA option */
unsigned int t1 = min_time == 0xffffffff ? 0xffffffff : min_time/2;
unsigned int t2 = min_time == 0xffffffff ? 0xffffffff : (min_time/8) * 7;
int sav = save_counter(t1cntr);
put_opt6_long(t1);
put_opt6_long(t2);
save_counter(sav);
}
else
{
/* no address, return erro */
int o1 = new_opt6(OPTION6_STATUS_CODE);
put_opt6_short(DHCP6NOADDRS);
put_opt6_string("No addresses available");
end_opt6(o1);
}
end_opt6(o);
break;
}
}
}
unsigned int iaid = opt6_uint(opt, 0, 4);
if (ia_option)
while ((ia_option = ia_option, ia_end, OPTION6_IAADDR, 24))
{
/* do address option */
ia_option = opt6_next(ia_option, ia_end);
}
else
/* same again for TA */
for (opt = packet_options; opt; opt = opt6_find(opt6_next(opt, end), end, OPTION6_IA_TA, 4))
{
/* no preferred address */
}
opt = opt6_next(opt, end);
do_options6(context, opt6_find(packet_options, end, OPTION6_ORO, 0));
}
else
return; /* no IA_NA and no IA_TA */
}
return outpacket_counter;
}
/* TODO tags to select options, and encapsualted options. */
static void do_options6(struct dhcp_context *context, void *oro)
{
unsigned char *req_options = NULL;
int req_options_len, i, o;
struct dhcp_opt *opt, *config_opts = daemon->dhcp_opts6;
if (oro)
{
req_options = opt6_ptr(oro, 0);
req_options_len = opt6_len(oro);
}
for (opt = config_opts; opt; opt = opt->next)
{
if (req_options)
{
/* required options are not aligned... */
for (i = 0; i < req_options_len - 1; i += 2)
if (((req_options[i] << 8) | req_options[i+1]) == opt->opt)
break;
/* option not requested */
if (i == req_options_len)
continue;
}
o = new_opt6(opt->opt);
put_opt6(opt->val, opt->len);
end_opt6(o);
}
}
#endif

View File

@@ -336,6 +336,29 @@ int is_same_net6(struct in6_addr *a, struct in6_addr *b, int prefixlen)
return 0;
}
/* return least signigicant 64 bits if IPv6 address */
u64 addr6part(struct in6_addr *addr)
{
int i;
u64 ret = 0;
for (i = 8; i < 16; i++)
ret = (ret << 8) + addr->s6_addr[i];
return ret;
}
void setaddr6part(struct in6_addr *addr, u64 host)
{
int i;
for (i = 15; i >= 8; i--)
{
addr->s6_addr[i] = host;
host = host >> 8;
}
}
#endif