mirror of
https://github.com/pi-hole/dnsmasq.git
synced 2025-12-19 10:18:25 +00:00
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:
2
Makefile
2
Makefile
@@ -45,7 +45,7 @@ VERSION= -DVERSION='\"`../bld/get-version`\"'
|
||||
|
||||
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 \
|
||||
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 :
|
||||
@cd $(SRC) && $(MAKE) \
|
||||
|
||||
@@ -6,7 +6,8 @@ include $(CLEAR_VARS)
|
||||
LOCAL_SRC_FILES := bpf.c cache.c dbus.c dhcp.c dnsmasq.c \
|
||||
forward.c helper.c lease.c log.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
|
||||
|
||||
|
||||
15
src/NOTES
15
src/NOTES
@@ -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]
|
||||
|
||||
|
||||
18
src/bpf.c
18
src/bpf.c
@@ -154,6 +154,24 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
||||
ifr = (struct ifreq *)ifreq.iov_base;
|
||||
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 (family == AF_INET)
|
||||
|
||||
65
src/cache.c
65
src/cache.c
@@ -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;
|
||||
addrlen = IN6ADDRSZ;
|
||||
domain_suffix = daemon->domain_suffix;
|
||||
domain_suffix = get_domain6(&addr.addr.addr6);
|
||||
}
|
||||
#else
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
#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
|
||||
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;
|
||||
}
|
||||
|
||||
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 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;
|
||||
struct cname *a;
|
||||
size_t addrlen = sizeof(struct in_addr);
|
||||
|
||||
while ((crec = cache_find_by_name(crec, host_name, 0, F_IPV4 | F_CNAME)))
|
||||
#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, flags | F_CNAME)))
|
||||
{
|
||||
/* check all addresses associated with name */
|
||||
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 */
|
||||
in_hosts = 1;
|
||||
|
||||
inet_ntop(prot, host_address, daemon->addrbuff, ADDRSTRLEN);
|
||||
if (crec->flags & F_CNAME)
|
||||
|
||||
my_syslog(MS_DHCP | LOG_WARNING,
|
||||
_("%s is a CNAME, not giving it to the DHCP lease of %s"),
|
||||
host_name, inet_ntoa(*host_address));
|
||||
else if (crec->addr.addr.addr.addr4.s_addr != host_address->s_addr)
|
||||
host_name, daemon->addrbuff);
|
||||
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,
|
||||
_("not giving name %s to the DHCP lease of %s because "
|
||||
"the name exists in %s with address %s"),
|
||||
host_name, inet_ntoa(*host_address),
|
||||
host_name, daemon->addrbuff,
|
||||
record_source(crec->uid), daemon->namebuff);
|
||||
}
|
||||
}
|
||||
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 */
|
||||
break;
|
||||
}
|
||||
@@ -994,14 +1023,16 @@ void cache_add_dhcp_entry(char *host_name,
|
||||
if (in_hosts)
|
||||
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)
|
||||
cache_scan_free(NULL, (struct all_addr *)host_address, 0, F_IPV4 | F_REVERSE);
|
||||
else
|
||||
/* avoid multiple reverse mappings */
|
||||
flags &= ~F_REVERSE;
|
||||
{
|
||||
flags |= F_REVERSE;
|
||||
cache_scan_free(NULL, (struct all_addr *)host_address, 0, flags);
|
||||
}
|
||||
}
|
||||
else
|
||||
flags |= F_REVERSE;
|
||||
|
||||
if ((crec = dhcp_spare))
|
||||
dhcp_spare = dhcp_spare->next;
|
||||
@@ -1010,12 +1041,12 @@ void cache_add_dhcp_entry(char *host_name,
|
||||
|
||||
if (crec) /* malloc may fail */
|
||||
{
|
||||
crec->flags = flags;
|
||||
crec->flags = flags | F_NAMEP | F_DHCP | F_FORWARD;
|
||||
if (ttd == 0)
|
||||
crec->flags |= F_IMMORTAL;
|
||||
else
|
||||
crec->ttd = ttd;
|
||||
crec->addr.addr.addr.addr4 = *host_address;
|
||||
crec->addr.addr = *host_address;
|
||||
crec->name.namep = host_name;
|
||||
crec->uid = uid++;
|
||||
cache_hash(crec);
|
||||
|
||||
@@ -116,7 +116,7 @@ RESOLVFILE
|
||||
has no library dependencies other than libc */
|
||||
|
||||
#define HAVE_DHCP
|
||||
/* #define HAVE_DHCP6 */
|
||||
#define HAVE_DHCP6
|
||||
#define HAVE_TFTP
|
||||
#define HAVE_SCRIPT
|
||||
/* #define HAVE_LUASCRIPT */
|
||||
|
||||
213
src/dhcp-common.c
Normal file
213
src/dhcp-common.c
Normal 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
|
||||
97
src/dhcp.c
97
src/dhcp.c
@@ -119,42 +119,6 @@ void dhcp_init(void)
|
||||
#endif
|
||||
|
||||
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)
|
||||
@@ -610,50 +574,6 @@ struct dhcp_config *config_find_by_address(struct dhcp_config *configs, struct i
|
||||
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,
|
||||
struct in_addr *addrp, unsigned char *hwaddr, int hw_len,
|
||||
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))
|
||||
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)
|
||||
if (is_addr_in_context(context, config))
|
||||
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 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
|
||||
|
||||
|
||||
192
src/dhcp6.c
192
src/dhcp6.c
@@ -23,27 +23,40 @@ struct iface_param {
|
||||
int ind;
|
||||
};
|
||||
|
||||
struct listen_param {
|
||||
int fd_or_iface;
|
||||
struct listen_param *next;
|
||||
};
|
||||
|
||||
static int join_multicast(struct in6_addr *local, int prefix,
|
||||
int scope, int if_index, int dad, void *vparam);
|
||||
|
||||
static int complete_context6(struct in6_addr *local, int prefix,
|
||||
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)
|
||||
{
|
||||
int fd;
|
||||
struct sockaddr_in6 saddr;
|
||||
struct listen_param *listenp, listen;
|
||||
#if defined(IP_TOS) && defined(IPTOS_CLASS_CS6)
|
||||
int class = IPTOS_CLASS_CS6;
|
||||
#endif
|
||||
|
||||
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 ||
|
||||
#endif
|
||||
!fix_fd(fd) ||
|
||||
!set_ipv6pktinfo(fd))
|
||||
die (_("cannot create DHCPv6 socket: %s"), NULL, EC_BADNET);
|
||||
|
||||
memset(&saddr, 0, sizeof(saddr));
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
saddr.sin6_len = sizeof(addr.in6);
|
||||
saddr.sin6_len = sizeof(struct sockaddr_in6);
|
||||
#endif
|
||||
saddr.sin6_family = AF_INET6;
|
||||
saddr.sin6_addr = in6addr_any;
|
||||
@@ -53,16 +66,18 @@ void dhcp6_init(void)
|
||||
die(_("failed to bind DHCPv6 server socket: %s"), NULL, EC_BADNET);
|
||||
|
||||
/* 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);
|
||||
for (listenp = listen.next; listenp; )
|
||||
{
|
||||
struct listen_param *tmp = listenp->next;
|
||||
free(listenp);
|
||||
listenp = tmp;
|
||||
}
|
||||
|
||||
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,
|
||||
@@ -70,15 +85,20 @@ static int join_multicast(struct in6_addr *local, int prefix,
|
||||
{
|
||||
char ifrn_name[IFNAMSIZ];
|
||||
struct ipv6_mreq mreq;
|
||||
struct in6_addr maddr;
|
||||
int fd = *((int *)vparam);
|
||||
struct listen_param *listenp, *param = vparam;
|
||||
int fd = param->fd_or_iface;
|
||||
struct dhcp_context *context;
|
||||
struct iname *tmp;
|
||||
|
||||
(void)prefix;
|
||||
(void)scope;
|
||||
(void)dad;
|
||||
|
||||
/* scope == link */
|
||||
if (scope != 253)
|
||||
/* 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;
|
||||
|
||||
if (!indextoname(fd, if_index, ifrn_name))
|
||||
@@ -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)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
listenp = whine_malloc(sizeof(struct listen_param));
|
||||
listenp->fd_or_iface = if_index;
|
||||
listenp->next = param->next;
|
||||
param->next = listenp;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -190,14 +214,15 @@ void dhcp6_packet(time_t now)
|
||||
lease_prune(NULL, now); /* lose any expired leases */
|
||||
|
||||
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,
|
||||
now, unicast_dest, &is_inform, pxe_fd, iface_addr); */
|
||||
lease_update_file(now);
|
||||
lease_update_dns();
|
||||
|
||||
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,
|
||||
@@ -205,11 +230,16 @@ static int complete_context6(struct in6_addr *local, int prefix,
|
||||
{
|
||||
struct dhcp_context *context;
|
||||
struct iface_param *param = vparam;
|
||||
|
||||
(void)scope; /* warning */
|
||||
(void)dad;
|
||||
|
||||
for (context = daemon->dhcp6; context; context = context->next)
|
||||
{
|
||||
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->end6, prefix))
|
||||
{
|
||||
@@ -218,6 +248,7 @@ static int complete_context6(struct in6_addr *local, int prefix,
|
||||
{
|
||||
context->current = param->current;
|
||||
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,
|
||||
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
|
||||
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;
|
||||
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. */
|
||||
addr = start;
|
||||
@@ -358,6 +389,133 @@ struct dhcp_context *narrow_context6(struct dhcp_context *context,
|
||||
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
|
||||
|
||||
|
||||
|
||||
@@ -53,7 +53,10 @@
|
||||
#define OPTION6_INTERFACE_ID 18
|
||||
#define OPTION6_RECONFIGURE_MSG 19
|
||||
#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 DHCP6UNSPEC 1
|
||||
|
||||
@@ -150,7 +150,9 @@ int main (int argc, char **argv)
|
||||
{
|
||||
/* 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. */
|
||||
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);
|
||||
if (daemon->dhcp)
|
||||
dhcp_init();
|
||||
|
||||
@@ -436,15 +436,20 @@ struct frec {
|
||||
#define ACTION_OLD 3
|
||||
#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 {
|
||||
int clid_len; /* length of client identifier */
|
||||
unsigned char *clid; /* clientid */
|
||||
char *hostname, *fqdn; /* name from client-hostname option or config */
|
||||
char *old_hostname; /* hostname before it moved to another lease */
|
||||
char auth_name; /* hostname came from config, not from client */
|
||||
char new; /* newly created */
|
||||
char changed; /* modified */
|
||||
char aux_changed; /* CLID or expiry changed */
|
||||
int flags;
|
||||
time_t expires; /* lease expiry */
|
||||
#ifdef HAVE_BROKEN_RTC
|
||||
unsigned int length;
|
||||
@@ -455,9 +460,6 @@ struct dhcp_lease {
|
||||
unsigned char *extradata;
|
||||
unsigned int extradata_len, extradata_size;
|
||||
int last_interface;
|
||||
#ifdef HAVE_DHCP6
|
||||
char is_ipv6;
|
||||
#endif
|
||||
struct dhcp_lease *next;
|
||||
};
|
||||
|
||||
@@ -500,6 +502,8 @@ struct dhcp_config {
|
||||
struct dhcp_config *next;
|
||||
};
|
||||
|
||||
#define have_config(config, mask) ((config) && ((config)->flags & (mask)))
|
||||
|
||||
#define CONFIG_DISABLE 1
|
||||
#define CONFIG_CLID 2
|
||||
#define CONFIG_TIME 8
|
||||
@@ -537,6 +541,7 @@ struct dhcp_opt {
|
||||
#define DHOPT_VENDOR_MATCH 1024
|
||||
#define DHOPT_RFC3925 2048
|
||||
#define DHOPT_TAGOK 4096
|
||||
#define DHOPT_ADDR6 8192
|
||||
|
||||
struct dhcp_boot {
|
||||
char *file, *sname, *tftp_sname;
|
||||
@@ -586,6 +591,12 @@ struct cond_domain {
|
||||
struct cond_domain *next;
|
||||
};
|
||||
|
||||
struct cond_domain6 {
|
||||
char *domain;
|
||||
struct in6_addr start, end;
|
||||
struct cond_domain6 *next;
|
||||
};
|
||||
|
||||
struct dhcp_context {
|
||||
unsigned int lease_time, addr_epoch;
|
||||
struct in_addr netmask, broadcast;
|
||||
@@ -672,6 +683,7 @@ extern struct daemon {
|
||||
int group_set, osport;
|
||||
char *domain_suffix;
|
||||
struct cond_domain *cond_domain;
|
||||
struct cond_domain6 *cond_domain6;
|
||||
char *runfile;
|
||||
char *lease_change_command;
|
||||
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,
|
||||
time_t now, unsigned long ttl, unsigned short flags);
|
||||
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);
|
||||
void cache_unhash_dhcp(void);
|
||||
void dump_cache(time_t now);
|
||||
char *cache_get_name(struct crec *crecp);
|
||||
char *get_domain(struct in_addr addr);
|
||||
#ifdef HAVE_IPV6
|
||||
char *get_domain6(struct in6_addr *addr);
|
||||
#endif
|
||||
|
||||
/* rfc1035.c */
|
||||
unsigned int extract_request(struct dns_header *header, size_t qlen,
|
||||
@@ -845,7 +860,8 @@ void flush_log(void);
|
||||
|
||||
/* option.c */
|
||||
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 set_option_bool(unsigned int opt);
|
||||
struct hostsfile *expand_filelist(struct hostsfile *list);
|
||||
@@ -883,18 +899,15 @@ int set_ipv6pktinfo(int fd);
|
||||
#ifdef HAVE_DHCP
|
||||
void dhcp_init(void);
|
||||
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 in_addr addr,
|
||||
struct dhcp_netid *netids);
|
||||
struct dhcp_context *narrow_context(struct dhcp_context *context,
|
||||
struct in_addr taddr,
|
||||
struct dhcp_netid *netids);
|
||||
int match_netid(struct dhcp_netid *check, struct dhcp_netid *pool, int negonly);
|
||||
int address_allocate(struct dhcp_context *context,
|
||||
struct in_addr *addrp, unsigned char *hwaddr, int hw_len,
|
||||
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);
|
||||
struct dhcp_config *find_config(struct dhcp_config *configs,
|
||||
struct dhcp_context *context,
|
||||
@@ -905,7 +918,6 @@ void dhcp_update_configs(struct dhcp_config *configs);
|
||||
void dhcp_read_ethers(void);
|
||||
void check_dhcp_hosts(int fatal);
|
||||
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 *get_domain(struct in_addr addr);
|
||||
#endif
|
||||
@@ -917,13 +929,14 @@ void lease_update_dns();
|
||||
void lease_init(time_t now);
|
||||
struct dhcp_lease *lease4_allocate(struct in_addr addr);
|
||||
#ifdef HAVE_DHCP6
|
||||
struct dhcp_lease *lease6_allocate(struct in6_addr *addrp);
|
||||
struct dhcp_lease *lease6_allocate(struct in6_addr *addrp, int lease_type);
|
||||
struct dhcp_lease *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_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);
|
||||
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_interface(struct dhcp_lease *lease, int interface);
|
||||
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_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);
|
||||
int serial, 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);
|
||||
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
|
||||
|
||||
/* rfc3315.c */
|
||||
#ifdef HAVE_DHCP6
|
||||
void make_duid(time_t now);
|
||||
size_t dhcp6_reply(struct dhcp_context *context, size_t sz, time_t now);
|
||||
size_t dhcp6_reply(struct dhcp_context *context, char *iface_name, size_t sz, int is_multicast, time_t now);
|
||||
#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);
|
||||
|
||||
175
src/lease.c
175
src/lease.c
@@ -30,14 +30,9 @@ void lease_init(time_t now)
|
||||
FILE *leasestream;
|
||||
#ifdef HAVE_DHCP6
|
||||
int v6pass = 0;
|
||||
int lease_type = 0;
|
||||
#endif
|
||||
|
||||
/* These each hold a DHCP option max size 255
|
||||
and get a terminating zero added */
|
||||
daemon->dhcp_buff = safe_malloc(256);
|
||||
daemon->dhcp_buff2 = safe_malloc(256);
|
||||
daemon->dhcp_buff3 = safe_malloc(256);
|
||||
|
||||
leases_left = daemon->dhcp_max;
|
||||
|
||||
if (option_bool(OPT_LEASE_RO))
|
||||
@@ -86,7 +81,18 @@ void lease_init(time_t now)
|
||||
{
|
||||
#ifdef HAVE_DHCP6
|
||||
if (v6pass)
|
||||
hw_type = atoi(daemon->dhcp_buff2);
|
||||
{
|
||||
char *s = daemon->dhcp_buff2;
|
||||
if (s[0] == 'T')
|
||||
{
|
||||
lease_type = LEASE_TA;
|
||||
s++;
|
||||
}
|
||||
else
|
||||
lease_type = LEASE_NA;
|
||||
|
||||
hw_type = atoi(s);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
@@ -109,7 +115,7 @@ void lease_init(time_t now)
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
if (v6pass)
|
||||
lease = lease6_allocate(&addr.addr.addr6);
|
||||
lease = lease6_allocate(&addr.addr.addr6, lease_type);
|
||||
else
|
||||
#endif
|
||||
lease = lease4_allocate(addr.addr.addr4);
|
||||
@@ -130,16 +136,24 @@ void lease_init(time_t now)
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
if (!v6pass)
|
||||
if (v6pass)
|
||||
lease_set_hwaddr(lease, NULL, (unsigned char *)daemon->packet, 0, hw_type, clid_len);
|
||||
else
|
||||
#endif
|
||||
lease_set_hwaddr(lease, (unsigned char *)daemon->dhcp_buff2, (unsigned char *)daemon->packet, hw_len, hw_type, clid_len);
|
||||
|
||||
if (strcmp(daemon->dhcp_buff, "*") != 0)
|
||||
lease_set_hostname(lease, daemon->dhcp_buff, 0);
|
||||
|
||||
{
|
||||
#ifdef HAVE_DHCP6
|
||||
if (v6pass)
|
||||
lease_set_hostname(lease, daemon->dhcp_buff, 0, get_domain6((struct in6_addr *)lease->hwaddr));
|
||||
else
|
||||
#endif
|
||||
lease_set_hostname(lease, daemon->dhcp_buff, 0, get_domain(lease->addr));
|
||||
}
|
||||
/* set these correctly: the "old" events are generated later from
|
||||
the startup synthesised SIGHUP. */
|
||||
lease->new = lease->changed = 0;
|
||||
lease->flags |= ~(LEASE_NEW | LEASE_CHANGED);
|
||||
}
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
@@ -202,9 +216,9 @@ void lease_update_from_configs(void)
|
||||
lease->hwaddr, lease->hwaddr_len, lease->hwaddr_type, NULL)) &&
|
||||
(config->flags & CONFIG_NAME) &&
|
||||
(!(config->flags & CONFIG_ADDR) || config->addr.s_addr == lease->addr.s_addr))
|
||||
lease_set_hostname(lease, config->hostname, 1);
|
||||
lease_set_hostname(lease, config->hostname, 1, get_domain(lease->addr));
|
||||
else if ((name = host_from_dns(lease->addr)))
|
||||
lease_set_hostname(lease, name, 1); /* updates auth flag only */
|
||||
lease_set_hostname(lease, name, 1, get_domain(lease->addr)); /* updates auth flag only */
|
||||
}
|
||||
|
||||
static void ourprintf(int *errp, char *format, ...)
|
||||
@@ -234,7 +248,7 @@ void lease_update_file(time_t now)
|
||||
{
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
if (lease->is_ipv6)
|
||||
if (lease->flags & (LEASE_TA | LEASE_NA))
|
||||
continue;
|
||||
#endif
|
||||
|
||||
@@ -279,7 +293,7 @@ void lease_update_file(time_t now)
|
||||
for (lease = leases; lease; lease = lease->next)
|
||||
{
|
||||
|
||||
if (!lease->is_ipv6)
|
||||
if (!(lease->flags & (LEASE_TA | LEASE_NA)))
|
||||
continue;
|
||||
|
||||
#ifdef HAVE_BROKEN_RTC
|
||||
@@ -290,7 +304,8 @@ void lease_update_file(time_t now)
|
||||
|
||||
inet_ntop(AF_INET6, lease->hwaddr, daemon->addrbuff, ADDRSTRLEN);
|
||||
|
||||
ourprintf(&err, "%u %s ", lease->hwaddr_type, daemon->addrbuff);
|
||||
ourprintf(&err, "%s%u %s ", (lease->flags & LEASE_TA) ? "T" : "",
|
||||
lease->hwaddr_type, daemon->addrbuff);
|
||||
ourprintf(&err, "%s ", lease->hostname ? lease->hostname : "*");
|
||||
|
||||
if (lease->clid && lease->clid_len != 0)
|
||||
@@ -343,11 +358,21 @@ void lease_update_dns(void)
|
||||
|
||||
for (lease = leases; lease; lease = lease->next)
|
||||
{
|
||||
int prot = AF_INET;
|
||||
#ifdef HAVE_DHCP6
|
||||
if (lease->flags & (LEASE_TA | LEASE_NA))
|
||||
prot = AF_INET6;
|
||||
#endif
|
||||
|
||||
if (lease->fqdn)
|
||||
cache_add_dhcp_entry(lease->fqdn, &lease->addr, lease->expires);
|
||||
cache_add_dhcp_entry(lease->fqdn, prot,
|
||||
prot == AF_INET ? (struct all_addr *)&lease->addr : (struct all_addr *)&lease->hwaddr,
|
||||
lease->expires);
|
||||
|
||||
if (!option_bool(OPT_DHCP_FQDN) && lease->hostname)
|
||||
cache_add_dhcp_entry(lease->hostname, &lease->addr, lease->expires);
|
||||
cache_add_dhcp_entry(lease->hostname, prot,
|
||||
prot == AF_INET ? (struct all_addr *)&lease->addr : (struct all_addr *)&lease->hwaddr,
|
||||
lease->expires);
|
||||
}
|
||||
|
||||
dns_dirty = 0;
|
||||
@@ -391,7 +416,7 @@ struct dhcp_lease *lease_find_by_client(unsigned char *hwaddr, int hw_len, int h
|
||||
for (lease = leases; lease; lease = lease->next)
|
||||
{
|
||||
#ifdef HAVE_DHCP6
|
||||
if (lease->is_ipv6)
|
||||
if (lease->flags & (LEASE_TA | LEASE_NA))
|
||||
continue;
|
||||
#endif
|
||||
if (lease->clid && clid_len == lease->clid_len &&
|
||||
@@ -402,7 +427,7 @@ struct dhcp_lease *lease_find_by_client(unsigned char *hwaddr, int hw_len, int h
|
||||
for (lease = leases; lease; lease = lease->next)
|
||||
{
|
||||
#ifdef HAVE_DHCP6
|
||||
if (lease->is_ipv6)
|
||||
if (lease->flags & (LEASE_TA | LEASE_NA))
|
||||
continue;
|
||||
#endif
|
||||
if ((!lease->clid || !clid) &&
|
||||
@@ -423,7 +448,7 @@ struct dhcp_lease *lease_find_by_addr(struct in_addr addr)
|
||||
for (lease = leases; lease; lease = lease->next)
|
||||
{
|
||||
#ifdef HAVE_DHCP6
|
||||
if (lease->is_ipv6)
|
||||
if (lease->flags & (LEASE_TA | LEASE_NA))
|
||||
continue;
|
||||
#endif
|
||||
if (lease->addr.s_addr == addr.s_addr)
|
||||
@@ -434,20 +459,37 @@ struct dhcp_lease *lease_find_by_addr(struct in_addr addr)
|
||||
}
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
struct dhcp_lease *lease6_find_by_client(unsigned char *clid, int clid_len, int iaid)
|
||||
/* addr or clid may be NULL for "don't care, both NULL resets "USED" flags both
|
||||
set activates USED check */
|
||||
struct dhcp_lease *lease6_find(unsigned char *clid, int clid_len,
|
||||
int lease_type, int iaid, struct in6_addr *addr)
|
||||
{
|
||||
struct dhcp_lease *lease;
|
||||
|
||||
for (lease = leases; lease; lease = lease->next)
|
||||
{
|
||||
if (!lease->is_ipv6)
|
||||
if (!(lease->flags & lease_type) || lease->hwaddr_type != iaid)
|
||||
continue;
|
||||
|
||||
if (lease->hwaddr_type == iaid &&
|
||||
lease->clid && clid_len == lease->clid_len &&
|
||||
memcmp(clid, lease->clid, clid_len) == 0)
|
||||
if (clid && addr && (lease->flags & LEASE_USED))
|
||||
continue;
|
||||
|
||||
if (addr && memcmp(lease->hwaddr, addr, IN6ADDRSZ) != 0)
|
||||
continue;
|
||||
|
||||
if (clid &&
|
||||
(clid_len != lease->clid_len ||
|
||||
memcmp(clid, lease->clid, clid_len) != 0))
|
||||
continue;
|
||||
|
||||
if (clid || addr)
|
||||
{
|
||||
lease->flags |= LEASE_USED;
|
||||
return lease;
|
||||
}
|
||||
else
|
||||
lease->flags &= ~LEASE_USED;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -458,7 +500,7 @@ struct dhcp_lease *lease6_find_by_addr(struct in6_addr *net, int prefix, u64 add
|
||||
|
||||
for (lease = leases; lease; lease = lease->next)
|
||||
{
|
||||
if (!lease->is_ipv6)
|
||||
if (!(lease->flags & (LEASE_TA | LEASE_NA)))
|
||||
continue;
|
||||
|
||||
if (is_same_net6((struct in6_addr *)lease->hwaddr, net, prefix) &&
|
||||
@@ -468,7 +510,6 @@ struct dhcp_lease *lease6_find_by_addr(struct in6_addr *net, int prefix, u64 add
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* Find largest assigned address in context */
|
||||
@@ -481,7 +522,7 @@ struct in_addr lease_find_max_addr(struct dhcp_context *context)
|
||||
for (lease = leases; lease; lease = lease->next)
|
||||
{
|
||||
#ifdef HAVE_DHCP6
|
||||
if (lease->is_ipv6)
|
||||
if (lease->flags & (LEASE_TA | LEASE_NA))
|
||||
continue;
|
||||
#endif
|
||||
if (((unsigned)ntohl(lease->addr.s_addr)) > ((unsigned)ntohl(context->start.s_addr)) &&
|
||||
@@ -500,7 +541,7 @@ static struct dhcp_lease *lease_allocate(void)
|
||||
return NULL;
|
||||
|
||||
memset(lease, 0, sizeof(struct dhcp_lease));
|
||||
lease->new = 1;
|
||||
lease->flags = LEASE_NEW;
|
||||
lease->expires = 1;
|
||||
#ifdef HAVE_BROKEN_RTC
|
||||
lease->length = 0xffffffff; /* illegal value */
|
||||
@@ -524,11 +565,11 @@ struct dhcp_lease *lease4_allocate(struct in_addr addr)
|
||||
}
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
struct dhcp_lease *lease6_allocate(struct in6_addr *addrp)
|
||||
struct dhcp_lease *lease6_allocate(struct in6_addr *addrp, int lease_type)
|
||||
{
|
||||
struct dhcp_lease *lease = lease_allocate();
|
||||
memcpy(lease->hwaddr, addrp, sizeof(*addrp)) ;
|
||||
lease->is_ipv6 = 1;
|
||||
lease->flags |= lease_type;
|
||||
|
||||
return lease;
|
||||
}
|
||||
@@ -549,7 +590,8 @@ void lease_set_expires(struct dhcp_lease *lease, unsigned int len, time_t now)
|
||||
dns_dirty = 1;
|
||||
lease->expires = exp;
|
||||
#ifndef HAVE_BROKEN_RTC
|
||||
lease->aux_changed = file_dirty = 1;
|
||||
lease->flags |= LEASE_AUX_CHANGED;
|
||||
file_dirty = 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -569,10 +611,12 @@ void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
|
||||
hw_type != lease->hwaddr_type ||
|
||||
(hw_len != 0 && memcmp(lease->hwaddr, hwaddr, hw_len) != 0))
|
||||
{
|
||||
if (hw_len != 0)
|
||||
memcpy(lease->hwaddr, hwaddr, hw_len);
|
||||
lease->hwaddr_len = hw_len;
|
||||
lease->hwaddr_type = hw_type;
|
||||
lease->changed = file_dirty = 1; /* run script on change */
|
||||
lease->flags |= LEASE_CHANGED;
|
||||
file_dirty = 1; /* run script on change */
|
||||
}
|
||||
|
||||
/* only update clid when one is available, stops packets
|
||||
@@ -585,13 +629,17 @@ void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
|
||||
|
||||
if (lease->clid_len != clid_len)
|
||||
{
|
||||
lease->aux_changed = file_dirty = 1;
|
||||
lease->flags |= LEASE_AUX_CHANGED;
|
||||
file_dirty = 1;
|
||||
free(lease->clid);
|
||||
if (!(lease->clid = whine_malloc(clid_len)))
|
||||
return;
|
||||
}
|
||||
else if (memcmp(lease->clid, clid, clid_len) != 0)
|
||||
lease->aux_changed = file_dirty = 1;
|
||||
{
|
||||
lease->flags |= LEASE_AUX_CHANGED;
|
||||
file_dirty = 1;
|
||||
}
|
||||
|
||||
lease->clid_len = clid_len;
|
||||
memcpy(lease->clid, clid, clid_len);
|
||||
@@ -608,7 +656,7 @@ static void kill_name(struct dhcp_lease *lease)
|
||||
free(lease->old_hostname);
|
||||
|
||||
/* If we know the fqdn, pass that. The helper will derive the
|
||||
unqualified name from it, free the unqulaified name here. */
|
||||
unqualified name from it, free the unqualified name here. */
|
||||
|
||||
if (lease->fqdn)
|
||||
{
|
||||
@@ -621,14 +669,15 @@ static void kill_name(struct dhcp_lease *lease)
|
||||
lease->hostname = lease->fqdn = NULL;
|
||||
}
|
||||
|
||||
void lease_set_hostname(struct dhcp_lease *lease, char *name, int auth)
|
||||
void lease_set_hostname(struct dhcp_lease *lease, char *name, int auth, char *domain)
|
||||
{
|
||||
struct dhcp_lease *lease_tmp;
|
||||
char *new_name = NULL, *new_fqdn = NULL;
|
||||
|
||||
if (lease->hostname && name && hostname_isequal(lease->hostname, name))
|
||||
{
|
||||
lease->auth_name = auth;
|
||||
if (auth)
|
||||
lease->flags |= LEASE_AUTH_NAME;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -638,19 +687,21 @@ void lease_set_hostname(struct dhcp_lease *lease, char *name, int auth)
|
||||
/* If a machine turns up on a new net without dropping the old lease,
|
||||
or two machines claim the same name, then we end up with two interfaces with
|
||||
the same name. Check for that here and remove the name from the old lease.
|
||||
Note that IPv6 leases are different. All the leases to the same DUID are
|
||||
allowed the same name.
|
||||
|
||||
Don't allow a name from the client to override a name from dnsmasq config. */
|
||||
|
||||
if (name)
|
||||
{
|
||||
if ((new_name = whine_malloc(strlen(name) + 1)))
|
||||
{
|
||||
char *suffix = get_domain(lease->addr);
|
||||
strcpy(new_name, name);
|
||||
if (suffix && (new_fqdn = whine_malloc(strlen(new_name) + strlen(suffix) + 2)))
|
||||
if (domain && (new_fqdn = whine_malloc(strlen(new_name) + strlen(domain) + 2)))
|
||||
{
|
||||
strcpy(new_fqdn, name);
|
||||
strcat(new_fqdn, ".");
|
||||
strcat(new_fqdn, suffix);
|
||||
strcat(new_fqdn, domain);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -659,7 +710,7 @@ void lease_set_hostname(struct dhcp_lease *lease, char *name, int auth)
|
||||
{
|
||||
if (option_bool(OPT_DHCP_FQDN))
|
||||
{
|
||||
if (!new_fqdn || !lease_tmp->fqdn || !hostname_isequal(lease_tmp->fqdn, new_fqdn) )
|
||||
if (!new_fqdn || !lease_tmp->fqdn || !hostname_isequal(lease_tmp->fqdn, new_fqdn))
|
||||
continue;
|
||||
}
|
||||
else
|
||||
@@ -668,7 +719,21 @@ void lease_set_hostname(struct dhcp_lease *lease, char *name, int auth)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (lease_tmp->auth_name && !auth)
|
||||
if (lease->flags & (LEASE_TA | LEASE_NA))
|
||||
{
|
||||
if (!(lease_tmp->flags & (LEASE_TA | LEASE_NA)))
|
||||
continue;
|
||||
|
||||
/* another lease for the saem DUID is OK for IPv6 */
|
||||
if (lease->clid_len == lease_tmp->clid_len &&
|
||||
lease->clid && lease_tmp->clid &&
|
||||
memcmp(lease->clid, lease_tmp->clid, lease->clid_len) == 0)
|
||||
continue;
|
||||
}
|
||||
else if (lease_tmp->flags & (LEASE_TA | LEASE_NA))
|
||||
continue;
|
||||
|
||||
if ((lease_tmp->flags & LEASE_AUTH_NAME) && !auth)
|
||||
{
|
||||
free(new_name);
|
||||
free(new_fqdn);
|
||||
@@ -685,11 +750,13 @@ void lease_set_hostname(struct dhcp_lease *lease, char *name, int auth)
|
||||
|
||||
lease->hostname = new_name;
|
||||
lease->fqdn = new_fqdn;
|
||||
lease->auth_name = auth;
|
||||
|
||||
if (auth)
|
||||
lease->flags |= LEASE_AUTH_NAME;
|
||||
|
||||
file_dirty = 1;
|
||||
dns_dirty = 1;
|
||||
lease->changed = 1; /* run script on change */
|
||||
lease->flags |= LEASE_CHANGED; /* run script on change */
|
||||
}
|
||||
|
||||
void lease_set_interface(struct dhcp_lease *lease, int interface)
|
||||
@@ -698,7 +765,7 @@ void lease_set_interface(struct dhcp_lease *lease, int interface)
|
||||
return;
|
||||
|
||||
lease->last_interface = interface;
|
||||
lease->changed = 1;
|
||||
lease->flags |= LEASE_CHANGED;
|
||||
}
|
||||
|
||||
void rerun_scripts(void)
|
||||
@@ -706,7 +773,7 @@ void rerun_scripts(void)
|
||||
struct dhcp_lease *lease;
|
||||
|
||||
for (lease = leases; lease; lease = lease->next)
|
||||
lease->changed = 1;
|
||||
lease->flags |= LEASE_CHANGED;
|
||||
}
|
||||
|
||||
/* deleted leases get transferred to the old_leases list.
|
||||
@@ -772,18 +839,18 @@ int do_script_run(time_t now)
|
||||
}
|
||||
|
||||
for (lease = leases; lease; lease = lease->next)
|
||||
if (lease->new || lease->changed ||
|
||||
(lease->aux_changed && option_bool(OPT_LEASE_RO)))
|
||||
if ((lease->flags & (LEASE_NEW | LEASE_CHANGED)) ||
|
||||
((lease->flags & LEASE_AUX_CHANGED) && option_bool(OPT_LEASE_RO)))
|
||||
{
|
||||
#ifdef HAVE_SCRIPT
|
||||
queue_script(lease->new ? ACTION_ADD : ACTION_OLD, lease,
|
||||
queue_script((lease->flags & LEASE_NEW) ? ACTION_ADD : ACTION_OLD, lease,
|
||||
lease->fqdn ? lease->fqdn : lease->hostname, now);
|
||||
#endif
|
||||
#ifdef HAVE_DBUS
|
||||
emit_dbus_signal(lease->new ? ACTION_ADD : ACTION_OLD, lease,
|
||||
emit_dbus_signal((lease->flags & LEASE_NEW) ? ACTION_ADD : ACTION_OLD, lease,
|
||||
lease->fqdn ? lease->fqdn : lease->hostname);
|
||||
#endif
|
||||
lease->new = lease->changed = lease->aux_changed = 0;
|
||||
lease->flags &= ~(LEASE_NEW | LEASE_CHANGED | LEASE_AUX_CHANGED);
|
||||
|
||||
/* this is used for the "add" call, then junked, since they're not in the database */
|
||||
free(lease->extradata);
|
||||
|
||||
@@ -282,7 +282,9 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
||||
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;
|
||||
}
|
||||
#endif
|
||||
|
||||
348
src/option.c
348
src/option.c
@@ -363,15 +363,16 @@ static struct {
|
||||
};
|
||||
|
||||
#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;
|
||||
unsigned char val, size;
|
||||
u16 val, size;
|
||||
} opttab[] = {
|
||||
{ "netmask", 1, OT_ADDR_LIST },
|
||||
{ "time-offset", 2, 4 },
|
||||
@@ -422,7 +423,7 @@ static const struct {
|
||||
{ "T1", 58, OT_INTERNAL },
|
||||
{ "T2", 59, OT_INTERNAL },
|
||||
{ "vendor-class", 60, 0 },
|
||||
{ "client-id", 61,OT_INTERNAL },
|
||||
{ "client-id", 61, OT_INTERNAL },
|
||||
{ "nis+-domain", 64, OT_NAME },
|
||||
{ "nis+-server", 65, OT_ADDR_LIST },
|
||||
{ "tftp-server", 66, OT_NAME },
|
||||
@@ -447,21 +448,125 @@ static const struct {
|
||||
{ NULL, 0, 0 }
|
||||
};
|
||||
|
||||
char *option_string(unsigned char opt, int *is_ip, int *is_name)
|
||||
{
|
||||
int i;
|
||||
#ifdef HAVE_DHCP6
|
||||
static const struct opttab_t opttab6[] = {
|
||||
{ "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)
|
||||
*is_ip = !!(opttab[i].size & OT_ADDR_LIST);
|
||||
if (is_name)
|
||||
*is_name = !!(opttab[i].size & OT_NAME);
|
||||
return opttab[i].name;
|
||||
if (buf)
|
||||
{
|
||||
memset(buf, 0, buf_len);
|
||||
|
||||
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
|
||||
@@ -699,6 +804,19 @@ static void display_opts(void)
|
||||
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)
|
||||
{
|
||||
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));
|
||||
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;
|
||||
struct dhcp_netid *np = NULL;
|
||||
unsigned char opt_len = 0;
|
||||
u16 opt_len = 0;
|
||||
int is6 = 0;
|
||||
|
||||
new->len = 0;
|
||||
new->flags = flags;
|
||||
@@ -759,6 +878,32 @@ static char *parse_dhcp_opt(char *arg, int flags)
|
||||
/* option:<optname> must follow tag and vendor string. */
|
||||
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)
|
||||
{
|
||||
new->u.vendor_class = (unsigned char *)opt_string_alloc(arg+7);
|
||||
@@ -794,6 +939,25 @@ static char *parse_dhcp_opt(char *arg, int flags)
|
||||
arg = comma;
|
||||
}
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
if (is6)
|
||||
{
|
||||
if (new->flags & (DHOPT_VENDOR | DHOPT_ENCAPSULATE))
|
||||
problem = _("unsupported encapsulation for IPv6 option");
|
||||
|
||||
if (opt_len == 0 &&
|
||||
!(new->flags & DHOPT_RFC3925))
|
||||
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++)
|
||||
@@ -813,7 +977,7 @@ static char *parse_dhcp_opt(char *arg, int flags)
|
||||
/* characterise the value */
|
||||
char c;
|
||||
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;
|
||||
dots = 0;
|
||||
for (cp = comma; (c = *cp); cp++)
|
||||
@@ -829,17 +993,17 @@ static char *parse_dhcp_opt(char *arg, int flags)
|
||||
}
|
||||
else if (c == '/')
|
||||
{
|
||||
is_dec = is_hex = 0;
|
||||
is_addr6 = is_dec = is_hex = 0;
|
||||
if (cp == comma) /* leading / means a pathname */
|
||||
is_addr = 0;
|
||||
}
|
||||
else if (c == '.')
|
||||
{
|
||||
is_dec = is_hex = 0;
|
||||
is_addr6 =is_dec = is_hex = 0;
|
||||
dots++;
|
||||
}
|
||||
else if (c == '-')
|
||||
is_hex = is_addr = 0;
|
||||
is_hex = is_addr = is_addr6 = 0;
|
||||
else if (c == ' ')
|
||||
is_dec = is_hex = 0;
|
||||
else if (!(c >='0' && c <= '9'))
|
||||
@@ -856,7 +1020,11 @@ static char *parse_dhcp_opt(char *arg, int flags)
|
||||
if (!((c >='A' && c <= 'F') ||
|
||||
(c >='a' && c <= 'f') ||
|
||||
(c == '*' && (flags & DHOPT_MATCH))))
|
||||
{
|
||||
is_hex = 0;
|
||||
if (c != '[' && c != ']')
|
||||
is_addr6 = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
found_dig = 1;
|
||||
@@ -868,12 +1036,16 @@ static char *parse_dhcp_opt(char *arg, int flags)
|
||||
if (opt_len & OT_ADDR_LIST)
|
||||
{
|
||||
is_string = is_dec = is_hex = 0;
|
||||
if (!is_addr || dots == 0)
|
||||
|
||||
if (!is6 && (!is_addr || dots == 0))
|
||||
problem = _("bad IP address");
|
||||
|
||||
if (is6 && !is_addr6)
|
||||
problem = _("bad IPv6 address");
|
||||
}
|
||||
/* or names */
|
||||
else if (opt_len & (OT_NAME | OT_RFC1035_NAME))
|
||||
is_addr = is_dec = is_hex = 0;
|
||||
else if (opt_len & (OT_NAME | OT_RFC1035_NAME | OT_CSTRING))
|
||||
is_addr6 = is_addr = is_dec = is_hex = 0;
|
||||
|
||||
if (is_hex && digs > 1)
|
||||
{
|
||||
@@ -908,7 +1080,7 @@ static char *parse_dhcp_opt(char *arg, int flags)
|
||||
for (i=0; i<new->len; i++)
|
||||
new->val[i] = val>>((new->len - i - 1)*8);
|
||||
}
|
||||
else if (is_addr)
|
||||
else if (is_addr && !is6)
|
||||
{
|
||||
struct in_addr in;
|
||||
unsigned char *op;
|
||||
@@ -953,11 +1125,37 @@ static char *parse_dhcp_opt(char *arg, int flags)
|
||||
}
|
||||
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)
|
||||
{
|
||||
/* text arg */
|
||||
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 */
|
||||
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->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
|
||||
{
|
||||
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 > 250 && (new->flags & DHOPT_RFC3925)))
|
||||
(new->len > 250 && (new->flags & DHOPT_RFC3925))))
|
||||
problem = _("dhcp-option too long");
|
||||
|
||||
if (!problem)
|
||||
@@ -1059,6 +1315,11 @@ static char *parse_dhcp_opt(char *arg, int flags)
|
||||
daemon->dhcp_match = new;
|
||||
}
|
||||
}
|
||||
else if (is6)
|
||||
{
|
||||
new->next = daemon->dhcp_opts6;
|
||||
daemon->dhcp_opts6 = new;
|
||||
}
|
||||
else
|
||||
{
|
||||
new->next = daemon->dhcp_opts;
|
||||
@@ -1989,6 +2250,8 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
|
||||
{
|
||||
new->prefix = pref;
|
||||
leasepos = 3;
|
||||
if (new->prefix < 64)
|
||||
problem = _("prefix must be at least 64");
|
||||
}
|
||||
}
|
||||
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)
|
||||
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
|
||||
{
|
||||
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;
|
||||
else if (option == 'w')
|
||||
{
|
||||
if (argc != 3 || strcmp(argv[2], "dhcp") != 0)
|
||||
do_usage();
|
||||
#ifdef HAVE_DHCP
|
||||
else
|
||||
if (argc == 3 && strcmp(argv[2], "dhcp") == 0)
|
||||
display_opts();
|
||||
#ifdef HAVE_DHCP6
|
||||
else if (argc == 3 && strcmp(argv[2], "dhcp6") == 0)
|
||||
display_opts6();
|
||||
#endif
|
||||
else
|
||||
#endif
|
||||
do_usage();
|
||||
|
||||
exit(0);
|
||||
}
|
||||
else if (option == 'v')
|
||||
|
||||
138
src/rfc2131.c
138
src/rfc2131.c
@@ -18,7 +18,6 @@
|
||||
|
||||
#ifdef HAVE_DHCP
|
||||
|
||||
#define have_config(config, mask) ((config) && ((config)->flags & (mask)))
|
||||
#define option_len(opt) ((int)(((unsigned char *)(opt))[1]))
|
||||
#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,
|
||||
int opt, char *string, int null_term);
|
||||
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 void log_packet(char *type, void *addr, unsigned char *ext_mac,
|
||||
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_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 void clear_packet(struct dhcp_packet *mess, unsigned char *end);
|
||||
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);
|
||||
}
|
||||
|
||||
log_tags(tagif_netid, mess);
|
||||
log_tags(tagif_netid, ntohl(mess->xid));
|
||||
|
||||
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);
|
||||
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. */
|
||||
lease_set_expires(lease,
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
log_tags(tagif_netid, mess);
|
||||
log_tags(tagif_netid, ntohl(mess->xid));
|
||||
|
||||
#ifdef HAVE_SCRIPT
|
||||
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)
|
||||
lease->giaddr = mess->giaddr;
|
||||
|
||||
lease->changed = 1;
|
||||
lease->flags |= LEASE_CHANGED;
|
||||
free(lease->extradata);
|
||||
lease->extradata = NULL;
|
||||
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)
|
||||
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_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)
|
||||
{
|
||||
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);
|
||||
|
||||
@@ -1601,30 +1598,10 @@ static void log_options(unsigned char *start, u32 xid)
|
||||
{
|
||||
while (*start != OPTION_END)
|
||||
{
|
||||
int is_ip, is_name, i;
|
||||
char *text = option_string(start[0], &is_ip, &is_name);
|
||||
unsigned char trunc = option_len(start);
|
||||
char *optname = option_string(AF_INET, start[0], option_ptr(start, 0), option_len(start), daemon->namebuff, MAXDNAME);
|
||||
|
||||
if (is_ip)
|
||||
for (daemon->namebuff[0]= 0, i = 0; i <= trunc - INADDRSZ; i += INADDRSZ)
|
||||
{
|
||||
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) ? "" : "...");
|
||||
my_syslog(MS_DHCP | LOG_INFO, "%u sent size:%3d option:%3d %s %s",
|
||||
ntohl(xid), option_len(start), start[0], optname, daemon->namebuff);
|
||||
start += start[1] + 2;
|
||||
}
|
||||
}
|
||||
@@ -1679,22 +1656,17 @@ static unsigned char *option_find(struct dhcp_packet *mess, size_t size, int opt
|
||||
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. */
|
||||
/* struct in_addr is network byte order */
|
||||
struct in_addr ret;
|
||||
|
||||
memcpy(&ret, option_ptr(opt, offset), INADDRSZ);
|
||||
memcpy(&ret, option_ptr(opt, 0), INADDRSZ);
|
||||
|
||||
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)
|
||||
{
|
||||
/* this worries about unaligned data and byte order */
|
||||
@@ -1729,31 +1701,6 @@ static unsigned char *find_overload(struct dhcp_packet *mess)
|
||||
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)
|
||||
{
|
||||
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_list *id_list;
|
||||
|
||||
/* flag options which are valid with the current tag set (sans context tags) */
|
||||
tagif = run_tag_if(netid);
|
||||
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);
|
||||
}
|
||||
/* filter options based on tags, those we want get DHOPT_TAGOK bit set */
|
||||
tagif = option_filter(netid, &context->netid, config_opts);
|
||||
|
||||
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);
|
||||
@@ -2269,12 +2175,12 @@ static void do_options(struct dhcp_context *context,
|
||||
char *q = daemon->namebuff;
|
||||
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),
|
||||
"%d%s%s%s",
|
||||
req_options[i],
|
||||
s ? ":" : "",
|
||||
s ? s : "",
|
||||
strlen(s) != 0 ? ":" : "",
|
||||
s,
|
||||
req_options[i+1] == OPTION_END ? "" : ", ");
|
||||
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,
|
||||
eg dhcp-option=encap:172,17,.......
|
||||
Also hand vendor-identifying vendor-encapsulated options,
|
||||
dhcp-option = rfc3925-encap:13,17,.......
|
||||
Also handle vendor-identifying vendor-encapsulated options,
|
||||
dhcp-option = vi-encap:13,17,.......
|
||||
The may be more that one "outer" to do, so group
|
||||
all the options which match each outer in turn. */
|
||||
for (opt = config_opts; opt; opt = opt->next)
|
||||
|
||||
1327
src/rfc3315.c
1327
src/rfc3315.c
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user