summaryrefslogtreecommitdiffstats
path: root/contrib/pcap2ulog
blob: d4cd3dcb287b9284b774fb758a900bbd7d60eb9a (plain)
1
2
3
4
5
6
7
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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
#!/usr/bin/perl -w

# Copyright (C) 2009-2010 Pierre Chifflier <chifflier@inl.fr>
#
# This program is free software; you can redistribute it and/or modify
# it under the same terms as Perl itself, either Perl version 5.8.4 or,
# at your option, any later version of Perl 5 you may have available.

use strict;

use IO::Socket;
use Net::Pcap;

my $ULOGD_SOCKET_MARK = 0x41c90fd4;

my $dumpfile = shift or die "Unable to open pcap file";
my($pcap_t, $err);
my($ulogd_client);
my $socketfile = "/var/run/ulogd2.sock";
my $data_buffer;
my $linktype;
my $proto_offset;

my %linktype_to_offset = (
	Net::Pcap::DLT_LINUX_SLL => 14,
	Net::Pcap::DLT_EN10MB => 12,
);

sub connect_ulogd2 {
    (-S $socketfile) or die "ulogd2 socket $socketfile does not exist - is ulogd running ?";

    $ulogd_client = IO::Socket::UNIX->new(Peer  => $socketfile,
                                          Type      => SOCK_STREAM ) or die $!;
    $ulogd_client->autoflush(0);
}

sub print_padding
{
    my ($offset) = @_;
    my $padding;
    my $align = 8;
    my $data;

    $padding = ($align - ($offset % $align)) % $align;
    #print "offset: $offset padding $padding\n";

    $data = "\0" x $padding;
    $data_buffer .= $data;
}

sub process_pkt {
    my($user, $hdr, $pkt) = @_;

    if (($user ne "xyz") or !defined($hdr) or !defined($pkt)) {
        print("Bad args passed to callback\n");
        print("Bad user data\n"), if ($user ne "xyz");
        print("Bad pkthdr\n"), if (!defined($hdr));
        print("Bad pkt data\n"), if (!defined($pkt));
        print("not ok\n");
        exit;
    }

    #print "Header: len $hdr->{len}\n";
    #my $len = length $pkt;
    #print "Packet length: $len\n";

    my $size = length($pkt) - ($proto_offset+2);

    #my $pcaphdr = unpack ("H*", substr ($pkt, 0, 16));
    #printf("pcap hdr: $pcaphdr\n");
    my $proto = unpack ("H*", substr ($pkt, $proto_offset, 2));
    #printf("proto: $proto\n");

    if ($proto ne "0800") {
      print "ignoring packet with proto $proto\n";
      return;
    }

    #my $ip_firstbyte = unpack ("H*", substr ($pkt, $proto_offset+2, 2));
    #printf("ip_firstbyte: $ip_firstbyte\n");

    # decode packet for a SLL:
    # packet type (sent by us: 4)
    # link layer address type: 1
    # link layer address length: 6
    # src dst
    # protocol (IP, ARP, PPP, SNMP ...)
    # data
    my $srcmac = substr ($pkt, 6, 6);

    (my $hex_src = unpack("H*", $srcmac)) =~ s/(..)/$1:/g;
    chop $hex_src;
    #printf "source mac: $hex_src\n";

    my $hex_dst = "\0";

    # format data
    my $data;

    $data_buffer = undef;

    # ulogd packet signature
    $data = pack ('N', $ULOGD_SOCKET_MARK);

    $data_buffer .= $data;

    my $options_num=2;
    my $options_len=length($hex_src) + length($hex_dst);
    # total length (will be filled later)
    my $total_size = 0;
    $data = pack ('n', $total_size);
    $data_buffer .= $data;

    # reserved + payload length + payload
    $data = pack ('Nna*', 0, $size, substr($pkt,$proto_offset+2,$size));
    $data_buffer .= $data;
    print_padding($size);

    # options
    my $OOB_IN = 2;
    $data = pack ('NNa*', $OOB_IN, length($hex_src), $hex_src);
    $data_buffer .= $data;
    print_padding(length($hex_src));
    my $OOB_OUT = 3;
    $data = pack ('NNa*', $OOB_OUT, length($hex_dst), $hex_dst);
    $data_buffer .= $data;
    print_padding(length($hex_dst));

    # replace total size in buffer
    my $l = length($data_buffer) - 4;
    substr($data_buffer, 4, 2) = pack('n', $l);

    #(my $hex = unpack("H*", $data_buffer)) =~ s/(..)/$1 /g;
    #print "$l will be encoded as " . unpack("H*", pack('n', $l)) . "\n";
    #print $hex, "\n";

    print $ulogd_client $data_buffer;

    $ulogd_client->flush;

    #exit;
}


connect_ulogd2 or die $!;

$pcap_t = Net::Pcap::open_offline($dumpfile, \$err);
if (!defined($pcap_t)) {
    print("Net::Pcap::dump_open failed: ", Net::Pcap::geterr($pcap_t), "\n");
    exit;
}

$linktype = Net::Pcap::pcap_datalink($pcap_t);

if (not exists $linktype_to_offset{$linktype}) {
	print("Unsupported link type ", Net::Pcap::pcap_datalink_val_to_name($linktype), "\n");
	exit 1;
}

$proto_offset = $linktype_to_offset{$linktype};

Net::Pcap::loop($pcap_t, -1, \&process_pkt, "xyz");
Net::Pcap::close($pcap_t);