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

@@ -45,7 +45,7 @@ VERSION= -DVERSION='\"`../bld/get-version`\"'
OBJS = cache.o rfc1035.o util.o option.o forward.o network.o \ OBJS = cache.o rfc1035.o util.o option.o forward.o network.o \
dnsmasq.o dhcp.o lease.o rfc2131.o netlink.o dbus.o bpf.o \ dnsmasq.o dhcp.o lease.o rfc2131.o netlink.o dbus.o bpf.o \
helper.o tftp.o log.o conntrack.o dhcp6.o rfc3315.o helper.o tftp.o log.o conntrack.o dhcp6.o rfc3315.o dhcp-common.o
all : all :
@cd $(SRC) && $(MAKE) \ @cd $(SRC) && $(MAKE) \
@@ -88,10 +88,10 @@ merge :
# rules below are targets in recusive makes with cwd=$(SRC) # rules below are targets in recusive makes with cwd=$(SRC)
.c.o: .c.o:
$(CC) $(CFLAGS) $(COPTS) $(I18N) $(BUILD_CFLAGS) $(RPM_OPT_FLAGS) -c $< $(CC) $(CFLAGS) $(COPTS) $(I18N) $(BUILD_CFLAGS) $(RPM_OPT_FLAGS) -c $<
dnsmasq : $(OBJS) dnsmasq : $(OBJS)
$(CC) $(LDFLAGS) -o $@ $(OBJS) $(BUILD_LIBS) $(LIBS) $(CC) $(LDFLAGS) -o $@ $(OBJS) $(BUILD_LIBS) $(LIBS)
dnsmasq.pot : $(OBJS:.o=.c) dnsmasq.h config.h dnsmasq.pot : $(OBJS:.o=.c) dnsmasq.h config.h

View File

@@ -6,7 +6,8 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES := bpf.c cache.c dbus.c dhcp.c dnsmasq.c \ LOCAL_SRC_FILES := bpf.c cache.c dbus.c dhcp.c dnsmasq.c \
forward.c helper.c lease.c log.c \ forward.c helper.c lease.c log.c \
netlink.c network.c option.c rfc1035.c \ netlink.c network.c option.c rfc1035.c \
rfc2131.c tftp.c util.c conntrack.c rfc2131.c tftp.c util.c conntrack.c \
dhcp6.c rfc3315.c dhcp-common.c
LOCAL_MODULE := dnsmasq LOCAL_MODULE := dnsmasq

View File

@@ -1,15 +0,0 @@
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

@@ -153,7 +153,25 @@ int iface_enumerate(int family, void *parm, int (*callback)())
ifr = (struct ifreq *)ifreq.iov_base; ifr = (struct ifreq *)ifreq.iov_base;
memcpy(ifr, ptr, len); memcpy(ifr, ptr, len);
#ifdef HAVE_DHCP6
if (family == AF_LOCAL)
{
unsigned int flags;
if (ioctl(fd, SIOCGIFFLAGS, ifr) != -1)
{
flags = ifr.ifr_flags;
ifr->ifr_addr.sa_family = AF_LINK;
if (ioctl(fd, SIOCGIFADDR, ifr) != -1 &&
!((*callback)((unsigned int) htons(ETHERTYPE_IP),
(unsigned int)link->ifi_flags,
LLADDR((struct sockaddr_dl *)&ifr->ifr_addr), ETHER_ADDR_LEN, parm)))
goto err;
}
continue;
}
#endif
if (ifr->ifr_addr.sa_family == family) if (ifr->ifr_addr.sa_family == family)
{ {
if (family == AF_INET) if (family == AF_INET)

View File

@@ -782,7 +782,7 @@ static int read_hostsfile(char *filename, int index, int cache_size, struct crec
{ {
flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV6; flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV6;
addrlen = IN6ADDRSZ; addrlen = IN6ADDRSZ;
domain_suffix = daemon->domain_suffix; domain_suffix = get_domain6(&addr.addr.addr6);
} }
#else #else
if ((addr.addr.addr4.s_addr = inet_addr(token)) != (in_addr_t) -1) if ((addr.addr.addr4.s_addr = inet_addr(token)) != (in_addr_t) -1)
@@ -920,6 +920,24 @@ char *get_domain(struct in_addr addr)
return daemon->domain_suffix; return daemon->domain_suffix;
} }
#ifdef HAVE_IPV6
char *get_domain6(struct in6_addr *addr)
{
struct cond_domain6 *c;
u64 addrpart = addr6part(addr);
for (c = daemon->cond_domain6; c; c = c->next)
if (is_same_net6(addr, &c->start, 64) &&
addrpart >= addr6part(&c->start) &&
addrpart <= addr6part(&c->end))
return c->domain;
return daemon->domain_suffix;
}
#endif
#ifdef HAVE_DHCP #ifdef HAVE_DHCP
struct in_addr a_record_from_hosts(char *name, time_t now) struct in_addr a_record_from_hosts(char *name, time_t now)
{ {
@@ -953,15 +971,24 @@ void cache_unhash_dhcp(void)
up = &cache->hash_next; up = &cache->hash_next;
} }
void cache_add_dhcp_entry(char *host_name, void cache_add_dhcp_entry(char *host_name, int prot,
struct in_addr *host_address, time_t ttd) struct all_addr *host_address, time_t ttd)
{ {
struct crec *crec = NULL, *aliasc; struct crec *crec = NULL, *aliasc;
unsigned short flags = F_NAMEP | F_DHCP | F_FORWARD | F_IPV4 | F_REVERSE; unsigned short flags = F_IPV4;
int in_hosts = 0; int in_hosts = 0;
struct cname *a; struct cname *a;
size_t addrlen = sizeof(struct in_addr);
#ifdef HAVE_IPV6
if (prot == AF_INET6)
{
flags = F_IPV6;
addrlen = sizeof(struct in6_addr);
}
#endif
while ((crec = cache_find_by_name(crec, host_name, 0, F_IPV4 | F_CNAME))) while ((crec = cache_find_by_name(crec, host_name, 0, flags | F_CNAME)))
{ {
/* check all addresses associated with name */ /* check all addresses associated with name */
if (crec->flags & F_HOSTS) if (crec->flags & F_HOSTS)
@@ -969,23 +996,25 @@ void cache_add_dhcp_entry(char *host_name,
/* if in hosts, don't need DHCP record */ /* if in hosts, don't need DHCP record */
in_hosts = 1; in_hosts = 1;
inet_ntop(prot, host_address, daemon->addrbuff, ADDRSTRLEN);
if (crec->flags & F_CNAME) if (crec->flags & F_CNAME)
my_syslog(MS_DHCP | LOG_WARNING, my_syslog(MS_DHCP | LOG_WARNING,
_("%s is a CNAME, not giving it to the DHCP lease of %s"), _("%s is a CNAME, not giving it to the DHCP lease of %s"),
host_name, inet_ntoa(*host_address)); host_name, daemon->addrbuff);
else if (crec->addr.addr.addr.addr4.s_addr != host_address->s_addr) else if (memcmp(&crec->addr.addr, host_address, addrlen) != 0)
{ {
strcpy(daemon->namebuff, inet_ntoa(crec->addr.addr.addr.addr4)); inet_ntop(prot, &crec->addr.addr, daemon->namebuff, MAXDNAME);
my_syslog(MS_DHCP | LOG_WARNING, my_syslog(MS_DHCP | LOG_WARNING,
_("not giving name %s to the DHCP lease of %s because " _("not giving name %s to the DHCP lease of %s because "
"the name exists in %s with address %s"), "the name exists in %s with address %s"),
host_name, inet_ntoa(*host_address), host_name, daemon->addrbuff,
record_source(crec->uid), daemon->namebuff); record_source(crec->uid), daemon->namebuff);
} }
} }
else if (!(crec->flags & F_DHCP)) else if (!(crec->flags & F_DHCP))
{ {
cache_scan_free(host_name, NULL, 0, crec->flags & (F_IPV4 | F_CNAME | F_FORWARD)); cache_scan_free(host_name, NULL, 0, crec->flags & (flags | F_CNAME | F_FORWARD));
/* scan_free deletes all addresses associated with name */ /* scan_free deletes all addresses associated with name */
break; break;
} }
@@ -994,14 +1023,16 @@ void cache_add_dhcp_entry(char *host_name,
if (in_hosts) if (in_hosts)
return; return;
if ((crec = cache_find_by_addr(NULL, (struct all_addr *)host_address, 0, F_IPV4))) if ((crec = cache_find_by_addr(NULL, (struct all_addr *)host_address, 0, flags)))
{ {
if (crec->flags & F_NEG) if (crec->flags & F_NEG)
cache_scan_free(NULL, (struct all_addr *)host_address, 0, F_IPV4 | F_REVERSE); {
else flags |= F_REVERSE;
/* avoid multiple reverse mappings */ cache_scan_free(NULL, (struct all_addr *)host_address, 0, flags);
flags &= ~F_REVERSE; }
} }
else
flags |= F_REVERSE;
if ((crec = dhcp_spare)) if ((crec = dhcp_spare))
dhcp_spare = dhcp_spare->next; dhcp_spare = dhcp_spare->next;
@@ -1010,12 +1041,12 @@ void cache_add_dhcp_entry(char *host_name,
if (crec) /* malloc may fail */ if (crec) /* malloc may fail */
{ {
crec->flags = flags; crec->flags = flags | F_NAMEP | F_DHCP | F_FORWARD;
if (ttd == 0) if (ttd == 0)
crec->flags |= F_IMMORTAL; crec->flags |= F_IMMORTAL;
else else
crec->ttd = ttd; crec->ttd = ttd;
crec->addr.addr.addr.addr4 = *host_address; crec->addr.addr = *host_address;
crec->name.namep = host_name; crec->name.namep = host_name;
crec->uid = uid++; crec->uid = uid++;
cache_hash(crec); cache_hash(crec);

View File

@@ -116,7 +116,7 @@ RESOLVFILE
has no library dependencies other than libc */ has no library dependencies other than libc */
#define HAVE_DHCP #define HAVE_DHCP
/* #define HAVE_DHCP6 */ #define HAVE_DHCP6
#define HAVE_TFTP #define HAVE_TFTP
#define HAVE_SCRIPT #define HAVE_SCRIPT
/* #define HAVE_LUASCRIPT */ /* #define HAVE_LUASCRIPT */

213
src/dhcp-common.c Normal file
View File

@@ -0,0 +1,213 @@
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 dated June, 1991, or
(at your option) version 3 dated 29 June, 2007.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "dnsmasq.h"
#ifdef HAVE_DHCP
void dhcp_common_init(void)
{
/* 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);
/* dhcp_packet is used by v4 and v6, outpacket only by v6
sizeof(struct dhcp_packet) is as good an initial size as any,
even for v6 */
expand_buf(&daemon->dhcp_packet, sizeof(struct dhcp_packet));
#ifdef HAVE_DHCP6
if (daemon->dhcp6)
expand_buf(&daemon->outpacket, sizeof(struct dhcp_packet));
#endif
}
ssize_t recv_dhcp_packet(int fd, struct msghdr *msg)
{
ssize_t sz;
while (1)
{
msg->msg_flags = 0;
while ((sz = recvmsg(fd, msg, MSG_PEEK | MSG_TRUNC)) == -1 && errno == EINTR);
if (sz == -1)
return -1;
if (!(msg->msg_flags & MSG_TRUNC))
break;
/* Very new Linux kernels return the actual size needed,
older ones always return truncated size */
if ((size_t)sz == daemon->dhcp_packet.iov_len)
{
if (!expand_buf(&daemon->dhcp_packet, sz + 100))
return -1;
}
else
{
expand_buf(&daemon->dhcp_packet, sz);
break;
}
}
while ((sz = recvmsg(fd, msg, 0)) == -1 && errno == EINTR);
return (msg->msg_flags & MSG_TRUNC) ? -1 : sz;
}
struct dhcp_netid *run_tag_if(struct dhcp_netid *tags)
{
struct tag_if *exprs;
struct dhcp_netid_list *list;
for (exprs = daemon->tag_if; exprs; exprs = exprs->next)
if (match_netid(exprs->tag, tags, 1))
for (list = exprs->set; list; list = list->next)
{
list->list->next = tags;
tags = list->list;
}
return tags;
}
struct dhcp_netid *option_filter(struct dhcp_netid *tags, struct dhcp_netid *context_tags, struct dhcp_opt *opts)
{
struct dhcp_netid *tagif = run_tag_if(tags);
struct dhcp_opt *opt;
/* flag options which are valid with the current tag set (sans context tags) */
for (opt = opts; opt; opt = opt->next)
{
opt->flags &= ~DHOPT_TAGOK;
if (!(opt->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925)) &&
match_netid(opt->netid, tagif, 0))
opt->flags |= DHOPT_TAGOK;
}
/* now flag options which are valid, including the context tags,
otherwise valid options are inhibited if we found a higher priotity one above */
if (context_tags)
{
struct dhcp_netid *last_tag;
for (last_tag = context_tags; last_tag->next; last_tag = last_tag->next);
last_tag->next = tags;
tagif = run_tag_if(context_tags);
for (opt = opts; opt; opt = opt->next)
if (!(opt->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925 | DHOPT_TAGOK)) &&
match_netid(opt->netid, tagif, 0))
{
struct dhcp_opt *tmp;
for (tmp = opts; tmp; tmp = tmp->next)
if (tmp->opt == opt->opt && opt->netid && (tmp->flags & DHOPT_TAGOK))
break;
if (!tmp)
opt->flags |= DHOPT_TAGOK;
}
}
/* now flag untagged options which are not overridden by tagged ones */
for (opt = opts; opt; opt = opt->next)
if (!(opt->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925 | DHOPT_TAGOK)) && !opt->netid)
{
struct dhcp_opt *tmp;
for (tmp = opts; tmp; tmp = tmp->next)
if (tmp->opt == opt->opt && (tmp->flags & DHOPT_TAGOK))
break;
if (!tmp)
opt->flags |= DHOPT_TAGOK;
else if (!tmp->netid)
my_syslog(MS_DHCP | LOG_WARNING, _("Ignoring duplicate dhcp-option %d"), tmp->opt);
}
return tagif;
}
/* Is every member of check matched by a member of pool?
If tagnotneeded, untagged is OK */
int match_netid(struct dhcp_netid *check, struct dhcp_netid *pool, int tagnotneeded)
{
struct dhcp_netid *tmp1;
if (!check && !tagnotneeded)
return 0;
for (; check; check = check->next)
{
/* '#' for not is for backwards compat. */
if (check->net[0] != '!' && check->net[0] != '#')
{
for (tmp1 = pool; tmp1; tmp1 = tmp1->next)
if (strcmp(check->net, tmp1->net) == 0)
break;
if (!tmp1)
return 0;
}
else
for (tmp1 = pool; tmp1; tmp1 = tmp1->next)
if (strcmp((check->net)+1, tmp1->net) == 0)
return 0;
}
return 1;
}
/* return domain or NULL if none. */
char *strip_hostname(char *hostname)
{
char *dot = strchr(hostname, '.');
if (!dot)
return NULL;
*dot = 0; /* truncate */
if (strlen(dot+1) != 0)
return dot+1;
return NULL;
}
void log_tags(struct dhcp_netid *netid, u32 xid)
{
if (netid && option_bool(OPT_LOG_OPTS))
{
char *s = daemon->namebuff;
for (*s = 0; netid; netid = netid->next)
{
/* kill dupes. */
struct dhcp_netid *n;
for (n = netid->next; n; n = n->next)
if (strcmp(netid->net, n->net) == 0)
break;
if (!n)
{
strncat (s, netid->net, (MAXDNAME-1) - strlen(s));
if (netid->next)
strncat (s, ", ", (MAXDNAME-1) - strlen(s));
}
}
my_syslog(MS_DHCP | LOG_INFO, _("%u tags: %s"), xid, s);
}
}
#endif

View File

@@ -119,42 +119,6 @@ void dhcp_init(void)
#endif #endif
check_dhcp_hosts(1); check_dhcp_hosts(1);
expand_buf(&daemon->dhcp_packet, sizeof(struct dhcp_packet));
}
ssize_t recv_dhcp_packet(int fd, struct msghdr *msg)
{
ssize_t sz;
while (1)
{
msg->msg_flags = 0;
while ((sz = recvmsg(fd, msg, MSG_PEEK | MSG_TRUNC)) == -1 && errno == EINTR);
if (sz == -1)
return -1;
if (!(msg->msg_flags & MSG_TRUNC))
break;
/* Very new Linux kernels return the actual size needed,
older ones always return truncated size */
if ((size_t)sz == daemon->dhcp_packet.iov_len)
{
if (!expand_buf(&daemon->dhcp_packet, sz + 100))
return -1;
}
else
{
expand_buf(&daemon->dhcp_packet, sz);
break;
}
}
while ((sz = recvmsg(fd, msg, 0)) == -1 && errno == EINTR);
return (msg->msg_flags & MSG_TRUNC) ? -1 : sz;
} }
void dhcp_packet(time_t now, int pxe_fd) void dhcp_packet(time_t now, int pxe_fd)
@@ -610,50 +574,6 @@ struct dhcp_config *config_find_by_address(struct dhcp_config *configs, struct i
return NULL; return NULL;
} }
/* Is every member of check matched by a member of pool?
If tagnotneeded, untagged is OK */
int match_netid(struct dhcp_netid *check, struct dhcp_netid *pool, int tagnotneeded)
{
struct dhcp_netid *tmp1;
if (!check && !tagnotneeded)
return 0;
for (; check; check = check->next)
{
/* '#' for not is for backwards compat. */
if (check->net[0] != '!' && check->net[0] != '#')
{
for (tmp1 = pool; tmp1; tmp1 = tmp1->next)
if (strcmp(check->net, tmp1->net) == 0)
break;
if (!tmp1)
return 0;
}
else
for (tmp1 = pool; tmp1; tmp1 = tmp1->next)
if (strcmp((check->net)+1, tmp1->net) == 0)
return 0;
}
return 1;
}
struct dhcp_netid *run_tag_if(struct dhcp_netid *tags)
{
struct tag_if *exprs;
struct dhcp_netid_list *list;
for (exprs = daemon->tag_if; exprs; exprs = exprs->next)
if (match_netid(exprs->tag, tags, 1))
for (list = exprs->set; list; list = list->next)
{
list->list->next = tags;
tags = list->list;
}
return tags;
}
int address_allocate(struct dhcp_context *context, int address_allocate(struct dhcp_context *context,
struct in_addr *addrp, unsigned char *hwaddr, int hw_len, struct in_addr *addrp, unsigned char *hwaddr, int hw_len,
struct dhcp_netid *netids, time_t now) struct dhcp_netid *netids, time_t now)
@@ -849,7 +769,7 @@ struct dhcp_config *find_config(struct dhcp_config *configs,
is_addr_in_context(context, config)) is_addr_in_context(context, config))
return config; return config;
/* use match with fewest wildcast octets */ /* use match with fewest wildcard octets */
for (candidate = NULL, count = 0, config = configs; config; config = config->next) for (candidate = NULL, count = 0, config = configs; config; config = config->next)
if (is_addr_in_context(context, config)) if (is_addr_in_context(context, config))
for (conf_addr = config->hwaddr; conf_addr; conf_addr = conf_addr->next) for (conf_addr = config->hwaddr; conf_addr; conf_addr = conf_addr->next)
@@ -1145,20 +1065,5 @@ char *host_from_dns(struct in_addr addr)
return NULL; return NULL;
} }
/* return domain or NULL if none. */
char *strip_hostname(char *hostname)
{
char *dot = strchr(hostname, '.');
if (!dot)
return NULL;
*dot = 0; /* truncate */
if (strlen(dot+1) != 0)
return dot+1;
return NULL;
}
#endif #endif

