import of dnsmasq-2.11.tar.gz

This commit is contained in:
Simon Kelley
2004-08-02 18:27:27 +01:00
parent feba5c1d25
commit dfa666f24b
11 changed files with 110 additions and 52 deletions

View File

@@ -1123,4 +1123,23 @@ release 2.10
support was added. Thanks to Michael Hamilton for support was added. Thanks to Michael Hamilton for
assistance with this. assistance with this.
version 2.11
Fixed DHCP problem which could result in two leases in the
database with the same address. This looked much more
alarming then it was, since it could only happen when a
machine changes MAC address but kept the same name. The
old lease would persist until it timed out but things
would still work OK.
Check that IP addresses in all dhcp-host directives are
unique and die horribly if they are not, since otherwise
endless protocol loops can occur.
Use IPV6_RECVPKTINFO as socket option rather than
IPV6_PKTINFO where available. This keeps late-model FreeBSD
happy.
Set source interface when replying to IPv6 UDP
queries. This is needed to cope with link-local addresses.

View File

@@ -5,7 +5,7 @@
############################################################################### ###############################################################################
Name: dnsmasq Name: dnsmasq
Version: 2.10 Version: 2.11
Release: 1 Release: 1
Copyright: GPL Copyright: GPL
Group: System Environment/Daemons Group: System Environment/Daemons

View File

@@ -5,7 +5,7 @@
############################################################################### ###############################################################################
Name: dnsmasq Name: dnsmasq
Version: 2.10 Version: 2.11
Release: 1 Release: 1
Copyright: GPL Copyright: GPL
Group: Productivity/Networking/DNS/Servers Group: Productivity/Networking/DNS/Servers

View File

@@ -112,7 +112,9 @@ bzip2 dnsmasq-zzz.tar
</PRE> </PRE>
<H2>Links.</H2> <H2>Links.</H2>
Ulrich Ivens has a nice HOWTO in German on installing dnsmasq at <A HREF="http://howto.linux-hardware-shop.de/dnsmasq.html">http://howto.linux-hardware-shop.de/dnsmasq.html</A> Ulrich Ivens has a nice HOWTO in German on installing dnsmasq at <A
HREF="http://howto.linux-hardware-shop.de/dnsmasq.html">http://howto.linux-hardware-shop.de/dnsmasq.html</A>
and Damien Raude-Morvan has one in French at <A HREF="http://www.drazzib.com/docs-dnsmasq.html">http://www.drazzib.com/docs-dnsmasq.html</A>
<H2>License.</H2> <H2>License.</H2>
Dnsmasq is distributed under the GPL. See the file COPYING in the distribution Dnsmasq is distributed under the GPL. See the file COPYING in the distribution

View File

@@ -12,7 +12,7 @@
/* Author's email: simon@thekelleys.org.uk */ /* Author's email: simon@thekelleys.org.uk */
#define VERSION "2.10" #define VERSION "2.11"
#define FTABSIZ 150 /* max number of outstanding requests */ #define FTABSIZ 150 /* max number of outstanding requests */
#define MAX_PROCS 20 /* max no children for TCP requests */ #define MAX_PROCS 20 /* max no children for TCP requests */

View File

