import of dnsmasq-2.1.tar.gz

This commit is contained in:
Simon Kelley
2004-01-29 16:48:35 +00:00
parent 9e4abcb5ac
commit 1ab84e2f35
18 changed files with 356 additions and 106 deletions

View File

@@ -639,7 +639,10 @@ void cache_add_dhcp_entry(char *host_name, struct in_addr *host_address, time_t
if ((crec = cache_find_by_name(NULL, host_name, 0, F_IPV4)))
{
if (crec->flags & F_HOSTS)
syslog(LOG_WARNING, "Ignoring DHCP lease for %s because it clashes with an /etc/hosts entry.", host_name);
{
if (crec->addr.addr.addr4.s_addr != host_address->s_addr)
syslog(LOG_WARNING, "Not naming DHCP lease for %s because it clashes with an /etc/hosts entry.", host_name);
}
else if (!(crec->flags & F_DHCP))
{
if (crec->flags & F_NEG)
@@ -650,7 +653,7 @@ void cache_add_dhcp_entry(char *host_name, struct in_addr *host_address, time_t
goto newrec;
}
else
syslog(LOG_WARNING, "Ignoring DHCP lease for %s because it clashes with a cached name.", cache_get_name(crec));
syslog(LOG_WARNING, "Not naming DHCP lease for %s because it clashes with a cached name.", cache_get_name(crec));
}
return;
}
@@ -671,7 +674,7 @@ void cache_add_dhcp_entry(char *host_name, struct in_addr *host_address, time_t
crec->flags |= F_IMMORTAL;
else
crec->ttd = ttd;
memcpy(&crec->addr, host_address, INADDRSZ);
crec->addr.addr.addr4 = *host_address;
crec->name.namep = host_name;
crec->prev = dhcp_inuse;
dhcp_inuse = crec;

View File

@@ -12,7 +12,7 @@
/* Author's email: simon@thekelleys.org.uk */
#define VERSION "2.0"
#define VERSION "2.1"
#define FTABSIZ 150 /* max number of outstanding requests */
#define TIMEOUT 40 /* drop queries after TIMEOUT seconds */

View File

@@ -269,5 +269,18 @@ struct dhcp_config *find_config(struct dhcp_config *configs,
return NULL;
}
void set_configs_from_cache(struct dhcp_config *configs)
/* Some people like to keep all static IP addresses in /etc/hosts.
This goes through /etc/hosts and sets static addresses for any DHCP config
records which don't have an address and whose name matches. */
{
struct dhcp_config *config;
struct crec *crec;
for (config = configs; config; config = config->next)
if (config->addr.s_addr == 0 && config->hostname &&
(crec = cache_find_by_name(NULL, config->hostname, 0, F_IPV4)) &&
(crec->flags & F_HOSTS))
config->addr = crec->addr.addr.addr4;
}

View File

@@ -158,6 +158,7 @@ int main (int argc, char **argv)
if (!dhcp_tmp->iface)
die("No suitable interface for DHCP service at address %s", inet_ntoa(dhcp_tmp->start));
set_configs_from_cache(dhcp_configs);
leasefd = lease_init(lease_file, domain_suffix, dnamebuff, packet, time(NULL), dhcp_configs);
lease_update_dns(1); /* must follow cache_init and lease_init */
}
@@ -270,6 +271,7 @@ int main (int argc, char **argv)
if (sighup)
{
cache_reload(options, dnamebuff, domain_suffix, addn_hosts);
set_configs_from_cache(dhcp_configs);
lease_update_dns(1);
if (resolv && (options & OPT_NO_POLL))
servers = last_server =

View File

@@ -16,6 +16,8 @@
#define _XOPEN_SOURCE 600
/* but then DNS headers don't compile without.... */
#define _BSD_SOURCE
/* and also, on FreeBSD 5.0 ..... */
#define __BSD_VISIBLE 1
/* get these before config.h for IPv6 stuff... */
#include <sys/types.h>
@@ -26,7 +28,6 @@
#include "config.h"
#include <netinet/in.h>
#include <arpa/nameser.h>
#include <arpa/inet.h>
#include <sys/stat.h>
@@ -229,8 +230,7 @@ struct dhcp_config {
};
struct dhcp_opt {
unsigned char opt;
unsigned char len;
int opt, len, is_addr;
unsigned char *val;
struct dhcp_opt *next;
};
@@ -360,6 +360,7 @@ struct dhcp_config *find_config(struct dhcp_config *configs,
unsigned char *clid, int clid_len,
unsigned char *hwaddr, char *hostname);
void set_configs_from_cache(struct dhcp_config *configs);
/* lease.c */
void lease_update_dns(int force_dns);
int lease_init(char *lease_file, char *domain, char *buff,

View File

@@ -132,6 +132,7 @@ struct server *forward_query(int udpfd, union mysockaddr *udpaddr, HEADER *heade
flags = 0; /* may be better match from previous literal */
domain = serv->domain;
matchlen = domainlen;
type = SERV_HAS_DOMAIN;
}
}
}

View File

@@ -76,12 +76,14 @@ static char *add_iface(struct irec **list, unsigned int flags,
specific addresses even if BIND is running and has bound *:53 */
opt = 1;
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
bind(fd, &addr->sa, sa_len(addr)))
bind(fd, &addr->sa, sa_len(addr)) == -1)
{
int errsave = errno;
close(fd);
errno = errsave;
return "failed to bind socket: %s";
/* IPv6 interfaces sometimes return ENODEV to bind() for unknown
(to me) reasons. Don't treat that as fatal. */
return errno == ENODEV ? NULL : "failed to bind socket: %s";
}
/* If OK, add it to the head of the list */
@@ -119,6 +121,7 @@ char *enumerate_interfaces(struct irec **interfacep,
struct irec *iface, *prev;
char *buf, *ptr, *err = NULL;
struct ifconf ifc;
struct ifreq *ifr = NULL;
int fd = socket(PF_INET, SOCK_DGRAM, 0);
int rawfd = -1;
@@ -158,12 +161,22 @@ char *enumerate_interfaces(struct irec **interfacep,
for (ptr = buf; ptr < buf + ifc.ifc_len; )
{
struct ifreq *ifr = (struct ifreq *) ptr;
union mysockaddr addr;
#ifdef HAVE_SOCKADDR_SA_LEN
ptr += ifr->ifr_addr.sa_len + IF_NAMESIZE;
/* subsequent entries may not be aligned, so copy into
an aligned buffer to avoid nasty complaints about
unaligned accesses. */
int ifr_len = ((struct ifreq *)ptr)->ifr_addr.sa_len + IF_NAMESIZE;
if (!(ifr = realloc(ifr, ifr_len)))
{
err = "cannot allocate buffer";
goto end;
}
memcpy(ifr, ptr, ifr_len);
ptr += ifr_len;
#else
ifr = (struct ifreq *)ptr;
ptr += sizeof(struct ifreq);
#endif
@@ -198,6 +211,54 @@ char *enumerate_interfaces(struct irec **interfacep,
&addr, names, addrs, except)))
goto end;
#if defined(HAVE_LINUX_IPV6_PROC) && defined(HAVE_IPV6)
/* IPv6 addresses don't seem to work with SIOCGIFCONF. Barf */
/* This code snarfed from net-tools 1.60 and certainly linux specific, though
it shouldn't break on other Unices, and their SIOGIFCONF might work. */
{
FILE *f = fopen(IP6INTERFACES, "r");
int found = 0;
if (f)
{
unsigned int plen, scope, flags, if_idx;
char devname[20], addrstring[32];
while (fscanf(f, "%32s %02x %02x %02x %02x %20s\n",
addrstring, &if_idx, &plen, &scope, &flags, devname) != EOF)
{
if (strcmp(devname, ifr->ifr_name) == 0)
{
int i;
unsigned char *addr6p = (unsigned char *) &addr.in6.sin6_addr;
memset(&addr, 0, sizeof(addr));
addr.sa.sa_family = AF_INET6;
for (i=0; i<16; i++)
{
unsigned int byte;
sscanf(addrstring+i+i, "%02x", &byte);
addr6p[i] = byte;
}
addr.in6.sin6_port = htons(port);
addr.in6.sin6_flowinfo = htonl(0);
addr.in6.sin6_scope_id = htonl(scope);
found = 1;
break;
}
}
fclose(f);
}
if (found &&
(err = add_iface(interfacep, ifr->ifr_flags, ifr->ifr_name,
&addr, names, addrs, except)))
goto end;
}
#endif /* LINUX */
/* dhcp is non-null only on the first call: set up the relevant
interface-related DHCP stuff here. DHCP is IPv4 only.
Because errors here are ultimately fatal we can return directly and not bother
@@ -289,32 +350,48 @@ char *enumerate_interfaces(struct irec **interfacep,
}
}
}
}
#ifdef HAVE_BPF
/* now go through the interfaces again, looking for AF_LINK records
to get hardware addresses from */
for (ptr = buf; ptr < buf + ifc.ifc_len; )
{
struct ifreq *ifr = (struct ifreq *) ptr;
struct dhcp_context *context;
#ifdef HAVE_SOCKADDR_SA_LEN
ptr += ifr->ifr_addr.sa_len + IF_NAMESIZE;
/* subsequent entries may not be aligned, so copy into
an aligned buffer to avoid nasty complaints about
unaligned accesses. */
int ifr_len = ((struct ifreq *)ptr)->ifr_addr.sa_len + IF_NAMESIZE;
if (!(ifr = realloc(ifr, ifr_len)))
{
err = "cannot allocate buffer";
goto end;
}
memcpy(ifr, ptr, ifr_len);
ptr += ifr_len;
#else
ifr = (struct ifreq *)ptr;
ptr += sizeof(struct ifreq);
#endif
if (ifr->ifr_addr.sa_family == AF_LINK)
for (context = dhcp; context; context = context->next)
if (context->iface && strcmp(context->iface, ifr->ifr_name) == 0)
memcpy(context->hwaddr, LLADDR((struct sockaddr_dl *)&ifr->ifr_addr), ETHER_ADDR_LEN);
}
#endif
end:
errsave = errno; /* since errno gets overwritten by close */
if (buf)
free(buf);
#ifdef HAVE_SOCKADDR_SA_LEN
if (ifr)
free(ifr);
#endif
close(fd);
if (err)
{
@@ -322,54 +399,6 @@ char *enumerate_interfaces(struct irec **interfacep,
return err;
}
#if defined(HAVE_LINUX_IPV6_PROC) && defined(HAVE_IPV6)
/* IPv6 addresses don't seem to work with SIOCGIFCONF. Barf */
/* This code snarfed from net-tools 1.60 and certainly linux specific, though
it shouldn't break on other Unices, and their SIOGIFCONF might work. */
{
FILE *f = fopen(IP6INTERFACES, "r");
if (f)
{
union mysockaddr addr;
unsigned int plen, scope, flags, if_idx;
char devname[20], addrstring[32];
while (fscanf(f, "%32s %02x %02x %02x %02x %20s\n",
addrstring, &if_idx, &plen, &scope, &flags, devname) != EOF)
{
int i;
unsigned char *addr6p = (unsigned char *) &addr.in6.sin6_addr;
memset(&addr, 0, sizeof(addr));
addr.sa.sa_family = AF_INET6;
for (i=0; i<16; i++)
{
unsigned int byte;
sscanf(addrstring+i+i, "%02x", &byte);
addr6p[i] = byte;
}
#ifdef HAVE_SOCKADDR_SA_LEN
/* For completeness - should never be defined on Linux. */
addr.in6.sin6_len = sizeof(struct sockaddr_in6);
#endif
addr.in6.sin6_port = htons(port);
addr.in6.sin6_flowinfo = htonl(0);
addr.in6.sin6_scope_id = htonl(scope);
if ((err = add_iface(interfacep, flags, devname, &addr, names, addrs, except)))
{
errsave = errno;
fclose(f);
errno = errsave;
return err;
}
}
fclose(f);
}
}
#endif /* LINUX */
/* now remove interfaces which were not found on this scan */
for(prev = NULL, iface = *interfacep; iface; )
{

View File

@@ -175,14 +175,18 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
else
{
char *p;
/* dump comments */
for (p = buff; *p; p++)
if (*p == '#')
*p = 0;
/* fgets gets end of line char too. */
while (strlen(buff) > 0 &&
(buff[strlen(buff)-1] == '\n' ||
buff[strlen(buff)-1] == ' ' ||
buff[strlen(buff)-1] == '\t'))
buff[strlen(buff)-1] = 0;
if (*buff == '#' || *buff == 0)
continue; /* comment */
if (*buff == 0)
continue;
if ((p=strchr(buff, '=')))
{
optarg = p+1;
@@ -639,7 +643,7 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
new->clid = NULL;
new->hostname = NULL;
new->addr.s_addr = 0;
new->lease_time = DEFLEASE;
new->lease_time = 0;
a[0] = optarg;
for (k = 1; k < 4; k++)
@@ -706,8 +710,8 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
{
case 'h':
case 'H':
fac *= 60;
/* fall through */
fac *= 60;
/* fall through */
case 'm':
case 'M':
fac *= 60;
@@ -717,7 +721,7 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
}
for (cp = a[j]; *cp; cp++)
if (!isdigit(*cp))
if (!isdigit(*cp) && *cp != ' ')
break;
if (*cp)
@@ -739,24 +743,33 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
{
struct dhcp_opt *new = safe_malloc(sizeof(struct dhcp_opt));
char *cp, *comma = strchr(optarg, ',');
int addrs;
int addrs, is_addr;
new->next = *dhcp_opts;
new->len = 0;
new->is_addr = 0;
*dhcp_opts = new;
if (!comma || (*comma = 0) || (new->opt = atoi(optarg)) == 0)
if ((new->opt = atoi(optarg)) == 0)
{
option = '?';
break;
}
if (!comma)
break;
*comma = 0;
/* check for non-address list characters */
for (addrs = 1, cp = comma+1; *cp; cp++)
for (addrs = 1, is_addr = 0, cp = comma+1; *cp; cp++)
if (*cp == ',')
addrs++;
else if (!(*cp == '.' || *cp == ' ' || (*cp >='0' && *cp <= '9')))
break;
else if (*cp == '.')
is_addr = 1;
if (*cp)
{
/* text arg */
@@ -768,17 +781,28 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
{
struct in_addr in;
unsigned char *op;
new->len = INADDRSZ * addrs;
new->val = op = safe_malloc(new->len);
while (addrs--)
if (addrs == 1 && !is_addr)
{
cp = comma;
if (cp && (comma = strchr(cp+1, ',')))
*comma = 0;
if (cp && (in.s_addr = inet_addr(cp+1)) == (in_addr_t)-1)
option = '?';
memcpy(op, &in, INADDRSZ);
op += INADDRSZ;
new->len = 1;
new->val = safe_malloc(1);
*(new->val) = atoi(comma+1);
}
else
{
new->len = INADDRSZ * addrs;
new->val = op = safe_malloc(new->len);
new->is_addr = 1;
while (addrs--)
{
cp = comma;
if (cp && (comma = strchr(cp+1, ',')))
*comma = 0;
if (cp && (in.s_addr = inet_addr(cp+1)) == (in_addr_t)-1)
option = '?';
memcpy(op, &in, INADDRSZ);
op += INADDRSZ;
}
}
}
break;

View File

@@ -139,7 +139,7 @@ int dhcp_reply(struct dhcp_context *context, struct dhcp_packet *mess,
/* search again now we have a hostname */
config = find_config(dhcp_configs, context, clid, clid_len, mess->chaddr, hostname);
def_time = config ? config->lease_time : context->lease_time;
def_time = config && config->lease_time ? config->lease_time : context->lease_time;
if ((opt = option_find(mess, sz, OPTION_LEASE_TIME)))
{
@@ -444,6 +444,9 @@ static unsigned char *do_req_options(struct dhcp_context *context,
if (!req_options)
return p;
if (in_list(req_options, OPTION_MAXMESSAGE))
p = option_put(p, end, OPTION_MAXMESSAGE, 2, sizeof(struct udp_dhcp_packet));
if (in_list(req_options, OPTION_NETMASK) &&
!option_find2(config_opts, OPTION_NETMASK))
p = option_put(p, end, OPTION_NETMASK, INADDRSZ, ntohl(context->netmask.s_addr));
@@ -484,12 +487,34 @@ static unsigned char *do_req_options(struct dhcp_context *context,
for (i = 0; req_options[i] != OPTION_END; i++)
{
struct dhcp_opt *opt = option_find2(config_opts, req_options[i]);
if (req_options[i] != OPTION_HOSTNAME && opt && (p + opt->len + 2 < end))
if (req_options[i] != OPTION_HOSTNAME &&
req_options[i] != OPTION_MAXMESSAGE &&
opt && (p + opt->len + 2 < end))
{
*(p++) = opt->opt;
*(p++) = opt->len;
memcpy(p, opt->val, opt->len);
p += opt->len;
if (opt->len != 0)
{
if (opt->is_addr)
{
int j;
struct in_addr *a = (struct in_addr *)opt->val;
for (j = 0; j < opt->len; j+=INADDRSZ, a++)
{
/* zero means "self" */
if (a->s_addr == 0)
memcpy(p, &context->serv_addr, INADDRSZ);
else
memcpy(p, a, INADDRSZ);
p += INADDRSZ;
}
}
else
{
memcpy(p, opt->val, opt->len);
p += opt->len;
}
}
}
}