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

1. 介绍

 

在上一篇博文http://xumingyong.iteye.com/blog/586743中,我在Erlang/OTP-R13B03中,用nif实现了抓网络包功能,但是由于在R13B04版本中,NIF接口形式发生了变化(见下一段在线文档摘要),所以我的源码也做了相应修改。

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

The NIF concept was introduced in R13B03 as an EXPERIMENTAL feature. The interfaces may be changed in any way in coming releases. The plan is however to lift the experimental label and maintain interface backward compatibility from R14B.

Incompatible changes in R13B04:

  • The function prototypes of the NIFs have changed to expect argc and argv arguments. The arity of a NIF is by that no longer limited to 3.
  • enif_get_data renamed as enif_priv_data.
  • enif_make_string got a third argument for character encoding.

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

 

2. nif_R13B04.c

 

主要是nif函数的声明形式发生了变化。

 

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

pcap_t *devHandler = NULL;


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


    memset(errbuf, 0, PCAP_ERRBUF_SIZE);
    memset(str, 0, 1024);
    memset(str1, 0, 1024);

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

    for(d= alldevs; d != NULL; d= d->next)
    {
        strcat(str, "{");
        itoa(++i, num, 10);
        strcat(str, num);
        strcat(str, ", ");
        strcat(str, d->name);
        strcat(str, ", ");
         if (d->description)
            strcat(str, d->description);
        else
            strcat(str,"null");
        strcat(str, "}, ");
    }
    pcap_freealldevs(alldevs);

    return enif_make_string(env, str, ERL_NIF_LATIN1);
}


