mirror of
http://thekelleys.org.uk/git/dnsmasq.git
synced 2026-11-04 13:48:30 +00:00
Compare commits
19
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
604f7598c2 | ||
|
|
2a7a2b84ec | ||
|
|
3e21a1a6fa | ||
|
|
2b29191e7c | ||
|
|
03431d6373 | ||
|
|
cc1a29e250 | ||
|
|
e62e9b6187 | ||
|
|
19c51cfa49 | ||
|
|
d5082158ee | ||
|
|
3f7483e816 | ||
|
|
0c8584eabc | ||
|
|
f00690f93e | ||
|
|
89b12ed35b | ||
|
|
1a9a3489ec | ||
|
|
c8a80487cd | ||
|
|
4ea8e80dd9 | ||
|
|
c07d30dcb1 | ||
|
|
d588ab54d4 | ||
|
|
f8b422a7b6 |
No files matched your search
@@ -67,7 +67,20 @@ version 2.69
|
||||
Add --servers-file. Allows dynamic update of upstream servers
|
||||
full access to configuration.
|
||||
|
||||
|
||||
Add --local-service. Accept DNS queries only from hosts
|
||||
whose address is on a local subnet, ie a subnet for which
|
||||
an interface exists on the server. This option
|
||||
only has effect if there are no --interface --except-interface,
|
||||
--listen-address or --auth-server options. It is intended
|
||||
to be set as a default on installation, to allow
|
||||
unconfigured installations to be useful but also safe from
|
||||
being used for DNS amplification attacks.
|
||||
|
||||
Fix crashes in cache_get_cname_target() when dangling CNAMEs
|
||||
encountered. Thanks to Andy and the rt-n56u project for
|
||||
find this and helping to chase it down.
|
||||
|
||||
|
||||
version 2.68
|
||||
Use random addresses for DHCPv6 temporary address
|
||||
allocations, instead of algorithmically determined stable
|
||||
|
||||
+4
-1
@@ -14,8 +14,11 @@ if grep "^\#[[:space:]]*define[[:space:]]*$search" config.h >/dev/null 2>&1 || \
|
||||
|
||||
if [ $op = "--copy" ]; then
|
||||
pkg="$*"
|
||||
elif grep "^\#[[:space:]]*define[[:space:]]*${search}_STATIC" config.h >/dev/null 2>&1 || \
|
||||
echo $in | grep ${search}_STATIC >/dev/null 2>&1; then
|
||||
pkg=`$pkg --static $op $*`
|
||||
else
|
||||
pkg=`$pkg $op $*`
|
||||
pkg=`$pkg $op $*`
|
||||
fi
|
||||
|
||||
if grep "^\#[[:space:]]*define[[:space:]]*${search}_STATIC" config.h >/dev/null 2>&1 || \
|
||||
|
||||
Vendored
+6
@@ -1,6 +1,12 @@
|
||||
dnsmasq (2.69-1) unstable; urgency=low
|
||||
|
||||
* New upstream.
|
||||
* Set --local-service. (closes: #732610)
|
||||
This tells dnsmasq to ignore DNS requests that don't come from a local network.
|
||||
It's automatically ignored if --interface --except-interface, --listen-address
|
||||
or --auth-server exist in the configuration, so for most installations, it will
|
||||
have no effect, but for otherwise-unconfigured installations, it stops dnsmasq
|
||||
from being vulnerable to DNS-reflection attacks.
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Tue, 4 Feb 2014 16:28:12 +0000
|
||||
|
||||
|
||||
Vendored
+8
@@ -90,6 +90,14 @@ if [ ! "$DNSMASQ_USER" ]; then
|
||||
DNSMASQ_USER="dnsmasq"
|
||||
fi
|
||||
|
||||
# This tells dnsmasq to ignore DNS requests that don't come from a local network.
|
||||
# It's automatically ignored if --interface --except-interface, --listen-address
|
||||
# or --auth-server exist in the configuration, so for most installations, it will
|
||||
# have no effect, but for otherwise-unconfigured installations, it stops dnsmasq
|
||||
# from being vulnerable to DNS-reflection attacks.
|
||||
|
||||
DNSMASQ_OPTS="$DNSMASQ_OPTS --local-service"
|
||||
|
||||
start()
|
||||
{
|
||||
# Return
|
||||
|
||||
+23
-4
@@ -208,6 +208,14 @@ resolve in the global DNS to a A and/or AAAA record which points to
|
||||
the address dnsmasq is listening on. When an interface is specified,
|
||||
it may be qualified with "/4" or "/6" to specify only the IPv4 or IPv6
|
||||
addresses associated with the interface.
|
||||
.TP
|
||||
.B --local-service
|
||||
Accept DNS queries only from hosts whose address is on a local subnet,
|
||||
ie a subnet for which an interface exists on the server. This option
|
||||
only has effect is there are no --interface --except-interface,
|
||||
--listen-address or --auth-server options. It is intended to be set as
|
||||
a default on installation, to allow unconfigured installations to be
|
||||
useful but also safe from being used for DNS amplification attacks.
|
||||
.TP
|
||||
.B \-2, --no-dhcp-interface=<interface name>
|
||||
Do not provide DHCP or TFTP on the specified interface, but do provide DNS service.
|
||||
@@ -599,7 +607,15 @@ clients unable to do validation, use of the AD bit set by dnsmasq is useful, pro
|
||||
the dnsmasq server and the client is trusted. Dnsmasq must be compiled with HAVE_DNSSEC enabled, and DNSSEC
|
||||
trust anchors provided, see
|
||||
.B --trust-anchor.
|
||||
Because the DNSSEC validation process uses the cache, it is not permitted to reduce the cache size below the default when DNSSEC is enabled.
|
||||
Because the DNSSEC validation process uses the cache, it is not
|
||||
permitted to reduce the cache size below the default when DNSSEC is
|
||||
enabled. The nameservers upstream of dnsmasq must be DNSSEC-capable,
|
||||
ie capable of returning DNSSEC records with data. If they are not,
|
||||
then dnsmasq will not be able to determine the trusted status of
|
||||
answers. In the default mode, this menas that all replies will be
|
||||
marked as untrusted. If
|
||||
.B --dnssec-check-unsigned
|
||||
is set and the upstream servers don't support DNSSEC, then DNS service will be entirely broken.
|
||||
.TP
|
||||
.B --trust-anchor=[<class>],<domain>,<key-tag>,<algorithm>,<digest-type>,<digest>
|
||||
Provide DS records to act a trust anchors for DNSSEC
|
||||
@@ -615,7 +631,10 @@ legitimate: they are assumed to be valid and passed on (without the
|
||||
attacker forging unsigned replies for signed DNS zones, but it is
|
||||
fast. If this flag is set, dnsmasq will check the zones of unsigned
|
||||
replies, to ensure that unsigned replies are allowed in those
|
||||
zones. The cost of this is more upstream queries and slower performance.
|
||||
zones. The cost of this is more upstream queries and slower
|
||||
performance. See also the warning about upstream servers in the
|
||||
section on
|
||||
.B --dnssec
|
||||
.TP
|
||||
.B --proxy-dnssec
|
||||
Copy the DNSSEC Authenticated Data bit from upstream servers to downstream clients and cache it. This is an
|
||||
@@ -754,7 +773,7 @@ or from /etc/ethers will be served. A static-only subnet with address
|
||||
all zeros may be used as a "catch-all" address to enable replies to all
|
||||
Information-request packets on a subnet which is provided with
|
||||
stateless DHCPv6, ie
|
||||
.B --dhcp=range=::,static
|
||||
.B --dhcp-range=::,static
|
||||
|
||||
For IPv4, the <mode> may be
|
||||
.B proxy
|
||||
@@ -1843,7 +1862,7 @@ which has tags will be used in preference to an untagged
|
||||
.B dhcp-option,
|
||||
provided that _all_ the tags match somewhere in the
|
||||
set collected as described above. The prefix '!' on a tag means 'not'
|
||||
so --dhcp=option=tag:!purple,3,1.2.3.4 sends the option when the
|
||||
so --dhcp-option=tag:!purple,3,1.2.3.4 sends the option when the
|
||||
tag purple is not in the set of valid tags. (If using this in a
|
||||
command line rather than a configuration file, be sure to escape !,
|
||||
which is a shell metacharacter)
|
||||
|
||||
+31
-17
@@ -24,7 +24,6 @@ static struct crec *new_chain = NULL;
|
||||
static int cache_inserted = 0, cache_live_freed = 0, insert_error;
|
||||
static union bigname *big_free = NULL;
|
||||
static int bignames_left, hash_size;
|
||||
static int uid = 1;
|
||||
|
||||
/* type->string mapping: this is also used by the name-hash function as a mixing table. */
|
||||
static const struct {
|
||||
@@ -73,6 +72,19 @@ static void cache_link(struct crec *crecp);
|
||||
static void rehash(int size);
|
||||
static void cache_hash(struct crec *crecp);
|
||||
|
||||
static unsigned int next_uid(void)
|
||||
{
|
||||
static unsigned int uid = 0;
|
||||
|
||||
uid++;
|
||||
|
||||
/* uid == 0 used to indicate CNAME to interface name. */
|
||||
if (uid == SRC_INTERFACE)
|
||||
uid++;
|
||||
|
||||
return uid;
|
||||
}
|
||||
|
||||
void cache_init(void)
|
||||
{
|
||||
struct crec *crecp;
|
||||
@@ -88,7 +100,7 @@ void cache_init(void)
|
||||
{
|
||||
cache_link(crecp);
|
||||
crecp->flags = 0;
|
||||
crecp->uid = uid++;
|
||||
crecp->uid = next_uid();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -192,10 +204,7 @@ static void cache_free(struct crec *crecp)
|
||||
{
|
||||
crecp->flags &= ~F_FORWARD;
|
||||
crecp->flags &= ~F_REVERSE;
|
||||
crecp->uid = uid++; /* invalidate CNAMES pointing to this. */
|
||||
|
||||
if (uid == -1)
|
||||
uid++;
|
||||
crecp->uid = next_uid(); /* invalidate CNAMES pointing to this. */
|
||||
|
||||
if (cache_tail)
|
||||
cache_tail->next = crecp;
|
||||
@@ -256,7 +265,7 @@ char *cache_get_name(struct crec *crecp)
|
||||
|
||||
char *cache_get_cname_target(struct crec *crecp)
|
||||
{
|
||||
if (crecp->addr.cname.uid != -1)
|
||||
if (crecp->addr.cname.uid != SRC_INTERFACE)
|
||||
return cache_get_name(crecp->addr.cname.target.cache);
|
||||
|
||||
return crecp->addr.cname.target.int_name->name;
|
||||
@@ -289,7 +298,7 @@ struct crec *cache_enumerate(int init)
|
||||
|
||||
static int is_outdated_cname_pointer(struct crec *crecp)
|
||||
{
|
||||
if (!(crecp->flags & F_CNAME) || crecp->addr.cname.uid == -1)
|
||||
if (!(crecp->flags & F_CNAME) || crecp->addr.cname.uid == SRC_INTERFACE)
|
||||
return 0;
|
||||
|
||||
/* NB. record may be reused as DS or DNSKEY, where uid is
|
||||
@@ -774,13 +783,14 @@ static void add_hosts_cname(struct crec *target)
|
||||
crec->name.namep = a->alias;
|
||||
crec->addr.cname.target.cache = target;
|
||||
crec->addr.cname.uid = target->uid;
|
||||
crec->uid = next_uid();
|
||||
cache_hash(crec);
|
||||
add_hosts_cname(crec); /* handle chains */
|
||||
}
|
||||
}
|
||||
|
||||
static void add_hosts_entry(struct crec *cache, struct all_addr *addr, int addrlen,
|
||||
int index, struct crec **rhash, int hashsz)
|
||||
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, nameexists = 0;
|
||||
@@ -884,7 +894,7 @@ static int gettok(FILE *f, char *token)
|
||||
}
|
||||
}
|
||||
|
||||
static int read_hostsfile(char *filename, int index, int cache_size, struct crec **rhash, int hashsz)
|
||||
static int read_hostsfile(char *filename, unsigned int index, int cache_size, struct crec **rhash, int hashsz)
|
||||
{
|
||||
FILE *f = fopen(filename, "r");
|
||||
char *token = daemon->namebuff, *domain_suffix = NULL;
|
||||
@@ -1034,7 +1044,8 @@ void cache_reload(void)
|
||||
cache->flags = F_FORWARD | F_NAMEP | F_CNAME | F_IMMORTAL | F_CONFIG;
|
||||
cache->name.namep = a->alias;
|
||||
cache->addr.cname.target.int_name = intr;
|
||||
cache->addr.cname.uid = -1;
|
||||
cache->addr.cname.uid = SRC_INTERFACE;
|
||||
cache->uid = next_uid();
|
||||
cache_hash(cache);
|
||||
add_hosts_cname(cache); /* handle chains */
|
||||
}
|
||||
@@ -1070,7 +1081,7 @@ void cache_reload(void)
|
||||
{
|
||||
cache->name.namep = nl->name;
|
||||
cache->flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4 | F_NAMEP | F_CONFIG;
|
||||
add_hosts_entry(cache, (struct all_addr *)&hr->addr, INADDRSZ, 0, (struct crec **)daemon->packet, revhashsz);
|
||||
add_hosts_entry(cache, (struct all_addr *)&hr->addr, INADDRSZ, SRC_CONFIG, (struct crec **)daemon->packet, revhashsz);
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
if (!IN6_IS_ADDR_UNSPECIFIED(&hr->addr6) &&
|
||||
@@ -1078,7 +1089,7 @@ void cache_reload(void)
|
||||
{
|
||||
cache->name.namep = nl->name;
|
||||
cache->flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV6 | F_NAMEP | F_CONFIG;
|
||||
add_hosts_entry(cache, (struct all_addr *)&hr->addr6, IN6ADDRSZ, 0, (struct crec **)daemon->packet, revhashsz);
|
||||
add_hosts_entry(cache, (struct all_addr *)&hr->addr6, IN6ADDRSZ, SRC_CONFIG, (struct crec **)daemon->packet, revhashsz);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -1091,7 +1102,7 @@ void cache_reload(void)
|
||||
}
|
||||
|
||||
if (!option_bool(OPT_NO_HOSTS))
|
||||
total_size = read_hostsfile(HOSTSFILE, 0, total_size, (struct crec **)daemon->packet, revhashsz);
|
||||
total_size = read_hostsfile(HOSTSFILE, SRC_HOSTS, total_size, (struct crec **)daemon->packet, revhashsz);
|
||||
|
||||
daemon->addn_hosts = expand_filelist(daemon->addn_hosts);
|
||||
for (ah = daemon->addn_hosts; ah; ah = ah->next)
|
||||
@@ -1155,6 +1166,7 @@ static void add_dhcp_cname(struct crec *target, time_t ttd)
|
||||
aliasc->name.namep = a->alias;
|
||||
aliasc->addr.cname.target.cache = target;
|
||||
aliasc->addr.cname.uid = target->uid;
|
||||
aliasc->uid = next_uid();
|
||||
cache_hash(aliasc);
|
||||
add_dhcp_cname(aliasc, ttd);
|
||||
}
|
||||
@@ -1242,7 +1254,7 @@ void cache_add_dhcp_entry(char *host_name, int prot,
|
||||
crec->ttd = ttd;
|
||||
crec->addr.addr = *host_address;
|
||||
crec->name.namep = host_name;
|
||||
crec->uid = uid++;
|
||||
crec->uid = next_uid();
|
||||
cache_hash(crec);
|
||||
|
||||
add_dhcp_cname(crec, ttd);
|
||||
@@ -1368,11 +1380,13 @@ void dump_cache(time_t now)
|
||||
}
|
||||
}
|
||||
|
||||
char *record_source(int index)
|
||||
char *record_source(unsigned int index)
|
||||
{
|
||||
struct hostsfile *ah;
|
||||
|
||||
if (index == 0)
|
||||
if (index == SRC_CONFIG)
|
||||
return "config";
|
||||
else if (index == SRC_HOSTS)
|
||||
return HOSTSFILE;
|
||||
|
||||
for (ah = daemon->addn_hosts; ah; ah = ah->next)
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@
|
||||
#define MAX_PROCS 20 /* max no children for TCP requests */
|
||||
#define CHILD_LIFETIME 150 /* secs 'till terminated (RFC1035 suggests > 120s) */
|
||||
#define EDNS_PKTSZ 4096 /* default max EDNS.0 UDP packet from RFC5625 */
|
||||
#define KEYBLOCK_LEN 35 /* choose to mininise fragmentation when storing DNSSEC keys */
|
||||
#define KEYBLOCK_LEN 40 /* choose to mininise fragmentation when storing DNSSEC keys */
|
||||
#define DNSSEC_WORK 50 /* Max number of queries to validate one question */
|
||||
#define TIMEOUT 10 /* drop UDP queries after TIMEOUT seconds */
|
||||
#define FORWARD_TEST 50 /* try all servers every 50 queries */
|
||||
|
||||
@@ -661,6 +661,9 @@ int main (int argc, char **argv)
|
||||
my_syslog(LOG_INFO, _("DBus support enabled: bus connection pending"));
|
||||
}
|
||||
#endif
|
||||
|
||||
if (option_bool(OPT_LOCAL_SERVICE))
|
||||
my_syslog(LOG_INFO, _("DNS service limited to local subnets"));
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (option_bool(OPT_DNSSEC_VALID))
|
||||
|
||||
+13
-5
@@ -233,7 +233,8 @@ struct event_desc {
|
||||
#define OPT_DNSSEC_PERMISS 46
|
||||
#define OPT_DNSSEC_DEBUG 47
|
||||
#define OPT_DNSSEC_NO_SIGN 48
|
||||
#define OPT_LAST 49
|
||||
#define OPT_LOCAL_SERVICE 49
|
||||
#define OPT_LAST 50
|
||||
|
||||
/* 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. */
|
||||
@@ -366,7 +367,7 @@ struct crec {
|
||||
struct crec *cache;
|
||||
struct interface_name *int_name;
|
||||
} target;
|
||||
int uid; /* -1 if union is interface-name */
|
||||
unsigned int uid; /* 0 if union is interface-name */
|
||||
} cname;
|
||||
struct {
|
||||
struct blockdata *keydata;
|
||||
@@ -387,7 +388,7 @@ struct crec {
|
||||
} addr;
|
||||
time_t ttd; /* time to die */
|
||||
/* used as class if DNSKEY/DS/RRSIG, index to source for F_HOSTS */
|
||||
int uid;
|
||||
unsigned int uid;
|
||||
unsigned short flags;
|
||||
union {
|
||||
char sname[SMALLDNAME];
|
||||
@@ -426,6 +427,12 @@ struct crec {
|
||||
#define F_SECSTAT (1u<<24)
|
||||
#define F_NO_RR (1u<<25)
|
||||
|
||||
/* Values of uid in crecs with F_CONFIG bit set. */
|
||||
#define SRC_INTERFACE 0
|
||||
#define SRC_CONFIG 1
|
||||
#define SRC_HOSTS 2
|
||||
#define SRC_AH 3
|
||||
|
||||
|
||||
/* struct sockaddr is not large enough to hold any address,
|
||||
and specifically not big enough to hold an IPv6 address.
|
||||
@@ -524,7 +531,7 @@ struct hostsfile {
|
||||
struct hostsfile *next;
|
||||
int flags;
|
||||
char *fname;
|
||||
int index; /* matches to cache entries for logging */
|
||||
unsigned int index; /* matches to cache entries for logging */
|
||||
};
|
||||
|
||||
|
||||
@@ -966,6 +973,7 @@ extern struct daemon {
|
||||
pid_t tcp_pids[MAX_PROCS];
|
||||
struct randfd randomsocks[RANDOM_SOCKS];
|
||||
int v6pktinfo;
|
||||
struct addrlist *interface_addrs; /* list of all addresses/prefix lengths associated with all local interfaces */
|
||||
|
||||
/* DHCP state */
|
||||
int dhcpfd, helperfd, pxefd;
|
||||
@@ -1003,7 +1011,7 @@ extern struct daemon {
|
||||
/* cache.c */
|
||||
void cache_init(void);
|
||||
void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg);
|
||||
char *record_source(int index);
|
||||
char *record_source(unsigned int index);
|
||||
char *querystr(char *desc, unsigned short type);
|
||||
struct crec *cache_find_by_addr(struct crec *crecp,
|
||||
struct all_addr *addr, time_t now,
|
||||
|
||||
+4
-4
@@ -827,7 +827,7 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
|
||||
for (; crecp; crecp = cache_find_by_name(crecp, keyname, now, F_DNSKEY))
|
||||
if (crecp->addr.key.algo == algo &&
|
||||
crecp->addr.key.keytag == key_tag &&
|
||||
crecp->uid == class &&
|
||||
crecp->uid == (unsigned int)class &&
|
||||
verify(crecp->addr.key.keydata, crecp->addr.key.keylen, sig, sig_len, digest, hash->digest_size, algo))
|
||||
return (labels < name_labels) ? STAT_SECURE_WILDCARD : STAT_SECURE;
|
||||
}
|
||||
@@ -932,7 +932,7 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
|
||||
|
||||
if (recp1->addr.ds.algo == algo &&
|
||||
recp1->addr.ds.keytag == keytag &&
|
||||
recp1->uid == class &&
|
||||
recp1->uid == (unsigned int)class &&
|
||||
(hash = hash_find(ds_digest_name(recp1->addr.ds.digest))) &&
|
||||
hash_init(hash, &ctx, &digest))
|
||||
|
||||
@@ -1918,14 +1918,14 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
|
||||
int dnssec_chase_cname(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname)
|
||||
{
|
||||
unsigned char *p = (unsigned char *)(header+1);
|
||||
int type, class, qtype, qclass, rdlen, j, rc;
|
||||
int type, class, qclass, rdlen, j, rc;
|
||||
int cname_count = CNAME_CHAIN;
|
||||
|
||||
/* Get question */
|
||||
if (!extract_name(header, plen, &p, name, 1, 4))
|
||||
return STAT_BOGUS;
|
||||
|
||||
GETSHORT(qtype, p);
|
||||
p +=2; /* type */
|
||||
GETSHORT(qclass, p);
|
||||
|
||||
while (1)
|
||||
|
||||
+85
-5
@@ -278,7 +278,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
blockdata_retrieve(forward->stash, forward->stash_len, (void *)header);
|
||||
plen = forward->stash_len;
|
||||
|
||||
if (forward->sentto->addr.sa.sa_family)
|
||||
if (forward->sentto->addr.sa.sa_family == AF_INET)
|
||||
log_query(F_DNSSEC | F_IPV4, "retry", (struct all_addr *)&forward->sentto->addr.in.sin_addr, "dnssec");
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
@@ -299,7 +299,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
|
||||
while (sendto(fd, (char *)header, plen, 0,
|
||||
&forward->sentto->addr.sa,
|
||||
sa_len(&forward->sentto->addr)) == -1 && retry_send());
|
||||
sa_len(&forward->sentto->addr)) == -1 && retry_send());
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -1076,11 +1076,60 @@ void receive_query(struct listener *listen, time_t now)
|
||||
return;
|
||||
|
||||
source_addr.sa.sa_family = listen->family;
|
||||
|
||||
if (listen->family == AF_INET)
|
||||
{
|
||||
/* Source-port == 0 is an error, we can't send back to that.
|
||||
http://www.ietf.org/mail-archive/web/dnsop/current/msg11441.html */
|
||||
if (source_addr.in.sin_port == 0)
|
||||
return;
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
if (listen->family == AF_INET6)
|
||||
source_addr.in6.sin6_flowinfo = 0;
|
||||
else
|
||||
{
|
||||
/* Source-port == 0 is an error, we can't send back to that. */
|
||||
if (source_addr.in6.sin6_port == 0)
|
||||
return;
|
||||
source_addr.in6.sin6_flowinfo = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* We can be configured to only accept queries from at-most-one-hop-away addresses. */
|
||||
if (option_bool(OPT_LOCAL_SERVICE))
|
||||
{
|
||||
struct addrlist *addr;
|
||||
#ifdef HAVE_IPV6
|
||||
if (listen->family == AF_INET6)
|
||||
{
|
||||
for (addr = daemon->interface_addrs; addr; addr = addr->next)
|
||||
if ((addr->flags & ADDRLIST_IPV6) &&
|
||||
is_same_net6(&addr->addr.addr.addr6, &source_addr.in6.sin6_addr, addr->prefixlen))
|
||||
break;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
struct in_addr netmask;
|
||||
for (addr = daemon->interface_addrs; addr; addr = addr->next)
|
||||
{
|
||||
netmask.s_addr = 0xffffffff << (32 - addr->prefixlen);
|
||||
if (!(addr->flags & ADDRLIST_IPV6) &&
|
||||
is_same_net(addr->addr.addr.addr4, source_addr.in.sin_addr, netmask))
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!addr)
|
||||
{
|
||||
static int warned = 0;
|
||||
if (!warned)
|
||||
{
|
||||
my_syslog(LOG_WARNING, _("Ignoring query from non-local network"));
|
||||
warned = 1;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (check_dst)
|
||||
{
|
||||
struct ifreq ifr;
|
||||
@@ -1544,6 +1593,37 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
|
||||
if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) == -1)
|
||||
return packet;
|
||||
|
||||
/* We can be configured to only accept queries from at-most-one-hop-away addresses. */
|
||||
if (option_bool(OPT_LOCAL_SERVICE))
|
||||
{
|
||||
struct addrlist *addr;
|
||||
#ifdef HAVE_IPV6
|
||||
if (peer_addr.sa.sa_family == AF_INET6)
|
||||
{
|
||||
for (addr = daemon->interface_addrs; addr; addr = addr->next)
|
||||
if ((addr->flags & ADDRLIST_IPV6) &&
|
||||
is_same_net6(&addr->addr.addr.addr6, &peer_addr.in6.sin6_addr, addr->prefixlen))
|
||||
break;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
struct in_addr netmask;
|
||||
for (addr = daemon->interface_addrs; addr; addr = addr->next)
|
||||
{
|
||||
netmask.s_addr = 0xffffffff << (32 - addr->prefixlen);
|
||||
if (!(addr->flags & ADDRLIST_IPV6) &&
|
||||
is_same_net(addr->addr.addr.addr4, peer_addr.in.sin_addr, netmask))
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!addr)
|
||||
{
|
||||
my_syslog(LOG_WARNING, _("Ignoring query from non-local network"));
|
||||
return packet;
|
||||
}
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
|
||||
+44
-1
@@ -268,7 +268,40 @@ static int iface_allowed(struct iface_param *param, int if_index, char *label,
|
||||
|
||||
if (!label)
|
||||
label = ifr.ifr_name;
|
||||
|
||||
/* maintain a list of all addresses on all interfaces for --local-service option */
|
||||
if (option_bool(OPT_LOCAL_SERVICE))
|
||||
{
|
||||
struct addrlist *al;
|
||||
|
||||
if (param->spare)
|
||||
{
|
||||
al = param->spare;
|
||||
param->spare = al->next;
|
||||
}
|
||||
else
|
||||
al = whine_malloc(sizeof(struct addrlist));
|
||||
|
||||
if (al)
|
||||
{
|
||||
al->next = daemon->interface_addrs;
|
||||
daemon->interface_addrs = al;
|
||||
al->prefixlen = prefixlen;
|
||||
|
||||
if (addr->sa.sa_family == AF_INET)
|
||||
{
|
||||
al->addr.addr.addr4 = addr->in.sin_addr;
|
||||
al->flags = 0;
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
{
|
||||
al->addr.addr.addr6 = addr->in6.sin6_addr;
|
||||
al->flags = ADDRLIST_IPV6;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (addr->sa.sa_family != AF_INET6 || !IN6_IS_ADDR_LINKLOCAL(&addr->in6.sin6_addr))
|
||||
@@ -565,6 +598,15 @@ int enumerate_interfaces(int reset)
|
||||
intname->addr = NULL;
|
||||
}
|
||||
|
||||
/* Remove list of addresses of local interfaces */
|
||||
for (addr = daemon->interface_addrs; addr; addr = tmp)
|
||||
{
|
||||
tmp = addr->next;
|
||||
addr->next = spare;
|
||||
spare = addr;
|
||||
}
|
||||
daemon->interface_addrs = NULL;
|
||||
|
||||
#ifdef HAVE_AUTH
|
||||
/* remove addresses stored against auth_zone subnets, but not
|
||||
ones configured as address literals */
|
||||
@@ -1528,7 +1570,8 @@ void newaddress(time_t now)
|
||||
{
|
||||
(void)now;
|
||||
|
||||
if (option_bool(OPT_CLEVERBIND) || daemon->doing_dhcp6 || daemon->relay6 || daemon->doing_ra)
|
||||
if (option_bool(OPT_CLEVERBIND) || option_bool(OPT_LOCAL_SERVICE) ||
|
||||
daemon->doing_dhcp6 || daemon->relay6 || daemon->doing_ra)
|
||||
enumerate_interfaces(0);
|
||||
|
||||
if (option_bool(OPT_CLEVERBIND))
|
||||
|
||||
+12
-3
@@ -144,6 +144,7 @@ struct myoption {
|
||||
#define LOPT_REV_SERV 332
|
||||
#define LOPT_SERVERS_FILE 333
|
||||
#define LOPT_DNSSEC_CHECK 334
|
||||
#define LOPT_LOCAL_SERVICE 335
|
||||
|
||||
#ifdef HAVE_GETOPT_LONG
|
||||
static const struct option opts[] =
|
||||
@@ -175,6 +176,7 @@ static const struct myoption opts[] =
|
||||
{ "domain-suffix", 1, 0, 's' },
|
||||
{ "interface", 1, 0, 'i' },
|
||||
{ "listen-address", 1, 0, 'a' },
|
||||
{ "local-service", 0, 0, LOPT_LOCAL_SERVICE },
|
||||
{ "bogus-priv", 0, 0, 'b' },
|
||||
{ "bogus-nxdomain", 1, 0, 'B' },
|
||||
{ "selfmx", 0, 0, 'e' },
|
||||
@@ -448,6 +450,7 @@ static struct {
|
||||
{ LOPT_QUIET_DHCP, OPT_QUIET_DHCP, NULL, gettext_noop("Do not log routine DHCP."), NULL },
|
||||
{ LOPT_QUIET_DHCP6, OPT_QUIET_DHCP6, NULL, gettext_noop("Do not log routine DHCPv6."), NULL },
|
||||
{ LOPT_QUIET_RA, OPT_QUIET_RA, NULL, gettext_noop("Do not log RA."), NULL },
|
||||
{ LOPT_LOCAL_SERVICE, OPT_LOCAL_SERVICE, NULL, gettext_noop("Accept queries only from directly-connected networks"), NULL },
|
||||
{ 0, 0, NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
@@ -1661,7 +1664,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
case 'H': /* --addn-hosts */
|
||||
{
|
||||
struct hostsfile *new = opt_malloc(sizeof(struct hostsfile));
|
||||
static int hosts_index = 1;
|
||||
static unsigned int hosts_index = SRC_AH;
|
||||
new->fname = opt_string_alloc(arg);
|
||||
new->index = hosts_index++;
|
||||
new->flags = 0;
|
||||
@@ -4017,10 +4020,11 @@ static int one_file(char *file, int hard_opt)
|
||||
/* expand any name which is a directory */
|
||||
struct hostsfile *expand_filelist(struct hostsfile *list)
|
||||
{
|
||||
int i;
|
||||
unsigned int i;
|
||||
struct hostsfile *ah;
|
||||
|
||||
for (i = 0, ah = list; ah; ah = ah->next)
|
||||
/* find largest used index */
|
||||
for (i = SRC_AH, ah = list; ah; ah = ah->next)
|
||||
{
|
||||
if (i <= ah->index)
|
||||
i = ah->index + 1;
|
||||
@@ -4457,6 +4461,11 @@ void read_opts(int argc, char **argv, char *compile_opts)
|
||||
else if (option_bool(OPT_DHCP_FQDN))
|
||||
die(_("there must be a default domain when --dhcp-fqdn is set"), NULL, EC_BADCONF);
|
||||
|
||||
/* If there's access-control config, then ignore --local-service, it's intended
|
||||
as a system default to keep otherwise unconfigured installations safe. */
|
||||
if (daemon->if_names || daemon->if_except || daemon->if_addrs || daemon->authserver)
|
||||
reset_option_bool(OPT_LOCAL_SERVICE);
|
||||
|
||||
if (testmode)
|
||||
{
|
||||
fprintf(stderr, "dnsmasq: %s.\n", _("syntax check OK"));
|
||||
|
||||
+4
-2
@@ -1065,6 +1065,8 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
|
||||
if (newc)
|
||||
{
|
||||
newc->addr.cname.target.cache = NULL;
|
||||
/* anything other than zero, to avoid being mistaken for CNAME to interface-name */
|
||||
newc->addr.cname.uid = 1;
|
||||
if (cpp)
|
||||
{
|
||||
cpp->addr.cname.target.cache = newc;
|
||||
@@ -1456,7 +1458,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
{
|
||||
char *name = daemon->namebuff;
|
||||
unsigned char *p, *ansp, *pheader;
|
||||
int qtype, qclass;
|
||||
unsigned int qtype, qclass;
|
||||
struct all_addr addr;
|
||||
int nameoffset;
|
||||
unsigned short flag;
|
||||
@@ -2016,7 +2018,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
|
||||
strcpy(name, cname_target);
|
||||
/* check if target interface_name */
|
||||
if (crecp->addr.cname.uid == -1)
|
||||
if (crecp->addr.cname.uid == SRC_INTERFACE)
|
||||
goto intname_restart;
|
||||
else
|
||||
goto cname_restart;
|
||||
|
||||
@@ -962,6 +962,8 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
case DHCPDISCOVER:
|
||||
if (ignore || have_config(config, CONFIG_DISABLE))
|
||||
{
|
||||
if (option_bool(OPT_QUIET_DHCP))
|
||||
return 0;
|
||||
message = _("ignored");
|
||||
opt = NULL;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user