VBAでIPv4アドレスを扱うコードの部品

注意事項

概要

後で自分がコピペする用のメモ。

SWのACL絡みのチェック等をエクセル上で行うことが業務上増えたので、IPv4アドレスあたりに関するVBAのパーツをいくつか用意した。
人によっては何かに使えるかもしれない。
※元々は作成中のクラスのコードから抜き出したものなので、いきなり記載していないメンバ変数がコード中に現れているかもしれない。できる限りその影響はないように編集はしたものの、その状態で実行できるかは未確認。

環境:
 Excel for Mac 16.16.16
 VBA 7.1

コードの部品

サブネットマスク32種類の情報を作る

'サブネットマスク構造体
Type subnetmask
    subnetmaskStr As String ' 文字列版サブネットマスク
    subnetmaskByte(4) As Byte
End Type

    Dim subnetmaskList(32) As subnetmask ' サブネットマスク構造体の配列 。要素番号-1がそのままプレフィックスを示
    Const base128 As Byte = 128
    Dim mask As Byte, i As Long

    mask = 0
    For i = 0 To 7
        mask = mask + base128 ¥ (2 ^ i)
        subnetmaskList(i).subnetmaskByte(0) = mask
        subnetmaskList(i).subnetmaskByte(1) = 0
        subnetmaskList(i).subnetmaskByte(2) = 0
        subnetmaskList(i).subnetmaskByte(3) = 0
        subnetmaskList(i).subnetmaskStr = subnetmaskList(i).subnetmaskByte(0) & "." & subnetmaskList(i).subnetmaskByte(1) & "." & subnetmaskList(i).subnetmaskByte(2) & "." & subnetmaskList(i).subnetmaskByte(3)

        subnetmaskList(i + 8).subnetmaskByte(0) = 255
        subnetmaskList(i + 8).subnetmaskByte(1) = mask
        subnetmaskList(i + 8).subnetmaskByte(2) = 0
        subnetmaskList(i + 8).subnetmaskByte(3) = 0
        subnetmaskList(i + 8).subnetmaskStr = subnetmaskList(i).subnetmaskByte(0) & "." & subnetmaskList(i).subnetmaskByte(1) & "." & subnetmaskList(i).subnetmaskByte(2) & "." & subnetmaskList(i).subnetmaskByte(3)
        
        subnetmaskList(i + 16).subnetmaskByte(0) = 255
        subnetmaskList(i + 16).subnetmaskByte(1) = 255
        subnetmaskList(i + 16).subnetmaskByte(2) = mask
        subnetmaskList(i + 16).subnetmaskByte(3) = 0
        subnetmaskList(i + 16).subnetmaskStr = subnetmaskList(i).subnetmaskByte(0) & "." & subnetmaskList(i).subnetmaskByte(1) & "." & subnetmaskList(i).subnetmaskByte(2) & "." & subnetmaskList(i).subnetmaskByte(3)
        
        subnetmaskList(i + 24).subnetmaskByte(0) = 255
        subnetmaskList(i + 24).subnetmaskByte(1) = 255
        subnetmaskList(i + 24).subnetmaskByte(2) = 255
        subnetmaskList(i + 24).subnetmaskByte(3) = mask
        subnetmaskList(i + 24).subnetmaskStr = subnetmaskList(i).subnetmaskByte(0) & "." & subnetmaskList(i).subnetmaskByte(1) & "." & subnetmaskList(i).subnetmaskByte(2) & "." & subnetmaskList(i).subnetmaskByte(3)
    Next

    'For i = 0 To 31
    '    Debug.Print "eee " & subnetmaskList(i).subnetmaskByte(0) & "." & subnetmaskList(i).subnetmaskByte(1) & "." & subnetmaskList(i).subnetmaskByte(2) & "." & subnetmaskList(i).subnetmaskByte(3) & "."
    'Next


サブネットマスク(xxx.xxx.xxx.xxx)をプレフィックスに変換する。
戻り値は1〜32。