static ERL_NIF_TERM opendevice(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
    /* char dev[64]; */
    char dev[1024];
    int ip, res, i, j;
    char errbuf[PCAP_ERRBUF_SIZE];
    pcap_if_t *alldevs, *d;

    memset(errbuf, 0, PCAP_ERRBUF_SIZE);
    memset(dev, 0, 1024);

    /* argv[0] = interface index */
    res = enif_get_int(env, argv[0], &ip);
    if(res < 0)
    {
        return enif_make_string(env, "error argument", ERL_NIF_LATIN1);
    }
    if (pcap_findalldevs_ex("rpcap://", NULL /* auth is not needed */, &alldevs, errbuf) == -1)
        return enif_make_string(env, errbuf, ERL_NIF_LATIN1);

    for(d = alldevs, i = 1; d != NULL; d = d->next, i++)
    {
        if(i == ip)
            strcpy(dev, d->name);
    }
    pcap_freealldevs(alldevs);

    /* 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, ERL_NIF_LATIN1);
}


static ERL_NIF_TERM capture(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
    int i, res;
    struct pcap_pkthdr *pkthdr;
    const u_char *packet = NULL;
    ErlNifBinary bin;

    res = pcap_next_ex(devHandler, &pkthdr, &packet);
    if(res > 0)
    {
        enif_alloc_binary(env, pkthdr->len, &bin);
        for(i = 0; i < pkthdr->len; i++)
        {
            bin.data[i] = packet[i];
        }
        bin.size = pkthdr->len;
        return enif_make_binary(env, &bin);
    }
    else if(res == 0)
    {
        return enif_make_string(env, "Timeout", ERL_NIF_LATIN1);
    }
    else if(res == -1)
    {
        return enif_make_string(env, pcap_geterr(devHandler), ERL_NIF_LATIN1);

    }
    else
    {
        return enif_make_string(env, "Unknown error", ERL_NIF_LATIN1);
    }

}


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

ERL_NIF_INIT(nif,funcs,NULL,NULL,NULL,NULL)

 

 

3. nif.h

 

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

#ifndef NIF_H
#define NIF_H

#ifdef __cplusplus
extern "C" {
#endif

static ERL_NIF_TERM opendevice(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM capture(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM lookup(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);

#ifdef __cplusplus
}
#endif

#endif

 

 

4. Makefile

 

# by xumingyong@gmail.com
all: nif_dll nif.beam

# for win32 dll compiler
# CFLAGS -g used for to generate debug info, used by gdb command.
CC = gcc
CFLAGS = -shared
INPUT = nif_R13B04.c wpcap.lib

nif_dll: nif.h
	$(CC) $(CFLAGS) -o nif.dll $(INPUT)

# for erlang beam compiler 
ERL = erlc	
.SUFFIXES: .erl .beam

.erl.beam:
	$(ERL) $<

clean:
	del *.beam *.dll erl_crash.dump

 

 

5. nif.erl

 

主要变化是:在R13B03中on_load函数的返回值必须是true,在R13B04中不需要了。

 

%%% nif sniffer

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

%%============================================================
%% Automatically loaded when load the module.
on_load() ->
    ok = erlang:load_nif("./nif", 0).

start(InterfaceIndex, CaptureNum) ->
    case opendevice(InterfaceIndex) of
	ok ->
	    loop(CaptureNum);
	_Any ->
	    {error, opendevice_fail}
    end.

%% return a tuple, with{id, name, description}...
lookup() ->
    error.

%check the lookup() return, here use the Interface id, e.g. 1, 2 or ... 
opendevice(_Interface) ->
    error.

capture() ->
    error.

loop(0) ->
    io:format("Time:~w ", [time()]);

loop(Count) ->
    Pkt = capture(),
    parser(Pkt),
    loop(Count-1).

%%============================================================
parser(Pkt) when is_binary(Pkt) ->
    <<_Addr:12/binary-little,
      TypeOrLen:2/binary-little,
      _Res/binary-little>> = Pkt,
    
    case (TypeOrLen > <<16#05, 16#DC>>) of 
	true ->
	    parser(ethernet, Pkt);
	false ->
	    parser(ieee, Pkt)
     end;

parser(Pkt) when not(is_binary(Pkt)) ->
    io:format("---Not a binary data-------------------------------~n"),
    io:format("\t~p~n", [Pkt]).

parser(ethernet, Pkt) ->
    <<Dst:6/binary-little,
      Src:6/binary-little,
      Type:2/binary-little,
      Res/binary-little>> = Pkt,

    io:format("---Ethernet II frame-------------------------------"),
    io:format("~nDst MAC:\t"), printHex(Dst), 
    io:format("~nSrc MAC:\t"), printHex(Src),
    io:format("~nType:\t\t"), printHex(Type), printEthernetIIType(Type),
    io:format("~nData:\t\t"), printHex(Res),
    io:format("~n~n");    

parser(ieee, Pkt) ->
    <<Dst:6/binary-little,
      Src:6/binary-little,
      Len:2/binary-little,
      DSAP:1/binary-little,
      SSAP:1/binary-little,
      Ctrl:1/binary-little, % ieee802.2 class 1, connectionless type. Normally be 0x03.
      Res/binary-little>> = Pkt,

    io:format("---IEEE802.3  frame-------------------------------"),
    io:format("~nDst MAC:\t"), printHex(Dst), 
    io:format("~nSrc MAC:\t"), printHex(Src),
    io:format("~nTotal Length:\t"), printHex(Len),
    io:format("~nDSAP:\t\t"), printHex(DSAP), printIeeeDSAP(DSAP),
    io:format("~nSSAP:\t\t"), printHex(SSAP), printIeeeSSAP(SSAP),
    io:format("~nControl:\t"), printHex(Ctrl),
    io:format("~nData:\t\t"), printHex(Res),
    io:format("~n~n").    


printHex(Bin) ->
    [io:format("~2.16.0B ",[X]) || X <- binary_to_list(Bin)].

printEthernetIIType(Type) ->
    case Type of
	<<16#08, 16#06>> ->
	    io:format("\t= ARP"); 
	<<16#08, 16#00>> ->
	    io:format("\t= IP"); 
	<<16#02, 16#00>> ->
	    io:format("\t= PUP"); 
	<<16#80, 16#35>> ->
	    io:format("\t= RARP"); 
	<<16#86, 16#DD>> ->
	    io:format("\t= IPv6"); 
	<<16#88, 16#63>> ->
	    io:format("\t= PPPOE Discovery"); 
	<<16#88, 16#64>> ->
	    io:format("\t= PPPoE Session"); 
	<<16#88, 16#47>> ->
	    io:format("\t= MPLS Unicast"); 
	<<16#88, 16#48>> ->
	    io:format("\t= MPLS Multicast"); 
	<<16#81, 16#37>> ->
	    io:format("\t= IPX/SPX"); 
	<<16#80, 16#00>> ->
	    io:format("\t= IS-IS"); 
	<<16#88, 16#09>> ->
	    io:format("\t= LACP"); 
	<<16#88, 16#8E>> ->
	    io:format("\t= 802.1x"); 
	<<16#81, 16#4C>> ->
	    io:format("\t= SNMP"); 
	<<16#88, 16#0B>> ->
	    io:format("\t= PPP"); 
	<<16#88, 16#A7>> ->
	    io:format("\t= Cluster"); 
	<<16#90, 16#00>> ->
	    io:format("\t= Loopback"); 
	<<16#90, 16#10>> ->
	    io:format("\t= Vlan Tag"); 
	<<16#90, 16#20>> ->
	    io:format("\t= Vlan Tag"); 
	_Any ->
	    io:format("\t= unknown")
    end.

printIeeeDSAP(Dsap) ->
    <<IG>> = Dsap,	
    case IG bsr 7 of
	0 ->
	    io:format("\t I/G=0 (Individual address)");
	1 ->
	    io:format("\t I/G=1 (Group address)")
    end.

printIeeeSSAP(Ssap) ->
    <<CR>> = Ssap,
    case CR bsr 7 of
	0 ->
	    io:format("\t C/R=0 (Command)");
	1 ->
	    io:format("\t C/R=1 (Response)")
    end.

 

 

6. 测试

 

省略,见上一篇博文http://xumingyong.iteye.com/blog/586743

 

另外:需要注意的是,R13B04的lib\tools-2.6.5.1\emacs目录下,缺少了erlang-skels.el和erlang-skels-old.el两个文件,导致EMACS不能正常进行语法高亮显示,可在源码中将这两个文件拷贝到该目录下即可。一个小小的bug。

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
基于PyTorch的Embedding和LSTM的自动写诗实验LSTM (Long Short-Term Memory) 是一种特殊的循环神经网络(RNN)架构,用于处理具有长期依赖关系的序列数据。传统的RNN在处理长序列时往往会遇到梯度消失或梯度爆炸的问题,导致无法有效地捕捉长期依赖。LSTM通过引入门控机制(Gating Mechanism)和记忆单元(Memory Cell)来克服这些问题。 以下是LSTM的基本结构和主要组件: 记忆单元(Memory Cell):记忆单元是LSTM的核心,用于存储长期信息。它像一个传送带一样,在整个链上运行,只有一些小的线性交互。信息很容易地在其上保持不变。 输入门(Input Gate):输入门决定了哪些新的信息会被加入到记忆单元中。它由当前时刻的输入和上一时刻的隐藏状态共同决定。 遗忘门(Forget Gate):遗忘门决定了哪些信息会从记忆单元中被丢弃或遗忘。它也由当前时刻的输入和上一时刻的隐藏状态共同决定。 输出门(Output Gate):输出门决定了哪些信息会从记忆单元中输出到当前时刻的隐藏状态中。同样地,它也由当前时刻的输入和上一时刻的隐藏状态共同决定。 LSTM的计算过程可以大致描述为: 通过遗忘门决定从记忆单元中丢弃哪些信息。 通过输入门决定哪些新的信息会被加入到记忆单元中。 更新记忆单元的状态。 通过输出门决定哪些信息会从记忆单元中输出到当前时刻的隐藏状态中。 由于LSTM能够有效地处理长期依赖关系,它在许多序列建模任务中都取得了很好的效果,如语音识别、文本生成、机器翻译、时序预测等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值