mirror of
http://thekelleys.org.uk/git/dnsmasq.git
synced 2026-11-07 16:01:41 +00:00
Compare commits
36
Commits
v2.93rc2
...
a9880c595f
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a9880c595f | ||
|
|
ad9208358e | ||
|
|
baf85a8f38 | ||
|
|
a9cb3971c6 | ||
|
|
f031f5b4b3 | ||
|
|
cf9c9c74e0 | ||
|
|
b518bc425d | ||
|
|
0c177ad607 | ||
|
|
4388c38468 | ||
|
|
0a31ade4db | ||
|
|
a4ebe438df | ||
|
|
8d8ad76d89 | ||
|
|
b50b55e227 | ||
|
|
7a663fd46b | ||
|
|
1f122521bb | ||
|
|
8af20e56ed | ||
|
|
8aa607d322 | ||
|
|
52982cfe8f | ||
|
|
81d78d9c75 | ||
|
|
7ebe7ebb93 | ||
|
|
1da5cc2951 | ||
|
|
5990261a57 | ||
|
|
b6b7e5a6fd | ||
|
|
f8c162b8b0 | ||
|
|
c93e9ce592 | ||
|
|
bf80262874 | ||
|
|
ea4645d52c | ||
|
|
ea9bd30cd4 | ||
|
|
1af6ee6468 | ||
|
|
c310853907 | ||
|
|
3ff66da573 | ||
|
|
d823d8e9cd | ||
|
|
2c78b6db6c | ||
|
|
4bf46ceb37 | ||
|
|
7d42376a3a | ||
|
|
08cc209e7a |
No files matched your search
@@ -1,6 +1,18 @@
|
|||||||
|
version 2.94
|
||||||
|
Record that CVE-2026-12969 has been allocated to the
|
||||||
|
buffer OOB read in find_soa() which is fixed in git commit
|
||||||
|
14094e88beca519c53151184cc4553656672b54f, released at 2.93.
|
||||||
|
Thanks to do litli for spotting this.
|
||||||
|
|
||||||
|
Fix erroneous behaviour of --no-dhcpv4-interface with
|
||||||
|
constructed DHCPv6/RA - DHCPv6 and RA are inhibited by
|
||||||
|
--no-dhcpv4-interface when using constructed address ranges.
|
||||||
|
Thanks to David Nichols for discovery, diagnosis and patch.
|
||||||
|
|
||||||
|
|
||||||
version 2.93
|
version 2.93
|
||||||
Fix a corner-case in DNSSEC validation with wildcards. If we have
|
Fix a corner-case in DNSSEC validation with wildcards. If we have
|
||||||
a wildcard record *.example.com and recieve a query for
|
a wildcard record *.example.com and receive a query for
|
||||||
a.example.com then that's OK, but we have to check that there isn't
|
a.example.com then that's OK, but we have to check that there isn't
|
||||||
an actual a.example.com record. The corner case is when we get a
|
an actual a.example.com record. The corner case is when we get a
|
||||||
query for *.example.com in that case the non-existence check
|
query for *.example.com in that case the non-existence check
|
||||||
@@ -19,7 +31,7 @@ version 2.93
|
|||||||
(eg rivcoed.org) will still fail. Thanks to Petr Menšík
|
(eg rivcoed.org) will still fail. Thanks to Petr Menšík
|
||||||
for the bug report.
|
for the bug report.
|
||||||
|
|
||||||
Fix DNSSEC fail with CNAME replies to DS queries. As CNAME reply
|
Fix DNSSEC fail with CNAME replies to DS queries. A CNAME reply
|
||||||
to a DNSSEC query was confusing the validation logic. It now
|
to a DNSSEC query was confusing the validation logic. It now
|
||||||
accepts a signed CNAME reply to a DS query as proof that no DS
|
accepts a signed CNAME reply to a DS query as proof that no DS
|
||||||
exists at the domain. This fixes the DS/zone break detection logic.
|
exists at the domain. This fixes the DS/zone break detection logic.
|
||||||
|
|||||||
+46
-9
@@ -154,6 +154,9 @@ allows the log file to be rotated without stopping dnsmasq.
|
|||||||
.B --log-debug
|
.B --log-debug
|
||||||
Enable extra logging intended for debugging rather than information.
|
Enable extra logging intended for debugging rather than information.
|
||||||
.TP
|
.TP
|
||||||
|
.B --log-malloc
|
||||||
|
Enable logging of memory allocation and release, for debugging.
|
||||||
|
.TP
|
||||||
.B --log-async[=<lines>]
|
.B --log-async[=<lines>]
|
||||||
Enable asynchronous logging and optionally set the limit on the
|
Enable asynchronous logging and optionally set the limit on the
|
||||||
number of lines
|
number of lines
|
||||||
@@ -176,7 +179,13 @@ can be over-ridden with this switch.
|
|||||||
.B \-g, --group=<groupname>
|
.B \-g, --group=<groupname>
|
||||||
Specify the group which dnsmasq will run
|
Specify the group which dnsmasq will run
|
||||||
as. The default is "dip", if available, to facilitate access to
|
as. The default is "dip", if available, to facilitate access to
|
||||||
/etc/ppp/resolv.conf which is not normally world readable.
|
/etc/ppp/resolv.conf which is not normally world readable. If "dip" is not available, the default becomes
|
||||||
|
the main group associated with the uid specified by
|
||||||
|
.B --user
|
||||||
|
, or "nobody".
|
||||||
|
Specifying
|
||||||
|
.B --group
|
||||||
|
without an argument inhibits any change to the gid of the process, even to the defaults.
|
||||||
.TP
|
.TP
|
||||||
.B \-v, --version
|
.B \-v, --version
|
||||||
Print the version number.
|
Print the version number.
|
||||||
@@ -865,7 +874,7 @@ will be logged. If this coincides with DNS not functioning, it
|
|||||||
is necessary to disable the feature. As at version 2.91, 0x20 encoding
|
is necessary to disable the feature. As at version 2.91, 0x20 encoding
|
||||||
is disabled by default, and must be enabled with --do-0x20-encode. The default
|
is disabled by default, and must be enabled with --do-0x20-encode. The default
|
||||||
may change in the future, so to be sure of its status after an upgrade, set --do-0x20-encode
|
may change in the future, so to be sure of its status after an upgrade, set --do-0x20-encode
|
||||||
or --no-0x20-encode in your config. --no-0x20-encode overrides --do-x20-encode or a future default
|
or --no-0x20-encode in your config. --no-0x20-encode overrides --do-0x20-encode or a future default
|
||||||
0x20-encode enable.
|
0x20-encode enable.
|
||||||
.TP
|
.TP
|
||||||
.B --use-stale-cache[=<max TTL excess in s>]
|
.B --use-stale-cache[=<max TTL excess in s>]
|
||||||
@@ -1038,7 +1047,10 @@ options. If the lease time is given, then leases
|
|||||||
will be given for that length of time. The lease time is in seconds,
|
will be given for that length of time. The lease time is in seconds,
|
||||||
or minutes (eg 45m) or hours (eg 1h) or days (2d) or weeks (1w) or "infinite". If not given,
|
or minutes (eg 45m) or hours (eg 1h) or days (2d) or weeks (1w) or "infinite". If not given,
|
||||||
the default lease time is one hour for IPv4 and one day for IPv6. The
|
the default lease time is one hour for IPv4 and one day for IPv6. The
|
||||||
minimum lease time is two minutes. For IPv6 ranges, the lease time
|
minimum lease time is two minutes. An explicitly configured lease time also
|
||||||
|
affects IPv6 router advertisements: it acts as a ceiling on the advertised
|
||||||
|
prefix lifetimes. For constructed ranges it also acts as a floor, unless the
|
||||||
|
prefix is being deprecated. For IPv6 ranges, the lease time
|
||||||
maybe "deprecated"; this sets the preferred lifetime sent in a DHCP
|
maybe "deprecated"; this sets the preferred lifetime sent in a DHCP
|
||||||
lease or router advertisement to zero, which causes clients to use
|
lease or router advertisement to zero, which causes clients to use
|
||||||
other addresses, if available, for new connections as a prelude to renumbering.
|
other addresses, if available, for new connections as a prelude to renumbering.
|
||||||
@@ -1326,7 +1338,7 @@ have exactly the same effect as
|
|||||||
options containing the same information. /etc/ethers is re-read when
|
options containing the same information. /etc/ethers is re-read when
|
||||||
dnsmasq receives SIGHUP. IPv6 addresses are NOT read from /etc/ethers.
|
dnsmasq receives SIGHUP. IPv6 addresses are NOT read from /etc/ethers.
|
||||||
.TP
|
.TP
|
||||||
.B \-O, --dhcp-option=[tag:<tag>,[tag:<tag>,]][encap:<opt>,][vi-encap:<enterprise>,][vendor:[<vendor-class>],][<opt>|option:<opt-name>|option6:<opt>|option6:<opt-name>],[<value>[,<value>]]
|
.B \-O, --dhcp-option=[tag:<tag>,[tag:<tag>,]][encap:<opt>,][vi-encap:<enterprise>,][vendor:[<vendor-class>],][<opt>|option:<opt>|option:<opt-name>|option4:<opt>|option4:<optname>|option6:<opt>|option6:<opt-name>],[<value>[,<value>]]
|
||||||
Send various extra options to DHCP clients. By default,
|
Send various extra options to DHCP clients. By default,
|
||||||
dnsmasq sends some standard options to DHCP clients, the netmask and
|
dnsmasq sends some standard options to DHCP clients, the netmask and
|
||||||
broadcast address are set to the same as the host running dnsmasq, and
|
broadcast address are set to the same as the host running dnsmasq, and
|
||||||
@@ -1345,6 +1357,13 @@ For example, to set the default route option to 192.168.4.4, use
|
|||||||
and to set the time-server address to 192.168.0.4, use
|
and to set the time-server address to 192.168.0.4, use
|
||||||
\fB--dhcp-option=42,192.168.0.4\fP or
|
\fB--dhcp-option=42,192.168.0.4\fP or
|
||||||
\fB--dhcp-option=option:ntp-server,192.168.0.4\fP.
|
\fB--dhcp-option=option:ntp-server,192.168.0.4\fP.
|
||||||
|
|
||||||
|
The above examples are backwards compatible, for consistency with IPV6, the time-server example
|
||||||
|
may also be given as
|
||||||
|
\fB--dhcp-option=option:42,192.168.0.4\fP or
|
||||||
|
\fB--dhcp-option=option4:42,192.168.0.4\fP or
|
||||||
|
\fB--dhcp-option=option4:ntp-server,192.168.0.4\fP
|
||||||
|
|
||||||
The special address 0.0.0.0 means "the address of the system running dnsmasq".
|
The special address 0.0.0.0 means "the address of the system running dnsmasq".
|
||||||
|
|
||||||
An option without data is valid, and includes just the option without data.
|
An option without data is valid, and includes just the option without data.
|
||||||
@@ -1369,11 +1388,14 @@ described in RFC 3442.
|
|||||||
IPv6 options are specified using the \fBoption6:\fP
|
IPv6 options are specified using the \fBoption6:\fP
|
||||||
keyword, followed by the option number or option name. The IPv6 option
|
keyword, followed by the option number or option name. The IPv6 option
|
||||||
name space is disjoint from the IPv4 option name space. IPv6 addresses
|
name space is disjoint from the IPv4 option name space. IPv6 addresses
|
||||||
in options must be bracketed with square brackets, eg.
|
in options must be bracketed with square brackets, eg. \fB --dhcp-option=option6:sntp-server,[1234::56]\fP or
|
||||||
\fB --dhcp-option=option6:ntp-server,[1234::56]\fP.
|
--dhcp-option=option6:31,[1234::56].
|
||||||
For IPv6, [::] means "the global address of
|
For IPv6, [::] means "the global address of
|
||||||
the machine running dnsmasq", whilst [fd00::] is replaced with the
|
the machine running dnsmasq", whilst [fd00::] is replaced with the
|
||||||
ULA, if it exists, and [fe80::] with the link-local address.
|
ULA, if it exists, and [fe80::] with the link-local address. The vendorclass option
|
||||||
|
is special for DHCPv6, since it requires an enterprise number which must appear as a decimal number
|
||||||
|
before the class(es). eg. \fB --dhcp-option=option6:vendor-class,343,HTTPClient\fP
|
||||||
|
|
||||||
|
|
||||||
Be careful: data-type suitability for the option number sent is not checked.
|
Be careful: data-type suitability for the option number sent is not checked.
|
||||||
It is quite possible to persuade dnsmasq to generate illegal DHCP packets with
|
It is quite possible to persuade dnsmasq to generate illegal DHCP packets with
|
||||||
@@ -1900,6 +1922,11 @@ DNSMASQ_CLIENT_ID if the host provided a client-id.
|
|||||||
DNSMASQ_CIRCUIT_ID, DNSMASQ_SUBSCRIBER_ID, DNSMASQ_REMOTE_ID if a
|
DNSMASQ_CIRCUIT_ID, DNSMASQ_SUBSCRIBER_ID, DNSMASQ_REMOTE_ID if a
|
||||||
DHCP relay-agent added any of these options.
|
DHCP relay-agent added any of these options.
|
||||||
|
|
||||||
|
DNSMASQ_CPEWAN_OUI, DNSMASQ_CPEWAN_SERIAL, DNSMASQ_CPEWAN_CLASS from
|
||||||
|
an RFC3925 Vendor-Identifying Vendor-Specific Information Option
|
||||||
|
containing the Broadband Forum enterprise number and options
|
||||||
|
defined in TR-069.
|
||||||
|
|
||||||
If the client provides vendor-class, DNSMASQ_VENDOR_CLASS.
|
If the client provides vendor-class, DNSMASQ_VENDOR_CLASS.
|
||||||
|
|
||||||
For IPv6 only:
|
For IPv6 only:
|
||||||
@@ -1922,7 +1949,17 @@ only supplied for
|
|||||||
since these data are not held in dnsmasq's lease
|
since these data are not held in dnsmasq's lease
|
||||||
database.
|
database.
|
||||||
|
|
||||||
|
Please note that the environment options DNSMASQ_USER_CLASS0..DNSMASQ_USER_CLASSn,
|
||||||
|
DNSMASQ_VENDOR_CLASS0..DNSMASQ_VENDOR_CLASSn,
|
||||||
|
DNSMASQ_VENDOR_CLASS,
|
||||||
|
DNSMASQ_CIRCUIT_ID, DNSMASQ_SUBSCRIBER_ID, DNSMASQ_REMOTE_ID,
|
||||||
|
DNSMASQ_CPEWAN_OUI, DNSMASQ_CPEWAN_SERIAL, DNSMASQ_CPEWAN_CLASS,
|
||||||
|
DNSMASQ_MUD_URL all contain values which are derived directly from untrusted data recieved
|
||||||
|
from clients. Be very careful with quoting when using these values, lest an attacker sends
|
||||||
|
a vendor class of "rm -rf /". Note also that the RFCs defining these options tend to simply
|
||||||
|
define them an opaque data: the implication but not the letter of the definition is
|
||||||
|
printable strings. In practise, dnsmasq passes all octets except zero, which is treated
|
||||||
|
as a terminator.
|
||||||
|
|
||||||
All file descriptors are
|
All file descriptors are
|
||||||
closed except stdin, which is open to /dev/null, and stdout and stderr which capture output for logging by dnsmasq.
|
closed except stdin, which is open to /dev/null, and stdout and stderr which capture output for logging by dnsmasq.
|
||||||
@@ -2701,7 +2738,7 @@ IPv4 and IPv6 addresses from /etc/hosts (and
|
|||||||
and
|
and
|
||||||
.B --interface-name
|
.B --interface-name
|
||||||
and
|
and
|
||||||
.B ---dynamic-host
|
.B --dynamic-host
|
||||||
provided the address falls into one of the subnets specified in the
|
provided the address falls into one of the subnets specified in the
|
||||||
.B --auth-zone.
|
.B --auth-zone.
|
||||||
.PP
|
.PP
|
||||||
|
|||||||
+2
-2
@@ -869,7 +869,7 @@ Om detta sammanfaller med att DNS inte fungerar, är det
|
|||||||
nödvändigt att inaktivera funktionen. I version 2.91 är 0x20-kodning
|
nödvändigt att inaktivera funktionen. I version 2.91 är 0x20-kodning
|
||||||
inaktiverad som standard och måste aktiveras med --do-0x20-encode. Standardinställningen
|
inaktiverad som standard och måste aktiveras med --do-0x20-encode. Standardinställningen
|
||||||
kan komma att ändras i framtiden, så för att vara säker på dess status efter en uppgradering, ställ in --do-0x20-encode
|
kan komma att ändras i framtiden, så för att vara säker på dess status efter en uppgradering, ställ in --do-0x20-encode
|
||||||
eller --no-0x20-encode i din konfiguration. --no-0x20-encode åsidosätter --do-x20-encode eller en framtida standardinställning
|
eller --no-0x20-encode i din konfiguration. --no-0x20-encode åsidosätter --do-0x20-encode eller en framtida standardinställning
|
||||||
0x20-encode enable.
|
0x20-encode enable.
|
||||||
.TP
|
.TP
|
||||||
.B --use-stale-cache[=<max TTL excess in s>]
|
.B --use-stale-cache[=<max TTL excess in s>]
|
||||||
@@ -2732,7 +2732,7 @@ IPv4- och IPv6-adresser från /etc/hosts (och
|
|||||||
och
|
och
|
||||||
.B --interface-name
|
.B --interface-name
|
||||||
och
|
och
|
||||||
.B ---dynamic-host
|
.B --dynamic-host
|
||||||
förutsatt att adressen faller inom ett av de subnät som anges i
|
förutsatt att adressen faller inom ett av de subnät som anges i
|
||||||
.B --auth-zone.
|
.B --auth-zone.
|
||||||
.PP
|
.PP
|
||||||
|
|||||||
+1
-1
@@ -132,7 +132,7 @@ int blockdata_expand(struct blockdata *block, size_t oldlen, char *data, size_t
|
|||||||
/* find size of current final block */
|
/* find size of current final block */
|
||||||
for (b = block; oldlen > KEYBLOCK_LEN && b; b = b->next, oldlen -= KEYBLOCK_LEN);
|
for (b = block; oldlen > KEYBLOCK_LEN && b; b = b->next, oldlen -= KEYBLOCK_LEN);
|
||||||
|
|
||||||
/* chain to short for length, something is broken */
|
/* chain too short for length, something is broken */
|
||||||
if (oldlen > KEYBLOCK_LEN)
|
if (oldlen > KEYBLOCK_LEN)
|
||||||
{
|
{
|
||||||
blockdata_free(block);
|
blockdata_free(block);
|
||||||
|
|||||||
+40
-18
@@ -217,29 +217,42 @@ static void free_config_crec(struct crec *p)
|
|||||||
config_spare = p;
|
config_spare = p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct nameblock *nameblock_spare = NULL;
|
||||||
|
|
||||||
static char *store_name(unsigned int namelen, unsigned int index)
|
static char *store_name(unsigned int namelen, unsigned int index)
|
||||||
{
|
{
|
||||||
struct nameblock *block;
|
struct nameblock *block;
|
||||||
char *ret = NULL;
|
char *ret = NULL;
|
||||||
|
int i;
|
||||||
|
|
||||||
if (namelen > NAMEBLOCK_CHARS)
|
if (namelen > NAMEBLOCK_CHARS)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
for (block = hostblocks; block; block = block->next)
|
/* Check the first few blocks for possible space. This allows efficient memory usage
|
||||||
|
without blowing up O(n^2) CPU usage which the linked list gets long. */
|
||||||
|
for (i = 10, block = hostblocks; i != 0 && block; block = block->next, i--)
|
||||||
if (block->index == index && NAMEBLOCK_CHARS - block->last >= namelen)
|
if (block->index == index && NAMEBLOCK_CHARS - block->last >= namelen)
|
||||||
break;
|
|
||||||
|
|
||||||
if (!block && ((block = whine_malloc(sizeof(struct nameblock)))))
|
|
||||||
{
|
|
||||||
block->next = hostblocks;
|
|
||||||
block->index = index;
|
|
||||||
hostblocks = block;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (block && NAMEBLOCK_CHARS - block->last >= namelen)
|
|
||||||
{
|
{
|
||||||
ret = &block->data[block->last];
|
ret = &block->data[block->last];
|
||||||
block->last += namelen;
|
block->last += namelen;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nameblock_spare)
|
||||||
|
{
|
||||||
|
block = nameblock_spare;
|
||||||
|
nameblock_spare = nameblock_spare->next;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
block = whine_malloc(sizeof(struct nameblock));
|
||||||
|
|
||||||
|
if (block)
|
||||||
|
{
|
||||||
|
block->next = hostblocks;
|
||||||
|
block->index = index;
|
||||||
|
block->last = namelen;
|
||||||
|
hostblocks = block;
|
||||||
|
ret = &block->data[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@@ -247,11 +260,20 @@ static char *store_name(unsigned int namelen, unsigned int index)
|
|||||||
|
|
||||||
static void free_names(unsigned int index)
|
static void free_names(unsigned int index)
|
||||||
{
|
{
|
||||||
struct nameblock *block;
|
struct nameblock *block, *tmp, **up;
|
||||||
|
|
||||||
for (block = hostblocks; block; block = block->next)
|
for (up = &hostblocks, block = hostblocks; block; block = tmp)
|
||||||
if (index == UID_NONE || block->index == index)
|
{
|
||||||
block->last = 0;
|
tmp = block->next;
|
||||||
|
if (index == UID_NONE || block->index == index)
|
||||||
|
{
|
||||||
|
*up = tmp;
|
||||||
|
block->next = nameblock_spare;
|
||||||
|
nameblock_spare = block;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
up = &block->next;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* In most cases, we create the hash table once here by calling this with (hash_table == NULL)
|
/* In most cases, we create the hash table once here by calling this with (hash_table == NULL)
|
||||||
@@ -2309,7 +2331,7 @@ static char *edestr(int ede)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int error_occured(unsigned int flags) {
|
static int error_occurred(unsigned int flags) {
|
||||||
if (flags & F_RCODE)
|
if (flags & F_RCODE)
|
||||||
return 1;
|
return 1;
|
||||||
else if (flags & F_NEG)
|
else if (flags & F_NEG)
|
||||||
@@ -2330,10 +2352,10 @@ void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg,
|
|||||||
if (!option_bool(OPT_LOG))
|
if (!option_bool(OPT_LOG))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if(option_bool(OPT_LOG_ONLY_FAILED) && !error_occured(flags))
|
if(option_bool(OPT_LOG_ONLY_FAILED) && !error_occurred(flags))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* F_NOERR is reused here to indicate logs arrising from auth queries */
|
/* F_NOERR is reused here to indicate logs arising from auth queries */
|
||||||
if (!(flags & F_NOERR) && option_bool(OPT_AUTH_LOG))
|
if (!(flags & F_NOERR) && option_bool(OPT_AUTH_LOG))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|||||||
+32
-1
@@ -734,7 +734,7 @@ static const struct opttab_t opttab6[] = {
|
|||||||
{ "status", 13, OT_INTERNAL },
|
{ "status", 13, OT_INTERNAL },
|
||||||
{ "rapid-commit", 14, OT_INTERNAL },
|
{ "rapid-commit", 14, OT_INTERNAL },
|
||||||
{ "user-class", 15, OT_INTERNAL | OT_CSTRING },
|
{ "user-class", 15, OT_INTERNAL | OT_CSTRING },
|
||||||
{ "vendor-class", 16, OT_INTERNAL | OT_CSTRING },
|
{ "vendor-class", 16, OT_DHCP6_VENDOR },
|
||||||
{ "vendor-opts", 17, OT_INTERNAL },
|
{ "vendor-opts", 17, OT_INTERNAL },
|
||||||
{ "sip-server-domain", 21, OT_RFC1035_NAME },
|
{ "sip-server-domain", 21, OT_RFC1035_NAME },
|
||||||
{ "sip-server", 22, OT_ADDR_LIST },
|
{ "sip-server", 22, OT_ADDR_LIST },
|
||||||
@@ -909,6 +909,37 @@ char *option_string(int prot, unsigned int opt, unsigned char *val, int opt_len,
|
|||||||
buf[j++] = ',';
|
buf[j++] = ',';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if ((ot[o].size & OT_DHCP6_VENDOR))
|
||||||
|
{
|
||||||
|
unsigned int enterprise;
|
||||||
|
unsigned char *p = &val[0];
|
||||||
|
|
||||||
|
if (opt_len >= 4)
|
||||||
|
{
|
||||||
|
GETLONG(enterprise, p);
|
||||||
|
snprintf(buf, buf_len, "%u", enterprise);
|
||||||
|
j = strlen(buf);
|
||||||
|
i = 4;
|
||||||
|
while (i + 2 <= opt_len)
|
||||||
|
{
|
||||||
|
int k, len;
|
||||||
|
p = &val[i];
|
||||||
|
GETSHORT(len, p);
|
||||||
|
if (i + 2 + len > opt_len)
|
||||||
|
break;
|
||||||
|
if (j < buf_len - 1)
|
||||||
|
buf[j++] = ',';
|
||||||
|
for (k = 0; k < len && j < buf_len - 1; k++)
|
||||||
|
{
|
||||||
|
char c = *p++;
|
||||||
|
if (isprint((unsigned char)c))
|
||||||
|
buf[j++] = c;
|
||||||
|
}
|
||||||
|
buf[j] = 0;
|
||||||
|
i += len + 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
else if ((ot[o].size & (OT_DEC | OT_TIME)) && opt_len != 0)
|
else if ((ot[o].size & (OT_DEC | OT_TIME)) && opt_len != 0)
|
||||||
{
|
{
|
||||||
|
|||||||
+1
-1
@@ -720,7 +720,7 @@ static int construct_worker(struct in6_addr *local, int prefix,
|
|||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
|
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
|
||||||
if (tmp->name && wildcard_match(tmp->name, ifrn_name))
|
if (tmp->name && (tmp->flags & INAME_6) && wildcard_match(tmp->name, ifrn_name))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
for (template = daemon->dhcp6; template; template = template->next)
|
for (template = daemon->dhcp6; template; template = template->next)
|
||||||
|
|||||||
+91
-41
@@ -1935,7 +1935,7 @@ static void check_dns_listeners(time_t now)
|
|||||||
/* Note that handling events here can create or destroy fds and
|
/* Note that handling events here can create or destroy fds and
|
||||||
render the result of the last poll() call invalid. Once
|
render the result of the last poll() call invalid. Once
|
||||||
we find an fd that needs service, do it, then return to go around the
|
we find an fd that needs service, do it, then return to go around the
|
||||||
poll() loop again. This avoid really, really, wierd bugs. */
|
poll() loop again. This avoid really, really, weird bugs. */
|
||||||
|
|
||||||
if (!option_bool(OPT_DEBUG))
|
if (!option_bool(OPT_DEBUG))
|
||||||
for (i = 0; i < daemon->max_procs; i++)
|
for (i = 0; i < daemon->max_procs; i++)
|
||||||
@@ -2016,19 +2016,31 @@ static void do_tcp_connection(struct listener *listener, time_t now, int slot)
|
|||||||
union mysockaddr tcp_addr;
|
union mysockaddr tcp_addr;
|
||||||
socklen_t tcp_len = sizeof(union mysockaddr);
|
socklen_t tcp_len = sizeof(union mysockaddr);
|
||||||
struct server *s;
|
struct server *s;
|
||||||
|
struct listener *l;
|
||||||
int flags, auth_dns = 0;
|
int flags, auth_dns = 0;
|
||||||
struct in_addr netmask;
|
struct in_addr netmask;
|
||||||
int pipefd[2];
|
int pipefd[2];
|
||||||
struct iovec tcpbuff;
|
struct iovec tcpbuff;
|
||||||
#ifdef HAVE_LINUX_NETWORK
|
|
||||||
unsigned char a = 0;
|
unsigned char a = 0;
|
||||||
#endif
|
|
||||||
netmask.s_addr = 0;
|
netmask.s_addr = 0;
|
||||||
|
|
||||||
while ((confd = accept(listener->tcpfd, NULL, NULL)) == -1 && errno == EINTR);
|
while ((confd = accept(listener->tcpfd, NULL, NULL)) == -1 && errno == EINTR);
|
||||||
|
|
||||||
if (confd == -1)
|
if (confd == -1)
|
||||||
return;
|
{
|
||||||
|
/* Transient errors: just return and retry on next poll cycle. */
|
||||||
|
if (errno == EAGAIN || errno == ECONNABORTED ||
|
||||||
|
errno == EMFILE || errno == ENFILE ||
|
||||||
|
errno == ENOMEM || errno == ENOBUFS)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Fatal error (EINVAL, EBADF, etc): socket is permanently broken.
|
||||||
|
Close it so poll() no longer selects it. In --bind-dynamic mode
|
||||||
|
the listener will be rebuilt on the next address change event. */
|
||||||
|
close(listener->tcpfd);
|
||||||
|
listener->tcpfd = -1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (getsockname(confd, (struct sockaddr *)&tcp_addr, &tcp_len) == -1)
|
if (getsockname(confd, (struct sockaddr *)&tcp_addr, &tcp_len) == -1)
|
||||||
{
|
{
|
||||||
@@ -2138,24 +2150,18 @@ static void do_tcp_connection(struct listener *listener, time_t now, int slot)
|
|||||||
/* fork() done: parent side */
|
/* fork() done: parent side */
|
||||||
close(pipefd[1]); /* parent needs read pipe end. */
|
close(pipefd[1]); /* parent needs read pipe end. */
|
||||||
|
|
||||||
#ifdef HAVE_LINUX_NETWORK
|
/* The child process inherits various sockets,
|
||||||
/* The child process inherits the netlink socket,
|
whose existence can mess up the function of
|
||||||
which it never uses, but when the parent (us)
|
the parent. See below for details of which
|
||||||
uses it in the future, the answer may go to the
|
sockets, and why they cause problems. The
|
||||||
child, resulting in the parent blocking
|
child closes the sockets during startup,
|
||||||
forever awaiting the result. To avoid this
|
but there's a nasty race, since the parent
|
||||||
the child closes the netlink socket, but there's
|
may use them before the child has done the close.
|
||||||
a nasty race, since the parent may use netlink
|
|
||||||
before the child has done the close.
|
|
||||||
|
|
||||||
To avoid this, the parent blocks here until a
|
To avoid the race, the parent blocks here until a
|
||||||
single byte comes back up the pipe, which
|
single byte comes back up the pipe, which
|
||||||
is sent by the child after it has closed the
|
is sent when the child has finished the close. */
|
||||||
netlink socket. */
|
|
||||||
|
|
||||||
read_write(pipefd[0], &a, 1, RW_READ);
|
read_write(pipefd[0], &a, 1, RW_READ);
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
daemon->tcp_pids[slot] = p;
|
daemon->tcp_pids[slot] = p;
|
||||||
daemon->tcp_pipes[slot] = pipefd[0];
|
daemon->tcp_pipes[slot] = pipefd[0];
|
||||||
@@ -2176,16 +2182,41 @@ static void do_tcp_connection(struct listener *listener, time_t now, int slot)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_LINUX_NETWORK
|
||||||
|
/* The child process inherits the netlink socket,
|
||||||
|
which it never uses, but when the parent
|
||||||
|
uses it in the future, the answer may go to the
|
||||||
|
child, resulting in the parent blocking
|
||||||
|
forever awaiting the result. To avoid this
|
||||||
|
close the netlink socket in the child. */
|
||||||
|
close(daemon->netlinkfd);
|
||||||
|
#elif defined(HAVE_BSD_NETWORK)
|
||||||
|
close(daemon->routefd);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Close inherited listening sockets in the child process.
|
||||||
|
These are not needed here and holding them prevents the
|
||||||
|
parent from re-binding if an interface is removed and
|
||||||
|
re-added (the child's copy causes EADDRINUSE). */
|
||||||
|
for (l = daemon->listeners; l; l = l->next)
|
||||||
|
{
|
||||||
|
if (l->fd != -1)
|
||||||
|
close(l->fd);
|
||||||
|
if (l->tcpfd != -1)
|
||||||
|
close(l->tcpfd);
|
||||||
|
if (l->tftpfd != -1)
|
||||||
|
close(l->tftpfd);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* unblock parent now we're not holding sockets we shouldn't. */
|
||||||
|
read_write(pipefd[1], &a, 1, RW_WRITE);
|
||||||
|
|
||||||
/* Arrange for SIGALRM after CHILD_LIFETIME seconds to
|
/* Arrange for SIGALRM after CHILD_LIFETIME seconds to
|
||||||
terminate the process. */
|
terminate the process. */
|
||||||
#ifdef HAVE_LINUX_NETWORK
|
|
||||||
/* See comment above re: netlink socket. */
|
|
||||||
close(daemon->netlinkfd);
|
|
||||||
read_write(pipefd[1], &a, 1, RW_WRITE);
|
|
||||||
#endif
|
|
||||||
alarm(CHILD_LIFETIME);
|
alarm(CHILD_LIFETIME);
|
||||||
close(pipefd[0]); /* close read end in child. */
|
close(pipefd[0]); /* close read end in child. */
|
||||||
daemon->pipe_to_parent = pipefd[1];
|
daemon->pipe_to_parent = pipefd[1];
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The connected socket inherits non-blocking
|
/* The connected socket inherits non-blocking
|
||||||
@@ -2232,14 +2263,13 @@ int swap_to_tcp(struct frec *forward, time_t now, int status, struct dns_header
|
|||||||
ssize_t *plen, char *name, int class, struct server *server, int *keycount, int *validatecount)
|
ssize_t *plen, char *name, int class, struct server *server, int *keycount, int *validatecount)
|
||||||
{
|
{
|
||||||
struct server *s;
|
struct server *s;
|
||||||
|
struct listener *l;
|
||||||
|
|
||||||
if (!option_bool(OPT_DEBUG))
|
if (!option_bool(OPT_DEBUG))
|
||||||
{
|
{
|
||||||
pid_t p;
|
pid_t p;
|
||||||
int i, pipefd[2];
|
int i, pipefd[2];
|
||||||
#ifdef HAVE_LINUX_NETWORK
|
|
||||||
unsigned char a = 0;
|
unsigned char a = 0;
|
||||||
#endif
|
|
||||||
|
|
||||||
/* check to see if we have a free tcp process slot. */
|
/* check to see if we have a free tcp process slot. */
|
||||||
for (i = daemon->max_procs - 1; i >= 0; i--)
|
for (i = daemon->max_procs - 1; i >= 0; i--)
|
||||||
@@ -2260,22 +2290,18 @@ int swap_to_tcp(struct frec *forward, time_t now, int status, struct dns_header
|
|||||||
return STAT_ABANDONED;
|
return STAT_ABANDONED;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_LINUX_NETWORK
|
/* The child process inherits various sockets,
|
||||||
/* The child process inherits the netlink socket,
|
whose existence can mess up the function of
|
||||||
which it never uses, but when the parent (us)
|
the parent. See below for details of which
|
||||||
uses it in the future, the answer may go to the
|
sockets, and why they cause problems. The
|
||||||
child, resulting in the parent blocking
|
child closes the sockets during startup,
|
||||||
forever awaiting the result. To avoid this
|
but there's a nasty race, since the parent
|
||||||
the child closes the netlink socket, but there's
|
may use them before the child has done the close.
|
||||||
a nasty race, since the parent may use netlink
|
|
||||||
before the child has done the close.
|
|
||||||
|
|
||||||
To avoid this, the parent blocks here until a
|
To avoid the race, the parent blocks here until a
|
||||||
single byte comes back up the pipe, which
|
single byte comes back up the pipe, which
|
||||||
is sent by the child after it has closed the
|
is sent when the child has finished the close. */
|
||||||
netlink socket. */
|
|
||||||
read_write(pipefd[0], &a, 1, RW_READ);
|
read_write(pipefd[0], &a, 1, RW_READ);
|
||||||
#endif
|
|
||||||
|
|
||||||
/* i holds index of free slot */
|
/* i holds index of free slot */
|
||||||
daemon->tcp_pids[i] = p;
|
daemon->tcp_pids[i] = p;
|
||||||
@@ -2294,10 +2320,34 @@ int swap_to_tcp(struct frec *forward, time_t now, int status, struct dns_header
|
|||||||
{
|
{
|
||||||
/* child starts here. */
|
/* child starts here. */
|
||||||
#ifdef HAVE_LINUX_NETWORK
|
#ifdef HAVE_LINUX_NETWORK
|
||||||
/* See comment above re: netlink socket. */
|
/* The child process inherits the netlink socket,
|
||||||
|
which it never uses, but when the parent
|
||||||
|
uses it in the future, the answer may go to the
|
||||||
|
child, resulting in the parent blocking
|
||||||
|
forever awaiting the result. To avoid this
|
||||||
|
close the netlink socket in the child. */
|
||||||
close(daemon->netlinkfd);
|
close(daemon->netlinkfd);
|
||||||
read_write(pipefd[1], &a, 1, RW_WRITE);
|
#elif defined(HAVE_BSD_NETWORK)
|
||||||
|
close(daemon->routefd);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Close inherited listening sockets in the child process.
|
||||||
|
These are not needed here and holding them prevents the
|
||||||
|
parent from re-binding if an interface is removed and
|
||||||
|
re-added (the child's copy causes EADDRINUSE). */
|
||||||
|
for (l = daemon->listeners; l; l = l->next)
|
||||||
|
{
|
||||||
|
if (l->fd != -1)
|
||||||
|
close(l->fd);
|
||||||
|
if (l->tcpfd != -1)
|
||||||
|
close(l->tcpfd);
|
||||||
|
if (l->tftpfd != -1)
|
||||||
|
close(l->tftpfd);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* unblock parent now we're not holding sockets we shouldn't. */
|
||||||
|
read_write(pipefd[1], &a, 1, RW_WRITE);
|
||||||
|
|
||||||
alarm(CHILD_LIFETIME);
|
alarm(CHILD_LIFETIME);
|
||||||
close(pipefd[0]); /* close read end in child. */
|
close(pipefd[0]); /* close read end in child. */
|
||||||
daemon->pipe_to_parent = pipefd[1];
|
daemon->pipe_to_parent = pipefd[1];
|
||||||
|
|||||||
+3
-2
@@ -723,7 +723,7 @@ struct resolvc {
|
|||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
/* adn-hosts parms from command-line (also dhcp-hostsfile and dhcp-optsfile and dhcp-hostsdir*/
|
/* addn-hosts parms from command-line (also dhcp-hostsfile and dhcp-optsfile and dhcp-hostsdir*/
|
||||||
#define AH_DIR 1
|
#define AH_DIR 1
|
||||||
#define AH_INACTIVE 2
|
#define AH_INACTIVE 2
|
||||||
#define AH_WD_DONE 4
|
#define AH_WD_DONE 4
|
||||||
@@ -834,6 +834,7 @@ struct frec {
|
|||||||
#define OT_CSTRING 0x0800
|
#define OT_CSTRING 0x0800
|
||||||
#define OT_DEC 0x0400
|
#define OT_DEC 0x0400
|
||||||
#define OT_TIME 0x0200
|
#define OT_TIME 0x0200
|
||||||
|
#define OT_DHCP6_VENDOR 0x0100
|
||||||
|
|
||||||
/* actions in the daemon->helper RPC */
|
/* actions in the daemon->helper RPC */
|
||||||
#define ACTION_DEL 1
|
#define ACTION_DEL 1
|
||||||
@@ -1170,7 +1171,7 @@ struct dhcp_relay {
|
|||||||
};
|
};
|
||||||
|
|
||||||
extern struct daemon {
|
extern struct daemon {
|
||||||
/* datastuctures representing the command-line and
|
/* datastructures representing the command-line and
|
||||||
config file arguments. All set (including defaults)
|
config file arguments. All set (including defaults)
|
||||||
in option.c */
|
in option.c */
|
||||||
|
|
||||||
|
|||||||
+22
-11
@@ -177,7 +177,7 @@ static int get_rdata(struct dns_header *header, size_t plen, struct rdata_state
|
|||||||
if ((state->c = state->end - state->ip) != 0)
|
if ((state->c = state->end - state->ip) != 0)
|
||||||
{
|
{
|
||||||
state->op = state->ip;
|
state->op = state->ip;
|
||||||
state->ip = state->end;;
|
state->ip = state->end;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return 0;
|
return 0;
|
||||||
@@ -189,23 +189,27 @@ static int get_rdata(struct dns_header *header, size_t plen, struct rdata_state
|
|||||||
if (d == (u16)0)
|
if (d == (u16)0)
|
||||||
{
|
{
|
||||||
/* domain-name, canonicalise */
|
/* domain-name, canonicalise */
|
||||||
int len;
|
|
||||||
|
|
||||||
|
/* If the name is malformed, or runs beyond the end of the RR, abort.
|
||||||
|
under no circumstances should state->ip be beyond state->end since
|
||||||
|
that will cause the run-out code above to turn the negative
|
||||||
|
calculted length into a very large postive value for state->c
|
||||||
|
and overrun the buffer. */
|
||||||
if (!extract_name(header, plen, &state->ip, state->buff, EXTR_NAME_EXTRACT, 0) ||
|
if (!extract_name(header, plen, &state->ip, state->buff, EXTR_NAME_EXTRACT, 0) ||
|
||||||
(len = to_wire(state->buff)) == 0)
|
state->ip > state->end)
|
||||||
continue;
|
return 0;
|
||||||
|
|
||||||
state->c = len;
|
/* to_wire() always returns length > 0 */
|
||||||
|
state->c = to_wire(state->buff);
|
||||||
state->op = (unsigned char *)state->buff;
|
state->op = (unsigned char *)state->buff;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* plain data preceding a domain-name, don't run off the end of the data */
|
/* Plain data preceding a domain-name.
|
||||||
if ((state->end - state->ip) < d)
|
Handle short RR, if there are no bytes left, return finished. */
|
||||||
d = state->end - state->ip;
|
if ((state->end - state->ip) < d &&
|
||||||
|
(d = state->end - state->ip) == 0)
|
||||||
if (d == 0)
|
return 0;
|
||||||
continue;
|
|
||||||
|
|
||||||
state->op = state->ip;
|
state->op = state->ip;
|
||||||
state->c = d;
|
state->c = d;
|
||||||
@@ -1018,6 +1022,13 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
|
|||||||
|
|
||||||
if (!servfail)
|
if (!servfail)
|
||||||
{
|
{
|
||||||
|
/* If the answer carries no proof of non-existence, we fall back to asking if the
|
||||||
|
zone is unsigned, but that question is answered by the very DS record we're
|
||||||
|
chasing here, so we'd loop getting nowhere. Treat the zone as unsigned and let
|
||||||
|
the checks below decide if that's acceptable. */
|
||||||
|
if (STAT_ISEQUAL(rc, STAT_NEED_DS) && hostname_isequal(name, keyname))
|
||||||
|
rc = STAT_INSECURE;
|
||||||
|
|
||||||
if (STAT_ISEQUAL(rc, STAT_INSECURE))
|
if (STAT_ISEQUAL(rc, STAT_INSECURE))
|
||||||
{
|
{
|
||||||
/* A INSECURE DS answer is OK if it's negative and there's a CNAME answer to the DS answer which is
|
/* A INSECURE DS answer is OK if it's negative and there's a CNAME answer to the DS answer which is
|
||||||
|
|||||||
+24
-22
@@ -129,6 +129,23 @@ void dump_packet_icmp(int mask, void *packet, size_t len,
|
|||||||
do_dump_packet(mask, packet, len, src, dst, -1, IPPROTO_ICMP);
|
do_dump_packet(mask, packet, len, src, dst, -1, IPPROTO_ICMP);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static u32 calc_data_checksum(u32 sum, void *packet, size_t len)
|
||||||
|
{
|
||||||
|
u32 i;
|
||||||
|
|
||||||
|
for (i = 0; i < len/2; i++)
|
||||||
|
sum += ((u16 *)packet)[i];
|
||||||
|
if (len & 1) /* last byte, in case length is odd. */
|
||||||
|
sum += ((unsigned char *)packet)[len - 1];
|
||||||
|
while (sum >> 16)
|
||||||
|
sum = (sum & 0xffff) + (sum >> 16);
|
||||||
|
|
||||||
|
if (sum != 0xffff)
|
||||||
|
sum = ~sum;
|
||||||
|
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
|
||||||
static void do_dump_packet(int mask, void *packet, size_t len,
|
static void do_dump_packet(int mask, void *packet, size_t len,
|
||||||
union mysockaddr *src, union mysockaddr *dst, int port, int proto)
|
union mysockaddr *src, union mysockaddr *dst, int port, int proto)
|
||||||
{
|
{
|
||||||
@@ -226,12 +243,8 @@ static void do_dump_packet(int mask, void *packet, size_t len,
|
|||||||
udp.uh_dport = dst->in.sin_port;
|
udp.uh_dport = dst->in.sin_port;
|
||||||
}
|
}
|
||||||
|
|
||||||
ip.ip_sum = 0;
|
ip.ip_sum = 0; /* for the calculation */
|
||||||
for (sum = 0, i = 0; i < sizeof(struct ip) / 2; i++)
|
ip.ip_sum = calc_data_checksum(0, &ip, sizeof(struct ip));
|
||||||
sum += ((u16 *)&ip)[i];
|
|
||||||
while (sum >> 16)
|
|
||||||
sum = (sum & 0xffff) + (sum >> 16);
|
|
||||||
ip.ip_sum = (sum == 0xffff) ? sum : ~sum;
|
|
||||||
|
|
||||||
/* start UDP/ICMP checksum */
|
/* start UDP/ICMP checksum */
|
||||||
sum = ip.ip_src.s_addr & 0xffff;
|
sum = ip.ip_src.s_addr & 0xffff;
|
||||||
@@ -240,9 +253,6 @@ static void do_dump_packet(int mask, void *packet, size_t len,
|
|||||||
sum += (ip.ip_dst.s_addr >> 16) & 0xffff;
|
sum += (ip.ip_dst.s_addr >> 16) & 0xffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (len & 1)
|
|
||||||
((unsigned char *)packet)[len] = 0; /* for checksum, in case length is odd. */
|
|
||||||
|
|
||||||
if (proto == IPPROTO_UDP)
|
if (proto == IPPROTO_UDP)
|
||||||
{
|
{
|
||||||
/* Add Remaining part of the pseudoheader. Note that though the
|
/* Add Remaining part of the pseudoheader. Note that though the
|
||||||
@@ -252,16 +262,11 @@ static void do_dump_packet(int mask, void *packet, size_t len,
|
|||||||
sum += htons(IPPROTO_UDP);
|
sum += htons(IPPROTO_UDP);
|
||||||
sum += htons(sizeof(struct udphdr) + len);
|
sum += htons(sizeof(struct udphdr) + len);
|
||||||
|
|
||||||
udp.uh_sum = 0;
|
udp.uh_sum = 0; /* for the calculation */
|
||||||
udp.uh_ulen = htons(sizeof(struct udphdr) + len);
|
udp.uh_ulen = htons(sizeof(struct udphdr) + len);
|
||||||
|
|
||||||
for (i = 0; i < sizeof(struct udphdr)/2; i++)
|
for (i = 0; i < sizeof(struct udphdr)/2; i++)
|
||||||
sum += ((u16 *)&udp)[i];
|
sum += ((u16 *)&udp)[i];
|
||||||
for (i = 0; i < (len + 1) / 2; i++)
|
udp.uh_sum = calc_data_checksum(sum, packet, len);
|
||||||
sum += ((u16 *)packet)[i];
|
|
||||||
while (sum >> 16)
|
|
||||||
sum = (sum & 0xffff) + (sum >> 16);
|
|
||||||
udp.uh_sum = (sum == 0xffff) ? sum : ~sum;
|
|
||||||
|
|
||||||
pcap_header.incl_len = pcap_header.orig_len = ipsz + sizeof(udp) + len;
|
pcap_header.incl_len = pcap_header.orig_len = ipsz + sizeof(udp) + len;
|
||||||
}
|
}
|
||||||
@@ -274,12 +279,9 @@ static void do_dump_packet(int mask, void *packet, size_t len,
|
|||||||
sum += htons(proto);
|
sum += htons(proto);
|
||||||
sum += htons(len);
|
sum += htons(len);
|
||||||
|
|
||||||
icmp->icmp6_cksum = 0;
|
icmp->icmp6_cksum = 0; /* for the calculation */
|
||||||
for (i = 0; i < (len + 1) / 2; i++)
|
icmp->icmp6_cksum = calc_data_checksum(sum, packet, len);
|
||||||
sum += ((u16 *)packet)[i];
|
|
||||||
while (sum >> 16)
|
|
||||||
sum = (sum & 0xffff) + (sum >> 16);
|
|
||||||
icmp->icmp6_cksum = (sum == 0xffff) ? sum : ~sum;
|
|
||||||
|
|
||||||
pcap_header.incl_len = pcap_header.orig_len = ipsz + len;
|
pcap_header.incl_len = pcap_header.orig_len = ipsz + len;
|
||||||
}
|
}
|
||||||
|
|||||||
+42
-24
@@ -177,6 +177,9 @@ static void forward_query(int udpfd, union mysockaddr *udpaddr,
|
|||||||
int forwarded = 0;
|
int forwarded = 0;
|
||||||
int ede = EDE_UNSET;
|
int ede = EDE_UNSET;
|
||||||
unsigned short rrtype, rrclass;
|
unsigned short rrtype, rrclass;
|
||||||
|
unsigned short id = ntohs(header->id); /* Retrieve the id from the new query before we overwrite it. */
|
||||||
|
unsigned int casediff = 0;
|
||||||
|
unsigned int *bitvector = NULL;
|
||||||
|
|
||||||
gotname = extract_request(header, plen, daemon->namebuff, &rrtype, &rrclass);
|
gotname = extract_request(header, plen, daemon->namebuff, &rrtype, &rrclass);
|
||||||
|
|
||||||
@@ -197,15 +200,6 @@ static void forward_query(int udpfd, union mysockaddr *udpaddr,
|
|||||||
FREC_HAS_PHEADER | FREC_DNSKEY_QUERY | FREC_DS_QUERY | FREC_NO_CACHE)))
|
FREC_HAS_PHEADER | FREC_DNSKEY_QUERY | FREC_DS_QUERY | FREC_NO_CACHE)))
|
||||||
{
|
{
|
||||||
struct frec_src *src;
|
struct frec_src *src;
|
||||||
unsigned int casediff = 0;
|
|
||||||
unsigned int *bitvector = NULL;
|
|
||||||
unsigned short id = ntohs(header->id); /* Retrieve the id from the new query before we overwrite it. */
|
|
||||||
|
|
||||||
/* Get the case-scambled version of the query to resend. This is important because we
|
|
||||||
may fall through below and forward the query in the packet buffer again and we
|
|
||||||
want to use the same case scrambling as the first time. */
|
|
||||||
blockdata_retrieve(forward->stash, forward->stash_len, (void *)header);
|
|
||||||
plen = forward->stash_len;
|
|
||||||
|
|
||||||
for (src = &forward->frec_src; src; src = src->next)
|
for (src = &forward->frec_src; src; src = src->next)
|
||||||
if (src->orig_id == id &&
|
if (src->orig_id == id &&
|
||||||
@@ -217,6 +211,11 @@ static void forward_query(int udpfd, union mysockaddr *udpaddr,
|
|||||||
old_src = 1;
|
old_src = 1;
|
||||||
/* If a query is retried, use the log_id for the retry when logging the answer. */
|
/* If a query is retried, use the log_id for the retry when logging the answer. */
|
||||||
src->log_id = daemon->log_id;
|
src->log_id = daemon->log_id;
|
||||||
|
/* Get the case-scambled version of the query to resend. This is important because we
|
||||||
|
may fall through below and forward the query in the packet buffer again and we
|
||||||
|
want to use the same case scrambling as the first time. */
|
||||||
|
blockdata_retrieve(forward->stash, forward->stash_len, (void *)header);
|
||||||
|
plen = forward->stash_len;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -242,9 +241,11 @@ static void forward_query(int udpfd, union mysockaddr *udpaddr,
|
|||||||
and never resetting until the frec gets deleted by
|
and never resetting until the frec gets deleted by
|
||||||
aging followed by the receipt of a different query. This
|
aging followed by the receipt of a different query. This
|
||||||
is a bit of a DoS vuln. Avoid by explicitly deleting the
|
is a bit of a DoS vuln. Avoid by explicitly deleting the
|
||||||
frec once it expires. */
|
frec once it expires. The deletion is done at the end of
|
||||||
if (difftime(now, forward->time) >= TIMEOUT)
|
this function, unless we set forward to NULL here. */
|
||||||
free_frec(forward);
|
if (difftime(now, forward->time) < TIMEOUT)
|
||||||
|
forward = NULL;
|
||||||
|
|
||||||
goto reply;
|
goto reply;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -264,6 +265,9 @@ static void forward_query(int udpfd, union mysockaddr *udpaddr,
|
|||||||
The original query we sent is now in packet buffer and the query name in the
|
The original query we sent is now in packet buffer and the query name in the
|
||||||
new instance is on daemon->namebuff. */
|
new instance is on daemon->namebuff. */
|
||||||
|
|
||||||
|
blockdata_retrieve(forward->stash, forward->stash_len, (void *)header);
|
||||||
|
plen = forward->stash_len;
|
||||||
|
|
||||||
if (extract_name(header, forward->stash_len, NULL, daemon->workspacename, EXTR_NAME_EXTRACT, 0))
|
if (extract_name(header, forward->stash_len, NULL, daemon->workspacename, EXTR_NAME_EXTRACT, 0))
|
||||||
{
|
{
|
||||||
unsigned int i, gobig = 0;
|
unsigned int i, gobig = 0;
|
||||||
@@ -312,7 +316,6 @@ static void forward_query(int udpfd, union mysockaddr *udpaddr,
|
|||||||
src->fd = udpfd;
|
src->fd = udpfd;
|
||||||
src->encode_bitmap = casediff;
|
src->encode_bitmap = casediff;
|
||||||
src->encode_bigmap = bitvector;
|
src->encode_bigmap = bitvector;
|
||||||
|
|
||||||
src->udp_pkt_size = (unsigned short)replylimit;
|
src->udp_pkt_size = (unsigned short)replylimit;
|
||||||
|
|
||||||
/* closely spaced identical queries cannot be a try and a retry, so
|
/* closely spaced identical queries cannot be a try and a retry, so
|
||||||
@@ -388,18 +391,15 @@ static void forward_query(int udpfd, union mysockaddr *udpaddr,
|
|||||||
forward->frec_src.orig_id = ntohs(header->id);
|
forward->frec_src.orig_id = ntohs(header->id);
|
||||||
forward->new_id = get_id();
|
forward->new_id = get_id();
|
||||||
header->id = ntohs(forward->new_id);
|
header->id = ntohs(forward->new_id);
|
||||||
forward->frec_src.encode_bitmap = (!option_bool(OPT_NO_0x20) && option_bool(OPT_DO_0x20)) ? rand32() : 0;
|
forward->frec_src.encode_bitmap = casediff = (!option_bool(OPT_NO_0x20) && option_bool(OPT_DO_0x20)) ? rand32() : 0;
|
||||||
forward->frec_src.encode_bigmap = NULL;
|
forward->frec_src.encode_bigmap = NULL;
|
||||||
|
|
||||||
if (!extract_name(header, plen, NULL, (char *)&forward->frec_src.encode_bitmap, EXTR_NAME_FLIP, 1))
|
if (casediff != 0 && !extract_name(header, plen, NULL, (char *)&casediff, EXTR_NAME_FLIP, 1))
|
||||||
goto reply;
|
goto reply;
|
||||||
|
|
||||||
/* Keep copy of query for retries and move to TCP */
|
/* Keep copy of query for retries and move to TCP */
|
||||||
if (!(forward->stash = blockdata_alloc((char *)header, plen)))
|
if (!(forward->stash = blockdata_alloc((char *)header, plen)))
|
||||||
{
|
goto reply; /* no mem. return REFUSED */
|
||||||
free_frec(forward);
|
|
||||||
goto reply; /* no mem. return REFUSED */
|
|
||||||
}
|
|
||||||
|
|
||||||
forward->stash_len = plen;
|
forward->stash_len = plen;
|
||||||
forward->frec_src.log_id = daemon->log_id;
|
forward->frec_src.log_id = daemon->log_id;
|
||||||
@@ -582,13 +582,25 @@ static void forward_query(int udpfd, union mysockaddr *udpaddr,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* could not send on, prepare to return */
|
/* could not send on, prepare to return */
|
||||||
header->id = htons(forward->frec_src.orig_id);
|
|
||||||
free_frec(forward); /* cancel */
|
|
||||||
ede = EDE_NETERR;
|
ede = EDE_NETERR;
|
||||||
|
|
||||||
reply:
|
reply:
|
||||||
if (udpfd != -1)
|
if (udpfd != -1)
|
||||||
{
|
{
|
||||||
|
/* The query now in the buffer can have changed from what arrived during
|
||||||
|
the preparation for forwarding in two respects.
|
||||||
|
1) The header->id field may have changed.
|
||||||
|
2) The case of letters in the query may have been changed.
|
||||||
|
|
||||||
|
Restore both of these changes before using it to build an error return for the client.
|
||||||
|
The original id is held in local variable id, and the difference in case
|
||||||
|
is encoded in casediff and also bitvector if the difference spreads beyond the first
|
||||||
|
32 characters.
|
||||||
|
*/
|
||||||
|
header->id = htons(id);
|
||||||
|
if (casediff != 0)
|
||||||
|
extract_name(header, plen, NULL, (char *)(bitvector ? bitvector : &casediff), EXTR_NAME_FLIP, bitvector ? casediff : 1);
|
||||||
|
|
||||||
if (!(plen = make_local_answer(flags, gotname, plen, header, daemon->namebuff, replylimit, first, last, ede)))
|
if (!(plen = make_local_answer(flags, gotname, plen, header, daemon->namebuff, replylimit, first, last, ede)))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -619,6 +631,11 @@ static void forward_query(int udpfd, union mysockaddr *udpaddr,
|
|||||||
}
|
}
|
||||||
|
|
||||||
daemon->metrics[METRIC_DNS_LOCAL_ANSWERED]++;
|
daemon->metrics[METRIC_DNS_LOCAL_ANSWERED]++;
|
||||||
|
|
||||||
|
/* This has to be after last use of bitvector. */
|
||||||
|
if (forward)
|
||||||
|
free_frec(forward);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1267,7 +1284,7 @@ void reply_query(int fd, time_t now)
|
|||||||
had replies from all to avoid filling the forwarding table when
|
had replies from all to avoid filling the forwarding table when
|
||||||
everything is broken */
|
everything is broken */
|
||||||
|
|
||||||
/* decrement count of replies recieved if we sent to more than one server. */
|
/* decrement count of replies received if we sent to more than one server. */
|
||||||
if (forward->forwardall && (--forward->forwardall > 1) && RCODE(header) == REFUSED)
|
if (forward->forwardall && (--forward->forwardall > 1) && RCODE(header) == REFUSED)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -1289,7 +1306,8 @@ void reply_query(int fd, time_t now)
|
|||||||
server->query_latency = server->mma_latency/128;
|
server->query_latency = server->mma_latency/128;
|
||||||
|
|
||||||
/* Flip the bits back in the query name. */
|
/* Flip the bits back in the query name. */
|
||||||
if (!extract_name(header, n, NULL, (char *)&forward->frec_src.encode_bitmap, EXTR_NAME_FLIP, 1))
|
if (forward->frec_src.encode_bitmap != 0 &&
|
||||||
|
!extract_name(header, n, NULL, (char *)&forward->frec_src.encode_bitmap, EXTR_NAME_FLIP, 1))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
#ifdef HAVE_DNSSEC
|
#ifdef HAVE_DNSSEC
|
||||||
@@ -2105,7 +2123,7 @@ static ssize_t tcp_talk(int first, int last, int start, struct dns_header *heade
|
|||||||
#if defined(SO_SNDTIMEO) && defined(SO_RCVTIMEO)
|
#if defined(SO_SNDTIMEO) && defined(SO_RCVTIMEO)
|
||||||
/* TCP connections by default take ages to time out.
|
/* TCP connections by default take ages to time out.
|
||||||
Set shorter timeouts more appropriate for a DNS server.
|
Set shorter timeouts more appropriate for a DNS server.
|
||||||
We set the recieve timeout as twice the send timeout; we
|
We set the receive timeout as twice the send timeout; we
|
||||||
want to fail quickly on a non-responsive server, but give it time to get an
|
want to fail quickly on a non-responsive server, but give it time to get an
|
||||||
answer. */
|
answer. */
|
||||||
tv.tv_sec = TCP_TIMEOUT;
|
tv.tv_sec = TCP_TIMEOUT;
|
||||||
|
|||||||
+1
-7
@@ -712,13 +712,7 @@ static unsigned char *grab_extradata(unsigned char *buf, unsigned char *end, ch
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
if (next && (next != buf))
|
if (next && (next != buf))
|
||||||
{
|
val = (char *)buf;
|
||||||
char *p;
|
|
||||||
/* No "=" in value */
|
|
||||||
if ((p = strchr((char *)buf, '=')))
|
|
||||||
*p = 0;
|
|
||||||
val = (char *)buf;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
my_setenv(env, val, err);
|
my_setenv(env, val, err);
|
||||||
|
|||||||
+1
-1
@@ -527,7 +527,7 @@ void lease_update_slaac(time_t now)
|
|||||||
|
|
||||||
/* Find interfaces associated with leases at start-up. This gets updated as
|
/* Find interfaces associated with leases at start-up. This gets updated as
|
||||||
we do DHCP transactions, but information about directly-connected subnets
|
we do DHCP transactions, but information about directly-connected subnets
|
||||||
is useful from scrips and necessary for determining SLAAC addresses from
|
is useful from scripts and necessary for determining SLAAC addresses from
|
||||||
start-time. */
|
start-time. */
|
||||||
void lease_find_interfaces(time_t now)
|
void lease_find_interfaces(time_t now)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -97,25 +97,28 @@ int log_start(struct passwd *ent_pw, int errfd)
|
|||||||
entries_alloced = 1;
|
entries_alloced = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If we're running as root and going to change uid later,
|
|
||||||
change the ownership here so that the file is always owned by
|
|
||||||
the dnsmasq user. Then logrotate can just copy the owner.
|
|
||||||
Failure of the chown call is OK, (for instance when started as non-root).
|
|
||||||
|
|
||||||
If we've created a file with group-id root, we also make
|
|
||||||
the file group-writable. This gives processes in the root group
|
|
||||||
write access to the file and avoids the problem that on some systems,
|
|
||||||
once the file is owned by the dnsmasq user, it can't be written
|
|
||||||
whilst dnsmasq is running as root during startup.
|
|
||||||
*/
|
|
||||||
if (log_to_file && !log_stderr && ent_pw && ent_pw->pw_uid != 0)
|
if (log_to_file && !log_stderr && ent_pw && ent_pw->pw_uid != 0)
|
||||||
{
|
{
|
||||||
struct stat ls;
|
struct stat ls;
|
||||||
if (getgid() == 0 && fstat(log_fd, &ls) == 0 && ls.st_gid == 0 &&
|
|
||||||
(ls.st_mode & S_IWGRP) == 0)
|
/* Only mess with permissions for regular files, not (eg) /dev/null */
|
||||||
(void)fchmod(log_fd, ls.st_mode | S_IWGRP);
|
if (fstat(log_fd, &ls) == 0 && S_ISREG(ls.st_mode))
|
||||||
if (fchown(log_fd, ent_pw->pw_uid, -1) != 0)
|
{
|
||||||
ret = errno;
|
/* If we're running as root and going to change uid later,
|
||||||
|
change the ownership here so that the file is always owned by
|
||||||
|
the dnsmasq user. Then logrotate can just copy the owner. */
|
||||||
|
if (fchown(log_fd, ent_pw->pw_uid, -1) != 0)
|
||||||
|
ret = errno;
|
||||||
|
|
||||||
|
/* If we've created a file with group-id root, we also make
|
||||||
|
the file group-writable. This gives processes in the root group
|
||||||
|
write access to the file and avoids the problem that on some systems,
|
||||||
|
once the file is owned by the dnsmasq user, it can't be written
|
||||||
|
whilst dnsmasq is running as root during startup.
|
||||||
|
Failure of the chown call is OK, (for instance when started as non-root). */
|
||||||
|
if (getgid() == 0 && ls.st_gid == 0 && (ls.st_mode & S_IWGRP) == 0)
|
||||||
|
(void)fchmod(log_fd, ls.st_mode | S_IWGRP);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|||||||
+8
-13
@@ -1254,19 +1254,14 @@ void warn_bound_listeners(void)
|
|||||||
int advice = 0;
|
int advice = 0;
|
||||||
|
|
||||||
for (iface = daemon->interfaces; iface; iface = iface->next)
|
for (iface = daemon->interfaces; iface; iface = iface->next)
|
||||||
if (!iface->dns_auth)
|
if (!iface->dns_auth && !iface->warned &&
|
||||||
|
iface->addr.sa.sa_family == AF_INET && !private_net(iface->addr.in.sin_addr, 1))
|
||||||
{
|
{
|
||||||
if (iface->addr.sa.sa_family == AF_INET)
|
inet_ntop(AF_INET, &iface->addr.in.sin_addr, daemon->addrbuff, ADDRSTRLEN);
|
||||||
{
|
iface->warned = advice = 1;
|
||||||
if (!private_net(iface->addr.in.sin_addr, 1))
|
my_syslog(LOG_WARNING,
|
||||||
{
|
_("LOUD WARNING: listening on %s may accept requests via interfaces other than %s"),
|
||||||
inet_ntop(AF_INET, &iface->addr.in.sin_addr, daemon->addrbuff, ADDRSTRLEN);
|
daemon->addrbuff, iface->name);
|
||||||
iface->warned = advice = 1;
|
|
||||||
my_syslog(LOG_WARNING,
|
|
||||||
_("LOUD WARNING: listening on %s may accept requests via interfaces other than %s"),
|
|
||||||
daemon->addrbuff, iface->name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (advice)
|
if (advice)
|
||||||
@@ -1462,7 +1457,7 @@ static struct serverfd *allocate_sfd(union mysockaddr *addr, char *intname, unsi
|
|||||||
|
|
||||||
/* when using random ports, servers which would otherwise use
|
/* when using random ports, servers which would otherwise use
|
||||||
the INADDR_ANY/port0 socket have sfd set to NULL, this is
|
the INADDR_ANY/port0 socket have sfd set to NULL, this is
|
||||||
anything without an explictly set source port. */
|
anything without an explicitly set source port. */
|
||||||
if (!daemon->osport)
|
if (!daemon->osport)
|
||||||
{
|
{
|
||||||
errno = 0;
|
errno = 0;
|
||||||
|
|||||||
+77
-41
@@ -745,7 +745,7 @@ static int numeric_check(char *a)
|
|||||||
{
|
{
|
||||||
char *p;
|
char *p;
|
||||||
|
|
||||||
if (!a)
|
if (!a || *a == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
unhide_metas(a);
|
unhide_metas(a);
|
||||||
@@ -771,11 +771,14 @@ static int strtoul_check(char *a, u32 *res)
|
|||||||
|
|
||||||
if (!numeric_check(a))
|
if (!numeric_check(a))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
x = strtoul(a, NULL, 10);
|
x = strtoul(a, NULL, 10);
|
||||||
if (errno || x > UINT32_MAX) {
|
if (errno || x > UINT32_MAX)
|
||||||
errno = 0;
|
{
|
||||||
return 0;
|
errno = 0;
|
||||||
}
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
*res = (u32)x;
|
*res = (u32)x;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -1383,7 +1386,7 @@ static void dhcp_netid_list_free(struct dhcp_netid_list *netid)
|
|||||||
netid = netid->next;
|
netid = netid->next;
|
||||||
/* Note: don't use dhcp_netid_free() here, since that
|
/* Note: don't use dhcp_netid_free() here, since that
|
||||||
frees a list linked on netid->next. Where a netid_list
|
frees a list linked on netid->next. Where a netid_list
|
||||||
is used that's because the the ->next pointers in the
|
is used that's because the ->next pointers in the
|
||||||
netids are being used to temporarily construct
|
netids are being used to temporarily construct
|
||||||
a list of valid tags. */
|
a list of valid tags. */
|
||||||
free(tmplist->list->net);
|
free(tmplist->list->net);
|
||||||
@@ -1471,58 +1474,45 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
|
|||||||
|
|
||||||
while (arg)
|
while (arg)
|
||||||
{
|
{
|
||||||
|
char *start = arg;
|
||||||
comma = split(arg);
|
comma = split(arg);
|
||||||
|
|
||||||
for (cp = arg; *cp; cp++)
|
if (strstr(arg, "option:") == arg)
|
||||||
|
start = arg+7;
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
else if (strstr(arg, "option6:") == arg)
|
||||||
|
{
|
||||||
|
start = arg+8;
|
||||||
|
is6 = 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
else if (strstr(arg, "option4:") == arg)
|
||||||
|
start = arg+8;
|
||||||
|
|
||||||
|
for (cp = start; *cp; cp++)
|
||||||
if (*cp < '0' || *cp > '9')
|
if (*cp < '0' || *cp > '9')
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (!*cp)
|
if (!*cp)
|
||||||
{
|
{
|
||||||
new->opt = atoi(arg);
|
new->opt = atoi(start);
|
||||||
opt_len = 0;
|
opt_len = 0;
|
||||||
option_ok = 1;
|
option_ok = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strstr(arg, "option:") == arg)
|
/* option*:<opt>|<optname> must follow tag and vendor string. */
|
||||||
|
if (start != arg)
|
||||||
{
|
{
|
||||||
if ((new->opt = lookup_dhcp_opt(AF_INET, arg+7)) != -1)
|
if ((new->opt = lookup_dhcp_opt(is6 ? AF_INET6: AF_INET, start)) != -1)
|
||||||
{
|
{
|
||||||
opt_len = lookup_dhcp_len(AF_INET, new->opt);
|
opt_len = lookup_dhcp_len(is6 ? AF_INET6: AF_INET, new->opt);
|
||||||
/* option:<optname> must follow tag and vendor string. */
|
/* option:<optname> must follow tag and vendor string. */
|
||||||
if (!(opt_len & OT_INTERNAL) || flags == DHOPT_MATCH)
|
if (!(opt_len & OT_INTERNAL) || flags == DHOPT_MATCH)
|
||||||
option_ok = 1;
|
option_ok = 1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#ifdef HAVE_DHCP6
|
|
||||||
else if (strstr(arg, "option6:") == arg)
|
|
||||||
{
|
|
||||||
for (cp = arg+8; *cp; cp++)
|
|
||||||
if (*cp < '0' || *cp > '9')
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (!*cp)
|
|
||||||
{
|
|
||||||
new->opt = atoi(arg+8);
|
|
||||||
opt_len = 0;
|
|
||||||
option_ok = 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if ((new->opt = lookup_dhcp_opt(AF_INET6, arg+8)) != -1)
|
|
||||||
{
|
|
||||||
opt_len = lookup_dhcp_len(AF_INET6, new->opt);
|
|
||||||
if (!(opt_len & OT_INTERNAL) || flags == DHOPT_MATCH)
|
|
||||||
option_ok = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* option6:<opt>|<optname> must follow tag and vendor string. */
|
|
||||||
is6 = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
else if (strstr(arg, "vendor:") == arg)
|
else if (strstr(arg, "vendor:") == arg)
|
||||||
{
|
{
|
||||||
new->u.vendor_class = (unsigned char *)opt_string_alloc(arg+7);
|
new->u.vendor_class = (unsigned char *)opt_string_alloc(arg+7);
|
||||||
@@ -1701,7 +1691,7 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
|
|||||||
parse_hex(comma, new->val, digs, (flags & DHOPT_MATCH) ? &new->u.wildcard_mask : NULL, NULL);
|
parse_hex(comma, new->val, digs, (flags & DHOPT_MATCH) ? &new->u.wildcard_mask : NULL, NULL);
|
||||||
new->flags |= DHOPT_HEX;
|
new->flags |= DHOPT_HEX;
|
||||||
}
|
}
|
||||||
else if (is_dec)
|
else if (is_dec && !(opt_len & OT_DHCP6_VENDOR))
|
||||||
{
|
{
|
||||||
int i, val = atoi(comma);
|
int i, val = atoi(comma);
|
||||||
/* assume numeric arg is 1 byte except for
|
/* assume numeric arg is 1 byte except for
|
||||||
@@ -1890,6 +1880,48 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
|
|||||||
arg = comma;
|
arg = comma;
|
||||||
comma = split(arg);
|
comma = split(arg);
|
||||||
|
|
||||||
|
while (arg && *arg)
|
||||||
|
{
|
||||||
|
u16 len = strlen(arg);
|
||||||
|
unhide_metas(arg);
|
||||||
|
PUTSHORT(len, p);
|
||||||
|
memcpy(p, arg, len);
|
||||||
|
p += len;
|
||||||
|
|
||||||
|
arg = comma;
|
||||||
|
comma = split(arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
new->val = newp;
|
||||||
|
new->len = p - newp;
|
||||||
|
}
|
||||||
|
else if (comma && (opt_len & OT_DHCP6_VENDOR))
|
||||||
|
{
|
||||||
|
/* First arg is Enterprise ID (4 bytes)
|
||||||
|
subsequent are length fields (2 bytes each) + string */
|
||||||
|
int enterprise, i, commas = 1;
|
||||||
|
unsigned char *p, *newp;
|
||||||
|
|
||||||
|
for (i = 0; comma[i]; i++)
|
||||||
|
if (comma[i] == ',')
|
||||||
|
commas++;
|
||||||
|
|
||||||
|
newp = opt_malloc(strlen(comma)+(2*commas)+4);
|
||||||
|
p = newp;
|
||||||
|
arg = comma;
|
||||||
|
comma = split(arg);
|
||||||
|
|
||||||
|
if (atoi_check(arg, &enterprise))
|
||||||
|
PUTLONG(enterprise, p);
|
||||||
|
else
|
||||||
|
goto_err(_("bad or missing enterprise ID in dhcp-option"));
|
||||||
|
|
||||||
|
arg = comma;
|
||||||
|
comma = split(arg);
|
||||||
|
|
||||||
|
if (!arg || !*arg)
|
||||||
|
goto_err(_("missing vendor class in dhcp-option"));
|
||||||
|
|
||||||
while (arg && *arg)
|
while (arg && *arg)
|
||||||
{
|
{
|
||||||
u16 len = strlen(arg);
|
u16 len = strlen(arg);
|
||||||
@@ -2800,7 +2832,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case LOPT_CPE_ID: /* --add-dns-client */
|
case LOPT_CPE_ID: /* --add-cpe-id */
|
||||||
if (arg)
|
if (arg)
|
||||||
daemon->dns_client_id = opt_string_alloc(arg);
|
daemon->dns_client_id = opt_string_alloc(arg);
|
||||||
break;
|
break;
|
||||||
@@ -6270,7 +6302,11 @@ void read_opts(int argc, char **argv, char *compile_opts)
|
|||||||
|
|
||||||
if ((token = strtok(NULL, " \t\n\r")) &&
|
if ((token = strtok(NULL, " \t\n\r")) &&
|
||||||
(daemon->domain_suffix = canonicalise_opt(token)))
|
(daemon->domain_suffix = canonicalise_opt(token)))
|
||||||
break;
|
{
|
||||||
|
/* We don't call get_line_alloc() until it returns false and frees the automatically */
|
||||||
|
get_line_alloc(NULL, &line, &linesz);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
|||||||
+16
-1
@@ -58,7 +58,7 @@ static int add_prefixes(struct in6_addr *local, int prefix,
|
|||||||
unsigned int preferred, unsigned int valid, void *vparam);
|
unsigned int preferred, unsigned int valid, void *vparam);
|
||||||
static int iface_search(struct in6_addr *local, int prefix,
|
static int iface_search(struct in6_addr *local, int prefix,
|
||||||
int scope, int if_index, int flags,
|
int scope, int if_index, int flags,
|
||||||
unsigned int prefered, unsigned int valid, void *vparam);
|
unsigned int preferred, unsigned int valid, void *vparam);
|
||||||
static int add_lla(int index, unsigned int type, char *mac, size_t maclen, void *parm);
|
static int add_lla(int index, unsigned int type, char *mac, size_t maclen, void *parm);
|
||||||
static void new_timeout(struct dhcp_context *context, char *iface_name, time_t now);
|
static void new_timeout(struct dhcp_context *context, char *iface_name, time_t now);
|
||||||
static unsigned int calc_lifetime(struct ra_interface *ra);
|
static unsigned int calc_lifetime(struct ra_interface *ra);
|
||||||
@@ -608,6 +608,7 @@ static int add_prefixes(struct in6_addr *local, int prefix,
|
|||||||
int do_slaac = 0;
|
int do_slaac = 0;
|
||||||
int deprecate = 0;
|
int deprecate = 0;
|
||||||
int constructed = 0;
|
int constructed = 0;
|
||||||
|
int have_lease = 0;
|
||||||
int adv_router = 0;
|
int adv_router = 0;
|
||||||
int off_link = 0;
|
int off_link = 0;
|
||||||
unsigned int time = 0xffffffff;
|
unsigned int time = 0xffffffff;
|
||||||
@@ -660,6 +661,8 @@ static int add_prefixes(struct in6_addr *local, int prefix,
|
|||||||
if (time < ((unsigned int)(3 * param->adv_interval)))
|
if (time < ((unsigned int)(3 * param->adv_interval)))
|
||||||
time = 3 * param->adv_interval;
|
time = 3 * param->adv_interval;
|
||||||
}
|
}
|
||||||
|
if (context->flags & CONTEXT_SETLEASE)
|
||||||
|
have_lease = 1;
|
||||||
|
|
||||||
if (context->flags & CONTEXT_DEPRECATE)
|
if (context->flags & CONTEXT_DEPRECATE)
|
||||||
deprecate = 1;
|
deprecate = 1;
|
||||||
@@ -698,6 +701,18 @@ static int add_prefixes(struct in6_addr *local, int prefix,
|
|||||||
if (!constructed || valid > time)
|
if (!constructed || valid > time)
|
||||||
valid = time;
|
valid = time;
|
||||||
|
|
||||||
|
/* For CONSTRUCTED prefixes an explicitly configured lease time is
|
||||||
|
also a floor: an upstream delegating with very short lifetimes
|
||||||
|
(mobile links) would otherwise churn the addresses of any client
|
||||||
|
that sleeps through a few RAs. Deprecation still wins below. */
|
||||||
|
if (constructed && have_lease && !deprecate && !(flags & IFACE_DEPRECATED))
|
||||||
|
{
|
||||||
|
if (valid < time)
|
||||||
|
valid = time;
|
||||||
|
if (preferred < time)
|
||||||
|
preferred = time;
|
||||||
|
}
|
||||||
|
|
||||||
if (flags & IFACE_DEPRECATED)
|
if (flags & IFACE_DEPRECATED)
|
||||||
preferred = 0;
|
preferred = 0;
|
||||||
|
|
||||||
|
|||||||
+6
-20
@@ -585,10 +585,7 @@ static int find_soa(struct dns_header *header, size_t qlen, char *name, int *sub
|
|||||||
{
|
{
|
||||||
len = to_wire(daemon->workspacename);
|
len = to_wire(daemon->workspacename);
|
||||||
if (!blockdata_expand(addr.rrblock.rrdata, addr.rrblock.datalen, daemon->workspacename, len))
|
if (!blockdata_expand(addr.rrblock.rrdata, addr.rrblock.datalen, daemon->workspacename, len))
|
||||||
{
|
return 0;
|
||||||
blockdata_free(addr.rrblock.rrdata);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
addr.rrblock.datalen += len;
|
addr.rrblock.datalen += len;
|
||||||
}
|
}
|
||||||
@@ -607,10 +604,7 @@ static int find_soa(struct dns_header *header, size_t qlen, char *name, int *sub
|
|||||||
int secflag = 0;
|
int secflag = 0;
|
||||||
|
|
||||||
if (!blockdata_expand(addr.rrblock.rrdata, addr.rrblock.datalen, (char *)p, 20))
|
if (!blockdata_expand(addr.rrblock.rrdata, addr.rrblock.datalen, (char *)p, 20))
|
||||||
{
|
return 0;
|
||||||
blockdata_free(addr.rrblock.rrdata);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
addr.rrblock.datalen += 20;
|
addr.rrblock.datalen += 20;
|
||||||
|
|
||||||
@@ -942,10 +936,8 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
|
|||||||
{
|
{
|
||||||
/* Copy the rest of the RR and end. */
|
/* Copy the rest of the RR and end. */
|
||||||
if (!blockdata_expand(addr.rrblock.rrdata, addr.rrblock.datalen, (char *)p1, endrr - p1))
|
if (!blockdata_expand(addr.rrblock.rrdata, addr.rrblock.datalen, (char *)p1, endrr - p1))
|
||||||
{
|
return 0;
|
||||||
blockdata_free(addr.rrblock.rrdata);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
addr.rrblock.datalen += endrr - p1;
|
addr.rrblock.datalen += endrr - p1;
|
||||||
}
|
}
|
||||||
else if (desc == 0)
|
else if (desc == 0)
|
||||||
@@ -962,10 +954,7 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
|
|||||||
|
|
||||||
len = to_wire(name);
|
len = to_wire(name);
|
||||||
if (!blockdata_expand(addr.rrblock.rrdata, addr.rrblock.datalen, name, len))
|
if (!blockdata_expand(addr.rrblock.rrdata, addr.rrblock.datalen, name, len))
|
||||||
{
|
return 0;
|
||||||
blockdata_free(addr.rrblock.rrdata);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
addr.rrblock.datalen += len;
|
addr.rrblock.datalen += len;
|
||||||
}
|
}
|
||||||
@@ -976,10 +965,7 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
|
|||||||
desc = endrr - p1;
|
desc = endrr - p1;
|
||||||
|
|
||||||
if (!blockdata_expand(addr.rrblock.rrdata, addr.rrblock.datalen, (char *)p1, desc))
|
if (!blockdata_expand(addr.rrblock.rrdata, addr.rrblock.datalen, (char *)p1, desc))
|
||||||
{
|
return 0;
|
||||||
blockdata_free(addr.rrblock.rrdata);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
addr.rrblock.datalen += desc;
|
addr.rrblock.datalen += desc;
|
||||||
p1 += desc;
|
p1 += desc;
|
||||||
|
|||||||
+2
-1
@@ -1611,7 +1611,8 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
|||||||
lease->extradata_size = lease->extradata_len = 0;
|
lease->extradata_size = lease->extradata_len = 0;
|
||||||
|
|
||||||
add_extradata_opt(lease, option_find(mess, sz, OPTION_VENDOR_ID, 1));
|
add_extradata_opt(lease, option_find(mess, sz, OPTION_VENDOR_ID, 1));
|
||||||
add_extradata_opt(lease, option_find(mess, sz, OPTION_HOSTNAME, 1));
|
lease_add_extradata(lease, (unsigned char *)client_hostname,
|
||||||
|
client_hostname ? strlen(client_hostname) : 0, 0);
|
||||||
add_extradata_opt(lease, oui);
|
add_extradata_opt(lease, oui);
|
||||||
add_extradata_opt(lease, serial);
|
add_extradata_opt(lease, serial);
|
||||||
add_extradata_opt(lease, class);
|
add_extradata_opt(lease, class);
|
||||||
|
|||||||
+2
-2
@@ -255,10 +255,10 @@ static int dhcp6_maybe_relay(struct state *state, unsigned char *inbuff, size_t
|
|||||||
/* the packet data is unaligned, copy to aligned storage */
|
/* the packet data is unaligned, copy to aligned storage */
|
||||||
memcpy(&align, inbuff + 2, IN6ADDRSZ);
|
memcpy(&align, inbuff + 2, IN6ADDRSZ);
|
||||||
|
|
||||||
/* RFC6221 para 4 says if link_address in encapulation
|
/* RFC6221 para 4 says if link_address in encapsulation
|
||||||
is zero, ignore it, and, by implication, use the link
|
is zero, ignore it, and, by implication, use the link
|
||||||
address of any enclosing encapsulation or, failing that
|
address of any enclosing encapsulation or, failing that
|
||||||
of the arrival interface on the the server. */
|
of the arrival interface on the server. */
|
||||||
if (!dhcp6_maybe_relay(state, opt6_ptr(opt, 0), opt6_len(opt), client_addr,
|
if (!dhcp6_maybe_relay(state, opt6_ptr(opt, 0), opt6_len(opt), client_addr,
|
||||||
IN6_IS_ADDR_UNSPECIFIED(&align) ? link_address : &align, now))
|
IN6_IS_ADDR_UNSPECIFIED(&align) ? link_address : &align, now))
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
+7
-9
@@ -251,15 +251,14 @@ static void tftp_request(char *packet, ssize_t plen, struct listener *listen, ti
|
|||||||
|
|
||||||
for (tftp_cnt = 0, transfer = daemon->tftp_trans, up = &daemon->tftp_trans; transfer; up = &transfer->next, transfer = transfer->next)
|
for (tftp_cnt = 0, transfer = daemon->tftp_trans, up = &daemon->tftp_trans; transfer; up = &transfer->next, transfer = transfer->next)
|
||||||
{
|
{
|
||||||
tftp_cnt++;
|
|
||||||
|
|
||||||
if (sockaddr_isequal(&peer, &transfer->peer))
|
if (sockaddr_isequal(&peer, &transfer->peer))
|
||||||
{
|
{
|
||||||
if (ntohs(*((unsigned short *)packet)) == OP_RRQ)
|
if (ntohs(*((unsigned short *)packet)) == OP_RRQ)
|
||||||
{
|
{
|
||||||
/* Handle repeated RRQ or abandoned transfer from same host and port
|
/* Handle repeated RRQ or abandoned transfer from same host and port
|
||||||
by unlinking and reusing the struct transfer. */
|
by abandoning old transfer. */
|
||||||
*up = transfer->next;
|
*up = transfer->next;
|
||||||
|
free_transfer(transfer);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -268,12 +267,14 @@ static void tftp_request(char *packet, ssize_t plen, struct listener *listen, ti
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tftp_cnt++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Enforce simultaneous transfer limit. In non-single-port mode
|
/* Enforce simultaneous transfer limit. In non-single-port mode
|
||||||
this is done by not listening on the server socket when
|
this is done by not listening on the server socket when
|
||||||
too many transfers are in progress. */
|
too many transfers are in progress. */
|
||||||
if (!transfer && tftp_cnt >= daemon->tftp_max)
|
if (tftp_cnt >= daemon->tftp_max)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -302,12 +303,9 @@ static void tftp_request(char *packet, ssize_t plen, struct listener *listen, ti
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/* May reuse struct transfer from abandoned transfer in single port mode. */
|
if (!(transfer = whine_malloc(sizeof(struct tftp_transfer))))
|
||||||
if (!transfer && !(transfer = whine_malloc(sizeof(struct tftp_transfer))))
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
memset(transfer, 0, sizeof(struct tftp_transfer));
|
|
||||||
|
|
||||||
if (option_bool(OPT_SINGLE_PORT))
|
if (option_bool(OPT_SINGLE_PORT))
|
||||||
transfer->sockfd = listen->tftpfd;
|
transfer->sockfd = listen->tftpfd;
|
||||||
else if ((transfer->sockfd = socket(family, SOCK_DGRAM, 0)) == -1)
|
else if ((transfer->sockfd = socket(family, SOCK_DGRAM, 0)) == -1)
|
||||||
@@ -857,7 +855,7 @@ static char *next(char **p, char *end)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If we don't do anything, don't write the the input/ouptut
|
/* If we don't do anything, don't write the input/output
|
||||||
buffer. This allows us to pass in safe read-only strings constants. */
|
buffer. This allows us to pass in safe read-only strings constants. */
|
||||||
static void sanitise(char *buf)
|
static void sanitise(char *buf)
|
||||||
{
|
{
|
||||||
|
|||||||
+5
-4
@@ -947,7 +947,7 @@ int kernel_version(void)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define hash_ptr(x) (((unsigned int)(((char *)(x)) - ((char *)NULL))) & 0xffffff)
|
#define hash_ptr(x) (((uintptr_t)(x)) & 0xffffff)
|
||||||
|
|
||||||
void *whine_malloc_real(const char *func, unsigned int line, size_t size)
|
void *whine_malloc_real(const char *func, unsigned int line, size_t size)
|
||||||
{
|
{
|
||||||
@@ -1038,15 +1038,14 @@ void free_real(const char *func, unsigned int line, void *ptr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* get lines from f, expand buffer as required. Buffer is freed when
|
/* get lines from f, expand buffer as required. Buffer is freed when
|
||||||
EOF reached and we return zero. */
|
EOF reached and we return zero. Buffer also freed if f == NULL. */
|
||||||
int get_line_alloc(FILE *f, char **buffp, size_t *sizep)
|
int get_line_alloc(FILE *f, char **buffp, size_t *sizep)
|
||||||
{
|
{
|
||||||
char c;
|
|
||||||
size_t cnt = 0;
|
size_t cnt = 0;
|
||||||
char *buff = *buffp;
|
char *buff = *buffp;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
c = getc(f);
|
int c = f ? getc(f) : EOF;
|
||||||
|
|
||||||
if (cnt == *sizep)
|
if (cnt == *sizep)
|
||||||
{
|
{
|
||||||
@@ -1081,6 +1080,8 @@ int get_line_alloc(FILE *f, char **buffp, size_t *sizep)
|
|||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
free(buff);
|
free(buff);
|
||||||
|
*buffp = NULL;
|
||||||
|
*sizep = 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user