import of dnsmasq-2.48.tar.gz

This commit is contained in:
Simon Kelley
2009-06-04 20:32:05 +01:00
parent 73a08a248d
commit 7622fc06ab
37 changed files with 7873 additions and 6709 deletions

View File

@@ -130,7 +130,7 @@ int iface_enumerate(void *parm, int (*ipv4_callback)(), int (*ipv6_callback)())
#endif
#if defined(HAVE_BSD_NETWORK)
#if defined(HAVE_BSD_NETWORK) && defined(HAVE_DHCP)
#include <net/bpf.h>
void init_bpf(void)
@@ -175,7 +175,7 @@ void send_via_bpf(struct dhcp_packet *mess, size_t len,
/* Only know how to do ethernet on *BSD */
if (mess->htype != ARPHRD_ETHER || mess->hlen != ETHER_ADDR_LEN)
{
my_syslog(LOG_WARNING, _("DHCP request for unsupported hardware type (%d) received on %s"),
my_syslog(MS_DHCP | LOG_WARNING, _("DHCP request for unsupported hardware type (%d) received on %s"),
mess->htype, ifr->ifr_name);
return;
}

View File

@@ -17,7 +17,10 @@
#include "dnsmasq.h"
static struct crec *cache_head = NULL, *cache_tail = NULL, **hash_table = NULL;
static struct crec *dhcp_spare = NULL, *new_chain = NULL;
#ifdef HAVE_DHCP
static struct crec *dhcp_spare = NULL;
#endif
static struct crec *new_chain = NULL;
static int cache_inserted = 0, cache_live_freed = 0, insert_error;
static union bigname *big_free = NULL;
static int bignames_left, hash_size;
@@ -859,10 +862,11 @@ static int read_hostsfile(char *filename, int index, int cache_size)
return name_count;
}
void cache_reload(struct hostsfile *addn_hosts)
void cache_reload(void)
{
struct crec *cache, **up, *tmp;
int i, total_size = daemon->cachesize;
struct hostsfile *ah;
cache_inserted = cache_live_freed = 0;
@@ -889,7 +893,7 @@ void cache_reload(struct hostsfile *addn_hosts)
up = &cache->hash_next;
}
if ((daemon->options & OPT_NO_HOSTS) && !addn_hosts)
if ((daemon->options & OPT_NO_HOSTS) && !daemon->addn_hosts)
{
if (daemon->cachesize > 0)
my_syslog(LOG_INFO, _("cleared cache"));
@@ -898,13 +902,116 @@ void cache_reload(struct hostsfile *addn_hosts)
if (!(daemon->options & OPT_NO_HOSTS))
total_size = read_hostsfile(HOSTSFILE, 0, total_size);
while (addn_hosts)
for (i = 0, ah = daemon->addn_hosts; ah; ah = ah->next)
{
total_size = read_hostsfile(addn_hosts->fname, addn_hosts->index, total_size);
addn_hosts = addn_hosts->next;
}
if (i <= ah->index)
i = ah->index + 1;
if (ah->flags & AH_DIR)
ah->flags |= AH_INACTIVE;
else
ah->flags &= ~AH_INACTIVE;
}
for (ah = daemon->addn_hosts; ah; ah = ah->next)
if (!(ah->flags & AH_INACTIVE))
{
struct stat buf;
if (stat(ah->fname, &buf) != -1 && S_ISDIR(buf.st_mode))
{
DIR *dir_stream;
struct dirent *ent;
/* don't read this as a file */
ah->flags |= AH_INACTIVE;
if (!(dir_stream = opendir(ah->fname)))
my_syslog(LOG_ERR, _("cannot access directory %s: %s"),
ah->fname, strerror(errno));
else
{
while ((ent = readdir(dir_stream)))
{
size_t lendir = strlen(ah->fname);
size_t lenfile = strlen(ent->d_name);
struct hostsfile *ah1;
char *path;
/* ignore emacs backups and dotfiles */
if (lenfile == 0 ||
ent->d_name[lenfile - 1] == '~' ||
(ent->d_name[0] == '#' && ent->d_name[lenfile - 1] == '#') ||
ent->d_name[0] == '.')
continue;
/* see if we have an existing record.
dir is ah->fname
file is ent->d_name
path to match is ah1->fname */
for (ah1 = daemon->addn_hosts; ah1; ah1 = ah1->next)
{
if (lendir < strlen(ah1->fname) &&
strstr(ah1->fname, ah->fname) == ah1->fname &&
ah1->fname[lendir] == '/' &&
strcmp(ah1->fname + lendir + 1, ent->d_name) == 0)
{
ah1->flags &= ~AH_INACTIVE;
break;
}
}
/* make new record */
if (!ah1)
{
if (!(ah1 = whine_malloc(sizeof(struct hostsfile))))
continue;
if (!(path = whine_malloc(lendir + lenfile + 2)))
{
free(ah1);
continue;
}
strcpy(path, ah->fname);
strcat(path, "/");
strcat(path, ent->d_name);
ah1->fname = path;
ah1->index = i++;
ah1->flags = AH_DIR;
ah1->next = daemon->addn_hosts;
daemon->addn_hosts = ah1;
}
/* inactivate record if not regular file */
if ((ah1->flags & AH_DIR) && stat(ah1->fname, &buf) != -1 && !S_ISREG(buf.st_mode))
ah1->flags |= AH_INACTIVE;
}
closedir(dir_stream);
}
}
}
for (ah = daemon->addn_hosts; ah; ah = ah->next)
if (!(ah->flags & AH_INACTIVE))
total_size = read_hostsfile(ah->fname, ah->index, total_size);
}
char *get_domain(struct in_addr addr)
{
struct cond_domain *c;
for (c = daemon->cond_domain; c; c = c->next)
if (ntohl(addr.s_addr) >= ntohl(c->start.s_addr) &&
ntohl(addr.s_addr) <= ntohl(c->end.s_addr))
return c->domain;
return daemon->domain_suffix;
}
#ifdef HAVE_DHCP
void cache_unhash_dhcp(void)
{
struct crec *cache, **up;
@@ -942,7 +1049,7 @@ void cache_add_dhcp_entry(char *host_name,
_("not giving name %s to the DHCP lease of %s because "
"the name exists in %s with address %s"),
host_name, inet_ntoa(*host_address),
record_source(daemon->addn_hosts, crec->uid), daemon->namebuff);
record_source(crec->uid), daemon->namebuff);
return;
}
else
@@ -1009,6 +1116,7 @@ void cache_add_dhcp_entry(char *host_name,
}
}
}
#endif
void dump_cache(time_t now)
@@ -1099,20 +1207,18 @@ void dump_cache(time_t now)
}
}
char *record_source(struct hostsfile *addn_hosts, int index)
char *record_source(int index)
{
char *source = HOSTSFILE;
while (addn_hosts)
{
if (addn_hosts->index == index)
{
source = addn_hosts->fname;
break;
}
addn_hosts = addn_hosts->next;
}
struct hostsfile *ah;
return source;
if (index == 0)
return HOSTSFILE;
for (ah = daemon->addn_hosts; ah; ah = ah->next)
if (ah->index == index)
return ah->fname;
return "<unknown>";
}
void querystr(char *str, unsigned short type)

View File

@@ -14,7 +14,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define VERSION "2.47"
#define VERSION "2.48"
#define FTABSIZ 150 /* max number of outstanding requests (default) */
#define MAX_PROCS 20 /* max no children for TCP requests */
@@ -106,9 +106,6 @@ HAVE_BSD_NETWORK
HAVE_SOLARIS_NETWORK
define exactly one of these to alter interaction with kernel networking.
HAVE_SOLARIS_PRIVS
define for Solaris > 10 which can split privileges.
HAVE_BROKEN_RTC
define this on embedded systems which don't have an RTC
which keeps time over reboots. Causes dnsmasq to use uptime
@@ -126,6 +123,9 @@ HAVE_BROKEN_RTC
HAVE_TFTP
define this to get dnsmasq's built-in TFTP server.
HAVE_DHCP
define this to get dnsmasq's DHCP server.
HAVE_GETOPT_LONG
define this if you have GNU libc or GNU getopt.
@@ -141,11 +141,6 @@ HAVE_DBUS
define some methods to allow (re)configuration of the upstream DNS
servers via DBus.
HAVE_BSD_BRIDGE
Define this to enable the --bridge-interface option, useful on some
BSD systems.
NOTES:
For Linux you should define
HAVE_LINUX_NETWORK
@@ -165,6 +160,7 @@ NOTES:
*/
/* platform independent options- uncomment to enable */
#define HAVE_DHCP
#define HAVE_TFTP
/* #define HAVE_BROKEN_RTC */
/* #define HAVE_DBUS */
@@ -174,6 +170,11 @@ NOTES:
#undef HAVE_TFTP
#endif
/* Allow DHCP to be disabled with COPTS=-DNO_DHCP */
#ifdef NO_DHCP
#undef HAVE_DHCP
#endif
/* platform dependent options. */
/* Must preceed __linux__ since uClinux defines __linux__ too. */
@@ -211,13 +212,6 @@ NOTES:
#define HAVE_GETOPT_LONG
#undef HAVE_ARC4RANDOM
#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 */
#if defined(__GLIBC__) && (__GLIBC__ == 2) && \
defined(__GLIBC_MINOR__) && (__GLIBC_MINOR__ < 2)
typedef unsigned long in_addr_t;
# define HAVE_BROKEN_SOCKADDR_IN6
#endif
#elif defined(__FreeBSD__) || \
defined(__OpenBSD__) || \
@@ -232,7 +226,6 @@ typedef unsigned long in_addr_t;
# define HAVE_ARC4RANDOM
#endif
#define HAVE_SOCKADDR_SA_LEN
#define HAVE_BSD_BRIDGE
#elif defined(__APPLE__)
#define HAVE_BSD_NETWORK
@@ -247,34 +240,16 @@ typedef unsigned long in_addr_t;
#define HAVE_GETOPT_LONG
#undef HAVE_ARC4RANDOM
#define HAVE_SOCKADDR_SA_LEN
#define HAVE_BSD_BRIDGE
#elif defined(__sun) || defined(__sun__)
#define HAVE_SOLARIS_NETWORK
/* only Solaris 10 does split privs. */
#if (SUNOS_VER >= 10)
# define HAVE_SOLARIS_PRIVS
# define HAVE_GETOPT_LONG
#endif
/* some CMSG stuff missing on early solaris */
#ifndef OSSH_ALIGNBYTES
# define OSSH_ALIGNBYTES (sizeof(int) - 1)
#endif
#ifndef __CMSG_ALIGN
# define __CMSG_ALIGN(p) (((u_int)(p) + OSSH_ALIGNBYTES) &~ OSSH_ALIGNBYTES)
#endif
#ifndef CMSG_LEN
# define CMSG_LEN(len) (__CMSG_ALIGN(sizeof(struct cmsghdr)) + (len))
#endif
#ifndef CMSG_SPACE
# define CMSG_SPACE(len) (__CMSG_ALIGN(sizeof(struct cmsghdr)) + __CMSG_ALIGN(len))
#endif
#define HAVE_GETOPT_LONG
#undef HAVE_ARC4RANDOM
#undef HAVE_SOCKADDR_SA_LEN
#define _XPG4_2
#define __EXTENSIONS__
#define ETHER_ADDR_LEN 6
#define ETHER_ADDR_LEN 6
#endif
/* Decide if we're going to support IPv6 */

View File

