SIN@SAPPOROWORKSの覚書

C#を中心に、夜な夜な試行錯誤したコードの記録です。

ARPテーブルの削除 (C#)(F#)


iphlpapi.dllのDeleteIpNetEntry()を使用してARPテーブルの削除が可能です。
下記のサンプルは、現在のARPテーブルを取得して、その情報を削除しています。(コマンドのラインから「arp -d」とした場合と同じ)
static(静的)なテーブルを削除したくない場合などは、MIB_IPNETROWのTypeで条件判断が可能です。
ARPテーブル取得についてはhttp://d.hatena.ne.jp/spw0022/20111108/1320700838を参照してください。


using System;
using System.Runtime.InteropServices;

namespace Example {
    class Program {

        [DllImport("iphlpapi.dll")]
        extern static int GetIpNetTable(IntPtr pTcpTable, ref int pdwSize, bool bOrder);
        [DllImport("iphlpapi.dll")]
        extern static int DeleteIpNetEntry(IntPtr pArpEntry);

        [StructLayout(LayoutKind.Sequential)]
        public struct MIB_IPNETROW {
            public int Index;
            public int PhysAddrLen;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
            public byte[] PhysAddr;
            public int Addr;
            public int Type;
        }
        
        static void Main(string[] args) {
            int size = 0;
            GetIpNetTable(IntPtr.Zero, ref size, true);//必要サイズの取得
            var p = Marshal.AllocHGlobal(size);//メモリ割当て
            if (GetIpNetTable(p, ref size, true) == 0) {//データの取得
                var ptr = IntPtr.Add(p, 4);//MIB_IPNETTABLE.dwNumEntries(データ数)以降へのポインタ
                for (int i = 0; i < Marshal.ReadInt32(p); i++) {
                    var n = (MIB_IPNETROW)Marshal.PtrToStructure(ptr, typeof(MIB_IPNETROW));
                    if(0==DeleteIpNetEntry(ptr)){
                        Console.WriteLine(string.Format("Interface:{0} {1,-15}を削除しました", n.Index,ipstr(n.Addr)));
                    }
                    ptr = IntPtr.Add(ptr, Marshal.SizeOf(typeof(MIB_IPNETROW)));//次のデータ
                }
                Marshal.FreeHGlobal(p);  //メモリ開放
            }
            Console.WriteLine();
            Console.WriteLine("何かのキーを押してください。");
            Console.ReadKey();
        }
        
        private static string ipstr(int addr) {
            var b = BitConverter.GetBytes(addr);
            return string.Format("{0}.{1}.{2}.{3}", b[0], b[1], b[2], b[3]);
        }
    }
}

F#サンプル
今回は、C#のサンプルとの統一性はあまり考えないで、F#らしさが少しでも出せればと、色々教えてい頂いた事を見よう見まねで頑張って書いてみました。
「突っ込み」大歓迎です。どうぞ宜しくお願いします~。

#nowarn "9" "51"
open System
open System.Runtime.InteropServices

[<DllImport("iphlpapi.dll")>]
extern int GetIpNetTable(IntPtr pTcpTable, int *pdwSize, bool bOrder)
[<DllImport("iphlpapi.dll")>]
extern int DeleteIpNetEntry(IntPtr pArpEntry)

[<Struct; StructLayout(LayoutKind.Sequential)>]
type MIB_IPNETROW =
    val Index:int
    val PhysAddrLen:int
    [<MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)>]
    val PhysAddr:byte []
    val Addr:int
    val Type:int

let ipstr(addr:int)=
    let b = BitConverter.GetBytes(addr)
    sprintf "%d.%d.%d.%d" b.[0] b.[1] b.[2] b.[3] 

let mutable size = 0
GetIpNetTable(IntPtr.Zero, &&size, true) |> ignore //必要サイズの取得
let p = Marshal.AllocHGlobal(size)//メモリ割当て
if GetIpNetTable(p, &&size, true) = 0 then //ARPテーブルの取得
    let step = Marshal.SizeOf(typeof<MIB_IPNETROW>)
    let num = Marshal.ReadInt32(p)
    [0..num-1]//データ数
    |> List.map(fun n ->IntPtr.Add(p,4 + n * step ))//ポインタ取得
    |> Seq.iter(fun ptr -> 
        let n = Marshal.PtrToStructure(ptr, typeof<MIB_IPNETROW>) :?> MIB_IPNETROW //構造体への変換
        if DeleteIpNetEntry(ptr)=0 then //ARPテーブルの削除
            printfn "Interface:%d %sを削除しました" n.Index (ipstr(n.Addr)))
Marshal.FreeHGlobal(p);  //メモリ開放

printfn "何かのキーを押してください。"
Console.ReadKey() |> ignore