Passing client IP to socket

Hi, I am trying to pass remote client IP from conn to socket without success. Below is my code:

In router.ex:

pipeline :browser do
  ...
  plug :put_client_ip
end

where the plug is:

def put_client_ip(conn, _), do:
  conn |> Plug.Conn.assign(:remote_ip, conn.remote_ip)

In mount/3:

sock = sock 
  |> assign_new(:remote_ip, fn -> {127, 0, 0, 1} end)
Logger.info "IP: #{inspect(sock.assigns.remote_ip)}"

I get this result:

12:33:44.456 [info]  IP: {0, 0, 0, 0, 0, 65535, 32512, 1}

12:33:44.458 [info]  Sent 200 in 4ms

12:33:45.022 [info]  CONNECTED TO Phoenix.LiveView.Socket in 188µs
  Transport: :websocket
  Serializer: Phoenix.Socket.V2.JSONSerializer
  Parameters: %{"_csrf_token" => "xxx", "vsn" => "2.0.0"}

12:33:45.091 [info]  IP: {127, 0, 0, 1}

So it looks like the IP is lost (correct is the IPv6 one) when the Websocket has been established! Anyone has an idea why?

Thanks a lot!

4 Likes

You only have access to the connection and its assigns on the initial mount.

As a workaround, you could add the :remote_ip to the session in your plug:

def put_client_ip(conn, _), do: Plug.Conn.put_session(conn, :remote_ip, conn.remote_ip)

then, in mount, pattern match on it:

def mount(_params, %{"remote_ip" => remote_ip}, socket) do
...
end
4 Likes

This is not specific to the IP. assign_new is an optimization to allow reusing of values in conn.assigns when mounting the liveview for the initial static render of the http request. For any subsequent mounts conn.assigns is no longer available, which means you need to be able to compute the same value using the function you have as second parameter of assign_new.

hi @sfusato,

that was exactly my solution, but I was hoping not to use session as the medium.

Thanks for answering!

I was looking for a solution for the same thing but I would like to have the IPv4 address, how can I achieve this?