45dd820432648149051e9bcddeb96e3643e3536d
[anna.git] / example / diameter / launcher / resources / pcap2diameterHex.sh
1 #!/bin/bash
2
3 #############
4 # VARIABLES #
5 #############
6 tmpdir=$(mktemp -d)
7
8 #############
9 # FUNCTIONS #
10 #############
11
12 usage () {
13   echo "Usage: $0 <pcap_file> [results_dir]"
14   echo
15   echo "       pcap_file:   pcap formatted file to be processed."
16   echo "       results_dir: directory where results are stored."
17   echo "                    By default, pcap file dirname is used."
18   echo
19   echo "       The utility, dumps the extracted hexadecimal content"
20   echo "       and useful information as timestamps, source and"
21   echo "       destination:"
22   echo "          <results_dir>/<frame sequence>.hex"
23   echo "          <results_dir>/<frame sequence>.metadata"
24   echo
25   _exit
26 }
27
28 _exit () {
29   echo
30   echo -e $1
31   echo
32
33   # Cleanup
34   #rm -rf $tmpdir
35
36   rc=1
37   [ -n "$2" ] && rc=$2
38   exit $rc
39 }
40
41 # $1: string; $2: substring
42 get_str_pos() {
43   local result=-1
44   local str=$1
45   local substr="${1%%$2*}"
46   local pos=${#substr}
47   local size=${#str}
48   [ $size -ne $pos ] && result=$pos
49   echo $result
50 }
51
52 #############
53 # EXECUTION #
54 #############
55
56 echo
57 echo "============================================"
58 echo "Diameter buffer extractor from PCAP raw file"
59 echo "============================================"
60 echo
61
62 # Usage:
63 [ "$1" = "" ] && usage
64
65 # Pcap file:
66 PCAP_FILE=$1
67 [ ! -f $PCAP_FILE ] && _exit "Cannot found provided pcap file '$1' !!"
68
69 # Optional result dir:
70 RESULTS_DIR=`dirname $PCAP_FILE`
71 [ "$2" != "" ] && RESULTS_DIR=$2
72 [ ! -d $RESULTS_DIR ] && _exit "The results directory '$RESULTS_DIR' must exists !!"
73
74 # Get the frames with diameter content (take care about '-2' two-pass option and don't add it, because we need to get reassembled parts in their corresponding frames):
75 # Fields needed (we won't need diameter.hopbyhopid & diameter.endtoendid to verify diameter message as hint patterns; length management will be enough):
76 FIELDS="-e frame.number -e frame.time_epoch -e ip.src_host -e ip.dst_host -e tcp.len -e diameter.length -e frame.protocols -e tcp.segment"
77 tshark -E separator="|" -r $PCAP_FILE -N mntC -Tfields $FIELDS 2>/dev/null | grep -i diameter > $tmpdir/diameter_frames
78 # Example output:
79 #                                           /length\
80 # frame     timestamp        src     dst    TCP DIAM          protocol                         segments 
81 #   1|1427215933.697904000|gt_traf|vcbavipt|432|432|eth:ip:tcp:diameter:diameter:diameter3gpp|
82 #   3|1427215934.449523000|vcbavipt|gt_traf|292|292|eth:ip:tcp:diameter:diameter:diameter3gpp|
83 #   5|1427215934.456160000|gt_traf|vcbavipt|1400||eth:ip:tcp:diameter|
84 #   6|1427215934.456204000|gt_traf|vcbavipt|572|1972|eth:ip:tcp:diameter:diameter:diameter3gpp|5,6
85 #   8|1427215935.123559000|vcbavipt|gt_traf|248|248|eth:ip:tcp:diameter:diameter:diameter3gpp|
86 all_frames=( $(cat $tmpdir/diameter_frames | cut -d\| -f1) )
87 needs_join=( $(cat $tmpdir/diameter_frames | cut -d\| -f8) )
88 main_frames=( $(cat $tmpdir/diameter_frames | awk -F\| '{ if ($6 != "") print $1 }') )
89
90 # Reassemble procedure (using frame 1 as example):
91 # (for non segmented frames, it is enough with tcp or diameter length within the frame content itself)
92 # 1) Get the TCP length: 432 bytes. 432*2 = 864 characters per byte in hexadecimal string format
93 # 2) Get the frame length: `wc -c $tmpdir/block.$frame` => 997
94 # 3) Get 864 from the tail: `cat $tmpdir/block.$frame | cut -c133
95
96 # Dump the hex blocks for all the diameter frames:
97 cat $PCAP_FILE | rawshark -s -r - -d proto:diameter -F data 2>/dev/null > $tmpdir/all_hex_data
98 for frame in ${all_frames[@]}; do
99   grep "^$frame " $tmpdir/all_hex_data | cut -d\" -f2 | sed 's/://g' > $tmpdir/block.$frame
100   frame_info=$(grep "^${frame}|" $tmpdir/diameter_frames)
101
102   # Get the diameter part:
103   tcp_len=$(echo $frame_info | cut -d\| -f5)
104   frm_len=$(wc -c $tmpdir/block.$frame | awk '{ print $1 }')
105   cut_len=$((frm_len-2*tcp_len))
106   cat $tmpdir/block.$frame | cut -c${cut_len}- > $RESULTS_DIR/$frame.hex
107   echo -n "Created $RESULTS_DIR/$frame.hex"
108
109   # Metadata:
110   ts=$(echo $frame_info | cut -d\| -f2)
111   date=$(date -d @$ts)
112   src=$(echo $frame_info | cut -d\| -f3)
113   dst=$(echo $frame_info | cut -d\| -f4)
114   echo -e "timestamp=$ts\ndate=$date\nsrc=$src\ndst=$dst" > $RESULTS_DIR/$frame.metadata
115   echo " and $RESULTS_DIR/$frame.metadata"
116 done
117
118 # Join frames which need to be reassembled:
119 for group in ${needs_join[@]}; do
120   echo "Grouping frames $group ..."
121   group_array=( $(echo $group | sed 's/,/ /g') )
122   for frame in ${group_array[@]}; do
123     cat $RESULTS_DIR/$frame.hex >> $tmpdir/diam.$group
124   done
125   cat $tmpdir/diam.$group | tr -d '\n' > $RESULTS_DIR/$frame.hex
126 done
127
128 # Delete superfluous metadata:
129 echo "Deleting superfluous metadata ..."
130 segments=( $(cat $tmpdir/diameter_frames | awk -F\| '{ if ($6 == "") print $1 }') )
131 for s in ${segments[@]}; do rm $RESULTS_DIR/$s.metadata; done
132
133
134 _exit "Done!" 0
135