Compare commits
78 Commits
v2.78
...
v2.80test2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7f0084316a | ||
|
|
a6918530ce | ||
|
|
4e72fec660 | ||
|
|
4441cf762c | ||
|
|
e83915d10d | ||
|
|
6d37924b86 | ||
|
|
f3d7974e86 | ||
|
|
734d53176f | ||
|
|
9a7be47614 | ||
|
|
26e27d0015 | ||
|
|
94b6878821 | ||
|
|
8b96552f0d | ||
|
|
ae290659de | ||
|
|
6b2b564ac3 | ||
|
|
4f7bb57e97 | ||
|
|
56f0623930 | ||
|
|
f3223fbff6 | ||
|
|
4c4f4c2649 | ||
|
|
773af304ea | ||
|
|
4cc944b0d6 | ||
|
|
87e00feb01 | ||
|
|
e7a4af8903 | ||
|
|
2d69d6146d | ||
|
|
30e4a9441e | ||
|
|
232a8f3569 | ||
|
|
1721453d51 | ||
|
|
499d8dde2b | ||
|
|
6f1cbfd000 | ||
|
|
55ecde7f1b | ||
|
|
6b54d69a85 | ||
|
|
246a31cd73 | ||
|
|
83e4b73596 | ||
|
|
6340ca734f | ||
|
|
baf553db0c | ||
|
|
486bcd5a7b | ||
|
|
be9a74d2f8 | ||
|
|
ffcbc0f011 | ||
|
|
a969ba6e2a | ||
|
|
f1781728af | ||
|
|
cd7df612b1 | ||
|
|
c1a4e257a3 | ||
|
|
4fe6744a22 | ||
|
|
3bd4c47f31 | ||
|
|
98196c4931 | ||
|
|
22cd860124 | ||
|
|
3c973ad92d | ||
|
|
faaf306a63 | ||
|
|
c7e6aea81b | ||
|
|
e541245987 | ||
|
|
84a01bee10 | ||
|
|
d1ced3ae38 | ||
|
|
a6cee69af4 | ||
|
|
0039920ab6 | ||
|
|
39d8550a80 | ||
|
|
ef3d137a64 | ||
|
|
8c707e1e37 | ||
|
|
373e917389 | ||
|
|
74f0f9a042 | ||
|
|
ed6bdb0967 | ||
|
|
c88af046b7 | ||
|
|
ae0187d454 | ||
|
|
0c50e3ddc8 | ||
|
|
075366ad6e | ||
|
|
8e8b2d6f63 | ||
|
|
087eb76140 | ||
|
|
ebedcbaeb8 | ||
|
|
0954a977c9 | ||
|
|
b77efc1948 | ||
|
|
3b0cb34710 | ||
|
|
aa6f832d61 | ||
|
|
ad9c6f06c5 | ||
|
|
a6004d7f17 | ||
|
|
c366717e66 | ||
|
|
22dee512f3 | ||
|
|
6fd5d79e73 | ||
|
|
9d6918d32c | ||
|
|
a49c5c2265 | ||
|
|
30858e3b9b |
5
.gitignore
vendored
5
.gitignore
vendored
@@ -7,9 +7,8 @@ src/.copts_*
|
||||
contrib/lease-tools/dhcp_lease_time
|
||||
contrib/lease-tools/dhcp_release
|
||||
contrib/lease-tools/dhcp_release6
|
||||
debian/base/
|
||||
debian/daemon/
|
||||
debian/files
|
||||
debian/substvars
|
||||
debian/utils-substvars
|
||||
debian/utils/
|
||||
debian/trees/
|
||||
debian/build/
|
||||
|
||||
91
CHANGELOG
91
CHANGELOG
@@ -1,3 +1,88 @@
|
||||
version 2.80
|
||||
Add support for RFC 4039 DHCP rapid commit. Thanks to Ashram Method
|
||||
for the initial patch and motivation.
|
||||
|
||||
Alter the default for dnssec-check-unsigned. Versions of
|
||||
dnsmasq prior to 2.80 defaulted to not checking unsigned
|
||||
replies, and used --dnssec-check-unsigned to switch
|
||||
this on. Such configurations will continue to work as before,
|
||||
but those which used the default of no checking will need to be
|
||||
altered to explicitly select no checking. The new default is
|
||||
because switching off checking for unsigned replies is
|
||||
inherently dangerous. Not only does it open the possiblity of forged
|
||||
replies, but it allows everything to appear to be working even
|
||||
when the upstream namesevers do not support DNSSEC, and in this
|
||||
case no DNSSEC validation at all is occuring.
|
||||
|
||||
|
||||
|
||||
|
||||
version 2.79
|
||||
Fix parsing of CNAME arguments, which are confused by extra spaces.
|
||||
Thanks to Diego Aguirre for spotting the bug.
|
||||
|
||||
Where available, use IP_UNICAST_IF or IPV6_UNICAST_IF to bind
|
||||
upstream servers to an interface, rather than SO_BINDTODEVICE.
|
||||
Thanks to Beniamino Galvani for the patch.
|
||||
|
||||
Always return a SERVFAIL answer to DNS queries without the
|
||||
recursion desired bit set, UNLESS acting as an authoritative
|
||||
DNS server. This avoids a potential route to cache snooping.
|
||||
|
||||
Add support for Ed25519 signatures in DNSSEC validation.
|
||||
|
||||
No longer support RSA/MD5 signatures in DNSSEC validation,
|
||||
since these are not secure. This behaviour is mandated in
|
||||
RFC-6944.
|
||||
|
||||
Fix incorrect error exit code from dhcp_release6 utility.
|
||||
Thanks Gaudenz Steinlin for the bug report.
|
||||
|
||||
Use SIGINT (instead of overloading SIGHUP) to turn on DNSSEC
|
||||
time validation when --dnssec-no-timecheck is in use.
|
||||
Note that this is an incompatible change from earlier releases.
|
||||
|
||||
Allow more than one --bridge-interface option to refer to an
|
||||
interface, so that we can use
|
||||
--bridge-interface=int1,alias1
|
||||
--bridge-interface=int1,alias2
|
||||
as an alternative to
|
||||
--bridge-interface=int1,alias1,alias2
|
||||
Thanks to Neil Jerram for work on this.
|
||||
|
||||
Fix for DNSSEC with wildcard-derived NSEC records.
|
||||
It's OK for NSEC records to be expanded from wildcards,
|
||||
but in that case, the proof of non-existence is only valid
|
||||
starting at the wildcard name, *.<domain> NOT the name expanded
|
||||
from the wildcard. Without this check it's possible for an
|
||||
attacker to craft an NSEC which wrongly proves non-existence.
|
||||
Thanks to Ralph Dolmans for finding this, and co-ordinating
|
||||
the vulnerability tracking and fix release.
|
||||
CVE-2017-15107 applies.
|
||||
|
||||
Remove special handling of A-for-A DNS queries. These
|
||||
are no longer a significant problem in the global DNS.
|
||||
http://cs.northwestern.edu/~ychen/Papers/DNS_ToN15.pdf
|
||||
Thanks to Mattias Hellström for the initial patch.
|
||||
|
||||
Fix failure to delete dynamically created dhcp options
|
||||
from files in -dhcp-optsdir directories. Thanks to
|
||||
Lindgren Fredrik for the bug report.
|
||||
|
||||
Add to --synth-domain the ability to create names using
|
||||
sequential numbers, as well as encodings of IP addresses.
|
||||
For instance,
|
||||
--synth-domain=thekelleys.org.uk,192.168.0.50,192.168.0.70,internal-*
|
||||
creates 21 domain names of the form
|
||||
internal-4.thekelleys.org.uk over the address range given, with
|
||||
internal-0.thekelleys.org.uk being 192.168.0.50 and
|
||||
internal-20.thekelleys.org.uk being 192.168.0.70
|
||||
Thanks to Andy Hawkins for the suggestion.
|
||||
|
||||
Tidy up Crypto code, removing workarounds for ancient
|
||||
versions of libnettle. We now require libnettle 3.
|
||||
|
||||
|
||||
version 2.78
|
||||
Fix logic of appending ".<layer>" to PXE basename. Thanks to Chris
|
||||
Novakovic for the patch.
|
||||
@@ -1526,7 +1611,7 @@ version 2.56
|
||||
|
||||
By default, setting an IPv4 address for a domain but not
|
||||
an IPv6 address causes dnsmasq to return
|
||||
an NODATA reply for IPv6 (or vice-versa). So
|
||||
a NODATA reply for IPv6 (or vice-versa). So
|
||||
--address=/google.com/1.2.3.4 stops IPv6 queries for
|
||||
*google.com from being forwarded. Make it possible to
|
||||
override this behaviour by defining the semantics if the
|
||||
@@ -2032,13 +2117,13 @@ version 2.47
|
||||
|
||||
Support arbitrarily encapsulated DHCP options, suggestion
|
||||
and initial patch from Samium Gromoff. This is useful for
|
||||
(eg) gPXE, which expect all its private options to be
|
||||
(eg) iPXE, which expect all its private options to be
|
||||
encapsulated inside a single option 175. So, eg,
|
||||
|
||||
dhcp-option = encap:175, 190, "iscsi-client0"
|
||||
dhcp-option = encap:175, 191, "iscsi-client0-secret"
|
||||
|
||||
will provide iSCSI parameters to gPXE.
|
||||
will provide iSCSI parameters to iPXE.
|
||||
|
||||
Enhance --dhcp-match to allow testing of the contents of a
|
||||
client-sent option, as well as its presence. This
|
||||
|
||||
@@ -1010,7 +1010,7 @@ release 2.9
|
||||
but to the address of another interface were ignored
|
||||
unless the loopback interface was explicitly configured.
|
||||
2) on OpenBSD failure to configure one interface now
|
||||
causes a fatal error on startup rather than an huge
|
||||
causes a fatal error on startup rather than a huge
|
||||
stream of log messages. Thanks to Erik Jan Tromp for
|
||||
finding that bug.
|
||||
|
||||
@@ -2067,7 +2067,7 @@ version 2.36
|
||||
kernel. Thanks to Philip Wall for the bug report.
|
||||
|
||||
Added --dhcp-bridge option, but only to the FreeBSD
|
||||
build. This fixes an oddity with a a particular bridged
|
||||
build. This fixes an oddity with a particular bridged
|
||||
network configuration on FreeBSD. Thanks to Luigi Rizzo
|
||||
for the patch.
|
||||
|
||||
@@ -2273,7 +2273,7 @@ version 2.40
|
||||
this.
|
||||
|
||||
Use client-id as hash-seed for DHCP address allocation
|
||||
with Firewire and InfiniBand, as these don't supply an MAC
|
||||
with Firewire and InfiniBand, as these don't supply a MAC
|
||||
address.
|
||||
|
||||
Tweaked TFTP file-open code to make it behave sensibly
|
||||
@@ -2433,7 +2433,7 @@ version 2.41
|
||||
|
||||
Add --dhcp-match flag, to check for arbitrary options in
|
||||
DHCP messages from clients. This enables use of dnsmasq
|
||||
with gPXE. Thanks to Rance Hall for the suggestion.
|
||||
with iPXE. Thanks to Rance Hall for the suggestion.
|
||||
|
||||
Added --dhcp-broadcast, to force broadcast replies to DHCP
|
||||
clients which need them but are too dumb or too old to
|
||||
|
||||
6
FAQ
6
FAQ
@@ -9,7 +9,7 @@ A: The high ports that dnsmasq opens are for replies from the upstream
|
||||
from port 53 the replies would be _to_ port 53 and get blocked.
|
||||
|
||||
This is not a security hole since dnsmasq will only accept replies to that
|
||||
port: queries are dropped. The replies must be to oustanding queries
|
||||
port: queries are dropped. The replies must be to outstanding queries
|
||||
which dnsmasq has forwarded, otherwise they are dropped too.
|
||||
|
||||
Addendum: dnsmasq now has the option "query-port" (-Q), which allows
|
||||
@@ -297,7 +297,7 @@ A: Dnsmasq from v2.63 can operate in one of three different "networking
|
||||
by dnsmasq when in --bind-interfaces mode. In wildcard or bind-dynamic
|
||||
mode, such interfaces are handled normally.
|
||||
|
||||
A --interface specification for a non-existent interface is a fatal
|
||||
An --interface specification for a non-existent interface is a fatal
|
||||
error at start-up when in --bind-interfaces mode, by just generates a
|
||||
warning in wildcard or bind-dynamic mode.
|
||||
|
||||
@@ -320,7 +320,7 @@ A: Yes, new releases of dnsmasq are always announced through
|
||||
|
||||
Q: What does the dhcp-authoritative option do?
|
||||
|
||||
A: The DHCP spec says that when a DHCP server recieves a renewal request
|
||||
A: The DHCP spec says that when a DHCP server receives a renewal request
|
||||
from a client it has no knowledge of, it should just ignore it.
|
||||
This is because it's supported to have more than one DHCP server
|
||||
on a network, and another DHCP server may be dealing with the client.
|
||||
|
||||
5
Makefile
5
Makefile
@@ -76,7 +76,7 @@ objs = cache.o rfc1035.o util.o option.o forward.o network.o \
|
||||
helper.o tftp.o log.o conntrack.o dhcp6.o rfc3315.o \
|
||||
dhcp-common.o outpacket.o radv.o slaac.o auth.o ipset.o \
|
||||
domain.o dnssec.o blockdata.o tables.o loop.o inotify.o \
|
||||
poll.o rrfilter.o edns0.o arp.o
|
||||
poll.o rrfilter.o edns0.o arp.o crypto.o
|
||||
|
||||
hdrs = dnsmasq.h config.h dhcp-protocol.h dhcp6-protocol.h \
|
||||
dns-protocol.h radv-protocol.h ip6addr.h
|
||||
@@ -100,7 +100,8 @@ clean : mostly_clean
|
||||
install : all install-common
|
||||
|
||||
install-common :
|
||||
$(INSTALL) -d $(DESTDIR)$(BINDIR) -d $(DESTDIR)$(MANDIR)/man8
|
||||
$(INSTALL) -d $(DESTDIR)$(BINDIR)
|
||||
$(INSTALL) -d $(DESTDIR)$(MANDIR)/man8
|
||||
$(INSTALL) -m 644 $(MAN)/dnsmasq.8 $(DESTDIR)$(MANDIR)/man8
|
||||
$(INSTALL) -m 755 $(BUILDDIR)/dnsmasq $(DESTDIR)$(BINDIR)
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ LOCAL_SRC_FILES := bpf.c cache.c dbus.c dhcp.c dnsmasq.c \
|
||||
dhcp6.c rfc3315.c dhcp-common.c outpacket.c \
|
||||
radv.c slaac.c auth.c ipset.c domain.c \
|
||||
dnssec.c dnssec-openssl.c blockdata.c tables.c \
|
||||
loop.c inotify.c poll.c rrfilter.c edns0.c arp.c
|
||||
loop.c inotify.c poll.c rrfilter.c edns0.c arp.c crypto.c
|
||||
|
||||
LOCAL_MODULE := dnsmasq
|
||||
|
||||
|
||||
@@ -46,7 +46,8 @@ typedef unsigned char u8;
|
||||
typedef unsigned short u16;
|
||||
typedef unsigned int u32;
|
||||
|
||||
enum DHCP6_TYPES{
|
||||
enum DHCP6_TYPES
|
||||
{
|
||||
SOLICIT = 1,
|
||||
ADVERTISE = 2,
|
||||
REQUEST = 3,
|
||||
@@ -61,8 +62,10 @@ enum DHCP6_TYPES{
|
||||
RELAY_FORW = 12,
|
||||
RELAY_REPL = 13
|
||||
|
||||
};
|
||||
enum DHCP6_OPTIONS{
|
||||
};
|
||||
|
||||
enum DHCP6_OPTIONS
|
||||
{
|
||||
CLIENTID = 1,
|
||||
SERVERID = 2,
|
||||
IA_NA = 3,
|
||||
@@ -82,25 +85,27 @@ enum DHCP6_OPTIONS{
|
||||
INTERFACE_ID = 18,
|
||||
RECONF_MSG = 19,
|
||||
RECONF_ACCEPT = 20,
|
||||
};
|
||||
};
|
||||
|
||||
enum DHCP6_STATUSES{
|
||||
enum DHCP6_STATUSES
|
||||
{
|
||||
SUCCESS = 0,
|
||||
UNSPEC_FAIL = 1,
|
||||
NOADDR_AVAIL=2,
|
||||
NO_BINDING = 3,
|
||||
NOT_ON_LINK = 4,
|
||||
USE_MULTICAST =5
|
||||
};
|
||||
};
|
||||
|
||||
static struct option longopts[] = {
|
||||
{"ip", required_argument, 0, 'a'},
|
||||
{"server-id", required_argument, 0, 's'},
|
||||
{"client-id", required_argument, 0, 'c'},
|
||||
{"iface", required_argument, 0, 'n'},
|
||||
{"iaid", required_argument, 0, 'i'},
|
||||
{"dry-run", no_argument, 0, 'd'},
|
||||
{"help", no_argument, 0, 'h'},
|
||||
{0, 0, 0, 0}
|
||||
{"ip", required_argument, 0, 'a' },
|
||||
{"server-id", required_argument, 0, 's' },
|
||||
{"client-id", required_argument, 0, 'c' },
|
||||
{"iface", required_argument, 0, 'n' },
|
||||
{"iaid", required_argument, 0, 'i' },
|
||||
{"dry-run", no_argument, 0, 'd' },
|
||||
{"help", no_argument, 0, 'h' },
|
||||
{0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
const short DHCP6_CLIENT_PORT = 546;
|
||||
@@ -108,207 +113,230 @@ const short DHCP6_SERVER_PORT = 547;
|
||||
|
||||
const char* DHCP6_MULTICAST_ADDRESS = "ff02::1:2";
|
||||
|
||||
struct dhcp6_option{
|
||||
uint16_t type;
|
||||
uint16_t len;
|
||||
char value[1024];
|
||||
struct dhcp6_option {
|
||||
uint16_t type;
|
||||
uint16_t len;
|
||||
char value[1024];
|
||||
};
|
||||
|
||||
struct dhcp6_iaaddr_option{
|
||||
uint16_t type;
|
||||
uint16_t len;
|
||||
struct in6_addr ip;
|
||||
uint32_t preferred_lifetime;
|
||||
uint32_t valid_lifetime;
|
||||
|
||||
|
||||
struct dhcp6_iaaddr_option {
|
||||
uint16_t type;
|
||||
uint16_t len;
|
||||
struct in6_addr ip;
|
||||
uint32_t preferred_lifetime;
|
||||
uint32_t valid_lifetime;
|
||||
};
|
||||
|
||||
struct dhcp6_iana_option{
|
||||
uint16_t type;
|
||||
uint16_t len;
|
||||
uint32_t iaid;
|
||||
uint32_t t1;
|
||||
uint32_t t2;
|
||||
char options[1024];
|
||||
struct dhcp6_iana_option {
|
||||
uint16_t type;
|
||||
uint16_t len;
|
||||
uint32_t iaid;
|
||||
uint32_t t1;
|
||||
uint32_t t2;
|
||||
char options[1024];
|
||||
};
|
||||
|
||||
|
||||
struct dhcp6_packet{
|
||||
size_t len;
|
||||
char buf[2048];
|
||||
|
||||
} ;
|
||||
struct dhcp6_packet {
|
||||
size_t len;
|
||||
char buf[2048];
|
||||
};
|
||||
|
||||
size_t pack_duid(const char* str, char* dst){
|
||||
|
||||
char* tmp = strdup(str);
|
||||
char* tmp_to_free = tmp;
|
||||
char *ptr;
|
||||
uint8_t write_pos = 0;
|
||||
while ((ptr = strtok (tmp, ":"))) {
|
||||
dst[write_pos] = (uint8_t) strtol(ptr, NULL, 16);
|
||||
write_pos += 1;
|
||||
tmp = NULL;
|
||||
|
||||
size_t pack_duid(const char* str, char* dst)
|
||||
{
|
||||
char* tmp = strdup(str);
|
||||
char* tmp_to_free = tmp;
|
||||
char *ptr;
|
||||
uint8_t write_pos = 0;
|
||||
while ((ptr = strtok (tmp, ":")))
|
||||
{
|
||||
dst[write_pos] = (uint8_t) strtol(ptr, NULL, 16);
|
||||
write_pos += 1;
|
||||
tmp = NULL;
|
||||
}
|
||||
free(tmp_to_free);
|
||||
return write_pos;
|
||||
|
||||
free(tmp_to_free);
|
||||
return write_pos;
|
||||
}
|
||||
|
||||
struct dhcp6_option create_client_id_option(const char* duid){
|
||||
struct dhcp6_option option;
|
||||
option.type = htons(CLIENTID);
|
||||
bzero(option.value, sizeof(option.value));
|
||||
option.len = htons(pack_duid(duid, option.value));
|
||||
return option;
|
||||
struct dhcp6_option create_client_id_option(const char* duid)
|
||||
{
|
||||
struct dhcp6_option option;
|
||||
option.type = htons(CLIENTID);
|
||||
bzero(option.value, sizeof(option.value));
|
||||
option.len = htons(pack_duid(duid, option.value));
|
||||
return option;
|
||||
}
|
||||
|
||||
struct dhcp6_option create_server_id_option(const char* duid){
|
||||
struct dhcp6_option option;
|
||||
option.type = htons(SERVERID);
|
||||
bzero(option.value, sizeof(option.value));
|
||||
option.len = htons(pack_duid(duid, option.value));
|
||||
return option;
|
||||
struct dhcp6_option create_server_id_option(const char* duid)
|
||||
{
|
||||
struct dhcp6_option option;
|
||||
option.type = htons(SERVERID);
|
||||
bzero(option.value, sizeof(option.value));
|
||||
option.len = htons(pack_duid(duid, option.value));
|
||||
return option;
|
||||
}
|
||||
|
||||
struct dhcp6_iaaddr_option create_iaadr_option(const char* ip){
|
||||
struct dhcp6_iaaddr_option result;
|
||||
result.type =htons(IAADDR);
|
||||
/* no suboptions needed here, so length is 24 */
|
||||
result.len = htons(24);
|
||||
result.preferred_lifetime = 0;
|
||||
result.valid_lifetime = 0;
|
||||
int s = inet_pton(AF_INET6, ip, &(result.ip));
|
||||
if (s <= 0) {
|
||||
if (s == 0)
|
||||
fprintf(stderr, "Not in presentation format");
|
||||
else
|
||||
perror("inet_pton");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
struct dhcp6_iana_option create_iana_option(const char * iaid, struct dhcp6_iaaddr_option ia_addr){
|
||||
struct dhcp6_iana_option result;
|
||||
result.type = htons(IA_NA);
|
||||
result.iaid = htonl(atoi(iaid));
|
||||
result.t1 = 0;
|
||||
result.t2 = 0;
|
||||
result.len = htons(12 + ntohs(ia_addr.len) + 2 * sizeof(uint16_t));
|
||||
memcpy(result.options, &ia_addr, ntohs(ia_addr.len) + 2 * sizeof(uint16_t));
|
||||
return result;
|
||||
struct dhcp6_iaaddr_option create_iaadr_option(const char* ip)
|
||||
{
|
||||
struct dhcp6_iaaddr_option result;
|
||||
result.type =htons(IAADDR);
|
||||
/* no suboptions needed here, so length is 24 */
|
||||
result.len = htons(24);
|
||||
result.preferred_lifetime = 0;
|
||||
result.valid_lifetime = 0;
|
||||
int s = inet_pton(AF_INET6, ip, &(result.ip));
|
||||
if (s <= 0) {
|
||||
if (s == 0)
|
||||
fprintf(stderr, "Not in presentation format");
|
||||
else
|
||||
perror("inet_pton");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
struct dhcp6_packet create_release_packet(const char* iaid, const char* ip, const char* client_id, const char* server_id){
|
||||
struct dhcp6_packet result;
|
||||
bzero(result.buf, sizeof(result.buf));
|
||||
/* message_type */
|
||||
result.buf[0] = RELEASE;
|
||||
/* tx_id */
|
||||
bzero(result.buf+1, 3);
|
||||
|
||||
struct dhcp6_option client_option = create_client_id_option(client_id);
|
||||
struct dhcp6_option server_option = create_server_id_option(server_id);
|
||||
struct dhcp6_iaaddr_option iaaddr_option = create_iaadr_option(ip);
|
||||
struct dhcp6_iana_option iana_option = create_iana_option(iaid, iaaddr_option);
|
||||
int offset = 4;
|
||||
memcpy(result.buf + offset, &client_option, ntohs(client_option.len) + 2*sizeof(uint16_t));
|
||||
offset += (ntohs(client_option.len)+ 2 *sizeof(uint16_t) );
|
||||
memcpy(result.buf + offset, &server_option, ntohs(server_option.len) + 2*sizeof(uint16_t) );
|
||||
offset += (ntohs(server_option.len)+ 2* sizeof(uint16_t));
|
||||
memcpy(result.buf + offset, &iana_option, ntohs(iana_option.len) + 2*sizeof(uint16_t) );
|
||||
offset += (ntohs(iana_option.len)+ 2* sizeof(uint16_t));
|
||||
result.len = offset;
|
||||
return result;
|
||||
struct dhcp6_iana_option create_iana_option(const char * iaid, struct dhcp6_iaaddr_option ia_addr)
|
||||
{
|
||||
struct dhcp6_iana_option result;
|
||||
result.type = htons(IA_NA);
|
||||
result.iaid = htonl(atoi(iaid));
|
||||
result.t1 = 0;
|
||||
result.t2 = 0;
|
||||
result.len = htons(12 + ntohs(ia_addr.len) + 2 * sizeof(uint16_t));
|
||||
memcpy(result.options, &ia_addr, ntohs(ia_addr.len) + 2 * sizeof(uint16_t));
|
||||
return result;
|
||||
}
|
||||
|
||||
uint16_t parse_iana_suboption(char* buf, size_t len){
|
||||
size_t current_pos = 0;
|
||||
char option_value[1024];
|
||||
while (current_pos < len) {
|
||||
uint16_t option_type, option_len;
|
||||
memcpy(&option_type,buf + current_pos, sizeof(uint16_t));
|
||||
memcpy(&option_len,buf + current_pos + sizeof(uint16_t), sizeof(uint16_t));
|
||||
option_type = ntohs(option_type);
|
||||
option_len = ntohs(option_len);
|
||||
current_pos += 2 * sizeof(uint16_t);
|
||||
if (option_type == STATUS_CODE){
|
||||
uint16_t status;
|
||||
memcpy(&status, buf + current_pos, sizeof(uint16_t));
|
||||
status = ntohs(status);
|
||||
if (status != SUCCESS){
|
||||
memcpy(option_value, buf + current_pos + sizeof(uint16_t) , option_len - sizeof(uint16_t));
|
||||
option_value[option_len-sizeof(uint16_t)] ='\0';
|
||||
fprintf(stderr, "Error: %s\n", option_value);
|
||||
struct dhcp6_packet create_release_packet(const char* iaid, const char* ip, const char* client_id, const char* server_id)
|
||||
{
|
||||
struct dhcp6_packet result;
|
||||
bzero(result.buf, sizeof(result.buf));
|
||||
/* message_type */
|
||||
result.buf[0] = RELEASE;
|
||||
/* tx_id */
|
||||
bzero(result.buf+1, 3);
|
||||
|
||||
struct dhcp6_option client_option = create_client_id_option(client_id);
|
||||
struct dhcp6_option server_option = create_server_id_option(server_id);
|
||||
struct dhcp6_iaaddr_option iaaddr_option = create_iaadr_option(ip);
|
||||
struct dhcp6_iana_option iana_option = create_iana_option(iaid, iaaddr_option);
|
||||
int offset = 4;
|
||||
memcpy(result.buf + offset, &client_option, ntohs(client_option.len) + 2*sizeof(uint16_t));
|
||||
offset += (ntohs(client_option.len)+ 2 *sizeof(uint16_t) );
|
||||
memcpy(result.buf + offset, &server_option, ntohs(server_option.len) + 2*sizeof(uint16_t) );
|
||||
offset += (ntohs(server_option.len)+ 2* sizeof(uint16_t));
|
||||
memcpy(result.buf + offset, &iana_option, ntohs(iana_option.len) + 2*sizeof(uint16_t) );
|
||||
offset += (ntohs(iana_option.len)+ 2* sizeof(uint16_t));
|
||||
result.len = offset;
|
||||
return result;
|
||||
}
|
||||
|
||||
uint16_t parse_iana_suboption(char* buf, size_t len)
|
||||
{
|
||||
size_t current_pos = 0;
|
||||
char option_value[1024];
|
||||
while (current_pos < len)
|
||||
{
|
||||
uint16_t option_type, option_len;
|
||||
memcpy(&option_type,buf + current_pos, sizeof(uint16_t));
|
||||
memcpy(&option_len,buf + current_pos + sizeof(uint16_t), sizeof(uint16_t));
|
||||
option_type = ntohs(option_type);
|
||||
option_len = ntohs(option_len);
|
||||
current_pos += 2 * sizeof(uint16_t);
|
||||
if (option_type == STATUS_CODE)
|
||||
{
|
||||
uint16_t status;
|
||||
memcpy(&status, buf + current_pos, sizeof(uint16_t));
|
||||
status = ntohs(status);
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
memcpy(option_value, buf + current_pos + sizeof(uint16_t) , option_len - sizeof(uint16_t));
|
||||
option_value[option_len-sizeof(uint16_t)] ='\0';
|
||||
fprintf(stderr, "Error: %s\n", option_value);
|
||||
}
|
||||
return status;
|
||||
return status;
|
||||
}
|
||||
}
|
||||
return -2;
|
||||
|
||||
return -2;
|
||||
}
|
||||
|
||||
int16_t parse_packet(char* buf, size_t len){
|
||||
uint8_t type = buf[0];
|
||||
/*skipping tx id. you need it, uncomment following line
|
||||
uint16_t tx_id = ntohs((buf[1] <<16) + (buf[2] <<8) + buf[3]);
|
||||
*/
|
||||
size_t current_pos = 4;
|
||||
if (type != REPLY ){
|
||||
return NOT_REPLY_CODE;
|
||||
}
|
||||
char option_value[1024];
|
||||
while (current_pos < len) {
|
||||
uint16_t option_type, option_len;
|
||||
memcpy(&option_type,buf + current_pos, sizeof(uint16_t));
|
||||
memcpy(&option_len,buf + current_pos + sizeof(uint16_t), sizeof(uint16_t));
|
||||
option_type = ntohs(option_type);
|
||||
option_len = ntohs(option_len);
|
||||
current_pos += 2 * sizeof(uint16_t);
|
||||
if (option_type == STATUS_CODE){
|
||||
uint16_t status;
|
||||
memcpy(&status, buf + current_pos, sizeof(uint16_t));
|
||||
status = ntohs(status);
|
||||
if (status != SUCCESS){
|
||||
memcpy(option_value, buf + current_pos +sizeof(uint16_t) , option_len -sizeof(uint16_t));
|
||||
fprintf(stderr, "Error: %d %s\n", status, option_value);
|
||||
return status;
|
||||
}
|
||||
|
||||
int16_t parse_packet(char* buf, size_t len)
|
||||
{
|
||||
int16_t ret = -1;
|
||||
uint8_t type = buf[0];
|
||||
/*skipping tx id. you need it, uncomment following line
|
||||
uint16_t tx_id = ntohs((buf[1] <<16) + (buf[2] <<8) + buf[3]);
|
||||
*/
|
||||
size_t current_pos = 4;
|
||||
if (type != REPLY )
|
||||
return NOT_REPLY_CODE;
|
||||
|
||||
char option_value[1024];
|
||||
while (current_pos < len)
|
||||
{
|
||||
uint16_t option_type, option_len;
|
||||
memcpy(&option_type,buf + current_pos, sizeof(uint16_t));
|
||||
memcpy(&option_len,buf + current_pos + sizeof(uint16_t), sizeof(uint16_t));
|
||||
option_type = ntohs(option_type);
|
||||
option_len = ntohs(option_len);
|
||||
current_pos += 2 * sizeof(uint16_t);
|
||||
if (option_type == STATUS_CODE)
|
||||
{
|
||||
uint16_t status;
|
||||
memcpy(&status, buf + current_pos, sizeof(uint16_t));
|
||||
status = ntohs(status);
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
memcpy(option_value, buf + current_pos +sizeof(uint16_t) , option_len -sizeof(uint16_t));
|
||||
fprintf(stderr, "Error: %d %s\n", status, option_value);
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Got success status, return that if there's no specific error in an IA_NA. */
|
||||
ret = SUCCESS;
|
||||
}
|
||||
if (option_type == IA_NA ){
|
||||
uint16_t result = parse_iana_suboption(buf + current_pos +24, option_len -24);
|
||||
if (result){
|
||||
return result;
|
||||
}
|
||||
}
|
||||
current_pos += option_len;
|
||||
|
||||
if (option_type == IA_NA )
|
||||
{
|
||||
uint16_t result = parse_iana_suboption(buf + current_pos +24, option_len -24);
|
||||
if (result)
|
||||
return result;
|
||||
}
|
||||
|
||||
current_pos += option_len;
|
||||
}
|
||||
return -1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void usage(const char* arg, FILE* stream){
|
||||
const char* usage_string ="--ip IPv6 --iface IFACE --server-id SERVER_ID --client-id CLIENT_ID --iaid IAID [--dry-run] | --help";
|
||||
fprintf (stream, "Usage: %s %s\n", arg, usage_string);
|
||||
|
||||
void usage(const char* arg, FILE* stream)
|
||||
{
|
||||
const char* usage_string ="--ip IPv6 --iface IFACE --server-id SERVER_ID --client-id CLIENT_ID --iaid IAID [--dry-run] | --help";
|
||||
fprintf (stream, "Usage: %s %s\n", arg, usage_string);
|
||||
}
|
||||
|
||||
int send_release_packet(const char* iface, struct dhcp6_packet* packet){
|
||||
|
||||
struct sockaddr_in6 server_addr, client_addr;
|
||||
char response[1400];
|
||||
int sock = socket(PF_INET6, SOCK_DGRAM, 0);
|
||||
int i = 0;
|
||||
if (sock < 0) {
|
||||
perror("creating socket");
|
||||
return -1;
|
||||
int send_release_packet(const char* iface, struct dhcp6_packet* packet)
|
||||
{
|
||||
struct sockaddr_in6 server_addr, client_addr;
|
||||
char response[1400];
|
||||
int sock = socket(PF_INET6, SOCK_DGRAM, 0);
|
||||
int i = 0;
|
||||
if (sock < 0)
|
||||
{
|
||||
perror("creating socket");
|
||||
return -1;
|
||||
}
|
||||
if (setsockopt(sock, SOL_SOCKET, 25, iface, strlen(iface)) == -1) {
|
||||
|
||||
if (setsockopt(sock, SOL_SOCKET, 25, iface, strlen(iface)) == -1)
|
||||
{
|
||||
perror("SO_BINDTODEVICE");
|
||||
close(sock);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
memset(&server_addr, 0, sizeof(server_addr));
|
||||
server_addr.sin6_family = AF_INET6;
|
||||
client_addr.sin6_family = AF_INET6;
|
||||
@@ -320,126 +348,149 @@ int send_release_packet(const char* iface, struct dhcp6_packet* packet){
|
||||
inet_pton(AF_INET6, DHCP6_MULTICAST_ADDRESS, &server_addr.sin6_addr);
|
||||
server_addr.sin6_port = htons(DHCP6_SERVER_PORT);
|
||||
int16_t recv_size = 0;
|
||||
for (i = 0; i < 5; i++) {
|
||||
if (sendto(sock, packet->buf, packet->len, 0,
|
||||
(struct sockaddr *)&server_addr,
|
||||
sizeof(server_addr)) < 0) {
|
||||
perror("sendto failed");
|
||||
for (i = 0; i < 5; i++)
|
||||
{
|
||||
if (sendto(sock, packet->buf, packet->len, 0, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)
|
||||
{
|
||||
perror("sendto failed");
|
||||
exit(4);
|
||||
}
|
||||
}
|
||||
|
||||
recv_size = recvfrom(sock, response, sizeof(response), MSG_DONTWAIT, NULL, 0);
|
||||
if (recv_size == -1){
|
||||
if (errno == EAGAIN){
|
||||
sleep(1);
|
||||
continue;
|
||||
}else {
|
||||
if (recv_size == -1)
|
||||
{
|
||||
if (errno == EAGAIN)
|
||||
{
|
||||
sleep(1);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
perror("recvfrom");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int16_t result = parse_packet(response, recv_size);
|
||||
if (result == NOT_REPLY_CODE){
|
||||
if (result == NOT_REPLY_CODE)
|
||||
{
|
||||
sleep(1);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
fprintf(stderr, "Response timed out\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
fprintf(stderr, "Response timed out\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char * const argv[]) {
|
||||
const char* UNINITIALIZED = "";
|
||||
const char* iface = UNINITIALIZED;
|
||||
const char* ip = UNINITIALIZED;
|
||||
const char* client_id = UNINITIALIZED;
|
||||
const char* server_id = UNINITIALIZED;
|
||||
const char* iaid = UNINITIALIZED;
|
||||
int dry_run = 0;
|
||||
while (1) {
|
||||
int option_index = 0;
|
||||
int c = getopt_long(argc, argv, "a:s:c:n:i:hd", longopts, &option_index);
|
||||
if (c == -1){
|
||||
break;
|
||||
}
|
||||
switch(c){
|
||||
case 0:
|
||||
if (longopts[option_index].flag !=0){
|
||||
break;
|
||||
}
|
||||
printf ("option %s", longopts[option_index].name);
|
||||
if (optarg)
|
||||
printf (" with arg %s", optarg);
|
||||
printf ("\n");
|
||||
break;
|
||||
case 'i':
|
||||
iaid = optarg;
|
||||
break;
|
||||
case 'n':
|
||||
iface = optarg;
|
||||
break;
|
||||
case 'a':
|
||||
ip = optarg;
|
||||
break;
|
||||
case 'c':
|
||||
client_id = optarg;
|
||||
break;
|
||||
case 'd':
|
||||
dry_run = 1;
|
||||
break;
|
||||
case 's':
|
||||
server_id = optarg;
|
||||
break;
|
||||
case 'h':
|
||||
usage(argv[0], stdout);
|
||||
return 0;
|
||||
case '?':
|
||||
usage(argv[0], stderr);
|
||||
return -1;
|
||||
default:
|
||||
abort();
|
||||
|
||||
}
|
||||
int main(int argc, char * const argv[])
|
||||
{
|
||||
const char* UNINITIALIZED = "";
|
||||
const char* iface = UNINITIALIZED;
|
||||
const char* ip = UNINITIALIZED;
|
||||
const char* client_id = UNINITIALIZED;
|
||||
const char* server_id = UNINITIALIZED;
|
||||
const char* iaid = UNINITIALIZED;
|
||||
int dry_run = 0;
|
||||
while (1)
|
||||
{
|
||||
int option_index = 0;
|
||||
int c = getopt_long(argc, argv, "a:s:c:n:i:hd", longopts, &option_index);
|
||||
if (c == -1)
|
||||
break;
|
||||
|
||||
switch(c)
|
||||
{
|
||||
case 0:
|
||||
if (longopts[option_index].flag !=0)
|
||||
break;
|
||||
|
||||
printf ("option %s", longopts[option_index].name);
|
||||
if (optarg)
|
||||
printf (" with arg %s", optarg);
|
||||
printf ("\n");
|
||||
break;
|
||||
|
||||
case 'i':
|
||||
iaid = optarg;
|
||||
break;
|
||||
case 'n':
|
||||
iface = optarg;
|
||||
break;
|
||||
case 'a':
|
||||
ip = optarg;
|
||||
break;
|
||||
case 'c':
|
||||
client_id = optarg;
|
||||
break;
|
||||
case 'd':
|
||||
dry_run = 1;
|
||||
break;
|
||||
case 's':
|
||||
server_id = optarg;
|
||||
break;
|
||||
case 'h':
|
||||
usage(argv[0], stdout);
|
||||
return 0;
|
||||
case '?':
|
||||
usage(argv[0], stderr);
|
||||
return -1;
|
||||
default:
|
||||
abort();
|
||||
|
||||
}
|
||||
}
|
||||
if (iaid == UNINITIALIZED){
|
||||
fprintf(stderr, "Missing required iaid parameter\n");
|
||||
usage(argv[0], stderr);
|
||||
return -1;
|
||||
|
||||
if (iaid == UNINITIALIZED)
|
||||
{
|
||||
fprintf(stderr, "Missing required iaid parameter\n");
|
||||
usage(argv[0], stderr);
|
||||
return -1;
|
||||
}
|
||||
if (server_id == UNINITIALIZED){
|
||||
|
||||
if (server_id == UNINITIALIZED)
|
||||
{
|
||||
fprintf(stderr, "Missing required server-id parameter\n");
|
||||
usage(argv[0], stderr);
|
||||
return -1;
|
||||
}
|
||||
if (client_id == UNINITIALIZED){
|
||||
}
|
||||
|
||||
if (client_id == UNINITIALIZED)
|
||||
{
|
||||
fprintf(stderr, "Missing required client-id parameter\n");
|
||||
usage(argv[0], stderr);
|
||||
return -1;
|
||||
}
|
||||
if (ip == UNINITIALIZED){
|
||||
}
|
||||
|
||||
if (ip == UNINITIALIZED)
|
||||
{
|
||||
fprintf(stderr, "Missing required ip parameter\n");
|
||||
usage(argv[0], stderr);
|
||||
return -1;
|
||||
}
|
||||
if (iface == UNINITIALIZED){
|
||||
fprintf(stderr, "Missing required iface parameter\n");
|
||||
}
|
||||
|
||||
if (iface == UNINITIALIZED)
|
||||
{
|
||||
fprintf(stderr, "Missing required iface parameter\n");
|
||||
usage(argv[0], stderr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct dhcp6_packet packet = create_release_packet(iaid, ip, client_id, server_id);
|
||||
if (dry_run){
|
||||
|
||||
if (dry_run)
|
||||
{
|
||||
uint16_t i;
|
||||
for(i=0;i<packet.len;i++){
|
||||
printf("%hhx", packet.buf[i]);
|
||||
}
|
||||
|
||||
for(i=0; i<packet.len; i++)
|
||||
printf("%hhx", packet.buf[i]);
|
||||
|
||||
printf("\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return send_release_packet(iface, &packet);
|
||||
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
STATUS_FILE="/tmp/dnsmasq-ip-mac.status"
|
||||
|
||||
# Script for dnsmasq lease-change hook.
|
||||
# Maintains the above file with a IP address/MAC address pairs,
|
||||
# Maintains the above file with an IP address/MAC address pairs,
|
||||
# one lease per line. Works with IPv4 and IPv6 leases, file is
|
||||
# atomically updated, so no races for users of the data.
|
||||
|
||||
|
||||
29
debian/changelog
vendored
29
debian/changelog
vendored
@@ -1,8 +1,33 @@
|
||||
dnsmasq (2.79-1) unstable; urgency=low
|
||||
|
||||
* New upstream. (closes: #888200)
|
||||
* Fix trust-anchor regex in init script. (closes: #884347)
|
||||
* Fix exit code for dhcp_release6 (closes: #883596)
|
||||
* Add project homepage to control file. (closes: #887764)
|
||||
* New binary package dnsmasq-base-lua, includes Lua support.
|
||||
* Remove hardwired shlibs dependency for libnettle 3.3 and
|
||||
fix code to avoid ABI breakage as long as compiled against
|
||||
libnettle 3.4 or later. (closes: #891315)
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Fri, 16 Feb 2018 19:54:22 +0000
|
||||
|
||||
dnsmasq (2.78-3) unstable; urgency=high
|
||||
|
||||
* Make failure of pidfile chown a warning. (closes: #889857)
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Thu, 8 Feb 2018 21:26:30 +0000
|
||||
|
||||
dnsmasq (2.78-2) unstable; urgency=high
|
||||
|
||||
* Change ownership of pid file, to keep systemd happy. (closes: #889336)
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Tue, 6 Feb 2018 17:21:30 +0000
|
||||
|
||||
dnsmasq (2.78-1) unstable; urgency=high
|
||||
|
||||
* New upstream.
|
||||
Security fixes for CVE-2017-13704 (closes: #877102)
|
||||
Security fixes for CVE-2017-14491 - CVE-2017-14496 inclusive.
|
||||
Security fixes for CVE-2017-14491 - CVE-2017-14496 inclusive.
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Sun, 29 Sep 2017 21:34:00 +0000
|
||||
|
||||
@@ -19,7 +44,7 @@ dnsmasq (2.77-1) unstable; urgency=low
|
||||
includes port=0 to disable DNS.
|
||||
* Handle gratuitous format change in /usr/share/dns/root.ds
|
||||
(closes: #858506) (closes: #860064)
|
||||
* Add lsb-base dependancy.
|
||||
* Add lsb-base dependency.
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Tue, 11 Apr 2017 14:19:20 +0000
|
||||
|
||||
|
||||
24
debian/control
vendored
24
debian/control
vendored
@@ -3,13 +3,15 @@ Section: net
|
||||
Priority: optional
|
||||
Build-depends: gettext, libnetfilter-conntrack-dev [linux-any],
|
||||
libidn11-dev, libdbus-1-dev (>=0.61), libgmp-dev,
|
||||
nettle-dev (>=2.4-3), libbsd-dev [!linux-any]
|
||||
nettle-dev (>=2.4-3), libbsd-dev [!linux-any],
|
||||
liblua5.2-dev
|
||||
Maintainer: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Homepage: http://www.thekelleys.org.uk/dnsmasq/doc.html
|
||||
Standards-Version: 3.9.8
|
||||
|
||||
Package: dnsmasq
|
||||
Architecture: all
|
||||
Depends: netbase, dnsmasq-base(>= ${binary:Version}),
|
||||
Depends: netbase, dnsmasq-base,
|
||||
init-system-helpers (>= 1.18~), lsb-base (>= 3.0-6)
|
||||
Suggests: resolvconf
|
||||
Conflicts: resolvconf (<<1.15)
|
||||
@@ -27,13 +29,29 @@ Package: dnsmasq-base
|
||||
Architecture: any
|
||||
Depends: adduser, ${shlibs:Depends}
|
||||
Breaks: dnsmasq (<< 2.63-1~)
|
||||
Replaces: dnsmasq (<< 2.63-1~)
|
||||
Replaces: dnsmasq (<< 2.63-1~), dnsmasq-base
|
||||
Recommends: dns-root-data
|
||||
Provides: dnsmasq-base
|
||||
Conflicts: dnsmasq-base-lua
|
||||
Description: Small caching DNS proxy and DHCP/TFTP server
|
||||
This package contains the dnsmasq executable and documentation, but
|
||||
not the infrastructure required to run it as a system daemon. For
|
||||
that, install the dnsmasq package.
|
||||
|
||||
Package: dnsmasq-base-lua
|
||||
Architecture: any
|
||||
Depends: adduser, ${shlibs:Depends}
|
||||
Breaks: dnsmasq (<< 2.63-1~)
|
||||
Replaces: dnsmasq (<< 2.63-1~), dnsmasq-base
|
||||
Recommends: dns-root-data
|
||||
Provides: dnsmasq-base
|
||||
Conflicts: dnsmasq-base
|
||||
Description: Small caching DNS proxy and DHCP/TFTP server
|
||||
This package contains the dnsmasq executable and documentation, but
|
||||
not the infrastructure required to run it as a system daemon. For
|
||||
that, install the dnsmasq package. This package is an alternative
|
||||
to dnsmasq-base which includes the LUA interpreter.
|
||||
|
||||
Package: dnsmasq-utils
|
||||
Architecture: linux-any
|
||||
Depends: ${shlibs:Depends}
|
||||
|
||||
2
debian/copyright
vendored
2
debian/copyright
vendored
@@ -1,4 +1,4 @@
|
||||
dnsmasq is Copyright (c) 2000-2016 Simon Kelley
|
||||
dnsmasq is Copyright (c) 2000-2018 Simon Kelley
|
||||
|
||||
It was downloaded from: http://www.thekelleys.org.uk/dnsmasq/
|
||||
|
||||
|
||||
2
debian/init
vendored
2
debian/init
vendored
@@ -111,7 +111,7 @@ DNSMASQ_OPTS="$DNSMASQ_OPTS --local-service"
|
||||
ROOT_DS="/usr/share/dns/root.ds"
|
||||
|
||||
if [ -f $ROOT_DS ]; then
|
||||
DNSMASQ_OPTS="$DNSMASQ_OPTS `sed -rne "s/^([.a-ZA-Z0-9]+)([[:space:]]+[0-9]+)*([[:space:]]+IN)*[[:space:]]+DS[[:space:]]+/--trust-anchor=\1,/;s/[[:space:]]+/,/gp" $ROOT_DS | tr '\n' ' '`"
|
||||
DNSMASQ_OPTS="$DNSMASQ_OPTS `env LC_ALL=C sed -rne "s/^([.a-zA-Z0-9]+)([[:space:]]+[0-9]+)*([[:space:]]+IN)*[[:space:]]+DS[[:space:]]+/--trust-anchor=\1,/;s/[[:space:]]+/,/gp" $ROOT_DS | tr '\n' ' '`"
|
||||
fi
|
||||
|
||||
start()
|
||||
|
||||
3
debian/lintian-override
vendored
Normal file
3
debian/lintian-override
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
# dnsmasq-base and dnsmasq-base-lua are mutually exclusive and both
|
||||
# provide /usr/share/doc/dnsmasq-base
|
||||
dnsmasq-base-lua binary: usr-share-doc-symlink-without-dependency dnsmasq-base
|
||||
2
debian/readme
vendored
2
debian/readme
vendored
@@ -54,7 +54,7 @@ Notes on configuring dnsmasq as packaged for Debian.
|
||||
nodhcp : omit DHCP support.
|
||||
nodhcp6 : omit DHCPv6 support.
|
||||
noscript : omit lease-change script support.
|
||||
use_lua : provide support for lease-change scripts written
|
||||
uselua : provide support for lease-change scripts written
|
||||
in Lua.
|
||||
noipv6 : omit IPv6 support.
|
||||
nodbus : omit DBus support.
|
||||
|
||||
264
debian/rules
vendored
264
debian/rules
vendored
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/make -f
|
||||
# debian/rules file - for dnsmasq.
|
||||
# Copyright 2001-2011 by Simon Kelley
|
||||
# Copyright 2001-2018 by Simon Kelley
|
||||
# Based on the sample in the debian hello package which carries the following:
|
||||
# Copyright 1994,1995 by Ian Jackson.
|
||||
# I hereby give you perpetual unlimited permission to copy,
|
||||
@@ -103,128 +103,170 @@ ifneq ($(DEB_HOST_ARCH_OS),linux)
|
||||
LDFLAGS += -lbsd
|
||||
endif
|
||||
|
||||
clean:
|
||||
$(checkdir)
|
||||
rm -rf debian/daemon debian/base debian/utils debian/*~ debian/files debian/substvars debian/utils-substvars
|
||||
make clean
|
||||
make -C contrib/lease-tools clean
|
||||
|
||||
binary-indep: checkroot
|
||||
$(checkdir)
|
||||
rm -rf debian/daemon
|
||||
define build_tree
|
||||
rm -rf $1
|
||||
install -m 755 \
|
||||
-d debian/daemon/DEBIAN \
|
||||
-d debian/daemon/usr/share/doc \
|
||||
-d debian/daemon/etc/init.d \
|
||||
-d debian/daemon/etc/dnsmasq.d \
|
||||
-d debian/daemon/etc/resolvconf/update.d \
|
||||
-d debian/daemon/usr/lib/resolvconf/dpkg-event.d \
|
||||
-d debian/daemon/usr/share/dnsmasq \
|
||||
-d debian/daemon/etc/default \
|
||||
-d debian/daemon/lib/systemd/system \
|
||||
-d debian/daemon/etc/insserv.conf.d
|
||||
install -m 644 debian/conffiles debian/daemon/DEBIAN
|
||||
install -m 755 debian/postinst debian/postrm debian/prerm debian/daemon/DEBIAN
|
||||
install -m 755 debian/init debian/daemon/etc/init.d/dnsmasq
|
||||
install -m 755 debian/resolvconf debian/daemon/etc/resolvconf/update.d/dnsmasq
|
||||
install -m 755 debian/resolvconf-package debian/daemon/usr/lib/resolvconf/dpkg-event.d/dnsmasq
|
||||
install -m 644 debian/installed-marker debian/daemon/usr/share/dnsmasq
|
||||
install -m 644 debian/default debian/daemon/etc/default/dnsmasq
|
||||
install -m 644 dnsmasq.conf.example debian/daemon/etc/dnsmasq.conf
|
||||
install -m 644 debian/readme.dnsmasq.d debian/daemon/etc/dnsmasq.d/README
|
||||
install -m 644 debian/systemd.service debian/daemon/lib/systemd/system/dnsmasq.service
|
||||
install -m 644 debian/insserv debian/daemon/etc/insserv.conf.d/dnsmasq
|
||||
ln -s $(package) debian/daemon/usr/share/doc/dnsmasq
|
||||
cd debian/daemon && find . -type f ! -regex '.*DEBIAN/.*' -printf '%P\0' | LC_ALL=C sort -z | xargs -r0 md5sum > DEBIAN/md5sums
|
||||
dpkg-gencontrol $(PACKAGE_VERSION) -T -pdnsmasq -Pdebian/daemon
|
||||
find debian/daemon -depth -newermt '$(BUILD_DATE)' -print0 | xargs -0r touch --no-dereference --date='$(BUILD_DATE)'
|
||||
chown -R root.root debian/daemon
|
||||
chmod -R g-ws debian/daemon
|
||||
dpkg --build debian/daemon ..
|
||||
-d $1/DEBIAN \
|
||||
-d $1/etc/dbus-1/system.d \
|
||||
-d $1/usr/share/doc/$(package) \
|
||||
-d $1/usr/share/doc/$(package)/examples \
|
||||
-d $1/usr/share/$(package) \
|
||||
-d $1/var/lib/misc
|
||||
|
||||
binary-arch: checkroot
|
||||
$(checkdir)
|
||||
rm -rf debian/base
|
||||
install -m 755 \
|
||||
-d debian/base/DEBIAN \
|
||||
-d debian/base/etc/dbus-1/system.d \
|
||||
-d debian/base/usr/share/doc/$(package) \
|
||||
-d debian/base/usr/share/doc/$(package)/examples \
|
||||
-d debian/base/usr/share/$(package) \
|
||||
-d debian/base/var/lib/misc
|
||||
make $(TARGET) PREFIX=/usr DESTDIR=`pwd`/debian/base CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" COPTS="$(DEB_COPTS)" CC=$(CC) PKG_CONFIG=$(PKG_CONFIG)
|
||||
ifeq (,$(findstring nodocs,$(DEB_BUILD_OPTIONS)))
|
||||
endef
|
||||
|
||||
define add_docs
|
||||
# Need to remove paypal links in Debian Package for policy reasons.
|
||||
sed -e /\<H2\>Donations/Q -e /icon.png/d doc.html -e /favicon.ico/d >debian/base/usr/share/doc/$(package)/doc.html
|
||||
echo "</BODY>" >>debian/base/usr/share/doc/$(package)/doc.html
|
||||
install -m 644 setup.html debian/base/usr/share/doc/$(package)/.
|
||||
install -m 644 dnsmasq.conf.example debian/base/usr/share/doc/$(package)/examples/.
|
||||
install -m 644 trust-anchors.conf debian/base/usr/share/$(package)/.
|
||||
install -m 644 FAQ debian/base/usr/share/doc/$(package)/.
|
||||
gzip -9n debian/base/usr/share/doc/$(package)/FAQ
|
||||
install -m 644 CHANGELOG debian/base/usr/share/doc/$(package)/changelog
|
||||
gzip -9n debian/base/usr/share/doc/$(package)/changelog
|
||||
install -m 644 CHANGELOG.archive debian/base/usr/share/doc/$(package)/changelog.archive
|
||||
gzip -9n debian/base/usr/share/doc/$(package)/changelog.archive
|
||||
install -m 644 dbus/DBus-interface debian/base/usr/share/doc/$(package)/.
|
||||
gzip -9n debian/base/usr/share/doc/$(package)/DBus-interface
|
||||
endif
|
||||
install -m 644 debian/dnsmasq-base.conffiles debian/base/DEBIAN/conffiles
|
||||
install -m 755 debian/dnsmasq-base.postinst debian/base/DEBIAN/postinst
|
||||
install -m 755 debian/dnsmasq-base.postrm debian/base/DEBIAN/postrm
|
||||
install -m 644 debian/changelog debian/base/usr/share/doc/$(package)/changelog.Debian
|
||||
gzip -9n debian/base/usr/share/doc/$(package)/changelog.Debian
|
||||
install -m 644 debian/readme debian/base/usr/share/doc/$(package)/README.Debian
|
||||
install -m 644 debian/copyright debian/base/usr/share/doc/$(package)/copyright
|
||||
install -m 644 debian/dbus.conf debian/base/etc/dbus-1/system.d/dnsmasq.conf
|
||||
gzip -9n debian/base/usr/share/man/man8/dnsmasq.8
|
||||
for f in debian/base/usr/share/man/*; do \
|
||||
sed -e /\<H2\>Donations/Q -e /icon.png/d doc.html -e /favicon.ico/d >$1/usr/share/doc/$(package)/doc.html
|
||||
echo "</BODY>" >>$1/usr/share/doc/$(package)/doc.html
|
||||
install -m 644 setup.html $1/usr/share/doc/$(package)/.
|
||||
install -m 644 dnsmasq.conf.example $1/usr/share/doc/$(package)/examples/.
|
||||
install -m 644 FAQ $1/usr/share/doc/$(package)/.
|
||||
gzip -9n $1/usr/share/doc/$(package)/FAQ
|
||||
install -m 644 CHANGELOG $1/usr/share/doc/$(package)/changelog
|
||||
gzip -9n $1/usr/share/doc/$(package)/changelog
|
||||
install -m 644 CHANGELOG.archive $1/usr/share/doc/$(package)/changelog.archive
|
||||
gzip -9n $1/usr/share/doc/$(package)/changelog.archive
|
||||
install -m 644 dbus/DBus-interface $1/usr/share/doc/$(package)/.
|
||||
gzip -9n $1/usr/share/doc/$(package)/DBus-interface
|
||||
gzip -9n $1/usr/share/man/man8/dnsmasq.8
|
||||
for f in $1/usr/share/man/*; do \
|
||||
if [ -f $$f/man8/dnsmasq.8 ]; then \
|
||||
gzip -9n $$f/man8/dnsmasq.8 ; \
|
||||
fi \
|
||||
done
|
||||
ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
|
||||
$(DEB_HOST_GNU_TYPE)-strip -R .note -R .comment debian/base/usr/sbin/dnsmasq
|
||||
endef
|
||||
|
||||
define add_files
|
||||
install -m 644 trust-anchors.conf $1/usr/share/$(package)/.
|
||||
install -m 644 debian/dnsmasq-base.conffiles $1/DEBIAN/conffiles
|
||||
install -m 755 debian/dnsmasq-base.postinst $1/DEBIAN/postinst
|
||||
install -m 755 debian/dnsmasq-base.postrm $1/DEBIAN/postrm
|
||||
install -m 644 debian/changelog $1/usr/share/doc/$(package)/changelog.Debian
|
||||
gzip -9n $1/usr/share/doc/$(package)/changelog.Debian
|
||||
install -m 644 debian/readme $1/usr/share/doc/$(package)/README.Debian
|
||||
install -m 644 debian/copyright $1/usr/share/doc/$(package)/copyright
|
||||
install -m 644 debian/dbus.conf $1/etc/dbus-1/system.d/dnsmasq.conf
|
||||
endef
|
||||
|
||||
clean:
|
||||
$(checkdir)
|
||||
make BUILDDIR=debian/build/no-lua clean
|
||||
make BUILDDIR=debian/build/lua clean
|
||||
make -C contrib/lease-tools clean
|
||||
rm -rf debian/build debian/trees debian/*~ debian/files debian/substvars debian/utils-substvars
|
||||
|
||||
binary-indep: checkroot
|
||||
$(checkdir)
|
||||
rm -rf debian/trees/daemon
|
||||
install -m 755 \
|
||||
-d debian/trees/daemon/DEBIAN \
|
||||
-d debian/trees/daemon/usr/share/doc \
|
||||
-d debian/trees/daemon/etc/init.d \
|
||||
-d debian/trees/daemon/etc/dnsmasq.d \
|
||||
-d debian/trees/daemon/etc/resolvconf/update.d \
|
||||
-d debian/trees/daemon/usr/lib/resolvconf/dpkg-event.d \
|
||||
-d debian/trees/daemon/usr/share/dnsmasq \
|
||||
-d debian/trees/daemon/etc/default \
|
||||
-d debian/trees/daemon/lib/systemd/system \
|
||||
-d debian/trees/daemon/etc/insserv.conf.d
|
||||
install -m 644 debian/conffiles debian/trees/daemon/DEBIAN
|
||||
install -m 755 debian/postinst debian/postrm debian/prerm debian/trees/daemon/DEBIAN
|
||||
install -m 755 debian/init debian/trees/daemon/etc/init.d/dnsmasq
|
||||
install -m 755 debian/resolvconf debian/trees/daemon/etc/resolvconf/update.d/dnsmasq
|
||||
install -m 755 debian/resolvconf-package debian/trees/daemon/usr/lib/resolvconf/dpkg-event.d/dnsmasq
|
||||
install -m 644 debian/installed-marker debian/trees/daemon/usr/share/dnsmasq
|
||||
install -m 644 debian/default debian/trees/daemon/etc/default/dnsmasq
|
||||
install -m 644 dnsmasq.conf.example debian/trees/daemon/etc/dnsmasq.conf
|
||||
install -m 644 debian/readme.dnsmasq.d debian/trees/daemon/etc/dnsmasq.d/README
|
||||
install -m 644 debian/systemd.service debian/trees/daemon/lib/systemd/system/dnsmasq.service
|
||||
install -m 644 debian/insserv debian/trees/daemon/etc/insserv.conf.d/dnsmasq
|
||||
ln -s $(package) debian/trees/daemon/usr/share/doc/dnsmasq
|
||||
cd debian/trees/daemon && find . -type f ! -regex '.*DEBIAN/.*' -printf '%P\0' | LC_ALL=C sort -z | xargs -r0 md5sum > DEBIAN/md5sums
|
||||
dpkg-gencontrol $(PACKAGE_VERSION) -T -pdnsmasq -Pdebian/trees/daemon
|
||||
find debian/trees/daemon -depth -newermt '$(BUILD_DATE)' -print0 | xargs -0r touch --no-dereference --date='$(BUILD_DATE)'
|
||||
chown -R root.root debian/trees/daemon
|
||||
chmod -R g-ws debian/trees/daemon
|
||||
dpkg --build debian/trees/daemon ..
|
||||
|
||||
binary-arch: checkroot
|
||||
$(call build_tree,debian/trees/base)
|
||||
make $(TARGET) BUILDDIR=debian/build/no-lua PREFIX=/usr DESTDIR=`pwd`/debian/trees/base CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" COPTS="$(DEB_COPTS)" CC=$(CC) PKG_CONFIG=$(PKG_CONFIG)
|
||||
ifeq (,$(findstring nodocs,$(DEB_BUILD_OPTIONS)))
|
||||
$(call add_docs,debian/trees/base)
|
||||
else
|
||||
rm -rf debian/trees/base/usr/share/man
|
||||
endif
|
||||
cd debian/base && find . -type f ! -regex '.*DEBIAN/.*' -printf '%P\0' | LC_ALL=C sort -z | xargs -r0 md5sum > DEBIAN/md5sums
|
||||
dpkg-shlibdeps --warnings=1 debian/base/usr/sbin/dnsmasq
|
||||
dpkg-gencontrol $(PACKAGE_VERSION) -pdnsmasq-base -Pdebian/base
|
||||
find debian/base -depth -newermt '$(BUILD_DATE)' -print0 | xargs -0r touch --no-dereference --date='$(BUILD_DATE)'
|
||||
chown -R root.root debian/base
|
||||
chmod -R g-ws debian/base
|
||||
dpkg --build debian/base ..
|
||||
$(call add_files,debian/trees/base)
|
||||
ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
|
||||
$(DEB_HOST_GNU_TYPE)-strip -R .note -R .comment debian/trees/base/usr/sbin/dnsmasq
|
||||
endif
|
||||
cd debian/trees/base && find . -type f ! -regex '.*DEBIAN/.*' -printf '%P\0' | LC_ALL=C sort -z | xargs -r0 md5sum > DEBIAN/md5sums
|
||||
dpkg-shlibdeps --warnings=1 debian/trees/base/usr/sbin/dnsmasq
|
||||
dpkg-gencontrol $(PACKAGE_VERSION) -pdnsmasq-base -Pdebian/trees/base
|
||||
find debian/trees/base -depth -newermt '$(BUILD_DATE)' -print0 | xargs -0r touch --no-dereference --date='$(BUILD_DATE)'
|
||||
chown -R root.root debian/trees/base
|
||||
chmod -R g-ws debian/trees/base
|
||||
dpkg --build debian/trees/base ..
|
||||
|
||||
$(call build_tree,debian/trees/lua-base)
|
||||
make $(TARGET) BUILDDIR=debian/build/lua PREFIX=/usr DESTDIR=`pwd`/debian/trees/lua-base CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" COPTS="-DHAVE_LUASCRIPT $(DEB_COPTS)" CC=$(CC) PKG_CONFIG=$(PKG_CONFIG)
|
||||
ifeq (,$(findstring nodocs,$(DEB_BUILD_OPTIONS)))
|
||||
$(call add_docs,debian/trees/lua-base)
|
||||
else
|
||||
rm -rf debian/trees/lua-base/usr/share/man
|
||||
endif
|
||||
$(call add_files,debian/trees/lua-base)
|
||||
install -m 755 -d debian/trees/lua-base/usr/share/lintian/overrides
|
||||
install -m 644 debian/lintian-override debian/trees/lua-base/usr/share/lintian/overrides/dnsmasq-base-lua
|
||||
ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
|
||||
$(DEB_HOST_GNU_TYPE)-strip -R .note -R .comment debian/trees/lua-base/usr/sbin/dnsmasq
|
||||
endif
|
||||
ln -s $(package) debian/trees/lua-base/usr/share/doc/dnsmasq-base-lua
|
||||
cd debian/trees/lua-base && find . -type f ! -regex '.*DEBIAN/.*' -printf '%P\0' | LC_ALL=C sort -z | xargs -r0 md5sum > DEBIAN/md5sums
|
||||
dpkg-shlibdeps --warnings=1 debian/trees/lua-base/usr/sbin/dnsmasq
|
||||
dpkg-gencontrol $(PACKAGE_VERSION) -pdnsmasq-base-lua -Pdebian/trees/lua-base
|
||||
find debian/trees/lua-base -depth -newermt '$(BUILD_DATE)' -print0 | xargs -0r touch --no-dereference --date='$(BUILD_DATE)'
|
||||
chown -R root.root debian/trees/lua-base
|
||||
chmod -R g-ws debian/trees/lua-base
|
||||
dpkg --build debian/trees/lua-base ..
|
||||
|
||||
|
||||
ifeq ($(DEB_HOST_ARCH_OS),linux)
|
||||
rm -rf debian/utils
|
||||
install -m 755 -d debian/utils/DEBIAN \
|
||||
-d debian/utils/usr/share/man/man1 \
|
||||
-d debian/utils/usr/bin \
|
||||
-d debian/utils/usr/share/doc/dnsmasq-utils
|
||||
make -C contrib/lease-tools PREFIX=/usr DESTDIR=`pwd`/debian/utils CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" COPTS="$(DEB_COPTS)" CC=$(CC) PKG_CONFIG=$(PKG_CONFIG)
|
||||
install -m 755 contrib/lease-tools/dhcp_release debian/utils/usr/bin/dhcp_release
|
||||
install -m 644 contrib/lease-tools/dhcp_release.1 debian/utils/usr/share/man/man1/dhcp_release.1
|
||||
gzip -9n debian/utils/usr/share/man/man1/dhcp_release.1
|
||||
install -m 755 contrib/lease-tools/dhcp_release6 debian/utils/usr/bin/dhcp_release6
|
||||
install -m 644 contrib/lease-tools/dhcp_release6.1 debian/utils/usr/share/man/man1/dhcp_release6.1
|
||||
gzip -9n debian/utils/usr/share/man/man1/dhcp_release6.1
|
||||
install -m 755 contrib/lease-tools/dhcp_lease_time debian/utils/usr/bin/dhcp_lease_time
|
||||
install -m 644 contrib/lease-tools/dhcp_lease_time.1 debian/utils/usr/share/man/man1/dhcp_lease_time.1
|
||||
install -m 644 debian/copyright debian/utils/usr/share/doc/dnsmasq-utils/copyright
|
||||
install -m 644 debian/changelog debian/utils/usr/share/doc/dnsmasq-utils/changelog.Debian
|
||||
gzip -9n debian/utils/usr/share/doc/dnsmasq-utils/changelog.Debian
|
||||
gzip -9n debian/utils/usr/share/man/man1/dhcp_lease_time.1
|
||||
rm -rf debian/trees/utils
|
||||
install -m 755 -d debian/trees/utils/DEBIAN \
|
||||
-d debian/trees/utils/usr/bin \
|
||||
-d debian/trees/utils/usr/share/doc/dnsmasq-utils
|
||||
ifeq (,$(findstring nodocs,$(DEB_BUILD_OPTIONS)))
|
||||
install -m 755 -d debian/trees/utils/usr/share/man/man1
|
||||
endif
|
||||
make -C contrib/lease-tools PREFIX=/usr DESTDIR=`pwd`/debian/trees/utils CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" COPTS="$(DEB_COPTS)" CC=$(CC) PKG_CONFIG=$(PKG_CONFIG)
|
||||
install -m 755 contrib/lease-tools/dhcp_release debian/trees/utils/usr/bin/dhcp_release
|
||||
install -m 755 contrib/lease-tools/dhcp_release6 debian/trees/utils/usr/bin/dhcp_release6
|
||||
install -m 755 contrib/lease-tools/dhcp_lease_time debian/trees/utils/usr/bin/dhcp_lease_time
|
||||
ifeq (,$(findstring nodocs,$(DEB_BUILD_OPTIONS)))
|
||||
install -m 644 contrib/lease-tools/dhcp_release.1 debian/trees/utils/usr/share/man/man1/dhcp_release.1
|
||||
gzip -9n debian/trees/utils/usr/share/man/man1/dhcp_release.1
|
||||
install -m 644 contrib/lease-tools/dhcp_release6.1 debian/trees/utils/usr/share/man/man1/dhcp_release6.1
|
||||
gzip -9n debian/trees/utils/usr/share/man/man1/dhcp_release6.1
|
||||
install -m 644 contrib/lease-tools/dhcp_lease_time.1 debian/trees/utils/usr/share/man/man1/dhcp_lease_time.1
|
||||
gzip -9n debian/trees/utils/usr/share/man/man1/dhcp_lease_time.1
|
||||
endif
|
||||
install -m 644 debian/copyright debian/trees/utils/usr/share/doc/dnsmasq-utils/copyright
|
||||
install -m 644 debian/changelog debian/trees/utils/usr/share/doc/dnsmasq-utils/changelog.Debian
|
||||
gzip -9n debian/trees/utils/usr/share/doc/dnsmasq-utils/changelog.Debian
|
||||
ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
|
||||
$(DEB_HOST_GNU_TYPE)-strip -R .note -R .comment debian/utils/usr/bin/dhcp_release
|
||||
$(DEB_HOST_GNU_TYPE)-strip -R .note -R .comment debian/utils/usr/bin/dhcp_release6
|
||||
$(DEB_HOST_GNU_TYPE)-strip -R .note -R .comment debian/utils/usr/bin/dhcp_lease_time
|
||||
$(DEB_HOST_GNU_TYPE)-strip -R .note -R .comment debian/trees/utils/usr/bin/dhcp_release
|
||||
$(DEB_HOST_GNU_TYPE)-strip -R .note -R .comment debian/trees/utils/usr/bin/dhcp_release6
|
||||
$(DEB_HOST_GNU_TYPE)-strip -R .note -R .comment debian/trees/utils/usr/bin/dhcp_lease_time
|
||||
endif
|
||||
cd debian/utils && find . -type f ! -regex '.*DEBIAN/.*' -printf '%P\0' | LC_ALL=C sort -z | xargs -r0 md5sum > DEBIAN/md5sums
|
||||
dpkg-shlibdeps -Tdebian/utils-substvars debian/utils/usr/bin/dhcp_release debian/utils/usr/bin/dhcp_lease_time
|
||||
dpkg-gencontrol $(PACKAGE_VERSION) -Tdebian/utils-substvars -pdnsmasq-utils -Pdebian/utils
|
||||
find debian/utils -depth -newermt '$(BUILD_DATE)' -print0 | xargs -0r touch --no-dereference --date='$(BUILD_DATE)'
|
||||
chown -R root.root debian/utils
|
||||
chmod -R g-ws debian/utils
|
||||
dpkg --build debian/utils ..
|
||||
cd debian/trees/utils && find . -type f ! -regex '.*DEBIAN/.*' -printf '%P\0' | LC_ALL=C sort -z | xargs -r0 md5sum > DEBIAN/md5sums
|
||||
dpkg-shlibdeps -Tdebian/utils-substvars debian/trees/utils/usr/bin/dhcp_release debian/trees/utils/usr/bin/dhcp_release6 debian/trees/utils/usr/bin/dhcp_lease_time
|
||||
dpkg-gencontrol $(PACKAGE_VERSION) -Tdebian/utils-substvars -pdnsmasq-utils -Pdebian/trees/utils
|
||||
find debian/trees/utils -depth -newermt '$(BUILD_DATE)' -print0 | xargs -0r touch --no-dereference --date='$(BUILD_DATE)'
|
||||
chown -R root.root debian/trees/utils
|
||||
chmod -R g-ws debian/trees/utils
|
||||
dpkg --build debian/trees/utils ..
|
||||
endif
|
||||
|
||||
define checkdir
|
||||
|
||||
1
debian/shlibs.local
vendored
1
debian/shlibs.local
vendored
@@ -1 +0,0 @@
|
||||
libnettle 6 libnettle6 (>= 3.3)
|
||||
@@ -90,7 +90,7 @@
|
||||
# server=10.1.2.3@eth1
|
||||
|
||||
# and this sets the source (ie local) address used to talk to
|
||||
# 10.1.2.3 to 192.168.1.1 port 55 (there must be a interface with that
|
||||
# 10.1.2.3 to 192.168.1.1 port 55 (there must be an interface with that
|
||||
# IP on the machine, obviously).
|
||||
# server=10.1.2.3@192.168.1.1#55
|
||||
|
||||
@@ -288,7 +288,7 @@
|
||||
# Give a fixed IPv6 address and name to client with
|
||||
# DUID 00:01:00:01:16:d2:83:fc:92:d4:19:e2:d8:b2
|
||||
# Note the MAC addresses CANNOT be used to identify DHCPv6 clients.
|
||||
# Note also the they [] around the IPv6 address are obligatory.
|
||||
# Note also that the [] around the IPv6 address are obligatory.
|
||||
#dhcp-host=id:00:01:00:01:16:d2:83:fc:92:d4:19:e2:d8:b2, fred, [1234::5]
|
||||
|
||||
# Ignore any clients which are not specified in dhcp-host lines
|
||||
@@ -354,11 +354,11 @@
|
||||
|
||||
# Set option 58 client renewal time (T1). Defaults to half of the
|
||||
# lease time if not specified. (RFC2132)
|
||||
#dhcp-option=option:T1:1m
|
||||
#dhcp-option=option:T1,1m
|
||||
|
||||
# Set option 59 rebinding time (T2). Defaults to 7/8 of the
|
||||
# lease time if not specified. (RFC2132)
|
||||
#dhcp-option=option:T2:2m
|
||||
#dhcp-option=option:T2,2m
|
||||
|
||||
# Set the NTP time server address to be the same machine as
|
||||
# is running dnsmasq
|
||||
@@ -436,22 +436,22 @@
|
||||
#dhcp-option-force=211,30i
|
||||
|
||||
# Set the boot filename for netboot/PXE. You will only need
|
||||
# this is you want to boot machines over the network and you will need
|
||||
# a TFTP server; either dnsmasq's built in TFTP server or an
|
||||
# this if you want to boot machines over the network and you will need
|
||||
# a TFTP server; either dnsmasq's built-in TFTP server or an
|
||||
# external one. (See below for how to enable the TFTP server.)
|
||||
#dhcp-boot=pxelinux.0
|
||||
|
||||
# The same as above, but use custom tftp-server instead machine running dnsmasq
|
||||
#dhcp-boot=pxelinux,server.name,192.168.1.100
|
||||
|
||||
# Boot for Etherboot gPXE. The idea is to send two different
|
||||
# filenames, the first loads gPXE, and the second tells gPXE what to
|
||||
# load. The dhcp-match sets the gpxe tag for requests from gPXE.
|
||||
#dhcp-match=set:gpxe,175 # gPXE sends a 175 option.
|
||||
#dhcp-boot=tag:!gpxe,undionly.kpxe
|
||||
#dhcp-boot=mybootimage
|
||||
# Boot for iPXE. The idea is to send two different
|
||||
# filenames, the first loads iPXE, and the second tells iPXE what to
|
||||
# load. The dhcp-match sets the ipxe tag for requests from iPXE.
|
||||
#dhcp-boot=undionly.kpxe
|
||||
#dhcp-match=set:ipxe,175 # iPXE sends a 175 option.
|
||||
#dhcp-boot=tag:ipxe,http://boot.ipxe.org/demo/boot.php
|
||||
|
||||
# Encapsulated options for Etherboot gPXE. All the options are
|
||||
# Encapsulated options for iPXE. All the options are
|
||||
# encapsulated within option 175
|
||||
#dhcp-option=encap:175, 1, 5b # priority code
|
||||
#dhcp-option=encap:175, 176, 1b # no-proxydhcp
|
||||
@@ -547,6 +547,14 @@
|
||||
# http://www.isc.org/files/auth.html
|
||||
#dhcp-authoritative
|
||||
|
||||
# Set the DHCP server to enable DHCPv4 Rapid Commit Option per RFC 4039.
|
||||
# In this mode it will respond to a DHCPDISCOVER message including a Rapid Commit
|
||||
# option with a DHCPACK including a Rapid Commit option and fully committed address
|
||||
# and configuration information. This must only be enabled if either the server is
|
||||
# the only server for the subnet, or multiple servers are present and they each
|
||||
# commit a binding for all clients.
|
||||
#dhcp-rapid-commit
|
||||
|
||||
# Run an executable when a DHCP lease is created or destroyed.
|
||||
# The arguments sent to the script are "add" or "del",
|
||||
# then the MAC address, the IP address and finally the hostname
|
||||
|
||||
4
doc.html
4
doc.html
@@ -66,6 +66,10 @@ the repo, or get a copy using git protocol with the command
|
||||
|
||||
<PRE><TT>git clone git://thekelleys.org.uk/dnsmasq.git </TT></PRE>
|
||||
|
||||
or
|
||||
|
||||
<PRE><TT>git clone http://thekelleys.org.uk/git/dnsmasq.git </TT></PRE>
|
||||
|
||||
<H2>License.</H2>
|
||||
Dnsmasq is distributed under the GPL, version 2 or version 3 at your discretion. See the files COPYING and COPYING-v3 in the distribution
|
||||
for details.
|
||||
|
||||
@@ -182,7 +182,8 @@ OS: this was the default behaviour in versions prior to 2.43.
|
||||
Do not use ports less than that given as source for outbound DNS
|
||||
queries. Dnsmasq picks random ports as source for outbound queries:
|
||||
when this option is given, the ports used will always to larger
|
||||
than that specified. Useful for systems behind firewalls.
|
||||
than that specified. Useful for systems behind firewalls. If not specified,
|
||||
defaults to 1024.
|
||||
.TP
|
||||
.B --max-port=<port>
|
||||
Use ports lower than that given as source for outbound DNS queries.
|
||||
@@ -241,7 +242,7 @@ configuration, indeed
|
||||
.B --auth-server
|
||||
will override these and provide a different DNS service on the
|
||||
specified interface. The <domain> is the "glue record". It should
|
||||
resolve in the global DNS to a A and/or AAAA record which points to
|
||||
resolve in the global DNS to an 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.
|
||||
@@ -464,7 +465,7 @@ is a synonym for
|
||||
.B server
|
||||
to make configuration files clearer in this case.
|
||||
|
||||
IPv6 addresses may include a %interface scope-id, eg
|
||||
IPv6 addresses may include an %interface scope-id, eg
|
||||
fe80::202:a412:4512:7bbf%eth0.
|
||||
|
||||
The optional string after the @ character tells dnsmasq how to set the source of
|
||||
@@ -597,7 +598,7 @@ hosts files), from DHCP, from --interface-name or from another
|
||||
.B --cname.
|
||||
If the target does not satisfy this
|
||||
criteria, the whole cname is ignored. The cname must be unique, but it
|
||||
is permissable to have more than one cname pointing to the same target. Indeed
|
||||
is permissible to have more than one cname pointing to the same target. Indeed
|
||||
it's possible to declare multiple cnames to a target in a single line, like so:
|
||||
.B --cname=cname1,cname2,target
|
||||
|
||||
@@ -625,13 +626,16 @@ address by repeating the flag; in that case the first instance is used
|
||||
for the reverse address-to-name mapping. Note that a name used in
|
||||
--interface-name may not appear in /etc/hosts.
|
||||
.TP
|
||||
.B --synth-domain=<domain>,<address range>[,<prefix>]
|
||||
.B --synth-domain=<domain>,<address range>[,<prefix>[*]]
|
||||
Create artificial A/AAAA and PTR records for an address range. The
|
||||
records use the address, with periods (or colons for IPv6) replaced
|
||||
with dashes.
|
||||
records either seqential numbers or the address, with periods (or colons for IPv6) replaced with dashes.
|
||||
|
||||
An example should make this clearer.
|
||||
.B --synth-domain=thekelleys.org.uk,192.168.0.0/24,internal-
|
||||
An examples should make this clearer. First sequential numbers.
|
||||
.B --synth-domain=thekelleys.org.uk,192.168.0.50,192.168.0.70,internal-*
|
||||
results in the name internal-0.thekelleys.org.uk. returning 192.168.0.50, internal-1.thekelleys.org.uk returning 192.168.0.51 and so on. (note the *) The same principle applies to IPv6 addresses (where the numbers may be very large). Reverse lookups from address to name behave as expected.
|
||||
|
||||
Second,
|
||||
.B --synth-domain=thekelleys.org.uk,192.168.0.0/24,internal- (no *)
|
||||
will result in a query for internal-192-168-0-56.thekelleys.org.uk returning
|
||||
192.168.0.56 and a reverse query vice versa. The same applies to IPv6,
|
||||
but IPv6 addresses may start with '::'
|
||||
@@ -641,7 +645,7 @@ configured a zero is added in front of the label. ::1 becomes 0--1.
|
||||
V4 mapped IPv6 addresses, which have a representation like ::ffff:1.2.3.4 are handled specially, and become like 0--ffff-1-2-3-4
|
||||
|
||||
The address range can be of the form
|
||||
<ip address>,<ip address> or <ip address>/<netmask>
|
||||
<ip address>,<ip address> or <ip address>/<netmask> in both forms of the option.
|
||||
.TP
|
||||
.B --add-mac[=base64|text]
|
||||
Add the MAC address of the requestor to DNS queries which are
|
||||
@@ -655,7 +659,7 @@ given for --add-subnet applies to --add-mac too. An alternative encoding of the
|
||||
MAC, as base64, is enabled by adding the "base64" parameter and a human-readable encoding of hex-and-colons is enabled by added the "text" parameter.
|
||||
.TP
|
||||
.B --add-cpe-id=<string>
|
||||
Add a arbitrary identifying string to o DNS queries which are
|
||||
Add an arbitrary identifying string to o DNS queries which are
|
||||
forwarded upstream.
|
||||
.TP
|
||||
.B --add-subnet[[=[<IPv4 address>/]<IPv4 prefix length>][,[<IPv6 address>/]<IPv6 prefix length>]]
|
||||
@@ -708,38 +712,41 @@ 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 means 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.
|
||||
answers and this means that 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
|
||||
validation. Typically these will be the DS record(s) for Zone Signing
|
||||
key(s) of the root zone,
|
||||
validation. Typically these will be the DS record(s) for Key Signing
|
||||
key(s) (KSK) of the root zone,
|
||||
but trust anchors for limited domains are also possible. The current
|
||||
root-zone trust anchors may be downloaded from https://data.iana.org/root-anchors/root-anchors.xml
|
||||
.TP
|
||||
.B --dnssec-check-unsigned
|
||||
As a default, dnsmasq does not check that unsigned DNS replies are
|
||||
legitimate: they are assumed to be valid and passed on (without the
|
||||
.B --dnssec-check-unsigned[=no]
|
||||
As a default, dnsmasq checks that unsigned DNS replies are
|
||||
legitimate: this entails possible extra queries even for the majority of DNS
|
||||
zones which are not, at the moment, signed. If
|
||||
.B --dnssec-check-unsigned=no
|
||||
appears in the configuration, then such replies they are assumed to be valid and passed on (without the
|
||||
"authentic data" bit set, of course). This does not protect against an
|
||||
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. See also the warning about upstream servers in the
|
||||
section on
|
||||
.B --dnssec
|
||||
fast.
|
||||
|
||||
Versions of dnsmasq prior to 2.80 defaulted to not checking unsigned replies, and used
|
||||
.B --dnssec-check-unsigned
|
||||
to switch this on. Such configurations will continue to work as before, but those which used the default of no checking will need to be altered to explicitly select no checking. The new default is because switching off checking for unsigned replies is inherently dangerous. Not only does it open the possiblity of forged replies, but it allows everything to appear to be working even when the upstream namesevers do not support DNSSEC, and in this case no DNSSEC validation at all is occuring.
|
||||
.TP
|
||||
.B --dnssec-no-timecheck
|
||||
DNSSEC signatures are only valid for specified time windows, and should be rejected outside those windows. This generates an
|
||||
interesting chicken-and-egg problem for machines which don't have a hardware real time clock. For these machines to determine the correct
|
||||
time typically requires use of NTP and therefore DNS, but validating DNS requires that the correct time is already known. Setting this flag
|
||||
removes the time-window checks (but not other DNSSEC validation.) only until the dnsmasq process receives SIGHUP. The intention is
|
||||
removes the time-window checks (but not other DNSSEC validation.) only until the dnsmasq process receives SIGINT. The intention is
|
||||
that dnsmasq should be started with this flag when the platform determines that reliable time is not currently available. As soon as
|
||||
reliable time is established, a SIGHUP should be sent to dnsmasq, which enables time checking, and purges the cache of DNS records
|
||||
which have not been throughly checked.
|
||||
reliable time is established, a SIGINT should be sent to dnsmasq, which enables time checking, and purges the cache of DNS records
|
||||
which have not been thoroughly checked.
|
||||
|
||||
Earlier versions of dnsmasq overloaded SIGHUP (which re-reads much configuration) to also enable time validation.
|
||||
|
||||
If dnsmasq is run in debug mode (-d flag) then SIGINT retains its usual meaning of terminating the dnsmasq process.
|
||||
.TP
|
||||
.B --dnssec-timestamp=<path>
|
||||
Enables an alternative way of checking the validity of the system time for DNSSEC (see --dnssec-no-timecheck). In this case, the
|
||||
@@ -1073,7 +1080,7 @@ in a dhcp-optsfile.
|
||||
This is equivalent to dhcp-hostsfile, except for the following. The path MUST be a
|
||||
directory, and not an individual file. Changed or new files within
|
||||
the directory are read automatically, without the need to send SIGHUP.
|
||||
If a file is deleted for changed after it has been read by dnsmasq, then the
|
||||
If a file is deleted or changed after it has been read by dnsmasq, then the
|
||||
host record it contained will remain until dnsmasq receives a SIGHUP, or
|
||||
is restarted; ie host records are only added dynamically.
|
||||
.TP
|
||||
@@ -1315,7 +1322,7 @@ Perform boolean operations on tags. Any tag appearing as set:<tag> is set if
|
||||
all the tags which appear as tag:<tag> are set, (or unset when tag:!<tag> is used)
|
||||
If no tag:<tag> appears set:<tag> tags are set unconditionally.
|
||||
Any number of set: and tag: forms may appear, in any order.
|
||||
Tag-if lines ares executed in order, so if the tag in tag:<tag> is a
|
||||
Tag-if lines are executed in order, so if the tag in tag:<tag> is a
|
||||
tag set by another
|
||||
.B tag-if,
|
||||
the line which sets the tag must precede the one which tests it.
|
||||
@@ -1444,6 +1451,13 @@ allows dnsmasq to rebuild its lease database without each client needing to
|
||||
reacquire a lease, if the database is lost. For DHCPv6 it sets the
|
||||
priority in replies to 255 (the maximum) instead of 0 (the minimum).
|
||||
.TP
|
||||
.B --dhcp-rapid-commit
|
||||
Enable DHCPv4 Rapid Commit Option specified in RFC 4039. When enabled, dnsmasq
|
||||
will respond to a DHCPDISCOVER message including a Rapid Commit
|
||||
option with a DHCPACK including a Rapid Commit option and fully committed
|
||||
address and configuration information. Should only be enabled if either the
|
||||
server is the only server for the subnet, or multiple servers are present and they each commit a binding for all clients.
|
||||
.TP
|
||||
.B --dhcp-alternate-port[=<server port>[,<client port>]]
|
||||
(IPv4 only) Change the ports used for DHCP from the default. If this option is
|
||||
given alone, without arguments, it changes the ports used for DHCP
|
||||
@@ -1691,13 +1705,17 @@ option also forces the leasechange script to be called on changes
|
||||
to the client-id and lease length and expiry time.
|
||||
.TP
|
||||
.B --bridge-interface=<interface>,<alias>[,<alias>]
|
||||
Treat DHCP (v4 and v6) request and IPv6 Router Solicit packets
|
||||
Treat DHCP (v4 and v6) requests and IPv6 Router Solicit packets
|
||||
arriving at any of the <alias> interfaces as if they had arrived at
|
||||
<interface>. This option allows dnsmasq to provide DHCP and RA
|
||||
service over unaddressed and unbridged Ethernet interfaces, e.g. on an
|
||||
OpenStack compute host where each such interface is a TAP interface to
|
||||
a VM, or as in "old style bridging" on BSD platforms. A trailing '*'
|
||||
wildcard can be used in each <alias>.
|
||||
|
||||
It is permissible to add more than one alias using more than one --bridge-interface option since
|
||||
--bridge-interface=int1,alias1,alias2 is exactly equivalent to
|
||||
--bridge-interface=int1,alias1 --bridge-interface=int1,alias2
|
||||
.TP
|
||||
.B \-s, --domain=<domain>[,<address range>[,local]]
|
||||
Specifies DNS domains for the DHCP server. Domains may be be given
|
||||
@@ -1979,7 +1997,7 @@ and
|
||||
|
||||
|
||||
.PP
|
||||
Dnsmasq is a DNS query forwarder: it it not capable of recursively
|
||||
Dnsmasq is a DNS query forwarder: it is not capable of recursively
|
||||
answering arbitrary queries starting from the root servers but
|
||||
forwards such queries to a fully recursive upstream DNS server which is
|
||||
typically provided by an ISP. By default, dnsmasq reads
|
||||
|
||||
387
po/pt_BR.po
387
po/pt_BR.po
File diff suppressed because it is too large
Load Diff
@@ -125,7 +125,7 @@ address of its ethernet card. For the former to work, a machine needs to know it
|
||||
requests a DHCP lease. For dhcpcd, the -h option specifies this. The
|
||||
names may be anything as far as DHCP is concerned, but dnsmasq adds
|
||||
some limitations. By default the names must no have a domain part, ie
|
||||
they must just be a alphanumeric name, without any dots. This is a
|
||||
they must just be alphanumeric names, without any dots. This is a
|
||||
security feature to stop a machine on your network telling DHCP that
|
||||
its name is "www.microsoft.com" and thereby grabbing traffic which
|
||||
shouldn't go to it. A domain part is only allowed by dnsmasq in DHCP machine names
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2017 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2018 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
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2017 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2018 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
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2017 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2018 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
|
||||
@@ -25,7 +25,7 @@ static void blockdata_expand(int n)
|
||||
{
|
||||
struct blockdata *new = whine_malloc(n * sizeof(struct blockdata));
|
||||
|
||||
if (n > 0 && new)
|
||||
if (new)
|
||||
{
|
||||
int i;
|
||||
|
||||
@@ -49,7 +49,7 @@ void blockdata_init(void)
|
||||
|
||||
/* Note that daemon->cachesize is enforced to have non-zero size if OPT_DNSSEC_VALID is set */
|
||||
if (option_bool(OPT_DNSSEC_VALID))
|
||||
blockdata_expand((daemon->cachesize * 100) / sizeof(struct blockdata));
|
||||
blockdata_expand(daemon->cachesize);
|
||||
}
|
||||
|
||||
void blockdata_report(void)
|
||||
@@ -100,6 +100,7 @@ struct blockdata *blockdata_alloc(char *data, size_t len)
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void blockdata_free(struct blockdata *blocks)
|
||||
{
|
||||
struct blockdata *tmp;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2017 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2018 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
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2017 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2018 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
|
||||
@@ -45,6 +45,7 @@ static const struct {
|
||||
{ 24, "SIG" },
|
||||
{ 25, "KEY" },
|
||||
{ 28, "AAAA" },
|
||||
{ 29, "LOC" },
|
||||
{ 33, "SRV" },
|
||||
{ 35, "NAPTR" },
|
||||
{ 36, "KX" },
|
||||
@@ -57,6 +58,10 @@ static const struct {
|
||||
{ 47, "NSEC" },
|
||||
{ 48, "DNSKEY" },
|
||||
{ 50, "NSEC3" },
|
||||
{ 51, "NSEC3PARAM" },
|
||||
{ 52, "TLSA" },
|
||||
{ 53, "SMIMEA" },
|
||||
{ 55, "HIP" },
|
||||
{ 249, "TKEY" },
|
||||
{ 250, "TSIG" },
|
||||
{ 251, "IXFR" },
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2017 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2018 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
|
||||
@@ -26,6 +26,7 @@
|
||||
#define TIMEOUT 10 /* drop UDP queries after TIMEOUT seconds */
|
||||
#define FORWARD_TEST 50 /* try all servers every 50 queries */
|
||||
#define FORWARD_TIME 20 /* or 20 seconds */
|
||||
#define UDP_TEST_TIME 60 /* How often to reset our idea of max packet size. */
|
||||
#define SERVERS_LOGGED 30 /* Only log this many servers when logging state */
|
||||
#define LOCALS_LOGGED 8 /* Only log this many local addresses when logging state */
|
||||
#define RANDOM_SOCKS 64 /* max simultaneous random ports */
|
||||
@@ -136,9 +137,6 @@ NO_INOTIFY
|
||||
otherwise be enabled automatically (HAVE_IPV6, >2Gb file sizes) or
|
||||
which are enabled by default in the distributed source tree. Building dnsmasq
|
||||
with something like "make COPTS=-DNO_SCRIPT" will do the trick.
|
||||
|
||||
NO_NETTLE_ECC
|
||||
Don't include the ECDSA cypher in DNSSEC validation. Needed for older Nettle versions.
|
||||
NO_GMP
|
||||
Don't use and link against libgmp, Useful if nettle is built with --enable-mini-gmp.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2017 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2018 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
|
||||
|
||||
460
src/crypto.c
Normal file
460
src/crypto.c
Normal file
@@ -0,0 +1,460 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 dated June, 1991, or
|
||||
(at your option) version 3 dated 29 June, 2007.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "dnsmasq.h"
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
|
||||
#include <nettle/rsa.h>
|
||||
#include <nettle/dsa.h>
|
||||
#include <nettle/ecdsa.h>
|
||||
#include <nettle/ecc-curve.h>
|
||||
#include <nettle/eddsa.h>
|
||||
#include <nettle/nettle-meta.h>
|
||||
#include <nettle/bignum.h>
|
||||
|
||||
/* Implement a "hash-function" to the nettle API, which simply returns
|
||||
the input data, concatenated into a single, statically maintained, buffer.
|
||||
|
||||
Used for the EdDSA sigs, which operate on the whole message, rather
|
||||
than a digest. */
|
||||
|
||||
struct null_hash_digest
|
||||
{
|
||||
uint8_t *buff;
|
||||
size_t len;
|
||||
};
|
||||
|
||||
struct null_hash_ctx
|
||||
{
|
||||
size_t len;
|
||||
};
|
||||
|
||||
static size_t null_hash_buff_sz = 0;
|
||||
static uint8_t *null_hash_buff = NULL;
|
||||
#define BUFF_INCR 128
|
||||
|
||||
static void null_hash_init(void *ctx)
|
||||
{
|
||||
((struct null_hash_ctx *)ctx)->len = 0;
|
||||
}
|
||||
|
||||
static void null_hash_update(void *ctxv, size_t length, const uint8_t *src)
|
||||
{
|
||||
struct null_hash_ctx *ctx = ctxv;
|
||||
size_t new_len = ctx->len + length;
|
||||
|
||||
if (new_len > null_hash_buff_sz)
|
||||
{
|
||||
uint8_t *new;
|
||||
|
||||
if (!(new = whine_malloc(new_len + BUFF_INCR)))
|
||||
return;
|
||||
|
||||
if (null_hash_buff)
|
||||
{
|
||||
if (ctx->len != 0)
|
||||
memcpy(new, null_hash_buff, ctx->len);
|
||||
free(null_hash_buff);
|
||||
}
|
||||
|
||||
null_hash_buff_sz = new_len + BUFF_INCR;
|
||||
null_hash_buff = new;
|
||||
}
|
||||
|
||||
memcpy(null_hash_buff + ctx->len, src, length);
|
||||
ctx->len += length;
|
||||
}
|
||||
|
||||
|
||||
static void null_hash_digest(void *ctx, size_t length, uint8_t *dst)
|
||||
{
|
||||
(void)length;
|
||||
|
||||
((struct null_hash_digest *)dst)->buff = null_hash_buff;
|
||||
((struct null_hash_digest *)dst)->len = ((struct null_hash_ctx *)ctx)->len;
|
||||
}
|
||||
|
||||
static struct nettle_hash null_hash = {
|
||||
"null_hash",
|
||||
sizeof(struct null_hash_ctx),
|
||||
sizeof(struct null_hash_digest),
|
||||
0,
|
||||
(nettle_hash_init_func *) null_hash_init,
|
||||
(nettle_hash_update_func *) null_hash_update,
|
||||
(nettle_hash_digest_func *) null_hash_digest
|
||||
};
|
||||
|
||||
/* Find pointer to correct hash function in nettle library */
|
||||
const struct nettle_hash *hash_find(char *name)
|
||||
{
|
||||
if (!name)
|
||||
return NULL;
|
||||
|
||||
/* We provide a "null" hash which returns the input data as digest. */
|
||||
if (strcmp(null_hash.name, name) == 0)
|
||||
return &null_hash;
|
||||
|
||||
/* libnettle >= 3.4 provides nettle_lookup_hash() which avoids nasty ABI
|
||||
incompatibilities if sizeof(nettle_hashes) changes between library
|
||||
versions. It also #defines nettle_hashes, so use that to tell
|
||||
if we have the new facilities. */
|
||||
|
||||
#ifdef nettle_hashes
|
||||
return nettle_lookup_hash(name);
|
||||
#else
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; nettle_hashes[i]; i++)
|
||||
if (strcmp(nettle_hashes[i]->name, name) == 0)
|
||||
return nettle_hashes[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* expand ctx and digest memory allocations if necessary and init hash function */
|
||||
int hash_init(const struct nettle_hash *hash, void **ctxp, unsigned char **digestp)
|
||||
{
|
||||
static void *ctx = NULL;
|
||||
static unsigned char *digest = NULL;
|
||||
static unsigned int ctx_sz = 0;
|
||||
static unsigned int digest_sz = 0;
|
||||
|
||||
void *new;
|
||||
|
||||
if (ctx_sz < hash->context_size)
|
||||
{
|
||||
if (!(new = whine_malloc(hash->context_size)))
|
||||
return 0;
|
||||
if (ctx)
|
||||
free(ctx);
|
||||
ctx = new;
|
||||
ctx_sz = hash->context_size;
|
||||
}
|
||||
|
||||
if (digest_sz < hash->digest_size)
|
||||
{
|
||||
if (!(new = whine_malloc(hash->digest_size)))
|
||||
return 0;
|
||||
if (digest)
|
||||
free(digest);
|
||||
digest = new;
|
||||
digest_sz = hash->digest_size;
|
||||
}
|
||||
|
||||
*ctxp = ctx;
|
||||
*digestp = digest;
|
||||
|
||||
hash->init(ctx);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int dnsmasq_rsa_verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
|
||||
unsigned char *digest, size_t digest_len, int algo)
|
||||
{
|
||||
unsigned char *p;
|
||||
size_t exp_len;
|
||||
|
||||
static struct rsa_public_key *key = NULL;
|
||||
static mpz_t sig_mpz;
|
||||
|
||||
(void)digest_len;
|
||||
|
||||
if (key == NULL)
|
||||
{
|
||||
if (!(key = whine_malloc(sizeof(struct rsa_public_key))))
|
||||
return 0;
|
||||
|
||||
nettle_rsa_public_key_init(key);
|
||||
mpz_init(sig_mpz);
|
||||
}
|
||||
|
||||
if ((key_len < 3) || !(p = blockdata_retrieve(key_data, key_len, NULL)))
|
||||
return 0;
|
||||
|
||||
key_len--;
|
||||
if ((exp_len = *p++) == 0)
|
||||
{
|
||||
GETSHORT(exp_len, p);
|
||||
key_len -= 2;
|
||||
}
|
||||
|
||||
if (exp_len >= key_len)
|
||||
return 0;
|
||||
|
||||
key->size = key_len - exp_len;
|
||||
mpz_import(key->e, exp_len, 1, 1, 0, 0, p);
|
||||
mpz_import(key->n, key->size, 1, 1, 0, 0, p + exp_len);
|
||||
|
||||
mpz_import(sig_mpz, sig_len, 1, 1, 0, 0, sig);
|
||||
|
||||
switch (algo)
|
||||
{
|
||||
case 1:
|
||||
return nettle_rsa_md5_verify_digest(key, digest, sig_mpz);
|
||||
case 5: case 7:
|
||||
return nettle_rsa_sha1_verify_digest(key, digest, sig_mpz);
|
||||
case 8:
|
||||
return nettle_rsa_sha256_verify_digest(key, digest, sig_mpz);
|
||||
case 10:
|
||||
return nettle_rsa_sha512_verify_digest(key, digest, sig_mpz);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dnsmasq_dsa_verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
|
||||
unsigned char *digest, size_t digest_len, int algo)
|
||||
{
|
||||
unsigned char *p;
|
||||
unsigned int t;
|
||||
|
||||
static mpz_t y;
|
||||
static struct dsa_params *params = NULL;
|
||||
static struct dsa_signature *sig_struct;
|
||||
|
||||
(void)digest_len;
|
||||
|
||||
if (params == NULL)
|
||||
{
|
||||
if (!(sig_struct = whine_malloc(sizeof(struct dsa_signature))) ||
|
||||
!(params = whine_malloc(sizeof(struct dsa_params))))
|
||||
return 0;
|
||||
|
||||
mpz_init(y);
|
||||
nettle_dsa_params_init(params);
|
||||
nettle_dsa_signature_init(sig_struct);
|
||||
}
|
||||
|
||||
if ((sig_len < 41) || !(p = blockdata_retrieve(key_data, key_len, NULL)))
|
||||
return 0;
|
||||
|
||||
t = *p++;
|
||||
|
||||
if (key_len < (213 + (t * 24)))
|
||||
return 0;
|
||||
|
||||
mpz_import(params->q, 20, 1, 1, 0, 0, p); p += 20;
|
||||
mpz_import(params->p, 64 + (t*8), 1, 1, 0, 0, p); p += 64 + (t*8);
|
||||
mpz_import(params->g, 64 + (t*8), 1, 1, 0, 0, p); p += 64 + (t*8);
|
||||
mpz_import(y, 64 + (t*8), 1, 1, 0, 0, p); p += 64 + (t*8);
|
||||
|
||||
mpz_import(sig_struct->r, 20, 1, 1, 0, 0, sig+1);
|
||||
mpz_import(sig_struct->s, 20, 1, 1, 0, 0, sig+21);
|
||||
|
||||
(void)algo;
|
||||
|
||||
return nettle_dsa_verify(params, y, digest_len, digest, sig_struct);
|
||||
}
|
||||
|
||||
static int dnsmasq_ecdsa_verify(struct blockdata *key_data, unsigned int key_len,
|
||||
unsigned char *sig, size_t sig_len,
|
||||
unsigned char *digest, size_t digest_len, int algo)
|
||||
{
|
||||
unsigned char *p;
|
||||
unsigned int t;
|
||||
struct ecc_point *key;
|
||||
|
||||
static struct ecc_point *key_256 = NULL, *key_384 = NULL;
|
||||
static mpz_t x, y;
|
||||
static struct dsa_signature *sig_struct;
|
||||
|
||||
if (!sig_struct)
|
||||
{
|
||||
if (!(sig_struct = whine_malloc(sizeof(struct dsa_signature))))
|
||||
return 0;
|
||||
|
||||
nettle_dsa_signature_init(sig_struct);
|
||||
mpz_init(x);
|
||||
mpz_init(y);
|
||||
}
|
||||
|
||||
switch (algo)
|
||||
{
|
||||
case 13:
|
||||
if (!key_256)
|
||||
{
|
||||
if (!(key_256 = whine_malloc(sizeof(struct ecc_point))))
|
||||
return 0;
|
||||
|
||||
nettle_ecc_point_init(key_256, &nettle_secp_256r1);
|
||||
}
|
||||
|
||||
key = key_256;
|
||||
t = 32;
|
||||
break;
|
||||
|
||||
case 14:
|
||||
if (!key_384)
|
||||
{
|
||||
if (!(key_384 = whine_malloc(sizeof(struct ecc_point))))
|
||||
return 0;
|
||||
|
||||
nettle_ecc_point_init(key_384, &nettle_secp_384r1);
|
||||
}
|
||||
|
||||
key = key_384;
|
||||
t = 48;
|
||||
break;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (sig_len != 2*t || key_len != 2*t ||
|
||||
!(p = blockdata_retrieve(key_data, key_len, NULL)))
|
||||
return 0;
|
||||
|
||||
mpz_import(x, t , 1, 1, 0, 0, p);
|
||||
mpz_import(y, t , 1, 1, 0, 0, p + t);
|
||||
|
||||
if (!ecc_point_set(key, x, y))
|
||||
return 0;
|
||||
|
||||
mpz_import(sig_struct->r, t, 1, 1, 0, 0, sig);
|
||||
mpz_import(sig_struct->s, t, 1, 1, 0, 0, sig + t);
|
||||
|
||||
return nettle_ecdsa_verify(key, digest_len, digest, sig_struct);
|
||||
}
|
||||
|
||||
static int dnsmasq_eddsa_verify(struct blockdata *key_data, unsigned int key_len,
|
||||
unsigned char *sig, size_t sig_len,
|
||||
unsigned char *digest, size_t digest_len, int algo)
|
||||
{
|
||||
unsigned char *p;
|
||||
|
||||
if (key_len != ED25519_KEY_SIZE ||
|
||||
sig_len != ED25519_SIGNATURE_SIZE ||
|
||||
digest_len != sizeof(struct null_hash_digest) ||
|
||||
!(p = blockdata_retrieve(key_data, key_len, NULL)))
|
||||
return 0;
|
||||
|
||||
/* The "digest" returned by the null_hash function is simply a struct null_hash_digest
|
||||
which has a pointer to the actual data and a length, because the buffer
|
||||
may need to be extended during "hashing". */
|
||||
|
||||
switch (algo)
|
||||
{
|
||||
case 15:
|
||||
return ed25519_sha512_verify(p,
|
||||
((struct null_hash_digest *)digest)->len,
|
||||
((struct null_hash_digest *)digest)->buff,
|
||||
sig);
|
||||
case 16:
|
||||
/* Ed448 when available */
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int (*verify_func(int algo))(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
|
||||
unsigned char *digest, size_t digest_len, int algo)
|
||||
{
|
||||
|
||||
/* Enure at runtime that we have support for this digest */
|
||||
if (!hash_find(algo_digest_name(algo)))
|
||||
return NULL;
|
||||
|
||||
/* This switch defines which sig algorithms we support, can't introspect Nettle for that. */
|
||||
switch (algo)
|
||||
{
|
||||
case 1: case 5: case 7: case 8: case 10:
|
||||
return dnsmasq_rsa_verify;
|
||||
|
||||
case 3: case 6:
|
||||
return dnsmasq_dsa_verify;
|
||||
|
||||
case 13: case 14:
|
||||
return dnsmasq_ecdsa_verify;
|
||||
|
||||
case 15: case 16:
|
||||
return dnsmasq_eddsa_verify;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
|
||||
unsigned char *digest, size_t digest_len, int algo)
|
||||
{
|
||||
|
||||
int (*func)(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
|
||||
unsigned char *digest, size_t digest_len, int algo);
|
||||
|
||||
func = verify_func(algo);
|
||||
|
||||
if (!func)
|
||||
return 0;
|
||||
|
||||
return (*func)(key_data, key_len, sig, sig_len, digest, digest_len, algo);
|
||||
}
|
||||
|
||||
/* Note the ds_digest_name(), algo_digest_name() and nsec3_digest_name()
|
||||
define which algo numbers we support. If algo_digest_name() returns
|
||||
non-NULL for an algorithm number, we assume that algorithm is
|
||||
supported by verify(). */
|
||||
|
||||
/* http://www.iana.org/assignments/ds-rr-types/ds-rr-types.xhtml */
|
||||
char *ds_digest_name(int digest)
|
||||
{
|
||||
switch (digest)
|
||||
{
|
||||
case 1: return "sha1";
|
||||
case 2: return "sha256";
|
||||
case 3: return "gosthash94";
|
||||
case 4: return "sha384";
|
||||
default: return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* http://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml */
|
||||
char *algo_digest_name(int algo)
|
||||
{
|
||||
switch (algo)
|
||||
{
|
||||
case 1: return NULL; /* RSA/MD5 - Must Not Implement. RFC 6944 para 2.3. */
|
||||
case 2: return NULL; /* Diffie-Hellman */
|
||||
case 3: return "sha1"; /* DSA/SHA1 */
|
||||
case 5: return "sha1"; /* RSA/SHA1 */
|
||||
case 6: return "sha1"; /* DSA-NSEC3-SHA1 */
|
||||
case 7: return "sha1"; /* RSASHA1-NSEC3-SHA1 */
|
||||
case 8: return "sha256"; /* RSA/SHA-256 */
|
||||
case 10: return "sha512"; /* RSA/SHA-512 */
|
||||
case 12: return NULL; /* ECC-GOST */
|
||||
case 13: return "sha256"; /* ECDSAP256SHA256 */
|
||||
case 14: return "sha384"; /* ECDSAP384SHA384 */
|
||||
case 15: return "null_hash"; /* ED25519 */
|
||||
case 16: return NULL; /* ED448 */
|
||||
default: return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* http://www.iana.org/assignments/dnssec-nsec3-parameters/dnssec-nsec3-parameters.xhtml */
|
||||
char *nsec3_digest_name(int digest)
|
||||
{
|
||||
switch (digest)
|
||||
{
|
||||
case 1: return "sha1";
|
||||
default: return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2017 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2018 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
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2017 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2018 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
|
||||
@@ -485,11 +485,8 @@ char *whichdevice(void)
|
||||
|
||||
void bindtodevice(char *device, int fd)
|
||||
{
|
||||
struct ifreq ifr;
|
||||
|
||||
strcpy(ifr.ifr_name, device);
|
||||
/* only allowed by root. */
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(ifr)) == -1 &&
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, device, IFNAMSIZ) == -1 &&
|
||||
errno != EPERM)
|
||||
die(_("failed to set SO_BINDTODEVICE on DHCP socket: %s"), NULL, EC_BADNET);
|
||||
}
|
||||
@@ -559,6 +556,7 @@ static const struct opttab_t {
|
||||
{ "nntp-server", 71, OT_ADDR_LIST },
|
||||
{ "irc-server", 74, OT_ADDR_LIST },
|
||||
{ "user-class", 77, 0 },
|
||||
{ "rapid-commit", 80, 0 },
|
||||
{ "FQDN", 81, OT_INTERNAL },
|
||||
{ "agent-id", 82, OT_INTERNAL },
|
||||
{ "client-arch", 93, 2 | OT_DEC },
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2017 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2018 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,6 +54,7 @@
|
||||
#define OPTION_SNAME 66
|
||||
#define OPTION_FILENAME 67
|
||||
#define OPTION_USER_CLASS 77
|
||||
#define OPTION_RAPID_COMMIT 80
|
||||
#define OPTION_CLIENT_FQDN 81
|
||||
#define OPTION_AGENT_ID 82
|
||||
#define OPTION_ARCH 93
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2017 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2018 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
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2017 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2018 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
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2017 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2018 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
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2017 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2018 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
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
#define NAMESERVER_PORT 53
|
||||
#define TFTP_PORT 69
|
||||
#define MIN_PORT 1024 /* first non-reserved port */
|
||||
#define MAX_PORT 65535u
|
||||
|
||||
#define IN6ADDRSZ 16
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2017 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2018 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
|
||||
@@ -48,6 +48,7 @@ int main (int argc, char **argv)
|
||||
long i, max_fd = sysconf(_SC_OPEN_MAX);
|
||||
char *baduser = NULL;
|
||||
int log_err;
|
||||
int chown_warn = 0;
|
||||
#if defined(HAVE_LINUX_NETWORK)
|
||||
cap_user_header_t hdr = NULL;
|
||||
cap_user_data_t data = NULL;
|
||||
@@ -77,7 +78,8 @@ int main (int argc, char **argv)
|
||||
sigaction(SIGTERM, &sigact, NULL);
|
||||
sigaction(SIGALRM, &sigact, NULL);
|
||||
sigaction(SIGCHLD, &sigact, NULL);
|
||||
|
||||
sigaction(SIGINT, &sigact, NULL);
|
||||
|
||||
/* ignore SIGPIPE */
|
||||
sigact.sa_handler = SIG_IGN;
|
||||
sigaction(SIGPIPE, &sigact, NULL);
|
||||
@@ -118,6 +120,9 @@ int main (int argc, char **argv)
|
||||
daemon->namebuff = safe_malloc(MAXDNAME * 2);
|
||||
daemon->keyname = safe_malloc(MAXDNAME * 2);
|
||||
daemon->workspacename = safe_malloc(MAXDNAME * 2);
|
||||
/* one char flag per possible RR in answer section (may get extended). */
|
||||
daemon->rr_status_sz = 64;
|
||||
daemon->rr_status = safe_malloc(daemon->rr_status_sz);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -220,9 +225,6 @@ int main (int argc, char **argv)
|
||||
die(_("loop detection not available: set HAVE_LOOP in src/config.h"), NULL, EC_BADCONF);
|
||||
#endif
|
||||
|
||||
if (daemon->max_port != MAX_PORT && daemon->min_port == 0)
|
||||
daemon->min_port = 1024u;
|
||||
|
||||
if (daemon->max_port < daemon->min_port)
|
||||
die(_("max_port cannot be smaller than min_port"), NULL, EC_BADCONF);
|
||||
|
||||
@@ -358,7 +360,8 @@ int main (int argc, char **argv)
|
||||
}
|
||||
|
||||
#ifdef HAVE_INOTIFY
|
||||
if (daemon->port != 0 || daemon->dhcp || daemon->doing_dhcp6)
|
||||
if ((daemon->port != 0 || daemon->dhcp || daemon->doing_dhcp6)
|
||||
&& (!option_bool(OPT_NO_RESOLV) || daemon->dynamic_dirs))
|
||||
inotify_dnsmasq_init();
|
||||
else
|
||||
daemon->inotifyfd = -1;
|
||||
@@ -386,10 +389,12 @@ int main (int argc, char **argv)
|
||||
daemon->scriptuser &&
|
||||
(daemon->lease_change_command || daemon->luascript))
|
||||
{
|
||||
if ((ent_pw = getpwnam(daemon->scriptuser)))
|
||||
struct passwd *scr_pw;
|
||||
|
||||
if ((scr_pw = getpwnam(daemon->scriptuser)))
|
||||
{
|
||||
script_uid = ent_pw->pw_uid;
|
||||
script_gid = ent_pw->pw_gid;
|
||||
script_uid = scr_pw->pw_uid;
|
||||
script_gid = scr_pw->pw_gid;
|
||||
}
|
||||
else
|
||||
baduser = daemon->scriptuser;
|
||||
@@ -537,9 +542,18 @@ int main (int argc, char **argv)
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We're still running as root here. Change the ownership of the PID file
|
||||
to the user we will be running as. Note that this is not to allow
|
||||
us to delete the file, since that depends on the permissions
|
||||
of the directory containing the file. That directory will
|
||||
need to by owned by the dnsmasq user, and the ownership of the
|
||||
file has to match, to keep systemd >273 happy. */
|
||||
if (getuid() == 0 && ent_pw && ent_pw->pw_uid != 0 && fchown(fd, ent_pw->pw_uid, ent_pw->pw_gid) == -1)
|
||||
chown_warn = errno;
|
||||
|
||||
if (!read_write(fd, (unsigned char *)daemon->namebuff, strlen(daemon->namebuff), 0))
|
||||
err = 1;
|
||||
else
|
||||
else
|
||||
{
|
||||
while (retry_send(close(fd)));
|
||||
if (errno != 0)
|
||||
@@ -726,6 +740,9 @@ int main (int argc, char **argv)
|
||||
}
|
||||
|
||||
my_syslog(LOG_INFO, _("compile time options: %s"), compile_opts);
|
||||
|
||||
if (chown_warn != 0)
|
||||
my_syslog(LOG_WARNING, "chown of PID file %s failed: %s", daemon->runfile, strerror(chown_warn));
|
||||
|
||||
#ifdef HAVE_DBUS
|
||||
if (option_bool(OPT_DBUS))
|
||||
@@ -751,11 +768,14 @@ int main (int argc, char **argv)
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
my_syslog(LOG_INFO, _("DNSSEC validation enabled"));
|
||||
if (option_bool(OPT_DNSSEC_IGN_NS))
|
||||
my_syslog(LOG_INFO, _("DNSSEC validation enabled but all unsigned answers are trusted"));
|
||||
else
|
||||
my_syslog(LOG_INFO, _("DNSSEC validation enabled"));
|
||||
|
||||
daemon->dnssec_no_time_check = option_bool(OPT_DNSSEC_TIME);
|
||||
if (option_bool(OPT_DNSSEC_TIME) && !daemon->back_to_the_future)
|
||||
my_syslog(LOG_INFO, _("DNSSEC signature timestamps not checked until first cache reload"));
|
||||
my_syslog(LOG_INFO, _("DNSSEC signature timestamps not checked until receipt of SIGINT"));
|
||||
|
||||
if (rc == 1)
|
||||
my_syslog(LOG_INFO, _("DNSSEC signature timestamps not checked until system time valid"));
|
||||
@@ -1079,7 +1099,7 @@ static void sig_handler(int sig)
|
||||
{
|
||||
/* ignore anything other than TERM during startup
|
||||
and in helper proc. (helper ignore TERM too) */
|
||||
if (sig == SIGTERM)
|
||||
if (sig == SIGTERM || sig == SIGINT)
|
||||
exit(EC_MISC);
|
||||
}
|
||||
else if (pid != getpid())
|
||||
@@ -1105,6 +1125,15 @@ static void sig_handler(int sig)
|
||||
event = EVENT_DUMP;
|
||||
else if (sig == SIGUSR2)
|
||||
event = EVENT_REOPEN;
|
||||
else if (sig == SIGINT)
|
||||
{
|
||||
/* Handle SIGINT normally in debug mode, so
|
||||
ctrl-c continues to operate. */
|
||||
if (option_bool(OPT_DEBUG))
|
||||
exit(EC_MISC);
|
||||
else
|
||||
event = EVENT_TIME;
|
||||
}
|
||||
else
|
||||
return;
|
||||
|
||||
@@ -1187,31 +1216,40 @@ static void fatal_event(struct event_desc *ev, char *msg)
|
||||
|
||||
case EVENT_FORK_ERR:
|
||||
die(_("cannot fork into background: %s"), NULL, EC_MISC);
|
||||
|
||||
|
||||
/* fall through */
|
||||
case EVENT_PIPE_ERR:
|
||||
die(_("failed to create helper: %s"), NULL, EC_MISC);
|
||||
|
||||
|
||||
/* fall through */
|
||||
case EVENT_CAP_ERR:
|
||||
die(_("setting capabilities failed: %s"), NULL, EC_MISC);
|
||||
|
||||
/* fall through */
|
||||
case EVENT_USER_ERR:
|
||||
die(_("failed to change user-id to %s: %s"), msg, EC_MISC);
|
||||
|
||||
/* fall through */
|
||||
case EVENT_GROUP_ERR:
|
||||
die(_("failed to change group-id to %s: %s"), msg, EC_MISC);
|
||||
|
||||
|
||||
/* fall through */
|
||||
case EVENT_PIDFILE:
|
||||
die(_("failed to open pidfile %s: %s"), msg, EC_FILE);
|
||||
|
||||
/* fall through */
|
||||
case EVENT_LOG_ERR:
|
||||
die(_("cannot open log %s: %s"), msg, EC_FILE);
|
||||
|
||||
|
||||
/* fall through */
|
||||
case EVENT_LUA_ERR:
|
||||
die(_("failed to load Lua script: %s"), msg, EC_MISC);
|
||||
|
||||
/* fall through */
|
||||
case EVENT_TFTP_ERR:
|
||||
die(_("TFTP directory %s inaccessible: %s"), msg, EC_FILE);
|
||||
|
||||
|
||||
/* fall through */
|
||||
case EVENT_TIME_ERR:
|
||||
die(_("cannot create timestamp file %s: %s" ), msg, EC_BADCONF);
|
||||
}
|
||||
@@ -1232,14 +1270,7 @@ static void async_event(int pipe, time_t now)
|
||||
{
|
||||
case EVENT_RELOAD:
|
||||
daemon->soa_sn++; /* Bump zone serial, as it may have changed. */
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (daemon->dnssec_no_time_check && option_bool(OPT_DNSSEC_VALID) && option_bool(OPT_DNSSEC_TIME))
|
||||
{
|
||||
my_syslog(LOG_INFO, _("now checking DNSSEC signature timestamps"));
|
||||
daemon->dnssec_no_time_check = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* fall through */
|
||||
|
||||
case EVENT_INIT:
|
||||
@@ -1348,6 +1379,17 @@ static void async_event(int pipe, time_t now)
|
||||
poll_resolv(0, 1, now);
|
||||
break;
|
||||
|
||||
case EVENT_TIME:
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (daemon->dnssec_no_time_check && option_bool(OPT_DNSSEC_VALID) && option_bool(OPT_DNSSEC_TIME))
|
||||
{
|
||||
my_syslog(LOG_INFO, _("now checking DNSSEC signature timestamps"));
|
||||
daemon->dnssec_no_time_check = 0;
|
||||
clear_cache_and_reload(now);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
|
||||
case EVENT_TERM:
|
||||
/* Knock all our children on the head. */
|
||||
for (i = 0; i < MAX_PROCS; i++)
|
||||
@@ -1472,9 +1514,6 @@ void clear_cache_and_reload(time_t now)
|
||||
if (option_bool(OPT_ETHERS))
|
||||
dhcp_read_ethers();
|
||||
reread_dhcp();
|
||||
#ifdef HAVE_INOTIFY
|
||||
set_dynamic_inotify(AH_DHCP_HST | AH_DHCP_OPT, 0, NULL, 0);
|
||||
#endif
|
||||
dhcp_update_configs(daemon->dhcp_conf);
|
||||
lease_update_from_configs();
|
||||
lease_update_file(now);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2017 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2018 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-2017 Simon Kelley"
|
||||
#define COPYRIGHT "Copyright (c) 2000-2018 Simon Kelley"
|
||||
|
||||
/* We do defines that influence behavior of stdio.h, so complain
|
||||
if included too early. */
|
||||
@@ -142,6 +142,10 @@ extern int capget(cap_user_header_t header, cap_user_data_t data);
|
||||
#include <priv.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
# include <nettle/nettle-meta.h>
|
||||
#endif
|
||||
|
||||
/* daemon is function in the C library.... */
|
||||
#define daemon dnsmasq_daemon
|
||||
|
||||
@@ -175,6 +179,7 @@ struct event_desc {
|
||||
#define EVENT_NEWROUTE 23
|
||||
#define EVENT_TIME_ERR 24
|
||||
#define EVENT_SCRIPT_LOG 25
|
||||
#define EVENT_TIME 26
|
||||
|
||||
/* Exit codes. */
|
||||
#define EC_GOOD 0
|
||||
@@ -236,7 +241,7 @@ struct event_desc {
|
||||
#define OPT_DNSSEC_VALID 45
|
||||
#define OPT_DNSSEC_TIME 46
|
||||
#define OPT_DNSSEC_DEBUG 47
|
||||
#define OPT_DNSSEC_NO_SIGN 48
|
||||
#define OPT_DNSSEC_IGN_NS 48
|
||||
#define OPT_LOCAL_SERVICE 49
|
||||
#define OPT_LOOP_DETECT 50
|
||||
#define OPT_EXTRALOG 51
|
||||
@@ -245,7 +250,8 @@ struct event_desc {
|
||||
#define OPT_MAC_B64 54
|
||||
#define OPT_MAC_HEX 55
|
||||
#define OPT_TFTP_APREF_MAC 56
|
||||
#define OPT_LAST 57
|
||||
#define OPT_RAPID_COMMIT 57
|
||||
#define OPT_LAST 58
|
||||
|
||||
/* 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. */
|
||||
@@ -452,6 +458,7 @@ struct crec {
|
||||
#define F_NO_RR (1u<<25)
|
||||
#define F_IPSET (1u<<26)
|
||||
#define F_NOEXTRA (1u<<27)
|
||||
#define F_SERVFAIL (1u<<28)
|
||||
|
||||
/* Values of uid in crecs with F_CONFIG bit set. */
|
||||
#define SRC_INTERFACE 0
|
||||
@@ -499,7 +506,7 @@ struct serverfd {
|
||||
int fd;
|
||||
union mysockaddr source_addr;
|
||||
char interface[IF_NAMESIZE+1];
|
||||
unsigned int ifindex, used;
|
||||
unsigned int ifindex, used, preallocated;
|
||||
struct serverfd *next;
|
||||
};
|
||||
|
||||
@@ -514,6 +521,7 @@ struct server {
|
||||
struct serverfd *sfd;
|
||||
char *domain; /* set if this server only handles a domain. */
|
||||
int flags, tcpfd, edns_pktsz;
|
||||
time_t pktsz_reduced;
|
||||
unsigned int queries, failed_queries;
|
||||
#ifdef HAVE_LOOP
|
||||
u32 uid;
|
||||
@@ -832,7 +840,7 @@ struct cond_domain {
|
||||
#ifdef HAVE_IPV6
|
||||
struct in6_addr start6, end6;
|
||||
#endif
|
||||
int is6;
|
||||
int is6, indexed;
|
||||
struct cond_domain *next;
|
||||
};
|
||||
|
||||
@@ -1025,6 +1033,8 @@ extern struct daemon {
|
||||
#ifdef HAVE_DNSSEC
|
||||
char *keyname; /* MAXDNAME size buffer */
|
||||
char *workspacename; /* ditto */
|
||||
char *rr_status; /* flags for individual RRs */
|
||||
int rr_status_sz;
|
||||
#endif
|
||||
unsigned int local_answer, queries_forwarded, auth_answer;
|
||||
struct frec *frec_list;
|
||||
@@ -1178,6 +1188,15 @@ size_t filter_rrsigs(struct dns_header *header, size_t plen);
|
||||
unsigned char* hash_questions(struct dns_header *header, size_t plen, char *name);
|
||||
int setup_timestamp(void);
|
||||
|
||||
/* crypto.c */
|
||||
const struct nettle_hash *hash_find(char *name);
|
||||
int hash_init(const struct nettle_hash *hash, void **ctxp, unsigned char **digestp);
|
||||
int verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
|
||||
unsigned char *digest, size_t digest_len, int algo);
|
||||
char *ds_digest_name(int digest);
|
||||
char *algo_digest_name(int algo);
|
||||
char *nsec3_digest_name(int digest);
|
||||
|
||||
/* util.c */
|
||||
void rand_init(void);
|
||||
unsigned short rand16(void);
|
||||
@@ -1254,7 +1273,7 @@ void free_rfd(struct randfd *rfd);
|
||||
|
||||
/* network.c */
|
||||
int indextoname(int fd, int index, char *name);
|
||||
int local_bind(int fd, union mysockaddr *addr, char *intname, int is_tcp);
|
||||
int local_bind(int fd, union mysockaddr *addr, char *intname, unsigned int ifindex, int is_tcp);
|
||||
int random_sock(int family);
|
||||
void pre_allocate_sfds(void);
|
||||
int reload_servers(char *fname);
|
||||
|
||||
739
src/dnssec.c
739
src/dnssec.c
@@ -1,5 +1,5 @@
|
||||
/* dnssec.c is Copyright (c) 2012 Giovanni Bajo <rasky@develer.com>
|
||||
and Copyright (c) 2012-2017 Simon Kelley
|
||||
and Copyright (c) 2012-2018 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
|
||||
@@ -19,332 +19,11 @@
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
|
||||
#include <nettle/rsa.h>
|
||||
#include <nettle/dsa.h>
|
||||
#ifndef NO_NETTLE_ECC
|
||||
# include <nettle/ecdsa.h>
|
||||
# include <nettle/ecc-curve.h>
|
||||
#endif
|
||||
#include <nettle/nettle-meta.h>
|
||||
#include <nettle/bignum.h>
|
||||
|
||||
/* Nettle-3.0 moved to a new API for DSA. We use a name that's defined in the new API
|
||||
to detect Nettle-3, and invoke the backwards compatibility mode. */
|
||||
#ifdef dsa_params_init
|
||||
#include <nettle/dsa-compat.h>
|
||||
#endif
|
||||
|
||||
#define SERIAL_UNDEF -100
|
||||
#define SERIAL_EQ 0
|
||||
#define SERIAL_LT -1
|
||||
#define SERIAL_GT 1
|
||||
|
||||
/* http://www.iana.org/assignments/ds-rr-types/ds-rr-types.xhtml */
|
||||
static char *ds_digest_name(int digest)
|
||||
{
|
||||
switch (digest)
|
||||
{
|
||||
case 1: return "sha1";
|
||||
case 2: return "sha256";
|
||||
case 3: return "gosthash94";
|
||||
case 4: return "sha384";
|
||||
default: return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* http://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml */
|
||||
static char *algo_digest_name(int algo)
|
||||
{
|
||||
switch (algo)
|
||||
{
|
||||
case 1: return "md5";
|
||||
case 3: return "sha1";
|
||||
case 5: return "sha1";
|
||||
case 6: return "sha1";
|
||||
case 7: return "sha1";
|
||||
case 8: return "sha256";
|
||||
case 10: return "sha512";
|
||||
case 12: return "gosthash94";
|
||||
case 13: return "sha256";
|
||||
case 14: return "sha384";
|
||||
default: return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* http://www.iana.org/assignments/dnssec-nsec3-parameters/dnssec-nsec3-parameters.xhtml */
|
||||
static char *nsec3_digest_name(int digest)
|
||||
{
|
||||
switch (digest)
|
||||
{
|
||||
case 1: return "sha1";
|
||||
default: return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Find pointer to correct hash function in nettle library */
|
||||
static const struct nettle_hash *hash_find(char *name)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!name)
|
||||
return NULL;
|
||||
|
||||
for (i = 0; nettle_hashes[i]; i++)
|
||||
{
|
||||
if (strcmp(nettle_hashes[i]->name, name) == 0)
|
||||
return nettle_hashes[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* expand ctx and digest memory allocations if necessary and init hash function */
|
||||
static int hash_init(const struct nettle_hash *hash, void **ctxp, unsigned char **digestp)
|
||||
{
|
||||
static void *ctx = NULL;
|
||||
static unsigned char *digest = NULL;
|
||||
static unsigned int ctx_sz = 0;
|
||||
static unsigned int digest_sz = 0;
|
||||
|
||||
void *new;
|
||||
|
||||
if (ctx_sz < hash->context_size)
|
||||
{
|
||||
if (!(new = whine_malloc(hash->context_size)))
|
||||
return 0;
|
||||
if (ctx)
|
||||
free(ctx);
|
||||
ctx = new;
|
||||
ctx_sz = hash->context_size;
|
||||
}
|
||||
|
||||
if (digest_sz < hash->digest_size)
|
||||
{
|
||||
if (!(new = whine_malloc(hash->digest_size)))
|
||||
return 0;
|
||||
if (digest)
|
||||
free(digest);
|
||||
digest = new;
|
||||
digest_sz = hash->digest_size;
|
||||
}
|
||||
|
||||
*ctxp = ctx;
|
||||
*digestp = digest;
|
||||
|
||||
hash->init(ctx);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int dnsmasq_rsa_verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
|
||||
unsigned char *digest, size_t digest_len, int algo)
|
||||
{
|
||||
unsigned char *p;
|
||||
size_t exp_len;
|
||||
|
||||
static struct rsa_public_key *key = NULL;
|
||||
static mpz_t sig_mpz;
|
||||
|
||||
(void)digest_len;
|
||||
|
||||
if (key == NULL)
|
||||
{
|
||||
if (!(key = whine_malloc(sizeof(struct rsa_public_key))))
|
||||
return 0;
|
||||
|
||||
nettle_rsa_public_key_init(key);
|
||||
mpz_init(sig_mpz);
|
||||
}
|
||||
|
||||
if ((key_len < 3) || !(p = blockdata_retrieve(key_data, key_len, NULL)))
|
||||
return 0;
|
||||
|
||||
key_len--;
|
||||
if ((exp_len = *p++) == 0)
|
||||
{
|
||||
GETSHORT(exp_len, p);
|
||||
key_len -= 2;
|
||||
}
|
||||
|
||||
if (exp_len >= key_len)
|
||||
return 0;
|
||||
|
||||
key->size = key_len - exp_len;
|
||||
mpz_import(key->e, exp_len, 1, 1, 0, 0, p);
|
||||
mpz_import(key->n, key->size, 1, 1, 0, 0, p + exp_len);
|
||||
|
||||
mpz_import(sig_mpz, sig_len, 1, 1, 0, 0, sig);
|
||||
|
||||
switch (algo)
|
||||
{
|
||||
case 1:
|
||||
return nettle_rsa_md5_verify_digest(key, digest, sig_mpz);
|
||||
case 5: case 7:
|
||||
return nettle_rsa_sha1_verify_digest(key, digest, sig_mpz);
|
||||
case 8:
|
||||
return nettle_rsa_sha256_verify_digest(key, digest, sig_mpz);
|
||||
case 10:
|
||||
return nettle_rsa_sha512_verify_digest(key, digest, sig_mpz);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dnsmasq_dsa_verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
|
||||
unsigned char *digest, size_t digest_len, int algo)
|
||||
{
|
||||
unsigned char *p;
|
||||
unsigned int t;
|
||||
|
||||
static struct dsa_public_key *key = NULL;
|
||||
static struct dsa_signature *sig_struct;
|
||||
|
||||
(void)digest_len;
|
||||
|
||||
if (key == NULL)
|
||||
{
|
||||
if (!(sig_struct = whine_malloc(sizeof(struct dsa_signature))) ||
|
||||
!(key = whine_malloc(sizeof(struct dsa_public_key))))
|
||||
return 0;
|
||||
|
||||
nettle_dsa_public_key_init(key);
|
||||
nettle_dsa_signature_init(sig_struct);
|
||||
}
|
||||
|
||||
if ((sig_len < 41) || !(p = blockdata_retrieve(key_data, key_len, NULL)))
|
||||
return 0;
|
||||
|
||||
t = *p++;
|
||||
|
||||
if (key_len < (213 + (t * 24)))
|
||||
return 0;
|
||||
|
||||
mpz_import(key->q, 20, 1, 1, 0, 0, p); p += 20;
|
||||
mpz_import(key->p, 64 + (t*8), 1, 1, 0, 0, p); p += 64 + (t*8);
|
||||
mpz_import(key->g, 64 + (t*8), 1, 1, 0, 0, p); p += 64 + (t*8);
|
||||
mpz_import(key->y, 64 + (t*8), 1, 1, 0, 0, p); p += 64 + (t*8);
|
||||
|
||||
mpz_import(sig_struct->r, 20, 1, 1, 0, 0, sig+1);
|
||||
mpz_import(sig_struct->s, 20, 1, 1, 0, 0, sig+21);
|
||||
|
||||
(void)algo;
|
||||
|
||||
return nettle_dsa_sha1_verify_digest(key, digest, sig_struct);
|
||||
}
|
||||
|
||||
#ifndef NO_NETTLE_ECC
|
||||
static int dnsmasq_ecdsa_verify(struct blockdata *key_data, unsigned int key_len,
|
||||
unsigned char *sig, size_t sig_len,
|
||||
unsigned char *digest, size_t digest_len, int algo)
|
||||
{
|
||||
unsigned char *p;
|
||||
unsigned int t;
|
||||
struct ecc_point *key;
|
||||
|
||||
static struct ecc_point *key_256 = NULL, *key_384 = NULL;
|
||||
static mpz_t x, y;
|
||||
static struct dsa_signature *sig_struct;
|
||||
|
||||
if (!sig_struct)
|
||||
{
|
||||
if (!(sig_struct = whine_malloc(sizeof(struct dsa_signature))))
|
||||
return 0;
|
||||
|
||||
nettle_dsa_signature_init(sig_struct);
|
||||
mpz_init(x);
|
||||
mpz_init(y);
|
||||
}
|
||||
|
||||
switch (algo)
|
||||
{
|
||||
case 13:
|
||||
if (!key_256)
|
||||
{
|
||||
if (!(key_256 = whine_malloc(sizeof(struct ecc_point))))
|
||||
return 0;
|
||||
|
||||
nettle_ecc_point_init(key_256, &nettle_secp_256r1);
|
||||
}
|
||||
|
||||
key = key_256;
|
||||
t = 32;
|
||||
break;
|
||||
|
||||
case 14:
|
||||
if (!key_384)
|
||||
{
|
||||
if (!(key_384 = whine_malloc(sizeof(struct ecc_point))))
|
||||
return 0;
|
||||
|
||||
nettle_ecc_point_init(key_384, &nettle_secp_384r1);
|
||||
}
|
||||
|
||||
key = key_384;
|
||||
t = 48;
|
||||
break;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (sig_len != 2*t || key_len != 2*t ||
|
||||
!(p = blockdata_retrieve(key_data, key_len, NULL)))
|
||||
return 0;
|
||||
|
||||
mpz_import(x, t , 1, 1, 0, 0, p);
|
||||
mpz_import(y, t , 1, 1, 0, 0, p + t);
|
||||
|
||||
if (!ecc_point_set(key, x, y))
|
||||
return 0;
|
||||
|
||||
mpz_import(sig_struct->r, t, 1, 1, 0, 0, sig);
|
||||
mpz_import(sig_struct->s, t, 1, 1, 0, 0, sig + t);
|
||||
|
||||
return nettle_ecdsa_verify(key, digest_len, digest, sig_struct);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int (*verify_func(int algo))(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
|
||||
unsigned char *digest, size_t digest_len, int algo)
|
||||
{
|
||||
|
||||
/* Enure at runtime that we have support for this digest */
|
||||
if (!hash_find(algo_digest_name(algo)))
|
||||
return NULL;
|
||||
|
||||
/* This switch defines which sig algorithms we support, can't introspect Nettle for that. */
|
||||
switch (algo)
|
||||
{
|
||||
case 1: case 5: case 7: case 8: case 10:
|
||||
return dnsmasq_rsa_verify;
|
||||
|
||||
case 3: case 6:
|
||||
return dnsmasq_dsa_verify;
|
||||
|
||||
#ifndef NO_NETTLE_ECC
|
||||
case 13: case 14:
|
||||
return dnsmasq_ecdsa_verify;
|
||||
#endif
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
|
||||
unsigned char *digest, size_t digest_len, int algo)
|
||||
{
|
||||
|
||||
int (*func)(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
|
||||
unsigned char *digest, size_t digest_len, int algo);
|
||||
|
||||
func = verify_func(algo);
|
||||
|
||||
if (!func)
|
||||
return 0;
|
||||
|
||||
return (*func)(key_data, key_len, sig, sig_len, digest, digest_len, algo);
|
||||
}
|
||||
|
||||
/* Convert from presentation format to wire format, in place.
|
||||
Also map UC -> LC.
|
||||
Note that using extract_name to get presentation format
|
||||
@@ -424,15 +103,17 @@ static void from_wire(char *name)
|
||||
static int count_labels(char *name)
|
||||
{
|
||||
int i;
|
||||
|
||||
char *p;
|
||||
|
||||
if (*name == 0)
|
||||
return 0;
|
||||
|
||||
for (i = 0; *name; name++)
|
||||
if (*name == '.')
|
||||
for (p = name, i = 0; *p; p++)
|
||||
if (*p == '.')
|
||||
i++;
|
||||
|
||||
return i+1;
|
||||
/* Don't count empty first label. */
|
||||
return *name == '.' ? i : i+1;
|
||||
}
|
||||
|
||||
/* Implement RFC1982 wrapped compare for 32-bit numbers */
|
||||
@@ -598,10 +279,10 @@ static int get_rdata(struct dns_header *header, size_t plen, unsigned char *end,
|
||||
leaving the following bytes as deciding the order. Hence the nasty left1 and left2 variables.
|
||||
*/
|
||||
|
||||
static void sort_rrset(struct dns_header *header, size_t plen, u16 *rr_desc, int rrsetidx,
|
||||
unsigned char **rrset, char *buff1, char *buff2)
|
||||
static int sort_rrset(struct dns_header *header, size_t plen, u16 *rr_desc, int rrsetidx,
|
||||
unsigned char **rrset, char *buff1, char *buff2)
|
||||
{
|
||||
int swap, quit, i;
|
||||
int swap, quit, i, j;
|
||||
|
||||
do
|
||||
{
|
||||
@@ -663,11 +344,21 @@ static void sort_rrset(struct dns_header *header, size_t plen, u16 *rr_desc, int
|
||||
rrset[i] = tmp;
|
||||
swap = quit = 1;
|
||||
}
|
||||
else if (rc == 0 && quit && len1 == len2)
|
||||
{
|
||||
/* Two RRs are equal, remove one copy. RFC 4034, para 6.3 */
|
||||
for (j = i+1; j < rrsetidx-1; j++)
|
||||
rrset[j] = rrset[j+1];
|
||||
rrsetidx--;
|
||||
i--;
|
||||
}
|
||||
else if (rc < 0)
|
||||
quit = 1;
|
||||
}
|
||||
}
|
||||
} while (swap);
|
||||
|
||||
return rrsetidx;
|
||||
}
|
||||
|
||||
static unsigned char **rrset = NULL, **sigs = NULL;
|
||||
@@ -812,7 +503,7 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
|
||||
/* Sort RRset records into canonical order.
|
||||
Note that at this point keyname and daemon->workspacename buffs are
|
||||
unused, and used as workspace by the sort. */
|
||||
sort_rrset(header, plen, rr_desc, rrsetidx, rrset, daemon->workspacename, keyname);
|
||||
rrsetidx = sort_rrset(header, plen, rr_desc, rrsetidx, rrset, daemon->workspacename, keyname);
|
||||
|
||||
/* Now try all the sigs to try and find one which validates */
|
||||
for (j = 0; j <sigidx; j++)
|
||||
@@ -866,6 +557,7 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
|
||||
u16 len, *dp;
|
||||
|
||||
p = rrset[i];
|
||||
|
||||
if (!extract_name(header, plen, &p, name, 1, 10))
|
||||
return STAT_BOGUS;
|
||||
|
||||
@@ -1120,7 +812,7 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
|
||||
{
|
||||
a.addr.log.keytag = keytag;
|
||||
a.addr.log.algo = algo;
|
||||
if (verify_func(algo))
|
||||
if (algo_digest_name(algo))
|
||||
log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DNSKEY keytag %hu, algo %hu");
|
||||
else
|
||||
log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DNSKEY keytag %hu, algo %hu (not supported)");
|
||||
@@ -1181,11 +873,18 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
|
||||
rc = STAT_BOGUS;
|
||||
else
|
||||
rc = dnssec_validate_reply(now, header, plen, name, keyname, NULL, 0, &neganswer, &nons);
|
||||
/* Note dnssec_validate_reply() will have cached positive answers */
|
||||
|
||||
if (rc == STAT_INSECURE)
|
||||
rc = STAT_BOGUS;
|
||||
|
||||
{
|
||||
static int reported = 0;
|
||||
if (!reported)
|
||||
{
|
||||
reported = 1;
|
||||
my_syslog(LOG_WARNING, _("Insecure DS reply received, do upstream DNS servers support DNSSEC?"));
|
||||
}
|
||||
rc = STAT_BOGUS;
|
||||
}
|
||||
|
||||
p = (unsigned char *)(header+1);
|
||||
extract_name(header, plen, &p, name, 1, 4);
|
||||
p += 4; /* qtype, qclass */
|
||||
@@ -1248,7 +947,7 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
|
||||
a.addr.log.keytag = keytag;
|
||||
a.addr.log.algo = algo;
|
||||
a.addr.log.digest = digest;
|
||||
if (hash_find(ds_digest_name(digest)) && verify_func(algo))
|
||||
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");
|
||||
else
|
||||
log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %hu, algo %hu, digest %hu (not supported)");
|
||||
@@ -1405,8 +1104,8 @@ static int hostname_cmp(const char *a, const char *b)
|
||||
}
|
||||
}
|
||||
|
||||
static int prove_non_existence_nsec(struct dns_header *header, size_t plen, unsigned char **nsecs, int nsec_count,
|
||||
char *workspace1, char *workspace2, char *name, int type, int *nons)
|
||||
static int prove_non_existence_nsec(struct dns_header *header, size_t plen, unsigned char **nsecs, unsigned char **labels, int nsec_count,
|
||||
char *workspace1_in, char *workspace2, char *name, int type, int *nons)
|
||||
{
|
||||
int i, rc, rdlen;
|
||||
unsigned char *p, *psave;
|
||||
@@ -1419,6 +1118,9 @@ static int prove_non_existence_nsec(struct dns_header *header, size_t plen, unsi
|
||||
/* Find NSEC record that proves name doesn't exist */
|
||||
for (i = 0; i < nsec_count; i++)
|
||||
{
|
||||
char *workspace1 = workspace1_in;
|
||||
int sig_labels, name_labels;
|
||||
|
||||
p = nsecs[i];
|
||||
if (!extract_name(header, plen, &p, workspace1, 1, 10))
|
||||
return 0;
|
||||
@@ -1427,7 +1129,27 @@ static int prove_non_existence_nsec(struct dns_header *header, size_t plen, unsi
|
||||
psave = p;
|
||||
if (!extract_name(header, plen, &p, workspace2, 1, 10))
|
||||
return 0;
|
||||
|
||||
|
||||
/* If NSEC comes from wildcard expansion, use original wildcard
|
||||
as name for computation. */
|
||||
sig_labels = *labels[i];
|
||||
name_labels = count_labels(workspace1);
|
||||
|
||||
if (sig_labels < name_labels)
|
||||
{
|
||||
int k;
|
||||
for (k = name_labels - sig_labels; k != 0; k--)
|
||||
{
|
||||
while (*workspace1 != '.' && *workspace1 != 0)
|
||||
workspace1++;
|
||||
if (k != 1 && *workspace1 == '.')
|
||||
workspace1++;
|
||||
}
|
||||
|
||||
workspace1--;
|
||||
*workspace1 = '*';
|
||||
}
|
||||
|
||||
rc = hostname_cmp(workspace1, name);
|
||||
|
||||
if (rc == 0)
|
||||
@@ -1453,8 +1175,9 @@ static int prove_non_existence_nsec(struct dns_header *header, size_t plen, unsi
|
||||
return 0;
|
||||
|
||||
/* If the SOA bit is set for a DS record, then we have the
|
||||
DS from the wrong side of the delegation. */
|
||||
if (type == T_DS && (p[2] & (0x80 >> T_SOA)) != 0)
|
||||
DS from the wrong side of the delegation. For the root DS,
|
||||
this is expected. */
|
||||
if (name_labels != 0 && type == T_DS && (p[2] & (0x80 >> T_SOA)) != 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1559,7 +1282,7 @@ static int base32_decode(char *in, unsigned char *out)
|
||||
}
|
||||
|
||||
static int check_nsec3_coverage(struct dns_header *header, size_t plen, int digest_len, unsigned char *digest, int type,
|
||||
char *workspace1, char *workspace2, unsigned char **nsecs, int nsec_count, int *nons)
|
||||
char *workspace1, char *workspace2, unsigned char **nsecs, int nsec_count, int *nons, int name_labels)
|
||||
{
|
||||
int i, hash_len, salt_len, base32_len, rdlen, flags;
|
||||
unsigned char *p, *psave;
|
||||
@@ -1614,8 +1337,9 @@ static int check_nsec3_coverage(struct dns_header *header, size_t plen, int dige
|
||||
return 0;
|
||||
|
||||
/* If the SOA bit is set for a DS record, then we have the
|
||||
DS from the wrong side of the delegation. */
|
||||
if (type == T_DS && (p[2] & (0x80 >> T_SOA)) != 0)
|
||||
DS from the wrong side of the delegation. For the root DS,
|
||||
this is expected. */
|
||||
if (name_labels != 0 && type == T_DS && (p[2] & (0x80 >> T_SOA)) != 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1756,7 +1480,7 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
|
||||
if ((digest_len = hash_name(name, &digest, hash, salt, salt_len, iterations)) == 0)
|
||||
return 0;
|
||||
|
||||
if (check_nsec3_coverage(header, plen, digest_len, digest, type, workspace1, workspace2, nsecs, nsec_count, nons))
|
||||
if (check_nsec3_coverage(header, plen, digest_len, digest, type, workspace1, workspace2, nsecs, nsec_count, nons, count_labels(name)))
|
||||
return 1;
|
||||
|
||||
/* Can't find an NSEC3 which covers the name directly, we need the "closest encloser NSEC3"
|
||||
@@ -1801,7 +1525,7 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
|
||||
if ((digest_len = hash_name(next_closest, &digest, hash, salt, salt_len, iterations)) == 0)
|
||||
return 0;
|
||||
|
||||
if (!check_nsec3_coverage(header, plen, digest_len, digest, type, workspace1, workspace2, nsecs, nsec_count, NULL))
|
||||
if (!check_nsec3_coverage(header, plen, digest_len, digest, type, workspace1, workspace2, nsecs, nsec_count, NULL, 1))
|
||||
return 0;
|
||||
|
||||
/* Finally, check that there's no seat of wildcard synthesis */
|
||||
@@ -1816,7 +1540,7 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
|
||||
if ((digest_len = hash_name(wildcard, &digest, hash, salt, salt_len, iterations)) == 0)
|
||||
return 0;
|
||||
|
||||
if (!check_nsec3_coverage(header, plen, digest_len, digest, type, workspace1, workspace2, nsecs, nsec_count, NULL))
|
||||
if (!check_nsec3_coverage(header, plen, digest_len, digest, type, workspace1, workspace2, nsecs, nsec_count, NULL, 1))
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1825,24 +1549,26 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
|
||||
|
||||
static int prove_non_existence(struct dns_header *header, size_t plen, char *keyname, char *name, int qtype, int qclass, char *wildname, int *nons)
|
||||
{
|
||||
static unsigned char **nsecset = NULL;
|
||||
static int nsecset_sz = 0;
|
||||
static unsigned char **nsecset = NULL, **rrsig_labels = NULL;
|
||||
static int nsecset_sz = 0, rrsig_labels_sz = 0;
|
||||
|
||||
int type_found = 0;
|
||||
unsigned char *p = skip_questions(header, plen);
|
||||
unsigned char *auth_start, *p = skip_questions(header, plen);
|
||||
int type, class, rdlen, i, nsecs_found;
|
||||
|
||||
/* Move to NS section */
|
||||
if (!p || !(p = skip_section(p, ntohs(header->ancount), header, plen)))
|
||||
return 0;
|
||||
|
||||
auth_start = p;
|
||||
|
||||
for (nsecs_found = 0, i = ntohs(header->nscount); i != 0; i--)
|
||||
{
|
||||
unsigned char *pstart = p;
|
||||
|
||||
if (!(p = skip_name(p, header, plen, 10)))
|
||||
if (!extract_name(header, plen, &p, daemon->workspacename, 1, 10))
|
||||
return 0;
|
||||
|
||||
|
||||
GETSHORT(type, p);
|
||||
GETSHORT(class, p);
|
||||
p += 4; /* TTL */
|
||||
@@ -1859,7 +1585,69 @@ static int prove_non_existence(struct dns_header *header, size_t plen, char *key
|
||||
if (!expand_workspace(&nsecset, &nsecset_sz, nsecs_found))
|
||||
return 0;
|
||||
|
||||
nsecset[nsecs_found++] = pstart;
|
||||
if (type == T_NSEC)
|
||||
{
|
||||
/* If we're looking for NSECs, find the corresponding SIGs, to
|
||||
extract the labels value, which we need in case the NSECs
|
||||
are the result of wildcard expansion.
|
||||
Note that the NSEC may not have been validated yet
|
||||
so if there are multiple SIGs, make sure the label value
|
||||
is the same in all, to avoid be duped by a rogue one.
|
||||
If there are no SIGs, that's an error */
|
||||
unsigned char *p1 = auth_start;
|
||||
int res, j, rdlen1, type1, class1;
|
||||
|
||||
if (!expand_workspace(&rrsig_labels, &rrsig_labels_sz, nsecs_found))
|
||||
return 0;
|
||||
|
||||
rrsig_labels[nsecs_found] = NULL;
|
||||
|
||||
for (j = ntohs(header->nscount); j != 0; j--)
|
||||
{
|
||||
if (!(res = extract_name(header, plen, &p1, daemon->workspacename, 0, 10)))
|
||||
return 0;
|
||||
|
||||
GETSHORT(type1, p1);
|
||||
GETSHORT(class1, p1);
|
||||
p1 += 4; /* TTL */
|
||||
GETSHORT(rdlen1, p1);
|
||||
|
||||
if (!CHECK_LEN(header, p1, plen, rdlen1))
|
||||
return 0;
|
||||
|
||||
if (res == 1 && class1 == qclass && type1 == T_RRSIG)
|
||||
{
|
||||
int type_covered;
|
||||
unsigned char *psav = p1;
|
||||
|
||||
if (rdlen1 < 18)
|
||||
return 0; /* bad packet */
|
||||
|
||||
GETSHORT(type_covered, p1);
|
||||
|
||||
if (type_covered == T_NSEC)
|
||||
{
|
||||
p1++; /* algo */
|
||||
|
||||
/* labels field must be the same in every SIG we find. */
|
||||
if (!rrsig_labels[nsecs_found])
|
||||
rrsig_labels[nsecs_found] = p1;
|
||||
else if (*rrsig_labels[nsecs_found] != *p1) /* algo */
|
||||
return 0;
|
||||
}
|
||||
p1 = psav;
|
||||
}
|
||||
|
||||
if (!ADD_RDLEN(header, p1, plen, rdlen1))
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Must have found at least one sig. */
|
||||
if (!rrsig_labels[nsecs_found])
|
||||
return 0;
|
||||
}
|
||||
|
||||
nsecset[nsecs_found++] = pstart;
|
||||
}
|
||||
|
||||
if (!ADD_RDLEN(header, p, plen, rdlen))
|
||||
@@ -1867,7 +1655,7 @@ static int prove_non_existence(struct dns_header *header, size_t plen, char *key
|
||||
}
|
||||
|
||||
if (type_found == T_NSEC)
|
||||
return prove_non_existence_nsec(header, plen, nsecset, nsecs_found, daemon->workspacename, keyname, name, qtype, nons);
|
||||
return prove_non_existence_nsec(header, plen, nsecset, rrsig_labels, nsecs_found, daemon->workspacename, keyname, name, qtype, nons);
|
||||
else if (type_found == T_NSEC3)
|
||||
return prove_non_existence_nsec3(header, plen, nsecset, nsecs_found, daemon->workspacename, keyname, name, qtype, wildname, nons);
|
||||
else
|
||||
@@ -1935,8 +1723,8 @@ static int zone_status(char *name, int class, char *keyname, time_t now)
|
||||
do
|
||||
{
|
||||
if (crecp->uid == (unsigned int)class &&
|
||||
hash_find(ds_digest_name(crecp->addr.ds.digest)) &&
|
||||
verify_func(crecp->addr.ds.algo))
|
||||
ds_digest_name(crecp->addr.ds.digest) &&
|
||||
algo_digest_name(crecp->addr.ds.algo))
|
||||
break;
|
||||
}
|
||||
while ((crecp = cache_find_by_name(crecp, keyname, now, F_DS)));
|
||||
@@ -1965,7 +1753,10 @@ static int zone_status(char *name, int class, char *keyname, time_t now)
|
||||
STAT_INSECURE at least one RRset not validated, because in unsigned zone.
|
||||
STAT_BOGUS signature is wrong, bad packet, no validation where there should be.
|
||||
STAT_NEED_KEY need DNSKEY to complete validation (name is returned in keyname, class in *class)
|
||||
STAT_NEED_DS need DS to complete validation (name is returned in keyname)
|
||||
STAT_NEED_DS need DS to complete validation (name is returned in keyname)
|
||||
|
||||
daemon->rr_status points to a char array which corressponds to the RRs in the
|
||||
answer section (only). This is set to 1 for each RR which is validated, and 0 for any which aren't.
|
||||
*/
|
||||
int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname,
|
||||
int *class, int check_unsigned, int *neganswer, int *nons)
|
||||
@@ -1974,9 +1765,25 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
|
||||
static int target_sz = 0;
|
||||
|
||||
unsigned char *ans_start, *p1, *p2;
|
||||
int type1, class1, rdlen1, type2, class2, rdlen2, qclass, qtype, targetidx;
|
||||
int type1, class1, rdlen1 = 0, type2, class2, rdlen2, qclass, qtype, targetidx;
|
||||
int i, j, rc;
|
||||
int secure = STAT_SECURE;
|
||||
|
||||
/* extend rr_status if necessary */
|
||||
if (daemon->rr_status_sz < ntohs(header->ancount))
|
||||
{
|
||||
char *new = whine_malloc(ntohs(header->ancount) + 64);
|
||||
|
||||
if (!new)
|
||||
return STAT_BOGUS;
|
||||
|
||||
free(daemon->rr_status);
|
||||
daemon->rr_status = new;
|
||||
daemon->rr_status_sz = ntohs(header->ancount) + 64;
|
||||
}
|
||||
|
||||
memset(daemon->rr_status, 0, ntohs(header->ancount));
|
||||
|
||||
if (neganswer)
|
||||
*neganswer = 0;
|
||||
|
||||
@@ -2033,7 +1840,10 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
|
||||
|
||||
for (p1 = ans_start, i = 0; i < ntohs(header->ancount) + ntohs(header->nscount); i++)
|
||||
{
|
||||
if (!extract_name(header, plen, &p1, name, 1, 10))
|
||||
if (i != 0 && !ADD_RDLEN(header, p1, plen, rdlen1))
|
||||
return STAT_BOGUS;
|
||||
|
||||
if (!extract_name(header, plen, &p1, name, 1, 10))
|
||||
return STAT_BOGUS; /* bad packet */
|
||||
|
||||
GETSHORT(type1, p1);
|
||||
@@ -2042,140 +1852,159 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
|
||||
GETSHORT(rdlen1, p1);
|
||||
|
||||
/* Don't try and validate RRSIGs! */
|
||||
if (type1 != T_RRSIG)
|
||||
if (type1 == T_RRSIG)
|
||||
continue;
|
||||
|
||||
/* Check if we've done this RRset already */
|
||||
for (p2 = ans_start, j = 0; j < i; j++)
|
||||
{
|
||||
/* Check if we've done this RRset already */
|
||||
for (p2 = ans_start, j = 0; j < i; j++)
|
||||
{
|
||||
if (!(rc = extract_name(header, plen, &p2, name, 0, 10)))
|
||||
return STAT_BOGUS; /* bad packet */
|
||||
|
||||
GETSHORT(type2, p2);
|
||||
GETSHORT(class2, p2);
|
||||
p2 += 4; /* TTL */
|
||||
GETSHORT(rdlen2, p2);
|
||||
|
||||
if (type2 == type1 && class2 == class1 && rc == 1)
|
||||
break; /* Done it before: name, type, class all match. */
|
||||
|
||||
if (!ADD_RDLEN(header, p2, plen, rdlen2))
|
||||
return STAT_BOGUS;
|
||||
}
|
||||
if (!(rc = extract_name(header, plen, &p2, name, 0, 10)))
|
||||
return STAT_BOGUS; /* bad packet */
|
||||
|
||||
GETSHORT(type2, p2);
|
||||
GETSHORT(class2, p2);
|
||||
p2 += 4; /* TTL */
|
||||
GETSHORT(rdlen2, p2);
|
||||
|
||||
if (type2 == type1 && class2 == class1 && rc == 1)
|
||||
break; /* Done it before: name, type, class all match. */
|
||||
|
||||
if (!ADD_RDLEN(header, p2, plen, rdlen2))
|
||||
return STAT_BOGUS;
|
||||
}
|
||||
|
||||
if (j != i)
|
||||
{
|
||||
/* Done already: copy the validation status */
|
||||
if (i < ntohs(header->ancount))
|
||||
daemon->rr_status[i] = daemon->rr_status[j];
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Not done, validate now */
|
||||
if (j == i)
|
||||
int sigcnt, rrcnt;
|
||||
char *wildname;
|
||||
|
||||
if (!explore_rrset(header, plen, class1, type1, name, keyname, &sigcnt, &rrcnt))
|
||||
return STAT_BOGUS;
|
||||
|
||||
/* No signatures for RRset. We can be configured to assume this is OK and return an INSECURE result. */
|
||||
if (sigcnt == 0)
|
||||
{
|
||||
int sigcnt, rrcnt;
|
||||
char *wildname;
|
||||
|
||||
if (!explore_rrset(header, plen, class1, type1, name, keyname, &sigcnt, &rrcnt))
|
||||
return STAT_BOGUS;
|
||||
|
||||
/* No signatures for RRset. We can be configured to assume this is OK and return a INSECURE result. */
|
||||
if (sigcnt == 0)
|
||||
if (check_unsigned)
|
||||
{
|
||||
if (check_unsigned)
|
||||
{
|
||||
rc = zone_status(name, class1, keyname, now);
|
||||
if (rc == STAT_SECURE)
|
||||
rc = STAT_BOGUS;
|
||||
if (class)
|
||||
*class = class1; /* Class for NEED_DS or NEED_KEY */
|
||||
}
|
||||
else
|
||||
rc = STAT_INSECURE;
|
||||
|
||||
return rc;
|
||||
rc = zone_status(name, class1, keyname, now);
|
||||
if (rc == STAT_SECURE)
|
||||
rc = STAT_BOGUS;
|
||||
if (class)
|
||||
*class = class1; /* Class for NEED_DS or NEED_KEY */
|
||||
}
|
||||
else
|
||||
rc = STAT_INSECURE;
|
||||
|
||||
if (rc != STAT_INSECURE)
|
||||
return rc;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* explore_rrset() gives us key name from sigs in keyname.
|
||||
Can't overwrite name here. */
|
||||
strcpy(daemon->workspacename, keyname);
|
||||
rc = zone_status(daemon->workspacename, class1, keyname, now);
|
||||
|
||||
if (rc != STAT_SECURE)
|
||||
{
|
||||
/* Zone is insecure, don't need to validate RRset */
|
||||
if (class)
|
||||
*class = class1; /* Class for NEED_DS or NEED_KEY */
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = validate_rrset(now, header, plen, class1, type1, sigcnt, rrcnt, name, keyname, &wildname, NULL, 0, 0, 0);
|
||||
|
||||
if (rc == STAT_BOGUS || rc == STAT_NEED_KEY || rc == STAT_NEED_DS)
|
||||
{
|
||||
if (class)
|
||||
*class = class1; /* Class for DS or DNSKEY */
|
||||
*class = class1; /* Class for NEED_DS or NEED_KEY */
|
||||
return rc;
|
||||
}
|
||||
else
|
||||
}
|
||||
|
||||
/* Zone is insecure, don't need to validate RRset */
|
||||
if (rc == STAT_SECURE)
|
||||
{
|
||||
rc = validate_rrset(now, header, plen, class1, type1, sigcnt,
|
||||
rrcnt, name, keyname, &wildname, NULL, 0, 0, 0);
|
||||
|
||||
if (rc == STAT_BOGUS || rc == STAT_NEED_KEY || rc == STAT_NEED_DS)
|
||||
{
|
||||
if (class)
|
||||
*class = class1; /* Class for DS or DNSKEY */
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* rc is now STAT_SECURE or STAT_SECURE_WILDCARD */
|
||||
|
||||
|
||||
/* Note that RR is validated */
|
||||
if (i < ntohs(header->ancount))
|
||||
daemon->rr_status[i] = 1;
|
||||
|
||||
/* Note if we've validated either the answer to the question
|
||||
or the target of a CNAME. Any not noted will need NSEC or
|
||||
to be in unsigned space. */
|
||||
|
||||
for (j = 0; j <targetidx; j++)
|
||||
if ((p2 = targets[j]))
|
||||
{
|
||||
if (!(rc = extract_name(header, plen, &p2, name, 0, 10)))
|
||||
int rc1;
|
||||
if (!(rc1 = extract_name(header, plen, &p2, name, 0, 10)))
|
||||
return STAT_BOGUS; /* bad packet */
|
||||
|
||||
if (class1 == qclass && rc == 1 && (type1 == T_CNAME || type1 == qtype || qtype == T_ANY ))
|
||||
if (class1 == qclass && rc1 == 1 && (type1 == T_CNAME || type1 == qtype || qtype == T_ANY ))
|
||||
targets[j] = NULL;
|
||||
}
|
||||
|
||||
/* An attacker replay a wildcard answer with a different
|
||||
answer and overlay a genuine RR. To prove this
|
||||
hasn't happened, the answer must prove that
|
||||
the genuine record doesn't exist. Check that here.
|
||||
Note that we may not yet have validated the NSEC/NSEC3 RRsets.
|
||||
That's not a problem since if the RRsets later fail
|
||||
we'll return BOGUS then. */
|
||||
if (rc == STAT_SECURE_WILDCARD && !prove_non_existence(header, plen, keyname, name, type1, class1, wildname, NULL))
|
||||
|
||||
/* An attacker replay a wildcard answer with a different
|
||||
answer and overlay a genuine RR. To prove this
|
||||
hasn't happened, the answer must prove that
|
||||
the genuine record doesn't exist. Check that here.
|
||||
Note that we may not yet have validated the NSEC/NSEC3 RRsets.
|
||||
That's not a problem since if the RRsets later fail
|
||||
we'll return BOGUS then. */
|
||||
if (rc == STAT_SECURE_WILDCARD &&
|
||||
!prove_non_existence(header, plen, keyname, name, type1, class1, wildname, NULL))
|
||||
return STAT_BOGUS;
|
||||
|
||||
rc = STAT_SECURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!ADD_RDLEN(header, p1, plen, rdlen1))
|
||||
return STAT_BOGUS;
|
||||
if (rc == STAT_INSECURE)
|
||||
secure = STAT_INSECURE;
|
||||
}
|
||||
|
||||
/* OK, all the RRsets validate, now see if we have a missing answer or CNAME target. */
|
||||
for (j = 0; j <targetidx; j++)
|
||||
if ((p2 = targets[j]))
|
||||
{
|
||||
if (neganswer)
|
||||
*neganswer = 1;
|
||||
|
||||
if (!extract_name(header, plen, &p2, name, 1, 10))
|
||||
return STAT_BOGUS; /* bad packet */
|
||||
|
||||
/* NXDOMAIN or NODATA reply, unanswered question is (name, qclass, qtype) */
|
||||
|
||||
/* For anything other than a DS record, this situation is OK if either
|
||||
the answer is in an unsigned zone, or there's a NSEC records. */
|
||||
if (!prove_non_existence(header, plen, keyname, name, qtype, qclass, NULL, nons))
|
||||
{
|
||||
/* Empty DS without NSECS */
|
||||
if (qtype == T_DS)
|
||||
return STAT_BOGUS;
|
||||
|
||||
if ((rc = zone_status(name, qclass, keyname, now)) != STAT_SECURE)
|
||||
{
|
||||
if (class)
|
||||
*class = qclass; /* Class for NEED_DS or NEED_KEY */
|
||||
return rc;
|
||||
}
|
||||
|
||||
return STAT_BOGUS; /* signed zone, no NSECs */
|
||||
}
|
||||
}
|
||||
if (secure == STAT_SECURE)
|
||||
for (j = 0; j <targetidx; j++)
|
||||
if ((p2 = targets[j]))
|
||||
{
|
||||
if (neganswer)
|
||||
*neganswer = 1;
|
||||
|
||||
if (!extract_name(header, plen, &p2, name, 1, 10))
|
||||
return STAT_BOGUS; /* bad packet */
|
||||
|
||||
/* NXDOMAIN or NODATA reply, unanswered question is (name, qclass, qtype) */
|
||||
|
||||
/* For anything other than a DS record, this situation is OK if either
|
||||
the answer is in an unsigned zone, or there's a NSEC records. */
|
||||
if (!prove_non_existence(header, plen, keyname, name, qtype, qclass, NULL, nons))
|
||||
{
|
||||
/* Empty DS without NSECS */
|
||||
if (qtype == T_DS)
|
||||
return STAT_BOGUS;
|
||||
|
||||
if ((rc = zone_status(name, qclass, keyname, now)) != STAT_SECURE)
|
||||
{
|
||||
if (class)
|
||||
*class = qclass; /* Class for NEED_DS or NEED_KEY */
|
||||
return rc;
|
||||
}
|
||||
|
||||
return STAT_BOGUS; /* signed zone, no NSECs */
|
||||
}
|
||||
}
|
||||
|
||||
return STAT_SECURE;
|
||||
return secure;
|
||||
}
|
||||
|
||||
|
||||
|
||||
227
src/domain.c
227
src/domain.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2017 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2018 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,83 +55,133 @@ int is_name_synthetic(int flags, char *name, struct all_addr *addr)
|
||||
|
||||
if (pref && *pref != 0)
|
||||
continue; /* prefix match fail */
|
||||
|
||||
/* NB, must not alter name if we return zero */
|
||||
for (p = tail; *p; p++)
|
||||
|
||||
if (c->indexed)
|
||||
{
|
||||
char c = *p;
|
||||
for (p = tail; *p; p++)
|
||||
{
|
||||
char c = *p;
|
||||
|
||||
if (c < '0' || c > '9')
|
||||
break;
|
||||
}
|
||||
|
||||
if ((c >='0' && c <= '9') || c == '-')
|
||||
if (*p != '.')
|
||||
continue;
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (prot == AF_INET6 && ((c >='A' && c <= 'F') || (c >='a' && c <= 'f')))
|
||||
continue;
|
||||
*p = 0;
|
||||
|
||||
if (hostname_isequal(c->domain, p+1))
|
||||
{
|
||||
if (prot == AF_INET)
|
||||
{
|
||||
unsigned int index = atoi(tail);
|
||||
|
||||
if (!c->is6 &&
|
||||
index <= ntohl(c->end.s_addr) - ntohl(c->start.s_addr))
|
||||
{
|
||||
addr->addr.addr4.s_addr = htonl(ntohl(c->start.s_addr) + index);
|
||||
found = 1;
|
||||
}
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
{
|
||||
u64 index = atoll(tail);
|
||||
|
||||
if (c->is6 &&
|
||||
index <= addr6part(&c->end6) - addr6part(&c->start6))
|
||||
{
|
||||
u64 start = addr6part(&c->start6);
|
||||
addr->addr.addr6 = c->start6;
|
||||
setaddr6part(&addr->addr.addr6, start + index);
|
||||
found = 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (*p != '.')
|
||||
continue;
|
||||
|
||||
*p = 0;
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (prot == AF_INET6 && strstr(tail, "--ffff-") == tail)
|
||||
{
|
||||
/* special hack for v4-mapped. */
|
||||
memcpy(tail, "::ffff:", 7);
|
||||
for (p = tail + 7; *p; p++)
|
||||
if (*p == '-')
|
||||
*p = '.';
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
/* swap . or : for - */
|
||||
/* NB, must not alter name if we return zero */
|
||||
for (p = tail; *p; p++)
|
||||
if (*p == '-')
|
||||
{
|
||||
if (prot == AF_INET)
|
||||
*p = '.';
|
||||
{
|
||||
char c = *p;
|
||||
|
||||
if ((c >='0' && c <= '9') || c == '-')
|
||||
continue;
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
*p = ':';
|
||||
if (prot == AF_INET6 && ((c >='A' && c <= 'F') || (c >='a' && c <= 'f')))
|
||||
continue;
|
||||
#endif
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (*p != '.')
|
||||
continue;
|
||||
|
||||
*p = 0;
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (prot == AF_INET6 && strstr(tail, "--ffff-") == tail)
|
||||
{
|
||||
/* special hack for v4-mapped. */
|
||||
memcpy(tail, "::ffff:", 7);
|
||||
for (p = tail + 7; *p; p++)
|
||||
if (*p == '-')
|
||||
*p = '.';
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
/* swap . or : for - */
|
||||
for (p = tail; *p; p++)
|
||||
if (*p == '-')
|
||||
{
|
||||
if (prot == AF_INET)
|
||||
*p = '.';
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
*p = ':';
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (hostname_isequal(c->domain, p+1) && inet_pton(prot, tail, addr))
|
||||
{
|
||||
if (prot == AF_INET)
|
||||
{
|
||||
if (!c->is6 &&
|
||||
ntohl(addr->addr.addr4.s_addr) >= ntohl(c->start.s_addr) &&
|
||||
ntohl(addr->addr.addr4.s_addr) <= ntohl(c->end.s_addr))
|
||||
found = 1;
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
{
|
||||
u64 addrpart = addr6part(&addr->addr.addr6);
|
||||
|
||||
if (c->is6 &&
|
||||
is_same_net6(&addr->addr.addr6, &c->start6, 64) &&
|
||||
addrpart >= addr6part(&c->start6) &&
|
||||
addrpart <= addr6part(&c->end6))
|
||||
found = 1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (hostname_isequal(c->domain, p+1) && inet_pton(prot, tail, addr))
|
||||
{
|
||||
if (prot == AF_INET)
|
||||
{
|
||||
if (!c->is6 &&
|
||||
ntohl(addr->addr.addr4.s_addr) >= ntohl(c->start.s_addr) &&
|
||||
ntohl(addr->addr.addr4.s_addr) <= ntohl(c->end.s_addr))
|
||||
found = 1;
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
{
|
||||
u64 addrpart = addr6part(&addr->addr.addr6);
|
||||
|
||||
if (c->is6 &&
|
||||
is_same_net6(&addr->addr.addr6, &c->start6, 64) &&
|
||||
addrpart >= addr6part(&c->start6) &&
|
||||
addrpart <= addr6part(&c->end6))
|
||||
found = 1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* restore name */
|
||||
for (p = tail; *p; p++)
|
||||
if (*p == '.' || *p == ':')
|
||||
*p = '-';
|
||||
|
||||
*p = '.';
|
||||
|
||||
|
||||
|
||||
if (found)
|
||||
return 1;
|
||||
}
|
||||
@@ -149,14 +199,22 @@ int is_rev_synth(int flag, struct all_addr *addr, char *name)
|
||||
char *p;
|
||||
|
||||
*name = 0;
|
||||
if (c->prefix)
|
||||
strncpy(name, c->prefix, MAXDNAME - ADDRSTRLEN);
|
||||
if (c->indexed)
|
||||
{
|
||||
unsigned int index = ntohl(addr->addr.addr4.s_addr) - ntohl(c->start.s_addr);
|
||||
snprintf(name, MAXDNAME, "%s%u", c->prefix ? c->prefix : "", index);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (c->prefix)
|
||||
strncpy(name, c->prefix, MAXDNAME - ADDRSTRLEN);
|
||||
|
||||
inet_ntop(AF_INET, &addr->addr.addr4, name + strlen(name), ADDRSTRLEN);
|
||||
for (p = name; *p; p++)
|
||||
if (*p == '.')
|
||||
*p = '-';
|
||||
}
|
||||
|
||||
inet_ntop(AF_INET, &addr->addr.addr4, name + strlen(name), ADDRSTRLEN);
|
||||
for (p = name; *p; p++)
|
||||
if (*p == '.')
|
||||
*p = '-';
|
||||
|
||||
strncat(name, ".", MAXDNAME);
|
||||
strncat(name, c->domain, MAXDNAME);
|
||||
|
||||
@@ -169,23 +227,32 @@ int is_rev_synth(int flag, struct all_addr *addr, char *name)
|
||||
char *p;
|
||||
|
||||
*name = 0;
|
||||
if (c->prefix)
|
||||
strncpy(name, c->prefix, MAXDNAME - ADDRSTRLEN);
|
||||
|
||||
inet_ntop(AF_INET6, &addr->addr.addr6, name + strlen(name), ADDRSTRLEN);
|
||||
|
||||
/* IPv6 presentation address can start with ":", but valid domain names
|
||||
cannot start with "-" so prepend a zero in that case. */
|
||||
if (!c->prefix && *name == ':')
|
||||
if (c->indexed)
|
||||
{
|
||||
*name = '0';
|
||||
inet_ntop(AF_INET6, &addr->addr.addr6, name+1, ADDRSTRLEN);
|
||||
u64 index = addr6part(&addr->addr.addr6) - addr6part(&c->start6);
|
||||
snprintf(name, MAXDNAME, "%s%llu", c->prefix ? c->prefix : "", index);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (c->prefix)
|
||||
strncpy(name, c->prefix, MAXDNAME - ADDRSTRLEN);
|
||||
|
||||
inet_ntop(AF_INET6, &addr->addr.addr6, name + strlen(name), ADDRSTRLEN);
|
||||
|
||||
/* V4-mapped have periods.... */
|
||||
for (p = name; *p; p++)
|
||||
if (*p == ':' || *p == '.')
|
||||
*p = '-';
|
||||
/* IPv6 presentation address can start with ":", but valid domain names
|
||||
cannot start with "-" so prepend a zero in that case. */
|
||||
if (!c->prefix && *name == ':')
|
||||
{
|
||||
*name = '0';
|
||||
inet_ntop(AF_INET6, &addr->addr.addr6, name+1, ADDRSTRLEN);
|
||||
}
|
||||
|
||||
/* V4-mapped have periods.... */
|
||||
for (p = name; *p; p++)
|
||||
if (*p == ':' || *p == '.')
|
||||
*p = '-';
|
||||
|
||||
}
|
||||
|
||||
strncat(name, ".", MAXDNAME);
|
||||
strncat(name, c->domain, MAXDNAME);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2017 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2018 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
|
||||
|
||||
146
src/forward.c
146
src/forward.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2017 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2018 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
|
||||
@@ -272,14 +272,13 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
while (forward->blocking_query)
|
||||
forward = forward->blocking_query;
|
||||
|
||||
forward->flags |= FREC_TEST_PKTSZ;
|
||||
|
||||
blockdata_retrieve(forward->stash, forward->stash_len, (void *)header);
|
||||
plen = forward->stash_len;
|
||||
|
||||
forward->flags |= FREC_TEST_PKTSZ;
|
||||
if (find_pseudoheader(header, plen, NULL, &pheader, &is_sign, NULL) && !is_sign)
|
||||
PUTSHORT(SAFE_PKTSZ, pheader);
|
||||
|
||||
|
||||
if (forward->sentto->addr.sa.sa_family == AF_INET)
|
||||
log_query(F_NOEXTRA | F_DNSSEC | F_IPV4, "retry", (struct all_addr *)&forward->sentto->addr.in.sin_addr, "dnssec");
|
||||
#ifdef HAVE_IPV6
|
||||
@@ -400,31 +399,22 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
struct server *firstsentto = start;
|
||||
int subnet, forwarded = 0;
|
||||
size_t edns0_len;
|
||||
|
||||
unsigned char *oph = find_pseudoheader(header, plen, NULL, NULL, NULL, NULL);
|
||||
unsigned char *pheader;
|
||||
|
||||
/* If a query is retried, use the log_id for the retry when logging the answer. */
|
||||
forward->log_id = daemon->log_id;
|
||||
|
||||
edns0_len = add_edns0_config(header, plen, ((unsigned char *)header) + PACKETSZ, &forward->source, now, &subnet);
|
||||
plen = add_edns0_config(header, plen, ((unsigned char *)header) + PACKETSZ, &forward->source, now, &subnet);
|
||||
|
||||
if (edns0_len != plen)
|
||||
{
|
||||
plen = edns0_len;
|
||||
forward->flags |= FREC_ADDED_PHEADER;
|
||||
|
||||
if (subnet)
|
||||
forward->flags |= FREC_HAS_SUBNET;
|
||||
}
|
||||
if (subnet)
|
||||
forward->flags |= FREC_HAS_SUBNET;
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (option_bool(OPT_DNSSEC_VALID) && do_dnssec)
|
||||
{
|
||||
size_t new = add_do_bit(header, plen, ((unsigned char *) header) + PACKETSZ);
|
||||
|
||||
if (new != plen)
|
||||
forward->flags |= FREC_ADDED_PHEADER;
|
||||
|
||||
plen = new;
|
||||
|
||||
plen = add_do_bit(header, plen, ((unsigned char *) header) + PACKETSZ);
|
||||
|
||||
/* For debugging, set Checking Disabled, otherwise, have the upstream check too,
|
||||
this allows it to select auth servers when one is returning bad data. */
|
||||
if (option_bool(OPT_DNSSEC_DEBUG))
|
||||
@@ -433,9 +423,20 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
}
|
||||
#endif
|
||||
|
||||
/* If we're sending an EDNS0 with any options, we can't recreate the query from a reply. */
|
||||
if (find_pseudoheader(header, plen, &edns0_len, NULL, NULL, NULL) && edns0_len > 11)
|
||||
forward->flags |= FREC_HAS_EXTRADATA;
|
||||
if (find_pseudoheader(header, plen, &edns0_len, &pheader, NULL, NULL))
|
||||
{
|
||||
/* If there wasn't a PH before, and there is now, we added it. */
|
||||
if (!oph)
|
||||
forward->flags |= FREC_ADDED_PHEADER;
|
||||
|
||||
/* If we're sending an EDNS0 with any options, we can't recreate the query from a reply. */
|
||||
if (edns0_len > 11)
|
||||
forward->flags |= FREC_HAS_EXTRADATA;
|
||||
|
||||
/* Reduce udp size on retransmits. */
|
||||
if (forward->flags & FREC_TEST_PKTSZ)
|
||||
PUTSHORT(SAFE_PKTSZ, pheader);
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
@@ -563,7 +564,7 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
|
||||
char **sets = 0;
|
||||
int munged = 0, is_sign;
|
||||
size_t plen;
|
||||
|
||||
|
||||
(void)ad_reqd;
|
||||
(void)do_bit;
|
||||
(void)bogusanswer;
|
||||
@@ -767,7 +768,11 @@ void reply_query(int fd, int family, time_t now)
|
||||
|
||||
if (!server)
|
||||
return;
|
||||
|
||||
|
||||
/* If sufficient time has elapsed, try and expand UDP buffer size again. */
|
||||
if (difftime(now, server->pktsz_reduced) > UDP_TEST_TIME)
|
||||
server->edns_pktsz = daemon->edns_pktsz;
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
hash = hash_questions(header, n, daemon->namebuff);
|
||||
#else
|
||||
@@ -797,10 +802,20 @@ void reply_query(int fd, int family, time_t now)
|
||||
unsigned char *pheader;
|
||||
size_t plen;
|
||||
int is_sign;
|
||||
|
||||
|
||||
/* In strict order mode, there must be a server later in the chain
|
||||
left to send to, otherwise without the forwardall mechanism,
|
||||
code further on will cycle around the list forwever if they
|
||||
all return REFUSED. Note that server is always non-NULL before
|
||||
this executes. */
|
||||
if (option_bool(OPT_ORDER))
|
||||
for (server = forward->sentto->next; server; server = server->next)
|
||||
if (!(server->flags & (SERV_LITERAL_ADDRESS | SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_NO_ADDR | SERV_LOOP)))
|
||||
break;
|
||||
|
||||
/* recreate query from reply */
|
||||
pheader = find_pseudoheader(header, (size_t)n, &plen, NULL, &is_sign, NULL);
|
||||
if (!is_sign)
|
||||
if (!is_sign && server)
|
||||
{
|
||||
header->ancount = htons(0);
|
||||
header->nscount = htons(0);
|
||||
@@ -844,12 +859,18 @@ void reply_query(int fd, int family, time_t now)
|
||||
}
|
||||
|
||||
/* We tried resending to this server with a smaller maximum size and got an answer.
|
||||
Make that permanent. To avoid reduxing the packet size for an single dropped packet,
|
||||
Make that permanent. To avoid reduxing the packet size for a single dropped packet,
|
||||
only do this when we get a truncated answer, or one larger than the safe size. */
|
||||
if (server && (forward->flags & FREC_TEST_PKTSZ) &&
|
||||
if (server && server->edns_pktsz > SAFE_PKTSZ && (forward->flags & FREC_TEST_PKTSZ) &&
|
||||
((header->hb3 & HB3_TC) || n >= SAFE_PKTSZ))
|
||||
server->edns_pktsz = SAFE_PKTSZ;
|
||||
|
||||
{
|
||||
server->edns_pktsz = SAFE_PKTSZ;
|
||||
server->pktsz_reduced = now;
|
||||
prettyprint_addr(&server->addr, daemon->addrbuff);
|
||||
my_syslog(LOG_WARNING, _("reducing DNS packet size for nameserver %s to %d"), daemon->addrbuff, SAFE_PKTSZ);
|
||||
}
|
||||
|
||||
|
||||
/* If the answer is an error, keep the forward record in place in case
|
||||
we get a good reply from another server. Kill it when we've
|
||||
had replies from all to avoid filling the forwarding table when
|
||||
@@ -858,7 +879,7 @@ void reply_query(int fd, int family, time_t now)
|
||||
(RCODE(header) != REFUSED && RCODE(header) != SERVFAIL))
|
||||
{
|
||||
int check_rebind = 0, no_cache_dnssec = 0, cache_secure = 0, bogusanswer = 0;
|
||||
|
||||
|
||||
if (option_bool(OPT_NO_REBIND))
|
||||
check_rebind = !(forward->flags & FREC_NOREBIND);
|
||||
|
||||
@@ -898,7 +919,8 @@ void reply_query(int fd, int family, time_t now)
|
||||
status = dnssec_validate_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class);
|
||||
else
|
||||
status = dnssec_validate_reply(now, header, n, daemon->namebuff, daemon->keyname, &forward->class,
|
||||
option_bool(OPT_DNSSEC_NO_SIGN) && (server->flags & SERV_DO_DNSSEC), NULL, NULL);
|
||||
!option_bool(OPT_DNSSEC_IGN_NS) && (server->flags & SERV_DO_DNSSEC),
|
||||
NULL, NULL);
|
||||
}
|
||||
|
||||
/* Can't validate, as we're missing key data. Put this
|
||||
@@ -1095,7 +1117,7 @@ void reply_query(int fd, int family, time_t now)
|
||||
header->hb4 |= HB4_RA; /* recursion if available */
|
||||
#ifdef HAVE_DNSSEC
|
||||
/* We added an EDNSO header for the purpose of getting DNSSEC RRs, and set the value of the UDP payload size
|
||||
greater than the no-EDNS0-implied 512 to have if space for the RRSIGS. If, having stripped them and the EDNS0
|
||||
greater than the no-EDNS0-implied 512 to have space for the RRSIGS. If, having stripped them and the EDNS0
|
||||
header, the answer is still bigger than 512, truncate it and mark it so. The client then retries with TCP. */
|
||||
if (option_bool(OPT_DNSSEC_VALID) && (forward->flags & FREC_ADDED_PHEADER) && (nn > PACKETSZ))
|
||||
{
|
||||
@@ -1482,7 +1504,8 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si
|
||||
new_status = dnssec_validate_ds(now, header, n, name, keyname, class);
|
||||
else
|
||||
new_status = dnssec_validate_reply(now, header, n, name, keyname, &class,
|
||||
option_bool(OPT_DNSSEC_NO_SIGN) && (server->flags & SERV_DO_DNSSEC), NULL, NULL);
|
||||
!option_bool(OPT_DNSSEC_IGN_NS) && (server->flags & SERV_DO_DNSSEC),
|
||||
NULL, NULL);
|
||||
|
||||
if (new_status != STAT_NEED_DS && new_status != STAT_NEED_KEY)
|
||||
break;
|
||||
@@ -1551,7 +1574,7 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si
|
||||
setsockopt(server->tcpfd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
|
||||
#endif
|
||||
|
||||
if (!local_bind(server->tcpfd, &server->source_addr, server->interface, 1) ||
|
||||
if (!local_bind(server->tcpfd, &server->source_addr, server->interface, 0, 1) ||
|
||||
connect(server->tcpfd, &server->addr.sa, sa_len(&server->addr)) == -1)
|
||||
{
|
||||
close(server->tcpfd);
|
||||
@@ -1783,17 +1806,30 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
struct all_addr *addrp = NULL;
|
||||
int type = SERV_DO_DNSSEC;
|
||||
char *domain = NULL;
|
||||
size_t new_size = add_edns0_config(header, size, ((unsigned char *) header) + 65536, &peer_addr, now, &check_subnet);
|
||||
unsigned char *oph = find_pseudoheader(header, size, NULL, NULL, NULL, NULL);
|
||||
|
||||
size = add_edns0_config(header, size, ((unsigned char *) header) + 65536, &peer_addr, now, &check_subnet);
|
||||
|
||||
if (size != new_size)
|
||||
{
|
||||
added_pheader = 1;
|
||||
size = new_size;
|
||||
}
|
||||
|
||||
if (gotname)
|
||||
flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind);
|
||||
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (option_bool(OPT_DNSSEC_VALID) && (type & SERV_DO_DNSSEC))
|
||||
{
|
||||
size = add_do_bit(header, size, ((unsigned char *) header) + 65536);
|
||||
|
||||
/* For debugging, set Checking Disabled, otherwise, have the upstream check too,
|
||||
this allows it to select auth servers when one is returning bad data. */
|
||||
if (option_bool(OPT_DNSSEC_DEBUG))
|
||||
header->hb4 |= HB4_CD;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Check if we added a pheader on forwarding - may need to
|
||||
strip it from the reply. */
|
||||
if (!oph && find_pseudoheader(header, size, NULL, NULL, NULL, NULL))
|
||||
added_pheader = 1;
|
||||
|
||||
type &= ~SERV_DO_DNSSEC;
|
||||
|
||||
if (type != 0 || option_bool(OPT_ORDER) || !daemon->last_server)
|
||||
@@ -1847,7 +1883,7 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
setsockopt(last_server->tcpfd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
|
||||
#endif
|
||||
|
||||
if ((!local_bind(last_server->tcpfd, &last_server->source_addr, last_server->interface, 1) ||
|
||||
if ((!local_bind(last_server->tcpfd, &last_server->source_addr, last_server->interface, 0, 1) ||
|
||||
connect(last_server->tcpfd, &last_server->addr.sa, sa_len(&last_server->addr)) == -1))
|
||||
{
|
||||
close(last_server->tcpfd);
|
||||
@@ -1858,24 +1894,6 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
last_server->flags &= ~SERV_GOT_TCP;
|
||||
}
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (option_bool(OPT_DNSSEC_VALID) && (last_server->flags & SERV_DO_DNSSEC))
|
||||
{
|
||||
new_size = add_do_bit(header, size, ((unsigned char *) header) + 65536);
|
||||
|
||||
if (size != new_size)
|
||||
{
|
||||
added_pheader = 1;
|
||||
size = new_size;
|
||||
}
|
||||
|
||||
/* For debugging, set Checking Disabled, otherwise, have the upstream check too,
|
||||
this allows it to select auth servers when one is returning bad data. */
|
||||
if (option_bool(OPT_DNSSEC_DEBUG))
|
||||
header->hb4 |= HB4_CD;
|
||||
}
|
||||
#endif
|
||||
|
||||
*length = htons(size);
|
||||
|
||||
/* get query name again for logging - may have been overwritten */
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2017 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2018 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
|
||||
@@ -97,13 +97,14 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
||||
return pipefd[1];
|
||||
}
|
||||
|
||||
/* ignore SIGTERM, so that we can clean up when the main process gets hit
|
||||
/* ignore SIGTERM and SIGINT, so that we can clean up when the main process gets hit
|
||||
and SIGALRM so that we can use sleep() */
|
||||
sigact.sa_handler = SIG_IGN;
|
||||
sigact.sa_flags = 0;
|
||||
sigemptyset(&sigact.sa_mask);
|
||||
sigaction(SIGTERM, &sigact, NULL);
|
||||
sigaction(SIGALRM, &sigact, NULL);
|
||||
sigaction(SIGINT, &sigact, NULL);
|
||||
|
||||
if (!option_bool(OPT_DEBUG) && uid != 0)
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2017 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2018 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
|
||||
@@ -20,7 +20,7 @@
|
||||
#include <sys/inotify.h>
|
||||
#include <sys/param.h> /* For MAXSYMLINKS */
|
||||
|
||||
/* the strategy is to set a inotify on the directories containing
|
||||
/* the strategy is to set an inotify on the directories containing
|
||||
resolv files, for any files in the directory which are close-write
|
||||
or moved into the directory.
|
||||
|
||||
@@ -227,19 +227,21 @@ int inotify_check(time_t now)
|
||||
|
||||
for (p = inotify_buffer; rc - (p - inotify_buffer) >= (int)sizeof(struct inotify_event); p += sizeof(struct inotify_event) + in->len)
|
||||
{
|
||||
size_t namelen;
|
||||
|
||||
in = (struct inotify_event*)p;
|
||||
|
||||
for (res = daemon->resolv_files; res; res = res->next)
|
||||
if (res->wd == in->wd && in->len != 0 && strcmp(res->file, in->name) == 0)
|
||||
hit = 1;
|
||||
|
||||
/* ignore emacs backups and dotfiles */
|
||||
if (in->len == 0 ||
|
||||
in->name[in->len - 1] == '~' ||
|
||||
(in->name[0] == '#' && in->name[in->len - 1] == '#') ||
|
||||
if (in->len == 0 || (namelen = strlen(in->name)) == 0 ||
|
||||
in->name[namelen - 1] == '~' ||
|
||||
(in->name[0] == '#' && in->name[namelen - 1] == '#') ||
|
||||
in->name[0] == '.')
|
||||
continue;
|
||||
|
||||
|
||||
for (res = daemon->resolv_files; res; res = res->next)
|
||||
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)
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2017 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2018 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
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2017 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2018 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
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2017 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2018 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
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2017 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2018 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
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2017 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2018 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
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2017 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2018 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
|
||||
@@ -1149,10 +1149,7 @@ int random_sock(int family)
|
||||
if (fix_fd(fd))
|
||||
while(tries--)
|
||||
{
|
||||
unsigned short port = rand16();
|
||||
|
||||
if (daemon->min_port != 0 || daemon->max_port != MAX_PORT)
|
||||
port = htons(daemon->min_port + (port % ((unsigned short)ports_avail)));
|
||||
unsigned short port = htons(daemon->min_port + (rand16() % ((unsigned short)ports_avail)));
|
||||
|
||||
if (family == AF_INET)
|
||||
{
|
||||
@@ -1187,7 +1184,7 @@ int random_sock(int family)
|
||||
}
|
||||
|
||||
|
||||
int local_bind(int fd, union mysockaddr *addr, char *intname, int is_tcp)
|
||||
int local_bind(int fd, union mysockaddr *addr, char *intname, unsigned int ifindex, int is_tcp)
|
||||
{
|
||||
union mysockaddr addr_copy = *addr;
|
||||
|
||||
@@ -1204,7 +1201,25 @@ int local_bind(int fd, union mysockaddr *addr, char *intname, int is_tcp)
|
||||
|
||||
if (bind(fd, (struct sockaddr *)&addr_copy, sa_len(&addr_copy)) == -1)
|
||||
return 0;
|
||||
|
||||
|
||||
if (!is_tcp && ifindex > 0)
|
||||
{
|
||||
#if defined(IP_UNICAST_IF)
|
||||
if (addr_copy.sa.sa_family == AF_INET)
|
||||
{
|
||||
uint32_t ifindex_opt = htonl(ifindex);
|
||||
return setsockopt(fd, IPPROTO_IP, IP_UNICAST_IF, &ifindex_opt, sizeof(ifindex_opt)) == 0;
|
||||
}
|
||||
#endif
|
||||
#if defined(HAVE_IPV6) && defined (IPV6_UNICAST_IF)
|
||||
if (addr_copy.sa.sa_family == AF_INET6)
|
||||
{
|
||||
uint32_t ifindex_opt = htonl(ifindex);
|
||||
return setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_IF, &ifindex_opt, sizeof(ifindex_opt)) == 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(SO_BINDTODEVICE)
|
||||
if (intname[0] != 0 &&
|
||||
setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, intname, IF_NAMESIZE) == -1)
|
||||
@@ -1219,7 +1234,8 @@ static struct serverfd *allocate_sfd(union mysockaddr *addr, char *intname)
|
||||
struct serverfd *sfd;
|
||||
unsigned int ifindex = 0;
|
||||
int errsave;
|
||||
|
||||
int opt = 1;
|
||||
|
||||
/* when using random ports, servers which would otherwise use
|
||||
the INADDR_ANY/port0 socket have sfd set to NULL */
|
||||
if (!daemon->osport && intname[0] == 0)
|
||||
@@ -1259,10 +1275,11 @@ static struct serverfd *allocate_sfd(union mysockaddr *addr, char *intname)
|
||||
free(sfd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!local_bind(sfd->fd, addr, intname, 0) || !fix_fd(sfd->fd))
|
||||
|
||||
if ((addr->sa.sa_family == AF_INET6 && setsockopt(sfd->fd, IPPROTO_IPV6, IPV6_V6ONLY, &opt, sizeof(opt)) == -1) ||
|
||||
!local_bind(sfd->fd, addr, intname, ifindex, 0) || !fix_fd(sfd->fd))
|
||||
{
|
||||
errsave = errno; /* save error from bind. */
|
||||
errsave = errno; /* save error from bind/setsockopt. */
|
||||
close(sfd->fd);
|
||||
free(sfd);
|
||||
errno = errsave;
|
||||
@@ -1273,6 +1290,7 @@ static struct serverfd *allocate_sfd(union mysockaddr *addr, char *intname)
|
||||
sfd->source_addr = *addr;
|
||||
sfd->next = daemon->sfds;
|
||||
sfd->ifindex = ifindex;
|
||||
sfd->preallocated = 0;
|
||||
daemon->sfds = sfd;
|
||||
|
||||
return sfd;
|
||||
@@ -1283,6 +1301,7 @@ static struct serverfd *allocate_sfd(union mysockaddr *addr, char *intname)
|
||||
void pre_allocate_sfds(void)
|
||||
{
|
||||
struct server *srv;
|
||||
struct serverfd *sfd;
|
||||
|
||||
if (daemon->query_port != 0)
|
||||
{
|
||||
@@ -1294,7 +1313,8 @@ void pre_allocate_sfds(void)
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
addr.in.sin_len = sizeof(struct sockaddr_in);
|
||||
#endif
|
||||
allocate_sfd(&addr, "");
|
||||
if ((sfd = allocate_sfd(&addr, "")))
|
||||
sfd->preallocated = 1;
|
||||
#ifdef HAVE_IPV6
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.in6.sin6_family = AF_INET6;
|
||||
@@ -1303,7 +1323,8 @@ void pre_allocate_sfds(void)
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
addr.in6.sin6_len = sizeof(struct sockaddr_in6);
|
||||
#endif
|
||||
allocate_sfd(&addr, "");
|
||||
if ((sfd = allocate_sfd(&addr, "")))
|
||||
sfd->preallocated = 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1456,16 +1477,10 @@ void check_servers(void)
|
||||
/* interface may be new since startup */
|
||||
if (!option_bool(OPT_NOWILD))
|
||||
enumerate_interfaces(0);
|
||||
|
||||
for (sfd = daemon->sfds; sfd; sfd = sfd->next)
|
||||
sfd->used = 0;
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
/* Disable DNSSEC validation when using server=/domain/.... servers
|
||||
unless there's a configured trust anchor. */
|
||||
for (serv = daemon->servers; serv; serv = serv->next)
|
||||
serv->flags |= SERV_DO_DNSSEC;
|
||||
#endif
|
||||
/* don't garbage collect pre-allocated sfds. */
|
||||
for (sfd = daemon->sfds; sfd; sfd = sfd->next)
|
||||
sfd->used = sfd->preallocated;
|
||||
|
||||
for (count = 0, serv = daemon->servers; serv; serv = serv->next)
|
||||
{
|
||||
@@ -1478,6 +1493,11 @@ void check_servers(void)
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (option_bool(OPT_DNSSEC_VALID))
|
||||
{
|
||||
if (!(serv->flags & SERV_FOR_NODOTS))
|
||||
serv->flags |= SERV_DO_DNSSEC;
|
||||
|
||||
/* Disable DNSSEC validation when using server=/domain/.... servers
|
||||
unless there's a configured trust anchor. */
|
||||
if (serv->flags & SERV_HAS_DOMAIN)
|
||||
{
|
||||
struct ds_config *ds;
|
||||
@@ -1494,8 +1514,6 @@ void check_servers(void)
|
||||
if (!ds)
|
||||
serv->flags &= ~SERV_DO_DNSSEC;
|
||||
}
|
||||
else if (serv->flags & SERV_FOR_NODOTS)
|
||||
serv->flags &= ~SERV_DO_DNSSEC;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
235
src/option.c
235
src/option.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2017 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2018 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
|
||||
@@ -160,6 +160,7 @@ struct myoption {
|
||||
#define LOPT_DHCPTTL 348
|
||||
#define LOPT_TFTP_MTU 349
|
||||
#define LOPT_REPLY_DELAY 350
|
||||
#define LOPT_RAPID_COMMIT 351
|
||||
|
||||
#ifdef HAVE_GETOPT_LONG
|
||||
static const struct option opts[] =
|
||||
@@ -310,7 +311,7 @@ static const struct myoption opts[] =
|
||||
{ "dnssec", 0, 0, LOPT_SEC_VALID },
|
||||
{ "trust-anchor", 1, 0, LOPT_TRUST_ANCHOR },
|
||||
{ "dnssec-debug", 0, 0, LOPT_DNSSEC_DEBUG },
|
||||
{ "dnssec-check-unsigned", 0, 0, LOPT_DNSSEC_CHECK },
|
||||
{ "dnssec-check-unsigned", 2, 0, LOPT_DNSSEC_CHECK },
|
||||
{ "dnssec-no-timecheck", 0, 0, LOPT_DNSSEC_TIME },
|
||||
{ "dnssec-timestamp", 1, 0, LOPT_DNSSEC_STAMP },
|
||||
#ifdef OPTION6_PREFIX_CLASS
|
||||
@@ -325,6 +326,7 @@ static const struct myoption opts[] =
|
||||
{ "script-arp", 0, 0, LOPT_SCRIPT_ARP },
|
||||
{ "dhcp-ttl", 1, 0 , LOPT_DHCPTTL },
|
||||
{ "dhcp-reply-delay", 1, 0, LOPT_REPLY_DELAY },
|
||||
{ "dhcp-rapid-commit", 0, 0, LOPT_RAPID_COMMIT },
|
||||
{ NULL, 0, 0, 0 }
|
||||
};
|
||||
|
||||
@@ -482,7 +484,7 @@ static struct {
|
||||
{ LOPT_SEC_VALID, OPT_DNSSEC_VALID, NULL, gettext_noop("Activate DNSSEC validation"), NULL },
|
||||
{ LOPT_TRUST_ANCHOR, ARG_DUP, "<domain>,[<class>],...", gettext_noop("Specify trust anchor key digest."), NULL },
|
||||
{ LOPT_DNSSEC_DEBUG, OPT_DNSSEC_DEBUG, NULL, gettext_noop("Disable upstream checking for DNSSEC debugging."), NULL },
|
||||
{ LOPT_DNSSEC_CHECK, OPT_DNSSEC_NO_SIGN, NULL, gettext_noop("Ensure answers without DNSSEC are in unsigned zones."), NULL },
|
||||
{ LOPT_DNSSEC_CHECK, ARG_DUP, NULL, gettext_noop("Ensure answers without DNSSEC are in unsigned zones."), NULL },
|
||||
{ LOPT_DNSSEC_TIME, OPT_DNSSEC_TIME, NULL, gettext_noop("Don't check DNSSEC signature timestamps until first cache-reload"), NULL },
|
||||
{ LOPT_DNSSEC_STAMP, ARG_ONE, "<path>", gettext_noop("Timestamp file to verify system clock for DNSSEC"), NULL },
|
||||
#ifdef OPTION6_PREFIX_CLASS
|
||||
@@ -497,6 +499,7 @@ static struct {
|
||||
{ LOPT_IGNORE_ADDR, ARG_DUP, "<ipaddr>", gettext_noop("Ignore DNS responses containing ipaddr."), NULL },
|
||||
{ LOPT_DHCPTTL, ARG_ONE, "<ttl>", gettext_noop("Set TTL in DNS responses with DHCP-derived addresses."), NULL },
|
||||
{ LOPT_REPLY_DELAY, ARG_ONE, "<integer>", gettext_noop("Delay DHCP replies for at least number of seconds."), NULL },
|
||||
{ LOPT_RAPID_COMMIT, OPT_RAPID_COMMIT, NULL, gettext_noop("Enables DHCPv4 Rapid Commit option."), NULL },
|
||||
{ 0, 0, NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
@@ -1163,7 +1166,7 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
|
||||
case 'd':
|
||||
case 'D':
|
||||
fac *= 24;
|
||||
/* fall though */
|
||||
/* fall through */
|
||||
case 'h':
|
||||
case 'H':
|
||||
fac *= 60;
|
||||
@@ -2071,7 +2074,8 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
char *netpart;
|
||||
|
||||
new->prefix = NULL;
|
||||
|
||||
new->indexed = 0;
|
||||
|
||||
unhide_metas(comma);
|
||||
if ((netpart = split_chr(comma, '/')))
|
||||
{
|
||||
@@ -2208,8 +2212,14 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
}
|
||||
else
|
||||
{
|
||||
char *star;
|
||||
new->next = daemon->synth_domains;
|
||||
daemon->synth_domains = new;
|
||||
if ((star = strrchr(new->prefix, '*')) && *(star+1) == 0)
|
||||
{
|
||||
*star = 0;
|
||||
new->indexed = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (option == 's')
|
||||
@@ -2733,15 +2743,24 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
|
||||
case LOPT_BRIDGE: /* --bridge-interface */
|
||||
{
|
||||
struct dhcp_bridge *new = opt_malloc(sizeof(struct dhcp_bridge));
|
||||
struct dhcp_bridge *new;
|
||||
|
||||
if (!(comma = split(arg)) || strlen(arg) > IF_NAMESIZE - 1 )
|
||||
ret_err(_("bad bridge-interface"));
|
||||
|
||||
strcpy(new->iface, arg);
|
||||
new->alias = NULL;
|
||||
new->next = daemon->bridges;
|
||||
daemon->bridges = new;
|
||||
|
||||
for (new = daemon->bridges; new; new = new->next)
|
||||
if (strcmp(new->iface, arg) == 0)
|
||||
break;
|
||||
|
||||
if (!new)
|
||||
{
|
||||
new = opt_malloc(sizeof(struct dhcp_bridge));
|
||||
strcpy(new->iface, arg);
|
||||
new->alias = NULL;
|
||||
new->next = daemon->bridges;
|
||||
daemon->bridges = new;
|
||||
}
|
||||
|
||||
do {
|
||||
arg = comma;
|
||||
comma = split(arg);
|
||||
@@ -2961,7 +2980,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
case 'd':
|
||||
case 'D':
|
||||
fac *= 24;
|
||||
/* fall though */
|
||||
/* fall through */
|
||||
case 'h':
|
||||
case 'H':
|
||||
fac *= 60;
|
||||
@@ -3847,6 +3866,7 @@ err:
|
||||
|
||||
while (arg != last)
|
||||
{
|
||||
int arglen = strlen(arg);
|
||||
alias = canonicalise_opt(arg);
|
||||
|
||||
if (!alias || !target)
|
||||
@@ -3862,7 +3882,7 @@ err:
|
||||
new->target = target;
|
||||
new->ttl = ttl;
|
||||
|
||||
arg += strlen(arg)+1;
|
||||
for (arg += arglen+1; *arg && isspace(*arg); arg++);
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -4119,6 +4139,16 @@ err:
|
||||
daemon->timestamp_file = opt_string_alloc(arg);
|
||||
break;
|
||||
|
||||
case LOPT_DNSSEC_CHECK:
|
||||
if (arg)
|
||||
{
|
||||
if (strcmp(arg, "no") == 0)
|
||||
set_option_bool(OPT_DNSSEC_IGN_NS);
|
||||
else
|
||||
ret_err(_("bad value for dnssec-check-unsigned"));
|
||||
}
|
||||
break;
|
||||
|
||||
case LOPT_TRUST_ANCHOR:
|
||||
{
|
||||
struct ds_config *new = opt_malloc(sizeof(struct ds_config));
|
||||
@@ -4318,7 +4348,7 @@ static void read_file(char *file, FILE *f, int hard_opt)
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
#ifdef HAVE_DHCP
|
||||
#if defined(HAVE_DHCP) && defined(HAVE_INOTIFY)
|
||||
int option_read_dynfile(char *file, int flags)
|
||||
{
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("read %s"), file);
|
||||
@@ -4519,86 +4549,99 @@ void read_servers_file(void)
|
||||
|
||||
|
||||
#ifdef HAVE_DHCP
|
||||
static void clear_dynamic_conf(void)
|
||||
{
|
||||
struct dhcp_config *configs, *cp, **up;
|
||||
|
||||
/* remove existing... */
|
||||
for (up = &daemon->dhcp_conf, configs = daemon->dhcp_conf; configs; configs = cp)
|
||||
{
|
||||
cp = configs->next;
|
||||
|
||||
if (configs->flags & CONFIG_BANK)
|
||||
{
|
||||
struct hwaddr_config *mac, *tmp;
|
||||
struct dhcp_netid_list *list, *tmplist;
|
||||
|
||||
for (mac = configs->hwaddr; mac; mac = tmp)
|
||||
{
|
||||
tmp = mac->next;
|
||||
free(mac);
|
||||
}
|
||||
|
||||
if (configs->flags & CONFIG_CLID)
|
||||
free(configs->clid);
|
||||
|
||||
for (list = configs->netid; list; list = tmplist)
|
||||
{
|
||||
free(list->list);
|
||||
tmplist = list->next;
|
||||
free(list);
|
||||
}
|
||||
|
||||
if (configs->flags & CONFIG_NAME)
|
||||
free(configs->hostname);
|
||||
|
||||
*up = configs->next;
|
||||
free(configs);
|
||||
}
|
||||
else
|
||||
up = &configs->next;
|
||||
}
|
||||
}
|
||||
|
||||
static void clear_dynamic_opt(void)
|
||||
{
|
||||
struct dhcp_opt *opts, *cp, **up;
|
||||
struct dhcp_netid *id, *next;
|
||||
|
||||
for (up = &daemon->dhcp_opts, opts = daemon->dhcp_opts; opts; opts = cp)
|
||||
{
|
||||
cp = opts->next;
|
||||
|
||||
if (opts->flags & DHOPT_BANK)
|
||||
{
|
||||
if ((opts->flags & DHOPT_VENDOR))
|
||||
free(opts->u.vendor_class);
|
||||
free(opts->val);
|
||||
for (id = opts->netid; id; id = next)
|
||||
{
|
||||
next = id->next;
|
||||
free(id->net);
|
||||
free(id);
|
||||
}
|
||||
*up = opts->next;
|
||||
free(opts);
|
||||
}
|
||||
else
|
||||
up = &opts->next;
|
||||
}
|
||||
}
|
||||
|
||||
void reread_dhcp(void)
|
||||
{
|
||||
struct hostsfile *hf;
|
||||
struct hostsfile *hf;
|
||||
|
||||
if (daemon->dhcp_hosts_file)
|
||||
/* Do these even if there is no daemon->dhcp_hosts_file or
|
||||
daemon->dhcp_opts_file since entries may have been created by the
|
||||
inotify dynamic file reading system. */
|
||||
|
||||
clear_dynamic_conf();
|
||||
clear_dynamic_opt();
|
||||
|
||||
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)
|
||||
{
|
||||
cp = configs->next;
|
||||
|
||||
if (configs->flags & CONFIG_BANK)
|
||||
{
|
||||
struct hwaddr_config *mac, *tmp;
|
||||
struct dhcp_netid_list *list, *tmplist;
|
||||
|
||||
for (mac = configs->hwaddr; mac; mac = tmp)
|
||||
{
|
||||
tmp = mac->next;
|
||||
free(mac);
|
||||
}
|
||||
|
||||
if (configs->flags & CONFIG_CLID)
|
||||
free(configs->clid);
|
||||
|
||||
for (list = configs->netid; list; list = tmplist)
|
||||
{
|
||||
free(list->list);
|
||||
tmplist = list->next;
|
||||
free(list);
|
||||
}
|
||||
|
||||
if (configs->flags & CONFIG_NAME)
|
||||
free(configs->hostname);
|
||||
|
||||
*up = configs->next;
|
||||
free(configs);
|
||||
}
|
||||
else
|
||||
up = &configs->next;
|
||||
}
|
||||
|
||||
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))
|
||||
{
|
||||
if (one_file(hf->fname, LOPT_BANK))
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("read %s"), hf->fname);
|
||||
}
|
||||
if (!(hf->flags & AH_INACTIVE))
|
||||
{
|
||||
if (one_file(hf->fname, LOPT_BANK))
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("read %s"), hf->fname);
|
||||
}
|
||||
}
|
||||
|
||||
if (daemon->dhcp_opts_file)
|
||||
{
|
||||
struct dhcp_opt *opts, *cp, **up;
|
||||
struct dhcp_netid *id, *next;
|
||||
|
||||
for (up = &daemon->dhcp_opts, opts = daemon->dhcp_opts; opts; opts = cp)
|
||||
{
|
||||
cp = opts->next;
|
||||
|
||||
if (opts->flags & DHOPT_BANK)
|
||||
{
|
||||
if ((opts->flags & DHOPT_VENDOR))
|
||||
free(opts->u.vendor_class);
|
||||
free(opts->val);
|
||||
for (id = opts->netid; id; id = next)
|
||||
{
|
||||
next = id->next;
|
||||
free(id->net);
|
||||
free(id);
|
||||
}
|
||||
*up = opts->next;
|
||||
free(opts);
|
||||
}
|
||||
else
|
||||
up = &opts->next;
|
||||
}
|
||||
|
||||
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))
|
||||
@@ -4607,11 +4650,18 @@ void reread_dhcp(void)
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("read %s"), hf->fname);
|
||||
}
|
||||
}
|
||||
|
||||
# ifdef HAVE_INOTIFY
|
||||
/* Setup notify and read pre-existing files. */
|
||||
set_dynamic_inotify(AH_DHCP_HST | AH_DHCP_OPT, 0, NULL, 0);
|
||||
# endif
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void read_opts(int argc, char **argv, char *compile_opts)
|
||||
{
|
||||
size_t argbuf_size = MAXDNAME;
|
||||
char *argbuf = opt_malloc(argbuf_size);
|
||||
char *buff = opt_malloc(MAXDNAME);
|
||||
int option, conffile_opt = '7', testmode = 0;
|
||||
char *arg, *conffile = CONFFILE;
|
||||
@@ -4642,6 +4692,7 @@ void read_opts(int argc, char **argv, char *compile_opts)
|
||||
daemon->soa_retry = SOA_RETRY;
|
||||
daemon->soa_expiry = SOA_EXPIRY;
|
||||
daemon->max_port = MAX_PORT;
|
||||
daemon->min_port = MIN_PORT;
|
||||
|
||||
#ifndef NO_ID
|
||||
add_txt("version.bind", "dnsmasq-" VERSION, 0 );
|
||||
@@ -4681,9 +4732,15 @@ void read_opts(int argc, char **argv, char *compile_opts)
|
||||
/* Copy optarg so that argv doesn't get changed */
|
||||
if (optarg)
|
||||
{
|
||||
strncpy(buff, optarg, MAXDNAME);
|
||||
buff[MAXDNAME-1] = 0;
|
||||
arg = buff;
|
||||
if (strlen(optarg) >= argbuf_size)
|
||||
{
|
||||
free(argbuf);
|
||||
argbuf_size = strlen(optarg) + 1;
|
||||
argbuf = opt_malloc(argbuf_size);
|
||||
}
|
||||
strncpy(argbuf, optarg, argbuf_size);
|
||||
argbuf[argbuf_size-1] = 0;
|
||||
arg = argbuf;
|
||||
}
|
||||
else
|
||||
arg = NULL;
|
||||
@@ -4731,6 +4788,8 @@ void read_opts(int argc, char **argv, char *compile_opts)
|
||||
}
|
||||
}
|
||||
|
||||
free(argbuf);
|
||||
|
||||
if (conffile)
|
||||
{
|
||||
one_file(conffile, conffile_opt);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2017 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2018 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
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2017 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2018 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
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2017 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2018 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
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2017 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2018 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
|
||||
@@ -407,7 +407,7 @@ static void send_ra_alias(time_t now, int iface, char *iface_name, struct in6_ad
|
||||
if (ra_param)
|
||||
mtu = ra_param->mtu;
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
/* Note that IPv6 MTU is not neccessarily the same as the IPv4 MTU
|
||||
/* Note that IPv6 MTU is not necessarily the same as the IPv4 MTU
|
||||
available from SIOCGIFMTU */
|
||||
if (mtu == 0)
|
||||
{
|
||||
|
||||
163
src/rfc1035.c
163
src/rfc1035.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2017 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2018 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
|
||||
@@ -36,7 +36,7 @@ int extract_name(struct dns_header *header, size_t plen, unsigned char **pp,
|
||||
if ((l = *p++) == 0)
|
||||
/* end marker */
|
||||
{
|
||||
/* check that there are the correct no of bytes after the name */
|
||||
/* check that there are the correct no. of bytes after the name */
|
||||
if (!CHECK_LEN(header, p1 ? p1 : p, plen, extrabytes))
|
||||
return 0;
|
||||
|
||||
@@ -156,7 +156,7 @@ int in_arpa_name_2_addr(char *namein, struct all_addr *addrp)
|
||||
memset(addrp, 0, sizeof(struct all_addr));
|
||||
|
||||
/* turn name into a series of asciiz strings */
|
||||
/* j counts no of labels */
|
||||
/* j counts no. of labels */
|
||||
for(j = 1,cp1 = name; *namein; cp1++, namein++)
|
||||
if (*namein == '.')
|
||||
{
|
||||
@@ -584,7 +584,8 @@ static int find_soa(struct dns_header *header, size_t qlen, char *name, int *doc
|
||||
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(struct dns_header *header, size_t qlen, char *name, time_t now,
|
||||
char **ipsets, int is_sign, int check_rebind, int no_cache_dnssec, int secure, int *doctored)
|
||||
char **ipsets, int is_sign, int check_rebind, int no_cache_dnssec,
|
||||
int secure, int *doctored)
|
||||
{
|
||||
unsigned char *p, *p1, *endrr, *namep;
|
||||
int i, j, qtype, qclass, aqtype, aqclass, ardlen, res, searched_soa = 0;
|
||||
@@ -595,6 +596,7 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
|
||||
#else
|
||||
(void)ipsets; /* unused */
|
||||
#endif
|
||||
|
||||
|
||||
cache_start_insert();
|
||||
|
||||
@@ -603,10 +605,18 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
|
||||
{
|
||||
searched_soa = 1;
|
||||
ttl = find_soa(header, qlen, name, doctored);
|
||||
|
||||
if (*doctored)
|
||||
{
|
||||
if (secure)
|
||||
return 0;
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (*doctored && secure)
|
||||
return 0;
|
||||
if (option_bool(OPT_DNSSEC_VALID))
|
||||
for (i = 0; i < ntohs(header->ancount); i++)
|
||||
if (daemon->rr_status[i])
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/* go through the questions. */
|
||||
@@ -617,7 +627,9 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
|
||||
int found = 0, cname_count = CNAME_CHAIN;
|
||||
struct crec *cpp = NULL;
|
||||
int flags = RCODE(header) == NXDOMAIN ? F_NXDOMAIN : 0;
|
||||
int secflag = secure ? F_DNSSECOK : 0;
|
||||
#ifdef HAVE_DNSSEC
|
||||
int cname_short = 0;
|
||||
#endif
|
||||
unsigned long cttl = ULONG_MAX, attl;
|
||||
|
||||
namep = p;
|
||||
@@ -645,8 +657,9 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
|
||||
if (!(p1 = skip_questions(header, qlen)))
|
||||
return 0;
|
||||
|
||||
for (j = ntohs(header->ancount); j != 0; j--)
|
||||
for (j = 0; j < ntohs(header->ancount); j++)
|
||||
{
|
||||
int secflag = 0;
|
||||
unsigned char *tmp = namep;
|
||||
/* the loop body overwrites the original name, so get it back here. */
|
||||
if (!extract_name(header, qlen, &tmp, name, 1, 0) ||
|
||||
@@ -672,11 +685,24 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
|
||||
{
|
||||
if (!extract_name(header, qlen, &p1, name, 1, 0))
|
||||
return 0;
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (option_bool(OPT_DNSSEC_VALID) && daemon->rr_status[j])
|
||||
{
|
||||
/* validated RR anywhere in CNAME chain, don't cache. */
|
||||
if (cname_short || aqtype == T_CNAME)
|
||||
return 0;
|
||||
|
||||
secflag = F_DNSSECOK;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (aqtype == T_CNAME)
|
||||
{
|
||||
if (!cname_count-- || secure)
|
||||
return 0; /* looped CNAMES, or DNSSEC, which we can't cache. */
|
||||
if (!cname_count--)
|
||||
return 0; /* looped CNAMES, we can't cache. */
|
||||
#ifdef HAVE_DNSSEC
|
||||
cname_short = 1;
|
||||
#endif
|
||||
goto cname_loop;
|
||||
}
|
||||
|
||||
@@ -698,7 +724,7 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
|
||||
ttl = find_soa(header, qlen, NULL, doctored);
|
||||
}
|
||||
if (ttl)
|
||||
cache_insert(NULL, &addr, now, ttl, name_encoding | F_REVERSE | F_NEG | flags | secflag);
|
||||
cache_insert(NULL, &addr, now, ttl, name_encoding | F_REVERSE | F_NEG | flags | (secure ? F_DNSSECOK : 0));
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -726,8 +752,10 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
|
||||
if (!(p1 = skip_questions(header, qlen)))
|
||||
return 0;
|
||||
|
||||
for (j = ntohs(header->ancount); j != 0; j--)
|
||||
for (j = 0; j < ntohs(header->ancount); j++)
|
||||
{
|
||||
int secflag = 0;
|
||||
|
||||
if (!(res = extract_name(header, qlen, &p1, name, 0, 10)))
|
||||
return 0; /* bad packet */
|
||||
|
||||
@@ -744,6 +772,10 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
|
||||
|
||||
if (aqclass == C_IN && res != 2 && (aqtype == T_CNAME || aqtype == qtype))
|
||||
{
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (option_bool(OPT_DNSSEC_VALID) && daemon->rr_status[j])
|
||||
secflag = F_DNSSECOK;
|
||||
#endif
|
||||
if (aqtype == T_CNAME)
|
||||
{
|
||||
if (!cname_count--)
|
||||
@@ -835,7 +867,7 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
|
||||
pointing at this, inherit its TTL */
|
||||
if (ttl || cpp)
|
||||
{
|
||||
newc = cache_insert(name, NULL, now, ttl ? ttl : cttl, F_FORWARD | F_NEG | flags | secflag);
|
||||
newc = cache_insert(name, NULL, now, ttl ? ttl : cttl, F_FORWARD | F_NEG | flags | (secure ? F_DNSSECOK : 0));
|
||||
if (newc && cpp)
|
||||
{
|
||||
cpp->addr.cname.target.cache = newc;
|
||||
@@ -915,6 +947,8 @@ size_t setup_reply(struct dns_header *header, size_t qlen,
|
||||
SET_RCODE(header, NOERROR); /* empty domain */
|
||||
else if (flags == F_NXDOMAIN)
|
||||
SET_RCODE(header, NXDOMAIN);
|
||||
else if (flags == F_SERVFAIL)
|
||||
SET_RCODE(header, SERVFAIL);
|
||||
else if (flags == F_IPV4)
|
||||
{ /* we know the address */
|
||||
SET_RCODE(header, NOERROR);
|
||||
@@ -950,7 +984,7 @@ int check_for_local_domain(char *name, time_t now)
|
||||
/* Note: the call to cache_find_by_name is intended to find any record which matches
|
||||
ie A, AAAA, CNAME. */
|
||||
|
||||
if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6 | F_CNAME |F_NO_RR)) &&
|
||||
if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6 | F_CNAME | F_NO_RR)) &&
|
||||
(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
|
||||
return 1;
|
||||
|
||||
@@ -1074,18 +1108,15 @@ int add_resource_record(struct dns_header *header, char *limit, int *truncp, int
|
||||
unsigned short usval;
|
||||
long lval;
|
||||
char *sval;
|
||||
|
||||
#define CHECK_LIMIT(size) \
|
||||
if (limit && p + (size) > (unsigned char*)limit) \
|
||||
{ \
|
||||
va_end(ap); \
|
||||
goto truncated; \
|
||||
}
|
||||
|
||||
if (truncp && *truncp)
|
||||
return 0;
|
||||
if (limit && p + (size) > (unsigned char*)limit) goto truncated;
|
||||
|
||||
va_start(ap, format); /* make ap point to 1st unamed argument */
|
||||
|
||||
|
||||
if (truncp && *truncp)
|
||||
goto truncated;
|
||||
|
||||
if (nameoffset > 0)
|
||||
{
|
||||
CHECK_LIMIT(2);
|
||||
@@ -1095,10 +1126,7 @@ int add_resource_record(struct dns_header *header, char *limit, int *truncp, int
|
||||
{
|
||||
char *name = va_arg(ap, char *);
|
||||
if (name && !(p = do_rfc1035_name(p, name, limit)))
|
||||
{
|
||||
va_end(ap);
|
||||
goto truncated;
|
||||
}
|
||||
goto truncated;
|
||||
|
||||
if (nameoffset < 0)
|
||||
{
|
||||
@@ -1163,13 +1191,9 @@ int add_resource_record(struct dns_header *header, char *limit, int *truncp, int
|
||||
/* get domain-name answer arg and store it in RDATA field */
|
||||
if (offset)
|
||||
*offset = p - (unsigned char *)header;
|
||||
p = do_rfc1035_name(p, va_arg(ap, char *), limit);
|
||||
if (!p)
|
||||
{
|
||||
va_end(ap);
|
||||
goto truncated;
|
||||
}
|
||||
CHECK_LIMIT(1);
|
||||
if (!(p = do_rfc1035_name(p, va_arg(ap, char *), limit)))
|
||||
goto truncated;
|
||||
CHECK_LIMIT(1);
|
||||
*p++ = 0;
|
||||
break;
|
||||
|
||||
@@ -1194,24 +1218,22 @@ int add_resource_record(struct dns_header *header, char *limit, int *truncp, int
|
||||
break;
|
||||
}
|
||||
|
||||
#undef CHECK_LIMIT
|
||||
va_end(ap); /* clean up variable argument pointer */
|
||||
|
||||
/* Now, store real RDLength. sav already checked against limit. */
|
||||
j = p - sav - 2;
|
||||
/* this has already been checked against limit before */
|
||||
PUTSHORT(j, sav); /* Now, store real RDLength */
|
||||
|
||||
/* check for overflow of buffer */
|
||||
if (limit && ((unsigned char *)limit - p) < 0)
|
||||
{
|
||||
truncated:
|
||||
if (truncp)
|
||||
*truncp = 1;
|
||||
return 0;
|
||||
}
|
||||
PUTSHORT(j, sav);
|
||||
|
||||
*pp = p;
|
||||
return 1;
|
||||
|
||||
truncated:
|
||||
va_end(ap);
|
||||
if (truncp)
|
||||
*truncp = 1;
|
||||
return 0;
|
||||
|
||||
#undef CHECK_LIMIT
|
||||
}
|
||||
|
||||
static unsigned long crec_ttl(struct crec *crecp, time_t now)
|
||||
@@ -1265,6 +1287,10 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
ntohs(header->qdcount) == 0 ||
|
||||
OPCODE(header) != QUERY )
|
||||
return 0;
|
||||
|
||||
/* always servfail queries with RD unset, to avoid cache snooping. */
|
||||
if (!(header->hb3 & HB3_RD))
|
||||
return setup_reply(header, qlen, NULL, F_SERVFAIL, 0);
|
||||
|
||||
/* Don't return AD set if checking disabled. */
|
||||
if (header->hb4 & HB4_CD)
|
||||
@@ -1542,44 +1568,6 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
if (qtype != type && qtype != T_ANY)
|
||||
continue;
|
||||
|
||||
/* Check for "A for A" queries; be rather conservative
|
||||
about what looks like dotted-quad. */
|
||||
if (qtype == T_A)
|
||||
{
|
||||
char *cp;
|
||||
unsigned int i, a;
|
||||
int x;
|
||||
|
||||
for (cp = name, i = 0, a = 0; *cp; i++)
|
||||
{
|
||||
if (!isdigit((unsigned char)*cp) || (x = strtol(cp, &cp, 10)) > 255)
|
||||
{
|
||||
i = 5;
|
||||
break;
|
||||
}
|
||||
|
||||
a = (a << 8) + x;
|
||||
|
||||
if (*cp == '.')
|
||||
cp++;
|
||||
}
|
||||
|
||||
if (i == 4)
|
||||
{
|
||||
ans = 1;
|
||||
sec_data = 0;
|
||||
if (!dryrun)
|
||||
{
|
||||
addr.addr.addr4.s_addr = htonl(a);
|
||||
log_query(F_FORWARD | F_CONFIG | F_IPV4, name, &addr, NULL);
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
daemon->local_ttl, NULL, type, C_IN, "4", &addr))
|
||||
anscount++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* interface name stuff */
|
||||
intname_restart:
|
||||
for (intr = daemon->int_names; intr; intr = intr->next)
|
||||
@@ -1748,8 +1736,9 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
|
||||
if (qtype == T_CNAME || qtype == T_ANY)
|
||||
{
|
||||
if ((crecp = cache_find_by_name(NULL, name, now, F_CNAME)) &&
|
||||
(qtype == T_CNAME || (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG | (dryrun ? F_NO_RR : 0)))))
|
||||
if ((crecp = cache_find_by_name(NULL, name, now, F_CNAME | (dryrun ? F_NO_RR : 0))) &&
|
||||
(qtype == T_CNAME || (crecp->flags & F_CONFIG)) &&
|
||||
((crecp->flags & F_CONFIG) || !do_bit || !(crecp->flags & F_DNSSECOK)))
|
||||
{
|
||||
if (!(crecp->flags & F_DNSSECOK))
|
||||
sec_data = 0;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2017 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2018 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 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
struct dhcp_vendor *vendor;
|
||||
struct dhcp_mac *mac;
|
||||
struct dhcp_netid_list *id_list;
|
||||
int clid_len = 0, ignore = 0, do_classes = 0, selecting = 0, pxearch = -1;
|
||||
int clid_len = 0, ignore = 0, do_classes = 0, rapid_commit = 0, selecting = 0, pxearch = -1;
|
||||
struct dhcp_packet *mess = (struct dhcp_packet *)daemon->dhcp_packet.iov_base;
|
||||
unsigned char *end = (unsigned char *)(mess + 1);
|
||||
unsigned char *real_end = (unsigned char *)(mess + 1);
|
||||
@@ -909,7 +909,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
|
||||
if (!workaround && boot)
|
||||
{
|
||||
/* Provide the bootfile here, for gPXE, and in case we have no menu items
|
||||
/* Provide the bootfile here, for iPXE, and in case we have no menu items
|
||||
and set discovery_control = 8 */
|
||||
if (boot->next_server.s_addr)
|
||||
mess->siaddr = boot->next_server;
|
||||
@@ -1073,6 +1073,13 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
|
||||
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;
|
||||
goto rapid_commit;
|
||||
}
|
||||
|
||||
log_packet("DHCPOFFER" , &mess->yiaddr, emac, emac_len, iface_name, NULL, NULL, mess->xid);
|
||||
|
||||
time = calc_time(context, config, option_find(mess, sz, OPTION_LEASE_TIME, 4));
|
||||
@@ -1085,7 +1092,8 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now, time, fuzz);
|
||||
|
||||
return dhcp_packet_size(mess, agent_id, real_end);
|
||||
|
||||
|
||||
|
||||
case DHCPREQUEST:
|
||||
if (ignore || have_config(config, CONFIG_DISABLE))
|
||||
return 0;
|
||||
@@ -1183,9 +1191,10 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
fuzz = rand16();
|
||||
mess->yiaddr = mess->ciaddr;
|
||||
}
|
||||
|
||||
|
||||
log_packet("DHCPREQUEST", &mess->yiaddr, emac, emac_len, iface_name, NULL, NULL, mess->xid);
|
||||
|
||||
|
||||
rapid_commit:
|
||||
if (!message)
|
||||
{
|
||||
struct dhcp_config *addr_config;
|
||||
@@ -1256,7 +1265,11 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
|
||||
if (message)
|
||||
{
|
||||
log_packet("DHCPNAK", &mess->yiaddr, emac, emac_len, iface_name, NULL, message, mess->xid);
|
||||
log_packet(rapid_commit ? "NOANSWER" : "DHCPNAK", &mess->yiaddr, emac, emac_len, iface_name, NULL, message, mess->xid);
|
||||
|
||||
/* rapid commit case: lease allocate failed but don't send DHCPNAK */
|
||||
if (rapid_commit)
|
||||
return 0;
|
||||
|
||||
mess->yiaddr.s_addr = 0;
|
||||
clear_packet(mess, end);
|
||||
@@ -1414,12 +1427,14 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
override = lease->override;
|
||||
|
||||
log_packet("DHCPACK", &mess->yiaddr, emac, emac_len, iface_name, hostname, NULL, mess->xid);
|
||||
|
||||
|
||||
clear_packet(mess, end);
|
||||
option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);
|
||||
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(server_id(context, override, fallback).s_addr));
|
||||
option_put(mess, end, OPTION_LEASE_TIME, 4, time);
|
||||
do_options(context, mess, end, req_options, hostname, get_domain(mess->yiaddr),
|
||||
if (rapid_commit)
|
||||
option_put(mess, end, OPTION_RAPID_COMMIT, 0, 0);
|
||||
do_options(context, mess, end, req_options, hostname, get_domain(mess->yiaddr),
|
||||
netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now, time, fuzz);
|
||||
}
|
||||
|
||||
@@ -2284,7 +2299,7 @@ static void do_options(struct dhcp_context *context,
|
||||
/* See if we can send the boot stuff as options.
|
||||
To do this we need a requested option list, BOOTP
|
||||
and very old DHCP clients won't have this, we also
|
||||
provide an manual option to disable it.
|
||||
provide a manual option to disable it.
|
||||
Some PXE ROMs have bugs (surprise!) and need zero-terminated
|
||||
names, so we always send those. */
|
||||
if ((boot = find_boot(tagif)))
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2017 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2018 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
|
||||
@@ -216,9 +216,9 @@ static int dhcp6_maybe_relay(struct state *state, void *inbuff, size_t sz,
|
||||
|
||||
for (opt = opts; opt; opt = opt6_next(opt, end))
|
||||
{
|
||||
if (opt6_ptr(opt, 0) + opt6_len(opt) >= end) {
|
||||
if (opt6_ptr(opt, 0) + opt6_len(opt) > end)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int o = new_opt6(opt6_type(opt));
|
||||
if (opt6_type(opt) == OPTION6_RELAY_MSG)
|
||||
{
|
||||
@@ -882,7 +882,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
|
||||
|
||||
if (!ia_option)
|
||||
{
|
||||
/* If we get a request with a IA_*A without addresses, treat it exactly like
|
||||
/* If we get a request with an IA_*A without addresses, treat it exactly like
|
||||
a SOLICT with rapid commit set. */
|
||||
save_counter(start);
|
||||
goto request_no_address;
|
||||
@@ -1625,7 +1625,7 @@ static void end_ia(int t1cntr, unsigned int min_time, int do_fuzz)
|
||||
{
|
||||
if (t1cntr != 0)
|
||||
{
|
||||
/* go back an fill in fields in IA_NA option */
|
||||
/* go back and fill in fields in IA_NA option */
|
||||
int sav = save_counter(t1cntr);
|
||||
unsigned int t1, t2, fuzz = 0;
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2017 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2018 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/>.
|
||||
*/
|
||||
|
||||
/* Code to safely remove RRs from an DNS answer */
|
||||
/* Code to safely remove RRs from a DNS answer */
|
||||
|
||||
#include "dnsmasq.h"
|
||||
|
||||
@@ -247,7 +247,7 @@ size_t rrfilter(struct dns_header *header, size_t plen, int mode)
|
||||
|
||||
check_rrs(p, header, plen, 1, rrs, rr_found);
|
||||
|
||||
/* Fouth pass, elide records */
|
||||
/* Fourth pass, elide records */
|
||||
for (p = rrs[0], i = 1; i < rr_found; i += 2)
|
||||
{
|
||||
unsigned char *start = rrs[i];
|
||||
@@ -270,7 +270,7 @@ u16 *rrfilter_desc(int type)
|
||||
{
|
||||
/* List of RRtypes which include domains in the data.
|
||||
0 -> domain
|
||||
integer -> no of plain bytes
|
||||
integer -> no. of plain bytes
|
||||
-1 -> end
|
||||
|
||||
zero is not a valid RRtype, so the final entry is returned for
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2017 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2018 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
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2017 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2018 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
src/util.c
14
src/util.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2017 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2018 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
|
||||
@@ -246,14 +246,16 @@ unsigned char *do_rfc1035_name(unsigned char *p, char *sval, char *limit)
|
||||
|
||||
while (sval && *sval)
|
||||
{
|
||||
if (limit && p + 1 > (unsigned char*)limit)
|
||||
return p;
|
||||
|
||||
unsigned char *cp = p++;
|
||||
|
||||
if (limit && p > (unsigned char*)limit)
|
||||
return NULL;
|
||||
|
||||
for (j = 0; *sval && (*sval != '.'); sval++, j++)
|
||||
{
|
||||
if (limit && p + 1 > (unsigned char*)limit)
|
||||
return p;
|
||||
return NULL;
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (option_bool(OPT_DNSSEC_VALID) && *sval == NAME_ESCAPE)
|
||||
*p++ = (*(++sval))-1;
|
||||
@@ -261,10 +263,12 @@ unsigned char *do_rfc1035_name(unsigned char *p, char *sval, char *limit)
|
||||
#endif
|
||||
*p++ = *sval;
|
||||
}
|
||||
|
||||
*cp = j;
|
||||
if (*sval)
|
||||
sval++;
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user