开源⽹络抓包与分析框架学习-Packetbeat篇
开源简介
packbeat是⼀个开源的实时⽹络抓包与分析框架,内置了很多常见的协议捕获及解析,如HTTP、MySQL、Redis等。在实际使⽤中,通常和Elasticsearch以及kibana联合使⽤,⽤于数据搜索和分析以及数据展⽰。
开发环境:Go语⾔
Git:源码管理
IDE:推荐sublime或者liteide
开发之前
1.packbeat已经被elastic整合在beats项⽬中,使⽤前登录github,并打开
github/elasticsearch/beats.fork到⾃⼰的仓库。
如:github/lindsay-show/packbeat
2.创建相应⽬录
[html]
1. mkdir -p $GOPATH/src/github/elastic
2. cd $GOPATH/src/github/elastic
3.git clone
[html]
1. git clone github/elasitc/beats.git
2. cd beats
4.修改官⽅库为upstream源,设置⾃⼰的仓库为orgin源
[html]
1. git remote rename origin upstream
2. git remote add origin git@github:lindsay-show/packbeat.git
5.获取最新代码(刚fork,可忽略),并创建分⽀⽤于⾃定义功能开发
[html]
1. git pull upstream master
2. git checkout -b mypackbeat
6.切换到packbeat,并获取依赖信息
[html]
1. cd packbeat
2. mkdir -p $GOPATH//x/
3. cd $GOPATH//x
4. git clone github/golang/tools.git
5. go get github/tools/godep
7.使⽤make编译packbeat源码,得到packbeat可执⾏⽂件
注:
[1] git的相关介绍和命令可参考 Git教程(www.liaoxuefeng/wiki/0013739516305929606dd183********c67b8067c8c017b000)
[2] go安装及环境变量配置可参考 Golang官⽹(/doc/install)
源码框架
packbeat项⽬源码结构如下:
packetbeat整合在beats项⽬中,其中还包括topbeat以及filebeat,现简要介绍beats源码框架内容如下:
/packbeat:⽹络抓包
/topbeat:监控系统性能;
/vendor:依赖的第三⽅库(如dns开源库或者其他协议栈)
/tests:⽤于测试的pcamp抓包⽂件
/scripts:测试脚本
关于topbeat及filebeat的更多介绍参考elastic官⽹(/)。
packebeat源码框架介绍如下:
/:项⽬启动⼊⼝;
/packetbeat/config/:,定义了所有配置相关的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源码后,配置⽂件l中默认已经配置了上述⽀持的协议类型。使⽤步骤简述如下:
安装Packetbeat源码
配置l⽂件,默认不⽤更改(默认配置输出到elasticsearch)
加载packetbeat索引⾄elasticsearch中(使⽤第三⽅脚本)
启动elasticsearch及kibana,查看http数据包捕获及分析
如:启动packetbeat,打开⼏个⽹页,在终端极即可看到packetbeat已注册的协议类型以及http请求数据和应答数据包
[html]
1. cd packetbeat-1.
2.1
2. ./packetbeat -N -e
注:
[1] Packetbeat详细使⽤说明,请参考Packetbeat官⽅帮助⽂档
(/guide/en/beats/packetbeat/current/_step_4_starting_packetbeat.html),⾮常详细。
[2] Elasticsearch及kibana的安装和使⽤,请参考Elastic官⽅帮助⽂档(/guide/index.html)。
扩展协议开发
在前⾯介绍到,⽬前packetbeat⽀持的协议类型主要是HTTP等常见协议类型,即时通信协议,如sip、msrp以及xmpp等暂不⽀持。如何对packetbeat进⾏协议扩展是我们研究该源码的主要⽬的。
⽹络传输两⼤协议TCP和UDP,应⽤层协议都离不开这两种协议,如源码中的HTTP、⾛的是TCP传输协议,DNS⾛的是UDP协议,在Packetbeat⾥⾯,要实现⾃定义协议,只需实现这两者对应的接⼝。扩展协议的框架代码可分别参考基于TCP的http以及基于udp的dns协议实现代码。
在进⾏扩展协议开发之前,需要了解protos/register.中tcp、udp以及基础协议的接⼝定义:
TcpPlugin:TCP协议插件的接⼝定义。其中Pares()⽤于解析Packet,ReceivedFin()⽤于处理TCP断开连接,GapInStream()处理空包丢包,ConnectionTimeout()处理超时时间
UdpPlugin:UDP协议插件的接⼝定义。其中ParseUdp()⽤于解析Packet
ProtocolPlugin:TCP和UDP以及其他扩展协议均需要实现ProtocolPlugin的基础接⼝,主要是提供获取端⼝⽅法
上述对应的接⼝定义如下所⽰:
[cpp]
1. type Plugin interface {
2. // Called to return the configured ports
3. GetPorts() []int
4. }
5. type TcpPlugin interface {
6. Plugin
7. // Called when TCP payload data is available for parsing.
8. Parse(pkt *Packet, tcptuple *common.TcpTuple,
9.    dir uint8, private ProtocolData) ProtocolData
10. // Called when the FIN flag is seen in the TCP stream.
11. ReceivedFin(tcptuple *common.TcpTuple, dir uint8,    private ProtocolData) ProtocolData
12.    // Called when a packets are missing from the tcp    // stream.
13. GapInStream(tcptuple *common.TcpTuple, dir uint8, nbytes int,
14.    private ProtocolData) (priv ProtocolData, drop bool)
15. // ConnectionTimeout returns the per stream connection timeout.
16. // Return <=0 to set default tcp module transaction timeout.
17. ConnectionTimeout() time.Duration
18. }
19. type UdpPlugin interface {
20. Plugin
21.
22. // ParseUdp is invoked when UDP payload data is available for parsing.
23.
24. ParseUdp(pkt *Packet)
25. }
接下来,需要了解中ProtocolCommon的结构体,扩展协议需要继承该基本结构.
协议的基本配置结构体定义如下所⽰(该结构体对应l的配置结构,参考默认的l⽂件):
1. type ProtocolCommon struct {
2. Ports              []int        `config:"ports"`
3. SendRequest        bool          `config:"send_request"`
4. SendResponse      bool          `config:"send_response"`
5. TransactionTimeout time.Duration `config:"transaction_timeout"`
6. }
最后了解⼀下packetbeat中的关于packet结构定义:
[cpp]
1. type Packet struct {
2. Ts      time.Time
3. Tuple  common.IpPortTuple
4. Payload []byte
5. }
Ts:收到数据包的时间戳
Tuple:来源ip+来源端⼝+⽬的ip+⽬的端⼝的元组
Payload:应⽤层字节数,不包括tcp及udp头部信息,这部分正是七层协议需要解析的部分
以上,扩展协议的基本思路介绍完毕。现以sip协议扩展开发为例:(扩展开发之前,参考前⽂开发之前所述)
[html]
1. cd $GOPATH/src/github/elastic/beats/packetbeat/protos
2. mkdir sip&&cd sip
3.
其中,⽤于sip协议的具体实现,包括实现基于TCP及UDP对应的解析⽅法,⽤于sip协议的配置结构定义,⽤于sip消息解析结构的定义。
<中定义如下:
[cpp]
1. package sip
2. import (
3.
4. "github/elastic/beats/packetbeat/config"
5.
6. "github/elastic/beats/packetbeat/protos"
7. )
8. //ProtocolCommon struct
9. type sipConfig struct {
10. config.ProtocolCommon ``config:",inline"
11. }
12. var (    defaultConfig = sipConfig{
13.    ProtocolCommon: config.ProtocolCommon{
go语言开发环境搭建
15.        TransactionTimeout: protos.DefaultTransactionExpiration,
16.    },
17. }
18. )
sip下的定义完毕后,在l中增加sip对应的配置,如下所⽰:
[html]
1. protocols:  sip:    ports: [5060,5260]
2.
3. # send_request and send_response control whether or not the stringified SIP
4. # request and response message are added to the result.
5. # Nearly all data about the request/response is available in the sip.*
6. # fields, but this can be useful if you need visibility specifically
7. # into the request or the response.
8. # Default: false
9. # send_request:  true
10. # send_response: true
在中实现udp协议插件接⼝⽅法Parseudp,并注册协议,使⽤中的register⽅法,如下:
[cpp]
1. func init() {
2.
3. protos.Register("sip", New)
4. }
5. func New(    testMode bool,
6. results publish.Transactions,
7.
8. cfg *common.Config,
9. ) (protos.Plugin, error) {
10. p := &Sip{}
11. config := defaultConfig
12. if !testMode {
13.    if err := cfg.Unpack(&config); err != nil {
14.        return nil, err
15.    }
16. }
17. if err := p.init(results, &config); err != nil {
18.    return nil, err
19. }
20. return p, nil
21. }
最后⼀步,在packetbeat的主程序中加载sip协议,如下所⽰:
[cpp]
1. package main
2. import (

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。