Skip to content

4.1.0: modern engine picks the best client IP, with exhaustive tests - #28

Merged
un33k merged 1 commit into
mainfrom
feat/modern-best-match
Sep 22, 2026
Merged

un33k merged 1 commit into
mainfrom
feat/modern-best-match

Conversation

@un33k

@un33k un33k commented Sep 22, 2026

Copy link
Copy Markdown
Owner

Summary

The modern engine now picks a better client IP than v3, and this is backed by exhaustive combination tests. The legacy engine is unchanged.

Best match (modern only)

  • Ranking: public > private > link-local > loopback. Unspecified (0.0.0.0, ::), multicast, broadcast, and reserved addresses are never returned. Python reports multicast as is_global, so v3 could return 224.0.0.1 as the client.
  • No proxy config: the first public hop of a chain wins, so 10.0.0.1, 177.139.233.139 now yields 177.139.233.139 instead of 10.0.0.1. With leftmost=False, the scan runs from the right.
  • With proxy_count / proxy_list: the client position is fixed exactly as in v3. trusted_route is now True for any address resolved through a matching config, including private clients.

Parsing and headers

  • RFC 7239 Forwarded elements are parsed by their for= value, including quoted, bracketed IPv6 with a port.
  • Malformed tokens are rejected instead of truncated ([::1, [::1]junk, 1.2.3.4:abc, 1.2.3.4:70000).
  • Non-string header values are skipped instead of crashing. Header keys match case-insensitively (AWS Lambda).
  • An empty proxy_list entry now raises: it used to match every address.
  • New headers: Azure Front Door, DigitalOcean App Platform, and Envoy/Istio. They are added only below every 4.0.0 entry, and a test pins the released order.

Tests (about 72k checks, roughly 2 s)

  • Every 1–3 hop chain over ten address types, in every leftmost / strict / proxy configuration, checked against an independent reference model.
  • Every assignment of three headers, in both dict orders.
  • 140 spellings of the same hop resolve identically.
  • Never worse than legacy across the whole matrix, and identical whenever legacy finds a public address.
  • Seeded fuzzing (3,000 junk inputs).
  • Mutation-checked: five deliberate engine bugs were each caught by the suite.

Compatibility

Results can differ from 4.0.0 on well-formed input, always toward a better address. IpWare(algorithm="legacy") keeps exact v3 behavior. The original 86 v3 tests pass on both engines.

CI

actions/upload-artifact → v7 and actions/download-artifact → v8 (Node 24).

Verified locally

  • Python 3.11, 3.12, 3.13, 3.14: full suite passes, and the v3 suite passes on legacy.
  • ruff check . is clean.
  • python -m build produces a 4.1.0 sdist and wheel.

No tag has been pushed, so nothing is published to PyPI.

🚀 Generated with Dojo ⛩️

Best match (modern only; legacy unchanged):
- Rank addresses public > private > link-local > loopback; never return
  unspecified, multicast, broadcast or reserved addresses.
- Without proxy config, take the first public hop of a chain, not chain[0].
- trusted_route is True for any address resolved through a matching proxy
  config, including private clients.

Parsing and headers:
- Parse RFC 7239 Forwarded elements by their for= value.
- Reject malformed tokens instead of truncating them; skip non-string
  header values; case-insensitive header keys; reject empty proxy_list
  entries.
- Add Azure Front Door, DigitalOcean and Envoy headers below all 4.0.0
  entries; the released precedence order is pinned by a test.

Tests: exhaustive chain/config/header/spelling matrix against an
independent reference model, never-worse-than-legacy check, seeded fuzz.

CI: upload-artifact v7, download-artifact v8 (Node 24).
@coveralls

Copy link
Copy Markdown

Coverage Status

coverage: 97.05% (+1.9%) from 95.189% — feat/modern-best-match into main

@un33k
un33k merged commit 3a649cc into main Sep 22, 2026
18 checks passed
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.

2 participants