import of dnsmasq-2.23.tar.gz

This commit is contained in:
Simon Kelley
2005-08-29 12:19:27 +01:00
parent 91dccd0958
commit 3d8df260e1
32 changed files with 1861 additions and 575 deletions

View File

@@ -1,16 +0,0 @@
# Uncomment this on Solaris.
#LIBS = -lsocket -lnsl
CFLAGS?= -O2
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
.c.o: dnsmasq.h config.h
$(CC) $(CFLAGS) $(RPM_OPT_FLAGS) -Wall -W -c $*.c
dnsmasq : $(OBJS) dnsmasq.h config.h
$(CC) -o $@ $(OBJS) $(LIBS)

View File

@@ -59,12 +59,12 @@ void cache_init(int size, int logq)
hash_table[i] = NULL;
}
static struct crec **hash_bucket(unsigned char *name)
static struct crec **hash_bucket(char *name)
{
unsigned int c, val = 0;
/* don't use tolower and friends here - they may be messed up by LOCALE */
while((c = *name++))
while((c = (unsigned char) *name++))
if (c >= 'A' && c <= 'Z')
val += c + 'a' - 'A';
else
@@ -579,12 +579,12 @@ static void read_hostsfile(char *filename, int opts, char *buff, char *domain_su
continue;
#ifdef HAVE_IPV6
if (inet_pton(AF_INET, token, &addr) == 1)
if (inet_pton(AF_INET, token, &addr) > 0)
{
flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4;
addrlen = INADDRSZ;
}
else if (inet_pton(AF_INET6, token, &addr) == 1)
else if (inet_pton(AF_INET6, token, &addr) > 0)
{
flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV6;
addrlen = IN6ADDRSZ;
@@ -902,9 +902,9 @@ void log_query(unsigned short flags, char *name, struct all_addr *addr,
else if (flags & F_QUERY)
{
unsigned int i;
static struct {
static const struct {
unsigned int type;
char *name;
const char * const name;
} typestr[] = {
{ 1, "A" },
{ 2, "NS" },
@@ -948,6 +948,9 @@ void log_query(unsigned short flags, char *name, struct all_addr *addr,
else
source = "cached";
if (strlen(name) == 0)
name = ".";
if ((flags & F_FORWARD) | (flags & F_NEG))
syslog(LOG_DEBUG, "%s %s %s %s", source, name, verb, addrbuff);
else if (flags & F_REVERSE)

View File

@@ -12,7 +12,7 @@
/* Author's email: simon@thekelleys.org.uk */
#define VERSION "2.22"
#define VERSION "2.23"
#define FTABSIZ 150 /* max number of outstanding requests */
#define MAX_PROCS 20 /* max no children for TCP requests */
@@ -50,6 +50,10 @@
#define DHCP_SERVER_PORT 67
#define DHCP_CLIENT_PORT 68
/* DBUS interface specifics */
#define DNSMASQ_SERVICE "uk.org.thekelleys.dnsmasq"
#define DNSMASQ_PATH "/uk/org/thekelleys/dnsmasq"
/* Logfile stuff - change this to change the options and facility */
/* debug is true if the --no-daemon flag is given */
#ifdef LOG_PERROR
@@ -164,6 +168,11 @@ HAVE_RTNETLINK
back to the Berkley API at runtime if netlink support is not
configured into the kernel.
HAVE_DBUS
Define this if you want to link against libdbus, and have dnsmasq
define some methods to allow (re)configuration of the upstream DNS
servers via DBus.
NOTES:
For Linux you should define
HAVE_LINUX_IPV6_PROC
@@ -201,6 +210,8 @@ NOTES:
# error HAVE_ISC_READER is not compatible with HAVE_BROKEN_RTC
#endif
#undef HAVE_DBUS
/* platform dependent options. */
/* Must preceed __linux__ since uClinux defines __linux__ too. */

342
src/dbus.c Normal file
View File

@@ -0,0 +1,342 @@
/* dnsmasq is Copyright (c) 2000-2005 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"
#ifdef HAVE_DBUS
#define DBUS_API_SUBJECT_TO_CHANGE
#include <dbus/dbus.h>
struct watch {
DBusWatch *watch;
struct watch *next;
};
static dbus_bool_t add_watch(DBusWatch *watch, void *data)
{
struct daemon *daemon = data;
struct watch *w;
for (w = daemon->watches; w; w = w->next)
if (w->watch == watch)
return TRUE;
if (!(w = malloc(sizeof(struct watch))))
return FALSE;
w->watch = watch;
w->next = daemon->watches;
daemon->watches = w;
dbus_watch_set_data (watch, (void *)daemon, NULL);
return TRUE;
}
static void remove_watch(DBusWatch *watch, void *data)
{
struct daemon *daemon = data;
struct watch **up, *w;
for (up = &(daemon->watches), w = daemon->watches; w; w = w->next)
if (w->watch == watch)
{
*up = w->next;
free(w);
}
else
up = &(w->next);
}
static void dbus_read_servers(struct daemon *daemon, DBusMessage *message)
{
struct server *serv, *tmp, **up;
DBusMessageIter iter;
union mysockaddr addr, source_addr;
char *domain;
dbus_message_iter_init(message, &iter);
/* mark everything from DBUS */
for (serv = daemon->servers; serv; serv = serv->next)
if (serv->flags & SERV_FROM_DBUS)
serv->flags |= SERV_MARK;
while (1)
{
int skip = 0;
if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_UINT32)
{
u32 a;
dbus_message_iter_get_basic(&iter, &a);
dbus_message_iter_next (&iter);
#ifdef HAVE_SOCKADDR_SA_LEN
source_addr.in.sin_len = addr.in.sin_len = sizeof(struct sockaddr_in);
#endif
addr.in.sin_addr.s_addr = ntohl(a);
source_addr.in.sin_family = addr.in.sin_family = AF_INET;
addr.in.sin_port = htons(NAMESERVER_PORT);
source_addr.in.sin_addr.s_addr = INADDR_ANY;
source_addr.in.sin_port = htons(daemon->query_port);
}
else if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_BYTE)
{
unsigned char p[sizeof(struct in6_addr)];
unsigned int i;
skip = 1;
for(i = 0; i < sizeof(struct in6_addr); i++)
{
dbus_message_iter_get_basic(&iter, &p[i]);
dbus_message_iter_next (&iter);
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BYTE)
break;
}
#ifndef HAVE_IPV6
syslog(LOG_WARNING, "attempt to set an IPv6 server address via DBus - no IPv6 support");
#else
if (i == sizeof(struct in6_addr)-1)
{
memcpy(&addr.in6.sin6_addr, p, sizeof(struct in6_addr));
#ifdef HAVE_SOCKADDR_SA_LEN
source_addr.in6.sin6_len = addr.in6.sin6_len = sizeof(struct sockaddr_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_addr = in6addr_any;
source_addr.in6.sin6_port = htons(daemon->query_port);
skip = 0;
}
#endif
}
else
/* At the end */
break;
do {
if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_STRING)
{
dbus_message_iter_get_basic(&iter, &domain);
dbus_message_iter_next (&iter);
}
else
domain = NULL;
if (!skip)
{
/* See if this is already there, and unmark */
for (serv = daemon->servers; serv; serv = serv->next)
if ((serv->flags & SERV_FROM_DBUS) &&
(serv->flags & SERV_MARK))
{
if (!(serv->flags & SERV_HAS_DOMAIN) && !domain)
{
serv->flags &= ~SERV_MARK;
break;
}
if ((serv->flags & SERV_HAS_DOMAIN) &&
domain &&
hostname_isequal(domain, serv->domain))
{
serv->flags &= ~SERV_MARK;
break;
}
}
if (!serv && (serv = malloc(sizeof (struct server))))
{
/* Not found, create a new one. */
if (domain)
serv->domain = malloc(strlen(domain)+1);
if (domain && !serv->domain)
{
free(serv);
serv = NULL;
}
else
{
serv->next = daemon->servers;
daemon->servers = serv;
serv->flags = SERV_FROM_DBUS;
serv->sfd = NULL;
if (domain)
{
strcpy(serv->domain, domain);
serv->flags |= SERV_HAS_DOMAIN;
}
}
}
if (serv)
{
if (source_addr.in.sin_family == AF_INET &&
addr.in.sin_addr.s_addr == 0 &&
serv->domain)
serv->flags |= SERV_NO_ADDR;
else
{
serv->flags &= ~SERV_NO_ADDR;
serv->addr = addr;
serv->source_addr = source_addr;
}
}
}
} while (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_STRING);
}
/* unlink and free anything still marked. */
for (serv = daemon->servers, up = &daemon->servers; serv; serv = tmp)
{
tmp = serv->next;
if (serv->flags & SERV_MARK)
{
*up = serv->next;
free(serv);
}
else
up = &serv->next;
}
}
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;
if (strcmp(method, "GetVersion") == 0)
{
char *v = VERSION;
DBusMessage *reply = dbus_message_new_method_return(message);
dbus_message_append_args(reply, DBUS_TYPE_STRING, &v, DBUS_TYPE_INVALID);
dbus_connection_send (connection, reply, NULL);
dbus_message_unref (reply);
}
else if (strcmp(method, "SetServers") == 0)
{
syslog(LOG_INFO, "setting upstream servers from DBus");
dbus_read_servers(daemon, message);
check_servers(daemon);
}
else if (strcmp(method, "ClearCache") == 0)
clear_cache_and_reload(daemon, dnsmasq_time(daemon->uptime_fd));
else
return (DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
return (DBUS_HANDLER_RESULT_HANDLED);
}
/* returns NULL or error message, may fail silently if dbus daemon not yet up. */
char *dbus_init(struct daemon *daemon)
{
DBusConnection *connection = NULL;
DBusObjectPathVTable dnsmasq_vtable = {NULL, &message_handler, NULL, NULL, NULL, NULL };
DBusError dbus_error;
DBusMessage *message;
dbus_error_init (&dbus_error);
if (!(connection = dbus_bus_get (DBUS_BUS_SYSTEM, &dbus_error)))
return NULL;
dbus_connection_set_exit_on_disconnect(connection, FALSE);
dbus_connection_set_watch_functions(connection, add_watch, remove_watch,
NULL, (void *)daemon, NULL);
dbus_error_init (&dbus_error);
dbus_bus_request_name (connection, DNSMASQ_SERVICE, 0, &dbus_error);
if (dbus_error_is_set (&dbus_error))
return (char *)dbus_error.message;
if (!dbus_connection_register_object_path(connection, DNSMASQ_PATH,
&dnsmasq_vtable, daemon))
return "could not register a DBus message handler";
daemon->dbus = connection;
if ((message = dbus_message_new_signal(DNSMASQ_PATH, DNSMASQ_SERVICE, "Up")))
dbus_connection_send(connection, message, NULL);
return NULL;
}
int set_dbus_listeners(struct daemon *daemon, int maxfd,
fd_set *rset, fd_set *wset, fd_set *eset)
{
struct watch *w;
for (w = daemon->watches; w; w = w->next)
if (dbus_watch_get_enabled(w->watch))
{
unsigned int flags = dbus_watch_get_flags(w->watch);
int fd = dbus_watch_get_fd(w->watch);
if (fd > maxfd)
maxfd = fd;
if (flags & DBUS_WATCH_READABLE)
FD_SET(fd, rset);
if (flags & DBUS_WATCH_WRITABLE)
FD_SET(fd, wset);
FD_SET(fd, eset);
}
return maxfd;
}
void check_dbus_listeners(struct daemon *daemon,
fd_set *rset, fd_set *wset, fd_set *eset)
{
DBusConnection *connection = (DBusConnection *)daemon->dbus;
struct watch *w;
for (w = daemon->watches; w; w = w->next)
if (dbus_watch_get_enabled(w->watch))
{
unsigned int flags = 0;
int fd = dbus_watch_get_fd(w->watch);
if (FD_ISSET(fd, rset))
flags |= DBUS_WATCH_READABLE;
if (FD_ISSET(fd, wset))
flags |= DBUS_WATCH_WRITABLE;
if (FD_ISSET(fd, eset))
flags |= DBUS_WATCH_ERROR;
if (flags != 0)
dbus_watch_handle(w->watch, flags);
}
if (connection)
{
dbus_connection_ref (connection);
while (dbus_connection_dispatch (connection) == DBUS_DISPATCH_DATA_REMAINS);
dbus_connection_unref (connection);
}
}
#endif

View File

@@ -56,7 +56,7 @@ void dhcp_init(struct daemon *daemon)
if ((fd = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP)) == -1 ||
(flags = fcntl(fd, F_GETFL, 0)) == -1 ||
fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1 ||
setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &oneopt, sizeof(oneopt)) ||
setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &oneopt, sizeof(oneopt)) == -1 ||
setsockopt(fd, SOL_SOCKET, SO_DONTROUTE, &zeroopt, sizeof(zeroopt)) == -1)
die("cannot create ICMP raw socket: %s.", NULL);
@@ -102,7 +102,7 @@ void dhcp_init(struct daemon *daemon)
and get a terminating zero added */
daemon->dhcp_buff = safe_malloc(256);
daemon->dhcp_buff2 = safe_malloc(256);
daemon->ping_results = NULL;
}
void dhcp_packet(struct daemon *daemon, time_t now)
@@ -191,6 +191,10 @@ void dhcp_packet(struct daemon *daemon, time_t now)
for (tmp = daemon->if_except; tmp; tmp = tmp->next)
if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0))
return;
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0))
return;
if (daemon->if_names || daemon->if_addrs)
{
@@ -333,6 +337,7 @@ void dhcp_packet(struct daemon *daemon, time_t now)
#else
struct sockaddr_ll dest;
memset(&dest, 0, sizeof(dest));
dest.sll_family = AF_PACKET;
dest.sll_halen = ETHER_ADDR_LEN;
dest.sll_ifindex = iface_index;
@@ -495,7 +500,8 @@ 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 dhcp_netid *netids)
struct in_addr *addrp, unsigned char *hwaddr,
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.
@@ -528,12 +534,47 @@ int address_allocate(struct dhcp_context *context, struct daemon *daemon,
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))
/* perturb address selection so that we are
/* 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;
}
@@ -548,7 +589,7 @@ int address_allocate(struct dhcp_context *context, struct daemon *daemon,
}
if (netids)
return address_allocate(context, daemon, addrp, hwaddr, NULL);
return address_allocate(context, daemon, addrp, hwaddr, NULL, now);
return 0;
}
@@ -590,14 +631,16 @@ struct dhcp_config *find_config(struct dhcp_config *configs,
return config;
}
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;
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;
if (hostname && context)
for (config = configs; config; config = config->next)
if ((config->flags & CONFIG_NAME) &&
@@ -605,20 +648,21 @@ struct dhcp_config *find_config(struct dhcp_config *configs,
is_addr_in_context(context, config))
return config;
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;
}
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;
}
return NULL;
}
@@ -632,6 +676,8 @@ void dhcp_read_ethers(struct daemon *daemon)
unsigned char hwaddr[ETHER_ADDR_LEN];
struct dhcp_config *config, *configs = daemon->dhcp_conf;
int count = 0;
addr.s_addr = 0; /* eliminate warning */
if (!f)
{
@@ -731,7 +777,9 @@ void dhcp_update_configs(struct dhcp_config *configs)
{
/* Some people like to keep all static IP addresses in /etc/hosts.
This goes through /etc/hosts and sets static addresses for any DHCP config
records which don't have an address and whose name matches. */
records which don't have an address and whose name matches.
We take care to maintain the invariant that any IP address can appear
in at most one dhcp-host. */
struct dhcp_config *config;
struct crec *crec;
@@ -742,8 +790,14 @@ void dhcp_update_configs(struct dhcp_config *configs)
(crec = cache_find_by_name(NULL, config->hostname, 0, F_IPV4)) &&
(crec->flags & F_HOSTS))
{
config->addr = crec->addr.addr.addr.addr4;
config->flags |= CONFIG_ADDR;
if (config_find_by_address(configs, crec->addr.addr.addr.addr4))
syslog(LOG_WARNING, "duplicate IP address %s (%s) in dhcp-config directive",
inet_ntoa(crec->addr.addr.addr.addr4), config->hostname);
else
{
config->addr = crec->addr.addr.addr.addr4;
config->flags |= CONFIG_ADDR;
}
}
}

