DEV Community

Cover image for Using IPAddress Java Library with ColdFusion to Standardize IPv4 & IPv6 Addresses
James Moberg
James Moberg

Posted on

Using IPAddress Java Library with ColdFusion to Standardize IPv4 & IPv6 Addresses

Our Microsoft IIS web server is configured to accept IPv4 connections and, since 1996, we've recorded IPs in databases using VARCHAR(15). We weren't impacted in 2012 when the ARIN and World IPv6 Launch Day introduced the new IPv6 IP addresses as IPv6 isn't enabled on our network. All incoming IPs for the past 28 years have all been IPv4.

Over the years, we've leveraged some third-party cloud providers that support IPv6 and their logs contain IPv6 addresses. I believe that SendGrid, StackPath, Edgio and Fastly all log IPv6 address. (SendGrid has an old article from 2016 entitled "Where is IPv6 in Email?" regarding the use of it with SMTP.)

While IPv6 traffic to our servers is proxied via our cloud-based WAF provider, we can access the IPv6 IP via the Forwarded-For HTTP header. This means that the IPv4 address that is avilable via CGI.REMOTE_ADDR belongs to our WAF provider and shouldn't be used for blocking or logging. The IPv6 must be explicitly fetched from HTTP headers using getHttpRequestData(false). If we need to store it as a string in the database, it will require a VARCHAR(45) data type.

Ben Nadel shared an article in 2018 entitled "Checking To See If An IP v4 Address Is In A CIDR Range Using ColdFusion And SubnetUtils" where he converted IPv4 addresses to an integer using java.net.InetAddress & java.math.BigInteger java classes. The logic to his ipAddressToInt UDF made it easy for us to additionally add the INT to our database for faster non-string searching, but when used with a IPv6 IP address, the java BIGINT "string" exceeded the allowable limits for a SQL BIGINT.

MSSQL BIGINT Max: 9,223,372,036,854,775,808 (and negative values)

ipAddressToInt("2a0d:5600:5b:9001:f6a4:817c:3bc6:2647"); // 55896819969464025771364933405273105991

Java BIGINT String: 55,896,819,969,464,025,771,364,933,405,273,105,991 (Whoa!)

As a result of the limited SQL range for BIGINT, we decided to store a representation of IPv4 & IPv6 strings using BINARY(16). This should make indexing and look-ups faster.

A string-to-binary-and back conversion solution via StackOverflow works well to convert, but it requires hitting the remote database in order to perform a conversion that should be done locally.

I also attempted to use AI to write a function to convert IPv4 & IPv6 to binary, but it kept hallucinating, used bogus functions and couldn't deliver. (It kept insisting that padLeft() was a CF function. It was a total fail at this point in time.)

I didn't want to have the extra overhead or become dependent on a Microsoft SQL Server connection for IP conversions. A short search turned up IPAddress, a "Java library for handling IP addresses and subnets, both IPv4 and IPv6." I figured that this was a safe bet as the library is used by many companies like Akamai, Amazon, Atlassian, AT&T, Cisco, Citibank, Comcast, Disney, Dell, Evernote, Google, Hulu, Netflix, Oracle, Proton-VPN, etc. I don't mind using third-party Java to extend ColdFusion and this library looks like it can perform a lot of IP-related functions that don't currently exist. The toNormalizedString() method is extremely beneficial and will be used to log IPs with consistent formatting.

Here's some basic CFML usage using the IPAddress IPAddressString class:

ipAddressString = createobject("java", "inet.ipaddr.IPAddressString");
ip = ipAddressString.init("2a0d:5600:5b:9001:f6a4:817c:3bc6:2647");
ipData = [
    "isValid": ip.isValid(),
    "isIPAddress": ip.isIPAddress(),
    "isLoopback": ip.isLoopback(),
    "isIPv4": ip.isIPv4(),
    "isIPv6": ip.isIPv6(),
    "isMixedIPv6": ip.isMixedIPv6(),
    "toNormalizedString": ip.toNormalizedString()
];
writedump(var=ipData, label=ip);
Enter fullscreen mode Exit fullscreen mode

Source Code and Tests

https://gist.github.com/JamoCA/0e638da6927d341ed61e411f5789b4ec

Top comments (0)