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>
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
10 * SPDX-License-Identifier: GPL-2.0-or-later
15 #include <epan/packet.h>
17 #include "packet-gssapi.h"
18 #include "packet-tls-utils.h"
19 #include "packet-tcp.h"
21 void proto_register_pgsql(void);
22 void proto_reg_handoff_pgsql(void);
24 static dissector_handle_t pgsql_handle
;
25 static dissector_handle_t pgsql_gssapi_handle
;
26 static dissector_handle_t tls_handle
;
27 static dissector_handle_t gssapi_handle
;
28 static dissector_handle_t ntlmssp_handle
;
30 static int proto_pgsql
;
31 static int hf_frontend
;
34 static int hf_version_major
;
35 static int hf_version_minor
;
36 static int hf_request_code
;
37 static int hf_supported_minor_version
;
38 static int hf_number_nonsupported_options
;
39 static int hf_nonsupported_option
;
40 static int hf_parameter_name
;
41 static int hf_parameter_value
;
43 static int hf_authtype
;
46 static int hf_gssapi_sspi_data
;
47 static int hf_sasl_auth_mech
;
48 static int hf_sasl_auth_data
;
49 static int hf_sasl_auth_data_length
;
50 static int hf_statement
;
55 static int hf_copydata
;
59 static int hf_condition
;
61 static int hf_tableoid
;
62 static int hf_typeoid
;
65 static int hf_field_count
;
66 static int hf_val_name
;
67 static int hf_val_idx
;
68 static int hf_val_length
;
69 static int hf_val_data
;
70 static int hf_val_mod
;
71 static int hf_severity
;
73 static int hf_message
;
76 static int hf_position
;
77 static int hf_internal_position
;
78 static int hf_internal_query
;
80 static int hf_schema_name
;
81 static int hf_table_name
;
82 static int hf_column_name
;
83 static int hf_type_name
;
84 static int hf_constraint_name
;
87 static int hf_routine
;
88 static int hf_ssl_response
;
89 static int hf_gssenc_response
;
90 static int hf_gssapi_encrypted_payload
;
93 static int ett_values
;
95 #define PGSQL_PORT 5432
96 static bool pgsql_desegment
= true;
97 static bool first_message
= true;
100 /* Reserve 0 (== GPOINTER_TO_UINT(NULL)) for no PGSQL detected */
101 PGSQL_AUTH_STATE_NONE
= 1, /* No authentication seen or used */
102 PGSQL_AUTH_SASL_REQUESTED
, /* Server sends SASL auth request with supported SASL mechanisms*/
103 PGSQL_AUTH_SASL_CONTINUE
, /* Server and/or client send further SASL challenge-response messages */
104 PGSQL_AUTH_GSSAPI_SSPI_DATA
, /* GSSAPI/SSPI in use */
105 PGSQL_AUTH_SSL_REQUESTED
, /* Client sends SSL encryption request */
106 PGSQL_AUTH_GSSENC_REQUESTED
, /* Client sends GSSAPI encryption request */
107 } pgsql_auth_state_t
;
109 typedef struct pgsql_conn_data
{
110 wmem_tree_t
*state_tree
; /* Tree of encryption and auth state changes */
111 uint32_t server_port
;
114 static const value_string fe_messages
[] = {
115 { 'p', "Authentication message" },
116 { 'Q', "Simple query" },
124 { 'F', "Function call" },
125 { 'd', "Copy data" },
126 { 'c', "Copy completion" },
127 { 'f', "Copy failure" },
128 { 'X', "Termination" },
132 static const value_string be_messages
[] = {
133 { 'R', "Authentication request" },
134 { 'K', "Backend key data" },
135 { 'S', "Parameter status" },
136 { '1', "Parse completion" },
137 { '2', "Bind completion" },
138 { '3', "Close completion" },
139 { 'C', "Command completion" },
140 { 't', "Parameter description" },
141 { 'T', "Row description" },
143 { 'I', "Empty query" },
147 { 's', "Portal suspended" },
148 { 'Z', "Ready for query" },
149 { 'A', "Notification" },
150 { 'V', "Function call response" },
151 { 'G', "CopyIn response" },
152 { 'H', "CopyOut response" },
153 { 'd', "Copy data" },
154 { 'c', "Copy completion" },
155 { 'v', "Negotiate protocol version" },
159 #define PGSQL_AUTH_TYPE_SUCCESS 0
160 #define PGSQL_AUTH_TYPE_KERBEROS4 1
161 #define PGSQL_AUTH_TYPE_KERBEROS5 2
162 #define PGSQL_AUTH_TYPE_PLAINTEXT 3
163 #define PGSQL_AUTH_TYPE_CRYPT 4
164 #define PGSQL_AUTH_TYPE_MD5 5
165 #define PGSQL_AUTH_TYPE_SCM 6
166 #define PGSQL_AUTH_TYPE_GSSAPI 7
167 #define PGSQL_AUTH_TYPE_GSSAPI_SSPI_CONTINUE 8
168 #define PGSQL_AUTH_TYPE_SSPI 9
169 #define PGSQL_AUTH_TYPE_SASL 10
170 #define PGSQL_AUTH_TYPE_SASL_CONTINUE 11
171 #define PGSQL_AUTH_TYPE_SASL_COMPLETE 12
173 static const value_string auth_types
[] = {
174 { PGSQL_AUTH_TYPE_SUCCESS
, "Success" },
175 { PGSQL_AUTH_TYPE_KERBEROS4
, "Kerberos V4" },
176 { PGSQL_AUTH_TYPE_KERBEROS5
, "Kerberos V5" },
177 { PGSQL_AUTH_TYPE_PLAINTEXT
, "Plaintext password" },
178 { PGSQL_AUTH_TYPE_CRYPT
, "crypt()ed password" },
179 { PGSQL_AUTH_TYPE_MD5
, "MD5 password" },
180 { PGSQL_AUTH_TYPE_SCM
, "SCM credentials" },
181 { PGSQL_AUTH_TYPE_GSSAPI
, "GSSAPI" },
182 { PGSQL_AUTH_TYPE_GSSAPI_SSPI_CONTINUE
, "GSSAPI/SSPI continue" },
183 { PGSQL_AUTH_TYPE_SSPI
, "SSPI" },
184 { PGSQL_AUTH_TYPE_SASL
, "SASL" },
185 { PGSQL_AUTH_TYPE_SASL_CONTINUE
, "SASL continue" },
186 { PGSQL_AUTH_TYPE_SASL_COMPLETE
, "SASL complete" },
190 static const value_string status_vals
[] = {
192 { 'T', "In a transaction" },
193 { 'E', "In a failed transaction" },
197 static const value_string format_vals
[] = {
203 #define PGSQL_CANCELREQUEST 80877102
204 #define PGSQL_SSLREQUEST 80877103
205 #define PGSQL_GSSENCREQUEST 80877104
207 static const value_string request_code_vals
[] = {
208 { PGSQL_CANCELREQUEST
, "CancelRequest" },
209 { PGSQL_SSLREQUEST
, "SSLRequest" },
210 { PGSQL_GSSENCREQUEST
, "GSSENCRequest" },
214 static const value_string ssl_response_vals
[] = {
215 { 'N', "Unwilling to perform SSL" },
216 { 'S', "Willing to perform SSL" },
220 static const value_string gssenc_response_vals
[] = {
221 { 'G', "Willing to perform GSSAPI encryption" },
222 { 'N', "Unwilling to perform GSSAPI encryption" },
226 static void dissect_pgsql_fe_msg(unsigned char type
, unsigned length
, tvbuff_t
*tvb
,
227 int n
, proto_tree
*tree
, packet_info
*pinfo
,
228 pgsql_conn_data_t
*conv_data
)
235 pgsql_auth_state_t state
;
237 dissector_handle_t payload_handle
;
240 /* Password, SASL or GSSAPI Response, depending on context */
242 state
= GPOINTER_TO_UINT(wmem_tree_lookup32_le(conv_data
->state_tree
, pinfo
->num
));
245 case PGSQL_AUTH_SASL_REQUESTED
:
246 /* SASLInitResponse */
247 siz
= tvb_strsize(tvb
, n
);
248 proto_tree_add_item(tree
, hf_sasl_auth_mech
, tvb
, n
, siz
, ENC_ASCII
);
250 proto_tree_add_item_ret_int(tree
, hf_sasl_auth_data_length
, tvb
, n
, 4, ENC_BIG_ENDIAN
, &data_length
);
253 proto_tree_add_item(tree
, hf_sasl_auth_data
, tvb
, n
, data_length
, ENC_NA
);
257 case PGSQL_AUTH_SASL_CONTINUE
:
258 proto_tree_add_item(tree
, hf_sasl_auth_data
, tvb
, n
, length
-4, ENC_NA
);
261 case PGSQL_AUTH_GSSAPI_SSPI_DATA
:
262 next_tvb
= tvb_new_subset_length(tvb
, n
, length
- 4);
263 /* https://www.postgresql.org/docs/current/sspi-auth.html
264 * "PostgreSQL will use SSPI in negotiate mode, which will use
265 * Kerberos when possible and automatically fall back to NTLM
266 * in other cases... When using Kerberos authentication, SSPI
267 * works the same way GSSAPI does."
268 * Assume this means the Kerberos mode for SSPI works like
269 * GSSAPI, and not, say, SPNEGO the way TDS does. (Need
272 if (tvb_strneql(next_tvb
, 0, "NTLMSSP", 7) == 0) {
273 payload_handle
= ntlmssp_handle
;
275 payload_handle
= gssapi_handle
;
277 n
= call_dissector_only(payload_handle
, next_tvb
, pinfo
, tree
, NULL
);
278 if ((length
= tvb_reported_length_remaining(next_tvb
, n
))) {
279 proto_tree_add_item(tree
, hf_gssapi_sspi_data
, next_tvb
, n
, length
, ENC_NA
);
284 siz
= tvb_strsize(tvb
, n
);
285 proto_tree_add_item(tree
, hf_passwd
, tvb
, n
, siz
, ENC_ASCII
);
292 siz
= tvb_strsize(tvb
, n
);
293 proto_tree_add_item(tree
, hf_query
, tvb
, n
, siz
, ENC_ASCII
);
298 siz
= tvb_strsize(tvb
, n
);
299 proto_tree_add_item(tree
, hf_statement
, tvb
, n
, siz
, ENC_ASCII
);
302 siz
= tvb_strsize(tvb
, n
);
303 proto_tree_add_item(tree
, hf_query
, tvb
, n
, siz
, ENC_ASCII
);
306 i
= tvb_get_ntohs(tvb
, n
);
307 shrub
= proto_tree_add_subtree_format(tree
, tvb
, n
, 2, ett_values
, NULL
, "Parameters: %d", i
);
310 proto_tree_add_item(shrub
, hf_typeoid
, tvb
, n
, 4, ENC_BIG_ENDIAN
);
317 siz
= tvb_strsize(tvb
, n
);
318 proto_tree_add_item(tree
, hf_portal
, tvb
, n
, siz
, ENC_ASCII
);
321 siz
= tvb_strsize(tvb
, n
);
322 proto_tree_add_item(tree
, hf_statement
, tvb
, n
, siz
, ENC_ASCII
);
325 i
= tvb_get_ntohs(tvb
, n
);
326 shrub
= proto_tree_add_subtree_format(tree
, tvb
, n
, 2, ett_values
, NULL
, "Parameter formats: %d", i
);
329 proto_tree_add_item(shrub
, hf_format
, tvb
, n
, 2, ENC_BIG_ENDIAN
);
333 i
= tvb_get_ntohs(tvb
, n
);
334 shrub
= proto_tree_add_subtree_format(tree
, tvb
, n
, 2, ett_values
, NULL
, "Parameter values: %d", i
);
337 siz
= tvb_get_ntohl(tvb
, n
);
338 proto_tree_add_int(shrub
, hf_val_length
, tvb
, n
, 4, siz
);
341 proto_tree_add_item(shrub
, hf_val_data
, tvb
, n
, siz
, ENC_NA
);
346 i
= tvb_get_ntohs(tvb
, n
);
347 shrub
= proto_tree_add_subtree_format(tree
, tvb
, n
, 2, ett_values
, NULL
, "Result formats: %d", i
);
350 proto_tree_add_item(shrub
, hf_format
, tvb
, n
, 2, ENC_BIG_ENDIAN
);
357 siz
= tvb_strsize(tvb
, n
);
358 proto_tree_add_item(tree
, hf_portal
, tvb
, n
, siz
, ENC_ASCII
);
361 i
= tvb_get_ntohl(tvb
, n
);
363 proto_tree_add_uint_format_value(tree
, hf_return
, tvb
, n
, 4, i
, "all rows");
365 proto_tree_add_uint_format_value(tree
, hf_return
, tvb
, n
, 4, i
, "%d rows", i
);
368 /* Describe, Close */
371 c
= tvb_get_uint8(tvb
, n
);
378 s
= tvb_get_stringz_enc(pinfo
->pool
, tvb
, n
, &siz
, ENC_ASCII
);
379 proto_tree_add_string(tree
, i
, tvb
, n
, siz
, s
);
382 /* Messages without a type identifier */
384 i
= tvb_get_ntohl(tvb
, n
);
388 /* Startup message */
390 proto_tree_add_item(tree
, hf_version_major
, tvb
, n
-4, 2, ENC_BIG_ENDIAN
);
391 proto_tree_add_item(tree
, hf_version_minor
, tvb
, n
-2, 2, ENC_BIG_ENDIAN
);
392 while ((signed)length
> 0) {
393 siz
= tvb_strsize(tvb
, n
);
395 if ((signed)length
<= 0) {
398 proto_tree_add_item(tree
, hf_parameter_name
, tvb
, n
, siz
, ENC_ASCII
);
399 i
= tvb_strsize(tvb
, n
+siz
);
400 proto_tree_add_item(tree
, hf_parameter_value
, tvb
, n
+ siz
, i
, ENC_ASCII
);
404 if (length
== 1 && tvb_get_uint8(tvb
, n
) == 0)
409 case PGSQL_SSLREQUEST
:
410 proto_tree_add_item(tree
, hf_request_code
, tvb
, n
-4, 4, ENC_BIG_ENDIAN
);
411 /* Next reply will be a single byte. */
412 wmem_tree_insert32(conv_data
->state_tree
, pinfo
->num
, GUINT_TO_POINTER(PGSQL_AUTH_SSL_REQUESTED
));
415 case PGSQL_GSSENCREQUEST
:
416 proto_tree_add_item(tree
, hf_request_code
, tvb
, n
-4, 4, ENC_BIG_ENDIAN
);
417 /* Next reply will be a single byte. */
418 wmem_tree_insert32(conv_data
->state_tree
, pinfo
->num
, GUINT_TO_POINTER(PGSQL_AUTH_GSSENC_REQUESTED
));
421 case PGSQL_CANCELREQUEST
:
422 proto_tree_add_item(tree
, hf_request_code
, tvb
, n
-4, 4, ENC_BIG_ENDIAN
);
423 proto_tree_add_item(tree
, hf_pid
, tvb
, n
, 4, ENC_BIG_ENDIAN
);
424 proto_tree_add_item(tree
, hf_key
, tvb
, n
+4, 4, ENC_BIG_ENDIAN
);
431 proto_tree_add_item(tree
, hf_copydata
, tvb
, n
, length
-n
+1, ENC_NA
);
436 siz
= tvb_strsize(tvb
, n
);
437 proto_tree_add_item(tree
, hf_error
, tvb
, n
, siz
, ENC_ASCII
);
442 proto_tree_add_item(tree
, hf_oid
, tvb
, n
, 4, ENC_BIG_ENDIAN
);
445 i
= tvb_get_ntohs(tvb
, n
);
446 shrub
= proto_tree_add_subtree_format(tree
, tvb
, n
, 2, ett_values
, NULL
, "Parameter formats: %d", i
);
449 proto_tree_add_item(shrub
, hf_format
, tvb
, n
, 2, ENC_BIG_ENDIAN
);
453 i
= tvb_get_ntohs(tvb
, n
);
454 shrub
= proto_tree_add_subtree_format(tree
, tvb
, n
, 2, ett_values
, NULL
, "Parameter values: %d", i
);
457 siz
= tvb_get_ntohl(tvb
, n
);
458 proto_tree_add_item(shrub
, hf_val_length
, tvb
, n
, 4, ENC_BIG_ENDIAN
);
461 proto_tree_add_item(shrub
, hf_val_data
, tvb
, n
, siz
, ENC_NA
);
466 proto_tree_add_item(tree
, hf_format
, tvb
, n
, 2, ENC_BIG_ENDIAN
);
472 static void dissect_pgsql_be_msg(unsigned char type
, unsigned length
, tvbuff_t
*tvb
,
473 int n
, proto_tree
*tree
, packet_info
*pinfo
,
474 pgsql_conn_data_t
*conv_data
)
479 int32_t num_nonsupported_options
;
485 /* Authentication request */
487 proto_tree_add_item_ret_uint(tree
, hf_authtype
, tvb
, n
, 4, ENC_BIG_ENDIAN
, &auth_type
);
489 case PGSQL_AUTH_TYPE_CRYPT
:
490 case PGSQL_AUTH_TYPE_MD5
:
492 siz
= (auth_type
== PGSQL_AUTH_TYPE_CRYPT
? 2 : 4);
493 proto_tree_add_item(tree
, hf_salt
, tvb
, n
, siz
, ENC_NA
);
495 case PGSQL_AUTH_TYPE_GSSAPI_SSPI_CONTINUE
:
496 proto_tree_add_item(tree
, hf_gssapi_sspi_data
, tvb
, n
, length
-8, ENC_NA
);
498 case PGSQL_AUTH_TYPE_GSSAPI
:
499 case PGSQL_AUTH_TYPE_SSPI
:
500 wmem_tree_insert32(conv_data
->state_tree
, pinfo
->num
, GUINT_TO_POINTER(PGSQL_AUTH_GSSAPI_SSPI_DATA
));
502 case PGSQL_AUTH_TYPE_SASL
:
503 wmem_tree_insert32(conv_data
->state_tree
, pinfo
->num
, GUINT_TO_POINTER(PGSQL_AUTH_SASL_REQUESTED
));
505 while ((unsigned)n
< length
) {
506 siz
= tvb_strsize(tvb
, n
);
507 proto_tree_add_item(tree
, hf_sasl_auth_mech
, tvb
, n
, siz
, ENC_ASCII
);
511 case PGSQL_AUTH_TYPE_SASL_CONTINUE
:
512 case PGSQL_AUTH_TYPE_SASL_COMPLETE
:
513 wmem_tree_insert32(conv_data
->state_tree
, pinfo
->num
, GUINT_TO_POINTER(PGSQL_AUTH_SASL_CONTINUE
));
515 if ((unsigned)n
< length
) {
516 proto_tree_add_item(tree
, hf_sasl_auth_data
, tvb
, n
, length
-8, ENC_NA
);
524 proto_tree_add_item(tree
, hf_pid
, tvb
, n
, 4, ENC_BIG_ENDIAN
);
525 proto_tree_add_item(tree
, hf_key
, tvb
, n
+4, 4, ENC_BIG_ENDIAN
);
528 /* Parameter status */
530 s
= tvb_get_stringz_enc(pinfo
->pool
, tvb
, n
, &siz
, ENC_ASCII
);
531 proto_tree_add_string(tree
, hf_parameter_name
, tvb
, n
, siz
, s
);
533 t
= tvb_get_stringz_enc(pinfo
->pool
, tvb
, n
, &i
, ENC_ASCII
);
534 proto_tree_add_string(tree
, hf_parameter_value
, tvb
, n
, i
, t
);
537 /* Parameter description */
539 i
= tvb_get_ntohs(tvb
, n
);
540 shrub
= proto_tree_add_subtree_format(tree
, tvb
, n
, 2, ett_values
, NULL
, "Parameters: %d", i
);
543 proto_tree_add_item(shrub
, hf_typeoid
, tvb
, n
, 4, ENC_BIG_ENDIAN
);
548 /* Row description */
550 i
= tvb_get_ntohs(tvb
, n
);
551 ti
= proto_tree_add_item(tree
, hf_field_count
, tvb
, n
, 2, ENC_BIG_ENDIAN
);
552 shrub
= proto_item_add_subtree(ti
, ett_values
);
556 siz
= tvb_strsize(tvb
, n
);
557 ti
= proto_tree_add_item(shrub
, hf_val_name
, tvb
, n
, siz
, ENC_ASCII
);
558 twig
= proto_item_add_subtree(ti
, ett_values
);
560 proto_tree_add_item(twig
, hf_tableoid
, tvb
, n
, 4, ENC_BIG_ENDIAN
);
562 proto_tree_add_item(twig
, hf_val_idx
, tvb
, n
, 2, ENC_BIG_ENDIAN
);
564 proto_tree_add_item(twig
, hf_typeoid
, tvb
, n
, 4, ENC_BIG_ENDIAN
);
566 proto_tree_add_item(twig
, hf_val_length
, tvb
, n
, 2, ENC_BIG_ENDIAN
);
568 proto_tree_add_item(twig
, hf_val_mod
, tvb
, n
, 4, ENC_BIG_ENDIAN
);
570 proto_tree_add_item(twig
, hf_format
, tvb
, n
, 2, ENC_BIG_ENDIAN
);
577 i
= tvb_get_ntohs(tvb
, n
);
578 ti
= proto_tree_add_item(tree
, hf_field_count
, tvb
, n
, 2, ENC_BIG_ENDIAN
);
579 shrub
= proto_item_add_subtree(ti
, ett_values
);
582 siz
= tvb_get_ntohl(tvb
, n
);
583 proto_tree_add_int(shrub
, hf_val_length
, tvb
, n
, 4, siz
);
586 proto_tree_add_item(shrub
, hf_val_data
, tvb
, n
, siz
, ENC_NA
);
592 /* Command completion */
594 siz
= tvb_strsize(tvb
, n
);
595 proto_tree_add_item(tree
, hf_tag
, tvb
, n
, siz
, ENC_ASCII
);
600 proto_tree_add_item(tree
, hf_status
, tvb
, n
, 1, ENC_BIG_ENDIAN
);
607 while ((signed)length
> 0) {
608 c
= tvb_get_uint8(tvb
, n
);
612 s
= tvb_get_stringz_enc(pinfo
->pool
, tvb
, n
+1, &siz
, ENC_ASCII
);
615 case 'S': i
= hf_severity
; break;
616 case 'C': i
= hf_code
; break;
617 case 'M': i
= hf_message
; break;
618 case 'D': i
= hf_detail
; break;
619 case 'H': i
= hf_hint
; break;
620 case 'P': i
= hf_position
; break;
621 case 'p': i
= hf_internal_position
; break;
622 case 'q': i
= hf_internal_query
; break;
623 case 'W': i
= hf_where
; break;
624 case 's': i
= hf_schema_name
; break;
625 case 't': i
= hf_table_name
; break;
626 case 'c': i
= hf_column_name
; break;
627 case 'd': i
= hf_type_name
; break;
628 case 'n': i
= hf_constraint_name
; break;
629 case 'F': i
= hf_file
; break;
630 case 'L': i
= hf_line
; break;
631 case 'R': i
= hf_routine
; break;
633 proto_tree_add_string(tree
, i
, tvb
, n
, siz
+1, s
);
639 /* NOTICE response */
641 proto_tree_add_item(tree
, hf_pid
, tvb
, n
, 4, ENC_BIG_ENDIAN
);
643 siz
= tvb_strsize(tvb
, n
);
644 proto_tree_add_item(tree
, hf_condition
, tvb
, n
, siz
, ENC_ASCII
);
646 siz
= tvb_strsize(tvb
, n
);
648 proto_tree_add_item(tree
, hf_text
, tvb
, n
, siz
, ENC_ASCII
);
654 proto_tree_add_item(tree
, hf_format
, tvb
, n
, 1, ENC_BIG_ENDIAN
);
656 i
= tvb_get_ntohs(tvb
, n
);
657 shrub
= proto_tree_add_subtree_format(tree
, tvb
, n
, 2, ett_values
, NULL
, "Columns: %d", i
);
660 proto_tree_add_item(shrub
, hf_format
, tvb
, n
, 2, ENC_BIG_ENDIAN
);
667 proto_tree_add_item(tree
, hf_copydata
, tvb
, n
, length
-n
+1, ENC_NA
);
670 /* Function call response */
672 siz
= tvb_get_ntohl(tvb
, n
);
673 proto_tree_add_int(tree
, hf_val_length
, tvb
, n
, 4, siz
);
675 proto_tree_add_item(tree
, hf_val_data
, tvb
, n
+4, siz
, ENC_NA
);
678 /* Negotiate Protocol Version */
680 proto_tree_add_item(tree
, hf_supported_minor_version
, tvb
, n
, 4, ENC_BIG_ENDIAN
);
682 proto_tree_add_item_ret_int(tree
, hf_number_nonsupported_options
, tvb
, n
, 4, ENC_BIG_ENDIAN
, &num_nonsupported_options
);
684 while (num_nonsupported_options
> 0) {
685 siz
= tvb_strsize(tvb
, n
);
686 proto_tree_add_item(tree
, hf_nonsupported_option
, tvb
, n
, siz
, ENC_ASCII
);
688 num_nonsupported_options
--;
694 /* This function is called by tcp_dissect_pdus() to find the size of the
695 message starting at tvb[offset]. */
697 pgsql_length(packet_info
*pinfo _U_
, tvbuff_t
*tvb
, int offset
, void *data _U_
)
703 /* The length is either the four bytes after the type, or, if the
704 type is 0, the first four bytes. */
705 type
= tvb_get_uint8(tvb
, offset
);
708 length
= tvb_get_ntohl(tvb
, offset
+n
);
712 /* This function is called by tcp_dissect_pdus() to find the size of the
713 wrapped GSS-API message starting at tvb[offset] whe. */
715 pgsql_gssapi_length(packet_info
*pinfo _U_
, tvbuff_t
*tvb
, int offset
, void *data _U_
)
717 /* The length of the GSS-API message is the first four bytes, and does
718 * not include the 4 byte length (the gss_wrap). */
719 return tvb_get_ntohl(tvb
, offset
) + 4;
723 /* This function is responsible for dissecting a single message. */
726 dissect_pgsql_msg(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data _U_
)
728 proto_item
*ti
, *hidden_item
;
730 conversation_t
*conversation
;
731 pgsql_conn_data_t
*conn_data
;
732 pgsql_auth_state_t state
;
740 conversation
= find_or_create_conversation(pinfo
);
741 conn_data
= (pgsql_conn_data_t
*)conversation_get_proto_data(conversation
, proto_pgsql
);
743 conn_data
= wmem_new(wmem_file_scope(), pgsql_conn_data_t
);
744 conn_data
->state_tree
= wmem_tree_new(wmem_file_scope());
745 conn_data
->server_port
= pinfo
->match_uint
;
746 wmem_tree_insert32(conn_data
->state_tree
, pinfo
->num
, GUINT_TO_POINTER(PGSQL_AUTH_STATE_NONE
));
747 conversation_add_proto_data(conversation
, proto_pgsql
, conn_data
);
750 fe
= (conn_data
->server_port
== pinfo
->destport
);
753 type
= tvb_get_uint8(tvb
, 0);
756 length
= tvb_get_ntohl(tvb
, n
);
758 /* This is like specifying VALS(messages) for hf_type, which we can't do
759 directly because of messages without type bytes, and because the type
760 interpretation depends on fe. */
762 /* There are a few frontend messages that have no leading type byte.
763 We identify them by the fact that the first byte of their length
764 must be zero, and that the next four bytes are a unique tag. */
766 unsigned tag
= tvb_get_ntohl(tvb
, 4);
768 if (length
== 16 && tag
== PGSQL_CANCELREQUEST
)
769 typestr
= "Cancel request";
770 else if (length
== 8 && tag
== PGSQL_SSLREQUEST
)
771 typestr
= "SSL request";
772 else if (length
== 8 && tag
== PGSQL_GSSENCREQUEST
)
773 typestr
= "GSS encrypt request";
774 else if (tag
== 196608)
775 typestr
= "Startup message";
778 } else if (type
== 'p') {
779 state
= GPOINTER_TO_UINT(wmem_tree_lookup32_le(conn_data
->state_tree
, pinfo
->num
));
781 case PGSQL_AUTH_SASL_REQUESTED
:
782 typestr
= "SASLInitialResponse message";
784 case PGSQL_AUTH_SASL_CONTINUE
:
785 typestr
= "SASLResponse message";
787 case PGSQL_AUTH_GSSAPI_SSPI_DATA
:
788 typestr
= "GSSResponse message";
791 typestr
= "Password message";
795 typestr
= val_to_str_const(type
, fe_messages
, "Unknown");
798 typestr
= val_to_str_const(type
, be_messages
, "Unknown");
801 /* This is a terrible hack. It makes the "Info" column reflect
802 the contents of every message in a TCP packet. Could it be
804 col_append_fstr(pinfo
->cinfo
, COL_INFO
, "%s%c",
805 ( first_message
? "" : "/" ), g_ascii_isprint(type
) ? type
: '?');
806 first_message
= false;
809 ti
= proto_tree_add_item(tree
, proto_pgsql
, tvb
, 0, -1, ENC_NA
);
810 ptree
= proto_item_add_subtree(ti
, ett_pgsql
);
815 proto_tree_add_string(ptree
, hf_type
, tvb
, 0, n
, typestr
);
816 proto_tree_add_item(ptree
, hf_length
, tvb
, n
, 4, ENC_BIG_ENDIAN
);
817 hidden_item
= proto_tree_add_boolean(ptree
, hf_frontend
, tvb
, 0, 0, fe
);
818 proto_item_set_hidden(hidden_item
);
822 dissect_pgsql_fe_msg(type
, length
, tvb
, n
, ptree
, pinfo
, conn_data
);
824 dissect_pgsql_be_msg(type
, length
, tvb
, n
, ptree
, pinfo
, conn_data
);
827 return tvb_captured_length(tvb
);
831 dissect_pgsql_gssapi_wrap(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
836 conversation_t
*conversation
;
837 pgsql_conn_data_t
*conn_data
;
839 conversation
= find_or_create_conversation(pinfo
);
840 conn_data
= (pgsql_conn_data_t
*)conversation_get_proto_data(conversation
, proto_pgsql
);
843 /* This shouldn't happen. */
844 conn_data
= wmem_new0(wmem_file_scope(), pgsql_conn_data_t
);
845 conn_data
->state_tree
= wmem_tree_new(wmem_file_scope());
846 conn_data
->server_port
= pinfo
->match_uint
;
847 wmem_tree_insert32(conn_data
->state_tree
, pinfo
->num
, GUINT_TO_POINTER(PGSQL_AUTH_GSSAPI_SSPI_DATA
));
848 conversation_add_proto_data(conversation
, proto_pgsql
, conn_data
);
851 bool fe
= (pinfo
->destport
== conn_data
->server_port
);
853 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "PGSQL");
854 col_set_str(pinfo
->cinfo
, COL_INFO
,
857 ti
= proto_tree_add_item(tree
, proto_pgsql
, tvb
, 0, -1, ENC_NA
);
858 ptree
= proto_item_add_subtree(ti
, ett_pgsql
);
860 proto_tree_add_string(ptree
, hf_type
, tvb
, 0, 0, "GSS-API encrypted message");
861 proto_tree_add_item(ptree
, hf_length
, tvb
, 0, 4, ENC_BIG_ENDIAN
);
863 gssapi_encrypt_info_t encrypt
;
864 memset(&encrypt
, 0, sizeof(encrypt
));
865 encrypt
.decrypt_gssapi_tvb
= DECRYPT_GSSAPI_NORMAL
;
868 tvbuff_t
*gssapi_tvb
= tvb_new_subset_remaining(tvb
, 4);
870 ver_len
= call_dissector_with_data(gssapi_handle
, gssapi_tvb
, pinfo
, ptree
, &encrypt
);
872 /* GSS-API couldn't do anything with it. */
873 return tvb_captured_length(tvb
);
875 if (encrypt
.gssapi_data_encrypted
) {
876 if (encrypt
.gssapi_decrypted_tvb
) {
877 tvbuff_t
*decr_tvb
= encrypt
.gssapi_decrypted_tvb
;
878 add_new_data_source(pinfo
, encrypt
.gssapi_decrypted_tvb
, "Decrypted GSS-API");
879 dissect_pgsql_msg(decr_tvb
, pinfo
, ptree
, data
);
881 /* Encrypted but couldn't be decrypted. */
882 proto_tree_add_item(ptree
, hf_gssapi_encrypted_payload
, gssapi_tvb
, ver_len
, -1, ENC_NA
);
885 /* No encrypted (sealed) payload. If any bytes are left, that is
886 * signed-only payload. */
888 if (encrypt
.gssapi_decrypted_tvb
) {
889 plain_tvb
= encrypt
.gssapi_decrypted_tvb
;
891 plain_tvb
= tvb_new_subset_remaining(gssapi_tvb
, ver_len
);
893 if (tvb_reported_length(plain_tvb
)) {
894 dissect_pgsql_msg(plain_tvb
, pinfo
, ptree
, data
);
897 return tvb_captured_length(tvb
);
901 dissect_pgsql_gssapi(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
903 tcp_dissect_pdus(tvb
, pinfo
, tree
, pgsql_desegment
, 4,
904 pgsql_gssapi_length
, dissect_pgsql_gssapi_wrap
, data
);
905 return tvb_captured_length(tvb
);
908 /* This function is called once per TCP packet. It sets COL_PROTOCOL and
909 * identifies FE/BE messages by adding a ">" or "<" to COL_INFO. Then it
910 * arranges for each message to be dissected individually. */
913 dissect_pgsql(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data
)
917 conversation_t
*conversation
;
918 pgsql_conn_data_t
*conn_data
;
919 pgsql_auth_state_t state
;
921 first_message
= true;
923 conversation
= find_or_create_conversation(pinfo
);
924 conn_data
= (pgsql_conn_data_t
*)conversation_get_proto_data(conversation
, proto_pgsql
);
926 bool fe
= (pinfo
->match_uint
== pinfo
->destport
);
928 if (fe
&& tvb_get_uint8(tvb
, 0) == 0x16 &&
929 (!conn_data
|| wmem_tree_lookup32_le(conn_data
->state_tree
, pinfo
->num
) == NULL
))
931 /* This is the first message in the conversation, and it looks
932 * like a TLS handshake. Assume the client is performing
933 * "direct SSL" negotiation.
935 tls_set_appdata_dissector(tls_handle
, pinfo
, pgsql_handle
);
938 if (!tvb_ascii_isprint(tvb
, 0, 1) && tvb_get_uint8(tvb
, 0) != '\0') {
939 /* Doesn't look like the start of a PostgreSQL packet. Have we
942 if (!conn_data
|| wmem_tree_lookup32_le(conn_data
->state_tree
, pinfo
->num
) == NULL
) {
943 /* No. Reject. This might be PostgreSQL over TLS and we missed
944 * the start of the transaction. The TLS dissector should get
949 /* Was there segmentation, and we lost a packet or were out of
950 * order without out of order processing, or we couldn't do
951 * desegmentation of a segment because of a bad checksum?
952 * XXX: Should we call this Continuation Data if this happens,
953 * so we don't send it to tcp_dissect_pdus()?
957 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "PGSQL");
958 col_set_str(pinfo
->cinfo
, COL_INFO
,
961 if (conn_data
&& !fe
) {
962 state
= GPOINTER_TO_UINT(wmem_tree_lookup32_le(conn_data
->state_tree
, pinfo
->num
));
963 if (state
== PGSQL_AUTH_SSL_REQUESTED
) {
964 /* Response to SSLRequest. */
965 wmem_tree_insert32(conn_data
->state_tree
, pinfo
->num
+ 1, GUINT_TO_POINTER(PGSQL_AUTH_STATE_NONE
));
966 ti
= proto_tree_add_item(tree
, proto_pgsql
, tvb
, 0, -1, ENC_NA
);
967 ptree
= proto_item_add_subtree(ti
, ett_pgsql
);
968 proto_tree_add_string(ptree
, hf_type
, tvb
, 0, 0, "SSL response");
969 proto_tree_add_item(ptree
, hf_ssl_response
, tvb
, 0, 1, ENC_NA
);
970 switch (tvb_get_uint8(tvb
, 0)) {
971 case 'S': /* Willing to perform SSL */
972 /* Next packet will start using SSL. */
973 ssl_starttls_ack(tls_handle
, pinfo
, pgsql_handle
);
975 case 'E': /* ErrorResponse when server does not support SSL. */
976 /* Process normally. */
977 tcp_dissect_pdus(tvb
, pinfo
, tree
, pgsql_desegment
, 5,
978 pgsql_length
, dissect_pgsql_msg
, data
);
980 case 'N': /* Unwilling to perform SSL */
981 default: /* Unexpected response. */
982 /* TODO: maybe add expert info here? */
985 /* XXX: If it's anything other than 'E', a length of more
986 * than one character is unexpected and should possibly have
987 * an expert info (possible MitM:
988 * https://www.postgresql.org/support/security/CVE-2021-23222/ )
990 return tvb_captured_length(tvb
);
991 } else if (state
== PGSQL_AUTH_GSSENC_REQUESTED
) {
992 /* Response to GSSENCRequest. */
993 wmem_tree_insert32(conn_data
->state_tree
, pinfo
->num
+ 1, GUINT_TO_POINTER(PGSQL_AUTH_STATE_NONE
));
994 ti
= proto_tree_add_item(tree
, proto_pgsql
, tvb
, 0, -1, ENC_NA
);
995 ptree
= proto_item_add_subtree(ti
, ett_pgsql
);
996 proto_tree_add_string(ptree
, hf_type
, tvb
, 0, 0, "GSS encrypt response");
997 proto_tree_add_item(ptree
, hf_gssenc_response
, tvb
, 0, 1, ENC_NA
);
998 switch (tvb_get_uint8(tvb
, 0)) {
999 case 'E': /* ErrorResponse; server does not support GSSAPI. */
1000 /* Process normally. */
1001 tcp_dissect_pdus(tvb
, pinfo
, tree
, pgsql_desegment
, 5,
1002 pgsql_length
, dissect_pgsql_msg
, data
);
1004 case 'G': /* Willing to perform GSSAPI Enc */
1005 wmem_tree_insert32(conn_data
->state_tree
, pinfo
->num
+ 1, GUINT_TO_POINTER(PGSQL_AUTH_GSSAPI_SSPI_DATA
));
1006 conversation_set_dissector_from_frame_number(conversation
, pinfo
->num
+ 1, pgsql_gssapi_handle
);
1008 case 'N': /* Unwilling to perform GSSAPI Enc */
1009 default: /* Unexpected response. */
1010 /* TODO: maybe add expert info here? */
1013 return tvb_captured_length(tvb
);
1017 tcp_dissect_pdus(tvb
, pinfo
, tree
, pgsql_desegment
, 5,
1018 pgsql_length
, dissect_pgsql_msg
, data
);
1019 return tvb_captured_length(tvb
);
1023 proto_register_pgsql(void)
1025 static hf_register_info hf
[] = {
1027 { "Frontend", "pgsql.frontend", FT_BOOLEAN
, BASE_NONE
, NULL
, 0x0,
1028 "True for messages from the frontend, false otherwise.",
1032 { "Type", "pgsql.type", FT_STRING
, BASE_NONE
, NULL
, 0,
1033 "A one-byte message type identifier.", HFILL
}
1036 { "Length", "pgsql.length", FT_UINT32
, BASE_DEC
, NULL
, 0,
1037 "The length of the message (not including the type).",
1040 { &hf_version_major
,
1041 { "Protocol major version", "pgsql.version_major", FT_UINT16
, BASE_DEC
, NULL
, 0,
1044 { &hf_version_minor
,
1045 { "Protocol minor version", "pgsql.version_minor", FT_UINT16
, BASE_DEC
, NULL
, 0,
1049 { "Request code", "pgsql.request_code", FT_UINT32
, BASE_DEC
,
1050 VALS(request_code_vals
), 0, NULL
, HFILL
}
1052 { &hf_supported_minor_version
,
1053 { "Supported minor version", "pgsql.version_supported_minor", FT_UINT32
, BASE_DEC
, NULL
, 0,
1054 "Newest minor protocol version supported by the server for the major protocol version requested by the client.", HFILL
}
1056 { &hf_number_nonsupported_options
,
1057 { "Number nonsupported options", "pgsql.number_nonsupported_options", FT_INT32
, BASE_DEC
, NULL
, 0,
1060 { &hf_nonsupported_option
,
1061 { "Nonsupported option", "pgsql.nonsupported_option", FT_STRINGZ
, BASE_NONE
, NULL
, 0,
1064 { &hf_parameter_name
,
1065 { "Parameter name", "pgsql.parameter_name", FT_STRINGZ
,
1066 BASE_NONE
, NULL
, 0, "The name of a database parameter.",
1069 { &hf_parameter_value
,
1070 { "Parameter value", "pgsql.parameter_value", FT_STRINGZ
,
1071 BASE_NONE
, NULL
, 0, "The value of a database parameter.",
1075 { "Query", "pgsql.query", FT_STRINGZ
, BASE_NONE
, NULL
, 0,
1076 "A query string.", HFILL
}
1079 { "Password", "pgsql.password", FT_STRINGZ
, BASE_NONE
, NULL
, 0,
1080 "A password.", HFILL
}
1083 { "Authentication type", "pgsql.authtype", FT_UINT32
, BASE_DEC
,
1084 VALS(auth_types
), 0,
1085 "The type of authentication requested by the backend.", HFILL
}
1088 { "Salt value", "pgsql.salt", FT_BYTES
, BASE_NONE
, NULL
, 0,
1089 "The salt to use while encrypting a password.", HFILL
}
1091 { &hf_gssapi_sspi_data
,
1092 { "GSSAPI or SSPI authentication data", "pgsql.auth.gssapi_sspi.data", FT_BYTES
, BASE_NONE
, NULL
, 0,
1095 { &hf_sasl_auth_mech
,
1096 { "SASL authentication mechanism", "pgsql.auth.sasl.mech", FT_STRINGZ
, BASE_NONE
, NULL
, 0,
1099 { &hf_sasl_auth_data_length
,
1100 { "SASL authentication data length", "pgsql.auth.sasl.data.length", FT_INT32
, BASE_DEC
, NULL
, 0,
1103 { &hf_sasl_auth_data
,
1104 { "SASL authentication data", "pgsql.auth.sasl.data", FT_BYTES
, BASE_NONE
, NULL
, 0,
1108 { "Statement", "pgsql.statement", FT_STRINGZ
, BASE_NONE
, NULL
, 0,
1109 "The name of a prepared statement.", HFILL
}
1112 { "Portal", "pgsql.portal", FT_STRINGZ
, BASE_NONE
, NULL
, 0,
1113 "The name of a portal.", HFILL
}
1116 { "Returns", "pgsql.returns", FT_UINT32
, BASE_DEC
,
1121 { "Tag", "pgsql.tag", FT_STRINGZ
, BASE_NONE
, NULL
, 0,
1122 "A completion tag.", HFILL
}
1125 { "Status", "pgsql.status", FT_UINT8
, BASE_DEC
, VALS(status_vals
),
1126 0, "The transaction status of the backend.", HFILL
}
1129 { "Copy data", "pgsql.copydata", FT_BYTES
, BASE_NONE
, NULL
, 0,
1130 "Data sent following a Copy-in or Copy-out response.", HFILL
}
1133 { "Error", "pgsql.error", FT_STRINGZ
, BASE_NONE
, NULL
, 0,
1134 "An error message.", HFILL
}
1137 { "PID", "pgsql.pid", FT_UINT32
, BASE_DEC
, NULL
, 0,
1138 "The process ID of a backend.", HFILL
}
1141 { "Key", "pgsql.key", FT_UINT32
, BASE_DEC
, NULL
, 0,
1142 "The secret key used by a particular backend.", HFILL
}
1145 { "Condition", "pgsql.condition", FT_STRINGZ
, BASE_NONE
, NULL
, 0,
1146 "The name of a NOTIFY condition.", HFILL
}
1149 { "Text", "pgsql.text", FT_STRINGZ
, BASE_NONE
, NULL
, 0,
1150 "Text from the backend.", HFILL
}
1153 { "Table OID", "pgsql.oid.table", FT_UINT32
, BASE_DEC
, NULL
, 0,
1154 "The object identifier of a table.", HFILL
}
1157 { "Type OID", "pgsql.oid.type", FT_UINT32
, BASE_DEC
, NULL
, 0,
1158 "The object identifier of a type.", HFILL
}
1161 { "OID", "pgsql.oid", FT_UINT32
, BASE_DEC
, NULL
, 0,
1162 "An object identifier.", HFILL
}
1165 { "Format", "pgsql.format", FT_UINT16
, BASE_DEC
, VALS(format_vals
),
1166 0, "A format specifier.", HFILL
}
1169 { "Field count", "pgsql.field.count", FT_UINT16
, BASE_DEC
, NULL
, 0,
1170 "The number of fields within a row.", HFILL
}
1173 { "Column name", "pgsql.col.name", FT_STRINGZ
, BASE_NONE
, NULL
, 0,
1174 "The name of a column.", HFILL
}
1177 { "Column index", "pgsql.col.index", FT_UINT32
, BASE_DEC
, NULL
, 0,
1178 "The position of a column within a row.", HFILL
}
1181 { "Column length", "pgsql.val.length", FT_INT32
, BASE_DEC
, NULL
, 0,
1182 "The length of a parameter value, in bytes. -1 means NULL.",
1186 { "Data", "pgsql.val.data", FT_BYTES
, BASE_NONE
, NULL
, 0,
1187 "Parameter data.", HFILL
}
1190 { "Type modifier", "pgsql.col.typemod", FT_INT32
, BASE_DEC
, NULL
, 0,
1191 "The type modifier for a column.", HFILL
}
1194 { "Severity", "pgsql.severity", FT_STRINGZ
, BASE_NONE
, NULL
, 0,
1195 "Message severity.", HFILL
}
1198 { "Code", "pgsql.code", FT_STRINGZ
, BASE_NONE
, NULL
, 0,
1199 "SQLState code.", HFILL
}
1202 { "Message", "pgsql.message", FT_STRINGZ
, BASE_NONE
, NULL
, 0,
1203 "Error message.", HFILL
}
1206 { "Detail", "pgsql.detail", FT_STRINGZ
, BASE_NONE
, NULL
, 0,
1207 "Detailed error message.", HFILL
}
1210 { "Hint", "pgsql.hint", FT_STRINGZ
, BASE_NONE
, NULL
, 0,
1211 "A suggestion to resolve an error.", HFILL
}
1214 { "Position", "pgsql.position", FT_STRINGZ
, BASE_NONE
, NULL
, 0,
1215 "The index of the error within the query string.", HFILL
}
1217 { &hf_internal_position
,
1218 { "Position (Internal)", "pgsql.internal_position", FT_STRINGZ
, BASE_NONE
, NULL
, 0,
1219 "The index of the error within the internally-generated query string.", HFILL
}
1221 { &hf_internal_query
,
1222 { "Query (Internal)", "pgsql.internal_query", FT_STRINGZ
, BASE_NONE
, NULL
, 0,
1223 "The internally-generated query string", HFILL
}
1226 { "Context", "pgsql.where", FT_STRINGZ
, BASE_NONE
, NULL
, 0,
1227 "The context in which an error occurred.", HFILL
}
1230 { "Schema", "pgsql.schema_name", FT_STRINGZ
, BASE_NONE
, NULL
, 0,
1231 "The schema with which an error is associated.", HFILL
}
1234 { "Table", "pgsql.table_name", FT_STRINGZ
, BASE_NONE
, NULL
, 0,
1235 "The table with which an error is associated.", HFILL
}
1238 { "Column", "pgsql.column_name", FT_STRINGZ
, BASE_NONE
, NULL
, 0,
1239 "The column with which an error is associated.", HFILL
}
1242 { "Type", "pgsql.type_name", FT_STRINGZ
, BASE_NONE
, NULL
, 0,
1243 "The date type with which an error is associated.", HFILL
}
1245 { &hf_constraint_name
,
1246 { "Constraint", "pgsql.constraint_name", FT_STRINGZ
, BASE_NONE
, NULL
, 0,
1247 "The constraint with which an error is associated.", HFILL
}
1250 { "File", "pgsql.file", FT_STRINGZ
, BASE_NONE
, NULL
, 0,
1251 "The source-code file where an error was reported.", HFILL
}
1254 { "Line", "pgsql.line", FT_STRINGZ
, BASE_NONE
, NULL
, 0,
1255 "The line number on which an error was reported.", HFILL
}
1258 { "Routine", "pgsql.routine", FT_STRINGZ
, BASE_NONE
, NULL
, 0,
1259 "The routine that reported an error.", HFILL
}
1262 { "SSL Response", "pgsql.ssl_response", FT_CHAR
, BASE_HEX
,
1263 VALS(ssl_response_vals
), 0, NULL
, HFILL
}
1265 { &hf_gssenc_response
,
1266 { "GSSAPI Encrypt Response", "pgsql.gssenc_response", FT_CHAR
,
1267 BASE_HEX
, VALS(gssenc_response_vals
), 0, NULL
, HFILL
}
1269 { &hf_gssapi_encrypted_payload
,
1270 { "GSS-API encrypted payload", "pgsql.gssapi.encrypted_payload", FT_BYTES
, BASE_NONE
, NULL
, 0,
1275 static int *ett
[] = {
1280 proto_pgsql
= proto_register_protocol("PostgreSQL", "PGSQL", "pgsql");
1281 pgsql_handle
= register_dissector("pgsql", dissect_pgsql
, proto_pgsql
);
1282 proto_register_field_array(proto_pgsql
, hf
, array_length(hf
));
1283 proto_register_subtree_array(ett
, array_length(ett
));
1285 /* Unfortunately there's no way to set up a GSS-API conversation
1286 * instructing the GSS-API dissector to use our wrap handle; that
1287 * only works for protocols that have an OID and that begin the
1288 * GSS-API conversation by sending that OID.
1290 pgsql_gssapi_handle
= register_dissector("pgsql.gssapi", dissect_pgsql_gssapi
, proto_pgsql
);
1294 proto_reg_handoff_pgsql(void)
1296 dissector_add_uint_with_preference("tcp.port", PGSQL_PORT
, pgsql_handle
);
1298 tls_handle
= find_dissector_add_dependency("tls", proto_pgsql
);
1299 gssapi_handle
= find_dissector_add_dependency("gssapi", proto_pgsql
);
1300 ntlmssp_handle
= find_dissector_add_dependency("ntlmssp", proto_pgsql
);
1304 * Editor modelines - https://www.wireshark.org/tools/modelines.html
1309 * indent-tabs-mode: nil
1312 * vi: set shiftwidth=4 tabstop=8 expandtab:
1313 * :indentSize=4:tabSize=8:noTabs=true: