Use Erlang NIF to snoop, capture packets(in Windows XP)

1. Overview

 

In my last blog topic, I realize a network sniffer in Ubuntu, here I rewrite the code in Windows XP, and add a new function to find all network adapter.

 

2. Developing enviroment

 

- windows xp

- minGW 5.1.6

- gcc 3.4.5

- winPcap 4.1.1

- Erlang/OTP R13B03

 

3. nif.erl

 

%%% nif sniffer

-module(nif).
-on_load(on_load/0).

-export([lookup/0, opendevice/1, capture/0, loop/1]).

on_load() ->
    ok = erlang:load_nif("./nif", 0),
    true.

lookup() ->
    error.

opendevice(_Interface) ->
    error.

capture() ->
    error.

loop(0) ->
    ok;
loop(Count) ->
    Pkt = capture(),
    io:format("~p~n", [Pkt]),
    loop(Count-1).

 

4.  nif.h

 

#include "erl_nif.h"
#include "stdio.h"
#include "pcap.h"
#include "string.h"
#include "ctype.h"

#ifndef NIF_H
#define NIF_H

#ifdef __cplusplus
extern "C" {
#endif

static ERL_NIF_TERM opendevice(ErlNifEnv* env, ERL_NIF_TERM device);
static ERL_NIF_TERM capture(ErlNifEnv* env);
static ERL_NIF_TERM lookup(ErlNifEnv* env);

#ifdef __cplusplus
}
#endif

#endif

 

5. nif.c

 

/* This file used to create a Erlang NIF which sniffer network packets. */
#include "nif.h"

pcap_t *devHandler = NULL;

static int my_enif_get_string(ErlNifEnv *env, ERL_NIF_TERM list, char* buf)
{
    ERL_NIF_TERM cell, head, tail;
    int val;

    while (enif_get_list_cell(env, list, &head, &tail))
    {
        if (!enif_get_int(env, head, &val)) return 1;
        *buf = (char)val;
        buf++;
        list = tail;
    }
    *buf = '\0';
    return 0;
}

static ERL_NIF_TERM lookup(ErlNifEnv* env)
{
    int i = 0;
    char errbuf[PCAP_ERRBUF_SIZE], str[1024];
    pcap_if_t *alldevs;
    pcap_if_t *d;


    if (pcap_findalldevs_ex("rpcap://", NULL /* auth is not needed */, &alldevs, errbuf) == -1)
        return enif_make_string(env, errbuf);

    for(d= alldevs; d != NULL; d= d->next)
    {
        strcat(str, d->name);
        strcat(str, "|||");

    /*
        strcat(str, "\t\t");
        if (d->description)
            strcat(str, d->description);
        else
            strcat(str,"\n");
    */
    }

    pcap_freealldevs(alldevs);
    return enif_make_string(env, str);
}


static ERL_NIF_TERM opendevice(ErlNifEnv* env, ERL_NIF_TERM device)
{
    char dev[64];
    char errbuf[PCAP_ERRBUF_SIZE];

    //memset(errbuf, 0, PCAP_ERRBUF_SIZE);
    my_enif_get_string(env, device, dev);
    /* return enif_make_string(env, dev); */

    /* Parms: dev,snaplen,promisc,timeout_ms,errbuf
     * to_ms=0 means wait enough packet to arrive.
     */
    devHandler = pcap_open_live(dev, 65535, 1, 0, errbuf);
    if(devHandler != NULL)
        return enif_make_atom(env, "ok");
    else
        return enif_make_string(env, errbuf);
}


static ERL_NIF_TERM capture(ErlNifEnv* env)
{
    int i;
    struct pcap_pkthdr pkthdr;
    const u_char *packet = NULL;
    ErlNifBinary bin;

    packet = pcap_next(devHandler, &pkthdr);
    if(packet != NULL)
    {
        enif_alloc_binary(env, pkthdr.len, &bin);
        for(i = 0; i < pkthdr.len; i++)
        {
            bin.data[i] = packet[i];
        }
    }
    else
    {
        bin.size = sizeof("NULL");
        bin.data = "NULL";
    }
    return enif_make_binary(env, &bin);
}


static ErlNifFunc nif_funcs[] =
{
    {"lookup", 0, lookup},
    {"capture", 0, capture},
    {"opendevice", 1, opendevice}
};

ERL_NIF_INIT(nif,nif_funcs,NULL,NULL,NULL,NULL)

 

6. Build the code

 

- Insatll minGW, and re-set %PATH%, %C_INCLUDE_PATH%, %LIBRARY_PATH%.

- Copy the ERTS  WinPcap include and lib folder to minGW folder.

- Copy wpcap.lib to source folder.

- in windows [cmd] enviroment, execute following

 

gcc -shared -o nif.dll nif.c wpcap.lib

 

7. Test the code

 

Erlang R13B03 (erts-5.7.4) [smp:2:2] [rq:2] [async-threads:0]

Eshell V5.7.4  (abort with ^G)
(first@ETxumingyong)1> cd("sniffer_nif/win32").
D:/workspace/sniffer_nif/win32
ok

(first@ETxumingyong)2> c(nif).
{ok,nif}

(first@ETxumingyong)3> nif:lookup().
"rpcap://\\Device\\NPF_GenericDialupAdapter|||
rpcap://\\Device\\NPF_{CB6CFA59-46DE-4172-BBB1-85C85E654848}
|||rpcap://\\Device\\NPF_{B9A5FCD5-1424-4F42-B680-E73A89CFF638}|||"

(first@ETxumingyong)4> nif:opendevice("rpcap://\\Device\\NPF_{CB6CFA59-46DE-4172-BBB1-85C85E654848}").
ok

--------------------------------------------------------------

<<255,255,255,255,255,255,0,27,185,223,71,97,8,0,69,0,0,78,188,123,0,0,128,17,
  13,12,10,184,45,169,10,184,45,255,0,137,0,137,0,58,111,159,134,52,1,16,0,1,0,
  0,0,0,0,0,32,69,75,69,74,69,66,69,79,69,76,69,80,69,79,69,72,69,67,69,66,69,
  79,67,65,67,65,67,65,67,65,67,65,0,0,32,0,1>>
<<255,255,255,255,255,255,0,35,77,220,61,143,8,0,69,0,0,78,19,248,0,0,64,17,
  245,76,10,184,45,236,10,184,45,255,0,137,0,137,0,58,191,137,128,20,1,16,0,1,
  0,0,0,0,0,0,32,69,70,69,73,70,65,70,65,67,65,67,65,67,65,67,65,67,65,67,65,
  67,65,67,65,67,65,67,65,67,65,66,76,0,0,32,0,1>>
<<1,128,194,0,0,0,0,2,125,41,137,65,0,38,66,66,3,0,0,0,0,0,128,0,0,2,125,41,
  137,64,0,0,0,0,128,0,0,2,125,41,137,64,10,13,0,0,20,0,2,0,15,0,0,0,0,0,0,0,0,
  0>>
<<255,255,255,255,255,255,0,35,84,32,248,213,8,6,0,1,8,0,6,4,0,1,0,35,84,32,
  248,213,10,184,45,230,0,0,0,0,0,0,10,184,45,136,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  0,0,0,0>>
 。。。

 8. Note

 

- I tried the visuall c++ 6.0, failed, the cl tool are so old.

- After call [nif:lookup() ] function, there are 3 net adapter with register style output, very strange.

 

 

你可能感兴趣的:(windows,erlang,XP,ubuntu,gcc)