@@ -14,12 +14,13 @@
#include "dnsmasq.h" #include "dnsmasq.h"
void dhcp_init(int *fdp, int* rfdp) void dhcp_init(int *fdp, int* rfdp, struct dhcp_config *configs)
{ {
int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
struct sockaddr_in saddr; struct sockaddr_in saddr;
int opt = 1; int opt = 1;
struct dhcp_config *cp;
if (fd == -1) if (fd == -1)
die ("cannot create DHCP socket : %s", NULL); die ("cannot create DHCP socket : %s", NULL);
@@ -57,6 +58,14 @@ void dhcp_init(int *fdp, int* rfdp)
#endif #endif
*rfdp = fd; *rfdp = fd;
/* If the same IP appears in more than one host config, then DISCOVER
for one of the hosts will get the address, but REQUEST will be NAKed,
since the address is reserved by the other one -> protocol loop. */
for (; configs; configs = configs->next)
for (cp = configs->next; cp; cp = cp->next)
if ((configs->flags & cp->flags & CONFIG_ADDR) && configs->addr.s_addr == cp->addr.s_addr)
die("Duplicate IP address %s in dhcp-config directive.", inet_ntoa(cp->addr));
} }
void dhcp_packet(struct dhcp_context *contexts, char *packet, void dhcp_packet(struct dhcp_context *contexts, char *packet,
@@ -370,6 +379,17 @@ int address_available(struct dhcp_context *context, struct in_addr taddr)
return 1; return 1;
} }
struct dhcp_config *config_find_by_address(struct dhcp_config *configs, struct in_addr addr)
{
struct dhcp_config *config;
for (config = configs; config; config = config->next)
if ((config->flags & CONFIG_ADDR) && config->addr.s_addr == addr.s_addr)
return config;
return NULL;
}
int address_allocate(struct dhcp_context *context, struct dhcp_config *configs, int address_allocate(struct dhcp_context *context, struct dhcp_config *configs,
struct in_addr *addrp, unsigned char *hwaddr) struct in_addr *addrp, unsigned char *hwaddr)
@@ -377,7 +397,6 @@ int address_allocate(struct dhcp_context *context, struct dhcp_config *configs,
/* Find a free address: exclude anything in use and anything allocated to /* Find a free address: exclude anything in use and anything allocated to
a particular hwaddr/clientid/hostname in our configuration */ a particular hwaddr/clientid/hostname in our configuration */
struct dhcp_config *config;
struct in_addr start, addr ; struct in_addr start, addr ;
unsigned int i, j; unsigned int i, j;
@@ -400,17 +419,10 @@ int address_allocate(struct dhcp_context *context, struct dhcp_config *configs,
addr.s_addr = htonl(ntohl(addr.s_addr) + 1); addr.s_addr = htonl(ntohl(addr.s_addr) + 1);
if (!lease_find_by_addr(addr)) if (!lease_find_by_addr(addr) && !config_find_by_address(configs, addr))
{ {
for (config = configs; config; config = config->next) *addrp = addr;
if ((config->flags & CONFIG_ADDR) && config->addr.s_addr == addr.s_addr) return 1;
break;
if (!config)
{
*addrp = addr;
return 1;
}
} }
} while (addr.s_addr != start.s_addr); } while (addr.s_addr != start.s_addr);

View File

@@ -206,7 +206,7 @@ int main (int argc, char **argv)
if (c != 1) if (c != 1)
die("must set exactly one interface on broken systems without IP_RECVIF", NULL); die("must set exactly one interface on broken systems without IP_RECVIF", NULL);
#endif #endif
dhcp_init(&dhcpfd, &dhcp_raw_fd); dhcp_init(&dhcpfd, &dhcp_raw_fd, dhcp_configs);
leasefd = lease_init(lease_file, domain_suffix, dnamebuff, packet, now, maxleases); leasefd = lease_init(lease_file, domain_suffix, dnamebuff, packet, now, maxleases);
} }

View File

