mirror of
https://github.com/pi-hole/dnsmasq.git
synced 2025-12-19 10:18:25 +00:00
import of dnsmasq-2.27.tar.gz
This commit is contained in:
@@ -194,7 +194,7 @@ static int cache_scan_free(char *name, struct all_addr *addr, time_t now, unsign
|
||||
}
|
||||
}
|
||||
else if ((crecp->flags & F_FORWARD) &&
|
||||
((flags & crecp->flags & (F_IPV4 | F_IPV6)) || (crecp->flags & F_CNAME)) &&
|
||||
((flags & crecp->flags & (F_IPV4 | F_IPV6)) || ((crecp->flags | flags) & F_CNAME)) &&
|
||||
hostname_isequal(cache_get_name(crecp), name))
|
||||
{
|
||||
if (crecp->flags & (F_HOSTS | F_DHCP))
|
||||
|
||||
@@ -12,13 +12,14 @@
|
||||
|
||||
/* Author's email: simon@thekelleys.org.uk */
|
||||
|
||||
#define VERSION "2.26"
|
||||
#define VERSION "2.27"
|
||||
|
||||
#define FTABSIZ 150 /* max number of outstanding requests */
|
||||
#define MAX_PROCS 20 /* max no children for TCP requests */
|
||||
#define CHILD_LIFETIME 150 /* secs 'till terminated (RFC1035 suggests > 120s) */
|
||||
#define EDNS_PKTSZ 1280 /* default max EDNS.0 UDP packet from RFC2671 */
|
||||
#define TIMEOUT 20 /* drop UDP queries after TIMEOUT seconds */
|
||||
#define LEASE_RETRY 60 /* on error, retry writing leasefile after LEASE_RETRY seconds */
|
||||
#define LOGRATE 120 /* log table overflows every LOGRATE seconds */
|
||||
#define CACHESIZ 150 /* default cache size */
|
||||
#define MAXTOK 50 /* token in DHCP leases */
|
||||
|
||||
282
src/dhcp.c
282
src/dhcp.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2005 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2006 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
|
||||
@@ -115,8 +115,9 @@ void dhcp_packet(struct daemon *daemon, time_t now)
|
||||
struct msghdr msg;
|
||||
struct iovec iov[2];
|
||||
struct cmsghdr *cmptr;
|
||||
int sz, newlen, iface_index = 0;
|
||||
int unicast_dest = 0;
|
||||
ssize_t sz;
|
||||
size_t newlen;
|
||||
int iface_index = 0, unicast_dest = 0;
|
||||
struct in_addr iface_addr;
|
||||
#ifdef HAVE_BPF
|
||||
unsigned char iface_hwaddr[ETHER_ADDR_LEN];
|
||||
@@ -144,7 +145,7 @@ void dhcp_packet(struct daemon *daemon, time_t now)
|
||||
|
||||
sz = recvmsg(daemon->dhcpfd, &msg, 0);
|
||||
|
||||
if (sz < (int)(sizeof(*mess) - sizeof(mess->options)))
|
||||
if (sz < (ssize_t)(sizeof(*mess) - sizeof(mess->options)))
|
||||
return;
|
||||
|
||||
#if defined (IP_PKTINFO)
|
||||
@@ -248,8 +249,8 @@ void dhcp_packet(struct daemon *daemon, time_t now)
|
||||
}
|
||||
|
||||
lease_prune(NULL, now); /* lose any expired leases */
|
||||
newlen = dhcp_reply(daemon, context, ifr.ifr_name, sz, now, unicast_dest);
|
||||
lease_update_file(0, now);
|
||||
newlen = dhcp_reply(daemon, context, ifr.ifr_name, (size_t)sz, now, unicast_dest);
|
||||
lease_update_file(daemon, 0, now);
|
||||
lease_update_dns(daemon);
|
||||
|
||||
if (newlen == 0)
|
||||
@@ -289,16 +290,16 @@ void dhcp_packet(struct daemon *daemon, time_t now)
|
||||
the kernel IP stack */
|
||||
|
||||
u32 i, sum;
|
||||
unsigned char hwdest[ETHER_ADDR_LEN];
|
||||
unsigned char hwdest[DHCP_CHADDR_MAX];
|
||||
|
||||
if (ntohs(mess->flags) & 0x8000)
|
||||
{
|
||||
memset(hwdest, 255, ETHER_ADDR_LEN);
|
||||
memset(hwdest, 255, mess->hlen);
|
||||
rawpacket->ip.ip_dst.s_addr = INADDR_BROADCAST;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(hwdest, mess->chaddr, ETHER_ADDR_LEN);
|
||||
memcpy(hwdest, mess->chaddr, mess->hlen);
|
||||
rawpacket->ip.ip_dst.s_addr = mess->yiaddr.s_addr;
|
||||
}
|
||||
|
||||
@@ -322,7 +323,8 @@ void dhcp_packet(struct daemon *daemon, time_t now)
|
||||
|
||||
rawpacket->udp.uh_sport = htons(DHCP_SERVER_PORT);
|
||||
rawpacket->udp.uh_dport = htons(DHCP_CLIENT_PORT);
|
||||
((u8 *)&rawpacket->data)[newlen] = 0; /* for checksum, in case length is odd. */
|
||||
if (newlen & 1)
|
||||
((u8 *)&rawpacket->data)[newlen] = 0; /* for checksum, in case length is odd. */
|
||||
rawpacket->udp.uh_sum = 0;
|
||||
rawpacket->udp.uh_ulen = sum = htons(sizeof(struct udphdr) + newlen);
|
||||
sum += htons(IPPROTO_UDP);
|
||||
@@ -338,26 +340,43 @@ void dhcp_packet(struct daemon *daemon, time_t now)
|
||||
#ifdef HAVE_BPF
|
||||
struct ether_header header;
|
||||
|
||||
header.ether_type = htons(ETHERTYPE_IP);
|
||||
memcpy(header.ether_shost, iface_hwaddr, ETHER_ADDR_LEN);
|
||||
memcpy(header.ether_dhost, hwdest, ETHER_ADDR_LEN);
|
||||
|
||||
ioctl(daemon->dhcp_raw_fd, BIOCSETIF, &ifr);
|
||||
|
||||
iov[0].iov_base = (char *)&header;
|
||||
iov[0].iov_len = sizeof(struct ether_header);
|
||||
iov[1].iov_base = (char *)rawpacket;
|
||||
iov[1].iov_len = ntohs(rawpacket->ip.ip_len);
|
||||
while (writev(daemon->dhcp_raw_fd, iov, 2) == -1 && retry_send());
|
||||
/* Only know how to do ethernet on *BSD */
|
||||
if (mess->htype != ARPHRD_ETHER || mess->hlen != ETHER_ADDR_LEN)
|
||||
syslog(LOG_WARNING, _("DHCP request for unsupported hardware type (%d) recieved on %s"),
|
||||
mess->htype, ifr.ifr_name);
|
||||
else
|
||||
{
|
||||
header.ether_type = htons(ETHERTYPE_IP);
|
||||
memcpy(header.ether_shost, iface_hwaddr, ETHER_ADDR_LEN);
|
||||
memcpy(header.ether_dhost, hwdest, ETHER_ADDR_LEN);
|
||||
|
||||
ioctl(daemon->dhcp_raw_fd, BIOCSETIF, &ifr);
|
||||
|
||||
iov[0].iov_base = (char *)&header;
|
||||
iov[0].iov_len = sizeof(struct ether_header);
|
||||
iov[1].iov_base = (char *)rawpacket;
|
||||
iov[1].iov_len = ntohs(rawpacket->ip.ip_len);
|
||||
while (writev(daemon->dhcp_raw_fd, iov, 2) == -1 && retry_send());
|
||||
}
|
||||
#else
|
||||
struct sockaddr_ll dest;
|
||||
/* Most definitions of this only include 8 bytes of address,
|
||||
so we roll our own, since later kernels allow more. */
|
||||
struct {
|
||||
unsigned short int sll_family;
|
||||
unsigned short int sll_protocol;
|
||||
int sll_ifindex;
|
||||
unsigned short int sll_hatype;
|
||||
unsigned char sll_pkttype;
|
||||
unsigned char sll_halen;
|
||||
unsigned char sll_addr[DHCP_CHADDR_MAX];
|
||||
} dest;
|
||||
|
||||
memset(&dest, 0, sizeof(dest));
|
||||
dest.sll_family = AF_PACKET;
|
||||
dest.sll_halen = ETHER_ADDR_LEN;
|
||||
dest.sll_halen = mess->hlen;
|
||||
dest.sll_ifindex = iface_index;
|
||||
dest.sll_protocol = htons(ETHERTYPE_IP);
|
||||
memcpy(dest.sll_addr, hwdest, ETHER_ADDR_LEN);
|
||||
memcpy(dest.sll_addr, hwdest, mess->hlen);
|
||||
while (sendto(daemon->dhcp_raw_fd, rawpacket, ntohs(rawpacket->ip.ip_len),
|
||||
0, (struct sockaddr *)&dest, sizeof(dest)) == -1 &&
|
||||
retry_send());
|
||||
@@ -493,12 +512,13 @@ 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? */
|
||||
int match_netid(struct dhcp_netid *check, struct dhcp_netid *pool)
|
||||
/* Is every member of check matched by a member of pool?
|
||||
If negonly, match unless there's a negative tag which matches. */
|
||||
int match_netid(struct dhcp_netid *check, struct dhcp_netid *pool, int negonly)
|
||||
{
|
||||
struct dhcp_netid *tmp1;
|
||||
|
||||
if (!check)
|
||||
if (!check && !negonly)
|
||||
return 0;
|
||||
|
||||
for (; check; check = check->next)
|
||||
@@ -508,7 +528,7 @@ int match_netid(struct dhcp_netid *check, struct dhcp_netid *pool)
|
||||
for (tmp1 = pool; tmp1; tmp1 = tmp1->next)
|
||||
if (strcmp(check->net, tmp1->net) == 0)
|
||||
break;
|
||||
if (!tmp1)
|
||||
if (!tmp1 || negonly)
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
@@ -520,97 +540,91 @@ int match_netid(struct dhcp_netid *check, struct dhcp_netid *pool)
|
||||
}
|
||||
|
||||
int address_allocate(struct dhcp_context *context, struct daemon *daemon,
|
||||
struct in_addr *addrp, unsigned char *hwaddr,
|
||||
struct in_addr *addrp, unsigned char *hwaddr, int hw_len,
|
||||
struct dhcp_netid *netids, time_t now)
|
||||
{
|
||||
/* Find a free address: exclude anything in use and anything allocated to
|
||||
a particular hwaddr/clientid/hostname in our configuration.
|
||||
Try to return from contexts which mathc netis first. */
|
||||
Try to return from contexts which match netids first. */
|
||||
|
||||
struct in_addr start, addr ;
|
||||
struct dhcp_context *c;
|
||||
unsigned int i, j;
|
||||
|
||||
for (c = context; c; c = c->current)
|
||||
if (c->flags & CONTEXT_STATIC)
|
||||
continue;
|
||||
else if (netids && !(c->flags & CONTEXT_FILTER))
|
||||
continue;
|
||||
else if (!netids && (c->flags & CONTEXT_FILTER))
|
||||
continue;
|
||||
else if (netids && (c->flags & CONTEXT_FILTER) && !match_netid(&c->netid, netids))
|
||||
continue;
|
||||
else
|
||||
{
|
||||
/* pick a seed based on hwaddr then iterate until we find a free address. */
|
||||
for (j = c->addr_epoch, i = 0; i < ETHER_ADDR_LEN; i++)
|
||||
j += hwaddr[i] + (hwaddr[i] << 8) + (hwaddr[i] << 16);
|
||||
|
||||
start.s_addr = addr.s_addr =
|
||||
htonl(ntohl(c->start.s_addr) +
|
||||
(j % (1 + ntohl(c->end.s_addr) - ntohl(c->start.s_addr))));
|
||||
|
||||
do {
|
||||
if (!lease_find_by_addr(addr) &&
|
||||
!config_find_by_address(daemon->dhcp_conf, addr))
|
||||
{
|
||||
struct ping_result *r, *victim = NULL;
|
||||
int count;
|
||||
int i, pass;
|
||||
unsigned int j;
|
||||
|
||||
/* check if we failed to ping addr sometime in the last
|
||||
30s. If so, assume the same situation still exists.
|
||||
This avoids problems when a stupid client bangs
|
||||
on us repeatedly. As a final check, is we did more
|
||||
than six ping checks in the last 30s, we are in
|
||||
high-load mode, so don't do any more. */
|
||||
for (count = 0, r = daemon->ping_results; r; r = r->next)
|
||||
if (difftime(now, r->time) > 30.0)
|
||||
victim = r; /* old record */
|
||||
else if (++count == 6 || r->addr.s_addr == addr.s_addr)
|
||||
for (pass = 0; pass <= 1; pass++)
|
||||
for (c = context; c; c = c->current)
|
||||
if (c->flags & CONTEXT_STATIC)
|
||||
continue;
|
||||
else if (!match_netid(c->filter, netids, pass))
|
||||
continue;
|
||||
else
|
||||
{
|
||||
/* pick a seed based on hwaddr then iterate until we find a free address. */
|
||||
for (j = c->addr_epoch, i = 0; i < hw_len; i++)
|
||||
j += hwaddr[i] + (hwaddr[i] << 8) + (hwaddr[i] << 16);
|
||||
|
||||
start.s_addr = addr.s_addr =
|
||||
htonl(ntohl(c->start.s_addr) +
|
||||
(j % (1 + ntohl(c->end.s_addr) - ntohl(c->start.s_addr))));
|
||||
|
||||
do {
|
||||
if (!lease_find_by_addr(addr) &&
|
||||
!config_find_by_address(daemon->dhcp_conf, addr))
|
||||
{
|
||||
struct ping_result *r, *victim = NULL;
|
||||
int count;
|
||||
|
||||
/* check if we failed to ping addr sometime in the last
|
||||
30s. If so, assume the same situation still exists.
|
||||
This avoids problems when a stupid client bangs
|
||||
on us repeatedly. As a final check, is we did more
|
||||
than six ping checks in the last 30s, we are in
|
||||
high-load mode, so don't do any more. */
|
||||
for (count = 0, r = daemon->ping_results; r; r = r->next)
|
||||
if (difftime(now, r->time) > 30.0)
|
||||
victim = r; /* old record */
|
||||
else if (++count == 6 || r->addr.s_addr == addr.s_addr)
|
||||
{
|
||||
*addrp = addr;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (icmp_ping(daemon, addr))
|
||||
/* address in use: perturb address selection so that we are
|
||||
less likely to try this address again. */
|
||||
c->addr_epoch++;
|
||||
else
|
||||
{
|
||||
/* at this point victim may hold an expired record */
|
||||
if (!victim)
|
||||
{
|
||||
if ((victim = malloc(sizeof(struct ping_result))))
|
||||
{
|
||||
victim->next = daemon->ping_results;
|
||||
daemon->ping_results = victim;
|
||||
}
|
||||
}
|
||||
|
||||
/* record that this address is OK for 30s
|
||||
without more ping checks */
|
||||
if (victim)
|
||||
{
|
||||
victim->addr = addr;
|
||||
victim->time = now;
|
||||
}
|
||||
*addrp = addr;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (icmp_ping(daemon, addr))
|
||||
/* address in use: perturb address selection so that we are
|
||||
less likely to try this address again. */
|
||||
c->addr_epoch++;
|
||||
else
|
||||
{
|
||||
/* at this point victim may hold an expired record */
|
||||
if (!victim)
|
||||
{
|
||||
if ((victim = malloc(sizeof(struct ping_result))))
|
||||
{
|
||||
victim->next = daemon->ping_results;
|
||||
daemon->ping_results = victim;
|
||||
}
|
||||
}
|
||||
|
||||
/* record that this address is OK for 30s
|
||||
without more ping checks */
|
||||
if (victim)
|
||||
{
|
||||
victim->addr = addr;
|
||||
victim->time = now;
|
||||
}
|
||||
*addrp = addr;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
addr.s_addr = htonl(ntohl(addr.s_addr) + 1);
|
||||
|
||||
if (addr.s_addr == htonl(ntohl(c->end.s_addr) + 1))
|
||||
addr = c->start;
|
||||
|
||||
} while (addr.s_addr != start.s_addr);
|
||||
}
|
||||
|
||||
if (netids)
|
||||
return address_allocate(context, daemon, addrp, hwaddr, NULL, now);
|
||||
}
|
||||
|
||||
addr.s_addr = htonl(ntohl(addr.s_addr) + 1);
|
||||
|
||||
if (addr.s_addr == htonl(ntohl(c->end.s_addr) + 1))
|
||||
addr = c->start;
|
||||
|
||||
} while (addr.s_addr != start.s_addr);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -631,7 +645,8 @@ static int is_addr_in_context(struct dhcp_context *context, struct dhcp_config *
|
||||
struct dhcp_config *find_config(struct dhcp_config *configs,
|
||||
struct dhcp_context *context,
|
||||
unsigned char *clid, int clid_len,
|
||||
unsigned char *hwaddr, char *hostname)
|
||||
unsigned char *hwaddr, int hw_len,
|
||||
int hw_type, char *hostname)
|
||||
{
|
||||
struct dhcp_config *config;
|
||||
|
||||
@@ -653,15 +668,16 @@ struct dhcp_config *find_config(struct dhcp_config *configs,
|
||||
}
|
||||
|
||||
|
||||
if (hwaddr)
|
||||
for (config = configs; config; config = config->next)
|
||||
if ((config->flags & CONFIG_HWADDR) &&
|
||||
config->wildcard_mask == 0 &&
|
||||
memcmp(config->hwaddr, hwaddr, ETHER_ADDR_LEN) == 0 &&
|
||||
is_addr_in_context(context, config))
|
||||
return config;
|
||||
|
||||
for (config = configs; config; config = config->next)
|
||||
if ((config->flags & CONFIG_HWADDR) &&
|
||||
config->wildcard_mask == 0 &&
|
||||
config->hwaddr_len == hw_len &&
|
||||
(config->hwaddr_type == hw_type || config->hwaddr_type == 0) &&
|
||||
memcmp(config->hwaddr, hwaddr, hw_len) == 0 &&
|
||||
is_addr_in_context(context, config))
|
||||
return config;
|
||||
|
||||
|
||||
if (hostname && context)
|
||||
for (config = configs; config; config = config->next)
|
||||
if ((config->flags & CONFIG_NAME) &&
|
||||
@@ -669,20 +685,21 @@ struct dhcp_config *find_config(struct dhcp_config *configs,
|
||||
is_addr_in_context(context, config))
|
||||
return config;
|
||||
|
||||
if (hwaddr)
|
||||
for (config = configs; config; config = config->next)
|
||||
if ((config->flags & CONFIG_HWADDR) &&
|
||||
config->wildcard_mask != 0 &&
|
||||
is_addr_in_context(context, config))
|
||||
{
|
||||
int i;
|
||||
unsigned int mask = config->wildcard_mask;
|
||||
for (i = ETHER_ADDR_LEN - 1; i >= 0; i--, mask = mask >> 1)
|
||||
if (mask & 1)
|
||||
config->hwaddr[i] = hwaddr[i];
|
||||
if (memcmp(config->hwaddr, hwaddr, ETHER_ADDR_LEN) == 0)
|
||||
return config;
|
||||
}
|
||||
for (config = configs; config; config = config->next)
|
||||
if ((config->flags & CONFIG_HWADDR) &&
|
||||
config->wildcard_mask != 0 &&
|
||||
config->hwaddr_len == hw_len &&
|
||||
(config->hwaddr_type == hw_type || config->hwaddr_type == 0) &&
|
||||
is_addr_in_context(context, config))
|
||||
{
|
||||
int i;
|
||||
unsigned int mask = config->wildcard_mask;
|
||||
for (i = hw_len - 1; i >= 0; i--, mask = mask >> 1)
|
||||
if (mask & 1)
|
||||
config->hwaddr[i] = hwaddr[i];
|
||||
if (memcmp(config->hwaddr, hwaddr, hw_len) == 0)
|
||||
return config;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -719,7 +736,7 @@ void dhcp_read_ethers(struct daemon *daemon)
|
||||
for (ip = buff; *ip && !isspace(*ip); ip++);
|
||||
for(; *ip && isspace(*ip); ip++)
|
||||
*ip = 0;
|
||||
if (!*ip || parse_hex(buff, hwaddr, 6, NULL) != 6)
|
||||
if (!*ip || parse_hex(buff, hwaddr, ETHER_ADDR_LEN, NULL, NULL) != ETHER_ADDR_LEN)
|
||||
{
|
||||
syslog(LOG_ERR, _("bad line at %s line %d"), ETHERSFILE, lineno);
|
||||
continue;
|
||||
@@ -764,6 +781,8 @@ void dhcp_read_ethers(struct daemon *daemon)
|
||||
for (config = configs; config; config = config->next)
|
||||
if ((config->flags & CONFIG_HWADDR) &&
|
||||
config->wildcard_mask == 0 &&
|
||||
config->hwaddr_len == ETHER_ADDR_LEN &&
|
||||
(config->hwaddr_type == ARPHRD_ETHER || config->hwaddr_type == 0) &&
|
||||
memcmp(config->hwaddr, hwaddr, ETHER_ADDR_LEN) == 0)
|
||||
break;
|
||||
|
||||
@@ -793,7 +812,8 @@ void dhcp_read_ethers(struct daemon *daemon)
|
||||
|
||||
config->flags |= CONFIG_HWADDR | CONFIG_NOCLID;
|
||||
memcpy(config->hwaddr, hwaddr, ETHER_ADDR_LEN);
|
||||
|
||||
config->hwaddr_len = ETHER_ADDR_LEN;
|
||||
config->hwaddr_type = ARPHRD_ETHER;
|
||||
count++;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2005 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2006 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
|
||||
@@ -176,8 +176,7 @@ int main (int argc, char **argv)
|
||||
die(_("DBus error: %s"), err);
|
||||
}
|
||||
#else
|
||||
if (daemon->options & OPT_DBUS)
|
||||
die(_("DBus not available: set HAVE_DBUS in src/config.h"), NULL);
|
||||
die(_("DBus not available: set HAVE_DBUS in src/config.h"), NULL);
|
||||
#endif
|
||||
|
||||
/* If query_port is set then create a socket now, before dumping root
|
||||
@@ -256,7 +255,7 @@ int main (int argc, char **argv)
|
||||
#endif
|
||||
|
||||
if (daemon->dhcp &&
|
||||
(i == daemon->lease_fd ||
|
||||
(i == fileno(daemon->lease_stream) ||
|
||||
i == daemon->dhcpfd ||
|
||||
i == daemon->dhcp_raw_fd ||
|
||||
i == daemon->dhcp_icmp_fd))
|
||||
@@ -314,14 +313,14 @@ int main (int argc, char **argv)
|
||||
if (if_tmp->name && !if_tmp->used)
|
||||
syslog(LOG_WARNING, _("warning: interface %s does not currently exist"), if_tmp->name);
|
||||
|
||||
#ifdef HAVE_RTNETLINK
|
||||
/* Must do this after daemonizing so that the pid is right */
|
||||
netlink_init(daemon);
|
||||
#endif
|
||||
|
||||
if (daemon->dhcp)
|
||||
{
|
||||
struct dhcp_context *dhcp_tmp;
|
||||
|
||||
#ifdef HAVE_RTNETLINK
|
||||
/* Must do this after daemonizing so that the pid is right */
|
||||
daemon->netlinkfd = netlink_init();
|
||||
#endif
|
||||
|
||||
for (dhcp_tmp = daemon->dhcp; dhcp_tmp; dhcp_tmp = dhcp_tmp->next)
|
||||
{
|
||||
@@ -375,7 +374,7 @@ int main (int argc, char **argv)
|
||||
{
|
||||
if (daemon->dhcp)
|
||||
{
|
||||
lease_update_file(1, now);
|
||||
lease_update_file(daemon, 1, now);
|
||||
#ifdef HAVE_BROKEN_RTC
|
||||
alarm(daemon->min_leasetime);
|
||||
#endif
|
||||
@@ -400,6 +399,15 @@ int main (int argc, char **argv)
|
||||
maxfd = daemon->dhcpfd;
|
||||
}
|
||||
|
||||
#ifdef HAVE_RTNETLINK
|
||||
if (daemon->netlinkfd != -1)
|
||||
{
|
||||
FD_SET(daemon->netlinkfd, &rset);
|
||||
if (daemon->netlinkfd > maxfd)
|
||||
maxfd = daemon->netlinkfd;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Whilst polling for the dbus, wake every quarter second */
|
||||
#ifdef HAVE_PSELECT
|
||||
{
|
||||
@@ -497,6 +505,11 @@ int main (int argc, char **argv)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_RTNETLINK
|
||||
if (daemon->netlinkfd != -1 && FD_ISSET(daemon->netlinkfd, &rset))
|
||||
netlink_multicast(daemon);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_DBUS
|
||||
/* if we didn't create a DBus connection, retry now. */
|
||||
@@ -522,9 +535,9 @@ int main (int argc, char **argv)
|
||||
if (daemon->dhcp)
|
||||
{
|
||||
#ifdef HAVE_BROKEN_RTC
|
||||
lease_update_file(1, now);
|
||||
lease_update_file(daemon, 1, now);
|
||||
#endif
|
||||
close(daemon->lease_fd);
|
||||
fclose(daemon->lease_stream);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -565,7 +578,7 @@ void clear_cache_and_reload(struct daemon *daemon, time_t now)
|
||||
dhcp_read_ethers(daemon);
|
||||
dhcp_update_configs(daemon->dhcp_conf);
|
||||
lease_update_from_configs(daemon);
|
||||
lease_update_file(0, now);
|
||||
lease_update_file(daemon, 0, now);
|
||||
lease_update_dns(daemon);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,13 +92,8 @@
|
||||
memory for the largest packet, and the largest record so the
|
||||
min for DNS is PACKETSZ+MAXDNAME+RRFIXEDSZ which is < 1000.
|
||||
This might be increased is EDNS packet size if greater than the minimum.
|
||||
The buffer is also used for NETLINK, which needs to be about 2000
|
||||
on systems with many interfaces/addresses. */
|
||||
#ifdef HAVE_RTNETLINK
|
||||
# define DNSMASQ_PACKETSZ PACKETSZ+MAXDNAME+RRFIXEDSZ
|
||||
#else
|
||||
# define DNSMASQ_PACKETSZ 2000
|
||||
#endif
|
||||
*/
|
||||
#define DNSMASQ_PACKETSZ PACKETSZ+MAXDNAME+RRFIXEDSZ
|
||||
|
||||
#define OPT_BOGUSPRIV 1
|
||||
#define OPT_FILTER 2
|
||||
@@ -197,7 +192,7 @@ struct crec {
|
||||
#define F_NOERR 32768
|
||||
|
||||
/* struct sockaddr is not large enough to hold any address,
|
||||
and specifically not big enough to hold and IPv6 address.
|
||||
and specifically not big enough to hold an IPv6 address.
|
||||
Blech. Roll our own. */
|
||||
union mysockaddr {
|
||||
struct sockaddr sa;
|
||||
@@ -278,7 +273,7 @@ struct resolvc {
|
||||
struct hostsfile {
|
||||
struct hostsfile *next;
|
||||
char *fname;
|
||||
int index; /* matches to cache entries fro logging */
|
||||
int index; /* matches to cache entries for logging */
|
||||
};
|
||||
|
||||
struct frec {
|
||||
@@ -293,13 +288,16 @@ struct frec {
|
||||
struct frec *next;
|
||||
};
|
||||
|
||||
#define DHCP_CHADDR_MAX 16
|
||||
|
||||
struct dhcp_lease {
|
||||
int clid_len; /* length of client identifier */
|
||||
unsigned char *clid; /* clientid */
|
||||
char *hostname, *fqdn; /* name from client-hostname option or config */
|
||||
int auth_name; /* hostname came from config, not from client */
|
||||
time_t expires; /* lease expiry */
|
||||
unsigned char hwaddr[ETHER_ADDR_LEN];
|
||||
int hwaddr_len, hwaddr_type;
|
||||
unsigned char hwaddr[DHCP_CHADDR_MAX];
|
||||
struct in_addr addr;
|
||||
struct dhcp_lease *next;
|
||||
};
|
||||
@@ -317,7 +315,8 @@ struct dhcp_config {
|
||||
unsigned int flags;
|
||||
int clid_len; /* length of client identifier */
|
||||
unsigned char *clid; /* clientid */
|
||||
unsigned char hwaddr[ETHER_ADDR_LEN];
|
||||
int hwaddr_len, hwaddr_type;
|
||||
unsigned char hwaddr[DHCP_CHADDR_MAX];
|
||||
char *hostname;
|
||||
struct dhcp_netid netid;
|
||||
struct in_addr addr;
|
||||
@@ -335,12 +334,15 @@ struct dhcp_config {
|
||||
#define CONFIG_NOCLID 128
|
||||
|
||||
struct dhcp_opt {
|
||||
int opt, len, is_addr;
|
||||
int opt, len, flags;
|
||||
unsigned char *val, *vendor_class;
|
||||
struct dhcp_netid *netid;
|
||||
struct dhcp_opt *next;
|
||||
};
|
||||
|
||||
#define DHOPT_ADDR 1
|
||||
#define DHOPT_STRING 2
|
||||
|
||||
struct dhcp_boot {
|
||||
char *file, *sname;
|
||||
struct in_addr next_server;
|
||||
@@ -355,20 +357,27 @@ struct dhcp_vendor {
|
||||
struct dhcp_vendor *next;
|
||||
};
|
||||
|
||||
struct dhcp_mac {
|
||||
unsigned int mask;
|
||||
int hwaddr_len, hwaddr_type;
|
||||
unsigned char hwaddr[DHCP_CHADDR_MAX];
|
||||
struct dhcp_netid netid;
|
||||
struct dhcp_mac *next;
|
||||
};
|
||||
|
||||
struct dhcp_context {
|
||||
unsigned int lease_time, addr_epoch;
|
||||
struct in_addr netmask, broadcast;
|
||||
struct in_addr local, router;
|
||||
struct in_addr start, end; /* range of available addresses */
|
||||
int flags;
|
||||
struct dhcp_netid netid;
|
||||
struct dhcp_netid netid, *filter;
|
||||
struct dhcp_context *next, *current;
|
||||
};
|
||||
|
||||
#define CONTEXT_STATIC 1
|
||||
#define CONTEXT_FILTER 2
|
||||
#define CONTEXT_NETMASK 4
|
||||
#define CONTEXT_BRDCAST 8
|
||||
#define CONTEXT_NETMASK 2
|
||||
#define CONTEXT_BRDCAST 4
|
||||
|
||||
|
||||
typedef unsigned char u8;
|
||||
@@ -389,7 +398,7 @@ struct udp_dhcp_packet {
|
||||
u32 xid;
|
||||
u16 secs, flags;
|
||||
struct in_addr ciaddr, yiaddr, siaddr, giaddr;
|
||||
u8 chaddr[16], sname[64], file[128];
|
||||
u8 chaddr[DHCP_CHADDR_MAX], sname[64], file[128];
|
||||
u8 options[312];
|
||||
} data;
|
||||
};
|
||||
@@ -425,6 +434,7 @@ struct daemon {
|
||||
struct dhcp_config *dhcp_conf;
|
||||
struct dhcp_opt *dhcp_opts, *vendor_opts;
|
||||
struct dhcp_vendor *dhcp_vendors;
|
||||
struct dhcp_mac *dhcp_macs;
|
||||
struct dhcp_boot *boot_config;
|
||||
struct dhcp_netid_list *dhcp_ignore;
|
||||
int dhcp_max;
|
||||
@@ -440,16 +450,19 @@ struct daemon {
|
||||
struct irec *interfaces;
|
||||
struct listener *listeners;
|
||||
struct server *last_server;
|
||||
struct server *srv_save; /* Used for resend on DoD */
|
||||
size_t packet_len; /* " " */
|
||||
int uptime_fd;
|
||||
|
||||
/* DHCP state */
|
||||
int dhcpfd, dhcp_raw_fd, dhcp_icmp_fd, lease_fd;
|
||||
int dhcpfd, dhcp_raw_fd, dhcp_icmp_fd;
|
||||
#ifdef HAVE_RTNETLINK
|
||||
int netlinkfd;
|
||||
#endif
|
||||
struct udp_dhcp_packet *dhcp_packet;
|
||||
char *dhcp_buff, *dhcp_buff2;
|
||||
struct ping_result *ping_results;
|
||||
FILE *lease_stream;
|
||||
|
||||
/* DBus stuff */
|
||||
#ifdef HAVE_DBUS
|
||||
@@ -480,23 +493,23 @@ void dump_cache(struct daemon *daemon);
|
||||
char *cache_get_name(struct crec *crecp);
|
||||
|
||||
/* rfc1035.c */
|
||||
unsigned short extract_request(HEADER *header, unsigned int qlen,
|
||||
unsigned short extract_request(HEADER *header, size_t qlen,
|
||||
char *name, unsigned short *typep);
|
||||
int setup_reply(HEADER *header, unsigned int qlen,
|
||||
struct all_addr *addrp, unsigned short flags,
|
||||
unsigned long local_ttl);
|
||||
void extract_addresses(HEADER *header, unsigned int qlen, char *namebuff,
|
||||
size_t setup_reply(HEADER *header, size_t qlen,
|
||||
struct all_addr *addrp, unsigned short flags,
|
||||
unsigned long local_ttl);
|
||||
void extract_addresses(HEADER *header, size_t qlen, char *namebuff,
|
||||
time_t now, struct daemon *daemon);
|
||||
int answer_request(HEADER *header, char *limit, unsigned int qlen, struct daemon *daemon,
|
||||
size_t answer_request(HEADER *header, char *limit, size_t qlen, struct daemon *daemon,
|
||||
struct in_addr local_addr, struct in_addr local_netmask, time_t now);
|
||||
int check_for_bogus_wildcard(HEADER *header, unsigned int qlen, char *name,
|
||||
int check_for_bogus_wildcard(HEADER *header, size_t qlen, char *name,
|
||||
struct bogus_addr *addr, time_t now);
|
||||
unsigned char *find_pseudoheader(HEADER *header, unsigned int plen,
|
||||
unsigned int *len, unsigned char **p);
|
||||
unsigned char *find_pseudoheader(HEADER *header, size_t plen,
|
||||
size_t *len, unsigned char **p);
|
||||
int check_for_local_domain(char *name, time_t now, struct daemon *daemon);
|
||||
unsigned int questions_crc(HEADER *header, unsigned int plen, char *buff);
|
||||
int resize_packet(HEADER *header, unsigned int plen,
|
||||
unsigned char *pheader, unsigned int hlen);
|
||||
unsigned int questions_crc(HEADER *header, size_t plen, char *buff);
|
||||
size_t resize_packet(HEADER *header, size_t plen,
|
||||
unsigned char *pheader, size_t hlen);
|
||||
|
||||
/* util.c */
|
||||
unsigned short rand16(void);
|
||||
@@ -515,7 +528,7 @@ int retry_send(void);
|
||||
void prettyprint_time(char *buf, unsigned int t);
|
||||
int prettyprint_addr(union mysockaddr *addr, char *buf);
|
||||
int parse_hex(char *in, unsigned char *out, int maxlen,
|
||||
unsigned int *wildcard_mask);
|
||||
unsigned int *wildcard_mask, int *mac_type);
|
||||
|
||||
/* option.c */
|
||||
struct daemon *read_opts (int argc, char **argv, char *compile_opts);
|
||||
@@ -542,14 +555,15 @@ void dhcp_packet(struct daemon *daemon, time_t now);
|
||||
|
||||
struct dhcp_context *address_available(struct dhcp_context *context, struct in_addr addr);
|
||||
struct dhcp_context *narrow_context(struct dhcp_context *context, struct in_addr taddr);
|
||||
int match_netid(struct dhcp_netid *check, struct dhcp_netid *pool);
|
||||
int match_netid(struct dhcp_netid *check, struct dhcp_netid *pool, int negonly);
|
||||
int address_allocate(struct dhcp_context *context, struct daemon *daemon,
|
||||
struct in_addr *addrp, unsigned char *hwaddr,
|
||||
struct in_addr *addrp, unsigned char *hwaddr, int hw_len,
|
||||
struct dhcp_netid *netids, time_t now);
|
||||
struct dhcp_config *find_config(struct dhcp_config *configs,
|
||||
struct dhcp_context *context,
|
||||
unsigned char *clid, int clid_len,
|
||||
unsigned char *hwaddr, char *hostname);
|
||||
unsigned char *hwaddr, int hw_len,
|
||||
int hw_type, char *hostname);
|
||||
void dhcp_update_configs(struct dhcp_config *configs);
|
||||
void dhcp_read_ethers(struct daemon *daemon);
|
||||
struct dhcp_config *config_find_by_address(struct dhcp_config *configs, struct in_addr addr);
|
||||
@@ -561,24 +575,24 @@ struct dhcp_context *complete_context(struct daemon *daemon, struct in_addr loca
|
||||
struct in_addr primary);
|
||||
|
||||
/* lease.c */
|
||||
void lease_update_file(int force, time_t now);
|
||||
void lease_update_file(struct daemon *daemon, int force, time_t now);
|
||||
void lease_update_dns(struct daemon *daemon);
|
||||
void lease_init(struct daemon *daemon, time_t now);
|
||||
struct dhcp_lease *lease_allocate(unsigned char *hwaddr, unsigned char *clid,
|
||||
int clid_len, struct in_addr addr);
|
||||
int hw_len, int hw_type, int clid_len, struct in_addr addr);
|
||||
int lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
|
||||
unsigned char *clid, 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,
|
||||
char *suffix, int auth);
|
||||
void lease_set_expires(struct dhcp_lease *lease, time_t exp);
|
||||
struct dhcp_lease *lease_find_by_client(unsigned char *hwaddr,
|
||||
struct dhcp_lease *lease_find_by_client(unsigned char *hwaddr, int hw_len, int hw_type,
|
||||
unsigned char *clid, int clid_len);
|
||||
struct dhcp_lease *lease_find_by_addr(struct in_addr addr);
|
||||
void lease_prune(struct dhcp_lease *target, time_t now);
|
||||
void lease_update_from_configs(struct daemon *daemon);
|
||||
|
||||
/* rfc2131.c */
|
||||
int dhcp_reply(struct daemon *daemon, struct dhcp_context *context, char *iface_name, unsigned int sz, time_t now, int unicast_dest);
|
||||
size_t dhcp_reply(struct daemon *daemon, struct dhcp_context *context, char *iface_name, size_t sz, time_t now, int unicast_dest);
|
||||
|
||||
/* dnsmasq.c */
|
||||
int icmp_ping(struct daemon *daemon, struct in_addr addr);
|
||||
@@ -591,10 +605,11 @@ void load_dhcp(struct daemon *daemon, time_t now);
|
||||
|
||||
/* netlink.c */
|
||||
#ifdef HAVE_RTNETLINK
|
||||
int netlink_init(void);
|
||||
void netlink_init(struct daemon *daemon);
|
||||
int netlink_process(struct daemon *daemon, int index,
|
||||
struct in_addr relay, struct in_addr primary,
|
||||
struct dhcp_context **retp);
|
||||
void netlink_multicast(struct daemon *daemon);
|
||||
#endif
|
||||
|
||||
/* dbus.c */
|
||||
|
||||
@@ -36,7 +36,7 @@ void forward_init(int first)
|
||||
|
||||
/* Send a UDP packet with it's source address set as "source"
|
||||
unless nowild is true, when we just send it with the kernel default */
|
||||
static void send_from(int fd, int nowild, char *packet, int len,
|
||||
static void send_from(int fd, int nowild, char *packet, size_t len,
|
||||
union mysockaddr *to, struct all_addr *source,
|
||||
unsigned int iface)
|
||||
{
|
||||
@@ -164,7 +164,7 @@ static unsigned short search_servers(struct daemon *daemon, time_t now, struct a
|
||||
if (namelen >= domainlen &&
|
||||
hostname_isequal(matchstart, serv->domain) &&
|
||||
domainlen >= matchlen &&
|
||||
(namelen == domainlen || *(serv->domain) == '.' || *(matchstart-1) == '.' ))
|
||||
(domainlen == 0 || namelen == domainlen || *(serv->domain) == '.' || *(matchstart-1) == '.' ))
|
||||
{
|
||||
unsigned short sflag = serv->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6;
|
||||
*type = SERV_HAS_DOMAIN;
|
||||
@@ -212,14 +212,14 @@ static unsigned short search_servers(struct daemon *daemon, time_t now, struct a
|
||||
/* returns new last_server */
|
||||
static void forward_query(struct daemon *daemon, int udpfd, union mysockaddr *udpaddr,
|
||||
struct all_addr *dst_addr, unsigned int dst_iface,
|
||||
HEADER *header, int plen, time_t now, struct frec *forward)
|
||||
HEADER *header, size_t plen, time_t now, struct frec *forward)
|
||||
{
|
||||
char *domain = NULL;
|
||||
int type = 0;
|
||||
struct all_addr *addrp = NULL;
|
||||
unsigned int crc = questions_crc(header, (unsigned int)plen, daemon->namebuff);
|
||||
unsigned int crc = questions_crc(header, plen, daemon->namebuff);
|
||||
unsigned short flags = 0;
|
||||
unsigned short gotname = extract_request(header, (unsigned int)plen, daemon->namebuff, NULL);
|
||||
unsigned short gotname = extract_request(header, plen, daemon->namebuff, NULL);
|
||||
struct server *start = NULL;
|
||||
|
||||
/* may be no servers available. */
|
||||
@@ -302,6 +302,10 @@ static void forward_query(struct daemon *daemon, int udpfd, union mysockaddr *ud
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Keep info in case we want to re-send this packet */
|
||||
daemon->srv_save = start;
|
||||
daemon->packet_len = plen;
|
||||
|
||||
if (!gotname)
|
||||
strcpy(daemon->namebuff, "query");
|
||||
if (start->addr.sa.sa_family == AF_INET)
|
||||
@@ -340,19 +344,20 @@ static void forward_query(struct daemon *daemon, int udpfd, union mysockaddr *ud
|
||||
/* could not send on, return empty answer or address if known for whole domain */
|
||||
if (udpfd != -1)
|
||||
{
|
||||
plen = setup_reply(header, (unsigned int)plen, addrp, flags, daemon->local_ttl);
|
||||
plen = setup_reply(header, plen, addrp, flags, daemon->local_ttl);
|
||||
send_from(udpfd, daemon->options & OPT_NOWILD, (char *)header, plen, udpaddr, dst_addr, dst_iface);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static int process_reply(struct daemon *daemon, HEADER *header, time_t now,
|
||||
unsigned int query_crc, struct server *server, unsigned int n)
|
||||
static size_t process_reply(struct daemon *daemon, HEADER *header, time_t now,
|
||||
unsigned int query_crc, struct server *server, size_t n)
|
||||
{
|
||||
unsigned char *pheader, *sizep;
|
||||
unsigned int plen, munged = 0;
|
||||
|
||||
int munged = 0;
|
||||
size_t plen;
|
||||
|
||||
/* If upstream is advertising a larger UDP packet size
|
||||
than we allow, trim it so that we don't get overlarge
|
||||
requests for the client. */
|
||||
@@ -433,8 +438,12 @@ void reply_query(struct serverfd *sfd, struct daemon *daemon, time_t now)
|
||||
HEADER *header;
|
||||
union mysockaddr serveraddr;
|
||||
socklen_t addrlen = sizeof(serveraddr);
|
||||
int n = recvfrom(sfd->fd, daemon->packet, daemon->edns_pktsz, 0, &serveraddr.sa, &addrlen);
|
||||
|
||||
ssize_t n = recvfrom(sfd->fd, daemon->packet, daemon->edns_pktsz, 0, &serveraddr.sa, &addrlen);
|
||||
size_t nn;
|
||||
|
||||
/* packet buffer overwritten */
|
||||
daemon->srv_save = NULL;
|
||||
|
||||
/* Determine the address of the server replying so that we can mark that as good */
|
||||
serveraddr.sa.sa_family = sfd->source_addr.sa.sa_family;
|
||||
#ifdef HAVE_IPV6
|
||||
@@ -453,14 +462,14 @@ void reply_query(struct serverfd *sfd, struct daemon *daemon, time_t now)
|
||||
/* for broken servers, attempt to send to another one. */
|
||||
{
|
||||
unsigned char *pheader;
|
||||
unsigned int plen;
|
||||
int nn;
|
||||
size_t plen;
|
||||
|
||||
/* recreate query from reply */
|
||||
pheader = find_pseudoheader(header, n, &plen, NULL);
|
||||
pheader = find_pseudoheader(header, (size_t)n, &plen, NULL);
|
||||
header->ancount = htons(0);
|
||||
header->nscount = htons(0);
|
||||
header->arcount = htons(0);
|
||||
if ((nn = resize_packet(header, n, pheader, plen)))
|
||||
if ((nn = resize_packet(header, (size_t)n, pheader, plen)))
|
||||
{
|
||||
forward->forwardall = 1;
|
||||
header->qr = 0;
|
||||
@@ -496,11 +505,11 @@ void reply_query(struct serverfd *sfd, struct daemon *daemon, time_t now)
|
||||
if (forward->forwardall == 0 || --forward->forwardall == 1 ||
|
||||
(header->rcode != REFUSED && header->rcode != SERVFAIL))
|
||||
{
|
||||
if ((n = process_reply(daemon, header, now, forward->crc, server, (unsigned int)n)))
|
||||
if ((nn = process_reply(daemon, header, now, forward->crc, server, (size_t)n)))
|
||||
{
|
||||
header->id = htons(forward->orig_id);
|
||||
header->ra = 1; /* recursion if available */
|
||||
send_from(forward->fd, daemon->options & OPT_NOWILD, daemon->packet, n,
|
||||
send_from(forward->fd, daemon->options & OPT_NOWILD, daemon->packet, nn,
|
||||
&forward->source, &forward->dest, forward->iface);
|
||||
}
|
||||
forward->new_id = 0; /* cancel */
|
||||
@@ -516,7 +525,9 @@ void receive_query(struct listener *listen, struct daemon *daemon, time_t now)
|
||||
struct iname *tmp;
|
||||
struct all_addr dst_addr;
|
||||
struct in_addr netmask, dst_addr_4;
|
||||
int m, n, if_index = 0;
|
||||
size_t m;
|
||||
ssize_t n;
|
||||
int if_index = 0;
|
||||
struct iovec iov[1];
|
||||
struct msghdr msg;
|
||||
struct cmsghdr *cmptr;
|
||||
@@ -533,6 +544,9 @@ void receive_query(struct listener *listen, struct daemon *daemon, time_t now)
|
||||
#endif
|
||||
} control_u;
|
||||
|
||||
/* packet buffer overwritten */
|
||||
daemon->srv_save = NULL;
|
||||
|
||||
if (listen->family == AF_INET && (daemon->options & OPT_NOWILD))
|
||||
{
|
||||
dst_addr_4 = listen->iface->addr.in.sin_addr;
|
||||
@@ -658,7 +672,7 @@ void receive_query(struct listener *listen, struct daemon *daemon, time_t now)
|
||||
}
|
||||
}
|
||||
|
||||
if (extract_request(header, (unsigned int)n, daemon->namebuff, &type))
|
||||
if (extract_request(header, (size_t)n, daemon->namebuff, &type))
|
||||
{
|
||||
if (listen->family == AF_INET)
|
||||
log_query(F_QUERY | F_IPV4 | F_FORWARD, daemon->namebuff,
|
||||
@@ -670,18 +684,18 @@ void receive_query(struct listener *listen, struct daemon *daemon, time_t now)
|
||||
#endif
|
||||
}
|
||||
|
||||
m = answer_request (header, ((char *) header) + PACKETSZ, (unsigned int)n, daemon,
|
||||
m = answer_request (header, ((char *) header) + PACKETSZ, (size_t)n, daemon,
|
||||
dst_addr_4, netmask, now);
|
||||
if (m >= 1)
|
||||
send_from(listen->fd, daemon->options & OPT_NOWILD, (char *)header, m, &source_addr, &dst_addr, if_index);
|
||||
else
|
||||
forward_query(daemon, listen->fd, &source_addr, &dst_addr, if_index,
|
||||
header, n, now, NULL);
|
||||
header, (size_t)n, now, NULL);
|
||||
}
|
||||
|
||||
static int read_write(int fd, unsigned char *packet, int size, int rw)
|
||||
{
|
||||
int n, done;
|
||||
ssize_t n, done;
|
||||
|
||||
for (done = 0; done < size; done += n)
|
||||
{
|
||||
@@ -711,7 +725,8 @@ static int read_write(int fd, unsigned char *packet, int size, int rw)
|
||||
unsigned char *tcp_request(struct daemon *daemon, int confd, time_t now,
|
||||
struct in_addr local_addr, struct in_addr netmask)
|
||||
{
|
||||
int size = 0, m;
|
||||
int size = 0;
|
||||
size_t m;
|
||||
unsigned short qtype, gotname;
|
||||
unsigned char c1, c2;
|
||||
/* Max TCP packet + slop */
|
||||
|
||||
105
src/lease.c
105
src/lease.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2005 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2006 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
|
||||
@@ -15,9 +15,8 @@
|
||||
#include "dnsmasq.h"
|
||||
|
||||
static struct dhcp_lease *leases;
|
||||
static FILE *lease_file;
|
||||
static int dns_dirty;
|
||||
enum { no, yes, force } file_dirty;
|
||||
static enum { no, yes, force } file_dirty;
|
||||
static int leases_left;
|
||||
|
||||
void lease_init(struct daemon *daemon, time_t now)
|
||||
@@ -25,25 +24,25 @@ void lease_init(struct daemon *daemon, time_t now)
|
||||
unsigned int a0, a1, a2, a3;
|
||||
unsigned long ei;
|
||||
time_t expires;
|
||||
unsigned char hwaddr[ETHER_ADDR_LEN];
|
||||
unsigned char hwaddr[DHCP_CHADDR_MAX];
|
||||
struct in_addr addr;
|
||||
struct dhcp_lease *lease;
|
||||
int clid_len = 0;
|
||||
int clid_len = 0, hw_len, hw_type;
|
||||
int has_old = 0;
|
||||
|
||||
leases = NULL;
|
||||
leases_left = daemon->dhcp_max;
|
||||
|
||||
/* NOTE: need a+ mode to create file if it doesn't exist */
|
||||
if (!(lease_file = fopen(daemon->lease_file, "a+")))
|
||||
if (!(daemon->lease_stream = fopen(daemon->lease_file, "a+")))
|
||||
die(_("cannot open or create leases file: %s"), NULL);
|
||||
|
||||
/* a+ mode lease pointer at end. */
|
||||
rewind(lease_file);
|
||||
rewind(daemon->lease_stream);
|
||||
|
||||
/* client-id max length is 255 which is 255*2 digits + 254 colons
|
||||
borrow DNS packet buffer which is always larger than 1000 bytes */
|
||||
while (fscanf(lease_file, "%lu %40s %d.%d.%d.%d %255s %764s",
|
||||
while (fscanf(daemon->lease_stream, "%lu %255s %d.%d.%d.%d %255s %764s",
|
||||
&ei, daemon->dhcp_buff2, &a0, &a1, &a2, &a3,
|
||||
daemon->dhcp_buff, daemon->packet) == 8)
|
||||
{
|
||||
@@ -64,16 +63,20 @@ void lease_init(struct daemon *daemon, time_t now)
|
||||
}
|
||||
#endif
|
||||
|
||||
parse_hex(daemon->dhcp_buff2, hwaddr, ETHER_ADDR_LEN, NULL);
|
||||
hw_len = parse_hex(daemon->dhcp_buff2, hwaddr, DHCP_CHADDR_MAX, NULL, &hw_type);
|
||||
/* For backwards compatibility, no explict MAC address type means ether. */
|
||||
if (hw_type == 0)
|
||||
hw_type = ARPHRD_ETHER;
|
||||
|
||||
addr.s_addr = htonl((a0<<24) + (a1<<16) + (a2<<8) + a3);
|
||||
|
||||
/* decode hex in place */
|
||||
if (strcmp(daemon->packet, "*") == 0)
|
||||
clid_len = 0;
|
||||
else
|
||||
clid_len = parse_hex(daemon->packet, (unsigned char *)daemon->packet, 255, NULL);
|
||||
clid_len = parse_hex(daemon->packet, (unsigned char *)daemon->packet, 255, NULL, NULL);
|
||||
|
||||
if (!(lease = lease_allocate(hwaddr, (unsigned char *)daemon->packet, clid_len, addr)))
|
||||
if (!(lease = lease_allocate(hwaddr, (unsigned char *)daemon->packet, hw_len, hw_type, clid_len, addr)))
|
||||
die (_("too many stored leases"), NULL);
|
||||
|
||||
lease->expires = expires;
|
||||
@@ -84,8 +87,6 @@ void lease_init(struct daemon *daemon, time_t now)
|
||||
|
||||
dns_dirty = 1;
|
||||
file_dirty = has_old ? yes: no;
|
||||
|
||||
daemon->lease_fd = fileno(lease_file);
|
||||
}
|
||||
|
||||
void lease_update_from_configs(struct daemon *daemon)
|
||||
@@ -97,7 +98,8 @@ void lease_update_from_configs(struct daemon *daemon)
|
||||
char *name;
|
||||
|
||||
for (lease = leases; lease; lease = lease->next)
|
||||
if ((config = find_config(daemon->dhcp_conf, NULL, lease->clid, lease->clid_len, lease->hwaddr, NULL)) &&
|
||||
if ((config = find_config(daemon->dhcp_conf, NULL, lease->clid, lease->clid_len,
|
||||
lease->hwaddr, lease->hwaddr_len, lease->hwaddr_type, NULL)) &&
|
||||
(config->flags & CONFIG_NAME) &&
|
||||
(!(config->flags & CONFIG_ADDR) || config->addr.s_addr == lease->addr.s_addr))
|
||||
lease_set_hostname(lease, config->hostname, daemon->domain_suffix, 1);
|
||||
@@ -105,11 +107,12 @@ void lease_update_from_configs(struct daemon *daemon)
|
||||
lease_set_hostname(lease, name, daemon->domain_suffix, 1); /* updates auth flag only */
|
||||
}
|
||||
|
||||
void lease_update_file(int always, time_t now)
|
||||
void lease_update_file(struct daemon *daemon, int always, time_t now)
|
||||
{
|
||||
struct dhcp_lease *lease;
|
||||
int i = always; /* avoid warning */
|
||||
unsigned long expires;
|
||||
char *mess;
|
||||
|
||||
#ifdef HAVE_BROKEN_RTC
|
||||
if (always || file_dirty == force)
|
||||
@@ -119,8 +122,10 @@ void lease_update_file(int always, time_t now)
|
||||
if (file_dirty != no)
|
||||
{
|
||||
#endif
|
||||
rewind(lease_file);
|
||||
ftruncate(fileno(lease_file), 0);
|
||||
errno = 0;
|
||||
rewind(daemon->lease_stream);
|
||||
if (errno != 0 || ftruncate(fileno(daemon->lease_stream), 0) != 0)
|
||||
goto write_err;
|
||||
|
||||
for (lease = leases; lease; lease = lease->next)
|
||||
{
|
||||
@@ -133,27 +138,51 @@ void lease_update_file(int always, time_t now)
|
||||
expires = now; /* eliminate warning */
|
||||
expires = (unsigned long)lease->expires;
|
||||
#endif
|
||||
fprintf(lease_file, "%lu %.2x:%.2x:%.2x:%.2x:%.2x:%.2x %s %s ",
|
||||
expires, lease->hwaddr[0], lease->hwaddr[1],
|
||||
lease->hwaddr[2], lease->hwaddr[3], lease->hwaddr[4],
|
||||
lease->hwaddr[5], inet_ntoa(lease->addr),
|
||||
lease->hostname && strlen(lease->hostname) != 0 ? lease->hostname : "*");
|
||||
if (fprintf(daemon->lease_stream, "%lu ", expires) < 0)
|
||||
goto write_err;
|
||||
if (lease->hwaddr_type != ARPHRD_ETHER &&
|
||||
fprintf(daemon->lease_stream, "%.2x-", lease->hwaddr_type) < 0)
|
||||
goto write_err;
|
||||
for (i = 0; i < lease->hwaddr_len - 1; i++)
|
||||
if (fprintf(daemon->lease_stream, "%.2x:", lease->hwaddr[i]) < 0)
|
||||
goto write_err;
|
||||
if (fprintf(daemon->lease_stream, "%.2x", lease->hwaddr[i]) < 0)
|
||||
goto write_err;
|
||||
if (fprintf(daemon->lease_stream, " %s %s ", inet_ntoa(lease->addr),
|
||||
lease->hostname && strlen(lease->hostname) != 0 ? lease->hostname : "*") < 0)
|
||||
goto write_err;
|
||||
|
||||
if (lease->clid && lease->clid_len != 0)
|
||||
{
|
||||
for (i = 0; i < lease->clid_len - 1; i++)
|
||||
fprintf(lease_file, "%.2x:", lease->clid[i]);
|
||||
fprintf(lease_file, "%.2x\n", lease->clid[i]);
|
||||
if (fprintf(daemon->lease_stream, "%.2x:", lease->clid[i]) < 0)
|
||||
goto write_err;
|
||||
if (fprintf(daemon->lease_stream, "%.2x\n", lease->clid[i]) < 0)
|
||||
goto write_err;
|
||||
}
|
||||
else
|
||||
fprintf(lease_file, "*\n");
|
||||
if (fprintf(daemon->lease_stream, "*\n") < 0)
|
||||
goto write_err;
|
||||
|
||||
}
|
||||
|
||||
fflush(lease_file);
|
||||
fsync(fileno(lease_file));
|
||||
if (fflush(daemon->lease_stream) != 0)
|
||||
goto write_err;
|
||||
if (fsync(fileno(daemon->lease_stream)) < 0)
|
||||
goto write_err;
|
||||
file_dirty = no;
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
write_err:
|
||||
mess = _("failed to write");
|
||||
#ifdef HAVE_BROKEN_RTC
|
||||
syslog(LOG_ERR, "%s %s: %m", mess, daemon->lease_file);
|
||||
#else
|
||||
syslog(LOG_ERR, "%s %s: %m (retry in %ds)", mess, daemon->lease_file, LEASE_RETRY);
|
||||
alarm(LEASE_RETRY);
|
||||
#endif
|
||||
}
|
||||
|
||||
void lease_update_dns(struct daemon *daemon)
|
||||
@@ -204,7 +233,7 @@ void lease_prune(struct dhcp_lease *target, time_t now)
|
||||
}
|
||||
|
||||
|
||||
struct dhcp_lease *lease_find_by_client(unsigned char *hwaddr,
|
||||
struct dhcp_lease *lease_find_by_client(unsigned char *hwaddr, int hw_len, int hw_type,
|
||||
unsigned char *clid, int clid_len)
|
||||
{
|
||||
struct dhcp_lease *lease;
|
||||
@@ -217,7 +246,9 @@ struct dhcp_lease *lease_find_by_client(unsigned char *hwaddr,
|
||||
|
||||
for (lease = leases; lease; lease = lease->next)
|
||||
if ((!lease->clid || !clid) &&
|
||||
memcmp(hwaddr, lease->hwaddr, ETHER_ADDR_LEN) == 0)
|
||||
lease->hwaddr_len == hw_len &&
|
||||
lease->hwaddr_type == hw_type &&
|
||||
memcmp(hwaddr, lease->hwaddr, hw_len) == 0)
|
||||
return lease;
|
||||
|
||||
return NULL;
|
||||
@@ -236,7 +267,7 @@ struct dhcp_lease *lease_find_by_addr(struct in_addr addr)
|
||||
|
||||
|
||||
struct dhcp_lease *lease_allocate(unsigned char *hwaddr, unsigned char *clid,
|
||||
int clid_len, struct in_addr addr)
|
||||
int hw_len, int hw_type, int clid_len, struct in_addr addr)
|
||||
{
|
||||
struct dhcp_lease *lease;
|
||||
if (!leases_left || !(lease = malloc(sizeof(struct dhcp_lease))))
|
||||
@@ -245,10 +276,10 @@ struct dhcp_lease *lease_allocate(unsigned char *hwaddr, unsigned char *clid,
|
||||
lease->clid = NULL;
|
||||
lease->hostname = lease->fqdn = NULL;
|
||||
lease->addr = addr;
|
||||
memset(lease->hwaddr, 0, ETHER_ADDR_LEN);
|
||||
memset(lease->hwaddr, 0, DHCP_CHADDR_MAX);
|
||||
lease->expires = 1;
|
||||
|
||||
if (!lease_set_hwaddr(lease, hwaddr, clid, clid_len))
|
||||
if (!lease_set_hwaddr(lease, hwaddr, clid, hw_len, hw_type, clid_len))
|
||||
{
|
||||
free(lease);
|
||||
return NULL;
|
||||
@@ -274,12 +305,16 @@ void lease_set_expires(struct dhcp_lease *lease, time_t exp)
|
||||
}
|
||||
|
||||
int lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
|
||||
unsigned char *clid, int clid_len)
|
||||
unsigned char *clid, int hw_len, int hw_type, int clid_len)
|
||||
{
|
||||
if (memcmp(lease->hwaddr, hwaddr, ETHER_ADDR_LEN) != 0)
|
||||
if (hw_len != lease->hwaddr_len ||
|
||||
hw_type != lease->hwaddr_type ||
|
||||
memcmp(lease->hwaddr, hwaddr, hw_len) != 0)
|
||||
{
|
||||
file_dirty = force;
|
||||
memcpy(lease->hwaddr, hwaddr, ETHER_ADDR_LEN);
|
||||
memcpy(lease->hwaddr, hwaddr, hw_len);
|
||||
lease->hwaddr_len = hw_len;
|
||||
lease->hwaddr_type = hw_type;
|
||||
}
|
||||
|
||||
/* only update clid when one is available, stops packets
|
||||
|
||||
114
src/netlink.c
114
src/netlink.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2005 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2006 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
|
||||
@@ -10,8 +10,6 @@
|
||||
GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
/* Author's email: simon@thekelleys.org.uk */
|
||||
|
||||
#include "dnsmasq.h"
|
||||
|
||||
#ifdef HAVE_RTNETLINK
|
||||
@@ -20,35 +18,74 @@
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
|
||||
int netlink_init(void)
|
||||
static struct iovec iov[1];
|
||||
|
||||
void netlink_init(struct daemon *daemon)
|
||||
{
|
||||
struct sockaddr_nl addr;
|
||||
int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
|
||||
daemon->netlinkfd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
|
||||
|
||||
if (sock < 0)
|
||||
return -1; /* no kernel support */
|
||||
if (daemon->netlinkfd < 0)
|
||||
return; /* no kernel support */
|
||||
|
||||
addr.nl_family = AF_NETLINK;
|
||||
addr.nl_pad = 0;
|
||||
addr.nl_pid = getpid();
|
||||
addr.nl_groups = 0;
|
||||
#ifdef HAVE_IPV6
|
||||
addr.nl_groups = RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR | RTMGRP_IPV4_ROUTE | RTMGRP_IPV6_ROUTE;
|
||||
#else
|
||||
addr.nl_groups = RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE;
|
||||
#endif
|
||||
|
||||
if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0)
|
||||
if (bind(daemon->netlinkfd, (struct sockaddr *)&addr, sizeof(addr)) < 0)
|
||||
die(_("cannot bind netlink socket: %s"), NULL);
|
||||
|
||||
return sock;
|
||||
|
||||
iov[0].iov_len = 200;
|
||||
iov[0].iov_base = safe_malloc(iov[0].iov_len);
|
||||
}
|
||||
|
||||
static ssize_t netlink_recv(struct daemon *daemon)
|
||||
{
|
||||
struct msghdr msg;
|
||||
ssize_t rc;
|
||||
|
||||
/* We borrow the DNS packet buffer here. (The DHCP one already has a packet in it)
|
||||
Since it's used only within this routine, that's fine, just remember
|
||||
that calling icmp_echo() will trash it */
|
||||
msg.msg_control = NULL;
|
||||
msg.msg_controllen = 0;
|
||||
msg.msg_flags = 0;
|
||||
msg.msg_name = NULL;
|
||||
msg.msg_namelen = 0;
|
||||
msg.msg_iov = iov;
|
||||
msg.msg_iovlen = 1;
|
||||
|
||||
retry:
|
||||
while ((rc = recvmsg(daemon->netlinkfd, &msg, MSG_PEEK)) == -1 && retry_send());
|
||||
|
||||
if (rc == -1)
|
||||
return -1;
|
||||
|
||||
if (msg.msg_flags & MSG_TRUNC)
|
||||
{
|
||||
size_t newsz = iov[0].iov_len + 100;
|
||||
void *new = realloc(iov[0].iov_base, newsz);
|
||||
if (!new)
|
||||
return -1;
|
||||
iov[0].iov_len = newsz;
|
||||
iov[0].iov_base = new;
|
||||
goto retry;
|
||||
}
|
||||
|
||||
while ((rc = recvmsg(daemon->netlinkfd, &msg, 0)) == -1 && retry_send());
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int netlink_process(struct daemon *daemon, int index, struct in_addr relay,
|
||||
struct in_addr primary, struct dhcp_context **retp)
|
||||
{
|
||||
struct sockaddr_nl addr;
|
||||
struct nlmsghdr *h;
|
||||
int len, found_primary = 0;
|
||||
int found_primary = 0;
|
||||
ssize_t len;
|
||||
struct dhcp_context *ret = NULL;
|
||||
static unsigned int seq = 0;
|
||||
|
||||
@@ -88,17 +125,11 @@ int netlink_process(struct daemon *daemon, int index, struct in_addr relay,
|
||||
}
|
||||
|
||||
get_next:
|
||||
while((len = recvfrom(daemon->netlinkfd, daemon->packet, daemon->packet_buff_sz,
|
||||
MSG_WAITALL, NULL, 0)) == -1 && retry_send());
|
||||
|
||||
if (len == -1)
|
||||
if ((len = netlink_recv(daemon)) == -1)
|
||||
return 0;
|
||||
|
||||
h = (struct nlmsghdr *)daemon->packet;
|
||||
|
||||
while (NLMSG_OK(h, (unsigned int)len))
|
||||
for (h = (struct nlmsghdr *)iov[0].iov_base; NLMSG_OK(h, (unsigned int)len); h = NLMSG_NEXT(h, len))
|
||||
{
|
||||
|
||||
if (h->nlmsg_seq != seq)
|
||||
goto get_next;
|
||||
|
||||
@@ -110,8 +141,7 @@ int netlink_process(struct daemon *daemon, int index, struct in_addr relay,
|
||||
|
||||
if (h->nlmsg_type == RTM_NEWADDR)
|
||||
{
|
||||
struct ifaddrmsg *ifa = NLMSG_DATA(h);
|
||||
|
||||
struct ifaddrmsg *ifa = NLMSG_DATA(h);
|
||||
if (ifa->ifa_index == index && ifa->ifa_family == AF_INET)
|
||||
{
|
||||
struct rtattr *rta = IFA_RTA(ifa);
|
||||
@@ -140,15 +170,43 @@ int netlink_process(struct daemon *daemon, int index, struct in_addr relay,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
h = NLMSG_NEXT(h, len);
|
||||
}
|
||||
|
||||
*retp = ret;
|
||||
|
||||
return found_primary;
|
||||
}
|
||||
|
||||
|
||||
/* We arrange to receive netlink multicast messages whenever the network config changes.
|
||||
If this happens and we still have a DNS packet in the buffer, we re-send it.
|
||||
This helps on DoD links, where frequently the packet which triggers dialling is
|
||||
a DNS query, which then gets lost. By re-sending, we can avoid the lookup
|
||||
failing. */
|
||||
void netlink_multicast(struct daemon *daemon)
|
||||
{
|
||||
ssize_t len;
|
||||
struct nlmsghdr *h;
|
||||
|
||||
if ((len = netlink_recv(daemon)) == -1)
|
||||
return;
|
||||
|
||||
if (!daemon->srv_save)
|
||||
return;
|
||||
|
||||
for (h = (struct nlmsghdr *)iov[0].iov_base; NLMSG_OK(h, (unsigned int)len); h = NLMSG_NEXT(h, len))
|
||||
{
|
||||
if (h->nlmsg_type == NLMSG_DONE || h->nlmsg_type == NLMSG_ERROR)
|
||||
break;
|
||||
|
||||
if (h->nlmsg_type == RTM_NEWADDR || h->nlmsg_type == RTM_NEWROUTE)
|
||||
{
|
||||
while(sendto(daemon->srv_save->sfd->fd, daemon->packet, daemon->packet_len, 0,
|
||||
&daemon->srv_save->addr.sa, sa_len(&daemon->srv_save->addr)) == -1 && retry_send());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -503,7 +503,7 @@ void check_servers(struct daemon *daemon)
|
||||
/* forward table rules reference servers, so have to blow them away */
|
||||
forward_init(0);
|
||||
|
||||
daemon->last_server = NULL;
|
||||
daemon->last_server = daemon->srv_save = NULL;
|
||||
|
||||
for (new = daemon->servers; new; new = tmp)
|
||||
{
|
||||
|
||||
123
src/option.c
123
src/option.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000 - 2005 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000 - 2006 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
|
||||
@@ -21,7 +21,7 @@ struct myoption {
|
||||
int val;
|
||||
};
|
||||
|
||||
#define OPTSTRING "31yZDNLERKzowefnbvhdkqr:m:p:c:l:s:i:t:u:g:a:x:S:C:A:T:H:Q:I:B:F:G:O:M:X:V:U:j:P:J:W:Y:2:"
|
||||
#define OPTSTRING "31yZDNLERKzowefnbvhdkqr:m:p:c:l:s:i:t:u:g:a:x:S:C:A:T:H:Q:I:B:F:G:O:M:X:V:U:j:P:J:W:Y:2:4:"
|
||||
|
||||
static const struct myoption opts[] = {
|
||||
{"version", 0, 0, 'v'},
|
||||
@@ -82,6 +82,7 @@ static const struct myoption opts[] = {
|
||||
{"txt-record", 1, 0, 'Y'},
|
||||
{"enable-dbus", 0, 0, '1'},
|
||||
{"bootp-dynamic", 0, 0, '3'},
|
||||
{"dhcp-mac", 1, 0, '4'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
@@ -177,6 +178,7 @@ static const struct {
|
||||
{ "-1, --enable-dbus", gettext_noop("Enable the DBus interface for setting upstream servers, etc."), NULL },
|
||||
{ "-2, --no-dhcp-interface=interface", gettext_noop("Do not provide DHCP on this interface, only provide DNS."), NULL },
|
||||
{ "-3, --bootp-dynamic", gettext_noop("Enable dynamic address allocation for bootp."), NULL },
|
||||
{ "-4, --dhcp-mac=<id>,<mac address>", gettext_noop("Map MAC address (with wildcards) to option set."), NULL },
|
||||
{ NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
@@ -949,6 +951,7 @@ struct daemon *read_opts (int argc, char **argv, char *compile_opts)
|
||||
new->broadcast.s_addr = 0;
|
||||
new->router.s_addr = 0;
|
||||
new->netid.net = NULL;
|
||||
new->filter = NULL;
|
||||
new->flags = 0;
|
||||
|
||||
problem = _("bad dhcp-range");
|
||||
@@ -959,26 +962,40 @@ struct daemon *read_opts (int argc, char **argv, char *compile_opts)
|
||||
break;
|
||||
}
|
||||
|
||||
for (cp = arg; *cp; cp++)
|
||||
if (!(*cp == ' ' || *cp == '.' || (*cp >='0' && *cp <= '9')))
|
||||
break;
|
||||
|
||||
if (*cp != ',' && (comma = strchr(arg, ',')))
|
||||
while(1)
|
||||
{
|
||||
*comma = 0;
|
||||
if (strstr(arg, "net:") == arg)
|
||||
for (cp = arg; *cp; cp++)
|
||||
if (!(*cp == ' ' || *cp == '.' || (*cp >='0' && *cp <= '9')))
|
||||
break;
|
||||
|
||||
if (*cp != ',' && (comma = strchr(arg, ',')))
|
||||
{
|
||||
new->netid.net = safe_string_alloc(arg+4);
|
||||
new->netid.next = NULL;
|
||||
new->flags |= CONTEXT_FILTER;
|
||||
*comma = 0;
|
||||
if (strstr(arg, "net:") == arg)
|
||||
{
|
||||
struct dhcp_netid *tt = safe_malloc(sizeof (struct dhcp_netid));
|
||||
tt->net = safe_string_alloc(arg+4);
|
||||
tt->next = new->filter;
|
||||
new->filter = tt;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (new->netid.net)
|
||||
{
|
||||
option = '?';
|
||||
problem = _("only one netid tag allowed");
|
||||
}
|
||||
else
|
||||
new->netid.net = safe_string_alloc(arg);
|
||||
}
|
||||
arg = comma + 1;
|
||||
}
|
||||
else
|
||||
new->netid.net = safe_string_alloc(arg);
|
||||
a[0] = comma + 1;
|
||||
{
|
||||
a[0] = arg;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
a[0] = arg;
|
||||
|
||||
|
||||
for (k = 1; k < 5; k++)
|
||||
{
|
||||
@@ -987,7 +1004,7 @@ struct daemon *read_opts (int argc, char **argv, char *compile_opts)
|
||||
*(a[k]++) = 0;
|
||||
}
|
||||
|
||||
if ((k < 2) || ((new->start.s_addr = inet_addr(a[0])) == (in_addr_t)-1))
|
||||
if (option == '?' || (k < 2) || ((new->start.s_addr = inet_addr(a[0])) == (in_addr_t)-1))
|
||||
option = '?';
|
||||
else if (strcmp(a[1], "static") == 0)
|
||||
{
|
||||
@@ -1110,7 +1127,7 @@ struct daemon *read_opts (int argc, char **argv, char *compile_opts)
|
||||
int len;
|
||||
arg += 3; /* dump id: */
|
||||
if (strchr(arg, ':'))
|
||||
len = parse_hex(arg, (unsigned char *)arg, -1, NULL);
|
||||
len = parse_hex(arg, (unsigned char *)arg, -1, NULL, NULL);
|
||||
else
|
||||
len = (int) strlen(arg);
|
||||
|
||||
@@ -1125,10 +1142,11 @@ struct daemon *read_opts (int argc, char **argv, char *compile_opts)
|
||||
new->flags |= CONFIG_NETID;
|
||||
new->netid.net = safe_string_alloc(arg+4);
|
||||
}
|
||||
else if (parse_hex(a[j], new->hwaddr, 6, &new->wildcard_mask) == 6)
|
||||
else
|
||||
{
|
||||
new->hwaddr_len = parse_hex(a[j], new->hwaddr, DHCP_CHADDR_MAX, &new->wildcard_mask, &new->hwaddr_type);
|
||||
new->flags |= CONFIG_HWADDR;
|
||||
else
|
||||
option = '?';
|
||||
}
|
||||
}
|
||||
else if (strchr(a[j], '.') && (in.s_addr = inet_addr(a[j])) != (in_addr_t)-1)
|
||||
{
|
||||
@@ -1223,7 +1241,7 @@ struct daemon *read_opts (int argc, char **argv, char *compile_opts)
|
||||
int addrs, digs, is_addr, is_hex, is_dec;
|
||||
|
||||
new->len = 0;
|
||||
new->is_addr = 0;
|
||||
new->flags = 0;
|
||||
new->netid = NULL;
|
||||
new->val = NULL;
|
||||
new->vendor_class = NULL;
|
||||
@@ -1335,7 +1353,7 @@ struct daemon *read_opts (int argc, char **argv, char *compile_opts)
|
||||
digs++;
|
||||
is_dec = is_addr = 0;
|
||||
}
|
||||
else if (*cp == '.')
|
||||
else if (*cp == '.' || *cp == '/')
|
||||
is_dec = is_hex = 0;
|
||||
else if (!((*cp >='0' && *cp <= '9') || *cp == '-'))
|
||||
{
|
||||
@@ -1357,7 +1375,7 @@ struct daemon *read_opts (int argc, char **argv, char *compile_opts)
|
||||
{
|
||||
new->len = digs;
|
||||
new->val = safe_malloc(new->len);
|
||||
parse_hex(comma, new->val, digs, NULL);
|
||||
parse_hex(comma, new->val, digs, NULL, NULL);
|
||||
}
|
||||
else if (is_dec)
|
||||
{
|
||||
@@ -1396,19 +1414,42 @@ struct daemon *read_opts (int argc, char **argv, char *compile_opts)
|
||||
else if (is_addr)
|
||||
{
|
||||
struct in_addr in;
|
||||
unsigned char *op;
|
||||
new->len = INADDRSZ * addrs;
|
||||
new->val = op = safe_malloc(new->len);
|
||||
new->is_addr = 1;
|
||||
unsigned char *op;
|
||||
char *slash;
|
||||
/* max length of address/subnet descriptor is five bytes */
|
||||
new->val = op = safe_malloc(5 * addrs);
|
||||
if (!new->vendor_class)
|
||||
new->flags |= DHOPT_ADDR;
|
||||
while (addrs--)
|
||||
{
|
||||
cp = comma;
|
||||
if ((comma = strchr(cp, ',')))
|
||||
*comma++ = 0;
|
||||
if ((slash = strchr(cp, '/')))
|
||||
*slash++ = 0;
|
||||
in.s_addr = inet_addr(cp);
|
||||
memcpy(op, &in, INADDRSZ);
|
||||
op += INADDRSZ;
|
||||
if (!slash)
|
||||
{
|
||||
memcpy(op, &in, INADDRSZ);
|
||||
op += INADDRSZ;
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned char *p = (unsigned char *)∈
|
||||
int netsize = atoi(slash);
|
||||
*op++ = netsize;
|
||||
if (netsize > 0)
|
||||
*op++ = *p++;
|
||||
if (netsize > 8)
|
||||
*op++ = *p++;
|
||||
if (netsize > 16)
|
||||
*op++ = *p++;
|
||||
if (netsize > 24)
|
||||
*op++ = *p++;
|
||||
new->flags &= ~DHOPT_ADDR; /* cannot re-write descriptor format */
|
||||
}
|
||||
}
|
||||
new->len = op - new->val;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1416,6 +1457,7 @@ struct daemon *read_opts (int argc, char **argv, char *compile_opts)
|
||||
new->len = strlen(comma);
|
||||
/* keep terminating zero on string */
|
||||
new->val = (unsigned char *)safe_string_alloc(comma);
|
||||
new->flags |= DHOPT_STRING;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1508,7 +1550,24 @@ struct daemon *read_opts (int argc, char **argv, char *compile_opts)
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case '4':
|
||||
{
|
||||
if (!(comma = safe_strchr(arg, ',')))
|
||||
option = '?';
|
||||
else
|
||||
{
|
||||
struct dhcp_mac *new = safe_malloc(sizeof(struct dhcp_mac));
|
||||
*comma = 0;
|
||||
new->netid.net = safe_string_alloc(arg);
|
||||
unhide_metas(comma+1);
|
||||
new->hwaddr_len = parse_hex(comma+1, new->hwaddr, DHCP_CHADDR_MAX, &new->mask, &new->hwaddr_type);
|
||||
new->next = daemon->dhcp_macs;
|
||||
daemon->dhcp_macs = new;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'U':
|
||||
case 'j':
|
||||
{
|
||||
|
||||
@@ -17,7 +17,7 @@ static int add_resource_record(HEADER *header, char *limit, int *truncp,
|
||||
unsigned long ttl, unsigned int *offset, unsigned short type,
|
||||
unsigned short class, char *format, ...);
|
||||
|
||||
static int extract_name(HEADER *header, unsigned int plen, unsigned char **pp,
|
||||
static int extract_name(HEADER *header, size_t plen, unsigned char **pp,
|
||||
char *name, int isExtract)
|
||||
{
|
||||
unsigned char *cp = (unsigned char *)name, *p = *pp, *p1 = NULL;
|
||||
@@ -38,7 +38,7 @@ static int extract_name(HEADER *header, unsigned int plen, unsigned char **pp,
|
||||
/* get offset */
|
||||
l = (l&0x3f) << 8;
|
||||
l |= *p++;
|
||||
if (l >= (unsigned int)plen)
|
||||
if (l >= plen)
|
||||
return 0;
|
||||
|
||||
if (!p1) /* first jump, save location to go back to */
|
||||
@@ -253,7 +253,7 @@ static int in_arpa_name_2_addr(char *namein, struct all_addr *addrp)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned char *skip_name(unsigned char *ansp, HEADER *header, unsigned int plen)
|
||||
static unsigned char *skip_name(unsigned char *ansp, HEADER *header, size_t plen)
|
||||
{
|
||||
while(1)
|
||||
{
|
||||
@@ -298,7 +298,7 @@ static unsigned char *skip_name(unsigned char *ansp, HEADER *header, unsigned in
|
||||
return ansp;
|
||||
}
|
||||
|
||||
static unsigned char *skip_questions(HEADER *header, unsigned int plen)
|
||||
static unsigned char *skip_questions(HEADER *header, size_t plen)
|
||||
{
|
||||
int q, qdcount = ntohs(header->qdcount);
|
||||
unsigned char *ansp = (unsigned char *)(header+1);
|
||||
@@ -315,7 +315,7 @@ static unsigned char *skip_questions(HEADER *header, unsigned int plen)
|
||||
return ansp;
|
||||
}
|
||||
|
||||
static unsigned char *skip_section(unsigned char *ansp, int count, HEADER *header, unsigned int plen)
|
||||
static unsigned char *skip_section(unsigned char *ansp, int count, HEADER *header, size_t plen)
|
||||
{
|
||||
int i, rdlen;
|
||||
|
||||
@@ -338,7 +338,7 @@ static unsigned char *skip_section(unsigned char *ansp, int count, HEADER *heade
|
||||
might be poisoning attacks. Note that we decode the name rather
|
||||
than CRC the raw bytes, since replies might be compressed differently.
|
||||
We ignore case in the names for the same reason. */
|
||||
unsigned int questions_crc(HEADER *header, unsigned int plen, char *name)
|
||||
unsigned int questions_crc(HEADER *header, size_t plen, char *name)
|
||||
{
|
||||
int q;
|
||||
unsigned int crc = 0xffffffff;
|
||||
@@ -380,7 +380,7 @@ unsigned int questions_crc(HEADER *header, unsigned int plen, char *name)
|
||||
}
|
||||
|
||||
|
||||
int resize_packet(HEADER *header, unsigned int plen, unsigned char *pheader, unsigned int hlen)
|
||||
size_t resize_packet(HEADER *header, size_t plen, unsigned char *pheader, size_t hlen)
|
||||
{
|
||||
unsigned char *ansp = skip_questions(header, plen);
|
||||
|
||||
@@ -403,7 +403,7 @@ int resize_packet(HEADER *header, unsigned int plen, unsigned char *pheader, uns
|
||||
return ansp - (unsigned char *)header;
|
||||
}
|
||||
|
||||
unsigned char *find_pseudoheader(HEADER *header, unsigned int plen, unsigned int *len, unsigned char **p)
|
||||
unsigned char *find_pseudoheader(HEADER *header, size_t plen, size_t *len, unsigned char **p)
|
||||
{
|
||||
/* See if packet has an RFC2671 pseudoheader, and if so return a pointer to it.
|
||||
also return length of pseudoheader in *len and pointer to the UDP size in *p */
|
||||
@@ -428,7 +428,7 @@ unsigned char *find_pseudoheader(HEADER *header, unsigned int plen, unsigned int
|
||||
save = ansp;
|
||||
ansp += 6; /* class, TTL */
|
||||
GETSHORT(rdlen, ansp);
|
||||
if ((unsigned int)(ansp + rdlen - (unsigned char *)header) > plen)
|
||||
if ((size_t)(ansp + rdlen - (unsigned char *)header) > plen)
|
||||
return NULL;
|
||||
ansp += rdlen;
|
||||
if (type == T_OPT)
|
||||
@@ -470,7 +470,7 @@ static void dns_doctor(HEADER *header, struct doctor *doctor, struct in_addr *ad
|
||||
}
|
||||
}
|
||||
|
||||
static int find_soa(HEADER *header, struct doctor *doctor, unsigned int qlen)
|
||||
static int find_soa(HEADER *header, struct doctor *doctor, size_t qlen)
|
||||
{
|
||||
unsigned char *p;
|
||||
int qtype, qclass, rdlen;
|
||||
@@ -513,7 +513,7 @@ static int find_soa(HEADER *header, struct doctor *doctor, unsigned int qlen)
|
||||
else
|
||||
p += rdlen;
|
||||
|
||||
if ((unsigned int)(p - (unsigned char *)header) > qlen)
|
||||
if ((size_t)(p - (unsigned char *)header) > qlen)
|
||||
return 0; /* bad packet */
|
||||
}
|
||||
|
||||
@@ -533,7 +533,7 @@ static int find_soa(HEADER *header, struct doctor *doctor, unsigned int qlen)
|
||||
|
||||
p += rdlen;
|
||||
|
||||
if ((unsigned int)(p - (unsigned char *)header) > qlen)
|
||||
if ((size_t)(p - (unsigned char *)header) > qlen)
|
||||
return 0; /* bad packet */
|
||||
}
|
||||
|
||||
@@ -543,7 +543,7 @@ static int find_soa(HEADER *header, struct doctor *doctor, unsigned int qlen)
|
||||
/* Note that the following code can create CNAME chains that don't point to a real record,
|
||||
either because of lack of memory, or lack of SOA records. These are treated by the cache code as
|
||||
expired and cleaned out that way. */
|
||||
void extract_addresses(HEADER *header, unsigned int qlen, char *name, time_t now, struct daemon *daemon)
|
||||
void extract_addresses(HEADER *header, size_t qlen, char *name, time_t now, struct daemon *daemon)
|
||||
{
|
||||
unsigned char *p, *p1, *endrr;
|
||||
int i, j, qtype, qclass, aqtype, aqclass, ardlen, res, searched_soa = 0;
|
||||
@@ -625,7 +625,7 @@ void extract_addresses(HEADER *header, unsigned int qlen, char *name, time_t now
|
||||
}
|
||||
|
||||
p1 = endrr;
|
||||
if ((unsigned int)(p1 - (unsigned char *)header) > qlen)
|
||||
if ((size_t)(p1 - (unsigned char *)header) > qlen)
|
||||
return; /* bad packet */
|
||||
}
|
||||
}
|
||||
@@ -709,7 +709,7 @@ void extract_addresses(HEADER *header, unsigned int qlen, char *name, time_t now
|
||||
}
|
||||
|
||||
p1 = endrr;
|
||||
if ((unsigned int)(p1 - (unsigned char *)header) > qlen)
|
||||
if ((size_t)(p1 - (unsigned char *)header) > qlen)
|
||||
return; /* bad packet */
|
||||
}
|
||||
}
|
||||
@@ -742,7 +742,7 @@ void extract_addresses(HEADER *header, unsigned int qlen, char *name, time_t now
|
||||
/* If the packet holds exactly one query
|
||||
return 1 and leave the name from the query in name. */
|
||||
|
||||
unsigned short extract_request(HEADER *header,unsigned int qlen, char *name, unsigned short *typep)
|
||||
unsigned short extract_request(HEADER *header, size_t qlen, char *name, unsigned short *typep)
|
||||
{
|
||||
unsigned char *p = (unsigned char *)(header+1);
|
||||
int qtype, qclass;
|
||||
@@ -776,7 +776,7 @@ unsigned short extract_request(HEADER *header,unsigned int qlen, char *name, uns
|
||||
}
|
||||
|
||||
|
||||
int setup_reply(HEADER *header, unsigned int qlen,
|
||||
size_t setup_reply(HEADER *header, size_t qlen,
|
||||
struct all_addr *addrp, unsigned short flags, unsigned long ttl)
|
||||
{
|
||||
unsigned char *p = skip_questions(header, qlen);
|
||||
@@ -841,7 +841,7 @@ int check_for_local_domain(char *name, time_t now, struct daemon *daemon)
|
||||
/* Is the packet a reply with the answer address equal to addr?
|
||||
If so mung is into an NXDOMAIN reply and also put that information
|
||||
in the cache. */
|
||||
int check_for_bogus_wildcard(HEADER *header, unsigned int qlen, char *name,
|
||||
int check_for_bogus_wildcard(HEADER *header, size_t qlen, char *name,
|
||||
struct bogus_addr *baddr, time_t now)
|
||||
{
|
||||
unsigned char *p;
|
||||
@@ -966,8 +966,8 @@ static int add_resource_record(HEADER *header, char *limit, int *truncp, unsigne
|
||||
}
|
||||
|
||||
/* return zero if we can't answer from cache, or packet size if we can */
|
||||
int answer_request(HEADER *header, char *limit, unsigned int qlen, struct daemon *daemon,
|
||||
struct in_addr local_addr, struct in_addr local_netmask, time_t now)
|
||||
size_t answer_request(HEADER *header, char *limit, size_t qlen, struct daemon *daemon,
|
||||
struct in_addr local_addr, struct in_addr local_netmask, time_t now)
|
||||
{
|
||||
char *name = daemon->namebuff;
|
||||
unsigned char *p, *ansp, *pheader;
|
||||
|
||||
254
src/rfc2131.c
254
src/rfc2131.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2005 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2006 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
|
||||
@@ -60,15 +60,16 @@
|
||||
|
||||
static unsigned char *option_put(unsigned char *p, unsigned char *end, int opt, int len, unsigned int val);
|
||||
static unsigned char *option_end(unsigned char *p, unsigned char *end, struct dhcp_packet *start);
|
||||
static unsigned char *option_put_string(unsigned char *p, unsigned char *end, int opt, char *string);
|
||||
static unsigned char *option_put_string(unsigned char *p, unsigned char *end,
|
||||
int opt, char *string, int null_term);
|
||||
static void bootp_option_put(struct dhcp_packet *mess,
|
||||
struct dhcp_boot *boot_opts, struct dhcp_netid *netids);
|
||||
static int option_len(unsigned char *opt);
|
||||
static void *option_ptr(unsigned char *opt);
|
||||
static struct in_addr option_addr(unsigned char *opt);
|
||||
static unsigned int option_uint(unsigned char *opt, int size);
|
||||
static void log_packet(char *type, struct in_addr *addr, unsigned char *hwaddr, char *interface, char *string);
|
||||
static unsigned char *option_find(struct dhcp_packet *mess, int size, int opt_type, int minsize);
|
||||
static void log_packet(char *type, struct in_addr *addr, unsigned char *hwaddr, int hw_len, char *interface, char *string);
|
||||
static unsigned char *option_find(struct dhcp_packet *mess, size_t size, int opt_type, int minsize);
|
||||
static unsigned char *do_req_options(struct dhcp_context *context,
|
||||
unsigned char *p, unsigned char *end,
|
||||
unsigned char *req_options,
|
||||
@@ -76,21 +77,23 @@ static unsigned char *do_req_options(struct dhcp_context *context,
|
||||
char *hostname,
|
||||
struct dhcp_netid *netid,
|
||||
struct in_addr subnet_addr,
|
||||
unsigned char fqdn_flags);
|
||||
unsigned char fqdn_flags,
|
||||
int null_term);
|
||||
|
||||
int dhcp_reply(struct daemon *daemon, struct dhcp_context *context, char *iface_name,
|
||||
unsigned int sz, time_t now, int unicast_dest)
|
||||
size_t dhcp_reply(struct daemon *daemon, struct dhcp_context *context, char *iface_name,
|
||||
size_t sz, time_t now, int unicast_dest)
|
||||
{
|
||||
unsigned char *opt, *clid = NULL;
|
||||
struct dhcp_lease *ltmp, *lease = NULL;
|
||||
struct dhcp_vendor *vendor;
|
||||
struct dhcp_mac *mac;
|
||||
struct dhcp_netid_list *id_list;
|
||||
int clid_len = 0, ignore = 0;
|
||||
struct dhcp_packet *mess = &daemon->dhcp_packet->data;
|
||||
unsigned char *p = mess->options + sizeof(u32); /* skip cookie */
|
||||
unsigned char *end = (unsigned char *)(daemon->dhcp_packet + 1);
|
||||
char *hostname = NULL, *offer_hostname = NULL, *client_hostname = NULL;
|
||||
int hostname_auth = 0;
|
||||
int hostname_auth = 0, borken_opt = 0;
|
||||
unsigned char *req_options = NULL;
|
||||
char *message = NULL;
|
||||
unsigned int time;
|
||||
@@ -99,12 +102,14 @@ int dhcp_reply(struct daemon *daemon, struct dhcp_context *context, char *iface_
|
||||
struct in_addr subnet_addr, fallback;
|
||||
unsigned short fuzz = 0;
|
||||
unsigned int mess_type = 0;
|
||||
u8 *chaddr;
|
||||
unsigned char fqdn_flags = 0;
|
||||
subnet_addr.s_addr = 0;
|
||||
|
||||
if (mess->op != BOOTREQUEST)
|
||||
return 0;
|
||||
|
||||
if (mess->hlen > DHCP_CHADDR_MAX)
|
||||
return 0;
|
||||
|
||||
/* check for DHCP rather than BOOTP */
|
||||
if ((opt = option_find(mess, sz, OPTION_MESSAGE_TYPE, 1)))
|
||||
@@ -132,8 +137,8 @@ int dhcp_reply(struct daemon *daemon, struct dhcp_context *context, char *iface_
|
||||
}
|
||||
|
||||
/* do we have a lease in store? */
|
||||
if (mess->htype != 0)
|
||||
lease = lease_find_by_client(mess->chaddr, clid, clid_len);
|
||||
if (mess->htype != 0 && mess->hlen != 0)
|
||||
lease = lease_find_by_client(mess->chaddr, mess->hlen, mess->htype, clid, clid_len);
|
||||
|
||||
/* If this request is missing a clid, but we've seen one before,
|
||||
use it again for option matching etc. */
|
||||
@@ -144,38 +149,31 @@ int dhcp_reply(struct daemon *daemon, struct dhcp_context *context, char *iface_
|
||||
}
|
||||
}
|
||||
|
||||
/* htype == 0 is only allowed in DHCPINFORM, this seems to be a
|
||||
microsoftism. chaddr == NULL in that case */
|
||||
|
||||
if (mess->htype == 0 && mess_type == DHCPINFORM)
|
||||
/* htype == 0 is only allowed in DHCPINFORM,
|
||||
this seems to be a microsoftism. */
|
||||
if (mess->htype == 0)
|
||||
{
|
||||
chaddr = NULL;
|
||||
if (mess->hlen != 0)
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
chaddr = mess->chaddr;
|
||||
|
||||
/* Token ring is supported when we have packet sockets
|
||||
to make the HW headers for us. We don't have the code to build
|
||||
token ring headers when using BPF. We rely on the fact that
|
||||
token ring hwaddrs are the same size as ethernet hwaddrs. */
|
||||
|
||||
#ifdef HAVE_BPF
|
||||
if (mess->htype != ARPHRD_ETHER)
|
||||
#else
|
||||
if (mess->htype != ARPHRD_ETHER && mess->htype != ARPHRD_IEEE802)
|
||||
#endif
|
||||
{
|
||||
syslog(LOG_WARNING, _("DHCP request for unsupported hardware type (%d) recieved on %s"),
|
||||
mess->htype, iface_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (mess->hlen != ETHER_ADDR_LEN)
|
||||
if (mess_type != DHCPINFORM || mess->hlen != 0)
|
||||
return 0;
|
||||
}
|
||||
else if (mess->hlen == 0)
|
||||
return 0;
|
||||
|
||||
for (mac = daemon->dhcp_macs; mac; mac = mac->next)
|
||||
if (mac->hwaddr_len == mess->hlen &&
|
||||
(mac->hwaddr_type == mess->htype || mac->hwaddr_type == 0))
|
||||
{
|
||||
int i;
|
||||
unsigned int mask = mac->mask;
|
||||
for (i = mac->hwaddr_len - 1; i >= 0; i--, mask = mask >> 1)
|
||||
if (mask & 1)
|
||||
mac->hwaddr[i] = mess->chaddr[i];
|
||||
if (memcmp(mac->hwaddr, mess->chaddr, mac->hwaddr_len) == 0)
|
||||
{
|
||||
mac->netid.next = netid;
|
||||
netid = &mac->netid;
|
||||
}
|
||||
}
|
||||
|
||||
/* Determine network for this packet. Our caller will have already linked all the
|
||||
contexts which match the addresses of the receiving interface but if the
|
||||
@@ -228,7 +226,8 @@ int dhcp_reply(struct daemon *daemon, struct dhcp_context *context, char *iface_
|
||||
|
||||
mess->op = BOOTREPLY;
|
||||
|
||||
config = find_config(daemon->dhcp_conf, context, clid, clid_len, chaddr, NULL);
|
||||
config = find_config(daemon->dhcp_conf, context, clid, clid_len,
|
||||
mess->chaddr, mess->hlen, mess->htype, NULL);
|
||||
|
||||
if (mess_type == 0)
|
||||
{
|
||||
@@ -261,7 +260,7 @@ int dhcp_reply(struct daemon *daemon, struct dhcp_context *context, char *iface_
|
||||
}
|
||||
|
||||
for (id_list = daemon->dhcp_ignore; id_list; id_list = id_list->next)
|
||||
if (match_netid(id_list->list, netid))
|
||||
if (match_netid(id_list->list, netid, 0))
|
||||
message = _("disabled");
|
||||
|
||||
if (!message)
|
||||
@@ -271,14 +270,15 @@ int dhcp_reply(struct daemon *daemon, struct dhcp_context *context, char *iface_
|
||||
logaddr = &config->addr;
|
||||
mess->yiaddr = config->addr;
|
||||
if ((lease = lease_find_by_addr(config->addr)) &&
|
||||
memcmp(lease->hwaddr, chaddr, ETHER_ADDR_LEN) != 0)
|
||||
(lease->hwaddr_len != mess->hlen ||
|
||||
memcmp(lease->hwaddr, mess->chaddr, lease->hwaddr_len) != 0))
|
||||
message = _("address in use");
|
||||
}
|
||||
else if (!(daemon->options & OPT_BOOTP_DYNAMIC))
|
||||
message = _("no address configured");
|
||||
else
|
||||
{
|
||||
if (!(lease = lease_find_by_client(mess->chaddr, NULL, 0)) ||
|
||||
if (!(lease = lease_find_by_client(mess->chaddr, mess->hlen, mess->htype, NULL, 0)) ||
|
||||
!address_available(context, lease->addr))
|
||||
{
|
||||
if (lease)
|
||||
@@ -287,14 +287,14 @@ int dhcp_reply(struct daemon *daemon, struct dhcp_context *context, char *iface_
|
||||
lease_prune(lease, now);
|
||||
lease = NULL;
|
||||
}
|
||||
if (!address_allocate(context, daemon, &mess->yiaddr, chaddr, netid, now))
|
||||
if (!address_allocate(context, daemon, &mess->yiaddr, mess->chaddr, mess->hlen, netid, now))
|
||||
message = _("no address available");
|
||||
}
|
||||
else
|
||||
mess->yiaddr = lease->addr;
|
||||
}
|
||||
|
||||
if (!message && !lease && (!(lease = lease_allocate(chaddr, NULL, 0, mess->yiaddr))))
|
||||
if (!message && !lease && (!(lease = lease_allocate(mess->chaddr, NULL, mess->hlen, mess->htype, 0, mess->yiaddr))))
|
||||
message = _("no leases left");
|
||||
|
||||
if (!message && !(context = narrow_context(context, mess->yiaddr)))
|
||||
@@ -304,19 +304,19 @@ int dhcp_reply(struct daemon *daemon, struct dhcp_context *context, char *iface_
|
||||
{
|
||||
logaddr = &mess->yiaddr;
|
||||
|
||||
if (context->netid.net && !(context->flags & CONTEXT_FILTER))
|
||||
if (context->netid.net)
|
||||
{
|
||||
context->netid.next = netid;
|
||||
netid = &context->netid;
|
||||
}
|
||||
|
||||
lease_set_hwaddr(lease, chaddr, NULL, 0);
|
||||
lease_set_hwaddr(lease, mess->chaddr, NULL, mess->hlen, mess->htype, 0);
|
||||
if (hostname)
|
||||
lease_set_hostname(lease, hostname, daemon->domain_suffix, 1);
|
||||
lease_set_expires(lease, 0); /* infinite lease */
|
||||
|
||||
p = do_req_options(context, p, end, NULL, daemon,
|
||||
hostname, netid, subnet_addr, fqdn_flags);
|
||||
hostname, netid, subnet_addr, fqdn_flags, 0);
|
||||
/* must do this after do_req_options since it overwrites filename field. */
|
||||
mess->siaddr = context->local;
|
||||
bootp_option_put(mess, daemon->boot_config, netid);
|
||||
@@ -324,7 +324,7 @@ int dhcp_reply(struct daemon *daemon, struct dhcp_context *context, char *iface_
|
||||
}
|
||||
}
|
||||
|
||||
log_packet(NULL, logaddr, chaddr, iface_name, message);
|
||||
log_packet(NULL, logaddr, mess->chaddr, mess->hlen, iface_name, message);
|
||||
mess->file[128] = save;
|
||||
|
||||
if (message)
|
||||
@@ -346,7 +346,7 @@ int dhcp_reply(struct daemon *daemon, struct dhcp_context *context, char *iface_
|
||||
pp = op;
|
||||
|
||||
/* Always force update, since the client has no way to do it itself. */
|
||||
if (fqdn_flags & 0x01)
|
||||
if (!(fqdn_flags & 0x01))
|
||||
fqdn_flags |= 0x02;
|
||||
|
||||
fqdn_flags &= ~0x08;
|
||||
@@ -363,6 +363,8 @@ int dhcp_reply(struct daemon *daemon, struct dhcp_context *context, char *iface_
|
||||
else
|
||||
{
|
||||
memcpy(pq, op, len);
|
||||
if (len > 0 && op[len-1] == 0)
|
||||
borken_opt = 1;
|
||||
pq += len + 1;
|
||||
}
|
||||
|
||||
@@ -378,8 +380,13 @@ int dhcp_reply(struct daemon *daemon, struct dhcp_context *context, char *iface_
|
||||
{
|
||||
int len = option_len(opt);
|
||||
memcpy(daemon->dhcp_buff, option_ptr(opt), len);
|
||||
/* May not be zero terminated */
|
||||
daemon->dhcp_buff[len] = 0;
|
||||
/* Microsoft clients are broken, and need zero-terminated strings
|
||||
in options. We detect this state here, and do the same in
|
||||
any options we send */
|
||||
if (len > 0 && daemon->dhcp_buff[len-1] == 0)
|
||||
borken_opt = 1;
|
||||
else
|
||||
daemon->dhcp_buff[len] = 0;
|
||||
if (canonicalise(daemon->dhcp_buff))
|
||||
client_hostname = daemon->dhcp_buff;
|
||||
}
|
||||
@@ -398,7 +405,9 @@ int dhcp_reply(struct daemon *daemon, struct dhcp_context *context, char *iface_
|
||||
/* Search again now we have a hostname.
|
||||
Only accept configs without CLID and HWADDR here, (they won't match)
|
||||
to avoid impersonation by name. */
|
||||
struct dhcp_config *new = find_config(daemon->dhcp_conf, context, NULL, 0, chaddr, hostname);
|
||||
struct dhcp_config *new = find_config(daemon->dhcp_conf, context, NULL, 0,
|
||||
mess->chaddr, mess->hlen,
|
||||
mess->htype, hostname);
|
||||
if (!have_config(new, CONFIG_CLID) && !have_config(new, CONFIG_HWADDR))
|
||||
config = new;
|
||||
}
|
||||
@@ -442,10 +451,10 @@ int dhcp_reply(struct daemon *daemon, struct dhcp_context *context, char *iface_
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* if all the netids in the ignore list are present, ignore this client */
|
||||
for (id_list = daemon->dhcp_ignore; id_list; id_list = id_list->next)
|
||||
if (match_netid(id_list->list, netid))
|
||||
if (match_netid(id_list->list, netid, 0))
|
||||
ignore = 1;
|
||||
|
||||
/* Can have setting to ignore the client ID for a particular MAC address or hostname */
|
||||
@@ -485,7 +494,7 @@ int dhcp_reply(struct daemon *daemon, struct dhcp_context *context, char *iface_
|
||||
if (!(opt = option_find(mess, sz, OPTION_REQUESTED_IP, INADDRSZ)))
|
||||
return 0;
|
||||
|
||||
log_packet("DECLINE", option_ptr(opt), chaddr, iface_name, message);
|
||||
log_packet("DECLINE", option_ptr(opt), mess->chaddr, mess->hlen, iface_name, message);
|
||||
|
||||
if (lease && lease->addr.s_addr == option_addr(opt).s_addr)
|
||||
lease_prune(lease, now);
|
||||
@@ -513,7 +522,7 @@ int dhcp_reply(struct daemon *daemon, struct dhcp_context *context, char *iface_
|
||||
else
|
||||
message = _("unknown lease");
|
||||
|
||||
log_packet("RELEASE", &mess->ciaddr, chaddr, iface_name, message);
|
||||
log_packet("RELEASE", &mess->ciaddr, mess->chaddr, mess->hlen, iface_name, message);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -533,15 +542,15 @@ int dhcp_reply(struct daemon *daemon, struct dhcp_context *context, char *iface_
|
||||
else if (opt && address_available(context, addr) && !lease_find_by_addr(addr) &&
|
||||
!config_find_by_address(daemon->dhcp_conf, addr))
|
||||
mess->yiaddr = addr;
|
||||
else if (!address_allocate(context, daemon, &mess->yiaddr, chaddr, netid, now))
|
||||
else if (!address_allocate(context, daemon, &mess->yiaddr, mess->chaddr, mess->hlen, netid, now))
|
||||
message = _("no address available");
|
||||
log_packet("DISCOVER", opt ? &addr : NULL, chaddr, iface_name, message);
|
||||
log_packet("DISCOVER", opt ? &addr : NULL, mess->chaddr, mess->hlen, iface_name, message);
|
||||
}
|
||||
|
||||
if (message || !(context = narrow_context(context, mess->yiaddr)))
|
||||
return 0;
|
||||
|
||||
if (context->netid.net && !(context->flags & CONTEXT_FILTER))
|
||||
if (context->netid.net)
|
||||
{
|
||||
context->netid.next = netid;
|
||||
netid = &context->netid;
|
||||
@@ -569,10 +578,10 @@ int dhcp_reply(struct daemon *daemon, struct dhcp_context *context, char *iface_
|
||||
p = option_put(p, end, OPTION_T2, 4, (time*7)/8);
|
||||
}
|
||||
p = do_req_options(context, p, end, req_options, daemon,
|
||||
offer_hostname, netid, subnet_addr, fqdn_flags);
|
||||
offer_hostname, netid, subnet_addr, fqdn_flags, borken_opt);
|
||||
p = option_end(p, end, mess);
|
||||
|
||||
log_packet("OFFER" , &mess->yiaddr, chaddr, iface_name, NULL);
|
||||
log_packet("OFFER" , &mess->yiaddr, mess->chaddr, mess->hlen, iface_name, NULL);
|
||||
return p - (unsigned char *)mess;
|
||||
|
||||
case DHCPREQUEST:
|
||||
@@ -613,8 +622,12 @@ int dhcp_reply(struct daemon *daemon, struct dhcp_context *context, char *iface_
|
||||
else
|
||||
{
|
||||
/* RENEWING or REBINDING */
|
||||
/* Must exist a lease for this address */
|
||||
if (!lease || mess->ciaddr.s_addr != lease->addr.s_addr)
|
||||
/* Check existing lease for this address.
|
||||
We allow it to be missing if dhcp-authoritative mode
|
||||
as long as we can allocate the lease now - checked below.
|
||||
This makes for a smooth recovery from a lost lease DB */
|
||||
if ((lease && mess->ciaddr.s_addr != lease->addr.s_addr) ||
|
||||
(!lease && !(daemon->options & OPT_AUTHORITATIVE)))
|
||||
{
|
||||
message = _("lease not found");
|
||||
/* ensure we broadcast NAK */
|
||||
@@ -625,7 +638,7 @@ int dhcp_reply(struct daemon *daemon, struct dhcp_context *context, char *iface_
|
||||
mess->yiaddr = mess->ciaddr;
|
||||
}
|
||||
|
||||
log_packet("REQUEST", &mess->yiaddr, chaddr, iface_name, NULL);
|
||||
log_packet("REQUEST", &mess->yiaddr, mess->chaddr, mess->hlen, iface_name, NULL);
|
||||
|
||||
if (!message)
|
||||
{
|
||||
@@ -660,20 +673,20 @@ int dhcp_reply(struct daemon *daemon, struct dhcp_context *context, char *iface_
|
||||
else if ((ltmp = lease_find_by_addr(mess->yiaddr)) && ltmp != lease)
|
||||
message = _("address in use");
|
||||
|
||||
else if (!lease && !(lease = lease_allocate(chaddr, clid, clid_len, mess->yiaddr)))
|
||||
else if (!lease && !(lease = lease_allocate(mess->chaddr, clid, mess->hlen, mess->htype, clid_len, mess->yiaddr)))
|
||||
message = _("no leases left");
|
||||
}
|
||||
|
||||
if (message)
|
||||
{
|
||||
log_packet("NAK", &mess->yiaddr, chaddr, iface_name, message);
|
||||
log_packet("NAK", &mess->yiaddr, mess->chaddr, mess->hlen, iface_name, message);
|
||||
|
||||
mess->siaddr.s_addr = mess->yiaddr.s_addr = 0;
|
||||
bootp_option_put(mess, NULL, NULL);
|
||||
p = option_put(p, end, OPTION_MESSAGE_TYPE, 1, DHCPNAK);
|
||||
p = option_put(p, end, OPTION_SERVER_IDENTIFIER, INADDRSZ,
|
||||
ntohl(context ? context->local.s_addr : fallback.s_addr));
|
||||
p = option_put_string(p, end, OPTION_MESSAGE, message);
|
||||
p = option_put_string(p, end, OPTION_MESSAGE, message, borken_opt);
|
||||
/* This fixes a problem with the DHCP spec, broadcasting a NAK to a host on
|
||||
a distant subnet which unicast a REQ to us won't work. */
|
||||
if (!unicast_dest || mess->giaddr.s_addr != 0 ||
|
||||
@@ -691,9 +704,9 @@ int dhcp_reply(struct daemon *daemon, struct dhcp_context *context, char *iface_
|
||||
hostname_auth = 1;
|
||||
}
|
||||
|
||||
log_packet("ACK", &mess->yiaddr, chaddr, iface_name, hostname);
|
||||
log_packet("ACK", &mess->yiaddr, mess->chaddr, mess->hlen, iface_name, hostname);
|
||||
|
||||
if (context->netid.net && !(context->flags & CONTEXT_FILTER))
|
||||
if (context->netid.net)
|
||||
{
|
||||
context->netid.next = netid;
|
||||
netid = &context->netid;
|
||||
@@ -707,7 +720,7 @@ int dhcp_reply(struct daemon *daemon, struct dhcp_context *context, char *iface_
|
||||
time = req_time;
|
||||
}
|
||||
|
||||
lease_set_hwaddr(lease, chaddr, clid, clid_len);
|
||||
lease_set_hwaddr(lease, mess->chaddr, clid, mess->hlen, mess->htype, clid_len);
|
||||
if (hostname)
|
||||
lease_set_hostname(lease, hostname, daemon->domain_suffix, hostname_auth);
|
||||
lease_set_expires(lease, time == 0xffffffff ? 0 : now + (time_t)time);
|
||||
@@ -725,7 +738,7 @@ int dhcp_reply(struct daemon *daemon, struct dhcp_context *context, char *iface_
|
||||
p = option_put(p, end, OPTION_T2, 4, ((time * 7)/8) - fuzz);
|
||||
}
|
||||
p = do_req_options(context, p, end, req_options, daemon,
|
||||
hostname, netid, subnet_addr, fqdn_flags);
|
||||
hostname, netid, subnet_addr, fqdn_flags, borken_opt);
|
||||
}
|
||||
|
||||
p = option_end(p, end, mess);
|
||||
@@ -735,7 +748,7 @@ int dhcp_reply(struct daemon *daemon, struct dhcp_context *context, char *iface_
|
||||
if (ignore || have_config(config, CONFIG_DISABLE))
|
||||
message = _("ignored");
|
||||
|
||||
log_packet("INFORM", &mess->ciaddr, chaddr, iface_name, message);
|
||||
log_packet("INFORM", &mess->ciaddr, mess->chaddr, mess->hlen, iface_name, message);
|
||||
|
||||
if (message || mess->ciaddr.s_addr == 0 ||
|
||||
!(context = narrow_context(context, mess->ciaddr)))
|
||||
@@ -754,31 +767,34 @@ int dhcp_reply(struct daemon *daemon, struct dhcp_context *context, char *iface_
|
||||
if (!hostname)
|
||||
hostname = host_from_dns(daemon, mess->yiaddr);
|
||||
p = do_req_options(context, p, end, req_options, daemon,
|
||||
hostname, netid, subnet_addr, fqdn_flags);
|
||||
hostname, netid, subnet_addr, fqdn_flags, borken_opt);
|
||||
p = option_end(p, end, mess);
|
||||
|
||||
log_packet("ACK", &mess->ciaddr, chaddr, iface_name, hostname);
|
||||
log_packet("ACK", &mess->ciaddr, mess->chaddr, mess->hlen, iface_name, hostname);
|
||||
return p - (unsigned char *)mess;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void log_packet(char *type, struct in_addr *addr, unsigned char *hwaddr, char *interface, char *string)
|
||||
static void log_packet(char *type, struct in_addr *addr, unsigned char *hwaddr, int hw_len, char *interface, char *string)
|
||||
{
|
||||
u8 empty[] = { 0, 0, 0, 0, 0, 0};
|
||||
char buff[(DHCP_CHADDR_MAX * 3) + 1];
|
||||
char *p = buff;
|
||||
int i;
|
||||
|
||||
if (!hwaddr)
|
||||
hwaddr = empty;
|
||||
|
||||
syslog(LOG_INFO, "%s%s(%s)%s%s %.2x:%.2x:%.2x:%.2x:%.2x:%.2x%s%s",
|
||||
*buff = 0;
|
||||
for (i = 0; i < hw_len - 1; i++)
|
||||
p += sprintf(p, "%.2x:", hwaddr[i]);
|
||||
p += sprintf(p, "%.2x ", hwaddr[i]);
|
||||
|
||||
syslog(LOG_INFO, "%s%s(%s) %s%s%s%s",
|
||||
type ? "DHCP" : "BOOTP",
|
||||
type ? type : "",
|
||||
interface,
|
||||
addr ? " " : "",
|
||||
addr ? inet_ntoa(*addr) : "",
|
||||
hwaddr[0], hwaddr[1], hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5],
|
||||
string ? " " : "",
|
||||
addr ? " " : "",
|
||||
buff,
|
||||
string ? string : "");
|
||||
}
|
||||
|
||||
@@ -822,12 +838,12 @@ static void bootp_option_put(struct dhcp_packet *mess,
|
||||
struct dhcp_boot *tmp;
|
||||
|
||||
for (tmp = boot_opts; tmp; tmp = tmp->next)
|
||||
if (match_netid(tmp->netid, netids))
|
||||
if (match_netid(tmp->netid, netids, 0))
|
||||
break;
|
||||
if (!tmp)
|
||||
/* No match, look for one without a netid */
|
||||
for (tmp = boot_opts; tmp; tmp = tmp->next)
|
||||
if (!tmp->netid)
|
||||
if (match_netid(tmp->netid, netids, 1))
|
||||
break;
|
||||
|
||||
/* Do this _after_ the matching above, since in
|
||||
@@ -884,10 +900,14 @@ static unsigned char *option_end(unsigned char *p, unsigned char *end, struct dh
|
||||
return p;
|
||||
}
|
||||
|
||||
static unsigned char *option_put_string(unsigned char *p, unsigned char *end, int opt, char *string)
|
||||
static unsigned char *option_put_string(unsigned char *p, unsigned char *end, int opt,
|
||||
char *string, int null_term)
|
||||
{
|
||||
size_t len = strlen(string);
|
||||
|
||||
if (null_term && len != 255)
|
||||
len++;
|
||||
|
||||
if (check_space(p, end, len, opt))
|
||||
{
|
||||
*(p++) = opt;
|
||||
@@ -935,7 +955,7 @@ static unsigned char *option_find1(unsigned char *p, unsigned char *end, int opt
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static unsigned char *option_find(struct dhcp_packet *mess, int size, int opt_type, int minsize)
|
||||
static unsigned char *option_find(struct dhcp_packet *mess, size_t size, int opt_type, int minsize)
|
||||
{
|
||||
int overload = 0;
|
||||
unsigned char *ret;
|
||||
@@ -976,31 +996,30 @@ static struct dhcp_opt *option_find2(struct dhcp_netid *netid, struct dhcp_opt *
|
||||
struct dhcp_opt *tmp;
|
||||
for (tmp = opts; tmp; tmp = tmp->next)
|
||||
if (tmp->opt == opt)
|
||||
{
|
||||
if (netid)
|
||||
{
|
||||
if (match_netid(tmp->netid, netid))
|
||||
return tmp;
|
||||
}
|
||||
else if (!tmp->netid)
|
||||
return tmp;
|
||||
}
|
||||
if (match_netid(tmp->netid, netid, 1) || match_netid(tmp->netid, netid, 0))
|
||||
return tmp;
|
||||
|
||||
return netid ? option_find2(NULL, opts, opt) : NULL;
|
||||
}
|
||||
|
||||
static unsigned char *do_opt(struct dhcp_opt *opt, unsigned char *p, unsigned char *end, struct in_addr local)
|
||||
static unsigned char *do_opt(struct dhcp_opt *opt, unsigned char *p, unsigned char *end,
|
||||
struct in_addr local, int null_term)
|
||||
{
|
||||
if (!check_space(p, end, opt->len, opt->opt))
|
||||
int len = opt->len;
|
||||
|
||||
if ((opt->flags & DHOPT_STRING) && null_term && len != 255)
|
||||
len++;
|
||||
|
||||
if (!check_space(p, end, len, opt->opt))
|
||||
return p;
|
||||
|
||||
*(p++) = opt->opt;
|
||||
*(p++) = opt->len;
|
||||
*(p++) = len;
|
||||
|
||||
if (opt->len == 0)
|
||||
if (len == 0)
|
||||
return p;
|
||||
|
||||
if (opt->is_addr && !opt->vendor_class)
|
||||
if (opt->flags & DHOPT_ADDR)
|
||||
{
|
||||
int j;
|
||||
struct in_addr *a = (struct in_addr *)opt->val;
|
||||
@@ -1016,8 +1035,8 @@ static unsigned char *do_opt(struct dhcp_opt *opt, unsigned char *p, unsigned ch
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(p, opt->val, opt->len);
|
||||
p += opt->len;
|
||||
memcpy(p, opt->val, len);
|
||||
p += len;
|
||||
}
|
||||
|
||||
return p;
|
||||
@@ -1030,7 +1049,8 @@ static unsigned char *do_req_options(struct dhcp_context *context,
|
||||
char *hostname,
|
||||
struct dhcp_netid *netid,
|
||||
struct in_addr subnet_addr,
|
||||
unsigned char fqdn_flags)
|
||||
unsigned char fqdn_flags,
|
||||
int null_term)
|
||||
{
|
||||
struct dhcp_opt *opt, *config_opts = daemon->dhcp_opts;
|
||||
char *vendor_class = NULL;
|
||||
@@ -1066,7 +1086,7 @@ static unsigned char *do_req_options(struct dhcp_context *context,
|
||||
|
||||
if (daemon->domain_suffix && in_list(req_options, OPTION_DOMAINNAME) &&
|
||||
!option_find2(netid, config_opts, OPTION_DOMAINNAME))
|
||||
p = option_put_string(p, end, OPTION_DOMAINNAME, daemon->domain_suffix);
|
||||
p = option_put_string(p, end, OPTION_DOMAINNAME, daemon->domain_suffix, null_term);
|
||||
|
||||
/* Note that we ignore attempts to set the hostname using
|
||||
--dhcp-option=12,<name> and the fqdn using
|
||||
@@ -1074,14 +1094,16 @@ static unsigned char *do_req_options(struct dhcp_context *context,
|
||||
if (hostname)
|
||||
{
|
||||
if (in_list(req_options, OPTION_HOSTNAME))
|
||||
p = option_put_string(p, end, OPTION_HOSTNAME, hostname);
|
||||
p = option_put_string(p, end, OPTION_HOSTNAME, hostname, null_term);
|
||||
|
||||
if (fqdn_flags != 0)
|
||||
{
|
||||
int len = strlen(hostname) + 3;
|
||||
if (fqdn_flags & 0x04)
|
||||
len += 2;
|
||||
|
||||
else if (null_term)
|
||||
len++;
|
||||
|
||||
if (daemon->domain_suffix)
|
||||
len += strlen(daemon->domain_suffix) + 1;
|
||||
|
||||
@@ -1109,7 +1131,9 @@ static unsigned char *do_req_options(struct dhcp_context *context,
|
||||
*(p++) = '.';
|
||||
memcpy(p, daemon->domain_suffix, strlen(daemon->domain_suffix));
|
||||
p += strlen(daemon->domain_suffix);
|
||||
}
|
||||
}
|
||||
if (null_term)
|
||||
*(p++) = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1138,13 +1162,13 @@ static unsigned char *do_req_options(struct dhcp_context *context,
|
||||
if (opt->opt == OPTION_VENDOR_ID)
|
||||
vendor_class = (char *)opt->val;
|
||||
else
|
||||
p = do_opt(opt, p, end, context->local);
|
||||
p = do_opt(opt, p, end, context->local, null_term);
|
||||
}
|
||||
|
||||
if (in_list(req_options, OPTION_VENDOR_ID))
|
||||
{
|
||||
for (opt = daemon->vendor_opts; opt; opt = opt->next)
|
||||
if (!opt->netid || match_netid(opt->netid, netid))
|
||||
if (match_netid(opt->netid, netid, 1) || match_netid(opt->netid, netid, 0))
|
||||
{
|
||||
if (vendor_class && strcmp(vendor_class, (char *)opt->vendor_class) != 0)
|
||||
syslog(LOG_WARNING, _("More than one vendor class matches, using %s"), vendor_class);
|
||||
@@ -1154,7 +1178,7 @@ static unsigned char *do_req_options(struct dhcp_context *context,
|
||||
|
||||
if (vendor_class)
|
||||
{
|
||||
p = option_put_string(p, end, OPTION_VENDOR_ID, vendor_class);
|
||||
p = option_put_string(p, end, OPTION_VENDOR_ID, vendor_class, 0);
|
||||
|
||||
if (in_list(req_options, OPTION_VENDOR_CLASS_OPT))
|
||||
{
|
||||
@@ -1172,9 +1196,9 @@ static unsigned char *do_req_options(struct dhcp_context *context,
|
||||
plen = p++; /* fill in later */
|
||||
|
||||
for (opt = daemon->vendor_opts; opt; opt = opt->next)
|
||||
if ((!opt->netid || match_netid(opt->netid, netid)) &&
|
||||
if ((match_netid(opt->netid, netid, 1) || match_netid(opt->netid, netid, 0)) &&
|
||||
strcmp(vendor_class, (char *)opt->vendor_class) == 0)
|
||||
p = do_opt(opt, p, oend, context->local);
|
||||
p = do_opt(opt, p, oend, context->local, null_term);
|
||||
|
||||
*plen = p - plen - 1;
|
||||
}
|
||||
|
||||
30
src/util.c
30
src/util.c
@@ -319,25 +319,39 @@ void prettyprint_time(char *buf, unsigned int t)
|
||||
|
||||
|
||||
/* in may equal out, when maxlen may be -1 (No max len). */
|
||||
int parse_hex(char *in, unsigned char *out, int maxlen, unsigned int *wildcard_mask)
|
||||
int parse_hex(char *in, unsigned char *out, int maxlen,
|
||||
unsigned int *wildcard_mask, int *mac_type)
|
||||
{
|
||||
int mask = 0, i = 0;
|
||||
char *r;
|
||||
|
||||
|
||||
if (mac_type)
|
||||
*mac_type = 0;
|
||||
|
||||
while (maxlen == -1 || i < maxlen)
|
||||
{
|
||||
for (r = in; *r != 0 && *r != ':' && *r != '-'; r++);
|
||||
if (*r == 0)
|
||||
maxlen = i;
|
||||
|
||||
if (r != in )
|
||||
{
|
||||
*r = 0;
|
||||
mask = mask << 1;
|
||||
if (strcmp(in, "*") == 0)
|
||||
mask |= 1;
|
||||
if (*r == '-' && i == 0 && mac_type)
|
||||
{
|
||||
*r = 0;
|
||||
*mac_type = strtol(in, NULL, 16);
|
||||
mac_type = NULL;
|
||||
}
|
||||
else
|
||||
out[i] = strtol(in, NULL, 16);
|
||||
i++;
|
||||
{
|
||||
*r = 0;
|
||||
mask = mask << 1;
|
||||
if (strcmp(in, "*") == 0)
|
||||
mask |= 1;
|
||||
else
|
||||
out[i] = strtol(in, NULL, 16);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
in = r+1;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user