A RetroSearch Logo

Home - News ( United States | United Kingdom | Italy | Germany ) - Football scores

Search Query:

Showing content from https://unix.stackexchange.com/a/725542 below:

dns - Why accessing 0.0.0.0:443 gets redirected to 127.0.0.1:443 on Linux and how to disallow it?

tl;dr: accessing 0.0.0.0:port (eg. curl http://0.0.0.0:443) gets redirected(internally) to 127.0.0.1:port (where port is any port number) (eg. the previous curl command is the same as curl http://127.0.0.1:443); why does this happen and how to block connections destined to 0.0.0.0 ?

UPDATE2: I've found a way to block it by patching the Linux kernel (version 6.0.9):


--- .orig/usr/src/linux/net/ipv4/route.c
+++ /usr/src/linux/net/ipv4/route.c
@@ -2740,14 +2740,17 @@ struct rtable *ip_route_output_key_hash_
    }
 
    if (!fl4->daddr) {
-       fl4->daddr = fl4->saddr;
+           rth = ERR_PTR(-ENETUNREACH);
+           goto out;
+                        /* commenting out the rest:
+       fl4->daddr = fl4->saddr; // if you did specify src address and dest is 0.0.0.0 then set dest=src addr
        if (!fl4->daddr)
-           fl4->daddr = fl4->saddr = htonl(INADDR_LOOPBACK);
+           fl4->daddr = fl4->saddr = htonl(INADDR_LOOPBACK); // if you didn't specify source address and dest address is 0.0.0.0 then make them both 127.0.0.1
        dev_out = net->loopback_dev;
        fl4->flowi4_oif = LOOPBACK_IFINDEX;
        res->type = RTN_LOCAL;
        flags |= RTCF_LOCAL;
-       goto make_route;
+       goto make_route; END of COMMENTed out block */
    }
 
    err = fib_lookup(net, fl4, res, 0);

Result: Where do packets sent to IP 0.0.0.0 go?:

$ ip route get 0.0.0.0
RTNETLINK answers: Network is unreachable

...they don't!

A client attempts to connect from 127.1.2.18:5000 to 0.0.0.0:80

$ nc -n -s 127.1.2.18 -p 5000 -vvvvvvvv -- 0.0.0.0 80
(UNKNOWN) [0.0.0.0] 80 (http) : Network is unreachable
 sent 0, rcvd 0

