zoukankan      html  css  js  c++  java
  • 开源网络抓包与分析框架学习-Packetbeat篇

    开源简介
    packbeat是一个开源的实时网络抓包与分析框架,内置了很多常见的协议捕获及解析,如HTTP、MySQL、Redis等。在实际使用中,通常和Elasticsearch以及kibana联合使用,用于数据搜索和分析以及数据展示。
    开发环境:Go语言
    Git:源码管理
    IDE:推荐sublime或者liteide
    开发之前
    1.packbeat已经被elastic整合在beats项目中,使用前登录github,并打开
    https://github.com/elasticsearch/beats.fork到自己的仓库。

    如:https://github.com/lindsay-show/packbeat

    2.创建相应目录

    mkdir -p $GOPATH/src/github.com/elastic
    cd $GOPATH/src/github.com/elastic
    3.git clone
    git clone https://github.com/elasitc/beats.git
    cd beats
    4.修改官方库为upstream源,设置自己的仓库为orgin源
    git remote rename origin upstream
    git remote add origin git@github.com:lindsay-show/packbeat.git
    5.获取最新代码(刚fork,可忽略),并创建分支用于自定义功能开发
    git pull upstream master
    git checkout -b mypackbeat
    6.切换到packbeat,并获取依赖信息
    cd packbeat
    mkdir -p $GOPATH/src/golang.org/x/
    cd $GOPATH/src/golang.org/x 
    git clone https://github.com/golang/tools.git
    go get github.com/tools/godep
    7.使用make编译packbeat源码,得到packbeat可执行文件
    注:
    [1] git的相关介绍和命令可参考 Git教程(http://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000)
    [2] go安装及环境变量配置可参考 Golang官网(https://golang.org/doc/install)

    源码框架
    packbeat项目源码结构如下:


    packetbeat整合在beats项目中,其中还包括topbeat以及filebeat,现简要介绍beats源码框架内容如下:

    • /libbeat:公共依赖库
    • /filebeat:logstash升级版,处理日志类型数据
    • /packbeat:网络抓包
    • /topbeat:监控系统性能;
    • /vendor:依赖的第三方库(如dns开源库或者其他协议栈)
    • /tests:用于测试的pcamp抓包文件
    • /scripts:测试脚本
    关于topbeat及filebeat的更多介绍参考elastic官网(https://www.elastic.co/)。

    packebeat源码框架介绍如下:

    • /packetbeat/main.go:项目启动入口;
    • /packetbeat/config/:config.go,定义了所有配置相关的struct结构体
    • /packetbeat/debian/:打包相关
    • /packetbeat/docs/:文档
    • /packetbeat/etc/:配置文件示例
    • /packetbeat/procs/:获取系统内核运作状态与进程信息的工具类
    • /packetbeat/protos/:自定义协议类,每个子目录对应一个应用协议,包含配置相关的结构体及具体实现
    • /packetbeat/sniffer/:三种不同抓包方式的实现,如pcap、af_packet及pf_ring
    • /packetbeat/tests/:测试相关的文件,包含协议pcap文件及python测试脚本

    注:以上介绍针对packetbeat-1.2.1,区别官网的开发帮助文档(官网未更新)。

    工作原理

    介绍了beats及packetbeat源码结构,简要说明一下packetbeat的工作原理:

    每一个协议都有一个或者多个固定的端口用于通信,开发者要做的事情就是定义协议端口,然后按照TCP以及UDP实现对应的接口,Packetbeat会捕获到指定端口的数据包,然后交给开发者定义的方法来解析,如TCP对应的是Parse,UDP是ParseUdp.解析出来的结构化数据封装成Json,插入到Elasticsearch中,后续便可使用Elasticsearch的搜索和数据统计能力进行应用层数据分析。

    使用方法

    了解Packetbeat的工作原理后,接下来介绍如何使用packetbeat进行网络数据包捕获及分析。

    在上述介绍中,我们知道packetbeat/protos目录下支持自定义协议,目前Packebeat支持的协议如下:

    • ICMP (v4 and v6)
    • DNS
    • HTTP
    • Mysql
    • PostgreSQL
    • Redis
    • Thrift-RPC
    • MongoDB
    • Memcache
    以HTTP为例,安装packetbeat源码后,配置文件packetbeat.yml中默认已经配置了上述支持的协议类型。使用步骤简述如下:

    • 安装Packetbeat源码
    • 配置packetbeat.yml文件,默认不用更改(默认配置输出到elasticsearch)
    • 加载packetbeat索引至elasticsearch中(使用第三方脚本)
    • 启动elasticsearch及kibana,查看http数据包捕获及分析
    如:启动packetbeat,打开几个网页,在终端极即可看到packetbeat已注册的协议类型以及http请求数据和应答数据包

    cd packetbeat-1.2.1
    ./packetbeat -N -e

    注:
    [1] Packetbeat详细使用说明,请参考Packetbeat官方帮助文档(https://www.elastic.co/guide/en/beats/packetbeat/current/_step_4_starting_packetbeat.html),非常详细。
    [2] Elasticsearch及kibana的安装和使用,请参考Elastic官方帮助文档(https://www.elastic.co/guide/index.html)。

    扩展协议开发
    在前面介绍到,目前packetbeat支持的协议类型主要是HTTP等常见协议类型,即时通信协议,如sip、msrp以及xmpp等暂不支持。如何对packetbeat进行协议扩展是我们研究该源码的主要目的。
    网络传输两大协议TCP和UDP,应用层协议都离不开这两种协议,如源码中的HTTP、MySQL走的是TCP传输协议,DNS走的是UDP协议,在Packetbeat里面,要实现自定义协议,只需实现这两者对应的接口。扩展协议的框架代码可分别参考基于TCP的http以及基于udp的dns协议实现代码。


    在进行扩展协议开发之前,需要了解protos/register.go中tcp、udp以及基础协议的接口定义:

    • TcpPlugin:TCP协议插件的接口定义。其中Pares()用于解析Packet,ReceivedFin()用于处理TCP断开连接,GapInStream()处理空包丢包,ConnectionTimeout()处理超时时间
    • UdpPlugin:UDP协议插件的接口定义。其中ParseUdp()用于解析Packet
    • ProtocolPlugin:TCP和UDP以及其他扩展协议均需要实现ProtocolPlugin的基础接口,主要是提供获取端口方法
    上述对应的接口定义如下所示:

    type Plugin interface {
    // Called to return the configured ports
    GetPorts() []int
    }
    type TcpPlugin interface {
    Plugin
    // Called when TCP payload data is available for parsing.
    Parse(pkt *Packet, tcptuple *common.TcpTuple,
        dir uint8, private ProtocolData) ProtocolData
    // Called when the FIN flag is seen in the TCP stream.
    ReceivedFin(tcptuple *common.TcpTuple, dir uint8,    private ProtocolData) ProtocolData
       // Called when a packets are missing from the tcp    // stream.
    GapInStream(tcptuple *common.TcpTuple, dir uint8, nbytes int,
        private ProtocolData) (priv ProtocolData, drop bool)
    // ConnectionTimeout returns the per stream connection timeout.
    // Return <=0 to set default tcp module transaction timeout.
    ConnectionTimeout() time.Duration
    }
    type UdpPlugin interface {
    Plugin
    
    // ParseUdp is invoked when UDP payload data is available for parsing.
    
    ParseUdp(pkt *Packet)
    }

    接下来,需要了解config.go中ProtocolCommon的结构体,扩展协议需要继承该基本结构.

    协议的基本配置结构体定义如下所示(该结构体对应packetbeat.yml的配置结构,参考默认的packetbeat.yml文件):

    type ProtocolCommon struct {
    Ports              []int         `config:"ports"`
    SendRequest        bool          `config:"send_request"`
    SendResponse       bool          `config:"send_response"`
    TransactionTimeout time.Duration `config:"transaction_timeout"`
    }

    最后了解一下packetbeat中的关于packet结构定义:

    type Packet struct {
    Ts      time.Time
    Tuple   common.IpPortTuple
    Payload []byte
    }

    • Ts:收到数据包的时间戳
    • Tuple:来源ip+来源端口+目的ip+目的端口的元组
    • Payload:应用层字节数,不包括tcp及udp头部信息,这部分正是七层协议需要解析的部分
    以上,扩展协议的基本思路介绍完毕。现以sip协议扩展开发为例:(扩展开发之前,参考前文开发之前所述)

    cd $GOPATH/src/github.com/elastic/beats/packetbeat/protos
    mkdir sip&&cd sip
    touch sip.go config.go sip_parse.go
    

    其中,sip.go用于sip协议的具体实现,包括实现基于TCP及UDP对应的解析方法,config.go用于sip协议的配置结构定义,sip_parse.go用于sip消息解析结构的定义。
    config.go中定义如下:

    package sip
    import (
    
    "github.com/elastic/beats/packetbeat/config"
    
    "github.com/elastic/beats/packetbeat/protos"
    )
    //ProtocolCommon struct
    type sipConfig struct {
    config.ProtocolCommon ``config:",inline"
    }
    var (    defaultConfig = sipConfig{
        ProtocolCommon: config.ProtocolCommon{
    
            TransactionTimeout: protos.DefaultTransactionExpiration,
        },
    }
    )
    

    sip下的config.go定义完毕后,在packetbeat.yml中增加sip对应的配置,如下所示:

    protocols:  sip:    ports: [5060,5260]
    
    # send_request and send_response control whether or not the stringified SIP
    # request and response message are added to the result.
    # Nearly all data about the request/response is available in the sip.*
    # fields, but this can be useful if you need visibility specifically
    # into the request or the response.
    # Default: false
    # send_request:  true
    # send_response: true

    在sip.go中实现udp协议插件接口方法Parseudp,并注册协议,使用registor.go中的register方法,如下:

    func init() {
    
    protos.Register("sip", New)
    }
    func New(    testMode bool,
    results publish.Transactions,
    
    cfg *common.Config,
    ) (protos.Plugin, error) {
    p := &Sip{}
    config := defaultConfig
    if !testMode {
        if err := cfg.Unpack(&config); err != nil {
            return nil, err
        }
    }
    if err := p.init(results, &config); err != nil {
        return nil, err
    }
    return p, nil
    } 

    最后一步,在packetbeat的main.go主程序中加载sip协议,如下所示:

    package main
    import (
    
    "os"
    "github.com/elastic/beats/libbeat/beat"
    "github.com/elastic/beats/packetbeat/beater"
    // import support protocol modules
    _ "github.com/elastic/beats/packetbeat/protos/amqp"
    _ "github.com/elastic/beats/packetbeat/protos/dns"
    _ "github.com/elastic/beats/packetbeat/protos/http"
    _ "github.com/elastic/beats/packetbeat/protos/memcache"
    _ "github.com/elastic/beats/packetbeat/protos/mongodb"
    _ "github.com/elastic/beats/packetbeat/protos/mysql"
    _ "github.com/elastic/beats/packetbeat/protos/nfs"
    _ "github.com/elastic/beats/packetbeat/protos/pgsql"
    _ "github.com/elastic/beats/packetbeat/protos/redis"
    _ "github.com/elastic/beats/packetbeat/protos/sip"
    _ "github.com/elastic/beats/packetbeat/protos/thrift"
    )

    使用makefile,编译packeteat,执行./packetbeat -N -e后,在终端上会显示sip协议已注册成功。


    至此,packetbeat的协议扩展介绍完毕了。

  • 相关阅读:
    表字符集与存储过程字符集不一致导致的存储过程执行缓慢
    自动类型转换与强制类型转换
    集合中的对象与引用
    54. 螺旋矩阵
    [算法] 二分查找(C++)
    [MySQL优化] 需要创建索引和不要创建索引的情况
    [Spring Cloud] Nacos注册中心服务分组
    mysql导入大sql文件
    [Spring Security] 前后端分离项目中后端登录代码的简单示例
    URL中含特殊字符传参
  • 原文地址:https://www.cnblogs.com/beautiful-code/p/6416710.html
Copyright © 2011-2022 走看看