import of dnsmasq-2.6.tar.gz
diff --git a/src/Makefile b/src/Makefile
index c2cb07f..77229d7 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -3,8 +3,8 @@
CFLAGS?= -O2
-OBJS = cache.o rfc1035.o util.o option.o forward.o \
- network.o dnsmasq.o dhcp.o lease.o rfc2131.o
+OBJS = cache.o rfc1035.o util.o option.o forward.o isc.o \
+ network.o dnsmasq.o dhcp.o lease.o rfc2131.o
.c.o: dnsmasq.h config.h
$(CC) $(CFLAGS) $(RPM_OPT_FLAGS) -Wall -W -c $*.c
diff --git a/src/config.h b/src/config.h
index ea503f9..ad9e08d 100644
--- a/src/config.h
+++ b/src/config.h
@@ -12,12 +12,13 @@
/* Author's email: simon@thekelleys.org.uk */
-#define VERSION "2.5"
+#define VERSION "2.6"
#define FTABSIZ 150 /* max number of outstanding requests */
#define TIMEOUT 20 /* drop queries after TIMEOUT seconds */
#define LOGRATE 120 /* log table overflows every LOGRATE seconds */
#define CACHESIZ 150 /* default cache size */
+#define MAXTOK 50 /* token in DHCP leases */
#define MAXLEASES 150 /* maximum number of DHCP leases */
#define SMALLDNAME 40 /* most domain names are smaller than this */
#define HOSTSFILE "/etc/hosts"
@@ -121,6 +122,10 @@
work on other systems by teaching dnsmasq_time() in utils.c how to
read the system uptime.
+HAVE_ISC_READER
+ define this to include the old ISC dhcpcd integration. Note that you cannot
+ set both HAVE_ISC_READER and HAVE_BROKEN_RTC.
+
HAVE_GETOPT_LONG
define this if you have GNU libc or GNU getopt.
@@ -175,6 +180,16 @@
*/
+/* platform independent options. */
+#undef HAVE_BROKEN_RTC
+#define HAVE_ISC_READER
+
+#if defined(HAVE_BROKEN_RTC) && defined(HAVE_ISC_READER)
+# error HAVE_ISC_READER is not compatible with HAVE_BROKEN_RTC
+#endif
+
+/* platform dependent options. */
+
/* Must preceed __linux__ since uClinux defines __linux__ too. */
#if defined(__uClinux__) || defined(__UCLIBC__)
#undef HAVE_LINUX_IPV6_PROC
@@ -255,6 +270,7 @@
#define HAVE_SOCKADDR_SA_LEN
#undef HAVE_PSELECT
#define HAVE_BPF
+#define BIND_8_COMPAT
/* Define before sys/socket.h is included so we get socklen_t */
#define _BSD_SOCKLEN_T_
/* The two below are not defined in Mac OS X arpa/nameserv.h */
@@ -287,3 +303,4 @@
+
diff --git a/src/dhcp.c b/src/dhcp.c
index f4f71a6..02e42b9 100644
--- a/src/dhcp.c
+++ b/src/dhcp.c
@@ -362,6 +362,10 @@
start = ntohl(context->start.s_addr);
end = ntohl(context->end.s_addr);
+ /* static leases only. */
+ if (start == end)
+ return 0;
+
if (addr < start)
return 0;
@@ -382,7 +386,11 @@
struct dhcp_config *config;
struct in_addr start = context->last;
-
+
+ /* start == end means no dynamic leases. */
+ if (context->end.s_addr == context->start.s_addr)
+ return 0;
+
do {
if (context->last.s_addr == context->end.s_addr)
context->last = context->start;
@@ -393,7 +401,7 @@
if (!lease_find_by_addr(context->last))
{
for (config = configs; config; config = config->next)
- if (config->addr.s_addr == context->last.s_addr)
+ if ((config->flags & CONFIG_ADDR) && config->addr.s_addr == context->last.s_addr)
break;
if (!config)
@@ -411,7 +419,7 @@
{
if (!context)
return 1;
- if (config->addr.s_addr == 0)
+ if (!(config->flags & CONFIG_ADDR))
return 1;
if ((config->addr.s_addr & context->netmask.s_addr) == (context->start.s_addr & context->netmask.s_addr))
return 1;
@@ -428,28 +436,31 @@
if (clid_len)
for (config = configs; config; config = config->next)
- {
- if (config->clid_len == clid_len &&
- memcmp(config->clid, clid, clid_len) == 0 &&
- is_addr_in_context(context, config))
- return config;
-
- /* dhcpcd prefixes ASCII client IDs by zero which is wrong, but we try and
- cope with that here */
- if (*clid == 0 && config->clid_len == clid_len-1 &&
- memcmp(config->clid, clid+1, clid_len-1) == 0 &&
- is_addr_in_context(context, config))
- return config;
- }
-
+ if (config->flags & CONFIG_CLID)
+ {
+ if (config->clid_len == clid_len &&
+ memcmp(config->clid, clid, clid_len) == 0 &&
+ is_addr_in_context(context, config))
+ return config;
+
+ /* dhcpcd prefixes ASCII client IDs by zero which is wrong, but we try and
+ cope with that here */
+ if (*clid == 0 && config->clid_len == clid_len-1 &&
+ memcmp(config->clid, clid+1, clid_len-1) == 0 &&
+ is_addr_in_context(context, config))
+ return config;
+ }
+
for (config = configs; config; config = config->next)
- if (memcmp(config->hwaddr, hwaddr, ETHER_ADDR_LEN) == 0 &&
+ if ((config->flags & CONFIG_HWADDR) &&
+ memcmp(config->hwaddr, hwaddr, ETHER_ADDR_LEN) == 0 &&
is_addr_in_context(context, config))
return config;
if (hostname)
for (config = configs; config; config = config->next)
- if (config->hostname && hostname_isequal(config->hostname, hostname) &&
+ if ((config->flags & CONFIG_NAME) &&
+ hostname_isequal(config->hostname, hostname) &&
is_addr_in_context(context, config))
return config;
@@ -459,28 +470,29 @@
struct dhcp_config *dhcp_read_ethers(struct dhcp_config *configs, char *buff)
{
FILE *f = fopen(ETHERSFILE, "r");
- unsigned int e0, e1, e2, e3, e4, e5;
- char *ip, *cp, *name;
+ unsigned int flags, e0, e1, e2, e3, e4, e5;
+ char *ip, *cp;
struct in_addr addr;
+ unsigned char hwaddr[ETHER_ADDR_LEN];
struct dhcp_config *config;
+ int count = 0;
if (!f)
- die("failed to open " ETHERSFILE ":%s", NULL);
-
+ {
+ syslog(LOG_ERR, "failed to read " ETHERSFILE ":%m");
+ return configs;
+ }
+
while (fgets(buff, MAXDNAME, f))
{
- while (strlen(buff) > 0 &&
- (buff[strlen(buff)-1] == '\n' ||
- buff[strlen(buff)-1] == ' ' ||
- buff[strlen(buff)-1] == '\r' ||
- buff[strlen(buff)-1] == '\t'))
+ while (strlen(buff) > 0 && isspace(buff[strlen(buff)-1]))
buff[strlen(buff)-1] = 0;
if ((*buff == '#') || (*buff == '+'))
continue;
- for (ip = buff; *ip && *ip != ' ' && *ip != '\t'; ip++);
- for(; *ip && (*ip == ' ' || *ip == '\t'); ip++)
+ for (ip = buff; *ip && !isspace(*ip); ip++);
+ for(; *ip && isspace(*ip); ip++)
*ip = 0;
if (!*ip)
continue;
@@ -488,6 +500,13 @@
if (!sscanf(buff, "%x:%x:%x:%x:%x:%x", &e0, &e1, &e2, &e3, &e4, &e5))
continue;
+ hwaddr[0] = e0;
+ hwaddr[1] = e1;
+ hwaddr[2] = e2;
+ hwaddr[3] = e3;
+ hwaddr[4] = e4;
+ hwaddr[5] = e5;
+
/* check for name or dotted-quad */
for (cp = ip; *cp; cp++)
if (!(*cp == '.' || (*cp >='0' && *cp <= '9')))
@@ -495,47 +514,64 @@
if (!*cp)
{
- name = NULL;
if ((addr.s_addr = inet_addr(ip)) == (in_addr_t)-1)
continue;
+ flags = CONFIG_ADDR;
for (config = configs; config; config = config->next)
- if (config->addr.s_addr == addr.s_addr)
+ if ((config->flags & CONFIG_ADDR) && config->addr.s_addr == addr.s_addr)
break;
}
else
{
if (!canonicalise(ip))
continue;
- name = ip;
- addr.s_addr = 0;
+ flags = CONFIG_NAME;
for (config = configs; config; config = config->next)
- if (config->hostname && hostname_isequal(config->hostname, name))
+ if ((config->flags & CONFIG_NAME) && hostname_isequal(config->hostname, ip))
break;
}
if (!config)
{
- config = safe_malloc(sizeof(struct dhcp_config));
- config->clid_len = 0;
- config->clid = NULL;
- config->lease_time = 0;
- config->hostname = safe_string_alloc(name);
- config->addr = addr;
- config->next = configs;
- configs = config;
+ for (config = configs; config; config = config->next)
+ if ((config->flags & CONFIG_HWADDR) &&
+ memcmp(config->hwaddr, hwaddr, ETHER_ADDR_LEN) == 0)
+ break;
+
+ if (!config)
+ {
+ if (!(config = malloc(sizeof(struct dhcp_config))))
+ continue;
+ config->flags = 0;
+ config->next = configs;
+ configs = config;
+ }
+
+ config->flags |= flags;
+
+ if (flags & CONFIG_NAME)
+ {
+ if ((config->hostname = malloc(strlen(ip)+1)))
+ strcpy(config->hostname, ip);
+ else
+ config->flags &= ~CONFIG_NAME;
+ }
+
+ if (flags & CONFIG_ADDR)
+ config->addr = addr;
}
+
+ config->flags |= CONFIG_HWADDR;
+ memcpy(config->hwaddr, hwaddr, ETHER_ADDR_LEN);
- config->hwaddr[0] = e0;
- config->hwaddr[1] = e1;
- config->hwaddr[2] = e2;
- config->hwaddr[3] = e3;
- config->hwaddr[4] = e4;
- config->hwaddr[5] = e5;
+ count++;
}
fclose(f);
+
+ syslog(LOG_INFO, "read " ETHERSFILE " - %d addresses", count);
return configs;
}
@@ -549,10 +585,13 @@
struct crec *crec;
for (config = configs; config; config = config->next)
- if (config->addr.s_addr == 0 && config->hostname &&
+ if (!(config->flags & CONFIG_ADDR) &&
+ (config->flags & CONFIG_NAME) &&
(crec = cache_find_by_name(NULL, config->hostname, 0, F_IPV4)) &&
(crec->flags & F_HOSTS))
- config->addr = crec->addr.addr.addr4;
-
+ {
+ config->addr = crec->addr.addr.addr4;
+ config->flags |= CONFIG_ADDR;
+ }
}
diff --git a/src/dnsmasq.c b/src/dnsmasq.c
index c626ed9..3169e55 100644
--- a/src/dnsmasq.c
+++ b/src/dnsmasq.c
@@ -71,7 +71,7 @@
int leasefd = -1, dhcpfd = -1, dhcp_raw_fd = -1;
struct sigaction sigact;
sigset_t sigmask;
-
+
sighup = 1; /* init cache the first time through */
sigusr1 = 0; /* but don't dump */
sigterm = 0; /* or die */
@@ -120,17 +120,14 @@
#endif
if (!lease_file)
- lease_file = LEASEFILE;
- else
{
- if (!dhcp)
- {
- complain("********* dhcp-lease option set, but not dhcp-range.", NULL);
- complain("********* Are you trying to use the obsolete ISC dhcpd integration?", NULL);
- complain("********* Please configure the dnsmasq integrated DHCP server by using", NULL);
- complain("********* the \"dhcp-range\" option, and remove any other DHCP server.", NULL);
- }
+ if (dhcp)
+ lease_file = LEASEFILE;
}
+#ifndef HAVE_ISC_READER
+ else if (!dhcp)
+ die("ISC dhcpd integration not available: set HAVE_ISC_READER in src/config.h", NULL);
+#endif
interfaces = enumerate_interfaces(if_names, if_addrs, if_except, port);
if (options & OPT_NOWILD)
@@ -152,11 +149,6 @@
{
dhcp_init(&dhcpfd, &dhcp_raw_fd);
leasefd = lease_init(lease_file, domain_suffix, dnamebuff, packet, now, maxleases);
- if (options & OPT_ETHERS)
- dhcp_configs = dhcp_read_ethers(dhcp_configs, dnamebuff);
- lease_update_from_configs(dhcp_configs, domain_suffix); /* must follow cache_init and lease_init */
- lease_update_file(0, now);
- lease_update_dns();
}
setbuf(stdout, NULL);
@@ -248,7 +240,10 @@
sprintf(packet, "infinite");
else
sprintf(packet, "%ds", (int)dhcp_tmp->lease_time);
- syslog(LOG_INFO, "DHCP, IP range %s -- %s, lease time %s",
+ syslog(LOG_INFO,
+ dhcp_tmp->start.s_addr == dhcp_tmp->end.s_addr ?
+ "DHCP, static leases only on %.0s%s, lease time %s" :
+ "DHCP, IP range %s -- %s, lease time %s",
dnamebuff, inet_ntoa(dhcp_tmp->end), packet);
}
@@ -271,6 +266,8 @@
cache_reload(options, dnamebuff, domain_suffix, addn_hosts);
if (dhcp)
{
+ if (options & OPT_ETHERS)
+ dhcp_configs = dhcp_read_ethers(dhcp_configs, dnamebuff);
dhcp_update_configs(dhcp_configs);
lease_update_from_configs(dhcp_configs, domain_suffix);
lease_update_file(0, now);
@@ -350,11 +347,17 @@
if (last == 0 || difftime(now, last) > 1.0)
{
last = now;
+
+#ifdef HAVE_ISC_READER
+ if (lease_file && !dhcp)
+ load_dhcp(lease_file, domain_suffix, now, dnamebuff);
+#endif
+
if (!(options & OPT_NO_POLL))
{
struct resolvc *res = resolv, *latest = NULL;
- time_t last_change = 0;
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. */
diff --git a/src/dnsmasq.h b/src/dnsmasq.h
index a67e488..edb10ad 100644
--- a/src/dnsmasq.h
+++ b/src/dnsmasq.h
@@ -238,15 +238,24 @@
};
struct dhcp_config {
+ unsigned int flags;
int clid_len; /* length of client identifier */
unsigned char *clid; /* clientid */
unsigned char hwaddr[ETHER_ADDR_LEN];
- char *hostname;
+ char *hostname, *netid;
struct in_addr addr;
unsigned int lease_time;
struct dhcp_config *next;
};
+#define CONFIG_DISABLE 1
+#define CONFIG_CLID 2
+#define CONFIG_HWADDR 4
+#define CONFIG_TIME 8
+#define CONFIG_NAME 16
+#define CONFIG_ADDR 32
+#define CONFIG_NETID 64
+
struct dhcp_opt {
int opt, len, is_addr;
unsigned char *val;
@@ -406,3 +415,7 @@
char *domain_suffix, char *dhcp_file, char *dhcp_sname,
struct in_addr dhcp_next_server, struct in_addr router);
+/* isc.c */
+#ifdef HAVE_ISC_READER
+void load_dhcp(char *file, char *suffix, time_t now, char *hostname);
+#endif
diff --git a/src/isc.c b/src/isc.c
new file mode 100644
index 0000000..a807eab
--- /dev/null
+++ b/src/isc.c
@@ -0,0 +1,249 @@
+/* dnsmasq is Copyright (c) 2000 - 2004 by Simon Kelley
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 dated June, 1991.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+*/
+
+
+/* Code in this file is based on contributions by John Volpe. */
+
+#include "dnsmasq.h"
+
+#ifdef HAVE_ISC_READER
+
+struct isc_lease {
+ char *name, *fqdn;
+ time_t expires;
+ struct in_addr addr;
+ struct isc_lease *next;
+};
+
+static struct isc_lease *leases = NULL;
+static off_t lease_file_size = (off_t)0;
+static ino_t lease_file_inode = (ino_t)0;
+static int logged_lease = 0;
+
+static int next_token (char *token, int buffsize, FILE * fp)
+{
+ int c, count = 0;
+ char *cp = token;
+
+ while((c = getc(fp)) != EOF)
+ {
+ if (c == '#')
+ do { c = getc(fp); } while (c != '\n' && c != EOF);
+
+ if (c == ' ' || c == '\t' || c == '\n' || c == ';')
+ {
+ if (count)
+ break;
+ }
+ else if ((c != '"') && (count<buffsize-1))
+ {
+ *cp++ = c;
+ count++;
+ }
+ }
+
+ *cp = 0;
+ return count ? 1 : 0;
+}
+
+void load_dhcp(char *file, char *suffix, time_t now, char *hostname)
+{
+ char token[MAXTOK], *dot;
+ struct in_addr host_address;
+ time_t ttd, tts;
+ FILE *fp;
+ struct isc_lease *lease, *tmp, **up;
+ struct stat statbuf;
+
+ if (stat(file, &statbuf) == -1)
+ {
+ if (!logged_lease)
+ syslog(LOG_WARNING, "failed to access %s: %m", file);
+ logged_lease = 1;
+ return;
+ }
+
+ logged_lease = 0;
+
+ if ((statbuf.st_size <= lease_file_size) &&
+ (statbuf.st_ino == lease_file_inode))
+ return;
+
+ lease_file_size = statbuf.st_size;
+ lease_file_inode = statbuf.st_ino;
+
+ if (!(fp = fopen (file, "r")))
+ {
+ syslog (LOG_ERR, "failed to load %s: %m", file);
+ return;
+ }
+
+ syslog (LOG_INFO, "reading %s", file);
+
+ while ((next_token(token, MAXTOK, fp)))
+ {
+ if (strcmp(token, "lease") == 0)
+ {
+ hostname[0] = '\0';
+ ttd = tts = (time_t)(-1);
+ if (next_token(token, MAXTOK, fp) &&
+ (host_address.s_addr = inet_addr(token)) != (in_addr_t) -1)
+ {
+ if (next_token(token, MAXTOK, fp) && *token == '{')
+ {
+ while (next_token(token, MAXTOK, fp) && *token != '}')
+ {
+ if ((strcmp(token, "client-hostname") == 0) ||
+ (strcmp(token, "hostname") == 0))
+ {
+ if (next_token(hostname, MAXDNAME, fp))
+ if (!canonicalise(hostname))
+ {
+ *hostname = 0;
+ syslog(LOG_ERR, "bad name in %s", file);
+ }
+ }
+ else if ((strcmp(token, "ends") == 0) ||
+ (strcmp(token, "starts") == 0))
+ {
+ struct tm lease_time;
+ int is_ends = (strcmp(token, "ends") == 0);
+ if (next_token(token, MAXTOK, fp) && /* skip weekday */
+ next_token(token, MAXTOK, fp) && /* Get date from lease file */
+ sscanf (token, "%d/%d/%d",
+ &lease_time.tm_year,
+ &lease_time.tm_mon,
+ &lease_time.tm_mday) == 3 &&
+ next_token(token, MAXTOK, fp) &&
+ sscanf (token, "%d:%d:%d:",
+ &lease_time.tm_hour,
+ &lease_time.tm_min,
+ &lease_time.tm_sec) == 3)
+ {
+ /* There doesn't seem to be a universally available library function
+ which converts broken-down _GMT_ time to seconds-in-epoch.
+ The following was borrowed from ISC dhcpd sources, where
+ it is noted that it might not be entirely accurate for odd seconds.
+ Since we're trying to get the same answer as dhcpd, that's just
+ fine here. */
+ static int months [11] = { 31, 59, 90, 120, 151, 181,
+ 212, 243, 273, 304, 334 };
+ time_t time = ((((((365 * (lease_time.tm_year - 1970) + /* Days in years since '70 */
+ (lease_time.tm_year - 1969) / 4 + /* Leap days since '70 */
+ (lease_time.tm_mon > 1 /* Days in months this year */
+ ? months [lease_time.tm_mon - 2]
+ : 0) +
+ (lease_time.tm_mon > 2 && /* Leap day this year */
+ !((lease_time.tm_year - 1972) & 3)) +
+ lease_time.tm_mday - 1) * 24) + /* Day of month */
+ lease_time.tm_hour) * 60) +
+ lease_time.tm_min) * 60) + lease_time.tm_sec;
+ if (is_ends)
+ ttd = time;
+ else
+ tts = time; }
+ }
+ }
+
+ /* missing info? */
+ if (!*hostname)
+ continue;
+ if (ttd == (time_t)(-1))
+ continue;
+
+ /* We use 0 as infinite in ttd */
+ if ((tts != -1) && (ttd == tts - 1))
+ ttd = (time_t)0;
+ else if (difftime(now, ttd) > 0)
+ continue;
+
+ if ((dot = strchr(hostname, '.')))
+ {
+ if (!suffix || hostname_isequal(dot+1, suffix))
+ {
+ syslog(LOG_WARNING,
+ "Ignoring DHCP lease for %s because it has an illegal domain part",
+ hostname);
+ continue;
+ }
+ *dot = 0;
+ }
+
+ for (lease = leases; lease; lease = lease->next)
+ if (hostname_isequal(lease->name, hostname))
+ {
+ lease->expires = ttd;
+ lease->addr = host_address;
+ break;
+ }
+
+ if (!lease && (lease = malloc(sizeof(struct isc_lease))))
+ {
+ lease->expires = ttd;
+ lease->addr = host_address;
+ lease->fqdn = NULL;
+ lease->next = leases;
+ if (!(lease->name = malloc(strlen(hostname)+1)))
+ free(lease);
+ else
+ {
+ leases = lease;
+ strcpy(lease->name, hostname);
+ if (suffix && (lease->fqdn = malloc(strlen(hostname) + strlen(suffix) + 2)))
+ {
+ strcpy(lease->fqdn, hostname);
+ strcat(lease->fqdn, ".");
+ strcat(lease->fqdn, suffix);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ fclose(fp);
+
+ /* prune expired leases */
+ for (lease = leases, up = &leases; lease; lease = tmp)
+ {
+ tmp = lease->next;
+ if (lease->expires != (time_t)0 && difftime(now, lease->expires) > 0)
+ {
+ *up = lease->next; /* unlink */
+ free(lease->name);
+ if (lease->fqdn)
+ free(lease->fqdn);
+ free(lease);
+ }
+ else
+ up = &lease->next;
+ }
+
+
+ /* remove all existing DHCP cache entries */
+ cache_unhash_dhcp();
+
+ for (lease = leases; lease; lease = lease->next)
+ {
+ if (lease->fqdn)
+ {
+ cache_add_dhcp_entry(lease->fqdn, &lease->addr, lease->expires, F_REVERSE);
+ cache_add_dhcp_entry(lease->name, &lease->addr, lease->expires, 0);
+ }
+ else
+ cache_add_dhcp_entry(lease->name, &lease->addr, lease->expires, F_REVERSE);
+ }
+}
+
+#endif
+
diff --git a/src/option.c b/src/option.c
index 8fe6a44..2aab234 100644
--- a/src/option.c
+++ b/src/option.c
@@ -161,10 +161,10 @@
{
int option = 0, i;
unsigned int flags = 0;
- FILE *f = NULL;
- char *conffile = CONFFILE;
+ FILE *file_save = NULL, *f = NULL;
+ char *file_name_save = NULL, *conffile = CONFFILE;
int conffile_set = 0;
- int lineno = 0;
+ int line_save = 0, lineno = 0;
opterr = 0;
*min_leasetime = UINT_MAX;
@@ -179,26 +179,38 @@
#endif
else
{ /* f non-NULL, reading from conffile. */
+ reread:
if (!fgets(buff, MAXDNAME, f))
{
/* At end of file, all done */
fclose(f);
+ if (file_save)
+ {
+ /* may be nested */
+ conffile = file_name_save;
+ f = file_save;
+ file_save = NULL;
+ lineno = line_save;
+ goto reread;
+ }
break;
}
else
{
char *p;
+ int white;
lineno++;
/* dump comments */
- for (p = buff; *p; p++)
- if (*p == '#')
- *p = 0;
+ for (white = 1, p = buff; *p; p++)
+ if (white && *p == '#')
+ {
+ *p = 0;
+ break;
+ }
+ else
+ white = isspace(*p);
/* fgets gets end of line char too. */
- while (strlen(buff) > 0 &&
- (buff[strlen(buff)-1] == '\n' ||
- buff[strlen(buff)-1] == ' ' ||
- buff[strlen(buff)-1] == '\r' ||
- buff[strlen(buff)-1] == '\t'))
+ while (strlen(buff) > 0 && isspace(buff[strlen(buff)-1]))
buff[strlen(buff)-1] = 0;
if (*buff == 0)
continue;
@@ -227,6 +239,7 @@
{ /* end of command line args, start reading conffile. */
if (!conffile)
break; /* "confile=" option disables */
+ fileopen:
option = 0;
if (!(f = fopen(conffile, "r")))
{
@@ -274,9 +287,27 @@
switch (option)
{
case 'C':
+ if (!f)
+ {
+ conffile = safe_string_alloc(optarg);
+ conffile_set = 1;
+ break;
+ }
+
+ /* nest conffiles one deep */
+ if (file_save)
+ {
+ sprintf(buff, "nested includes not allowed at line %d of %s ", lineno, conffile);
+ complain(buff, NULL);
+ continue;
+ }
+ file_name_save = conffile;
+ file_save = f;
+ line_save = lineno;
conffile = safe_string_alloc(optarg);
conffile_set = 1;
- break;
+ lineno = 0;
+ goto fileopen;
case 'x':
*runfile = safe_string_alloc(optarg);
@@ -643,11 +674,15 @@
*(a[k]++) = 0;
}
- if ((k < 2) ||
- ((new->start.s_addr = inet_addr(a[0])) == (in_addr_t)-1) ||
- ((new->end.s_addr = inet_addr(a[1])) == (in_addr_t)-1))
+ if ((k < 2) || ((new->start.s_addr = inet_addr(a[0])) == (in_addr_t)-1))
+ option = '?';
+ else if (strcmp(a[1], "static") == 0)
+ new->end = new->start;
+ else if ((new->end.s_addr = inet_addr(a[1])) == (in_addr_t)-1)
+ option = '?';
+
+ if (option == '?')
{
- option = '?';
free(new);
break;
}
@@ -700,22 +735,17 @@
case 'G':
{
int j, k;
- char *a[4] = { NULL, NULL, NULL, NULL };
+ char *a[6] = { NULL, NULL, NULL, NULL, NULL, NULL };
unsigned int e0, e1, e2, e3, e4, e5;
struct dhcp_config *new = safe_malloc(sizeof(struct dhcp_config));
struct in_addr in;
new->next = *dhcp_conf;
-
- memset(new->hwaddr, 0, ETHER_ADDR_LEN);
- new->clid_len = 0;
- new->clid = NULL;
- new->hostname = NULL;
- new->addr.s_addr = 0;
- new->lease_time = 0;
+ new->flags = 0;
+
a[0] = optarg;
- for (k = 1; k < 4; k++)
+ for (k = 1; k < 6; k++)
{
if (!(a[k] = strchr(a[k-1], ',')))
break;
@@ -723,37 +753,60 @@
}
for(j = 0; j < k; j++)
- if (strchr(a[j], ':')) /* ethernet address or binary CLID */
+ if (strchr(a[j], ':')) /* ethernet address, netid or binary CLID */
{
char *arg = a[j];
if ((arg[0] == 'i' || arg[0] == 'I') &&
(arg[1] == 'd' || arg[1] == 'D') &&
arg[2] == ':')
{
- int s, len;
+ int len;
arg += 3; /* dump id: */
if (strchr(arg, ':'))
{
- s = (strlen(arg)/3) + 1;
- /* decode in place */
- for (len = 0; len < s; len++)
+ /* decode hex in place */
+ char *p = arg, *q = arg, *r;
+ while (*p)
{
- if (arg[(len*3)+2] != ':')
- option = '?';
- arg[(len*3)+2] = 0;
- arg[len] = strtol(&arg[len*3], NULL, 16);
+ for (r = p; *r && *r != ':'; r++);
+ if (*r)
+ {
+ if (r != p)
+ {
+ *r = 0;
+ *(q++) = strtol(p, NULL, 16);
+ }
+ p = r+1;
+ }
+ else
+ {
+ if (*p)
+ *(q++) = strtol(p, NULL, 16);
+ break;
+ }
}
+ len = q - arg;
}
else
len = strlen(arg);
+ new->flags |= CONFIG_CLID;
new->clid_len = len;
new->clid = safe_malloc(len);
memcpy(new->clid, arg, len);
}
+ else if ((arg[0] == 'n' || arg[0] == 'N') &&
+ (arg[1] == 'e' || arg[1] == 'E') &&
+ (arg[2] == 't' || arg[3] == 'T') &&
+ arg[3] == ':')
+ {
+ new->flags |= CONFIG_NETID;
+ new->netid = safe_string_alloc(arg+4);
+ }
else if (sscanf(a[j], "%x:%x:%x:%x:%x:%x",
&e0, &e1, &e2, &e3, &e4, &e5) == 6)
{
+ new->flags |= CONFIG_HWADDR;
new->hwaddr[0] = e0;
new->hwaddr[1] = e1;
new->hwaddr[2] = e2;
@@ -765,7 +818,10 @@
option = '?';
}
else if (strchr(a[j], '.') && (in.s_addr = inet_addr(a[j])) != (in_addr_t)-1)
- new->addr = in;
+ {
+ new->addr = in;
+ new->flags |= CONFIG_ADDR;
+ }
else
{
char *cp, *lastp = NULL, last = 0;
@@ -800,19 +856,38 @@
if (lastp)
*lastp = last;
if (strcmp(a[j], "infinite") == 0)
- new->lease_time = 0xffffffff;
+ {
+ new->lease_time = 0xffffffff;
+ new->flags |= CONFIG_TIME;
+ }
+ else if (strcmp(a[j], "ignore") == 0)
+ new->flags |= CONFIG_DISABLE;
else
- new->hostname = safe_string_alloc(a[j]);
+ {
+ new->hostname = safe_string_alloc(a[j]);
+ new->flags |= CONFIG_NAME;
+ }
}
else
- new->lease_time = atoi(a[j]) * fac;
+ {
+ new->lease_time = atoi(a[j]) * fac;
+ new->flags |= CONFIG_TIME;
+ }
}
if (option == '?')
- free(new);
+ {
+ if (new->flags & CONFIG_NAME)
+ free(new->hostname);
+ if (new->flags & CONFIG_CLID)
+ free(new->clid);
+ if (new->flags & CONFIG_NETID)
+ free(new->netid);
+ free(new);
+ }
else
{
- if (new->lease_time < *min_leasetime)
+ if ((new->flags & CONFIG_TIME) && new->lease_time < *min_leasetime)
*min_leasetime = new->lease_time;
*dhcp_conf = new;
}
@@ -823,7 +898,7 @@
{
struct dhcp_opt *new = safe_malloc(sizeof(struct dhcp_opt));
char *cp, *comma;
- int addrs, is_addr;
+ int addrs, digs, is_addr, is_hex, is_dec;
new->next = *dhcp_opts;
new->len = 0;
@@ -853,58 +928,113 @@
free(new);
break;
}
-
+
+ *dhcp_opts = new;
+
if (!comma)
- {
- *dhcp_opts = new;
- break;
- }
-
- /* check for non-address list characters */
- for (addrs = 1, is_addr = 0, cp = comma+1; *cp; cp++)
+ break;
+
+ /* characterise the value */
+ is_addr = is_hex = is_dec = 1;
+ addrs = digs = 1;
+ for (cp = comma+1; *cp; cp++)
if (*cp == ',')
- addrs++;
- else if (!(*cp == '.' || *cp == ' ' || (*cp >='0' && *cp <= '9')))
- break;
+ {
+ addrs++;
+ is_dec = is_hex = 0;
+ }
+ else if (*cp == ':')
+ {
+ digs++;
+ is_dec = is_addr = 0;
+ }
else if (*cp == '.')
- is_addr = 1;
-
- if (*cp)
+ is_dec = is_hex = 0;
+ else if (!(*cp >='0' && *cp <= '9'))
+ {
+ is_dec = is_addr = 0;
+ if (!((*cp >='A' && *cp <= 'F') ||
+ (*cp >='a' && *cp <= 'F')))
+ is_hex = 0;
+ }
+
+ if (is_hex && digs > 1)
+ {
+ char *p = comma+1, *q, *r;
+ new->len = digs;
+ q = new->val = safe_malloc(new->len);
+ while (*p)
+ {
+ for (r = p; *r && *r != ':'; r++);
+ if (*r)
+ {
+ if (r != p)
+ {
+ *r = 0;
+ *(q++) = strtol(p, NULL, 16);
+ }
+ p = r+1;
+ }
+ else
+ {
+ if (*p)
+ *(q++) = strtol(p, NULL, 16);
+ break;
+ }
+ }
+ }
+ else if (is_dec)
+ {
+ /* Given that we don't know the length,
+ this applaing hack is the best available */
+ unsigned int val = atoi(comma+1);
+ if (val < 256)
+ {
+ new->len = 1;
+ new->val = safe_malloc(1);
+ *(new->val) = val;
+ }
+ else if (val < 65536)
+ {
+ new->len = 2;
+ new->val = safe_malloc(2);
+ *(new->val) = val>>8;
+ *(new->val+1) = val;
+ }
+ else
+ {
+ new->len = 4;
+ new->val = safe_malloc(4);
+ *(new->val) = val>>24;
+ *(new->val+1) = val>>16;
+ *(new->val+2) = val>>8;
+ *(new->val+3) = val;
+ }
+ }
+ else if (is_addr)
+ {
+ struct in_addr in;
+ unsigned char *op;
+ new->len = INADDRSZ * addrs;
+ new->val = op = safe_malloc(new->len);
+ new->is_addr = 1;
+ while (addrs--)
+ {
+ cp = comma;
+ if ((comma = strchr(cp+1, ',')))
+ *comma = 0;
+ in.s_addr = inet_addr(cp+1);
+ memcpy(op, &in, INADDRSZ);
+ op += INADDRSZ;
+ }
+ }
+ else
{
/* text arg */
new->len = strlen(comma+1);
new->val = safe_malloc(new->len);
memcpy(new->val, comma+1, new->len);
}
- else
- {
- struct in_addr in;
- unsigned char *op;
-
- if (addrs == 1 && !is_addr)
- {
- 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;
- }
- }
- }
- *dhcp_opts = new;
break;
}
diff --git a/src/rfc2131.c b/src/rfc2131.c
index a4bd5c0..1b7364d 100644
--- a/src/rfc2131.c
+++ b/src/rfc2131.c
@@ -63,8 +63,12 @@
char *domainname, char *hostname,
struct in_addr router,
struct in_addr iface_addr,
- int iface_mtu);
+ int iface_mtu, char *netid);
+static int have_config(struct dhcp_config *config, unsigned int mask)
+{
+ return config && (config->flags & mask);
+}
int dhcp_reply(struct dhcp_context *context,
struct in_addr iface_addr,
@@ -88,13 +92,27 @@
char *message = NULL;
unsigned int renewal_time, expires_time, def_time;
struct dhcp_config *config;
-
+ char *netid;
+
if (mess->op != BOOTREQUEST ||
- mess->htype != ARPHRD_ETHER ||
mess->hlen != ETHER_ADDR_LEN ||
mess->cookie != htonl(DHCP_COOKIE))
- return 0;
+ return 0;
+ /* Token ring is supported when we have packet sockets
+ to make the HW headers for us. We don't have the code to build
+ token ring headers when using BPF. We rely on the fact that
+ token ring hwaddrs are the same size as ethernet hwaddrs. */
+
+#ifdef HAVE_BPF
+ if (mess->htype != ARPHRD_ETHER)
+ return 0;
+#else
+ if (mess->htype != ARPHRD_ETHER &&
+ mess->htype != ARPHRD_IEEE802)
+ return 0;
+#endif
+
mess->op = BOOTREPLY;
if ((opt = option_find(mess, sz, OPTION_MAXMESSAGE)))
@@ -130,9 +148,9 @@
memcpy(req_options, option_ptr(opt), len);
req_options[len] = OPTION_END;
}
-
+
if ((config = find_config(dhcp_configs, context, clid, clid_len, mess->chaddr, NULL)) &&
- config->hostname)
+ have_config(config, CONFIG_NAME))
hostname = config->hostname;
else if ((opt = option_find(mess, sz, OPTION_HOSTNAME)))
{
@@ -164,7 +182,8 @@
/* 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 ? config->lease_time : context->lease_time;
+ def_time = have_config(config, CONFIG_TIME) ? config->lease_time : context->lease_time;
+ netid = have_config(config, CONFIG_NETID) ? config->netid : context->netid;
if ((opt = option_find(mess, sz, OPTION_LEASE_TIME)))
{
@@ -219,11 +238,11 @@
if (lease && lease->addr.s_addr == option_addr(opt).s_addr)
lease_prune(lease, now);
- if (config && config->addr.s_addr &&
+ if (have_config(config, CONFIG_ADDR) &&
config->addr.s_addr == option_addr(opt).s_addr)
{
syslog(LOG_WARNING, "disabling DHCP static address %s", inet_ntoa(config->addr));
- config->addr.s_addr = 0;
+ config->flags &= ~CONFIG_ADDR ;
}
return 0;
@@ -244,9 +263,9 @@
if ((opt = option_find(mess, sz, OPTION_REQUESTED_IP)))
mess->yiaddr = option_addr(opt);
- log_packet("DISCOVER", opt ? &mess->yiaddr : NULL, mess->chaddr, iface_name, NULL);
-
- if (config && config->addr.s_addr && !lease_find_by_addr(config->addr))
+ if (have_config(config, CONFIG_DISABLE))
+ message = "ignored";
+ else if (have_config(config, CONFIG_ADDR) && !lease_find_by_addr(config->addr))
mess->yiaddr = config->addr;
else if (lease &&
((lease->addr.s_addr & context->netmask.s_addr) ==
@@ -254,18 +273,19 @@
mess->yiaddr = lease->addr;
else if ((!opt || !address_available(context, mess->yiaddr)) &&
!address_allocate(context, dhcp_configs, &mess->yiaddr))
- {
- syslog(LOG_WARNING, "address pool exhausted");
- return 0;
- }
-
+ message = "no address available";
+
+ log_packet("DISCOVER", opt ? &mess->yiaddr : NULL, mess->chaddr, iface_name, message);
+ if (message)
+ return 0;
+
bootp_option_put(mess, dhcp_file, dhcp_sname);
mess->siaddr = dhcp_next_server;
p = option_put(p, end, OPTION_MESSAGE_TYPE, 1, DHCPOFFER);
p = option_put(p, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(iface_addr.s_addr));
p = option_put(p, end, OPTION_LEASE_TIME, 4, expires_time);
p = do_req_options(context, p, end, req_options, dhcp_opts, domain_suffix,
- NULL, router, iface_addr, iface_mtu);
+ NULL, router, iface_addr, iface_mtu, netid);
p = option_put(p, end, OPTION_END, 0, 0);
log_packet("OFFER" , &mess->yiaddr, mess->chaddr, iface_name, NULL);
@@ -297,7 +317,7 @@
if (!lease)
{
if (!address_available(context, mess->yiaddr) &&
- (!config || config->addr.s_addr == 0 || config->addr.s_addr != mess->yiaddr.s_addr))
+ (!have_config(config, CONFIG_ADDR) || config->addr.s_addr != mess->yiaddr.s_addr))
message = "address unavailable";
else if (!(lease = lease_allocate(clid, clid_len, mess->yiaddr)))
message = "no leases left";
@@ -319,6 +339,9 @@
if ((mess->yiaddr.s_addr & context->netmask.s_addr) != (context->start.s_addr & context->netmask.s_addr))
message = "wrong network";
+ if (have_config(config, CONFIG_DISABLE))
+ message = "disabled";
+
log_packet("REQUEST", &mess->yiaddr, mess->chaddr, iface_name, NULL);
if (message)
@@ -354,17 +377,23 @@
p = option_put(p, end, OPTION_T2, 4, ((renewal_time * 7)/8) - fuzz);
}
p = do_req_options(context, p, end, req_options, dhcp_opts, domain_suffix,
- hostname, router, iface_addr, iface_mtu);
+ hostname, router, iface_addr, iface_mtu, netid);
p = option_put(p, end, OPTION_END, 0, 0);
return p - (unsigned char *)mess;
case DHCPINFORM:
+ if (have_config(config, CONFIG_DISABLE))
+ {
+ log_packet("INFORM", &mess->ciaddr, mess->chaddr, iface_name, "ignored");
+ return 0;
+ }
+
log_packet("INFORM", &mess->ciaddr, mess->chaddr, iface_name, NULL);
p = option_put(p, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);
p = option_put(p, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(iface_addr.s_addr));
p = do_req_options(context, p, end, req_options, dhcp_opts, domain_suffix,
- hostname, router, iface_addr, iface_mtu);
+ hostname, router, iface_addr, iface_mtu, netid);
p = option_put(p, end, OPTION_END, 0, 0);
log_packet("ACK", &mess->ciaddr, mess->chaddr, iface_name, hostname);
@@ -524,11 +553,11 @@
return 0;
}
-static struct dhcp_opt *option_find2(struct dhcp_context *context, struct dhcp_opt *opts, int opt)
+static struct dhcp_opt *option_find2(char *netid, struct dhcp_opt *opts, int opt)
{
for (; opts; opts = opts->next)
if (opts->opt == opt &&
- (!opts->netid || (context->netid && strcmp(opts->netid, context->netid) == 0)))
+ (!opts->netid || (netid && strcmp(opts->netid, netid) == 0)))
return opts;
return NULL;
}
@@ -540,7 +569,7 @@
char *domainname, char *hostname,
struct in_addr router,
struct in_addr iface_addr,
- int iface_mtu)
+ int iface_mtu, char *netid)
{
int i;
@@ -553,24 +582,24 @@
iface_mtu : DNSMASQ_PACKETSZ);
if (in_list(req_options, OPTION_NETMASK) &&
- !option_find2(context, config_opts, OPTION_NETMASK))
+ !option_find2(netid, config_opts, OPTION_NETMASK))
p = option_put(p, end, OPTION_NETMASK, INADDRSZ, ntohl(context->netmask.s_addr));
if (in_list(req_options, OPTION_BROADCAST) &&
- !option_find2(context, config_opts, OPTION_BROADCAST))
+ !option_find2(netid, config_opts, OPTION_BROADCAST))
p = option_put(p, end, OPTION_BROADCAST, INADDRSZ, ntohl(context->broadcast.s_addr));
if (in_list(req_options, OPTION_ROUTER) &&
- !option_find2(context, config_opts, OPTION_ROUTER))
+ !option_find2(netid, config_opts, OPTION_ROUTER))
p = option_put(p, end, OPTION_ROUTER, INADDRSZ,
ntohl(router.s_addr));
if (in_list(req_options, OPTION_DNSSERVER) &&
- !option_find2(context, config_opts, OPTION_DNSSERVER))
+ !option_find2(netid, config_opts, OPTION_DNSSERVER))
p = option_put(p, end, OPTION_DNSSERVER, INADDRSZ, ntohl(iface_addr.s_addr));
if (domainname && in_list(req_options, OPTION_DOMAINNAME) &&
- !option_find2(context, config_opts, OPTION_DOMAINNAME))
+ !option_find2(netid, config_opts, OPTION_DOMAINNAME))
p = option_put_string(p, end, OPTION_DOMAINNAME, domainname);
/* Note that we ignore attempts to set the hostname using
@@ -580,38 +609,49 @@
for (i = 0; req_options[i] != OPTION_END; i++)
{
- struct dhcp_opt *opt = option_find2(context, config_opts, req_options[i]);
- if (req_options[i] != OPTION_HOSTNAME &&
- req_options[i] != OPTION_MAXMESSAGE &&
- opt && (p + opt->len + 3 < end))
+ struct dhcp_opt *opt;
+
+ if (req_options[i] == OPTION_HOSTNAME ||
+ req_options[i] == OPTION_MAXMESSAGE ||
+ !(opt = option_find2(netid, config_opts, req_options[i])) ||
+ (p + opt->len + 3 >= end))
+ continue;
+
+ /* For the options we have default values on
+ dhc-option=<optionno> means "don't include this option"
+ not "include a zero-length option" */
+ if (opt->len == 0 &&
+ (opt->opt == OPTION_NETMASK ||
+ opt->opt == OPTION_BROADCAST ||
+ opt->opt == OPTION_ROUTER ||
+ opt->opt == OPTION_DNSSERVER))
+ continue;
+
+ *(p++) = opt->opt;
+ *(p++) = opt->len;
+ if (opt->len == 0)
+ continue;
+
+ if (opt->is_addr)
{
- *(p++) = opt->opt;
- *(p++) = opt->len;
- if (opt->len != 0)
+ int j;
+ struct in_addr *a = (struct in_addr *)opt->val;
+ for (j = 0; j < opt->len; j+=INADDRSZ, a++)
{
- 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, &iface_addr, INADDRSZ);
- else
- memcpy(p, a, INADDRSZ);
- p += INADDRSZ;
- }
- }
+ /* zero means "self" */
+ if (a->s_addr == 0)
+ memcpy(p, &iface_addr, INADDRSZ);
else
- {
- memcpy(p, opt->val, opt->len);
- p += opt->len;
- }
+ memcpy(p, a, INADDRSZ);
+ p += INADDRSZ;
}
}
- }
-
+ else
+ {
+ memcpy(p, opt->val, opt->len);
+ p += opt->len;
+ }
+ }
return p;
}