perl解析pcap文件

栏目: Perl · 发布时间: 6年前

内容简介:关于

关于 Pcap 文件解析的方法网上有很多相关文章, Pcap 文件的格式以及使用 Wireshark 查看Pcap文件的方法也都有详细教程。然而利用 Perl 脚本语言对 Pcap 文件进行解析的相关代码和文章并没有。本文介绍了如何使用 Perl 脚本语言对 Pcap 文件进行解析。

模块安装

Net::Pcap 模块封装了用于解析Pcap文件的一些方法,首先介绍如何使用CPAN安装 Net::Pcap 模块。

//CPAN相关命令
//获得帮助  
cpan>h  

//列出CPAN上所有模块的列表  
cpan>m  

//安装模块  
cpan>install Net::Pcap 

//退出  
cpan>q 

读取Pcap文件

pcap_loop($pcap, $count, \&callback, $user_data)
从pcap读取count个包,并且调用使用参数user_data调取callback函数。如果count为负,则循环读取直到错误发生。

my $pcap = pcap_open_offline($fileDir, \$err) || die "failed to open pcap file $pcap!";
while(1)
{
    $ret = pcap_loop($pcap, -1, \&load_pcap, $this);
    if($ret == -1)
    {
        print "error on processing packets in pcap file: $@!\n";
        die "error on processing packets in pcap file: $@!\n";
        last;
    }
    elsif($ret == 0 || $ret == -2)
    {
        print "end of pcap processing: $@!\n";
        last;
    }
}

解析数据包

网络数据包格式如下图所示:

perl解析pcap文件

unpack (packformat, formatstr) 函数将以机器格式存贮的值转化成 Perl 中值。packformat代表解析格式,formatstr为要解析的对象。

通过判断各个位置上的值从而确定包的类型。通过记录连接的状态,确定TCP三次握手的建立与解除。具体代码如下:

