From Kovarththanan Rajaratnam via bug 3548:
[obnox/wireshark/wip.git] / epan / dissectors / packet-redbackli.c
1 /* packet-redbackli.c
2  *
3  * $Id$
4  *
5  * Redback Lawful Intercept Packet dissector
6  *
7  * Copyright 2008 Florian Lohoff <flo[AT]rfc822.org>
8  *
9  * Wireshark - Network traffic analyzer
10  * By Gerald Combs <gerald[AT]wireshark.org>
11  * Copyright 1998 Gerald Combs
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
26  */
27
28 #ifdef HAVE_CONFIG_H
29 #include "config.h"
30 #endif
31
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <ctype.h>
35 #include <time.h>
36 #include <string.h>
37
38 #include <glib.h>
39 #include <epan/packet.h>
40 #include <epan/addr_resolv.h>
41 #include <epan/strutil.h>
42
43 static int proto_redbackli = -1;
44
45 static int hf_redbackli_seqno = -1;             /* Sequence No */
46 static int hf_redbackli_liid = -1;              /* LI Id */
47 static int hf_redbackli_sessid = -1;            /* Session Id */
48 static int hf_redbackli_label = -1;             /* Label */
49 static int hf_redbackli_acctid = -1;            /* Accounting Session Id */
50 static int hf_redbackli_dir = -1;               /* Direction */
51 static int hf_redbackli_eohpad = -1;            /* End Of Header Padding */
52 static int hf_redbackli_unknownavp = -1;        /* Unknown AVP */
53
54 static int ett_redbackli = -1;
55
56 static dissector_handle_t ip_handle;
57
58 #define RB_AVP_SEQNO    1
59 #define RB_AVP_LIID     2
60 #define RB_AVP_SESSID   3
61 #define RB_AVP_DIR      4
62 #define RB_AVP_LABEL    20
63 #define RB_AVP_ACCTID   40
64 #define RB_AVP_EOH      0
65
66 static const value_string avp_names[] = {
67         {RB_AVP_SEQNO,          "Sequence No"},
68         {RB_AVP_LIID,           "Lawful Intercept Id"},
69         {RB_AVP_SESSID,         "Session Id"},
70         {RB_AVP_LABEL,          "Label"},
71         {RB_AVP_ACCTID,         "Accounting Session Id"},
72         {RB_AVP_DIR,            "Direction"},
73         {RB_AVP_EOH,            "End Of Header"},
74         {0,                     NULL}
75 };
76
77 static void
78 redbackli_dissect_avp(guint8 avptype, guint8 avplen, tvbuff_t *tvb, gint offset, proto_tree *tree)
79 {
80         const char      *avpname;
81         proto_tree      *ti, *st=NULL;
82
83         avpname=val_to_str(avptype, avp_names, "Unknown");
84
85         ti = proto_tree_add_text(tree, tvb, offset, avplen+2, "%s AVP", avpname);
86         st = proto_item_add_subtree(ti, ett_redbackli);
87
88         proto_tree_add_text(st, tvb, offset, 1, "AVP Type: %d", avptype);
89         proto_tree_add_text(st, tvb, offset+1, 1, "AVP Length: %d", avplen);
90
91         if (!avplen)
92                 return;
93
94         switch(avptype) {
95                 case(RB_AVP_SEQNO):
96                         proto_tree_add_item(st, hf_redbackli_seqno, tvb,
97                                             offset+2, avplen, FALSE);
98                         break;
99                 case(RB_AVP_LIID):
100                         proto_tree_add_item(st, hf_redbackli_liid, tvb,
101                                             offset+2, avplen, FALSE);
102                         break;
103                 case(RB_AVP_SESSID):
104                         proto_tree_add_item(st, hf_redbackli_sessid, tvb,
105                                             offset+2, avplen, FALSE);
106                         break;
107                 case(RB_AVP_LABEL):
108                         proto_tree_add_item(st, hf_redbackli_label, tvb,
109                                             offset+2, avplen, FALSE);
110                         break;
111                 case(RB_AVP_EOH):
112                         proto_tree_add_item(st, hf_redbackli_eohpad, tvb,
113                                             offset+2, avplen, FALSE);
114                         break;
115                 case(RB_AVP_DIR):
116                         proto_tree_add_item(st, hf_redbackli_dir, tvb,
117                                         offset+2, avplen, FALSE);
118                         break;
119                 case(RB_AVP_ACCTID):
120                         proto_tree_add_item(st, hf_redbackli_acctid, tvb,
121                                             offset+2, avplen, FALSE);
122                         break;
123                 default:
124                         proto_tree_add_item(st, hf_redbackli_unknownavp, tvb,
125                                             offset+2, avplen, FALSE);
126                         break;
127         }
128
129         return;
130 }
131
132 static void
133 redbackli_dissect(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
134 {
135         guint8          avptype, avplen;
136         gint            len, offset=0;
137         gboolean        eoh;
138         proto_tree      *ti, *redbackli_tree=NULL;
139         tvbuff_t        *next_tvb;
140
141         if(check_col(pinfo->cinfo,COL_PROTOCOL))
142                 col_add_str(pinfo->cinfo,COL_PROTOCOL,"RBLI");
143
144         if (tree) {
145                 ti = proto_tree_add_item(tree, proto_redbackli,
146                                          tvb, 0, -1, FALSE);
147                 redbackli_tree = proto_item_add_subtree(ti, ett_redbackli);
148         }
149
150         len=tvb_length(tvb);
151         offset=0;
152         eoh=FALSE;
153         while(!eoh && len > 2) {
154                 avptype = tvb_get_guint8(tvb, offset+0);
155                 avplen = tvb_get_guint8(tvb, offset+1);
156
157                 if (len < avplen+2)             /* AVP Complete ? */
158                         break;
159
160                 if (tree)
161                         redbackli_dissect_avp(avptype, avplen, tvb, offset, redbackli_tree);
162
163                 if (avptype == RB_AVP_EOH)
164                         eoh=TRUE;
165
166                 offset+=2+avplen;
167                 len-=2+avplen;
168         }
169
170         next_tvb = tvb_new_subset(tvb, offset, -1, -1);
171         call_dissector(ip_handle, next_tvb, pinfo, tree);
172 }
173
174
175 #define REDBACKLI_INTSIZE       6
176 #define REDBACKLI_EOHSIZE       2
177 #define MIN_REDBACKLI_SIZE      (3*REDBACKLI_INTSIZE+REDBACKLI_EOHSIZE)
178
179 static gboolean
180 redbackli_dissect_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
181 {
182         gint            len, offset=0;
183         gboolean        eoh=FALSE;
184         guint8          avptype, avplen;
185         guint32         avpfound=0;
186
187         len=tvb_length(tvb);
188         if (len < MIN_REDBACKLI_SIZE)
189                 return FALSE;
190
191         /*
192          * We scan the possible AVPs and look out for mismatches.
193          * An int AVP needs to be 4 byte long, and the eoh must be 0 or 1
194          * long .. Unknown AVPs also mean not for us ...
195          *
196          */
197         while(len > 2 && !eoh) {
198                 avptype = tvb_get_guint8(tvb, offset+0);
199                 avplen = tvb_get_guint8(tvb, offset+1);
200
201                 switch(avptype) {
202                         case(RB_AVP_SEQNO):
203                         case(RB_AVP_LIID):
204                         case(RB_AVP_SESSID):
205                                 if (avplen != 4)
206                                         return FALSE;
207                                 avpfound|=1<<avptype;
208                                 break;
209                         case(RB_AVP_EOH):
210                                 if (avplen > 1 || offset == 0)
211                                         return FALSE;
212                                 eoh=TRUE;
213                                 break;
214                         case(RB_AVP_LABEL):
215                         case(RB_AVP_DIR):
216                         case(RB_AVP_ACCTID):
217                                 break;
218                         default:
219                                 return FALSE;
220                 }
221                 offset+=2+avplen;
222                 len-=2+avplen;
223         }
224
225         if (!(avpfound & (1<<RB_AVP_SEQNO)))
226                 return FALSE;
227         if (!(avpfound & (1<<RB_AVP_SESSID)))
228                 return FALSE;
229         if (!(avpfound & (1<<RB_AVP_LIID)))
230                 return FALSE;
231
232         redbackli_dissect(tvb, pinfo, tree);
233
234         return TRUE;
235 }
236 void proto_register_redbackli(void) {
237         static hf_register_info hf[] = {
238                 { &hf_redbackli_seqno,
239                         { "Sequence No", "redbackli.seqno", FT_UINT32, BASE_DEC, NULL, 0x0,
240                         NULL, HFILL }},
241                 { &hf_redbackli_liid,
242                         { "Lawful Intercept Id", "redbackli.liid", FT_UINT32, BASE_DEC, NULL, 0x0,
243                         "LI Identifier", HFILL }},
244                 { &hf_redbackli_sessid,
245                         { "Session Id", "redbackli.sessid", FT_UINT32, BASE_DEC, NULL, 0x0,
246                         "Session Identifier", HFILL }},
247                 { &hf_redbackli_dir,
248                         { "Direction", "redbackli.dir", FT_UINT8, BASE_DEC, NULL, 0x0,
249                         NULL, HFILL }},
250                 { &hf_redbackli_label,
251                         { "Label", "redbackli.label", FT_STRING, BASE_NONE, NULL, 0x0,
252                         NULL, HFILL }},
253                 { &hf_redbackli_acctid,
254                         { "Acctid", "redbackli.acctid", FT_BYTES, BASE_NONE, NULL, 0x0,
255                         NULL, HFILL }},
256                 { &hf_redbackli_eohpad,
257                         { "End of Header Padding", "redbackli.eohpad", FT_BYTES, BASE_NONE, NULL, 0x0,
258                         NULL, HFILL }},
259                 { &hf_redbackli_unknownavp,
260                         { "Unknown AVP", "redbackli.unknownavp", FT_BYTES, BASE_NONE, NULL, 0x0,
261                         NULL, HFILL }}
262                 };
263
264         static gint *ett[] = {
265                 &ett_redbackli
266         };
267
268         proto_redbackli = proto_register_protocol("Redback Lawful Intercept",
269                                                   "RedbackLI","redbackli");
270
271         proto_register_field_array(proto_redbackli,hf,array_length(hf));
272         proto_register_subtree_array(ett,array_length(ett));
273
274         register_dissector("redbackli", redbackli_dissect, proto_redbackli);
275 }
276
277 void proto_reg_handoff_redbackli(void) {
278         dissector_handle_t redbackli_handle;
279
280         ip_handle = find_dissector("ip");
281
282         redbackli_handle = find_dissector("redbackli");
283         dissector_add_handle("udp.port", redbackli_handle);  /* for 'decode-as' */
284
285         heur_dissector_add("udp", redbackli_dissect_heur, proto_redbackli);
286 }