论坛首页 综合技术论坛

Use Erlang NIF to snoop, capture packets.

浏览 2951 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2010-02-01   最后修改:2010-02-01
Use Erlang NIF to snoop, capture packets.


1. Overview



In Erlang/OTP R13B03, there is new feature called Native Implementation Function, Here I use NIF and libpcap library to have implemented a simple sniffer to real-time capturing packet from one interface.



简述:使用NIF实现简单的抓包程序。



2. Developing enviroment:



- Ubuntu 9.10: 2.6.31-14-generic

- gcc: 4.4.1

- libpcap.so.1.0.0

- Erlang/OTP R13B03



3. nif.erl

%%% nif sniffer  
 
-module(nif).  
-on_load(on_load/0).  
 
-export([opendevice/1, capture/0, loop/1]).  
 
on_load() ->  
    ok = erlang:load_nif("./nif", 0),  
    true.  
 
opendevice(_Interface) ->  
    error.  
 
capture() ->  
    error.  
 
loop(0) ->  
    ok;  
loop(Count) ->  
    Pkt = capture(),  
    io:format("~p~n", [Pkt]),  
    loop(Count-1). 



4. nif.c


/* This file used to create a Erlang NIF which sniffer network packets. */ 
 
#include <erl_nif.h>  
#include <stdio.h>  
#include <pcap.h>  
#include <string.h>  
#include <ctype.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 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 
     * Notes: if timeout_ms is set by non-zero, system give "segment fault" error ? 
     * to_ms=0 means wait enough packet to arrive. 
     */ 
    devHandler = pcap_open_live(dev, 65535, 1, 0, errbuf);  
    if(devHandler != NULL)  
        return enif_make_string(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[] =  
{  
    {"capture", 0, capture},  
    {"opendevice", 1, opendevice}  
};  
 
ERL_NIF_INIT(nif,nif_funcs,NULL,NULL,NULL,NULL) 


5. 编译nif.c程序

gcc -fPIC -shared -o nif.so nif.c /usr/lib/libpcap.so -I/usr/lib/erlang/usr/include/ 



6. 开始测试

xumingyong@ubuntu:~/workspace/sniffer_nif$ sudo erl  
Erlang R13B03 (erts-5.7.4) [source] [smp:2:2] [rq:2] [async-threads:0] [hipe] [kernel-poll:false]  
 
Eshell V5.7.4  (abort with ^G)  
1> c(nif).  
{ok,nif}  
2> nif:opendevice("eth0").  
"ok" 
3> nif:loop(5).  
<<255,255,255,255,255,255,0,12,41,66,42,16,8,6,0,1,8,0,6,4,0,1,0,12,41,66,42,16,192,168,0,200,0,0,0,0,0,0,192,168,0,1>>  
<<0,12,41,66,42,16,0,80,86,192,0,1,8,6,0,1,8,0,6,4,0,2,0,80,86,192,0,1,192,168,0,1,0,12,41,66,42,16,192,168,0,200,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0>>  
<<0,80,86,192,0,1,0,12,41,66,42,16,8,0,69,0,0,84,0,0,64,0,64,1,184,143,192,168,0,200,192,168,0,1,8,0,68,170,146,13,0,1,86,157,102,75,108,91,13,0,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55>>  
<<0,12,41,66,42,16,0,80,86,192,0,1,8,0,69,0,0,84,178,130,64,0,128,1,198,12,192,168,0,1,192,168,0,200,0,0,76,170,146,13,0,1,86,157,102,75,108,91,13,0,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55>>  
<<0,80,86,192,0,1,0,12,41,66,42,16,8,0,69,0,0,84,0,0,64,0,64,1,184,143,192,168,0,200,192,168,0,1,8,0,121,143,146,13,0,2,87,157,102,75,54,117,13,0,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55>>  
ok  
4>  


7. 注意



- Must be root user when start "erl" command, or you cannot open the network adapter interface.

- The output of "nif:loop(5)" command is 5 ARP packet, 1st is broadcast, 2nd is request, 3rd is reply, 4th is request, 5th is reply.

- Because the erlang/OTP NIF is experimental, the new erlang/OTP may be incompatible with this version, please check the newest online documentation.



论坛首页 综合技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics