import of dnsmasq-2.43.tar.gz

This commit is contained in:
Simon Kelley
2008-07-11 11:11:42 +01:00
parent 9e038946a1
commit 1a6bca81f6
28 changed files with 5052 additions and 4241 deletions

View File

@@ -45,6 +45,7 @@ static const struct {
{ 25, "KEY" },
{ 28, "AAAA" },
{ 33, "SRV" },
{ 35, "NAPTR" },
{ 36, "KX" },
{ 37, "CERT" },
{ 38, "A6" },
@@ -63,7 +64,6 @@ static const struct {
static void cache_free(struct crec *crecp);
static void cache_unlink(struct crec *crecp);
static void cache_link(struct crec *crecp);
static char *record_source(struct hostsfile *add_hosts, int index);
static void rehash(int size);
static void cache_hash(struct crec *crecp);
@@ -361,7 +361,7 @@ struct crec *cache_insert(char *name, struct all_addr *addr,
int freed_all = flags & F_REVERSE;
int free_avail = 0;
log_query(flags | F_UPSTREAM, name, addr, 0, NULL, 0);
log_query(flags | F_UPSTREAM, name, addr, NULL);
/* CONFIG bit no needed except for logging */
flags &= ~F_CONFIG;
@@ -395,16 +395,11 @@ struct crec *cache_insert(char *name, struct all_addr *addr,
{
/* If free_avail set, we believe that an entry has been freed.
Bugs have been known to make this not true, resulting in
a tight loop here. If that happens, log a warning and abandon the
a tight loop here. If that happens, abandon the
insert. Once in this state, all inserts will probably fail. */
if (free_avail)
{
static int warned = 0;
if (!warned)
my_syslog(LOG_ERR, "BUG in cache detected. Please mail simon@thekelleys.org.uk");
warned = insert_error = 1;
insert_error = 1;
return NULL;
}
@@ -1008,7 +1003,7 @@ void dump_cache(time_t now)
}
}
static char *record_source(struct hostsfile *addn_hosts, int index)
char *record_source(struct hostsfile *addn_hosts, int index)
{
char *source = HOSTSFILE;
while (addn_hosts)
@@ -1024,12 +1019,20 @@ static char *record_source(struct hostsfile *addn_hosts, int index)
return source;
}
void log_query(unsigned short flags, char *name, struct all_addr *addr,
unsigned short type, struct hostsfile *addn_hosts, int index)
void querystr(char *str, unsigned short type)
{
unsigned int i;
sprintf(str, "query[type=%d]", type);
for (i = 0; i < (sizeof(typestr)/sizeof(typestr[0])); i++)
if (typestr[i].type == type)
sprintf(str,"query[%s]", typestr[i].name);
}
void log_query(unsigned short flags, char *name, struct all_addr *addr, char *arg)
{
char *source, *dest = addrbuff;
char *verb = "is";
char types[20];
if (!(daemon->options & OPT_LOG))
return;
@@ -1073,15 +1076,9 @@ void log_query(unsigned short flags, char *name, struct all_addr *addr,
}
else if (flags & F_CNAME)
{
/* nasty abuse of IPV4 and IPV6 flags */
if (flags & F_IPV4)
dest = "<MX>";
else if (flags & F_IPV6)
dest = "<SRV>";
else if (flags & F_NXDOMAIN)
dest = "<TXT>";
else if (flags & F_BIGNAME)
dest = "<PTR>";
/* nasty abuse of NXDOMAIN and CNAME flags */
if (flags & F_NXDOMAIN)
dest = arg;
else
dest = "<CNAME>";
}
@@ -1089,7 +1086,7 @@ void log_query(unsigned short flags, char *name, struct all_addr *addr,
if (flags & F_DHCP)
source = "DHCP";
else if (flags & F_HOSTS)
source = record_source(addn_hosts, index);
source = arg;
else if (flags & F_CONFIG)
source = "config";
else if (flags & F_UPSTREAM)
@@ -1101,16 +1098,7 @@ void log_query(unsigned short flags, char *name, struct all_addr *addr,
}
else if (flags & F_QUERY)
{
unsigned int i;
if (type != 0)
{
sprintf(types, "query[type=%d]", type);
for (i = 0; i < (sizeof(typestr)/sizeof(typestr[0])); i++)
if (typestr[i].type == type)
sprintf(types,"query[%s]", typestr[i].name);
}
source = types;
source = arg;
verb = "from";
}
else

View File

@@ -14,13 +14,14 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define VERSION "2.42"
#define VERSION "2.43"
#define FTABSIZ 150 /* max number of outstanding requests (default) */
#define MAX_PROCS 20 /* max no children for TCP requests */
#define CHILD_LIFETIME 150 /* secs 'till terminated (RFC1035 suggests > 120s) */
#define EDNS_PKTSZ 1280 /* default max EDNS.0 UDP packet from RFC2671 */
#define TIMEOUT 10 /* drop UDP queries after TIMEOUT seconds */
#define RANDOM_SOCKS 64 /* max simultaneous random ports */
#define LEASE_RETRY 60 /* on error, retry writing leasefile after LEASE_RETRY seconds */
#define CACHESIZ 150 /* default cache size */
#define MAXLEASES 150 /* maximum number of DHCP leases */
@@ -39,7 +40,7 @@
#define RUNFILE "/var/run/dnsmasq.pid"
#if defined(__FreeBSD__) || defined (__OpenBSD__) || defined(__DragonFly__)
# define LEASEFILE "/var/db/dnsmasq.leases"
#elif defined(__sun__)
#elif defined(__sun__) || defined (__sun)
# define LEASEFILE "/var/cache/dnsmasq.leases"
#else
# define LEASEFILE "/var/lib/misc/dnsmasq.leases"
@@ -59,6 +60,7 @@
#define TFTP_PORT 69
#define TFTP_MAX_CONNECTIONS 50 /* max simultaneous connections */
#define LOG_MAX 5 /* log-queue length */
#define RANDFILE "/dev/urandom"
/* DBUS interface specifics */
#define DNSMASQ_SERVICE "uk.org.thekelleys.dnsmasq"
@@ -127,19 +129,6 @@ HAVE_ARC4RANDOM
define this if you have arc4random() to get better security from DNS spoofs
by using really random ids (OpenBSD)
HAVE_RANDOM
define this if you have the 4.2BSD random() function (and its
associated srandom() function), which is at least as good as (if not
better than) the rand() function.
HAVE_DEV_RANDOM
define this if you have the /dev/random device, which gives truly
random numbers but may run out of random numbers.
HAVE_DEV_URANDOM
define this if you have the /dev/urandom device, which gives
semi-random numbers when it runs out of truly random numbers.
HAVE_SOCKADDR_SA_LEN
define this if struct sockaddr has sa_len field (*BSD)
@@ -152,13 +141,14 @@ HAVE_BSD_BRIDGE
Define this to enable the --bridge-interface option, useful on some
BSD systems.
HAVE_LARGFILE
Define this if the C library supports large (>2GB) files probably true everywhere
except some builds of uclibc
NOTES:
For Linux you should define
HAVE_LINUX_NETWORK
HAVE_GETOPT_LONG
HAVE_RANDOM
HAVE_DEV_RANDOM
HAVE_DEV_URANDOM
you should NOT define
HAVE_ARC4RANDOM
HAVE_SOCKADDR_SA_LEN
@@ -166,12 +156,8 @@ NOTES:
For *BSD systems you should define
HAVE_BSD_NETWORK
HAVE_SOCKADDR_SA_LEN
HAVE_RANDOM
and you MAY define
HAVE_ARC4RANDOM - OpenBSD and FreeBSD and NetBSD version 2.0 or later
HAVE_DEV_URANDOM - OpenBSD and FreeBSD and NetBSD
HAVE_DEV_RANDOM - FreeBSD and NetBSD
(OpenBSD with hardware random number generator)
HAVE_GETOPT_LONG - NetBSD, later FreeBSD
(FreeBSD and OpenBSD only if you link GNU getopt)
@@ -199,9 +185,6 @@ NOTES:
#define HAVE_LINUX_NETWORK
#define HAVE_GETOPT_LONG
#undef HAVE_ARC4RANDOM
#define HAVE_RANDOM
#define HAVE_DEV_URANDOM
#define HAVE_DEV_RANDOM
#undef HAVE_SOCKADDR_SA_LEN
/* Never use fork() on uClinux. Note that this is subtly different from the
--keep-in-foreground option, since it also suppresses forking new
@@ -214,13 +197,8 @@ NOTES:
#if defined(__UCLIBC_HAS_GNU_GETOPT__) || \
((__UCLIBC_MAJOR__==0) && (__UCLIBC_MINOR__==9) && (__UCLIBC_SUBLEVEL__<21))
# define HAVE_GETOPT_LONG
#else
# undef HAVE_GETOPT_LONG
#endif
#undef HAVE_ARC4RANDOM
#define HAVE_RANDOM
#define HAVE_DEV_URANDOM
#define HAVE_DEV_RANDOM
#undef HAVE_SOCKADDR_SA_LEN
#if !defined(__ARCH_HAS_MMU__) && !defined(__UCLIBC_HAS_MMU__)
# define NO_FORK
@@ -236,9 +214,6 @@ NOTES:
#define HAVE_LINUX_NETWORK
#define HAVE_GETOPT_LONG
#undef HAVE_ARC4RANDOM
#define HAVE_RANDOM
#define HAVE_DEV_URANDOM
#define HAVE_DEV_RANDOM
#undef HAVE_SOCKADDR_SA_LEN
/* glibc < 2.2 has broken Sockaddr_in6 so we have to use our own. */
/* glibc < 2.2 doesn't define in_addr_t */
@@ -256,12 +231,10 @@ typedef unsigned long in_addr_t;
/* Later verions of FreeBSD have getopt_long() */
#if defined(optional_argument) && defined(required_argument)
# define HAVE_GETOPT_LONG
#else
# undef HAVE_GETOPT_LONG
#endif
#define HAVE_ARC4RANDOM
#define HAVE_RANDOM
#define HAVE_DEV_URANDOM
#if !defined (__FreeBSD_kernel__)
# define HAVE_ARC4RANDOM
#endif
#define HAVE_SOCKADDR_SA_LEN
#define HAVE_BSD_BRIDGE
@@ -269,8 +242,6 @@ typedef unsigned long in_addr_t;
#define HAVE_BSD_NETWORK
#undef HAVE_GETOPT_LONG
#define HAVE_ARC4RANDOM
#define HAVE_RANDOM
#define HAVE_DEV_URANDOM
#define HAVE_SOCKADDR_SA_LEN
/* Define before sys/socket.h is included so we get socklen_t */
#define _BSD_SOCKLEN_T_
@@ -281,9 +252,6 @@ typedef unsigned long in_addr_t;
#define HAVE_BSD_NETWORK
#define HAVE_GETOPT_LONG
#undef HAVE_ARC4RANDOM
#define HAVE_RANDOM
#define HAVE_DEV_URANDOM
#define HAVE_DEV_RANDOM
#define HAVE_SOCKADDR_SA_LEN
#define HAVE_BSD_BRIDGE
@@ -308,10 +276,8 @@ typedef unsigned long in_addr_t;
# define CMSG_SPACE(len) (__CMSG_ALIGN(sizeof(struct cmsghdr)) + __CMSG_ALIGN(len))
#endif
#undef HAVE_ARC4RANDOM
#define HAVE_RANDOM
#undef HAVE_DEV_URANDOM
#undef HAVE_DEV_RANDOM
#undef HAVE_SOCKADDR_SA_LEN
#define _XPG4_2
#define __EXTENSIONS__
#define ETHER_ADDR_LEN 6

View File

@@ -896,7 +896,7 @@ void dhcp_update_configs(struct dhcp_config *configs)
crec = cache_find_by_name(crec, config->hostname, 0, F_IPV4);
if (!crec)
continue; /* should be never */
my_syslog(LOG_WARNING, _("%s has more then one address in hostsfile, using %s for DHCP"),
my_syslog(LOG_WARNING, _("%s has more than one address in hostsfile, using %s for DHCP"),
config->hostname, inet_ntoa(crec->addr.addr.addr.addr4));
}

View File

@@ -60,18 +60,27 @@ static int set_dns_listeners(time_t now, fd_set *set, int *maxfdp);
static void check_dns_listeners(fd_set *set, time_t now);
static void sig_handler(int sig);
static void async_event(int pipe, time_t now);
static void fatal_event(struct event_desc *ev);
static void poll_resolv(void);
int main (int argc, char **argv)
{
int bind_fallback = 0;
int bad_capabilities = 0;
time_t now, last = 0;
struct sigaction sigact;
struct iname *if_tmp;
int piperead, pipefd[2];
struct passwd *ent_pw;
int piperead, pipefd[2], err_pipe[2];
struct passwd *ent_pw = NULL;
uid_t script_uid = 0;
gid_t script_gid = 0;
struct group *gp= NULL;
long i, max_fd = sysconf(_SC_OPEN_MAX);
char *baduser = NULL;
int log_err;
#if defined(HAVE_LINUX_NETWORK)
cap_user_header_t hdr = NULL;
cap_user_data_t data = NULL;
#endif
#ifdef LOCALEDIR
setlocale(LC_ALL, "");
@@ -102,7 +111,7 @@ int main (int argc, char **argv)
daemon->packet_buff_sz = daemon->edns_pktsz > DNSMASQ_PACKETSZ ?
daemon->edns_pktsz : DNSMASQ_PACKETSZ;
daemon->packet = safe_malloc(daemon->packet_buff_sz);
if (!daemon->lease_file)
{
if (daemon->dhcp)
@@ -140,6 +149,8 @@ int main (int argc, char **argv)
die(_("asychronous logging is not available under Solaris"), NULL, EC_BADCONF);
#endif
rand_init();
now = dnsmasq_time();
if (daemon->dhcp)
@@ -184,7 +195,7 @@ int main (int argc, char **argv)
if (daemon->port != 0)
cache_init();
if (daemon->options & OPT_DBUS)
#ifdef HAVE_DBUS
{
@@ -200,25 +211,81 @@ int main (int argc, char **argv)
if (daemon->port != 0)
pre_allocate_sfds();
/* Note getpwnam returns static storage */
if (daemon->dhcp && daemon->lease_change_command && daemon->scriptuser)
{
if ((ent_pw = getpwnam(daemon->scriptuser)))
{
script_uid = ent_pw->pw_uid;
script_gid = ent_pw->pw_gid;
}
else
baduser = daemon->scriptuser;
}
if (daemon->username && !(ent_pw = getpwnam(daemon->username)))
baduser = daemon->username;
else if (daemon->groupname && !(gp = getgrnam(daemon->groupname)))
baduser = daemon->groupname;
if (baduser)
die(_("unknown user or group: %s"), baduser, EC_BADCONF);
/* implement group defaults, "dip" if available, or group associated with uid */
if (!daemon->group_set && !gp)
{
if (!(gp = getgrnam(CHGRP)) && ent_pw)
gp = getgrgid(ent_pw->pw_gid);
/* for error message */
if (gp)
daemon->groupname = gp->gr_name;
}
#if defined(HAVE_LINUX_NETWORK)
/* determine capability API version here, while we can still
call safe_malloc */
if (ent_pw && ent_pw->pw_uid != 0)
{
hdr = safe_malloc(sizeof(*hdr));
int capsize = 1; /* for header version 1 */
/* find version supported by kernel */
memset(hdr, 0, sizeof(*hdr));
capget(hdr, NULL);
if (hdr->version != LINUX_CAPABILITY_VERSION_1)
{
/* if unknown version, use largest supported version (3) */
if (hdr->version != LINUX_CAPABILITY_VERSION_2)
hdr->version = LINUX_CAPABILITY_VERSION_3;
capsize = 2;
}
data = safe_malloc(sizeof(*data) * capsize);
memset(data, 0, sizeof(*data) * capsize);
}
#endif
/* Use a pipe to carry signals and other events back to the event loop
in a race-free manner */
if (pipe(pipefd) == -1 || !fix_fd(pipefd[0]) || !fix_fd(pipefd[1]))
die(_("cannot create pipe: %s"), NULL, EC_MISC);
in a race-free manner and another to carry errors to daemon-invoking process */
safe_pipe(pipefd, 1);
piperead = pipefd[0];
pipewrite = pipefd[1];
/* prime the pipe to load stuff first time. */
send_event(pipewrite, EVENT_RELOAD, 0);
err_pipe[1] = -1;
if (!(daemon->options & OPT_DEBUG))
{
FILE *pidfile;
int nullfd;
/* The following code "daemonizes" the process.
See Stevens section 12.4 */
if (chdir("/") != 0)
die(_("cannot chdir to filesystem root: %s"), NULL, EC_MISC);
@@ -227,13 +294,30 @@ int main (int argc, char **argv)
{
pid_t pid;
/* pipe to carry errors back to original process.
When startup is complete we close this and the process terminates. */
safe_pipe(err_pipe, 0);
if ((pid = fork()) == -1 )
die(_("cannot fork into background: %s"), NULL, EC_MISC);
/* NO calls to die() from here on. */
if (pid != 0)
_exit(EC_GOOD);
{
struct event_desc ev;
/* close our copy of write-end */
close(err_pipe[1]);
/* check for errors after the fork */
if (read_write(err_pipe[0], (unsigned char *)&ev, sizeof(ev), 1))
fatal_event(&ev);
_exit(EC_GOOD);
}
close(err_pipe[0]);
/* NO calls to die() from here on. */
setsid();
pid = fork();
@@ -244,12 +328,23 @@ int main (int argc, char **argv)
#endif
/* write pidfile _after_ forking ! */
if (daemon->runfile && (pidfile = fopen(daemon->runfile, "w")))
{
fprintf(pidfile, "%d\n", (int) getpid());
fclose(pidfile);
if (daemon->runfile)
{
FILE *pidfile;
/* only complain if started as root */
if ((pidfile = fopen(daemon->runfile, "w")))
{
fprintf(pidfile, "%d\n", (int) getpid());
fclose(pidfile);
}
else if (getuid() == 0)
{
send_event(err_pipe[1], EVENT_PIDFILE, errno);
_exit(0);
}
}
/* open stdout etc to /dev/null */
nullfd = open("/dev/null", O_RDWR);
dup2(nullfd, STDOUT_FILENO);
@@ -258,60 +353,41 @@ int main (int argc, char **argv)
close(nullfd);
}
/* if we are to run scripts, we need to fork a helper before dropping root. */
#ifndef NO_FORK
daemon->helperfd = create_helper(pipewrite, max_fd);
#endif
log_err = log_start(ent_pw, err_pipe[1]);
ent_pw = daemon->username ? getpwnam(daemon->username) : NULL;
log_start(ent_pw);
/* if we are to run scripts, we need to fork a helper before dropping root. */
daemon->helperfd = -1;
#ifndef NO_FORK
if (daemon->dhcp && daemon->lease_change_command)
daemon->helperfd = create_helper(pipewrite, err_pipe[1], script_uid, script_gid, max_fd);
#endif
if (!(daemon->options & OPT_DEBUG))
if (!(daemon->options & OPT_DEBUG) && getuid() == 0)
{
/* UID changing, etc */
if (daemon->groupname || ent_pw)
{
gid_t dummy;
struct group *gp;
/* change group for /etc/ppp/resolv.conf otherwise get the group for "nobody" */
if ((daemon->groupname && (gp = getgrnam(daemon->groupname))) ||
(ent_pw && (gp = getgrgid(ent_pw->pw_gid))))
{
/* remove all supplimentary groups */
setgroups(0, &dummy);
setgid(gp->gr_gid);
}
}
int bad_capabilities = 0;
gid_t dummy;
/* remove all supplimentary groups */
if (gp &&
(setgroups(0, &dummy) == -1 ||
setgid(gp->gr_gid) == -1))
{
send_event(err_pipe[1], EVENT_GROUP_ERR, errno);
_exit(0);
}
if (ent_pw && ent_pw->pw_uid != 0)
{
#if defined(HAVE_LINUX_NETWORK)
/* On linux, we keep CAP_NETADMIN (for ARP-injection) and
CAP_NET_RAW (for icmp) if we're doing dhcp */
cap_user_header_t hdr = safe_malloc(sizeof(*hdr));
cap_user_data_t data;
int capsize = 1; /* for header version 1 */
hdr->version = 0;
/* find version supported by kernel */
capget(hdr, NULL);
if (hdr->version != LINUX_CAPABILITY_VERSION_1)
{
/* if not version 1, use version 2 */
hdr->version = LINUX_CAPABILITY_VERSION_2;
capsize = 2;
}
hdr->pid = 0; /* this process */
data = safe_malloc(sizeof(*data) * capsize);
memset(hdr, sizeof(*data) * capsize, 0);
data->effective = data->permitted = data->inheritable =
(1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) |
(1 << CAP_SETGID) | (1 << CAP_SETUID);
(1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) | (1 << CAP_SETUID);
/* Tell kernel to not clear capabilities when dropping root */
if (capset(hdr, data) == -1 || prctl(PR_SET_KEEPCAPS, 1) == -1)
bad_capabilities = errno;
#elif defined(HAVE_SOLARIS_PRIVS)
/* http://developers.sun.com/solaris/articles/program_privileges.html */
priv_set_t *priv_set;
@@ -337,20 +413,32 @@ int main (int argc, char **argv)
bad_capabilities = ENOTSUP;
#endif
if (bad_capabilities == 0)
if (bad_capabilities != 0)
{
/* finally drop root */
setuid(ent_pw->pw_uid);
#ifdef HAVE_LINUX_NETWORK
data->effective = data->permitted =
(1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW);
data->inheritable = 0;
/* lose the setuid and setgid capbilities */
capset(hdr, data);
#endif
send_event(err_pipe[1], EVENT_CAP_ERR, bad_capabilities);
_exit(0);
}
/* finally drop root */
if (setuid(ent_pw->pw_uid) == -1)
{
send_event(err_pipe[1], EVENT_USER_ERR, errno);
_exit(0);
}
#ifdef HAVE_LINUX_NETWORK
data->effective = data->permitted =
(1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW);
data->inheritable = 0;
/* lose the setuid and setgid capbilities */
if (capset(hdr, data) == -1)
{
send_event(err_pipe[1], EVENT_CAP_ERR, errno);
_exit(0);
}
#endif
}
}
@@ -378,6 +466,10 @@ int main (int argc, char **argv)
}
#endif
if (log_err != 0)
my_syslog(LOG_WARNING, _("warning: failed to change owner of %s: %s"),
daemon->log_file, strerror(log_err));
if (bind_fallback)
my_syslog(LOG_WARNING, _("setting --bind-interfaces option because of OS limitations"));
@@ -457,13 +549,9 @@ int main (int argc, char **argv)
}
#endif
if (!(daemon->options & OPT_DEBUG) && (getuid() == 0 || geteuid() == 0))
{
if (bad_capabilities)
my_syslog(LOG_WARNING, _("warning: setting capabilities failed: %s"), strerror(bad_capabilities));
my_syslog(LOG_WARNING, _("running as root"));
}
/* finished start-up - release original process */
if (err_pipe[1] != -1)
close(err_pipe[1]);
if (daemon->port != 0)
check_servers();
@@ -642,11 +730,48 @@ void send_event(int fd, int event, int data)
ev.event = event;
ev.data = data;
/* pipe is non-blocking and struct event_desc is smaller than
PIPE_BUF, so this either fails or writes everything */
while (write(fd, &ev, sizeof(ev)) == -1 && errno == EINTR);
/* error pipe, debug mode. */
if (fd == -1)
fatal_event(&ev);
else
/* pipe is non-blocking and struct event_desc is smaller than
PIPE_BUF, so this either fails or writes everything */
while (write(fd, &ev, sizeof(ev)) == -1 && errno == EINTR);
}
static void fatal_event(struct event_desc *ev)
{
errno = ev->data;
switch (ev->event)
{
case EVENT_DIE:
exit(0);
case EVENT_PIPE_ERR:
die(_("failed to create helper: %s"), NULL, EC_MISC);
case EVENT_CAP_ERR:
die(_("setting capabilities failed: %s"), NULL, EC_MISC);
case EVENT_USER_ERR:
case EVENT_HUSER_ERR:
die(_("failed to change user-id to %s: %s"),
ev->event == EVENT_USER_ERR ? daemon->username : daemon->scriptuser,
EC_MISC);
case EVENT_GROUP_ERR:
die(_("failed to change group-id to %s: %s"), daemon->groupname, EC_MISC);
case EVENT_PIDFILE:
die(_("failed to open pidfile %s: %s"), daemon->runfile, EC_FILE);
case EVENT_LOG_ERR:
die(_("cannot open %s: %s"), daemon->log_file ? daemon->log_file : "log", EC_FILE);
}
}
static void async_event(int pipe, time_t now)
{
pid_t p;
@@ -706,15 +831,10 @@ static void async_event(int pipe, time_t now)
daemon->lease_change_command, strerror(ev.data));
break;
case EVENT_PIPE_ERR:
my_syslog(LOG_ERR, _("failed to create helper: %s"), strerror(ev.data));
break;
case EVENT_USER_ERR:
my_syslog(LOG_ERR, _("cannot change to user %s for script execution%s%s"),
daemon->scriptuser,
ev.data != 0 ? ": " : "",
ev.data != 0 ? strerror(ev.data) : "");
/* necessary for fatal errors in helper */
case EVENT_HUSER_ERR:
case EVENT_DIE:
fatal_event(&ev);
break;
case EVENT_REOPEN:
@@ -850,7 +970,15 @@ static int set_dns_listeners(time_t now, fd_set *set, int *maxfdp)
FD_SET(serverfdp->fd, set);
bump_maxfd(serverfdp->fd, maxfdp);
}
if (daemon->port != 0 && !daemon->osport)
for (i = 0; i < RANDOM_SOCKS; i++)
if (daemon->randomsocks[i].refcount != 0)
{
FD_SET(daemon->randomsocks[i].fd, set);
bump_maxfd(daemon->randomsocks[i].fd, maxfdp);
}
for (listener = daemon->listeners; listener; listener = listener->next)
{
/* only listen for queries if we have resources */
@@ -887,17 +1015,24 @@ static int set_dns_listeners(time_t now, fd_set *set, int *maxfdp)
static void check_dns_listeners(fd_set *set, time_t now)
{
struct serverfd *serverfdp;
struct listener *listener;
struct listener *listener;
int i;
for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
if (FD_ISSET(serverfdp->fd, set))
reply_query(serverfdp, now);
reply_query(serverfdp->fd, serverfdp->source_addr.sa.sa_family, now);
if (daemon->port != 0 && !daemon->osport)
for (i = 0; i < RANDOM_SOCKS; i++)
if (daemon->randomsocks[i].refcount != 0 &&
FD_ISSET(daemon->randomsocks[i].fd, set))
reply_query(daemon->randomsocks[i].fd, daemon->randomsocks[i].family, now);
for (listener = daemon->listeners; listener; listener = listener->next)
{
if (listener->fd != -1 && FD_ISSET(listener->fd, set))
receive_query(listener, now);
#ifdef HAVE_TFTP
if (listener->tftpfd != -1 && FD_ISSET(listener->tftpfd, set))
tftp_request(listener, now);

View File

@@ -16,9 +16,11 @@
#define COPYRIGHT "Copyright (C) 2000-2008 Simon Kelley"
#ifndef NO_LARGEFILE
/* Ensure we can use files >2GB (log files may grow this big) */
#define _LARGEFILE_SOURCE 1
#define _FILE_OFFSET_BITS 64
# define _LARGEFILE_SOURCE 1
# define _FILE_OFFSET_BITS 64
#endif
/* Get linux C library versions. */
#ifdef __linux__
@@ -76,7 +78,7 @@
#include <pwd.h>
#include <grp.h>
#include <stdarg.h>
#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__sun__)
#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__sun__) || defined (__sun)
# include <netinet/if_ether.h>
#else
# include <net/ethernet.h>
@@ -100,6 +102,7 @@ extern int capset(cap_user_header_t header, cap_user_data_t data);
extern int capget(cap_user_header_t header, cap_user_data_t data);
#define LINUX_CAPABILITY_VERSION_1 0x19980330
#define LINUX_CAPABILITY_VERSION_2 0x20071026
#define LINUX_CAPABILITY_VERSION_3 0x20080522
#include <sys/prctl.h>
#elif defined(HAVE_SOLARIS_PRIVS)
@@ -125,6 +128,12 @@ struct event_desc {
#define EVENT_EXEC_ERR 9
#define EVENT_PIPE_ERR 10
#define EVENT_USER_ERR 11
#define EVENT_CAP_ERR 12
#define EVENT_PIDFILE 13
#define EVENT_HUSER_ERR 14
#define EVENT_GROUP_ERR 15
#define EVENT_DIE 16
#define EVENT_LOG_ERR 17
/* Exit codes. */
#define EC_GOOD 0
@@ -142,38 +151,38 @@ struct event_desc {
*/
#define DNSMASQ_PACKETSZ PACKETSZ+MAXDNAME+RRFIXEDSZ
#define OPT_BOGUSPRIV (1<<0)
#define OPT_FILTER (1<<1)
#define OPT_LOG (1<<2)
#define OPT_SELFMX (1<<3)
#define OPT_NO_HOSTS (1<<4)
#define OPT_NO_POLL (1<<5)
#define OPT_DEBUG (1<<6)
#define OPT_ORDER (1<<7)
#define OPT_NO_RESOLV (1<<8)
#define OPT_EXPAND (1<<9)
#define OPT_LOCALMX (1<<10)
#define OPT_NO_NEG (1<<11)
#define OPT_NODOTS_LOCAL (1<<12)
#define OPT_NOWILD (1<<13)
#define OPT_ETHERS (1<<14)
#define OPT_RESOLV_DOMAIN (1<<15)
#define OPT_NO_FORK (1<<16)
#define OPT_AUTHORITATIVE (1<<17)
#define OPT_LOCALISE (1<<18)
#define OPT_DBUS (1<<19)
#define OPT_BOOTP_DYNAMIC (1<<20)
#define OPT_NO_PING (1<<21)
#define OPT_LEASE_RO (1<<22)
#define OPT_ALL_SERVERS (1<<23)
#define OPT_RELOAD (1<<24)
#define OPT_TFTP (1<<25)
#define OPT_TFTP_SECURE (1<<26)
#define OPT_TFTP_NOBLOCK (1<<27)
#define OPT_LOG_OPTS (1<<28)
#define OPT_TFTP_APREF (1<<29)
#define OPT_NO_OVERRIDE (1<<30)
#define OPT_NO_REBIND (1<<31)
#define OPT_BOGUSPRIV (1u<<0)
#define OPT_FILTER (1u<<1)
#define OPT_LOG (1u<<2)
#define OPT_SELFMX (1u<<3)
#define OPT_NO_HOSTS (1u<<4)
#define OPT_NO_POLL (1u<<5)
#define OPT_DEBUG (1u<<6)
#define OPT_ORDER (1u<<7)
#define OPT_NO_RESOLV (1u<<8)
#define OPT_EXPAND (1u<<9)
#define OPT_LOCALMX (1u<<10)
#define OPT_NO_NEG (1u<<11)
#define OPT_NODOTS_LOCAL (1u<<12)
#define OPT_NOWILD (1u<<13)
#define OPT_ETHERS (1u<<14)
#define OPT_RESOLV_DOMAIN (1u<<15)
#define OPT_NO_FORK (1u<<16)
#define OPT_AUTHORITATIVE (1u<<17)
#define OPT_LOCALISE (1u<<18)
#define OPT_DBUS (1u<<19)
#define OPT_BOOTP_DYNAMIC (1u<<20)
#define OPT_NO_PING (1u<<21)
#define OPT_LEASE_RO (1u<<22)
#define OPT_ALL_SERVERS (1u<<23)
#define OPT_RELOAD (1u<<24)
#define OPT_TFTP (1u<<25)
#define OPT_TFTP_SECURE (1u<<26)
#define OPT_TFTP_NOBLOCK (1u<<27)
#define OPT_LOG_OPTS (1u<<28)
#define OPT_TFTP_APREF (1u<<29)
#define OPT_NO_OVERRIDE (1u<<30)
#define OPT_NO_REBIND (1u<<31)
struct all_addr {
union {
@@ -202,6 +211,12 @@ struct mx_srv_record {
struct mx_srv_record *next;
};
struct naptr {
char *name, *replace, *regexp, *services, *flags;
unsigned int order, pref;
struct naptr *next;
};
struct txt_record {
char *name, *txt;
unsigned short class, len;
@@ -302,6 +317,11 @@ struct serverfd {
struct serverfd *next;
};
struct randfd {
int fd;
unsigned short refcount, family;
};
struct server {
union mysockaddr addr, source_addr;
char interface[IF_NAMESIZE+1];
@@ -352,6 +372,10 @@ struct frec {
union mysockaddr source;
struct all_addr dest;
struct server *sentto; /* NULL means free */
struct randfd *rfd4;
#ifdef HAVE_IPV6
struct randfd *rfd6;
#endif
unsigned int iface;
unsigned short orig_id, new_id;
int fd, forwardall;
@@ -383,7 +407,7 @@ struct dhcp_lease {
#endif
int hwaddr_len, hwaddr_type;
unsigned char hwaddr[DHCP_CHADDR_MAX];
struct in_addr addr;
struct in_addr addr, override;
unsigned char *vendorclass, *userclass;
unsigned int vendorclass_len, userclass_len;
int last_interface;
@@ -541,12 +565,14 @@ extern struct daemon {
unsigned int options;
struct resolvc default_resolv, *resolv_files;
struct mx_srv_record *mxnames;
struct naptr *naptr;
struct txt_record *txt;
struct ptr_record *ptr;
struct interface_name *int_names;
char *mxtarget;
char *lease_file;
char *username, *groupname, *scriptuser;
int group_set, osport;
char *domain_suffix;
char *runfile;
char *lease_change_command;
@@ -557,7 +583,7 @@ extern struct daemon {
char *log_file; /* optional log file */
int max_logs; /* queue limit */
int cachesize, ftabsize;
int port, query_port;
int port, query_port, min_port;
unsigned long local_ttl, neg_ttl;
struct hostsfile *addn_hosts;
struct dhcp_context *dhcp;
@@ -581,6 +607,7 @@ extern struct daemon {
int packet_buff_sz; /* size of above */
char *namebuff; /* MAXDNAME size buffer */
unsigned int local_answer, queries_forwarded;
struct frec *frec_list;
struct serverfd *sfds;
struct irec *interfaces;
struct listener *listeners;
@@ -588,7 +615,8 @@ extern struct daemon {
struct server *srv_save; /* Used for resend on DoD */
size_t packet_len; /* " " */
pid_t tcp_pids[MAX_PROCS];
struct randfd randomsocks[RANDOM_SOCKS];
/* DHCP state */
int dhcpfd, helperfd;
#ifdef HAVE_LINUX_NETWORK
@@ -618,8 +646,9 @@ extern struct daemon {
/* cache.c */
void cache_init(void);
void log_query(unsigned short flags, char *name, struct all_addr *addr,
unsigned short type, struct hostsfile *addn_hosts, int index);
void log_query(unsigned short flags, char *name, struct all_addr *addr, char *arg);
char *record_source(struct hostsfile *addn_hosts, int index);
void querystr(char *str, unsigned short type);
struct crec *cache_find_by_addr(struct crec *crecp,
struct all_addr *addr, time_t now,
unsigned short prot);
@@ -654,11 +683,13 @@ size_t resize_packet(HEADER *header, size_t plen,
unsigned char *pheader, size_t hlen);
/* util.c */
void rand_init(void);
unsigned short rand16(void);
int legal_char(char c);
int canonicalise(char *s);
unsigned char *do_rfc1035_name(unsigned char *p, char *sval);
void *safe_malloc(size_t size);
void safe_pipe(int *fd, int read_noblock);
void *whine_malloc(size_t size);
int sa_len(union mysockaddr *addr);
int sockaddr_isequal(union mysockaddr *s1, union mysockaddr *s2);
@@ -679,7 +710,7 @@ int read_write(int fd, unsigned char *packet, int size, int rw);
/* log.c */
void die(char *message, char *arg1, int exit_code);
void log_start(struct passwd *ent_pw);
int log_start(struct passwd *ent_pw, int errfd);
int log_reopen(char *log_file);
void my_syslog(int priority, const char *format, ...);
void set_log_writer(fd_set *set, int *maxfdp);
@@ -692,7 +723,7 @@ char *option_string(unsigned char opt);
void reread_dhcp(void);
/* forward.c */
void reply_query(struct serverfd *sfd, time_t now);
void reply_query(int fd, int family, time_t now);
void receive_query(struct listener *listen, time_t now);
unsigned char *tcp_request(int confd, time_t now,
struct in_addr local_addr, struct in_addr netmask);
@@ -701,6 +732,7 @@ struct frec *get_new_frec(time_t now, int *wait);
/* network.c */
int local_bind(int fd, union mysockaddr *addr, char *intname, int is_tcp);
int random_sock(int family);
void pre_allocate_sfds(void);
int reload_servers(char *fname);
void check_servers(void);
@@ -797,7 +829,7 @@ void set_dbus_listeners(int *maxfdp, fd_set *rset, fd_set *wset, fd_set *eset);
/* helper.c */
#ifndef NO_FORK
int create_helper(int log_fd, long max_fd);
int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd);
void helper_write(void);
void queue_script(int action, struct dhcp_lease *lease,
char *hostname, time_t now);

View File

@@ -16,14 +16,13 @@
#include "dnsmasq.h"
static struct frec *frec_list = NULL;
static struct frec *lookup_frec(unsigned short id, unsigned int crc);
static struct frec *lookup_frec_by_sender(unsigned short id,
union mysockaddr *addr,
unsigned int crc);
static unsigned short get_id(int force, unsigned short force_id, unsigned int crc);
static void free_frec(struct frec *f);
static struct randfd *allocate_rfd(int family);
/* Send a UDP packet with its source address set as "source"
unless nowild is true, when we just send it with the kernel default */
@@ -196,7 +195,7 @@ static unsigned short search_servers(time_t now, struct all_addr **addrpp,
if (flags == F_NXDOMAIN || flags == F_NOERR)
logflags = F_NEG | qtype;
log_query(logflags | flags | F_CONFIG | F_FORWARD, qdomain, *addrpp, 0, NULL, 0);
log_query(logflags | flags | F_CONFIG | F_FORWARD, qdomain, *addrpp, NULL);
}
return flags;
@@ -290,7 +289,32 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
(type != SERV_HAS_DOMAIN || hostname_isequal(domain, start->domain)) &&
!(start->flags & SERV_LITERAL_ADDRESS))
{
if (sendto(start->sfd->fd, (char *)header, plen, 0,
int fd;
/* find server socket to use, may need to get random one. */
if (start->sfd)
fd = start->sfd->fd;
else
{
#ifdef HAVE_IPV6
if (start->addr.sa.sa_family == AF_INET6)
{
if (!forward->rfd6 &&
!(forward->rfd6 = allocate_rfd(AF_INET6)))
break;
fd = forward->rfd6->fd;
}
else
#endif
{
if (!forward->rfd4 &&
!(forward->rfd4 = allocate_rfd(AF_INET)))
break;
fd = forward->rfd4->fd;
}
}
if (sendto(fd, (char *)header, plen, 0,
&start->addr.sa,
sa_len(&start->addr)) == -1)
{
@@ -307,13 +331,11 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
strcpy(daemon->namebuff, "query");
if (start->addr.sa.sa_family == AF_INET)
log_query(F_SERVER | F_IPV4 | F_FORWARD, daemon->namebuff,
(struct all_addr *)&start->addr.in.sin_addr, 0,
NULL, 0);
(struct all_addr *)&start->addr.in.sin_addr, NULL);
#ifdef HAVE_IPV6
else
log_query(F_SERVER | F_IPV6 | F_FORWARD, daemon->namebuff,
(struct all_addr *)&start->addr.in6.sin6_addr, 0,
NULL, 0);
(struct all_addr *)&start->addr.in6.sin6_addr, NULL);
#endif
start->queries++;
forwarded = 1;
@@ -336,7 +358,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
/* could not send on, prepare to return */
header->id = htons(forward->orig_id);
forward->sentto = NULL; /* cancel */
free_frec(forward); /* cancel */
}
/* could not send on, return empty answer or address if known for whole domain */
@@ -428,7 +450,7 @@ static size_t process_reply(HEADER *header, time_t now,
}
/* sets new last_server */
void reply_query(struct serverfd *sfd, time_t now)
void reply_query(int fd, int family, time_t now)
{
/* packet from peer server, extract data for cache, and send to
original requester */
@@ -436,91 +458,101 @@ void reply_query(struct serverfd *sfd, time_t now)
union mysockaddr serveraddr;
struct frec *forward;
socklen_t addrlen = sizeof(serveraddr);
ssize_t n = recvfrom(sfd->fd, daemon->packet, daemon->edns_pktsz, 0, &serveraddr.sa, &addrlen);
ssize_t n = recvfrom(fd, daemon->packet, daemon->edns_pktsz, 0, &serveraddr.sa, &addrlen);
size_t nn;
struct server *server;
/* packet buffer overwritten */
daemon->srv_save = NULL;
/* Determine the address of the server replying so that we can mark that as good */
serveraddr.sa.sa_family = sfd->source_addr.sa.sa_family;
serveraddr.sa.sa_family = family;
#ifdef HAVE_IPV6
if (serveraddr.sa.sa_family == AF_INET6)
serveraddr.in6.sin6_flowinfo = 0;
#endif
/* spoof check: answer must come from known server, */
for (server = daemon->servers; server; server = server->next)
if (!(server->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR)) &&
sockaddr_isequal(&server->addr, &serveraddr))
break;
header = (HEADER *)daemon->packet;
if (n >= (int)sizeof(HEADER) && header->qr &&
(forward = lookup_frec(ntohs(header->id), questions_crc(header, n, daemon->namebuff))))
if (!server ||
n < (int)sizeof(HEADER) || !header->qr ||
!(forward = lookup_frec(ntohs(header->id), questions_crc(header, n, daemon->namebuff))))
return;
server = forward->sentto;
if ((header->rcode == SERVFAIL || header->rcode == REFUSED) &&
!(daemon->options & OPT_ORDER) &&
forward->forwardall == 0)
/* for broken servers, attempt to send to another one. */
{
struct server *server = forward->sentto;
unsigned char *pheader;
size_t plen;
int is_sign;
if ((header->rcode == SERVFAIL || header->rcode == REFUSED) &&
!(daemon->options & OPT_ORDER) &&
forward->forwardall == 0)
/* for broken servers, attempt to send to another one. */
/* recreate query from reply */
pheader = find_pseudoheader(header, (size_t)n, &plen, NULL, &is_sign);
if (!is_sign)
{
unsigned char *pheader;
size_t plen;
int is_sign;
header->ancount = htons(0);
header->nscount = htons(0);
header->arcount = htons(0);
if ((nn = resize_packet(header, (size_t)n, pheader, plen)))
{
header->qr = 0;
header->tc = 0;
forward_query(-1, NULL, NULL, 0, header, nn, now, forward);
return;
}
}
}
if ((forward->sentto->flags & SERV_TYPE) == 0)
{
if (header->rcode == SERVFAIL || header->rcode == REFUSED)
server = NULL;
else
{
struct server *last_server;
/* recreate query from reply */
pheader = find_pseudoheader(header, (size_t)n, &plen, NULL, &is_sign);
if (!is_sign)
{
header->ancount = htons(0);
header->nscount = htons(0);
header->arcount = htons(0);
if ((nn = resize_packet(header, (size_t)n, pheader, plen)))
{
header->qr = 0;
header->tc = 0;
forward_query(-1, NULL, NULL, 0, header, nn, now, forward);
return;
}
}
}
if ((forward->sentto->flags & SERV_TYPE) == 0)
/* find good server by address if possible, otherwise assume the last one we sent to */
for (last_server = daemon->servers; last_server; last_server = last_server->next)
if (!(last_server->flags & (SERV_LITERAL_ADDRESS | SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_NO_ADDR)) &&
sockaddr_isequal(&last_server->addr, &serveraddr))
{
server = last_server;
break;
}
}
if (!(daemon->options & OPT_ALL_SERVERS))
daemon->last_server = server;
}
/* If the answer is an error, keep the forward record in place in case
we get a good reply from another server. Kill it when we've
had replies from all to avoid filling the forwarding table when
everything is broken */
if (forward->forwardall == 0 || --forward->forwardall == 1 ||
(header->rcode != REFUSED && header->rcode != SERVFAIL))
{
if ((nn = process_reply(header, now, server, (size_t)n)))
{
if (header->rcode == SERVFAIL || header->rcode == REFUSED)
server = NULL;
else
{
struct server *last_server;
/* find good server by address if possible, otherwise assume the last one we sent to */
for (last_server = daemon->servers; last_server; last_server = last_server->next)
if (!(last_server->flags & (SERV_LITERAL_ADDRESS | SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_NO_ADDR)) &&
sockaddr_isequal(&last_server->addr, &serveraddr))
{
server = last_server;
break;
}
}
if (!(daemon->options & OPT_ALL_SERVERS))
daemon->last_server = server;
}
/* If the answer is an error, keep the forward record in place in case
we get a good reply from another server. Kill it when we've
had replies from all to avoid filling the forwarding table when
everything is broken */
if (forward->forwardall == 0 || --forward->forwardall == 1 ||
(header->rcode != REFUSED && header->rcode != SERVFAIL))
{
if ((nn = process_reply(header, now, server, (size_t)n)))
{
header->id = htons(forward->orig_id);
header->ra = 1; /* recursion if available */
send_from(forward->fd, daemon->options & OPT_NOWILD, daemon->packet, nn,
&forward->source, &forward->dest, forward->iface);
}
forward->sentto = NULL; /* cancel */
header->id = htons(forward->orig_id);
header->ra = 1; /* recursion if available */
send_from(forward->fd, daemon->options & OPT_NOWILD, daemon->packet, nn,
&forward->source, &forward->dest, forward->iface);
}
free_frec(forward); /* cancel */
}
}
void receive_query(struct listener *listen, time_t now)
{
HEADER *header = (HEADER *)daemon->packet;
@@ -658,13 +690,17 @@ void receive_query(struct listener *listen, time_t now)
if (extract_request(header, (size_t)n, daemon->namebuff, &type))
{
char types[20];
querystr(types, type);
if (listen->family == AF_INET)
log_query(F_QUERY | F_IPV4 | F_FORWARD, daemon->namebuff,
(struct all_addr *)&source_addr.in.sin_addr, type, NULL, 0);
(struct all_addr *)&source_addr.in.sin_addr, types);
#ifdef HAVE_IPV6
else
log_query(F_QUERY | F_IPV6 | F_FORWARD, daemon->namebuff,
(struct all_addr *)&source_addr.in6.sin6_addr, type, NULL, 0);
(struct all_addr *)&source_addr.in6.sin6_addr, types);
#endif
}
@@ -719,13 +755,17 @@ unsigned char *tcp_request(int confd, time_t now,
if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) != -1)
{
char types[20];
querystr(types, qtype);
if (peer_addr.sa.sa_family == AF_INET)
log_query(F_QUERY | F_IPV4 | F_FORWARD, daemon->namebuff,
(struct all_addr *)&peer_addr.in.sin_addr, qtype, NULL, 0);
(struct all_addr *)&peer_addr.in.sin_addr, types);
#ifdef HAVE_IPV6
else
log_query(F_QUERY | F_IPV6 | F_FORWARD, daemon->namebuff,
(struct all_addr *)&peer_addr.in6.sin6_addr, qtype, NULL, 0);
(struct all_addr *)&peer_addr.in6.sin6_addr, types);
#endif
}
}
@@ -812,11 +852,11 @@ unsigned char *tcp_request(int confd, time_t now,
strcpy(daemon->namebuff, "query");
if (last_server->addr.sa.sa_family == AF_INET)
log_query(F_SERVER | F_IPV4 | F_FORWARD, daemon->namebuff,
(struct all_addr *)&last_server->addr.in.sin_addr, 0, NULL, 0);
(struct all_addr *)&last_server->addr.in.sin_addr, NULL);
#ifdef HAVE_IPV6
else
log_query(F_SERVER | F_IPV6 | F_FORWARD, daemon->namebuff,
(struct all_addr *)&last_server->addr.in6.sin6_addr, 0, NULL, 0);
(struct all_addr *)&last_server->addr.in6.sin6_addr, NULL);
#endif
/* There's no point in updating the cache, since this process will exit and
@@ -854,34 +894,99 @@ static struct frec *allocate_frec(time_t now)
if ((f = (struct frec *)whine_malloc(sizeof(struct frec))))
{
f->next = frec_list;
f->next = daemon->frec_list;
f->time = now;
f->sentto = NULL;
frec_list = f;
f->rfd4 = NULL;
#ifdef HAVE_IPV6
f->rfd6 = NULL;
#endif
daemon->frec_list = f;
}
return f;
}
static struct randfd *allocate_rfd(int family)
{
static int finger = 0;
int i;
/* limit the number of sockets we have open to avoid starvation of
(eg) TFTP. Once we have a reasonable number, randomness should be OK */
for (i = 0; i < RANDOM_SOCKS; i++)
if (daemon->randomsocks[i].refcount == 0 &&
(daemon->randomsocks[i].fd = random_sock(family)) != -1)
{
daemon->randomsocks[i].refcount = 1;
daemon->randomsocks[i].family = family;
return &daemon->randomsocks[i];
}
/* No free ones, grab an existing one */
for (i = 0; i < RANDOM_SOCKS; i++)
{
int j = (i+finger) % RANDOM_SOCKS;
if (daemon->randomsocks[j].family == family && daemon->randomsocks[j].refcount != 0xffff)
{
finger = j;
daemon->randomsocks[j].refcount++;
return &daemon->randomsocks[j];
}
}
return NULL; /* doom */
}
static void free_frec(struct frec *f)
{
if (f->rfd4 && --(f->rfd4->refcount) == 0)
close(f->rfd4->fd);
f->rfd4 = NULL;
f->sentto = NULL;
#ifdef HAVE_IPV6
if (f->rfd6 && --(f->rfd6->refcount) == 0)
close(f->rfd6->fd);
f->rfd6 = NULL;
#endif
}
/* if wait==NULL return a free or older than TIMEOUT record.
else return *wait zero if one available, or *wait is delay to
when the oldest in-use record will expire. */
when the oldest in-use record will expire. Impose an absolute
limit of 4*TIMEOUT before we wipe things (for random sockets) */
struct frec *get_new_frec(time_t now, int *wait)
{
struct frec *f, *oldest;
struct frec *f, *oldest, *target;
int count;
if (wait)
*wait = 0;
for (f = frec_list, oldest = NULL, count = 0; f; f = f->next, count++)
for (f = daemon->frec_list, oldest = NULL, target = NULL, count = 0; f; f = f->next, count++)
if (!f->sentto)
target = f;
else
{
f->time = now;
return f;
if (difftime(now, f->time) >= 4*TIMEOUT)
{
free_frec(f);
target = f;
}
if (!oldest || difftime(f->time, oldest->time) <= 0)
oldest = f;
}
else if (!oldest || difftime(f->time, oldest->time) <= 0)
oldest = f;
if (target)
{
target->time = now;
return target;
}
/* can't find empty one, use oldest if there is one
and it's older than timeout */
@@ -896,7 +1001,7 @@ struct frec *get_new_frec(time_t now, int *wait)
if (!wait)
{
oldest->sentto = 0;
free_frec(oldest);
oldest->time = now;
}
return oldest;
@@ -922,7 +1027,7 @@ static struct frec *lookup_frec(unsigned short id, unsigned int crc)
{
struct frec *f;
for(f = frec_list; f; f = f->next)
for(f = daemon->frec_list; f; f = f->next)
if (f->sentto && f->new_id == id &&
(f->crc == crc || crc == 0xffffffff))
return f;
@@ -936,7 +1041,7 @@ static struct frec *lookup_frec_by_sender(unsigned short id,
{
struct frec *f;
for(f = frec_list; f; f = f->next)
for(f = daemon->frec_list; f; f = f->next)
if (f->sentto &&
f->orig_id == id &&
f->crc == crc &&
@@ -951,9 +1056,9 @@ void server_gone(struct server *server)
{
struct frec *f;
for (f = frec_list; f; f = f->next)
for (f = daemon->frec_list; f; f = f->next)
if (f->sentto && f->sentto == server)
f->sentto = NULL;
free_frec(f);
if (daemon->last_server == server)
daemon->last_server = NULL;
@@ -974,7 +1079,7 @@ static unsigned short get_id(int force, unsigned short force_id, unsigned int cr
{
struct frec *f = lookup_frec(force_id, crc);
if (f)
f->sentto = NULL; /* free */
free_frec(f); /* free */
ret = force_id;
}
else do

View File

@@ -50,30 +50,18 @@ struct script_data
static struct script_data *buf = NULL;
static size_t bytes_in_buf = 0, buf_size = 0;
int create_helper(int event_fd, long max_fd)
int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
{
pid_t pid;
int i, pipefd[2];
struct sigaction sigact;
struct passwd *ent_pw = NULL;
if (!daemon->dhcp || !daemon->lease_change_command)
return -1;
if (daemon->scriptuser && !(ent_pw = getpwnam(daemon->scriptuser)))
{
/* too late to die() */
send_event(event_fd, EVENT_USER_ERR, 0);
return -1;
}
/* create the pipe through which the main program sends us commands,
then fork our process. By now it's too late to die(), we just log
any failure via the main process. */
then fork our process. */
if (pipe(pipefd) == -1 || !fix_fd(pipefd[1]) || (pid = fork()) == -1)
{
send_event(event_fd, EVENT_PIPE_ERR, errno);
return -1;
send_event(err_fd, EVENT_PIPE_ERR, errno);
_exit(0);
}
if (pid != 0)
@@ -90,7 +78,29 @@ int create_helper(int event_fd, long max_fd)
sigaction(SIGTERM, &sigact, NULL);
sigaction(SIGALRM, &sigact, NULL);
/* close all the sockets etc, we don't need them here */
if (!(daemon->options & OPT_DEBUG) && uid != 0)
{
gid_t dummy;
if (setgroups(0, &dummy) == -1 ||
setgid(gid) == -1 ||
setuid(uid) == -1)
{
if (daemon->options & OPT_NO_FORK)
/* send error to daemon process if no-fork */
send_event(event_fd, EVENT_HUSER_ERR, errno);
else
{
/* kill daemon */
send_event(event_fd, EVENT_DIE, 0);
/* return error */
send_event(err_fd, EVENT_HUSER_ERR, errno);;
}
_exit(0);
}
}
/* close all the sockets etc, we don't need them here. This closes err_fd, so that
main process can return. */
for (max_fd--; max_fd > 0; max_fd--)
if (max_fd != STDOUT_FILENO && max_fd != STDERR_FILENO &&
max_fd != STDIN_FILENO && max_fd != pipefd[0] && max_fd != event_fd)
@@ -181,20 +191,6 @@ int create_helper(int event_fd, long max_fd)
continue;
}
/* Change ownership of child, if this fails, log and ditch,
rather than running wrong user */
if (ent_pw)
{
gid_t dummy;
if (setgroups(0, &dummy) == -1 ||
setgid(ent_pw->pw_gid) == -1 ||
setuid(ent_pw->pw_uid) == -1)
{
send_event(event_fd, EVENT_USER_ERR, errno);
_exit(0);
}
}
if (data.clid_len != 0)
my_setenv("DNSMASQ_CLIENT_ID", daemon->packet, &err);

View File

@@ -50,8 +50,10 @@ static struct log_entry *entries = NULL;
static struct log_entry *free_entries = NULL;
void log_start(struct passwd *ent_pw)
int log_start(struct passwd *ent_pw, int errfd)
{
int ret = 0;
log_stderr = !!(daemon->options & OPT_DEBUG);
if (daemon->log_fac != -1)
@@ -70,8 +72,11 @@ void log_start(struct passwd *ent_pw)
max_logs = daemon->max_logs;
if (!log_reopen(daemon->log_file))
die(_("cannot open %s: %s"), daemon->log_file ? daemon->log_file : "log", EC_FILE);
{
send_event(errfd, EVENT_LOG_ERR, errno);
_exit(0);
}
/* if queuing is inhibited, make sure we allocate
the one required buffer now. */
if (max_logs == 0)
@@ -85,8 +90,11 @@ void log_start(struct passwd *ent_pw)
change the ownership here so that the file is always owned by
the dnsmasq user. Then logrotate can just copy the owner.
Failure of the chown call is OK, (for instance when started as non-root) */
if (log_to_file && ent_pw && ent_pw->pw_uid != 0 && fchown(log_fd, ent_pw->pw_uid, -1) != 0)
my_syslog(LOG_WARNING, _("warning: failed to change owner of %s: %s"), daemon->log_file, strerror(errno));
if (log_to_file && ent_pw && ent_pw->pw_uid != 0 &&
fchown(log_fd, ent_pw->pw_uid, -1) != 0)
ret = errno;
return ret;
}
int log_reopen(char *log_file)

View File

@@ -441,6 +441,61 @@ struct listener *create_bound_listeners(void)
return listeners;
}
/* return a UDP socket bound to a random port, have to coper with straying into
occupied port nos and reserved ones. */
int random_sock(int family)
{
int fd;
if ((fd = socket(family, SOCK_DGRAM, 0)) != -1)
{
union mysockaddr addr;
memset(&addr, 0, sizeof(addr));
addr.in.sin_family = family;
if (fix_fd(fd))
while (1)
{
unsigned short port = rand16();
if (port <= (unsigned short) daemon->min_port)
continue;
if (family == AF_INET)
{
addr.in.sin_addr.s_addr = INADDR_ANY;
addr.in.sin_port = htons(port);
#ifdef HAVE_SOCKADDR_SA_LEN
addr.in.sin_len = sizeof(struct sockaddr_in);
#endif
}
#ifdef HAVE_IPV6
else
{
addr.in6.sin6_addr = in6addr_any;
addr.in6.sin6_port = htons(port);
#ifdef HAVE_SOCKADDR_SA_LEN
addr.in6.sin6_len = sizeof(struct sockaddr_in6);
#endif
}
#endif
if (bind(fd, (struct sockaddr *)&addr, sa_len(&addr)) == 0)
return fd;
if (errno != EADDRINUSE && errno != EACCES)
break;
}
close(fd);
}
return -1;
}
int local_bind(int fd, union mysockaddr *addr, char *intname, int is_tcp)
{
union mysockaddr addr_copy = *addr;
@@ -473,6 +528,25 @@ static struct serverfd *allocate_sfd(union mysockaddr *addr, char *intname)
struct serverfd *sfd;
int errsave;
/* when using random ports, servers which would otherwise use
the INADDR_ANY/port0 socket have sfd set to NULL */
if (!daemon->osport)
{
errno = 0;
if (addr->sa.sa_family == AF_INET &&
addr->in.sin_addr.s_addr == INADDR_ANY &&
addr->in.sin_port == htons(0))
return NULL;
#ifdef HAVE_IPV6
if (addr->sa.sa_family == AF_INET6 &&
memcmp(&addr->in6.sin6_addr, &in6addr_any, sizeof(in6addr_any)) == 0 &&
addr->in6.sin6_port == htons(0))
return NULL;
#endif
}
/* may have a suitable one already */
for (sfd = daemon->sfds; sfd; sfd = sfd->next )
if (sockaddr_isequal(&sfd->source_addr, addr) &&
@@ -538,6 +612,7 @@ void pre_allocate_sfds(void)
for (srv = daemon->servers; srv; srv = srv->next)
if (!(srv->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR)) &&
!allocate_sfd(&srv->source_addr, srv->interface) &&
errno != 0 &&
(daemon->options & OPT_NOWILD))
{
prettyprint_addr(&srv->addr, daemon->namebuff);
@@ -585,7 +660,9 @@ void check_servers(void)
}
/* Do we need a socket set? */
if (!new->sfd && !(new->sfd = allocate_sfd(&new->source_addr, new->interface)))
if (!new->sfd &&
!(new->sfd = allocate_sfd(&new->source_addr, new->interface)) &&
errno != 0)
{
my_syslog(LOG_WARNING,
_("ignoring nameserver %s - cannot make/bind socket: %s"),

View File

@@ -93,6 +93,9 @@ struct myoption {
#define LOPT_NEGTTL 283
#define LOPT_ALTPORT 284
#define LOPT_SCRIPTUSR 285
#define LOPT_LOCAL 286
#define LOPT_NAPTR 287
#define LOPT_MINPORT 288
#ifdef HAVE_GETOPT_LONG
static const struct option opts[] =
@@ -130,7 +133,7 @@ static const struct myoption opts[] =
{"pid-file", 2, 0, 'x'},
{"strict-order", 0, 0, 'o'},
{"server", 1, 0, 'S'},
{"local", 1, 0, 'S' },
{"local", 1, 0, LOPT_LOCAL },
{"address", 1, 0, 'A' },
{"conf-file", 2, 0, 'C'},
{"no-resolv", 0, 0, 'R'},
@@ -173,6 +176,7 @@ static const struct myoption opts[] =
{"tftp-root", 1, 0, LOPT_PREFIX },
{"tftp-max", 1, 0, LOPT_TFTP_MAX },
{"ptr-record", 1, 0, LOPT_PTR },
{"naptr-record", 1, 0, LOPT_NAPTR },
#ifdef HAVE_BSD_BRIDGE
{"bridge-interface", 1, 0 , LOPT_BRIDGE },
#endif
@@ -195,150 +199,119 @@ static const struct myoption opts[] =
{"neg-ttl", 1, 0, LOPT_NEGTTL },
{"dhcp-alternate-port", 2, 0, LOPT_ALTPORT },
{"dhcp-scriptuser", 1, 0, LOPT_SCRIPTUSR },
{"min-port", 1, 0, LOPT_MINPORT },
{ NULL, 0, 0, 0 }
};
struct optflags {
int c;
unsigned int flag;
};
/* These must have more the one '1' bit */
#define ARG_DUP 3
#define ARG_ONE 5
#define ARG_USED_CL 7
#define ARG_USED_FILE 9
static const struct optflags optmap[] = {
{ 'b', OPT_BOGUSPRIV },
{ 'f', OPT_FILTER },
{ 'q', OPT_LOG },
{ 'e', OPT_SELFMX },
{ 'h', OPT_NO_HOSTS },
{ 'n', OPT_NO_POLL },
{ 'd', OPT_DEBUG },
{ 'k', OPT_NO_FORK },
{ 'K', OPT_AUTHORITATIVE },
{ 'o', OPT_ORDER },
{ 'R', OPT_NO_RESOLV },
{ 'E', OPT_EXPAND },
{ 'L', OPT_LOCALMX },
{ 'N', OPT_NO_NEG },
{ 'D', OPT_NODOTS_LOCAL },
{ 'z', OPT_NOWILD },
{ 'Z', OPT_ETHERS },
{ 'y', OPT_LOCALISE },
{ '1', OPT_DBUS },
{ '3', OPT_BOOTP_DYNAMIC },
{ '5', OPT_NO_PING },
{ '9', OPT_LEASE_RO },
{ LOPT_RELOAD, OPT_RELOAD },
{ LOPT_TFTP, OPT_TFTP },
{ LOPT_SECURE, OPT_TFTP_SECURE },
{ LOPT_NOBLOCK, OPT_TFTP_NOBLOCK },
{ LOPT_LOG_OPTS, OPT_LOG_OPTS },
{ LOPT_APREF, OPT_TFTP_APREF },
{ LOPT_OVERRIDE, OPT_NO_OVERRIDE },
{ LOPT_REBIND, OPT_NO_REBIND },
{ LOPT_NOLAST, OPT_ALL_SERVERS },
{ 'v', 0},
{ 'w', 0},
{ 0, 0 }
};
static const struct {
char * const flag;
static struct {
int opt;
unsigned int rept;
char * const flagdesc;
char * const desc;
char * const arg;
} usage[] = {
{ "-a, --listen-address=ipaddr", gettext_noop("Specify local address(es) to listen on."), NULL },
{ "-A, --address=/domain/ipaddr", gettext_noop("Return ipaddr for all hosts in specified domains."), NULL },
{ "-b, --bogus-priv", gettext_noop("Fake reverse lookups for RFC1918 private address ranges."), NULL },
{ "-B, --bogus-nxdomain=ipaddr", gettext_noop("Treat ipaddr as NXDOMAIN (defeats Verisign wildcard)."), NULL },
{ "-c, --cache-size=cachesize", gettext_noop("Specify the size of the cache in entries (defaults to %s)."), "$" },
{ "-C, --conf-file=path", gettext_noop("Specify configuration file (defaults to %s)."), CONFFILE },
{ "-d, --no-daemon", gettext_noop("Do NOT fork into the background: run in debug mode."), NULL },
{ "-D, --domain-needed", gettext_noop("Do NOT forward queries with no domain part."), NULL },
{ "-e, --selfmx", gettext_noop("Return self-pointing MX records for local hosts."), NULL },
{ "-E, --expand-hosts", gettext_noop("Expand simple names in /etc/hosts with domain-suffix."), NULL },
{ "-f, --filterwin2k", gettext_noop("Don't forward spurious DNS requests from Windows hosts."), NULL },
{ "-F, --dhcp-range=ipaddr,ipaddr,time", gettext_noop("Enable DHCP in the range given with lease duration."), NULL },
{ "-g, --group=groupname", gettext_noop("Change to this group after startup (defaults to %s)."), CHGRP },
{ "-G, --dhcp-host=<hostspec>", gettext_noop("Set address or hostname for a specified machine."), NULL },
{ " --dhcp-hostsfile=<filename>", gettext_noop("Read DHCP host specs from file"), NULL },
{ " --dhcp-optsfile=<filename>", gettext_noop("Read DHCP option specs from file"), NULL },
{ "-h, --no-hosts", gettext_noop("Do NOT load %s file."), HOSTSFILE },
{ "-H, --addn-hosts=path", gettext_noop("Specify a hosts file to be read in addition to %s."), HOSTSFILE },
{ "-i, --interface=interface", gettext_noop("Specify interface(s) to listen on."), NULL },
{ "-I, --except-interface=int", gettext_noop("Specify interface(s) NOT to listen on.") , NULL },
{ "-j, --dhcp-userclass=<tag>,<class>", gettext_noop("Map DHCP user class to tag."), NULL },
{ " --dhcp-circuitid=<tag>,<circuit>", gettext_noop("Map RFC3046 circuit-id to tag."), NULL },
{ " --dhcp-remoteid=<tag>,<remote>", gettext_noop("Map RFC3046 remote-id to tag."), NULL },
{ " --dhcp-subscrid=<tag>,<remote>", gettext_noop("Map RFC3993 subscriber-id to tag."), NULL },
{ "-J, --dhcp-ignore=<tag>", gettext_noop("Don't do DHCP for hosts with tag set."), NULL },
{ " --dhcp-broadcast=<tag>", gettext_noop("Force broadcast replies for hosts with tag set."), NULL },
{ "-k, --keep-in-foreground", gettext_noop("Do NOT fork into the background, do NOT run in debug mode."), NULL },
{ "-K, --dhcp-authoritative", gettext_noop("Assume we are the only DHCP server on the local network."), NULL },
{ "-l, --dhcp-leasefile=path", gettext_noop("Specify where to store DHCP leases (defaults to %s)."), LEASEFILE },
{ "-L, --localmx", gettext_noop("Return MX records for local hosts."), NULL },
{ "-m, --mx-host=host_name,target,pref", gettext_noop("Specify an MX record."), NULL },
{ "-M, --dhcp-boot=<bootp opts>", gettext_noop("Specify BOOTP options to DHCP server."), NULL },
{ "-n, --no-poll", gettext_noop("Do NOT poll %s file, reload only on SIGHUP."), RESOLVFILE },
{ "-N, --no-negcache", gettext_noop("Do NOT cache failed search results."), NULL },
{ "-o, --strict-order", gettext_noop("Use nameservers strictly in the order given in %s."), RESOLVFILE },
{ "-O, --dhcp-option=<optspec>", gettext_noop("Specify options to be sent to DHCP clients."), NULL },
{ " --dhcp-option-force=<optspec>", gettext_noop("DHCP option sent even if the client does not request it."), NULL},
{ "-p, --port=number", gettext_noop("Specify port to listen for DNS requests on (defaults to 53)."), NULL },
{ "-P, --edns-packet-max=<size>", gettext_noop("Maximum supported UDP packet size for EDNS.0 (defaults to %s)."), "*" },
{ "-q, --log-queries", gettext_noop("Log DNS queries."), NULL },
{ "-Q, --query-port=number", gettext_noop("Force the originating port for upstream DNS queries."), NULL },
{ "-R, --no-resolv", gettext_noop("Do NOT read resolv.conf."), NULL },
{ "-r, --resolv-file=path", gettext_noop("Specify path to resolv.conf (defaults to %s)."), RESOLVFILE },
{ "-S, --server=/domain/ipaddr", gettext_noop("Specify address(es) of upstream servers with optional domains."), NULL },
{ " --local=/domain/", gettext_noop("Never forward queries to specified domains."), NULL },
{ "-s, --domain=domain", gettext_noop("Specify the domain to be assigned in DHCP leases."), NULL },
{ "-t, --mx-target=host_name", gettext_noop("Specify default target in an MX record."), NULL },
{ "-T, --local-ttl=time", gettext_noop("Specify time-to-live in seconds for replies from /etc/hosts."), NULL },
{ " --neg-ttl=time", gettext_noop("Specify time-to-live in seconds for negative caching."), NULL },
{ "-u, --user=username", gettext_noop("Change to this user after startup. (defaults to %s)."), CHUSER },
{ "-U, --dhcp-vendorclass=<id>,<class>", gettext_noop("Map DHCP vendor class to tag."), NULL },
{ "-v, --version", gettext_noop("Display dnsmasq version and copyright information."), NULL },
{ "-V, --alias=addr,addr,mask", gettext_noop("Translate IPv4 addresses from upstream servers."), NULL },
{ "-W, --srv-host=name,target,...", gettext_noop("Specify a SRV record."), NULL },
{ "-w, --help", gettext_noop("Display this message. Use --help dhcp for known DHCP options."), NULL },
{ "-x, --pid-file=path", gettext_noop("Specify path of PID file (defaults to %s)."), RUNFILE },
{ "-X, --dhcp-lease-max=number", gettext_noop("Specify maximum number of DHCP leases (defaults to %s)."), "&" },
{ "-y, --localise-queries", gettext_noop("Answer DNS queries based on the interface a query was sent to."), NULL },
{ "-Y --txt-record=name,txt....", gettext_noop("Specify TXT DNS record."), NULL },
{ " --ptr-record=name,target", gettext_noop("Specify PTR DNS record."), NULL },
{ " --interface-name=name,interface", gettext_noop("Give DNS name to IPv4 address of interface."), NULL },
{ "-z, --bind-interfaces", gettext_noop("Bind only to interfaces in use."), NULL },
{ "-Z, --read-ethers", gettext_noop("Read DHCP static host information from %s."), ETHERSFILE },
{ "-1, --enable-dbus", gettext_noop("Enable the DBus interface for setting upstream servers, etc."), NULL },
{ "-2, --no-dhcp-interface=interface", gettext_noop("Do not provide DHCP on this interface, only provide DNS."), NULL },
{ "-3, --bootp-dynamic", gettext_noop("Enable dynamic address allocation for bootp."), NULL },
{ "-4, --dhcp-mac=<id>,<mac address>", gettext_noop("Map MAC address (with wildcards) to option set."), NULL },
{ 'a', ARG_DUP, "ipaddr", gettext_noop("Specify local address(es) to listen on."), NULL },
{ 'A', ARG_DUP, "/domain/ipaddr", gettext_noop("Return ipaddr for all hosts in specified domains."), NULL },
{ 'b', OPT_BOGUSPRIV, NULL, gettext_noop("Fake reverse lookups for RFC1918 private address ranges."), NULL },
{ 'B', ARG_DUP, "ipaddr", gettext_noop("Treat ipaddr as NXDOMAIN (defeats Verisign wildcard)."), NULL },
{ 'c', ARG_ONE, "cachesize", gettext_noop("Specify the size of the cache in entries (defaults to %s)."), "$" },
{ 'C', ARG_DUP, "path", gettext_noop("Specify configuration file (defaults to %s)."), CONFFILE },
{ 'd', OPT_DEBUG, NULL, gettext_noop("Do NOT fork into the background: run in debug mode."), NULL },
{ 'D', OPT_NODOTS_LOCAL, NULL, gettext_noop("Do NOT forward queries with no domain part."), NULL },
{ 'e', OPT_SELFMX, NULL, gettext_noop("Return self-pointing MX records for local hosts."), NULL },
{ 'E', OPT_EXPAND, NULL, gettext_noop("Expand simple names in /etc/hosts with domain-suffix."), NULL },
{ 'f', OPT_FILTER, NULL, gettext_noop("Don't forward spurious DNS requests from Windows hosts."), NULL },
{ 'F', ARG_DUP, "ipaddr,ipaddr,time", gettext_noop("Enable DHCP in the range given with lease duration."), NULL },
{ 'g', ARG_ONE, "groupname", gettext_noop("Change to this group after startup (defaults to %s)."), CHGRP },
{ 'G', ARG_DUP, "<hostspec>", gettext_noop("Set address or hostname for a specified machine."), NULL },
{ LOPT_DHCP_HOST, ARG_ONE, "<filename>", gettext_noop("Read DHCP host specs from file"), NULL },
{ LOPT_DHCP_OPTS, ARG_ONE, "<filename>", gettext_noop("Read DHCP option specs from file"), NULL },
{ 'h', OPT_NO_HOSTS, NULL, gettext_noop("Do NOT load %s file."), HOSTSFILE },
{ 'H', ARG_DUP, "path", gettext_noop("Specify a hosts file to be read in addition to %s."), HOSTSFILE },
{ 'i', ARG_DUP, "interface", gettext_noop("Specify interface(s) to listen on."), NULL },
{ 'I', ARG_DUP, "int", gettext_noop("Specify interface(s) NOT to listen on.") , NULL },
{ 'j', ARG_DUP, "<tag>,<class>", gettext_noop("Map DHCP user class to tag."), NULL },
{ LOPT_CIRCUIT, ARG_DUP, "<tag>,<circuit>", gettext_noop("Map RFC3046 circuit-id to tag."), NULL },
{ LOPT_REMOTE, ARG_DUP, "<tag>,<remote>", gettext_noop("Map RFC3046 remote-id to tag."), NULL },
{ LOPT_SUBSCR, ARG_DUP, "<tag>,<remote>", gettext_noop("Map RFC3993 subscriber-id to tag."), NULL },
{ 'J', ARG_DUP, "<tag>", gettext_noop("Don't do DHCP for hosts with tag set."), NULL },
{ LOPT_BROADCAST, ARG_DUP, "<tag>", gettext_noop("Force broadcast replies for hosts with tag set."), NULL },
{ 'k', OPT_NO_FORK, NULL, gettext_noop("Do NOT fork into the background, do NOT run in debug mode."), NULL },
{ 'K', OPT_AUTHORITATIVE, NULL, gettext_noop("Assume we are the only DHCP server on the local network."), NULL },
{ 'l', ARG_ONE, "path", gettext_noop("Specify where to store DHCP leases (defaults to %s)."), LEASEFILE },
{ 'L', OPT_LOCALMX, NULL, gettext_noop("Return MX records for local hosts."), NULL },
{ 'm', ARG_DUP, "host_name,target,pref", gettext_noop("Specify an MX record."), NULL },
{ 'M', ARG_DUP, "<bootp opts>", gettext_noop("Specify BOOTP options to DHCP server."), NULL },
{ 'n', OPT_NO_POLL, NULL, gettext_noop("Do NOT poll %s file, reload only on SIGHUP."), RESOLVFILE },
{ 'N', OPT_NO_NEG, NULL, gettext_noop("Do NOT cache failed search results."), NULL },
{ 'o', OPT_ORDER, NULL, gettext_noop("Use nameservers strictly in the order given in %s."), RESOLVFILE },
{ 'O', ARG_DUP, "<optspec>", gettext_noop("Specify options to be sent to DHCP clients."), NULL },
{ LOPT_FORCE, ARG_DUP, "<optspec>", gettext_noop("DHCP option sent even if the client does not request it."), NULL},
{ 'p', ARG_ONE, "number", gettext_noop("Specify port to listen for DNS requests on (defaults to 53)."), NULL },
{ 'P', ARG_ONE, "<size>", gettext_noop("Maximum supported UDP packet size for EDNS.0 (defaults to %s)."), "*" },
{ 'q', OPT_LOG, NULL, gettext_noop("Log DNS queries."), NULL },
{ 'Q', ARG_ONE, "number", gettext_noop("Force the originating port for upstream DNS queries."), NULL },
{ 'R', OPT_NO_RESOLV, NULL, gettext_noop("Do NOT read resolv.conf."), NULL },
{ 'r', ARG_DUP, "path", gettext_noop("Specify path to resolv.conf (defaults to %s)."), RESOLVFILE },
{ 'S', ARG_DUP, "/domain/ipaddr", gettext_noop("Specify address(es) of upstream servers with optional domains."), NULL },
{ LOPT_LOCAL, ARG_DUP, "/domain/", gettext_noop("Never forward queries to specified domains."), NULL },
{ 's', ARG_ONE, "<domain>", gettext_noop("Specify the domain to be assigned in DHCP leases."), NULL },
{ 't', ARG_ONE, "host_name", gettext_noop("Specify default target in an MX record."), NULL },
{ 'T', ARG_ONE, "time", gettext_noop("Specify time-to-live in seconds for replies from /etc/hosts."), NULL },
{ LOPT_NEGTTL, ARG_ONE, "time", gettext_noop("Specify time-to-live in seconds for negative caching."), NULL },
{ 'u', ARG_ONE, "username", gettext_noop("Change to this user after startup. (defaults to %s)."), CHUSER },
{ 'U', ARG_DUP, "<id>,<class>", gettext_noop("Map DHCP vendor class to tag."), NULL },
{ 'v', 0, NULL, gettext_noop("Display dnsmasq version and copyright information."), NULL },
{ 'V', ARG_DUP, "addr,addr,mask", gettext_noop("Translate IPv4 addresses from upstream servers."), NULL },
{ 'W', ARG_DUP, "name,target,...", gettext_noop("Specify a SRV record."), NULL },
{ 'w', 0, NULL, gettext_noop("Display this message. Use --help dhcp for known DHCP options."), NULL },
{ 'x', ARG_ONE, "path", gettext_noop("Specify path of PID file (defaults to %s)."), RUNFILE },
{ 'X', ARG_ONE, "number", gettext_noop("Specify maximum number of DHCP leases (defaults to %s)."), "&" },
{ 'y', OPT_LOCALISE, NULL, gettext_noop("Answer DNS queries based on the interface a query was sent to."), NULL },
{ 'Y', ARG_DUP, "name,txt....", gettext_noop("Specify TXT DNS record."), NULL },
{ LOPT_PTR, ARG_DUP, "name,target", gettext_noop("Specify PTR DNS record."), NULL },
{ LOPT_INTNAME, ARG_DUP, "name,interface", gettext_noop("Give DNS name to IPv4 address of interface."), NULL },
{ 'z', OPT_NOWILD, NULL, gettext_noop("Bind only to interfaces in use."), NULL },
{ 'Z', OPT_ETHERS, NULL, gettext_noop("Read DHCP static host information from %s."), ETHERSFILE },
{ '1', OPT_DBUS, NULL, gettext_noop("Enable the DBus interface for setting upstream servers, etc."), NULL },
{ '2', ARG_DUP, "interface", gettext_noop("Do not provide DHCP on this interface, only provide DNS."), NULL },
{ '3', OPT_BOOTP_DYNAMIC, NULL, gettext_noop("Enable dynamic address allocation for bootp."), NULL },
{ '4', ARG_DUP, "<id>,<mac address>", gettext_noop("Map MAC address (with wildcards) to option set."), NULL },
#ifdef HAVE_BSD_BRIDGE
{ " --bridge-interface=iface,alias,..", gettext_noop("Treat DHCP requests on aliases as arriving from interface."), NULL },
{ LOPT_BRIDGE, ARG_DUP, "iface,alias,..", gettext_noop("Treat DHCP requests on aliases as arriving from interface."), NULL },
#endif
{ "-5, --no-ping", gettext_noop("Disable ICMP echo address checking in the DHCP server."), NULL },
{ "-6, --dhcp-script=path", gettext_noop("Script to run on DHCP lease creation and destruction."), NULL },
{ "-7, --conf-dir=path", gettext_noop("Read configuration from all the files in this directory."), NULL },
{ "-8, --log-facility=facilty|file", gettext_noop("Log to this syslog facility or file. (defaults to DAEMON)"), NULL },
{ "-9, --leasefile-ro", gettext_noop("Read leases at startup, but never write the lease file."), NULL },
{ "-0, --dns-forward-max=<queries>", gettext_noop("Maximum number of concurrent DNS queries. (defaults to %s)"), "!" },
{ " --clear-on-reload", gettext_noop("Clear DNS cache when reloading %s."), RESOLVFILE },
{ " --dhcp-ignore-names[=<id>]", gettext_noop("Ignore hostnames provided by DHCP clients."), NULL },
{ " --dhcp-no-override", gettext_noop("Do NOT reuse filename and server fields for extra DHCP options."), NULL },
{ " --enable-tftp", gettext_noop("Enable integrated read-only TFTP server."), NULL },
{ " --tftp-root=<directory>", gettext_noop("Export files by TFTP only from the specified subtree."), NULL },
{ " --tftp-unique-root", gettext_noop("Add client IP address to tftp-root."), NULL },
{ " --tftp-secure", gettext_noop("Allow access only to files owned by the user running dnsmasq."), NULL },
{ " --tftp-max=<connections>", gettext_noop("Maximum number of conncurrent TFTP transfers (defaults to %s)."), "#" },
{ " --tftp-no-blocksize", gettext_noop("Disable the TFTP blocksize extension."), NULL },
{ " --tftp-port-range=<start>,<end>", gettext_noop("Ephemeral port range for use by TFTP transfers."), NULL },
{ " --log-dhcp", gettext_noop("Extra logging for DHCP."), NULL },
{ " --log-async[=<log lines>]", gettext_noop("Enable async. logging; optionally set queue length."), NULL },
{ " --stop-dns-rebind", gettext_noop("Stop DNS rebinding. Filter private IP ranges when resolving."), NULL },
{ " --all-servers", gettext_noop("Always perform DNS queries to all servers."), NULL },
{ " --dhcp-match=<netid>,<opt-no>", gettext_noop("Set tag if client includes option in request."), NULL },
{ " --dhcp-alternate-port[=<ports>]", gettext_noop("Use alternative ports for DHCP."), NULL },
{ " --dhcp-scriptuser=<username>", gettext_noop("Run lease-change script as this user."), NULL },
{ NULL, NULL, NULL }
{ '5', OPT_NO_PING, NULL, gettext_noop("Disable ICMP echo address checking in the DHCP server."), NULL },
{ '6', ARG_ONE, "path", gettext_noop("Script to run on DHCP lease creation and destruction."), NULL },
{ '7', ARG_DUP, "path", gettext_noop("Read configuration from all the files in this directory."), NULL },
{ '8', ARG_ONE, "<facilty>|<file>", gettext_noop("Log to this syslog facility or file. (defaults to DAEMON)"), NULL },
{ '9', OPT_LEASE_RO, NULL, gettext_noop("Do not use leasefile."), NULL },
{ '0', ARG_ONE, "<queries>", gettext_noop("Maximum number of concurrent DNS queries. (defaults to %s)"), "!" },
{ LOPT_RELOAD, OPT_RELOAD, NULL, gettext_noop("Clear DNS cache when reloading %s."), RESOLVFILE },
{ LOPT_NO_NAMES, ARG_DUP, "[=<id>]", gettext_noop("Ignore hostnames provided by DHCP clients."), NULL },
{ LOPT_OVERRIDE, OPT_NO_OVERRIDE, NULL, gettext_noop("Do NOT reuse filename and server fields for extra DHCP options."), NULL },
{ LOPT_TFTP, OPT_TFTP, NULL, gettext_noop("Enable integrated read-only TFTP server."), NULL },
{ LOPT_PREFIX, ARG_ONE, "<directory>", gettext_noop("Export files by TFTP only from the specified subtree."), NULL },
{ LOPT_APREF, OPT_TFTP_APREF, NULL, gettext_noop("Add client IP address to tftp-root."), NULL },
{ LOPT_SECURE, OPT_TFTP_SECURE, NULL, gettext_noop("Allow access only to files owned by the user running dnsmasq."), NULL },
{ LOPT_TFTP_MAX, ARG_ONE, "<connections>", gettext_noop("Maximum number of conncurrent TFTP transfers (defaults to %s)."), "#" },
{ LOPT_NOBLOCK, OPT_TFTP_NOBLOCK, NULL, gettext_noop("Disable the TFTP blocksize extension."), NULL },
{ LOPT_TFTPPORTS, ARG_ONE, "<start>,<end>", gettext_noop("Ephemeral port range for use by TFTP transfers."), NULL },
{ LOPT_LOG_OPTS, OPT_LOG_OPTS, NULL, gettext_noop("Extra logging for DHCP."), NULL },
{ LOPT_MAX_LOGS, ARG_ONE, "[=<log lines>]", gettext_noop("Enable async. logging; optionally set queue length."), NULL },
{ LOPT_REBIND, OPT_NO_REBIND, NULL, gettext_noop("Stop DNS rebinding. Filter private IP ranges when resolving."), NULL },
{ LOPT_NOLAST, OPT_ALL_SERVERS, NULL, gettext_noop("Always perform DNS queries to all servers."), NULL },
{ LOPT_MATCH, ARG_DUP, "<netid>,<opt-no>", gettext_noop("Set tag if client includes option in request."), NULL },
{ LOPT_ALTPORT, ARG_ONE, "[=<ports>]", gettext_noop("Use alternative ports for DHCP."), NULL },
{ LOPT_SCRIPTUSR, ARG_ONE, "<username>", gettext_noop("Run lease-change script as this user."), NULL },
{ LOPT_NAPTR, ARG_DUP, "<name>,<naptr>", gettext_noop("Specify NAPTR DNS record."), NULL },
{ LOPT_MINPORT, ARG_ONE, "<port>", gettext_noop("Specify lowest port available for DNS query transmission."), NULL },
{ 0, 0, NULL, NULL, NULL }
};
/* makes options which take a list of addresses */
@@ -592,10 +565,30 @@ static void do_usage(void)
#ifndef HAVE_GETOPT_LONG
printf(_("Use short options only on the command line.\n"));
#endif
printf(_("Valid options are :\n"));
printf(_("Valid options are:\n"));
for (i = 0; usage[i].flag; i++)
for (i = 0; usage[i].opt != 0; i++)
{
char *desc = usage[i].flagdesc;
char *eq = "=";
if (!desc || *desc == '[')
eq = "";
if (!desc)
desc = "";
for ( j = 0; opts[j].name; j++)
if (opts[j].val == usage[i].opt)
break;
if (usage[i].opt < 256)
sprintf(buff, "-%c, ", usage[i].opt);
else
sprintf(buff, " ");
sprintf(buff+4, "--%s%s%s", opts[j].name, eq, desc);
printf("%-36.36s", buff);
if (usage[i].arg)
{
strcpy(buff, usage[i].arg);
@@ -603,7 +596,6 @@ static void do_usage(void)
if (tab[j].handle == *(usage[i].arg))
sprintf(buff, "%d", tab[j].val);
}
printf("%-36.36s", usage[i].flag);
printf(_(usage[i].desc), buff);
printf("\n");
}
@@ -918,13 +910,37 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
if (option == '?')
return gen_prob;
for (i=0; optmap[i].c; i++)
if (option == optmap[i].c)
for (i=0; usage[i].opt != 0; i++)
if (usage[i].opt == option)
{
daemon->options |= optmap[i].flag;
return NULL;
int rept = usage[i].rept;
if (nest == 0)
{
/* command line */
if (rept == ARG_USED_CL)
return _("illegal repeated flag");
if (rept == ARG_ONE)
usage[i].rept = ARG_USED_CL;
}
else
{
/* allow file to override command line */
if (rept == ARG_USED_FILE)
return _("illegal repeated keyword");
if (rept == ARG_USED_CL || rept == ARG_ONE)
usage[i].rept = ARG_USED_FILE;
}
if (rept != ARG_DUP && rept != ARG_ONE && rept != ARG_USED_CL)
{
daemon->options |= rept;
return NULL;
}
break;
}
switch (option)
{
case 'C': /* --conf-file */
@@ -1113,6 +1129,7 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
case 'g': /* --group */
daemon->groupname = opt_string_alloc(arg);
daemon->group_set = 1;
break;
case LOPT_SCRIPTUSR: /* --scriptuser */
@@ -1204,8 +1221,9 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
} while (arg);
break;
case 'S': /* --server */
case 'A': /* --address */
case 'S': /* --server */
case LOPT_LOCAL: /* --local */
case 'A': /* --address */
{
struct server *serv, *newlist = NULL;
@@ -1376,6 +1394,11 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
option = '?';
break;
case LOPT_MINPORT: /* --min-port */
if (!atoi_check(arg, &daemon->min_port))
option = '?';
break;
case '0': /* --dns-forward-max */
if (!atoi_check(arg, &daemon->ftabsize))
option = '?';
@@ -1401,6 +1424,10 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
case 'Q': /* --query-port */
if (!atoi_check(arg, &daemon->query_port))
option = '?';
/* if explicitly set to zero, use single OS ephemeral port
and disable random ports */
if (daemon->query_port == 0)
daemon->osport = 1;
break;
case 'T': /* --local-ttl */
@@ -1879,6 +1906,7 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
break;
case LOPT_MATCH:
new->match_type = MATCH_OPTION;
break;
}
new->next = daemon->dhcp_vendors;
daemon->dhcp_vendors = new;
@@ -2015,6 +2043,42 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
break;
}
case LOPT_NAPTR: /* --naptr-record */
{
char *a[7] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL };
int k = 0;
struct naptr *new;
int order, pref;
if ((a[0] = arg))
for (k = 1; k < 7; k++)
if (!(a[k] = split(a[k-1])))
break;
if (k < 6 ||
!canonicalise_opt(a[0]) ||
!atoi_check(a[1], &order) ||
!atoi_check(a[2], &pref) ||
(k == 7 && !canonicalise_opt(a[6])))
problem = _("bad NAPTR record");
else
{
new = opt_malloc(sizeof(struct naptr));
new->next = daemon->naptr;
daemon->naptr = new;
new->name = opt_string_alloc(a[0]);
new->flags = opt_string_alloc(a[3]);
new->services = opt_string_alloc(a[4]);
new->regexp = opt_string_alloc(a[5]);
if (k == 7)
new->replace = opt_string_alloc(a[6]);
new->order = order;
new->pref = pref;
}
break;
}
case 'Y': /* --txt-record */
{
struct txt_record *new;
@@ -2384,7 +2448,6 @@ void read_opts(int argc, char **argv, char *compile_opts)
daemon->default_resolv.name = RESOLVFILE;
daemon->resolv_files = &daemon->default_resolv;
daemon->username = CHUSER;
daemon->groupname = CHGRP;
daemon->runfile = RUNFILE;
daemon->dhcp_max = MAXLEASES;
daemon->tftp_max = TFTP_MAX_CONNECTIONS;
@@ -2453,7 +2516,7 @@ void read_opts(int argc, char **argv, char *compile_opts)
if (conffile)
one_file(conffile, nest, 0);
/* port might no be known when the address is parsed - fill in here */
/* port might not be known when the address is parsed - fill in here */
if (daemon->servers)
{
struct server *tmp;
@@ -2567,6 +2630,3 @@ void read_opts(int argc, char **argv, char *compile_opts)
}
}
}

View File

@@ -1044,6 +1044,16 @@ static int add_resource_record(HEADER *header, char *limit, int *truncp, unsigne
memcpy(p, sval, usval);
p += usval;
break;
case 'z':
sval = va_arg(ap, char *);
usval = sval ? strlen(sval) : 0;
if (usval > 255)
usval = 255;
*p++ = (unsigned char)usval;
memcpy(p, sval, usval);
p += usval;
break;
}
va_end(ap); /* clean up variable argument pointer */
@@ -1145,7 +1155,7 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
ans = 1;
if (!dryrun)
{
log_query(F_CNAME | F_FORWARD | F_CONFIG | F_NXDOMAIN, name, NULL, 0, NULL, 0);
log_query(F_CNAME | F_FORWARD | F_CONFIG | F_NXDOMAIN, name, NULL, "<TXT>");
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
daemon->local_ttl, NULL,
T_TXT, t->class, "t", t->len, t->txt))
@@ -1184,7 +1194,7 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
ans = 1;
if (!dryrun)
{
log_query(F_IPV4 | F_REVERSE | F_CONFIG, intr->name, &addr, 0, NULL, 0);
log_query(F_IPV4 | F_REVERSE | F_CONFIG, intr->name, &addr, NULL);
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
daemon->local_ttl, NULL,
T_PTR, C_IN, "d", intr->name))
@@ -1196,7 +1206,7 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
ans = 1;
if (!dryrun)
{
log_query(F_CNAME | F_FORWARD | F_CONFIG | F_BIGNAME, name, NULL, 0, NULL, 0);
log_query(F_CNAME | F_FORWARD | F_CONFIG | F_NXDOMAIN, name, NULL, "<PTR>");
for (ptr = daemon->ptr; ptr; ptr = ptr->next)
if (hostname_isequal(name, ptr->name) &&
add_resource_record(header, limit, &trunc, nameoffset, &ansp,
@@ -1220,7 +1230,7 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
if (crecp->flags & F_NXDOMAIN)
nxdomain = 1;
if (!dryrun)
log_query(crecp->flags & ~F_FORWARD, name, &addr, 0, NULL, 0);
log_query(crecp->flags & ~F_FORWARD, name, &addr, NULL);
}
else if ((crecp->flags & (F_HOSTS | F_DHCP)) || !sec_reqd)
{
@@ -1237,8 +1247,8 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
else
ttl = crecp->ttd - now;
log_query(crecp->flags & ~F_FORWARD, cache_get_name(crecp), &addr,
0, daemon->addn_hosts, crecp->uid);
log_query(crecp->flags & ~F_FORWARD, cache_get_name(crecp), &addr,
record_source(daemon->addn_hosts, crecp->uid));
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, ttl, NULL,
T_PTR, C_IN, "d", cache_get_name(crecp)))
@@ -1255,7 +1265,7 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
nxdomain = 1;
if (!dryrun)
log_query(F_CONFIG | F_REVERSE | F_IPV4 | F_NEG | F_NXDOMAIN,
name, &addr, 0, NULL, 0);
name, &addr, NULL);
}
}
@@ -1279,7 +1289,7 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
ans = 1;
if (!dryrun)
{
log_query(F_FORWARD | F_CONFIG | F_IPV4, name, &addr, 0, NULL, 0);
log_query(F_FORWARD | F_CONFIG | F_IPV4, name, &addr, NULL);
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
daemon->local_ttl, NULL, type, C_IN, "4", &addr))
anscount++;
@@ -1302,10 +1312,10 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
if (!dryrun)
{
if ((addr.addr.addr4 = get_ifaddr(intr->intr)).s_addr == (in_addr_t) -1)
log_query(F_FORWARD | F_CONFIG | F_IPV4 | F_NEG, name, NULL, 0, NULL, 0);
log_query(F_FORWARD | F_CONFIG | F_IPV4 | F_NEG, name, NULL, NULL);
else
{
log_query(F_FORWARD | F_CONFIG | F_IPV4, name, &addr, 0, NULL, 0);
log_query(F_FORWARD | F_CONFIG | F_IPV4, name, &addr, NULL);
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
daemon->local_ttl, NULL, type, C_IN, "4", &addr))
anscount++;
@@ -1347,7 +1357,7 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
{
if (!dryrun)
{
log_query(crecp->flags, name, NULL, 0, daemon->addn_hosts, crecp->uid);
log_query(crecp->flags, name, NULL, record_source(daemon->addn_hosts, crecp->uid));
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, crecp->ttd - now, &nameoffset,
T_CNAME, C_IN, "d", cache_get_name(crecp->addr.cname.cache)))
anscount++;
@@ -1364,7 +1374,7 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
if (crecp->flags & F_NXDOMAIN)
nxdomain = 1;
if (!dryrun)
log_query(crecp->flags, name, NULL, 0, NULL, 0);
log_query(crecp->flags, name, NULL, NULL);
}
else if ((crecp->flags & (F_HOSTS | F_DHCP)) || !sec_reqd)
{
@@ -1389,7 +1399,7 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
ttl = crecp->ttd - now;
log_query(crecp->flags & ~F_REVERSE, name, &crecp->addr.addr,
0, daemon->addn_hosts, crecp->uid);
record_source(daemon->addn_hosts, crecp->uid));
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, ttl, NULL, type, C_IN,
type == T_A ? "4" : "6", &crecp->addr))
@@ -1410,7 +1420,7 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
if (!dryrun)
{
unsigned int offset;
log_query(F_CNAME | F_FORWARD | F_CONFIG | F_IPV4, name, NULL, 0, NULL, 0);
log_query(F_CNAME | F_FORWARD | F_CONFIG | F_NXDOMAIN, name, NULL, "<MX>");
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
&offset, T_MX, C_IN, "sd", rec->weight, rec->target))
{
@@ -1427,7 +1437,7 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
ans = 1;
if (!dryrun)
{
log_query(F_CNAME | F_FORWARD | F_CONFIG | F_IPV4, name, NULL, 0, NULL, 0);
log_query(F_CNAME | F_FORWARD | F_CONFIG | F_NXDOMAIN, name, NULL, "<MX>");
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl, NULL,
T_MX, C_IN, "sd", 1,
(daemon->options & OPT_SELFMX) ? name : daemon->mxtarget))
@@ -1447,7 +1457,7 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
if (!dryrun)
{
unsigned int offset;
log_query(F_CNAME | F_FORWARD | F_CONFIG | F_IPV6, name, NULL, 0, NULL, 0);
log_query(F_CNAME | F_FORWARD | F_CONFIG | F_NXDOMAIN, name, NULL, "<SRV>");
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
&offset, T_SRV, C_IN, "sssd",
rec->priority, rec->weight, rec->srvport, rec->target))
@@ -1463,9 +1473,27 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
{
ans = 1;
if (!dryrun)
log_query(F_CONFIG | F_NEG, name, NULL, 0, NULL, 0);
log_query(F_CONFIG | F_NEG, name, NULL, NULL);
}
}
if (qtype == T_NAPTR || qtype == T_ANY)
{
struct naptr *na;
for (na = daemon->naptr; na; na = na->next)
if (hostname_isequal(name, na->name))
{
ans = 1;
if (!dryrun)
{
log_query(F_CNAME | F_FORWARD | F_CONFIG | F_NXDOMAIN, name, NULL, "<NAPTR>");
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
NULL, T_NAPTR, C_IN, "sszzzd",
na->order, na->pref, na->flags, na->services, na->regexp, na->replace))
anscount++;
}
}
}
if (qtype == T_MAILB)
ans = 1, nxdomain = 1;
@@ -1474,7 +1502,7 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
{
ans = 1;
if (!dryrun)
log_query(F_CONFIG | F_NEG, name, &addr, 0, NULL, 0);
log_query(F_CONFIG | F_NEG, name, &addr, NULL);
}
}

View File

@@ -56,6 +56,7 @@
#define SUBOPT_REMOTE_ID 2
#define SUBOPT_SUBNET_SELECT 5 /* RFC 3527 */
#define SUBOPT_SUBSCR_ID 6 /* RFC 3393 */
#define SUBOPT_SERVER_OR 11 /* RFC 5107 */
#define DHCPDISCOVER 1
#define DHCPOFFER 2
@@ -68,9 +69,10 @@
#define have_config(config, mask) ((config) && ((config)->flags & (mask)))
#define option_len(opt) ((int)(((unsigned char *)(opt))[1]))
#define option_ptr(opt) ((void *)&(((unsigned char *)(opt))[2]))
#define option_ptr(opt, i) ((void *)&(((unsigned char *)(opt))[2u+(unsigned int)(i)]))
static int sanitise(unsigned char *opt, char *buf);
static struct in_addr server_id(struct dhcp_context *context, struct in_addr override);
static unsigned int calc_time(struct dhcp_context *context, struct dhcp_config *config, unsigned char *opt);
static void option_put(struct dhcp_packet *mess, unsigned char *end, int opt, int len, unsigned int val);
static void option_put_string(struct dhcp_packet *mess, unsigned char *end,
@@ -117,16 +119,16 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
unsigned int time;
struct dhcp_config *config;
struct dhcp_netid *netid = NULL;
struct in_addr subnet_addr, fallback;
struct in_addr subnet_addr, fallback, override;
unsigned short fuzz = 0;
unsigned int mess_type = 0;
unsigned char fqdn_flags = 0;
unsigned char *agent_id = NULL;
unsigned char *emac = NULL;
int emac_len;
int emac_len = 0;
struct dhcp_netid known_id;
subnet_addr.s_addr = 0;
subnet_addr.s_addr = override.s_addr = 0;
if (mess->op != BOOTREQUEST || mess->hlen > DHCP_CHADDR_MAX)
return 0;
@@ -184,8 +186,12 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
}
/* look for RFC3527 Link selection sub-option */
if ((sopt = option_find1(option_ptr(opt), option_ptr(opt) + option_len(opt), SUBOPT_SUBNET_SELECT, INADDRSZ)))
if ((sopt = option_find1(option_ptr(opt, 0), option_ptr(opt, option_len(opt)), SUBOPT_SUBNET_SELECT, INADDRSZ)))
subnet_addr = option_addr(sopt);
/* look for RFC5107 server-identifier-override */
if ((sopt = option_find1(option_ptr(opt, 0), option_ptr(opt, option_len(opt)), SUBOPT_SERVER_OR, INADDRSZ)))
override = option_addr(sopt);
/* if a circuit-id or remote-is option is provided, exact-match to options. */
for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)
@@ -201,9 +207,9 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
else
continue;
if ((sopt = option_find1(option_ptr(opt), option_ptr(opt) + option_len(opt), search, 1)) &&
if ((sopt = option_find1(option_ptr(opt, 0), option_ptr(opt, option_len(opt)), search, 1)) &&
vendor->len == option_len(sopt) &&
memcmp(option_ptr(sopt), vendor->data, vendor->len) == 0)
memcmp(option_ptr(sopt, 0), vendor->data, vendor->len) == 0)
{
vendor->netid.next = netid;
netid = &vendor->netid;
@@ -220,7 +226,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
if ((opt = option_find(mess, sz, OPTION_CLIENT_ID, 1)))
{
clid_len = option_len(opt);
clid = option_ptr(opt);
clid = option_ptr(opt, 0);
}
/* do we have a lease in store? */
@@ -434,7 +440,10 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
lease_set_hwaddr(lease, mess->chaddr, NULL, mess->hlen, mess->htype, 0);
if (hostname)
lease_set_hostname(lease, hostname, daemon->domain_suffix, 1);
lease_set_expires(lease, 0xffffffff, now); /* infinite lease */
/* infinite lease unless nailed in dhcp-host line. */
lease_set_expires(lease,
have_config(config, CONFIG_TIME) ? config->lease_time : 0xffffffff,
now);
lease_set_interface(lease, int_index);
clear_packet(mess, end, NULL);
@@ -453,7 +462,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
/* 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);
unsigned char *pp, *op = option_ptr(opt, 0);
fqdn_flags = *op;
len -= 3;
@@ -494,7 +503,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
else if ((opt = option_find(mess, sz, OPTION_HOSTNAME, 1)))
{
int len = option_len(opt);
memcpy(daemon->dhcp_buff, option_ptr(opt), len);
memcpy(daemon->dhcp_buff, option_ptr(opt, 0), len);
/* Microsoft clients are broken, and need zero-terminated strings
in options. We detect this state here, and do the same in
any options we send */
@@ -562,7 +571,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
if ((opt = option_find(mess, sz, OPTION_USER_CLASS, 1)))
{
unsigned char *ucp = option_ptr(opt);
unsigned char *ucp = option_ptr(opt, 0);
int tmp, j;
for (j = 0; j < option_len(opt); j += ucp[j] + 1);
if (j == option_len(opt))
@@ -597,7 +606,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
{
int i;
for (i = 0; i <= (option_len(opt) - vendor->len); i++)
if (memcmp(vendor->data, option_ptr(opt)+i, vendor->len) == 0)
if (memcmp(vendor->data, option_ptr(opt, i), vendor->len) == 0)
{
vendor->netid.next = netid;
netid = &vendor->netid;
@@ -629,7 +638,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
if ((opt = option_find(mess, sz, OPTION_REQUESTED_OPTIONS, 0)))
{
req_options = (unsigned char *)daemon->dhcp_buff2;
memcpy(req_options, option_ptr(opt), option_len(opt));
memcpy(req_options, option_ptr(opt, 0), option_len(opt));
req_options[option_len(opt)] = OPTION_END;
}
@@ -637,16 +646,16 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
{
case DHCPDECLINE:
if (!(opt = option_find(mess, sz, OPTION_SERVER_IDENTIFIER, INADDRSZ)) ||
(context->local.s_addr != option_addr(opt).s_addr))
option_addr(opt).s_addr != server_id(context, override).s_addr)
return 0;
/* sanitise any message. Paranoid? Moi? */
sanitise(option_find(mess, sz, OPTION_MESSAGE, 1), daemon->dhcp_buff);
if (!(opt = option_find(mess, sz, OPTION_REQUESTED_IP, INADDRSZ)))
return 0;
log_packet("DECLINE", option_ptr(opt), emac, emac_len, iface_name, daemon->dhcp_buff);
log_packet("DECLINE", option_ptr(opt, 0), emac, emac_len, iface_name, daemon->dhcp_buff);
if (lease && lease->addr.s_addr == option_addr(opt).s_addr)
lease_prune(lease, now);
@@ -670,7 +679,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
case DHCPRELEASE:
if (!(context = narrow_context(context, mess->ciaddr, netid)) ||
!(opt = option_find(mess, sz, OPTION_SERVER_IDENTIFIER, INADDRSZ)) ||
(context->local.s_addr != option_addr(opt).s_addr))
option_addr(opt).s_addr != server_id(context, override).s_addr)
return 0;
if (lease && lease->addr.s_addr == mess->ciaddr.s_addr)
@@ -692,10 +701,11 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
{
struct in_addr addr, conf;
addr.s_addr = conf.s_addr = 0;
if ((opt = option_find(mess, sz, OPTION_REQUESTED_IP, INADDRSZ)))
addr = option_addr(opt);
conf.s_addr = 0;
if (have_config(config, CONFIG_ADDR))
{
char *addrs = inet_ntoa(config->addr);
@@ -737,7 +747,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
message = _("no address available");
}
log_packet("DISCOVER", opt ? option_ptr(opt) : NULL, emac, emac_len, iface_name, message);
log_packet("DISCOVER", opt ? option_ptr(opt, 0) : NULL, emac, emac_len, iface_name, message);
if (message || !(context = narrow_context(context, mess->yiaddr, netid)))
return 0;
@@ -753,7 +763,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
time = calc_time(context, config, option_find(mess, sz, OPTION_LEASE_TIME, 4));
clear_packet(mess, end, agent_id);
option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPOFFER);
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(context->local.s_addr));
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(server_id(context, override).s_addr));
option_put(mess, end, OPTION_LEASE_TIME, 4, time);
/* T1 and T2 are required in DHCPOFFER by HP's wacky Jetdirect client. */
if (time != 0xffffffff)
@@ -782,13 +792,21 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
/* SELECTING */
selecting = 1;
for (; context; context = context->current)
if (context->local.s_addr == option_addr(opt).s_addr)
break;
if (override.s_addr != 0)
{
if (option_addr(opt).s_addr != override.s_addr)
return 0;
}
else
{
for (; context; context = context->current)
if (context->local.s_addr == option_addr(opt).s_addr)
break;
if (!context)
return 0;
}
if (!context)
return 0;
/* If a lease exists for this host and another address, squash it. */
if (lease && lease->addr.s_addr != mess->yiaddr.s_addr)
{
@@ -893,7 +911,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
clear_packet(mess, end, agent_id);
option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPNAK);
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ,
ntohl(context ? context->local.s_addr : fallback.s_addr));
ntohl(server_id(context, override).s_addr ? server_id(context, override).s_addr : fallback.s_addr));
option_put_string(mess, end, OPTION_MESSAGE, message, borken_opt);
/* DHCPNAK gets agent-id too */
restore_agent_id(agent_id, mess, end);
@@ -915,7 +933,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
if ((opt = option_find(mess, sz, OPTION_USER_CLASS, 1)))
{
int len = option_len(opt);
unsigned char *ucp = option_ptr(opt);
unsigned char *ucp = option_ptr(opt, 0);
/* If the user-class option started as counted strings, the first byte will be zero. */
if (len != 0 && ucp[0] == 0)
ucp++, len--;
@@ -930,7 +948,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
if ((opt = option_find(mess, sz, OPTION_VENDOR_ID, 1)))
{
int len = option_len(opt);
unsigned char *ucp = option_ptr(opt);
unsigned char *ucp = option_ptr(opt, 0);
free(lease->vendorclass);
if ((lease->vendorclass = whine_malloc(len+1)))
{
@@ -970,12 +988,17 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
lease_set_expires(lease, time, now);
lease_set_interface(lease, int_index);
if (override.s_addr != 0)
lease->override = override;
else
override = lease->override;
log_packet("ACK", &mess->yiaddr, emac, emac_len, iface_name, hostname);
clear_packet(mess, end, agent_id);
option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(context->local.s_addr));
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(server_id(context, override).s_addr));
option_put(mess, end, OPTION_LEASE_TIME, 4, time);
if (time != 0xffffffff)
{
@@ -1018,9 +1041,14 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
netid = &context->netid;
}
if (lease && override.s_addr != 0)
lease->override = override;
else
override = lease->override;
clear_packet(mess, end, agent_id);
option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(context->local.s_addr));
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(server_id(context, override).s_addr));
if (lease)
{
@@ -1093,6 +1121,14 @@ static unsigned int calc_time(struct dhcp_context *context, struct dhcp_config *
return time;
}
static struct in_addr server_id(struct dhcp_context *context, struct in_addr override)
{
if (override.s_addr != 0)
return override;
else
return context->local;
}
static int sanitise(unsigned char *opt, char *buf)
{
char *p;
@@ -1103,7 +1139,7 @@ static int sanitise(unsigned char *opt, char *buf)
if (!opt)
return 0;
p = option_ptr(opt);
p = option_ptr(opt, 0);
for (i = option_len(opt); i > 0; i--)
{
@@ -1153,27 +1189,27 @@ static void log_options(unsigned char *start)
static unsigned char *option_find1(unsigned char *p, unsigned char *end, int opt, int minsize)
{
while (*p != OPTION_END)
while (1)
{
if (p >= end)
return NULL; /* malformed packet */
if (p > end)
return NULL;
else if (*p == OPTION_END)
return opt == OPTION_END ? p : NULL;
else if (*p == OPTION_PAD)
p++;
else
{
int opt_len;
if (p >= end - 2)
if (p > end - 2)
return NULL; /* malformed packet */
opt_len = option_len(p);
if (p >= end - (2 + opt_len))
if (p > end - (2 + opt_len))
return NULL; /* malformed packet */
if (*p == opt && opt_len >= minsize)
return p;
p += opt_len + 2;
}
}
return opt == OPTION_END ? p : NULL;
}
static unsigned char *option_find(struct dhcp_packet *mess, size_t size, int opt_type, int minsize)
@@ -1207,7 +1243,7 @@ static struct in_addr option_addr(unsigned char *opt)
/* struct in_addr is network byte order */
struct in_addr ret;
memcpy(&ret, option_ptr(opt), INADDRSZ);
memcpy(&ret, option_ptr(opt, 0), INADDRSZ);
return ret;
}
@@ -1217,7 +1253,7 @@ static unsigned int option_uint(unsigned char *opt, int size)
/* this worries about unaligned data and byte order */
unsigned int ret = 0;
int i;
unsigned char *p = option_ptr(opt);
unsigned char *p = option_ptr(opt, 0);
for (i = 0; i < size; i++)
ret = (ret << 8) | *p++;
@@ -1456,7 +1492,7 @@ static void match_vendor_opts(unsigned char *opt, struct dhcp_opt *dopt)
if (dopt->vendor_class)
len = strlen((char *)dopt->vendor_class);
for (i = 0; i <= (option_len(opt) - len); i++)
if (len == 0 || memcmp(dopt->vendor_class, option_ptr(opt)+i, len) == 0)
if (len == 0 || memcmp(dopt->vendor_class, option_ptr(opt, i), len) == 0)
{
dopt->flags |= DHOPT_VENDOR_MATCH;
break;

View File

@@ -16,82 +16,88 @@
/* Some code in this file contributed by Rob Funk. */
/* The SURF random number generator was taken from djbdns-1.05, by
Daniel J Berstein, which is public domain. */
#include "dnsmasq.h"
#ifdef HAVE_BROKEN_RTC
#include <sys/times.h>
#endif
/* Prefer arc4random(3) over random(3) over rand(3) */
/* Also prefer /dev/urandom over /dev/random, to preserve the entropy pool */
#ifdef HAVE_ARC4RANDOM
# define rand() arc4random()
# define srand(s) (void)0
# define RANDFILE (NULL)
#else
# ifdef HAVE_RANDOM
# define rand() random()
# define srand(s) srandom(s)
# endif
# ifdef HAVE_DEV_URANDOM
# define RANDFILE "/dev/urandom"
# else
# ifdef HAVE_DEV_RANDOM
# define RANDFILE "/dev/random"
# else
# define RANDFILE (NULL)
# endif
# endif
#endif
void rand_init(void)
{
return;
}
unsigned short rand16(void)
{
static int been_seeded = 0;
const char *randfile = RANDFILE;
if (! been_seeded)
{
int fd, n = 0;
unsigned int c = 0, seed = 0, badseed;
char sbuf[sizeof(seed)];
char *s;
struct timeval now;
/* get the bad seed as a backup */
/* (but we'd rather have something more random) */
gettimeofday(&now, NULL);
badseed = now.tv_sec ^ now.tv_usec ^ (getpid() << 16);
fd = open(randfile, O_RDONLY);
if (fd < 0)
seed = badseed;
else
{
s = (char *) &seed;
while ((c < sizeof(seed)) &&
((n = read(fd, sbuf, sizeof(seed)) > 0)))
{
memcpy(s, sbuf, n);
s += n;
c += n;
}
if (n < 0)
seed = badseed;
close(fd);
}
srand(seed);
been_seeded = 1;
}
/* Some rand() implementations have less randomness in low bits
* than in high bits, so we only pay attention to the high ones.
* But most implementations don't touch the high bit, so we
* ignore that one.
*/
return( (unsigned short) (rand() >> 15) );
return (unsigned short) (arc4random() >> 15);
}
#else
/* SURF random number generator */
typedef unsigned int uint32;
static uint32 seed[32];
static uint32 in[12];
static uint32 out[8];
void rand_init()
{
int fd = open(RANDFILE, O_RDONLY);
if (fd == -1 ||
!read_write(fd, (unsigned char *)&seed, sizeof(seed), 1) ||
!read_write(fd, (unsigned char *)&in, sizeof(in), 1))
die(_("failed to seed the random number generator: %s"), NULL, EC_MISC);
close(fd);
}
#define ROTATE(x,b) (((x) << (b)) | ((x) >> (32 - (b))))
#define MUSH(i,b) x = t[i] += (((x ^ seed[i]) + sum) ^ ROTATE(x,b));
static void surf(void)
{
uint32 t[12]; uint32 x; uint32 sum = 0;
int r; int i; int loop;
for (i = 0;i < 12;++i) t[i] = in[i] ^ seed[12 + i];
for (i = 0;i < 8;++i) out[i] = seed[24 + i];
x = t[11];
for (loop = 0;loop < 2;++loop) {
for (r = 0;r < 16;++r) {
sum += 0x9e3779b9;
MUSH(0,5) MUSH(1,7) MUSH(2,9) MUSH(3,13)
MUSH(4,5) MUSH(5,7) MUSH(6,9) MUSH(7,13)
MUSH(8,5) MUSH(9,7) MUSH(10,9) MUSH(11,13)
}
for (i = 0;i < 8;++i) out[i] ^= t[i + 4];
}
}
unsigned short rand16(void)
{
static int outleft = 0;
if (!outleft) {
if (!++in[0]) if (!++in[1]) if (!++in[2]) ++in[3];
surf();
outleft = 8;
}
return (unsigned short) out[--outleft];
}
#endif
int legal_char(char c)
{
/* check for legal char a-z A-Z 0-9 -
@@ -162,6 +168,14 @@ void *safe_malloc(size_t size)
return ret;
}
void safe_pipe(int *fd, int read_noblock)
{
if (pipe(fd) == -1 ||
!fix_fd(fd[1]) ||
(read_noblock && !fix_fd(fd[0])))
die(_("cannot create pipe: %s"), NULL, EC_MISC);
}
void *whine_malloc(size_t size)
{
void *ret = malloc(size);
@@ -429,3 +443,4 @@ int read_write(int fd, unsigned char *packet, int size, int rw)
}
return 1;
}