2 * Routines for PostgreSQL v3 protocol dissection.
3 * <http://www.postgresql.org/docs/current/static/protocol.html>
4 * Copyright 2004 Abhijit Menon-Sen <ams@oryx.com>
8 * Wireshark - Network traffic analyzer
9 * By Gerald Combs <gerald@wireshark.org>
10 * Copyright 1998 Gerald Combs
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.
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.
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.
32 #include <epan/packet.h>
33 #include <epan/conversation.h>
34 #include <epan/prefs.h>
36 #include "packet-tcp.h"
39 static int proto_pgsql = -1;
40 static int hf_frontend = -1;
41 static int hf_type = -1;
42 static int hf_length = -1;
43 static int hf_parameter_name = -1;
44 static int hf_parameter_value = -1;
45 static int hf_query = -1;
46 static int hf_authtype = -1;
47 static int hf_passwd = -1;
48 static int hf_salt = -1;
49 static int hf_statement = -1;
50 static int hf_portal = -1;
51 static int hf_tag = -1;
52 static int hf_status = -1;
53 static int hf_copydata = -1;
54 static int hf_error = -1;
55 static int hf_pid = -1;
56 static int hf_key = -1;
57 static int hf_condition = -1;
58 static int hf_text = -1;
59 static int hf_tableoid = -1;
60 static int hf_typeoid = -1;
61 static int hf_oid = -1;
62 static int hf_format = -1;
63 static int hf_val_name = -1;
64 static int hf_val_idx = -1;
65 static int hf_val_length = -1;
66 static int hf_val_data = -1;
67 static int hf_val_mod = -1;
68 static int hf_severity = -1;
69 static int hf_code = -1;
70 static int hf_message = -1;
71 static int hf_detail = -1;
72 static int hf_hint = -1;
73 static int hf_position = -1;
74 static int hf_where = -1;
75 static int hf_file = -1;
76 static int hf_line = -1;
77 static int hf_routine = -1;
79 static gint ett_pgsql = -1;
80 static gint ett_values = -1;
82 static guint pgsql_port = 5432;
83 static gboolean pgsql_desegment = TRUE;
84 static gboolean first_message = TRUE;
86 static void dissect_pgsql_fe_msg(guchar, guint, tvbuff_t *, gint, proto_tree *);
87 static void dissect_pgsql_be_msg(guchar, guint, tvbuff_t *, gint, proto_tree *);
88 static void dissect_pgsql_msg(tvbuff_t *, packet_info *, proto_tree *);
89 static void dissect_pgsql(tvbuff_t *, packet_info *, proto_tree *);
90 static guint pgsql_length(packet_info *, tvbuff_t *, int);
92 static const value_string fe_messages[] = {
93 { 'p', "Password message" },
94 { 'Q', "Simple query" },
102 { 'F', "Function call" },
103 { 'd', "Copy data" },
104 { 'c', "Copy completion" },
105 { 'f', "Copy failure" },
106 { 'X', "Termination" },
110 static const value_string be_messages[] = {
111 { 'R', "Authentication request" },
112 { 'K', "Backend key data" },
113 { 'S', "Parameter status" },
114 { '1', "Parse completion" },
115 { '2', "Bind completion" },
116 { '3', "Close completion" },
117 { 'C', "Command completion" },
118 { 't', "Parameter description" },
119 { 'T', "Row description" },
121 { 'I', "Empty query" },
125 { 's', "Portal suspended" },
126 { 'Z', "Ready for query" },
127 { 'A', "Notification" },
128 { 'V', "Function call response" },
129 { 'G', "CopyIn response" },
130 { 'H', "CopyOut response" },
131 { 'd', "Copy data" },
132 { 'c', "Copy completion" },
137 static const value_string auth_types[] = {
139 { 1, "Kerberos V4" },
140 { 2, "Kerberos V5" },
141 { 3, "Plaintext password" },
142 { 4, "crypt()ed password" },
143 { 5, "MD5 password" },
144 { 6, "SCM credentials" },
148 static const value_string status_vals[] = {
150 { 'T', "In a transaction" },
151 { 'E', "In a failed transaction" },
155 static const value_string format_vals[] = {
161 /* This function is called once per TCP packet. It sets COL_PROTOCOL and
162 * identifies FE/BE messages by adding a ">" or "<" to COL_INFO. Then it
163 * arranges for each message to be dissected individually. */
166 dissect_pgsql(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
170 first_message = TRUE;
172 /* We don't use conversation data yet, but... */
173 cv = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
174 pinfo->srcport, pinfo->destport, 0);
176 cv = conversation_new(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
177 pinfo->srcport, pinfo->destport, 0);
180 if (check_col(pinfo->cinfo, COL_PROTOCOL))
181 col_set_str(pinfo->cinfo, COL_PROTOCOL, "PGSQL");
182 if (check_col(pinfo->cinfo, COL_INFO))
183 col_set_str(pinfo->cinfo, COL_INFO,
184 (pinfo->match_port == pinfo->destport) ?
187 tcp_dissect_pdus(tvb, pinfo, tree, pgsql_desegment, 5,
188 pgsql_length, dissect_pgsql_msg);
192 /* This function is called by tcp_dissect_pdus() to find the size of the
193 message starting at tvb[offset]. */
196 pgsql_length(packet_info *pinfo _U_, tvbuff_t *tvb, int offset)
202 /* The length is either the four bytes after the type, or, if the
203 type is 0, the first four bytes. */
204 type = tvb_get_guint8(tvb, offset);
207 length = tvb_get_ntohl(tvb, offset+n);
212 /* This function is responsible for dissecting a single message. */
215 dissect_pgsql_msg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
217 proto_item *ti, *hidden_item;
224 gboolean info = check_col(pinfo->cinfo, COL_INFO);
225 gboolean fe = (pinfo->match_port == pinfo->destport);
228 type = tvb_get_guint8(tvb, 0);
231 length = tvb_get_ntohl(tvb, n);
233 /* This is like specifying VALS(messages) for hf_type, which we can't do
234 directly because of messages without type bytes, and because the type
235 interpretation depends on fe. */
237 /* There are a few frontend messages that have no leading type byte.
238 We identify them by the fact that the first byte of their length
239 must be zero, and that the next four bytes are a unique tag. */
241 guint tag = tvb_get_ntohl(tvb, 4);
243 if (length == 16 && tag == 80877102)
244 typestr = "Cancel request";
245 else if (length == 8 && tag == 80877103)
246 typestr = "SSL request";
247 else if (tag == 196608)
248 typestr = "Startup message";
252 typestr = val_to_str(type, fe_messages, "Unknown");
255 typestr = val_to_str(type, be_messages, "Unknown");
259 /* This is a terrible hack. It makes the "Info" column reflect
260 the contents of every message in a TCP packet. Could it be
262 col_append_fstr(pinfo->cinfo, COL_INFO, "%s%c",
263 ( first_message ? "" : "/" ), type);
264 first_message = FALSE;
268 ti = proto_tree_add_item(tree, proto_pgsql, tvb, 0, -1, FALSE);
269 ptree = proto_item_add_subtree(ti, ett_pgsql);
274 proto_tree_add_text(ptree, tvb, 0, n, "Type: %s", typestr);
275 hidden_item = proto_tree_add_item(ptree, hf_type, tvb, 0, n, FALSE);
276 PROTO_ITEM_SET_HIDDEN(hidden_item);
277 proto_tree_add_item(ptree, hf_length, tvb, n, 4, FALSE);
278 hidden_item = proto_tree_add_boolean(ptree, hf_frontend, tvb, 0, 0, fe);
279 PROTO_ITEM_SET_HIDDEN(hidden_item);
283 dissect_pgsql_fe_msg(type, length, tvb, n, ptree);
285 dissect_pgsql_be_msg(type, length, tvb, n, ptree);
290 static void dissect_pgsql_fe_msg(guchar type, guint length, tvbuff_t *tvb,
291 gint n, proto_tree *tree)
296 proto_item *ti, *hidden_item;
302 s = tvb_get_ephemeral_stringz(tvb, n, &l);
303 proto_tree_add_string(tree, hf_passwd, tvb, n, l, s);
308 s = tvb_get_ephemeral_stringz(tvb, n, &l);
309 proto_tree_add_string(tree, hf_query, tvb, n, l, s);
314 s = tvb_get_ephemeral_stringz(tvb, n, &l);
315 proto_tree_add_string(tree, hf_statement, tvb, n, l, s);
318 s = tvb_get_ephemeral_stringz(tvb, n, &l);
319 proto_tree_add_string(tree, hf_query, tvb, n, l, s);
322 i = tvb_get_ntohs(tvb, n);
323 ti = proto_tree_add_text(tree, tvb, n, 2, "Parameters: %d", i);
324 shrub = proto_item_add_subtree(ti, ett_values);
327 proto_tree_add_item(shrub, hf_typeoid, tvb, n, 4, FALSE);
334 s = tvb_get_ephemeral_stringz(tvb, n, &l);
335 proto_tree_add_string(tree, hf_portal, tvb, n, l, s);
338 s = tvb_get_ephemeral_stringz(tvb, n, &l);
339 proto_tree_add_string(tree, hf_statement, tvb, n, l, s);
342 i = tvb_get_ntohs(tvb, n);
343 ti = proto_tree_add_text(tree, tvb, n, 2, "Parameter formats: %d", i);
344 shrub = proto_item_add_subtree(ti, ett_values);
347 proto_tree_add_item(shrub, hf_format, tvb, n, 2, FALSE);
351 i = tvb_get_ntohs(tvb, n);
352 ti = proto_tree_add_text(tree, tvb, n, 2, "Parameter values: %d", i);
353 shrub = proto_item_add_subtree(ti, ett_values);
356 l = tvb_get_ntohl(tvb, n);
357 proto_tree_add_int(shrub, hf_val_length, tvb, n, 4, l);
360 proto_tree_add_item(shrub, hf_val_data, tvb, n, l, FALSE);
365 i = tvb_get_ntohs(tvb, n);
366 ti = proto_tree_add_text(tree, tvb, n, 2, "Result formats: %d", i);
367 shrub = proto_item_add_subtree(ti, ett_values);
370 proto_tree_add_item(shrub, hf_format, tvb, n, 2, FALSE);
377 s = tvb_get_ephemeral_stringz(tvb, n, &l);
378 proto_tree_add_string(tree, hf_portal, tvb, n, l, s);
381 ti = proto_tree_add_text(tree, tvb, n, 4, "Returns: ");
382 i = tvb_get_ntohl(tvb, n);
384 proto_item_append_text(ti, "all");
386 proto_item_append_text(ti, "%d", i);
387 proto_item_append_text(ti, " rows");
390 /* Describe, Close */
394 c = tvb_get_guint8(tvb, n);
402 s = tvb_get_ephemeral_stringz(tvb, n, &l);
403 hidden_item = proto_tree_add_string(tree, i, tvb, n, l, s);
404 PROTO_ITEM_SET_HIDDEN(hidden_item);
406 tree, tvb, n-1, l, "%s: %s",
407 (c == 'P' ? "Portal" : "Statement"), s
412 /* Messages without a type identifier */
414 i = tvb_get_ntohl(tvb, n);
418 /* Startup message */
421 s = tvb_get_ephemeral_stringz(tvb, n, &l);
426 t = tvb_get_ephemeral_stringz(tvb, n+l, &i);
427 proto_tree_add_text(tree, tvb, n, l+i, "%s: %s", s, t);
430 if (length == 1 && tvb_get_guint8(tvb, n) == 0)
437 /* There's nothing to parse here, but what do we do if the
438 SSL negotiation succeeds? */
441 /* Cancellation request */
443 proto_tree_add_item(tree, hf_pid, tvb, n, 4, FALSE);
444 proto_tree_add_item(tree, hf_key, tvb, n+4, 4, FALSE);
451 proto_tree_add_item(tree, hf_copydata, tvb, n, length-n+1, FALSE);
456 s = tvb_get_ephemeral_stringz(tvb, n, &l);
457 proto_tree_add_string(tree, hf_error, tvb, n, l, s);
462 proto_tree_add_item(tree, hf_oid, tvb, n, 4, FALSE);
465 i = tvb_get_ntohs(tvb, n);
466 ti = proto_tree_add_text(tree, tvb, n, 2, "Parameter formats: %d", i);
467 shrub = proto_item_add_subtree(ti, ett_values);
470 proto_tree_add_item(shrub, hf_format, tvb, n, 2, FALSE);
474 i = tvb_get_ntohs(tvb, n);
475 ti = proto_tree_add_text(tree, tvb, n, 2, "Parameter values: %d", i);
476 shrub = proto_item_add_subtree(ti, ett_values);
479 l = tvb_get_ntohl(tvb, n);
480 proto_tree_add_item(shrub, hf_val_length, tvb, n, 4, FALSE);
483 proto_tree_add_item(shrub, hf_val_data, tvb, n, l, FALSE);
488 proto_tree_add_item(tree, hf_format, tvb, n, 2, FALSE);
494 static void dissect_pgsql_be_msg(guchar type, guint length, tvbuff_t *tvb,
495 gint n, proto_tree *tree)
500 proto_item *ti, *hidden_item;
504 /* Authentication request */
506 proto_tree_add_item(tree, hf_authtype, tvb, n, 4, FALSE);
507 i = tvb_get_ntohl(tvb, n);
508 if (i == 4 || i == 5) {
509 /* i -= (6-i); :-) */
511 l = (i == 4 ? 2 : 4);
512 proto_tree_add_item(tree, hf_salt, tvb, n, l, FALSE);
518 proto_tree_add_item(tree, hf_pid, tvb, n, 4, FALSE);
519 proto_tree_add_item(tree, hf_key, tvb, n+4, 4, FALSE);
522 /* Parameter status */
524 s = tvb_get_ephemeral_stringz(tvb, n, &l);
525 hidden_item = proto_tree_add_string(tree, hf_parameter_name, tvb, n, l, s);
526 PROTO_ITEM_SET_HIDDEN(hidden_item);
528 t = tvb_get_ephemeral_stringz(tvb, n, &i);
529 hidden_item = proto_tree_add_string(tree, hf_parameter_value, tvb, n, i, t);
530 PROTO_ITEM_SET_HIDDEN(hidden_item);
531 proto_tree_add_text(tree, tvb, n-l, l+i, "%s: %s", s, t);
534 /* Parameter description */
536 i = tvb_get_ntohs(tvb, n);
537 proto_tree_add_text(tree, tvb, n, 2, "Parameters: %d", i);
540 proto_tree_add_item(tree, hf_typeoid, tvb, n, 4, FALSE);
545 /* Row description */
547 i = tvb_get_ntohs(tvb, n);
548 ti = proto_tree_add_text(tree, tvb, n, 2, "Columns: %d", i);
549 shrub = proto_item_add_subtree(ti, ett_values);
553 s = tvb_get_ephemeral_stringz(tvb, n, &l);
554 ti = proto_tree_add_string(shrub, hf_val_name, tvb, n, l, s);
555 twig = proto_item_add_subtree(ti, ett_values);
557 proto_tree_add_item(twig, hf_tableoid, tvb, n, 4, FALSE);
559 proto_tree_add_item(twig, hf_val_idx, tvb, n, 2, FALSE);
561 proto_tree_add_item(twig, hf_typeoid, tvb, n, 4, FALSE);
563 proto_tree_add_item(twig, hf_val_length, tvb, n, 2, FALSE);
565 proto_tree_add_item(twig, hf_val_mod, tvb, n, 4, FALSE);
567 proto_tree_add_item(twig, hf_format, tvb, n, 2, FALSE);
574 i = tvb_get_ntohs(tvb, n);
575 ti = proto_tree_add_text(tree, tvb, n, 2, "Columns: %d", i);
576 shrub = proto_item_add_subtree(ti, ett_values);
579 l = tvb_get_ntohl(tvb, n);
580 proto_tree_add_int(shrub, hf_val_length, tvb, n, 4, l);
583 proto_tree_add_item(shrub, hf_val_data, tvb, n, l, FALSE);
589 /* Command completion */
591 s = tvb_get_ephemeral_stringz(tvb, n, &l);
592 proto_tree_add_string(tree, hf_tag, tvb, n, l, s);
597 proto_tree_add_item(tree, hf_status, tvb, n, 1, FALSE);
605 c = tvb_get_guint8(tvb, n);
608 s = tvb_get_ephemeral_stringz(tvb, n+1, &l);
611 case 'S': i = hf_severity; break;
612 case 'C': i = hf_code; break;
613 case 'M': i = hf_message; break;
614 case 'D': i = hf_detail; break;
615 case 'H': i = hf_hint; break;
616 case 'P': i = hf_position; break;
617 case 'W': i = hf_where; break;
618 case 'F': i = hf_file; break;
619 case 'L': i = hf_line; break;
620 case 'R': i = hf_routine; break;
622 proto_tree_add_string(tree, i, tvb, n, l+1, s);
627 /* NOTICE response */
629 proto_tree_add_item(tree, hf_pid, tvb, n, 4, FALSE);
631 s = tvb_get_ephemeral_stringz(tvb, n, &l);
632 proto_tree_add_string(tree, hf_condition, tvb, n, l, s);
634 s = tvb_get_ephemeral_stringz(tvb, n, &l);
636 proto_tree_add_string(tree, hf_text, tvb, n, l, s);
642 proto_tree_add_item(tree, hf_format, tvb, n, 1, FALSE);
644 i = tvb_get_ntohs(tvb, n);
645 ti = proto_tree_add_text(tree, tvb, n, 2, "Columns: %d", i);
646 shrub = proto_item_add_subtree(ti, ett_values);
649 proto_tree_add_item(shrub, hf_format, tvb, n, 2, FALSE);
656 proto_tree_add_item(tree, hf_copydata, tvb, n, length-n+1, FALSE);
659 /* Function call response */
661 l = tvb_get_ntohl(tvb, n);
662 proto_tree_add_int(tree, hf_val_length, tvb, n, 4, l);
664 proto_tree_add_item(tree, hf_val_data, tvb, n+4, l, FALSE);
670 proto_reg_handoff_pgsql(void);
673 proto_register_pgsql(void)
675 static hf_register_info hf[] = {
677 { "Frontend", "pgsql.frontend", FT_BOOLEAN, BASE_NONE, NULL, 0,
678 "True for messages from the frontend, false otherwise.",
682 { "Type", "pgsql.type", FT_STRING, BASE_NONE, NULL, 0,
683 "A one-byte message type identifier.", HFILL }
686 { "Length", "pgsql.length", FT_UINT32, BASE_DEC, NULL, 0,
687 "The length of the message (not including the type).",
690 { &hf_parameter_name,
691 { "Parameter name", "pgsql.parameter_name", FT_STRINGZ,
692 BASE_NONE, NULL, 0, "The name of a database parameter.",
695 { &hf_parameter_value,
696 { "Parameter value", "pgsql.parameter_value", FT_STRINGZ,
697 BASE_NONE, NULL, 0, "The value of a database parameter.",
701 { "Query", "pgsql.query", FT_STRINGZ, BASE_NONE, NULL, 0,
702 "A query string.", HFILL }
705 { "Password", "pgsql.password", FT_STRINGZ, BASE_NONE, NULL, 0,
706 "A password.", HFILL }
709 { "Authentication type", "pgsql.authtype", FT_INT32, BASE_DEC,
711 "The type of authentication requested by the backend.", HFILL }
714 { "Salt value", "pgsql.salt", FT_BYTES, BASE_HEX, NULL, 0,
715 "The salt to use while encrypting a password.", HFILL }
718 { "Statement", "pgsql.statement", FT_STRINGZ, BASE_NONE, NULL, 0,
719 "The name of a prepared statement.", HFILL }
722 { "Portal", "pgsql.portal", FT_STRINGZ, BASE_NONE, NULL, 0,
723 "The name of a portal.", HFILL }
726 { "Tag", "pgsql.tag", FT_STRINGZ, BASE_NONE, NULL, 0,
727 "A completion tag.", HFILL }
730 { "Status", "pgsql.status", FT_UINT8, BASE_DEC, VALS(status_vals),
731 0, "The transaction status of the backend.", HFILL }
734 { "Copy data", "pgsql.copydata", FT_BYTES, BASE_NONE, NULL, 0,
735 "Data sent following a Copy-in or Copy-out response.", HFILL }
738 { "Error", "pgsql.error", FT_STRINGZ, BASE_NONE, NULL, 0,
739 "An error message.", HFILL }
742 { "PID", "pgsql.pid", FT_UINT32, BASE_DEC, NULL, 0,
743 "The process ID of a backend.", HFILL }
746 { "Key", "pgsql.key", FT_UINT32, BASE_DEC, NULL, 0,
747 "The secret key used by a particular backend.", HFILL }
750 { "Condition", "pgsql.condition", FT_STRINGZ, BASE_NONE, NULL, 0,
751 "The name of a NOTIFY condition.", HFILL }
754 { "Text", "pgsql.text", FT_STRINGZ, BASE_NONE, NULL, 0,
755 "Text from the backend.", HFILL }
758 { "Table OID", "pgsql.oid.table", FT_UINT32, BASE_DEC, NULL, 0,
759 "The object identifier of a table.", HFILL }
762 { "Type OID", "pgsql.oid.type", FT_UINT32, BASE_DEC, NULL, 0,
763 "The object identifier of a type.", HFILL }
766 { "OID", "pgsql.oid", FT_UINT32, BASE_DEC, NULL, 0,
767 "An object identifier.", HFILL }
770 { "Format", "pgsql.format", FT_UINT16, BASE_DEC, VALS(format_vals),
771 0, "A format specifier.", HFILL }
774 { "Column name", "pgsql.col.name", FT_STRINGZ, BASE_NONE, NULL, 0,
775 "The name of a column.", HFILL }
778 { "Column index", "pgsql.col.index", FT_UINT32, BASE_DEC, NULL, 0,
779 "The position of a column within a row.", HFILL }
782 { "Column length", "pgsql.val.length", FT_INT32, BASE_DEC, NULL, 0,
783 "The length of a parameter value, in bytes. -1 means NULL.",
787 { "Data", "pgsql.val.data", FT_BYTES, BASE_NONE, NULL, 0,
788 "Parameter data.", HFILL }
791 { "Type modifier", "pgsql.col.typemod", FT_INT32, BASE_DEC, NULL, 0,
792 "The type modifier for a column.", HFILL }
795 { "Severity", "pgsql.severity", FT_STRINGZ, BASE_NONE, NULL, 0,
796 "Message severity.", HFILL }
799 { "Code", "pgsql.code", FT_STRINGZ, BASE_NONE, NULL, 0,
800 "SQLState code.", HFILL }
803 { "Message", "pgsql.message", FT_STRINGZ, BASE_NONE, NULL, 0,
804 "Error message.", HFILL }
807 { "Detail", "pgsql.detail", FT_STRINGZ, BASE_NONE, NULL, 0,
808 "Detailed error message.", HFILL }
811 { "Hint", "pgsql.hint", FT_STRINGZ, BASE_NONE, NULL, 0,
812 "A suggestion to resolve an error.", HFILL }
815 { "Position", "pgsql.position", FT_STRINGZ, BASE_NONE, NULL, 0,
816 "The index of the error within the query string.", HFILL }
819 { "Context", "pgsql.where", FT_STRINGZ, BASE_NONE, NULL, 0,
820 "The context in which an error occurred.", HFILL }
823 { "File", "pgsql.file", FT_STRINGZ, BASE_NONE, NULL, 0,
824 "The source-code file where an error was reported.", HFILL }
827 { "Line", "pgsql.line", FT_STRINGZ, BASE_NONE, NULL, 0,
828 "The line number on which an error was reported.", HFILL }
831 { "Routine", "pgsql.routine", FT_STRINGZ, BASE_NONE, NULL, 0,
832 "The routine that reported an error.", HFILL }
836 static gint *ett[] = {
843 proto_pgsql = proto_register_protocol("PostgreSQL", "PGSQL", "pgsql");
844 proto_register_field_array(proto_pgsql, hf, array_length(hf));
845 proto_register_subtree_array(ett, array_length(ett));
847 mod_pgsql = prefs_register_protocol(proto_pgsql, proto_reg_handoff_pgsql);
848 prefs_register_uint_preference(
849 mod_pgsql, "tcp.port", "PGSQL TCP port", "Set the port for PGSQL "
850 "messages (if different from the default of 5432)", 10, &pgsql_port
855 proto_reg_handoff_pgsql(void)
857 static gboolean initialized = FALSE;
858 static dissector_handle_t pgsql_handle;
859 static guint saved_pgsql_port;
862 pgsql_handle = create_dissector_handle(dissect_pgsql, proto_pgsql);
865 dissector_delete("tcp.port", saved_pgsql_port, pgsql_handle);
868 dissector_add("tcp.port", pgsql_port, pgsql_handle);
869 saved_pgsql_port = pgsql_port;