Class ClientAddressResolver

java.lang.Object
com.iizix.server.geo.ip2location.ClientAddressResolver

public final class ClientAddressResolver extends Object
Decides which IP address stands for a client: the address Jetty saw, or, when that address is a trusted proxy (a reverse proxy or the IIZI load balancer), the client address the proxy forwarded in a Forwarded (RFC 7239) or X-Forwarded-For header.

The rule is the usual one: a forwarded header is believed only when the immediate peer is in the operator's list of trusted proxies (ServerSettings.getGeoTrustedProxies(), empty by default, so by default nothing is believed); the chain is walked from the right (the proxy nearest to the server) to the left, and the first address that is not itself a trusted proxy is the client. An entry that is not an IP literal (an obfuscated identifier, a host name, garbage) ends the walk and the immediate peer stands - a spoofed header can never name an address the operator did not vouch for. When Forwarded is present it is used and X-Forwarded-For is ignored, per RFC 7239 section 7.4.

isPrivateOrLocal(InetAddress) answers whether an address may be looked up at all: loopback, unspecified, link-local, RFC 1918 site-local, carrier-grade NAT (RFC 6598, 100.64.0.0/10) and IPv6 unique-local (RFC 4193, fc00::/7) addresses are not geolocatable and must not be sent to any provider. A client-reported local address is by nature one of these on most networks; it is information, never a lookup key.

Pure functions over Java types, no server state: fully testable.

Author:
Christopher Mindus
  • Method Details

    • resolve

      Resolves the client address.
      Parameters:
      remote - The address of the immediate peer as seen by Jetty, null for unknown.
      headers - The forwarded headers of the upgrade request, null for none.
      trusted - The trusted proxies, null for none.
      Returns:
      The resolution, never null; ClientAddressResolver.Resolution.NONE when remote is null.
    • parseXForwardedFor

      public static List<InetAddress> parseXForwardedFor(List<String> values)
      Parses X-Forwarded-For values: comma-separated IP literals, leftmost the client.
      Parameters:
      values - The header values in the order received.
      Returns:
      The chain, or null when an element is not an IP literal.
    • parseForwarded

      public static List<InetAddress> parseForwarded(List<String> values)
      Parses Forwarded values (RFC 7239): comma-separated elements, each a semicolon-separated list of name=value pairs, of which for= carries the node; a quoted value may hold an IPv6 literal in brackets and a port.
      Parameters:
      values - The header values in the order received.
      Returns:
      The chain of for= nodes, or null when a node is not an IP literal.
    • isPrivateOrLocal

      public static boolean isPrivateOrLocal(InetAddress address)
      Returns if an address cannot be geolocated and must not be sent to any provider: unspecified, loopback, link-local, RFC 1918 site-local, carrier-grade NAT 100.64.0.0/10 (RFC 6598) and IPv6 unique-local fc00::/7 (RFC 4193).
      Parameters:
      address - The address, null counts as not geolocatable.
      Returns:
      true when the address is private or local.
    • toText

      public static String toText(InetAddress address)
      Formats an address for a log line: the literal without the leading slash of InetAddress.toString(), lower case for IPv6.
      Parameters:
      address - The address, null for "-".
      Returns:
      The text.