mirror of
https://github.com/pi-hole/dnsmasq.git
synced 2025-12-19 10:18:25 +00:00
import of dnsmasq-2.56.tar.gz
This commit is contained in:
129
src/bpf.c
129
src/bpf.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2010 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2011 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
|
||||
@@ -28,7 +28,64 @@ static struct iovec ifreq = {
|
||||
.iov_len = 0
|
||||
};
|
||||
|
||||
int iface_enumerate(void *parm, int (*ipv4_callback)(), int (*ipv6_callback)())
|
||||
#if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__)
|
||||
|
||||
#include <sys/sysctl.h>
|
||||
#include <net/route.h>
|
||||
#include <net/if_dl.h>
|
||||
#include <netinet/if_ether.h>
|
||||
|
||||
int arp_enumerate(void *parm, int (*callback)())
|
||||
{
|
||||
int mib[6];
|
||||
size_t needed;
|
||||
char *next;
|
||||
struct rt_msghdr *rtm;
|
||||
struct sockaddr_inarp *sin2;
|
||||
struct sockaddr_dl *sdl;
|
||||
int rc;
|
||||
|
||||
mib[0] = CTL_NET;
|
||||
mib[1] = PF_ROUTE;
|
||||
mib[2] = 0;
|
||||
mib[3] = AF_INET;
|
||||
mib[4] = NET_RT_FLAGS;
|
||||
#ifdef RTF_LLINFO
|
||||
mib[5] = RTF_LLINFO;
|
||||
#else
|
||||
mib[5] = 0;
|
||||
#endif
|
||||
if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1 || needed == 0)
|
||||
return 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (!expand_buf(&ifconf, needed))
|
||||
return 0;
|
||||
if ((rc = sysctl(mib, 6, ifconf.iov_base, &needed, NULL, 0)) == 0 ||
|
||||
errno != ENOMEM)
|
||||
break;
|
||||
needed += needed / 8;
|
||||
}
|
||||
if (rc == -1)
|
||||
return 0;
|
||||
|
||||
for (next = ifconf.iov_base ; next < (char *)ifconf.iov_base + needed; next += rtm->rtm_msglen)
|
||||
{
|
||||
rtm = (struct rt_msghdr *)next;
|
||||
sin2 = (struct sockaddr_inarp *)(rtm + 1);
|
||||
sdl = (struct sockaddr_dl *)((char *)sin2 + SA_SIZE(sin2));
|
||||
if (!(*callback)(AF_INET, &sin2->sin_addr, LLADDR(sdl), sdl->sdl_alen, parm))
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
int iface_enumerate(int family, void *parm, int (*callback)())
|
||||
{
|
||||
char *ptr;
|
||||
struct ifreq *ifr;
|
||||
@@ -37,6 +94,13 @@ int iface_enumerate(void *parm, int (*ipv4_callback)(), int (*ipv6_callback)())
|
||||
int lastlen = 0;
|
||||
size_t len = 0;
|
||||
|
||||
if (family == AF_UNSPEC)
|
||||
#if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__)
|
||||
return arp_enumerate(parm, callback);
|
||||
#else
|
||||
return 0; /* need code for Solaris and MacOS*/
|
||||
#endif
|
||||
|
||||
if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1)
|
||||
return 0;
|
||||
|
||||
@@ -83,39 +147,42 @@ int iface_enumerate(void *parm, int (*ipv4_callback)(), int (*ipv6_callback)())
|
||||
ifr = (struct ifreq *)ifreq.iov_base;
|
||||
memcpy(ifr, ptr, len);
|
||||
|
||||
if (ifr->ifr_addr.sa_family == AF_INET && ipv4_callback)
|
||||
if (ifr->ifr_addr.sa_family == family)
|
||||
{
|
||||
struct in_addr addr, netmask, broadcast;
|
||||
broadcast.s_addr = 0;
|
||||
addr = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr;
|
||||
if (ioctl(fd, SIOCGIFNETMASK, ifr) == -1)
|
||||
continue;
|
||||
netmask = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr;
|
||||
if (ioctl(fd, SIOCGIFBRDADDR, ifr) != -1)
|
||||
broadcast = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr;
|
||||
if (!((*ipv4_callback)(addr,
|
||||
(int)if_nametoindex(ifr->ifr_name),
|
||||
netmask, broadcast,
|
||||
parm)))
|
||||
goto err;
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
else if (ifr->ifr_addr.sa_family == AF_INET6 && ipv6_callback)
|
||||
{
|
||||
struct in6_addr *addr = &((struct sockaddr_in6 *)&ifr->ifr_addr)->sin6_addr;
|
||||
/* voodoo to clear interface field in address */
|
||||
if (!(daemon->options & OPT_NOWILD) && IN6_IS_ADDR_LINKLOCAL(addr))
|
||||
if (family == AF_INET)
|
||||
{
|
||||
addr->s6_addr[2] = 0;
|
||||
addr->s6_addr[3] = 0;
|
||||
struct in_addr addr, netmask, broadcast;
|
||||
broadcast.s_addr = 0;
|
||||
addr = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr;
|
||||
if (ioctl(fd, SIOCGIFNETMASK, ifr) == -1)
|
||||
continue;
|
||||
netmask = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr;
|
||||
if (ioctl(fd, SIOCGIFBRDADDR, ifr) != -1)
|
||||
broadcast = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr;
|
||||
if (!((*callback)(addr,
|
||||
(int)if_nametoindex(ifr->ifr_name),
|
||||
netmask, broadcast,
|
||||
parm)))
|
||||
goto err;
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
else if (family == AF_INET6)
|
||||
{
|
||||
struct in6_addr *addr = &((struct sockaddr_in6 *)&ifr->ifr_addr)->sin6_addr;
|
||||
/* voodoo to clear interface field in address */
|
||||
if (!option_bool(OPT_NOWILD) && IN6_IS_ADDR_LINKLOCAL(addr))
|
||||
{
|
||||
addr->s6_addr[2] = 0;
|
||||
addr->s6_addr[3] = 0;
|
||||
}
|
||||
if (!((*callback)(addr,
|
||||
(int)((struct sockaddr_in6 *)&ifr->ifr_addr)->sin6_scope_id,
|
||||
(int)if_nametoindex(ifr->ifr_name),
|
||||
parm)))
|
||||
goto err;
|
||||
}
|
||||
if (!((*ipv6_callback)(addr,
|
||||
(int)((struct sockaddr_in6 *)&ifr->ifr_addr)->sin6_scope_id,
|
||||
(int)if_nametoindex(ifr->ifr_name),
|
||||
parm)))
|
||||
goto err;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
ret = 1;
|
||||
|
||||
150
src/cache.c
150
src/cache.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2010 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2011 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
|
||||
@@ -75,7 +75,7 @@ void cache_init(void)
|
||||
struct crec *crecp;
|
||||
int i;
|
||||
|
||||
if (daemon->options & OPT_LOG)
|
||||
if (option_bool(OPT_LOG))
|
||||
addrbuff = safe_malloc(ADDRSTRLEN);
|
||||
|
||||
bignames_left = daemon->cachesize/10;
|
||||
@@ -226,7 +226,7 @@ char *cache_get_name(struct crec *crecp)
|
||||
{
|
||||
if (crecp->flags & F_BIGNAME)
|
||||
return crecp->name.bname->name;
|
||||
else if (crecp->flags & (F_DHCP | F_CONFIG))
|
||||
else if (crecp->flags & F_NAMEP)
|
||||
return crecp->name.namep;
|
||||
|
||||
return crecp->name.sname;
|
||||
@@ -366,9 +366,6 @@ struct crec *cache_insert(char *name, struct all_addr *addr,
|
||||
|
||||
log_query(flags | F_UPSTREAM, name, addr, NULL);
|
||||
|
||||
/* CONFIG bit means something else when stored in cache entries */
|
||||
flags &= ~F_CONFIG;
|
||||
|
||||
/* if previous insertion failed give up now. */
|
||||
if (insert_error)
|
||||
return NULL;
|
||||
@@ -503,7 +500,7 @@ struct crec *cache_find_by_name(struct crec *crecp, char *name, time_t now, unsi
|
||||
/* first search, look for relevant entries and push to top of list
|
||||
also free anything which has expired */
|
||||
struct crec *next, **up, **insert = NULL, **chainp = &ans;
|
||||
int ins_flags = 0;
|
||||
unsigned short ins_flags = 0;
|
||||
|
||||
for (up = hash_bucket(name), crecp = *up; crecp; crecp = next)
|
||||
{
|
||||
@@ -695,7 +692,7 @@ static void add_hosts_entry(struct crec *cache, struct all_addr *addr, int addrl
|
||||
if (hostname_isequal(cache->name.sname, a->target) &&
|
||||
(lookup = whine_malloc(sizeof(struct crec))))
|
||||
{
|
||||
lookup->flags = F_FORWARD | F_IMMORTAL | F_CONFIG | F_HOSTS | F_CNAME;
|
||||
lookup->flags = F_FORWARD | F_IMMORTAL | F_NAMEP | F_HOSTS | F_CNAME;
|
||||
lookup->name.namep = a->alias;
|
||||
lookup->addr.cname.cache = cache;
|
||||
lookup->addr.cname.uid = index;
|
||||
@@ -832,7 +829,7 @@ static int read_hostsfile(char *filename, int index, int cache_size)
|
||||
if ((canon = canonicalise(token, &nomem)))
|
||||
{
|
||||
/* If set, add a version of the name with a default domain appended */
|
||||
if ((daemon->options & OPT_EXPAND) && domain_suffix && !fqdn &&
|
||||
if (option_bool(OPT_EXPAND) && domain_suffix && !fqdn &&
|
||||
(cache = whine_malloc(sizeof(struct crec) +
|
||||
strlen(canon)+2+strlen(domain_suffix)-SMALLDNAME)))
|
||||
{
|
||||
@@ -896,107 +893,17 @@ void cache_reload(void)
|
||||
up = &cache->hash_next;
|
||||
}
|
||||
|
||||
if ((daemon->options & OPT_NO_HOSTS) && !daemon->addn_hosts)
|
||||
if (option_bool(OPT_NO_HOSTS) && !daemon->addn_hosts)
|
||||
{
|
||||
if (daemon->cachesize > 0)
|
||||
my_syslog(LOG_INFO, _("cleared cache"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(daemon->options & OPT_NO_HOSTS))
|
||||
if (!option_bool(OPT_NO_HOSTS))
|
||||
total_size = read_hostsfile(HOSTSFILE, 0, total_size);
|
||||
|
||||
for (i = 0, ah = daemon->addn_hosts; ah; ah = ah->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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
daemon->addn_hosts = expand_filelist(daemon->addn_hosts);
|
||||
for (ah = daemon->addn_hosts; ah; ah = ah->next)
|
||||
if (!(ah->flags & AH_INACTIVE))
|
||||
total_size = read_hostsfile(ah->fname, ah->index, total_size);
|
||||
@@ -1036,7 +943,7 @@ void cache_add_dhcp_entry(char *host_name,
|
||||
struct in_addr *host_address, time_t ttd)
|
||||
{
|
||||
struct crec *crec = NULL, *aliasc;
|
||||
unsigned short flags = F_DHCP | F_FORWARD | F_IPV4 | F_REVERSE;
|
||||
unsigned short flags = F_NAMEP | F_DHCP | F_FORWARD | F_IPV4 | F_REVERSE;
|
||||
int in_hosts = 0;
|
||||
struct cname *a;
|
||||
|
||||
@@ -1049,13 +956,13 @@ void cache_add_dhcp_entry(char *host_name,
|
||||
in_hosts = 1;
|
||||
|
||||
if (crec->flags & F_CNAME)
|
||||
my_syslog(LOG_WARNING,
|
||||
my_syslog(MS_DHCP | LOG_WARNING,
|
||||
_("%s is a CNAME, not giving it to the DHCP lease of %s"),
|
||||
host_name, inet_ntoa(*host_address));
|
||||
else if (crec->addr.addr.addr.addr4.s_addr != host_address->s_addr)
|
||||
{
|
||||
strcpy(daemon->namebuff, inet_ntoa(crec->addr.addr.addr.addr4));
|
||||
my_syslog(LOG_WARNING,
|
||||
my_syslog(MS_DHCP | LOG_WARNING,
|
||||
_("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),
|
||||
@@ -1109,7 +1016,7 @@ void cache_add_dhcp_entry(char *host_name,
|
||||
|
||||
if (aliasc)
|
||||
{
|
||||
aliasc->flags = F_FORWARD | F_CONFIG | F_DHCP | F_CNAME;
|
||||
aliasc->flags = F_FORWARD | F_NAMEP | F_DHCP | F_CNAME;
|
||||
if (ttd == 0)
|
||||
aliasc->flags |= F_IMMORTAL;
|
||||
else
|
||||
@@ -1143,12 +1050,15 @@ void dump_cache(time_t now)
|
||||
serv->flags &= ~SERV_COUNTED;
|
||||
|
||||
for (serv = daemon->servers; serv; serv = serv->next)
|
||||
if (!(serv->flags & (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED)))
|
||||
if (!(serv->flags &
|
||||
(SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)))
|
||||
{
|
||||
int port;
|
||||
unsigned int queries = 0, failed_queries = 0;
|
||||
for (serv1 = serv; serv1; serv1 = serv1->next)
|
||||
if (!(serv1->flags & (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED)) && sockaddr_isequal(&serv->addr, &serv1->addr))
|
||||
if (!(serv1->flags &
|
||||
(SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)) &&
|
||||
sockaddr_isequal(&serv->addr, &serv1->addr))
|
||||
{
|
||||
serv1->flags |= SERV_COUNTED;
|
||||
queries += serv1->queries;
|
||||
@@ -1158,11 +1068,11 @@ void dump_cache(time_t now)
|
||||
my_syslog(LOG_INFO, _("server %s#%d: queries sent %u, retried or failed %u"), addrbuff, port, queries, failed_queries);
|
||||
}
|
||||
|
||||
if ((daemon->options & (OPT_DEBUG | OPT_LOG)))
|
||||
if (option_bool(OPT_DEBUG) || option_bool(OPT_LOG))
|
||||
{
|
||||
struct crec *cache ;
|
||||
int i;
|
||||
my_syslog(LOG_DEBUG, "Host Address Flags Expires");
|
||||
my_syslog(LOG_INFO, "Host Address Flags Expires");
|
||||
|
||||
for (i=0; i<hash_size; i++)
|
||||
for (cache = hash_table[i]; cache; cache = cache->hash_next)
|
||||
@@ -1208,7 +1118,7 @@ void dump_cache(time_t now)
|
||||
/* ctime includes trailing \n - eat it */
|
||||
*(p-1) = 0;
|
||||
#endif
|
||||
my_syslog(LOG_DEBUG, daemon->namebuff);
|
||||
my_syslog(LOG_INFO, daemon->namebuff);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1237,12 +1147,12 @@ void querystr(char *str, unsigned short type)
|
||||
sprintf(str,"query[%s]", typestr[i].name);
|
||||
}
|
||||
|
||||
void log_query(unsigned short flags, char *name, struct all_addr *addr, char *arg)
|
||||
void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg)
|
||||
{
|
||||
char *source, *dest = addrbuff;
|
||||
char *verb = "is";
|
||||
|
||||
if (!(daemon->options & OPT_LOG))
|
||||
if (!option_bool(OPT_LOG))
|
||||
return;
|
||||
|
||||
if (addr)
|
||||
@@ -1283,13 +1193,9 @@ void log_query(unsigned short flags, char *name, struct all_addr *addr, char *ar
|
||||
}
|
||||
}
|
||||
else if (flags & F_CNAME)
|
||||
{
|
||||
/* nasty abuse of NXDOMAIN and CNAME flags */
|
||||
if (flags & F_NXDOMAIN)
|
||||
dest = arg;
|
||||
else
|
||||
dest = "<CNAME>";
|
||||
}
|
||||
dest = "<CNAME>";
|
||||
else if (flags & F_RRNAME)
|
||||
dest = arg;
|
||||
|
||||
if (flags & F_CONFIG)
|
||||
source = "config";
|
||||
@@ -1315,6 +1221,6 @@ void log_query(unsigned short flags, char *name, struct all_addr *addr, char *ar
|
||||
if (strlen(name) == 0)
|
||||
name = ".";
|
||||
|
||||
my_syslog(LOG_DEBUG, "%s %s %s %s", source, name, verb, dest);
|
||||
my_syslog(LOG_INFO, "%s %s %s %s", source, name, verb, dest);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2010 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2011 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
|
||||
@@ -14,7 +14,7 @@
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define VERSION "2.55"
|
||||
#define VERSION "2.56"
|
||||
|
||||
#define FTABSIZ 150 /* max number of outstanding requests (default) */
|
||||
#define MAX_PROCS 20 /* max no children for TCP requests */
|
||||
@@ -22,7 +22,7 @@
|
||||
#define EDNS_PKTSZ 4096 /* default max EDNS.0 UDP packet from RFC5625 */
|
||||
#define TIMEOUT 10 /* drop UDP queries after TIMEOUT seconds */
|
||||
#define FORWARD_TEST 50 /* try all servers every 50 queries */
|
||||
#define FORWARD_TIME 20 /* or 10 seconds */
|
||||
#define FORWARD_TIME 20 /* or 20 seconds */
|
||||
#define RANDOM_SOCKS 64 /* max simultaneous random ports */
|
||||
#define LEASE_RETRY 60 /* on error, retry writing leasefile after LEASE_RETRY seconds */
|
||||
#define CACHESIZ 150 /* default cache size */
|
||||
@@ -72,6 +72,7 @@
|
||||
#define LOG_MAX 5 /* log-queue length */
|
||||
#define RANDFILE "/dev/urandom"
|
||||
#define DAD_WAIT 20 /* retry binding IPv6 sockets for this long */
|
||||
#define EDNS0_OPTION_MAC 5 /* dyndns.org temporary assignment */
|
||||
|
||||
/* DBUS interface specifics */
|
||||
#define DNSMASQ_SERVICE "uk.org.thekelleys.dnsmasq"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2010 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2011 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
|
||||
|
||||
10
src/dhcp.c
10
src/dhcp.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2010 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2011 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
|
||||
@@ -54,7 +54,7 @@ static int make_fd(int port)
|
||||
/* 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. */
|
||||
if (daemon->options & OPT_NOWILD)
|
||||
if (option_bool(OPT_NOWILD))
|
||||
{
|
||||
#ifdef SO_REUSEPORT
|
||||
int rc = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &oneopt, sizeof(oneopt));
|
||||
@@ -96,7 +96,7 @@ void dhcp_init(void)
|
||||
we drop root. Also, set buffer size small, to avoid wasting
|
||||
kernel buffers */
|
||||
|
||||
if (daemon->options & OPT_NO_PING)
|
||||
if (option_bool(OPT_NO_PING))
|
||||
daemon->dhcp_icmp_fd = -1;
|
||||
else if ((daemon->dhcp_icmp_fd = make_icmp_sock()) == -1 ||
|
||||
setsockopt(daemon->dhcp_icmp_fd, SOL_SOCKET, SO_RCVBUF, &oneopt, sizeof(oneopt)) == -1 )
|
||||
@@ -295,7 +295,7 @@ void dhcp_packet(time_t now, int pxe_fd)
|
||||
}
|
||||
}
|
||||
|
||||
if (!iface_enumerate(&parm, complete_context, NULL))
|
||||
if (!iface_enumerate(AF_INET, &parm, complete_context))
|
||||
return;
|
||||
lease_prune(NULL, now); /* lose any expired leases */
|
||||
iov.iov_len = dhcp_reply(parm.current, ifr.ifr_name, iface_index, (size_t)sz,
|
||||
@@ -660,7 +660,7 @@ int address_allocate(struct dhcp_context *context,
|
||||
|
||||
*addrp = addr;
|
||||
|
||||
if (daemon->options & OPT_NO_PING)
|
||||
if (option_bool(OPT_NO_PING))
|
||||
return 1;
|
||||
|
||||
/* check if we failed to ping addr sometime in the last
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2010 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2011 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
|
||||
@@ -133,10 +133,10 @@ int main (int argc, char **argv)
|
||||
#elif !(defined(IP_RECVDSTADDR) && \
|
||||
defined(IP_RECVIF) && \
|
||||
defined(IP_SENDSRCADDR))
|
||||
if (!(daemon->options & OPT_NOWILD))
|
||||
if (!option_bool(OPT_NOWILD))
|
||||
{
|
||||
bind_fallback = 1;
|
||||
daemon->options |= OPT_NOWILD;
|
||||
set_option_bool(OPT_NOWILD);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -168,7 +168,7 @@ int main (int argc, char **argv)
|
||||
if (!enumerate_interfaces())
|
||||
die(_("failed to find list of interfaces: %s"), NULL, EC_MISC);
|
||||
|
||||
if (daemon->options & OPT_NOWILD)
|
||||
if (option_bool(OPT_NOWILD))
|
||||
{
|
||||
daemon->listeners = create_bound_listeners();
|
||||
|
||||
@@ -183,14 +183,13 @@ int main (int argc, char **argv)
|
||||
die(_("no interface with address %s"), daemon->namebuff, EC_BADNET);
|
||||
}
|
||||
}
|
||||
else if ((daemon->port != 0 || daemon->tftp_interfaces || daemon->tftp_unlimited) &&
|
||||
!(daemon->listeners = create_wildcard_listeners()))
|
||||
die(_("failed to create listening socket: %s"), NULL, EC_BADNET);
|
||||
else
|
||||
daemon->listeners = create_wildcard_listeners();
|
||||
|
||||
if (daemon->port != 0)
|
||||
cache_init();
|
||||
|
||||
if (daemon->options & OPT_DBUS)
|
||||
if (option_bool(OPT_DBUS))
|
||||
#ifdef HAVE_DBUS
|
||||
{
|
||||
char *err;
|
||||
@@ -275,7 +274,7 @@ int main (int argc, char **argv)
|
||||
|
||||
err_pipe[1] = -1;
|
||||
|
||||
if (!(daemon->options & OPT_DEBUG))
|
||||
if (!option_bool(OPT_DEBUG))
|
||||
{
|
||||
/* The following code "daemonizes" the process.
|
||||
See Stevens section 12.4 */
|
||||
@@ -284,7 +283,7 @@ int main (int argc, char **argv)
|
||||
die(_("cannot chdir to filesystem root: %s"), NULL, EC_MISC);
|
||||
|
||||
#ifndef NO_FORK
|
||||
if (!(daemon->options & OPT_NO_FORK))
|
||||
if (!option_bool(OPT_NO_FORK))
|
||||
{
|
||||
pid_t pid;
|
||||
|
||||
@@ -345,7 +344,7 @@ int main (int argc, char **argv)
|
||||
|
||||
log_err = log_start(ent_pw, err_pipe[1]);
|
||||
|
||||
if (!(daemon->options & OPT_DEBUG))
|
||||
if (!option_bool(OPT_DEBUG))
|
||||
{
|
||||
/* open stdout etc to /dev/null */
|
||||
int nullfd = open("/dev/null", O_RDWR);
|
||||
@@ -362,7 +361,7 @@ int main (int argc, char **argv)
|
||||
daemon->helperfd = create_helper(pipewrite, err_pipe[1], script_uid, script_gid, max_fd);
|
||||
#endif
|
||||
|
||||
if (!(daemon->options & OPT_DEBUG) && getuid() == 0)
|
||||
if (!option_bool(OPT_DEBUG) && getuid() == 0)
|
||||
{
|
||||
int bad_capabilities = 0;
|
||||
gid_t dummy;
|
||||
@@ -440,7 +439,7 @@ int main (int argc, char **argv)
|
||||
}
|
||||
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
if (daemon->options & OPT_DEBUG)
|
||||
if (option_bool(OPT_DEBUG))
|
||||
prctl(PR_SET_DUMPABLE, 1);
|
||||
#endif
|
||||
|
||||
@@ -454,7 +453,7 @@ int main (int argc, char **argv)
|
||||
my_syslog(LOG_INFO, _("compile time options: %s"), compile_opts);
|
||||
|
||||
#ifdef HAVE_DBUS
|
||||
if (daemon->options & OPT_DBUS)
|
||||
if (option_bool(OPT_DBUS))
|
||||
{
|
||||
if (daemon->dbus)
|
||||
my_syslog(LOG_INFO, _("DBus support enabled: connected to system bus"));
|
||||
@@ -470,12 +469,12 @@ int main (int argc, char **argv)
|
||||
if (bind_fallback)
|
||||
my_syslog(LOG_WARNING, _("setting --bind-interfaces option because of OS limitations"));
|
||||
|
||||
if (!(daemon->options & OPT_NOWILD))
|
||||
if (!option_bool(OPT_NOWILD))
|
||||
for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
|
||||
if (if_tmp->name && !if_tmp->used)
|
||||
my_syslog(LOG_WARNING, _("warning: interface %s does not currently exist"), if_tmp->name);
|
||||
|
||||
if (daemon->port != 0 && (daemon->options & OPT_NO_RESOLV))
|
||||
if (daemon->port != 0 && option_bool(OPT_NO_RESOLV))
|
||||
{
|
||||
if (daemon->resolv_files && !daemon->resolv_files->is_default)
|
||||
my_syslog(LOG_WARNING, _("warning: ignoring resolv-file flag because no-resolv is set"));
|
||||
@@ -518,7 +517,7 @@ int main (int argc, char **argv)
|
||||
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") : "");
|
||||
option_bool(OPT_TFTP_SECURE) ? _("secure mode") : "");
|
||||
|
||||
/* This is a guess, it assumes that for small limits,
|
||||
disjoint files might be served, but for large limits,
|
||||
@@ -580,7 +579,7 @@ int main (int argc, char **argv)
|
||||
|
||||
/* Whilst polling for the dbus, or doing a tftp transfer, wake every quarter second */
|
||||
if (daemon->tftp_trans ||
|
||||
((daemon->options & OPT_DBUS) && !daemon->dbus))
|
||||
(option_bool(OPT_DBUS) && !daemon->dbus))
|
||||
{
|
||||
t.tv_sec = 0;
|
||||
t.tv_usec = 250000;
|
||||
@@ -664,7 +663,7 @@ int main (int argc, char **argv)
|
||||
|
||||
#ifdef HAVE_DBUS
|
||||
/* if we didn't create a DBus connection, retry now. */
|
||||
if ((daemon->options & OPT_DBUS) && !daemon->dbus)
|
||||
if (option_bool(OPT_DBUS) && !daemon->dbus)
|
||||
{
|
||||
char *err;
|
||||
if ((err = dbus_init()))
|
||||
@@ -801,7 +800,7 @@ static void async_event(int pipe, time_t now)
|
||||
{
|
||||
case EVENT_RELOAD:
|
||||
clear_cache_and_reload(now);
|
||||
if (daemon->port != 0 && daemon->resolv_files && (daemon->options & OPT_NO_POLL))
|
||||
if (daemon->port != 0 && daemon->resolv_files && option_bool(OPT_NO_POLL))
|
||||
{
|
||||
reload_servers(daemon->resolv_files->name);
|
||||
check_servers();
|
||||
@@ -908,7 +907,7 @@ void poll_resolv(int force, int do_reload, time_t now)
|
||||
Go through and find the one which changed _last_.
|
||||
Warn of any which can't be read. */
|
||||
|
||||
if (daemon->port == 0 || (daemon->options & OPT_NO_POLL))
|
||||
if (daemon->port == 0 || option_bool(OPT_NO_POLL))
|
||||
return;
|
||||
|
||||
for (latest = NULL, res = daemon->resolv_files; res; res = res->next)
|
||||
@@ -954,7 +953,7 @@ void poll_resolv(int force, int do_reload, time_t now)
|
||||
my_syslog(LOG_INFO, _("reading %s"), latest->name);
|
||||
warned = 0;
|
||||
check_servers();
|
||||
if ((daemon->options & OPT_RELOAD) && do_reload)
|
||||
if (option_bool(OPT_RELOAD) && do_reload)
|
||||
clear_cache_and_reload(now);
|
||||
}
|
||||
else
|
||||
@@ -977,7 +976,7 @@ void clear_cache_and_reload(time_t now)
|
||||
#ifdef HAVE_DHCP
|
||||
if (daemon->dhcp)
|
||||
{
|
||||
if (daemon->options & OPT_ETHERS)
|
||||
if (option_bool(OPT_ETHERS))
|
||||
dhcp_read_ethers();
|
||||
reread_dhcp();
|
||||
dhcp_update_configs(daemon->dhcp_conf);
|
||||
@@ -1094,7 +1093,7 @@ static void check_dns_listeners(fd_set *set, time_t now)
|
||||
if (confd == -1)
|
||||
continue;
|
||||
|
||||
if (daemon->options & OPT_NOWILD)
|
||||
if (option_bool(OPT_NOWILD))
|
||||
iface = listener->iface;
|
||||
else
|
||||
{
|
||||
@@ -1120,7 +1119,7 @@ static void check_dns_listeners(fd_set *set, time_t now)
|
||||
close(confd);
|
||||
}
|
||||
#ifndef NO_FORK
|
||||
else if (!(daemon->options & OPT_DEBUG) && (p = fork()) != 0)
|
||||
else if (!option_bool(OPT_DEBUG) && (p = fork()) != 0)
|
||||
{
|
||||
if (p != -1)
|
||||
{
|
||||
@@ -1147,7 +1146,7 @@ static void check_dns_listeners(fd_set *set, time_t now)
|
||||
#ifndef NO_FORK
|
||||
/* Arrange for SIGALARM after CHILD_LIFETIME seconds to
|
||||
terminate the process. */
|
||||
if (!(daemon->options & OPT_DEBUG))
|
||||
if (!option_bool(OPT_DEBUG))
|
||||
alarm(CHILD_LIFETIME);
|
||||
#endif
|
||||
|
||||
@@ -1179,7 +1178,7 @@ static void check_dns_listeners(fd_set *set, time_t now)
|
||||
close(s->tcpfd);
|
||||
}
|
||||
#ifndef NO_FORK
|
||||
if (!(daemon->options & OPT_DEBUG))
|
||||
if (!option_bool(OPT_DEBUG))
|
||||
{
|
||||
flush_log();
|
||||
_exit(0);
|
||||
|
||||
141
src/dnsmasq.h
141
src/dnsmasq.h
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2010 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2011 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
|
||||
@@ -14,7 +14,7 @@
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define COPYRIGHT "Copyright (c) 2000-2010 Simon Kelley"
|
||||
#define COPYRIGHT "Copyright (c) 2000-2011 Simon Kelley"
|
||||
|
||||
#ifndef NO_LARGEFILE
|
||||
/* Ensure we can use files >2GB (log files may grow this big) */
|
||||
@@ -163,38 +163,44 @@ struct event_desc {
|
||||
*/
|
||||
#define DNSMASQ_PACKETSZ PACKETSZ+MAXDNAME+RRFIXEDSZ
|
||||
|
||||
#define OPT_BOGUSPRIV (1u<<0)
|
||||
#define OPT_FILTER (1u<<1)
|
||||
#define OPT_LOG (1u<<2)
|
||||
#define OPT_SELFMX (1u<<3)
|
||||
#define OPT_NO_HOSTS (1u<<4)
|
||||
#define OPT_NO_POLL (1u<<5)
|
||||
#define OPT_DEBUG (1u<<6)
|
||||
#define OPT_ORDER (1u<<7)
|
||||
#define OPT_NO_RESOLV (1u<<8)
|
||||
#define OPT_EXPAND (1u<<9)
|
||||
#define OPT_LOCALMX (1u<<10)
|
||||
#define OPT_NO_NEG (1u<<11)
|
||||
#define OPT_NODOTS_LOCAL (1u<<12)
|
||||
#define OPT_NOWILD (1u<<13)
|
||||
#define OPT_ETHERS (1u<<14)
|
||||
#define OPT_RESOLV_DOMAIN (1u<<15)
|
||||
#define OPT_NO_FORK (1u<<16)
|
||||
#define OPT_AUTHORITATIVE (1u<<17)
|
||||
#define OPT_LOCALISE (1u<<18)
|
||||
#define OPT_DBUS (1u<<19)
|
||||
#define OPT_DHCP_FQDN (1u<<20)
|
||||
#define OPT_NO_PING (1u<<21)
|
||||
#define OPT_LEASE_RO (1u<<22)
|
||||
#define OPT_ALL_SERVERS (1u<<23)
|
||||
#define OPT_RELOAD (1u<<24)
|
||||
#define OPT_LOCAL_REBIND (1u<<25)
|
||||
#define OPT_TFTP_SECURE (1u<<26)
|
||||
#define OPT_TFTP_NOBLOCK (1u<<27)
|
||||
#define OPT_LOG_OPTS (1u<<28)
|
||||
#define OPT_TFTP_APREF (1u<<29)
|
||||
#define OPT_NO_OVERRIDE (1u<<30)
|
||||
#define OPT_NO_REBIND (1u<<31)
|
||||
/* Trust the compiler dead-code elimator.... */
|
||||
#define option_bool(x) (((x) < 32) ? daemon->options & (1u << (x)) : daemon->options2 & (1u << ((x) - 32)))
|
||||
|
||||
#define OPT_BOGUSPRIV 0
|
||||
#define OPT_FILTER 1
|
||||
#define OPT_LOG 2
|
||||
#define OPT_SELFMX 3
|
||||
#define OPT_NO_HOSTS 4
|
||||
#define OPT_NO_POLL 5
|
||||
#define OPT_DEBUG 6
|
||||
#define OPT_ORDER 7
|
||||
#define OPT_NO_RESOLV 8
|
||||
#define OPT_EXPAND 9
|
||||
#define OPT_LOCALMX 10
|
||||
#define OPT_NO_NEG 11
|
||||
#define OPT_NODOTS_LOCAL 12
|
||||
#define OPT_NOWILD 13
|
||||
#define OPT_ETHERS 14
|
||||
#define OPT_RESOLV_DOMAIN 15
|
||||
#define OPT_NO_FORK 16
|
||||
#define OPT_AUTHORITATIVE 17
|
||||
#define OPT_LOCALISE 18
|
||||
#define OPT_DBUS 19
|
||||
#define OPT_DHCP_FQDN 20
|
||||
#define OPT_NO_PING 21
|
||||
#define OPT_LEASE_RO 22
|
||||
#define OPT_ALL_SERVERS 23
|
||||
#define OPT_RELOAD 24
|
||||
#define OPT_LOCAL_REBIND 25
|
||||
#define OPT_TFTP_SECURE 26
|
||||
#define OPT_TFTP_NOBLOCK 27
|
||||
#define OPT_LOG_OPTS 28
|
||||
#define OPT_TFTP_APREF 29
|
||||
#define OPT_NO_OVERRIDE 30
|
||||
#define OPT_NO_REBIND 31
|
||||
#define OPT_ADD_MAC 32
|
||||
#define OPT_DNSSEC 33
|
||||
#define OPT_LAST 34
|
||||
|
||||
/* 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. */
|
||||
@@ -235,7 +241,8 @@ struct naptr {
|
||||
};
|
||||
|
||||
struct txt_record {
|
||||
char *name, *txt;
|
||||
char *name;
|
||||
unsigned char *txt;
|
||||
unsigned short class, len;
|
||||
struct txt_record *next;
|
||||
};
|
||||
@@ -280,22 +287,28 @@ struct crec {
|
||||
} name;
|
||||
};
|
||||
|
||||
#define F_IMMORTAL 1
|
||||
#define F_CONFIG 2
|
||||
#define F_REVERSE 4
|
||||
#define F_FORWARD 8
|
||||
#define F_DHCP 16
|
||||
#define F_NEG 32
|
||||
#define F_HOSTS 64
|
||||
#define F_IPV4 128
|
||||
#define F_IPV6 256
|
||||
#define F_BIGNAME 512
|
||||
#define F_UPSTREAM 1024
|
||||
#define F_SERVER 2048
|
||||
#define F_NXDOMAIN 4096
|
||||
#define F_QUERY 8192
|
||||
#define F_CNAME 16384
|
||||
#define F_NOERR 32768
|
||||
#define F_IMMORTAL (1u<<0)
|
||||
#define F_NAMEP (1u<<1)
|
||||
#define F_REVERSE (1u<<2)
|
||||
#define F_FORWARD (1u<<3)
|
||||
#define F_DHCP (1u<<4)
|
||||
#define F_NEG (1u<<5)
|
||||
#define F_HOSTS (1u<<6)
|
||||
#define F_IPV4 (1u<<7)
|
||||
#define F_IPV6 (1u<<8)
|
||||
#define F_BIGNAME (1u<<9)
|
||||
#define F_NXDOMAIN (1u<<10)
|
||||
#define F_CNAME (1u<<11)
|
||||
#define F_NOERR (1u<<12)
|
||||
#define F_CONFIG (1u<<13)
|
||||
/* below here are only valid as args to log_query: cache
|
||||
entries are limited to 16 bits */
|
||||
#define F_UPSTREAM (1u<<16)
|
||||
#define F_RRNAME (1u<<17)
|
||||
#define F_SERVER (1u<<18)
|
||||
#define F_QUERY (1u<<19)
|
||||
#define F_NSRR (1u<<20)
|
||||
|
||||
|
||||
/* struct sockaddr is not large enough to hold any address,
|
||||
and specifically not big enough to hold an IPv6 address.
|
||||
@@ -374,7 +387,7 @@ struct resolvc {
|
||||
char *name;
|
||||
};
|
||||
|
||||
/* adn-hosts parms from command-line */
|
||||
/* adn-hosts parms from command-line (also dhcp-hostsfile and dhcp-optsfile */
|
||||
#define AH_DIR 1
|
||||
#define AH_INACTIVE 2
|
||||
struct hostsfile {
|
||||
@@ -384,6 +397,9 @@ struct hostsfile {
|
||||
int index; /* matches to cache entries for logging */
|
||||
};
|
||||
|
||||
#define FREC_NOREBIND 1
|
||||
#define FREC_CHECKING_DISABLED 2
|
||||
|
||||
struct frec {
|
||||
union mysockaddr source;
|
||||
struct all_addr dest;
|
||||
@@ -394,7 +410,7 @@ struct frec {
|
||||
#endif
|
||||
unsigned int iface;
|
||||
unsigned short orig_id, new_id;
|
||||
int fd, forwardall, norebind;
|
||||
int fd, forwardall, flags;
|
||||
unsigned int crc;
|
||||
time_t time;
|
||||
struct frec *next;
|
||||
@@ -601,7 +617,7 @@ struct tftp_transfer {
|
||||
int backoff;
|
||||
unsigned int block, blocksize, expansion;
|
||||
off_t offset;
|
||||
struct sockaddr_in peer;
|
||||
union mysockaddr peer;
|
||||
char opt_blocksize, opt_transize, netascii, carrylf;
|
||||
struct tftp_file *file;
|
||||
struct tftp_transfer *next;
|
||||
@@ -629,7 +645,7 @@ extern struct daemon {
|
||||
config file arguments. All set (including defaults)
|
||||
in option.c */
|
||||
|
||||
unsigned int options;
|
||||
unsigned int options, options2;
|
||||
struct resolvc default_resolv, *resolv_files;
|
||||
time_t last_resolv;
|
||||
struct mx_srv_record *mxnames;
|
||||
@@ -669,7 +685,7 @@ extern struct daemon {
|
||||
int enable_pxe;
|
||||
struct dhcp_netid_list *dhcp_ignore, *dhcp_ignore_names, *dhcp_gen_names;
|
||||
struct dhcp_netid_list *force_broadcast, *bootp_dynamic;
|
||||
char *dhcp_hosts_file, *dhcp_opts_file;
|
||||
struct hostsfile *dhcp_hosts_file, *dhcp_opts_file;
|
||||
int dhcp_max, tftp_max;
|
||||
int dhcp_server_port, dhcp_client_port;
|
||||
int start_tftp_port, end_tftp_port;
|
||||
@@ -727,7 +743,7 @@ extern struct daemon {
|
||||
|
||||
/* cache.c */
|
||||
void cache_init(void);
|
||||
void log_query(unsigned short flags, char *name, struct all_addr *addr, char *arg);
|
||||
void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg);
|
||||
char *record_source(int index);
|
||||
void querystr(char *str, unsigned short type);
|
||||
struct crec *cache_find_by_addr(struct crec *crecp,
|
||||
@@ -747,13 +763,13 @@ 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,
|
||||
unsigned int extract_request(HEADER *header, size_t qlen,
|
||||
char *name, unsigned short *typep);
|
||||
size_t setup_reply(HEADER *header, size_t qlen,
|
||||
struct all_addr *addrp, unsigned short flags,
|
||||
struct all_addr *addrp, unsigned int flags,
|
||||
unsigned long local_ttl);
|
||||
int extract_addresses(HEADER *header, size_t qlen, char *namebuff,
|
||||
time_t now, int is_sign, int checkrebind);
|
||||
time_t now, int is_sign, int checkrebind, int checking_disabled);
|
||||
size_t answer_request(HEADER *header, char *limit, size_t qlen,
|
||||
struct in_addr local_addr, struct in_addr local_netmask, time_t now);
|
||||
int check_for_bogus_wildcard(HEADER *header, size_t qlen, char *name,
|
||||
@@ -764,6 +780,7 @@ int check_for_local_domain(char *name, time_t now);
|
||||
unsigned int questions_crc(HEADER *header, size_t plen, char *buff);
|
||||
size_t resize_packet(HEADER *header, size_t plen,
|
||||
unsigned char *pheader, size_t hlen);
|
||||
size_t add_mac(HEADER *header, size_t plen, char *limit, union mysockaddr *l3);
|
||||
|
||||
/* util.c */
|
||||
void rand_init(void);
|
||||
@@ -804,6 +821,8 @@ void flush_log(void);
|
||||
void read_opts (int argc, char **argv, char *compile_opts);
|
||||
char *option_string(unsigned char opt, int *is_ip, int *is_name);
|
||||
void reread_dhcp(void);
|
||||
void set_option_bool(unsigned int opt);
|
||||
struct hostsfile *expand_filelist(struct hostsfile *list);
|
||||
|
||||
/* forward.c */
|
||||
void reply_query(int fd, int family, time_t now);
|
||||
@@ -908,7 +927,7 @@ void send_via_bpf(struct dhcp_packet *mess, size_t len,
|
||||
#endif
|
||||
|
||||
/* bpf.c or netlink.c */
|
||||
int iface_enumerate(void *parm, int (*ipv4_callback)(), int (*ipv6_callback)());
|
||||
int iface_enumerate(int family, void *parm, int (callback)());
|
||||
|
||||
/* dbus.c */
|
||||
#ifdef HAVE_DBUS
|
||||
|
||||
166
src/forward.c
166
src/forward.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2010 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2011 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
|
||||
@@ -111,8 +111,8 @@ static void send_from(int fd, int nowild, char *packet, size_t len,
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned short search_servers(time_t now, struct all_addr **addrpp,
|
||||
unsigned short qtype, char *qdomain, int *type, char **domain, int *norebind)
|
||||
static unsigned int search_servers(time_t now, struct all_addr **addrpp,
|
||||
unsigned int qtype, char *qdomain, int *type, char **domain, int *norebind)
|
||||
|
||||
{
|
||||
/* If the query ends in the domain in one of our servers, set
|
||||
@@ -122,13 +122,13 @@ static unsigned short search_servers(time_t now, struct all_addr **addrpp,
|
||||
unsigned int namelen = strlen(qdomain);
|
||||
unsigned int matchlen = 0;
|
||||
struct server *serv;
|
||||
unsigned short flags = 0;
|
||||
unsigned int flags = 0;
|
||||
|
||||
for (serv = daemon->servers; serv; serv=serv->next)
|
||||
/* domain matches take priority over NODOTS matches */
|
||||
if ((serv->flags & SERV_FOR_NODOTS) && *type != SERV_HAS_DOMAIN && !strchr(qdomain, '.') && namelen != 0)
|
||||
{
|
||||
unsigned short sflag = serv->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6;
|
||||
unsigned int sflag = serv->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6;
|
||||
*type = SERV_FOR_NODOTS;
|
||||
if (serv->flags & SERV_NO_ADDR)
|
||||
flags = F_NXDOMAIN;
|
||||
@@ -158,37 +158,57 @@ static unsigned short search_servers(time_t now, struct all_addr **addrpp,
|
||||
{
|
||||
if (serv->flags & SERV_NO_REBIND)
|
||||
*norebind = 1;
|
||||
else if (domainlen >= matchlen)
|
||||
else
|
||||
{
|
||||
unsigned short sflag = serv->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6;
|
||||
*type = serv->flags & (SERV_HAS_DOMAIN | SERV_USE_RESOLV | SERV_NO_REBIND);
|
||||
*domain = serv->domain;
|
||||
matchlen = domainlen;
|
||||
if (serv->flags & SERV_NO_ADDR)
|
||||
flags = F_NXDOMAIN;
|
||||
else if (serv->flags & SERV_LITERAL_ADDRESS)
|
||||
unsigned int sflag = serv->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6;
|
||||
/* implement priority rules for --address and --server for same domain.
|
||||
--address wins if the address is for the correct AF
|
||||
--server wins otherwise. */
|
||||
if (domainlen != 0 && domainlen == matchlen)
|
||||
{
|
||||
if (sflag & qtype)
|
||||
if ((serv->flags & SERV_LITERAL_ADDRESS))
|
||||
{
|
||||
flags = sflag;
|
||||
if (serv->addr.sa.sa_family == AF_INET)
|
||||
*addrpp = (struct all_addr *)&serv->addr.in.sin_addr;
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
*addrpp = (struct all_addr *)&serv->addr.in6.sin6_addr;
|
||||
#endif
|
||||
if (!(sflag & qtype) && flags == 0)
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (flags & (F_IPV4 | F_IPV6))
|
||||
continue;
|
||||
}
|
||||
else if (!flags || (flags & F_NXDOMAIN))
|
||||
flags = F_NOERR;
|
||||
}
|
||||
else
|
||||
flags = 0;
|
||||
}
|
||||
|
||||
if (domainlen >= matchlen)
|
||||
{
|
||||
*type = serv->flags & (SERV_HAS_DOMAIN | SERV_USE_RESOLV | SERV_NO_REBIND);
|
||||
*domain = serv->domain;
|
||||
matchlen = domainlen;
|
||||
if (serv->flags & SERV_NO_ADDR)
|
||||
flags = F_NXDOMAIN;
|
||||
else if (serv->flags & SERV_LITERAL_ADDRESS)
|
||||
{
|
||||
if (sflag & qtype)
|
||||
{
|
||||
flags = sflag;
|
||||
if (serv->addr.sa.sa_family == AF_INET)
|
||||
*addrpp = (struct all_addr *)&serv->addr.in.sin_addr;
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
*addrpp = (struct all_addr *)&serv->addr.in6.sin6_addr;
|
||||
#endif
|
||||
}
|
||||
else if (!flags || (flags & F_NXDOMAIN))
|
||||
flags = F_NOERR;
|
||||
}
|
||||
else
|
||||
flags = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (flags == 0 && !(qtype & F_BIGNAME) &&
|
||||
(daemon->options & OPT_NODOTS_LOCAL) && !strchr(qdomain, '.') && namelen != 0)
|
||||
if (flags == 0 && !(qtype & F_NSRR) &&
|
||||
option_bool(OPT_NODOTS_LOCAL) && !strchr(qdomain, '.') && namelen != 0)
|
||||
/* don't forward simple names, make exception for NS queries and empty name. */
|
||||
flags = F_NXDOMAIN;
|
||||
|
||||
@@ -220,10 +240,13 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
int type = 0, norebind = 0;
|
||||
struct all_addr *addrp = NULL;
|
||||
unsigned int crc = questions_crc(header, plen, daemon->namebuff);
|
||||
unsigned short flags = 0;
|
||||
unsigned short gotname = extract_request(header, plen, daemon->namebuff, NULL);
|
||||
unsigned int flags = 0;
|
||||
unsigned int gotname = extract_request(header, plen, daemon->namebuff, NULL);
|
||||
struct server *start = NULL;
|
||||
|
||||
/* RFC 4035: sect 4.6 para 2 */
|
||||
header->ad = 0;
|
||||
|
||||
/* may be no servers available. */
|
||||
if (!daemon->servers)
|
||||
forward = NULL;
|
||||
@@ -232,7 +255,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
/* retry on existing query, send to all available servers */
|
||||
domain = forward->sentto->domain;
|
||||
forward->sentto->failed_queries++;
|
||||
if (!(daemon->options & OPT_ORDER))
|
||||
if (!option_bool(OPT_ORDER))
|
||||
{
|
||||
forward->forwardall = 1;
|
||||
daemon->last_server = NULL;
|
||||
@@ -261,9 +284,13 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
forward->fd = udpfd;
|
||||
forward->crc = crc;
|
||||
forward->forwardall = 0;
|
||||
forward->norebind = norebind;
|
||||
header->id = htons(forward->new_id);
|
||||
if (norebind)
|
||||
forward->flags |= FREC_NOREBIND;
|
||||
if (header->cd)
|
||||
forward->flags |= FREC_CHECKING_DISABLED;
|
||||
|
||||
header->id = htons(forward->new_id);
|
||||
|
||||
/* In strict_order mode, always try servers in the order
|
||||
specified in resolv.conf, if a domain is given
|
||||
always try all the available servers,
|
||||
@@ -271,7 +298,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
|
||||
if (type == 0)
|
||||
{
|
||||
if (daemon->options & OPT_ORDER)
|
||||
if (option_bool(OPT_ORDER))
|
||||
start = daemon->servers;
|
||||
else if (!(start = daemon->last_server) ||
|
||||
daemon->forwardcount++ > FORWARD_TEST ||
|
||||
@@ -286,7 +313,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
else
|
||||
{
|
||||
start = daemon->servers;
|
||||
if (!(daemon->options & OPT_ORDER))
|
||||
if (!option_bool(OPT_ORDER))
|
||||
forward->forwardall = 1;
|
||||
}
|
||||
}
|
||||
@@ -300,7 +327,10 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
{
|
||||
struct server *firstsentto = start;
|
||||
int forwarded = 0;
|
||||
|
||||
|
||||
if (udpaddr && option_bool(OPT_ADD_MAC))
|
||||
plen = add_mac(header, plen, ((char *) header) + PACKETSZ, udpaddr);
|
||||
|
||||
while (1)
|
||||
{
|
||||
/* only send to servers dealing with our domain.
|
||||
@@ -389,14 +419,14 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
if (udpfd != -1)
|
||||
{
|
||||
plen = setup_reply(header, plen, addrp, flags, daemon->local_ttl);
|
||||
send_from(udpfd, daemon->options & OPT_NOWILD, (char *)header, plen, udpaddr, dst_addr, dst_iface);
|
||||
send_from(udpfd, option_bool(OPT_NOWILD), (char *)header, plen, udpaddr, dst_addr, dst_iface);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static size_t process_reply(HEADER *header, time_t now,
|
||||
struct server *server, size_t n, int check_rebind)
|
||||
struct server *server, size_t n, int check_rebind, int checking_disabled)
|
||||
{
|
||||
unsigned char *pheader, *sizep;
|
||||
int munged = 0, is_sign;
|
||||
@@ -416,6 +446,10 @@ static size_t process_reply(HEADER *header, time_t now,
|
||||
PUTSHORT(daemon->edns_pktsz, psave);
|
||||
}
|
||||
|
||||
/* RFC 4035 sect 4.6 para 3 */
|
||||
if (!is_sign && !option_bool(OPT_DNSSEC))
|
||||
header->ad = 0;
|
||||
|
||||
if (header->opcode != QUERY || (header->rcode != NOERROR && header->rcode != NXDOMAIN))
|
||||
return n;
|
||||
|
||||
@@ -425,7 +459,7 @@ static size_t process_reply(HEADER *header, time_t now,
|
||||
{
|
||||
prettyprint_addr(&server->addr, daemon->namebuff);
|
||||
my_syslog(LOG_WARNING, _("nameserver %s refused to do a recursive query"), daemon->namebuff);
|
||||
if (!(daemon->options & OPT_LOG))
|
||||
if (!option_bool(OPT_LOG))
|
||||
server->flags |= SERV_WARNED_RECURSIVE;
|
||||
}
|
||||
|
||||
@@ -450,7 +484,7 @@ static size_t process_reply(HEADER *header, time_t now,
|
||||
header->rcode = NOERROR;
|
||||
}
|
||||
|
||||
if (extract_addresses(header, n, daemon->namebuff, now, is_sign, check_rebind))
|
||||
if (extract_addresses(header, n, daemon->namebuff, now, is_sign, check_rebind, checking_disabled))
|
||||
{
|
||||
my_syslog(LOG_WARNING, _("possible DNS-rebind attack detected: %s"), daemon->namebuff);
|
||||
munged = 1;
|
||||
@@ -512,7 +546,7 @@ void reply_query(int fd, int family, time_t now)
|
||||
server = forward->sentto;
|
||||
|
||||
if ((header->rcode == SERVFAIL || header->rcode == REFUSED) &&
|
||||
!(daemon->options & OPT_ORDER) &&
|
||||
!option_bool(OPT_ORDER) &&
|
||||
forward->forwardall == 0)
|
||||
/* for broken servers, attempt to send to another one. */
|
||||
{
|
||||
@@ -554,7 +588,7 @@ void reply_query(int fd, int family, time_t now)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!(daemon->options & OPT_ALL_SERVERS))
|
||||
if (!option_bool(OPT_ALL_SERVERS))
|
||||
daemon->last_server = server;
|
||||
}
|
||||
|
||||
@@ -565,16 +599,16 @@ void reply_query(int fd, int family, time_t now)
|
||||
if (forward->forwardall == 0 || --forward->forwardall == 1 ||
|
||||
(header->rcode != REFUSED && header->rcode != SERVFAIL))
|
||||
{
|
||||
int check_rebind = !forward->norebind;
|
||||
int check_rebind = !(forward->flags & FREC_NOREBIND);
|
||||
|
||||
if (!(daemon->options & OPT_NO_REBIND))
|
||||
if (!option_bool(OPT_NO_REBIND))
|
||||
check_rebind = 0;
|
||||
|
||||
if ((nn = process_reply(header, now, server, (size_t)n, check_rebind)))
|
||||
if ((nn = process_reply(header, now, server, (size_t)n, check_rebind, forward->flags & FREC_CHECKING_DISABLED)))
|
||||
{
|
||||
header->id = htons(forward->orig_id);
|
||||
header->ra = 1; /* recursion if available */
|
||||
send_from(forward->fd, daemon->options & OPT_NOWILD, daemon->packet, nn,
|
||||
send_from(forward->fd, option_bool(OPT_NOWILD), daemon->packet, nn,
|
||||
&forward->source, &forward->dest, forward->iface);
|
||||
}
|
||||
free_frec(forward); /* cancel */
|
||||
@@ -614,7 +648,7 @@ void receive_query(struct listener *listen, time_t now)
|
||||
/* packet buffer overwritten */
|
||||
daemon->srv_save = NULL;
|
||||
|
||||
if (listen->family == AF_INET && (daemon->options & OPT_NOWILD))
|
||||
if (listen->family == AF_INET && option_bool(OPT_NOWILD))
|
||||
{
|
||||
dst_addr_4 = listen->iface->addr.in.sin_addr;
|
||||
netmask = listen->iface->netmask;
|
||||
@@ -649,8 +683,8 @@ void receive_query(struct listener *listen, time_t now)
|
||||
if (listen->family == AF_INET6)
|
||||
source_addr.in6.sin6_flowinfo = 0;
|
||||
#endif
|
||||
|
||||
if (!(daemon->options & OPT_NOWILD))
|
||||
|
||||
if (!option_bool(OPT_NOWILD))
|
||||
{
|
||||
struct ifreq ifr;
|
||||
|
||||
@@ -721,7 +755,7 @@ void receive_query(struct listener *listen, time_t now)
|
||||
return;
|
||||
|
||||
if (listen->family == AF_INET &&
|
||||
(daemon->options & OPT_LOCALISE) &&
|
||||
option_bool(OPT_LOCALISE) &&
|
||||
ioctl(listen->fd, SIOCGIFNETMASK, &ifr) == -1)
|
||||
return;
|
||||
|
||||
@@ -748,7 +782,7 @@ void receive_query(struct listener *listen, time_t now)
|
||||
dst_addr_4, netmask, now);
|
||||
if (m >= 1)
|
||||
{
|
||||
send_from(listen->fd, daemon->options & OPT_NOWILD, (char *)header,
|
||||
send_from(listen->fd, option_bool(OPT_NOWILD), (char *)header,
|
||||
m, &source_addr, &dst_addr, if_index);
|
||||
daemon->local_answer++;
|
||||
}
|
||||
@@ -766,7 +800,9 @@ void receive_query(struct listener *listen, time_t now)
|
||||
unsigned char *tcp_request(int confd, time_t now,
|
||||
struct in_addr local_addr, struct in_addr netmask)
|
||||
{
|
||||
int size = 0, norebind = 0;
|
||||
size_t size = 0;
|
||||
int norebind = 0;
|
||||
int checking_disabled;
|
||||
size_t m;
|
||||
unsigned short qtype, gotname;
|
||||
unsigned char c1, c2;
|
||||
@@ -787,6 +823,12 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
continue;
|
||||
|
||||
header = (HEADER *)packet;
|
||||
|
||||
/* save state of "cd" flag in query */
|
||||
checking_disabled = header->cd;
|
||||
|
||||
/* RFC 4035: sect 4.6 para 2 */
|
||||
header->ad = 0;
|
||||
|
||||
if ((gotname = extract_request(header, (unsigned int)size, daemon->namebuff, &qtype)))
|
||||
{
|
||||
@@ -819,15 +861,24 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
|
||||
if (m == 0)
|
||||
{
|
||||
unsigned short flags = 0;
|
||||
unsigned int flags = 0;
|
||||
struct all_addr *addrp = NULL;
|
||||
int type = 0;
|
||||
char *domain = NULL;
|
||||
|
||||
|
||||
if (option_bool(OPT_ADD_MAC))
|
||||
{
|
||||
union mysockaddr peer_addr;
|
||||
socklen_t peer_len = sizeof(union mysockaddr);
|
||||
|
||||
if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) != -1)
|
||||
size = add_mac(header, size, ((char *) header) + 65536, &peer_addr);
|
||||
}
|
||||
|
||||
if (gotname)
|
||||
flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind);
|
||||
|
||||
if (type != 0 || (daemon->options & OPT_ORDER) || !daemon->last_server)
|
||||
if (type != 0 || option_bool(OPT_ORDER) || !daemon->last_server)
|
||||
last_server = daemon->servers;
|
||||
else
|
||||
last_server = daemon->last_server;
|
||||
@@ -906,7 +957,8 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
someone might be attempting to insert bogus values into the cache by
|
||||
sending replies containing questions and bogus answers. */
|
||||
if (crc == questions_crc(header, (unsigned int)m, daemon->namebuff))
|
||||
m = process_reply(header, now, last_server, (unsigned int)m, (daemon->options & OPT_NO_REBIND) && !norebind );
|
||||
m = process_reply(header, now, last_server, (unsigned int)m,
|
||||
option_bool(OPT_NO_REBIND) && !norebind, checking_disabled);
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -938,6 +990,7 @@ static struct frec *allocate_frec(time_t now)
|
||||
f->time = now;
|
||||
f->sentto = NULL;
|
||||
f->rfd4 = NULL;
|
||||
f->flags = 0;
|
||||
#ifdef HAVE_IPV6
|
||||
f->rfd6 = NULL;
|
||||
#endif
|
||||
@@ -990,6 +1043,7 @@ static void free_frec(struct frec *f)
|
||||
|
||||
f->rfd4 = NULL;
|
||||
f->sentto = NULL;
|
||||
f->flags = 0;
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (f->rfd6 && --(f->rfd6->refcount) == 0)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2010 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2011 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
|
||||
@@ -79,14 +79,14 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
||||
sigaction(SIGTERM, &sigact, NULL);
|
||||
sigaction(SIGALRM, &sigact, NULL);
|
||||
|
||||
if (!(daemon->options & OPT_DEBUG) && uid != 0)
|
||||
if (!option_bool(OPT_DEBUG) && uid != 0)
|
||||
{
|
||||
gid_t dummy;
|
||||
if (setgroups(0, &dummy) == -1 ||
|
||||
setgid(gid) == -1 ||
|
||||
setuid(uid) == -1)
|
||||
{
|
||||
if (daemon->options & OPT_NO_FORK)
|
||||
if (option_bool(OPT_NO_FORK))
|
||||
/* send error to daemon process if no-fork */
|
||||
send_event(event_fd, EVENT_HUSER_ERR, errno);
|
||||
else
|
||||
|
||||
12
src/lease.c
12
src/lease.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2010 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2011 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
|
||||
@@ -37,7 +37,7 @@ void lease_init(time_t now)
|
||||
|
||||
leases_left = daemon->dhcp_max;
|
||||
|
||||
if (daemon->options & OPT_LEASE_RO)
|
||||
if (option_bool(OPT_LEASE_RO))
|
||||
{
|
||||
/* run "<lease_change_script> init" once to get the
|
||||
initial state of the database. If leasefile-ro is
|
||||
@@ -254,7 +254,7 @@ void lease_update_dns(void)
|
||||
if (lease->fqdn)
|
||||
cache_add_dhcp_entry(lease->fqdn, &lease->addr, lease->expires);
|
||||
|
||||
if (!(daemon->options & OPT_DHCP_FQDN) && lease->hostname)
|
||||
if (!option_bool(OPT_DHCP_FQDN) && lease->hostname)
|
||||
cache_add_dhcp_entry(lease->hostname, &lease->addr, lease->expires);
|
||||
}
|
||||
|
||||
@@ -470,7 +470,7 @@ void lease_set_hostname(struct dhcp_lease *lease, char *name, int auth)
|
||||
/* Depending on mode, we check either unqualified name or FQDN. */
|
||||
for (lease_tmp = leases; lease_tmp; lease_tmp = lease_tmp->next)
|
||||
{
|
||||
if (daemon->options & OPT_DHCP_FQDN)
|
||||
if (option_bool(OPT_DHCP_FQDN))
|
||||
{
|
||||
if (!new_fqdn || !lease_tmp->fqdn || !hostname_isequal(lease_tmp->fqdn, new_fqdn) )
|
||||
continue;
|
||||
@@ -534,7 +534,7 @@ int do_script_run(time_t now)
|
||||
#ifdef HAVE_DBUS
|
||||
/* If we're going to be sending DBus signals, but the connection is not yet up,
|
||||
delay everything until it is. */
|
||||
if ((daemon->options & OPT_DBUS) && !daemon->dbus)
|
||||
if (option_bool(OPT_DBUS) && !daemon->dbus)
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
@@ -586,7 +586,7 @@ int do_script_run(time_t now)
|
||||
|
||||
for (lease = leases; lease; lease = lease->next)
|
||||
if (lease->new || lease->changed ||
|
||||
(lease->aux_changed && (daemon->options & OPT_LEASE_RO)))
|
||||
(lease->aux_changed && option_bool(OPT_LEASE_RO)))
|
||||
{
|
||||
#ifdef HAVE_SCRIPT
|
||||
queue_script(lease->new ? ACTION_ADD : ACTION_OLD, lease,
|
||||
|
||||
17
src/log.c
17
src/log.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2010 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2011 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
|
||||
@@ -55,12 +55,12 @@ int log_start(struct passwd *ent_pw, int errfd)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
echo_stderr = !!(daemon->options & OPT_DEBUG);
|
||||
echo_stderr = option_bool(OPT_DEBUG);
|
||||
|
||||
if (daemon->log_fac != -1)
|
||||
log_fac = daemon->log_fac;
|
||||
#ifdef LOG_LOCAL0
|
||||
else if (daemon->options & OPT_DEBUG)
|
||||
else if (option_bool(OPT_DEBUG))
|
||||
log_fac = LOG_LOCAL0;
|
||||
#endif
|
||||
|
||||
@@ -327,7 +327,11 @@ void my_syslog(int priority, const char *format, ...)
|
||||
if (!log_to_file)
|
||||
p += sprintf(p, "<%d>", priority | log_fac);
|
||||
|
||||
p += sprintf(p, "%.15s dnsmasq%s[%d]: ", ctime(&time_now) + 4, func, (int)pid);
|
||||
/* Omit timestamp for default daemontools situation */
|
||||
if (!log_stderr || !option_bool(OPT_NO_FORK))
|
||||
p += sprintf(p, "%.15s ", ctime(&time_now) + 4);
|
||||
|
||||
p += sprintf(p, "dnsmasq%s[%d]: ", func, (int)pid);
|
||||
|
||||
len = p - entry->payload;
|
||||
va_start(ap, format);
|
||||
@@ -398,12 +402,13 @@ void check_log_writer(fd_set *set)
|
||||
|
||||
void flush_log(void)
|
||||
{
|
||||
/* write until queue empty */
|
||||
/* write until queue empty, but don't loop forever if there's
|
||||
no connection to the syslog in existance */
|
||||
while (log_fd != -1)
|
||||
{
|
||||
struct timespec waiter;
|
||||
log_write();
|
||||
if (!entries)
|
||||
if (!entries || !connection_good)
|
||||
{
|
||||
close(log_fd);
|
||||
break;
|
||||
|
||||
115
src/netlink.c
115
src/netlink.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2010 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2011 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
|
||||
@@ -30,6 +30,10 @@
|
||||
# include <linux/if_addr.h>
|
||||
#endif
|
||||
|
||||
#ifndef NDA_RTA
|
||||
# define NDA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ndmsg))))
|
||||
#endif
|
||||
|
||||
static struct iovec iov;
|
||||
static u32 netlink_pid;
|
||||
|
||||
@@ -122,13 +126,14 @@ static ssize_t netlink_recv(void)
|
||||
return rc;
|
||||
}
|
||||
|
||||
int iface_enumerate(void *parm, int (*ipv4_callback)(), int (*ipv6_callback)())
|
||||
|
||||
/* family = AF_UNSPEC finds ARP table entries. */
|
||||
int iface_enumerate(int family, void *parm, int (*callback)())
|
||||
{
|
||||
struct sockaddr_nl addr;
|
||||
struct nlmsghdr *h;
|
||||
ssize_t len;
|
||||
static unsigned int seq = 0;
|
||||
int family = AF_INET;
|
||||
|
||||
struct {
|
||||
struct nlmsghdr nlh;
|
||||
@@ -142,7 +147,7 @@ int iface_enumerate(void *parm, int (*ipv4_callback)(), int (*ipv6_callback)())
|
||||
|
||||
again:
|
||||
req.nlh.nlmsg_len = sizeof(req);
|
||||
req.nlh.nlmsg_type = RTM_GETADDR;
|
||||
req.nlh.nlmsg_type = family == AF_UNSPEC ? RTM_GETNEIGH : RTM_GETADDR;
|
||||
req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST | NLM_F_ACK;
|
||||
req.nlh.nlmsg_pid = 0;
|
||||
req.nlh.nlmsg_seq = ++seq;
|
||||
@@ -173,66 +178,84 @@ int iface_enumerate(void *parm, int (*ipv4_callback)(), int (*ipv6_callback)())
|
||||
else if (h->nlmsg_type == NLMSG_ERROR)
|
||||
nl_err(h);
|
||||
else if (h->nlmsg_type == NLMSG_DONE)
|
||||
{
|
||||
#ifdef HAVE_IPV6
|
||||
if (family == AF_INET && ipv6_callback)
|
||||
{
|
||||
family = AF_INET6;
|
||||
goto again;
|
||||
}
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
else if (h->nlmsg_type == RTM_NEWADDR)
|
||||
return 1;
|
||||
else if (h->nlmsg_type == RTM_NEWADDR && family != AF_UNSPEC)
|
||||
{
|
||||
struct ifaddrmsg *ifa = NLMSG_DATA(h);
|
||||
struct rtattr *rta = IFA_RTA(ifa);
|
||||
unsigned int len1 = h->nlmsg_len - NLMSG_LENGTH(sizeof(*ifa));
|
||||
|
||||
if (ifa->ifa_family == AF_INET)
|
||||
if (ifa->ifa_family == family)
|
||||
{
|
||||
struct in_addr netmask, addr, broadcast;
|
||||
|
||||
netmask.s_addr = htonl(0xffffffff << (32 - ifa->ifa_prefixlen));
|
||||
addr.s_addr = 0;
|
||||
broadcast.s_addr = 0;
|
||||
|
||||
while (RTA_OK(rta, len1))
|
||||
if (ifa->ifa_family == AF_INET)
|
||||
{
|
||||
if (rta->rta_type == IFA_LOCAL)
|
||||
addr = *((struct in_addr *)(rta+1));
|
||||
else if (rta->rta_type == IFA_BROADCAST)
|
||||
broadcast = *((struct in_addr *)(rta+1));
|
||||
struct in_addr netmask, addr, broadcast;
|
||||
|
||||
rta = RTA_NEXT(rta, len1);
|
||||
netmask.s_addr = htonl(0xffffffff << (32 - ifa->ifa_prefixlen));
|
||||
addr.s_addr = 0;
|
||||
broadcast.s_addr = 0;
|
||||
|
||||
while (RTA_OK(rta, len1))
|
||||
{
|
||||
if (rta->rta_type == IFA_LOCAL)
|
||||
addr = *((struct in_addr *)(rta+1));
|
||||
else if (rta->rta_type == IFA_BROADCAST)
|
||||
broadcast = *((struct in_addr *)(rta+1));
|
||||
|
||||
rta = RTA_NEXT(rta, len1);
|
||||
}
|
||||
|
||||
if (addr.s_addr)
|
||||
if (!((*callback)(addr, ifa->ifa_index, netmask, broadcast, parm)))
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (addr.s_addr && ipv4_callback)
|
||||
if (!((*ipv4_callback)(addr, ifa->ifa_index, netmask, broadcast, parm)))
|
||||
return 0;
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
else if (ifa->ifa_family == AF_INET6)
|
||||
{
|
||||
struct in6_addr *addrp = NULL;
|
||||
while (RTA_OK(rta, len1))
|
||||
else if (ifa->ifa_family == AF_INET6)
|
||||
{
|
||||
if (rta->rta_type == IFA_ADDRESS)
|
||||
addrp = ((struct in6_addr *)(rta+1));
|
||||
struct in6_addr *addrp = NULL;
|
||||
while (RTA_OK(rta, len1))
|
||||
{
|
||||
if (rta->rta_type == IFA_ADDRESS)
|
||||
addrp = ((struct in6_addr *)(rta+1));
|
||||
|
||||
rta = RTA_NEXT(rta, len1);
|
||||
}
|
||||
|
||||
rta = RTA_NEXT(rta, len1);
|
||||
if (addrp)
|
||||
if (!((*callback)(addrp, ifa->ifa_index, ifa->ifa_index, parm)))
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else if (h->nlmsg_type == RTM_NEWNEIGH && family == AF_UNSPEC)
|
||||
{
|
||||
struct ndmsg *neigh = NLMSG_DATA(h);
|
||||
struct rtattr *rta = NDA_RTA(neigh);
|
||||
unsigned int len1 = h->nlmsg_len - NLMSG_LENGTH(sizeof(*neigh));
|
||||
size_t maclen = 0;
|
||||
char *inaddr = NULL, *mac = NULL;
|
||||
|
||||
while (RTA_OK(rta, len1))
|
||||
{
|
||||
if (rta->rta_type == NDA_DST)
|
||||
inaddr = (char *)(rta+1);
|
||||
else if (rta->rta_type == NDA_LLADDR)
|
||||
{
|
||||
maclen = rta->rta_len - sizeof(struct rtattr);
|
||||
mac = (char *)(rta+1);
|
||||
}
|
||||
|
||||
if (addrp && ipv6_callback)
|
||||
if (!((*ipv6_callback)(addrp, ifa->ifa_index, ifa->ifa_index, parm)))
|
||||
return 0;
|
||||
rta = RTA_NEXT(rta, len1);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (inaddr && mac)
|
||||
if (!((*callback)(neigh->ndm_family, inaddr, mac, maclen, parm)))
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void netlink_multicast(void)
|
||||
{
|
||||
ssize_t len;
|
||||
|
||||
459
src/network.c
459
src/network.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2010 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2011 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
|
||||
@@ -34,6 +34,67 @@ int indextoname(int fd, int index, char *name)
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
#elif defined(HAVE_SOLARIS_NETWORK)
|
||||
|
||||
#include <zone.h>
|
||||
#include <alloca.h>
|
||||
#ifndef LIFC_UNDER_IPMP
|
||||
# define LIFC_UNDER_IPMP 0
|
||||
#endif
|
||||
|
||||
int indextoname(int fd, int index, char *name)
|
||||
{
|
||||
int64_t lifc_flags;
|
||||
struct lifnum lifn;
|
||||
int numifs, bufsize, i;
|
||||
struct lifconf lifc;
|
||||
struct lifreq *lifrp;
|
||||
|
||||
if (index == 0)
|
||||
return 0;
|
||||
|
||||
if (getzoneid() == GLOBAL_ZONEID)
|
||||
{
|
||||
if (!if_indextoname(index, name))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
lifc_flags = LIFC_NOXMIT | LIFC_TEMPORARY | LIFC_ALLZONES | LIFC_UNDER_IPMP;
|
||||
lifn.lifn_family = AF_UNSPEC;
|
||||
lifn.lifn_flags = lifc_flags;
|
||||
if (ioctl(fd, SIOCGLIFNUM, &lifn) < 0)
|
||||
return 0;
|
||||
|
||||
numifs = lifn.lifn_count;
|
||||
bufsize = numifs * sizeof(struct lifreq);
|
||||
|
||||
lifc.lifc_family = AF_UNSPEC;
|
||||
lifc.lifc_flags = lifc_flags;
|
||||
lifc.lifc_len = bufsize;
|
||||
lifc.lifc_buf = alloca(bufsize);
|
||||
|
||||
if (ioctl(fd, SIOCGLIFCONF, &lifc) < 0)
|
||||
return 0;
|
||||
|
||||
lifrp = lifc.lifc_req;
|
||||
for (i = lifc.lifc_len / sizeof(struct lifreq); i; i--, lifrp++)
|
||||
{
|
||||
struct lifreq lifr;
|
||||
strncpy(lifr.lifr_name, lifrp->lifr_name, IF_NAMESIZE);
|
||||
if (ioctl(fd, SIOCGLIFINDEX, &lifr) < 0)
|
||||
return 0;
|
||||
|
||||
if (lifr.lifr_index == index) {
|
||||
strncpy(name, lifr.lifr_name, IF_NAMESIZE);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
|
||||
int indextoname(int fd, int index, char *name)
|
||||
@@ -188,15 +249,14 @@ static int iface_allowed(struct irec **irecp, int if_index,
|
||||
|
||||
#ifdef HAVE_TFTP
|
||||
/* implement wierd TFTP service rules */
|
||||
if (addr->sa.sa_family == AF_INET)
|
||||
for (ir = daemon->tftp_interfaces; ir; ir = ir->next)
|
||||
if (strcmp(ir->interface, ifr.ifr_name) == 0)
|
||||
{
|
||||
tftp_ok = 1;
|
||||
break;
|
||||
}
|
||||
for (ir = daemon->tftp_interfaces; ir; ir = ir->next)
|
||||
if (strcmp(ir->interface, ifr.ifr_name) == 0)
|
||||
{
|
||||
tftp_ok = 1;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
if (!ir)
|
||||
{
|
||||
if (addr->sa.sa_family == AF_INET &&
|
||||
@@ -276,10 +336,11 @@ static int iface_allowed_v4(struct in_addr local, int if_index,
|
||||
int enumerate_interfaces(void)
|
||||
{
|
||||
#ifdef HAVE_IPV6
|
||||
return iface_enumerate(&daemon->interfaces, iface_allowed_v4, iface_allowed_v6);
|
||||
#else
|
||||
return iface_enumerate(&daemon->interfaces, iface_allowed_v4, NULL);
|
||||
if (!iface_enumerate(AF_INET6, &daemon->interfaces, iface_allowed_v6))
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
return iface_enumerate(AF_INET, &daemon->interfaces, iface_allowed_v4);
|
||||
}
|
||||
|
||||
/* set NONBLOCK bit on fd: See Stevens 16.6 */
|
||||
@@ -294,233 +355,207 @@ int fix_fd(int fd)
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if defined(HAVE_IPV6)
|
||||
static int create_ipv6_listener(struct listener **link, int port)
|
||||
static int make_sock(union mysockaddr *addr, int type)
|
||||
{
|
||||
union mysockaddr addr;
|
||||
int tcpfd, fd;
|
||||
struct listener *l;
|
||||
int opt = 1;
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.in6.sin6_family = AF_INET6;
|
||||
addr.in6.sin6_addr = in6addr_any;
|
||||
addr.in6.sin6_port = htons(port);
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
addr.in6.sin6_len = sizeof(addr.in6);
|
||||
int family = addr->sa.sa_family;
|
||||
int fd, rc, opt = 1;
|
||||
#ifdef HAVE_IPV6
|
||||
static int dad_count = 0;
|
||||
#endif
|
||||
|
||||
/* No error of the kernel doesn't support IPv6 */
|
||||
if ((fd = socket(AF_INET6, SOCK_DGRAM, 0)) == -1)
|
||||
return (errno == EPROTONOSUPPORT ||
|
||||
errno == EAFNOSUPPORT ||
|
||||
errno == EINVAL);
|
||||
|
||||
if ((tcpfd = socket(AF_INET6, SOCK_STREAM, 0)) == -1)
|
||||
return 0;
|
||||
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
|
||||
setsockopt(tcpfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
|
||||
setsockopt(fd, IPV6_LEVEL, IPV6_V6ONLY, &opt, sizeof(opt)) == -1 ||
|
||||
setsockopt(tcpfd, IPV6_LEVEL, IPV6_V6ONLY, &opt, sizeof(opt)) == -1 ||
|
||||
!fix_fd(fd) ||
|
||||
!fix_fd(tcpfd) ||
|
||||
bind(tcpfd, (struct sockaddr *)&addr, sa_len(&addr)) == -1 ||
|
||||
listen(tcpfd, 5) == -1 ||
|
||||
bind(fd, (struct sockaddr *)&addr, sa_len(&addr)) == -1)
|
||||
return 0;
|
||||
|
||||
/* The API changed around Linux 2.6.14 but the old ABI is still supported:
|
||||
handle all combinations of headers and kernel.
|
||||
OpenWrt note that this fixes the problem addressed by your very broken patch. */
|
||||
|
||||
daemon->v6pktinfo = IPV6_PKTINFO;
|
||||
|
||||
#ifdef IPV6_RECVPKTINFO
|
||||
# ifdef IPV6_2292PKTINFO
|
||||
if (setsockopt(fd, IPV6_LEVEL, IPV6_RECVPKTINFO, &opt, sizeof(opt)) == -1)
|
||||
if ((fd = socket(family, type, 0)) == -1)
|
||||
{
|
||||
if (errno == ENOPROTOOPT && setsockopt(fd, IPV6_LEVEL, IPV6_2292PKTINFO, &opt, sizeof(opt)) != -1)
|
||||
daemon->v6pktinfo = IPV6_2292PKTINFO;
|
||||
else
|
||||
return 0;
|
||||
int port;
|
||||
|
||||
/* No error if the kernel just doesn't support this IP flavour */
|
||||
if (errno == EPROTONOSUPPORT ||
|
||||
errno == EAFNOSUPPORT ||
|
||||
errno == EINVAL)
|
||||
return -1;
|
||||
|
||||
err:
|
||||
port = prettyprint_addr(addr, daemon->namebuff);
|
||||
if (!option_bool(OPT_NOWILD))
|
||||
sprintf(daemon->namebuff, "port %d", port);
|
||||
die(_("failed to create listening socket for %s: %s"),
|
||||
daemon->namebuff, EC_BADNET);
|
||||
}
|
||||
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 || !fix_fd(fd))
|
||||
goto err;
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (family == AF_INET6 && setsockopt(fd, IPV6_LEVEL, IPV6_V6ONLY, &opt, sizeof(opt)) == -1)
|
||||
goto err;
|
||||
#endif
|
||||
|
||||
while (1)
|
||||
{
|
||||
if ((rc = bind(fd, (struct sockaddr *)addr, sa_len(addr))) != -1)
|
||||
break;
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
/* An interface may have an IPv6 address which is still undergoing DAD.
|
||||
If so, the bind will fail until the DAD completes, so we try over 20 seconds
|
||||
before failing. */
|
||||
if (family == AF_INET6 &&
|
||||
(errno == ENODEV || errno == EADDRNOTAVAIL) &&
|
||||
dad_count++ < DAD_WAIT)
|
||||
{
|
||||
sleep(1);
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
if (rc == -1)
|
||||
goto err;
|
||||
|
||||
if (type == SOCK_STREAM)
|
||||
{
|
||||
if (listen(fd, 5) == -1)
|
||||
goto err;
|
||||
}
|
||||
else if (!option_bool(OPT_NOWILD))
|
||||
{
|
||||
if (family == AF_INET)
|
||||
{
|
||||
#if defined(HAVE_LINUX_NETWORK)
|
||||
if (setsockopt(fd, SOL_IP, IP_PKTINFO, &opt, sizeof(opt)) == -1)
|
||||
goto err;
|
||||
#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
|
||||
if (setsockopt(fd, IPPROTO_IP, IP_RECVDSTADDR, &opt, sizeof(opt)) == -1 ||
|
||||
setsockopt(fd, IPPROTO_IP, IP_RECVIF, &opt, sizeof(opt)) == -1)
|
||||
goto err;
|
||||
#endif
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
{
|
||||
/* The API changed around Linux 2.6.14 but the old ABI is still supported:
|
||||
handle all combinations of headers and kernel.
|
||||
OpenWrt note that this fixes the problem addressed by your very broken patch. */
|
||||
daemon->v6pktinfo = IPV6_PKTINFO;
|
||||
|
||||
# ifdef IPV6_RECVPKTINFO
|
||||
# ifdef IPV6_2292PKTINFO
|
||||
if (setsockopt(fd, IPV6_LEVEL, IPV6_RECVPKTINFO, &opt, sizeof(opt)) == -1)
|
||||
{
|
||||
if (errno == ENOPROTOOPT && setsockopt(fd, IPV6_LEVEL, IPV6_2292PKTINFO, &opt, sizeof(opt)) != -1)
|
||||
daemon->v6pktinfo = IPV6_2292PKTINFO;
|
||||
else
|
||||
goto err;
|
||||
}
|
||||
# else
|
||||
if (setsockopt(fd, IPV6_LEVEL, IPV6_RECVPKTINFO, &opt, sizeof(opt)) == -1)
|
||||
goto err;
|
||||
# endif
|
||||
# else
|
||||
if (setsockopt(fd, IPV6_LEVEL, IPV6_RECVPKTINFO, &opt, sizeof(opt)) == -1)
|
||||
return 0;
|
||||
# endif
|
||||
#else
|
||||
if (setsockopt(fd, IPV6_LEVEL, IPV6_PKTINFO, &opt, sizeof(opt)) == -1)
|
||||
return 0;
|
||||
if (setsockopt(fd, IPV6_LEVEL, IPV6_PKTINFO, &opt, sizeof(opt)) == -1)
|
||||
goto err;
|
||||
# endif
|
||||
}
|
||||
#endif
|
||||
|
||||
l = safe_malloc(sizeof(struct listener));
|
||||
l->fd = fd;
|
||||
l->tcpfd = tcpfd;
|
||||
l->tftpfd = -1;
|
||||
l->family = AF_INET6;
|
||||
l->next = NULL;
|
||||
*link = l;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
static struct listener *create_listeners(union mysockaddr *addr, int do_tftp)
|
||||
{
|
||||
struct listener *l = NULL;
|
||||
int fd = -1, tcpfd = -1, tftpfd = -1;
|
||||
|
||||
if (daemon->port != 0)
|
||||
{
|
||||
fd = make_sock(addr, SOCK_DGRAM);
|
||||
tcpfd = make_sock(addr, SOCK_STREAM);
|
||||
}
|
||||
|
||||
#ifdef HAVE_TFTP
|
||||
if (do_tftp)
|
||||
{
|
||||
if (addr->sa.sa_family == AF_INET)
|
||||
{
|
||||
/* port must be restored to DNS port for TCP code */
|
||||
short save = addr->in.sin_port;
|
||||
addr->in.sin_port = htons(TFTP_PORT);
|
||||
tftpfd = make_sock(addr, SOCK_DGRAM);
|
||||
addr->in.sin_port = save;
|
||||
}
|
||||
# ifdef HAVE_IPV6
|
||||
else
|
||||
{
|
||||
short save = addr->in6.sin6_port;
|
||||
addr->in6.sin6_port = htons(TFTP_PORT);
|
||||
tftpfd = make_sock(addr, SOCK_DGRAM);
|
||||
addr->in6.sin6_port = save;
|
||||
}
|
||||
# endif
|
||||
}
|
||||
#endif
|
||||
|
||||
if (fd != -1 || tcpfd != -1 || tftpfd != -1)
|
||||
{
|
||||
l = safe_malloc(sizeof(struct listener));
|
||||
l->next = NULL;
|
||||
l->family = addr->sa.sa_family;
|
||||
l->fd = fd;
|
||||
l->tcpfd = tcpfd;
|
||||
l->tftpfd = tftpfd;
|
||||
}
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
struct listener *create_wildcard_listeners(void)
|
||||
{
|
||||
union mysockaddr addr;
|
||||
int opt = 1;
|
||||
struct listener *l, *l6 = NULL;
|
||||
int tcpfd = -1, fd = -1, tftpfd = -1;
|
||||
struct listener *l;
|
||||
int tftp_enabled = daemon->tftp_unlimited || daemon->tftp_interfaces;
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
addr.in.sin_len = sizeof(addr.in);
|
||||
#endif
|
||||
addr.in.sin_family = AF_INET;
|
||||
addr.in.sin_addr.s_addr = INADDR_ANY;
|
||||
addr.in.sin_port = htons(daemon->port);
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
addr.in.sin_len = sizeof(struct sockaddr_in);
|
||||
#endif
|
||||
|
||||
if (daemon->port != 0)
|
||||
{
|
||||
|
||||
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1 ||
|
||||
(tcpfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
|
||||
return NULL;
|
||||
|
||||
if (setsockopt(tcpfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
|
||||
bind(tcpfd, (struct sockaddr *)&addr, sa_len(&addr)) == -1 ||
|
||||
listen(tcpfd, 5) == -1 ||
|
||||
!fix_fd(tcpfd) ||
|
||||
l = create_listeners(&addr, tftp_enabled);
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
!create_ipv6_listener(&l6, daemon->port) ||
|
||||
#endif
|
||||
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
|
||||
!fix_fd(fd) ||
|
||||
#if defined(HAVE_LINUX_NETWORK)
|
||||
setsockopt(fd, SOL_IP, IP_PKTINFO, &opt, sizeof(opt)) == -1 ||
|
||||
#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
|
||||
setsockopt(fd, IPPROTO_IP, IP_RECVDSTADDR, &opt, sizeof(opt)) == -1 ||
|
||||
setsockopt(fd, IPPROTO_IP, IP_RECVIF, &opt, sizeof(opt)) == -1 ||
|
||||
#endif
|
||||
bind(fd, (struct sockaddr *)&addr, sa_len(&addr)) == -1)
|
||||
return NULL;
|
||||
}
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
# ifdef HAVE_SOCKADDR_SA_LEN
|
||||
addr.in6.sin6_len = sizeof(addr.in6);
|
||||
# endif
|
||||
addr.in6.sin6_family = AF_INET6;
|
||||
addr.in6.sin6_addr = in6addr_any;
|
||||
addr.in6.sin6_port = htons(daemon->port);
|
||||
|
||||
#ifdef HAVE_TFTP
|
||||
if (daemon->tftp_unlimited || daemon->tftp_interfaces)
|
||||
{
|
||||
addr.in.sin_port = htons(TFTP_PORT);
|
||||
if ((tftpfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
|
||||
return NULL;
|
||||
|
||||
if (!fix_fd(tftpfd) ||
|
||||
#if defined(HAVE_LINUX_NETWORK)
|
||||
setsockopt(tftpfd, SOL_IP, IP_PKTINFO, &opt, sizeof(opt)) == -1 ||
|
||||
#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
|
||||
setsockopt(tftpfd, IPPROTO_IP, IP_RECVDSTADDR, &opt, sizeof(opt)) == -1 ||
|
||||
setsockopt(tftpfd, IPPROTO_IP, IP_RECVIF, &opt, sizeof(opt)) == -1 ||
|
||||
#endif
|
||||
bind(tftpfd, (struct sockaddr *)&addr, sa_len(&addr)) == -1)
|
||||
return NULL;
|
||||
}
|
||||
if (l)
|
||||
l->next = create_listeners(&addr, tftp_enabled);
|
||||
else
|
||||
l = create_listeners(&addr, tftp_enabled);
|
||||
#endif
|
||||
|
||||
l = safe_malloc(sizeof(struct listener));
|
||||
l->family = AF_INET;
|
||||
l->fd = fd;
|
||||
l->tcpfd = tcpfd;
|
||||
l->tftpfd = tftpfd;
|
||||
l->next = l6;
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
struct listener *create_bound_listeners(void)
|
||||
{
|
||||
struct listener *listeners = NULL;
|
||||
struct listener *new, *listeners = NULL;
|
||||
struct irec *iface;
|
||||
int rc, opt = 1;
|
||||
#ifdef HAVE_IPV6
|
||||
static int dad_count = 0;
|
||||
#endif
|
||||
|
||||
for (iface = daemon->interfaces; iface; iface = iface->next)
|
||||
{
|
||||
struct listener *new = safe_malloc(sizeof(struct listener));
|
||||
new->family = iface->addr.sa.sa_family;
|
||||
new->iface = iface;
|
||||
new->next = listeners;
|
||||
new->tftpfd = -1;
|
||||
new->tcpfd = -1;
|
||||
new->fd = -1;
|
||||
listeners = new;
|
||||
|
||||
if (daemon->port != 0)
|
||||
{
|
||||
if ((new->tcpfd = socket(iface->addr.sa.sa_family, SOCK_STREAM, 0)) == -1 ||
|
||||
(new->fd = socket(iface->addr.sa.sa_family, SOCK_DGRAM, 0)) == -1 ||
|
||||
setsockopt(new->fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
|
||||
setsockopt(new->tcpfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
|
||||
!fix_fd(new->tcpfd) ||
|
||||
!fix_fd(new->fd))
|
||||
die(_("failed to create listening socket: %s"), NULL, EC_BADNET);
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (iface->addr.sa.sa_family == AF_INET6)
|
||||
{
|
||||
if (setsockopt(new->fd, IPV6_LEVEL, IPV6_V6ONLY, &opt, sizeof(opt)) == -1 ||
|
||||
setsockopt(new->tcpfd, IPV6_LEVEL, IPV6_V6ONLY, &opt, sizeof(opt)) == -1)
|
||||
die(_("failed to set IPV6 options on listening socket: %s"), NULL, EC_BADNET);
|
||||
}
|
||||
#endif
|
||||
|
||||
while(1)
|
||||
{
|
||||
if ((rc = bind(new->fd, &iface->addr.sa, sa_len(&iface->addr))) != -1)
|
||||
break;
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
/* An interface may have an IPv6 address which is still undergoing DAD.
|
||||
If so, the bind will fail until the DAD completes, so we try over 20 seconds
|
||||
before failing. */
|
||||
if (iface->addr.sa.sa_family == AF_INET6 && (errno == ENODEV || errno == EADDRNOTAVAIL) &&
|
||||
dad_count++ < DAD_WAIT)
|
||||
{
|
||||
sleep(1);
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
if (rc == -1 || bind(new->tcpfd, &iface->addr.sa, sa_len(&iface->addr)) == -1)
|
||||
{
|
||||
prettyprint_addr(&iface->addr, daemon->namebuff);
|
||||
die(_("failed to bind listening socket for %s: %s"),
|
||||
daemon->namebuff, EC_BADNET);
|
||||
}
|
||||
|
||||
if (listen(new->tcpfd, 5) == -1)
|
||||
die(_("failed to listen on socket: %s"), NULL, EC_BADNET);
|
||||
}
|
||||
|
||||
#ifdef HAVE_TFTP
|
||||
if (iface->addr.sa.sa_family == AF_INET && iface->tftp_ok)
|
||||
{
|
||||
short save = iface->addr.in.sin_port;
|
||||
iface->addr.in.sin_port = htons(TFTP_PORT);
|
||||
if ((new->tftpfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1 ||
|
||||
setsockopt(new->tftpfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
|
||||
!fix_fd(new->tftpfd) ||
|
||||
bind(new->tftpfd, &iface->addr.sa, sa_len(&iface->addr)) == -1)
|
||||
die(_("failed to create TFTP socket: %s"), NULL, EC_BADNET);
|
||||
iface->addr.in.sin_port = save;
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
if ((new = create_listeners(&iface->addr, iface->tftp_ok)))
|
||||
{
|
||||
new->iface = iface;
|
||||
new->next = listeners;
|
||||
listeners = new;
|
||||
}
|
||||
|
||||
return listeners;
|
||||
}
|
||||
|
||||
@@ -700,7 +735,7 @@ void pre_allocate_sfds(void)
|
||||
if (!(srv->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR | SERV_USE_RESOLV | SERV_NO_REBIND)) &&
|
||||
!allocate_sfd(&srv->source_addr, srv->interface) &&
|
||||
errno != 0 &&
|
||||
(daemon->options & OPT_NOWILD))
|
||||
option_bool(OPT_NOWILD))
|
||||
{
|
||||
prettyprint_addr(&srv->source_addr, daemon->namebuff);
|
||||
if (srv->interface[0] != 0)
|
||||
@@ -721,7 +756,7 @@ void check_servers(void)
|
||||
int port = 0;
|
||||
|
||||
/* interface may be new since startup */
|
||||
if (!(daemon->options & OPT_NOWILD))
|
||||
if (!option_bool(OPT_NOWILD))
|
||||
enumerate_interfaces();
|
||||
|
||||
for (new = daemon->servers; new; new = tmp)
|
||||
@@ -921,7 +956,9 @@ struct in_addr get_ifaddr(char *intr)
|
||||
|
||||
ret.sin_addr.s_addr = -1;
|
||||
|
||||
for (l = daemon->listeners; l && l->family != AF_INET; l = l->next);
|
||||
for (l = daemon->listeners;
|
||||
l && (l->family != AF_INET || l->fd == -1);
|
||||
l = l->next);
|
||||
|
||||
strncpy(ifr.ifr_name, intr, IF_NAMESIZE);
|
||||
ifr.ifr_addr.sa_family = AF_INET;
|
||||
|
||||
545
src/option.c
545
src/option.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2010 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2011 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
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
static volatile int mem_recover = 0;
|
||||
static jmp_buf mem_jmp;
|
||||
static void one_file(char *file, int nest, int hard_opt);
|
||||
static void one_file(char *file, int hard_opt);
|
||||
|
||||
/* Solaris headers don't have facility names. */
|
||||
#ifdef HAVE_SOLARIS_NETWORK
|
||||
@@ -108,6 +108,8 @@ struct myoption {
|
||||
#define LOPT_MAXTTL 297
|
||||
#define LOPT_NO_REBIND 298
|
||||
#define LOPT_LOC_REBND 299
|
||||
#define LOPT_ADD_MAC 300
|
||||
#define LOPT_DNSSEC 301
|
||||
|
||||
#ifdef HAVE_GETOPT_LONG
|
||||
static const struct option opts[] =
|
||||
@@ -221,14 +223,16 @@ static const struct myoption opts[] =
|
||||
{ "dhcp-proxy", 2, 0, LOPT_PROXY },
|
||||
{ "dhcp-generate-names", 2, 0, LOPT_GEN_NAMES },
|
||||
{ "rebind-localhost-ok", 0, 0, LOPT_LOC_REBND },
|
||||
{ "add-mac", 0, 0, LOPT_ADD_MAC },
|
||||
{ "proxy-dnssec", 0, 0, LOPT_DNSSEC },
|
||||
{ NULL, 0, 0, 0 }
|
||||
};
|
||||
|
||||
/* These must have more the one '1' bit */
|
||||
#define ARG_DUP 3
|
||||
#define ARG_ONE 5
|
||||
#define ARG_USED_CL 7
|
||||
#define ARG_USED_FILE 9
|
||||
|
||||
#define ARG_DUP OPT_LAST
|
||||
#define ARG_ONE OPT_LAST + 1
|
||||
#define ARG_USED_CL OPT_LAST + 2
|
||||
#define ARG_USED_FILE OPT_LAST + 3
|
||||
|
||||
static struct {
|
||||
int opt;
|
||||
@@ -251,8 +255,8 @@ static struct {
|
||||
{ 'F', ARG_DUP, "ipaddr,ipaddr,time", gettext_noop("Enable DHCP in the range given with lease duration."), NULL },
|
||||
{ 'g', ARG_ONE, "groupname", gettext_noop("Change to this group after startup (defaults to %s)."), CHGRP },
|
||||
{ 'G', ARG_DUP, "<hostspec>", gettext_noop("Set address or hostname for a specified machine."), NULL },
|
||||
{ LOPT_DHCP_HOST, ARG_ONE, "<filename>", gettext_noop("Read DHCP host specs from file."), NULL },
|
||||
{ LOPT_DHCP_OPTS, ARG_ONE, "<filename>", gettext_noop("Read DHCP option specs from file."), NULL },
|
||||
{ LOPT_DHCP_HOST, ARG_DUP, "<filename>", gettext_noop("Read DHCP host specs from file."), NULL },
|
||||
{ LOPT_DHCP_OPTS, ARG_DUP, "<filename>", gettext_noop("Read DHCP option specs from file."), NULL },
|
||||
{ LOPT_TAG_IF, ARG_DUP, "tag-expression", gettext_noop("Evaluate conditional tag expression."), NULL },
|
||||
{ 'h', OPT_NO_HOSTS, NULL, gettext_noop("Do NOT load %s file."), HOSTSFILE },
|
||||
{ 'H', ARG_DUP, "path", gettext_noop("Specify a hosts file to be read in addition to %s."), HOSTSFILE },
|
||||
@@ -341,15 +345,17 @@ static struct {
|
||||
{ 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 },
|
||||
{ LOPT_ADD_MAC, OPT_ADD_MAC, NULL, gettext_noop("Add requestor's MAC address to forwarded DNS queries"), NULL },
|
||||
{ LOPT_DNSSEC, OPT_DNSSEC, NULL, gettext_noop("Proxy DNSSEC validation results from upstream nameservers"), NULL },
|
||||
{ 0, 0, NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
#ifdef HAVE_DHCP
|
||||
/* makes options which take a list of addresses */
|
||||
#define OT_ADDR_LIST 0x80
|
||||
/* DHCP-internal options, for logging. not valid in config file */
|
||||
#define OT_INTERNAL 0x40
|
||||
#define OT_NAME 0x20
|
||||
#define OT_RFC1035_NAME 0x40
|
||||
#define OT_INTERNAL 0x20
|
||||
#define OT_NAME 0x10
|
||||
|
||||
|
||||
static const struct {
|
||||
char *name;
|
||||
@@ -365,8 +371,8 @@ static const struct {
|
||||
{ "boot-file-size", 13, 2 },
|
||||
{ "domain-name", 15, OT_NAME },
|
||||
{ "swap-server", 16, OT_ADDR_LIST },
|
||||
{ "root-path", 17, 0 },
|
||||
{ "extension-path", 18, 0 },
|
||||
{ "root-path", 17, OT_NAME },
|
||||
{ "extension-path", 18, OT_NAME },
|
||||
{ "ip-forward-enable", 19, 1 },
|
||||
{ "non-local-source-routing", 20, 1 },
|
||||
{ "policy-filter", 21, OT_ADDR_LIST },
|
||||
@@ -383,7 +389,7 @@ static const struct {
|
||||
{ "ethernet-encap", 36, 1 },
|
||||
{ "tcp-ttl", 37, 1 },
|
||||
{ "tcp-keepalive", 38, 4 },
|
||||
{ "nis-domain", 40, 0 },
|
||||
{ "nis-domain", 40, OT_NAME },
|
||||
{ "nis-server", 41, OT_ADDR_LIST },
|
||||
{ "ntp-server", 42, OT_ADDR_LIST },
|
||||
{ "vendor-encap", 43, OT_INTERNAL },
|
||||
@@ -405,10 +411,10 @@ static const struct {
|
||||
{ "T2", 59, OT_INTERNAL },
|
||||
{ "vendor-class", 60, 0 },
|
||||
{ "client-id", 61,OT_INTERNAL },
|
||||
{ "nis+-domain", 64, 0 },
|
||||
{ "nis+-domain", 64, OT_NAME },
|
||||
{ "nis+-server", 65, OT_ADDR_LIST },
|
||||
{ "tftp-server", 66, 0 },
|
||||
{ "bootfile-name", 67, 0 },
|
||||
{ "tftp-server", 66, OT_NAME },
|
||||
{ "bootfile-name", 67, OT_NAME },
|
||||
{ "mobile-ip-home", 68, OT_ADDR_LIST },
|
||||
{ "smtp-server", 69, OT_ADDR_LIST },
|
||||
{ "pop3-server", 70, OT_ADDR_LIST },
|
||||
@@ -421,7 +427,7 @@ static const struct {
|
||||
{ "client-interface-id", 94, 0 },
|
||||
{ "client-machine-id", 97, 0 },
|
||||
{ "subnet-select", 118, OT_INTERNAL },
|
||||
{ "domain-search", 119, 0 },
|
||||
{ "domain-search", 119, OT_RFC1035_NAME },
|
||||
{ "sip-server", 120, 0 },
|
||||
{ "classless-static-route", 121, 0 },
|
||||
{ "vendor-id-encap", 125, 0 },
|
||||
@@ -776,6 +782,17 @@ static char *parse_dhcp_opt(char *arg, int flags)
|
||||
arg = comma;
|
||||
}
|
||||
|
||||
if (opt_len == 0 &&
|
||||
!(new->flags & (DHOPT_VENDOR | DHOPT_ENCAPSULATE | DHOPT_RFC3925)))
|
||||
for (i = 0; opttab[i].name; i++)
|
||||
if (new->opt == opttab[i].val)
|
||||
{
|
||||
opt_len = opttab[i].size;
|
||||
if (opt_len & OT_INTERNAL)
|
||||
opt_len = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
/* option may be missing with rfc3925 match */
|
||||
if (new->opt == 0)
|
||||
problem = _("bad dhcp-option");
|
||||
@@ -783,6 +800,7 @@ static char *parse_dhcp_opt(char *arg, int flags)
|
||||
{
|
||||
/* characterise the value */
|
||||
char c;
|
||||
int found_dig = 0;
|
||||
is_addr = is_hex = is_dec = is_string = 1;
|
||||
addrs = digs = 1;
|
||||
dots = 0;
|
||||
@@ -828,15 +846,22 @@ static char *parse_dhcp_opt(char *arg, int flags)
|
||||
(c == '*' && (flags & DHOPT_MATCH))))
|
||||
is_hex = 0;
|
||||
}
|
||||
else
|
||||
found_dig = 1;
|
||||
|
||||
if (!found_dig)
|
||||
is_dec = is_addr = 0;
|
||||
|
||||
/* We know that some options take addresses */
|
||||
|
||||
if (opt_len & OT_ADDR_LIST)
|
||||
{
|
||||
is_string = is_dec = is_hex = 0;
|
||||
if (!is_addr || dots == 0)
|
||||
problem = _("bad IP address");
|
||||
}
|
||||
/* or names */
|
||||
else if (opt_len & (OT_NAME | OT_RFC1035_NAME))
|
||||
is_addr = is_dec = is_hex = 0;
|
||||
|
||||
if (is_hex && digs > 1)
|
||||
{
|
||||
@@ -1032,7 +1057,15 @@ static char *parse_dhcp_opt(char *arg, int flags)
|
||||
|
||||
#endif
|
||||
|
||||
static char *one_opt(int option, char *arg, char *gen_prob, int nest)
|
||||
void set_option_bool(unsigned int opt)
|
||||
{
|
||||
if (opt < 32)
|
||||
daemon->options |= 1u << opt;
|
||||
else
|
||||
daemon->options2 |= 1u << (opt - 32);
|
||||
}
|
||||
|
||||
static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
|
||||
{
|
||||
int i;
|
||||
char *comma, *problem = NULL;;
|
||||
@@ -1045,7 +1078,7 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
|
||||
{
|
||||
int rept = usage[i].rept;
|
||||
|
||||
if (nest == 0)
|
||||
if (command_line)
|
||||
{
|
||||
/* command line */
|
||||
if (rept == ARG_USED_CL)
|
||||
@@ -1064,7 +1097,7 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
|
||||
|
||||
if (rept != ARG_DUP && rept != ARG_ONE && rept != ARG_USED_CL)
|
||||
{
|
||||
daemon->options |= rept;
|
||||
set_option_bool(rept);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1078,7 +1111,7 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
|
||||
char *file = opt_string_alloc(arg);
|
||||
if (file)
|
||||
{
|
||||
one_file(file, nest, 0);
|
||||
one_file(file, 0);
|
||||
free(file);
|
||||
}
|
||||
break;
|
||||
@@ -1145,8 +1178,8 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
|
||||
if (!S_ISREG(buf.st_mode))
|
||||
continue;
|
||||
|
||||
/* dir is one level, so files must be readable */
|
||||
one_file(path, nest + 1, 0);
|
||||
/* files must be readable */
|
||||
one_file(path, 0);
|
||||
free(path);
|
||||
}
|
||||
|
||||
@@ -1183,20 +1216,6 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
|
||||
daemon->runfile = opt_string_alloc(arg);
|
||||
break;
|
||||
|
||||
case LOPT_DHCP_HOST: /* --dhcp-hostfile */
|
||||
if (daemon->dhcp_hosts_file)
|
||||
problem = _("only one dhcp-hostsfile allowed");
|
||||
else
|
||||
daemon->dhcp_hosts_file = opt_string_alloc(arg);
|
||||
break;
|
||||
|
||||
case LOPT_DHCP_OPTS: /* --dhcp-optsfile */
|
||||
if (daemon->dhcp_opts_file)
|
||||
problem = _("only one dhcp-optsfile allowed");
|
||||
else
|
||||
daemon->dhcp_opts_file = opt_string_alloc(arg);
|
||||
break;
|
||||
|
||||
case 'r': /* --resolv-file */
|
||||
{
|
||||
char *name = opt_string_alloc(arg);
|
||||
@@ -1275,6 +1294,8 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
|
||||
break;
|
||||
#endif
|
||||
|
||||
case LOPT_DHCP_HOST: /* --dhcp-hostfile */
|
||||
case LOPT_DHCP_OPTS: /* --dhcp-optsfile */
|
||||
case 'H': /* --addn-hosts */
|
||||
{
|
||||
struct hostsfile *new = opt_malloc(sizeof(struct hostsfile));
|
||||
@@ -1282,14 +1303,27 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
|
||||
new->fname = opt_string_alloc(arg);
|
||||
new->index = hosts_index++;
|
||||
new->flags = 0;
|
||||
new->next = daemon->addn_hosts;
|
||||
daemon->addn_hosts = new;
|
||||
if (option == 'H')
|
||||
{
|
||||
new->next = daemon->addn_hosts;
|
||||
daemon->addn_hosts = new;
|
||||
}
|
||||
else if (option == LOPT_DHCP_HOST)
|
||||
{
|
||||
new->next = daemon->dhcp_hosts_file;
|
||||
daemon->dhcp_hosts_file = new;
|
||||
}
|
||||
else if (option == LOPT_DHCP_OPTS)
|
||||
{
|
||||
new->next = daemon->dhcp_opts_file;
|
||||
daemon->dhcp_opts_file = new;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 's': /* --domain */
|
||||
if (strcmp (arg, "#") == 0)
|
||||
daemon->options |= OPT_RESOLV_DOMAIN;
|
||||
set_option_bool(OPT_RESOLV_DOMAIN);
|
||||
else
|
||||
{
|
||||
char *d;
|
||||
@@ -1301,18 +1335,59 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
|
||||
if (comma)
|
||||
{
|
||||
struct cond_domain *new = safe_malloc(sizeof(struct cond_domain));
|
||||
char *netpart;
|
||||
|
||||
unhide_metas(comma);
|
||||
if ((arg = split_chr(comma, '/')))
|
||||
if ((netpart = split_chr(comma, '/')))
|
||||
{
|
||||
int mask;
|
||||
int msize, mask;
|
||||
arg = split(netpart);
|
||||
if ((new->start.s_addr = inet_addr(comma)) == (in_addr_t)-1 ||
|
||||
!atoi_check(arg, &mask))
|
||||
!atoi_check(netpart, &msize))
|
||||
option = '?';
|
||||
else
|
||||
{
|
||||
mask = (1 << (32 - mask)) - 1;
|
||||
mask = (1 << (32 - msize)) - 1;
|
||||
new->start.s_addr = ntohl(htonl(new->start.s_addr) & ~mask);
|
||||
new->end.s_addr = new->start.s_addr | htonl(mask);
|
||||
if (arg)
|
||||
{
|
||||
/* generate the equivalent of
|
||||
local=/<domain>/
|
||||
local=/xxx.yyy.zzz.in-addr.arpa/ */
|
||||
|
||||
if (strcmp(arg, "local") != 0 ||
|
||||
(msize != 8 && msize != 16 && msize != 24))
|
||||
option = '?';
|
||||
else
|
||||
{
|
||||
struct server *serv = opt_malloc(sizeof(struct server));
|
||||
in_addr_t a = ntohl(new->start.s_addr) >> 8;
|
||||
char *p;
|
||||
|
||||
memset(serv, 0, sizeof(struct server));
|
||||
serv->domain = d;
|
||||
serv->flags = SERV_HAS_DOMAIN | SERV_NO_ADDR;
|
||||
serv->next = daemon->servers;
|
||||
daemon->servers = serv;
|
||||
|
||||
serv = opt_malloc(sizeof(struct server));
|
||||
memset(serv, 0, sizeof(struct server));
|
||||
p = serv->domain = opt_malloc(25); /* strlen("xxx.yyy.zzz.in-addr.arpa")+1 */
|
||||
|
||||
if (msize == 24)
|
||||
p += sprintf(p, "%d.", a & 0xff);
|
||||
a = a >> 8;
|
||||
if (msize != 8)
|
||||
p += sprintf(p, "%d.", a & 0xff);
|
||||
a = a >> 8;
|
||||
p += sprintf(p, "%d.in-addr.arpa", a & 0xff);
|
||||
|
||||
serv->flags = SERV_HAS_DOMAIN | SERV_NO_ADDR;
|
||||
serv->next = daemon->servers;
|
||||
daemon->servers = serv;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ((arg = split(comma)))
|
||||
@@ -1934,7 +2009,9 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
|
||||
len = (int) strlen(arg);
|
||||
}
|
||||
|
||||
if ((new->clid = opt_malloc(len)))
|
||||
if (len == -1)
|
||||
problem = _("bad hex constant");
|
||||
else if ((new->clid = opt_malloc(len)))
|
||||
{
|
||||
new->flags |= CONFIG_CLID;
|
||||
new->clid_len = len;
|
||||
@@ -1957,10 +2034,15 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
|
||||
else
|
||||
{
|
||||
struct hwaddr_config *newhw = opt_malloc(sizeof(struct hwaddr_config));
|
||||
newhw->next = new->hwaddr;
|
||||
new->hwaddr = newhw;
|
||||
newhw->hwaddr_len = parse_hex(a[j], newhw->hwaddr, DHCP_CHADDR_MAX,
|
||||
&newhw->wildcard_mask, &newhw->hwaddr_type);
|
||||
if ((newhw->hwaddr_len = parse_hex(a[j], newhw->hwaddr, DHCP_CHADDR_MAX,
|
||||
&newhw->wildcard_mask, &newhw->hwaddr_type)) == -1)
|
||||
problem = _("bad hex constant");
|
||||
else
|
||||
{
|
||||
|
||||
newhw->next = new->hwaddr;
|
||||
new->hwaddr = newhw;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (strchr(a[j], '.') && (in.s_addr = inet_addr(a[j])) != (in_addr_t)-1)
|
||||
@@ -2295,8 +2377,13 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
|
||||
new->netid.net = opt_string_alloc(set_prefix(arg));
|
||||
unhide_metas(comma);
|
||||
new->hwaddr_len = parse_hex(comma, new->hwaddr, DHCP_CHADDR_MAX, &new->mask, &new->hwaddr_type);
|
||||
new->next = daemon->dhcp_macs;
|
||||
daemon->dhcp_macs = new;
|
||||
if (new->hwaddr_len == -1)
|
||||
option = '?';
|
||||
else
|
||||
{
|
||||
new->next = daemon->dhcp_macs;
|
||||
daemon->dhcp_macs = new;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -2587,63 +2674,49 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
|
||||
case 'Y': /* --txt-record */
|
||||
{
|
||||
struct txt_record *new;
|
||||
unsigned char *p, *q;
|
||||
|
||||
if ((comma = split(arg)))
|
||||
comma--;
|
||||
|
||||
gen_prob = _("TXT record string too long");
|
||||
|
||||
if ((q = (unsigned char *)comma))
|
||||
while (1)
|
||||
{
|
||||
size_t len;
|
||||
if ((p = (unsigned char *)strchr((char*)q+1, ',')))
|
||||
{
|
||||
if ((len = p - q - 1) > 255)
|
||||
option = '?';
|
||||
*q = len;
|
||||
for (q = q+1; q < p; q++)
|
||||
*q = unhide_meta(*q);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((len = strlen((char *)q+1)) > 255)
|
||||
option = '?';
|
||||
*q = len;
|
||||
for (q = q+1; *q; q++)
|
||||
*q = unhide_meta(*q);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned char *p, *cnt;
|
||||
size_t len;
|
||||
|
||||
comma = split(arg);
|
||||
|
||||
new = opt_malloc(sizeof(struct txt_record));
|
||||
new->next = daemon->txt;
|
||||
daemon->txt = new;
|
||||
new->class = C_IN;
|
||||
if (comma)
|
||||
{
|
||||
new->len = q - ((unsigned char *)comma);
|
||||
new->txt = opt_malloc(new->len);
|
||||
memcpy(new->txt, comma, new->len);
|
||||
}
|
||||
else
|
||||
{
|
||||
static char empty[] = "";
|
||||
new->len = 1;
|
||||
new->txt = empty;
|
||||
}
|
||||
|
||||
/* ensure arg is terminated */
|
||||
if (comma)
|
||||
*comma = 0;
|
||||
|
||||
if (!(new->name = canonicalise_opt(arg)))
|
||||
{
|
||||
problem = _("bad TXT record");
|
||||
break;
|
||||
}
|
||||
|
||||
len = comma ? strlen(comma) : 0;
|
||||
len += (len/255) + 1; /* room for extra counts */
|
||||
new->txt = p = opt_malloc(len);
|
||||
|
||||
cnt = p++;
|
||||
*cnt = 0;
|
||||
|
||||
while (comma && *comma)
|
||||
{
|
||||
unsigned char c = (unsigned char)*comma++;
|
||||
|
||||
if (c == ',' || *cnt == 255)
|
||||
{
|
||||
if (c != ',')
|
||||
comma--;
|
||||
cnt = p++;
|
||||
*cnt = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
*p++ = unhide_meta(c);
|
||||
(*cnt)++;
|
||||
}
|
||||
}
|
||||
|
||||
new->len = p - new->txt;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2716,53 +2789,10 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void one_file(char *file, int nest, int hard_opt)
|
||||
static void read_file(char *file, FILE *f, int hard_opt)
|
||||
{
|
||||
volatile int lineno = 0;
|
||||
FILE *f;
|
||||
char *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)
|
||||
return; /* No conffile, all done. */
|
||||
else
|
||||
{
|
||||
char *str = _("cannot read %s: %s");
|
||||
if (hard_opt != 0)
|
||||
{
|
||||
my_syslog(LOG_ERR, str, file, strerror(errno));
|
||||
return;
|
||||
}
|
||||
else
|
||||
die(str, file, EC_FILE);
|
||||
}
|
||||
}
|
||||
|
||||
while (fgets(buff, MAXDNAME, f))
|
||||
{
|
||||
@@ -2877,7 +2907,7 @@ static void one_file(char *file, int nest, int hard_opt)
|
||||
}
|
||||
|
||||
if (!errmess)
|
||||
errmess = one_opt(option, arg, _("error"), nest + 1);
|
||||
errmess = one_opt(option, arg, _("error"), 0);
|
||||
|
||||
if (errmess)
|
||||
{
|
||||
@@ -2894,13 +2924,183 @@ static void one_file(char *file, int nest, int hard_opt)
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
static void one_file(char *file, int hard_opt)
|
||||
{
|
||||
FILE *f;
|
||||
int nofile_ok = 0;
|
||||
static int read_stdin = 0;
|
||||
static struct fileread {
|
||||
dev_t dev;
|
||||
ino_t ino;
|
||||
struct fileread *next;
|
||||
} *filesread = NULL;
|
||||
|
||||
if (hard_opt == '7')
|
||||
{
|
||||
/* default conf-file reading */
|
||||
hard_opt = 0;
|
||||
nofile_ok = 1;
|
||||
}
|
||||
|
||||
if (hard_opt == 0 && strcmp(file, "-") == 0)
|
||||
{
|
||||
if (read_stdin == 1)
|
||||
return;
|
||||
read_stdin = 1;
|
||||
file = "stdin";
|
||||
f = stdin;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* ignore repeated files. */
|
||||
struct stat statbuf;
|
||||
|
||||
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 (!(f = fopen(file, "r")))
|
||||
{
|
||||
if (errno == ENOENT && nofile_ok)
|
||||
return; /* No conffile, all done. */
|
||||
else
|
||||
{
|
||||
char *str = _("cannot read %s: %s");
|
||||
if (hard_opt != 0)
|
||||
{
|
||||
my_syslog(LOG_ERR, str, file, strerror(errno));
|
||||
return;
|
||||
}
|
||||
else
|
||||
die(str, file, EC_FILE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
read_file(file, f, hard_opt);
|
||||
}
|
||||
|
||||
/* expand any name which is a directory */
|
||||
struct hostsfile *expand_filelist(struct hostsfile *list)
|
||||
{
|
||||
int i;
|
||||
struct hostsfile *ah;
|
||||
|
||||
for (i = 0, ah = list; ah; ah = ah->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 = list; 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 = list; 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 = list;
|
||||
list = 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
#ifdef HAVE_DHCP
|
||||
void reread_dhcp(void)
|
||||
{
|
||||
struct hostsfile *hf;
|
||||
|
||||
if (daemon->dhcp_hosts_file)
|
||||
{
|
||||
struct dhcp_config *configs, *cp, **up;
|
||||
|
||||
|
||||
/* remove existing... */
|
||||
for (up = &daemon->dhcp_conf, configs = daemon->dhcp_conf; configs; configs = cp)
|
||||
{
|
||||
@@ -2930,7 +3130,6 @@ void reread_dhcp(void)
|
||||
if (configs->flags & CONFIG_NAME)
|
||||
free(configs->hostname);
|
||||
|
||||
|
||||
*up = configs->next;
|
||||
free(configs);
|
||||
}
|
||||
@@ -2938,8 +3137,13 @@ void reread_dhcp(void)
|
||||
up = &configs->next;
|
||||
}
|
||||
|
||||
one_file(daemon->dhcp_hosts_file, 1, LOPT_BANK);
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("read %s"), daemon->dhcp_hosts_file);
|
||||
daemon->dhcp_hosts_file = expand_filelist(daemon->dhcp_hosts_file);
|
||||
for (hf = daemon->dhcp_hosts_file; hf; hf = hf->next)
|
||||
if (!(hf->flags & AH_INACTIVE))
|
||||
{
|
||||
one_file(hf->fname, LOPT_BANK);
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("read %s"), hf->fname);
|
||||
}
|
||||
}
|
||||
|
||||
if (daemon->dhcp_opts_file)
|
||||
@@ -2969,8 +3173,13 @@ void reread_dhcp(void)
|
||||
up = &opts->next;
|
||||
}
|
||||
|
||||
one_file(daemon->dhcp_opts_file, 1, LOPT_OPTS);
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("read %s"), daemon->dhcp_opts_file);
|
||||
daemon->dhcp_opts_file = expand_filelist(daemon->dhcp_opts_file);
|
||||
for (hf = daemon->dhcp_opts_file; hf; hf = hf->next)
|
||||
if (!(hf->flags & AH_INACTIVE))
|
||||
{
|
||||
one_file(hf->fname, LOPT_OPTS);
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("read %s"), hf->fname);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -2978,7 +3187,7 @@ void reread_dhcp(void)
|
||||
void read_opts(int argc, char **argv, char *compile_opts)
|
||||
{
|
||||
char *buff = opt_malloc(MAXDNAME);
|
||||
int option, nest = 0, testmode = 0;
|
||||
int option, conffile_opt = '7', testmode = 0;
|
||||
char *errmess, *arg, *conffile = CONFFILE;
|
||||
|
||||
opterr = 0;
|
||||
@@ -3015,8 +3224,12 @@ void read_opts(int argc, char **argv, char *compile_opts)
|
||||
#endif
|
||||
|
||||
if (option == -1)
|
||||
break;
|
||||
|
||||
{
|
||||
if (optind < argc)
|
||||
die(_("junk found in command line"), NULL, EC_BADCONF);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Copy optarg so that argv doesn't get changed */
|
||||
if (optarg)
|
||||
{
|
||||
@@ -3051,15 +3264,15 @@ void read_opts(int argc, char **argv, char *compile_opts)
|
||||
}
|
||||
else if (option == 'C')
|
||||
{
|
||||
conffile_opt = 0; /* file must exist */
|
||||
conffile = opt_string_alloc(arg);
|
||||
nest++;
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef HAVE_GETOPT_LONG
|
||||
errmess = one_opt(option, arg, _("try --help"), 0);
|
||||
errmess = one_opt(option, arg, _("try --help"), 1);
|
||||
#else
|
||||
errmess = one_opt(option, arg, _("try -w"), 0);
|
||||
errmess = one_opt(option, arg, _("try -w"), 1);
|
||||
#endif
|
||||
if (errmess)
|
||||
die(_("bad command line options: %s"), errmess, EC_BADCONF);
|
||||
@@ -3067,7 +3280,7 @@ void read_opts(int argc, char **argv, char *compile_opts)
|
||||
}
|
||||
|
||||
if (conffile)
|
||||
one_file(conffile, nest, 0);
|
||||
one_file(conffile, conffile_opt);
|
||||
|
||||
/* port might not be known when the address is parsed - fill in here */
|
||||
if (daemon->servers)
|
||||
@@ -3098,7 +3311,7 @@ void read_opts(int argc, char **argv, char *compile_opts)
|
||||
}
|
||||
|
||||
/* only one of these need be specified: the other defaults to the host-name */
|
||||
if ((daemon->options & OPT_LOCALMX) || daemon->mxnames || daemon->mxtarget)
|
||||
if (option_bool(OPT_LOCALMX) || daemon->mxnames || daemon->mxtarget)
|
||||
{
|
||||
struct mx_srv_record *mx;
|
||||
|
||||
@@ -3109,7 +3322,7 @@ void read_opts(int argc, char **argv, char *compile_opts)
|
||||
if (!mx->issrv && hostname_isequal(mx->name, buff))
|
||||
break;
|
||||
|
||||
if ((daemon->mxtarget || (daemon->options & OPT_LOCALMX)) && !mx)
|
||||
if ((daemon->mxtarget || option_bool(OPT_LOCALMX)) && !mx)
|
||||
{
|
||||
mx = opt_malloc(sizeof(struct mx_srv_record));
|
||||
mx->next = daemon->mxnames;
|
||||
@@ -3127,18 +3340,18 @@ void read_opts(int argc, char **argv, char *compile_opts)
|
||||
mx->target = daemon->mxtarget;
|
||||
}
|
||||
|
||||
if (!(daemon->options & OPT_NO_RESOLV) &&
|
||||
if (!option_bool(OPT_NO_RESOLV) &&
|
||||
daemon->resolv_files &&
|
||||
daemon->resolv_files->next &&
|
||||
(daemon->options & OPT_NO_POLL))
|
||||
option_bool(OPT_NO_POLL))
|
||||
die(_("only one resolv.conf file allowed in no-poll mode."), NULL, EC_BADCONF);
|
||||
|
||||
if (daemon->options & OPT_RESOLV_DOMAIN)
|
||||
if (option_bool(OPT_RESOLV_DOMAIN))
|
||||
{
|
||||
char *line;
|
||||
FILE *f;
|
||||
|
||||
if ((daemon->options & OPT_NO_RESOLV) ||
|
||||
if (option_bool(OPT_NO_RESOLV) ||
|
||||
!daemon->resolv_files ||
|
||||
(daemon->resolv_files)->next)
|
||||
die(_("must have exactly one resolv.conf to read domain from."), NULL, EC_BADCONF);
|
||||
@@ -3181,7 +3394,7 @@ void read_opts(int argc, char **argv, char *compile_opts)
|
||||
srv->name = opt_string_alloc(buff);
|
||||
}
|
||||
}
|
||||
else if (daemon->options & OPT_DHCP_FQDN)
|
||||
else if (option_bool(OPT_DHCP_FQDN))
|
||||
die(_("there must be a default domain when --dhcp-fqdn is set"), NULL, EC_BADCONF);
|
||||
|
||||
if (testmode)
|
||||
|
||||
195
src/rfc1035.c
195
src/rfc1035.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2010 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2011 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
|
||||
@@ -510,8 +510,122 @@ unsigned char *find_pseudoheader(HEADER *header, size_t plen, size_t *len, unsi
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
struct macparm {
|
||||
unsigned char *limit;
|
||||
HEADER *header;
|
||||
size_t plen;
|
||||
union mysockaddr *l3;
|
||||
};
|
||||
|
||||
static int filter_mac(int family, char *addrp, char *mac, size_t maclen, void *parmv)
|
||||
{
|
||||
struct macparm *parm = parmv;
|
||||
int match = 0;
|
||||
unsigned short rdlen;
|
||||
HEADER *header = parm->header;
|
||||
unsigned char *lenp, *datap, *p;
|
||||
|
||||
if (family == parm->l3->sa.sa_family)
|
||||
{
|
||||
if (family == AF_INET && memcmp (&parm->l3->in.sin_addr, addrp, INADDRSZ) == 0)
|
||||
match = 1;
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
if (family == AF_INET6 && memcmp (&parm->l3->in6.sin6_addr, addrp, IN6ADDRSZ) == 0)
|
||||
match = 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!match)
|
||||
return 1; /* continue */
|
||||
|
||||
if (ntohs(header->arcount) == 0)
|
||||
{
|
||||
/* We are adding the pseudoheader */
|
||||
if (!(p = skip_questions(header, parm->plen)) ||
|
||||
!(p = skip_section(p,
|
||||
ntohs(header->ancount) + ntohs(header->nscount),
|
||||
header, parm->plen)))
|
||||
return 0;
|
||||
*p++ = 0; /* empty name */
|
||||
PUTSHORT(T_OPT, p);
|
||||
PUTSHORT(PACKETSZ, p); /* max packet length - is 512 suitable default for non-EDNS0 resolvers? */
|
||||
PUTLONG(0, p); /* extended RCODE */
|
||||
lenp = p;
|
||||
PUTSHORT(0, p); /* RDLEN */
|
||||
rdlen = 0;
|
||||
if (((ssize_t)maclen) > (parm->limit - (p + 4)))
|
||||
return 0; /* Too big */
|
||||
header->arcount = htons(1);
|
||||
datap = p;
|
||||
}
|
||||
else
|
||||
{
|
||||
int i, is_sign;
|
||||
unsigned short code, len;
|
||||
|
||||
if (ntohs(header->arcount) != 1 ||
|
||||
!(p = find_pseudoheader(header, parm->plen, NULL, NULL, &is_sign)) ||
|
||||
is_sign ||
|
||||
(!(p = skip_name(p, header, parm->plen, 10))))
|
||||
return 0;
|
||||
|
||||
p += 8; /* skip UDP length and RCODE */
|
||||
|
||||
lenp = p;
|
||||
GETSHORT(rdlen, p);
|
||||
if (!CHECK_LEN(header, p, parm->plen, rdlen))
|
||||
return 0; /* bad packet */
|
||||
datap = p;
|
||||
|
||||
/* check if option already there */
|
||||
for (i = 0; i + 4 < rdlen; i += len + 4)
|
||||
{
|
||||
GETSHORT(code, p);
|
||||
GETSHORT(len, p);
|
||||
if (code == EDNS0_OPTION_MAC)
|
||||
return 0;
|
||||
p += len;
|
||||
}
|
||||
|
||||
if (((ssize_t)maclen) > (parm->limit - (p + 4)))
|
||||
return 0; /* Too big */
|
||||
}
|
||||
|
||||
PUTSHORT(EDNS0_OPTION_MAC, p);
|
||||
PUTSHORT(maclen, p);
|
||||
memcpy(p, mac, maclen);
|
||||
p += maclen;
|
||||
|
||||
PUTSHORT(p - datap, lenp);
|
||||
parm->plen = p - (unsigned char *)header;
|
||||
|
||||
return 0; /* done */
|
||||
}
|
||||
|
||||
|
||||
size_t add_mac(HEADER *header, size_t plen, char *limit, union mysockaddr *l3)
|
||||
{
|
||||
struct macparm parm;
|
||||
|
||||
/* Must have an existing pseudoheader as the only ar-record,
|
||||
or have no ar-records. Must also not be signed */
|
||||
|
||||
if (ntohs(header->arcount) > 1)
|
||||
return plen;
|
||||
|
||||
parm.header = header;
|
||||
parm.limit = (unsigned char *)limit;
|
||||
parm.plen = plen;
|
||||
parm.l3 = l3;
|
||||
|
||||
iface_enumerate(AF_UNSPEC, &parm, filter_mac);
|
||||
|
||||
return parm.plen;
|
||||
}
|
||||
|
||||
|
||||
/* is addr in the non-globally-routed IP space? */
|
||||
static int private_net(struct in_addr addr, int ban_localhost)
|
||||
{
|
||||
@@ -532,7 +646,7 @@ static unsigned char *do_doctor(unsigned char *p, int count, HEADER *header, siz
|
||||
|
||||
for (i = count; i != 0; i--)
|
||||
{
|
||||
if (name && (daemon->options & OPT_LOG))
|
||||
if (name && option_bool(OPT_LOG))
|
||||
{
|
||||
if (!extract_name(header, qlen, &p, name, 1, 10))
|
||||
return 0;
|
||||
@@ -575,7 +689,7 @@ static unsigned char *do_doctor(unsigned char *p, int count, HEADER *header, siz
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (qtype == T_TXT && name && (daemon->options & OPT_LOG))
|
||||
else if (qtype == T_TXT && name && option_bool(OPT_LOG))
|
||||
{
|
||||
unsigned char *p1 = p;
|
||||
if (!CHECK_LEN(header, p1, qlen, rdlen))
|
||||
@@ -592,7 +706,7 @@ static unsigned char *do_doctor(unsigned char *p, int count, HEADER *header, siz
|
||||
p2++;
|
||||
}
|
||||
*p2 = 0;
|
||||
my_syslog(LOG_DEBUG, "reply %s is %s", name, p1);
|
||||
my_syslog(LOG_INFO, "reply %s is %s", name, p1);
|
||||
/* restore */
|
||||
memmove(p1 + 1, p1, len);
|
||||
*p1 = len;
|
||||
@@ -665,7 +779,8 @@ static int find_soa(HEADER *header, size_t qlen, char *name)
|
||||
either because of lack of memory, or lack of SOA records. These are treated by the cache code as
|
||||
expired and cleaned out that way.
|
||||
Return 1 if we reject an address because it look like part of dns-rebinding attack. */
|
||||
int extract_addresses(HEADER *header, size_t qlen, char *name, time_t now, int is_sign, int check_rebind)
|
||||
int extract_addresses(HEADER *header, size_t qlen, char *name, time_t now,
|
||||
int is_sign, int check_rebind, int checking_disabled)
|
||||
{
|
||||
unsigned char *p, *p1, *endrr, *namep;
|
||||
int i, j, qtype, qclass, aqtype, aqclass, ardlen, res, searched_soa = 0;
|
||||
@@ -675,7 +790,7 @@ int extract_addresses(HEADER *header, size_t qlen, char *name, time_t now, int i
|
||||
cache_start_insert();
|
||||
|
||||
/* find_soa is needed for dns_doctor and logging side-effects, so don't call it lazily if there are any. */
|
||||
if (daemon->doctors || (daemon->options & OPT_LOG))
|
||||
if (daemon->doctors || option_bool(OPT_LOG))
|
||||
{
|
||||
searched_soa = 1;
|
||||
ttl = find_soa(header, qlen, name);
|
||||
@@ -761,7 +876,7 @@ int extract_addresses(HEADER *header, size_t qlen, char *name, time_t now, int i
|
||||
}
|
||||
}
|
||||
|
||||
if (!found && !(daemon->options & OPT_NO_NEG))
|
||||
if (!found && !option_bool(OPT_NO_NEG))
|
||||
{
|
||||
if (!searched_soa)
|
||||
{
|
||||
@@ -848,7 +963,7 @@ int extract_addresses(HEADER *header, size_t qlen, char *name, time_t now, int i
|
||||
/* check for returned address in private space */
|
||||
if (check_rebind &&
|
||||
(flags & F_IPV4) &&
|
||||
private_net(addr.addr.addr4, !(daemon->options & OPT_LOCAL_REBIND)))
|
||||
private_net(addr.addr.addr4, !option_bool(OPT_LOCAL_REBIND)))
|
||||
return 1;
|
||||
|
||||
newc = cache_insert(name, &addr, now, attl, flags | F_FORWARD);
|
||||
@@ -867,7 +982,7 @@ int extract_addresses(HEADER *header, size_t qlen, char *name, time_t now, int i
|
||||
}
|
||||
}
|
||||
|
||||
if (!found && !(daemon->options & OPT_NO_NEG))
|
||||
if (!found && !option_bool(OPT_NO_NEG))
|
||||
{
|
||||
if (!searched_soa)
|
||||
{
|
||||
@@ -889,18 +1004,19 @@ int extract_addresses(HEADER *header, size_t qlen, char *name, time_t now, int i
|
||||
}
|
||||
}
|
||||
|
||||
/* Don't put stuff from a truncated packet into the cache, but do everything else */
|
||||
if (!header->tc)
|
||||
/* Don't put stuff from a truncated packet into the cache,
|
||||
also don't cache replies where DNSSEC validation was turned off, either
|
||||
the upstream server told us so, or the original query specified it. */
|
||||
if (!header->tc && !header->cd && !checking_disabled)
|
||||
cache_end_insert();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If the packet holds exactly one query
|
||||
return F_IPV4 or F_IPV6 and leave the name from the query in name.
|
||||
Abuse F_BIGNAME to indicate an NS query - yuck. */
|
||||
return F_IPV4 or F_IPV6 and leave the name from the query in name */
|
||||
|
||||
unsigned short extract_request(HEADER *header, size_t qlen, char *name, unsigned short *typep)
|
||||
unsigned int extract_request(HEADER *header, size_t qlen, char *name, unsigned short *typep)
|
||||
{
|
||||
unsigned char *p = (unsigned char *)(header+1);
|
||||
int qtype, qclass;
|
||||
@@ -929,7 +1045,7 @@ unsigned short extract_request(HEADER *header, size_t qlen, char *name, unsigned
|
||||
if (qtype == T_ANY)
|
||||
return F_IPV4 | F_IPV6;
|
||||
if (qtype == T_NS || qtype == T_SOA)
|
||||
return F_QUERY | F_BIGNAME;
|
||||
return F_QUERY | F_NSRR;
|
||||
}
|
||||
|
||||
return F_QUERY;
|
||||
@@ -937,7 +1053,7 @@ unsigned short extract_request(HEADER *header, size_t qlen, char *name, unsigned
|
||||
|
||||
|
||||
size_t setup_reply(HEADER *header, size_t qlen,
|
||||
struct all_addr *addrp, unsigned short flags, unsigned long ttl)
|
||||
struct all_addr *addrp, unsigned int flags, unsigned long ttl)
|
||||
{
|
||||
unsigned char *p = skip_questions(header, qlen);
|
||||
|
||||
@@ -1249,7 +1365,7 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
|
||||
ans = 1;
|
||||
if (!dryrun)
|
||||
{
|
||||
log_query(F_CNAME | F_FORWARD | F_CONFIG | F_NXDOMAIN, name, NULL, "<TXT>");
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, "<TXT>");
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
daemon->local_ttl, NULL,
|
||||
T_TXT, t->class, "t", t->len, t->txt))
|
||||
@@ -1300,7 +1416,7 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
|
||||
ans = 1;
|
||||
if (!dryrun)
|
||||
{
|
||||
log_query(F_CNAME | F_FORWARD | F_CONFIG | F_NXDOMAIN, name, NULL, "<PTR>");
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, "<PTR>");
|
||||
for (ptr = daemon->ptr; ptr; ptr = ptr->next)
|
||||
if (hostname_isequal(name, ptr->name) &&
|
||||
add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
@@ -1344,7 +1460,7 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
|
||||
}
|
||||
} while ((crecp = cache_find_by_addr(crecp, &addr, now, is_arpa)));
|
||||
else if (is_arpa == F_IPV4 &&
|
||||
(daemon->options & OPT_BOGUSPRIV) &&
|
||||
option_bool(OPT_BOGUSPRIV) &&
|
||||
private_net(addr.addr.addr4, 1))
|
||||
{
|
||||
/* if not in cache, enabled and private IPV4 address, return NXDOMAIN */
|
||||
@@ -1442,7 +1558,7 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
|
||||
|
||||
/* See if a putative address is on the network from which we recieved
|
||||
the query, is so we'll filter other answers. */
|
||||
if (local_addr.s_addr != 0 && (daemon->options & OPT_LOCALISE) && flag == F_IPV4)
|
||||
if (local_addr.s_addr != 0 && option_bool(OPT_LOCALISE) && flag == F_IPV4)
|
||||
{
|
||||
struct crec *save = crecp;
|
||||
do {
|
||||
@@ -1525,7 +1641,7 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
|
||||
if (!dryrun)
|
||||
{
|
||||
unsigned int offset;
|
||||
log_query(F_CNAME | F_FORWARD | F_CONFIG | F_NXDOMAIN, name, NULL, "<MX>");
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>");
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
|
||||
&offset, T_MX, C_IN, "sd", rec->weight, rec->target))
|
||||
{
|
||||
@@ -1536,16 +1652,16 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
|
||||
}
|
||||
}
|
||||
|
||||
if (!found && (daemon->options & (OPT_SELFMX | OPT_LOCALMX)) &&
|
||||
if (!found && (option_bool(OPT_SELFMX) || option_bool(OPT_LOCALMX)) &&
|
||||
cache_find_by_name(NULL, name, now, F_HOSTS | F_DHCP))
|
||||
{
|
||||
ans = 1;
|
||||
if (!dryrun)
|
||||
{
|
||||
log_query(F_CNAME | F_FORWARD | F_CONFIG | F_NXDOMAIN, name, NULL, "<MX>");
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>");
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl, NULL,
|
||||
T_MX, C_IN, "sd", 1,
|
||||
(daemon->options & OPT_SELFMX) ? name : daemon->mxtarget))
|
||||
option_bool(OPT_SELFMX) ? name : daemon->mxtarget))
|
||||
anscount++;
|
||||
}
|
||||
}
|
||||
@@ -1554,7 +1670,8 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
|
||||
if (qtype == T_SRV || qtype == T_ANY)
|
||||
{
|
||||
int found = 0;
|
||||
|
||||
struct mx_srv_record *move = NULL, **up = &daemon->mxnames;
|
||||
|
||||
for (rec = daemon->mxnames; rec; rec = rec->next)
|
||||
if (rec->issrv && hostname_isequal(name, rec->name))
|
||||
{
|
||||
@@ -1562,7 +1679,7 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
|
||||
if (!dryrun)
|
||||
{
|
||||
unsigned int offset;
|
||||
log_query(F_CNAME | F_FORWARD | F_CONFIG | F_NXDOMAIN, name, NULL, "<SRV>");
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, "<SRV>");
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
|
||||
&offset, T_SRV, C_IN, "sssd",
|
||||
rec->priority, rec->weight, rec->srvport, rec->target))
|
||||
@@ -1572,9 +1689,27 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
|
||||
rec->offset = offset;
|
||||
}
|
||||
}
|
||||
|
||||
/* unlink first SRV record found */
|
||||
if (!move)
|
||||
{
|
||||
move = rec;
|
||||
*up = rec->next;
|
||||
}
|
||||
else
|
||||
up = &rec->next;
|
||||
}
|
||||
else
|
||||
up = &rec->next;
|
||||
|
||||
/* put first SRV record back at the end. */
|
||||
if (move)
|
||||
{
|
||||
*up = move;
|
||||
move->next = NULL;
|
||||
}
|
||||
|
||||
if (!found && (daemon->options & OPT_FILTER) && (qtype == T_SRV || (qtype == T_ANY && strchr(name, '_'))))
|
||||
if (!found && option_bool(OPT_FILTER) && (qtype == T_SRV || (qtype == T_ANY && strchr(name, '_'))))
|
||||
{
|
||||
ans = 1;
|
||||
if (!dryrun)
|
||||
@@ -1591,7 +1726,7 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
|
||||
ans = 1;
|
||||
if (!dryrun)
|
||||
{
|
||||
log_query(F_CNAME | F_FORWARD | F_CONFIG | F_NXDOMAIN, name, NULL, "<NAPTR>");
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, "<NAPTR>");
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
|
||||
NULL, T_NAPTR, C_IN, "sszzzd",
|
||||
na->order, na->pref, na->flags, na->services, na->regexp, na->replace))
|
||||
@@ -1603,7 +1738,7 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
|
||||
if (qtype == T_MAILB)
|
||||
ans = 1, nxdomain = 1;
|
||||
|
||||
if (qtype == T_SOA && (daemon->options & OPT_FILTER))
|
||||
if (qtype == T_SOA && option_bool(OPT_FILTER))
|
||||
{
|
||||
ans = 1;
|
||||
if (!dryrun)
|
||||
|
||||
111
src/rfc2131.c
111
src/rfc2131.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2010 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2011 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
|
||||
@@ -383,7 +383,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
/* keep _a_ local address available. */
|
||||
fallback = context->local;
|
||||
|
||||
if (daemon->options & OPT_LOG_OPTS)
|
||||
if (option_bool(OPT_LOG_OPTS))
|
||||
{
|
||||
struct dhcp_context *context_tmp;
|
||||
for (context_tmp = context; context_tmp; context_tmp = context_tmp->current)
|
||||
@@ -603,7 +603,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
client_hostname = daemon->dhcp_buff;
|
||||
}
|
||||
|
||||
if (client_hostname && daemon->options & OPT_LOG_OPTS)
|
||||
if (client_hostname && option_bool(OPT_LOG_OPTS))
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("%u client provides name: %s"), ntohl(mess->xid), client_hostname);
|
||||
|
||||
if (have_config(config, CONFIG_NAME))
|
||||
@@ -756,7 +756,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
}
|
||||
match_vendor_opts(opt, daemon->dhcp_opts);
|
||||
|
||||
if (daemon->options & OPT_LOG_OPTS)
|
||||
if (option_bool(OPT_LOG_OPTS))
|
||||
{
|
||||
if (sanitise(opt, daemon->namebuff))
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("%u vendor class: %s"), ntohl(mess->xid), daemon->namebuff);
|
||||
@@ -865,40 +865,49 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
pxearch = option_uint(opt, 0, 2);
|
||||
|
||||
/* proxy DHCP here. */
|
||||
if ((mess_type == DHCPDISCOVER || (pxe && mess_type == DHCPREQUEST)) &&
|
||||
(context->flags & CONTEXT_PROXY))
|
||||
if ((mess_type == DHCPDISCOVER || (pxe && mess_type == DHCPREQUEST)))
|
||||
{
|
||||
struct dhcp_boot *boot = find_boot(tagif_netid);
|
||||
|
||||
mess->yiaddr.s_addr = 0;
|
||||
if (mess_type == DHCPDISCOVER || mess->ciaddr.s_addr == 0)
|
||||
{
|
||||
mess->ciaddr.s_addr = 0;
|
||||
mess->flags |= htons(0x8000); /* broadcast */
|
||||
}
|
||||
|
||||
clear_packet(mess, end);
|
||||
struct dhcp_context *tmp;
|
||||
|
||||
/* Provide the bootfile here, for gPXE, and in case we have no menu items
|
||||
and set discovery_control = 8 */
|
||||
if (boot)
|
||||
for (tmp = context; tmp; tmp = tmp->current)
|
||||
if ((tmp->flags & CONTEXT_PROXY) &&
|
||||
match_netid(tmp->filter, tagif_netid, 1))
|
||||
break;
|
||||
|
||||
if (tmp)
|
||||
{
|
||||
if (boot->next_server.s_addr)
|
||||
mess->siaddr = boot->next_server;
|
||||
struct dhcp_boot *boot = find_boot(tagif_netid);
|
||||
|
||||
mess->yiaddr.s_addr = 0;
|
||||
if (mess_type == DHCPDISCOVER || mess->ciaddr.s_addr == 0)
|
||||
{
|
||||
mess->ciaddr.s_addr = 0;
|
||||
mess->flags |= htons(0x8000); /* broadcast */
|
||||
}
|
||||
|
||||
if (boot->file)
|
||||
strncpy((char *)mess->file, boot->file, sizeof(mess->file)-1);
|
||||
clear_packet(mess, end);
|
||||
|
||||
/* Provide the bootfile here, for gPXE, and in case we have no menu items
|
||||
and set discovery_control = 8 */
|
||||
if (boot)
|
||||
{
|
||||
if (boot->next_server.s_addr)
|
||||
mess->siaddr = boot->next_server;
|
||||
|
||||
if (boot->file)
|
||||
strncpy((char *)mess->file, boot->file, sizeof(mess->file)-1);
|
||||
}
|
||||
|
||||
option_put(mess, end, OPTION_MESSAGE_TYPE, 1,
|
||||
mess_type == DHCPDISCOVER ? DHCPOFFER : DHCPACK);
|
||||
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, htonl(context->local.s_addr));
|
||||
pxe_misc(mess, end, uuid);
|
||||
prune_vendor_opts(tagif_netid);
|
||||
do_encap_opts(pxe_opts(pxearch, tagif_netid, context->local), OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, 0);
|
||||
|
||||
log_packet("PXE", NULL, emac, emac_len, iface_name, ignore ? "proxy-ignored" : "proxy", mess->xid);
|
||||
return ignore ? 0 : dhcp_packet_size(mess, tagif_netid, agent_id, real_end);
|
||||
}
|
||||
|
||||
option_put(mess, end, OPTION_MESSAGE_TYPE, 1,
|
||||
mess_type == DHCPDISCOVER ? DHCPOFFER : DHCPACK);
|
||||
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, htonl(context->local.s_addr));
|
||||
pxe_misc(mess, end, uuid);
|
||||
prune_vendor_opts(tagif_netid);
|
||||
do_encap_opts(pxe_opts(pxearch, tagif_netid, context->local), OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, 0);
|
||||
|
||||
log_packet("PXE", NULL, emac, emac_len, iface_name, ignore ? "proxy-ignored" : "proxy", mess->xid);
|
||||
return ignore ? 0 : dhcp_packet_size(mess, tagif_netid, agent_id, real_end);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1085,7 +1094,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
/* In auth mode, a REQUEST sent to the wrong server
|
||||
should be faulted, so that the client establishes
|
||||
communication with us, otherwise, silently ignore. */
|
||||
if (!(daemon->options & OPT_AUTHORITATIVE))
|
||||
if (!option_bool(OPT_AUTHORITATIVE))
|
||||
return 0;
|
||||
message = _("wrong server-ID");
|
||||
}
|
||||
@@ -1101,7 +1110,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
else
|
||||
{
|
||||
/* INIT-REBOOT */
|
||||
if (!lease && !(daemon->options & OPT_AUTHORITATIVE))
|
||||
if (!lease && !option_bool(OPT_AUTHORITATIVE))
|
||||
return 0;
|
||||
|
||||
if (lease && lease->addr.s_addr != mess->yiaddr.s_addr)
|
||||
@@ -1116,8 +1125,13 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
as long as we can allocate the lease now - checked below.
|
||||
This makes for a smooth recovery from a lost lease DB */
|
||||
if ((lease && mess->ciaddr.s_addr != lease->addr.s_addr) ||
|
||||
(!lease && !(daemon->options & OPT_AUTHORITATIVE)))
|
||||
(!lease && !option_bool(OPT_AUTHORITATIVE)))
|
||||
{
|
||||
/* A client rebinding will broadcast the request, so we may see it even
|
||||
if the lease is held by another server. Just ignore it in that case.
|
||||
If the request is unicast to us, then somethings wrong, NAK */
|
||||
if (!unicast_dest)
|
||||
return 0;
|
||||
message = _("lease not found");
|
||||
/* ensure we broadcast NAK */
|
||||
unicast_dest = 0;
|
||||
@@ -1235,6 +1249,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
|
||||
lease->changed = 1;
|
||||
free(lease->extradata);
|
||||
lease->extradata = NULL;
|
||||
lease->extradata_size = lease->extradata_len = 0;
|
||||
|
||||
add_extradata_opt(lease, option_find(mess, sz, OPTION_VENDOR_ID, 1));
|
||||
@@ -1568,7 +1583,7 @@ static void log_packet(char *type, void *addr, unsigned char *ext_mac,
|
||||
|
||||
print_mac(daemon->namebuff, ext_mac, mac_len);
|
||||
|
||||
if(daemon->options & OPT_LOG_OPTS)
|
||||
if(option_bool(OPT_LOG_OPTS))
|
||||
my_syslog(MS_DHCP | LOG_INFO, "%u %s(%s) %s%s%s %s",
|
||||
ntohl(xid),
|
||||
type,
|
||||
@@ -1737,7 +1752,7 @@ static size_t dhcp_packet_size(struct dhcp_packet *mess, struct dhcp_netid *neti
|
||||
}
|
||||
|
||||
/* We do logging too */
|
||||
if (netid && (daemon->options & OPT_LOG_OPTS))
|
||||
if (netid && option_bool(OPT_LOG_OPTS))
|
||||
{
|
||||
char *s = daemon->namebuff;
|
||||
for (*s = 0; netid; netid = netid->next)
|
||||
@@ -1763,19 +1778,19 @@ static size_t dhcp_packet_size(struct dhcp_packet *mess, struct dhcp_netid *neti
|
||||
if (overload && (option_uint(overload, 0, 1) & 1))
|
||||
{
|
||||
*dhcp_skip_opts(mess->file) = OPTION_END;
|
||||
if (daemon->options & OPT_LOG_OPTS)
|
||||
if (option_bool(OPT_LOG_OPTS))
|
||||
log_options(mess->file, mess->xid);
|
||||
}
|
||||
else if ((daemon->options & OPT_LOG_OPTS) && strlen((char *)mess->file) != 0)
|
||||
else if (option_bool(OPT_LOG_OPTS) && strlen((char *)mess->file) != 0)
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("%u bootfile name: %s"), ntohl(mess->xid), (char *)mess->file);
|
||||
|
||||
if (overload && (option_uint(overload, 0, 1) & 2))
|
||||
{
|
||||
*dhcp_skip_opts(mess->sname) = OPTION_END;
|
||||
if (daemon->options & OPT_LOG_OPTS)
|
||||
if (option_bool(OPT_LOG_OPTS))
|
||||
log_options(mess->sname, mess->xid);
|
||||
}
|
||||
else if ((daemon->options & OPT_LOG_OPTS) && strlen((char *)mess->sname) != 0)
|
||||
else if (option_bool(OPT_LOG_OPTS) && strlen((char *)mess->sname) != 0)
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("%u server name: %s"), ntohl(mess->xid), (char *)mess->sname);
|
||||
|
||||
|
||||
@@ -1787,7 +1802,7 @@ static size_t dhcp_packet_size(struct dhcp_packet *mess, struct dhcp_netid *neti
|
||||
if (id_list)
|
||||
mess->flags |= htons(0x8000); /* force broadcast */
|
||||
|
||||
if (daemon->options & OPT_LOG_OPTS)
|
||||
if (option_bool(OPT_LOG_OPTS))
|
||||
{
|
||||
if (mess->siaddr.s_addr != 0)
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("%u next server: %s"), ntohl(mess->xid), inet_ntoa(mess->siaddr));
|
||||
@@ -2218,7 +2233,7 @@ static void do_options(struct dhcp_context *context,
|
||||
my_syslog(MS_DHCP | LOG_WARNING, _("Ignoring domain %s for DHCP host name %s"), config_domain, hostname);
|
||||
|
||||
/* logging */
|
||||
if ((daemon->options & OPT_LOG_OPTS) && req_options)
|
||||
if (option_bool(OPT_LOG_OPTS) && req_options)
|
||||
{
|
||||
char *q = daemon->namebuff;
|
||||
for (i = 0; req_options[i] != OPTION_END; i++)
|
||||
@@ -2251,7 +2266,7 @@ static void do_options(struct dhcp_context *context,
|
||||
{
|
||||
if (boot->sname)
|
||||
{
|
||||
if (!(daemon->options & OPT_NO_OVERRIDE) &&
|
||||
if (!option_bool(OPT_NO_OVERRIDE) &&
|
||||
req_options &&
|
||||
in_list(req_options, OPTION_SNAME))
|
||||
option_put_string(mess, end, OPTION_SNAME, boot->sname, 1);
|
||||
@@ -2261,7 +2276,7 @@ static void do_options(struct dhcp_context *context,
|
||||
|
||||
if (boot->file)
|
||||
{
|
||||
if (!(daemon->options & OPT_NO_OVERRIDE) &&
|
||||
if (!option_bool(OPT_NO_OVERRIDE) &&
|
||||
req_options &&
|
||||
in_list(req_options, OPTION_FILENAME))
|
||||
option_put_string(mess, end, OPTION_FILENAME, boot->file, 1);
|
||||
@@ -2300,7 +2315,7 @@ static void do_options(struct dhcp_context *context,
|
||||
fields look like they are in use, even when they aren't. This gets restored
|
||||
at the end of this function. */
|
||||
|
||||
if (!req_options || (daemon->options & OPT_NO_OVERRIDE))
|
||||
if (!req_options || option_bool(OPT_NO_OVERRIDE))
|
||||
{
|
||||
f0 = mess->file[0];
|
||||
mess->file[0] = 1;
|
||||
@@ -2537,7 +2552,7 @@ static void do_options(struct dhcp_context *context,
|
||||
memcpy(p, daemon->dhcp_buff3, vendor_class_len);
|
||||
|
||||
/* restore BOOTP anti-overload hack */
|
||||
if (!req_options || (daemon->options & OPT_NO_OVERRIDE))
|
||||
if (!req_options || option_bool(OPT_NO_OVERRIDE))
|
||||
{
|
||||
mess->file[0] = f0;
|
||||
mess->sname[0] = s0;
|
||||
|
||||
177
src/tftp.c
177
src/tftp.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2010 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2011 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
|
||||
@@ -43,7 +43,7 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
ssize_t len;
|
||||
char *packet = daemon->packet;
|
||||
char *filename, *mode, *p, *end, *opt;
|
||||
struct sockaddr_in addr, peer;
|
||||
union mysockaddr addr, peer;
|
||||
struct msghdr msg;
|
||||
struct iovec iov;
|
||||
struct ifreq ifr;
|
||||
@@ -57,6 +57,7 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
int mtuflag = IP_PMTUDISC_DONT;
|
||||
#endif
|
||||
char namebuff[IF_NAMESIZE];
|
||||
char pretty_addr[ADDRSTRLEN];
|
||||
char *name;
|
||||
char *prefix = daemon->tftp_prefix;
|
||||
struct tftp_prefix *pref;
|
||||
@@ -64,6 +65,9 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
|
||||
union {
|
||||
struct cmsghdr align; /* this ensures alignment */
|
||||
#ifdef HAVE_IPV6
|
||||
char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
|
||||
#endif
|
||||
#if defined(HAVE_LINUX_NETWORK)
|
||||
char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
|
||||
#elif defined(HAVE_SOLARIS_NETWORK)
|
||||
@@ -90,9 +94,9 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
if ((len = recvmsg(listen->tftpfd, &msg, 0)) < 2)
|
||||
return;
|
||||
|
||||
if (daemon->options & OPT_NOWILD)
|
||||
if (option_bool(OPT_NOWILD))
|
||||
{
|
||||
addr = listen->iface->addr.in;
|
||||
addr = listen->iface->addr;
|
||||
mtu = listen->iface->mtu;
|
||||
name = listen->iface->name;
|
||||
}
|
||||
@@ -102,59 +106,88 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
int check;
|
||||
struct interface_list *ir;
|
||||
|
||||
addr.sin_addr.s_addr = 0;
|
||||
if (msg.msg_controllen < sizeof(struct cmsghdr))
|
||||
return;
|
||||
|
||||
addr.sa.sa_family = listen->family;
|
||||
|
||||
#if defined(HAVE_LINUX_NETWORK)
|
||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||
if (cmptr->cmsg_level == SOL_IP && cmptr->cmsg_type == IP_PKTINFO)
|
||||
if (listen->family == AF_INET)
|
||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||
if (cmptr->cmsg_level == SOL_IP && cmptr->cmsg_type == IP_PKTINFO)
|
||||
{
|
||||
union {
|
||||
unsigned char *c;
|
||||
struct in_pktinfo *p;
|
||||
} p;
|
||||
p.c = CMSG_DATA(cmptr);
|
||||
addr.in.sin_addr = p.p->ipi_spec_dst;
|
||||
if_index = p.p->ipi_ifindex;
|
||||
}
|
||||
|
||||
#elif defined(HAVE_SOLARIS_NETWORK)
|
||||
if (listen->family == AF_INET)
|
||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||
{
|
||||
union {
|
||||
unsigned char *c;
|
||||
struct in_pktinfo *p;
|
||||
struct in_addr *a;
|
||||
unsigned int *i;
|
||||
} p;
|
||||
p.c = CMSG_DATA(cmptr);
|
||||
addr.sin_addr = p.p->ipi_spec_dst;
|
||||
if_index = p.p->ipi_ifindex;
|
||||
if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVDSTADDR)
|
||||
addr.in.sin_addr = *(p.a);
|
||||
else if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
|
||||
if_index = *(p.i);
|
||||
}
|
||||
|
||||
#elif defined(HAVE_SOLARIS_NETWORK)
|
||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||
{
|
||||
union {
|
||||
unsigned char *c;
|
||||
struct in_addr *a;
|
||||
unsigned int *i;
|
||||
} p;
|
||||
p.c = CMSG_DATA(cmptr);
|
||||
if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVDSTADDR)
|
||||
addr.sin_addr = *(p.a);
|
||||
else if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
|
||||
if_index = *(p.i);
|
||||
}
|
||||
|
||||
#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
|
||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||
{
|
||||
union {
|
||||
unsigned char *c;
|
||||
struct in_addr *a;
|
||||
struct sockaddr_dl *s;
|
||||
} p;
|
||||
p.c = CMSG_DATA(cmptr);
|
||||
if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVDSTADDR)
|
||||
addr.sin_addr = *(p.a);
|
||||
else if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
|
||||
if_index = p.s->sdl_index;
|
||||
}
|
||||
if (listen->family == AF_INET)
|
||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||
{
|
||||
union {
|
||||
unsigned char *c;
|
||||
struct in_addr *a;
|
||||
struct sockaddr_dl *s;
|
||||
} p;
|
||||
p.c = CMSG_DATA(cmptr);
|
||||
if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVDSTADDR)
|
||||
addr.in.sin_addr = *(p.a);
|
||||
else if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
|
||||
if_index = p.s->sdl_index;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (listen->family == AF_INET6)
|
||||
{
|
||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||
if (cmptr->cmsg_level == IPV6_LEVEL && cmptr->cmsg_type == daemon->v6pktinfo)
|
||||
{
|
||||
union {
|
||||
unsigned char *c;
|
||||
struct in6_pktinfo *p;
|
||||
} p;
|
||||
p.c = CMSG_DATA(cmptr);
|
||||
|
||||
addr.in6.sin6_addr = p.p->ipi6_addr;
|
||||
if_index = p.p->ipi6_ifindex;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!indextoname(listen->tftpfd, if_index, namebuff) ||
|
||||
addr.sin_addr.s_addr == 0)
|
||||
if (!indextoname(listen->tftpfd, if_index, namebuff))
|
||||
return;
|
||||
|
||||
name = namebuff;
|
||||
check = iface_check(AF_INET, (struct all_addr *)&addr.sin_addr, name, &if_index);
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (listen->family == AF_INET6)
|
||||
check = iface_check(AF_INET6, (struct all_addr *)&addr.in6.sin6_addr, name, &if_index);
|
||||
else
|
||||
#endif
|
||||
check = iface_check(AF_INET, (struct all_addr *)&addr.in.sin_addr, name, &if_index);
|
||||
|
||||
/* wierd TFTP service override */
|
||||
for (ir = daemon->tftp_interfaces; ir; ir = ir->next)
|
||||
@@ -189,16 +222,24 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
if (strcmp(ir->interface, name) == 0)
|
||||
special = 1;
|
||||
|
||||
addr.sin_port = htons(port);
|
||||
addr.sin_family = AF_INET;
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
addr.sin_len = sizeof(addr);
|
||||
addr.sa.sa_len = sa_len(&addr);
|
||||
#endif
|
||||
|
||||
|
||||
if (listen->family == AF_INET)
|
||||
addr.in.sin_port = htons(port);
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
{
|
||||
addr.in6.sin6_port = htons(port);
|
||||
addr.in6.sin6_flowinfo = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!(transfer = whine_malloc(sizeof(struct tftp_transfer))))
|
||||
return;
|
||||
|
||||
if ((transfer->sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
|
||||
if ((transfer->sockfd = socket(listen->family, SOCK_DGRAM, 0)) == -1)
|
||||
{
|
||||
free(transfer);
|
||||
return;
|
||||
@@ -213,11 +254,13 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
transfer->file = NULL;
|
||||
transfer->opt_blocksize = transfer->opt_transize = 0;
|
||||
transfer->netascii = transfer->carrylf = 0;
|
||||
|
||||
|
||||
prettyprint_addr(&peer, pretty_addr);
|
||||
|
||||
/* if we have a nailed-down range, iterate until we find a free one. */
|
||||
while (1)
|
||||
{
|
||||
if (bind(transfer->sockfd, (struct sockaddr *)&addr, sizeof(addr)) == -1 ||
|
||||
if (bind(transfer->sockfd, &addr.sa, sizeof(addr)) == -1 ||
|
||||
#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
|
||||
setsockopt(transfer->sockfd, SOL_IP, IP_MTU_DISCOVER, &mtuflag, sizeof(mtuflag)) == -1 ||
|
||||
#endif
|
||||
@@ -227,7 +270,12 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
{
|
||||
if (++port <= daemon->end_tftp_port)
|
||||
{
|
||||
addr.sin_port = htons(port);
|
||||
if (listen->family == AF_INET)
|
||||
addr.in.sin_port = htons(port);
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
addr.in6.sin6_port = htons(port);
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
my_syslog(MS_TFTP | LOG_ERR, _("unable to get free port for TFTP"));
|
||||
@@ -245,7 +293,7 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
!(filename = next(&p, end)) ||
|
||||
!(mode = next(&p, end)) ||
|
||||
(strcasecmp(mode, "octet") != 0 && strcasecmp(mode, "netascii") != 0))
|
||||
len = tftp_err(ERR_ILL, packet, _("unsupported request from %s"), inet_ntoa(peer.sin_addr));
|
||||
len = tftp_err(ERR_ILL, packet, _("unsupported request from %s"), pretty_addr);
|
||||
else
|
||||
{
|
||||
if (strcasecmp(mode, "netascii") == 0)
|
||||
@@ -256,7 +304,7 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
if (strcasecmp(opt, "blksize") == 0)
|
||||
{
|
||||
if ((opt = next(&p, end)) &&
|
||||
(special || !(daemon->options & OPT_TFTP_NOBLOCK)))
|
||||
(special || !option_bool(OPT_TFTP_NOBLOCK)))
|
||||
{
|
||||
transfer->blocksize = atoi(opt);
|
||||
if (transfer->blocksize < 1)
|
||||
@@ -290,12 +338,12 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
if (prefix[strlen(prefix)-1] != '/')
|
||||
strncat(daemon->namebuff, "/", (MAXDNAME-1) - strlen(daemon->namebuff));
|
||||
|
||||
if (!special && (daemon->options & OPT_TFTP_APREF))
|
||||
if (!special && option_bool(OPT_TFTP_APREF))
|
||||
{
|
||||
size_t oldlen = strlen(daemon->namebuff);
|
||||
struct stat statbuf;
|
||||
|
||||
strncat(daemon->namebuff, inet_ntoa(peer.sin_addr), (MAXDNAME-1) - strlen(daemon->namebuff));
|
||||
strncat(daemon->namebuff, pretty_addr, (MAXDNAME-1) - strlen(daemon->namebuff));
|
||||
strncat(daemon->namebuff, "/", (MAXDNAME-1) - strlen(daemon->namebuff));
|
||||
|
||||
/* remove unique-directory if it doesn't exist */
|
||||
@@ -333,7 +381,6 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
free_transfer(transfer);
|
||||
else
|
||||
{
|
||||
my_syslog(MS_TFTP | LOG_INFO, _("sent %s to %s"), daemon->namebuff, inet_ntoa(peer.sin_addr));
|
||||
transfer->next = daemon->tftp_trans;
|
||||
daemon->tftp_trans = transfer;
|
||||
}
|
||||
@@ -376,7 +423,7 @@ static struct tftp_file *check_tftp_fileperm(ssize_t *len, char *prefix, int spe
|
||||
goto perm;
|
||||
}
|
||||
/* in secure mode, must be owned by user running dnsmasq */
|
||||
else if (!special && (daemon->options & OPT_TFTP_SECURE) && uid != statbuf.st_uid)
|
||||
else if (!special && option_bool(OPT_TFTP_SECURE) && uid != statbuf.st_uid)
|
||||
goto perm;
|
||||
|
||||
/* If we're doing many tranfers from the same file, only
|
||||
@@ -426,6 +473,7 @@ void check_tftp_listeners(fd_set *rset, time_t now)
|
||||
{
|
||||
struct tftp_transfer *transfer, *tmp, **up;
|
||||
ssize_t len;
|
||||
char pretty_addr[ADDRSTRLEN];
|
||||
|
||||
struct ack {
|
||||
unsigned short op, block;
|
||||
@@ -440,6 +488,8 @@ void check_tftp_listeners(fd_set *rset, time_t now)
|
||||
{
|
||||
/* we overwrote the buffer... */
|
||||
daemon->srv_save = NULL;
|
||||
|
||||
prettyprint_addr(&transfer->peer, pretty_addr);
|
||||
|
||||
if ((len = recv(transfer->sockfd, daemon->packet, daemon->packet_buff_sz, 0)) >= (ssize_t)sizeof(struct ack))
|
||||
{
|
||||
@@ -456,6 +506,7 @@ void check_tftp_listeners(fd_set *rset, time_t now)
|
||||
char *p = daemon->packet + sizeof(struct ack);
|
||||
char *end = daemon->packet + len;
|
||||
char *err = next(&p, end);
|
||||
|
||||
/* Sanitise error message */
|
||||
if (!err)
|
||||
err = "";
|
||||
@@ -467,9 +518,10 @@ void check_tftp_listeners(fd_set *rset, time_t now)
|
||||
*(q++) = *r;
|
||||
*q = 0;
|
||||
}
|
||||
|
||||
my_syslog(MS_TFTP | LOG_ERR, _("error %d %s received from %s"),
|
||||
(int)ntohs(mess->block), err,
|
||||
inet_ntoa(transfer->peer.sin_addr));
|
||||
pretty_addr);
|
||||
|
||||
/* Got err, ensure we take abort */
|
||||
transfer->timeout = now;
|
||||
@@ -498,9 +550,12 @@ 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(MS_TFTP | LOG_ERR, _("failed sending %s to %s"),
|
||||
transfer->file->filename, inet_ntoa(transfer->peer.sin_addr));
|
||||
len = 0;
|
||||
{
|
||||
my_syslog(MS_TFTP | LOG_ERR, _("failed sending %s to %s"),
|
||||
transfer->file->filename, pretty_addr);
|
||||
len = 0;
|
||||
endcon = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (len != 0)
|
||||
@@ -509,6 +564,8 @@ void check_tftp_listeners(fd_set *rset, time_t now)
|
||||
|
||||
if (endcon || len == 0)
|
||||
{
|
||||
if (!endcon)
|
||||
my_syslog(MS_TFTP | LOG_INFO, _("sent %s to %s"), transfer->file->filename, pretty_addr);
|
||||
/* unlink */
|
||||
*up = tmp;
|
||||
free_transfer(transfer);
|
||||
@@ -517,7 +574,7 @@ void check_tftp_listeners(fd_set *rset, time_t now)
|
||||
}
|
||||
|
||||
up = &transfer->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void free_transfer(struct tftp_transfer *transfer)
|
||||
|
||||
10
src/util.c
10
src/util.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2010 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2011 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
|
||||
@@ -365,7 +365,8 @@ void prettyprint_time(char *buf, unsigned int t)
|
||||
}
|
||||
|
||||
|
||||
/* in may equal out, when maxlen may be -1 (No max len). */
|
||||
/* in may equal out, when maxlen may be -1 (No max len).
|
||||
Return -1 for extraneous no-hex chars found. */
|
||||
int parse_hex(char *in, unsigned char *out, int maxlen,
|
||||
unsigned int *wildcard_mask, int *mac_type)
|
||||
{
|
||||
@@ -377,7 +378,10 @@ int parse_hex(char *in, unsigned char *out, int maxlen,
|
||||
|
||||
while (maxlen == -1 || i < maxlen)
|
||||
{
|
||||
for (r = in; *r != 0 && *r != ':' && *r != '-'; r++);
|
||||
for (r = in; *r != 0 && *r != ':' && *r != '-'; r++)
|
||||
if (!isxdigit((int)*r))
|
||||
return -1;
|
||||
|
||||
if (*r == 0)
|
||||
maxlen = i;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user