import of dnsmasq-2.27.tar.gz

This commit is contained in:
Simon Kelley
2006-03-16 20:16:06 +00:00
parent aedef83058
commit cdeda28f82
27 changed files with 2427 additions and 1966 deletions

View File

@@ -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))

View File

@@ -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 */

View File

@@ -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++;
}

View File

@@ -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);
}
}

View File

@@ -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 */

View File

@@ -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 */

View File

@@ -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

View File

@@ -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

View File

@@ -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)
{

View File

@@ -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 *)&in;
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':
{

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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;
}