Skip to content

Conversation

@paimus
Copy link

@paimus paimus commented Nov 18, 2025

This change introduces a new /server-ip endpoint that returns the IP address of the server (or Pod in Kubernetes) handling the request, as opposed to the existing /ip endpoint which returns the client's IP address.

Changes:

  • Add getServerIP() helper in helpers.go to detect server's primary IP
    • Prefers non-loopback IPv4 addresses
    • Falls back to IPv6 if no IPv4 found
    • Uses UDP dial as last resort for IP detection
  • Add ServerIP handler in handlers.go
  • Register /server-ip route in httpbin.go
  • Add serverIPResponse struct in responses.go

This is useful for debugging and service discovery in containerized environments where the server's IP may need to be identified.

This change introduces a new /server-ip endpoint that returns the IP address
of the server (or Pod in Kubernetes) handling the request, as opposed to the
existing /ip endpoint which returns the client's IP address.

Changes:
- Add getServerIP() helper in helpers.go to detect server's primary IP
  - Prefers non-loopback IPv4 addresses
  - Falls back to IPv6 if no IPv4 found
  - Uses UDP dial as last resort for IP detection
- Add ServerIP handler in handlers.go
- Register /server-ip route in httpbin.go
- Add serverIPResponse struct in responses.go

This is useful for debugging and service discovery in containerized
environments where the server's IP may need to be identified.
@mccutchen
Copy link
Owner

I appreciate the contribution, but as noted in #113 (comment) I am reluctant to expose this potentially sensitive info about internal networks by default.

I'd consider a change that only exposed this endpoint if it was explicitly enabled, along the lines of the USE_REAL_HOSTNAME option added in #81.

That being said, I'm not sure about the implementation here. Why is IPv4 preferred over IPv6? Also I don't think making a throwaway UDP connection (why to port 80? does the port just not matter here?) is a reasonable thing to do.

@derekmpage
Copy link
Contributor

derekmpage commented Jan 7, 2026

Also I don't think making a throwaway UDP connection (why to port 80? does the port just not matter here?) is a reasonable thing to do.

I was curious about this so I did some research.

First off UDP is a connectionless protocol.

net.Dial("udp", "8.8.8.8:80") -> This asks the kernel, “If I wanted to send a UDP packet to 8.8.8.8, which IP/interface would you use?”

Then you use localAddr := conn.LocalAddr().(*net.UDPAddr) to receive the local IP of the interface used.
So no packets are actually sent unless you "Write" to the socket.

Since we are not planning on writing any data, the port does not mater but it's required.

For the "prefering" of ipv4

I would may consider just making a json payload that shows everything

{
  "primary_address": {
    "10.0.5.25"
  },
  "ip_addresses": {
    "ipv4": [
      "192.168.1.101",
      "10.0.5.25",
      "172.16.254.1"
    ],
    "ipv6": [
      "2001:0db8:85a3::8a2e:0370:7334",
      "fe80::1ff:fe23:4567:890a"
    ]
  }
}

Whatever you consider the primary address to be?

@mccutchen
Copy link
Owner

First off UDP is a connectionless protocol.

net.Dial("udp", "8.8.8.8:80") -> This asks the kernel, “If I wanted to send a UDP packet to 8.8.8.8, which IP/interface would you use?”

Then you use localAddr := conn.LocalAddr().(*net.UDPAddr) to receive the local IP of the interface used. So no packets are actually sent unless you "Write" to the socket.

Ah, thank you for the explanation, TIL!

I would may consider just making a json payload that shows everything

I think if we add this functionality I like this direction: return all the IP addresses we know about. Is there a reasonable heuristic we can use to choose a "primary" address that would make sense to most clients of this hypothetical endpoint? If not, I'd be inclined to just return them all and let the client choose one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants