Let's be extra careful whenever we return from recvmsg() and see
MSG_CTRUNC set. This generally means we ran into a programming error, as
we didn't size the control buffer large enough. It's an error condition
we should at least log about, or propagate up. Hence do that.
This is particularly important when receiving fds, since for those the
control data can be of any size. In particular on stream sockets that's
nasty, because if we miss an fd because of control data truncation we
cannot recover, we might not even realize that we are one off.
(Also, when failing early, if there's any chance the socket might be
AF_UNIX let's close all received fds, all the time. We got this right
most of the time, but there were a few cases missing. God, UNIX is hard
to use)
It's not that I think that "hostname" is vastly superior to "host name". Quite
the opposite — the difference is small, and in some context the two-word version
does fit better. But in the tree, there are ~200 occurrences of the first, and
>1600 of the other, and consistent spelling is more important than any particular
spelling choice.
When the stub listener is disabled, stub-resolv.conf is useless. Instead of
warning about this, let's just make stub-resolv.conf point to the private
resolv.conf file. (The original bug report asked for "mirroring", but I think
a symlink is nicer than a copy because it is easier to see that a redirection
was made.)
Fixes#14700.
All callers ignore the return value.
This is almost entirely theoretical, since writing to /run is unlikely to
fail..., but the user is almost certainly better off keeping the old copy
around and having working dns resolution with an out-of-date dns server list
than having having a dangling /etc/resolv.conf symlink.
An error with a full path is immediately clear. OTOH, a user might not be
familiar with concenpt like "private resolv.conf".
I opted to use %s-formatting for the path, because the code is much easier to
read this way. Any difference in t speed of execution is not important.
This is useful to raise the log level for a single transaction or a few,
without affecting other state of the resolved as a restart would.
The log level can only be set, I didn't bother with having the ability
to restore the original as in pid1.
There are legitimate reasons to access the file directly, as currently
discussed on fedora-devel. Hence tone things down from "must" to "should
typically not".
Also, let's use fputs() instead of fputs_unlocked() here,
fopen_temporary_label() turns off stdio locking anyway for the whole
FILE*, hence no need to do this manually each time.
On certain distributions such as NixOS the mtime of `/etc/hosts` is
locked to a fixed value. In such cases, only checking the last mtime of
`/etc/hosts` is not enough - we also need to check if the st_ino/st_dev
match up. Thus, let's make sure make sure that systemd-resolved also
rereads `/etc/hosts` if the inode or the device containing `/etc/hosts` changes.
Test script:
```bash
hosts="/etc/hosts"
echo "127.0.0.1 testpr" > "hosts_new"
mv "hosts_new" "$hosts"
resolvectl query testpr || exit 1
mtime="$(stat -c %y "$hosts")"
echo "127.0.0.1 newhost" > "hosts_tmp"
touch -d "$mtime" "hosts_tmp"
install -p "hosts_tmp" "$hosts"
sleep 10
resolvectl query newhost || exit 1
rm -f "hosts_tmp"
```
Closes#14456.
Widely accepted certificates for IP addresses are expensive and only
affordable for larger organizations. Therefore if the user provides
the hostname in the DNS= option, we should use it instead of the IP
address.
Section 6.2 of RFC4034 requires that "all uppercase US-ASCII letters in
the DNS names contained within the RDATA are replaced by the corresponding
lowercase US-ASCII letters" for a long list of RR types.
Fixes#14891
In subsequent commits, calls to if_nametoindex() will be replaced by a wrapper
that falls back to alternative name resolution over netlink. netlink support
requires libsystemd (for sd-netlink), and we don't want to add any functions
that require netlink in basic/. So stuff that calls if_nametoindex() for user
supplied interface names, and everything that depends on that, needs to be
moved.
We don't need a seperate output parameter that is of type int. glibc() says
that the type is "unsigned", but the kernel thinks it's "int". And the
"alternative names" interface also uses ints. So let's standarize on ints,
since it's clearly not realisitic to have interface numbers in the upper half
of unsigned int range.
If a daemon is not started as root, most likely it also can't create its
directory and let's not try to resolve the user in that case either.
Create /run/systemd/netif/lldp with tmpfiles.d like other netif directories.
This is also very helpful for preparing a RootImage for the daemons as NSS crud
is not needed.
This cleans up and unifies the outut of --help texts a bit:
1. Highlight the human friendly description string, not the command
line via ANSI sequences. Previously both this description string and
the brief command line summary was marked with the same ANSI
highlight sequence, but given we auto-page to less and less does not
honour multi-line highlights only the command line summary was
affectively highlighted. Rationale: for highlighting the description
instead of the command line: the command line summary is relatively
boring, and mostly the same for out tools, the description on the
other hand is pregnant, important and captions the whole thing and
hence deserves highlighting.
2. Always suffix "Options" with ":" in the help text
3. Rename "Flags" → "Options" in one case
4. Move commands to the top in a few cases
5. add coloring to many more help pages
6. Unify on COMMAND instead of {COMMAND} in the command line summary.
Some tools did it one way, others the other way. I am not sure what
precisely {} is supposed to mean, that uppercasing doesn't, hence
let's simplify and stick to the {}-less syntax
And minor other tweaks.
Validate the IP address in the certificate for DNS-over-TLS in strict mode when GnuTLS is used. As this is not yet the case in contrast to the documentation.
Increase the required version to ensure TLS 1.3 is always supported when using GnuTLS for DNS-over-TLS and allow further changes to use recent API additions.
Notifications are only sent for the top object, and not for individual
links. This should be enough for the most obvious cases where somebody
just cares about the effective set of servers.
Fixes#13721.
The DnsStreamType was added to track different types of DNS TCP streams,
instead of refcounting all of them together. However, the stream type was
not actually set into the stream->type field, so while the reference count
was correctly incremented per-stream-type, the reference count was always
decremented in the cleanup function for stream type 0, leading to
underflow for the type 0 stream (unsigned) refcount, and preventing new
type 0 streams from being created.
Since type 0 is DNS_STREAM_LOOKUP, which is used to communicate with
upstream nameservers, once the refcount underflows the stub resolver
no longer is able to successfully fall back to TCP upstream lookups
for any truncated UDP packets.
This was found because lookups of A records with a large number of
addresses, too much to fit into a single 512 byte DNS UDP reply,
were causing getaddrinfo() to fall back to TCP and trigger this bug,
which then caused the TCP fallback for later large record lookups
to fail with 'connection timed out; no servers could be reached'.
The stream type was introduced in commit:
652ba568c6
Prefer TLS 1.3 before TLS 1.2 for DNS-over-TLS support, otherwise
servers compliant with RFC 8446 might end up agreeing TLS 1.2 plus a
downgrade signal which is not expected by GnuTLS clients. This manifests
in the following error:
Failed to invoke gnutls_handshake: An illegal parameter has been received.
Fixes: #13528
Fixes: v242-962-g9c0624dcdb ("resolved: support TLS 1.3 when using GnuTLS for DNS-over-TLS")
For executables which take a verb, we should list the verbs first, and
then options which modify those verbs second. The general layout of
the man page is from general description to specific details, usually
Overview, Commands, Options, Return Value, Examples, References.
"reset" is more understandable. The verb is "revert", but it might actually be
better to have a description which uses different words instead of duplicating
the name of the command.
379158684a (commitcomment-34992552)
This matches what is done in networkd very closely. In fact even the
policy descriptions are all identical (with s/network/resolve), except
for the last one:
resolved has org.freedesktop.resolve1.revert while
networkd has org.freedesktop.network1.revert-ntp and
org.freedesktop.network1.revert-dns so the description is a bit different.
This doesn't matter much, but let's just do the loop once and allocate
the populate the result set on the fly. If we find an error, it'll get
cleaned up automatically.
Change the resolved.conf Cache option to a tri-state "no, no-negative, yes" values.
If a lookup returns SERVFAIL systemd-resolved will cache the result for 30s (See 201d995),
however, there are several use cases on which this condition is not acceptable (See systemd#5552 comments)
and the only workaround would be to disable cache entirely or flush it , which isn't optimal.
This change adds the 'no-negative' option when set it avoids putting in cache
negative answers but still works the same heuristics for positive answers.
Signed-off-by: Jorge Niedbalski <jnr@metaklass.org>
Whenever I see EXTRACT_QUOTES, I'm always confused whether it means to
leave the quotes in or to take them out. Let's say "unquote", like we
say "cunescape".
Instead of having a context and/or trusted CA list per server this is now moved to the server. Ensures future TLS configuration options are global instead of per server.
This reverts commit 18bddeaaf2.
Revert this because it does not take the OpenSSL internal read pointer
into considoration. Resulting in padding in packetdata and therefore
broken SSL connections.
When emitting the calendarspec warning we want to see some color.
Follow-up for 04220fda5c.
Exceptions:
- systemctl, because it has a lot hand-crafted coloring
- tmpfiles, sysusers, stdio-bridge, etc, because they are also used in
services and I'm not sure if this wouldn't mess up something.
This is partially a refactoring, but also makes many more places use
unlocked operations implicitly, i.e. all users of fopen_temporary().
AFAICT, the uses are always for short-lived files which are not shared
externally, and are just used within the same context. Locking is not
necessary.
We'd call dns_resource_record_equal(), which calls dns_resource_key_equal()
internally, and then dns_resource_key_equal() a second time. Let's be
a bit smarter, and call dns_resource_key_equal() only once.
(before)
dns_resource_key_hash_func_count=514
dns_resource_key_compare_func_count=275
dns_resource_key_equal_count=62371
4.13s user 0.01s system 99% cpu 4.153 total
(after)
dns_resource_key_hash_func_count=514
dns_resource_key_compare_func_count=276
dns_resource_key_equal_count=31337
2.13s user 0.01s system 99% cpu 2.139 total
This doesn't necessarily make things faster, because we still spend more time
in dns_answer_add(), but it improves the compuational complexity of this part.
If we even make dns_resource_key_equal_faster, this will become worthwhile.
* Current logic:
For each NSEC RR find the common suffix between the owner name and
the next name, append asterisk to that suffix and check that
generated wildcard is covered by the NSEC RR in question.
* New logic:
Find NSEC RR covering queried name, generate wildcard as
<asterisk>.<closest encloser> using this RR, then check if any
of the NSEC RRs covers generated wildcard.
/usr/local/lib/systemd/dnssd is now also included in the search path. This
path is of limited usefulness, but it makes sense to be consistent.
Documentation is updated to match. Outdated advice against drop-ins in /usr
is removed.
In all other cases (i.e. classic DNS connection towards an upstream
server, or incoming stub connection, or incoming LMMNR connection) we
want long-running connections, hence keep the connection open for good.
Only in the LLMNR client case let's close the stream as soon as we are
done.
Previously we'd start the timeout once when we allocated the stream.
However, we'd now like to emphasize long-running connections hence let's
rework the timeout logic, and restart it whenever we see action ont the
stream. Thus, idle streams are eventually closed down, but those where
we read or write from are not.
We use stream objects in four different cases: let's track them.
This in particular allows us to make sure the limit on outgoing streams
cannot be exhausted by having incoming streams as this means we can
neatly separate the counters for all four types.
In all three cases, sd_event_loop() will return the exit code anyway.
If sd_event_loop() returns negative, failure is logged and results in an
immediate return. Otherwise, we don't care if sd_event_loop() returns 0
or positive, because the return value feeds into DEFINE_MAIN_FUNCTION(), which
doesn't make the distinction.
Previously, we'd use a link as "default" route depending on whether
there are route-only domains defined on it or not. (If there are, it
would not be used as default route, if there aren't it would.)
Let's make this explicit and add a link variable controlling this. The
variable is not changeable from the outside yet, but subsequent commits
are supposed to add that.
Note that making this configurable adds a certain amount of redundancy,
as there are now two ways to ensure a link does not receive "default"
lookup (i.e. DNS queries matching no configured route):
1. By ensuring that at least one other link configures a route on it
(for example by add "." to its search list)
2. By setting this new boolean to false.
But this is exactly what is intended with this patch: that there is an
explicit way to configure on the link itself whether it receives
'default' traffic, rather than require this to be configured on other
links.
The variable added is a tri-state: if true, the link is suitable for
recieving "default" traffic. If false, the link is not suitable for it.
If unset (i.e. negative) the original logic of "has this route-only
routes" is used, to ensure compatibility with the status quo ante.
The function dns_server_limited_domains() was very strange as it
enumerate the domains associated with a DnsScope object to determine
whether any "route-only" domains, but did so as a function associated
with a DnsServer object.
Let's clear this up, and replace it by a function associated with a
DnsScope instead. This makes more sense philosphically and allows us to
reduce the loops through which we need to jump to determine whether a
scope is suitable for default routing a bit.
Previously, we'd return DNS_SCOPE_MAYBE for all domain lookups matching
LLMNR or mDNS. Let's upgrade this to DNS_SCOPE_YES, to make the binding
stronger.
The effect of this is that even if "local" is defined as routing domain
on some iface, we'll still lookup domains in local via mDNS — if mDNS is
turned on. This should not be limiting, as people who don't want such
lookups should turn off mDNS altogether, as it is useless if nothing is
routed to it.
This also has the nice benefit that mDNS/LLMR continue to work if people
use "~." as routing domain on some interface.
Similar for LLMNR and single label names.
Similar also for the link local IPv4 and IPv6 reverse lookups.
Fixes: #10125
There's no value in authenticating SOA RRs that are neither answer to
our question nor parent of our question (the latter being relevant so
that we have a TTL from the SOA field for negative caching of the actual
query).
By being to eager here, and trying to authenticate too much we run the
risk of creating cyclic deps between our transactions which then causes
the over-all authentication to fail.
Fixes: #9771
This appears to be necessary for client software to ensure the reponse data
is validated with DNSSEC. For example, `ssh -v -o VerifyHostKeyDNS=yes -o
StrictHostKeyChecking=yes redpilllinpro01.ring.nlnog.net` fails if EDNS0 is
not enabled. The debugging output reveals that the `SSHFP` records were
found in DNS, but were considered insecure.
Note that the patch intentionally does *not* enable EDNS0 in the
`/run/systemd/resolve/resolv.conf` file (the one that contains `nameserver`
entries for the upstream DNS servers), as it is impossible to know for
certain that all the upstream DNS servers handles EDNS0 correctly.
Apparently people want more of these (as #11175 shows). Since this is
merely a safety limit for us, let's just bump all values substantially.
Fixes: #11175
RFC7766 section 4 states that in the absence of EDNS0, a response that
is too large for a 512-byte UDP packet will have the 'truncated' bit
set. The client is expected to retry the query over TCP.
Fixes#10264.
It would be very wrong if any of the specfier printf calls modified
any of the objects or data being printed. Let's mark all arguments as const
(primarily to make it easier for the reader to see where modifications cannot
occur).
https://tools.ietf.org/html/rfc1035#section-2.3.1 says (approximately)
that only letters, numbers, and non-leading non-trailing dashes are allowed
(for entries with A/AAAA records). We set no restrictions.
hosts(5) says:
> Host names may contain only alphanumeric characters, minus signs ("-"), and
> periods ("."). They must begin with an alphabetic character and end with an
> alphanumeric character.
nss-files follows those rules, and will ignore names in /etc/hosts that do not
follow this rule.
Let's follow the documented rules for /etc/hosts. In particular, this makes us
consitent with nss-files, reducing surprises for the user.
I'm pretty sure we should apply stricter filtering to names received over DNS
and LLMNR and MDNS, but it's a bigger project, because the rules differ
depepending on which level the label appears (rules for top-level names are
stricter), and this patch takes the minimalistic approach and only changes
behaviour for /etc/hosts.
Escape syntax is also disallowed in /etc/hosts, even if the resulting character
would be allowed. Other tools that parse /etc/hosts do not support this, and
there is no need to use it because no allowed characters benefit from escaping.
Do not treat various errors (missing hostname, invalid address) as fatal,
just warn and continue. /etc/hosts is written by humans and we should not
reject the whole file just because a singly entry is not to our liking.
Handle comments as described in hosts(5):
everything from the comment character until the end of the line should be
ignored.
Fixes#10779.
Add tests.
This adds a helper call for detaching a DnsServer from a DnsStream if
the latter is the "default" stream of the server.
Also, let's unref the stream in dns_stream_stop() rather than
dns_stream_free(): as soon as our stream is disconnected by stopping
there's really no need to keep it as default stream for the server
around.
Since dns_stream_free() calls dns_stream_stop() we can remove it from
the former.
DnsStream and DnsServer have a symbiotic relationship: one DnsStream is
the current "default" stream of the server (and thus reffed by it), but
each stream also refs the server it is connected to. This cyclic
dependency can result in weird situations: when one is
destroyed/unlinked/stopped it needs to unregister itself from the other,
but doing this will trigger unregistration of the other. Hence, let's
make sure we unregister the stream from the server before destroying it,
to break this cycle.
Most likely fixes: #10725
We register an on_packet() handler anyway, which is called first.
There's hence no need to check in on_stream_complete() again, as it is
already taken by that time.
Let's not name a variable of type ssize_t "r". We usually use "r" for
return values of API calls that return some kind of error as in int.
This creates a lot of confusion if used differently here, which actually
resulted in connect()'s return value being assigned to this mistyped "r"
by accident.
Let's rename the variable "m" hence, and not use it for connect() return
values.
If file "/etc/hosts" does not exist, fopen fails and sets errno to ENOENT
("No such file or directory"). So errno should be compared with ENOENT.
This mistake causes test test-resolved-etc-hosts to fail when run on Debian
image built with mkosi.debian included in the repo. The image does not include
"/etc/hosts" file as it is not created by debootstrap, see debootstrap manpage
https://manpages.debian.org/stretch/debootstrap/debootstrap.8.en.html.
Similar as before: don't output ifindex twice on the same address, and
show it as comment only.
Do this for reverse lookup output and all other output too.
We already used in_addr_ifindex_to_string() which internally appends the
ifindex to the address with % if necessary. It's simply wrong to attach the
intreface a second time with % then. Also, it breaks stuff that cannot
deal with that. Hence, let's reformat this, and add the ifindex as a
comment to the output, and drop the second % suffix.
All our bus calls validate whether the specified device is a loopback
device anyway on the server side. Let's hence simplify the client,
there's no value in optimizing error paths after all. But there is value
in simpler code.
it's a bit confusing that we take two interfaces for verbs such as "dns"
or "domain": once after the verb, and once as --interface=. While
there's logic behind it, let's make this least surprising: if either is
specified be happy.
This means "resolvectl -i foo dns" is now equivalent to "resolvectl dns
foo …". Note that this is a tweak only, to minimize surprises. We don't
document this alternative syntax, and shouldn't to keep things simple.
Let's compare the ifname passed in with what is set already if there is
something set already. Complain in that case. This makes commands such
as "resolvectl -i foo dns bar" less weird, as we'll refuse the duplicate
ifname specifications.
Also, free the old arg_ifname right before assigning the new, instead of
doing so in advance.
This information is useful to pass back to the caller, as it tells us
where we found the answer.
(While we are at it, fix the socket level for the RECVERR logic)
Fixes: #9778
This splits out a bunch of functions from fileio.c that have to do with
temporary files. Simply to make the header files a bit shorter, and to
group things more nicely.
No code changes, just some rearranging of source files.
DNS_PACKET_PAYLOAD_SIZE_MAX is limiting the size of the stub replies to
512 with EDNS off or 4096 with EDNS on, without checking the protocol
used. This makes TCP replies for clients without EDNS support to be
limited to 512, making the truncate flag useless if the query result is
bigger than 512 bytes.
This commit increases the size of TCP replies to DNS_PACKET_SIZE_MAX
Fixes: #10816
Ideally, coccinelle would strip unnecessary braces too. But I do not see any
option in coccinelle for this, so instead, I edited the patch text using
search&replace to remove the braces. Unfortunately this is not fully automatic,
in particular it didn't deal well with if-else-if-else blocks and ifdefs, so
there is an increased likelikehood be some bugs in such spots.
I also removed part of the patch that coccinelle generated for udev, where we
returns -1 for failure. This should be fixed independently.
Now that we don't (mis-)use the env file parser to parse kernel command
lines there's no need anymore to override the used newline character
set. Let's hence drop the argument and just "\n\r" always. This nicely
simplifies our code.
All users of the macro (except for one, in serialize.c), use the macro in
connection with read_line(), so they must include fileio.h. Let's not play
libc games and require multiple header file to be included for the most common
use of a function.
The removal of def.h includes is not exact. I mostly went over the commits that
switch over to use read_line() and add def.h at the same time and reverted the
addition of def.h in those files.
Pretty much everything uses just the first argument, and this doesn't make this
common pattern more complicated, but makes it simpler to pass multiple options.
All over the place we define local variables for the various sockopts
that take a bool-like "int" value. Sometimes they are const, sometimes
static, sometimes both, sometimes neither.
Let's clean this up, introduce a common const variable "const_int_one"
(as well as one matching "const_int_zero") and use it everywhere, all
acorss the codebase.
`systemd-resolved.service` runs as `User=systemd-resolved`, and uses certain
Capabilit{y,ies} magic. By my understanding, this means it is started with a
number of "privileges". Indeed, `capabilities(7)` explains
> Linux divides the privileges traditionally
> associated with superuser into distinct units, known as capabilities,
> which can be independently enabled and disabled."
This situation appears to contradict our current code comment which said
> If we are not running as root we assume all privileges are already dropped.
This appears to be a confusion in the comment only. The rest of the code
tells a much clearer story. (Don't ask me if the story is correct.
`capabilities(7)` scares me). Let's tweak the comment to make it consistent
and avoid worrying readers about this.
Let's fold get_user_creds_clean() into get_user_creds(), and introduce a
flags argument for it to select "clean" behaviour. This flags parameter
also learns to other new flags:
- USER_CREDS_SYNTHESIZE_FALLBACK: in this mode the user records for
root/nobody are only synthesized as fallback. Normally, the synthesized
records take precedence over what is in the user database. With this
flag set this is reversed, and the user database takes precedence, and
the synthesized records are only used if they are missing there. This
flag should be set in cases where doing NSS is deemed safe, and where
there's interest in knowing the correct shell, for example if the
admin changed root's shell to zsh or suchlike.
- USER_CREDS_ALLOW_MISSING: if set, and a UID/GID is specified by
numeric value, and there's no user/group record for it accept it
anyway. This allows us to fix#9767
This then also ports all users to set the most appropriate flags.
Fixes: #9767
[zj: remove one isempty() call]
This is a bit like the info link in most of GNU's --help texts, but we
don't do info but man pages, and we make them properly clickable on
terminal supporting that, because awesome.
I think it's generally advisable to link up our (brief) --help texts and
our (more comprehensive) man pages a bit, so this should be an easy and
straight-forward way to do it.
This fixes a memory leak:
```
d5070e2f67ededca022f81f2941900606b16f3196b2268e856295f59._openpgpkey.gmail.com: resolve call failed: 'd5070e2f67ededca022f81f2941900606b16f3196b2268e856295f59._openpgpkey.gmail.com' not found
=================================================================
==224==ERROR: LeakSanitizer: detected memory leaks
Direct leak of 65 byte(s) in 1 object(s) allocated from:
#0 0x7f71b0878850 in malloc (/usr/lib64/libasan.so.4+0xde850)
#1 0x7f71afaf69b0 in malloc_multiply ../src/basic/alloc-util.h:63
#2 0x7f71afaf6c95 in hexmem ../src/basic/hexdecoct.c:62
#3 0x7f71afbb574b in string_hashsum ../src/basic/gcrypt-util.c:45
#4 0x56201333e0b9 in string_hashsum_sha256 ../src/basic/gcrypt-util.h:30
#5 0x562013347b63 in resolve_openpgp ../src/resolve/resolvectl.c:908
#6 0x562013348b9f in verb_openpgp ../src/resolve/resolvectl.c:944
#7 0x7f71afbae0b0 in dispatch_verb ../src/basic/verbs.c:119
#8 0x56201335790b in native_main ../src/resolve/resolvectl.c:2947
#9 0x56201335880d in main ../src/resolve/resolvectl.c:3087
#10 0x7f71ad8fcf29 in __libc_start_main (/lib64/libc.so.6+0x20f29)
SUMMARY: AddressSanitizer: 65 byte(s) leaked in 1 allocation(s).
```
The references to the dns_server are now setup after the tls connection is setup.
This ensures that the stream got fully stopped when the initial tls setup failed
instead of having the unref being blocked by the reference to the stream by the server.
Therefore on_stream_io would no longer be called with a half setup encrypted connection.
Fixes the issue reported in #9838.
This function doesn't really implement ordering, but CMP() is still fine to use
there. Keep the comment in place, just update it slightly to indicate that.