Commit 5e9e0efb authored by Simon Kelley's avatar Simon Kelley

import of dnsmasq-2.28.tar.gz

parent cdeda28f
......@@ -1694,3 +1694,94 @@ version 2.27
Generalised the DHCP code to cope with any hardware
address type, at least on Linux. *BSD is still limited to
ethernet only.
version 2.28
Eliminated all raw network access when running on
Linux. All DHCP network activity now goes through the IP
stack. Packet sockets are no longer required. Apart from
being a neat hack, this should also allow DHCP over IPsec
to work better. On *BSD and OS X, the old method of raw net
access through BPF is retained.
Simplified build options. Networking is now slimmed down
to a choice of "linux" or "other". Netlink is always used
under Linux. Since netlink has been available since 2.2
and non-optional in an IPv4-configured kernel since 2.4,
and the dnsmasq netlink code is now well tested, this
should work out fine.
Removed decayed build support for libc5 and Solaris.
Removed pselect code: use a pipe for race-free signal
handling instead, as this works everywhere.
No longer enable the ISC leasefile reading code in the
distributed sources. I doubt there are many people left
using this 1.x compatibility code. Those that are will
have to explicitly enable it in src/config.h.
Don't send the "DHCP maximum message size" option, even if
requested. RFC2131 says this is a "MUST NOT".
Support larger-than-minimum DHCP message. Dnsmasq is now
happy to get larger than 576-byte DHCP messages, and will
return large messages, if permitted by the "maximum
message size" option of the message to which it is
replying. There's now an arbitrary sanity limit of 16384
bytes.
Added --no-ping option. This fixes an RFC2131 "SHOULD".
Building on the 2.27 MAC-address changes, allow clients to
provide no MAC address at all, relying on the client-id as
a unique identifier. This should make things like DHCP for
USB come easier.
Fixed regression in netlink code under 2.2.x kernels which
occurred in 2.27. Erik Jan Tromp is the vintage kernel fan
who found this. P.S. It looks like this "netlink bind:
permission denied" problem occured in kernels at least as
late a 2.4.18. Good information from Alain Richoux.
Added a warning when it's impossible to give a host its
configured address because the address is leased
elsewhere. A sensible suggestion from Mircea Bardac.
Added minimal support for RFC 3046 DHCP relay agent-id
options. The DHCP server now echoes these back to the
relay, as required by the RFC. Also, RFC 3527 link selection
sub-options are honoured.
Set the process "dumpable" flag when running in debug
mode: this makes getting core dumps from root processes
much easier.
Fixed one-byte buffer overflow which seems to only cause
problems when dnsmasq is linked with uclibc. Thanks to
Eric House and Eric Spakman for help in chasing this down.
Tolerate configuration screwups which lead to the DHCP
server attemping to allocate its own address to a
client; eg setting the whole subnet range as a DHCP
range. Addresses in use by the server are now excluded
from use by clients.
Did some thinking about HAVE_BROKEN_RTC mode, and made it
much simpler and better. The key is to just keep lease
lengths in the lease file. Since these normally never
change, even as the lease is renewed, the lease file never
needs to change except when machines arrive on the network
or leave. This eliminates the code for timed writes, and
reduces the amount of wear on a flash filesystem to the
absolute minimum. Also re-did the basic time function in
this mode to use the portable times(), rather than parsing
/proc/uptime.
Believe the source port number when replying to unicast
DHCP requests and DHCP requests via a relay, instead of always
using the standard ports. This will allow relays on
non-standard ports and DHCPINFORM from unprivileged ports
to work. The source port sent by unconfigured clients is still
ignored, since this may be unreliable. This means that a DHCP
client must use the standard port to do full configuration.
......@@ -369,6 +369,12 @@ A: Yes, dynmaically allocated IP addresses are checked by sending an
other DHCP requests during this time. To avoid dropping requests,
the address probe may be skipped when dnsmasq is under heavy load.
Q: I'm using dnsmasq on a machine with the Firestarter firewall, and
DHCP doesn't work. What's the problem?
A: This a variant on the iptables problem. Explicit details on how to
proceed can be found at
http://lists.thekelleys.org.uk/pipermail/dnsmasq-discuss/2005q3/000431.html
......
# Uncomment this on Solaris.
#LIBS = -lsocket -lnsl
CFLAGS ?= -O2
PKG_CONFIG ?= pkg-config
OBJS = cache.o rfc1035.o util.o option.o forward.o isc.o network.o \
dnsmasq.o dhcp.o lease.o rfc2131.o netlink.o dbus.o
dnsmasq.o dhcp.o lease.o rfc2131.o netlink.o dbus.o bpf.o
.c.o:
$(CC) $(CFLAGS) $(I18N) `../bld/pkg-wrapper $(PKG_CONFIG) --cflags dbus-1` $(RPM_OPT_FLAGS) -Wall -W -c $<
......
......@@ -5,7 +5,7 @@
###############################################################################
Name: dnsmasq
Version: 2.27
Version: 2.28
Release: 1
License: GPL
Group: System Environment/Daemons
......
......@@ -5,7 +5,7 @@
###############################################################################
Name: dnsmasq
Version: 2.27
Version: 2.28
Release: 1
Copyright: GPL
Group: Productivity/Networking/DNS/Servers
......
......@@ -525,6 +525,13 @@ with care, since each address allocated to a BOOTP client is leased
forever, and therefore becomes permanently unavailable for re-use by
other hosts.
.TP
.B \-5, --no-ping
By default, the DHCP server will attempt to ensure that an address in
not in use before allocating it to a host. It does this by sending an
ICMP echo request (aka "ping") to the address in question. If it gets
a reply, then the address must already be in use, and another is
tried. This flag disables this check. Use with caution.
.TP
.B \-l, --dhcp-leasefile=<path>
Use the specified file to store DHCP lease information. If this option
is given but no dhcp-range option is given then dnsmasq version 1
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -20,13 +20,4 @@
#define IP6INTERFACES "/proc/net/if_inet6"
#define UPTIME "/proc/uptime"
#define DHCP_SERVER_PORT 67
@@ -195,8 +195,8 @@
/* platform independent options. */
#undef HAVE_BROKEN_RTC
-#define HAVE_ISC_READER
+#undef HAVE_ISC_READER
#undef HAVE_DBUS
#if defined(HAVE_BROKEN_RTC) && defined(HAVE_ISC_READER)
# error HAVE_ISC_READER is not compatible with HAVE_BROKEN_RTC
/* 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
the Free Software Foundation; version 2 dated June, 1991.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#include "dnsmasq.h"
#ifndef HAVE_LINUX_NETWORK
#include <net/bpf.h>
static struct iovec ifconf = {
.iov_base = NULL,
.iov_len = 0
};
static struct iovec ifreq = {
.iov_base = NULL,
.iov_len = 0
};
struct header {
struct ether_header ether;
struct ip ip;
struct udphdr {
u16 uh_sport; /* source port */
u16 uh_dport; /* destination port */
u16 uh_ulen; /* udp length */
u16 uh_sum; /* udp checksum */
} udp;
};
void init_bpf(struct daemon *daemon)
{
int i = 0;
while (1)
{
/* useful size which happens to be sufficient */
if (expand_buf(&ifreq, sizeof(struct ifreq)))
{
sprintf(ifreq.iov_base, "/dev/bpf%d", i++);
if ((daemon->dhcp_raw_fd = open(ifreq.iov_base, O_RDWR, 0)) != -1)
return;
}
if (errno != EBUSY)
die(_("cannot create DHCP BPF socket: %s"), NULL);
}
}
void send_via_bpf(struct daemon *daemon, struct dhcp_packet *mess, size_t len,
struct in_addr iface_addr, struct ifreq *ifr)
{
/* Hairy stuff, packet either has to go to the
net broadcast or the destination can't reply to ARP yet,
but we do know the physical address.
Build the packet by steam, and send directly, bypassing
the kernel IP stack */
struct header header;
u32 i, sum;
struct iovec iov[2];
/* 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) received on %s"),
mess->htype, ifr->ifr_name);
return;
}
ifr->ifr_addr.sa_family = AF_LINK;
if (ioctl(daemon->dhcpfd, SIOCGIFADDR, ifr) < 0)
return;
memcpy(header.ether.ether_shost, LLADDR((struct sockaddr_dl *)&ifr->ifr_addr), ETHER_ADDR_LEN);
header.ether.ether_type = htons(ETHERTYPE_IP);
if (ntohs(mess->flags) & 0x8000)
{
memset(header.ether.ether_dhost, 255, ETHER_ADDR_LEN);
header.ip.ip_dst.s_addr = INADDR_BROADCAST;
}
else
{
memcpy(header.ether.ether_dhost, mess->chaddr, ETHER_ADDR_LEN);
header.ip.ip_dst.s_addr = mess->yiaddr.s_addr;
}
header.ip.ip_p = IPPROTO_UDP;
header.ip.ip_src.s_addr = iface_addr.s_addr;
header.ip.ip_len = htons(sizeof(struct ip) +
sizeof(struct udphdr) +
len) ;
header.ip.ip_hl = sizeof(struct ip) / 4;
header.ip.ip_v = IPVERSION;
header.ip.ip_tos = 0;
header.ip.ip_id = htons(0);
header.ip.ip_off = htons(0x4000); /* don't fragment */
header.ip.ip_ttl = IPDEFTTL;
header.ip.ip_sum = 0;
for (sum = 0, i = 0; i < sizeof(struct ip) / 2; i++)
sum += ((u16 *)&header.ip)[i];
while (sum>>16)
sum = (sum & 0xffff) + (sum >> 16);
header.ip.ip_sum = (sum == 0xffff) ? sum : ~sum;
header.udp.uh_sport = htons(DHCP_SERVER_PORT);
header.udp.uh_dport = htons(DHCP_CLIENT_PORT);
if (len & 1)
((char *)mess)[len] = 0; /* for checksum, in case length is odd. */
header.udp.uh_sum = 0;
header.udp.uh_ulen = sum = htons(sizeof(struct udphdr) + len);
sum += htons(IPPROTO_UDP);
for (i = 0; i < 4; i++)
sum += ((u16 *)&header.ip.ip_src)[i];
for (i = 0; i < sizeof(struct udphdr)/2; i++)
sum += ((u16 *)&header.udp)[i];
for (i = 0; i < (len + 1) / 2; i++)
sum += ((u16 *)mess)[i];
while (sum>>16)
sum = (sum & 0xffff) + (sum >> 16);
header.udp.uh_sum = (sum == 0xffff) ? sum : ~sum;
ioctl(daemon->dhcp_raw_fd, BIOCSETIF, ifr);
iov[0].iov_base = &header;
iov[0].iov_len = sizeof(struct header);
iov[1].iov_base = mess;
iov[1].iov_len = len;
while (writev(daemon->dhcp_raw_fd, iov, 2) == -1 && retry_send());
}
int iface_enumerate(struct daemon *daemon, void *parm, int (*ipv4_callback)(), int (*ipv6_callback)())
{
char *ptr;
struct ifreq *ifr, ifaux;
struct ifconf ifc;
int fd, errsav, ret = 0;
int lastlen = 0;
size_t len;
if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1)
return 0;
for (len = 0; ; len += 10*sizeof(struct ifreq))
{
if (!expand_buf(&ifconf, len))
goto err;
ifc.ifc_len = len;
ifc.ifc_buf = ifconf.iov_base;
if (ioctl(fd, SIOCGIFCONF, &ifc) == -1)
{
if (errno != EINVAL || lastlen != 0)
goto err;
}
else
{
if (ifc.ifc_len == lastlen)
break; /* got a big enough buffer now */
lastlen = ifc.ifc_len;
}
}
for (ptr = ifc.ifc_buf; ptr < ifc.ifc_buf + ifc.ifc_len; ptr += len )
{
/* subsequent entries may not be aligned, so copy into
an aligned buffer to avoid nasty complaints about
unaligned accesses. */
#ifdef HAVE_SOCKADDR_SA_LEN
len = ((struct ifreq *)ptr)->ifr_addr.sa_len + IF_NAMESIZE;
#else
len = sizeof(struct ifreq);
#endif
if (!expand_buf(&ifreq, len))
goto err;
ifr = ifreq.iov_base;
memcpy(ifr, ptr, len);
strncpy(ifaux.ifr_name, ifr->ifr_name, IF_NAMESIZE);
if (ifr->ifr_addr.sa_family == AF_INET && ipv4_callback)
{
struct in_addr addr, netmask, broadcast;
if (ioctl(fd, SIOCGIFINDEX, &ifaux) == -1)
continue;
broadcast.s_addr = 0;
addr = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr;
if (ioctl(fd, SIOCGIFNETMASK, ifr) == -1)
continue;
netmask = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr;
if (ioctl(fd, SIOCGIFBRDADDR, ifr) != -1)
broadcast = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr;
if (!((*ipv4_callback)(daemon, addr, (int)ifaux.ifr_index, netmask, broadcast, parm)))
goto err;
}
#ifdef HAVE_IPV6
else if (ifr->ifr_addr.sa_family == AF_INET6 && ipv6_callback)
{
struct in6_addr *addr = &((struct sockaddr_in6 *)&ifr->ifr_addr)->sin6_addr;
/* voodoo to clear interface field in address */
if (!(daemon->options & OPT_NOWILD) && IN6_IS_ADDR_LINKLOCAL(addr))
{
addr->s6_addr[2] = 0;
addr->s6_addr[3] = 0;
}
if (ioctl(fd, SIOCGIFINDEX, &ifaux) == -1)
continue;
if (!((*ipv6_callback)(daemon, addr,
(int)((struct sockaddr_in6 *)&ifr->ifr_addr)->sin6_scope_id,
(int)ifaux.ifr_index,
parm)))
goto err;
}
#endif
}
ret = 1;
err:
errsav = errno;
close(fd);
errno = errsav;
return ret;
}
#endif
......@@ -18,6 +18,7 @@ static int cache_inserted, cache_live_freed, insert_error;
static union bigname *big_free;
static int bignames_left, log_queries, cache_size, hash_size;
static int uid;
static char *addrbuff;
static void cache_free(struct crec *crecp);
static void cache_unlink(struct crec *crecp);
......@@ -29,7 +30,11 @@ void cache_init(int size, int logq)
struct crec *crecp;
int i;
log_queries = logq;
if ((log_queries = logq))
addrbuff = safe_malloc(ADDRSTRLEN);
else
addrbuff = NULL;
cache_head = cache_tail = NULL;
dhcp_inuse = dhcp_spare = NULL;
new_chain = NULL;
......@@ -762,17 +767,17 @@ void cache_add_dhcp_entry(struct daemon *daemon, char *host_name,
void dump_cache(struct daemon *daemon)
void dump_cache(struct daemon *daemon, time_t now)
{
syslog(LOG_INFO, _("cache size %d, %d/%d cache insertions re-used unexpired cache entries."),
daemon->cachesize, cache_live_freed, cache_inserted);
syslog(LOG_INFO, _("time %lu, cache size %d, %d/%d cache insertions re-used unexpired cache entries."),
(unsigned long)now, daemon->cachesize, cache_live_freed, cache_inserted);
if (daemon->options & (OPT_DEBUG | OPT_LOG))
if ((daemon->options & (OPT_DEBUG | OPT_LOG)) &&
(addrbuff || (addrbuff = malloc(ADDRSTRLEN))))
{
struct crec *cache ;
char addrbuff[ADDRSTRLEN];
int i;
syslog(LOG_DEBUG, "Host Address Flags Expires\n");
syslog(LOG_DEBUG, "Host Address Flags Expires");
for (i=0; i<hash_size; i++)
for (cache = hash_table[i]; cache; cache = cache->hash_next)
......@@ -797,7 +802,7 @@ void dump_cache(struct daemon *daemon)
#endif
syslog(LOG_DEBUG,
#ifdef HAVE_BROKEN_RTC
"%-40.40s %-30.30s %s%s%s%s%s%s%s%s%s%s %ld\n",
"%-40.40s %-30.30s %s%s%s%s%s%s%s%s%s%s %lu",
#else
"%-40.40s %-30.30s %s%s%s%s%s%s%s%s%s%s %s",
#endif
......@@ -813,7 +818,7 @@ void dump_cache(struct daemon *daemon)
cache->flags & F_NXDOMAIN ? "X" : " ",
cache->flags & F_HOSTS ? "H" : " ",
#ifdef HAVE_BROKEN_RTC
cache->flags & F_IMMORTAL ? 0: (unsigned long)cache->ttd
cache->flags & F_IMMORTAL ? 0: (unsigned long)(cache->ttd - now)
#else
cache->flags & F_IMMORTAL ? "\n" : ctime(&(cache->ttd))
#endif
......@@ -844,8 +849,7 @@ void log_query(unsigned short flags, char *name, struct all_addr *addr,
char *source;
char *verb = "is";
char types[20];
char addrbuff[ADDRSTRLEN];
if (!log_queries)
return;
......
This diff is collapsed.
......@@ -113,13 +113,14 @@ static void dbus_read_servers(struct daemon *daemon, DBusMessage *message)
#else
if (i == sizeof(struct in6_addr)-1)
{
memcpy(&addr.in6.sin6_addr, p, sizeof(struct in6_addr));
memcpy(&addr.in6.sin6_addr, p, sizeof(addr.in6));
#ifdef HAVE_SOCKADDR_SA_LEN
source_addr.in6.sin6_len = addr.in6.sin6_len = sizeof(struct sockaddr_in6);
source_addr.in6.sin6_len = addr.in6.sin6_len = sizeof(addr.in6);
#endif
source_addr.in6.sin6_family = addr.in6.sin6_family = AF_INET6;
addr.in6.sin6_port = htons(NAMESERVER_PORT);
source_addr.in6.sin6_flowinfo = addr.in6.sin6_flowinfo = htonl(0);
source_addr.in6.sin6_flowinfo = addr.in6.sin6_flowinfo = 0;
source_addr.in6.sin6_scope_id = addr.in6.sin6_scope_id = 0;
source_addr.in6.sin6_addr = in6addr_any;
source_addr.in6.sin6_port = htons(daemon->query_port);
skip = 0;
......@@ -211,14 +212,14 @@ static void dbus_read_servers(struct daemon *daemon, DBusMessage *message)
free(serv);
}
else
up = &serv->next;
up = &serv->next;
}
}
DBusHandlerResult message_handler (DBusConnection *connection,
DBusMessage *message,
void *user_data)
DBusHandlerResult message_handler(DBusConnection *connection,
DBusMessage *message,
void *user_data)
{
char *method = (char *)dbus_message_get_member(message);
struct daemon *daemon = (struct daemon *)user_data;
......@@ -239,7 +240,7 @@ DBusHandlerResult message_handler (DBusConnection *connection,
check_servers(daemon);
}
else if (strcmp(method, "ClearCache") == 0)
clear_cache_and_reload(daemon, dnsmasq_time(daemon->uptime_fd));
clear_cache_and_reload(daemon);
else
return (DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -17,6 +17,8 @@
#ifdef HAVE_ISC_READER
#define MAXTOK 50
struct isc_lease {
char *name, *fqdn;
time_t expires;
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment