From Graeme Hewson:
[obnox/wireshark/wip.git] / packet-postgresql.c
1 /* packet-postgresql.c
2  * Routines for postgresql packet disassembly
3  *
4  * Copyright 2004, Edwin Calo <calo@fusemail.com>
5  *
6  * $Id: packet-postgresql.c,v 1.7 2004/03/02 01:39:35 jmayer Exp $
7  *
8  * Ethereal - Network traffic analyzer
9  * By Gerald Combs <gerald@ethereal.com>
10  * Copyright 1998 Gerald Combs
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
25  */
26
27 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif
30
31 #include <glib.h>
32 #include <epan/packet.h>
33
34 static int proto_postgresql = -1;
35 static int hf_postgresql_response = -1;
36 static int hf_postgresql_request = -1;
37 static int hf_postgresql_length = -1;
38 static int hf_postgresql_string_size = -1;
39 static int hf_postgresql_string = -1;
40 static int hf_postgresql_total_length = -1;
41 static int hf_postgresql_bitone = -1;
42 static int hf_postgresql_buff_remaining = -1;
43 static int hf_postgresql_opcode = -1;
44 static int hf_postgresql_idone = -1;
45 static gint ett_postgresql = -1;
46
47 #define TCP_PORT_POSTGRESQL     5432
48
49 /*
50  * For a protocol description, see:
51  *
52  *      http://www.postgresql.org/docs/7.4/interactive/protocol.html
53  *
54  * for version 3.0 of the protocol and
55  *
56  *      http://www.postgresql.org/docs/7.3/interactive/protocol.html
57  *
58  * for version 2.0 of the protocol and
59  *
60  *      http://www.postgresql.org/docs/6.3/interactive/c50.htm
61  *
62  * for version 1.0 of the protocol.
63  *
64  * It looks like there are two types of PDUs: Old style and new style.
65  * New style PDUs start with a Length guint32, where the high byte is
66  * equal to 0. Old style PDUs start with a single Byte (different from 0)
67  * that contains the type of the PDU.
68  *
69  * The specific types can be found at:
70  * http://www.postgresql.org/docs/7.4/interactive/protocol-message-formats.html
71  * 
72  */
73
74 static void
75 dissect_postgresql (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree)
76 {
77   proto_tree *postgresql_tree;
78   proto_item *ti;
79   gint offset = 0;
80   gint buff_remaining = 0;
81
82   guint8 *string;
83   guint8 bitone;
84   gint flag = 0;
85   gint counter = 0;
86
87
88
89
90   if (check_col (pinfo->cinfo, COL_PROTOCOL))
91     col_set_str (pinfo->cinfo, COL_PROTOCOL, "POSTGRESQL");
92
93   ti = proto_tree_add_item (tree, proto_postgresql, tvb, offset, -1, FALSE);
94   postgresql_tree = proto_item_add_subtree (ti, ett_postgresql);
95
96   buff_remaining = tvb_length_remaining (tvb, offset);
97
98   if (check_col (pinfo->cinfo, COL_INFO))
99     {
100       col_add_str (pinfo->cinfo, COL_INFO,
101                    (pinfo->match_port ==
102                     pinfo->destport) ? " Request" : " Response");
103     }
104
105     counter=0;
106     flag=0;
107     while ( buff_remaining >= 1 )
108     {
109          bitone = tvb_get_guint8 (tvb, offset);
110          offset += 1;
111
112          if(bitone > 0x7f || (bitone > 0x0 && bitone < 0x20) ) 
113          {
114             if(counter > 3)
115             {
116               if(offset > counter)
117               {
118                    offset -= counter+1;
119
120                     /* Reading the string from the packet */
121                     string = tvb_get_string(tvb,offset,counter);
122                     /* Printing the data */
123                     proto_tree_add_string (postgresql_tree,hf_postgresql_string,tvb, offset,counter, string );
124                     if (check_col (pinfo->cinfo, COL_INFO)) { col_append_fstr (pinfo->cinfo, COL_INFO, " %s", string ); }
125                     g_free(string);  /* Freeing up string */
126                     string=NULL;
127
128                    offset += counter+1;
129                    counter=0;
130               }
131               else
132               {
133                counter=0;
134                offset+=1;
135               }
136             }
137             else
138             {
139              counter=0;
140              offset+=1;
141             }
142          }
143
144          if( bitone == 0 )
145          {
146                 if(counter != 0)
147                 { 
148                   if(offset > counter)
149                   {
150                    offset -= counter+1;
151                    if( counter > 1)
152                    {
153                     /* Reading the string from the packet */
154                     string = tvb_get_string(tvb,offset,counter);
155                     /* Printing the data */
156                     proto_tree_add_string (postgresql_tree,hf_postgresql_string,tvb, offset,counter, string );
157                     if (check_col (pinfo->cinfo, COL_INFO)) { col_append_fstr (pinfo->cinfo, COL_INFO, " %s", string ); }
158                     g_free(string);  /* Freeing up string */
159                     string=NULL;
160
161                    }
162                    offset += counter+1;
163                   }
164                   counter = 0;
165                 }
166                 counter=0;
167          }
168          else
169          {
170              counter += 1;
171          }
172
173          buff_remaining = tvb_length_remaining (tvb, offset);
174      }
175
176
177
178 void proto_register_postgresql (void)
179 {
180
181   static hf_register_info hf[] = {
182     {&hf_postgresql_response,
183      {"Response", "postgresql.response",
184       FT_BOOLEAN, BASE_NONE, NULL, 0x0,
185       "TRUE if postgresql response", HFILL}},
186     {&hf_postgresql_request,
187      {"Request", "postgresql.request",
188       FT_BOOLEAN, BASE_NONE, NULL, 0x0,
189       "TRUE if postgresql request", HFILL}},
190     {&hf_postgresql_string, {"String", "hf_postgresql_string", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL}},
191     {&hf_postgresql_length, {"Length", "hf_postgresql_length", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL}},
192     {&hf_postgresql_string_size, {"Size", "hf_postgresql_string_size", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL}},
193     {&hf_postgresql_total_length, {"TotalLength", "hf_postgresql_total_length", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL}},
194     {&hf_postgresql_buff_remaining, {"Buffer Remaining", "hf_postgresql_buff_remaining", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL}},
195     {&hf_postgresql_opcode, {"Op Code", "hf_postgresql_opcode", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL}},
196     {&hf_postgresql_bitone, {"Bitone", "hf_postgresql_bitone", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL}},
197     {&hf_postgresql_idone, {"idone", "hf_postgresql_idone", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL}},
198  
199
200
201   };
202
203   static gint *ett[] = {
204     &ett_postgresql,
205   };
206
207   proto_postgresql =
208     proto_register_protocol ("POSTGRESQL", "POSTGRESQL", "postgresql");
209   proto_register_field_array (proto_postgresql, hf, array_length (hf));
210   proto_register_subtree_array (ett, array_length (ett));
211 }
212
213 void
214 proto_reg_handoff_postgresql (void)
215 {
216   dissector_handle_t postgresql_handle;
217
218   postgresql_handle =
219     create_dissector_handle (dissect_postgresql, proto_postgresql);
220   dissector_add ("tcp.port", TCP_PORT_POSTGRESQL, postgresql_handle);
221 }