Get real Client IP Address for a Ruby TCP Server

Hello, I have the following TCP server written in Ruby. However, client.peeraddr[3] always returns a bogon IP address: 172.16.1.138. I assume Fly.io is masking the IP address. Is there a way to get the actual client IP address?

require 'socket'
require 'eventmachine'
require 'rest-client'
require 'logger'

@logger = Logger.new($stdout)

EM.run do
  acceptor = TCPServer.open('0.0.0.0', 8080)
  fds = [acceptor]

  @logger.info 'Server started'

  EM.add_periodic_timer(0.1) do
    if ios = IO.select(fds, [], [], 0)
      reads = ios.first
      reads.each do |client|
        if client == acceptor
          client, sockaddr = acceptor.accept
          client_ip = client.peeraddr[3] # Extract the client's external IP address
          @logger.info "Someone connected to server from IP: #{client_ip}. Adding socket to fds."
          fds << client
        elsif client.eof?
          @logger.info 'Client disconnected'
          fds.delete(client)
          client.close
        else
          data = client.gets("\n").chomp
          @logger.info 'Received input...'
          @logger.info data

          @logger.info 'Contacting the online server...'
          begin
            # DO STUFF

            puts "\n"

            fds.delete(client)
            client.close
            @logger.info 'Answered client and closed connection'
            next
          rescue StandardError => e
            @logger.error "Error: #{e.message}"
            client.puts "Error: #{e.message}"
          end
        end
      end
    end
  end
end

my fly.toml looks like this instead:

app = 'myapp'
primary_region = 'ams'

[build]

[[services]]
  protocol = "tcp"
  internal_port = 8080

  [[services.ports]]
    port = 8080

[[vm]]
  memory = '512mb'
  cpu_kind = 'shared'
  cpus = 1

[checks]
  [checks.tcp_check]
    grace_period = "30s"
    interval = "15s"
    port = 8080
    timeout = "10s"
    type = "tcp"

TCP is a low level protocol. Fly.io has a number of proxies and edge hosts that are involved in routing of requests. I’m guessing that what you are seeing is the address of the proxy that will handle the routing of your response.

I can tell you that with HTTP there are headers that include the information you are looking for, but that’s not much use to your server.

1 Like

Thanks for the clarification. That’s the conclusion I also reached after a bit of research, but I decided to post anyway just in case there was some other workaround.

The client IP address would be available using Fly’s PROXY protocol handler (proxy_proto) if you could support the PROXY protocol in your TCP server.

2 Likes

Hey this worked! thanks a lot for your suggestion, implementing the proxy protocol in my simple Ruby TCP server did the trick and I can see the actual client’s IP address now!

Thanks again! :grin:

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.