Function SubnetmaskToPrefix(subnet As String) As Long
    Dim aa As Long, bb As Long
    Dim tmp As Variant
    Const base128 As Byte = 128
    Dim mask As Byte
    Dim countPrefix As Long ' 結果のプレフィックスを格納
    Dim resAnd As Byte ' And を取ったときの結果を一時的に格納
    Dim endFlag As Boolean ' ループを抜けるかどうかのフラグ

    tmp = Split(subnet, ".")
    num = UBound(tmp)
    If num <> 3 Then
        Exit Function
    End If

    countPrefix = 0
    endFlag = False
    For aa = 0 To 3 ' オクテット毎ループ
        mask = 0
        For bb = 0 To 7  '8bit 分ループ
            mask = mask + base128 ¥ (2 ^ bb)
            resAnd = mask And CByte(tmp(aa))  ' 今のビット位置でAndをとる。同じ位置のbitが立っていれば、次のIFの結果はイコールになる。
            'Debug.Print "mask : " & mask & " , resAnd : " & resAnd
            If mask <> resAnd Then 'And の結果が違えばそこでループを抜ける
                endFlag = True
                Exit For
            End If
            countPrefix = countPrefix + 1
        Next
        If endFlag = True Then
            Exit For
        End If
    Next

    'Debug.Print "prefix: " & countPrefix

    SubnetmaskToPrefix = countPrefix
 End Function


IPv4 の文字列を受け取り、引数(参照)の配列にByte型で格納する。

Sub AddressStrToByte(ipv4str As String, ByRef resultArr() As Byte)

    Dim tmp As Variant, num As Integer
    tmp = Split(ipv4str, ".")
            
    num = UBound(tmp)
    If num <> 3 Then
        Exit Sub
    End If

    resultArr(0) = CByte(tmp(0))
    resultArr(1) = CByte(tmp(1))
    resultArr(2) = CByte(tmp(2))
    resultArr(3) = CByte(tmp(3))

End Sub


・あるNW内に、あるIPv4アドレスが含まれるかチェックする。
引数のdata()はIPv4アドレスの各オクテットの値を格納したByte型で要素数4の配列。
引数のprefixは、data()のアドレスのプレフィックス。1〜32。
ipv4strは、調べたいIPv4アドレスの文字列。
data()のNW内に、ipv4strのアドレスが含まれているかチェックする。含まれていればTrueを返す。
また、前述のサブネットマスク32種類の情報(subnetmaskList(32) As subnetmask)が既に存在して、この関数内からアクセスできる前提。

Function checkBelogToNetwork(ByRef data() As Byte, prefix As Long, ipv4str As String) As Boolean
    
    Dim nwaddress(4) As Byte
     
    nwaddress(0) = data(0) And subnetmaskList(prefix - 1).subnetmaskByte(0)
    nwaddress(1) = data(1) And subnetmaskList(prefix - 1).subnetmaskByte(1)
    nwaddress(2) = data(2) And subnetmaskList(prefix - 1).subnetmaskByte(2)
    nwaddress(3) = data(3) And subnetmaskList(prefix - 1).subnetmaskByte(3)

    Dim ckIPByte(4) As Byte
    Call AddressStrToByte(ipv4str, ckIPByte())
    Dim nwad2(4) As Byte
    nwad2(0) = ckIPByte(0) And subnetmaskList(prefix - 1).subnetmaskByte(0)
    nwad2(1) = ckIPByte(1) And subnetmaskList(prefix - 1).subnetmaskByte(1)
    nwad2(2) = ckIPByte(2) And subnetmaskList(prefix - 1).subnetmaskByte(2)
    nwad2(3) = ckIPByte(3) And subnetmaskList(prefix - 1).subnetmaskByte(3)

    If nwaddress(0) = nwad2(0) And nwaddress(1) = nwad2(1) And nwaddress(2) = nwad2(2) And nwaddress(3) = nwad2(3) Then
        checkBelogToNetwork = True
    Else
        checkBelogToNetwork = False
    End If

End Function