@@ -230,6 +230,7 @@ struct frec {
union mysockaddr source; union mysockaddr source;
struct all_addr dest; struct all_addr dest;
struct server *sentto; struct server *sentto;
unsigned int iface;
unsigned short orig_id, new_id; unsigned short orig_id, new_id;
int fd; int fd;
time_t time; time_t time;
@@ -412,7 +413,7 @@ struct irec *enumerate_interfaces(struct iname **names,
struct listener *create_wildcard_listeners(int port); struct listener *create_wildcard_listeners(int port);
struct listener *create_bound_listeners(struct irec *interfaces, int port); struct listener *create_bound_listeners(struct irec *interfaces, int port);
/* dhcp.c */ /* dhcp.c */
void dhcp_init(int *fdp, int* rfdp); void dhcp_init(int *fdp, int* rfdp, struct dhcp_config *configs);
void dhcp_packet(struct dhcp_context *contexts, char *packet, void dhcp_packet(struct dhcp_context *contexts, char *packet,
struct dhcp_opt *dhcp_opts, struct dhcp_config *dhcp_configs, struct dhcp_opt *dhcp_opts, struct dhcp_config *dhcp_configs,
struct dhcp_vendor *vendors, struct dhcp_vendor *vendors,
@@ -430,7 +431,7 @@ struct dhcp_config *find_config(struct dhcp_config *configs,
struct dhcp_config *read_ethers(struct dhcp_config *configs, char *buff); struct dhcp_config *read_ethers(struct dhcp_config *configs, char *buff);
void dhcp_update_configs(struct dhcp_config *configs); void dhcp_update_configs(struct dhcp_config *configs);
struct dhcp_config *dhcp_read_ethers(struct dhcp_config *configs, char *buff); struct dhcp_config *dhcp_read_ethers(struct dhcp_config *configs, char *buff);
struct dhcp_config *config_find_by_address(struct dhcp_config *configs, struct in_addr addr);
/* lease.c */ /* lease.c */
void lease_update_file(int force, time_t now); void lease_update_file(int force, time_t now);
void lease_update_dns(void); void lease_update_dns(void);

View File

@@ -36,7 +36,8 @@ void forward_init(int first)
/* Send a UDP packet with it's source address set as "source" /* 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 */ 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, int len,
union mysockaddr *to, struct all_addr *source) union mysockaddr *to, struct all_addr *source,
unsigned int iface)
{ {
struct msghdr msg; struct msghdr msg;
struct iovec iov[1]; struct iovec iov[1];
@@ -94,7 +95,7 @@ static void send_from(int fd, int nowild, char *packet, int len,
{ {
struct cmsghdr *cmptr = CMSG_FIRSTHDR(&msg); struct cmsghdr *cmptr = CMSG_FIRSTHDR(&msg);
struct in6_pktinfo *pkt = (struct in6_pktinfo *)CMSG_DATA(cmptr); struct in6_pktinfo *pkt = (struct in6_pktinfo *)CMSG_DATA(cmptr);
pkt->ipi6_ifindex = 0; pkt->ipi6_ifindex = iface; /* Need iface for IPv6 to handle link-local addrs */
pkt->ipi6_addr = source->addr.addr6; pkt->ipi6_addr = source->addr.addr6;
msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
cmptr->cmsg_type = IPV6_PKTINFO; cmptr->cmsg_type = IPV6_PKTINFO;
@@ -191,8 +192,8 @@ unsigned short search_servers(struct server *servers, unsigned int options, stru
/* returns new last_server */ /* returns new last_server */
static struct server *forward_query(int udpfd, union mysockaddr *udpaddr, static struct server *forward_query(int udpfd, union mysockaddr *udpaddr,
struct all_addr *dst_addr, HEADER *header, struct all_addr *dst_addr, unsigned int dst_iface,
int plen, unsigned int options, char *dnamebuff, HEADER *header, int plen, unsigned int options, char *dnamebuff,
struct server *servers, struct server *last_server, struct server *servers, struct server *last_server,
time_t now, unsigned long local_ttl) time_t now, unsigned long local_ttl)
{ {
@@ -246,6 +247,7 @@ static struct server *forward_query(int udpfd, union mysockaddr *udpaddr,
forward->source = *udpaddr; forward->source = *udpaddr;
forward->dest = *dst_addr; forward->dest = *dst_addr;
forward->iface = dst_iface;
forward->new_id = get_id(); forward->new_id = get_id();
forward->fd = udpfd; forward->fd = udpfd;
forward->orig_id = ntohs(header->id); forward->orig_id = ntohs(header->id);
@@ -310,7 +312,7 @@ static struct server *forward_query(int udpfd, union mysockaddr *udpaddr,
/* could not send on, return empty answer or address if known for whole domain */ /* could not send on, return empty answer or address if known for whole domain */
plen = setup_reply(header, (unsigned int)plen, addrp, flags, local_ttl); plen = setup_reply(header, (unsigned int)plen, addrp, flags, local_ttl);
send_from(udpfd, options & OPT_NOWILD, (char *)header, plen, udpaddr, dst_addr); send_from(udpfd, options & OPT_NOWILD, (char *)header, plen, udpaddr, dst_addr, dst_iface);
return last_server; return last_server;
} }
@@ -405,7 +407,7 @@ struct server *reply_query(struct serverfd *sfd, int options, char *packet, time
return NULL; return NULL;
header->id = htons(forward->orig_id); header->id = htons(forward->orig_id);
send_from(forward->fd, options & OPT_NOWILD, packet, n, &forward->source, &forward->dest); send_from(forward->fd, options & OPT_NOWILD, packet, n, &forward->source, &forward->dest, forward->iface);
forward->new_id = 0; /* cancel */ forward->new_id = 0; /* cancel */
} }
@@ -564,9 +566,9 @@ struct server *receive_query(struct listener *listen, char *packet, struct mx_re
m = answer_request (header, ((char *) header) + PACKETSZ, (unsigned int)n, m = answer_request (header, ((char *) header) + PACKETSZ, (unsigned int)n,
mxnames, mxtarget, options, now, local_ttl, namebuff, edns_pcktsz); mxnames, mxtarget, options, now, local_ttl, namebuff, edns_pcktsz);
if (m >= 1) if (m >= 1)
send_from(listen->fd, options & OPT_NOWILD, (char *)header, m, &source_addr, &dst_addr); send_from(listen->fd, options & OPT_NOWILD, (char *)header, m, &source_addr, &dst_addr, if_index);
else else
last_server = forward_query(listen->fd, &source_addr, &dst_addr, last_server = forward_query(listen->fd, &source_addr, &dst_addr, if_index,
header, n, options, namebuff, servers, header, n, options, namebuff, servers,
last_server, now, local_ttl); last_server, now, local_ttl);
return last_server; return last_server;

View File

@@ -263,7 +263,11 @@ static int create_ipv6_listener(struct listener **link, int port)
setsockopt(tcpfd, IPV6_LEVEL, IPV6_V6ONLY, &opt, sizeof(opt)) == -1 || setsockopt(tcpfd, IPV6_LEVEL, IPV6_V6ONLY, &opt, sizeof(opt)) == -1 ||
(flags = fcntl(tcpfd, F_GETFL, 0)) == -1 || (flags = fcntl(tcpfd, F_GETFL, 0)) == -1 ||
fcntl(tcpfd, F_SETFL, flags | O_NONBLOCK) == -1 || fcntl(tcpfd, F_SETFL, flags | O_NONBLOCK) == -1 ||
#ifdef IPV6_RECVPKTINFO
setsockopt(fd, IPV6_LEVEL, IPV6_RECVPKTINFO, &opt, sizeof(opt)) == -1 ||
#else
setsockopt(fd, IPV6_LEVEL, IPV6_PKTINFO, &opt, sizeof(opt)) == -1 || setsockopt(fd, IPV6_LEVEL, IPV6_PKTINFO, &opt, sizeof(opt)) == -1 ||
#endif
bind(tcpfd, (struct sockaddr *)&addr, sa_len(&addr)) == -1 || bind(tcpfd, (struct sockaddr *)&addr, sa_len(&addr)) == -1 ||
listen(tcpfd, 5) == -1 || listen(tcpfd, 5) == -1 ||
bind(fd, (struct sockaddr *)&addr, sa_len(&addr)) == -1) bind(fd, (struct sockaddr *)&addr, sa_len(&addr)) == -1)

View File

@@ -152,8 +152,9 @@ int dhcp_reply(struct dhcp_context *context,
clid_len = 0; clid_len = 0;
} }
if ((config = find_config(dhcp_configs, context, clid, clid_len, mess->chaddr, NULL)) && config = find_config(dhcp_configs, context, clid, clid_len, mess->chaddr, NULL);
have_config(config, CONFIG_NAME))
if (have_config(config, CONFIG_NAME))
hostname = config->hostname; hostname = config->hostname;
else if ((opt = option_find(mess, sz, OPTION_HOSTNAME))) else if ((opt = option_find(mess, sz, OPTION_HOSTNAME)))
{ {
@@ -184,8 +185,16 @@ int dhcp_reply(struct dhcp_context *context,
hostname = NULL; /* nothing left */ hostname = NULL; /* nothing left */
} }
} }
/* search again now we have a hostname */
config = find_config(dhcp_configs, context, clid, clid_len, mess->chaddr, hostname); /* Search again now we have a hostname.
Only accept configs without CLID and HWADDR here, (they won't match)
to avoid impersonation by name. */
if (!config)
{
struct dhcp_config *new = find_config(dhcp_configs, context, NULL, 0, mess->chaddr, hostname);
if (!have_config(new, CONFIG_CLID) && !have_config(new, CONFIG_HWADDR))
config = new;
}
} }
} }
@@ -347,7 +356,8 @@ int dhcp_reply(struct dhcp_context *context,
mess->yiaddr = config->addr; mess->yiaddr = config->addr;
else if (lease && address_available(context, lease->addr)) else if (lease && address_available(context, lease->addr))
mess->yiaddr = lease->addr; mess->yiaddr = lease->addr;
else if (opt && address_available(context, addr) && !lease_find_by_addr(addr)) else if (opt && address_available(context, addr) && !lease_find_by_addr(addr) &&
!config_find_by_address(dhcp_configs, addr))
mess->yiaddr = addr; mess->yiaddr = addr;
else if (!address_allocate(context, dhcp_configs, &mess->yiaddr, mess->chaddr)) else if (!address_allocate(context, dhcp_configs, &mess->yiaddr, mess->chaddr))
message = "no address available"; message = "no address available";
@@ -400,12 +410,11 @@ int dhcp_reply(struct dhcp_context *context,
if (!lease) if (!lease)
{ {
if ((!address_available(context, mess->yiaddr) || lease_find_by_addr(mess->yiaddr)) && if (lease_find_by_addr(mess->yiaddr))
(!have_config(config, CONFIG_ADDR) || config->addr.s_addr != mess->yiaddr.s_addr)) message = "address in use";
message = "address unavailable";
else if (!(lease = lease_allocate(clid, clid_len, mess->yiaddr))) else if (!(lease = lease_allocate(clid, clid_len, mess->yiaddr)))
message = "no leases left"; message = "no leases left";
} }
} }
else else
{ {
@@ -424,29 +433,38 @@ int dhcp_reply(struct dhcp_context *context,
fuzz = fuzz/2; fuzz = fuzz/2;
} }
/* If a machine moves networks whilst it has a lease, we catch that here. */ if (!message)
if (!message && !is_same_net(mess->yiaddr, context->start, context->netmask)) {
message = "wrong network"; struct dhcp_config *addr_config;
/* If a machine moves networks whilst it has a lease, we catch that here. */
if (!is_same_net(mess->yiaddr, context->start, context->netmask))
message = "wrong network";
/* Check for renewal of a lease which is now outside the allowed range. */ /* Check for renewal of a lease which is now outside the allowed range. */
if (!message && !address_available(context, mess->yiaddr) && else if (!address_available(context, mess->yiaddr) &&
(!have_config(config, CONFIG_ADDR) || config->addr.s_addr != mess->yiaddr.s_addr)) (!have_config(config, CONFIG_ADDR) || config->addr.s_addr != mess->yiaddr.s_addr))
message = "address no longer available"; message = "address no longer available";
/* Check if a new static address has been configured. Be very sure that
when the client does DISCOVER, it will get the static address, otherwise
an endless protocol loop will ensue. */
else if (have_config(config, CONFIG_ADDR) && !lease_find_by_addr(config->addr))
message = "static lease available";
/* Check to see if the address is reserved as a static address for another host */
else if ((addr_config = config_find_by_address(dhcp_configs, mess->yiaddr)) && addr_config != config)
message ="address reserved";
}
/* Check if a new static address has been configured. Be very sure that
when the client does DISCOVER, it will get the static address, otherwise
an endless protocol loop will ensue. */
if (!message && have_config(config, CONFIG_ADDR) &&
!have_config(config, CONFIG_DISABLE) &&
!lease_find_by_addr(config->addr))
message = "static lease available";
log_packet("REQUEST", &mess->yiaddr, mess->chaddr, iface_name, NULL); log_packet("REQUEST", &mess->yiaddr, mess->chaddr, iface_name, NULL);
if (message) if (message)
{ {
log_packet("NAK", &mess->yiaddr, mess->chaddr, iface_name, message); log_packet("NAK", &mess->yiaddr, mess->chaddr, iface_name, message);
lease_prune(lease, now);
mess->siaddr.s_addr = mess->yiaddr.s_addr = mess->ciaddr.s_addr = 0; mess->siaddr.s_addr = mess->yiaddr.s_addr = mess->ciaddr.s_addr = 0;
bootp_option_put(mess, NULL, NULL); bootp_option_put(mess, NULL, NULL);
p = option_put(p, end, OPTION_MESSAGE_TYPE, 1, DHCPNAK); p = option_put(p, end, OPTION_MESSAGE_TYPE, 1, DHCPNAK);