mirror of
https://github.com/pi-hole/dnsmasq.git
synced 2025-12-19 10:18:25 +00:00
import of dnsmasq-2.43.tar.gz
This commit is contained in:
54
src/cache.c
54
src/cache.c
@@ -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
|
||||
|
||||
58
src/config.h
58
src/config.h
@@ -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
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
323
src/dnsmasq.c
323
src/dnsmasq.c
@@ -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);
|
||||
|
||||
118
src/dnsmasq.h
118
src/dnsmasq.h
@@ -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);
|
||||
|
||||
297
src/forward.c
297
src/forward.c
@@ -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
|
||||
|
||||
58
src/helper.c
58
src/helper.c
@@ -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);
|
||||
|
||||
|
||||
18
src/log.c
18
src/log.c
@@ -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)
|
||||
|
||||
@@ -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"),
|
||||
|
||||
362
src/option.c
362
src/option.c
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
124
src/rfc2131.c
124
src/rfc2131.c
@@ -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;
|
||||
|
||||
143
src/util.c
143
src/util.c
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user