diff -ur dnsmasq-2.43rc2/src/config.h dnsmasq-2.43/src/config.h
--- dnsmasq-2.43rc2/src/config.h 2008-07-08 11:31:05.000000000 +0100
+++ dnsmasq-2.43/src/config.h 2008-07-10 13:23:13.000000000 +0100
@@ -14,13 +14,14 @@
along with this program. If not, see .
*/
-#define VERSION "2.43rc2"
+#define VERSION "2.43rc5"
#define FTABSIZ 150 /* max number of outstanding requests (default) */
#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 10 /* drop UDP queries after TIMEOUT seconds */
+#define RANDOM_SOCKS 64 /* max simultaneous random ports */
#define LEASE_RETRY 60 /* on error, retry writing leasefile after LEASE_RETRY seconds */
#define CACHESIZ 150 /* default cache size */
#define MAXLEASES 150 /* maximum number of DHCP leases */
@@ -59,6 +60,7 @@
#define TFTP_PORT 69
#define TFTP_MAX_CONNECTIONS 50 /* max simultaneous connections */
#define LOG_MAX 5 /* log-queue length */
+#define RANDFILE "/dev/urandom"
/* DBUS interface specifics */
#define DNSMASQ_SERVICE "uk.org.thekelleys.dnsmasq"
@@ -127,19 +129,6 @@
define this if you have arc4random() to get better security from DNS spoofs
by using really random ids (OpenBSD)
-HAVE_RANDOM
- define this if you have the 4.2BSD random() function (and its
- associated srandom() function), which is at least as good as (if not
- better than) the rand() function.
-
-HAVE_DEV_RANDOM
- define this if you have the /dev/random device, which gives truly
- random numbers but may run out of random numbers.
-
-HAVE_DEV_URANDOM
- define this if you have the /dev/urandom device, which gives
- semi-random numbers when it runs out of truly random numbers.
-
HAVE_SOCKADDR_SA_LEN
define this if struct sockaddr has sa_len field (*BSD)
@@ -160,9 +149,6 @@
For Linux you should define
HAVE_LINUX_NETWORK
HAVE_GETOPT_LONG
- HAVE_RANDOM
- HAVE_DEV_RANDOM
- HAVE_DEV_URANDOM
you should NOT define
HAVE_ARC4RANDOM
HAVE_SOCKADDR_SA_LEN
@@ -170,12 +156,8 @@
For *BSD systems you should define
HAVE_BSD_NETWORK
HAVE_SOCKADDR_SA_LEN
- HAVE_RANDOM
and you MAY define
HAVE_ARC4RANDOM - OpenBSD and FreeBSD and NetBSD version 2.0 or later
- HAVE_DEV_URANDOM - OpenBSD and FreeBSD and NetBSD
- HAVE_DEV_RANDOM - FreeBSD and NetBSD
- (OpenBSD with hardware random number generator)
HAVE_GETOPT_LONG - NetBSD, later FreeBSD
(FreeBSD and OpenBSD only if you link GNU getopt)
@@ -203,18 +185,12 @@
#define HAVE_LINUX_NETWORK
#define HAVE_GETOPT_LONG
#undef HAVE_ARC4RANDOM
-#define HAVE_RANDOM
-#define HAVE_DEV_URANDOM
-#define HAVE_DEV_RANDOM
#undef HAVE_SOCKADDR_SA_LEN
/* Never use fork() on uClinux. Note that this is subtly different from the
--keep-in-foreground option, since it also suppresses forking new
processes for TCP connections and disables the call-a-script on leasechange
system. It's intended for use on MMU-less kernels. */
#define NO_FORK
#elif defined(__UCLIBC__)
#define HAVE_LINUX_NETWORK
@@ -223,16 +199,10 @@
# define HAVE_GETOPT_LONG
#endif
#undef HAVE_ARC4RANDOM
-#define HAVE_RANDOM
-#define HAVE_DEV_URANDOM
-#define HAVE_DEV_RANDOM
#undef HAVE_SOCKADDR_SA_LEN
#if !defined(__ARCH_HAS_MMU__) && !defined(__UCLIBC_HAS_MMU__)
# define NO_FORK
#endif
#if defined(__UCLIBC_HAS_IPV6__)
# ifndef IPV6_V6ONLY
# define IPV6_V6ONLY 26
@@ -244,9 +214,6 @@
#define HAVE_LINUX_NETWORK
#define HAVE_GETOPT_LONG
#undef HAVE_ARC4RANDOM
-#define HAVE_RANDOM
-#define HAVE_DEV_URANDOM
-#define HAVE_DEV_RANDOM
#undef HAVE_SOCKADDR_SA_LEN
/* glibc < 2.2 has broken Sockaddr_in6 so we have to use our own. */
/* glibc < 2.2 doesn't define in_addr_t */
@@ -255,7 +222,6 @@
typedef unsigned long in_addr_t;
# define HAVE_BROKEN_SOCKADDR_IN6
#endif
#elif defined(__FreeBSD__) || \
defined(__OpenBSD__) || \
@@ -269,35 +235,25 @@
#if !defined (__FreeBSD_kernel__)
# define HAVE_ARC4RANDOM
#endif
-#define HAVE_RANDOM
-#define HAVE_DEV_URANDOM
#define HAVE_SOCKADDR_SA_LEN
#define HAVE_BSD_BRIDGE
#elif defined(__APPLE__)
#define HAVE_BSD_NETWORK
#undef HAVE_GETOPT_LONG
#define HAVE_ARC4RANDOM
-#define HAVE_RANDOM
-#define HAVE_DEV_URANDOM
#define HAVE_SOCKADDR_SA_LEN
/* Define before sys/socket.h is included so we get socklen_t */
#define _BSD_SOCKLEN_T_
/* This is not defined in Mac OS X arpa/nameserv.h */
#define IN6ADDRSZ 16
#elif defined(__NetBSD__)
#define HAVE_BSD_NETWORK
#define HAVE_GETOPT_LONG
#undef HAVE_ARC4RANDOM
-#define HAVE_RANDOM
-#define HAVE_DEV_URANDOM
-#define HAVE_DEV_RANDOM
#define HAVE_SOCKADDR_SA_LEN
#define HAVE_BSD_BRIDGE
-#define HAVE_LARGEFILE
#elif defined(__sun) || defined(__sun__)
#define HAVE_SOLARIS_NETWORK
@@ -320,11 +276,8 @@
# define CMSG_SPACE(len) (__CMSG_ALIGN(sizeof(struct cmsghdr)) + __CMSG_ALIGN(len))
#endif
#undef HAVE_ARC4RANDOM
-#define HAVE_RANDOM
-#undef HAVE_DEV_URANDOM
-#undef HAVE_DEV_RANDOM
#undef HAVE_SOCKADDR_SA_LEN
+
#define _XPG4_2
#define __EXTENSIONS__
#define ETHER_ADDR_LEN 6
diff -ur dnsmasq-2.43rc2/src/dnsmasq.c dnsmasq-2.43/src/dnsmasq.c
--- dnsmasq-2.43rc2/src/dnsmasq.c 2008-07-08 11:31:05.000000000 +0100
+++ dnsmasq-2.43/src/dnsmasq.c 2008-07-10 13:18:49.000000000 +0100
@@ -111,7 +111,7 @@
daemon->packet_buff_sz = daemon->edns_pktsz > DNSMASQ_PACKETSZ ?
daemon->edns_pktsz : DNSMASQ_PACKETSZ;
daemon->packet = safe_malloc(daemon->packet_buff_sz);
-
+
if (!daemon->lease_file)
{
if (daemon->dhcp)
@@ -149,6 +149,8 @@
die(_("asychronous logging is not available under Solaris"), NULL, EC_BADCONF);
#endif
+ rand_init();
+
now = dnsmasq_time();
if (daemon->dhcp)
@@ -193,7 +195,7 @@
if (daemon->port != 0)
cache_init();
-
+
if (daemon->options & OPT_DBUS)
#ifdef HAVE_DBUS
{
@@ -963,7 +970,15 @@
FD_SET(serverfdp->fd, set);
bump_maxfd(serverfdp->fd, maxfdp);
}
-
+
+ if (daemon->port != 0 && !daemon->osport)
+ for (i = 0; i < RANDOM_SOCKS; i++)
+ if (daemon->randomsocks[i].refcount != 0)
+ {
+ FD_SET(daemon->randomsocks[i].fd, set);
+ bump_maxfd(daemon->randomsocks[i].fd, maxfdp);
+ }
+
for (listener = daemon->listeners; listener; listener = listener->next)
{
/* only listen for queries if we have resources */
@@ -1000,17 +1015,24 @@
static void check_dns_listeners(fd_set *set, time_t now)
{
struct serverfd *serverfdp;
- struct listener *listener;
-
+ struct listener *listener;
+ int i;
+
for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
if (FD_ISSET(serverfdp->fd, set))
- reply_query(serverfdp, now);
+ reply_query(serverfdp->fd, serverfdp->source_addr.sa.sa_family, now);
+
+ if (daemon->port != 0 && !daemon->osport)
+ for (i = 0; i < RANDOM_SOCKS; i++)
+ if (daemon->randomsocks[i].refcount != 0 &&
+ FD_ISSET(daemon->randomsocks[i].fd, set))
+ reply_query(daemon->randomsocks[i].fd, daemon->randomsocks[i].family, now);
for (listener = daemon->listeners; listener; listener = listener->next)
{
if (listener->fd != -1 && FD_ISSET(listener->fd, set))
receive_query(listener, now);
-
+
#ifdef HAVE_TFTP
if (listener->tftpfd != -1 && FD_ISSET(listener->tftpfd, set))
tftp_request(listener, now);
diff -ur dnsmasq-2.43rc2/src/dnsmasq.h dnsmasq-2.43/src/dnsmasq.h
--- dnsmasq-2.43rc2/src/dnsmasq.h 2008-07-08 11:31:05.000000000 +0100
+++ dnsmasq-2.43/src/dnsmasq.h 2008-07-09 20:47:31.000000000 +0100
@@ -317,6 +317,11 @@
struct serverfd *next;
};
+struct randfd {
+ int fd;
+ unsigned short refcount, family;
+};
+
struct server {
union mysockaddr addr, source_addr;
char interface[IF_NAMESIZE+1];
@@ -367,6 +372,10 @@
union mysockaddr source;
struct all_addr dest;
struct server *sentto; /* NULL means free */
+ struct randfd *rfd4;
+#ifdef HAVE_IPV6
+ struct randfd *rfd6;
+#endif
unsigned int iface;
unsigned short orig_id, new_id;
int fd, forwardall;
@@ -563,7 +572,7 @@
char *mxtarget;
char *lease_file;
char *username, *groupname, *scriptuser;
- int group_set;
+ int group_set, osport;
char *domain_suffix;
char *runfile;
char *lease_change_command;
@@ -598,6 +607,7 @@
int packet_buff_sz; /* size of above */
char *namebuff; /* MAXDNAME size buffer */
unsigned int local_answer, queries_forwarded;
+ struct frec *frec_list;
struct serverfd *sfds;
struct irec *interfaces;
struct listener *listeners;
@@ -605,7 +615,8 @@
struct server *srv_save; /* Used for resend on DoD */
size_t packet_len; /* " " */
pid_t tcp_pids[MAX_PROCS];
-
+ struct randfd randomsocks[RANDOM_SOCKS];
+
/* DHCP state */
int dhcpfd, helperfd;
#ifdef HAVE_LINUX_NETWORK
@@ -672,6 +683,7 @@
unsigned char *pheader, size_t hlen);
/* util.c */
+void rand_init(void);
unsigned short rand16(void);
int legal_char(char c);
int canonicalise(char *s);
@@ -711,7 +723,7 @@
void reread_dhcp(void);
/* forward.c */
-void reply_query(struct serverfd *sfd, time_t now);
+void reply_query(int fd, int family, time_t now);
void receive_query(struct listener *listen, time_t now);
unsigned char *tcp_request(int confd, time_t now,
struct in_addr local_addr, struct in_addr netmask);
@@ -720,6 +732,7 @@
/* network.c */
int local_bind(int fd, union mysockaddr *addr, char *intname, int is_tcp);
+int random_sock(int family);
void pre_allocate_sfds(void);
int reload_servers(char *fname);
void check_servers(void);
diff -ur dnsmasq-2.43rc2/src/forward.c dnsmasq-2.43/src/forward.c
--- dnsmasq-2.43rc2/src/forward.c 2008-07-08 11:31:05.000000000 +0100
+++ dnsmasq-2.43/src/forward.c 2008-07-09 21:32:16.000000000 +0100
@@ -16,14 +16,13 @@
#include "dnsmasq.h"
-static struct frec *frec_list = NULL;
-
static struct frec *lookup_frec(unsigned short id, unsigned int crc);
static struct frec *lookup_frec_by_sender(unsigned short id,
union mysockaddr *addr,
unsigned int crc);
static unsigned short get_id(int force, unsigned short force_id, unsigned int crc);
-
+static void free_frec(struct frec *f);
+static struct randfd *allocate_rfd(int family);
/* Send a UDP packet with its source address set as "source"
unless nowild is true, when we just send it with the kernel default */
@@ -290,7 +289,32 @@
(type != SERV_HAS_DOMAIN || hostname_isequal(domain, start->domain)) &&
!(start->flags & SERV_LITERAL_ADDRESS))
{
- if (sendto(start->sfd->fd, (char *)header, plen, 0,
+ int fd;
+
+ /* find server socket to use, may need to get random one. */
+ if (start->sfd)
+ fd = start->sfd->fd;
+ else
+ {
+#ifdef HAVE_IPV6
+ if (start->addr.sa.sa_family == AF_INET6)
+ {
+ if (!forward->rfd6 &&
+ !(forward->rfd6 = allocate_rfd(AF_INET6)))
+ break;
+ fd = forward->rfd6->fd;
+ }
+ else
+#endif
+ {
+ if (!forward->rfd4 &&
+ !(forward->rfd4 = allocate_rfd(AF_INET)))
+ break;
+ fd = forward->rfd4->fd;
+ }
+ }
+
+ if (sendto(fd, (char *)header, plen, 0,
&start->addr.sa,
sa_len(&start->addr)) == -1)
{
@@ -334,7 +358,7 @@
/* could not send on, prepare to return */
header->id = htons(forward->orig_id);
- forward->sentto = NULL; /* cancel */
+ free_frec(forward); /* cancel */
}
/* could not send on, return empty answer or address if known for whole domain */
@@ -426,7 +450,7 @@
}
/* sets new last_server */
-void reply_query(struct serverfd *sfd, time_t now)
+void reply_query(int fd, int family, time_t now)
{
/* packet from peer server, extract data for cache, and send to
original requester */
@@ -434,91 +458,101 @@
union mysockaddr serveraddr;
struct frec *forward;
socklen_t addrlen = sizeof(serveraddr);
- ssize_t n = recvfrom(sfd->fd, daemon->packet, daemon->edns_pktsz, 0, &serveraddr.sa, &addrlen);
+ ssize_t n = recvfrom(fd, daemon->packet, daemon->edns_pktsz, 0, &serveraddr.sa, &addrlen);
size_t nn;
-
+ struct server *server;
+
/* 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;
+ serveraddr.sa.sa_family = family;
#ifdef HAVE_IPV6
if (serveraddr.sa.sa_family == AF_INET6)
serveraddr.in6.sin6_flowinfo = 0;
#endif
+ /* spoof check: answer must come from known server, */
+ for (server = daemon->servers; server; server = server->next)
+ if (!(server->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR)) &&
+ sockaddr_isequal(&server->addr, &serveraddr))
+ break;
+
header = (HEADER *)daemon->packet;
- if (n >= (int)sizeof(HEADER) && header->qr &&
- (forward = lookup_frec(ntohs(header->id), questions_crc(header, n, daemon->namebuff))))
- {
- struct server *server = forward->sentto;
-
- if ((header->rcode == SERVFAIL || header->rcode == REFUSED) &&
- !(daemon->options & OPT_ORDER) &&
- forward->forwardall == 0)
- /* for broken servers, attempt to send to another one. */
+ if (!server ||
+ n < (int)sizeof(HEADER) || !header->qr ||
+ !(forward = lookup_frec(ntohs(header->id), questions_crc(header, n, daemon->namebuff))))
+ return;
+
+ server = forward->sentto;
+
+ if ((header->rcode == SERVFAIL || header->rcode == REFUSED) &&
+ !(daemon->options & OPT_ORDER) &&
+ forward->forwardall == 0)
+ /* for broken servers, attempt to send to another one. */
+ {
+ unsigned char *pheader;
+ size_t plen;
+ int is_sign;
+
+ /* recreate query from reply */
+ pheader = find_pseudoheader(header, (size_t)n, &plen, NULL, &is_sign);
+ if (!is_sign)
{
- unsigned char *pheader;
- size_t plen;
- int is_sign;
-
- /* recreate query from reply */
- pheader = find_pseudoheader(header, (size_t)n, &plen, NULL, &is_sign);
- if (!is_sign)
+ header->ancount = htons(0);
+ header->nscount = htons(0);
+ header->arcount = htons(0);
+ if ((nn = resize_packet(header, (size_t)n, pheader, plen)))
{
- header->ancount = htons(0);
- header->nscount = htons(0);
- header->arcount = htons(0);
- if ((nn = resize_packet(header, (size_t)n, pheader, plen)))
- {
- header->qr = 0;
- header->tc = 0;
- forward_query(-1, NULL, NULL, 0, header, nn, now, forward);
- return;
- }
+ header->qr = 0;
+ header->tc = 0;
+ forward_query(-1, NULL, NULL, 0, header, nn, now, forward);
+ return;
}
- }
-
- if ((forward->sentto->flags & SERV_TYPE) == 0)
- {
- if (header->rcode == SERVFAIL || header->rcode == REFUSED)
- server = NULL;
- else
- {
- struct server *last_server;
- /* find good server by address if possible, otherwise assume the last one we sent to */
- for (last_server = daemon->servers; last_server; last_server = last_server->next)
- if (!(last_server->flags & (SERV_LITERAL_ADDRESS | SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_NO_ADDR)) &&
- sockaddr_isequal(&last_server->addr, &serveraddr))
- {
- server = last_server;
- break;
- }
- }
- if (!(daemon->options & OPT_ALL_SERVERS))
- daemon->last_server = server;
}
-
- /* If the answer is an error, keep the forward record in place in case
- we get a good reply from another server. Kill it when we've
- had replies from all to avoid filling the forwarding table when
- everything is broken */
- if (forward->forwardall == 0 || --forward->forwardall == 1 ||
- (header->rcode != REFUSED && header->rcode != SERVFAIL))
+ }
+
+ if ((forward->sentto->flags & SERV_TYPE) == 0)
+ {
+ if (header->rcode == SERVFAIL || header->rcode == REFUSED)
+ server = NULL;
+ else
{
- if ((nn = process_reply(header, now, 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, nn,
- &forward->source, &forward->dest, forward->iface);
- }
- forward->sentto = NULL; /* cancel */
+ struct server *last_server;
+
+ /* find good server by address if possible, otherwise assume the last one we sent to */
+ for (last_server = daemon->servers; last_server; last_server = last_server->next)
+ if (!(last_server->flags & (SERV_LITERAL_ADDRESS | SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_NO_ADDR)) &&
+ sockaddr_isequal(&last_server->addr, &serveraddr))
+ {
+ server = last_server;
+ break;
+ }
+ }
+ if (!(daemon->options & OPT_ALL_SERVERS))
+ daemon->last_server = server;
+ }
+
+ /* If the answer is an error, keep the forward record in place in case
+ we get a good reply from another server. Kill it when we've
+ had replies from all to avoid filling the forwarding table when
+ everything is broken */
+ if (forward->forwardall == 0 || --forward->forwardall == 1 ||
+ (header->rcode != REFUSED && header->rcode != SERVFAIL))
+ {
+ if ((nn = process_reply(header, now, 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, nn,
+ &forward->source, &forward->dest, forward->iface);
}
+ free_frec(forward); /* cancel */
}
}
+
void receive_query(struct listener *listen, time_t now)
{
HEADER *header = (HEADER *)daemon->packet;
@@ -860,34 +894,99 @@
if ((f = (struct frec *)whine_malloc(sizeof(struct frec))))
{
- f->next = frec_list;
+ f->next = daemon->frec_list;
f->time = now;
f->sentto = NULL;
- frec_list = f;
+ f->rfd4 = NULL;
+#ifdef HAVE_IPV6
+ f->rfd6 = NULL;
+#endif
+ daemon->frec_list = f;
}
return f;
}
+static struct randfd *allocate_rfd(int family)
+{
+ static int finger = 0;
+ int i;
+
+ /* limit the number of sockets we have open to avoid starvation of
+ (eg) TFTP. Once we have a reasonable number, randomness should be OK */
+
+ for (i = 0; i < RANDOM_SOCKS; i++)
+ if (daemon->randomsocks[i].refcount == 0 &&
+ (daemon->randomsocks[i].fd = random_sock(family)) != -1)
+ {
+ daemon->randomsocks[i].refcount = 1;
+ daemon->randomsocks[i].family = family;
+ return &daemon->randomsocks[i];
+ }
+
+ /* No free ones, grab an existing one */
+ for (i = 0; i < RANDOM_SOCKS; i++)
+ {
+ int j = (i+finger) % RANDOM_SOCKS;
+ if (daemon->randomsocks[j].family == family && daemon->randomsocks[j].refcount != 0xffff)
+ {
+ finger = j;
+ daemon->randomsocks[j].refcount++;
+ return &daemon->randomsocks[j];
+ }
+ }
+
+ return NULL; /* doom */
+}
+
+static void free_frec(struct frec *f)
+{
+ if (f->rfd4 && --(f->rfd4->refcount) == 0)
+ close(f->rfd4->fd);
+
+ f->rfd4 = NULL;
+ f->sentto = NULL;
+
+#ifdef HAVE_IPV6
+ if (f->rfd6 && --(f->rfd6->refcount) == 0)
+ close(f->rfd6->fd);
+
+ f->rfd6 = NULL;
+#endif
+}
+
/* if wait==NULL return a free or older than TIMEOUT record.
else return *wait zero if one available, or *wait is delay to
- when the oldest in-use record will expire. */
+ when the oldest in-use record will expire. Impose an absolute
+ limit of 4*TIMEOUT before we wipe things (for random sockets) */
struct frec *get_new_frec(time_t now, int *wait)
{
- struct frec *f, *oldest;
+ struct frec *f, *oldest, *target;
int count;
if (wait)
*wait = 0;
- for (f = frec_list, oldest = NULL, count = 0; f; f = f->next, count++)
+ for (f = daemon->frec_list, oldest = NULL, target = NULL, count = 0; f; f = f->next, count++)
if (!f->sentto)
+ target = f;
+ else
{
- f->time = now;
- return f;
+ if (difftime(now, f->time) >= 4*TIMEOUT)
+ {
+ free_frec(f);
+ target = f;
+ }
+
+ if (!oldest || difftime(f->time, oldest->time) <= 0)
+ oldest = f;
}
- else if (!oldest || difftime(f->time, oldest->time) <= 0)
- oldest = f;
+
+ if (target)
+ {
+ target->time = now;
+ return target;
+ }
/* can't find empty one, use oldest if there is one
and it's older than timeout */
@@ -902,7 +1001,7 @@
if (!wait)
{
- oldest->sentto = 0;
+ free_frec(oldest);
oldest->time = now;
}
return oldest;
@@ -928,7 +1027,7 @@
{
struct frec *f;
- for(f = frec_list; f; f = f->next)
+ for(f = daemon->frec_list; f; f = f->next)
if (f->sentto && f->new_id == id &&
(f->crc == crc || crc == 0xffffffff))
return f;
@@ -942,7 +1041,7 @@
{
struct frec *f;
- for(f = frec_list; f; f = f->next)
+ for(f = daemon->frec_list; f; f = f->next)
if (f->sentto &&
f->orig_id == id &&
f->crc == crc &&
@@ -957,9 +1056,9 @@
{
struct frec *f;
- for (f = frec_list; f; f = f->next)
+ for (f = daemon->frec_list; f; f = f->next)
if (f->sentto && f->sentto == server)
- f->sentto = NULL;
+ free_frec(f);
if (daemon->last_server == server)
daemon->last_server = NULL;
@@ -980,7 +1079,7 @@
{
struct frec *f = lookup_frec(force_id, crc);
if (f)
- f->sentto = NULL; /* free */
+ free_frec(f); /* free */
ret = force_id;
}
else do
diff -ur dnsmasq-2.43rc2/src/network.c dnsmasq-2.43/src/network.c
--- dnsmasq-2.43rc2/src/network.c 2008-07-08 11:31:05.000000000 +0100
+++ dnsmasq-2.43/src/network.c 2008-07-09 15:59:39.000000000 +0100
@@ -441,6 +441,55 @@
return listeners;
}
+
+/* return a UDP socket bound to a random port, have to coper with straying into
+ occupied port nos and reserved ones. */
+int random_sock(int family)
+{
+ int fd;
+
+ if ((fd = socket(family, SOCK_DGRAM, 0)) != -1)
+ {
+ union mysockaddr addr;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.in.sin_family = family;
+
+ while (1)
+ {
+ if (family == AF_INET)
+ {
+ addr.in.sin_addr.s_addr = INADDR_ANY;
+ addr.in.sin_port = rand16();
+#ifdef HAVE_SOCKADDR_SA_LEN
+ addr.in.sin_len = sizeof(struct sockaddr_in);
+#endif
+ }
+#ifdef HAVE_IPV6
+ else
+ {
+ addr.in6.sin6_addr = in6addr_any;
+ addr.in6.sin6_port = rand16();
+#ifdef HAVE_SOCKADDR_SA_LEN
+ addr.in6.sin6_len = sizeof(struct sockaddr_in6);
+#endif
+ }
+#endif
+
+ if (bind(fd, (struct sockaddr *)&addr, sa_len(&addr)) == 0)
+ return fd;
+
+ if (errno != EADDRINUSE && errno != EACCES)
+ break;
+ }
+
+ close(fd);
+ }
+
+ return -1;
+}
+
+
int local_bind(int fd, union mysockaddr *addr, char *intname, int is_tcp)
{
union mysockaddr addr_copy = *addr;
@@ -473,6 +522,25 @@
struct serverfd *sfd;
int errsave;
+ /* when using random ports, servers which would otherwise use
+ the INADDR_ANY/port0 socket have sfd set to NULL */
+ if (!daemon->osport)
+ {
+ errno = 0;
+
+ if (addr->sa.sa_family == AF_INET &&
+ addr->in.sin_addr.s_addr == INADDR_ANY &&
+ addr->in.sin_port == htons(0))
+ return NULL;
+
+#ifdef HAVE_IPV6
+ if (addr->sa.sa_family == AF_INET6 &&
+ memcmp(&addr->in6.sin6_addr, &in6addr_any, sizeof(in6addr_any)) == 0 &&
+ addr->in6.sin6_port == htons(0))
+ return NULL;
+#endif
+ }
+
/* may have a suitable one already */
for (sfd = daemon->sfds; sfd; sfd = sfd->next )
if (sockaddr_isequal(&sfd->source_addr, addr) &&
@@ -538,6 +606,7 @@
for (srv = daemon->servers; srv; srv = srv->next)
if (!(srv->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR)) &&
!allocate_sfd(&srv->source_addr, srv->interface) &&
+ errno != 0 &&
(daemon->options & OPT_NOWILD))
{
prettyprint_addr(&srv->addr, daemon->namebuff);
@@ -585,7 +654,9 @@
}
/* Do we need a socket set? */
- if (!new->sfd && !(new->sfd = allocate_sfd(&new->source_addr, new->interface)))
+ if (!new->sfd &&
+ !(new->sfd = allocate_sfd(&new->source_addr, new->interface)) &&
+ errno != 0)
{
my_syslog(LOG_WARNING,
_("ignoring nameserver %s - cannot make/bind socket: %s"),
diff -ur dnsmasq-2.43rc2/src/option.c dnsmasq-2.43/src/option.c
--- dnsmasq-2.43rc2/src/option.c 2008-07-08 11:31:05.000000000 +0100
+++ dnsmasq-2.43/src/option.c 2008-07-10 13:32:40.000000000 +0100
@@ -1416,6 +1416,10 @@
case 'Q': /* --query-port */
if (!atoi_check(arg, &daemon->query_port))
option = '?';
+ /* if explicitly set to zero, use single OS ephemeral port
+ and disable random ports */
+ if (daemon->query_port == 0)
+ daemon->osport = 1;
break;
case 'T': /* --local-ttl */
diff -ur dnsmasq-2.43rc2/src/util.c dnsmasq-2.43/src/util.c
--- dnsmasq-2.43rc2/src/util.c 2008-07-08 11:31:05.000000000 +0100
+++ dnsmasq-2.43/src/util.c 2008-07-09 20:24:25.000000000 +0100
@@ -16,82 +16,88 @@
/* Some code in this file contributed by Rob Funk. */
+/* The SURF random number generator was taken from djbdns-1.05, by
+ Daniel J Berstein, which is public domain. */
+
+
#include "dnsmasq.h"
#ifdef HAVE_BROKEN_RTC
#include
#endif
-/* Prefer arc4random(3) over random(3) over rand(3) */
-/* Also prefer /dev/urandom over /dev/random, to preserve the entropy pool */
+
#ifdef HAVE_ARC4RANDOM
-# define rand() arc4random()
-# define srand(s) (void)0
-# define RANDFILE (NULL)
-#else
-# ifdef HAVE_RANDOM
-# define rand() random()
-# define srand(s) srandom(s)
-# endif
-# ifdef HAVE_DEV_URANDOM
-# define RANDFILE "/dev/urandom"
-# else
-# ifdef HAVE_DEV_RANDOM
-# define RANDFILE "/dev/random"
-# else
-# define RANDFILE (NULL)
-# endif
-# endif
-#endif
+void rand_init(void)
+{
+ return;
+}
unsigned short rand16(void)
{
- static int been_seeded = 0;
- const char *randfile = RANDFILE;
+ return (unsigned short) (arc4random() >> 15);
+}
+
+#else
+
+/* SURF random number generator */
+
+typedef unsigned int uint32;
+
+static uint32 seed[32];
+static uint32 in[12];
+static uint32 out[8];
+
+void rand_init()
+{
+ int fd = open(RANDFILE, O_RDONLY);
- if (! been_seeded)
- {
- int fd, n = 0;
- unsigned int c = 0, seed = 0, badseed;
- char sbuf[sizeof(seed)];
- char *s;
- struct timeval now;
-
- /* get the bad seed as a backup */
- /* (but we'd rather have something more random) */
- gettimeofday(&now, NULL);
- badseed = now.tv_sec ^ now.tv_usec ^ (getpid() << 16);
-
- fd = open(randfile, O_RDONLY);
- if (fd < 0)
- seed = badseed;
- else
- {
- s = (char *) &seed;
- while ((c < sizeof(seed)) &&
- ((n = read(fd, sbuf, sizeof(seed)) > 0)))
- {
- memcpy(s, sbuf, n);
- s += n;
- c += n;
- }
- if (n < 0)
- seed = badseed;
- close(fd);
- }
+ if (fd == -1 ||
+ !read_write(fd, (unsigned char *)&seed, sizeof(seed), 1) ||
+ !read_write(fd, (unsigned char *)&in, sizeof(in), 1))
+ die(_("failed to seed the random number generator: %s"), NULL, EC_MISC);
+
+ close(fd);
+}
- srand(seed);
- been_seeded = 1;
+#define ROTATE(x,b) (((x) << (b)) | ((x) >> (32 - (b))))
+#define MUSH(i,b) x = t[i] += (((x ^ seed[i]) + sum) ^ ROTATE(x,b));
+
+static void surf(void)
+{
+ uint32 t[12]; uint32 x; uint32 sum = 0;
+ int r; int i; int loop;
+
+ for (i = 0;i < 12;++i) t[i] = in[i] ^ seed[12 + i];
+ for (i = 0;i < 8;++i) out[i] = seed[24 + i];
+ x = t[11];
+ for (loop = 0;loop < 2;++loop) {
+ for (r = 0;r < 16;++r) {
+ sum += 0x9e3779b9;
+ MUSH(0,5) MUSH(1,7) MUSH(2,9) MUSH(3,13)
+ MUSH(4,5) MUSH(5,7) MUSH(6,9) MUSH(7,13)
+ MUSH(8,5) MUSH(9,7) MUSH(10,9) MUSH(11,13)
}
-
- /* Some rand() implementations have less randomness in low bits
- * than in high bits, so we only pay attention to the high ones.
- * But most implementations don't touch the high bit, so we
- * ignore that one.
- */
- return( (unsigned short) (rand() >> 15) );
+ for (i = 0;i < 8;++i) out[i] ^= t[i + 4];
+ }
}
+unsigned short rand16(void)
+{
+ static int outleft = 0;
+
+ if (!outleft) {
+ if (!++in[0]) if (!++in[1]) if (!++in[2]) ++in[3];
+ surf();
+ outleft = 8;
+ }
+
+ return (unsigned short) out[--outleft];
+}
+
+#endif
+
+
int legal_char(char c)
{
/* check for legal char a-z A-Z 0-9 -