View File

@@ -14,6 +14,27 @@
#include "dnsmasq.h"
static char *compile_opts =
#ifndef HAVE_IPV6
"no-"
#endif
"IPv6 "
#ifndef HAVE_GETOPT_LONG
"no-"
#endif
"GNU-getopt "
#ifdef HAVE_BROKEN_RTC
"no-RTC "
#endif
#ifndef HAVE_ISC_READER
"no-"
#endif
"ISC-leasefile "
#ifndef HAVE_DBUS
"no-"
#endif
"DBus";
static volatile int sigterm, sighup, sigusr1, sigalarm, num_kids, in_child;
static int set_dns_listeners(struct daemon *daemon, fd_set *set, int maxfd);
@@ -25,9 +46,7 @@ int main (int argc, char **argv)
struct daemon *daemon;
int first_loop = 1;
int bind_fallback = 0;
time_t resolv_changed = 0;
time_t now, last = 0;
struct irec *interfaces;
struct sigaction sigact;
sigset_t sigmask;
struct iname *if_tmp;
@@ -65,7 +84,7 @@ int main (int argc, char **argv)
sigaddset(&sigact.sa_mask, SIGCHLD);
sigprocmask(SIG_BLOCK, &sigact.sa_mask, &sigmask);
daemon = read_opts(argc, argv);
daemon = read_opts(argc, argv, compile_opts);
if (daemon->edns_pktsz < PACKETSZ)
daemon->edns_pktsz = PACKETSZ;
@@ -83,7 +102,7 @@ int main (int argc, char **argv)
die("ISC dhcpd integration not available: set HAVE_ISC_READER in src/config.h", NULL);
#endif
if (!enumerate_interfaces(daemon, &interfaces, NULL, NULL))
if (!enumerate_interfaces(daemon, &daemon->interfaces, NULL, NULL))
die("failed to find list of interfaces: %s", NULL);
if (!(daemon->options & OPT_NOWILD) &&
@@ -95,7 +114,7 @@ int main (int argc, char **argv)
if (daemon->options & OPT_NOWILD)
{
daemon->listeners = create_bound_listeners(interfaces, daemon->port);
daemon->listeners = create_bound_listeners(daemon->interfaces, daemon->port);
for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
if (if_tmp->name && !if_tmp->used)
@@ -104,18 +123,8 @@ int main (int argc, char **argv)
for (if_tmp = daemon->if_addrs; if_tmp; if_tmp = if_tmp->next)
if (!if_tmp->used)
{
char *addrbuff = daemon->namebuff;
#ifdef HAVE_IPV6
if (if_tmp->addr.sa.sa_family == AF_INET)
inet_ntop(AF_INET, &if_tmp->addr.in.sin_addr,
addrbuff, ADDRSTRLEN);
else
inet_ntop(AF_INET6, &if_tmp->addr.in6.sin6_addr,
addrbuff, ADDRSTRLEN);
#else
strcpy(addrbuff, inet_ntoa(if_tmp->addr.in.sin_addr));
#endif
die("no interface with address %s", addrbuff);
prettyprint_addr(&if_tmp->addr, daemon->namebuff);
die("no interface with address %s", daemon->namebuff);
}
}
@@ -144,6 +153,20 @@ int main (int argc, char **argv)
lease_init(daemon, now);
}
if (daemon->options & OPT_DBUS)
#ifdef HAVE_DBUS
{
char *err;
daemon->dbus = NULL;
daemon->watches = NULL;
if ((err = dbus_init(daemon)))
die("DBus error: %s", err);
}
#else
if (daemon->options & OPT_DBUS)
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
for use to access nameservers without more specific source addresses.
This allows query_port to be a low port */
@@ -174,14 +197,19 @@ int main (int argc, char **argv)
if (!(daemon->options & OPT_DEBUG))
{
FILE *pidfile;
struct serverfd *serverfdp;
struct listener *listener;
struct passwd *ent_pw;
int i;
fd_set test_set;
int maxfd, i;
FD_ZERO(&test_set);
maxfd = set_dns_listeners(daemon, &test_set, -1);
#ifdef HAVE_DBUS
maxfd = set_dbus_listeners(daemon, maxfd, &test_set, &test_set, &test_set);
#endif
/* The following code "daemonizes" the process.
See Stevens section 12.4 */
#ifndef NO_FORK
if (!(daemon->options & OPT_NO_FORK))
{
@@ -209,28 +237,19 @@ int main (int argc, char **argv)
for (i=0; i<64; i++)
{
for (listener = daemon->listeners; listener; listener = listener->next)
if (listener->fd == i || listener->tcpfd == i)
break;
if (listener)
continue;
#ifdef HAVE_BROKEN_RTC
if (i == daemon->uptime_fd)
continue;
#endif
if (daemon->dhcp &&
(i == daemon->lease_fd ||
i == daemon->dhcpfd ||
i == daemon->dhcp_raw_fd ||
i == daemon->dhcp_icmp_fd))
continue;
for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
if (serverfdp->fd == i)
break;
if (serverfdp)
if (i <= maxfd && FD_ISSET(i, &test_set))
continue;
close(i);
@@ -261,7 +280,19 @@ int main (int argc, char **argv)
syslog(LOG_INFO, "started, version %s cachesize %d", VERSION, daemon->cachesize);
else
syslog(LOG_INFO, "started, version %s cache disabled", VERSION);
syslog(LOG_INFO, "compile time options: %s", compile_opts);
#ifdef HAVE_DBUS
if (daemon->options & OPT_DBUS)
{
if (daemon->dbus)
syslog(LOG_INFO, "DBus support enabled: connected to system bus");
else
syslog(LOG_INFO, "DBus support enabled: bus connection pending");
}
#endif
if (bind_fallback)
syslog(LOG_WARNING, "setting --bind-interfaces option because of OS limitations");
@@ -304,28 +335,19 @@ int main (int argc, char **argv)
if (!(daemon->options & OPT_DEBUG) && (getuid() == 0 || geteuid() == 0))
syslog(LOG_WARNING, "running as root");
check_servers(daemon, interfaces);
check_servers(daemon);
while (sigterm == 0)
{
fd_set rset;
fd_set rset, wset, eset;
if (sighup)
{
cache_reload(daemon->options, daemon->namebuff, daemon->domain_suffix, daemon->addn_hosts);
if (daemon->dhcp)
{
if (daemon->options & OPT_ETHERS)
dhcp_read_ethers(daemon);
dhcp_update_configs(daemon->dhcp_conf);
lease_update_from_configs(daemon->dhcp_conf, daemon->domain_suffix);
lease_update_file(0, now);
lease_update_dns(daemon);
}
clear_cache_and_reload(daemon, now);
if (daemon->resolv_files && (daemon->options & OPT_NO_POLL))
{
reload_servers(daemon->resolv_files->name, daemon);
check_servers(daemon, interfaces);
check_servers(daemon);
}
sighup = 0;
}
@@ -349,11 +371,15 @@ int main (int argc, char **argv)
}
FD_ZERO(&rset);
FD_ZERO(&wset);
FD_ZERO(&eset);
if (!first_loop)
{
int maxfd = set_dns_listeners(daemon, &rset, 0);
int maxfd = set_dns_listeners(daemon, &rset, -1);
#ifdef HAVE_DBUS
maxfd = set_dbus_listeners(daemon, maxfd, &rset, &wset, &eset);
#endif
if (daemon->dhcp)
{
FD_SET(daemon->dhcpfd, &rset);
@@ -361,25 +387,56 @@ int main (int argc, char **argv)
maxfd = daemon->dhcpfd;
}
/* Whilst polling for the dbus, wake every quarter second */
#ifdef HAVE_PSELECT
if (pselect(maxfd+1, &rset, NULL, NULL, NULL, &sigmask) < 0)
FD_ZERO(&rset); /* rset otherwise undefined after error */
{
struct timespec *tp = NULL;
#ifdef HAVE_DBUS
struct timespec t;
if ((daemon->options & OPT_DBUS) && !daemon->dbus)
{
tp = &t;
tp->tv_sec = 0;
tp->tv_nsec = 250000000;
}
#endif
if (pselect(maxfd+1, &rset, &wset, &eset, tp, &sigmask) < 0)
{
/* otherwise undefined after error */
FD_ZERO(&rset); FD_ZERO(&wset); FD_ZERO(&eset);
}
}
#else
{
sigset_t save_mask;
struct timeval *tp = NULL;
#ifdef HAVE_DBUS
struct timeval t;
if ((daemon->options & OPT_DBUS) && !daemon->dbus)
{
tp = &t;
tp->tv_sec = 0;
tp->tv_usec = 250000;
}
#endif
sigprocmask(SIG_SETMASK, &sigmask, &save_mask);
if (select(maxfd+1, &rset, NULL, NULL, NULL) < 0)
FD_ZERO(&rset); /* rset otherwise undefined after error */
if (select(maxfd+1, &rset, &wset, &eset, tp) < 0)
{
/* otherwise undefined after error */
FD_ZERO(&rset); FD_ZERO(&wset); FD_ZERO(&eset);
}
sigprocmask(SIG_SETMASK, &save_mask, NULL);
}
#endif
}
first_loop = 0;
now = dnsmasq_time(daemon->uptime_fd);
/* Check for changes to resolv files once per second max. */
if (last == 0 || difftime(now, last) > 1.0)
/* Don't go silent for long periods if the clock goes backwards. */
if (last == 0 || difftime(now, last) > 1.0 || difftime(now, last) < 1.0)
{
last = now;
@@ -407,24 +464,40 @@ int main (int argc, char **argv)
else
{
res->logged = 0;
if (difftime(statbuf.st_mtime, last_change) > 0.0)
if (statbuf.st_mtime != res->mtime)
{
last_change = statbuf.st_mtime;
latest = res;
res->mtime = statbuf.st_mtime;
if (difftime(res->mtime, last_change) > 0.0)
{
last_change = res->mtime;
latest = res;
}
}
}
res = res->next;
}
if (latest && difftime(last_change, resolv_changed) > 0.0)
if (latest)
{
resolv_changed = last_change;
reload_servers(latest->name, daemon);
check_servers(daemon, interfaces);
check_servers(daemon);
}
}
}
#ifdef HAVE_DBUS
/* if we didn't create a DBus connection, retry now. */
if ((daemon->options & OPT_DBUS) && !daemon->dbus)
{
char *err;
if ((err = dbus_init(daemon)))
syslog(LOG_WARNING, "DBus error: %s", err);
if (daemon->dbus)
syslog(LOG_INFO, "connected to system DBus");
}
check_dbus_listeners(daemon, &rset, &wset, &eset);
#endif
check_dns_listeners(daemon, &rset, now);
if (daemon->dhcp && FD_ISSET(daemon->dhcpfd, &rset))
@@ -432,7 +505,7 @@ int main (int argc, char **argv)
}
syslog(LOG_INFO, "exiting on receipt of SIGTERM");
if (daemon->dhcp)
{
#ifdef HAVE_BROKEN_RTC
@@ -469,6 +542,21 @@ static void sig_handler(int sig)
}
}
void clear_cache_and_reload(struct daemon *daemon, time_t now)
{
cache_reload(daemon->options, daemon->namebuff, daemon->domain_suffix, daemon->addn_hosts);
if (daemon->dhcp)
{
if (daemon->options & OPT_ETHERS)
dhcp_read_ethers(daemon);
dhcp_update_configs(daemon->dhcp_conf);
lease_update_from_configs(daemon->dhcp_conf, daemon->domain_suffix);
lease_update_file(0, now);
lease_update_dns(daemon);
}
}
static int set_dns_listeners(struct daemon *daemon, fd_set *set, int maxfd)
{
struct serverfd *serverfdp;
@@ -540,7 +628,7 @@ static void check_dns_listeners(struct daemon *daemon, fd_set *set, time_t now)
#endif
else
{
char *buff;
unsigned char *buff;
struct server *s;
int flags;
@@ -649,7 +737,8 @@ int icmp_ping(struct daemon *daemon, struct in_addr addr)
struct timeval tv;
fd_set rset;
struct sockaddr_in faddr;
int maxfd, len = sizeof(faddr);
int maxfd;
socklen_t len = sizeof(faddr);
tv.tv_usec = 250000;
tv.tv_sec = 0;

View File

@@ -110,6 +110,8 @@
#define OPT_NO_FORK 65536
#define OPT_AUTHORITATIVE 131072
#define OPT_LOCALISE 262144
#define OPT_DBUS 524288
#define OPT_BOOTP_DYNAMIC 1048576
struct all_addr {
union {
@@ -133,7 +135,8 @@ struct doctor {
struct mx_srv_record {
char *name, *target;
int issrv, srvport, priority, weight, offset;
int issrv, srvport, priority, weight;
unsigned int offset;
struct mx_srv_record *next;
};
@@ -214,6 +217,8 @@ union mysockaddr {
#define SERV_HAS_DOMAIN 16 /* server for one domain only */
#define SERV_FOR_NODOTS 32 /* server for names with no domain part only */
#define SERV_WARNED_RECURSIVE 64 /* avoid warning spam */
#define SERV_FROM_DBUS 128 /* 1 if source is DBus */
#define SERV_MARK 256 /* for mark-and-delete */
#define SERV_TYPE (SERV_HAS_DOMAIN | SERV_FOR_NODOTS)
@@ -255,8 +260,8 @@ struct iname {
/* resolv-file parms from command-line */
struct resolvc {
struct resolvc *next;
int is_default;
int logged;
int is_default, logged;
time_t mtime;
char *name;
};
@@ -379,6 +384,11 @@ struct udp_dhcp_packet {
} data;
};
struct ping_result {
struct in_addr addr;
time_t time;
struct ping_result *next;
};
struct daemon {
/* datastuctures representing the command-line and
@@ -394,7 +404,7 @@ struct daemon {
char *username, *groupname;
char *domain_suffix;
char *runfile;
struct iname *if_names, *if_addrs, *if_except;
struct iname *if_names, *if_addrs, *if_except, *dhcp_except;
struct bogus_addr *bogus_addr;
struct server *servers;
int cachesize;
@@ -417,6 +427,7 @@ struct daemon {
int packet_buff_sz; /* size of above */
char *namebuff; /* MAXDNAME size buffer */
struct serverfd *sfds;
struct irec *interfaces;
struct listener *listeners;
struct server *last_server;
int uptime_fd;
@@ -428,6 +439,15 @@ struct daemon {
#endif
struct udp_dhcp_packet *dhcp_packet;
char *dhcp_buff, *dhcp_buff2;
struct ping_result *ping_results;
/* DBus stuff */
#ifdef HAVE_DBUS
/* void * here to avoid depending on dbus headers outside dbus.c */
void *dbus;
struct watch *watches;
#endif
};
/* cache.c */
@@ -472,35 +492,35 @@ int resize_packet(HEADER *header, unsigned int plen,
unsigned short rand16(void);
int legal_char(char c);
int canonicalise(char *s);
int atoi_check(char *a, int *res);
unsigned char *do_rfc1035_name(unsigned char *p, char *sval);
void die(char *message, char *arg1);
void complain(char *message, int lineno, char *file);
void *safe_malloc(size_t size);
char *safe_string_alloc(char *cp);
int sa_len(union mysockaddr *addr);
int sockaddr_isequal(union mysockaddr *s1, union mysockaddr *s2);
int hostname_isequal(unsigned char *a, unsigned char *b);
int hostname_isequal(char *a, char *b);
time_t dnsmasq_time(int fd);
int is_same_net(struct in_addr a, struct in_addr b, struct in_addr mask);
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);
/* option.c */
struct daemon *read_opts (int argc, char **argv);
struct daemon *read_opts (int argc, char **argv, char *compile_opts);
/* forward.c */
void forward_init(int first);
void reply_query(struct serverfd *sfd, struct daemon *daemon, time_t now);
void receive_query(struct listener *listen, struct daemon *daemon, time_t now);
char *tcp_request(struct daemon *daemon, int confd, time_t now,
struct in_addr local_addr, struct in_addr netmask);
unsigned char *tcp_request(struct daemon *daemon, int confd, time_t now,
struct in_addr local_addr, struct in_addr netmask);
/* network.c */
struct serverfd *allocate_sfd(union mysockaddr *addr, struct serverfd **sfds);
void reload_servers(char *fname, struct daemon *daemon);
void check_servers(struct daemon *daemon, struct irec *interfaces);
void check_servers(struct daemon *daemon);
int enumerate_interfaces(struct daemon *daemon, struct irec **chainp,
union mysockaddr *test_addrp, struct in_addr *netmaskp);
struct listener *create_wildcard_listeners(int port);
@@ -515,7 +535,7 @@ struct dhcp_context *narrow_context(struct dhcp_context *context, struct in_addr
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 dhcp_netid *netids);
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,
@@ -551,6 +571,7 @@ int dhcp_reply(struct daemon *daemon, struct dhcp_context *context, char *iface_
/* dnsmasq.c */
int icmp_ping(struct daemon *daemon, struct in_addr addr);
void clear_cache_and_reload(struct daemon *daemon, time_t now);
/* isc.c */
#ifdef HAVE_ISC_READER
@@ -564,3 +585,12 @@ int netlink_process(struct daemon *daemon, int index,
struct in_addr relay, struct in_addr primary,
struct dhcp_context **retp);
#endif
/* dbus.c */
#ifdef HAVE_DBUS
char *dbus_init(struct daemon *daemon);
void check_dbus_listeners(struct daemon *daemon,
fd_set *rset, fd_set *wset, fd_set *eset);
int set_dbus_listeners(struct daemon *daemon, int maxfd,
fd_set *rset, fd_set *wset, fd_set *eset);
#endif

View File

@@ -89,9 +89,8 @@ static void send_from(int fd, int nowild, char *packet, int len,
cmptr->cmsg_type = IP_SENDSRCADDR;
#endif
}
#ifdef HAVE_IPV6
else
#ifdef HAVE_IPV
{
struct in6_pktinfo *pkt = (struct in6_pktinfo *)CMSG_DATA(cmptr);
pkt->ipi6_ifindex = iface; /* Need iface for IPv6 to handle link-local addrs */
@@ -100,6 +99,8 @@ static void send_from(int fd, int nowild, char *packet, int len,
cmptr->cmsg_type = IPV6_PKTINFO;
cmptr->cmsg_level = IPV6_LEVEL;
}
#else
iface = 0; /* eliminate warning */
#endif
}
@@ -134,7 +135,7 @@ static unsigned short search_servers(struct daemon *daemon, time_t now, struct a
for (serv = daemon->servers; serv; serv=serv->next)
/* domain matches take priority over NODOTS matches */
if ((serv->flags & SERV_FOR_NODOTS) && *type != SERV_HAS_DOMAIN && !strchr(qdomain, '.'))
if ((serv->flags & SERV_FOR_NODOTS) && *type != SERV_HAS_DOMAIN && !strchr(qdomain, '.') && namelen != 0)
{
unsigned short sflag = serv->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6;
*type = SERV_FOR_NODOTS;
@@ -194,7 +195,7 @@ static unsigned short search_servers(struct daemon *daemon, time_t now, struct a
else
log_query(F_CONFIG | F_FORWARD | flags, qdomain, *addrpp, 0, NULL, 0);
}
else if (qtype && (daemon->options & OPT_NODOTS_LOCAL) && !strchr(qdomain, '.'))
else if (qtype && (daemon->options & OPT_NODOTS_LOCAL) && !strchr(qdomain, '.') && namelen != 0)
flags = F_NXDOMAIN;
if (flags == F_NXDOMAIN && check_for_local_domain(qdomain, now, daemon))
@@ -215,13 +216,13 @@ static void forward_query(struct daemon *daemon, int udpfd, union mysockaddr *ud
char *domain = NULL;
int type = 0;
struct all_addr *addrp = NULL;
unsigned int crc = questions_crc(header, (unsigned int)plen, daemon->namebuff);
unsigned short flags = 0;
unsigned short gotname = extract_request(header, (unsigned int)plen, daemon->namebuff, NULL);
struct server *start = NULL;
unsigned int crc = questions_crc(header,(unsigned int)plen, daemon->namebuff);
/* may be recursion not speced or no servers available. */
if (!header->rd || !daemon->servers)
/* may be no servers available. */
if (!daemon->servers)
forward = NULL;
else if ((forward = lookup_frec_by_sender(ntohs(header->id), udpaddr, crc)))
{
@@ -369,16 +370,8 @@ static int process_reply(struct daemon *daemon, HEADER *header, time_t now,
if (!header->ra && header->rcode == NOERROR && ntohs(header->ancount) == 0 &&
server && !(server->flags & SERV_WARNED_RECURSIVE))
{
char addrbuff[ADDRSTRLEN];
#ifdef HAVE_IPV6
if (server->addr.sa.sa_family == AF_INET)
inet_ntop(AF_INET, &server->addr.in.sin_addr, addrbuff, ADDRSTRLEN);
else if (server->addr.sa.sa_family == AF_INET6)
inet_ntop(AF_INET6, &server->addr.in6.sin6_addr, addrbuff, ADDRSTRLEN);
#else
strcpy(addrbuff, inet_ntoa(server->addr.in.sin_addr));
#endif
syslog(LOG_WARNING, "nameserver %s refused to do a recursive query", addrbuff);
prettyprint_addr(&server->addr, daemon->namebuff);
syslog(LOG_WARNING, "nameserver %s refused to do a recursive query", daemon->namebuff);
if (!(daemon->options & OPT_LOG))
server->flags |= SERV_WARNED_RECURSIVE;
}
@@ -520,7 +513,10 @@ void receive_query(struct listener *listen, struct daemon *daemon, time_t now)
netmask = listen->iface->netmask;
}
else
dst_addr_4.s_addr = 0;
{
dst_addr_4.s_addr = 0;
netmask.s_addr = 0;
}
iov[0].iov_base = daemon->packet;
iov[0].iov_len = daemon->edns_pktsz;
@@ -657,7 +653,7 @@ void receive_query(struct listener *listen, struct daemon *daemon, time_t now)
header, n, now);
}
static int read_write(int fd, char *packet, int size, int rw)
static int read_write(int fd, unsigned char *packet, int size, int rw)
{
int n, done;
@@ -686,14 +682,14 @@ static int read_write(int fd, char *packet, int size, int rw)
blocking as neccessary, and then return. Note, need to be a bit careful
about resources for debug mode, when the fork is suppressed: that's
done by the caller. */
char *tcp_request(struct daemon *daemon, int confd, time_t now,
struct in_addr local_addr, struct in_addr netmask)
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;
unsigned short qtype, gotname;
unsigned char c1, c2;
/* Max TCP packet + slop */
char *packet = malloc(65536 + MAXDNAME + RRFIXEDSZ);
unsigned char *packet = malloc(65536 + MAXDNAME + RRFIXEDSZ);
HEADER *header;
struct server *last_server;

View File

@@ -136,8 +136,8 @@ void load_dhcp(struct daemon *daemon, time_t now)
it is noted that it might not be entirely accurate for odd seconds.
Since we're trying to get the same answer as dhcpd, that's just
fine here. */
static int months [11] = { 31, 59, 90, 120, 151, 181,
212, 243, 273, 304, 334 };
static const int months [11] = { 31, 59, 90, 120, 151, 181,
212, 243, 273, 304, 334 };
time_t time = ((((((365 * (lease_time.tm_year - 1970) + /* Days in years since '70 */
(lease_time.tm_year - 1969) / 4 + /* Leap days since '70 */
(lease_time.tm_mon > 1 /* Days in months this year */

View File

@@ -71,9 +71,9 @@ void lease_init(struct daemon *daemon, time_t now)
if (strcmp(daemon->packet, "*") == 0)
clid_len = 0;
else
clid_len = parse_hex(daemon->packet, daemon->packet, 255, NULL);
clid_len = parse_hex(daemon->packet, (unsigned char *)daemon->packet, 255, NULL);
if (!(lease = lease_allocate(hwaddr, daemon->packet, clid_len, addr)))
if (!(lease = lease_allocate(hwaddr, (unsigned char *)daemon->packet, clid_len, addr)))
die ("too many stored leases", NULL);
lease->expires = expires;

View File

@@ -33,7 +33,8 @@ static int iface_allowed(struct daemon *daemon, struct irec *iface,
if (!lo)
{
lo = safe_malloc(sizeof(struct iname));
lo->name = safe_string_alloc(name);
lo->name = safe_malloc(strlen(name)+1);
strcpy(lo->name, name);
lo->isloop = lo->used = 1;
lo->next = daemon->if_names;
daemon->if_names = lo;
@@ -100,6 +101,8 @@ int enumerate_interfaces(struct daemon *daemon, struct irec **chainp,
int fd = socket(PF_INET, SOCK_DGRAM, 0);
struct in_addr netmask;
int ret = 0;
netmask.s_addr = 0; /* eliminate warning */
if (fd == -1)
return 0;
@@ -262,7 +265,7 @@ int enumerate_interfaces(struct daemon *daemon, struct irec **chainp,
return ret;
}
#ifdef HAVE_IPV6
#if defined(HAVE_IPV6) && (defined(IP_PKTINFO) || (defined(IP_RECVDSTADDR) && defined(IP_RECVIF) && defined(IP_SENDSRCADDR)))
static int create_ipv6_listener(struct listener **link, int port)
{
union mysockaddr addr;
@@ -330,6 +333,7 @@ static int create_ipv6_listener(struct listener **link, int port)
struct listener *create_wildcard_listeners(int port)
{
#if !(defined(IP_PKTINFO) || (defined(IP_RECVDSTADDR) && defined(IP_RECVIF) && defined(IP_SENDSRCADDR)))
port = 0; /* eliminate warning */
return NULL;
#else
union mysockaddr addr;
@@ -434,7 +438,11 @@ struct listener *create_bound_listeners(struct irec *interfaces, int port)
}
else
#endif
die("failed to bind listening socket: %s", NULL);
{
char addrbuff[ADDRSTRLEN];
prettyprint_addr(&iface->addr, addrbuff);
die("failed to bind listening socket for %s: %s", addrbuff);
}
}
else
{
@@ -486,9 +494,8 @@ struct serverfd *allocate_sfd(union mysockaddr *addr, struct serverfd **sfds)
return sfd;
}
void check_servers(struct daemon *daemon, struct irec *interfaces)
void check_servers(struct daemon *daemon)
{
char addrbuff[ADDRSTRLEN];
struct irec *iface;
struct server *new, *tmp, *ret = NULL;
int port = 0;
@@ -504,27 +511,14 @@ void check_servers(struct daemon *daemon, struct irec *interfaces)
if (!(new->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR)))
{
#ifdef HAVE_IPV6
if (new->addr.sa.sa_family == AF_INET)
{
inet_ntop(AF_INET, &new->addr.in.sin_addr, addrbuff, ADDRSTRLEN);
port = ntohs(new->addr.in.sin_port);
}
else if (new->addr.sa.sa_family == AF_INET6)
{
inet_ntop(AF_INET6, &new->addr.in6.sin6_addr, addrbuff, ADDRSTRLEN);
port = ntohs(new->addr.in6.sin6_port);
}
#else
strcpy(addrbuff, inet_ntoa(new->addr.in.sin_addr));
port = ntohs(new->addr.in.sin_port);
#endif
for (iface = interfaces; iface; iface = iface->next)
port = prettyprint_addr(&new->addr, daemon->namebuff);
for (iface = daemon->interfaces; iface; iface = iface->next)
if (sockaddr_isequal(&new->addr, &iface->addr))
break;
if (iface)
{
syslog(LOG_WARNING, "ignoring nameserver %s - local interface", addrbuff);
syslog(LOG_WARNING, "ignoring nameserver %s - local interface", daemon->namebuff);
free(new);
continue;
}
@@ -533,7 +527,7 @@ void check_servers(struct daemon *daemon, struct irec *interfaces)
if (!new->sfd && !(new->sfd = allocate_sfd(&new->source_addr, &daemon->sfds)))
{
syslog(LOG_WARNING,
"ignoring nameserver %s - cannot make/bind socket: %m", addrbuff);
"ignoring nameserver %s - cannot make/bind socket: %m", daemon->namebuff);
free(new);
continue;
}
@@ -554,10 +548,10 @@ void check_servers(struct daemon *daemon, struct irec *interfaces)
if (new->flags & SERV_NO_ADDR)
syslog(LOG_INFO, "using local addresses only for %s %s", s1, s2);
else if (!(new->flags & SERV_LITERAL_ADDRESS))
syslog(LOG_INFO, "using nameserver %s#%d for %s %s", addrbuff, port, s1, s2);
syslog(LOG_INFO, "using nameserver %s#%d for %s %s", daemon->namebuff, port, s1, s2);
}
else
syslog(LOG_INFO, "using nameserver %s#%d", addrbuff, port);
syslog(LOG_INFO, "using nameserver %s#%d", daemon->namebuff, port);
}
daemon->servers = ret;
@@ -611,7 +605,7 @@ void reload_servers(char *fname, struct daemon *daemon)
continue;
#ifdef HAVE_IPV6
if (inet_pton(AF_INET, token, &addr.in.sin_addr))
if (inet_pton(AF_INET, token, &addr.in.sin_addr) > 0)
#else
if ((addr.in.sin_addr.s_addr = inet_addr(token)) != (in_addr_t) -1)
#endif
@@ -625,7 +619,7 @@ void reload_servers(char *fname, struct daemon *daemon)
source_addr.in.sin_port = htons(daemon->query_port);
}
#ifdef HAVE_IPV6
else if (inet_pton(AF_INET6, token, &addr.in6.sin6_addr))
else if (inet_pton(AF_INET6, token, &addr.in6.sin6_addr) > 0)
{
#ifdef HAVE_SOCKADDR_SA_LEN
source_addr.in6.sin6_len = addr.in6.sin6_len = sizeof(struct sockaddr_in6);

View File

@@ -21,9 +21,9 @@ struct myoption {
int val;
};
#define OPTSTRING "yZDNLERKzowefnbvhdkqr: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:"
#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:"
static struct myoption opts[] = {
static const struct myoption opts[] = {
{"version", 0, 0, 'v'},
{"no-hosts", 0, 0, 'h'},
{"no-poll", 0, 0, 'n'},
@@ -65,6 +65,7 @@ static struct myoption opts[] = {
{"addn-hosts", 1, 0, 'H'},
{"query-port", 1, 0, 'Q'},
{"except-interface", 1, 0, 'I'},
{"no-dhcp-interface", 1, 0, '2'},
{"domain-needed", 0, 0, 'D'},
{"dhcp-lease-max", 1, 0, 'X' },
{"bind-interfaces", 0, 0, 'z'},
@@ -79,6 +80,8 @@ static struct myoption opts[] = {
{"srv-host", 1, 0, 'W'},
{"localise-queries", 0, 0, 'y'},
{"txt-record", 1, 0, 'Y'},
{"enable-dbus", 0, 0, '1'},
{"bootp-dynamic", 0, 0, '3'},
{0, 0, 0, 0}
};
@@ -87,7 +90,7 @@ struct optflags {
unsigned int flag;
};
static struct optflags optmap[] = {
static const struct optflags optmap[] = {
{ 'b', OPT_BOGUSPRIV },
{ 'f', OPT_FILTER },
{ 'q', OPT_LOG },
@@ -106,12 +109,14 @@ static struct optflags optmap[] = {
{ 'z', OPT_NOWILD },
{ 'Z', OPT_ETHERS },
{ 'y', OPT_LOCALISE },
{ '1', OPT_DBUS },
{ '3', OPT_BOOTP_DYNAMIC },
{ 'v', 0},
{ 'w', 0},
{ 0, 0 }
};
static char *usage =
static const char * const usage =
"Usage: dnsmasq [options]\n\n"
#ifndef HAVE_GETOPT_LONG
"Use short options only on the command line.\n"
@@ -170,8 +175,98 @@ static char *usage =
"-Y --txt-record=name,txt.... Specify TXT DNS record.\n"
"-z, --bind-interfaces Bind only to interfaces in use.\n"
"-Z, --read-ethers Read DHCP static host information from " ETHERSFILE ".\n"
"-1, --enable-dbus Enable the DBus interface for setting upstream servers, etc.\n"
"-2, --no-dhcp-interface=interface Do not provide DHCP on this interface, only provide DNS.\n"
"-3, --bootp-dynamic Enable dynamic address allocation for bootp.\n"
"\n";
/* We hide metacharaters in quoted strings by mapping them into the ASCII control
character space. Note that the \0, \t \a \b \r and \n characters are carefully placed in the
following sequence so that they map to themselves: it is therefore possible to call
unhide_metas repeatedly on string without breaking things.
The transformation gets undone by opt_canonicalise, atoi_check and safe_string_alloc, and a
couple of other places. */
static char meta[] = "\000123456\a\b\t\n78\r90abcdefABCDEF:,.";
static char hide_meta(char c)
{
unsigned int i;
for (i = 0; i < (sizeof(meta) - 1); i++)
if (c == meta[i])
return (char)i;
return c;
}
static char unhide_meta(char cr)
{
unsigned int c = cr;
if (c < (sizeof(meta) - 1))
cr = meta[c];
return cr;
}
static void unhide_metas(char *cp)
{
if (cp)
for(; *cp; cp++)
*cp = unhide_meta(*cp);
}
static char *safe_string_alloc(char *cp)
{
char *ret = NULL;
if (cp && strlen(cp) != 0)
{
ret = safe_malloc(strlen(cp)+1);
strcpy(ret, cp);
/* restore hidden metachars */
unhide_metas(ret);
}
return ret;
}
static char *safe_strchr(char *s, int c)
{
if (!s)
return NULL;
return strchr(s, c);
}
static int canonicalise_opt(char *s)
{
if (!s)
return 0;
unhide_metas(s);
return canonicalise(s);
}
static int atoi_check(char *a, int *res)
{
char *p;
if (!a)
return 0;
unhide_metas(a);
for (p = a; *p; p++)
if (*p < '0' || *p > '9')
return 0;
*res = atoi(a);
return 1;
}
static void add_txt(struct daemon *daemon, char *name, char *txt)
{
size_t len = strlen(txt);
@@ -187,20 +282,7 @@ static void add_txt(struct daemon *daemon, char *name, char *txt)
memcpy((r->txt)+1, txt, len);
}
/* filenames are OK with unquoted commas, restore them here. */
static char *safe_filename_alloc(char *filename)
{
char *p, *ret = safe_string_alloc(filename);
if (ret)
for (p = ret; *p; p++)
if (*p == '\001')
*p = ',';
return ret;
}
struct daemon *read_opts (int argc, char **argv)
struct daemon *read_opts (int argc, char **argv, char *compile_opts)
{
struct daemon *daemon = safe_malloc(sizeof(struct daemon));
char *problem = NULL, *buff = safe_malloc(MAXDNAME);
@@ -248,9 +330,6 @@ struct daemon *read_opts (int argc, char **argv)
strncpy(buff, optarg, MAXDNAME);
buff[MAXDNAME-1] = 0;
arg = buff;
for (p = arg; *p; p++)
if (*p == ',')
*p = '\001';
}
else
arg = NULL;
@@ -276,28 +355,40 @@ struct daemon *read_opts (int argc, char **argv)
else
{
int white;
unsigned int lastquote;
lineno++;
/* Implement quotes, inside quotes we allow \\ \" \n and \t
unquoted commas get changed to \001 also strip comments */
metacharacters get hidden also strip comments */
for (white = 1, p = buff; *p; p++)
for (white = 1, lastquote = 0, p = buff; *p; p++)
{
if (*p == '"')
{
memmove(p, p+1, strlen(p+1)+1);
for(; *p && *p != '"'; p++)
if (*p == '\\' &&
(p[1] == '\\' || p[1] == '"' || p[1] == 'n' || p[1] == 't'))
{
if (p[1] == 't')
p[1] = '\t';
else if (p[1] == 'n')
p[1] = '\n';
memmove(p, p+1, strlen(p+1)+1);
}
{
if (*p == '\\' && strchr("\"tnabr\\", p[1]))
{
if (p[1] == 't')
p[1] = '\t';
else if (p[1] == 'n')
p[1] = '\n';
else if (p[1] == 'a')
p[1] = '\a';
else if (p[1] == 'b')
p[1] = '\b';
else if (p[1] == 'r')
p[1] = '\r';
memmove(p, p+1, strlen(p+1)+1);
}
*p = hide_meta(*p);
}
if (*p == '"')
memmove(p, p+1, strlen(p+1)+1);
{
memmove(p, p+1, strlen(p+1)+1);
lastquote = p - buff;
}
else
complain("missing \"", lineno, conffile);
}
@@ -307,13 +398,10 @@ struct daemon *read_opts (int argc, char **argv)
*p = 0;
break;
}
white = isspace(*p);
if (*p == ',')
*p = '\001';
white = isspace(unhide_meta(*p));
}
/* fgets gets end of line char too. */
while (strlen(buff) > 0 && isspace(buff[strlen(buff)-1]))
while (strlen(buff) > lastquote && isspace(unhide_meta(buff[strlen(buff)-1])))
buff[strlen(buff)-1] = 0;
if (*buff == 0)
continue;
@@ -360,7 +448,8 @@ struct daemon *read_opts (int argc, char **argv)
if (!f && option == 'v')
{
printf("Dnsmasq version %s %s\n\n", VERSION, COPYRIGHT);
printf("Dnsmasq version %s %s\n", VERSION, COPYRIGHT);
printf("Compile time options %s\n\n", compile_opts);
printf("This software comes with ABSOLUTELY NO WARRANTY.\n");
printf("Dnsmasq is free software, and you are welcome to redistribute it\n");
printf("under the terms of the GNU General Public License, version 2.\n");
@@ -390,7 +479,7 @@ struct daemon *read_opts (int argc, char **argv)
case 'C':
if (!f)
{
conffile = safe_filename_alloc(arg);
conffile = safe_string_alloc(arg);
conffile_set = 1;
break;
}
@@ -404,18 +493,18 @@ struct daemon *read_opts (int argc, char **argv)
file_name_save = conffile;
file_save = f;
line_save = lineno;
conffile = safe_filename_alloc(arg);
conffile = safe_string_alloc(arg);
conffile_set = 1;
lineno = 0;
goto fileopen;
case 'x':
daemon->runfile = safe_filename_alloc(arg);
daemon->runfile = safe_string_alloc(arg);
break;
case 'r':
{
char *name = safe_filename_alloc(arg);
char *name = safe_string_alloc(arg);
struct resolvc *new, *list = daemon->resolv_files;
if (list && list->is_default)
@@ -435,6 +524,7 @@ struct daemon *read_opts (int argc, char **argv)
new->next = list;
new->name = name;
new->is_default = 0;
new->mtime = 0;
new->logged = 0;
list = new;
}
@@ -447,11 +537,11 @@ struct daemon *read_opts (int argc, char **argv)
int pref = 1;
struct mx_srv_record *new;
if ((comma = strchr(arg, '\001')))
if ((comma = safe_strchr(arg, ',')))
{
char *prefstr;
*(comma++) = 0;
if ((prefstr=strchr(comma, '\001')))
if ((prefstr=strchr(comma, ',')))
{
*(prefstr++) = 0;
if (!atoi_check(prefstr, &pref))
@@ -463,7 +553,7 @@ struct daemon *read_opts (int argc, char **argv)
}
}
if (!canonicalise(arg) || (comma && !canonicalise(comma)))
if (!canonicalise_opt(arg) || (comma && !canonicalise_opt(comma)))
{
option = '?';
problem = "bad MX name";
@@ -481,7 +571,7 @@ struct daemon *read_opts (int argc, char **argv)
}
case 't':
if (!canonicalise(arg))
if (!canonicalise_opt(arg))
{
option = '?';
problem = "bad MX target";
@@ -491,13 +581,13 @@ struct daemon *read_opts (int argc, char **argv)
break;
case 'l':
daemon->lease_file = safe_filename_alloc(arg);
daemon->lease_file = safe_string_alloc(arg);
break;
case 'H':
{
struct hostsfile *new = safe_malloc(sizeof(struct hostsfile));
new->fname = safe_filename_alloc(arg);
new->fname = safe_string_alloc(arg);
new->index = hosts_index++;
new->next = daemon->addn_hosts;
daemon->addn_hosts = new;
@@ -507,7 +597,7 @@ struct daemon *read_opts (int argc, char **argv)
case 's':
if (strcmp (arg, "#") == 0)
daemon->options |= OPT_RESOLV_DOMAIN;
else if (!canonicalise(arg))
else if (!canonicalise_opt(arg))
option = '?';
else
daemon->domain_suffix = safe_string_alloc(arg);
@@ -524,7 +614,7 @@ struct daemon *read_opts (int argc, char **argv)
case 'i':
do {
struct iname *new = safe_malloc(sizeof(struct iname));
if ((comma = strchr(arg, '\001')))
if ((comma = safe_strchr(arg, ',')))
*comma++ = 0;
new->next = daemon->if_names;
daemon->if_names = new;
@@ -532,30 +622,40 @@ struct daemon *read_opts (int argc, char **argv)
"interface=" to disable all interfaces except loop. */
new->name = safe_string_alloc(arg);
new->isloop = new->used = 0;
if (strchr(arg, ':'))
if (safe_strchr(new->name, ':'))
daemon->options |= OPT_NOWILD;
arg = comma;
} while (arg);
break;
case 'I':
case '2':
do {
struct iname *new = safe_malloc(sizeof(struct iname));
if ((comma = strchr(arg, '\001')))
if ((comma = safe_strchr(arg, ',')))
*comma++ = 0;
new->next = daemon->if_except;
daemon->if_except = new;
new->name = safe_string_alloc(arg);
if (strchr(arg, ':'))
daemon->options |= OPT_NOWILD;
if (option == 'I')
{
new->next = daemon->if_except;
daemon->if_except = new;
if (safe_strchr(new->name, ':'))
daemon->options |= OPT_NOWILD;
}
else
{
new->next = daemon->dhcp_except;
daemon->dhcp_except = new;
}
arg = comma;
} while (arg);
break;
case 'B':
{
struct in_addr addr;
if ((addr.s_addr = inet_addr(arg)) != (in_addr_t)-1)
unhide_metas(arg);
if (arg && (addr.s_addr = inet_addr(arg)) != (in_addr_t)-1)
{
struct bogus_addr *baddr = safe_malloc(sizeof(struct bogus_addr));
baddr->next = daemon->bogus_addr;
@@ -570,18 +670,19 @@ struct daemon *read_opts (int argc, char **argv)
case 'a':
do {
struct iname *new = safe_malloc(sizeof(struct iname));
if ((comma = strchr(arg, '\001')))
if ((comma = safe_strchr(arg, ',')))
*comma++ = 0;
unhide_metas(arg);
new->next = daemon->if_addrs;
#ifdef HAVE_IPV6
if (inet_pton(AF_INET, arg, &new->addr.in.sin_addr))
if (arg && (new->addr.in.sin_addr.s_addr = inet_addr(arg)) != (in_addr_t)-1)
{
new->addr.sa.sa_family = AF_INET;
#ifdef HAVE_SOCKADDR_SA_LEN
new->addr.in.sin_len = sizeof(struct sockaddr_in);
#endif
}
else if (inet_pton(AF_INET6, arg, &new->addr.in6.sin6_addr))
#ifdef HAVE_IPV6
else if (arg && inet_pton(AF_INET6, arg, &new->addr.in6.sin6_addr) > 0)
{
new->addr.sa.sa_family = AF_INET6;
new->addr.in6.sin6_flowinfo = htonl(0);
@@ -589,14 +690,6 @@ struct daemon *read_opts (int argc, char **argv)
new->addr.in6.sin6_len = sizeof(struct sockaddr_in6);
#endif
}
#else
if ((new->addr.in.sin_addr.s_addr = inet_addr(arg)) != (in_addr_t)-1)
{
new->addr.sa.sa_family = AF_INET;
#ifdef HAVE_SOCKADDR_SA_LEN
new->addr.in.sin_len = sizeof(struct sockaddr_in);
#endif
}
#endif
else
{
@@ -615,7 +708,9 @@ struct daemon *read_opts (int argc, char **argv)
{
struct server *serv, *newlist = NULL;
if (*arg == '/')
unhide_metas(arg);
if (arg && *arg == '/')
{
char *end;
arg++;
@@ -626,7 +721,7 @@ struct daemon *read_opts (int argc, char **argv)
/* # matches everything and becomes a zero length domain string */
if (strcmp(arg, "#") == 0)
domain = "";
else if (!canonicalise(arg) && strlen(arg) != 0)
else if (!canonicalise_opt(arg) && strlen(arg) != 0)
option = '?';
else
domain = safe_string_alloc(arg); /* NULL if strlen is zero */
@@ -661,7 +756,7 @@ struct daemon *read_opts (int argc, char **argv)
option = '?';
}
if (!*arg)
if (!arg || !*arg)
{
newlist->flags |= SERV_NO_ADDR; /* no server */
if (newlist->flags & SERV_LITERAL_ADDRESS)
@@ -696,11 +791,7 @@ struct daemon *read_opts (int argc, char **argv)
}
}
#ifdef HAVE_IPV6
if (inet_pton(AF_INET, arg, &newlist->addr.in.sin_addr))
#else
if ((newlist->addr.in.sin_addr.s_addr = inet_addr(arg)) != (in_addr_t) -1)
#endif
{
newlist->addr.in.sin_port = htons(serv_port);
newlist->source_addr.in.sin_port = htons(source_port);
@@ -710,11 +801,7 @@ struct daemon *read_opts (int argc, char **argv)
#endif
if (source)
{
#ifdef HAVE_IPV6
if (inet_pton(AF_INET, source+1, &newlist->source_addr.in.sin_addr))
#else
if ((newlist->source_addr.in.sin_addr.s_addr = inet_addr(source+1)) != (in_addr_t) -1)
#endif
newlist->flags |= SERV_HAS_SOURCE;
else
option = '?'; /* error */
@@ -723,7 +810,7 @@ struct daemon *read_opts (int argc, char **argv)
newlist->source_addr.in.sin_addr.s_addr = INADDR_ANY;
}
#ifdef HAVE_IPV6
else if (inet_pton(AF_INET6, arg, &newlist->addr.in6.sin6_addr))
else if (inet_pton(AF_INET6, arg, &newlist->addr.in6.sin6_addr) > 0)
{
newlist->addr.in6.sin6_port = htons(serv_port);
newlist->source_addr.in6.sin6_port = htons(source_port);
@@ -734,7 +821,7 @@ struct daemon *read_opts (int argc, char **argv)
#endif
if (source)
{
if (inet_pton(AF_INET6, source+1, &newlist->source_addr.in6.sin6_addr))
if (inet_pton(AF_INET6, source+1, &newlist->source_addr.in6.sin6_addr) > 0)
newlist->flags |= SERV_HAS_SOURCE;
else
option = '?'; /* error */
@@ -774,6 +861,7 @@ struct daemon *read_opts (int argc, char **argv)
case 'c':
{
int size;
if (!atoi_check(arg, &size))
option = '?';
else
@@ -841,11 +929,17 @@ struct daemon *read_opts (int argc, char **argv)
problem = "bad dhcp-range";
if (!arg)
{
option = '?';
break;
}
for (cp = arg; *cp; cp++)
if (!(*cp == ' ' || *cp == '.' || (*cp >='0' && *cp <= '9')))
break;
if (*cp != '\001' && (comma = strchr(arg, '\001')))
if (*cp != ',' && (comma = strchr(arg, ',')))
{
*comma = 0;
if (strstr(arg, "net:") == arg)
@@ -864,7 +958,7 @@ struct daemon *read_opts (int argc, char **argv)
for (k = 1; k < 5; k++)
{
if (!(a[k] = strchr(a[k-1], '\001')))
if (!(a[k] = strchr(a[k-1], ',')))
break;
*(a[k]++) = 0;
}
@@ -924,6 +1018,10 @@ struct daemon *read_opts (int argc, char **argv)
{
switch (a[leasepos][strlen(a[leasepos]) - 1])
{
case 'd':
case 'D':
fac *= 24;
/* fall though */
case 'h':
case 'H':
fac *= 60;
@@ -962,15 +1060,17 @@ struct daemon *read_opts (int argc, char **argv)
new->flags = 0;
a[0] = arg;
for (k = 1; k < 6; k++)
{
if (!(a[k] = strchr(a[k-1], '\001')))
break;
*(a[k]++) = 0;
}
if ((a[0] = arg))
for (k = 1; k < 6; k++)
{
if (!(a[k] = strchr(a[k-1], ',')))
break;
*(a[k]++) = 0;
}
else
k = 0;
for(j = 0; j < k; j++)
for (j = 0; j < k; j++)
if (strchr(a[j], ':')) /* ethernet address, netid or binary CLID */
{
char *arg = a[j];
@@ -986,7 +1086,7 @@ struct daemon *read_opts (int argc, char **argv)
int len;
arg += 3; /* dump id: */
if (strchr(arg, ':'))
len = parse_hex(arg, arg, -1, NULL);
len = parse_hex(arg, (unsigned char *)arg, -1, NULL);
else
len = (int) strlen(arg);
@@ -1022,6 +1122,10 @@ struct daemon *read_opts (int argc, char **argv)
last = *lastp;
switch (last)
{
case 'd':
case 'D':
fac *= 24;
/* fall through */
case 'h':
case 'H':
fac *= 60;
@@ -1100,7 +1204,7 @@ struct daemon *read_opts (int argc, char **argv)
new->val = NULL;
new->vendor_class = NULL;
if ((comma = strchr(arg, '\001')))
if ((comma = safe_strchr(arg, ',')))
{
struct dhcp_netid *np = NULL;
*comma++ = 0;
@@ -1113,7 +1217,7 @@ struct daemon *read_opts (int argc, char **argv)
break;
if (strstr(arg, "vendor:") == arg)
new->vendor_class = safe_string_alloc(arg+7);
new->vendor_class = (unsigned char *)safe_string_alloc(arg+7);
else
{
new->netid = safe_malloc(sizeof (struct dhcp_netid));
@@ -1122,7 +1226,7 @@ struct daemon *read_opts (int argc, char **argv)
np = new->netid;
}
arg = comma;
if ((comma = strchr(arg, '\001')))
if ((comma = safe_strchr(arg, ',')))
*comma++ = 0;
} while (arg);
}
@@ -1140,12 +1244,12 @@ struct daemon *read_opts (int argc, char **argv)
size_t newlen, len = 0;
arg = comma;
if ((comma = strchr(arg, '\001')))
if ((comma = safe_strchr(arg, ',')))
*(comma++) = 0;
while (arg && *arg)
{
if (!canonicalise(arg))
if (!canonicalise_opt(arg))
{
option = '?';
problem = "bad domain in dhcp-option";
@@ -1159,7 +1263,7 @@ struct daemon *read_opts (int argc, char **argv)
/* add string on the end in RFC1035 format */
while (*arg)
{
char *cp = q++;
unsigned char *cp = q++;
int j;
for (j = 0; *arg && (*arg != '.'); arg++, j++)
*q++ = *arg;
@@ -1173,7 +1277,7 @@ struct daemon *read_opts (int argc, char **argv)
newlen = q - p;
for (tail = p + len; *tail; tail += (*tail) + 1)
for (r = p; r - p < (int)len; r += (*r) + 1)
if (strcmp(r, tail) == 0)
if (strcmp((char *)r, (char *)tail) == 0)
{
PUTSHORT((r - p) | 0xc000, tail);
newlen = tail - p;
@@ -1183,7 +1287,7 @@ struct daemon *read_opts (int argc, char **argv)
len = newlen;
arg = comma;
if (arg && (comma = strchr(arg, '\001')))
if ((comma = safe_strchr(arg, ',')))
*(comma++) = 0;
}
@@ -1197,7 +1301,7 @@ struct daemon *read_opts (int argc, char **argv)
is_addr = is_hex = is_dec = 1;
addrs = digs = 1;
for (cp = comma; *cp; cp++)
if (*cp == '\001')
if (*cp == ',')
{
addrs++;
is_dec = is_hex = 0;
@@ -1275,7 +1379,7 @@ struct daemon *read_opts (int argc, char **argv)
while (addrs--)
{
cp = comma;
if ((comma = strchr(cp, '\001')))
if ((comma = strchr(cp, ',')))
*comma++ = 0;
in.s_addr = inet_addr(cp);
memcpy(op, &in, INADDRSZ);
@@ -1287,7 +1391,7 @@ struct daemon *read_opts (int argc, char **argv)
/* text arg */
new->len = strlen(comma);
/* keep terminating zero on string */
new->val = safe_string_alloc(comma);
new->val = (unsigned char *)safe_string_alloc(comma);
}
}
@@ -1328,7 +1432,7 @@ struct daemon *read_opts (int argc, char **argv)
struct dhcp_netid *newid = safe_malloc(sizeof(struct dhcp_netid));
newid->next = id;
id = newid;
if ((comma = strchr(arg, '\001')))
if ((comma = strchr(arg, ',')))
*comma++ = 0;
newid->net = safe_string_alloc(arg+4);
arg = comma;
@@ -1340,18 +1444,22 @@ struct daemon *read_opts (int argc, char **argv)
{
char *dhcp_file, *dhcp_sname = NULL;
struct in_addr dhcp_next_server;
if ((comma = strchr(arg, '\001')))
if ((comma = strchr(arg, ',')))
*comma++ = 0;
dhcp_file = safe_string_alloc(arg);
dhcp_next_server.s_addr = 0;
if (comma)
{
arg = comma;
if ((comma = strchr(arg, '\001')))
if ((comma = strchr(arg, ',')))
*comma++ = 0;
dhcp_sname = safe_string_alloc(arg);
if (comma && (dhcp_next_server.s_addr = inet_addr(comma)) == (in_addr_t)-1)
option = '?';
if (comma)
{
unhide_metas(comma);
if ((dhcp_next_server.s_addr = inet_addr(comma)) == (in_addr_t)-1)
option = '?';
}
}
if (option != '?')
{
@@ -1380,13 +1488,14 @@ struct daemon *read_opts (int argc, char **argv)
case 'U':
case 'j':
{
if (!(comma = strchr(arg, '\001')))
if (!(comma = safe_strchr(arg, ',')))
option = '?';
else
{
struct dhcp_vendor *new = safe_malloc(sizeof(struct dhcp_vendor));
*comma = 0;
new->netid.net = safe_string_alloc(arg);
unhide_metas(comma+1);
new->len = strlen(comma+1);
new->data = safe_malloc(new->len);
memcpy(new->data, comma+1, new->len);
@@ -1405,7 +1514,7 @@ struct daemon *read_opts (int argc, char **argv)
daemon->dhcp_ignore = new;
do {
struct dhcp_netid *member = safe_malloc(sizeof(struct dhcp_netid));
if ((comma = strchr(arg, '\001')))
if ((comma = safe_strchr(arg, ',')))
*comma++ = 0;
member->next = list;
list = member;
@@ -1426,15 +1535,18 @@ struct daemon *read_opts (int argc, char **argv)
mask.s_addr = 0xffffffff;
a[0] = arg;
for (k = 1; k < 4; k++)
{
if (!(a[k] = strchr(a[k-1], '\001')))
break;
*(a[k]++) = 0;
}
if ((a[0] = arg))
for (k = 1; k < 3; k++)
{
if (!(a[k] = strchr(a[k-1], ',')))
break;
*(a[k]++) = 0;
unhide_metas(a[k]);
}
else
k = 0;
if ((k < 2) ||
if ((k < 2) ||
((in.s_addr = inet_addr(a[0])) == (in_addr_t)-1) ||
((out.s_addr = inet_addr(a[1])) == (in_addr_t)-1))
{
@@ -1460,21 +1572,21 @@ struct daemon *read_opts (int argc, char **argv)
struct txt_record *new;
unsigned char *p, *q;
if ((comma = strchr(arg, '\001')))
if ((comma = safe_strchr(arg, ',')))
*(comma) = 0;
if (!canonicalise(arg))
if (!canonicalise_opt(arg))
{
option = '?';
problem = "bad TXT record";
break;
}
if ((q = comma))
if ((q = (unsigned char *)comma))
while (1)
{
size_t len;
if ((p = strchr(q+1, '\001')))
if ((p = (unsigned char *)strchr((char*)q+1, ',')))
{
if ((len = p - q - 1) > 255)
{
@@ -1482,13 +1594,16 @@ struct daemon *read_opts (int argc, char **argv)
break;
}
*q = len;
q = p;
for (q = q+1; q < p; q++)
*q = unhide_meta(*q);
}
else
{
if ((len = strlen(q+1)) > 255)
if ((len = strlen((char *)q+1)) > 255)
option = '?';
*q = len;
for (q = q+1; *q; q++)
*q = unhide_meta(*q);
break;
}
}
@@ -1505,7 +1620,7 @@ struct daemon *read_opts (int argc, char **argv)
new->class = C_IN;
if (comma)
{
new->len = q - ((unsigned char *)comma) + *q + 1;
new->len = q - ((unsigned char *)comma);
new->txt = safe_malloc(new->len);
memcpy(new->txt, comma, new->len);
}
@@ -1528,10 +1643,10 @@ struct daemon *read_opts (int argc, char **argv)
char *name, *target = NULL;
struct mx_srv_record *new;
if ((comma = strchr(arg, '\001')))
if ((comma = safe_strchr(arg, ',')))
*(comma++) = 0;
if (!canonicalise(arg))
if (!canonicalise_opt(arg))
{
option = '?';
problem = "bad SRV record";
@@ -1542,9 +1657,9 @@ struct daemon *read_opts (int argc, char **argv)
if (comma)
{
arg = comma;
if ((comma = strchr(arg, '\001')))
if ((comma = strchr(arg, ',')))
*(comma++) = 0;
if (!canonicalise(arg))
if (!canonicalise_opt(arg))
{
option = '?';
problem = "bad SRV target";
@@ -1554,7 +1669,7 @@ struct daemon *read_opts (int argc, char **argv)
if (comma)
{
arg = comma;
if ((comma = strchr(arg, '\001')))
if ((comma = strchr(arg, ',')))
*(comma++) = 0;
if (!atoi_check(arg, &port))
{
@@ -1565,7 +1680,7 @@ struct daemon *read_opts (int argc, char **argv)
if (comma)
{
arg = comma;
if ((comma = strchr(arg, '\001')))
if ((comma = strchr(arg, ',')))
*(comma++) = 0;
if (!atoi_check(arg, &priority))
{
@@ -1576,7 +1691,7 @@ struct daemon *read_opts (int argc, char **argv)
if (comma)
{
arg = comma;
if ((comma = strchr(arg, '\001')))
if ((comma = strchr(arg, ',')))
*(comma++) = 0;
if (!atoi_check(arg, &weight))
{
@@ -1674,27 +1789,11 @@ struct daemon *read_opts (int argc, char **argv)
mx->target = daemon->mxtarget;
}
if (daemon->domain_suffix)
{
/* add domain for any srv record without one. */
struct mx_srv_record *srv;
for (srv = daemon->mxnames; srv; srv = srv->next)
if (srv->issrv &&
strchr(srv->name, '.') &&
strchr(srv->name, '.') == strrchr(srv->name, '.'))
{
strcpy(buff, srv->name);
strcat(buff, ".");
strcat(buff, daemon->domain_suffix);
free(srv->name);
srv->name = safe_string_alloc(buff);
}
}
if (daemon->options & OPT_NO_RESOLV)
daemon->resolv_files = 0;
else if (daemon->resolv_files && (daemon->resolv_files)->next && (daemon->options & OPT_NO_POLL))
else if (daemon->resolv_files &&
(daemon->resolv_files)->next &&
(daemon->options & OPT_NO_POLL))
die("only one resolv.conf file allowed in no-poll mode.", NULL);
if (daemon->options & OPT_RESOLV_DOMAIN)
@@ -1715,7 +1814,7 @@ struct daemon *read_opts (int argc, char **argv)
continue;
if ((token = strtok(NULL, " \t\n\r")) &&
canonicalise(token) &&
canonicalise_opt(token) &&
(daemon->domain_suffix = safe_string_alloc(token)))
break;
}
@@ -1725,7 +1824,25 @@ struct daemon *read_opts (int argc, char **argv)
if (!daemon->domain_suffix)
die("no search directive found in %s", (daemon->resolv_files)->name);
}
if (daemon->domain_suffix)
{
/* add domain for any srv record without one. */
struct mx_srv_record *srv;
for (srv = daemon->mxnames; srv; srv = srv->next)
if (srv->issrv &&
strchr(srv->name, '.') &&
strchr(srv->name, '.') == strrchr(srv->name, '.'))
{
strcpy(buff, srv->name);
strcat(buff, ".");
strcat(buff, daemon->domain_suffix);
free(srv->name);
srv->name = safe_string_alloc(buff);
}
}
return daemon;
}

View File

@@ -14,13 +14,13 @@
static int add_resource_record(HEADER *header, char *limit, int *truncp,
unsigned int nameoffset, unsigned char **pp,
unsigned long ttl, int *offset, unsigned short type,
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,
unsigned char *name, int isExtract)
char *name, int isExtract)
{
unsigned char *cp = name, *p = *pp, *p1 = NULL;
unsigned char *cp = (unsigned char *)name, *p = *pp, *p1 = NULL;
unsigned int j, l, hops = 0;
int retvalue = 1;
@@ -68,7 +68,7 @@ static int extract_name(HEADER *header, unsigned int plen, unsigned char **pp,
digs = ((count-1)>>2)+1;
/* output is \[x<hex>/siz]. which is digs+9 chars */
if (cp - name + digs + 9 >= MAXDNAME)
if (cp - (unsigned char *)name + digs + 9 >= MAXDNAME)
return 0;
if (p - (unsigned char *)header + ((count-1)>>3) + 1u >= plen)
return 0;
@@ -86,13 +86,13 @@ static int extract_name(HEADER *header, unsigned int plen, unsigned char **pp,
*cp++ = dig < 10 ? dig + '0' : dig + 'A' - 10;
}
cp += sprintf(cp, "/%d]", count);
cp += sprintf((char *)cp, "/%d]", count);
/* do this here to overwrite the zero char from sprintf */
*cp++ = '.';
}
else
{ /* label_type = 0 -> label. */
if (cp - name + l + 1 >= MAXDNAME)
if (cp - (unsigned char *)name + l + 1 >= MAXDNAME)
return 0;
if (p - (unsigned char *)header + 1u >= plen)
return 0;
@@ -349,7 +349,7 @@ unsigned int questions_crc(HEADER *header, unsigned int plen, char *name)
if (!extract_name(header, plen, &p, name, 1))
return crc; /* bad packet */
for (p1 = name; *p1; p1++)
for (p1 = (unsigned char *)name; *p1; p1++)
{
int i = 8;
char c = *p1;
@@ -883,7 +883,7 @@ int check_for_bogus_wildcard(HEADER *header, unsigned int qlen, char *name,
}
static int add_resource_record(HEADER *header, char *limit, int *truncp, unsigned int nameoffset, unsigned char **pp,
unsigned long ttl, int *offset, unsigned short type, unsigned short class, char *format, ...)
unsigned long ttl, unsigned int *offset, unsigned short type, unsigned short class, char *format, ...)
{
va_list ap;
unsigned char *sav, *p = *pp;
@@ -936,19 +936,10 @@ static int add_resource_record(HEADER *header, char *limit, int *truncp, unsigne
/* get domain-name answer arg and store it in RDATA field */
if (offset)
*offset = p - (unsigned char *)header;
sval = va_arg(ap, char *);
while (sval && *sval)
{
unsigned char *cp = p++;
for (j = 0; *sval && (*sval != '.'); sval++, j++)
*p++ = *sval;
*cp = j;
if (*sval)
sval++;
}
p = do_rfc1035_name(p, va_arg(ap, char *));
*p++ = 0;
break;
case 't':
usval = va_arg(ap, int);
sval = va_arg(ap, char *);
@@ -1126,17 +1117,31 @@ int answer_request(HEADER *header, char *limit, unsigned int qlen, struct daemon
for (flag = F_IPV4; flag; flag = (flag == F_IPV4) ? F_IPV6 : 0)
{
unsigned short type = T_A;
if (flag == F_IPV6)
#ifdef HAVE_IPV6
type = T_AAAA;
type = T_AAAA;
#else
break;
break;
#endif
if (qtype != type && qtype != T_ANY)
continue;
/* Check for "A for A" queries. */
if (qtype == T_A && (addr.addr.addr4.s_addr = inet_addr(name)) != (in_addr_t) -1)
{
ans = 1;
if (!dryrun)
{
log_query(F_FORWARD | F_CONFIG | F_IPV4, name, &addr, 0, NULL, 0);
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
daemon->local_ttl, NULL, type, C_IN, "4", &addr))
anscount++;
}
continue;
}
cname_restart:
if ((crecp = cache_find_by_name(NULL, name, now, flag | F_CNAME)))
{
@@ -1231,7 +1236,7 @@ int answer_request(HEADER *header, char *limit, unsigned int qlen, struct daemon
ans = found = 1;
if (!dryrun)
{
int offset;
unsigned int offset;
log_query(F_CNAME | F_FORWARD | F_CONFIG | F_IPV4, name, NULL, 0, NULL, 0);
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
&offset, T_MX, C_IN, "sd", rec->weight, rec->target))
@@ -1268,7 +1273,7 @@ int answer_request(HEADER *header, char *limit, unsigned int qlen, struct daemon
found = ans = 1;
if (!dryrun)
{
int offset;
unsigned int offset;
log_query(F_CNAME | F_FORWARD | F_CONFIG | F_IPV6, name, NULL, 0, NULL, 0);
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
&offset, T_SRV, C_IN, "sssd",

View File

@@ -43,6 +43,7 @@
#define OPTION_VENDOR_ID 60
#define OPTION_CLIENT_ID 61
#define OPTION_USER_CLASS 77
#define OPTION_CLIENT_FQDN 81
#define OPTION_SUBNET_SELECT 118
#define OPTION_END 255
@@ -74,11 +75,11 @@ static unsigned char *do_req_options(struct dhcp_context *context,
struct daemon *daemon,
char *hostname,
struct dhcp_netid *netid,
struct in_addr subnet_addr);
struct in_addr subnet_addr,
unsigned char fqdn_flags);
int dhcp_reply(struct daemon *daemon, struct dhcp_context *context, char *iface_name, unsigned int sz, time_t now)
{
struct dhcp_context *context_tmp;
unsigned char *opt, *clid = NULL;
struct dhcp_lease *ltmp, *lease = NULL;
struct dhcp_vendor *vendor;
@@ -87,40 +88,22 @@ int dhcp_reply(struct daemon *daemon, struct dhcp_context *context, char *iface_
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;
char *req_options = NULL;
char *hostname = NULL, *offer_hostname = NULL, *client_hostname = NULL;
unsigned char *req_options = NULL;
char *message = NULL;
unsigned int time;
struct dhcp_config *config;
struct dhcp_netid *netid = NULL;
struct in_addr addr, subnet_addr;
struct in_addr subnet_addr;
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;
/* 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)
return 0;
/* check for DHCP rather than BOOTP */
if ((opt = option_find(mess, sz, OPTION_MESSAGE_TYPE, 1)))
{
@@ -147,7 +130,8 @@ int dhcp_reply(struct daemon *daemon, struct dhcp_context *context, char *iface_
}
/* do we have a lease in store? */
lease = lease_find_by_client(mess->chaddr, clid, clid_len);
if (mess->htype != 0)
lease = lease_find_by_client(mess->chaddr, clid, clid_len);
/* If this request is missing a clid, but we've seen one before,
use it again for option matching etc. */
@@ -158,26 +142,75 @@ 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)
{
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)
return 0;
}
/* 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
machine has an address already, or came via a relay, or we have a subnet selector,
we search again. If we don't have have a giaddr or explicit subnet selector,
use the ciaddr. This is necessary because a machine which got a lease via a
relay won't use the relay to renew. */
relay won't use the relay to renew. If matching a ciaddr fails but we have a context
from the physical network, continue using that to allow correct DHCPNAK generation later. */
if (mess->giaddr.s_addr || subnet_addr.s_addr || mess->ciaddr.s_addr)
{
addr =
subnet_addr.s_addr ? subnet_addr :
(mess->giaddr.s_addr ? mess->giaddr : mess->ciaddr);
struct dhcp_context *context_tmp, *context_new = NULL;
struct in_addr addr = mess->ciaddr;
int force = 0;
for (context = NULL, context_tmp = daemon->dhcp; context_tmp; context_tmp = context_tmp->next)
if (subnet_addr.s_addr)
{
addr = subnet_addr;
force = 1;
}
else if (mess->giaddr.s_addr)
{
addr = mess->giaddr;
force = 1;
}
for (context_tmp = daemon->dhcp; context_tmp; context_tmp = context_tmp->next)
if (context_tmp->netmask.s_addr &&
is_same_net(addr, context_tmp->start, context_tmp->netmask) &&
is_same_net(addr, context_tmp->end, context_tmp->netmask))
{
context_tmp->current = context;
context = context_tmp;
context_tmp->current = context_new;
context_new = context_tmp;
}
if (context_new || force)
context = context_new;
}
if (!context)
@@ -190,7 +223,7 @@ 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, mess->chaddr, NULL);
config = find_config(daemon->dhcp_conf, context, clid, clid_len, chaddr, NULL);
if (mess_type == 0)
{
@@ -199,17 +232,6 @@ int dhcp_reply(struct daemon *daemon, struct dhcp_context *context, char *iface_
char save = mess->file[128];
struct in_addr *logaddr = NULL;
if (have_config(config, CONFIG_ADDR))
{
logaddr = &config->addr;
mess->yiaddr = config->addr;
if (lease_find_by_addr(config->addr))
message = "address in use";
context = narrow_context(context, config->addr);
}
else
message = "no address configured";
if (have_config(config, CONFIG_DISABLE))
message = "disabled";
@@ -218,12 +240,6 @@ int dhcp_reply(struct daemon *daemon, struct dhcp_context *context, char *iface_
if (have_config(config, CONFIG_NAME))
hostname = config->hostname;
if (context->netid.net && !(context->flags & CONTEXT_FILTER))
{
context->netid.next = netid;
netid = &context->netid;
}
if (have_config(config, CONFIG_NETID))
{
config->netid.next = netid;
@@ -234,7 +250,7 @@ int dhcp_reply(struct daemon *daemon, struct dhcp_context *context, char *iface_
if (mess->file[0])
{
mess->file[128] = 0; /* ensure zero term. */
id.net = mess->file;
id.net = (char *)mess->file;
id.next = netid;
netid = &id;
}
@@ -243,13 +259,55 @@ int dhcp_reply(struct daemon *daemon, struct dhcp_context *context, char *iface_
if (match_netid(id_list->list, netid))
message = "disabled";
p = do_req_options(context, p, end, NULL, daemon,
hostname, netid, subnet_addr);
/* must do this after do_req_options since it overwrites filename field. */
mess->siaddr = context->local;
bootp_option_put(mess, daemon->boot_config, netid);
p = option_end(p, end, mess);
log_packet(NULL, logaddr, mess->chaddr, iface_name, message);
if (!message)
{
if (have_config(config, CONFIG_ADDR))
{
logaddr = &config->addr;
mess->yiaddr = config->addr;
if ((lease = lease_find_by_addr(config->addr)) &&
memcmp(lease->hwaddr, chaddr, ETHER_ADDR_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)))
mess->yiaddr = lease->addr;
else if (!address_allocate(context, daemon, &mess->yiaddr, chaddr, netid, now))
message = "no address available";
}
if (!message && !lease && (!(lease = lease_allocate(chaddr, NULL, 0, mess->yiaddr))))
message = "no leases left";
if (!message)
{
logaddr = &mess->yiaddr;
context = narrow_context(context, mess->yiaddr);
if (context->netid.net && !(context->flags & CONTEXT_FILTER))
{
context->netid.next = netid;
netid = &context->netid;
}
lease_set_hwaddr(lease, chaddr, NULL, 0);
if (hostname)
lease_set_hostname(lease, hostname, daemon->domain_suffix);
lease_set_expires(lease, 0); /* infinite lease */
p = do_req_options(context, p, end, NULL, daemon,
hostname, netid, subnet_addr, fqdn_flags);
/* must do this after do_req_options since it overwrites filename field. */
mess->siaddr = context->local;
bootp_option_put(mess, daemon->boot_config, netid);
p = option_end(p, end, mess);
}
}
log_packet(NULL, logaddr, chaddr, iface_name, message);
mess->file[128] = save;
if (message)
@@ -258,27 +316,73 @@ int dhcp_reply(struct daemon *daemon, struct dhcp_context *context, char *iface_
return p - (unsigned char *)mess;
}
if (have_config(config, CONFIG_NAME))
hostname = config->hostname;
if ((opt = option_find(mess, sz, OPTION_CLIENT_FQDN, 4)))
{
/* http://tools.ietf.org/wg/dhc/draft-ietf-dhc-fqdn-option/draft-ietf-dhc-fqdn-option-10.txt */
int len = option_len(opt);
char *pq = daemon->dhcp_buff;
unsigned char *pp, *op = option_ptr(opt);
fqdn_flags = *op;
len -= 3;
op += 3;
pp = op;
/* Always force update, since the client has no way to do it itself. */
if (fqdn_flags & 0x01)
fqdn_flags |= 0x02;
fqdn_flags &= ~0x08;
fqdn_flags |= 0x01;
if (fqdn_flags & 0x04)
while (*op != 0 && ((op + (*op) + 1) - pp) < len)
{
memcpy(pq, op+1, *op);
pq += *op;
op += (*op)+1;
*(pq++) = '.';
}
else
{
memcpy(pq, op, len);
pq += len + 1;
}
if (pq != daemon->dhcp_buff)
pq--;
*pq = 0;
if (canonicalise(daemon->dhcp_buff))
offer_hostname = client_hostname = daemon->dhcp_buff;
}
else if ((opt = option_find(mess, sz, OPTION_HOSTNAME, 1)))
{
int len = option_len(opt);
hostname = daemon->dhcp_buff;
memcpy(hostname, option_ptr(opt), len);
memcpy(daemon->dhcp_buff, option_ptr(opt), len);
/* May not be zero terminated */
hostname[len] = 0;
/* ensure there are no strange chars in there */
if (!canonicalise(hostname))
hostname = NULL;
else if ((hostname = strip_hostname(daemon, hostname)) && !config)
{
/* 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, mess->chaddr, hostname);
if (!have_config(new, CONFIG_CLID) && !have_config(new, CONFIG_HWADDR))
config = new;
}
daemon->dhcp_buff[len] = 0;
if (canonicalise(daemon->dhcp_buff))
client_hostname = daemon->dhcp_buff;
}
if (have_config(config, CONFIG_NAME))
{
hostname = config->hostname;
/* be careful not to send an OFFER with a hostname not
matching the DISCOVER. */
if (fqdn_flags != 0 || !client_hostname || hostname_isequal(hostname, client_hostname))
offer_hostname = hostname;
}
else if (client_hostname && (hostname = strip_hostname(daemon, client_hostname)) && !config)
{
/* 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);
if (!have_config(new, CONFIG_CLID) && !have_config(new, CONFIG_HWADDR))
config = new;
}
if (have_config(config, CONFIG_NETID))
@@ -332,7 +436,7 @@ int dhcp_reply(struct daemon *daemon, struct dhcp_context *context, char *iface_
if ((opt = option_find(mess, sz, OPTION_REQUESTED_OPTIONS, 0)))
{
req_options = daemon->dhcp_buff2;
req_options = (unsigned char *)daemon->dhcp_buff2;
memcpy(req_options, option_ptr(opt), option_len(opt));
req_options[option_len(opt)] = OPTION_END;
}
@@ -363,7 +467,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), mess->chaddr, iface_name, message);
log_packet("DECLINE", option_ptr(opt), chaddr, iface_name, message);
if (lease && lease->addr.s_addr == option_addr(opt).s_addr)
lease_prune(lease, now);
@@ -391,27 +495,31 @@ int dhcp_reply(struct daemon *daemon, struct dhcp_context *context, char *iface_
else
message = "unknown lease";
log_packet("RELEASE", &mess->ciaddr, mess->chaddr, iface_name, message);
log_packet("RELEASE", &mess->ciaddr, chaddr, iface_name, message);
return 0;
case DHCPDISCOVER:
if ((opt = option_find(mess, sz, OPTION_REQUESTED_IP, INADDRSZ)))
addr = option_addr(opt);
if (ignore || have_config(config, CONFIG_DISABLE))
message = "ignored";
else if (have_config(config, CONFIG_ADDR) &&
(!(ltmp = lease_find_by_addr(config->addr)) || ltmp == lease))
mess->yiaddr = config->addr;
else if (lease && address_available(context, lease->addr))
mess->yiaddr = lease->addr;
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, mess->chaddr, netid))
message = "no address available";
log_packet("DISCOVER", opt ? &addr : NULL, mess->chaddr, iface_name, message);
{
struct in_addr addr;
if ((opt = option_find(mess, sz, OPTION_REQUESTED_IP, INADDRSZ)))
addr = option_addr(opt);
if (ignore || have_config(config, CONFIG_DISABLE))
message = "ignored";
else if (have_config(config, CONFIG_ADDR) &&
(!(ltmp = lease_find_by_addr(config->addr)) || ltmp == lease))
mess->yiaddr = config->addr;
else if (lease && address_available(context, lease->addr))
mess->yiaddr = lease->addr;
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))
message = "no address available";
log_packet("DISCOVER", opt ? &addr : NULL, chaddr, iface_name, message);
}
if (message)
return 0;
@@ -444,10 +552,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,
NULL, netid, subnet_addr);
offer_hostname, netid, subnet_addr, fqdn_flags);
p = option_end(p, end, mess);
log_packet("OFFER" , &mess->yiaddr, mess->chaddr, iface_name, NULL);
log_packet("OFFER" , &mess->yiaddr, chaddr, iface_name, NULL);
return p - (unsigned char *)mess;
case DHCPREQUEST:
@@ -493,7 +601,7 @@ int dhcp_reply(struct daemon *daemon, struct dhcp_context *context, char *iface_
mess->yiaddr = mess->ciaddr;
}
log_packet("REQUEST", &mess->yiaddr, mess->chaddr, iface_name, NULL);
log_packet("REQUEST", &mess->yiaddr, chaddr, iface_name, NULL);
if (!message)
{
@@ -524,23 +632,27 @@ 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(mess->chaddr, clid, clid_len, mess->yiaddr)))
else if (!lease && !(lease = lease_allocate(chaddr, clid, clid_len, mess->yiaddr)))
message = "no leases left";
}
if (message)
{
log_packet("NAK", &mess->yiaddr, mess->chaddr, iface_name, message);
log_packet("NAK", &mess->yiaddr, chaddr, iface_name, message);
mess->siaddr.s_addr = mess->yiaddr.s_addr = mess->ciaddr.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->local.s_addr));
p = option_put_string(p, end, OPTION_MESSAGE, message);
mess->flags |= htons(0x8000); /* broadcast */
}
else
{
log_packet("ACK", &mess->yiaddr, mess->chaddr, iface_name, hostname);
if (!hostname)
hostname = host_from_dns(daemon, mess->yiaddr);
log_packet("ACK", &mess->yiaddr, chaddr, iface_name, hostname);
context = narrow_context(context, mess->yiaddr);
if (context->netid.net && !(context->flags & CONTEXT_FILTER))
@@ -557,9 +669,7 @@ int dhcp_reply(struct daemon *daemon, struct dhcp_context *context, char *iface_
time = req_time;
}
lease_set_hwaddr(lease, mess->chaddr, clid, clid_len);
if (!hostname)
hostname = host_from_dns(daemon, mess->yiaddr);
lease_set_hwaddr(lease, chaddr, clid, clid_len);
if (hostname)
lease_set_hostname(lease, hostname, daemon->domain_suffix);
lease_set_expires(lease, time == 0xffffffff ? 0 : now + (time_t)time);
@@ -577,7 +687,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);
hostname, netid, subnet_addr, fqdn_flags);
}
p = option_end(p, end, mess);
@@ -587,7 +697,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, mess->chaddr, iface_name, message);
log_packet("INFORM", &mess->ciaddr, chaddr, iface_name, message);
if (message || mess->ciaddr.s_addr == 0)
return 0;
@@ -606,10 +716,10 @@ 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);
hostname, netid, subnet_addr, fqdn_flags);
p = option_end(p, end, mess);
log_packet("ACK", &mess->ciaddr, mess->chaddr, iface_name, hostname);
log_packet("ACK", &mess->ciaddr, chaddr, iface_name, hostname);
return p - (unsigned char *)mess;
}
@@ -618,6 +728,11 @@ int dhcp_reply(struct daemon *daemon, struct dhcp_context *context, char *iface_
static void log_packet(char *type, struct in_addr *addr, unsigned char *hwaddr, char *interface, char *string)
{
u8 empty[] = { 0, 0, 0, 0, 0, 0};
if (!hwaddr)
hwaddr = empty;
syslog(LOG_INFO, "%s%s(%s)%s%s %.2x:%.2x:%.2x:%.2x:%.2x:%.2x%s%s",
type ? "DHCP" : "BOOTP",
type ? type : "",
@@ -686,9 +801,9 @@ static void bootp_option_put(struct dhcp_packet *mess,
if (tmp)
{
if (tmp->sname)
strncpy(mess->sname, tmp->sname, sizeof(mess->sname)-1);
strncpy((char *)mess->sname, tmp->sname, sizeof(mess->sname)-1);
if (tmp->file)
strncpy(mess->file, tmp->file, sizeof(mess->file)-1);
strncpy((char *)mess->file, tmp->file, sizeof(mess->file)-1);
if (tmp->next_server.s_addr)
mess->siaddr = tmp->next_server;
}
@@ -864,7 +979,8 @@ static unsigned char *do_req_options(struct dhcp_context *context,
struct daemon *daemon,
char *hostname,
struct dhcp_netid *netid,
struct in_addr subnet_addr)
struct in_addr subnet_addr,
unsigned char fqdn_flags)
{
struct dhcp_opt *opt, *config_opts = daemon->dhcp_opts;
char *vendor_class = NULL;
@@ -903,13 +1019,56 @@ static unsigned char *do_req_options(struct dhcp_context *context,
p = option_put_string(p, end, OPTION_DOMAINNAME, daemon->domain_suffix);
/* Note that we ignore attempts to set the hostname using
--dhcp-option=12,<name> */
if (hostname && in_list(req_options, OPTION_HOSTNAME))
p = option_put_string(p, end, OPTION_HOSTNAME, hostname);
--dhcp-option=12,<name> and the fqdn using
--dhc-option=81,<name> */
if (hostname)
{
if (in_list(req_options, OPTION_HOSTNAME))
p = option_put_string(p, end, OPTION_HOSTNAME, hostname);
if (fqdn_flags != 0)
{
int len = strlen(hostname) + 3;
if (fqdn_flags & 0x04)
len += 2;
if (daemon->domain_suffix)
len += strlen(daemon->domain_suffix) + 1;
if (p + len + 1 < end)
{
*(p++) = OPTION_CLIENT_FQDN;
*(p++) = len;
*(p++) = fqdn_flags;
*(p++) = 255;
*(p++) = 255;
if (fqdn_flags & 0x04)
{
p = do_rfc1035_name(p, hostname);
if (daemon->domain_suffix)
p = do_rfc1035_name(p, daemon->domain_suffix);
*p++ = 0;
}
else
{
memcpy(p, hostname, strlen(hostname));
p += strlen(hostname);
if (daemon->domain_suffix)
{
*(p++) = '.';
memcpy(p, daemon->domain_suffix, strlen(daemon->domain_suffix));
p += strlen(daemon->domain_suffix);
}
}
}
}
}
for (opt=config_opts; opt; opt = opt->next)
{
if (opt->opt == OPTION_HOSTNAME ||
opt->opt == OPTION_CLIENT_FQDN ||
opt->opt == OPTION_MAXMESSAGE ||
!in_list(req_options, opt->opt) ||
opt != option_find2(netid, config_opts, opt->opt))
@@ -927,7 +1086,7 @@ static unsigned char *do_req_options(struct dhcp_context *context,
/* opt->val has terminating zero */
if (opt->opt == OPTION_VENDOR_ID)
vendor_class = opt->val;
vendor_class = (char *)opt->val;
else
p = do_opt(opt, p, end, context->local);
}
@@ -937,10 +1096,10 @@ static unsigned char *do_req_options(struct dhcp_context *context,
for (opt = daemon->vendor_opts; opt; opt = opt->next)
if (!opt->netid || match_netid(opt->netid, netid))
{
if (vendor_class && strcmp(vendor_class, opt->vendor_class) != 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);
else
vendor_class = opt->vendor_class;
vendor_class = (char *)opt->vendor_class;
}
if (vendor_class)
@@ -964,7 +1123,7 @@ static unsigned char *do_req_options(struct dhcp_context *context,
for (opt = daemon->vendor_opts; opt; opt = opt->next)
if ((!opt->netid || match_netid(opt->netid, netid)) &&
strcmp(vendor_class, opt->vendor_class) == 0)
strcmp(vendor_class, (char *)opt->vendor_class) == 0)
p = do_opt(opt, p, oend, context->local);
*plen = p - plen - 1;

View File

@@ -85,18 +85,6 @@ unsigned short rand16(void)
return( (unsigned short) (rand() >> 15) );
}
int atoi_check(char *a, int *res)
{
char *p;
for (p = a; *p; p++)
if (*p < '0' || *p > '9')
return 0;
*res = atoi(a);
return 1;
}
int legal_char(char c)
{
/* check for legal char a-z A-Z 0-9 -
@@ -125,15 +113,33 @@ int canonicalise(char *s)
s[l-1] = 0;
}
while ((c = *s++))
if (c == '.')
dotgap = 0;
else if (!legal_char(c) || (++dotgap > MAXLABEL))
return 0;
while ((c = *s))
{
if (c == '.')
dotgap = 0;
else if (!legal_char(c) || (++dotgap > MAXLABEL))
return 0;
s++;
}
return 1;
}
unsigned char *do_rfc1035_name(unsigned char *p, char *sval)
{
int j;
while (sval && *sval)
{
unsigned char *cp = p++;
for (j = 0; *sval && (*sval != '.'); sval++, j++)
*p++ = *sval;
*cp = j;
if (*sval)
sval++;
}
return p;
}
/* for use during startup */
void *safe_malloc(size_t size)
{
@@ -143,20 +149,7 @@ void *safe_malloc(size_t size)
die("could not get memory", NULL);
return ret;
}
char *safe_string_alloc(char *cp)
{
char *ret = NULL;
if (cp && strlen(cp) != 0)
{
ret = safe_malloc(strlen(cp)+1);
strcpy(ret, cp);
}
return ret;
}
}
static void log_err(char *message, char *arg1)
{
@@ -176,8 +169,8 @@ void complain(char *message, int lineno, char *file)
{
char buff[256];
sprintf(buff, "%s at line %d of %s", message, lineno, file);
log_err(buff, NULL);
sprintf(buff, "%s at line %d of %%s", message, lineno);
log_err(buff, file);
}
void die(char *message, char *arg1)
@@ -221,13 +214,13 @@ int sa_len(union mysockaddr *addr)
}
/* don't use strcasecmp and friends here - they may be messed up by LOCALE */
int hostname_isequal(unsigned char *a, unsigned char *b)
int hostname_isequal(char *a, char *b)
{
unsigned int c1, c2;
do {
c1 = *a++;
c2 = *b++;
c1 = (unsigned char) *a++;
c2 = (unsigned char) *b++;
if (c1 >= 'A' && c1 <= 'Z')
c1 += 'a' - 'A';
@@ -250,6 +243,9 @@ time_t dnsmasq_time(int fd)
char buf[30];
lseek(fd, 0, SEEK_SET);
read(fd, buf, 30);
/* ensure the time is terminated even if /proc/uptime sends something unexpected */
buf[29] = 0;
read(fd, buf, 30);
return (time_t)atol(buf);
#else
fd = 0; /* stop warning */
@@ -279,6 +275,30 @@ int retry_send(void)
return 0;
}
/* returns port number from address */
int prettyprint_addr(union mysockaddr *addr, char *buf)
{
int port = 0;
#ifdef HAVE_IPV6
if (addr->sa.sa_family == AF_INET)
{
inet_ntop(AF_INET, &addr->in.sin_addr, buf, ADDRSTRLEN);
port = ntohs(addr->in.sin_port);
}
else if (addr->sa.sa_family == AF_INET6)
{
inet_ntop(AF_INET6, &addr->in6.sin6_addr, buf, ADDRSTRLEN);
port = ntohs(addr->in6.sin6_port);
}
#else
strcpy(buf, inet_ntoa(addr->in.sin_addr));
port = ntohs(addr->in.sin_port);
#endif
return port;
}
void prettyprint_time(char *buf, unsigned int t)
{
if (t == 0xffffffff)
@@ -286,7 +306,9 @@ void prettyprint_time(char *buf, unsigned int t)
else
{
unsigned int x, p = 0;
if ((x = t/3600))
if ((x = t/86400))
p += sprintf(&buf[p], "%dd", x);
if ((x = (t/3600)%24))
p += sprintf(&buf[p], "%dh", x);
if ((x = (t/60)%60))
p += sprintf(&buf[p], "%dm", x);