1

For geolocation purposes, I am trying to get a string representation of the numeric value of an ip v6 address. Because Classic ASP doesn't handle bigint values, I'm attempting to work around it with a Javascript function.

Based on this working Fiddle: https://jsfiddle.net/adamish/mrx3880p/ that uses the biginteger.js library, I adapted the library to work as a valid include for ASP.

var ip = '2a00:85c0:0001:0000:0000:0000:0241:0023';


// simulate your address.binaryZeroPad(); method
var parts = [];
ip.split(":").forEach(function(it) {
    var bin = parseInt(it, 16).toString(2);
    while (bin.length < 16) {
        bin = "0" + bin;
    }
    parts.push(bin);
})
var bin = parts.join("");

// Use BigInteger library
var dec = bigInt(bin, 2).toString();
console.log(dec);

The code in the Fiddle converts the ipv6 into its binary representation then calls the toString function, requesting the conversion in base 2.

It works in the Fiddle. However, I can't get it to work in my code as the return value is in scientific notation, which is not good for me.

The goal is to input the string "2a00:85c0:1::241:23" (or its non shortened version, "2a00:85c0:0001:0000:0000:0000:0241:0023", doesn't matter) and output a string representation of the numeric equivalent, or "55830288595252163998698714105846497315".

As I am limited to what I can use in Classic ASP, has anyone any pointer on how I can get that conversion to work?

ChrisBE
  • 131
  • 3
  • So what does your Classic ASP code look like? Are you using JScript in Classic ASP? – user692942 Jan 16 '21 at 12:52
  • 1
    You can't just convert a JavaScript library to a JScript include file and expect it to work, depending on how modern the JavaScript library is will determine how likely it is to work on conversion. Just tried it myself and the include errors at line 24: `BigInteger.prototype = Object.create(Integer.prototype);` with the error `Object doesn't support this property or method`. – user692942 Jan 16 '21 at 14:00
  • 1
    My ASP code is basically just a call to the javascript you see in my example turned into a function in a .js include file. I am aware that the jscript support in Classic ASP is by far not as extended as that of "real" javascript, which is the whole point of my question: does anyone know how I could make this work with the weapons I have? – ChrisBE Jan 16 '21 at 14:13
  • Perhaps you can use two fields. Remember that your IPv6 addressing is really going to use `/64` networks, so you may be able to use a 64-bit network field, and a 64-bit IID field. That assumes you have unsigned 64-bit integers available. – Ron Maupin Jan 17 '21 at 04:04
  • Thanks, Ron Maupin. That would work if I wanted to keep a log of ipv6 addresses but unfortunately in this case, I really need the decimal representation to match it in the ranges provided by ip2location. – ChrisBE Jan 17 '21 at 10:25

2 Answers2

0

Unfortunately, you won't be able to do this because VBScript and JScript can't handle the numerical precision required.

Here was my first attempt in VBScript

<%
Option Explicit
Const base = 65536
Dim ipv6: ipv6 = "2a00:85c0:0001:0000:0000:0000:0241:0023"
Dim pwr: pwr = 8
Dim hextets: hextets = Split(ipv6, ":")
Dim hextet, ipnum
If IsArray(hextets) Then
  For Each hextet In hextets
    pwr = pwr - 1
    ipnum = ipnum + ((base^pwr) * CLng("&h" & hextet))
  Next
End If
%>
<!doctype html>
<html>
  <head>
    <title>IPv6 to IP Number</title>
  </head>

  <body>
    <pre><%= ipv6 %></pre>
    <pre><%= FormatNumber(ipnum, 0, -2, -2, false) %></pre>
  </body>
</html>

Output:

2a00:85c0:0001:0000:0000:0000:0241:0023
55830288595252200000000000000000000000

The problem here is the calculation is right but the number can't handle the precision so when it reaches the maximum it defaults to 0.

My next attempt was JScript (not my strongest language)

<% @Language = "JScript" %>
<%
var base = 65536;
var ipv6 = "2a00:85c0:0001:0000:0000:0000:0241:0023";
var pwr = 8;
var hextets = ipv6.split(":");
var ipnum;

for (var hextet in hextets) {
  pwr--;
  ipnum += (Math.pow(base, pwr) * parseInt("0x" + hextets[hextet]));
};
%>
<!doctype html>
<html>
  <head>
    <title>IPv6 to IP Number</title>
  </head>

  <body>
    <pre><%= ipv6 %></pre>
    <pre><%= ipnum %></pre>
  </body>
</html>

Output:

2a00:85c0:0001:0000:0000:0000:0241:0023
-1.#IND

This time it fails with a -1.#IND conversion error which basically means the number is too big to be represented.

So while not doable directly in VBScript or JScript you could still build a COM exposed class in another language (C#, VB.Net etc) that did the computation and produced a string that VBScript / Jscript could display.


Useful Links

user692942
  • 16,398
  • 7
  • 76
  • 175
-1

I deleted my previous answer as it wasn't very helpful. Its been established that you can't use Classic ASP to convert an IPv6 address to a numeric value using VBscript. JScript could be possible, but seems unlikley.

I also convert and log IPv4/6 numeric values for geolocation purposes on a high traffic Classic ASP website.

For IPv4, the conversion is quite simple using VBscript:

Function IPv4ToNumber(ByVal IPv4)

    Dim i, Pos, PrevPos, Num

    For i = 1 To 4

        Pos = InStr(PrevPos + 1, IPv4, ".", 1)
        If i = 4 Then pos = Len(IPv4) + 1
        Num = Int(Mid(IPv4, PrevPos + 1, Pos - PrevPos - 1))
        PrevPos = Pos
        IPv4ToNumber = ((Num Mod 256) * (256 ^ (4 - i))) + IPv4ToNumber

    Next

End function

Here's another useful VBscript function that returns the type of IP (IPv4, IPv6 or an empty string for invalid IPs). You could just use InStr():

. = IPv4

: = IPv6

But this function uses regular expressions to properly validate IP addresses:

Function IP_Type(ByVal IP)

    IP_Type = "" ' Default
    
    ' Check for valid IPv4 and IPv6 addresses
    
    Dim IP_RegExp
    
    If Len(IP) >= 7 AND Len(IP) <= 15 Then
    
        ' Potential IPv4
        
        Set IP_RegExp = New RegExp
        
            IP_RegExp.Pattern = "^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$"
            IP_Type = IP_RegExp.Test(IP)
            
            If IP_Type Then IP_Type = "IPv4" Else IP_Type  = ""
        
        Set IP_RegExp = Nothing
    
    ElseIf Len(IP) > 15 AND Len(IP) <= 39 Then
    
        ' Potential IPv6
        
        Set IP_RegExp = New RegExp
        
            IP_RegExp.Pattern = "^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$"
            IP_Type = IP_RegExp.Test(IP)
            
            If IP_Type Then IP_Type = "IPv6" Else IP_Type  = ""
        
        Set IP_RegExp = Nothing
    
    End If
    
End Function

For IPv6, I use MySQL to calculate the numeric value. Here's a simple SELECT example:

SELECT CAST(
    CONV(
        SUBSTR(
            HEX(
                INET6_ATON('2a00:85c0:0001:0000:0000:0000:0241:0023')
            )
        ,1,16)
    ,16,10
)AS DECIMAL(65))
*18446744073709551616
+CAST(
    CONV(
        SUBSTR(
            HEX(
                INET6_ATON('2a00:85c0:0001:0000:0000:0000:0241:0023')
            )
        ,17,16)
    ,16,10
) AS DECIMAL(65)) AS ipv6_num;

Output: 55830288595252163998698714105846497315 (using either the full or shortened IPv6 address)

It also works with MariaDB. For other SQL platforms, the logic is the same, but the syntax and functions will probably need to be replaced with equivalents.

If you're logging IP numeric values for geolocation purposes, you're obviously using a database, so adapting the above MySQL code for other SQL platforms is the best solution I can offer.

I also looked up an IP to numeric API (free or subscription based) but there doesn't seem to be any (IPv6 is still quite rare, so a REST API call could be a possible solution). Hopefully there is a solution using JScript, or as already mentioned you could use a COM DLL (I have experience with this, I've created a number of COM DLL's using C# for use in Classic ASP applications on my GitHub page. You will need root access though. I'm using a new laptop so will need to reinstall Visual Studio, but I'll create a COM DLL for IP to numeric values when I get the time).

Adam
  • 836
  • 2
  • 8
  • 13
  • The OP is asking about IPv6 conversion in Classic ASP not IPv4. However, some of the other ideas have their merits. Not sure though how much of the stated advice just reiterates what has already been said. – user692942 May 13 '21 at 00:34
  • 1
    It’s not possible in classic asp, vbscript or jscript. I was offering a database alternative, I think that’s valid. – Adam May 13 '21 at 11:09
  • That part yes, by all means, but the rest is pretty much a commentary on my existing answer. – user692942 May 13 '21 at 11:56