@@ -18,7 +18,6 @@
#ifdef HAVE_DBUS
#define DBUS_API_SUBJECT_TO_CHANGE
#include <dbus/dbus.h>
const char* introspection_xml =
@@ -345,11 +344,7 @@ void set_dbus_listeners(int *maxfdp,
if (dbus_watch_get_enabled(w->watch))
{
unsigned int flags = dbus_watch_get_flags(w->watch);
#if (DBUS_MINOR > 0)
int fd = dbus_watch_get_unix_fd(w->watch);
#else
int fd = dbus_watch_get_fd(w->watch);
#endif
bump_maxfd(fd, maxfdp);
@@ -372,11 +367,7 @@ void check_dbus_listeners(fd_set *rset, fd_set *wset, fd_set *eset)
if (dbus_watch_get_enabled(w->watch))
{
unsigned int flags = 0;
#if (DBUS_MINOR > 0)
int fd = dbus_watch_get_unix_fd(w->watch);
#else
int fd = dbus_watch_get_fd(w->watch);
#endif
if (FD_ISSET(fd, rset))
flags |= DBUS_WATCH_READABLE;

View File

@@ -16,6 +16,8 @@
#include "dnsmasq.h"
#ifdef HAVE_DHCP
struct iface_param {
struct in_addr relay, primary;
struct dhcp_context *current;
@@ -35,7 +37,7 @@ void dhcp_init(void)
#endif
if (fd == -1)
die (_("cannot create DHCP socket : %s"), NULL, EC_BADNET);
die (_("cannot create DHCP socket: %s"), NULL, EC_BADNET);
if (!fix_fd(fd) ||
#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
@@ -43,7 +45,7 @@ void dhcp_init(void)
#endif
#if defined(HAVE_LINUX_NETWORK)
setsockopt(fd, SOL_IP, IP_PKTINFO, &oneopt, sizeof(oneopt)) == -1 ||
#elif defined(IP_RECVIF)
#else
setsockopt(fd, IPPROTO_IP, IP_RECVIF, &oneopt, sizeof(oneopt)) == -1 ||
#endif
setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &oneopt, sizeof(oneopt)) == -1)
@@ -51,12 +53,7 @@ void dhcp_init(void)
/* When bind-interfaces is set, there might be more than one dnmsasq
instance binding port 67. That's OK if they serve different networks.
Need to set REUSEADDR to make this posible, or REUSEPORT on *BSD.
OpenBSD <= 4.0 screws up IP_RECVIF when SO_REUSEPORT is set, but
OpenBSD <= 3.9 doesn't have IP_RECVIF anyway, so we just have to elide
this for OpenBSD 4.0, if you want more than one instance on oBSD4.0, tough. */
#ifndef OpenBSD4_0
Need to set REUSEADDR to make this posible, or REUSEPORT on *BSD. */
if (daemon->options & OPT_NOWILD)
{
#ifdef SO_REUSEPORT
@@ -67,7 +64,6 @@ void dhcp_init(void)
if (rc == -1)
die(_("failed to set SO_REUSE{ADDR|PORT} on DHCP socket: %s"), NULL, EC_BADNET);
}
#endif
memset(&saddr, 0, sizeof(saddr));
saddr.sin_family = AF_INET;
@@ -124,7 +120,7 @@ void dhcp_packet(time_t now)
char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
#elif defined(HAVE_SOLARIS_NETWORK)
char control[CMSG_SPACE(sizeof(unsigned int))];
#elif defined(IP_RECVIF)
#elif defined(HAVE_BSD_NETWORK)
char control[CMSG_SPACE(sizeof(struct sockaddr_dl))];
#endif
} control_u;
@@ -136,13 +132,30 @@ void dhcp_packet(time_t now)
msg.msg_iov = &daemon->dhcp_packet;
msg.msg_iovlen = 1;
do
while (1)
{
msg.msg_flags = 0;
while ((sz = recvmsg(daemon->dhcpfd, &msg, MSG_PEEK)) == -1 && errno == EINTR);
while ((sz = recvmsg(daemon->dhcpfd, &msg, MSG_PEEK | MSG_TRUNC)) == -1 && errno == EINTR);
if (sz == -1)
return;
if (!(msg.msg_flags & MSG_TRUNC))
break;
/* Very new Linux kernels return the actual size needed,
older ones always return truncated size */
if ((size_t)sz == daemon->dhcp_packet.iov_len)
{
if (!expand_buf(&daemon->dhcp_packet, sz + 100))
return;
}
else
{
expand_buf(&daemon->dhcp_packet, sz);
break;
}
}
while (sz != -1 && (msg.msg_flags & MSG_TRUNC) &&
expand_buf(&daemon->dhcp_packet, daemon->dhcp_packet.iov_len + 100));
/* expand_buf may have moved buffer */
mess = (struct dhcp_packet *)daemon->dhcp_packet.iov_base;
@@ -154,7 +167,7 @@ void dhcp_packet(time_t now)
while ((sz = recvmsg(daemon->dhcpfd, &msg, 0)) == -1 && errno == EINTR);
if (sz < (ssize_t)(sizeof(*mess) - sizeof(mess->options)))
if ((msg.msg_flags & MSG_TRUNC) || sz < (ssize_t)(sizeof(*mess) - sizeof(mess->options)))
return;
#if defined (HAVE_LINUX_NETWORK)
@@ -166,41 +179,31 @@ void dhcp_packet(time_t now)
if (((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_addr.s_addr != INADDR_BROADCAST)
unicast_dest = 1;
}
if (!(ifr.ifr_ifindex = iface_index) ||
ioctl(daemon->dhcpfd, SIOCGIFNAME, &ifr) == -1)
return;
#elif defined(IP_RECVIF)
#elif defined(HAVE_BSD_NETWORK)
if (msg.msg_controllen >= sizeof(struct cmsghdr))
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
#ifdef HAVE_SOLARIS_NETWORK
iface_index = *((unsigned int *)CMSG_DATA(cmptr));
#else
iface_index = ((struct sockaddr_dl *)CMSG_DATA(cmptr))->sdl_index;
#endif
if (!iface_index || !if_indextoname(iface_index, ifr.ifr_name))
return;
#elif defined(HAVE_SOLARIS_NETWORK)
if (msg.msg_controllen >= sizeof(struct cmsghdr))
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
iface_index = *((unsigned int *)CMSG_DATA(cmptr));
#endif
if (!indextoname(daemon->dhcpfd, iface_index, ifr.ifr_name))
return;
#ifdef MSG_BCAST
/* OpenBSD tells us when a packet was broadcast */
if (!(msg.msg_flags & MSG_BCAST))
unicast_dest = 1;
#endif
#else
/* fallback for systems without IP_RECVIF - allow only one interface
and assume packets arrive from it - yuk. */
{
struct iname *name;
for (name = daemon->if_names; name->isloop; name = name->next);
strcpy(ifr.ifr_name, name->name);
iface_index = if_nametoindex(name->name);
}
#endif
ifr.ifr_addr.sa_family = AF_INET;
if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) != -1 )
{
@@ -208,7 +211,7 @@ void dhcp_packet(time_t now)
iface_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
}
if (!iface_check(AF_INET, (struct all_addr *)addrp, &ifr, &iface_index))
if (!iface_check(AF_INET, (struct all_addr *)addrp, ifr.ifr_name, &iface_index))
return;
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
@@ -218,9 +221,9 @@ void dhcp_packet(time_t now)
/* interface may have been changed by alias in iface_check */
if (!addrp)
{
if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) != -1)
if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) == -1)
{
my_syslog(LOG_WARNING, _("DHCP packet received on %s which has no address"), ifr.ifr_name);
my_syslog(MS_DHCP | LOG_WARNING, _("DHCP packet received on %s which has no address"), ifr.ifr_name);
return;
}
else
@@ -319,7 +322,7 @@ void dhcp_packet(time_t now)
dest.sin_addr.s_addr = INADDR_BROADCAST;
dest.sin_port = htons(daemon->dhcp_client_port);
/* note that we don't specify the interface here: that's done by the
IP_XMIT_IF sockopt lower down. */
IP_BOUND_IF sockopt lower down. */
}
else
{
@@ -345,12 +348,7 @@ void dhcp_packet(time_t now)
#endif
#ifdef HAVE_SOLARIS_NETWORK
/* OpenSolaris eliminates IP_XMIT_IF */
# ifdef IP_XMIT_IF
setsockopt(daemon->dhcpfd, IPPROTO_IP, IP_XMIT_IF, &iface_index, sizeof(iface_index));
# else
setsockopt(daemon->dhcpfd, IPPROTO_IP, IP_BOUND_IF, &iface_index, sizeof(iface_index));
# endif
#endif
while(sendmsg(daemon->dhcpfd, &msg, 0) == -1 && retry_send());
@@ -384,7 +382,7 @@ static int complete_context(struct in_addr local, int if_index,
{
strcpy(daemon->dhcp_buff, inet_ntoa(context->start));
strcpy(daemon->dhcp_buff2, inet_ntoa(context->end));
my_syslog(LOG_WARNING, _("DHCP range %s -- %s is not consistent with netmask %s"),
my_syslog(MS_DHCP | LOG_WARNING, _("DHCP range %s -- %s is not consistent with netmask %s"),
daemon->dhcp_buff, daemon->dhcp_buff2, inet_ntoa(netmask));
}
context->netmask = netmask;
@@ -474,9 +472,9 @@ struct dhcp_context *narrow_context(struct dhcp_context *context,
if (!(tmp = address_available(context, taddr, netids)))
{
for (tmp = context; tmp; tmp = tmp->current)
if (is_same_net(taddr, tmp->start, tmp->netmask) &&
(tmp->flags & CONTEXT_STATIC))
break;
if (is_same_net(taddr, tmp->start, tmp->netmask) &&
(tmp->flags & CONTEXT_STATIC))
break;
if (!tmp)
for (tmp = context; tmp; tmp = tmp->current)
@@ -667,7 +665,8 @@ struct dhcp_config *find_config(struct dhcp_config *configs,
unsigned char *hwaddr, int hw_len,
int hw_type, char *hostname)
{
struct dhcp_config *config;
int count, new;
struct dhcp_config *config, *candidate;
struct hwaddr_config *conf_addr;
if (clid)
@@ -699,17 +698,21 @@ struct dhcp_config *find_config(struct dhcp_config *configs,
hostname_isequal(config->hostname, hostname) &&
is_addr_in_context(context, config))
return config;
for (config = configs; config; config = config->next)
for (conf_addr = config->hwaddr; conf_addr; conf_addr = conf_addr->next)
if (conf_addr->wildcard_mask != 0 &&
conf_addr->hwaddr_len == hw_len &&
(conf_addr->hwaddr_type == hw_type || conf_addr->hwaddr_type == 0) &&
is_addr_in_context(context, config) &&
memcmp_masked(conf_addr->hwaddr, hwaddr, hw_len, conf_addr->wildcard_mask))
return config;
return NULL;
/* use match with fewest wildcast octets */
for (candidate = NULL, count = 0, config = configs; config; config = config->next)
if (is_addr_in_context(context, config))
for (conf_addr = config->hwaddr; conf_addr; conf_addr = conf_addr->next)
if (conf_addr->wildcard_mask != 0 &&
conf_addr->hwaddr_len == hw_len &&
(conf_addr->hwaddr_type == hw_type || conf_addr->hwaddr_type == 0) &&
(new = memcmp_masked(conf_addr->hwaddr, hwaddr, hw_len, conf_addr->wildcard_mask)) > count)
{
count = new;
candidate = config;
}
return candidate;
}
void dhcp_read_ethers(void)
@@ -728,7 +731,7 @@ void dhcp_read_ethers(void)
if (!f)
{
my_syslog(LOG_ERR, _("failed to read %s:%s"), ETHERSFILE, strerror(errno));
my_syslog(MS_DHCP | LOG_ERR, _("failed to read %s: %s"), ETHERSFILE, strerror(errno));
return;
}
@@ -764,7 +767,7 @@ void dhcp_read_ethers(void)
*ip = 0;
if (!*ip || parse_hex(buff, hwaddr, ETHER_ADDR_LEN, NULL, NULL) != ETHER_ADDR_LEN)
{
my_syslog(LOG_ERR, _("bad line at %s line %d"), ETHERSFILE, lineno);
my_syslog(MS_DHCP | LOG_ERR, _("bad line at %s line %d"), ETHERSFILE, lineno);
continue;
}
@@ -777,7 +780,7 @@ void dhcp_read_ethers(void)
{
if ((addr.s_addr = inet_addr(ip)) == (in_addr_t)-1)
{
my_syslog(LOG_ERR, _("bad address at %s line %d"), ETHERSFILE, lineno);
my_syslog(MS_DHCP | LOG_ERR, _("bad address at %s line %d"), ETHERSFILE, lineno);
continue;
}
@@ -791,7 +794,7 @@ void dhcp_read_ethers(void)
{
if (!canonicalise(ip))
{
my_syslog(LOG_ERR, _("bad name at %s line %d"), ETHERSFILE, lineno);
my_syslog(MS_DHCP | LOG_ERR, _("bad name at %s line %d"), ETHERSFILE, lineno);
continue;
}
@@ -857,7 +860,7 @@ void dhcp_read_ethers(void)
fclose(f);
my_syslog(LOG_INFO, _("read %s - %d addresses"), ETHERSFILE, count);
my_syslog(MS_DHCP | LOG_INFO, _("read %s - %d addresses"), ETHERSFILE, count);
}
void check_dhcp_hosts(int fatal)
@@ -882,7 +885,7 @@ void check_dhcp_hosts(int fatal)
die(_("duplicate IP address %s in dhcp-config directive."),
inet_ntoa(cp->addr), EC_BADCONF);
else
my_syslog(LOG_ERR, _("duplicate IP address %s in %s."),
my_syslog(MS_DHCP | LOG_ERR, _("duplicate IP address %s in %s."),
inet_ntoa(cp->addr), daemon->dhcp_hosts_file);
configs->flags &= ~CONFIG_ADDR;
}
@@ -925,12 +928,12 @@ 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 than one address in hostsfile, using %s for DHCP"),
my_syslog(MS_DHCP | LOG_WARNING, _("%s has more than one address in hostsfile, using %s for DHCP"),
config->hostname, inet_ntoa(crec->addr.addr.addr.addr4));
}
if (config_find_by_address(configs, crec->addr.addr.addr.addr4))
my_syslog(LOG_WARNING, _("duplicate IP address %s (%s) in dhcp-config directive"),
my_syslog(MS_DHCP | LOG_WARNING, _("duplicate IP address %s (%s) in dhcp-config directive"),
inet_ntoa(crec->addr.addr.addr.addr4), config->hostname);
else
{
@@ -982,14 +985,5 @@ char *strip_hostname(char *hostname)
return NULL;
}
char *get_domain(struct in_addr addr)
{
struct cond_domain *c;
#endif
for (c = daemon->cond_domain; c; c = c->next)
if (ntohl(addr.s_addr) >= ntohl(c->start.s_addr) &&
ntohl(addr.s_addr) <= ntohl(c->end.s_addr))
return c->domain;
return daemon->domain_suffix;
}

View File

@@ -33,9 +33,6 @@ static char *compile_opts =
#ifdef NO_FORK
"no-MMU "
#endif
#ifdef HAVE_BSD_BRIDGE
"BSD-bridge "
#endif
#ifndef HAVE_DBUS
"no-"
#endif
@@ -44,6 +41,10 @@ static char *compile_opts =
"no-"
#endif
"I18N "
#ifndef HAVE_DHCP
"no-"
#endif
"DHCP "
#ifndef HAVE_TFTP
"no-"
#endif
@@ -67,9 +68,11 @@ int main (int argc, char **argv)
struct iname *if_tmp;
int piperead, pipefd[2], err_pipe[2];
struct passwd *ent_pw = NULL;
#ifdef HAVE_DHCP
uid_t script_uid = 0;
gid_t script_gid = 0;
struct group *gp= NULL;
#endif
struct group *gp = NULL;
long i, max_fd = sysconf(_SC_OPEN_MAX);
char *baduser = NULL;
int log_err;
@@ -108,11 +111,13 @@ int main (int argc, char **argv)
daemon->edns_pktsz : DNSMASQ_PACKETSZ;
daemon->packet = safe_malloc(daemon->packet_buff_sz);
#ifdef HAVE_DHCP
if (!daemon->lease_file)
{
if (daemon->dhcp)
daemon->lease_file = LEASEFILE;
}
#endif
/* Close any file descriptors we inherited apart from std{in|out|err} */
for (i = 0; i < max_fd; i++)
@@ -145,23 +150,16 @@ int main (int argc, char **argv)
now = dnsmasq_time();
#ifdef HAVE_DHCP
if (daemon->dhcp)
{
#if !defined(HAVE_LINUX_NETWORK) && !defined(IP_RECVIF)
int c;
struct iname *tmp;
for (c = 0, tmp = daemon->if_names; tmp; tmp = tmp->next)
if (!tmp->isloop)
c++;
if (c != 1)
die(_("must set exactly one interface on broken systems without IP_RECVIF"), NULL, EC_BADCONF);
#endif
/* Note that order matters here, we must call lease_init before
creating any file descriptors which shouldn't be leaked
to the lease-script init process. */
lease_init(now);
dhcp_init();
}
#endif
if (!enumerate_interfaces())
die(_("failed to find list of interfaces: %s"), NULL, EC_MISC);
@@ -204,6 +202,7 @@ int main (int argc, char **argv)
if (daemon->port != 0)
pre_allocate_sfds();
#ifdef HAVE_DHCP
/* Note getpwnam returns static storage */
if (daemon->dhcp && daemon->lease_change_command && daemon->scriptuser)
{
@@ -215,6 +214,7 @@ int main (int argc, char **argv)
else
baduser = daemon->scriptuser;
}
#endif
if (daemon->username && !(ent_pw = getpwnam(daemon->username)))
baduser = daemon->username;
@@ -290,8 +290,9 @@ int main (int argc, char **argv)
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);
if ((pid = fork()) == -1)
/* fd == -1 since we've not forked, never returns. */
send_event(-1, EVENT_FORK_ERR, errno);
if (pid != 0)
{
@@ -312,9 +313,11 @@ int main (int argc, char **argv)
/* NO calls to die() from here on. */
setsid();
pid = fork();
if (pid != 0 && pid != -1)
if ((pid = fork()) == -1)
send_event(err_pipe[1], EVENT_FORK_ERR, errno);
if (pid != 0)
_exit(0);
}
#endif
@@ -349,7 +352,7 @@ int main (int argc, char **argv)
/* if we are to run scripts, we need to fork a helper before dropping root. */
daemon->helperfd = -1;
#ifndef NO_FORK
#if defined(HAVE_DHCP) && !defined(NO_FORK)
if (daemon->dhcp && daemon->lease_change_command)
daemon->helperfd = create_helper(pipewrite, err_pipe[1], script_uid, script_gid, max_fd);
#endif
@@ -380,7 +383,7 @@ int main (int argc, char **argv)
if (capset(hdr, data) == -1 || prctl(PR_SET_KEEPCAPS, 1) == -1)
bad_capabilities = errno;
#elif defined(HAVE_SOLARIS_PRIVS)
#elif defined(HAVE_SOLARIS_NETWORK)
/* http://developers.sun.com/solaris/articles/program_privileges.html */
priv_set_t *priv_set;
@@ -400,9 +403,6 @@ int main (int argc, char **argv)
if (priv_set)
priv_freeset(priv_set);
#elif defined(HAVE_SOLARIS_NETWORK)
bad_capabilities = ENOTSUP;
#endif
if (bad_capabilities != 0)
@@ -482,6 +482,7 @@ int main (int argc, char **argv)
if (daemon->max_logs != 0)
my_syslog(LOG_INFO, _("asynchronous logging enabled, queue limit is %d messages"), daemon->max_logs);
#ifdef HAVE_DHCP
if (daemon->dhcp)
{
struct dhcp_context *dhcp_tmp;
@@ -490,13 +491,16 @@ int main (int argc, char **argv)
{
prettyprint_time(daemon->dhcp_buff2, dhcp_tmp->lease_time);
strcpy(daemon->dhcp_buff, inet_ntoa(dhcp_tmp->start));
my_syslog(LOG_INFO,
my_syslog(MS_DHCP | LOG_INFO,
(dhcp_tmp->flags & CONTEXT_STATIC) ?
_("DHCP, static leases only on %.0s%s, lease time %s") :
(dhcp_tmp->flags & CONTEXT_PROXY) ?
_("DHCP, proxy on subnet %.0s%s%.0s") :
_("DHCP, IP range %s -- %s, lease time %s"),
daemon->dhcp_buff, inet_ntoa(dhcp_tmp->end), daemon->dhcp_buff2);
}
}
#endif
#ifdef HAVE_TFTP
if (daemon->options & OPT_TFTP)
@@ -506,7 +510,7 @@ int main (int argc, char **argv)
max_fd = FD_SETSIZE;
#endif
my_syslog(LOG_INFO, "TFTP %s%s %s",
my_syslog(MS_TFTP | LOG_INFO, "TFTP %s%s %s",
daemon->tftp_prefix ? _("root is ") : _("enabled"),
daemon->tftp_prefix ? daemon->tftp_prefix: "",
daemon->options & OPT_TFTP_SECURE ? _("secure mode") : "");
@@ -534,7 +538,7 @@ int main (int argc, char **argv)
if (daemon->tftp_max > max_fd)
{
daemon->tftp_max = max_fd;
my_syslog(LOG_WARNING,
my_syslog(MS_TFTP | LOG_WARNING,
_("restricting maximum simultaneous TFTP transfers to %d"),
daemon->tftp_max);
}
@@ -582,11 +586,13 @@ int main (int argc, char **argv)
set_dbus_listeners(&maxfd, &rset, &wset, &eset);
#endif
#ifdef HAVE_DHCP
if (daemon->dhcp)
{
FD_SET(daemon->dhcpfd, &rset);
bump_maxfd(daemon->dhcpfd, &maxfd);
}
#endif
#ifdef HAVE_LINUX_NETWORK
FD_SET(daemon->netlinkfd, &rset);
@@ -596,7 +602,8 @@ int main (int argc, char **argv)
FD_SET(piperead, &rset);
bump_maxfd(piperead, &maxfd);
#ifndef NO_FORK
#ifdef HAVE_DHCP
# ifdef NO_FORK
while (helper_buf_empty() && do_script_run(now));
if (!helper_buf_empty())
@@ -604,11 +611,12 @@ int main (int argc, char **argv)
FD_SET(daemon->helperfd, &wset);
bump_maxfd(daemon->helperfd, &maxfd);
}
#else
# else
/* need this for other side-effects */
while (do_script_run(now));
# endif
#endif
/* must do this just before select(), when we know no
more calls to my_syslog() can occur */
set_log_writer(&wset, &maxfd);
@@ -662,12 +670,14 @@ int main (int argc, char **argv)
check_tftp_listeners(&rset, now);
#endif
#ifdef HAVE_DHCP
if (daemon->dhcp && FD_ISSET(daemon->dhcpfd, &rset))
dhcp_packet(now);
#ifndef NO_FORK
# ifndef NO_FORK
if (daemon->helperfd != -1 && FD_ISSET(daemon->helperfd, &wset))
helper_write();
# endif
#endif
}
@@ -737,6 +747,9 @@ static void fatal_event(struct event_desc *ev)
{
case EVENT_DIE:
exit(0);
case EVENT_FORK_ERR:
die(_("cannot fork into background: %s"), NULL, EC_MISC);
case EVENT_PIPE_ERR:
die(_("failed to create helper: %s"), NULL, EC_MISC);
@@ -777,7 +790,9 @@ static void async_event(int pipe, time_t now)
reload_servers(daemon->resolv_files->name);
check_servers();
}
#ifdef HAVE_DHCP
rerun_scripts();
#endif
break;
case EVENT_DUMP:
@@ -786,11 +801,13 @@ static void async_event(int pipe, time_t now)
break;
case EVENT_ALARM:
#ifdef HAVE_DHCP
if (daemon->dhcp)
{
lease_prune(NULL, now);
lease_update_file(now);
}
#endif
break;
case EVENT_CHILD:
@@ -840,7 +857,7 @@ static void async_event(int pipe, time_t now)
if (daemon->tcp_pids[i] != 0)
kill(daemon->tcp_pids[i], SIGALRM);
#ifndef NO_FORK
#if defined(HAVE_DHCP) && !defined(NO_FORK)
/* handle pending lease transitions */
if (daemon->helperfd != -1)
{
@@ -904,7 +921,7 @@ static void poll_resolv()
warned = 0;
check_servers();
if (daemon->options & OPT_RELOAD)
cache_reload(daemon->addn_hosts);
cache_reload();
}
else
{
@@ -921,8 +938,9 @@ static void poll_resolv()
void clear_cache_and_reload(time_t now)
{
if (daemon->port != 0)
cache_reload(daemon->addn_hosts);
cache_reload();
#ifdef HAVE_DHCP
if (daemon->dhcp)
{
if (daemon->options & OPT_ETHERS)
@@ -934,6 +952,7 @@ void clear_cache_and_reload(time_t now)
lease_update_file(now);
lease_update_dns();
}
#endif
}
static int set_dns_listeners(time_t now, fd_set *set, int *maxfdp)
@@ -1135,7 +1154,7 @@ static void check_dns_listeners(fd_set *set, time_t now)
}
}
#ifdef HAVE_DHCP
int make_icmp_sock(void)
{
int fd;
@@ -1258,5 +1277,6 @@ int icmp_ping(struct in_addr addr)
return gotreply;
}
#endif

View File

@@ -106,7 +106,7 @@ extern int capget(cap_user_header_t header, cap_user_data_t data);
#define LINUX_CAPABILITY_VERSION_3 0x20080522
#include <sys/prctl.h>
#elif defined(HAVE_SOLARIS_PRIVS)
#elif defined(HAVE_SOLARIS_NETWORK)
#include <priv.h>
#endif
@@ -135,6 +135,7 @@ struct event_desc {
#define EVENT_GROUP_ERR 15
#define EVENT_DIE 16
#define EVENT_LOG_ERR 17
#define EVENT_FORK_ERR 18
/* Exit codes. */
#define EC_GOOD 0
@@ -185,6 +186,11 @@ struct event_desc {
#define OPT_NO_OVERRIDE (1u<<30)
#define OPT_NO_REBIND (1u<<31)
/* extra flags for my_syslog, we use a couple of facilities since they are known
not to occupy the same bits as priorities, no matter how syslog.h is set up. */
#define MS_TFTP LOG_USER
#define MS_DHCP LOG_DAEMON
struct all_addr {
union {
struct in_addr addr4;
@@ -287,19 +293,7 @@ struct crec {
union mysockaddr {
struct sockaddr sa;
struct sockaddr_in in;
#ifdef HAVE_BROKEN_SOCKADDR_IN6
/* early versions of glibc don't include sin6_scope_id in sockaddr_in6
but latest kernels _require_ it to be set. The choice is to have
dnsmasq fail to compile on back-level libc or fail to run
on latest kernels with IPv6. Or to do this: sorry that it's so gross. */
struct my_sockaddr_in6 {
sa_family_t sin6_family; /* AF_INET6 */
uint16_t sin6_port; /* transport layer port # */
uint32_t sin6_flowinfo; /* IPv6 traffic class & flow info */
struct in6_addr sin6_addr; /* IPv6 address */
uint32_t sin6_scope_id; /* set of interfaces for a scope */
} in6;
#elif defined(HAVE_IPV6)
#if defined(HAVE_IPV6)
struct sockaddr_in6 in6;
#endif
};
@@ -368,8 +362,11 @@ struct resolvc {
};
/* adn-hosts parms from command-line */
#define AH_DIR 1
#define AH_INACTIVE 2
struct hostsfile {
struct hostsfile *next;
int flags;
char *fname;
int index; /* matches to cache entries for logging */
};
@@ -484,6 +481,7 @@ struct dhcp_opt {
#define DHOPT_MATCH 128
#define DHOPT_VENDOR 256
#define DHOPT_HEX 512
#define DHOPT_VENDOR_MATCH 1024
struct dhcp_boot {
char *file, *sname;
@@ -492,6 +490,14 @@ struct dhcp_boot {
struct dhcp_boot *next;
};
struct pxe_service {
unsigned short CSA, type;
char *menu, *basename;
struct in_addr server;
struct dhcp_netid *netid;
struct pxe_service *next;
};
#define MATCH_VENDOR 1
#define MATCH_USER 2
#define MATCH_CIRCUIT 3
@@ -514,12 +520,10 @@ struct dhcp_mac {
struct dhcp_mac *next;
};
#ifdef HAVE_BSD_BRIDGE
struct dhcp_bridge {
char iface[IF_NAMESIZE];
struct dhcp_bridge *alias, *next;
};
#endif
struct cond_domain {
char *domain;
@@ -540,6 +544,7 @@ struct dhcp_context {
#define CONTEXT_STATIC 1
#define CONTEXT_NETMASK 2
#define CONTEXT_BRDCAST 4
#define CONTEXT_PROXY 8
typedef unsigned char u8;
@@ -620,6 +625,7 @@ extern struct daemon {
struct dhcp_vendor *dhcp_vendors;
struct dhcp_mac *dhcp_macs;
struct dhcp_boot *boot_config;
struct pxe_service *pxe_services;
struct dhcp_netid_list *dhcp_ignore, *dhcp_ignore_names, *force_broadcast, *bootp_dynamic;
char *dhcp_hosts_file, *dhcp_opts_file;
int dhcp_max, tftp_max;
@@ -643,23 +649,21 @@ extern struct daemon {
struct server *srv_save; /* Used for resend on DoD */
size_t packet_len; /* " " */
struct randfd *rfd_save; /* " " */
pid_t tcp_pids[MAX_PROCS];
pid_t tcp_pids[MAX_PROCS];
struct randfd randomsocks[RANDOM_SOCKS];
/* DHCP state */
int dhcpfd, helperfd;
#ifdef HAVE_LINUX_NETWORK
#if defined(HAVE_LINUX_NETWORK)
int netlinkfd;
#else
#elif defined(HAVE_BSD_NETWORK)
int dhcp_raw_fd, dhcp_icmp_fd;
#endif
struct iovec dhcp_packet;
char *dhcp_buff, *dhcp_buff2;
struct ping_result *ping_results;
FILE *lease_stream;
#ifdef HAVE_BSD_BRIDGE
struct dhcp_bridge *bridges;
#endif
/* DBus stuff */
/* void * here to avoid depending on dbus headers outside dbus.c */
@@ -676,7 +680,7 @@ pid_t tcp_pids[MAX_PROCS];
/* cache.c */
void cache_init(void);
void log_query(unsigned short flags, char *name, struct all_addr *addr, char *arg);
char *record_source(struct hostsfile *addn_hosts, int index);
char *record_source(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,
@@ -687,11 +691,12 @@ void cache_end_insert(void);
void cache_start_insert(void);
struct crec *cache_insert(char *name, struct all_addr *addr,
time_t now, unsigned long ttl, unsigned short flags);
void cache_reload(struct hostsfile *addn_hosts);
void cache_reload(void);
void cache_add_dhcp_entry(char *host_name, struct in_addr *host_address, time_t ttd);
void cache_unhash_dhcp(void);
void dump_cache(time_t now);
char *cache_get_name(struct crec *crecp);
char *get_domain(struct in_addr addr);
/* rfc1035.c */
unsigned short extract_request(HEADER *header, size_t qlen,
@@ -748,7 +753,7 @@ void flush_log(void);
/* option.c */
void read_opts (int argc, char **argv, char *compile_opts);
char *option_string(unsigned char opt);
char *option_string(unsigned char opt, int *is_ip, int *is_name);
void reread_dhcp(void);
/* forward.c */
@@ -760,6 +765,7 @@ void server_gone(struct server *server);
struct frec *get_new_frec(time_t now, int *wait);
/* network.c */
int indextoname(int fd, int index, char *name);
int local_bind(int fd, union mysockaddr *addr, char *intname, int is_tcp);
int random_sock(int family);
void pre_allocate_sfds(void);
@@ -768,15 +774,14 @@ void check_servers(void);
int enumerate_interfaces();
struct listener *create_wildcard_listeners(void);
struct listener *create_bound_listeners(void);
int iface_check(int family, struct all_addr *addr,
struct ifreq *ifr, int *indexp);
int iface_check(int family, struct all_addr *addr, char *name, int *indexp);
int fix_fd(int fd);
struct in_addr get_ifaddr(char *intr);
/* dhcp.c */
#ifdef HAVE_DHCP
void dhcp_init(void);
void dhcp_packet(time_t now);
char *get_domain(struct in_addr addr);
struct dhcp_context *address_available(struct dhcp_context *context,
struct in_addr addr,
struct dhcp_netid *netids);
@@ -799,8 +804,10 @@ struct dhcp_config *config_find_by_address(struct dhcp_config *configs, struct i
char *strip_hostname(char *hostname);
char *host_from_dns(struct in_addr addr);
char *get_domain(struct in_addr addr);
#endif
/* lease.c */
#ifdef HAVE_DHCP
void lease_update_file(time_t now);
void lease_update_dns();
void lease_init(time_t now);
@@ -817,16 +824,21 @@ void lease_prune(struct dhcp_lease *target, time_t now);
void lease_update_from_configs(void);
int do_script_run(time_t now);
void rerun_scripts(void);
#endif
/* rfc2131.c */
#ifdef HAVE_DHCP
size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
size_t sz, time_t now, int unicast_dest, int *is_inform);
unsigned char *extended_hwaddr(int hwtype, int hwlen, unsigned char *hwaddr,
int clid_len, unsigned char *clid, int *len_out);
#endif
/* dnsmasq.c */
#ifdef HAVE_DHCP
int make_icmp_sock(void);
int icmp_ping(struct in_addr addr);
#endif
void send_event(int fd, int event, int data);
void clear_cache_and_reload(time_t now);
@@ -855,7 +867,7 @@ void emit_dbus_signal(int action, char *mac, char *hostname, char *addr);
#endif
/* helper.c */
#ifndef NO_FORK
#if defined(HAVE_DHCP) && !defined(NO_FORK)
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,

View File

@@ -667,19 +667,8 @@ void receive_query(struct listener *listen, time_t now)
/* enforce available interface configuration */
if (if_index == 0)
return;
#ifdef SIOCGIFNAME
ifr.ifr_ifindex = if_index;
if (ioctl(listen->fd, SIOCGIFNAME, &ifr) == -1)
return;
#else
if (!if_indextoname(if_index, ifr.ifr_name))
return;
#endif
if (!iface_check(listen->family, &dst_addr, &ifr, &if_index))
if (!indextoname(listen->fd, if_index, ifr.ifr_name) ||
!iface_check(listen->family, &dst_addr, ifr.ifr_name, &if_index))
return;
if (listen->family == AF_INET &&

View File

@@ -28,7 +28,7 @@
main process.
*/
#ifndef NO_FORK
#if defined(HAVE_DHCP) && !defined(NO_FORK)
static void my_setenv(const char *name, const char *value, int *error);
@@ -276,28 +276,8 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
static void my_setenv(const char *name, const char *value, int *error)
{
if (*error == 0)
{
#if defined(HAVE_SOLARIS_NETWORK) && !defined(HAVE_SOLARIS_PRIVS)
/* old Solaris is missing setenv..... */
char *p;
if (!(p = malloc(strlen(name) + strlen(value) + 2)))
*error = ENOMEM;
else
{
strcpy(p, name);
strcat(p, "=");
strcat(p, value);
if (putenv(p) != 0)
*error = errno;
}
#else
if (setenv(name, value, 1) != 0)
*error = errno;
#endif
}
if (*error == 0 && setenv(name, value, 1) != 0)
*error = errno;
}
/* pack up lease data into a buffer */

View File

@@ -16,6 +16,8 @@
#include "dnsmasq.h"
#ifdef HAVE_DHCP
static struct dhcp_lease *leases = NULL, *old_leases = NULL;
static int dns_dirty, file_dirty, leases_left;
@@ -57,7 +59,7 @@ void lease_init(time_t now)
if (!leasestream)
die(_("cannot open or create lease file %s: %s"), daemon->lease_file, EC_FILE);
/* a+ mode lease pointer at end. */
/* a+ mode leaves pointer at end. */
rewind(leasestream);
}
@@ -235,7 +237,7 @@ void lease_update_file(time_t now)
if (next_event == 0 || difftime(next_event, LEASE_RETRY + now) > 0.0)
next_event = LEASE_RETRY + now;
my_syslog(LOG_ERR, _("failed to write %s: %s (retry in %us)"),
my_syslog(MS_DHCP | LOG_ERR, _("failed to write %s: %s (retry in %us)"),
daemon->lease_file, strerror(err),
(unsigned int)difftime(next_event, now));
}
@@ -607,6 +609,8 @@ int do_script_run(time_t now)
return 0; /* nothing to do */
}
#endif

View File

@@ -248,6 +248,10 @@ static void log_write(void)
}
}
/* priority is one of LOG_DEBUG, LOG_INFO, LOG_NOTICE, etc. See sys/syslog.h.
OR'd to priority can be MS_TFTP, MS_DHCP, ... to be able to do log separation between
DNS, DHCP and TFTP services.
*/
void my_syslog(int priority, const char *format, ...)
{
va_list ap;
@@ -256,10 +260,18 @@ void my_syslog(int priority, const char *format, ...)
char *p;
size_t len;
pid_t pid = getpid();
char *func = "";
if ((LOG_FACMASK & priority) == MS_TFTP)
func = "-tftp";
else if ((LOG_FACMASK & priority) == MS_DHCP)
func = "-dhcp";
priority = LOG_PRI(priority);
if (log_stderr)
{
fprintf(stderr, "dnsmasq: ");
fprintf(stderr, "dnsmasq%s: ", func);
va_start(ap, format);
vfprintf(stderr, format, ap);
va_end(ap);
@@ -305,8 +317,9 @@ void my_syslog(int priority, const char *format, ...)
p = entry->payload;
if (!log_to_file)
p += sprintf(p, "<%d>", priority | log_fac);
p += sprintf(p, "%.15s dnsmasq[%d]: ", ctime(&time_now) + 4, (int)pid);
p += sprintf(p, "%.15s dnsmasq%s[%d]: ", ctime(&time_now) + 4, func, (int)pid);
len = p - entry->payload;
va_start(ap, format);
len += vsnprintf(p, MAX_MESSAGE - len, format, ap) + 1; /* include zero-terminator */

View File

@@ -31,6 +31,7 @@
#endif
static struct iovec iov;
static u32 netlink_pid;
static void nl_err(struct nlmsghdr *h);
static void nl_routechange(struct nlmsghdr *h);
@@ -38,6 +39,7 @@ static void nl_routechange(struct nlmsghdr *h);
void netlink_init(void)
{
struct sockaddr_nl addr;
socklen_t slen = sizeof(addr);
addr.nl_family = AF_NETLINK;
addr.nl_pad = 0;
@@ -59,48 +61,63 @@ void netlink_init(void)
}
}
if (daemon->netlinkfd == -1)
if (daemon->netlinkfd == -1 ||
getsockname(daemon->netlinkfd, (struct sockaddr *)&addr, &slen) == 1)
die(_("cannot create netlink socket: %s"), NULL, EC_MISC);
/* save pid assigned by bind() and retrieved by getsockname() */
netlink_pid = addr.nl_pid;
iov.iov_len = 200;
iov.iov_len = 100;
iov.iov_base = safe_malloc(iov.iov_len);
}
static ssize_t netlink_recv(void)
{
struct msghdr msg;
struct sockaddr_nl nladdr;
ssize_t rc;
msg.msg_control = NULL;
msg.msg_controllen = 0;
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
while (1)
{
msg.msg_control = NULL;
msg.msg_controllen = 0;
msg.msg_name = &nladdr;
msg.msg_namelen = sizeof(nladdr);
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_flags = 0;
while ((rc = recvmsg(daemon->netlinkfd, &msg, MSG_PEEK)) == -1 && errno == EINTR);
/* 2.2.x doesn't suport MSG_PEEK at all, returning EOPNOTSUPP, so we just grab a
big buffer and pray in that case. */
if (rc == -1 && errno == EOPNOTSUPP)
while ((rc = recvmsg(daemon->netlinkfd, &msg, MSG_PEEK | MSG_TRUNC)) == -1 && errno == EINTR);
/* make buffer big enough */
if (rc != -1 && (msg.msg_flags & MSG_TRUNC))
{
if (!expand_buf(&iov, 2000))
return -1;
break;
/* Very new Linux kernels return the actual size needed, older ones always return truncated size */
if ((size_t)rc == iov.iov_len)
{
if (expand_buf(&iov, rc + 100))
continue;
}
else
expand_buf(&iov, rc);
}
if (rc == -1 || !(msg.msg_flags & MSG_TRUNC))
break;
if (!expand_buf(&iov, iov.iov_len + 100))
return -1;
}
/* finally, read it for real */
while ((rc = recvmsg(daemon->netlinkfd, &msg, 0)) == -1 && errno == EINTR);
/* read it for real */
msg.msg_flags = 0;
while ((rc = recvmsg(daemon->netlinkfd, &msg, 0)) == -1 && errno == EINTR);
/* Make sure this is from the kernel */
if (rc == -1 || nladdr.nl_pid == 0)
break;
}
/* discard stuff which is truncated at this point (expand_buf() may fail) */
if (msg.msg_flags & MSG_TRUNC)
{
rc = -1;
errno = ENOMEM;
}
return rc;
}
@@ -141,13 +158,20 @@ int iface_enumerate(void *parm, int (*ipv4_callback)(), int (*ipv6_callback)())
while (1)
{
if ((len = netlink_recv()) == -1)
return 0;
{
if (errno == ENOBUFS)
{
sleep(1);
goto again;
}
return 0;
}
for (h = (struct nlmsghdr *)iov.iov_base; NLMSG_OK(h, (size_t)len); h = NLMSG_NEXT(h, len))
if (h->nlmsg_type == NLMSG_ERROR)
nl_err(h);
else if (h->nlmsg_seq != seq)
if (h->nlmsg_seq != seq || h->nlmsg_pid != netlink_pid)
nl_routechange(h); /* May be multicast arriving async */
else if (h->nlmsg_type == NLMSG_ERROR)
nl_err(h);
else if (h->nlmsg_type == NLMSG_DONE)
{
#ifdef HAVE_IPV6
@@ -208,10 +232,17 @@ int iface_enumerate(void *parm, int (*ipv4_callback)(), int (*ipv6_callback)())
}
}
void netlink_multicast(void)
{
ssize_t len;
struct nlmsghdr *h;
int flags;
/* don't risk blocking reading netlink messages here. */
if ((flags = fcntl(daemon->netlinkfd, F_GETFL)) == -1 ||
fcntl(daemon->netlinkfd, F_SETFL, flags | O_NONBLOCK) == -1)
return;
if ((len = netlink_recv()) != -1)
{
@@ -221,11 +252,15 @@ void netlink_multicast(void)
else
nl_routechange(h);
}
/* restore non-blocking status */
fcntl(daemon->netlinkfd, F_SETFL, flags);
}
static void nl_err(struct nlmsghdr *h)
{
struct nlmsgerr *err = NLMSG_DATA(h);
if (err->error != 0)
my_syslog(LOG_ERR, _("netlink returns error: %s"), strerror(-(err->error)));
}
@@ -234,10 +269,10 @@ static void nl_err(struct nlmsghdr *h)
If this happens and we still have a DNS packet in the buffer, we re-send it.
This helps on DoD links, where frequently the packet which triggers dialling is
a DNS query, which then gets lost. By re-sending, we can avoid the lookup
failing. */
failing. Note that we only accept these messages from the kernel (pid == 0) */
static void nl_routechange(struct nlmsghdr *h)
{
if (h->nlmsg_type == RTM_NEWROUTE)
if (h->nlmsg_pid == 0 && h->nlmsg_type == RTM_NEWROUTE)
{
struct rtmsg *rtm = NLMSG_DATA(h);
int fd;

View File

@@ -16,8 +16,37 @@
#include "dnsmasq.h"
int iface_check(int family, struct all_addr *addr,
struct ifreq *ifr, int *indexp)
#ifdef HAVE_LINUX_NETWORK
int indextoname(int fd, int index, char *name)
{
struct ifreq ifr;
if (index == 0)
return 0;
ifr.ifr_ifindex = index;
if (ioctl(fd, SIOCGIFNAME, &ifr) == -1)
return 0;
strncpy(name, ifr.ifr_name, IF_NAMESIZE);
return 1;
}
#else
int indextoname(int fd, int index, char *name)
{
if (index == 0 || !if_indextoname(index, name))
return 0;
return 1;
}
#endif
int iface_check(int family, struct all_addr *addr, char *name, int *indexp)
{
struct iname *tmp;
int ret = 1;
@@ -27,7 +56,6 @@ int iface_check(int family, struct all_addr *addr,
if (indexp)
{
#ifdef HAVE_BSD_BRIDGE
/* One form of bridging on BSD has the property that packets
can be recieved on bridge interfaces which do not have an IP address.
We allow these to be treated as aliases of another interface which does have
@@ -36,26 +64,25 @@ int iface_check(int family, struct all_addr *addr,
for (bridge = daemon->bridges; bridge; bridge = bridge->next)
{
for (alias = bridge->alias; alias; alias = alias->next)
if (strncmp(ifr->ifr_name, alias->iface, IF_NAMESIZE) == 0)
if (strncmp(name, alias->iface, IF_NAMESIZE) == 0)
{
int newindex;
if (!(newindex = if_nametoindex(bridge->iface)))
{
my_syslog(LOG_WARNING, _("unknown interface %s in bridge-interface"), ifr->ifr_name);
my_syslog(LOG_WARNING, _("unknown interface %s in bridge-interface"), name);
return 0;
}
else
{
*indexp = newindex;
strncpy(ifr->ifr_name, bridge->iface, IF_NAMESIZE);
strncpy(name, bridge->iface, IF_NAMESIZE);
break;
}
}
if (alias)
break;
}
#endif
}
if (daemon->if_names || (addr && daemon->if_addrs))
@@ -63,7 +90,7 @@ int iface_check(int family, struct all_addr *addr,
ret = 0;
for (tmp = daemon->if_names; tmp; tmp = tmp->next)
if (tmp->name && (strcmp(tmp->name, ifr->ifr_name) == 0))
if (tmp->name && (strcmp(tmp->name, name) == 0))
ret = tmp->used = 1;
for (tmp = daemon->if_addrs; tmp; tmp = tmp->next)
@@ -82,7 +109,7 @@ int iface_check(int family, struct all_addr *addr,
}
for (tmp = daemon->if_except; tmp; tmp = tmp->next)
if (tmp->name && (strcmp(tmp->name, ifr->ifr_name) == 0))
if (tmp->name && (strcmp(tmp->name, name) == 0))
ret = 0;
return ret;
@@ -103,16 +130,8 @@ static int iface_allowed(struct irec **irecp, int if_index,
if (sockaddr_isequal(&iface->addr, addr))
return 1;
#ifdef HAVE_LINUX_NETWORK
ifr.ifr_ifindex = if_index;
#endif
if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1 ||
#ifdef HAVE_LINUX_NETWORK
ioctl(fd, SIOCGIFNAME, &ifr) == -1 ||
#else
!if_indextoname(if_index, ifr.ifr_name) ||
#endif
!indextoname(fd, if_index, ifr.ifr_name) ||
ioctl(fd, SIOCGIFFLAGS, &ifr) == -1)
{
if (fd != -1)
@@ -150,7 +169,7 @@ static int iface_allowed(struct irec **irecp, int if_index,
}
if (addr->sa.sa_family == AF_INET &&
!iface_check(AF_INET, (struct all_addr *)&addr->in.sin_addr, &ifr, NULL))
!iface_check(AF_INET, (struct all_addr *)&addr->in.sin_addr, ifr.ifr_name, NULL))
return 1;
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
@@ -159,7 +178,7 @@ static int iface_allowed(struct irec **irecp, int if_index,
#ifdef HAVE_IPV6
if (addr->sa.sa_family == AF_INET6 &&
!iface_check(AF_INET6, (struct all_addr *)&addr->in6.sin6_addr, &ifr, NULL))
!iface_check(AF_INET6, (struct all_addr *)&addr->in6.sin6_addr, ifr.ifr_name, NULL))
return 1;
#endif
@@ -217,7 +236,6 @@ static int iface_allowed_v4(struct in_addr local, int if_index,
return iface_allowed((struct irec **)vparam, if_index, &addr, netmask);
}
int enumerate_interfaces(void)
{
#ifdef HAVE_IPV6
@@ -529,7 +547,7 @@ int local_bind(int fd, union mysockaddr *addr, char *intname, int is_tcp)
#if defined(SO_BINDTODEVICE)
if (intname[0] != 0 &&
setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, intname, sizeof(intname)) == -1)
setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, intname, strlen(intname)) == -1)
return 0;
#endif

View File

@@ -19,6 +19,10 @@
#include "dnsmasq.h"
#include <setjmp.h>
static volatile int mem_recover = 0;
static jmp_buf mem_jmp;
static void one_file(char *file, int nest, int hard_opt);
/* Solaris headers don't have facility names. */
#ifdef HAVE_SOLARIS_NETWORK
static const struct {
@@ -34,10 +38,7 @@ static const struct {
{ "lpr", LOG_LPR },
{ "news", LOG_NEWS },
{ "uucp", LOG_UUCP },
#ifdef LOG_AUDIT
/* Not Solaris < 10 */
{ "audit", LOG_AUDIT },
#endif
{ "cron", LOG_CRON },
{ "local0", LOG_LOCAL0 },
{ "local1", LOG_LOCAL1 },
@@ -98,6 +99,9 @@ struct myoption {
#define LOPT_MINPORT 288
#define LOPT_DHCP_FQDN 289
#define LOPT_CNAME 290
#define LOPT_PXE_PROMT 291
#define LOPT_PXE_SERV 292
#define LOPT_TEST 293
#ifdef HAVE_GETOPT_LONG
static const struct option opts[] =
@@ -105,105 +109,106 @@ static const struct option opts[] =
static const struct myoption opts[] =
#endif
{
{"version", 0, 0, 'v'},
{"no-hosts", 0, 0, 'h'},
{"no-poll", 0, 0, 'n'},
{"help", 0, 0, 'w'},
{"no-daemon", 0, 0, 'd'},
{"log-queries", 0, 0, 'q'},
{"user", 2, 0, 'u'},
{"group", 2, 0, 'g'},
{"resolv-file", 2, 0, 'r'},
{"mx-host", 1, 0, 'm'},
{"mx-target", 1, 0, 't'},
{"cache-size", 2, 0, 'c'},
{"port", 1, 0, 'p'},
{"dhcp-leasefile", 2, 0, 'l'},
{"dhcp-lease", 1, 0, 'l' },
{"dhcp-host", 1, 0, 'G'},
{"dhcp-range", 1, 0, 'F'},
{"dhcp-option", 1, 0, 'O'},
{"dhcp-boot", 1, 0, 'M'},
{"domain", 1, 0, 's'},
{"domain-suffix", 1, 0, 's'},
{"interface", 1, 0, 'i'},
{"listen-address", 1, 0, 'a'},
{"bogus-priv", 0, 0, 'b'},
{"bogus-nxdomain", 1, 0, 'B'},
{"selfmx", 0, 0, 'e'},
{"filterwin2k", 0, 0, 'f'},
{"pid-file", 2, 0, 'x'},
{"strict-order", 0, 0, 'o'},
{"server", 1, 0, 'S'},
{"local", 1, 0, LOPT_LOCAL },
{"address", 1, 0, 'A' },
{"conf-file", 2, 0, 'C'},
{"no-resolv", 0, 0, 'R'},
{"expand-hosts", 0, 0, 'E'},
{"localmx", 0, 0, 'L'},
{"local-ttl", 1, 0, 'T'},
{"no-negcache", 0, 0, 'N'},
{"addn-hosts", 1, 0, 'H'},
{"query-port", 1, 0, 'Q'},
{"except-interface", 1, 0, 'I'},
{"no-dhcp-interface", 1, 0, '2'},
{"domain-needed", 0, 0, 'D'},
{"dhcp-lease-max", 1, 0, 'X' },
{"bind-interfaces", 0, 0, 'z'},
{"read-ethers", 0, 0, 'Z' },
{"alias", 1, 0, 'V' },
{"dhcp-vendorclass", 1, 0, 'U'},
{"dhcp-userclass", 1, 0, 'j'},
{"dhcp-ignore", 1, 0, 'J'},
{"edns-packet-max", 1, 0, 'P'},
{"keep-in-foreground", 0, 0, 'k'},
{"dhcp-authoritative", 0, 0, 'K'},
{"srv-host", 1, 0, 'W'},
{"localise-queries", 0, 0, 'y'},
{"txt-record", 1, 0, 'Y'},
{"enable-dbus", 0, 0, '1'},
{"bootp-dynamic", 2, 0, '3'},
{"dhcp-mac", 1, 0, '4'},
{"no-ping", 0, 0, '5'},
{"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'},
{"clear-on-reload", 0, 0, LOPT_RELOAD },
{"dhcp-ignore-names", 2, 0, LOPT_NO_NAMES },
{"enable-tftp", 0, 0, LOPT_TFTP },
{"tftp-secure", 0, 0, LOPT_SECURE },
{"tftp-unique-root", 0, 0, LOPT_APREF },
{"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
{"dhcp-option-force", 1, 0, LOPT_FORCE },
{"tftp-no-blocksize", 0, 0, LOPT_NOBLOCK },
{"log-dhcp", 0, 0, LOPT_LOG_OPTS },
{"log-async", 2, 0, LOPT_MAX_LOGS },
{"dhcp-circuitid", 1, 0, LOPT_CIRCUIT },
{"dhcp-remoteid", 1, 0, LOPT_REMOTE },
{"dhcp-subscrid", 1, 0, LOPT_SUBSCR },
{"interface-name", 1, 0, LOPT_INTNAME },
{"dhcp-hostsfile", 1, 0, LOPT_DHCP_HOST },
{"dhcp-optsfile", 1, 0, LOPT_DHCP_OPTS },
{"dhcp-no-override", 0, 0, LOPT_OVERRIDE },
{"tftp-port-range", 1, 0, LOPT_TFTPPORTS },
{"stop-dns-rebind", 0, 0, LOPT_REBIND },
{"all-servers", 0, 0, LOPT_NOLAST},
{"dhcp-match", 1, 0, LOPT_MATCH },
{"dhcp-broadcast", 1, 0, LOPT_BROADCAST },
{"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 },
{"dhcp-fqdn", 0, 0, LOPT_DHCP_FQDN },
{"cname", 1, 0, LOPT_CNAME },
{ "version", 0, 0, 'v' },
{ "no-hosts", 0, 0, 'h' },
{ "no-poll", 0, 0, 'n' },
{ "help", 0, 0, 'w' },
{ "no-daemon", 0, 0, 'd' },
{ "log-queries", 0, 0, 'q' },
{ "user", 2, 0, 'u' },
{ "group", 2, 0, 'g' },
{ "resolv-file", 2, 0, 'r' },
{ "mx-host", 1, 0, 'm' },
{ "mx-target", 1, 0, 't' },
{ "cache-size", 2, 0, 'c' },
{ "port", 1, 0, 'p' },
{ "dhcp-leasefile", 2, 0, 'l' },
{ "dhcp-lease", 1, 0, 'l' },
{ "dhcp-host", 1, 0, 'G' },
{ "dhcp-range", 1, 0, 'F' },
{ "dhcp-option", 1, 0, 'O' },
{ "dhcp-boot", 1, 0, 'M' },
{ "domain", 1, 0, 's' },
{ "domain-suffix", 1, 0, 's' },
{ "interface", 1, 0, 'i' },
{ "listen-address", 1, 0, 'a' },
{ "bogus-priv", 0, 0, 'b' },
{ "bogus-nxdomain", 1, 0, 'B' },
{ "selfmx", 0, 0, 'e' },
{ "filterwin2k", 0, 0, 'f' },
{ "pid-file", 2, 0, 'x' },
{ "strict-order", 0, 0, 'o' },
{ "server", 1, 0, 'S' },
{ "local", 1, 0, LOPT_LOCAL },
{ "address", 1, 0, 'A' },
{ "conf-file", 2, 0, 'C' },
{ "no-resolv", 0, 0, 'R' },
{ "expand-hosts", 0, 0, 'E' },
{ "localmx", 0, 0, 'L' },
{ "local-ttl", 1, 0, 'T' },
{ "no-negcache", 0, 0, 'N' },
{ "addn-hosts", 1, 0, 'H' },
{ "query-port", 1, 0, 'Q' },
{ "except-interface", 1, 0, 'I' },
{ "no-dhcp-interface", 1, 0, '2' },
{ "domain-needed", 0, 0, 'D' },
{ "dhcp-lease-max", 1, 0, 'X' },
{ "bind-interfaces", 0, 0, 'z' },
{ "read-ethers", 0, 0, 'Z' },
{ "alias", 1, 0, 'V' },
{ "dhcp-vendorclass", 1, 0, 'U' },
{ "dhcp-userclass", 1, 0, 'j' },
{ "dhcp-ignore", 1, 0, 'J' },
{ "edns-packet-max", 1, 0, 'P' },
{ "keep-in-foreground", 0, 0, 'k' },
{ "dhcp-authoritative", 0, 0, 'K' },
{ "srv-host", 1, 0, 'W' },
{ "localise-queries", 0, 0, 'y' },
{ "txt-record", 1, 0, 'Y' },
{ "enable-dbus", 0, 0, '1' },
{ "bootp-dynamic", 2, 0, '3' },
{ "dhcp-mac", 1, 0, '4' },
{ "no-ping", 0, 0, '5' },
{ "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' },
{ "clear-on-reload", 0, 0, LOPT_RELOAD },
{ "dhcp-ignore-names", 2, 0, LOPT_NO_NAMES },
{ "enable-tftp", 0, 0, LOPT_TFTP },
{ "tftp-secure", 0, 0, LOPT_SECURE },
{ "tftp-unique-root", 0, 0, LOPT_APREF },
{ "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 },
{ "bridge-interface", 1, 0 , LOPT_BRIDGE },
{ "dhcp-option-force", 1, 0, LOPT_FORCE },
{ "tftp-no-blocksize", 0, 0, LOPT_NOBLOCK },
{ "log-dhcp", 0, 0, LOPT_LOG_OPTS },
{ "log-async", 2, 0, LOPT_MAX_LOGS },
{ "dhcp-circuitid", 1, 0, LOPT_CIRCUIT },
{ "dhcp-remoteid", 1, 0, LOPT_REMOTE },
{ "dhcp-subscrid", 1, 0, LOPT_SUBSCR },
{ "interface-name", 1, 0, LOPT_INTNAME },
{ "dhcp-hostsfile", 1, 0, LOPT_DHCP_HOST },
{ "dhcp-optsfile", 1, 0, LOPT_DHCP_OPTS },
{ "dhcp-no-override", 0, 0, LOPT_OVERRIDE },
{ "tftp-port-range", 1, 0, LOPT_TFTPPORTS },
{ "stop-dns-rebind", 0, 0, LOPT_REBIND },
{ "all-servers", 0, 0, LOPT_NOLAST },
{ "dhcp-match", 1, 0, LOPT_MATCH },
{ "dhcp-broadcast", 1, 0, LOPT_BROADCAST },
{ "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 },
{ "dhcp-fqdn", 0, 0, LOPT_DHCP_FQDN },
{ "cname", 1, 0, LOPT_CNAME },
{ "pxe-prompt", 1, 0, LOPT_PXE_PROMT },
{ "pxe-service", 1, 0, LOPT_PXE_SERV },
{ "test", 0, 0, LOPT_TEST },
{ NULL, 0, 0, 0 }
};
@@ -287,9 +292,7 @@ static struct {
{ '2', ARG_DUP, "interface", gettext_noop("Do not provide DHCP on this interface, only provide DNS."), NULL },
{ '3', ARG_DUP, "[=<id>[,<id>]]", 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
{ LOPT_BRIDGE, ARG_DUP, "iface,alias,..", gettext_noop("Treat DHCP requests on aliases as arriving from interface."), NULL },
#endif
{ '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 },
@@ -317,13 +320,18 @@ static struct {
{ LOPT_MINPORT, ARG_ONE, "<port>", gettext_noop("Specify lowest port available for DNS query transmission."), NULL },
{ LOPT_DHCP_FQDN, OPT_DHCP_FQDN, NULL, gettext_noop("Use only fully qualified domain names for DHCP clients."), NULL },
{ LOPT_CNAME, ARG_DUP, "<alias>,<target>", gettext_noop("Specify alias name for LOCAL DNS name."), NULL },
{ LOPT_PXE_PROMT, ARG_DUP, "<prompt>,[<timeout>]", gettext_noop("Prompt to send to PXE clients."), NULL },
{ LOPT_PXE_SERV, ARG_DUP, "<service>", gettext_noop("Boot service for PXE menu."), NULL },
{ LOPT_TEST, 0, NULL, gettext_noop("Check configuration syntax."), NULL },
{ 0, 0, NULL, NULL, NULL }
};
#ifdef HAVE_DHCP
/* makes options which take a list of addresses */
#define OT_ADDR_LIST 255
#define OT_ADDR_LIST 0x80
/* DHCP-internal options, for logging. not valid in config file */
#define OT_INTERNAL 254
#define OT_INTERNAL 0x40
#define OT_NAME 0x20
static const struct {
char *name;
@@ -335,9 +343,9 @@ static const struct {
{ "dns-server", 6, OT_ADDR_LIST },
{ "log-server", 7, OT_ADDR_LIST },
{ "lpr-server", 9, OT_ADDR_LIST },
{ "hostname", 12, OT_INTERNAL },
{ "hostname", 12, OT_INTERNAL | OT_NAME },
{ "boot-file-size", 13, 2 },
{ "domain-name", 15, 0 },
{ "domain-name", 15, OT_NAME },
{ "swap-server", 16, OT_ADDR_LIST },
{ "root-path", 17, 0 },
{ "extension-path", 18, 0 },
@@ -348,7 +356,7 @@ static const struct {
{ "default-ttl", 23, 1 },
{ "mtu", 26, 2 },
{ "all-subnets-local", 27, 1 },
{ "broadcast", 28, OT_INTERNAL },
{ "broadcast", 28, OT_INTERNAL | OT_ADDR_LIST },
{ "router-discovery", 31, 1 },
{ "router-solicitation", 32, OT_ADDR_LIST },
{ "static-route", 33, OT_ADDR_LIST },
@@ -367,11 +375,11 @@ static const struct {
{ "netbios-scope", 47, 0 },
{ "x-windows-fs", 48, OT_ADDR_LIST },
{ "x-windows-dm", 49, OT_ADDR_LIST },
{ "requested-address", 50, OT_INTERNAL },
{ "requested-address", 50, OT_INTERNAL | OT_ADDR_LIST },
{ "lease-time", 51, OT_INTERNAL },
{ "option-overload", 52, OT_INTERNAL },
{ "message-type", 53, OT_INTERNAL, },
{ "server-identifier", 54, OT_INTERNAL },
{ "server-identifier", 54, OT_INTERNAL | OT_ADDR_LIST },
{ "parameter-request", 55, OT_INTERNAL },
{ "message", 56, OT_INTERNAL },
{ "max-message-size", 57, OT_INTERNAL },
@@ -401,21 +409,25 @@ static const struct {
{ NULL, 0, 0 }
};
static volatile int mem_recover = 0;
static jmp_buf mem_jmp;
static void one_file(char *file, int nest, int hard_opt);
char *option_string(unsigned char opt)
char *option_string(unsigned char opt, int *is_ip, int *is_name)
{
int i;
for (i = 0; opttab[i].name; i++)
if (opttab[i].val == opt)
return opttab[i].name;
{
if (is_ip)
*is_ip = !!(opttab[i].size & OT_ADDR_LIST);
if (is_name)
*is_name = !!(opttab[i].size & OT_NAME);
return opttab[i].name;
}
return NULL;
}
#endif
/* We hide metacharaters in quoted strings by mapping them into the ASCII control
character space. Note that the \0, \t \b \r \033 and \n characters are carefully placed in the
following sequence so that they map to themselves: it is therefore possible to call
@@ -626,6 +638,7 @@ static void do_usage(void)
}
}
#ifdef HAVE_DHCP
static void display_opts(void)
{
int i;
@@ -760,7 +773,7 @@ static char *parse_dhcp_opt(char *arg, int flags)
/* We know that some options take addresses */
if (opt_len == OT_ADDR_LIST)
if (opt_len & OT_ADDR_LIST)
{
is_string = is_dec = is_hex = 0;
if (!is_addr || dots == 0)
@@ -919,7 +932,7 @@ static char *parse_dhcp_opt(char *arg, int flags)
}
}
if (new->len > 255)
if ((new->len > 255) || (new->len > 253 && (new->flags & (DHOPT_VENDOR | DHOPT_ENCAPSULATE))))
problem = _("dhcp-option too long");
if (!problem)
@@ -946,6 +959,7 @@ static char *parse_dhcp_opt(char *arg, int flags)
return problem;
}
#endif
static char *one_opt(int option, char *arg, char *gen_prob, int nest)
{
@@ -1013,20 +1027,21 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
while ((ent = readdir(dir_stream)))
{
size_t len;
size_t len = strlen(ent->d_name);
struct stat buf;
if ((len = strlen(ent->d_name)) == 0)
continue;
/* ignore emacs backups and dotfiles */
if (ent->d_name[len - 1] == '~' ||
if (len == 0 ||
ent->d_name[len - 1] == '~' ||
(ent->d_name[0] == '#' && ent->d_name[len - 1] == '#') ||
ent->d_name[0] == '.')
continue;
path = opt_malloc(strlen(directory) + len + 2);
strcpy(path, directory);
strcat(path, "/");
strcat(path, ent->d_name);
if (stat(path, &buf) == -1)
die(_("cannot access %s: %s"), path, EC_FILE);
/* only reg files allowed. */
@@ -1139,25 +1154,28 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
else
daemon->mxtarget = opt_string_alloc(arg);
break;
#ifdef HAVE_DHCP
case 'l': /* --dhcp-leasefile */
daemon->lease_file = opt_string_alloc(arg);
break;
case '6': /* --dhcp-script */
#ifdef NO_FORK
# ifdef NO_FORK
problem = _("cannot run scripts under uClinux");
#else
# else
daemon->lease_change_command = opt_string_alloc(arg);
#endif
# endif
break;
#endif
case 'H': /* --addn-hosts */
{
struct hostsfile *new = opt_malloc(sizeof(struct hostsfile));
static int hosts_index = 1;
new->fname = opt_string_alloc(arg);
new->index = hosts_index++;
new->flags = 0;
new->next = daemon->addn_hosts;
daemon->addn_hosts = new;
break;
@@ -1219,9 +1237,11 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
daemon->group_set = 1;
break;
#ifdef HAVE_DHCP
case LOPT_SCRIPTUSR: /* --scriptuser */
daemon->scriptuser = opt_string_alloc(arg);
break;
#endif
case 'i': /* --interface */
do {
@@ -1520,11 +1540,14 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
break;
}
#ifdef HAVE_DHCP
case 'X': /* --dhcp-lease-max */
if (!atoi_check(arg, &daemon->dhcp_max))
option = '?';
break;
#endif
#ifdef HAVE_TFTP
case LOPT_TFTP_MAX: /* --tftp-max */
if (!atoi_check(arg, &daemon->tftp_max))
option = '?';
@@ -1548,8 +1571,8 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
}
break;
#endif
#ifdef HAVE_BSD_BRIDGE
case LOPT_BRIDGE: /* --bridge-interface */
{
struct dhcp_bridge *new = opt_malloc(sizeof(struct dhcp_bridge));
@@ -1578,8 +1601,8 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
break;
}
#endif
#ifdef HAVE_DHCP
case 'F': /* --dhcp-range */
{
int k, leasepos = 2;
@@ -1646,6 +1669,11 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
new->end = new->start;
new->flags |= CONTEXT_STATIC;
}
else if (strcmp(a[1], "proxy") == 0)
{
new->end = new->start;
new->flags |= CONTEXT_PROXY;
}
else if ((new->end.s_addr = inet_addr(a[1])) == (in_addr_t)-1)
option = '?';
@@ -1916,7 +1944,122 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
break;
}
case LOPT_PXE_PROMT: /* --pxe-prompt */
{
struct dhcp_opt *new = opt_malloc(sizeof(struct dhcp_opt));
int timeout;
new->netid = NULL;
new->opt = 10; /* PXE_MENU_PROMPT */
while (arg && strstr(arg, "net:") == arg)
{
struct dhcp_netid *nn = opt_malloc(sizeof (struct dhcp_netid));
comma = split(arg);
nn->next = new->netid;
new->netid = nn;
nn->net = opt_string_alloc(arg+4);
arg = comma;
}
if (!arg)
option = '?';
else
{
comma = split(arg);
unhide_metas(arg);
new->len = strlen(arg) + 1;
new->val = opt_malloc(new->len);
memcpy(new->val + 1, arg, new->len - 1);
new->u.vendor_class = (unsigned char *)"PXEClient";
new->flags = DHOPT_VENDOR;
if (comma && atoi_check(comma, &timeout))
*(new->val) = timeout;
else
*(new->val) = 255;
new->next = daemon->dhcp_opts;
daemon->dhcp_opts = new;
}
break;
}
case LOPT_PXE_SERV: /* --pxe-service */
{
struct pxe_service *new = opt_malloc(sizeof(struct pxe_service));
char *CSA[] = { "x86PC", "PC98", "IA64_EFI", "Alpha", "Arc_x86", "Intel_Lean_Client",
"IA32_EFI", "BC_EFI", "Xscale_EFI", "x86-64_EFI", NULL };
static int boottype = 32768;
new->netid = NULL;
new->server.s_addr = 0;
while (arg && strstr(arg, "net:") == arg)
{
struct dhcp_netid *nn = opt_malloc(sizeof (struct dhcp_netid));
comma = split(arg);
nn->next = new->netid;
new->netid = nn;
nn->net = opt_string_alloc(arg+4);
arg = comma;
}
if (arg && (comma = split(arg)))
{
for (i = 0; CSA[i]; i++)
if (strcasecmp(CSA[i], arg) == 0)
break;
if (CSA[i] || atoi_check(arg, &i))
{
arg = comma;
comma = split(arg);
new->CSA = i;
new->menu = opt_string_alloc(arg);
if (comma)
{
arg = comma;
comma = split(arg);
if (atoi_check(arg, &i))
{
new->type = i;
new->basename = NULL;
}
else
{
new->type = boottype++;
new->basename = opt_string_alloc(arg);
}
if (comma && (new->server.s_addr = inet_addr(comma)) == (in_addr_t)-1)
option = '?';
/* Order matters */
new->next = NULL;
if (!daemon->pxe_services)
daemon->pxe_services = new;
else
{
struct pxe_service *s;
for (s = daemon->pxe_services; s->next; s = s->next);
s->next = new;
}
break;
}
}
}
option = '?';
break;
}
case '4': /* --dhcp-mac */
{
if (!(comma = split(arg)))
@@ -2058,6 +2201,7 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
new->list = list;
break;
}
#endif
case 'V': /* --alias */
{
@@ -2311,6 +2455,10 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
new->weight = weight;
break;
}
default:
return _("unsupported option (check that dnsmasq was compiled with DHCP/TFTP/DBus support)");
}
if (problem)
@@ -2328,10 +2476,32 @@ static void one_file(char *file, int nest, int hard_opt)
int i, option;
FILE *f;
char *p, *arg, *start, *buff = daemon->namebuff;
static struct fileread {
dev_t dev;
ino_t ino;
struct fileread *next;
} *filesread = NULL;
struct stat statbuf;
/* ignore repeated files. */
if (hard_opt == 0 && stat(file, &statbuf) == 0)
{
struct fileread *r;
for (r = filesread; r; r = r->next)
if (r->dev == statbuf.st_dev && r->ino == statbuf.st_ino)
return;
r = safe_malloc(sizeof(struct fileread));
r->next = filesread;
filesread = r;
r->dev = statbuf.st_dev;
r->ino = statbuf.st_ino;
}
if (nest > 20)
die(_("files nested too deep in %s"), file, EC_BADCONF);
if (!(f = fopen(file, "r")))
{
if (errno == ENOENT && nest == 0)
@@ -2476,6 +2646,7 @@ static void one_file(char *file, int nest, int hard_opt)
fclose(f);
}
#ifdef HAVE_DHCP
void reread_dhcp(void)
{
if (daemon->dhcp_hosts_file)
@@ -2546,11 +2717,12 @@ void reread_dhcp(void)
my_syslog(LOG_INFO, _("read %s"), daemon->dhcp_opts_file);
}
}
#endif
void read_opts(int argc, char **argv, char *compile_opts)
{
char *buff = opt_malloc(MAXDNAME);
int option, nest = 0;
int option, nest = 0, testmode = 0;
char *errmess, *arg, *conffile = CONFFILE;
opterr = 0;
@@ -2600,12 +2772,16 @@ void read_opts(int argc, char **argv, char *compile_opts)
arg = NULL;
/* command-line only stuff */
if (option == 'w')
if (option == LOPT_TEST)
testmode = 1;
else if (option == 'w')
{
if (argc == 3 && strcmp(argv[2], "dhcp") == 0)
display_opts();
else
if (argc != 3 || strcmp(argv[2], "dhcp") != 0)
do_usage();
#ifdef HAVE_DHCP
else
display_opts();
#endif
exit(0);
}
else if (option == 'v')
@@ -2752,4 +2928,10 @@ void read_opts(int argc, char **argv, char *compile_opts)
}
else if (daemon->options & OPT_DHCP_FQDN)
die(_("there must be a default domain when --dhcp-fqdn is set"), NULL, EC_BADCONF);
if (testmode)
{
fprintf(stderr, "dnsmasq: %s.\n", _("syntax check OK"));
exit(0);
}
}

View File

@@ -1290,7 +1290,7 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
if (!dryrun)
{
log_query(crecp->flags & ~F_FORWARD, cache_get_name(crecp), &addr,
record_source(daemon->addn_hosts, crecp->uid));
record_source(crecp->uid));
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
crec_ttl(crecp, now), NULL,
@@ -1400,7 +1400,7 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
{
if (!dryrun)
{
log_query(crecp->flags, name, NULL, record_source(daemon->addn_hosts, crecp->uid));
log_query(crecp->flags, name, NULL, record_source(crecp->uid));
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
crec_ttl(crecp, now), &nameoffset,
T_CNAME, C_IN, "d", cache_get_name(crecp->addr.cname.cache)))
@@ -1436,7 +1436,7 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
if (!dryrun)
{
log_query(crecp->flags & ~F_REVERSE, name, &crecp->addr.addr,
record_source(daemon->addn_hosts, crecp->uid));
record_source(crecp->uid));
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
crec_ttl(crecp, now), NULL, type, C_IN,

File diff suppressed because it is too large Load Diff

View File

@@ -45,9 +45,7 @@ void tftp_request(struct listener *listen, time_t now)
char *filename, *mode, *p, *end, *opt;
struct sockaddr_in addr, peer;
struct msghdr msg;
struct cmsghdr *cmptr;
struct iovec iov;
struct ifreq ifr;
int is_err = 1, if_index = 0;
struct iname *tmp;
struct tftp_transfer *transfer;
@@ -62,7 +60,7 @@ void tftp_request(struct listener *listen, time_t now)
char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
#elif defined(HAVE_SOLARIS_NETWORK)
char control[CMSG_SPACE(sizeof(unsigned int))];
#else
#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
char control[CMSG_SPACE(sizeof(struct sockaddr_dl))];
#endif
} control_u;
@@ -88,6 +86,9 @@ void tftp_request(struct listener *listen, time_t now)
addr = listen->iface->addr.in;
else
{
char name[IF_NAMESIZE];
struct cmsghdr *cmptr;
addr.sin_addr.s_addr = 0;
#if defined(HAVE_LINUX_NETWORK)
@@ -97,36 +98,32 @@ void tftp_request(struct listener *listen, time_t now)
addr.sin_addr = ((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_spec_dst;
if_index = ((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_ifindex;
}
if (!(ifr.ifr_ifindex = if_index) ||
ioctl(listen->tftpfd, SIOCGIFNAME, &ifr) == -1)
return;
#elif defined(HAVE_SOLARIS_NETWORK)
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVDSTADDR)
addr.sin_addr = *((struct in_addr *)CMSG_DATA(cmptr));
else if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
if_index = *((unsigned int *)CMSG_DATA(cmptr));
#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVDSTADDR)
addr.sin_addr = *((struct in_addr *)CMSG_DATA(cmptr));
else if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
#ifdef HAVE_SOLARIS_NETWORK
if_index = *((unsigned int *)CMSG_DATA(cmptr));
#else
if_index = ((struct sockaddr_dl *)CMSG_DATA(cmptr))->sdl_index;
if_index = ((struct sockaddr_dl *)CMSG_DATA(cmptr))->sdl_index;
#endif
if (if_index == 0 || !if_indextoname(if_index, ifr.ifr_name))
return;
#endif
if (addr.sin_addr.s_addr == 0)
return;
if (!iface_check(AF_INET, (struct all_addr *)&addr.sin_addr,
&ifr, &if_index))
if (!indextoname(listen->tftpfd, if_index, name) ||
addr.sin_addr.s_addr == 0 ||
!iface_check(AF_INET, (struct all_addr *)&addr.sin_addr, name, &if_index))
return;
/* allowed interfaces are the same as for DHCP */
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0))
if (tmp->name && (strcmp(tmp->name, name) == 0))
return;
}
@@ -172,7 +169,7 @@ void tftp_request(struct listener *listen, time_t now)
addr.sin_port = htons(port);
continue;
}
my_syslog(LOG_ERR, _("unable to get free port for TFTP"));
my_syslog(MS_TFTP | LOG_ERR, _("unable to get free port for TFTP"));
}
free_transfer(transfer);
return;
@@ -268,7 +265,7 @@ void tftp_request(struct listener *listen, time_t now)
free_transfer(transfer);
else
{
my_syslog(LOG_INFO, _("TFTP sent %s to %s"), daemon->namebuff, inet_ntoa(peer.sin_addr));
my_syslog(MS_TFTP | LOG_INFO, _("TFTP sent %s to %s"), daemon->namebuff, inet_ntoa(peer.sin_addr));
transfer->next = daemon->tftp_trans;
daemon->tftp_trans = transfer;
}
@@ -402,7 +399,7 @@ void check_tftp_listeners(fd_set *rset, time_t now)
*(q++) = *r;
*q = 0;
}
my_syslog(LOG_ERR, _("TFTP error %d %s received from %s"),
my_syslog(MS_TFTP | LOG_ERR, _("TFTP error %d %s received from %s"),
(int)ntohs(mess->block), err,
inet_ntoa(transfer->peer.sin_addr));
@@ -433,7 +430,7 @@ void check_tftp_listeners(fd_set *rset, time_t now)
/* don't complain about timeout when we're awaiting the last
ACK, some clients never send it */
if (len != 0)
my_syslog(LOG_ERR, _("TFTP failed sending %s to %s"),
my_syslog(MS_TFTP | LOG_ERR, _("TFTP failed sending %s to %s"),
transfer->file->filename, inet_ntoa(transfer->peer.sin_addr));
len = 0;
}
@@ -493,7 +490,7 @@ static ssize_t tftp_err(int err, char *packet, char *message, char *file)
mess->err = htons(err);
ret += (snprintf(mess->message, 500, message, file, errstr) + 1);
if (err != ERR_FNF)
my_syslog(LOG_ERR, "TFTP %s", mess->message);
my_syslog(MS_TFTP | LOG_ERR, "TFTP %s", mess->message);
return ret;
}

View File

@@ -15,7 +15,7 @@
*/
/* The SURF random number generator was taken from djbdns-1.05, by
Daniel J Berstein, which is public domain. */
Daniel J Bernstein, which is public domain. */
#include "dnsmasq.h"
@@ -344,14 +344,19 @@ int parse_hex(char *in, unsigned char *out, int maxlen,
return i;
}
/* return 0 for no match, or (no matched octets) + 1 */
int memcmp_masked(unsigned char *a, unsigned char *b, int len, unsigned int mask)
{
int i;
for (i = len - 1; i >= 0; i--, mask = mask >> 1)
if (!(mask & 1) && a[i] != b[i])
return 0;
return 1;
int i, count;
for (count = 1, i = len - 1; i >= 0; i--, mask = mask >> 1)
if (!(mask & 1))
{
if (a[i] == b[i])
count++;
else
return 0;
}
return count;
}
/* _note_ may copy buffer */