foreach my $event (sort(keys(%{$packets})))
    {
        print "testlog: a new packet begin----------------------- \n";

        my $packet = $packets->{$event}->{pkt};
        my $proto = unpack("H*", substr($packet, 12, 2));
        if($proto eq "0800") #ipv4
        {
            $count ++;
            my $off = 14;
            my $iphl = (unpack("C", substr($packet, $off, 1)) & 0x0f); # header length  , <<2 is the actual length
            my $ip_payload_len = unpack("n", substr($packet, $off + 2, 2)); #total length
            #print "testlog: packet total length: ". $ip_payload_len ."\n";
            $proto = unpack("C", substr($packet, $off + 9, 1)); #net proto

            my $sip = inet_ntoa(substr($packet, $off + 12, 4)); #source ip addr
            my $dip = inet_ntoa(substr($packet, $off + 16, 4)); #dest ip addr

            # chop the padding bytes off
            $packet = substr($packet, 0, $off + $ip_payload_len); #a full packet

            if($iphl > 5)
            {print "Warning: ip packet with ip option\n";}

            my $ipPayloadLen = unpack("n", substr($packet, $off + 2, 2)) - ($iphl << 2); #total length - header length 

            # skip ipv4 header
            $off += ($iphl << 2);
            if($proto == 6)        # tcp session
            {
                my $tcp_hdrl = unpack("C", substr($packet, $off + 12, 1)) >> 2; # tcp header length , <<2 is the actual length
                my $tcp_flag = unpack("C", substr($packet, $off + 13, 1)); #tcp flag
                #print $tcp_flag . "\n";
                my $sport = unpack("n", substr($packet, $off, 2));    #source port
                my $dport = unpack("n", substr($packet, $off + 2, 2));    #dest port

                if($ipPayloadLen - $tcp_hdrl < 0) # eq 0
                {
                    print "invalid tcp packet: $proto packet not supported!\n";    
                    last;
                }

                my $c = "$sip:$sport<->$dip:$dport";
                my $s = "$dip:$dport<->$sip:$sport";

                # recode session state
                if(!defined($session))
                {
                    print "testlog: session will be defined! \n";
                    $session = {
                        id => $c,
                        cstate => "closed",
                        sip => $sip,
                        dip => $dip,
                        sport => $sport,
                        dport => $dport
                    };
                }

                if($tcp_flag & 0x04)
                {
                    print "Warning: tcp session with RST, need mannual checking!Stop session analyzing: $frameID!\n";
                    $session->{cstate} = "closed";
                }
                print "testlog: session state: ". $session->{cstate} ."\n";
                if($session->{cstate} eq "closed")    # open session
                {
                    if(($tcp_flag & 0x02))        # syn open sesstion
                    {
                        $session->{cstate} = "syn_sent";
                    }
                    else
                    {
                        if(length(substr($packet, $off + $tcp_hdrl)) > 0)
                        {print "Warning: tcp session disordered on closed, need mannual checking!Stop session analyzing: $sip : $sport <-> $dip : $dport \n";}
                    }

                }
                elsif($session->{cstate} eq "syn_sent")
                {
                    #print ($tcp_flag);
                    #print "\n";
                    if(($tcp_flag & 0x12)==0x12){
                        print "ok";
                    };
                    print "\n";
                    if(($tcp_flag & 0x02) && ($sip eq $session->{sip}) && ($sport eq $session->{sport})) # syn from client retransmission
                    {print "tcp retransmission detected!\n";}
                    elsif(($tcp_flag & 0x12) && ($sip eq $session->{dip}) && ($sport eq $session->{dport}))    # syn_ack from server
                    {$session->{cstate} = "syn_rcvd";}
                    else
                    {
                        print "Warning: tcp session disordered on syn_sent, need mannual checking!Stop session analyzing!\n";
                    }

                }
                elsif($session->{cstate} eq "syn_rcvd")
                {
                    if(($tcp_flag & 0x10) && ($sip eq $session->{sip}) && ($sport eq $session->{sport}))  # ack from client
                    {
                        $session->{cstate} = "connected";         # won't check ack
                        print(FD "CONNECT twoarm 1 0 tcp $dip $dport $sip $sport\n\n");
                    }
                    else
                    {print "Warning: none ack packet on syn_rcvd!\n";}
                }
                elsif($session->{cstate} eq "connected")
                {
                    #print "testlog: $sip ---- $session->{sip} ----- $session->{dip}";
                    if($sip eq $session->{sip} && ($sport eq $session->{sport}))        # from client
                    {
                        if($tcp_flag & 0x01)
                        {
                            $session->{FIN} += 1;
                            $session->{FINFrom} = 1; # this is the second FIN, disconnect begin from server
                        }
                        else
                        {
                            if(length(substr($packet, $off + $tcp_hdrl)) > 0) #TCP payload is not empty
                            {
                                $str_temp = unpack('H*',substr($packet, $off + $tcp_hdrl));
                                my @str_temp2 = split(//, $str_temp);
                                my $str_temp3;
                                for($i=0; $i<@str_temp2; $i=$i+2){
                                    $str_temp3 = $str_temp3 . "\\x" . $str_temp2[$i] . $str_temp2[$i+1];
                                }
                                print "$str_temp3 \n";
                                print(FD "SEND 0 #\"$str_temp3\" NOW\n\n");
                            }
                        }
                    }
                    elsif($sip eq $session->{dip} && ($sport eq $session->{dport}))
                    {
                        if($tcp_flag & 0x01)
                        {
                            $session->{FIN} += 1;
                            $session->{FINFrom} = 0; # this is the second FIN, disconnect begin from client
                        }
                        else
                        {
                            if(length(substr($packet, $off + $tcp_hdrl)) > 0)
                            {
                                $str_temp = unpack('H*',substr($packet, $off + $tcp_hdrl));
                                my @str_temp2 = split(//, $str_temp);
                                my $str_temp3;
                                for($i=0; $i<@str_temp2; $i=$i+2){
                                    $str_temp3 = $str_temp3 . "\\x" . $str_temp2[$i] . $str_temp2[$i+1];
                                }
                                print "$str_temp3 \n";
                                print(FD "SEND 1 #\"$str_temp3\" NOW\n\n");
                            }
                        }
                    }
                    else
                    {
                        print "invalid packet on connected tcp session\n";
                    }
                }
                if($session->{cstate} eq "connected" && $session->{FIN} == 2)
                {
                    $FINFrom = $session->{FINFrom};
                    print(FD "DISCONNECT $FINFrom\n");
                    $session->{cstate} = "closed";
                    delete($session->{FIN});
                }
            }
        }
    }

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Wireshark网络分析实战

Wireshark网络分析实战

[以色列 Yoram Orzach / 古宏霞、孙余强 / 人民邮电出版社 / 2015-1 / 79.00元

本书采用步骤式为读者讲解了一些使用Wireshark来解决网络实际问题的技巧。 本书共分为14章,其内容涵盖了Wireshark的基础知识,抓包过滤器的用法,显示过滤器的用法,基本/高级信息统计工具的用法,Expert Info工具的用法,Wiresahrk在Ethernet、LAN及无线LAN中的用法,ARP和IP故障分析,TCP/UDP故障分析,HTTP和DNS故障分析,企业网应用程序行......一起来看看 《Wireshark网络分析实战》 这本书的介绍吧!

随机密码生成器
随机密码生成器

多种字符组合密码

SHA 加密
SHA 加密

SHA 加密工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换