import of dnsmasq-2.33.tar.gz

This commit is contained in:
Simon Kelley
2006-08-05 21:41:37 +01:00
parent 849a8357ba
commit 208b65c5cf
32 changed files with 2364 additions and 1534 deletions

View File

@@ -10,9 +10,9 @@
GNU General Public License for more details.
*/
#define VERSION "2.32"
#define VERSION "2.33"
#define FTABSIZ 150 /* max number of outstanding requests */
#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 */

View File

@@ -227,15 +227,19 @@ void dhcp_packet(struct daemon *daemon, time_t now)
if (mess->giaddr.s_addr)
{
/* Send to BOOTP relay */
if (!dest.sin_port)
dest.sin_port = htons(DHCP_SERVER_PORT);
dest.sin_port = htons(DHCP_SERVER_PORT);
dest.sin_addr = mess->giaddr;
}
else if (mess->ciaddr.s_addr)
{
dest.sin_addr = mess->ciaddr;
if (!dest.sin_port)
dest.sin_port = htons(DHCP_CLIENT_PORT);
/* If the client's idea of its own address tallys with
the source address in the request packet, we believe the
source port too, and send back to that. */
if (dest.sin_addr.s_addr != mess->ciaddr.s_addr || !dest.sin_port)
{
dest.sin_port = htons(DHCP_CLIENT_PORT);
dest.sin_addr = mess->ciaddr;
}
}
#ifdef HAVE_LINUX_NETWORK
else if ((ntohs(mess->flags) & 0x8000) || mess->hlen == 0 ||

View File

@@ -286,7 +286,7 @@ int main (int argc, char **argv)
#endif
if (daemon->dhcp &&
(i == fileno(daemon->lease_stream) ||
((daemon->lease_stream && i == fileno(daemon->lease_stream)) ||
#ifndef HAVE_LINUX_NETWORK
i == daemon->dhcp_raw_fd ||
i == daemon->dhcp_icmp_fd ||
@@ -362,6 +362,13 @@ int main (int argc, char **argv)
if (if_tmp->name && !if_tmp->used)
syslog(LOG_WARNING, _("warning: interface %s does not currently exist"), if_tmp->name);
if (daemon->options & OPT_NO_RESOLV)
{
if (daemon->resolv_files && !daemon->resolv_files->is_default)
syslog(LOG_WARNING, _("warning: ignoring resolv-file flag because no-resolv is set"));
daemon->resolv_files = NULL;
}
if (daemon->dhcp)
{
struct dhcp_context *dhcp_tmp;
@@ -460,47 +467,50 @@ int main (int argc, char **argv)
if (!(daemon->options & OPT_NO_POLL))
{
struct resolvc *res = daemon->resolv_files, *latest = NULL;
struct resolvc *res, *latest;
struct stat statbuf;
time_t last_change = 0;
/* There may be more than one possible file.
Go through and find the one which changed _last_.
Warn of any which can't be read. */
while (res)
{
if (stat(res->name, &statbuf) == -1)
{
if (!res->logged)
syslog(LOG_WARNING, _("failed to access %s: %m"), res->name);
res->logged = 1;
}
else
{
res->logged = 0;
if (statbuf.st_mtime != res->mtime &&
difftime(statbuf.st_mtime, last_change) > 0.0)
{
last_change = statbuf.st_mtime;
latest = res;
}
}
res = res->next;
}
for (latest = NULL, res = daemon->resolv_files; res; res = res->next)
if (stat(res->name, &statbuf) == -1)
{
if (!res->logged)
syslog(LOG_WARNING, _("failed to access %s: %m"), res->name);
res->logged = 1;
}
else
{
res->logged = 0;
if (statbuf.st_mtime != res->mtime)
{
res->mtime = statbuf.st_mtime;
if (difftime(statbuf.st_mtime, last_change) > 0.0)
{
last_change = statbuf.st_mtime;
latest = res;
}
}
}
if (latest)
{
static int warned = 0;
if (reload_servers(latest->name, daemon))
{
syslog(LOG_INFO, _("reading %s"), latest->name);
latest->mtime = last_change;
warned = 0;
check_servers(daemon);
}
else if (!warned)
else
{
syslog(LOG_WARNING, _("no servers found in %s, will retry"), latest->name);
warned = 1;
latest->mtime = 0;
if (!warned)
{
syslog(LOG_WARNING, _("no servers found in %s, will retry"), latest->name);
warned = 1;
}
}
}
}
@@ -544,7 +554,7 @@ int main (int argc, char **argv)
if (daemon->tcp_pids[i] != 0)
kill(daemon->tcp_pids[i], SIGALRM);
if (daemon->dhcp)
if (daemon->lease_stream)
fclose(daemon->lease_stream);
exit(0);

View File

@@ -110,6 +110,7 @@ extern int capset(cap_user_header_t header, cap_user_data_t data);
#define OPT_DBUS 524288
#define OPT_BOOTP_DYNAMIC 1048576
#define OPT_NO_PING 2097152
#define OPT_LEASE_RO 4194304
struct all_addr {
union {
@@ -290,7 +291,8 @@ struct dhcp_lease {
char *hostname, *fqdn; /* name from client-hostname option or config */
char auth_name; /* hostname came from config, not from client */
char new; /* newly created */
char old; /* read from leasefile */
char changed; /* modified */
char aux_changed; /* CLID or expiry changed */
time_t expires; /* lease expiry */
#ifdef HAVE_BROKEN_RTC
unsigned int length;
@@ -422,7 +424,7 @@ struct daemon {
struct bogus_addr *bogus_addr;
struct server *servers;
int log_fac; /* log facility */
int cachesize;
int cachesize, ftabsize;
int port, query_port;
unsigned long local_ttl;
struct hostsfile *addn_hosts;

View File

@@ -14,7 +14,7 @@
static struct frec *frec_list = NULL;
static struct frec *get_new_frec(time_t now);
static struct frec *get_new_frec(struct daemon *daemon, time_t now);
static struct frec *lookup_frec(unsigned short id);
static struct frec *lookup_frec_by_sender(unsigned short id,
union mysockaddr *addr,
@@ -232,7 +232,7 @@ static void forward_query(struct daemon *daemon, int udpfd, union mysockaddr *ud
if (gotname)
flags = search_servers(daemon, now, &addrp, gotname, daemon->namebuff, &type, &domain);
if (!flags && !(forward = get_new_frec(now)))
if (!flags && !(forward = get_new_frec(daemon, now)))
/* table full - server failure. */
flags = F_NEG;
@@ -837,7 +837,7 @@ unsigned char *tcp_request(struct daemon *daemon, int confd, time_t now,
}
}
static struct frec *get_new_frec(time_t now)
static struct frec *get_new_frec(struct daemon *daemon, time_t now)
{
struct frec *f = frec_list, *oldest = NULL;
time_t oldtime = now;
@@ -870,7 +870,7 @@ static struct frec *get_new_frec(time_t now)
return oldest;
}
if (count > FTABSIZ)
if (count > daemon->ftabsize)
{ /* limit logging rate so syslog isn't DOSed either */
if (!warntime || difftime(now, warntime) > LOGRATE)
{

View File

@@ -21,60 +21,103 @@ void lease_init(struct daemon *daemon, time_t now)
struct in_addr addr;
struct dhcp_lease *lease;
int flags, clid_len, hw_len, hw_type;
FILE *leasestream;
leases = old_leases = NULL;
leases_left = daemon->dhcp_max;
/* NOTE: need a+ mode to create file if it doesn't exist */
if (!(daemon->lease_stream = fopen(daemon->lease_file, "a+")))
die(_("cannot open or create leases file: %s"), NULL);
flags = fcntl(fileno(daemon->lease_stream), F_GETFD);
if (flags != -1)
fcntl(fileno(daemon->lease_stream), F_SETFD, flags | FD_CLOEXEC);
if (daemon->options & OPT_LEASE_RO)
{
/* run "<lease_change_script> init" once to get the
initial state of the database. If leasefile-ro is
set without a script, we just do without any
lease database. */
if (!daemon->lease_change_command)
{
file_dirty = dns_dirty = 0;
return;
}
strcpy(daemon->dhcp_buff, daemon->lease_change_command);
strcat(daemon->dhcp_buff, " init");
leasestream = popen(daemon->dhcp_buff, "r");
}
else
{
/* NOTE: need a+ mode to create file if it doesn't exist */
leasestream = daemon->lease_stream = fopen(daemon->lease_file, "a+");
if (!leasestream)
die(_("cannot open or create lease file %s: %s"), daemon->lease_file);
flags = fcntl(fileno(leasestream), F_GETFD);
if (flags != -1)
fcntl(fileno(leasestream), F_SETFD, flags | FD_CLOEXEC);
/* a+ mode lease pointer at end. */
rewind(leasestream);
}
/* a+ mode lease pointer at end. */
rewind(daemon->lease_stream);
/* client-id max length is 255 which is 255*2 digits + 254 colons
borrow DNS packet buffer which is always larger than 1000 bytes */
while (fscanf(daemon->lease_stream, "%lu %255s %16s %255s %764s",
&ei, daemon->dhcp_buff2, daemon->namebuff,
daemon->dhcp_buff, daemon->packet) == 5)
{
hw_len = parse_hex(daemon->dhcp_buff2, (unsigned char *)daemon->dhcp_buff2, DHCP_CHADDR_MAX, NULL, &hw_type);
/* For backwards compatibility, no explict MAC address type means ether. */
if (hw_type == 0 && hw_len != 0)
hw_type = ARPHRD_ETHER;
addr.s_addr = inet_addr(daemon->namebuff);
/* decode hex in place */
clid_len = 0;
if (strcmp(daemon->packet, "*") != 0)
clid_len = parse_hex(daemon->packet, (unsigned char *)daemon->packet, 255, NULL, NULL);
if (!(lease = lease_allocate(addr)))
die (_("too many stored leases"), NULL);
/* not actually new */
lease->new = 0;
if (leasestream)
while (fscanf(leasestream, "%lu %255s %16s %255s %764s",
&ei, daemon->dhcp_buff2, daemon->namebuff,
daemon->dhcp_buff, daemon->packet) == 5)
{
hw_len = parse_hex(daemon->dhcp_buff2, (unsigned char *)daemon->dhcp_buff2, DHCP_CHADDR_MAX, NULL, &hw_type);
/* For backwards compatibility, no explict MAC address type means ether. */
if (hw_type == 0 && hw_len != 0)
hw_type = ARPHRD_ETHER;
addr.s_addr = inet_addr(daemon->namebuff);
/* decode hex in place */
clid_len = 0;
if (strcmp(daemon->packet, "*") != 0)
clid_len = parse_hex(daemon->packet, (unsigned char *)daemon->packet, 255, NULL, NULL);
if (!(lease = lease_allocate(addr)))
die (_("too many stored leases"), NULL);
/* not actually new */
lease->new = 0;
#ifdef HAVE_BROKEN_RTC
if (ei != 0)
lease->expires = (time_t)ei + now;
else
lease->expires = (time_t)0;
lease->length = ei;
if (ei != 0)
lease->expires = (time_t)ei + now;
else
lease->expires = (time_t)0;
lease->length = ei;
#else
/* strictly time_t is opaque, but this hack should work on all sane systems,
even when sizeof(time_t) == 8 */
lease->expires = (time_t)ei;
/* strictly time_t is opaque, but this hack should work on all sane systems,
even when sizeof(time_t) == 8 */
lease->expires = (time_t)ei;
#endif
lease_set_hwaddr(lease, (unsigned char *)daemon->dhcp_buff2, (unsigned char *)daemon->packet, hw_len, hw_type, clid_len);
if (strcmp(daemon->dhcp_buff, "*") != 0)
lease_set_hostname(lease, daemon->dhcp_buff, daemon->domain_suffix, 0);
}
if (!daemon->lease_stream)
{
int rc = 0;
lease_set_hwaddr(lease, (unsigned char *)daemon->dhcp_buff2, (unsigned char *)daemon->packet, hw_len, hw_type, clid_len);
if (strcmp(daemon->dhcp_buff, "*") != 0)
lease_set_hostname(lease, daemon->dhcp_buff, daemon->domain_suffix, 0);
/* shell returns 127 for "command not found", 126 for bad permissions. */
if (!leasestream || (rc = pclose(leasestream)) == -1 || WEXITSTATUS(rc) == 127 || WEXITSTATUS(rc) == 126)
{
if (WEXITSTATUS(rc) == 127)
errno = ENOENT;
else if (WEXITSTATUS(rc) == 126)
errno = EACCES;
die(_("cannot run lease-init script %s: %s"), daemon->lease_change_command);
}
if (WEXITSTATUS(rc) != 0)
{
sprintf(daemon->dhcp_buff, "%d", WEXITSTATUS(rc));
die(_("lease-init script returned exit code %s"), daemon->dhcp_buff);
}
}
/* Some leases may have expired */
@@ -117,7 +160,7 @@ void lease_update_file(struct daemon *daemon, time_t now)
time_t next_event;
int i, err = 0;
if (file_dirty != 0)
if (file_dirty != 0 && daemon->lease_stream)
{
errno = 0;
rewind(daemon->lease_stream);
@@ -298,7 +341,7 @@ void lease_set_expires(struct dhcp_lease *lease, unsigned int len, time_t now)
dns_dirty = 1;
lease->expires = exp;
#ifndef HAVE_BROKEN_RTC
file_dirty = 1;
lease->aux_changed = file_dirty = 1;
#endif
}
@@ -306,7 +349,7 @@ void lease_set_expires(struct dhcp_lease *lease, unsigned int len, time_t now)
if (len != lease->length)
{
lease->length = len;
file_dirty = 1;
lease->aux_changed = file_dirty = 1;
}
#endif
}
@@ -318,11 +361,10 @@ void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
hw_type != lease->hwaddr_type ||
(hw_len != 0 && memcmp(lease->hwaddr, hwaddr, hw_len) != 0))
{
file_dirty = 1;
memcpy(lease->hwaddr, hwaddr, hw_len);
lease->hwaddr_len = hw_len;
lease->hwaddr_type = hw_type;
lease->old = 1; /* run script on change */
lease->changed = file_dirty = 1; /* run script on change */
}
/* only update clid when one is available, stops packets
@@ -335,18 +377,19 @@ void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
if (lease->clid_len != clid_len)
{
file_dirty = 1;
lease->aux_changed = file_dirty = 1;
if (lease->clid)
free(lease->clid);
if (!(lease->clid = malloc(clid_len)))
return;
}
else if (memcmp(lease->clid, clid, clid_len) != 0)
file_dirty = 1;
lease->aux_changed = file_dirty = 1;
lease->clid_len = clid_len;
memcpy(lease->clid, clid, clid_len);
}
}
void lease_set_hostname(struct dhcp_lease *lease, char *name, char *suffix, int auth)
@@ -375,7 +418,7 @@ void lease_set_hostname(struct dhcp_lease *lease, char *name, char *suffix, int
{
if (lease_tmp->auth_name && !auth)
return;
lease_tmp->old = 1; /* call script on change */
lease_tmp->changed = 1; /* call script on change */
new_name = lease_tmp->hostname;
lease_tmp->hostname = NULL;
if (lease_tmp->fqdn)
@@ -408,7 +451,7 @@ void lease_set_hostname(struct dhcp_lease *lease, char *name, char *suffix, int
file_dirty = 1;
dns_dirty = 1;
lease->old = 1; /* run script on change */
lease->changed = 1; /* run script on change */
}
@@ -417,19 +460,63 @@ static pid_t run_script(struct daemon *daemon, char *action, struct dhcp_lease *
{
if (daemon->lease_change_command)
{
char *mac = print_mac(daemon, lease->hwaddr, lease->hwaddr_len);
char *addr = inet_ntoa(lease->addr);
char *com = strrchr(daemon->lease_change_command, '/');
pid_t pid = fork();
char *p;
pid_t pid;
int i;
/* stringify MAC into dhcp_buff */
p = daemon->dhcp_buff;
if (lease->hwaddr_type != ARPHRD_ETHER || lease->hwaddr_len == 0)
p += sprintf(p, "%.2x-", lease->hwaddr_type);
for (i = 0; i < lease->hwaddr_len; i++)
{
p += sprintf(p, "%.2x", lease->hwaddr[i]);
if (i != lease->hwaddr_len - 1)
p += sprintf(p, ":");
}
/* and CLID into namebuff */
p = daemon->namebuff;
if (lease->clid)
for (i = 0; i < lease->clid_len; i++)
{
p += sprintf(p, "%.2x", lease->clid[i]);
if (i != lease->clid_len - 1)
p += sprintf(p, ":");
}
/* and expiry or length into dhcp_buff2 */
#ifdef HAVE_BROKEN_RTC
sprintf(daemon->dhcp_buff2, "%u ", lease->length);
#else
sprintf(daemon->dhcp_buff2, "%lu ", (unsigned long)lease->expires);
#endif
pid = fork();
if (pid == -1)
return 0; /* fork error */
else if (pid != 0)
return pid;
if (lease->clid && lease->clid_len != 0)
setenv("DNSMASQ_CLIENT_ID", daemon->namebuff, 1);
else
unsetenv("DNSMASQ_CLIENT_ID");
#ifdef HAVE_BROKEN_RTC
setenv("DNSMASQ_LEASE_LENGTH", daemon->dhcp_buff2, 1);
unsetenv("DNSMASQ_LEASE_EXPIRES");
#else
setenv("DNSMASQ_LEASE_EXPIRES", daemon->dhcp_buff2, 1);
unsetenv("DNSMASQ_LEASE_LENGTH");
#endif
execl(daemon->lease_change_command,
com ? com+1 : daemon->lease_change_command,
action, mac, addr, lease->hostname, (char*)NULL);
action, daemon->dhcp_buff, addr, lease->hostname, (char*)NULL);
/* log socket should still be open, right? */
syslog(LOG_ERR, _("failed to execute %s: %m"),
@@ -470,7 +557,8 @@ void lease_collect(struct daemon *daemon)
}
for (lease = leases; lease; lease = lease->next)
if (lease->new || lease->old)
if (lease->new || lease->changed ||
(lease->aux_changed && (daemon->options & OPT_LEASE_RO)))
{
if (daemon->script_pid != 0)
return; /* busy */
@@ -479,7 +567,7 @@ void lease_collect(struct daemon *daemon)
daemon->script_pid = run_script(daemon, lease->new ? "add" : "old", lease);
#endif
lease->new = lease->old = 0;
lease->new = lease->changed = lease->aux_changed = 0;
}
}

View File

@@ -24,7 +24,7 @@ struct myoption {
};
#endif
#define OPTSTRING "531yZDNLERKzowefnbvhdkqr:m:p:c:l:s:i:t:u:g:a:x:S:C:A:T:H:Q:I:B:F:G:O:M:X:V:U:j:P:J:W:Y:2:4:6:7:8:"
#define OPTSTRING "9531yZDNLERKzowefnbvhdkqr:m:p:c:l:s:i:t:u:g:a:x:S:C:A:T:H:Q:I:B:F:G:O:M:X:V:U:j:P:J:W:Y:2:4:6:7:8:0:"
#ifdef HAVE_GETOPT_LONG
static const struct option opts[] =
@@ -95,6 +95,8 @@ static const struct myoption opts[] =
{"dhcp-script", 1, 0, '6'},
{"conf-dir", 1, 0, '7'},
{"log-facility", 1, 0 ,'8'},
{"leasefile-ro", 0, 0, '9'},
{"dns-forward-max", 1, 0, '0'},
{ NULL, 0, 0, 0 }
};
@@ -125,6 +127,7 @@ static const struct optflags optmap[] = {
{ '1', OPT_DBUS },
{ '3', OPT_BOOTP_DYNAMIC },
{ '5', OPT_NO_PING },
{ '9', OPT_LEASE_RO },
{ 'v', 0},
{ 'w', 0},
{ 0, 0 }
@@ -195,7 +198,9 @@ static const struct {
{ "-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", gettext_noop("Log to this syslog facility."), NULL },
{ "-8, --log-facility=facilty", gettext_noop("Log to this syslog facility. (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)"), "!" },
{ NULL, NULL, NULL }
};
@@ -324,6 +329,8 @@ static void do_usage(void)
sprintf(buff, "%d", EDNS_PKTSZ);
else if (strcmp(usage[i].arg, "&") == 0)
sprintf(buff, "%d", MAXLEASES);
else if (strcmp(usage[i].arg, "!") == 0)
sprintf(buff, "%d", FTABSIZ);
else
strcpy(buff, usage[i].arg);
}
@@ -810,7 +817,12 @@ static char *one_opt(struct daemon *daemon, int option, char *arg, char *problem
if (!atoi_check(arg, &daemon->port))
option = '?';
break;
case '0':
if (!atoi_check(arg, &daemon->ftabsize))
option = '?';
break;
case 'P':
{
int i;
@@ -1818,6 +1830,7 @@ struct daemon *read_opts(int argc, char **argv, char *compile_opts)
/* Set defaults - everything else is zero or NULL */
daemon->cachesize = CACHESIZ;
daemon->ftabsize = FTABSIZ;
daemon->port = NAMESERVER_PORT;
daemon->default_resolv.is_default = 1;
daemon->default_resolv.name = RESOLVFILE;
@@ -1956,11 +1969,10 @@ struct daemon *read_opts(int argc, char **argv, char *compile_opts)
mx->target = daemon->mxtarget;
}
if (daemon->options & OPT_NO_RESOLV)
daemon->resolv_files = 0;
else if (daemon->resolv_files &&
(daemon->resolv_files)->next &&
(daemon->options & OPT_NO_POLL))
if (!(daemon->options & OPT_NO_RESOLV) &&
daemon->resolv_files &&
daemon->resolv_files->next &&
(daemon->options & OPT_NO_POLL))
die(_("only one resolv.conf file allowed in no-poll mode."), NULL);
if (daemon->options & OPT_RESOLV_DOMAIN)
@@ -1968,11 +1980,13 @@ struct daemon *read_opts(int argc, char **argv, char *compile_opts)
char *line;
FILE *f;
if (!daemon->resolv_files || (daemon->resolv_files)->next)
if ((daemon->options & OPT_NO_RESOLV) ||
!daemon->resolv_files ||
(daemon->resolv_files)->next)
die(_("must have exactly one resolv.conf to read domain from."), NULL);
if (!(f = fopen((daemon->resolv_files)->name, "r")))
die(_("failed to read %s: %m"), (daemon->resolv_files)->name);
die(_("failed to read %s: %s"), (daemon->resolv_files)->name);
while ((line = fgets(buff, MAXDNAME, f)))
{