mirror of
http://thekelleys.org.uk/git/dnsmasq.git
synced 2026-11-03 13:38:32 +00:00
Compare commits
21
Commits
v2.88test1
...
v2.88rc2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7f227a83f2 | ||
|
|
9ed3ee67ec | ||
|
|
1f9215f5f9 | ||
|
|
f52cfdd8c3 | ||
|
|
2fc904111d | ||
|
|
262dadf50e | ||
|
|
6c596f1cc1 | ||
|
|
dafa16c400 | ||
|
|
1db9943c68 | ||
|
|
5b868c213b | ||
|
|
2d8905dafd | ||
|
|
9002108551 | ||
|
|
d3c21c596e | ||
|
|
34fac952b6 | ||
|
|
92c32e0bac | ||
|
|
1bcad67806 | ||
|
|
fe9a134baf | ||
|
|
930428fb97 | ||
|
|
936be022d9 | ||
|
|
0017dd74d5 | ||
|
|
0ba25a0512 |
No files matched your search
@@ -18,6 +18,37 @@ version 2.88
|
||||
flushed when its TTL expires, so the cache becomes
|
||||
strictly least-recently-used.
|
||||
|
||||
Make --hostsdir (but NOT --dhcp-hostsdir and --dhcp-optsdir)
|
||||
handle removal of whole files or entries within files.
|
||||
Thanks to Dominik Derigs for the initial patches for this.
|
||||
|
||||
Fix bug, introduced in 2.87, which could result in DNS
|
||||
servers being removed from the configuration when reloading
|
||||
server configuration from DBus, or re-reading /etc/resolv.conf
|
||||
Only servers from the same source should be replaced, but some
|
||||
servers from other sources (ie hard coded or another dynamic source)
|
||||
could mysteriously disappear. Thanks to all reporting this,
|
||||
but especially Christopher J. Masden who reduced the problem
|
||||
to an easily reproducible case which saved mucg labour in
|
||||
finding it.
|
||||
|
||||
Add --no-round-robin option.
|
||||
|
||||
Allow domain names as well as IP addresses when specifying
|
||||
upstream DNS servers. There are some gotchas associated with this,
|
||||
(it will mysteriously fail to work if the dnsmasq instance
|
||||
being started is in the path from the system resolver to the DNS)
|
||||
and a seemingly sensible configuration like
|
||||
--server=domain.name@1.2.3.4 is unactionable if domain.name
|
||||
only resolves to an IPv6 address). There are, however,
|
||||
cases where is can be useful. Thanks to Dominik Derigs for
|
||||
the patch.
|
||||
|
||||
Handle DS records for unsupported crypto algorithms correctly.
|
||||
Such a DS, as long as it is validated, should allow answers
|
||||
in the domain is attests to be returned as unvalidated, and not
|
||||
as a validation error.
|
||||
|
||||
|
||||
version 2.87
|
||||
Allow arbitrary prefix lengths in --rev-server and
|
||||
|
||||
Vendored
+8
@@ -1,3 +1,11 @@
|
||||
dnsmasq (2.88-1) unstable; urgency=low
|
||||
|
||||
* New upstream.
|
||||
* Fix loss of server configuration (closes: #1020830)
|
||||
Git commit 930428fb970f4991e5c2933fd5a5d2504c18a551
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Wed, 2 Nov 2022 22:15:45 +0000
|
||||
|
||||
dnsmasq (2.87-1) unstable; urgency=low
|
||||
|
||||
* New upstream. (closes: #1001209, #1003156)
|
||||
|
||||
+17
-4
@@ -60,7 +60,8 @@ in alphabetical order.
|
||||
.TP
|
||||
.B --hostsdir=<path>
|
||||
Read all the hosts files contained in the directory. New or changed files
|
||||
are read automatically. See \fB--dhcp-hostsdir\fP for details.
|
||||
are read automatically and modified and deleted files have removed records
|
||||
automatically deleted.
|
||||
.TP
|
||||
.B \-E, --expand-hosts
|
||||
Add the domain to simple names (without a period) in /etc/hosts
|
||||
@@ -461,8 +462,8 @@ Tells dnsmasq to never forward A or AAAA queries for plain names, without dots
|
||||
or domain parts, to upstream nameservers. If the name is not known
|
||||
from /etc/hosts or DHCP then a "not found" answer is returned.
|
||||
.TP
|
||||
.B \-S, --local, --server=[/[<domain>]/[domain/]][<ipaddr>[#<port>]][@<interface>][@<source-ip>[#<port>]]
|
||||
Specify IP address of upstream servers directly. Setting this flag does
|
||||
.B \-S, --local, --server=[/[<domain>]/[domain/]][<server>[#<port>]][@<interface>][@<source-ip>[#<port>]]
|
||||
Specify upstream servers directly. Setting this flag does
|
||||
not suppress reading of /etc/resolv.conf, use \fB--no-resolv\fP to do that. If one or more
|
||||
optional domains are given, that server is used only for those domains
|
||||
and they are queried only using the specified server. This is
|
||||
@@ -530,8 +531,14 @@ The query-port flag is ignored for any servers which have a
|
||||
source address specified but the port may be specified directly as
|
||||
part of the source address. Forcing queries to an interface is not
|
||||
implemented on all platforms supported by dnsmasq.
|
||||
|
||||
Upstream servers may be specified with a hostname rather than an IP address.
|
||||
In this case, dnsmasq will try to use the system resolver to get the IP address
|
||||
of a server during startup. If name resolution fails, starting dnsmasq fails, too.
|
||||
If the system's configuration is such that the system resolver sends DNS queries
|
||||
through the dnsmasq instance which is starting up then this will time-out and fail.
|
||||
.TP
|
||||
.B --rev-server=<ip-address>[/<prefix-len>][,<ipaddr>][#<port>][@<interface>][@<source-ip>[#<port>]]
|
||||
.B --rev-server=<ip-address>[/<prefix-len>][,<server>][#<port>][@<interface>][@<source-ip>[#<port>]]
|
||||
This is functionally the same as
|
||||
.B --server,
|
||||
but provides some syntactic sugar to make specifying address-to-name queries easier. For example
|
||||
@@ -815,6 +822,12 @@ Disable negative caching. Negative caching allows dnsmasq to remember
|
||||
"no such domain" answers from upstream nameservers and answer
|
||||
identical queries without forwarding them again.
|
||||
.TP
|
||||
.B --no-round-robin
|
||||
Dnsmasq normally permutes the order of A or AAAA records for the same
|
||||
name on successive queries, for load-balancing. This turns off that
|
||||
behaviour, so that the records are always returned in the order
|
||||
that they are received from upstream.
|
||||
.TP
|
||||
.B --use-stale-cache
|
||||
When set, if a DNS name exists in the cache, but its time-to-live has expired, dnsmasq will return the data anyway. (It attempts to refresh the
|
||||
data with an upstream query after returning the stale data.) This can improve speed and reliability. It comes at the expense
|
||||
|
||||
+48
-17
@@ -189,7 +189,7 @@ static void rehash(int size)
|
||||
else if (new_size <= hash_size || !(new = whine_malloc(new_size * sizeof(struct crec *))))
|
||||
return;
|
||||
|
||||
for(i = 0; i < new_size; i++)
|
||||
for (i = 0; i < new_size; i++)
|
||||
new[i] = NULL;
|
||||
|
||||
old = hash_table;
|
||||
@@ -233,7 +233,8 @@ static void cache_hash(struct crec *crecp)
|
||||
immortal entries are at the end of the hash-chain.
|
||||
This allows reverse searches and garbage collection to be optimised */
|
||||
|
||||
struct crec **up = hash_bucket(cache_get_name(crecp));
|
||||
char *name = cache_get_name(crecp);
|
||||
struct crec **up = hash_bucket(name);
|
||||
|
||||
if (!(crecp->flags & F_REVERSE))
|
||||
{
|
||||
@@ -244,6 +245,11 @@ static void cache_hash(struct crec *crecp)
|
||||
while (*up && !((*up)->flags & F_IMMORTAL))
|
||||
up = &((*up)->hash_next);
|
||||
}
|
||||
|
||||
/* Preserve order when inserting the same name multiple times. */
|
||||
while (*up && hostname_isequal(cache_get_name(*up), name))
|
||||
up = &((*up)->hash_next);
|
||||
|
||||
crecp->hash_next = *up;
|
||||
*up = crecp;
|
||||
}
|
||||
@@ -388,6 +394,27 @@ static int is_expired(time_t now, struct crec *crecp)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Remove entries with a given UID from the cache */
|
||||
unsigned int cache_remove_uid(const unsigned int uid)
|
||||
{
|
||||
int i;
|
||||
unsigned int removed = 0;
|
||||
struct crec *crecp, **up;
|
||||
|
||||
for (i = 0; i < hash_size; i++)
|
||||
for (crecp = hash_table[i], up = &hash_table[i]; crecp; crecp = crecp->hash_next)
|
||||
if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) && crecp->uid == uid)
|
||||
{
|
||||
*up = crecp->hash_next;
|
||||
free(crecp);
|
||||
removed++;
|
||||
}
|
||||
else
|
||||
up = &crecp->hash_next;
|
||||
|
||||
return removed;
|
||||
}
|
||||
|
||||
static struct crec *cache_scan_free(char *name, union all_addr *addr, unsigned short class, time_t now,
|
||||
unsigned int flags, struct crec **target_crec, unsigned int *target_uid)
|
||||
{
|
||||
@@ -701,7 +728,7 @@ static struct crec *really_insert(char *name, union all_addr *addr, unsigned sho
|
||||
new->ttd = now + (time_t)ttl;
|
||||
new->next = new_chain;
|
||||
new_chain = new;
|
||||
|
||||
|
||||
return new;
|
||||
}
|
||||
|
||||
@@ -879,7 +906,7 @@ int cache_find_non_terminal(char *name, time_t now)
|
||||
struct crec *cache_find_by_name(struct crec *crecp, char *name, time_t now, unsigned int prot)
|
||||
{
|
||||
struct crec *ans;
|
||||
int no_rr = prot & F_NO_RR;
|
||||
int no_rr = (prot & F_NO_RR) || option_bool(OPT_NORR);
|
||||
|
||||
prot &= ~F_NO_RR;
|
||||
|
||||
@@ -1027,16 +1054,17 @@ struct crec *cache_find_by_addr(struct crec *crecp, union all_addr *addr,
|
||||
static void add_hosts_entry(struct crec *cache, union all_addr *addr, int addrlen,
|
||||
unsigned int index, struct crec **rhash, int hashsz)
|
||||
{
|
||||
struct crec *lookup = cache_find_by_name(NULL, cache_get_name(cache), 0, cache->flags & (F_IPV4 | F_IPV6));
|
||||
int i;
|
||||
unsigned int j;
|
||||
struct crec *lookup = NULL;
|
||||
|
||||
/* Remove duplicates in hosts files. */
|
||||
if (lookup && (lookup->flags & F_HOSTS) && memcmp(&lookup->addr, addr, addrlen) == 0)
|
||||
{
|
||||
free(cache);
|
||||
return;
|
||||
}
|
||||
while ((lookup = cache_find_by_name(lookup, cache_get_name(cache), 0, cache->flags & (F_IPV4 | F_IPV6))))
|
||||
if ((lookup->flags & F_HOSTS) && memcmp(&lookup->addr, addr, addrlen) == 0)
|
||||
{
|
||||
free(cache);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Ensure there is only one address -> name mapping (first one trumps)
|
||||
We do this by steam here, The entries are kept in hash chains, linked
|
||||
@@ -1141,7 +1169,7 @@ int read_hostsfile(char *filename, unsigned int index, int cache_size, struct cr
|
||||
{
|
||||
FILE *f = fopen(filename, "r");
|
||||
char *token = daemon->namebuff, *domain_suffix = NULL;
|
||||
int addr_count = 0, name_count = cache_size, lineno = 1;
|
||||
int names_done = 0, name_count = cache_size, lineno = 1;
|
||||
unsigned int flags = 0;
|
||||
union all_addr addr;
|
||||
int atnl, addrlen = 0;
|
||||
@@ -1177,8 +1205,6 @@ int read_hostsfile(char *filename, unsigned int index, int cache_size, struct cr
|
||||
continue;
|
||||
}
|
||||
|
||||
addr_count++;
|
||||
|
||||
/* rehash every 1000 names. */
|
||||
if (rhash && ((name_count - cache_size) > 1000))
|
||||
{
|
||||
@@ -1210,6 +1236,7 @@ int read_hostsfile(char *filename, unsigned int index, int cache_size, struct cr
|
||||
cache->ttd = daemon->local_ttl;
|
||||
add_hosts_entry(cache, &addr, addrlen, index, rhash, hashsz);
|
||||
name_count++;
|
||||
names_done++;
|
||||
}
|
||||
if ((cache = whine_malloc(SIZEOF_BARE_CREC + strlen(canon) + 1)))
|
||||
{
|
||||
@@ -1218,6 +1245,7 @@ int read_hostsfile(char *filename, unsigned int index, int cache_size, struct cr
|
||||
cache->ttd = daemon->local_ttl;
|
||||
add_hosts_entry(cache, &addr, addrlen, index, rhash, hashsz);
|
||||
name_count++;
|
||||
names_done++;
|
||||
}
|
||||
free(canon);
|
||||
|
||||
@@ -1234,7 +1262,7 @@ int read_hostsfile(char *filename, unsigned int index, int cache_size, struct cr
|
||||
if (rhash)
|
||||
rehash(name_count);
|
||||
|
||||
my_syslog(LOG_INFO, _("read %s - %d addresses"), filename, addr_count);
|
||||
my_syslog(LOG_INFO, _("read %s - %d names"), filename, names_done);
|
||||
|
||||
return name_count;
|
||||
}
|
||||
@@ -1861,6 +1889,7 @@ void dump_cache(time_t now)
|
||||
char *record_source(unsigned int index)
|
||||
{
|
||||
struct hostsfile *ah;
|
||||
struct dyndir *dd;
|
||||
|
||||
if (index == SRC_CONFIG)
|
||||
return "config";
|
||||
@@ -1872,9 +1901,11 @@ char *record_source(unsigned int index)
|
||||
return ah->fname;
|
||||
|
||||
#ifdef HAVE_INOTIFY
|
||||
for (ah = daemon->dynamic_dirs; ah; ah = ah->next)
|
||||
if (ah->index == index)
|
||||
return ah->fname;
|
||||
/* Dynamic directories contain multiple files */
|
||||
for (dd = daemon->dynamic_dirs; dd; dd = dd->next)
|
||||
for (ah = dd->files; ah; ah = ah->next)
|
||||
if (ah->index == index)
|
||||
return ah->fname;
|
||||
#endif
|
||||
|
||||
return "<unknown>";
|
||||
|
||||
+21
-8
@@ -309,14 +309,14 @@ static int dnsmasq_gostdsa_verify(struct blockdata *key_data, unsigned int key_l
|
||||
mpz_init(y);
|
||||
}
|
||||
|
||||
mpz_import(x, 32 , 1, 1, 0, 0, p);
|
||||
mpz_import(y, 32 , 1, 1, 0, 0, p + 32);
|
||||
mpz_import(x, 32, -1, 1, 0, 0, p);
|
||||
mpz_import(y, 32, -1, 1, 0, 0, p + 32);
|
||||
|
||||
if (!ecc_point_set(gost_key, x, y))
|
||||
return 0;
|
||||
return 0;
|
||||
|
||||
mpz_import(sig_struct->r, 32, 1, 1, 0, 0, sig);
|
||||
mpz_import(sig_struct->s, 32, 1, 1, 0, 0, sig + 32);
|
||||
mpz_import(sig_struct->s, 32, 1, 1, 0, 0, sig);
|
||||
mpz_import(sig_struct->r, 32, 1, 1, 0, 0, sig + 32);
|
||||
|
||||
return nettle_gostdsa_verify(gost_key, digest_len, digest, sig_struct);
|
||||
}
|
||||
@@ -390,7 +390,12 @@ static int (*verify_func(int algo))(struct blockdata *key_data, unsigned int key
|
||||
return dnsmasq_ecdsa_verify;
|
||||
|
||||
#if MIN_VERSION(3, 1)
|
||||
case 15: case 16:
|
||||
case 15:
|
||||
return dnsmasq_eddsa_verify;
|
||||
#endif
|
||||
|
||||
#if MIN_VERSION(3, 6)
|
||||
case 16:
|
||||
return dnsmasq_eddsa_verify;
|
||||
#endif
|
||||
}
|
||||
@@ -425,7 +430,9 @@ char *ds_digest_name(int digest)
|
||||
{
|
||||
case 1: return "sha1";
|
||||
case 2: return "sha256";
|
||||
case 3: return "gosthash94";
|
||||
#if MIN_VERSION(3, 6)
|
||||
case 3: return "gosthash94cp";
|
||||
#endif
|
||||
case 4: return "sha384";
|
||||
default: return NULL;
|
||||
}
|
||||
@@ -444,11 +451,17 @@ char *algo_digest_name(int algo)
|
||||
case 7: return "sha1"; /* RSASHA1-NSEC3-SHA1 */
|
||||
case 8: return "sha256"; /* RSA/SHA-256 */
|
||||
case 10: return "sha512"; /* RSA/SHA-512 */
|
||||
case 12: return "gosthash94"; /* ECC-GOST */
|
||||
#if MIN_VERSION(3, 6)
|
||||
case 12: return "gosthash94cp"; /* ECC-GOST */
|
||||
#endif
|
||||
case 13: return "sha256"; /* ECDSAP256SHA256 */
|
||||
case 14: return "sha384"; /* ECDSAP384SHA384 */
|
||||
#if MIN_VERSION(3, 1)
|
||||
case 15: return "null_hash"; /* ED25519 */
|
||||
# if MIN_VERSION(3, 6)
|
||||
case 16: return "null_hash"; /* ED448 */
|
||||
# endif
|
||||
#endif
|
||||
default: return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
+61
-17
@@ -292,6 +292,11 @@ static DBusMessage* dbus_read_servers_ex(DBusMessage *message, int strings)
|
||||
u16 flags = 0;
|
||||
char interface[IF_NAMESIZE];
|
||||
char *str_addr, *str_domain = NULL;
|
||||
struct server_details sdetails = { 0 };
|
||||
sdetails.addr = &addr;
|
||||
sdetails.source_addr = &source_addr;
|
||||
sdetails.interface = interface;
|
||||
sdetails.flags = &flags;
|
||||
|
||||
if (strings)
|
||||
{
|
||||
@@ -374,20 +379,6 @@ static DBusMessage* dbus_read_servers_ex(DBusMessage *message, int strings)
|
||||
strcpy(str_addr, str);
|
||||
}
|
||||
|
||||
/* parse the IP address */
|
||||
if ((addr_err = parse_server(str_addr, &addr, &source_addr, (char *) &interface, &flags)))
|
||||
{
|
||||
error = dbus_message_new_error_printf(message, DBUS_ERROR_INVALID_ARGS,
|
||||
"Invalid IP address '%s': %s",
|
||||
str, addr_err);
|
||||
break;
|
||||
}
|
||||
|
||||
/* 0.0.0.0 for server address == NULL, for Dbus */
|
||||
if (addr.in.sin_family == AF_INET &&
|
||||
addr.in.sin_addr.s_addr == 0)
|
||||
flags |= SERV_LITERAL_ADDRESS;
|
||||
|
||||
if (strings)
|
||||
{
|
||||
char *p;
|
||||
@@ -401,7 +392,31 @@ static DBusMessage* dbus_read_servers_ex(DBusMessage *message, int strings)
|
||||
else
|
||||
p = NULL;
|
||||
|
||||
add_update_server(flags | SERV_FROM_DBUS, &addr, &source_addr, interface, str_domain, NULL);
|
||||
if (strings && strlen(str_addr) == 0)
|
||||
add_update_server(SERV_LITERAL_ADDRESS | SERV_FROM_DBUS, &addr, &source_addr, interface, str_domain, NULL);
|
||||
else
|
||||
{
|
||||
if ((addr_err = parse_server(str_addr, &sdetails)))
|
||||
{
|
||||
error = dbus_message_new_error_printf(message, DBUS_ERROR_INVALID_ARGS,
|
||||
"Invalid IP address '%s': %s",
|
||||
str, addr_err);
|
||||
break;
|
||||
}
|
||||
|
||||
while (parse_server_next(&sdetails))
|
||||
{
|
||||
if ((addr_err = parse_server_addr(&sdetails)))
|
||||
{
|
||||
error = dbus_message_new_error_printf(message, DBUS_ERROR_INVALID_ARGS,
|
||||
"Invalid IP address '%s': %s",
|
||||
str, addr_err);
|
||||
break;
|
||||
}
|
||||
|
||||
add_update_server(flags | SERV_FROM_DBUS, &addr, &source_addr, interface, str_domain, NULL);
|
||||
}
|
||||
}
|
||||
} while ((str_domain = p));
|
||||
}
|
||||
else
|
||||
@@ -415,11 +430,40 @@ static DBusMessage* dbus_read_servers_ex(DBusMessage *message, int strings)
|
||||
if (dbus_message_iter_get_arg_type(&string_iter) == DBUS_TYPE_STRING)
|
||||
dbus_message_iter_get_basic(&string_iter, &str);
|
||||
dbus_message_iter_next (&string_iter);
|
||||
|
||||
if ((addr_err = parse_server(str_addr, &sdetails)))
|
||||
{
|
||||
error = dbus_message_new_error_printf(message, DBUS_ERROR_INVALID_ARGS,
|
||||
"Invalid IP address '%s': %s",
|
||||
str, addr_err);
|
||||
break;
|
||||
}
|
||||
|
||||
add_update_server(flags | SERV_FROM_DBUS, &addr, &source_addr, interface, str, NULL);
|
||||
while (parse_server_next(&sdetails))
|
||||
{
|
||||
if ((addr_err = parse_server_addr(&sdetails)))
|
||||
{
|
||||
error = dbus_message_new_error_printf(message, DBUS_ERROR_INVALID_ARGS,
|
||||
"Invalid IP address '%s': %s",
|
||||
str, addr_err);
|
||||
break;
|
||||
}
|
||||
|
||||
/* 0.0.0.0 for server address == NULL, for Dbus */
|
||||
if (addr.in.sin_family == AF_INET &&
|
||||
addr.in.sin_addr.s_addr == 0)
|
||||
flags |= SERV_LITERAL_ADDRESS;
|
||||
else
|
||||
flags &= ~SERV_LITERAL_ADDRESS;
|
||||
|
||||
add_update_server(flags | SERV_FROM_DBUS, &addr, &source_addr, interface, str, NULL);
|
||||
}
|
||||
} while (dbus_message_iter_get_arg_type(&string_iter) == DBUS_TYPE_STRING);
|
||||
}
|
||||
|
||||
|
||||
if (sdetails.orig_hostinfo)
|
||||
freeaddrinfo(sdetails.orig_hostinfo);
|
||||
|
||||
/* jump to next element in outer array */
|
||||
dbus_message_iter_next(&array_iter);
|
||||
}
|
||||
|
||||
+26
-5
@@ -133,6 +133,7 @@ typedef unsigned long long u64;
|
||||
#include <sys/uio.h>
|
||||
#include <syslog.h>
|
||||
#include <dirent.h>
|
||||
#include <netdb.h>
|
||||
#ifndef HAVE_LINUX_NETWORK
|
||||
# include <net/if_dl.h>
|
||||
#endif
|
||||
@@ -280,7 +281,8 @@ struct event_desc {
|
||||
#define OPT_STRIP_ECS 69
|
||||
#define OPT_STRIP_MAC 70
|
||||
#define OPT_STALE_CACHE 71
|
||||
#define OPT_LAST 72
|
||||
#define OPT_NORR 72
|
||||
#define OPT_LAST 73
|
||||
|
||||
#define OPTION_BITS (sizeof(unsigned int)*8)
|
||||
#define OPTION_SIZE ( (OPT_LAST/OPTION_BITS)+((OPT_LAST%OPTION_BITS)!=0) )
|
||||
@@ -687,10 +689,17 @@ struct hostsfile {
|
||||
struct hostsfile *next;
|
||||
int flags;
|
||||
char *fname;
|
||||
unsigned int index; /* matches to cache entries for logging */
|
||||
};
|
||||
|
||||
struct dyndir {
|
||||
struct dyndir *next;
|
||||
struct hostsfile *files;
|
||||
int flags;
|
||||
char *dname;
|
||||
#ifdef HAVE_INOTIFY
|
||||
int wd; /* inotify watch descriptor */
|
||||
#endif
|
||||
unsigned int index; /* matches to cache entries for logging */
|
||||
};
|
||||
|
||||
/* packet-dump flags */
|
||||
@@ -1152,6 +1161,7 @@ extern struct daemon {
|
||||
u32 umbrella_org;
|
||||
u32 umbrella_asset;
|
||||
u8 umbrella_device[8];
|
||||
int host_index;
|
||||
struct hostsfile *addn_hosts;
|
||||
struct dhcp_context *dhcp, *dhcp6;
|
||||
struct ra_interface *ra_interfaces;
|
||||
@@ -1172,7 +1182,8 @@ extern struct daemon {
|
||||
int doing_ra, doing_dhcp6;
|
||||
struct dhcp_netid_list *dhcp_ignore, *dhcp_ignore_names, *dhcp_gen_names;
|
||||
struct dhcp_netid_list *force_broadcast, *bootp_dynamic;
|
||||
struct hostsfile *dhcp_hosts_file, *dhcp_opts_file, *dynamic_dirs;
|
||||
struct hostsfile *dhcp_hosts_file, *dhcp_opts_file;
|
||||
struct dyndir *dynamic_dirs;
|
||||
int dhcp_max, tftp_max, tftp_mtu;
|
||||
int dhcp_server_port, dhcp_client_port;
|
||||
int start_tftp_port, end_tftp_port;
|
||||
@@ -1282,6 +1293,14 @@ extern struct daemon {
|
||||
#endif
|
||||
} *daemon;
|
||||
|
||||
struct server_details {
|
||||
union mysockaddr *addr, *source_addr;
|
||||
struct addrinfo *hostinfo, *orig_hostinfo;
|
||||
char *interface, *source, *scope_id, *interface_opt;
|
||||
int serv_port, source_port, addr_type, scope_index, valid;
|
||||
u16 *flags;
|
||||
};
|
||||
|
||||
/* cache.c */
|
||||
void cache_init(void);
|
||||
void next_uid(struct crec *crecp);
|
||||
@@ -1295,6 +1314,7 @@ struct crec *cache_find_by_name(struct crec *crecp,
|
||||
char *name, time_t now, unsigned int prot);
|
||||
void cache_end_insert(void);
|
||||
void cache_start_insert(void);
|
||||
unsigned int cache_remove_uid(const unsigned int uid);
|
||||
int cache_recv_insert(time_t now, int fd);
|
||||
struct crec *cache_insert(char *name, union all_addr *addr, unsigned short class,
|
||||
time_t now, unsigned long ttl, unsigned int flags);
|
||||
@@ -1456,8 +1476,9 @@ void read_servers_file(void);
|
||||
void set_option_bool(unsigned int opt);
|
||||
void reset_option_bool(unsigned int opt);
|
||||
struct hostsfile *expand_filelist(struct hostsfile *list);
|
||||
char *parse_server(char *arg, union mysockaddr *addr,
|
||||
union mysockaddr *source_addr, char *interface, u16 *flags);
|
||||
char *parse_server(char *arg, struct server_details *sdetails);
|
||||
char *parse_server_addr(struct server_details *sdetails);
|
||||
int parse_server_next(struct server_details *sdetails);
|
||||
int option_read_dynfile(char *file, int flags);
|
||||
|
||||
/* forward.c */
|
||||
|
||||
+37
-22
@@ -979,10 +979,13 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
|
||||
}
|
||||
|
||||
/* The DNS packet is expected to contain the answer to a DS query
|
||||
Put all DSs in the answer which are valid into the cache.
|
||||
Put all DSs in the answer which are valid and have hash and signature algos
|
||||
we support into the cache.
|
||||
Also handles replies which prove that there's no DS at this location,
|
||||
either because the zone is unsigned or this isn't a zone cut. These are
|
||||
cached too.
|
||||
If none of the DS's are for supported algos, treat the answer as if
|
||||
it's a proof of no DS at this location. RFC4035 para 5.2.
|
||||
return codes:
|
||||
STAT_OK At least one valid DS found and in cache.
|
||||
STAT_BOGUS no DS in reply or not signed, fails validation, bad packet.
|
||||
@@ -993,8 +996,8 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
|
||||
int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int class)
|
||||
{
|
||||
unsigned char *p = (unsigned char *)(header+1);
|
||||
int qtype, qclass, rc, i, neganswer, nons, neg_ttl = 0;
|
||||
int aclass, atype, rdlen;
|
||||
int qtype, qclass, rc, i, neganswer, nons, neg_ttl = 0, found_supported = 0;
|
||||
int aclass, atype, rdlen, flags;
|
||||
unsigned long ttl;
|
||||
union all_addr a;
|
||||
|
||||
@@ -1065,14 +1068,22 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
|
||||
algo = *p++;
|
||||
digest = *p++;
|
||||
|
||||
if ((key = blockdata_alloc((char*)p, rdlen - 4)))
|
||||
if (!ds_digest_name(digest) || !ds_digest_name(digest))
|
||||
{
|
||||
a.log.keytag = keytag;
|
||||
a.log.algo = algo;
|
||||
a.log.digest = digest;
|
||||
log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %hu, algo %hu, digest %hu (not supported)", 0);
|
||||
neg_ttl = ttl;
|
||||
}
|
||||
else if ((key = blockdata_alloc((char*)p, rdlen - 4)))
|
||||
{
|
||||
a.ds.digest = digest;
|
||||
a.ds.keydata = key;
|
||||
a.ds.algo = algo;
|
||||
a.ds.keytag = keytag;
|
||||
a.ds.keylen = rdlen - 4;
|
||||
|
||||
|
||||
if (!cache_insert(name, &a, class, now, ttl, F_FORWARD | F_DS | F_DNSSECOK))
|
||||
{
|
||||
blockdata_free(key);
|
||||
@@ -1083,26 +1094,29 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
|
||||
a.log.keytag = keytag;
|
||||
a.log.algo = algo;
|
||||
a.log.digest = digest;
|
||||
if (ds_digest_name(digest) && algo_digest_name(algo))
|
||||
log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %hu, algo %hu, digest %hu", 0);
|
||||
else
|
||||
log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %hu, algo %hu, digest %hu (not supported)", 0);
|
||||
log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %hu, algo %hu, digest %hu", 0);
|
||||
found_supported = 1;
|
||||
}
|
||||
}
|
||||
|
||||
p = psave;
|
||||
}
|
||||
|
||||
if (!ADD_RDLEN(header, p, plen, rdlen))
|
||||
return STAT_BOGUS; /* bad packet */
|
||||
}
|
||||
|
||||
cache_end_insert();
|
||||
|
||||
/* Fall through if no supported algo DS found. */
|
||||
if (found_supported)
|
||||
return STAT_OK;
|
||||
}
|
||||
else
|
||||
|
||||
flags = F_FORWARD | F_DS | F_NEG | F_DNSSECOK;
|
||||
|
||||
if (neganswer)
|
||||
{
|
||||
int flags = F_FORWARD | F_DS | F_NEG | F_DNSSECOK;
|
||||
|
||||
if (RCODE(header) == NXDOMAIN)
|
||||
flags |= F_NXDOMAIN;
|
||||
|
||||
@@ -1110,17 +1124,18 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
|
||||
to store presence/absence of NS. */
|
||||
if (nons)
|
||||
flags &= ~F_DNSSECOK;
|
||||
|
||||
cache_start_insert();
|
||||
|
||||
/* Use TTL from NSEC for negative cache entries */
|
||||
if (!cache_insert(name, NULL, class, now, neg_ttl, flags))
|
||||
return STAT_BOGUS;
|
||||
|
||||
cache_end_insert();
|
||||
|
||||
log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, nons ? "no DS/cut" : "no DS", 0);
|
||||
}
|
||||
|
||||
cache_start_insert();
|
||||
|
||||
/* Use TTL from NSEC for negative cache entries */
|
||||
if (!cache_insert(name, NULL, class, now, neg_ttl, flags))
|
||||
return STAT_BOGUS;
|
||||
|
||||
cache_end_insert();
|
||||
|
||||
if (neganswer)
|
||||
log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, nons ? "no DS/cut" : "no DS", 0);
|
||||
|
||||
return STAT_OK;
|
||||
}
|
||||
|
||||
+3
-1
@@ -683,7 +683,9 @@ int add_update_server(int flags,
|
||||
serv->next = NULL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
up = &serv->next;
|
||||
}
|
||||
|
||||
if (serv)
|
||||
|
||||
+92
-45
@@ -133,81 +133,112 @@ void inotify_dnsmasq_init()
|
||||
}
|
||||
}
|
||||
|
||||
static struct hostsfile *dyndir_addhosts(struct dyndir *dd, char *path)
|
||||
{
|
||||
/* Check if this file is already known in dd->files */
|
||||
struct hostsfile *ah = NULL;
|
||||
for(ah = dd->files; ah; ah = ah->next)
|
||||
if(ah && ah->fname && strcmp(path, ah->fname) == 0)
|
||||
return ah;
|
||||
|
||||
/* Not known, create new hostsfile record for this dyndir */
|
||||
struct hostsfile *newah = NULL;
|
||||
if(!(newah = whine_malloc(sizeof(struct hostsfile))))
|
||||
return NULL;
|
||||
|
||||
/* Add this file to the tip of the linked list */
|
||||
newah->next = dd->files;
|
||||
dd->files = newah;
|
||||
|
||||
/* Copy flags, set index and the full file path */
|
||||
newah->flags = dd->flags;
|
||||
newah->index = daemon->host_index++;
|
||||
newah->fname = path;
|
||||
|
||||
return newah;
|
||||
}
|
||||
|
||||
|
||||
/* initialisation for dynamic-dir. Set inotify watch for each directory, and read pre-existing files */
|
||||
void set_dynamic_inotify(int flag, int total_size, struct crec **rhash, int revhashsz)
|
||||
{
|
||||
struct hostsfile *ah;
|
||||
|
||||
for (ah = daemon->dynamic_dirs; ah; ah = ah->next)
|
||||
struct dyndir *dd;
|
||||
|
||||
for (dd = daemon->dynamic_dirs; dd; dd = dd->next)
|
||||
{
|
||||
DIR *dir_stream = NULL;
|
||||
struct dirent *ent;
|
||||
struct stat buf;
|
||||
|
||||
if (!(ah->flags & flag))
|
||||
|
||||
if (!(dd->flags & flag))
|
||||
continue;
|
||||
|
||||
if (stat(ah->fname, &buf) == -1)
|
||||
|
||||
if (stat(dd->dname, &buf) == -1)
|
||||
{
|
||||
my_syslog(LOG_ERR, _("bad dynamic directory %s: %s"),
|
||||
ah->fname, strerror(errno));
|
||||
dd->dname, strerror(errno));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(S_ISDIR(buf.st_mode)))
|
||||
{
|
||||
my_syslog(LOG_ERR, _("bad dynamic directory %s: %s"),
|
||||
ah->fname, _("not a directory"));
|
||||
dd->dname, _("not a directory"));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(ah->flags & AH_WD_DONE))
|
||||
|
||||
if (!(dd->flags & AH_WD_DONE))
|
||||
{
|
||||
ah->wd = inotify_add_watch(daemon->inotifyfd, ah->fname, IN_CLOSE_WRITE | IN_MOVED_TO);
|
||||
ah->flags |= AH_WD_DONE;
|
||||
dd->wd = inotify_add_watch(daemon->inotifyfd, dd->dname, IN_CLOSE_WRITE | IN_MOVED_TO | IN_DELETE);
|
||||
dd->flags |= AH_WD_DONE;
|
||||
}
|
||||
|
||||
/* Read contents of dir _after_ calling add_watch, in the hope of avoiding
|
||||
a race which misses files being added as we start */
|
||||
if (ah->wd == -1 || !(dir_stream = opendir(ah->fname)))
|
||||
if (dd->wd == -1 || !(dir_stream = opendir(dd->dname)))
|
||||
{
|
||||
my_syslog(LOG_ERR, _("failed to create inotify for %s: %s"),
|
||||
ah->fname, strerror(errno));
|
||||
dd->dname, strerror(errno));
|
||||
continue;
|
||||
}
|
||||
|
||||
while ((ent = readdir(dir_stream)))
|
||||
{
|
||||
size_t lendir = strlen(ah->fname);
|
||||
size_t lendir = strlen(dd->dname);
|
||||
size_t lenfile = strlen(ent->d_name);
|
||||
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;
|
||||
|
||||
|
||||
if ((path = whine_malloc(lendir + lenfile + 2)))
|
||||
{
|
||||
strcpy(path, ah->fname);
|
||||
struct hostsfile *ah;
|
||||
|
||||
strcpy(path, dd->dname);
|
||||
strcat(path, "/");
|
||||
strcat(path, ent->d_name);
|
||||
|
||||
if (!(ah = dyndir_addhosts(dd, path)))
|
||||
{
|
||||
free(path);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* ignore non-regular files */
|
||||
if (stat(path, &buf) != -1 && S_ISREG(buf.st_mode))
|
||||
{
|
||||
if (ah->flags & AH_HOSTS)
|
||||
if (dd->flags & AH_HOSTS)
|
||||
total_size = read_hostsfile(path, ah->index, total_size, rhash, revhashsz);
|
||||
#ifdef HAVE_DHCP
|
||||
else if (ah->flags & (AH_DHCP_HST | AH_DHCP_OPT))
|
||||
option_read_dynfile(path, ah->flags);
|
||||
else if (dd->flags & (AH_DHCP_HST | AH_DHCP_OPT))
|
||||
option_read_dynfile(path, dd->flags);
|
||||
#endif
|
||||
}
|
||||
|
||||
free(path);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -218,7 +249,7 @@ void set_dynamic_inotify(int flag, int total_size, struct crec **rhash, int revh
|
||||
int inotify_check(time_t now)
|
||||
{
|
||||
int hit = 0;
|
||||
struct hostsfile *ah;
|
||||
struct dyndir *dd;
|
||||
|
||||
while (1)
|
||||
{
|
||||
@@ -249,36 +280,51 @@ int inotify_check(time_t now)
|
||||
if (res->wd == in->wd && strcmp(res->file, in->name) == 0)
|
||||
hit = 1;
|
||||
|
||||
for (ah = daemon->dynamic_dirs; ah; ah = ah->next)
|
||||
if (ah->wd == in->wd)
|
||||
for (dd = daemon->dynamic_dirs; dd; dd = dd->next)
|
||||
if (dd->wd == in->wd)
|
||||
{
|
||||
size_t lendir = strlen(ah->fname);
|
||||
size_t lendir = strlen(dd->dname);
|
||||
char *path;
|
||||
|
||||
|
||||
if ((path = whine_malloc(lendir + in->len + 2)))
|
||||
{
|
||||
strcpy(path, ah->fname);
|
||||
struct hostsfile *ah = NULL;
|
||||
|
||||
strcpy(path, dd->dname);
|
||||
strcat(path, "/");
|
||||
strcat(path, in->name);
|
||||
|
||||
my_syslog(LOG_INFO, _("inotify, new or changed file %s"), path);
|
||||
|
||||
if (ah->flags & AH_HOSTS)
|
||||
/* Is this is a deletion event? */
|
||||
if (in->mask & IN_DELETE)
|
||||
my_syslog(LOG_INFO, _("inotify: %s removed"), path);
|
||||
else
|
||||
my_syslog(LOG_INFO, _("inotify: %s new or modified"), path);
|
||||
|
||||
if (dd->flags & AH_HOSTS)
|
||||
{
|
||||
read_hostsfile(path, ah->index, 0, NULL, 0);
|
||||
#ifdef HAVE_DHCP
|
||||
if (daemon->dhcp || daemon->doing_dhcp6)
|
||||
if ((ah = dyndir_addhosts(dd, path)))
|
||||
{
|
||||
/* Propagate the consequences of loading a new dhcp-host */
|
||||
dhcp_update_configs(daemon->dhcp_conf);
|
||||
lease_update_from_configs();
|
||||
lease_update_file(now);
|
||||
lease_update_dns(1);
|
||||
}
|
||||
const unsigned int removed = cache_remove_uid(ah->index);
|
||||
if (removed > 0)
|
||||
my_syslog(LOG_INFO, _("inotify: flushed %u names read from %s"), removed, path);
|
||||
|
||||
/* (Re-)load hostsfile only if this event isn't triggered by deletion */
|
||||
if (!(in->mask & IN_DELETE))
|
||||
read_hostsfile(path, ah->index, 0, NULL, 0);
|
||||
#ifdef HAVE_DHCP
|
||||
if (daemon->dhcp || daemon->doing_dhcp6)
|
||||
{
|
||||
/* Propagate the consequences of loading a new dhcp-host */
|
||||
dhcp_update_configs(daemon->dhcp_conf);
|
||||
lease_update_from_configs();
|
||||
lease_update_file(now);
|
||||
lease_update_dns(1);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#ifdef HAVE_DHCP
|
||||
else if (ah->flags & AH_DHCP_HST)
|
||||
else if (dd->flags & AH_DHCP_HST)
|
||||
{
|
||||
if (option_read_dynfile(path, AH_DHCP_HST))
|
||||
{
|
||||
@@ -289,11 +335,12 @@ int inotify_check(time_t now)
|
||||
lease_update_dns(1);
|
||||
}
|
||||
}
|
||||
else if (ah->flags & AH_DHCP_OPT)
|
||||
else if (dd->flags & AH_DHCP_OPT)
|
||||
option_read_dynfile(path, AH_DHCP_OPT);
|
||||
#endif
|
||||
|
||||
free(path);
|
||||
if (!ah)
|
||||
free(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+343
-139
@@ -184,6 +184,7 @@ struct myoption {
|
||||
#define LOPT_RANDPORT_LIM 375
|
||||
#define LOPT_FAST_RETRY 376
|
||||
#define LOPT_STALE_CACHE 377
|
||||
#define LOPT_NORR 378
|
||||
|
||||
#ifdef HAVE_GETOPT_LONG
|
||||
static const struct option opts[] =
|
||||
@@ -236,6 +237,7 @@ static const struct myoption opts[] =
|
||||
{ "localmx", 0, 0, 'L' },
|
||||
{ "local-ttl", 1, 0, 'T' },
|
||||
{ "no-negcache", 0, 0, 'N' },
|
||||
{ "no-round-robin", 0, 0, LOPT_NORR },
|
||||
{ "addn-hosts", 1, 0, 'H' },
|
||||
{ "hostsdir", 1, 0, LOPT_HOST_INOTIFY },
|
||||
{ "query-port", 1, 0, 'Q' },
|
||||
@@ -567,6 +569,7 @@ static struct {
|
||||
{ LOPT_SCRIPT_TIME, OPT_LEASE_RENEW, NULL, gettext_noop("Call dhcp-script when lease expiry changes."), NULL },
|
||||
{ LOPT_UMBRELLA, ARG_ONE, "[=<optspec>]", gettext_noop("Send Cisco Umbrella identifiers including remote IP."), NULL },
|
||||
{ LOPT_QUIET_TFTP, OPT_QUIET_TFTP, NULL, gettext_noop("Do not log routine TFTP."), NULL },
|
||||
{ LOPT_NORR, OPT_NORR, NULL, gettext_noop("Suppress round-robin ordering of DNS records."), NULL },
|
||||
{ 0, 0, NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
@@ -852,117 +855,244 @@ static char *parse_mysockaddr(char *arg, union mysockaddr *addr)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *parse_server(char *arg, union mysockaddr *addr, union mysockaddr *source_addr, char *interface, u16 *flags)
|
||||
char *parse_server(char *arg, struct server_details *sdetails)
|
||||
{
|
||||
int source_port = 0, serv_port = NAMESERVER_PORT;
|
||||
char *portno, *source;
|
||||
char *interface_opt = NULL;
|
||||
int scope_index = 0;
|
||||
char *scope_id;
|
||||
|
||||
*interface = 0;
|
||||
sdetails->serv_port = NAMESERVER_PORT;
|
||||
char *portno;
|
||||
int ecode = 0;
|
||||
struct addrinfo hints;
|
||||
|
||||
memset(&hints, 0, sizeof(struct addrinfo));
|
||||
|
||||
*sdetails->interface = 0;
|
||||
sdetails->addr_type = AF_UNSPEC;
|
||||
sdetails->valid = 0;
|
||||
sdetails->hostinfo = sdetails->orig_hostinfo = NULL;
|
||||
|
||||
|
||||
if (strcmp(arg, "#") == 0)
|
||||
{
|
||||
if (flags)
|
||||
*flags |= SERV_USE_RESOLV;
|
||||
if (sdetails->flags)
|
||||
*sdetails->flags |= SERV_USE_RESOLV;
|
||||
sdetails->addr_type = AF_LOCAL;
|
||||
sdetails->valid = 1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((source = split_chr(arg, '@')) && /* is there a source. */
|
||||
(portno = split_chr(source, '#')) &&
|
||||
!atoi_check16(portno, &source_port))
|
||||
if ((sdetails->source = split_chr(arg, '@')) && /* is there a source. */
|
||||
(portno = split_chr(sdetails->source, '#')) &&
|
||||
!atoi_check16(portno, &sdetails->source_port))
|
||||
return _("bad port");
|
||||
|
||||
if ((portno = split_chr(arg, '#')) && /* is there a port no. */
|
||||
!atoi_check16(portno, &serv_port))
|
||||
!atoi_check16(portno, &sdetails->serv_port))
|
||||
return _("bad port");
|
||||
|
||||
scope_id = split_chr(arg, '%');
|
||||
sdetails->scope_id = split_chr(arg, '%');
|
||||
|
||||
if (source) {
|
||||
interface_opt = split_chr(source, '@');
|
||||
if (sdetails->source) {
|
||||
sdetails->interface_opt = split_chr(sdetails->source, '@');
|
||||
|
||||
if (interface_opt)
|
||||
if (sdetails->interface_opt)
|
||||
{
|
||||
#if defined(SO_BINDTODEVICE)
|
||||
safe_strncpy(interface, source, IF_NAMESIZE);
|
||||
source = interface_opt;
|
||||
safe_strncpy(sdetails->interface, sdetails->source, IF_NAMESIZE);
|
||||
sdetails->source = sdetails->interface_opt;
|
||||
#else
|
||||
return _("interface binding not supported");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (inet_pton(AF_INET, arg, &addr->in.sin_addr) > 0)
|
||||
if (inet_pton(AF_INET, arg, &sdetails->addr->in.sin_addr) > 0)
|
||||
sdetails->addr_type = AF_INET;
|
||||
else if (inet_pton(AF_INET6, arg, &sdetails->addr->in6.sin6_addr) > 0)
|
||||
sdetails->addr_type = AF_INET6;
|
||||
else
|
||||
{
|
||||
addr->in.sin_port = htons(serv_port);
|
||||
addr->sa.sa_family = source_addr->sa.sa_family = AF_INET;
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
source_addr->in.sin_len = addr->in.sin_len = sizeof(struct sockaddr_in);
|
||||
/* if the argument is neither an IPv4 not an IPv6 address, it might be a
|
||||
hostname and we should try to resolve it to a suitable address. */
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
/* The AI_ADDRCONFIG flag ensures that then IPv4 addresses are returned in
|
||||
the result only if the local system has at least one IPv4 address
|
||||
configured, and IPv6 addresses are returned only if the local system
|
||||
has at least one IPv6 address configured. The loopback address is not
|
||||
considered for this case as valid as a configured address. This flag is
|
||||
useful on, for example, IPv4-only systems, to ensure that getaddrinfo()
|
||||
does not return IPv6 socket addresses that would always fail in
|
||||
subsequent connect() or bind() attempts. */
|
||||
hints.ai_flags = AI_ADDRCONFIG;
|
||||
#if defined(HAVE_IDN) && defined(AI_IDN)
|
||||
/* If the AI_IDN flag is specified and we have glibc 2.3.4 or newer, then
|
||||
the node name given in node is converted to IDN format if necessary.
|
||||
The source encoding is that of the current locale. */
|
||||
hints.ai_flags |= AI_IDN;
|
||||
#endif
|
||||
source_addr->in.sin_addr.s_addr = INADDR_ANY;
|
||||
source_addr->in.sin_port = htons(daemon->query_port);
|
||||
|
||||
if (source)
|
||||
{
|
||||
if (flags)
|
||||
*flags |= SERV_HAS_SOURCE;
|
||||
source_addr->in.sin_port = htons(source_port);
|
||||
if (!(inet_pton(AF_INET, source, &source_addr->in.sin_addr) > 0))
|
||||
{
|
||||
#if defined(SO_BINDTODEVICE)
|
||||
if (interface_opt)
|
||||
return _("interface can only be specified once");
|
||||
|
||||
source_addr->in.sin_addr.s_addr = INADDR_ANY;
|
||||
safe_strncpy(interface, source, IF_NAMESIZE);
|
||||
#else
|
||||
return _("interface binding not supported");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (inet_pton(AF_INET6, arg, &addr->in6.sin6_addr) > 0)
|
||||
{
|
||||
if (scope_id && (scope_index = if_nametoindex(scope_id)) == 0)
|
||||
return _("bad interface name");
|
||||
|
||||
addr->in6.sin6_port = htons(serv_port);
|
||||
addr->in6.sin6_scope_id = scope_index;
|
||||
source_addr->in6.sin6_addr = in6addr_any;
|
||||
source_addr->in6.sin6_port = htons(daemon->query_port);
|
||||
source_addr->in6.sin6_scope_id = 0;
|
||||
addr->sa.sa_family = source_addr->sa.sa_family = AF_INET6;
|
||||
addr->in6.sin6_flowinfo = source_addr->in6.sin6_flowinfo = 0;
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
addr->in6.sin6_len = source_addr->in6.sin6_len = sizeof(addr->in6);
|
||||
#endif
|
||||
if (source)
|
||||
{
|
||||
if (flags)
|
||||
*flags |= SERV_HAS_SOURCE;
|
||||
source_addr->in6.sin6_port = htons(source_port);
|
||||
if (inet_pton(AF_INET6, source, &source_addr->in6.sin6_addr) == 0)
|
||||
{
|
||||
#if defined(SO_BINDTODEVICE)
|
||||
if (interface_opt)
|
||||
return _("interface can only be specified once");
|
||||
|
||||
source_addr->in6.sin6_addr = in6addr_any;
|
||||
safe_strncpy(interface, source, IF_NAMESIZE);
|
||||
#else
|
||||
return _("interface binding not supported");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
return _("bad address");
|
||||
/* The value AF_UNSPEC indicates that getaddrinfo() should return socket
|
||||
addresses for any address family (either IPv4 or IPv6, for example)
|
||||
that can be used with node <arg> and service "domain". */
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
|
||||
/* Get addresses suitable for sending datagrams. We assume that we can use the
|
||||
same addresses for TCP connections. Settting this to zero gets each address
|
||||
threes times, for SOCK_STREAM, SOCK_RAW and SOCK_DGRAM, which is not useful. */
|
||||
hints.ai_socktype = SOCK_DGRAM;
|
||||
|
||||
/* Get address associated with this hostname */
|
||||
ecode = getaddrinfo(arg, NULL, &hints, &sdetails->hostinfo);
|
||||
if (ecode == 0)
|
||||
{
|
||||
/* The getaddrinfo() function allocated and initialized a linked list of
|
||||
addrinfo structures, one for each network address that matches node
|
||||
and service, subject to the restrictions imposed by our <hints>
|
||||
above, and returns a pointer to the start of the list in <hostinfo>.
|
||||
The items in the linked list are linked by the <ai_next> field. */
|
||||
sdetails->valid = 1;
|
||||
sdetails->orig_hostinfo = sdetails->hostinfo;
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Lookup failed, return human readable error string */
|
||||
if (ecode == EAI_AGAIN)
|
||||
return _("Cannot resolve server name");
|
||||
else
|
||||
return _((char*)gai_strerror(ecode));
|
||||
}
|
||||
}
|
||||
|
||||
sdetails->valid = 1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *parse_server_addr(struct server_details *sdetails)
|
||||
{
|
||||
if (sdetails->addr_type == AF_INET)
|
||||
{
|
||||
sdetails->addr->in.sin_port = htons(sdetails->serv_port);
|
||||
sdetails->addr->sa.sa_family = sdetails->source_addr->sa.sa_family = AF_INET;
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
sdetails->source_addr->in.sin_len = sdetails->addr->in.sin_len = sizeof(struct sockaddr_in);
|
||||
#endif
|
||||
sdetails->source_addr->in.sin_addr.s_addr = INADDR_ANY;
|
||||
sdetails->source_addr->in.sin_port = htons(daemon->query_port);
|
||||
|
||||
if (sdetails->source)
|
||||
{
|
||||
if (sdetails->flags)
|
||||
*sdetails->flags |= SERV_HAS_SOURCE;
|
||||
sdetails->source_addr->in.sin_port = htons(sdetails->source_port);
|
||||
if (inet_pton(AF_INET, sdetails->source, &sdetails->source_addr->in.sin_addr) == 0)
|
||||
{
|
||||
if (inet_pton(AF_INET6, sdetails->source, &sdetails->source_addr->in6.sin6_addr) == 1)
|
||||
{
|
||||
sdetails->source_addr->sa.sa_family = AF_INET6;
|
||||
/* When resolving a server IP by hostname, we can simply skip mismatching
|
||||
server / source IP pairs. Otherwise, when an IP address is given directly,
|
||||
this is a fatal error. */
|
||||
if (!sdetails->orig_hostinfo)
|
||||
return _("cannot use IPv4 server address with IPv6 source address");
|
||||
}
|
||||
else
|
||||
{
|
||||
#if defined(SO_BINDTODEVICE)
|
||||
if (sdetails->interface_opt)
|
||||
return _("interface can only be specified once");
|
||||
|
||||
sdetails->source_addr->in.sin_addr.s_addr = INADDR_ANY;
|
||||
safe_strncpy(sdetails->interface, sdetails->source, IF_NAMESIZE);
|
||||
#else
|
||||
return _("interface binding not supported");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (sdetails->addr_type == AF_INET6)
|
||||
{
|
||||
if (sdetails->scope_id && (sdetails->scope_index = if_nametoindex(sdetails->scope_id)) == 0)
|
||||
return _("bad interface name");
|
||||
|
||||
sdetails->addr->in6.sin6_port = htons(sdetails->serv_port);
|
||||
sdetails->addr->in6.sin6_scope_id = sdetails->scope_index;
|
||||
sdetails->source_addr->in6.sin6_addr = in6addr_any;
|
||||
sdetails->source_addr->in6.sin6_port = htons(daemon->query_port);
|
||||
sdetails->source_addr->in6.sin6_scope_id = 0;
|
||||
sdetails->addr->sa.sa_family = sdetails->source_addr->sa.sa_family = AF_INET6;
|
||||
sdetails->addr->in6.sin6_flowinfo = sdetails->source_addr->in6.sin6_flowinfo = 0;
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
sdetails->addr->in6.sin6_len = sdetails->source_addr->in6.sin6_len = sizeof(sdetails->addr->in6);
|
||||
#endif
|
||||
if (sdetails->source)
|
||||
{
|
||||
if (sdetails->flags)
|
||||
*sdetails->flags |= SERV_HAS_SOURCE;
|
||||
sdetails->source_addr->in6.sin6_port = htons(sdetails->source_port);
|
||||
if (inet_pton(AF_INET6, sdetails->source, &sdetails->source_addr->in6.sin6_addr) == 0)
|
||||
{
|
||||
if (inet_pton(AF_INET, sdetails->source, &sdetails->source_addr->in.sin_addr) == 1)
|
||||
{
|
||||
sdetails->source_addr->sa.sa_family = AF_INET;
|
||||
/* When resolving a server IP by hostname, we can simply skip mismatching
|
||||
server / source IP pairs. Otherwise, when an IP address is given directly,
|
||||
this is a fatal error. */
|
||||
if(!sdetails->orig_hostinfo)
|
||||
return _("cannot use IPv6 server address with IPv4 source address");
|
||||
}
|
||||
else
|
||||
{
|
||||
#if defined(SO_BINDTODEVICE)
|
||||
if (sdetails->interface_opt)
|
||||
return _("interface can only be specified once");
|
||||
|
||||
sdetails->source_addr->in6.sin6_addr = in6addr_any;
|
||||
safe_strncpy(sdetails->interface, sdetails->source, IF_NAMESIZE);
|
||||
#else
|
||||
return _("interface binding not supported");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (sdetails->addr_type != AF_LOCAL)
|
||||
return _("bad address");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int parse_server_next(struct server_details *sdetails)
|
||||
{
|
||||
/* Looping over resolved addresses? */
|
||||
if (sdetails->hostinfo)
|
||||
{
|
||||
/* Get address type */
|
||||
sdetails->addr_type = sdetails->hostinfo->ai_family;
|
||||
|
||||
/* Get address */
|
||||
if (sdetails->addr_type == AF_INET)
|
||||
memcpy(&sdetails->addr->in.sin_addr,
|
||||
&((struct sockaddr_in *) sdetails->hostinfo->ai_addr)->sin_addr,
|
||||
sizeof(sdetails->addr->in.sin_addr));
|
||||
else if (sdetails->addr_type == AF_INET6)
|
||||
memcpy(&sdetails->addr->in6.sin6_addr,
|
||||
&((struct sockaddr_in6 *) sdetails->hostinfo->ai_addr)->sin6_addr,
|
||||
sizeof(sdetails->addr->in6.sin6_addr));
|
||||
|
||||
/* Iterate to the next available address */
|
||||
sdetails->valid = sdetails->hostinfo->ai_next != NULL;
|
||||
sdetails->hostinfo = sdetails->hostinfo->ai_next;
|
||||
return 1;
|
||||
}
|
||||
else if (sdetails->valid)
|
||||
{
|
||||
/* When using an IP address, we return the address only once */
|
||||
sdetails->valid = 0;
|
||||
return 1;
|
||||
}
|
||||
/* Stop iterating here, we used all available addresses */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *domain_rev4(int from_file, char *server, struct in_addr *addr4, int size)
|
||||
{
|
||||
int i, j;
|
||||
@@ -973,22 +1103,27 @@ static char *domain_rev4(int from_file, char *server, struct in_addr *addr4, int
|
||||
union mysockaddr serv_addr, source_addr;
|
||||
char interface[IF_NAMESIZE+1];
|
||||
int count = 1, rem, addrbytes, addrbits;
|
||||
|
||||
struct server_details sdetails;
|
||||
sdetails.addr = &serv_addr;
|
||||
sdetails.source_addr = &source_addr;
|
||||
sdetails.interface = interface;
|
||||
sdetails.flags = &flags;
|
||||
|
||||
if (!server)
|
||||
flags = SERV_LITERAL_ADDRESS;
|
||||
else if ((string = parse_server(server, &serv_addr, &source_addr, interface, &flags)))
|
||||
else if ((string = parse_server(server, &sdetails)))
|
||||
return string;
|
||||
|
||||
|
||||
if (from_file)
|
||||
flags |= SERV_FROM_FILE;
|
||||
|
||||
|
||||
rem = size & 0x7;
|
||||
addrbytes = (32 - size) >> 3;
|
||||
addrbits = (32 - size) & 7;
|
||||
|
||||
if (size > 32 || size < 1)
|
||||
return _("bad IPv4 prefix length");
|
||||
|
||||
|
||||
/* Zero out last address bits according to CIDR mask */
|
||||
((u8 *)addr4)[3-addrbytes] &= ~((1 << addrbits)-1);
|
||||
|
||||
@@ -1002,23 +1137,40 @@ static char *domain_rev4(int from_file, char *server, struct in_addr *addr4, int
|
||||
*domain = 0;
|
||||
string = domain;
|
||||
msize = size/8;
|
||||
|
||||
|
||||
for (j = (rem == 0) ? msize-1 : msize; j >= 0; j--)
|
||||
{
|
||||
int dig = ((unsigned char *)addr4)[j];
|
||||
|
||||
|
||||
if (j == msize)
|
||||
dig += i;
|
||||
|
||||
|
||||
string += sprintf(string, "%d.", dig);
|
||||
}
|
||||
|
||||
|
||||
sprintf(string, "in-addr.arpa");
|
||||
|
||||
if (!add_update_server(flags, &serv_addr, &source_addr, interface, domain, NULL))
|
||||
return _("error");
|
||||
}
|
||||
if (flags & SERV_LITERAL_ADDRESS)
|
||||
{
|
||||
if (!add_update_server(flags, &serv_addr, &source_addr, interface, domain, NULL))
|
||||
return _("error");
|
||||
}
|
||||
else
|
||||
{
|
||||
while (parse_server_next(&sdetails))
|
||||
{
|
||||
if ((string = parse_server_addr(&sdetails)))
|
||||
return string;
|
||||
|
||||
if (!add_update_server(flags, &serv_addr, &source_addr, interface, domain, NULL))
|
||||
return _("error");
|
||||
}
|
||||
|
||||
if (sdetails.orig_hostinfo)
|
||||
freeaddrinfo(sdetails.orig_hostinfo);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1032,10 +1184,15 @@ static char *domain_rev6(int from_file, char *server, struct in6_addr *addr6, in
|
||||
union mysockaddr serv_addr, source_addr;
|
||||
char interface[IF_NAMESIZE+1];
|
||||
int count = 1, rem, addrbytes, addrbits;
|
||||
|
||||
struct server_details sdetails;
|
||||
sdetails.addr = &serv_addr;
|
||||
sdetails.source_addr = &source_addr;
|
||||
sdetails.interface = interface;
|
||||
sdetails.flags = &flags;
|
||||
|
||||
if (!server)
|
||||
flags = SERV_LITERAL_ADDRESS;
|
||||
else if ((string = parse_server(server, &serv_addr, &source_addr, interface, &flags)))
|
||||
else if ((string = parse_server(server, &sdetails)))
|
||||
return string;
|
||||
|
||||
if (from_file)
|
||||
@@ -1076,10 +1233,27 @@ static char *domain_rev6(int from_file, char *server, struct in6_addr *addr6, in
|
||||
|
||||
sprintf(string, "ip6.arpa");
|
||||
|
||||
if (!add_update_server(flags, &serv_addr, &source_addr, interface, domain, NULL))
|
||||
return _("error");
|
||||
}
|
||||
if (flags & SERV_LITERAL_ADDRESS)
|
||||
{
|
||||
if (!add_update_server(flags, &serv_addr, &source_addr, interface, domain, NULL))
|
||||
return _("error");
|
||||
}
|
||||
else
|
||||
{
|
||||
while (parse_server_next(&sdetails))
|
||||
{
|
||||
if ((string = parse_server_addr(&sdetails)))
|
||||
return string;
|
||||
|
||||
if (!add_update_server(flags, &serv_addr, &source_addr, interface, domain, NULL))
|
||||
return _("error");
|
||||
}
|
||||
|
||||
if (sdetails.orig_hostinfo)
|
||||
freeaddrinfo(sdetails.orig_hostinfo);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -2162,15 +2336,11 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
|
||||
case LOPT_DHCP_HOST: /* --dhcp-hostsfile */
|
||||
case LOPT_DHCP_OPTS: /* --dhcp-optsfile */
|
||||
case LOPT_DHCP_INOTIFY: /* --dhcp-hostsdir */
|
||||
case LOPT_DHOPT_INOTIFY: /* --dhcp-optsdir */
|
||||
case LOPT_HOST_INOTIFY: /* --hostsdir */
|
||||
case 'H': /* --addn-hosts */
|
||||
{
|
||||
struct hostsfile *new = opt_malloc(sizeof(struct hostsfile));
|
||||
static unsigned int hosts_index = SRC_AH;
|
||||
new->fname = opt_string_alloc(arg);
|
||||
new->index = hosts_index++;
|
||||
new->index = daemon->host_index++;
|
||||
new->flags = 0;
|
||||
if (option == 'H')
|
||||
{
|
||||
@@ -2186,21 +2356,29 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
{
|
||||
new->next = daemon->dhcp_opts_file;
|
||||
daemon->dhcp_opts_file = new;
|
||||
}
|
||||
else
|
||||
{
|
||||
new->next = daemon->dynamic_dirs;
|
||||
daemon->dynamic_dirs = new;
|
||||
if (option == LOPT_DHCP_INOTIFY)
|
||||
new->flags |= AH_DHCP_HST;
|
||||
else if (option == LOPT_DHOPT_INOTIFY)
|
||||
new->flags |= AH_DHCP_OPT;
|
||||
else if (option == LOPT_HOST_INOTIFY)
|
||||
new->flags |= AH_HOSTS;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case LOPT_DHCP_INOTIFY: /* --dhcp-hostsdir */
|
||||
case LOPT_DHOPT_INOTIFY: /* --dhcp-optsdir */
|
||||
case LOPT_HOST_INOTIFY: /* --hostsdir */
|
||||
{
|
||||
struct dyndir *new = opt_malloc(sizeof(struct dyndir));
|
||||
new->dname = opt_string_alloc(arg);
|
||||
new->flags = 0;
|
||||
new->next = daemon->dynamic_dirs;
|
||||
daemon->dynamic_dirs = new;
|
||||
if (option == LOPT_DHCP_INOTIFY)
|
||||
new->flags |= AH_DHCP_HST;
|
||||
else if (option == LOPT_DHOPT_INOTIFY)
|
||||
new->flags |= AH_DHCP_OPT;
|
||||
else if (option == LOPT_HOST_INOTIFY)
|
||||
new->flags |= AH_HOSTS;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case LOPT_AUTHSERV: /* --auth-server */
|
||||
comma = split(arg);
|
||||
@@ -2786,13 +2964,19 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
case LOPT_LOCAL: /* --local */
|
||||
case 'A': /* --address */
|
||||
{
|
||||
char *lastdomain = NULL, *domain = "";
|
||||
char *lastdomain = NULL, *domain = "", *cur_domain;
|
||||
u16 flags = 0;
|
||||
char *err;
|
||||
union all_addr addr;
|
||||
union mysockaddr serv_addr, source_addr;
|
||||
char interface[IF_NAMESIZE+1];
|
||||
|
||||
struct server_details sdetails;
|
||||
sdetails.addr = &serv_addr;
|
||||
sdetails.source_addr = &source_addr;
|
||||
sdetails.interface = interface;
|
||||
sdetails.flags = &flags;
|
||||
|
||||
unhide_metas(arg);
|
||||
|
||||
/* split the domain args, if any and skip to the end of them. */
|
||||
@@ -2825,36 +3009,55 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((err = parse_server(arg, &serv_addr, &source_addr, interface, &flags)))
|
||||
if ((err = parse_server(arg, &sdetails)))
|
||||
ret_err(err);
|
||||
}
|
||||
|
||||
if (servers_only && option == 'S')
|
||||
flags |= SERV_FROM_FILE;
|
||||
|
||||
while (1)
|
||||
{
|
||||
/* server=//1.2.3.4 is special. */
|
||||
if (lastdomain)
|
||||
{
|
||||
if (strlen(domain) == 0)
|
||||
flags |= SERV_FOR_NODOTS;
|
||||
else
|
||||
flags &= ~SERV_FOR_NODOTS;
|
||||
|
||||
/* address=/#/ matches the same as without domain */
|
||||
if (option == 'A' && domain[0] == '#' && domain[1] == 0)
|
||||
domain[0] = 0;
|
||||
cur_domain = domain;
|
||||
while ((flags & SERV_LITERAL_ADDRESS) || parse_server_next(&sdetails))
|
||||
{
|
||||
cur_domain = domain;
|
||||
|
||||
if (!(flags & SERV_LITERAL_ADDRESS) && (err = parse_server_addr(&sdetails)))
|
||||
ret_err(err);
|
||||
|
||||
/* When source is set only use DNS records of the same type and skip all others */
|
||||
if (flags & SERV_HAS_SOURCE && sdetails.addr_type != sdetails.source_addr->sa.sa_family)
|
||||
continue;
|
||||
|
||||
while (1)
|
||||
{
|
||||
/* server=//1.2.3.4 is special. */
|
||||
if (lastdomain)
|
||||
{
|
||||
if (strlen(cur_domain) == 0)
|
||||
flags |= SERV_FOR_NODOTS;
|
||||
else
|
||||
flags &= ~SERV_FOR_NODOTS;
|
||||
|
||||
/* address=/#/ matches the same as without domain */
|
||||
if (option == 'A' && cur_domain[0] == '#' && cur_domain[1] == 0)
|
||||
cur_domain[0] = 0;
|
||||
}
|
||||
|
||||
if (!add_update_server(flags, sdetails.addr, sdetails.source_addr, sdetails.interface, cur_domain, &addr))
|
||||
ret_err(gen_err);
|
||||
|
||||
if (!lastdomain || cur_domain == lastdomain)
|
||||
break;
|
||||
|
||||
cur_domain += strlen(cur_domain) + 1;
|
||||
}
|
||||
|
||||
if (!add_update_server(flags, &serv_addr, &source_addr, interface, domain, &addr))
|
||||
ret_err(gen_err);
|
||||
|
||||
if (!lastdomain || domain == lastdomain)
|
||||
|
||||
if (flags & SERV_LITERAL_ADDRESS)
|
||||
break;
|
||||
|
||||
domain += strlen(domain) + 1;
|
||||
}
|
||||
|
||||
if (sdetails.orig_hostinfo)
|
||||
freeaddrinfo(sdetails.orig_hostinfo);
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -5532,7 +5735,8 @@ void read_opts(int argc, char **argv, char *compile_opts)
|
||||
daemon->soa_retry = SOA_RETRY;
|
||||
daemon->soa_expiry = SOA_EXPIRY;
|
||||
daemon->randport_limit = 1;
|
||||
|
||||
daemon->host_index = SRC_AH;
|
||||
|
||||
#ifndef NO_ID
|
||||
add_txt("version.bind", "dnsmasq-" VERSION, 0 );
|
||||
add_txt("authors.bind", "Simon Kelley", 0);
|
||||
|
||||
+8
-1
@@ -1153,15 +1153,22 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
tagif_netid = run_tag_if(&context->netid);
|
||||
}
|
||||
|
||||
log_tags(tagif_netid, ntohl(mess->xid));
|
||||
apply_delay(mess->xid, recvtime, tagif_netid);
|
||||
|
||||
if (option_bool(OPT_RAPID_COMMIT) && option_find(mess, sz, OPTION_RAPID_COMMIT, 0))
|
||||
{
|
||||
rapid_commit = 1;
|
||||
/* If a lease exists for this host and another address, squash it. */
|
||||
if (lease && lease->addr.s_addr != mess->yiaddr.s_addr)
|
||||
{
|
||||
lease_prune(lease, now);
|
||||
lease = NULL;
|
||||
}
|
||||
goto rapid_commit;
|
||||
}
|
||||
|
||||
log_tags(tagif_netid, ntohl(mess->xid));
|
||||
|
||||
daemon->metrics[METRIC_DHCPOFFER]++;
|
||||
log_packet("DHCPOFFER" , &mess->yiaddr, emac, emac_len, iface_name, NULL, NULL, mess->xid);
|
||||
|
||||
|
||||
Reference in new issue
Block a user