(if you didn't apply kernel patch, you will need a server like the following for the above client to be able to successfully connect: (as root, in bash)while true; do nc -n -l -p 80 -s 127.1.2.18 -vvvvvvvv -- 127.1.2.18 5000; echo "------------------$(date)";sleep 1; done)

Patched ping(ie. a ping that doesn't set destination address to be the same as the source address when destination address is 0.0.0.0, ie. comment out the 2 lines under // special case for 0 dst address that you see here):

$ ping -c1 0.0.0.0
ping: connect: Network is unreachable

instant. However, if specifying source address, it takes a timeout(of 10 sec) until it finishes:

$ ping -I 127.1.2.3 -c1 -- 0.0.0.0
PING 0.0.0.0 (0.0.0.0) from 127.1.2.3 : 56(84) bytes of data.

--- 0.0.0.0 ping statistics ---
1 packets transmitted, 0 received, 100% packet loss, time 0ms

UPDATE1:

The why part is explained here but I'm expecting a little bit more details as to why does this happen, for example(thanks to user with nickname anyone on liberachat #kernel channel):

$ ip route get 0.0.0.0
local 0.0.0.0 dev lo src 127.0.0.1 uid 1000
    cache <local>

This shows that somehow packets destined for 0.0.0.0 get routed to the localhost interface lo and they get source ip 127.0.0.1 (if I'm interpreting this right) and because that route doesn't appear in this list:

$ ip route list table local
local 127.0.0.0/8 dev lo proto kernel scope host src 127.0.0.1
local 127.0.0.1 dev lo proto kernel scope host src 127.0.0.1
broadcast 127.255.255.255 dev lo proto kernel scope link src 127.0.0.1
local 169.254.6.5 dev em1 proto kernel scope host src 169.254.6.5
broadcast 169.254.6.255 dev em1 proto kernel scope link src 169.254.6.5
local 192.168.0.17 dev em1 proto kernel scope host src 192.168.0.17
broadcast 192.168.255.255 dev em1 proto kernel scope link src 192.168.0.17

it means that it must be somehow internal to the Linux kernel. ie. hardcoded

To give you an idea, here's how it looks for an IP that's on the internet (I used quad1 as an example IP):

$ ip route get 1.1.1.1
1.1.1.1 via 192.168.1.1 dev em1 src 192.168.0.17 uid 1000
    cache

where 192.168.1.1 is my gateway, ie.:

$ ip route
default via 192.168.1.1 dev em1 metric 2
169.254.6.0/24 dev em1 proto kernel scope link src 169.254.6.5
192.168.0.0/16 dev em1 proto kernel scope link src 192.168.0.17

Because iptables cannot be used to sense (and thus block/drop) such connections destined to 0.0.0.0 that get somehow routed to 127.0.0.1, it might prove difficult to find a way to block them... but I'll definitely try to find a way, unless someone already knows one.

@Stephen Kitt (in the comments) suggested a way to block hostnames that reside in /etc/hosts, so instead of:
0.0.0.0 someblockedhostname
you can have
127.1.2.3 someblockedhostname
127.1.2.3 someOTHERblockedhostname
(anything other than 127.0.0.1, but you can use the same IP for every blocked hostname, unless you want to differentiate)
which IP you can then block using iptables.

However if your DNS resolver (ie. NextDNS, or 1.1.1.3) returns 0.0.0.0 for blocked hostnames (instead of NXDOMAIN) then you cannot do this (unless, of course, you want to add each host manually in /etc/hosts, because /etc/hosts takes precedence - assuming you didn't change the line hosts: files dns from /etc/nsswitch.conf)

OLD: (though edited)

On Linux (I tried Gentoo and Pop OS!, latest) if you have this line in /etc/hosts:

0.0.0.0 somehosthere

and you run this as root (to emulate a localhost server listening on port 443)
# nc -l -p 443 -s 127.0.0.1
then you go into your browser (Firefox and Chrome/Chromium tested) and put this in address bar:
https://somehosthere
or
0.0.0.0:443
or
https://0.0.0.0

then the terminal where you started nc(aka netcat) shows a connection attempt (some garbage text including the plaintext somehosthere if you used it in the url)

or instead of the browser, you can try:
curl https://somehosthere
or if you want to see the plaintext request:
curl http://somehosthere:443

This doesn't seem to be mitigable even when using dnsmasq as long as that 0.0.0.0 somehosthere is in /etc/hosts, but when using dnsmasq and your DNS resolver (ie. NextDNS or Cloudflare's 1.1.1.3) returns 0.0.0.0 instead of NXDOMAIN (true at the time of this writing) and that hostname isn't in your /etc/hosts(AND in what you told dnsmasq is the /etc/hosts to use) then there are two ways to mitigate it(either or both will work):

  1. use dnsmasq arg --stop-dns-rebind
       --stop-dns-rebind
              Reject (and log) addresses from upstream nameservers which are in
              the private ranges. This blocks an attack where a browser  behind
              a  firewall  is  used to probe machines on the local network. For
              IPv6, the private range covers the IPv4-mapped addresses in  pri‐
              vate  space  plus  all  link-local  (LL) and site-local (ULA) ad‐
              dresses.
  1. use line bogus-nxdomain=0.0.0.0 in /etc/dnsmasq.conf which makes dnsmasq itself return NXDOMAIN for any hostname that resolved to 0.0.0.0 (except, once again, if that hostname was in /etc/hosts (bypasses dnsmasq) and what you told dnsmasq to use as /etc/hosts (if you did))

So, the second part of this question is how to disallow accesses to 0.0.0.0 from being redirected to 127.0.0.1 ? I want this because when using NextDNS (or cloudflare's 1.1.1.3) as DNS resolver, it returns 0.0.0.0 for blocked hostnames, instead of NXDOMAIN, thus when loading webpages, parts of them(that are located on blocked hostnames) will try to access my localhost server running on port 443 (if any) and load pages from it instead of just being blocked.

Relevant browser-specific public issues being aware of this(that 0.0.0.0 maps to 127.0.0.1):
Chrome/Chromium: https://bugs.chromium.org/p/chromium/issues/detail?id=1300021 Firefox: https://bugzilla.mozilla.org/show_bug.cgi?id=1672528#c17


RetroSearch is an open source project built by @garambo | Open a GitHub Issue

Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo

HTML: 3.2 | Encoding: UTF-8 | Version: 0.7.3