How to Normalize IPv4-Mapped IPv6 Addresses in Proxy Logs

The same IPv4 proxy exit can appear in logs as a dotted address such as 203.0.113.7 and as an IPv4-mapped IPv6 value such as ::ffff:203.0.113.7. If an analytics pipeline treats those strings as different exits, it inflates pool diversity, distorts repeat-rate calculations, and can create false geolocation or reputation conflicts.

Two internet address streams pass through a normalization junction and emerge as one consistent proxy route

An IPv4-mapped IPv6 address does not prove that a request used a native IPv6 exit. It is an IPv6 representation of an IPv4 node, commonly surfaced by dual-stack software interfaces. Normalize the identity for analysis, but retain the raw observation for troubleshooting and audit.

What the mapped form means

The IPv6 addressing architecture defines the mapped format inside ::ffff:0:0/96: 80 zero bits, 16 one bits, and the 32-bit IPv4 address. Both dotted and hexadecimal tails can represent the same underlying IPv4 value.

Public source note: RFC Editor, “IP Version 6 Addressing Architecture,” February 2006; RFC Editor, “A Recommendation for IPv6 Address Text Representation,” August 2010; Python Software Foundation, “ipaddress — IPv4/IPv6 Manipulation Library,” Python 3.14 documentation.

Three observations must remain separate:

  • raw peer value: exactly what the client, socket, or application recorded;
  • normalized identity: the canonical address used for counting and joining data;
  • effective family: IPv4 for a mapped value, IPv6 for a native IPv6 value.

If transport-family evidence is available, store it in another field. Do not infer the complete network path from the address string alone.

Why proxy measurements break without normalization

String-level grouping can make one exit look like two. That affects:

  • unique exit counts and churn rates;
  • sticky-session repeat measurements;
  • ASN and subnet concentration;
  • country or city consistency checks;
  • per-exit success and latency statistics;
  • block-rate and reputation comparisons;
  • cost per valid unique exit.

Normalization should happen before deduplication, aggregation, joins, alerting, and dashboard calculation. Keep both raw and canonical fields so investigators can still reproduce the original observation.

Use strict parsing, not string replacement

Do not remove ::ffff: with a regular expression and assume the remainder is valid. A trusted IP-address library can validate syntax, recognize the mapped range, convert a hexadecimal tail, and emit canonical text.

from ipaddress import ip_address, IPv6Address

def normalize_peer(raw):
    address = ip_address(raw)
    if isinstance(address, IPv6Address) and address.ipv4_mapped is not None:
        return {
            "raw_peer": raw,
            "normalized_ip": str(address.ipv4_mapped),
            "effective_family": 4,
            "was_ipv4_mapped": True,
        }
    return {
        "raw_peer": raw,
        "normalized_ip": str(address),
        "effective_family": address.version,
        "was_ipv4_mapped": False,
    }

Catch parsing errors at the ingestion boundary and quarantine invalid values instead of silently converting them to an empty string. If an input also contains brackets, a port, or a zone identifier, parse that endpoint structure explicitly before passing only the address component to the IP library.

Build a stable evidence schema

Use a schema that preserves source and transformation details:

observed_at
run_id
client_id
raw_peer
normalized_ip
effective_family
was_ipv4_mapped
parser_version
requested_region
observed_country
observed_asn
application_valid
latency_ms

For shared reports, hash the normalized address with a run-specific salt. Keep raw addresses and unsalted values in access-controlled operational storage only. Never store proxy passwords, tokens, cookies, or authorization headers in measurement logs.

Test the normalizer before deployment

Use documentation-only ranges rather than live customer addresses:

InputNormalized identityFamilyMapped
203.0.113.7203.0.113.74no
::ffff:203.0.113.7203.0.113.74yes
::ffff:cb00:7107203.0.113.74yes
2001:db8::72001:db8::76no
invalid inputrejected

Also test uppercase hex, expanded IPv6 text, leading and trailing whitespace according to your ingestion contract, bracketed endpoints, ports, null values, and unexpected binary-to-text conversion. The parser should be deterministic across workers.

Compare metrics before and after normalization

Run the old and new grouping logic over the same bounded dataset. Compare:

  1. raw distinct address strings;
  2. normalized distinct identities;
  3. mapped-value share;
  4. repeat rate per normalized exit;
  5. ASN and country conflicts per normalized exit;
  6. success rate and p95 latency per normalized exit;
  7. cost per valid normalized exit.

A lower unique count is expected when mapped and dotted forms were duplicates. A large change deserves investigation: it may reveal a logging-layer change, a client-family difference, or an earlier measurement error. It does not automatically mean the provider reduced inventory.

Use the proxy exit churn measurement guide after identity normalization, and check proxy pool ASN concentration with the same canonical key. For location validation, apply the proxy location accuracy test only after duplicate identities are merged.

Roll out safely

  • Version the normalization rule and parser library.
  • Backfill a small sample before touching historical dashboards.
  • Keep raw and normalized fields side by side.
  • Add a metric for mapped-address share by client and runtime.
  • Alert on sudden representation shifts, not on mapped values alone.
  • Recompute dependent aggregates in a controlled order.
  • Document whether “IPv6 exit” means native IPv6 identity, transport observation, or provider product label.
  • Preserve a reversible mapping for audit and incident review.

FAQ

Is ::ffff:203.0.113.7 a native IPv6 proxy exit?

No. It is an IPv4-mapped IPv6 representation of the underlying IPv4 address. Do not count it as independent native IPv6 inventory.

Should the raw value be discarded after normalization?

No. Preserve it with source and parser version. The raw form helps identify which client, runtime, or logging layer changed representation.

Can a regular expression safely normalize mapped addresses?

String replacement is fragile and may accept invalid or non-mapped input. Use a maintained IP-address parser and test its mapped-address property.

Should mapped and dotted forms share reputation and geolocation results?

They should use the same normalized identity key. Preserve the source and timestamp of each lookup so stale or conflicting metadata remains diagnosable.

Compliance note

Analyze only proxy traffic, accounts, logs, and endpoints you are authorized to operate. Minimize retained network identifiers, restrict access, honor provider and destination rules, and follow applicable privacy and regional requirements. Address normalization is a measurement-quality control, not a method for evading access controls or disguising activity.