From 10cbd8dd483f0fe08d504b6e7094d667d39b310e Mon Sep 17 00:00:00 2001 From: Graham McIntire Date: Sat, 25 Apr 2026 18:05:22 -0500 Subject: [PATCH] fix(remote_ip): log IPv6 in canonical hex via :inet.ntoa IPv6 segments were being printed in decimal (e.g. 10772:1985:1024:45::1 for 2a14:7c1:400:2d::1), which made request_id logs unreadable. --- lib/microwaveprop_web/plugs/remote_ip.ex | 9 +++++++-- test/microwaveprop_web/plugs/remote_ip_test.exs | 16 ++++++++++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/lib/microwaveprop_web/plugs/remote_ip.ex b/lib/microwaveprop_web/plugs/remote_ip.ex index cdd1ca5a..7b190e57 100644 --- a/lib/microwaveprop_web/plugs/remote_ip.ex +++ b/lib/microwaveprop_web/plugs/remote_ip.ex @@ -173,7 +173,12 @@ defmodule MicrowavepropWeb.Plugs.RemoteIp do (e <<< 48) + (f <<< 32) + (g <<< 16) + h end - defp format_ip({a, b, c, d}), do: "#{a}.#{b}.#{c}.#{d}" - defp format_ip({a, b, c, d, e, f, g, h}), do: "#{a}:#{b}:#{c}:#{d}:#{e}:#{f}:#{g}:#{h}" + defp format_ip(ip) when tuple_size(ip) in [4, 8] do + case :inet.ntoa(ip) do + {:error, _} -> "unknown" + charlist -> List.to_string(charlist) + end + end + defp format_ip(_), do: "unknown" end diff --git a/test/microwaveprop_web/plugs/remote_ip_test.exs b/test/microwaveprop_web/plugs/remote_ip_test.exs index c6e54227..c72292d0 100644 --- a/test/microwaveprop_web/plugs/remote_ip_test.exs +++ b/test/microwaveprop_web/plugs/remote_ip_test.exs @@ -249,6 +249,22 @@ defmodule MicrowavepropWeb.Plugs.RemoteIpTest do assert conn.remote_ip == {127, 0, 0, 1} end + test "logs IPv6 peer in canonical hex form, not decimal" do + # Regression: a public IPv6 client like 2a14:7c1:400:2d::1 was being + # logged as "10772:1985:1024:45:0:0:0:1" because we stringified the + # 8-tuple in decimal. Logger metadata should hold the canonical hex. + peer = {0x2A14, 0x07C1, 0x0400, 0x002D, 0, 0, 0, 1} + + :get + |> conn("/") + |> with_peer(peer) + |> call_plug() + + assert {:remote_ip, ip_str} = List.keyfind(Logger.metadata(), :remote_ip, 0) + assert ip_str =~ "2a14" + refute ip_str =~ "10772" + end + test "single-host CIDR (/32) trusts only that exact IP" do conn = :get