/* mono C# Pcap wrapper for libpcap 0.9 tested on a x86_64 SUSE 11.1 * * bash $ mcs pcap.cs * * bash # mono pcap.exe -- for live capture * bash # mono pcap.exe dump 1.cap -- to capture to a file * bash # mono pcap.exe load 1.cap -- to open 1.cap offline * * capture-files can also be read using tcpdump/wireshark etc. * This wrapper doesn't need /unsafe code. * * (C) 2007-2009 Sebastian Krahmer * You may use it under the GPL. Code comes with absolutely no warranty. */ using System; using System.IO; using System.Net; using System.Text; using System.Runtime.InteropServices; [StructLayout(LayoutKind.Sequential)] public struct pcap_if { private IntPtr d_next; public pcap_if next { get { Type t = Type.GetType("pcap_if"); return (pcap_if)Marshal.PtrToStructure(d_next, t); } } private IntPtr d_name; public string name { get { return Marshal.PtrToStringAnsi(d_name); } } public IntPtr d_description, d_addresses; public Int32 flags; } [StructLayout(LayoutKind.Explicit)] public struct pcap_pkthdr { public struct tv { public UInt64 tv_sec, tv_usec; } [FieldOffset(16)] public UInt32 caplen; [FieldOffset(20)] public UInt32 len; } [StructLayout(LayoutKind.Sequential)] public struct bpf_program { public int bf_len; public IntPtr bf_insns; } [StructLayout(LayoutKind.Explicit)] public struct IPhdr { [FieldOffset(0)] public byte vers_hl; [FieldOffset(1)] public byte tos; [FieldOffset(2)] public UInt16 totl; [FieldOffset(4)] public UInt16 id; [FieldOffset(6)] public UInt16 frag; [FieldOffset(8)] public byte ttl; [FieldOffset(9)] public byte protocol; [FieldOffset(10)] public UInt16 check; [FieldOffset(12)] public UInt32 src; [FieldOffset(16)] public UInt32 dst; } [StructLayout(LayoutKind.Explicit)] public struct UDPhdr { [FieldOffset(0)] public UInt16 sport; [FieldOffset(2)] public UInt16 dport; [FieldOffset(4)] public UInt16 len; [FieldOffset(6)] public UInt16 check; } [StructLayout(LayoutKind.Explicit)] public struct TCPhdr { [FieldOffset(0)] public UInt16 sport; [FieldOffset(2)] public UInt16 dport; [FieldOffset(4)] public UInt32 seq; [FieldOffset(8)] public UInt32 ack; [FieldOffset(12)] public UInt16 bits_hl; [FieldOffset(14)] public UInt16 window; [FieldOffset(16)] public UInt16 check; [FieldOffset(18)] public UInt16 urg; } public class Pcap { private const string lib = "libpcap.so.0"; private IntPtr ph, pd; public Pcap() { ph = IntPtr.Zero; pd = IntPtr.Zero; } [DllImport(lib)] private static extern IntPtr pcap_open_live(string dev, int snaplen, int promisc, int to_ms, byte[] ebuf); public int open_live(string dev, int snaplen, int promisc, int to_ms, byte[] ebuf) { ph = pcap_open_live(dev, snaplen, promisc, to_ms, ebuf); if (ph == IntPtr.Zero) return -1; return 0; } [DllImport(lib)] private static extern int pcap_setnonblock(IntPtr ph, int nonblock, byte[] ebuf); public int setnonblock(int nonblock, byte[] ebuf) { return pcap_setnonblock(ph, nonblock, ebuf); } [DllImport(lib)] private static extern int pcap_getnonblock(IntPtr ph, byte[] ebuf); public int pcap_getnonblock(byte[] ebuf) { return pcap_getnonblock(ph, ebuf); } [DllImport(lib)] private static extern IntPtr pcap_open_dead(int linktype, int snaplen); public int open_dead(int linktype, int snaplen) { ph = pcap_open_dead(linktype, snaplen); if (ph == IntPtr.Zero) return -1; return 0; } [DllImport(lib)] private static extern IntPtr pcap_open_offline(string fname, byte[] ebuf); public int open_offline(string fname, byte[] ebuf) { ph = pcap_open_offline(fname, ebuf); if (ph == IntPtr.Zero) return -1; return 0; } [DllImport(lib)] private static extern IntPtr pcap_dump_open(IntPtr ph, string fname); public int dump_open(string fname) { if (pd != IntPtr.Zero) dump_close(); pd = pcap_dump_open(ph, fname); if (ph == IntPtr.Zero) return -1; return 0; } [DllImport(lib)] private static extern int pcap_findalldevs(out IntPtr alldevsp, byte[] ebuf); public static int findalldevs(ref pcap_if pifs, byte[] ebuf) { IntPtr alldevsp = new IntPtr(); if (pcap_findalldevs(out alldevsp, ebuf) < 0) return -1; pifs = (pcap_if)Marshal.PtrToStructure(alldevsp, typeof(pcap_if)); return 0; } public static int findalldevs(IntPtr alldevsp, byte[] ebuf) { if (pcap_findalldevs(out alldevsp, ebuf) < 0) return -1; return 0; } [DllImport(lib)] private static extern void pcap_freealldevs(IntPtr alldevs); public static void freealldevs(IntPtr alldevs) { pcap_freealldevs(alldevs); } [DllImport(lib)] private static extern IntPtr pcap_lookupdev(byte[] ebuf); public static string lookupdev(byte[] ebuf) { IntPtr i = pcap_lookupdev(ebuf); return Marshal.PtrToStringAnsi(i); } [DllImport(lib)] private static extern int pcap_lookupnet(string device, out UInt32 netp, out UInt32 maskp, byte[] ebuf); public static int lookupnet(string device, ref uint netp, ref uint maskp, byte[] ebuf) { UInt32 n, m; int r = pcap_lookupnet(device, out n, out m, ebuf); netp = n; maskp = m; return r; } [DllImport(lib)] private static extern int pcap_compile(IntPtr ph, IntPtr fp, string str, int optimize, UInt32 netmask); [DllImport(lib)] private static extern int pcap_setfilter(IntPtr ph, IntPtr fp); public int compile_and_setfilter(string str, int optimize, UInt32 netmask) { bpf_program bpf = new bpf_program(); IntPtr fp = Marshal.AllocHGlobal(Marshal.SizeOf(bpf)); Marshal.StructureToPtr(bpf, fp, false); if (pcap_compile(ph, fp, str, optimize, netmask) < 0) return -1; int r = pcap_setfilter(ph, fp); pcap_freecode(fp); return r; } [DllImport(lib)] private static extern int pcap_setdirection(IntPtr ph, int d); public int setdirection(int d) { return pcap_setdirection(ph, d); } [DllImport(lib)] private static extern int pcap_inject(IntPtr ph, byte [] buf, UInt32 size); public int inject(byte [] buf, UInt32 size) { return pcap_inject(ph, buf, size); } [DllImport(lib)] private static extern int pcap_sendpacket(IntPtr ph, byte [] buf, int size); public int sendpacket(byte [] buf, int size) { return pcap_sendpacket(ph, buf, size); } [DllImport(lib)] private static extern int pcap_datalink(IntPtr p); public int datalink() { return pcap_datalink(ph); } [DllImport(lib)] private static extern int pcap_snapshot(IntPtr ph); public int snapshot() { return pcap_snapshot(ph); } [DllImport(lib)] private static extern int pcap_set_datalink(IntPtr ph, int dlt); public int set_datalink(int dlt) { return pcap_set_datalink(ph, dlt); } [DllImport(lib)] private static extern int pcap_datalink_name_to_val(string name); public static int datalink_name_to_val(string name) { return pcap_datalink_name_to_val(name); } [DllImport(lib)] private static extern IntPtr pcap_datalink_val_to_name(int dlt); public static string datalink_val_to_name(int dlt) { return Marshal.PtrToStringAnsi(pcap_datalink_val_to_name(dlt)); } [DllImport(lib)] private static extern IntPtr pcap_datalink_val_to_description(int dlt); public static string datalink_val_to_description(int dlt) { return Marshal.PtrToStringAnsi(pcap_datalink_val_to_description(dlt)); } [DllImport(lib)] private static extern int pcap_is_swapped(IntPtr ph); public int is_swapped() { return pcap_is_swapped(ph); } [DllImport(lib)] private static extern int pcap_major_version(IntPtr ph); public int major_version() { return pcap_major_version(ph); } [DllImport(lib)] private static extern int pcap_minor_version(IntPtr ph); public int minor_version() { return pcap_minor_version(ph); } [DllImport(lib)] private static extern IntPtr pcap_geterr(IntPtr ph); public string geterr() { return Marshal.PtrToStringAnsi(pcap_geterr(ph)); } [DllImport(lib)] private static extern IntPtr pcap_strerror(int error); public static string strerror(int error) { return Marshal.PtrToStringAnsi(pcap_strerror(error)); } [DllImport(lib)] private static extern IntPtr pcap_lib_version(); public static string lib_version() { return Marshal.PtrToStringAnsi(pcap_lib_version()); } ~Pcap() { this.close(); } [DllImport(lib)] private static extern void pcap_close(IntPtr ph); public void close() { pcap_close(ph); ph = IntPtr.Zero; } [DllImport(lib)] private static extern int pcap_stats(IntPtr ph, IntPtr ps); public int stats(IntPtr ps) { return pcap_stats(ph, ps); } [DllImport(lib)] private static extern int pcap_fileno(IntPtr ph); public int fileno() { return pcap_fileno(ph); } [DllImport(lib)] private static extern IntPtr pcap_next(IntPtr ph, IntPtr pkth); public IntPtr next(IntPtr pkth) { return pcap_next(ph, pkth); } [DllImport(lib)] private static extern void pcap_freecode(IntPtr f); public delegate void pcap_handler(IntPtr user, IntPtr pkth, IntPtr bytes); [DllImport(lib)] private static extern int pcap_dispatch(IntPtr ph, int cnt, pcap_handler callback, IntPtr user); public int dispatch(int cnt, pcap_handler callback, IntPtr user) { return pcap_dispatch(ph, cnt, callback, user); } [DllImport(lib)] private static extern int pcap_loop(IntPtr ph, int cnt, pcap_handler callback, IntPtr user); public int loop(int cnt, pcap_handler callback, IntPtr user) { return pcap_loop(ph, cnt, callback, user); } [DllImport(lib)] private static extern void pcap_breakloop(IntPtr ph); public void breakloop() { pcap_breakloop(ph); } [DllImport(lib)] private static extern int pcap_list_datalinks(IntPtr ph, out IntPtr dlt_buf); // need to marshall to int[] public int list_datalinks(out IntPtr dlt_buf) { return pcap_list_datalinks(ph, out dlt_buf); } [DllImport(lib)] private static extern void pcap_dump(IntPtr user, IntPtr pkth, IntPtr sp); public void dump(IntPtr pkth, IntPtr sp) { pcap_dump(pd, pkth, sp); } [DllImport(lib)] private static extern int pcap_dump_flush(IntPtr pd); public int dump_flush() { return pcap_dump_flush(pd); } [DllImport(lib)] private static extern void pcap_dump_close(IntPtr pd); public void dump_close() { pcap_dump_close(pd); pd = IntPtr.Zero; } } // class Pcap /* ---------------------------------------------------------------------------- */ class Test { public static Pcap pcap; static void dump_pack(IntPtr user, IntPtr p, IntPtr bytes) { if (p == IntPtr.Zero || bytes == IntPtr.Zero) return; pcap_pkthdr pkth = (pcap_pkthdr)Marshal.PtrToStructure(p, typeof(pcap_pkthdr)); // ethernet assumed IPhdr iph = new IPhdr(); iph = (IPhdr)Marshal.PtrToStructure(new IntPtr((long)bytes+14), typeof(IPhdr)); Console.WriteLine("len={0}, {1}->{2}", pkth.caplen, new IPAddress(iph.src).ToString(), new IPAddress(iph.dst).ToString()); } public static void dumpto(string fname) { if (pcap.dump_open(fname) < 0) { Console.WriteLine("Unable to open capture-file '{0}!", fname); return; } pcap_pkthdr pkth = new pcap_pkthdr(); IntPtr pkt = Marshal.AllocHGlobal(Marshal.SizeOf(pkth)); for (;;) { IntPtr bytes = pcap.next(pkt); if (bytes == IntPtr.Zero) continue; pcap.dump(pkt, bytes); } } public static void Main(string[] argv) { byte [] err = new byte[1024]; Console.WriteLine("{0}", Pcap.lib_version()); pcap_if pifs = new pcap_if(); Pcap.findalldevs(ref pifs, err); string dev = pifs.name; uint net = 0, netmask = 0; Pcap.lookupnet(dev, ref net, ref netmask, err); string IPNet = new IPAddress(net).ToString(), IPNetmask = new IPAddress(netmask).ToString(); Console.WriteLine("Dev: {0}, net: {1}, mask: {2}", dev, IPNet, IPNetmask); pcap = new Pcap(); if (argv.Length == 2 && argv[0] == "load") { pcap.open_offline(argv[1], err); } else { if (pcap.open_live(dev, 1500, 1, 1, err) < 0) { Console.WriteLine("Unable to open device '{0}'", dev); return; } if (pcap.compile_and_setfilter("ip", 1, netmask) < 0) { Console.WriteLine("Unable to set filter. Exiting!"); return; } if (argv.Length == 2 && argv[0] == "dump") { Console.WriteLine("Dumping to file '{0}'", argv[1]); dumpto(argv[1]); return; } } Pcap.pcap_handler callback = new Pcap.pcap_handler(dump_pack); pcap.loop(-1, callback, new IntPtr()); } } // class Test