mirror of
https://github.com/pi-hole/dnsmasq.git
synced 2025-12-19 10:18:25 +00:00
import of dnsmasq-2.23.tar.gz
This commit is contained in:
16
src/Makefile
16
src/Makefile
@@ -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)
|
||||
|
||||
|
||||
|
||||
15
src/cache.c
15
src/cache.c
@@ -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)
|
||||
|
||||
13
src/config.h
13
src/config.h
@@ -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
342
src/dbus.c
Normal 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
|
||||
112
src/dhcp.c
112
src/dhcp.c
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
221
src/dnsmasq.c
221
src/dnsmasq.c
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
427
src/option.c
427
src/option.c
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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",
|
||||
|
||||
397
src/rfc2131.c
397
src/rfc2131.c
@@ -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;
|
||||
|
||||
98
src/util.c
98
src/util.c
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user