View File

@@ -23,27 +23,40 @@ struct iface_param {
int ind; int ind;
}; };
struct listen_param {
int fd_or_iface;
struct listen_param *next;
};
static int join_multicast(struct in6_addr *local, int prefix, static int join_multicast(struct in6_addr *local, int prefix,
int scope, int if_index, int dad, void *vparam); int scope, int if_index, int dad, void *vparam);
static int complete_context6(struct in6_addr *local, int prefix, static int complete_context6(struct in6_addr *local, int prefix,
int scope, int if_index, int dad, void *vparam); int scope, int if_index, int dad, void *vparam);
static int make_duid1(unsigned int type, unsigned int flags, char *mac,
size_t maclen, void *parm);
void dhcp6_init(void) void dhcp6_init(void)
{ {
int fd; int fd;
struct sockaddr_in6 saddr; struct sockaddr_in6 saddr;
struct listen_param *listenp, listen;
#if defined(IP_TOS) && defined(IPTOS_CLASS_CS6)
int class = IPTOS_CLASS_CS6; int class = IPTOS_CLASS_CS6;
#endif
if ((fd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP)) == -1 || if ((fd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP)) == -1 ||
#if defined(IP_TOS) && defined(IPTOS_CLASS_CS6)
setsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS, &class, sizeof(class)) == -1 || setsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS, &class, sizeof(class)) == -1 ||
#endif
!fix_fd(fd) || !fix_fd(fd) ||
!set_ipv6pktinfo(fd)) !set_ipv6pktinfo(fd))
die (_("cannot create DHCPv6 socket: %s"), NULL, EC_BADNET); die (_("cannot create DHCPv6 socket: %s"), NULL, EC_BADNET);
memset(&saddr, 0, sizeof(saddr)); memset(&saddr, 0, sizeof(saddr));
#ifdef HAVE_SOCKADDR_SA_LEN #ifdef HAVE_SOCKADDR_SA_LEN
saddr.sin6_len = sizeof(addr.in6); saddr.sin6_len = sizeof(struct sockaddr_in6);
#endif #endif
saddr.sin6_family = AF_INET6; saddr.sin6_family = AF_INET6;
saddr.sin6_addr = in6addr_any; saddr.sin6_addr = in6addr_any;
@@ -53,16 +66,18 @@ void dhcp6_init(void)
die(_("failed to bind DHCPv6 server socket: %s"), NULL, EC_BADNET); die(_("failed to bind DHCPv6 server socket: %s"), NULL, EC_BADNET);
/* join multicast groups on each interface we're interested in */ /* join multicast groups on each interface we're interested in */
if (!iface_enumerate(AF_INET6, &fd, join_multicast)) listen.fd_or_iface = fd;
listen.next = NULL;
if (!iface_enumerate(AF_INET6, &listen, join_multicast))
die(_("failed to join DHCPv6 multicast group: %s"), NULL, EC_BADNET); die(_("failed to join DHCPv6 multicast group: %s"), NULL, EC_BADNET);
for (listenp = listen.next; listenp; )
{
struct listen_param *tmp = listenp->next;
free(listenp);
listenp = tmp;
}
daemon->dhcp6fd = fd; 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, static int join_multicast(struct in6_addr *local, int prefix,
@@ -70,20 +85,25 @@ static int join_multicast(struct in6_addr *local, int prefix,
{ {
char ifrn_name[IFNAMSIZ]; char ifrn_name[IFNAMSIZ];
struct ipv6_mreq mreq; struct ipv6_mreq mreq;
struct in6_addr maddr; struct listen_param *listenp, *param = vparam;
int fd = *((int *)vparam); int fd = param->fd_or_iface;
struct dhcp_context *context; struct dhcp_context *context;
struct iname *tmp; struct iname *tmp;
(void)prefix; (void)prefix;
(void)scope;
(void)dad;
/* record which interfaces we join on, so
that we do it at most one per interface, even when they
have multiple addresses */
for (listenp = param->next; listenp; listenp = listenp->next)
if (if_index == listenp->fd_or_iface)
return 1;
/* scope == link */
if (scope != 253)
return 1;
if (!indextoname(fd, if_index, ifrn_name)) if (!indextoname(fd, if_index, ifrn_name))
return 0; return 0;
/* Are we doing DHCP on this interface? */ /* Are we doing DHCP on this interface? */
if (!iface_check(AF_INET6, (struct all_addr *)local, ifrn_name)) if (!iface_check(AF_INET6, (struct all_addr *)local, ifrn_name))
return 1; return 1;
@@ -111,8 +131,12 @@ static int join_multicast(struct in6_addr *local, int prefix,
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 0;
listenp = whine_malloc(sizeof(struct listen_param));
listenp->fd_or_iface = if_index;
listenp->next = param->next;
param->next = listenp;
return 1; return 1;
} }
@@ -176,7 +200,7 @@ void dhcp6_packet(time_t now)
if (!context) if (!context)
return; return;
/* unlinked contexts are marked by context->current == context */ /* unlinked contexts are marked by context->current == context */
for (context = daemon->dhcp6; context; context = context->next) for (context = daemon->dhcp6; context; context = context->next)
context->current = context; context->current = context;
@@ -190,14 +214,15 @@ void dhcp6_packet(time_t now)
lease_prune(NULL, now); /* lose any expired leases */ lease_prune(NULL, now); /* lose any expired leases */
msg.msg_iov = &daemon->dhcp_packet; msg.msg_iov = &daemon->dhcp_packet;
sz = dhcp6_reply(parm.current, sz, now); sz = dhcp6_reply(parm.current, ifr.ifr_name, sz, IN6_IS_ADDR_MULTICAST(&from), now);
/* ifr.ifr_name, if_index, (size_t)sz, /* ifr.ifr_name, if_index, (size_t)sz,
now, unicast_dest, &is_inform, pxe_fd, iface_addr); */ now, unicast_dest, &is_inform, pxe_fd, iface_addr); */
lease_update_file(now); lease_update_file(now);
lease_update_dns(); lease_update_dns();
if (sz != 0) if (sz != 0)
send_from(daemon->dhcp6fd, 0, daemon->outpacket.iov_base, sz, &from, &dest, if_index); while (sendto(daemon->dhcp6fd, daemon->outpacket.iov_base, sz, 0, (struct sockaddr *)&from, sizeof(from)) &&
retry_send());
} }
static int complete_context6(struct in6_addr *local, int prefix, static int complete_context6(struct in6_addr *local, int prefix,
@@ -205,11 +230,16 @@ static int complete_context6(struct in6_addr *local, int prefix,
{ {
struct dhcp_context *context; struct dhcp_context *context;
struct iface_param *param = vparam; struct iface_param *param = vparam;
(void)scope; /* warning */ (void)scope; /* warning */
(void)dad;
for (context = daemon->dhcp6; context; context = context->next) for (context = daemon->dhcp6; context; context = context->next)
{ {
if (prefix == context->prefix && if (prefix == context->prefix &&
!IN6_IS_ADDR_LOOPBACK(local) &&
!IN6_IS_ADDR_LINKLOCAL(local) &&
!IN6_IS_ADDR_MULTICAST(local) &&
is_same_net6(local, &context->start6, prefix) && is_same_net6(local, &context->start6, prefix) &&
is_same_net6(local, &context->end6, prefix)) is_same_net6(local, &context->end6, prefix))
{ {
@@ -218,6 +248,7 @@ static int complete_context6(struct in6_addr *local, int prefix,
{ {
context->current = param->current; context->current = param->current;
param->current = context; param->current = context;
context->local6 = *local;
} }
} }
} }
@@ -238,7 +269,7 @@ struct dhcp_config *config_find_by_address6(struct dhcp_config *configs, struct
} }
int address6_allocate(struct dhcp_context *context, unsigned char *clid, int clid_len, int address6_allocate(struct dhcp_context *context, unsigned char *clid, int clid_len,
struct dhcp_netid *netids, struct in6_addr *ans) int serial, struct dhcp_netid *netids, struct in6_addr *ans)
{ {
/* Find a free address: exclude anything in use and anything allocated to /* Find a free address: exclude anything in use and anything allocated to
a particular hwaddr/clientid/hostname in our configuration. a particular hwaddr/clientid/hostname in our configuration.
@@ -266,7 +297,7 @@ int address6_allocate(struct dhcp_context *context, unsigned char *clid, int cl
continue; continue;
else else
{ {
start = addr6part(&c->start6) + ((j + c->addr_epoch) % (1 + addr6part(&c->end6) - addr6part(&c->start6))); start = addr6part(&c->start6) + ((j + c->addr_epoch + serial) % (1 + addr6part(&c->end6) - addr6part(&c->start6)));
/* iterate until we find a free address. */ /* iterate until we find a free address. */
addr = start; addr = start;
@@ -358,6 +389,133 @@ struct dhcp_context *narrow_context6(struct dhcp_context *context,
return tmp; return tmp;
} }
static int is_addr_in_context6(struct dhcp_context *context, struct dhcp_config *config)
{
if (!context) /* called via find_config() from lease_update_from_configs() */
return 1;
if (!(config->flags & CONFIG_ADDR6))
return 1;
for (; context; context = context->current)
if (is_same_net6(&config->addr6, &context->start6, context->prefix))
return 1;
return 0;
}
struct dhcp_config *find_config6(struct dhcp_config *configs,
struct dhcp_context *context,
unsigned char *duid, int duid_len,
char *hostname)
{
int count, new;
struct dhcp_config *config;
struct hwaddr_config *conf_addr;
unsigned char *hwaddr = NULL;
int duid_type, hw_len = 0, hw_type = 0;
if (duid)
{
for (config = configs; config; config = config->next)
if (config->flags & CONFIG_CLID)
{
if (config->clid_len == duid_len &&
memcmp(config->clid, duid, duid_len) == 0 &&
is_addr_in_context6(context, config))
return config;
}
/* DHCPv6 doesn't deal in MAC addresses per-se, but some DUIDs do include
MAC addresses, so we try and parse them out here. Not that there is only one
DUID per host and it's created using any one of the MACs, so this is no
good no good for multihomed hosts. */
hwaddr = duid;
GETSHORT(duid_type, hwaddr);
if (duid_type == 1 || duid_type == 3)
{
GETSHORT(hw_type, hwaddr);
if (duid_type == 1)
hwaddr += 4; /* skip time */
hw_len = duid_len - 8;
}
if (hwaddr)
for (config = configs; config; config = config->next)
if (config_has_mac(config, hwaddr, hw_len, hw_type) &&
is_addr_in_context6(context, config))
return config;
}
if (hostname && context)
for (config = configs; config; config = config->next)
if ((config->flags & CONFIG_NAME) &&
hostname_isequal(config->hostname, hostname) &&
is_addr_in_context6(context, config))
return config;
/* use match with fewest wildcard octets */
if (hwaddr)
{
struct dhcp_config *candidate;
for (candidate = NULL, count = 0, config = configs; config; config = config->next)
if (is_addr_in_context6(context, config))
for (conf_addr = config->hwaddr; conf_addr; conf_addr = conf_addr->next)
if (conf_addr->wildcard_mask != 0 &&
conf_addr->hwaddr_len == hw_len &&
(conf_addr->hwaddr_type == hw_type || conf_addr->hwaddr_type == 0) &&
(new = memcmp_masked(conf_addr->hwaddr, hwaddr, hw_len, conf_addr->wildcard_mask)) > count)
{
count = new;
candidate = config;
}
return candidate;
}
return NULL;
}
void make_duid(time_t now)
{
/* rebase epoch to 1/1/2000 */
time_t newnow = now - 946684800;
iface_enumerate(AF_LOCAL, &newnow, make_duid1);
if (!daemon->duid)
die("Cannot create DHCPv6 server DUID", NULL, EC_MISC);
}
static int make_duid1(unsigned int type, unsigned int flags, char *mac,
size_t maclen, void *parm)
{
/* create DUID as specified in RFC3315. We use the MAC of the
first interface we find that isn't loopback or P-to-P */
unsigned char *p;
if (flags & (IFF_LOOPBACK | IFF_POINTOPOINT))
return 1;
daemon->duid = p = safe_malloc(maclen + 8);
daemon->duid_len = maclen + 8;
#ifdef HAVE_BROKEN_RTC
PUTSHORT(3, p); /* DUID_LL */
#else
PUTSHORT(1, p); /* DUID_LLT */
#endif
PUTSHORT(type, p); /* address type */
#ifndef HAVE_BROKEN_RTC
PUTLONG(*((time_t *)parm), p); /* time */
#endif
memcpy(p, mac, maclen);
return 0;
}
#endif #endif

View File

@@ -53,7 +53,10 @@
#define OPTION6_INTERFACE_ID 18 #define OPTION6_INTERFACE_ID 18
#define OPTION6_RECONFIGURE_MSG 19 #define OPTION6_RECONFIGURE_MSG 19
#define OPTION6_RECONF_ACCEPT 20 #define OPTION6_RECONF_ACCEPT 20
#define OPTION6_DNS_SERVER 23
#define OPTION6_REMOTE_ID 37
#define OPTION6_SUBSCRIBER_ID 38
#define OPTION6_FQDN 39
#define DHCP6SUCCESS 0 #define DHCP6SUCCESS 0
#define DHCP6UNSPEC 1 #define DHCP6UNSPEC 1

View File

@@ -150,7 +150,9 @@ int main (int argc, char **argv)
{ {
/* Note that order matters here, we must call lease_init before /* Note that order matters here, we must call lease_init before
creating any file descriptors which shouldn't be leaked creating any file descriptors which shouldn't be leaked
to the lease-script init process. */ to the lease-script init process. We need to call common_init
before lease_init to allocate buffers it uses.*/
dhcp_common_init();
lease_init(now); lease_init(now);
if (daemon->dhcp) if (daemon->dhcp)
dhcp_init(); dhcp_init();

View File

@@ -436,15 +436,20 @@ struct frec {
#define ACTION_OLD 3 #define ACTION_OLD 3
#define ACTION_ADD 4 #define ACTION_ADD 4
#define LEASE_NEW 1 /* newly created */
#define LEASE_CHANGED 2 /* modified */
#define LEASE_AUX_CHANGED 4 /* CLID or expiry changed */
#define LEASE_AUTH_NAME 8 /* hostname came from config, not from client */
#define LEASE_USED 16 /* used this DHCPv6 transaction */
#define LEASE_NA 32 /* IPv6 no-temporary lease */
#define LEASE_TA 64 /* IPv6 temporary lease */
struct dhcp_lease { struct dhcp_lease {
int clid_len; /* length of client identifier */ int clid_len; /* length of client identifier */
unsigned char *clid; /* clientid */ unsigned char *clid; /* clientid */
char *hostname, *fqdn; /* name from client-hostname option or config */ char *hostname, *fqdn; /* name from client-hostname option or config */
char *old_hostname; /* hostname before it moved to another lease */ char *old_hostname; /* hostname before it moved to another lease */
char auth_name; /* hostname came from config, not from client */ int flags;
char new; /* newly created */
char changed; /* modified */
char aux_changed; /* CLID or expiry changed */
time_t expires; /* lease expiry */ time_t expires; /* lease expiry */
#ifdef HAVE_BROKEN_RTC #ifdef HAVE_BROKEN_RTC
unsigned int length; unsigned int length;
@@ -455,9 +460,6 @@ struct dhcp_lease {
unsigned char *extradata; unsigned char *extradata;
unsigned int extradata_len, extradata_size; unsigned int extradata_len, extradata_size;
int last_interface; int last_interface;
#ifdef HAVE_DHCP6
char is_ipv6;
#endif
struct dhcp_lease *next; struct dhcp_lease *next;
}; };
@@ -500,6 +502,8 @@ struct dhcp_config {
struct dhcp_config *next; struct dhcp_config *next;
}; };
#define have_config(config, mask) ((config) && ((config)->flags & (mask)))
#define CONFIG_DISABLE 1 #define CONFIG_DISABLE 1
#define CONFIG_CLID 2 #define CONFIG_CLID 2
#define CONFIG_TIME 8 #define CONFIG_TIME 8
@@ -537,6 +541,7 @@ struct dhcp_opt {
#define DHOPT_VENDOR_MATCH 1024 #define DHOPT_VENDOR_MATCH 1024
#define DHOPT_RFC3925 2048 #define DHOPT_RFC3925 2048
#define DHOPT_TAGOK 4096 #define DHOPT_TAGOK 4096
#define DHOPT_ADDR6 8192
struct dhcp_boot { struct dhcp_boot {
char *file, *sname, *tftp_sname; char *file, *sname, *tftp_sname;
@@ -586,6 +591,12 @@ struct cond_domain {
struct cond_domain *next; struct cond_domain *next;
}; };
struct cond_domain6 {
char *domain;
struct in6_addr start, end;
struct cond_domain6 *next;
};
struct dhcp_context { struct dhcp_context {
unsigned int lease_time, addr_epoch; unsigned int lease_time, addr_epoch;
struct in_addr netmask, broadcast; struct in_addr netmask, broadcast;
@@ -672,6 +683,7 @@ extern struct daemon {
int group_set, osport; int group_set, osport;
char *domain_suffix; char *domain_suffix;
struct cond_domain *cond_domain; struct cond_domain *cond_domain;
struct cond_domain6 *cond_domain6;
char *runfile; char *runfile;
char *lease_change_command; char *lease_change_command;
struct iname *if_names, *if_addrs, *if_except, *dhcp_except; struct iname *if_names, *if_addrs, *if_except, *dhcp_except;
@@ -776,12 +788,15 @@ void cache_start_insert(void);
struct crec *cache_insert(char *name, struct all_addr *addr, struct crec *cache_insert(char *name, struct all_addr *addr,
time_t now, unsigned long ttl, unsigned short flags); time_t now, unsigned long ttl, unsigned short flags);
void cache_reload(void); void cache_reload(void);
void cache_add_dhcp_entry(char *host_name, struct in_addr *host_address, time_t ttd); void cache_add_dhcp_entry(char *host_name, int prot, struct all_addr *host_address, time_t ttd);
struct in_addr a_record_from_hosts(char *name, time_t now); struct in_addr a_record_from_hosts(char *name, time_t now);
void cache_unhash_dhcp(void); void cache_unhash_dhcp(void);
void dump_cache(time_t now); void dump_cache(time_t now);
char *cache_get_name(struct crec *crecp); char *cache_get_name(struct crec *crecp);
char *get_domain(struct in_addr addr); char *get_domain(struct in_addr addr);
#ifdef HAVE_IPV6
char *get_domain6(struct in6_addr *addr);
#endif
/* rfc1035.c */ /* rfc1035.c */
unsigned int extract_request(struct dns_header *header, size_t qlen, unsigned int extract_request(struct dns_header *header, size_t qlen,
@@ -845,7 +860,8 @@ void flush_log(void);
/* option.c */ /* option.c */
void read_opts (int argc, char **argv, char *compile_opts); void read_opts (int argc, char **argv, char *compile_opts);
char *option_string(unsigned char opt, int *is_ip, int *is_name); char *option_string(int prot, unsigned int opt, unsigned char *val,
int opt_len, char *buf, int buf_len);
void reread_dhcp(void); void reread_dhcp(void);
void set_option_bool(unsigned int opt); void set_option_bool(unsigned int opt);
struct hostsfile *expand_filelist(struct hostsfile *list); struct hostsfile *expand_filelist(struct hostsfile *list);
@@ -883,18 +899,15 @@ int set_ipv6pktinfo(int fd);
#ifdef HAVE_DHCP #ifdef HAVE_DHCP
void dhcp_init(void); void dhcp_init(void);
void dhcp_packet(time_t now, int pxe_fd); void dhcp_packet(time_t now, int pxe_fd);
ssize_t recv_dhcp_packet(int fd, struct msghdr *msg);
struct dhcp_context *address_available(struct dhcp_context *context, struct dhcp_context *address_available(struct dhcp_context *context,
struct in_addr addr, struct in_addr addr,
struct dhcp_netid *netids); struct dhcp_netid *netids);
struct dhcp_context *narrow_context(struct dhcp_context *context, struct dhcp_context *narrow_context(struct dhcp_context *context,
struct in_addr taddr, struct in_addr taddr,
struct dhcp_netid *netids); struct dhcp_netid *netids);
int match_netid(struct dhcp_netid *check, struct dhcp_netid *pool, int negonly);
int address_allocate(struct dhcp_context *context, int address_allocate(struct dhcp_context *context,
struct in_addr *addrp, unsigned char *hwaddr, int hw_len, struct in_addr *addrp, unsigned char *hwaddr, int hw_len,
struct dhcp_netid *netids, time_t now); struct dhcp_netid *netids, time_t now);
struct dhcp_netid *run_tag_if(struct dhcp_netid *input);
int config_has_mac(struct dhcp_config *config, unsigned char *hwaddr, int len, int type); int config_has_mac(struct dhcp_config *config, unsigned char *hwaddr, int len, int type);
struct dhcp_config *find_config(struct dhcp_config *configs, struct dhcp_config *find_config(struct dhcp_config *configs,
struct dhcp_context *context, struct dhcp_context *context,
@@ -905,7 +918,6 @@ void dhcp_update_configs(struct dhcp_config *configs);
void dhcp_read_ethers(void); void dhcp_read_ethers(void);
void check_dhcp_hosts(int fatal); void check_dhcp_hosts(int fatal);
struct dhcp_config *config_find_by_address(struct dhcp_config *configs, struct in_addr addr); struct dhcp_config *config_find_by_address(struct dhcp_config *configs, struct in_addr addr);
char *strip_hostname(char *hostname);
char *host_from_dns(struct in_addr addr); char *host_from_dns(struct in_addr addr);
char *get_domain(struct in_addr addr); char *get_domain(struct in_addr addr);
#endif #endif
@@ -917,13 +929,14 @@ void lease_update_dns();
void lease_init(time_t now); void lease_init(time_t now);
struct dhcp_lease *lease4_allocate(struct in_addr addr); struct dhcp_lease *lease4_allocate(struct in_addr addr);
#ifdef HAVE_DHCP6 #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 *lease6_find(unsigned char *clid, int clid_len,
int lease_type, int iaid, struct in6_addr *addr);
struct dhcp_lease *lease6_find_by_addr(struct in6_addr *net, int prefix, u64 addr); 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 #endif
void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr, void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
unsigned char *clid, int hw_len, int hw_type, int clid_len); unsigned char *clid, int hw_len, int hw_type, int clid_len);
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);
void lease_set_expires(struct dhcp_lease *lease, unsigned int len, time_t now); void lease_set_expires(struct dhcp_lease *lease, unsigned int len, time_t now);
void lease_set_interface(struct dhcp_lease *lease, int interface); void lease_set_interface(struct dhcp_lease *lease, int interface);
struct dhcp_lease *lease_find_by_client(unsigned char *hwaddr, int hw_len, int hw_type, struct dhcp_lease *lease_find_by_client(unsigned char *hwaddr, int hw_len, int hw_type,
@@ -1005,17 +1018,31 @@ int get_incoming_mark(union mysockaddr *peer_addr, struct all_addr *local_addr,
void dhcp6_init(void); void dhcp6_init(void);
void dhcp6_packet(time_t now); void dhcp6_packet(time_t now);
int address6_allocate(struct dhcp_context *context, unsigned char *clid, int clid_len, int address6_allocate(struct dhcp_context *context, unsigned char *clid, int clid_len,
struct dhcp_netid *netids, struct in6_addr *ans); int serial, struct dhcp_netid *netids, struct in6_addr *ans);
struct dhcp_context *address6_available(struct dhcp_context *context, struct dhcp_context *address6_available(struct dhcp_context *context,
struct in6_addr *taddr, struct in6_addr *taddr,
struct dhcp_netid *netids); struct dhcp_netid *netids);
struct dhcp_context *narrow_context6(struct dhcp_context *context, struct dhcp_context *narrow_context6(struct dhcp_context *context,
struct in6_addr *taddr, struct in6_addr *taddr,
struct dhcp_netid *netids); struct dhcp_netid *netids);
struct dhcp_config *find_config6(struct dhcp_config *configs,
struct dhcp_context *context,
unsigned char *duid, int duid_len,
char *hostname);
void make_duid(time_t now);
#endif #endif
/* rfc3315.c */ /* rfc3315.c */
#ifdef HAVE_DHCP6 #ifdef HAVE_DHCP6
void make_duid(time_t now); size_t dhcp6_reply(struct dhcp_context *context, char *iface_name, size_t sz, int is_multicast, time_t now);
size_t dhcp6_reply(struct dhcp_context *context, size_t sz, time_t now);
#endif #endif
/* dhcp-common.c */
void dhcp_common_init(void);
ssize_t recv_dhcp_packet(int fd, struct msghdr *msg);
struct dhcp_netid *run_tag_if(struct dhcp_netid *input);
struct dhcp_netid *option_filter(struct dhcp_netid *tags, struct dhcp_netid *context_tags,
struct dhcp_opt *opts);
int match_netid(struct dhcp_netid *check, struct dhcp_netid *pool, int negonly);
char *strip_hostname(char *hostname);
void log_tags(struct dhcp_netid *netid, u32 xid);

View File

@@ -30,14 +30,9 @@ void lease_init(time_t now)
FILE *leasestream; FILE *leasestream;
#ifdef HAVE_DHCP6 #ifdef HAVE_DHCP6
int v6pass = 0; int v6pass = 0;
int lease_type = 0;
#endif #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; leases_left = daemon->dhcp_max;
if (option_bool(OPT_LEASE_RO)) if (option_bool(OPT_LEASE_RO))
@@ -86,7 +81,18 @@ void lease_init(time_t now)
{ {
#ifdef HAVE_DHCP6 #ifdef HAVE_DHCP6
if (v6pass) 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 else
#endif #endif
{ {
@@ -109,7 +115,7 @@ void lease_init(time_t now)
#ifdef HAVE_DHCP6 #ifdef HAVE_DHCP6
if (v6pass) if (v6pass)
lease = lease6_allocate(&addr.addr.addr6); lease = lease6_allocate(&addr.addr.addr6, lease_type);
else else
#endif #endif
lease = lease4_allocate(addr.addr.addr4); lease = lease4_allocate(addr.addr.addr4);
@@ -130,16 +136,24 @@ void lease_init(time_t now)
#endif #endif
#ifdef HAVE_DHCP6 #ifdef HAVE_DHCP6
if (!v6pass) if (v6pass)
lease_set_hwaddr(lease, NULL, (unsigned char *)daemon->packet, 0, hw_type, clid_len);
else
#endif #endif
lease_set_hwaddr(lease, (unsigned char *)daemon->dhcp_buff2, (unsigned char *)daemon->packet, hw_len, hw_type, clid_len); 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) 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 /* set these correctly: the "old" events are generated later from
the startup synthesised SIGHUP. */ the startup synthesised SIGHUP. */
lease->new = lease->changed = 0; lease->flags |= ~(LEASE_NEW | LEASE_CHANGED);
} }
#ifdef HAVE_DHCP6 #ifdef HAVE_DHCP6
@@ -196,17 +210,17 @@ void lease_update_from_configs(void)
struct dhcp_lease *lease; struct dhcp_lease *lease;
struct dhcp_config *config; struct dhcp_config *config;
char *name; char *name;
for (lease = leases; lease; lease = lease->next) for (lease = leases; lease; lease = lease->next)
if ((config = find_config(daemon->dhcp_conf, NULL, lease->clid, lease->clid_len, if ((config = find_config(daemon->dhcp_conf, NULL, lease->clid, lease->clid_len,
lease->hwaddr, lease->hwaddr_len, lease->hwaddr_type, NULL)) && lease->hwaddr, lease->hwaddr_len, lease->hwaddr_type, NULL)) &&
(config->flags & CONFIG_NAME) && (config->flags & CONFIG_NAME) &&
(!(config->flags & CONFIG_ADDR) || config->addr.s_addr == lease->addr.s_addr)) (!(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))) 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, ...) static void ourprintf(int *errp, char *format, ...)
{ {
va_list ap; va_list ap;
@@ -234,7 +248,7 @@ void lease_update_file(time_t now)
{ {
#ifdef HAVE_DHCP6 #ifdef HAVE_DHCP6
if (lease->is_ipv6) if (lease->flags & (LEASE_TA | LEASE_NA))
continue; continue;
#endif #endif
@@ -279,7 +293,7 @@ void lease_update_file(time_t now)
for (lease = leases; lease; lease = lease->next) for (lease = leases; lease; lease = lease->next)
{ {
if (!lease->is_ipv6) if (!(lease->flags & (LEASE_TA | LEASE_NA)))
continue; continue;
#ifdef HAVE_BROKEN_RTC #ifdef HAVE_BROKEN_RTC
@@ -290,7 +304,8 @@ void lease_update_file(time_t now)
inet_ntop(AF_INET6, lease->hwaddr, daemon->addrbuff, ADDRSTRLEN); 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 : "*"); ourprintf(&err, "%s ", lease->hostname ? lease->hostname : "*");
if (lease->clid && lease->clid_len != 0) if (lease->clid && lease->clid_len != 0)
@@ -343,11 +358,21 @@ void lease_update_dns(void)
for (lease = leases; lease; lease = lease->next) 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) 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) 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; 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) for (lease = leases; lease; lease = lease->next)
{ {
#ifdef HAVE_DHCP6 #ifdef HAVE_DHCP6
if (lease->is_ipv6) if (lease->flags & (LEASE_TA | LEASE_NA))
continue; continue;
#endif #endif
if (lease->clid && clid_len == lease->clid_len && 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) for (lease = leases; lease; lease = lease->next)
{ {
#ifdef HAVE_DHCP6 #ifdef HAVE_DHCP6
if (lease->is_ipv6) if (lease->flags & (LEASE_TA | LEASE_NA))
continue; continue;
#endif #endif
if ((!lease->clid || !clid) && 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) for (lease = leases; lease; lease = lease->next)
{ {
#ifdef HAVE_DHCP6 #ifdef HAVE_DHCP6
if (lease->is_ipv6) if (lease->flags & (LEASE_TA | LEASE_NA))
continue; continue;
#endif #endif
if (lease->addr.s_addr == addr.s_addr) 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 #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; struct dhcp_lease *lease;
for (lease = leases; lease; lease = lease->next) for (lease = leases; lease; lease = lease->next)
{ {
if (!lease->is_ipv6) if (!(lease->flags & lease_type) || lease->hwaddr_type != iaid)
continue; continue;
if (lease->hwaddr_type == iaid && if (clid && addr && (lease->flags & LEASE_USED))
lease->clid && clid_len == lease->clid_len && continue;
memcmp(clid, lease->clid, clid_len) == 0)
return lease; 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; 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 *lease6_find_by_addr(struct in6_addr *net, int prefix, u64 addr)
{ {
struct dhcp_lease *lease; struct dhcp_lease *lease;
for (lease = leases; lease; lease = lease->next) for (lease = leases; lease; lease = lease->next)
{ {
if (!lease->is_ipv6) if (!(lease->flags & (LEASE_TA | LEASE_NA)))
continue; continue;
if (is_same_net6((struct in6_addr *)lease->hwaddr, net, prefix) && if (is_same_net6((struct in6_addr *)lease->hwaddr, net, prefix) &&
(prefix == 128 || addr6part((struct in6_addr *)lease->hwaddr) == addr)) (prefix == 128 || addr6part((struct in6_addr *)lease->hwaddr) == addr))
return lease; return lease;
@@ -468,7 +510,6 @@ struct dhcp_lease *lease6_find_by_addr(struct in6_addr *net, int prefix, u64 add
return NULL; return NULL;
} }
#endif #endif
/* Find largest assigned address in context */ /* 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) for (lease = leases; lease; lease = lease->next)
{ {
#ifdef HAVE_DHCP6 #ifdef HAVE_DHCP6
if (lease->is_ipv6) if (lease->flags & (LEASE_TA | LEASE_NA))
continue; continue;
#endif #endif
if (((unsigned)ntohl(lease->addr.s_addr)) > ((unsigned)ntohl(context->start.s_addr)) && 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; return NULL;
memset(lease, 0, sizeof(struct dhcp_lease)); memset(lease, 0, sizeof(struct dhcp_lease));
lease->new = 1; lease->flags = LEASE_NEW;
lease->expires = 1; lease->expires = 1;
#ifdef HAVE_BROKEN_RTC #ifdef HAVE_BROKEN_RTC
lease->length = 0xffffffff; /* illegal value */ lease->length = 0xffffffff; /* illegal value */
@@ -524,11 +565,11 @@ struct dhcp_lease *lease4_allocate(struct in_addr addr)
} }
#ifdef HAVE_DHCP6 #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(); struct dhcp_lease *lease = lease_allocate();
memcpy(lease->hwaddr, addrp, sizeof(*addrp)) ; memcpy(lease->hwaddr, addrp, sizeof(*addrp)) ;
lease->is_ipv6 = 1; lease->flags |= lease_type;
return lease; return lease;
} }
@@ -549,7 +590,8 @@ void lease_set_expires(struct dhcp_lease *lease, unsigned int len, time_t now)
dns_dirty = 1; dns_dirty = 1;
lease->expires = exp; lease->expires = exp;
#ifndef HAVE_BROKEN_RTC #ifndef HAVE_BROKEN_RTC
lease->aux_changed = file_dirty = 1; lease->flags |= LEASE_AUX_CHANGED;
file_dirty = 1;
#endif #endif
} }
@@ -569,10 +611,12 @@ void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
hw_type != lease->hwaddr_type || hw_type != lease->hwaddr_type ||
(hw_len != 0 && memcmp(lease->hwaddr, hwaddr, hw_len) != 0)) (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_len = hw_len;
lease->hwaddr_type = hw_type; 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 /* 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) if (lease->clid_len != clid_len)
{ {
lease->aux_changed = file_dirty = 1; lease->flags |= LEASE_AUX_CHANGED;
file_dirty = 1;
free(lease->clid); free(lease->clid);
if (!(lease->clid = whine_malloc(clid_len))) if (!(lease->clid = whine_malloc(clid_len)))
return; return;
} }
else if (memcmp(lease->clid, clid, clid_len) != 0) 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; lease->clid_len = clid_len;
memcpy(lease->clid, clid, clid_len); memcpy(lease->clid, clid, clid_len);
} }
@@ -608,7 +656,7 @@ static void kill_name(struct dhcp_lease *lease)
free(lease->old_hostname); free(lease->old_hostname);
/* If we know the fqdn, pass that. The helper will derive the /* 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) if (lease->fqdn)
{ {
@@ -621,14 +669,15 @@ static void kill_name(struct dhcp_lease *lease)
lease->hostname = lease->fqdn = NULL; 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; struct dhcp_lease *lease_tmp;
char *new_name = NULL, *new_fqdn = NULL; char *new_name = NULL, *new_fqdn = NULL;
if (lease->hostname && name && hostname_isequal(lease->hostname, name)) if (lease->hostname && name && hostname_isequal(lease->hostname, name))
{ {
lease->auth_name = auth; if (auth)
lease->flags |= LEASE_AUTH_NAME;
return; 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, /* 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 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. 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. */ Don't allow a name from the client to override a name from dnsmasq config. */
if (name) if (name)
{ {
if ((new_name = whine_malloc(strlen(name) + 1))) if ((new_name = whine_malloc(strlen(name) + 1)))
{ {
char *suffix = get_domain(lease->addr);
strcpy(new_name, name); 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); strcpy(new_fqdn, name);
strcat(new_fqdn, "."); 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 (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; continue;
} }
else 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) ) if (!new_name || !lease_tmp->hostname || !hostname_isequal(lease_tmp->hostname, new_name) )
continue; 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_name);
free(new_fqdn); free(new_fqdn);
@@ -685,11 +750,13 @@ void lease_set_hostname(struct dhcp_lease *lease, char *name, int auth)
lease->hostname = new_name; lease->hostname = new_name;
lease->fqdn = new_fqdn; lease->fqdn = new_fqdn;
lease->auth_name = auth;
if (auth)
lease->flags |= LEASE_AUTH_NAME;
file_dirty = 1; file_dirty = 1;
dns_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) 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; return;
lease->last_interface = interface; lease->last_interface = interface;
lease->changed = 1; lease->flags |= LEASE_CHANGED;
} }
void rerun_scripts(void) void rerun_scripts(void)
@@ -706,7 +773,7 @@ void rerun_scripts(void)
struct dhcp_lease *lease; struct dhcp_lease *lease;
for (lease = leases; lease; lease = lease->next) for (lease = leases; lease; lease = lease->next)
lease->changed = 1; lease->flags |= LEASE_CHANGED;
} }
/* deleted leases get transferred to the old_leases list. /* 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) for (lease = leases; lease; lease = lease->next)
if (lease->new || lease->changed || if ((lease->flags & (LEASE_NEW | LEASE_CHANGED)) ||
(lease->aux_changed && option_bool(OPT_LEASE_RO))) ((lease->flags & LEASE_AUX_CHANGED) && option_bool(OPT_LEASE_RO)))
{ {
#ifdef HAVE_SCRIPT #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); lease->fqdn ? lease->fqdn : lease->hostname, now);
#endif #endif
#ifdef HAVE_DBUS #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); lease->fqdn ? lease->fqdn : lease->hostname);
#endif #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 */ /* this is used for the "add" call, then junked, since they're not in the database */
free(lease->extradata); free(lease->extradata);

View File

@@ -282,7 +282,9 @@ int iface_enumerate(int family, void *parm, int (*callback)())
rta = RTA_NEXT(rta, len1); rta = RTA_NEXT(rta, len1);
} }
if (mac && !((*callback)(link->ifi_type, link->ifi_flags, mac, maclen, parm))) if (mac && !((*callback)((unsigned int)link->ifi_type,
(unsigned int)link->ifi_flags,
mac, maclen, parm)))
return 0; return 0;
} }
#endif #endif

View File

@@ -363,15 +363,16 @@ static struct {
}; };
#ifdef HAVE_DHCP #ifdef HAVE_DHCP
#define OT_ADDR_LIST 0x80
#define OT_RFC1035_NAME 0x40
#define OT_INTERNAL 0x20
#define OT_NAME 0x10
#define OT_ADDR_LIST 0x8000
#define OT_RFC1035_NAME 0x4000
#define OT_INTERNAL 0x2000
#define OT_NAME 0x1000
#define OT_CSTRING 0x0800
static const struct { static const struct opttab_t {
char *name; char *name;
unsigned char val, size; u16 val, size;
} opttab[] = { } opttab[] = {
{ "netmask", 1, OT_ADDR_LIST }, { "netmask", 1, OT_ADDR_LIST },
{ "time-offset", 2, 4 }, { "time-offset", 2, 4 },
@@ -422,7 +423,7 @@ static const struct {
{ "T1", 58, OT_INTERNAL }, { "T1", 58, OT_INTERNAL },
{ "T2", 59, OT_INTERNAL }, { "T2", 59, OT_INTERNAL },
{ "vendor-class", 60, 0 }, { "vendor-class", 60, 0 },
{ "client-id", 61,OT_INTERNAL }, { "client-id", 61, OT_INTERNAL },
{ "nis+-domain", 64, OT_NAME }, { "nis+-domain", 64, OT_NAME },
{ "nis+-server", 65, OT_ADDR_LIST }, { "nis+-server", 65, OT_ADDR_LIST },
{ "tftp-server", 66, OT_NAME }, { "tftp-server", 66, OT_NAME },
@@ -447,21 +448,125 @@ static const struct {
{ NULL, 0, 0 } { NULL, 0, 0 }
}; };
char *option_string(unsigned char opt, int *is_ip, int *is_name) #ifdef HAVE_DHCP6
{ static const struct opttab_t opttab6[] = {
int i; { "client-id", 1, OT_INTERNAL },
{ "server-id", 2, OT_INTERNAL },
{ "ia-na", 3, OT_INTERNAL },
{ "ia-ta", 4, OT_INTERNAL },
{ "iaaddr", 5, OT_INTERNAL },
{ "oro", 6, OT_INTERNAL },
{ "preference", 7, OT_INTERNAL },
{ "unicast", 12, OT_INTERNAL },
{ "status-code", 13, OT_INTERNAL },
{ "rapid-commit", 14, OT_INTERNAL },
{ "user-class", 15, OT_INTERNAL | OT_CSTRING },
{ "vendor-class", 16, OT_INTERNAL | OT_CSTRING },
{ "vendor-opts", 17, OT_INTERNAL },
{ "sip-server-domain", 21, OT_RFC1035_NAME },
{ "sip-server", 22, OT_ADDR_LIST },
{ "dns-server", 23, OT_ADDR_LIST },
{ "domain-search", 24, OT_RFC1035_NAME },
{ "nis-server", 27, OT_ADDR_LIST },
{ "nis+-server", 28, OT_ADDR_LIST },
{ "nis-domain", 29, OT_RFC1035_NAME },
{ "nis+-domain", 30, OT_RFC1035_NAME },
{ "sntp-server", 31, OT_ADDR_LIST },
{ "FQDN", 39, OT_INTERNAL | OT_RFC1035_NAME },
{ "ntp-server", 56, OT_ADDR_LIST },
{ "bootfile-url", 59, OT_NAME },
{ "bootfile-param", 60, OT_CSTRING },
{ NULL, 0, 0 }
};
#endif
for (i = 0; opttab[i].name; i++)
if (opttab[i].val == opt) char *option_string(int prot, unsigned int opt, unsigned char *val, int opt_len, char *buf, int buf_len)
{
int o, i, j, nodecode = 0;
const struct opttab_t *ot = opttab;
#ifdef HAVE_DHCP6
if (prot == AF_INET6)
ot = opttab6;
#endif
for (o = 0; ot[o].name; o++)
if (ot[o].val == opt)
{ {
if (is_ip) if (buf)
*is_ip = !!(opttab[i].size & OT_ADDR_LIST); {
if (is_name) memset(buf, 0, buf_len);
*is_name = !!(opttab[i].size & OT_NAME);
return opttab[i].name; if (ot[o].size & OT_ADDR_LIST)
{
struct all_addr addr;
int addr_len = INADDRSZ;
#ifdef HAVE_DHCP6
if (prot == AF_INET6)
addr_len = IN6ADDRSZ;
#endif
for (buf[0]= 0, i = 0; i <= opt_len - addr_len; i += addr_len)
{
if (i != 0)
strncat(buf, ", ", buf_len - strlen(buf));
/* align */
memcpy(&addr, &val[i], addr_len);
inet_ntop(prot, &val[i], daemon->addrbuff, ADDRSTRLEN);
strncat(buf, daemon->addrbuff, buf_len - strlen(buf));
}
}
else if (ot[o].size & OT_NAME)
for (i = 0, j = 0; i < opt_len && j < buf_len ; i++)
{
char c = val[i];
if (isprint((int)c))
buf[j++] = c;
}
#ifdef HAVE_DHCP6
/* We don't handle compressed rfc1035 names, so no good in IPv4 land */
else if ((ot[o].size & OT_RFC1035_NAME) && prot == AF_INET6)
{
i = 0, j = 0;
while (i < opt_len && val[i] != 0)
{
int k, l = i + val[i] + 1;
for (k = i + 1; k < opt_len && k < l && j < buf_len ; k++)
{
char c = val[k];
if (isprint((int)c))
buf[j++] = c;
}
i = l;
if (val[i] != 0 && j < buf_len)
buf[j++] = '.';
}
}
#endif
else
nodecode = 1;
}
break;
} }
return NULL; if (buf && (!ot[o].name || nodecode))
{
int trunc = 0;
if (opt_len > 13)
{
trunc = 1;
opt_len = 13;
}
print_mac(buf, val, opt_len);
if (trunc)
strncat(buf, "...", buf_len - strlen(buf));
}
return ot[o].name ? ot[o].name : "";
} }
#endif #endif
@@ -699,6 +804,19 @@ static void display_opts(void)
printf("%3d %s\n", opttab[i].val, opttab[i].name); printf("%3d %s\n", opttab[i].val, opttab[i].name);
} }
#ifdef HAVE_DHCP6
static void display_opts6(void)
{
int i;
printf(_("Known DHCPv6 options:\n"));
for (i = 0; opttab6[i].name; i++)
if (!(opttab6[i].size & OT_INTERNAL))
printf("%3d %s\n", opttab6[i].val, opttab6[i].name);
}
#endif
static int is_tag_prefix(char *arg) static int is_tag_prefix(char *arg)
{ {
if (arg && (strstr(arg, "net:") == arg || strstr(arg, "tag:") == arg)) if (arg && (strstr(arg, "net:") == arg || strstr(arg, "tag:") == arg))
@@ -720,10 +838,11 @@ static char *parse_dhcp_opt(char *arg, int flags)
{ {
struct dhcp_opt *new = opt_malloc(sizeof(struct dhcp_opt)); struct dhcp_opt *new = opt_malloc(sizeof(struct dhcp_opt));
char lenchar = 0, *cp; char lenchar = 0, *cp;
int i, addrs, digs, is_addr, is_hex, is_dec, is_string, dots; int i, addrs, digs, is_addr, is_addr6, is_hex, is_dec, is_string, dots;
char *comma = NULL, *problem = NULL; char *comma = NULL, *problem = NULL;
struct dhcp_netid *np = NULL; struct dhcp_netid *np = NULL;
unsigned char opt_len = 0; u16 opt_len = 0;
int is6 = 0;
new->len = 0; new->len = 0;
new->flags = flags; new->flags = flags;
@@ -759,6 +878,32 @@ static char *parse_dhcp_opt(char *arg, int flags)
/* option:<optname> must follow tag and vendor string. */ /* option:<optname> must follow tag and vendor string. */
break; break;
} }
#ifdef HAVE_DHCP6
else if (strstr(arg, "option6:") == arg)
{
for (cp = arg+8; *cp; cp++)
if (*cp < '0' || *cp > '9')
break;
if (!*cp)
{
new->opt = atoi(arg+8);
opt_len = 0;
}
else
for (i = 0; opttab6[i].name; i++)
if (!(opttab6[i].size & OT_INTERNAL) &&
strcasecmp(opttab6[i].name, arg+8) == 0)
{
new->opt = opttab6[i].val;
opt_len = opttab6[i].size;
break;
}
/* option6:<opt>|<optname> must follow tag and vendor string. */
is6 = 1;
break;
}
#endif
else if (strstr(arg, "vendor:") == arg) else if (strstr(arg, "vendor:") == arg)
{ {
new->u.vendor_class = (unsigned char *)opt_string_alloc(arg+7); new->u.vendor_class = (unsigned char *)opt_string_alloc(arg+7);
@@ -793,17 +938,36 @@ static char *parse_dhcp_opt(char *arg, int flags)
arg = comma; arg = comma;
} }
if (opt_len == 0 && #ifdef HAVE_DHCP6
!(new->flags & (DHOPT_VENDOR | DHOPT_ENCAPSULATE | DHOPT_RFC3925))) if (is6)
for (i = 0; opttab[i].name; i++) {
if (new->opt == opttab[i].val) if (new->flags & (DHOPT_VENDOR | DHOPT_ENCAPSULATE))
{ problem = _("unsupported encapsulation for IPv6 option");
opt_len = opttab[i].size;
if (opt_len & OT_INTERNAL) if (opt_len == 0 &&
opt_len = 0; !(new->flags & DHOPT_RFC3925))
break; for (i = 0; opttab6[i].name; i++)
} if (new->opt == opttab6[i].val)
{
opt_len = opttab6[i].size;
if (opt_len & OT_INTERNAL)
opt_len = 0;
break;
}
}
else
#endif
if (opt_len == 0 &&
!(new->flags & (DHOPT_VENDOR | DHOPT_ENCAPSULATE | DHOPT_RFC3925)))
for (i = 0; opttab[i].name; i++)
if (new->opt == opttab[i].val)
{
opt_len = opttab[i].size;
if (opt_len & OT_INTERNAL)
opt_len = 0;
break;
}
/* option may be missing with rfc3925 match */ /* option may be missing with rfc3925 match */
if (new->opt == 0) if (new->opt == 0)
@@ -813,7 +977,7 @@ static char *parse_dhcp_opt(char *arg, int flags)
/* characterise the value */ /* characterise the value */
char c; char c;
int found_dig = 0; int found_dig = 0;
is_addr = is_hex = is_dec = is_string = 1; is_addr = is_addr6 = is_hex = is_dec = is_string = 1;
addrs = digs = 1; addrs = digs = 1;
dots = 0; dots = 0;
for (cp = comma; (c = *cp); cp++) for (cp = comma; (c = *cp); cp++)
@@ -829,17 +993,17 @@ static char *parse_dhcp_opt(char *arg, int flags)
} }
else if (c == '/') else if (c == '/')
{ {
is_dec = is_hex = 0; is_addr6 = is_dec = is_hex = 0;
if (cp == comma) /* leading / means a pathname */ if (cp == comma) /* leading / means a pathname */
is_addr = 0; is_addr = 0;
} }
else if (c == '.') else if (c == '.')
{ {
is_dec = is_hex = 0; is_addr6 =is_dec = is_hex = 0;
dots++; dots++;
} }
else if (c == '-') else if (c == '-')
is_hex = is_addr = 0; is_hex = is_addr = is_addr6 = 0;
else if (c == ' ') else if (c == ' ')
is_dec = is_hex = 0; is_dec = is_hex = 0;
else if (!(c >='0' && c <= '9')) else if (!(c >='0' && c <= '9'))
@@ -856,25 +1020,33 @@ static char *parse_dhcp_opt(char *arg, int flags)
if (!((c >='A' && c <= 'F') || if (!((c >='A' && c <= 'F') ||
(c >='a' && c <= 'f') || (c >='a' && c <= 'f') ||
(c == '*' && (flags & DHOPT_MATCH)))) (c == '*' && (flags & DHOPT_MATCH))))
is_hex = 0; {
is_hex = 0;
if (c != '[' && c != ']')
is_addr6 = 0;
}
} }
else else
found_dig = 1; found_dig = 1;
if (!found_dig) if (!found_dig)
is_dec = is_addr = 0; is_dec = is_addr = 0;
/* We know that some options take addresses */ /* We know that some options take addresses */
if (opt_len & OT_ADDR_LIST) if (opt_len & OT_ADDR_LIST)
{ {
is_string = is_dec = is_hex = 0; is_string = is_dec = is_hex = 0;
if (!is_addr || dots == 0)
if (!is6 && (!is_addr || dots == 0))
problem = _("bad IP address"); problem = _("bad IP address");
if (is6 && !is_addr6)
problem = _("bad IPv6 address");
} }
/* or names */ /* or names */
else if (opt_len & (OT_NAME | OT_RFC1035_NAME)) else if (opt_len & (OT_NAME | OT_RFC1035_NAME | OT_CSTRING))
is_addr = is_dec = is_hex = 0; is_addr6 = is_addr = is_dec = is_hex = 0;
if (is_hex && digs > 1) if (is_hex && digs > 1)
{ {
new->len = digs; new->len = digs;
@@ -908,7 +1080,7 @@ static char *parse_dhcp_opt(char *arg, int flags)
for (i=0; i<new->len; i++) for (i=0; i<new->len; i++)
new->val[i] = val>>((new->len - i - 1)*8); new->val[i] = val>>((new->len - i - 1)*8);
} }
else if (is_addr) else if (is_addr && !is6)
{ {
struct in_addr in; struct in_addr in;
unsigned char *op; unsigned char *op;
@@ -953,11 +1125,37 @@ static char *parse_dhcp_opt(char *arg, int flags)
} }
new->len = op - new->val; new->len = op - new->val;
} }
else if (is_addr6 && is6)
{
unsigned char *op;
new->val = op = opt_malloc(16 * addrs);
new->flags |= DHOPT_ADDR6;
while (addrs--)
{
cp = comma;
comma = split(cp);
/* check for [1234::7] */
if (*cp == '[')
cp++;
if (strlen(cp) > 1 && cp[strlen(cp)-1] == ']')
cp[strlen(cp)-1] = 0;
if (inet_pton(AF_INET6, cp, op))
{
op += IN6ADDRSZ;
continue;
}
problem = _("bad IPv6 address");
}
new->len = op - new->val;
}
else if (is_string) else if (is_string)
{ {
/* text arg */ /* text arg */
if ((new->opt == OPTION_DOMAIN_SEARCH || new->opt == OPTION_SIP_SERVER) && if ((new->opt == OPTION_DOMAIN_SEARCH || new->opt == OPTION_SIP_SERVER) &&
!(new->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925))) !is6 && !(new->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925)))
{ {
/* dns search, RFC 3397, or SIP, RFC 3361 */ /* dns search, RFC 3397, or SIP, RFC 3361 */
unsigned char *q, *r, *tail; unsigned char *q, *r, *tail;
@@ -1030,6 +1228,63 @@ static char *parse_dhcp_opt(char *arg, int flags)
new->len = (int) len + header_size; new->len = (int) len + header_size;
new->val = m; new->val = m;
} }
#ifdef HAVE_DHCP6
else if (comma && (opt_len & OT_CSTRING))
{
/* length fields are two bytes so need 16 bits for each string */
int commas = 1;
unsigned char *p, *newp;
for(i = 0; comma[i]; i++)
if (comma[i] == ',')
commas++;
newp = opt_malloc(strlen(comma)+(2*commas));
p = newp;
arg = comma;
comma = split(arg);
while (arg && *arg)
{
u16 len = strlen(arg);
PUTSHORT(len, p);
memcpy(p, arg, len);
p += len;
arg = comma;
comma = split(arg);
}
new->val = newp;
new->len = p - newp;
}
else if (comma && (opt_len & OT_RFC1035_NAME))
{
int commas = 1;
unsigned char *p, *newp;
for(i = 0; comma[i]; i++)
if (comma[i] == ',')
commas++;
newp = opt_malloc(strlen(comma)+(2*commas));
p = newp;
arg = comma;
comma = split(arg);
while (arg && *arg)
{
p = do_rfc1035_name(p, arg);
*p++ = 0;
arg = comma;
comma = split(arg);
}
new->val = newp;
new->len = p - newp;
}
#endif
else else
{ {
new->len = strlen(comma); new->len = strlen(comma);
@@ -1040,9 +1295,10 @@ static char *parse_dhcp_opt(char *arg, int flags)
} }
} }
if ((new->len > 255) || if (!is6 &&
((new->len > 255) ||
(new->len > 253 && (new->flags & (DHOPT_VENDOR | DHOPT_ENCAPSULATE))) || (new->len > 253 && (new->flags & (DHOPT_VENDOR | DHOPT_ENCAPSULATE))) ||
(new->len > 250 && (new->flags & DHOPT_RFC3925))) (new->len > 250 && (new->flags & DHOPT_RFC3925))))
problem = _("dhcp-option too long"); problem = _("dhcp-option too long");
if (!problem) if (!problem)
@@ -1059,7 +1315,12 @@ static char *parse_dhcp_opt(char *arg, int flags)
daemon->dhcp_match = new; daemon->dhcp_match = new;
} }
} }
else else if (is6)
{
new->next = daemon->dhcp_opts6;
daemon->dhcp_opts6 = new;
}
else
{ {
new->next = daemon->dhcp_opts; new->next = daemon->dhcp_opts;
daemon->dhcp_opts = new; daemon->dhcp_opts = new;
@@ -1989,6 +2250,8 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
{ {
new->prefix = pref; new->prefix = pref;
leasepos = 3; leasepos = 3;
if (new->prefix < 64)
problem = _("prefix must be at least 64");
} }
} }
if (!is_same_net6(&new->start6, &new->end6, new->prefix)) if (!is_same_net6(&new->start6, &new->end6, new->prefix))
@@ -2109,6 +2372,18 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
} }
else if (strstr(arg, "tag:") == arg) else if (strstr(arg, "tag:") == arg)
problem = _("cannot match tags in --dhcp-host"); problem = _("cannot match tags in --dhcp-host");
#ifdef HAVE_DHCP6
else if (arg[0] == '[' && arg[strlen(arg)-1] == ']')
{
arg[strlen(arg)-1] = 0;
arg++;
if (!inet_pton(AF_INET6, arg, &new->addr6))
problem = _("bad IPv6 address");
new->flags |= CONFIG_ADDR6;
}
#endif
else else
{ {
struct hwaddr_config *newhw = opt_malloc(sizeof(struct hwaddr_config)); struct hwaddr_config *newhw = opt_malloc(sizeof(struct hwaddr_config));
@@ -3338,12 +3613,17 @@ void read_opts(int argc, char **argv, char *compile_opts)
testmode = 1; testmode = 1;
else if (option == 'w') else if (option == 'w')
{ {
if (argc != 3 || strcmp(argv[2], "dhcp") != 0)
do_usage();
#ifdef HAVE_DHCP #ifdef HAVE_DHCP
else if (argc == 3 && strcmp(argv[2], "dhcp") == 0)
display_opts(); display_opts();
#ifdef HAVE_DHCP6
else if (argc == 3 && strcmp(argv[2], "dhcp6") == 0)
display_opts6();
#endif #endif
else
#endif
do_usage();
exit(0); exit(0);
} }
else if (option == 'v') else if (option == 'v')

View File

@@ -18,7 +18,6 @@
#ifdef HAVE_DHCP #ifdef HAVE_DHCP
#define have_config(config, mask) ((config) && ((config)->flags & (mask)))
#define option_len(opt) ((int)(((unsigned char *)(opt))[1])) #define option_len(opt) ((int)(((unsigned char *)(opt))[1]))
#define option_ptr(opt, i) ((void *)&(((unsigned char *)(opt))[2u+(unsigned int)(i)])) #define option_ptr(opt, i) ((void *)&(((unsigned char *)(opt))[2u+(unsigned int)(i)]))
@@ -35,13 +34,11 @@ static void option_put(struct dhcp_packet *mess, unsigned char *end, int opt, in
static void option_put_string(struct dhcp_packet *mess, unsigned char *end, static void option_put_string(struct dhcp_packet *mess, unsigned char *end,
int opt, char *string, int null_term); int opt, char *string, int null_term);
static struct in_addr option_addr(unsigned char *opt); static struct in_addr option_addr(unsigned char *opt);
static struct in_addr option_addr_arr(unsigned char *opt, int offset);
static unsigned int option_uint(unsigned char *opt, int i, int size); static unsigned int option_uint(unsigned char *opt, int i, int size);
static void log_packet(char *type, void *addr, unsigned char *ext_mac, static void log_packet(char *type, void *addr, unsigned char *ext_mac,
int mac_len, char *interface, char *string, u32 xid); int mac_len, char *interface, char *string, u32 xid);
static unsigned char *option_find(struct dhcp_packet *mess, size_t size, int opt_type, int minsize); static unsigned char *option_find(struct dhcp_packet *mess, size_t size, int opt_type, int minsize);
static unsigned char *option_find1(unsigned char *p, unsigned char *end, int opt, int minsize); static unsigned char *option_find1(unsigned char *p, unsigned char *end, int opt, int minsize);
static void log_tags(struct dhcp_netid *netid, struct dhcp_packet *mess);
static size_t dhcp_packet_size(struct dhcp_packet *mess, unsigned char *agent_id, unsigned char *real_end); static size_t dhcp_packet_size(struct dhcp_packet *mess, unsigned char *agent_id, unsigned char *real_end);
static void clear_packet(struct dhcp_packet *mess, unsigned char *end); static void clear_packet(struct dhcp_packet *mess, unsigned char *end);
static void do_options(struct dhcp_context *context, static void do_options(struct dhcp_context *context,
@@ -468,7 +465,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
tagif_netid = run_tag_if(&context->netid); tagif_netid = run_tag_if(&context->netid);
} }
log_tags(tagif_netid, mess); log_tags(tagif_netid, ntohl(mess->xid));
if (!message && !nailed) if (!message && !nailed)
{ {
@@ -490,7 +487,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
lease_set_hwaddr(lease, mess->chaddr, NULL, mess->hlen, mess->htype, 0); lease_set_hwaddr(lease, mess->chaddr, NULL, mess->hlen, mess->htype, 0);
if (hostname) if (hostname)
lease_set_hostname(lease, hostname, 1); lease_set_hostname(lease, hostname, 1, get_domain(lease->addr));
/* infinite lease unless nailed in dhcp-host line. */ /* infinite lease unless nailed in dhcp-host line. */
lease_set_expires(lease, lease_set_expires(lease,
have_config(config, CONFIG_TIME) ? config->lease_time : 0xffffffff, have_config(config, CONFIG_TIME) ? config->lease_time : 0xffffffff,
@@ -819,7 +816,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
do_encap_opts(&opt71, OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, 0); do_encap_opts(&opt71, OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, 0);
log_packet("PXE", &mess->yiaddr, emac, emac_len, iface_name, (char *)mess->file, mess->xid); log_packet("PXE", &mess->yiaddr, emac, emac_len, iface_name, (char *)mess->file, mess->xid);
log_tags(tagif_netid, mess); log_tags(tagif_netid, ntohl(mess->xid));
return dhcp_packet_size(mess, agent_id, real_end); return dhcp_packet_size(mess, agent_id, real_end);
} }
@@ -871,7 +868,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
do_encap_opts(pxe_opts(pxearch, tagif_netid, context->local), OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, 0); do_encap_opts(pxe_opts(pxearch, tagif_netid, context->local), OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, 0);
log_packet("PXE", NULL, emac, emac_len, iface_name, ignore ? "proxy-ignored" : "proxy", mess->xid); log_packet("PXE", NULL, emac, emac_len, iface_name, ignore ? "proxy-ignored" : "proxy", mess->xid);
log_tags(tagif_netid, mess); log_tags(tagif_netid, ntohl(mess->xid));
return ignore ? 0 : dhcp_packet_size(mess, agent_id, real_end); return ignore ? 0 : dhcp_packet_size(mess, agent_id, real_end);
} }
} }
@@ -1009,7 +1006,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
tagif_netid = run_tag_if(&context->netid); tagif_netid = run_tag_if(&context->netid);
} }
log_tags(tagif_netid, mess); log_tags(tagif_netid, ntohl(mess->xid));
log_packet("DHCPOFFER" , &mess->yiaddr, emac, emac_len, iface_name, NULL, mess->xid); log_packet("DHCPOFFER" , &mess->yiaddr, emac, emac_len, iface_name, NULL, mess->xid);
@@ -1223,7 +1220,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
tagif_netid = run_tag_if( &context->netid); tagif_netid = run_tag_if( &context->netid);
} }
log_tags(tagif_netid, mess); log_tags(tagif_netid, ntohl(mess->xid));
#ifdef HAVE_SCRIPT #ifdef HAVE_SCRIPT
if (do_classes && daemon->lease_change_command) if (do_classes && daemon->lease_change_command)
@@ -1233,7 +1230,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
if (mess->giaddr.s_addr) if (mess->giaddr.s_addr)
lease->giaddr = mess->giaddr; lease->giaddr = mess->giaddr;
lease->changed = 1; lease->flags |= LEASE_CHANGED;
free(lease->extradata); free(lease->extradata);
lease->extradata = NULL; lease->extradata = NULL;
lease->extradata_size = lease->extradata_len = 0; lease->extradata_size = lease->extradata_len = 0;
@@ -1310,7 +1307,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
} }
if (hostname) if (hostname)
lease_set_hostname(lease, hostname, hostname_auth); lease_set_hostname(lease, hostname, hostname_auth, get_domain(lease->addr));
lease_set_expires(lease, time, now); lease_set_expires(lease, time, now);
lease_set_interface(lease, int_index); lease_set_interface(lease, int_index);
@@ -1364,10 +1361,10 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
if (context && context->netid.net) if (context && context->netid.net)
{ {
context->netid.next = netid; context->netid.next = netid;
tagif_netid = run_tag_if( &context->netid); tagif_netid = run_tag_if(&context->netid);
} }
log_tags(tagif_netid, mess); log_tags(tagif_netid, ntohl(mess->xid));
log_packet("DHCPACK", &mess->ciaddr, emac, emac_len, iface_name, hostname, mess->xid); log_packet("DHCPACK", &mess->ciaddr, emac, emac_len, iface_name, hostname, mess->xid);
@@ -1601,30 +1598,10 @@ static void log_options(unsigned char *start, u32 xid)
{ {
while (*start != OPTION_END) while (*start != OPTION_END)
{ {
int is_ip, is_name, i; char *optname = option_string(AF_INET, start[0], option_ptr(start, 0), option_len(start), daemon->namebuff, MAXDNAME);
char *text = option_string(start[0], &is_ip, &is_name);
unsigned char trunc = option_len(start);
if (is_ip) my_syslog(MS_DHCP | LOG_INFO, "%u sent size:%3d option:%3d %s %s",
for (daemon->namebuff[0]= 0, i = 0; i <= trunc - INADDRSZ; i += INADDRSZ) ntohl(xid), option_len(start), start[0], optname, daemon->namebuff);
{
if (i != 0)
strncat(daemon->namebuff, ", ", 256 - strlen(daemon->namebuff));
strncat(daemon->namebuff, inet_ntoa(option_addr_arr(start, i)), 256 - strlen(daemon->namebuff));
}
else if (!is_name || !sanitise(start, daemon->namebuff))
{
if (trunc > 13)
trunc = 13;
print_mac(daemon->namebuff, option_ptr(start, 0), trunc);
}
my_syslog(MS_DHCP | LOG_INFO, "%u sent size:%3d option:%3d%s%s%s%s%s",
ntohl(xid), option_len(start), start[0],
text ? ":" : "", text ? text : "",
trunc == 0 ? "" : " ",
trunc == 0 ? "" : daemon->namebuff,
trunc == option_len(start) ? "" : "...");
start += start[1] + 2; start += start[1] + 2;
} }
} }
@@ -1679,22 +1656,17 @@ static unsigned char *option_find(struct dhcp_packet *mess, size_t size, int opt
return NULL; return NULL;
} }
static struct in_addr option_addr_arr(unsigned char *opt, int offset) static struct in_addr option_addr(unsigned char *opt)
{ {
/* this worries about unaligned data in the option. */ /* this worries about unaligned data in the option. */
/* struct in_addr is network byte order */ /* struct in_addr is network byte order */
struct in_addr ret; struct in_addr ret;
memcpy(&ret, option_ptr(opt, offset), INADDRSZ); memcpy(&ret, option_ptr(opt, 0), INADDRSZ);
return ret; return ret;
} }
static struct in_addr option_addr(unsigned char *opt)
{
return option_addr_arr(opt, 0);
}
static unsigned int option_uint(unsigned char *opt, int offset, int size) static unsigned int option_uint(unsigned char *opt, int offset, int size)
{ {
/* this worries about unaligned data and byte order */ /* this worries about unaligned data and byte order */
@@ -1729,31 +1701,6 @@ static unsigned char *find_overload(struct dhcp_packet *mess)
return NULL; return NULL;
} }
static void log_tags(struct dhcp_netid *netid, struct dhcp_packet *mess)
{
if (netid && option_bool(OPT_LOG_OPTS))
{
char *s = daemon->namebuff;
for (*s = 0; netid; netid = netid->next)
{
/* kill dupes. */
struct dhcp_netid *n;
for (n = netid->next; n; n = n->next)
if (strcmp(netid->net, n->net) == 0)
break;
if (!n)
{
strncat (s, netid->net, (MAXDNAME-1) - strlen(s));
if (netid->next)
strncat (s, ", ", (MAXDNAME-1) - strlen(s));
}
}
my_syslog(MS_DHCP | LOG_INFO, _("%u tags: %s"), ntohl(mess->xid), s);
}
}
static size_t dhcp_packet_size(struct dhcp_packet *mess, unsigned char *agent_id, unsigned char *real_end) static size_t dhcp_packet_size(struct dhcp_packet *mess, unsigned char *agent_id, unsigned char *real_end)
{ {
unsigned char *p = dhcp_skip_opts(&mess->options[0] + sizeof(u32)); unsigned char *p = dhcp_skip_opts(&mess->options[0] + sizeof(u32));
@@ -2216,49 +2163,8 @@ static void do_options(struct dhcp_context *context,
struct dhcp_netid *tagif; struct dhcp_netid *tagif;
struct dhcp_netid_list *id_list; struct dhcp_netid_list *id_list;
/* flag options which are valid with the current tag set (sans context tags) */ /* filter options based on tags, those we want get DHOPT_TAGOK bit set */
tagif = run_tag_if(netid); tagif = option_filter(netid, &context->netid, config_opts);
for (opt = config_opts; opt; opt = opt->next)
{
opt->flags &= ~DHOPT_TAGOK;
if (!(opt->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925)) &&
match_netid(opt->netid, tagif, 0))
opt->flags |= DHOPT_TAGOK;
}
/* now flag options which are valid, including the context tags,
otherwise valid options are inhibited if we found a higher priotity one above */
if (context && context->netid.net)
{
context->netid.next = netid;
tagif = run_tag_if(&context->netid);
for (opt = config_opts; opt; opt = opt->next)
if (!(opt->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925 | DHOPT_TAGOK)) &&
match_netid(opt->netid, tagif, 0))
{
struct dhcp_opt *tmp;
for (tmp = config_opts; tmp; tmp = tmp->next)
if (tmp->opt == opt->opt && opt->netid && (tmp->flags & DHOPT_TAGOK))
break;
if (!tmp)
opt->flags |= DHOPT_TAGOK;
}
}
/* now flag untagged options which are not overridden by tagged ones */
for (opt = config_opts; opt; opt = opt->next)
if (!(opt->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925 | DHOPT_TAGOK)) && !opt->netid)
{
struct dhcp_opt *tmp;
for (tmp = config_opts; tmp; tmp = tmp->next)
if (tmp->opt == opt->opt && (tmp->flags & DHOPT_TAGOK))
break;
if (!tmp)
opt->flags |= DHOPT_TAGOK;
else if (!tmp->netid)
my_syslog(MS_DHCP | LOG_WARNING, _("Ignoring duplicate dhcp-option %d"), tmp->opt);
}
if (config_domain && (!domain || !hostname_isequal(domain, config_domain))) if (config_domain && (!domain || !hostname_isequal(domain, config_domain)))
my_syslog(MS_DHCP | LOG_WARNING, _("Ignoring domain %s for DHCP host name %s"), config_domain, hostname); my_syslog(MS_DHCP | LOG_WARNING, _("Ignoring domain %s for DHCP host name %s"), config_domain, hostname);
@@ -2269,12 +2175,12 @@ static void do_options(struct dhcp_context *context,
char *q = daemon->namebuff; char *q = daemon->namebuff;
for (i = 0; req_options[i] != OPTION_END; i++) for (i = 0; req_options[i] != OPTION_END; i++)
{ {
char *s = option_string(req_options[i], NULL, NULL); char *s = option_string(AF_INET, req_options[i], NULL, 0, NULL, 0);
q += snprintf(q, MAXDNAME - (q - daemon->namebuff), q += snprintf(q, MAXDNAME - (q - daemon->namebuff),
"%d%s%s%s", "%d%s%s%s",
req_options[i], req_options[i],
s ? ":" : "", strlen(s) != 0 ? ":" : "",
s ? s : "", s,
req_options[i+1] == OPTION_END ? "" : ", "); req_options[i+1] == OPTION_END ? "" : ", ");
if (req_options[i+1] == OPTION_END || (q - daemon->namebuff) > 40) if (req_options[i+1] == OPTION_END || (q - daemon->namebuff) > 40)
{ {
@@ -2511,8 +2417,8 @@ static void do_options(struct dhcp_context *context,
/* Now send options to be encapsulated in arbitrary options, /* Now send options to be encapsulated in arbitrary options,
eg dhcp-option=encap:172,17,....... eg dhcp-option=encap:172,17,.......
Also hand vendor-identifying vendor-encapsulated options, Also handle vendor-identifying vendor-encapsulated options,
dhcp-option = rfc3925-encap:13,17,....... dhcp-option = vi-encap:13,17,.......
The may be more that one "outer" to do, so group The may be more that one "outer" to do, so group
all the options which match each outer in turn. */ all the options which match each outer in turn. */
for (opt = config_opts; opt; opt = opt->next) for (opt = config_opts; opt; opt = opt->next)

File diff suppressed because it is too large Load Diff