Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 16 additions & 3 deletions debug_toolbar/middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,9 @@ def show_toolbar_with_docker(request: HttpRequest) -> bool:
if not settings.DEBUG:
return False

# Test: settings
if request.META.get("REMOTE_ADDR") in settings.INTERNAL_IPS:
return True

# Test: Docker
try:
# This is a hack for docker installations. It attempts to look
# up the IP address of the docker host.
Expand All @@ -64,7 +62,22 @@ def show_toolbar_with_docker(request: HttpRequest) -> bool:
# It's fine if the lookup errored since they may not be using docker
pass

# No test passed
# Some Docker runtimes (for example OrbStack) resolve host.docker.internal
# to an address that is unrelated to the container network, so the check
# above cannot derive the host address from it.
try:
# Make a reasonable guess at the gateway from the container's own
# interface. This assumes the process is running inside a container.
# If this were used outside a container this would grant access to
# anything that appears to come from the network's gateway (router).
container_ips = socket.gethostbyname_ex(socket.gethostname())[2]
gateways = {ip.rsplit(".", 1)[0] + ".1" for ip in container_ips}
if request.META.get("REMOTE_ADDR") in gateways:
return True
except socket.gaierror:
# It's fine if the lookup errored since they may not be using docker
pass

return False


Expand Down
3 changes: 3 additions & 0 deletions docs/changes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ Pending
older versions of Django, the panel explains that upgrading is required.
* Fixed the Django version check in the SQL panel test suite for Django's
boolean parameter handling.
* Fixed ``show_toolbar_with_docker`` on Docker runtimes such as OrbStack that
can resolve ``host.docker.internal`` to an address outside the container
network.
* Restored the select and explain buttons for queries that run without
parameters.
* Fixed the error shown when panel content fails to load, which could not
Expand Down
7 changes: 7 additions & 0 deletions docs/installation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,13 @@ option.
Docker gateway IP and treat it as an allowable internal IP so that the
toolbar is shown to you.

When the Docker host lookup fails, the ``show_toolbar_with_docker``
callback guesses the host's address from the container's own network. If
run outside a container that guess can resolve to another machine on your
network, granting it access to the toolbar's data. The
``show_toolbar_with_docker`` callback should only be used inside a
container.

7. Disable the toolbar when running tests (optional)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Expand Down
1 change: 1 addition & 0 deletions docs/spelling_wordlist.txt
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ refactoring
reinitializing
resizing
runserver
runtimes
spellchecking
sphinxcontrib
spooler
Expand Down
15 changes: 15 additions & 0 deletions tests/test_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,21 @@ def test_show_toolbar_docker(self, mocked_gethostbyname):
self.assertTrue(show_toolbar_with_docker(self.request))
mocked_gethostbyname.assert_called_once_with("host.docker.internal")

@patch("socket.gethostbyname", return_value="0.250.250.254")
@patch("socket.gethostname", return_value="container")
@patch(
"socket.gethostbyname_ex",
return_value=("container", [], ["192.168.215.7"]),
)
def test_show_toolbar_docker_unrelated_host_address(self, *mocks):
"""Runtimes such as OrbStack resolve host.docker.internal to an
address outside of the container network, so the host address has to
be derived from the container's own address instead."""
self.request.META["REMOTE_ADDR"] = "192.168.215.1"
with self.settings(INTERNAL_IPS=[]):
self.assertFalse(show_toolbar(self.request))
self.assertTrue(show_toolbar_with_docker(self.request))

def test_not_iterating_over_INTERNAL_IPS(self):
"""Verify that the middleware does not iterate over INTERNAL_IPS in some way.

Expand Down
Loading