declare local var.ip IP;
declare local var.anon_ip STRING;
declare local var.ip_str STRING;
set var.ip = req.http.Fastly-Client-Ip;
// Uncomment this line to use an IPv6 address for testing
//set var.ip = "2a04:4e42:400::c0ff:ee:cafe";
if (addr.is_ipv4(var.ip)) {
# IPv4 is simple, just zero out the last octet.
set var.anon_ip = regsub(var.ip, "\d+$", "0");
} else if (addr.is_ipv6(var.ip)) {
# To anonymize an IPv6 IP, we want to retain the first 48 bits, which
# is the first 3 groups of hex numbers. However, they need not all
# exist. Regular expressions cannot easily make sense of all the
# variations these may take, but we can rely on the normalizing that
# will happen to a real IPv6 to catch the unlikely corner cases...
# Convert the IP to a normalized string so that it can be regexp'd...
set var.ip_str = var.ip;
# This will catch nearly every IPv6 address seen in the wild.
# "1:2:3:..." or "1:2::..."
if ( var.ip_str ~ "(?i)^((?:(?:^|:)[0-9a-f]{1,4}){2,3}):" ) {
set var.anon_ip = re.group.1 + "::";
# pathological...
# "1::3:4:5:6:7:8"
} elseif ( var.ip_str ~ "(?i)^(?:([0-9a-f]{1,4}))::([0-9a-f]{1,4}):" ) {
set var.anon_ip = re.group.1 + ":0:" + re.group.2 + "::";
# even more unlikely...
# "::2:3:4:5:6:7:8" or "::3:4:5:6:7:8"
} elseif ( var.ip_str ~ "(?i)::([0-9a-f]{1,4}:)?([0-9a-f]{1,4})(?::[0-9a-f]{1,4}){5}$" ) {
set var.anon_ip = "0:" + if(re.group.1, re.group.1, "0:") + re.group.2 + "::";
# things which really shouldn't happen,
# "::7:8:9", etc.
} else {
set var.anon_ip = "::";
}
}
log "IP " + var.ip + " anonymized to " + var.anon_ip;