When a Windows machine syncs a shared folder that contains /etc/hosts, the file often ends up with Windows‑style CRLF line endings.
If you’ve ever pulled a hosts file from a Windows share, you’ve probably noticed that the resolver starts acting weird. The glibc resolver stops at the carriage return (\r) and treats the rest of the line as part of the hostname. That means lookups for localhost, myserver, or any entry that follows a stray CR fail, and some services silently fall back to DNS—exposing the system to name‑resolution attacks.
Why stray CR matters
The resolver parses /etc/hosts line‑by‑line. A line that looks like
127.0.0.1\r localhost
is read as the IP 127.0.0.1 and the hostname localhost\r. The trailing CR is not trimmed, so the resolver never matches the exact string localhost. Applications that rely on the hosts file—ping, curl, systemd‑resolved, or even sshd when UseDNS no is set—will fail to resolve the host. In a production environment this can break health checks, container networking, or local authentication.
Because the resolver silently ignores the malformed entry, the problem can go unnoticed until a service starts using DNS instead of the intended local IP. That switch can introduce latency or, worse, expose the system to DNS spoofing if the external DNS server is compromised.
Detecting stray CR characters
The quickest way to spot CRs is to use grep with a literal carriage return:
grep -n $'\r' /etc/hosts
If any lines are returned, the file contains CRLF endings. od -c shows the raw bytes:
od -c /etc/hosts | head
Lines ending with \r\n will display \r before the newline. cat -v also reveals hidden characters:
cat -v /etc/hosts
A line that ends with ^M indicates a stray CR.
Fixing the file
The simplest fix is to strip CRs with dos2unix, which is available on most distributions:
sudo dos2unix /etc/hosts
If you prefer a one‑liner that works without external tools, sed can do the job:
sudo sed -i 's/\r$//' /etc/hosts
For a more robust approach that also normalises whitespace, use awk:
sudo awk '{ sub(/\r$/,""); print }' /etc/hosts > /tmp/hosts.tmp && sudo mv /tmp/hosts.tmp /etc/hosts
After cleaning, verify that the file contains only LF line endings:
file /etc/hosts
# /etc/hosts: ASCII text
If you want to enforce the format automatically, add a small wrapper script to your sync process:
#!/usr/bin/env bash
# sync-hosts.sh
rsync -avz --iconv=utf-8,utf-8 --no-whole-file "$1" /etc/hosts
dos2unix /etc/hosts
Call this script whenever the Windows machine updates the shared folder.
Preventing future sync issues
Use rsync with
--iconv– it converts line endings on the fly if you set the correct character set.Enable SMB “Unix extensions” – when Windows shares a folder with the
unix extensionsoption, it preserves LF line endings.Store the hosts file in a Git repo – add a
.gitattributesentry to force LF:/etc/hosts text eol=lfRun
dos2unixautomatically – add a cron job that checks/etc/hostsfor CRs and cleans them.Use a Windows tool – configure the Windows sync client (e.g.,
robocopyorSyncToy) to use Unix line endings or to skip the file entirely.
Security considerations
The hosts file is a critical component of local name resolution. An attacker who can inject a malformed entry could trick services into connecting to the wrong IP. To mitigate this:
Restrict permissions:
/etc/hostsshould be owned by root and readable by all, writable only by root (chmod 644 /etc/hosts).Use the immutable flag:
chattr +i /etc/hostsprevents accidental edits, but remember to remove the flag (chattr -i) when you need to update it.Audit changes: Enable
auditdto log any modifications to/etc/hosts:auditctl -w /etc/hosts -p wa -k hosts-changeSELinux/AppArmor: Ensure the policy allows the resolver to read
/etc/hostsbut restricts write access to the root user only.Validate after sync: A small script that runs
grep -n $'\r'and exits with a non‑zero status if CRs are found can be integrated into CI pipelines or systemd unit files.
By treating /etc/hosts as a protected resource and automating its cleanup, you reduce the risk of both accidental misconfiguration and malicious tampering.
See also
- How I Stopped Debian from Installing KDE Plasma During a System Upgrade – A Practical APT Pinning Example
- Why Your systemd Service Stays “activating” After a Kernel Upgrade – A Step‑by‑Step Fix
- Taming the DNS Resolver: Mastering resolvectl for Faster and More Reliable Internet Connections
- Taming Duplicate Entries in Your Bash History with a Simple Script
- Taming systemd Restart Policies to Prevent Service Deluge